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)
1  2 
doc/apiref.rst
src/dump.c
test/.gitignore
test/suites/api/Makefile.am

diff --combined doc/apiref.rst
@@@ -154,9 -154,31 +154,31 @@@ Normally, all functions accepting a JSO
  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
@@@ -493,16 -515,6 +515,16 @@@ The following functions implement an it
     Returns an opaque iterator which can be used to iterate over all
     key-value pairs in *object*, or *NULL* if *object* is empty.
  
 +.. cfunction:: void *json_object_iter_at(json_t *object, const char *key)
 +
 +   Like :cfunc:`json_object_iter()`, but returns an iterator to the
 +   key-value pair in *object* whose key is equal to *key*, or NULL if
 +   *key* is not found in *object*. Iterating forward to the end of
 +   *object* only yields all key-value pairs of the object if *key*
 +   happens to be the first key in the underlying hash table.
 +
 +   .. versionadded:: 1.3
 +
  .. cfunction:: void *json_object_iter_next(json_t *object, void *iter)
  
     Returns an iterator pointing to the next key-value pair in *object*
  
     Extract the associated value from *iter*.
  
 +.. cfunction:: int json_object_iter_set(json_t *object, void *iter, json_t *value)
 +
 +   Set the value of the key-value pair in *object*, that is pointed to
 +   by *iter*, to *value*.
 +
 +   .. versionadded:: 1.3
 +
 +.. cfunction:: int json_object_iter_set_new(json_t *object, void *iter, json_t *value)
 +
 +   Like :cfunc:`json_object_iter_set()`, but steals the reference to
 +   *value*. This is useful when *value* is newly created and not used
 +   after the call.
 +
 +   .. versionadded:: 1.3
 +
  The iteration protocol can be used for example as follows::
  
     /* obj is a JSON object */
@@@ -595,14 -592,6 +617,14 @@@ can be ORed together to obtain *flags*
  
     .. versionadded:: 1.2
  
 +``JSON_PRESERVE_ORDER``
 +   If this flag is used, object keys in the output are sorted into the
 +   same order in which they were first inserted to the object. For
 +   example, decoding a JSON text and then encoding with this flag
 +   preserves the order of object keys.
 +
 +   .. versionadded:: 1.3
 +
  The following functions perform the actual JSON encoding. The result
  is in UTF-8.
  
diff --combined src/dump.c
@@@ -153,16 -153,9 +153,16 @@@ static int dump_string(const char *str
      return dump("\"", 1, data);
  }
  
 -static int object_key_cmp(const void *key1, const void *key2)
 +static int object_key_compare_keys(const void *key1, const void *key2)
  {
 -    return strcmp(*(const char **)key1, *(const char **)key2);
 +    return strcmp((*(const object_key_t **)key1)->key,
 +                  (*(const object_key_t **)key2)->key);
 +}
 +
 +static int object_key_compare_serials(const void *key1, const void *key2)
 +{
 +    return (*(const object_key_t **)key1)->serial -
 +           (*(const object_key_t **)key2)->serial;
  }
  
  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:
              /* 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)
 +            if(flags & JSON_SORT_KEYS || flags & JSON_PRESERVE_ORDER)
              {
 -                /* Sort keys */
 -
 -                const char **keys;
 +                const object_key_t **keys;
                  unsigned int size;
                  unsigned int i;
 +                int (*cmp_func)(const void *, const void *);
  
                  size = json_object_size(json);
 -                keys = malloc(size * sizeof(const char *));
 +                keys = malloc(size * sizeof(object_key_t *));
                  if(!keys)
-                     return -1;
+                     goto object_error;
  
                  i = 0;
                  while(iter)
                  {
 -                    keys[i] = json_object_iter_key(iter);
 +                    keys[i] = jsonp_object_iter_fullkey(iter);
                      iter = json_object_iter_next((json_t *)json, iter);
                      i++;
                  }
                  assert(i == size);
  
 -                qsort(keys, size, sizeof(const char *), object_key_cmp);
 +                if(flags & JSON_SORT_KEYS)
 +                    cmp_func = object_key_compare_keys;
 +                else
 +                    cmp_func = object_key_compare_serials;
 +
 +                qsort(keys, size, sizeof(object_key_t *), cmp_func);
  
                  for(i = 0; i < size; i++)
                  {
                      const char *key;
                      json_t *value;
  
 -                    key = keys[i];
 +                    key = keys[i]->key;
                      value = json_object_get(json, key);
                      assert(value);
  
                         do_dump(value, flags, depth + 1, dump, data))
                      {
                          free(keys);
-                         return -1;
+                         goto object_error;
                      }
  
                      if(i < size - 1)
                             dump_indent(flags, depth + 1, 1, dump, data))
                          {
                              free(keys);
-                             return -1;
+                             goto object_error;
                          }
                      }
                      else
                          if(dump_indent(flags, depth, 0, dump, data))
                          {
                              free(keys);
-                             return -1;
+                             goto object_error;
                          }
                      }
                  }
                      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;
  
              object->visited = 0;
              return dump("}", 1, data);
+         object_error:
+             object->visited = 0;
+             return -1;
          }
  
          default:
diff --combined test/.gitignore
@@@ -3,8 -3,8 +3,9 @@@ bin/json_proces
  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
  suites/api/test_simple
 +suites/api/test_cpp
@@@ -4,19 -4,19 +4,21 @@@ check_PROGRAMS = 
        test_array \
        test_equal \
        test_copy \
+       test_dump \
        test_load \
        test_simple \
        test_number \
 -      test_object
 +      test_object \
 +      test_cpp
  
  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
  test_object_SOURCES = test_object.c util.h
 +test_cpp_SOURCES = test_cpp.cpp
  
  AM_CPPFLAGS = -I$(top_srcdir)/src
  AM_CFLAGS = -Wall -Werror