[libvirt] [PATCH 1/4] json: support removing a value from an object

Eric Blake eblake at redhat.com
Fri Apr 26 21:01:54 UTC 2013


In an upcoming patch, I need the way to safely transfer a nested
virJSON object out of its parent container for independent use,
even after the parent is freed.

* src/util/virjson.h (virJSONValueObjectRemoveKey): New function.
(_virJSONObject, _virJSONArray): Use correct type.
* src/util/virjson.c (virJSONValueObjectRemoveKey): Implement it.
* src/libvirt_private.syms (virjson.h): Export it.
* tests/jsontest.c (mymain): Test it.

Signed-off-by: Eric Blake <eblake at redhat.com>
---
 src/libvirt_private.syms |  1 +
 src/util/virjson.c       | 34 +++++++++++++++++++-
 src/util/virjson.h       |  9 ++++--
 tests/jsontest.c         | 83 ++++++++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 120 insertions(+), 7 deletions(-)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 0bb6f5f..b502ed8 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1392,6 +1392,7 @@ virJSONValueObjectGetValue;
 virJSONValueObjectHasKey;
 virJSONValueObjectIsNull;
 virJSONValueObjectKeysNumber;
+virJSONValueObjectRemoveKey;
 virJSONValueToString;


diff --git a/src/util/virjson.c b/src/util/virjson.c
index e6a3b1b..10afe88 100644
--- a/src/util/virjson.c
+++ b/src/util/virjson.c
@@ -1,7 +1,7 @@
 /*
  * virjson.c: JSON object parsing/formatting
  *
- * Copyright (C) 2009-2010, 2012 Red Hat, Inc.
+ * Copyright (C) 2009-2010, 2012-2013 Red Hat, Inc.
  * Copyright (C) 2009 Daniel P. Berrange
  *
  * This library is free software; you can redistribute it and/or
@@ -447,6 +447,38 @@ const char *virJSONValueObjectGetKey(virJSONValuePtr object, unsigned int n)
     return object->data.object.pairs[n].key;
 }

+/* Remove the key-value pair tied to KEY out of OBJECT.  If VALUE is
+ * not NULL, the dropped value object is returned instead of freed.
+ * Returns 1 on success, 0 if no key was found, and -1 on error.  */
+int
+virJSONValueObjectRemoveKey(virJSONValuePtr object, const char *key,
+                            virJSONValuePtr *value)
+{
+    int i;
+
+    if (value)
+        *value = NULL;
+
+    if (object->type != VIR_JSON_TYPE_OBJECT)
+        return -1;
+
+    for (i = 0 ; i < object->data.object.npairs ; i++) {
+        if (STREQ(object->data.object.pairs[i].key, key)) {
+            if (value) {
+                *value = object->data.object.pairs[i].value;
+                object->data.object.pairs[i].value = NULL;
+            }
+            VIR_FREE(object->data.object.pairs[i].key);
+            virJSONValueFree(object->data.object.pairs[i].value);
+            VIR_DELETE_ELEMENT(object->data.object.pairs, i,
+                               object->data.object.npairs);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
 virJSONValuePtr virJSONValueObjectGetValue(virJSONValuePtr object, unsigned int n)
 {
     if (object->type != VIR_JSON_TYPE_OBJECT)
diff --git a/src/util/virjson.h b/src/util/virjson.h
index 67f4398..ff0fe75 100644
--- a/src/util/virjson.h
+++ b/src/util/virjson.h
@@ -1,7 +1,7 @@
 /*
  * virjson.h: JSON object parsing/formatting
  *
- * Copyright (C) 2009, 2012 Red Hat, Inc.
+ * Copyright (C) 2009, 2012-2013 Red Hat, Inc.
  * Copyright (C) 2009 Daniel P. Berrange
  *
  * This library is free software; you can redistribute it and/or
@@ -55,12 +55,12 @@ struct _virJSONObjectPair {
 };

 struct _virJSONObject {
-    unsigned int npairs;
+    size_t npairs;
     virJSONObjectPairPtr pairs;
 };

 struct _virJSONArray {
-    unsigned int nvalues;
+    size_t nvalues;
     virJSONValuePtr *values;
 };

@@ -131,6 +131,9 @@ int virJSONValueObjectAppendNumberDouble(virJSONValuePtr object, const char *key
 int virJSONValueObjectAppendBoolean(virJSONValuePtr object, const char *key, int boolean);
 int virJSONValueObjectAppendNull(virJSONValuePtr object, const char *key);

+int virJSONValueObjectRemoveKey(virJSONValuePtr object, const char *key,
+                                virJSONValuePtr *value);
+
 virJSONValuePtr virJSONValueFromString(const char *jsonstring);
 char *virJSONValueToString(virJSONValuePtr object,
                            bool pretty);
diff --git a/tests/jsontest.c b/tests/jsontest.c
index 98a6069..a37a980 100644
--- a/tests/jsontest.c
+++ b/tests/jsontest.c
@@ -11,6 +11,7 @@

 struct testInfo {
     const char *doc;
+    const char *expect;
     bool pass;
 };

@@ -55,19 +56,88 @@ cleanup:


 static int
+testJSONAddRemove(const void *data)
+{
+    const struct testInfo *info = data;
+    virJSONValuePtr json;
+    virJSONValuePtr name;
+    char *result = NULL;
+    int ret = -1;
+
+    json = virJSONValueFromString(info->doc);
+
+    switch (virJSONValueObjectRemoveKey(json, "name", &name)) {
+    case 1:
+        if (!info->pass) {
+            if (virTestGetVerbose())
+                fprintf(stderr, "should not remove from non-object %s\n",
+                        info->doc);
+            goto cleanup;
+        }
+        break;
+    case -1:
+        if (!info->pass)
+            ret = 0;
+        else if (virTestGetVerbose())
+            fprintf(stderr, "Fail to recognize non-object %s\n", info->doc);
+        goto cleanup;
+    default:
+        if (virTestGetVerbose())
+            fprintf(stderr, "unexpected result when removing from %s\n",
+                    info->doc);
+        goto cleanup;
+    }
+    if (STRNEQ_NULLABLE(virJSONValueGetString(name), "sample")) {
+        if (virTestGetVerbose())
+            fprintf(stderr, "unexpected value after removing name: %s\n",
+                    NULLSTR(virJSONValueGetString(name)));
+        goto cleanup;
+    }
+    if (virJSONValueObjectRemoveKey(json, "name", NULL)) {
+        if (virTestGetVerbose())
+            fprintf(stderr, "%s",
+                    "unexpected success when removing missing key\n");
+        goto cleanup;
+    }
+    if (virJSONValueObjectAppendString(json, "newname", "foo") < 0) {
+        if (virTestGetVerbose())
+            fprintf(stderr, "%s", "unexpected failure adding new key\n");
+        goto cleanup;
+    }
+    if (!(result = virJSONValueToString(json, false))) {
+        if (virTestGetVerbose())
+            fprintf(stderr, "%s", "failed to stringize result\n");
+        goto cleanup;
+    }
+    if (STRNEQ(info->expect, result)) {
+        if (virTestGetVerbose())
+            virtTestDifference(stderr, info->expect, result);
+        goto cleanup;
+    }
+    ret = 0;
+
+cleanup:
+    virJSONValueFree(json);
+    virJSONValueFree(name);
+    VIR_FREE(result);
+    return ret;
+}
+
+
+static int
 mymain(void)
 {
     int ret = 0;

-#define DO_TEST_FULL(name, cmd, doc, pass)                          \
+#define DO_TEST_FULL(name, cmd, doc, expect, pass)                  \
     do {                                                            \
-        struct testInfo info = { doc, pass };                       \
+        struct testInfo info = { doc, expect, pass };               \
         if (virtTestRun(name, 1, testJSON ## cmd, &info) < 0)       \
             ret = -1;                                               \
     } while (0)

 #define DO_TEST_PARSE(name, doc)                \
-    DO_TEST_FULL(name, FromString, doc, true)
+    DO_TEST_FULL(name, FromString, doc, NULL, true)

     DO_TEST_PARSE("Simple", "{\"return\": {}, \"id\": \"libvirt-1\"}");
     DO_TEST_PARSE("NotSoSimple", "{\"QMP\": {\"version\": {\"qemu\":"
@@ -105,6 +175,13 @@ mymain(void)
                   "\"query-uuid\"}, {\"name\": \"query-migrate\"}, {\"name\": "
                   "\"query-balloon\"}], \"id\": \"libvirt-2\"}");

+    DO_TEST_FULL("add and remove", AddRemove,
+                 "{\"name\": \"sample\", \"value\": true}",
+                 "{\"value\":true,\"newname\":\"foo\"}",
+                 true);
+    DO_TEST_FULL("add and remove", AddRemove,
+                 "[ 1 ]", NULL, false);
+
     return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
 }

-- 
1.8.1.4




More information about the libvir-list mailing list