Merge branch '1.2'
[jansson.git] / src / dump.c
index dc3fcbc..a862cba 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009 Petri Lehtinen <petri@digip.org>
+ * 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.
@@ -9,7 +9,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <stdint.h>
+#include <assert.h>
 
 #include <jansson.h>
 #include "jansson_private.h"
@@ -153,6 +153,18 @@ static int dump_string(const char *str, int ascii, dump_func dump, void *data)
     return dump("\"", 1, data);
 }
 
+static int object_key_compare_keys(const void *key1, const void *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,
                    dump_func dump, void *data)
 {
@@ -185,10 +197,25 @@ static int do_dump(const json_t *json, unsigned long flags, int depth,
             char buffer[MAX_REAL_STR_LENGTH];
             int size;
 
-            size = snprintf(buffer, MAX_REAL_STR_LENGTH, "%0.17f", json_real_value(json));
+            size = snprintf(buffer, MAX_REAL_STR_LENGTH, "%.17g",
+                            json_real_value(json));
             if(size >= MAX_REAL_STR_LENGTH)
                 return -1;
 
+            /* Make sure there's a dot or 'e' in the output. Otherwise
+               a real is converted to an integer when decoding */
+            if(strchr(buffer, '.') == NULL &&
+               strchr(buffer, 'e') == NULL)
+            {
+                if(size + 2 >= MAX_REAL_STR_LENGTH) {
+                    /* No space to append ".0" */
+                    return -1;
+                }
+                buffer[size] = '.';
+                buffer[size + 1] = '0';
+                size += 2;
+            }
+
             return dump(buffer, size, data);
         }
 
@@ -269,29 +296,100 @@ static int do_dump(const json_t *json, unsigned long flags, int depth,
             if(dump_indent(flags, depth + 1, 0, dump, data))
                 return -1;
 
-            while(iter)
+            if(flags & JSON_SORT_KEYS || flags & JSON_PRESERVE_ORDER)
             {
-                void *next = json_object_iter_next((json_t *)json, iter);
-
-                dump_string(json_object_iter_key(iter), ascii, dump, data);
-                if(dump(separator, separator_length, data) ||
-                   do_dump(json_object_iter_value(iter), flags, depth + 1,
-                           dump, data))
+                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(object_key_t *));
+                if(!keys)
                     return -1;
 
-                if(next)
+                i = 0;
+                while(iter)
                 {
-                    if(dump(",", 1, data) ||
-                       dump_indent(flags, depth + 1, 1, dump, data))
-                        return -1;
+                    keys[i] = jsonp_object_iter_fullkey(iter);
+                    iter = json_object_iter_next((json_t *)json, iter);
+                    i++;
                 }
+                assert(i == size);
+
+                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++)
                 {
-                    if(dump_indent(flags, depth, 0, dump, data))
+                    const char *key;
+                    json_t *value;
+
+                    key = keys[i]->key;
+                    value = json_object_get(json, key);
+                    assert(value);
+
+                    dump_string(key, ascii, dump, data);
+                    if(dump(separator, separator_length, data) ||
+                       do_dump(value, flags, depth + 1, dump, data))
+                    {
+                        free(keys);
                         return -1;
+                    }
+
+                    if(i < size - 1)
+                    {
+                        if(dump(",", 1, data) ||
+                           dump_indent(flags, depth + 1, 1, dump, data))
+                        {
+                            free(keys);
+                            return -1;
+                        }
+                    }
+                    else
+                    {
+                        if(dump_indent(flags, depth, 0, dump, data))
+                        {
+                            free(keys);
+                            return -1;
+                        }
+                    }
                 }
 
-                iter = next;
+                free(keys);
+            }
+            else
+            {
+                /* Don't sort keys */
+
+                while(iter)
+                {
+                    void *next = json_object_iter_next((json_t *)json, iter);
+
+                    dump_string(json_object_iter_key(iter), ascii, dump, data);
+                    if(dump(separator, separator_length, data) ||
+                       do_dump(json_object_iter_value(iter), flags, depth + 1,
+                               dump, data))
+                        return -1;
+
+                    if(next)
+                    {
+                        if(dump(",", 1, data) ||
+                           dump_indent(flags, depth + 1, 1, dump, data))
+                            return -1;
+                    }
+                    else
+                    {
+                        if(dump_indent(flags, depth, 0, dump, data))
+                            return -1;
+                    }
+
+                    iter = next;
+                }
             }
 
             object->visited = 0;