Implement dumping to file
[jansson.git] / src / dump.c
1 #define _GNU_SOURCE
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5
6 #include <jansson.h>
7
8 typedef int (*dump_func)(const char *buffer, int size, void *data);
9
10 static int dump_to_file(const char *buffer, int size, void *data)
11 {
12     FILE *dest = (FILE *)data;
13     if(fwrite(buffer, size, 1, dest) != 1)
14         return -1;
15     return 0;
16 }
17
18 static int dump_indent(uint32_t flags, int depth, dump_func dump, void *data)
19 {
20     if(JSON_INDENT(flags) > 0)
21     {
22         char *ws_buffer;
23         int ws_count = JSON_INDENT(flags) * depth;
24
25         if(dump("\n", 1, data))
26             return -1;
27
28         if(ws_count == 0)
29             return 0;
30
31         ws_buffer = alloca(ws_count);
32         memset(ws_buffer, ' ', ws_count);
33         return dump(ws_buffer, ws_count, data);
34     }
35     else
36         return dump(" ", 1, data);
37 }
38
39 static int dump_string(const char *str, dump_func dump, void *data)
40 {
41     const char *end;
42
43     if(dump("\"", 1, data))
44         return -1;
45
46     end = str;
47     while(*end)
48     {
49         while(*end && *end != '\\' && *end != '"')
50             end++;
51
52         if(end != str)
53             if(dump(str, end - str, data))
54                 return -1;
55
56         if(*end == '\\')
57         {
58             if(dump("\\\\", 2, data))
59                 return -1;
60             end++;
61         }
62         else if(*end == '"')
63         {
64             if(dump("\\\"", 2, data))
65                 return -1;
66             end++;
67         }
68         str = end;
69     }
70
71     return dump("\"", 1, data);
72 }
73
74 static int do_dump(const json_t *json, uint32_t flags, int depth,
75                    dump_func dump, void *data)
76 {
77     switch(json_typeof(json)) {
78         case JSON_NULL:
79             return dump("null", 4, data);
80
81         case JSON_TRUE:
82             return dump("true", 4, data);
83
84         case JSON_FALSE:
85             return dump("false", 5, data);
86
87         case JSON_NUMBER:
88         {
89             char *buffer;
90             int size, ret;
91
92             size = asprintf(&buffer, "%.17f", json_number_value(json));
93             if(size == -1)
94                 return -1;
95
96             ret = dump(buffer, size, data);
97             free(buffer);
98             return ret;
99         }
100
101         case JSON_STRING:
102             return dump_string(json_string_value(json), dump, data);
103
104         case JSON_ARRAY:
105         {
106             int i;
107             int n = json_array_size(json);
108
109             if(dump("[", 1, data))
110                 return -1;
111             if(n == 0)
112                 dump("]", 1, data);
113             if(dump_indent(flags, depth + 1, dump, data))
114                 return -1;
115
116             for(i = 0; i < n; ++i) {
117                 if(do_dump(json_array_get(json, i), flags, depth + 1,
118                            dump, data))
119                     return -1;
120
121                 if(i < n - 1)
122                 {
123                     if(dump(",", 1, data) ||
124                        dump_indent(flags, depth + 1, dump, data))
125                         return -1;
126                 }
127                 else
128                 {
129                     if(dump_indent(flags, depth, dump, data))
130                         return -1;
131                 }
132             }
133             return dump("]", 1, data);
134         }
135
136         case JSON_OBJECT:
137         {
138             void *iter = json_object_iter((json_t *)json);
139
140             if(dump("{", 1, data))
141                 return -1;
142             if(!iter)
143                 return dump("}", 1, data);
144             if(dump_indent(flags, depth + 1, dump, data))
145                 return -1;
146
147             while(iter)
148             {
149                 void *next = json_object_iter_next((json_t *)json, iter);
150
151                 dump_string(json_object_iter_key(iter), dump, data);
152                 if(dump(": ", 2, data) ||
153                    do_dump(json_object_iter_value(iter), flags, depth + 1,
154                            dump, data))
155                     return -1;
156
157                 if(next)
158                 {
159                     if(dump(",", 1, data) ||
160                        dump_indent(flags, depth + 1, dump, data))
161                         return -1;
162                 }
163                 else
164                 {
165                     if(dump_indent(flags, depth, dump, data))
166                         return -1;
167                 }
168
169                 iter = next;
170             }
171             return dump("}", 1, data);
172         }
173
174         default:
175             /* not reached */
176             return -1;
177     }
178 }
179
180
181 int json_dumpf(const json_t *json, FILE *output, uint32_t flags)
182 {
183     if(do_dump(json, flags, 0, dump_to_file, (void *)output))
184         return -1;
185     return dump_to_file("\n", 1, (void *)output);
186 }