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