Merge branch '1.2'
authorPetri Lehtinen <petri@digip.org>
Thu, 20 May 2010 15:47:30 +0000 (18:47 +0300)
committerPetri Lehtinen <petri@digip.org>
Thu, 20 May 2010 15:47:30 +0000 (18:47 +0300)
doc/apiref.rst
src/dump.c
test/.gitignore
test/suites/api/Makefile.am
test/suites/api/test_dump.c [new file with mode: 0644]

index ebe00ea..bacd756 100644 (file)
@@ -154,9 +154,31 @@ Normally, all functions accepting a JSON value as an argument will
 manage the reference, i.e. increase and decrease the reference count
 as needed. However, some functions **steal** the reference, i.e. they
 have the same result as if the user called :cfunc:`json_decref()` on
-the argument right after calling the function. These are usually
-convenience functions for adding new references to containers and not
-to worry about the reference count.
+the argument right after calling the function. These functions are
+suffixed with ``_new`` or have ``_new_`` somewhere in their name.
+
+For example, the following code creates a new JSON array and appends
+an integer to it::
+
+  json_t *array, *integer;
+
+  array = json_array();
+  integer = json_integer(42);
+
+  json_array_append(array, integer);
+  json_decref(integer);
+
+Note how the caller has to release the reference to the integer value
+by calling :cfunc:`json_decref()`. By using a reference stealing
+function :cfunc:`json_array_append_new()` instead of
+:cfunc:`json_array_append()`, the code becomes much simpler::
+
+  json_t *array = json_array();
+  json_array_append_new(array, json_integer(42));
+
+In this case, the user doesn't have to explicitly release the
+reference to the integer value, as :cfunc:`json_array_append_new()`
+steals the reference when appending the value to the array.
 
 In the following sections it is clearly documented whether a function
 will return a new or borrowed reference or steal a reference to its
index a862cba..dc27fbd 100644 (file)
@@ -231,38 +231,44 @@ static int do_dump(const json_t *json, unsigned long flags, int depth,
             /* detect circular references */
             array = json_to_array(json);
             if(array->visited)
-                return -1;
+                goto array_error;
             array->visited = 1;
 
             n = json_array_size(json);
 
             if(dump("[", 1, data))
-                return -1;
-            if(n == 0)
+                goto array_error;
+            if(n == 0) {
+                array->visited = 0;
                 return dump("]", 1, data);
+            }
             if(dump_indent(flags, depth + 1, 0, dump, data))
-                return -1;
+                goto array_error;
 
             for(i = 0; i < n; ++i) {
                 if(do_dump(json_array_get(json, i), flags, depth + 1,
                            dump, data))
-                    return -1;
+                    goto array_error;
 
                 if(i < n - 1)
                 {
                     if(dump(",", 1, data) ||
                        dump_indent(flags, depth + 1, 1, dump, data))
-                        return -1;
+                        goto array_error;
                 }
                 else
                 {
                     if(dump_indent(flags, depth, 0, dump, data))
-                        return -1;
+                        goto array_error;
                 }
             }
 
             array->visited = 0;
             return dump("]", 1, data);
+
+        array_error:
+            array->visited = 0;
+            return -1;
         }
 
         case JSON_OBJECT:
@@ -284,17 +290,19 @@ static int do_dump(const json_t *json, unsigned long flags, int depth,
             /* detect circular references */
             object = json_to_object(json);
             if(object->visited)
-                return -1;
+                goto object_error;
             object->visited = 1;
 
             iter = json_object_iter((json_t *)json);
 
             if(dump("{", 1, data))
-                return -1;
-            if(!iter)
+                goto object_error;
+            if(!iter) {
+                object->visited = 0;
                 return dump("}", 1, data);
+            }
             if(dump_indent(flags, depth + 1, 0, dump, data))
-                return -1;
+                goto object_error;
 
             if(flags & JSON_SORT_KEYS || flags & JSON_PRESERVE_ORDER)
             {
@@ -306,7 +314,7 @@ static int do_dump(const json_t *json, unsigned long flags, int depth,
                 size = json_object_size(json);
                 keys = malloc(size * sizeof(object_key_t *));
                 if(!keys)
-                    return -1;
+                    goto object_error;
 
                 i = 0;
                 while(iter)
@@ -338,7 +346,7 @@ static int do_dump(const json_t *json, unsigned long flags, int depth,
                        do_dump(value, flags, depth + 1, dump, data))
                     {
                         free(keys);
-                        return -1;
+                        goto object_error;
                     }
 
                     if(i < size - 1)
@@ -347,7 +355,7 @@ static int do_dump(const json_t *json, unsigned long flags, int depth,
                            dump_indent(flags, depth + 1, 1, dump, data))
                         {
                             free(keys);
-                            return -1;
+                            goto object_error;
                         }
                     }
                     else
@@ -355,7 +363,7 @@ static int do_dump(const json_t *json, unsigned long flags, int depth,
                         if(dump_indent(flags, depth, 0, dump, data))
                         {
                             free(keys);
-                            return -1;
+                            goto object_error;
                         }
                     }
                 }
@@ -374,18 +382,18 @@ static int do_dump(const json_t *json, unsigned long flags, int depth,
                     if(dump(separator, separator_length, data) ||
                        do_dump(json_object_iter_value(iter), flags, depth + 1,
                                dump, data))
-                        return -1;
+                        goto object_error;
 
                     if(next)
                     {
                         if(dump(",", 1, data) ||
                            dump_indent(flags, depth + 1, 1, dump, data))
-                            return -1;
+                            goto object_error;
                     }
                     else
                     {
                         if(dump_indent(flags, depth, 0, dump, data))
-                            return -1;
+                            goto object_error;
                     }
 
                     iter = next;
@@ -394,6 +402,10 @@ static int do_dump(const json_t *json, unsigned long flags, int depth,
 
             object->visited = 0;
             return dump("}", 1, data);
+
+        object_error:
+            object->visited = 0;
+            return -1;
         }
 
         default:
index 065b4ea..dca3c1e 100644 (file)
@@ -3,6 +3,7 @@ bin/json_process
 suites/api/test_array
 suites/api/test_equal
 suites/api/test_copy
+suites/api/test_dump
 suites/api/test_load
 suites/api/test_number
 suites/api/test_object
index ddeb147..939b7be 100644 (file)
@@ -4,6 +4,7 @@ check_PROGRAMS = \
        test_array \
        test_equal \
        test_copy \
+       test_dump \
        test_load \
        test_simple \
        test_number \
@@ -12,6 +13,7 @@ check_PROGRAMS = \
 
 test_array_SOURCES = test_array.c util.h
 test_copy_SOURCES = test_copy.c util.h
+test_dump_SOURCES = test_dump.c util.h
 test_load_SOURCES = test_load.c util.h
 test_simple_SOURCES = test_simple.c util.h
 test_number_SOURCES = test_number.c util.h
diff --git a/test/suites/api/test_dump.c b/test/suites/api/test_dump.c
new file mode 100644 (file)
index 0000000..97eb03e
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include <jansson.h>
+#include <string.h>
+#include "util.h"
+
+int main()
+{
+    json_t *json;
+    char *result;
+
+    /* Encode an empty object/array, add an item, encode again */
+
+    json = json_object();
+    result = json_dumps(json, 0);
+    if(!result || strcmp(result, "{}"))
+      fail("json_dumps failed");
+
+    json_object_set_new(json, "foo", json_integer(5));
+    result = json_dumps(json, 0);
+    if(!result || strcmp(result, "{\"foo\": 5}"))
+      fail("json_dumps failed");
+
+    json_decref(json);
+
+    json = json_array();
+    result = json_dumps(json, 0);
+    if(!result || strcmp(result, "[]"))
+      fail("json_dumps failed");
+    free(result);
+
+    json_array_append_new(json, json_integer(5));
+    result = json_dumps(json, 0);
+    if(!result || strcmp(result, "[5]"))
+      fail("json_dumps failed");
+    free(result);
+
+    json_decref(json);
+
+    /* Construct a JSON object/array with a circular reference:
+
+       object: {"a": {"b": {"c": <circular reference to $.a>}}}
+       array: [[[<circular reference to the $[0] array>]]]
+
+       Encode it, remove the circular reference and encode again.
+    */
+    json = json_object();
+    json_object_set_new(json, "a", json_object());
+    json_object_set_new(json_object_get(json, "a"), "b", json_object());
+    json_object_set(json_object_get(json_object_get(json, "a"), "b"), "c",
+                    json_object_get(json, "a"));
+
+    if(json_dumps(json, 0))
+        fail("json_dumps encoded a circular reference!");
+
+    json_object_del(json_object_get(json_object_get(json, "a"), "b"), "c");
+
+    result = json_dumps(json, 0);
+    if(!result || strcmp(result, "{\"a\": {\"b\": {}}}"))
+        fail("json_dumps failed!");
+    free(result);
+
+    json_decref(json);
+
+    json = json_array();
+    json_array_append_new(json, json_array());
+    json_array_append_new(json_array_get(json, 0), json_array());
+    json_array_append(json_array_get(json_array_get(json, 0), 0),
+                      json_array_get(json, 0));
+
+    if(json_dumps(json, 0))
+        fail("json_dumps encoded a circular reference!");
+
+    json_array_remove(json_array_get(json_array_get(json, 0), 0), 0);
+
+    result = json_dumps(json, 0);
+    if(!result || strcmp(result, "[[[]]]"))
+        fail("json_dumps failed!");
+    free(result);
+
+    json_decref(json);
+
+    return 0;
+}