1 | /* JSON Printer |
---|
2 | * ZZJSON - Copyright (C) 2008 by Ivo van Poorten |
---|
3 | * License: GNU Lesser General Public License version 2.1 |
---|
4 | */ |
---|
5 | |
---|
6 | #include "zzjson.h" |
---|
7 | |
---|
8 | #define PRINT(fmt...) if (config->print(config->ohandle, ##fmt) < 0) return -1; |
---|
9 | //#define PUTC(c) if (config->putchar(c, config->ohandle) < 0) return -1; |
---|
10 | #define PUTC(c) PRINT("%c",c) |
---|
11 | #define INC 4 |
---|
12 | |
---|
13 | static int print_string(ZZJSON_CONFIG *config, char *s) { |
---|
14 | int c, bs; |
---|
15 | if (!s) return 0; |
---|
16 | while ((c = *s++)) { |
---|
17 | bs = 1; |
---|
18 | switch (c) { |
---|
19 | // case '/': // useless escape of forward slash |
---|
20 | case '\\': |
---|
21 | if (*s == 'u') bs = 0; // copy \uHHHH verbatim |
---|
22 | break; |
---|
23 | case '"': break; |
---|
24 | case '\b': c = 'b'; break; |
---|
25 | case '\f': c = 'f'; break; |
---|
26 | case '\n': c = 'n'; break; |
---|
27 | case '\r': c = 'r'; break; |
---|
28 | case '\t': c = 't'; break; |
---|
29 | default: bs = 0; break; |
---|
30 | } |
---|
31 | if (bs) PUTC('\\'); |
---|
32 | PUTC(c); |
---|
33 | } |
---|
34 | return 0; |
---|
35 | } |
---|
36 | |
---|
37 | static int zzjson_print2(ZZJSON_CONFIG *config, ZZJSON *zzjson, |
---|
38 | unsigned int indent, unsigned int objval) { |
---|
39 | char c = 0, d = 0; |
---|
40 | if (!zzjson) return -1; |
---|
41 | |
---|
42 | switch(zzjson->type) { |
---|
43 | case ZZJSON_OBJECT: c = '{'; d = '}'; break; |
---|
44 | case ZZJSON_ARRAY: c = '['; d = ']'; break; |
---|
45 | default: break; |
---|
46 | } |
---|
47 | |
---|
48 | if (c) PRINT("%s%*s%c", indent ? "\n" : "", indent, "", c); |
---|
49 | |
---|
50 | while (zzjson) { |
---|
51 | switch(zzjson->type) { |
---|
52 | case ZZJSON_OBJECT: |
---|
53 | if (zzjson->value.object.val) { |
---|
54 | PRINT("\n%*s\"", indent+INC, ""); |
---|
55 | if (print_string(config, zzjson->value.object.label) < 0) |
---|
56 | return -1; |
---|
57 | PRINT("\" :"); |
---|
58 | if (zzjson_print2(config, zzjson->value.object.val, |
---|
59 | indent+INC, 1) < 0) return -1; |
---|
60 | } |
---|
61 | break; |
---|
62 | case ZZJSON_ARRAY: |
---|
63 | if (zzjson->value.array.val) |
---|
64 | if (zzjson_print2(config, zzjson->value.array.val, |
---|
65 | indent+INC, 0) < 0) return -1; |
---|
66 | break; |
---|
67 | case ZZJSON_STRING: |
---|
68 | PRINT(objval ? " \"" : "\n%*s\"", indent, ""); |
---|
69 | if (print_string(config, zzjson->value.string.string)<0) return -1; |
---|
70 | PUTC('"'); |
---|
71 | break; |
---|
72 | case ZZJSON_FALSE: |
---|
73 | PRINT(objval ? " false" : "\n%*sfalse", indent, ""); |
---|
74 | break; |
---|
75 | case ZZJSON_NULL: |
---|
76 | PRINT(objval ? " null" : "\n%*snull", indent, ""); |
---|
77 | break; |
---|
78 | case ZZJSON_TRUE: |
---|
79 | PRINT(objval ? " true" : "\n%*strue", indent, ""); |
---|
80 | break; |
---|
81 | case ZZJSON_NUMBER_NEGINT: |
---|
82 | case ZZJSON_NUMBER_POSINT: |
---|
83 | case ZZJSON_NUMBER_DOUBLE: |
---|
84 | PRINT(objval ? " " : "\n%*s", indent, ""); |
---|
85 | if (zzjson->type == ZZJSON_NUMBER_DOUBLE) { |
---|
86 | PRINT("%16.16e", zzjson->value.number.val.dval); |
---|
87 | } else { |
---|
88 | if (zzjson->type == ZZJSON_NUMBER_NEGINT) PUTC('-'); |
---|
89 | PRINT("%llu", zzjson->value.number.val.ival); |
---|
90 | } |
---|
91 | default: |
---|
92 | break; |
---|
93 | } |
---|
94 | zzjson = zzjson->next; |
---|
95 | if (zzjson) PUTC(','); |
---|
96 | } |
---|
97 | |
---|
98 | if (d) PRINT("\n%*s%c", indent, "", d); |
---|
99 | |
---|
100 | return 0; |
---|
101 | } |
---|
102 | |
---|
103 | int zzjson_print(ZZJSON_CONFIG *config, ZZJSON *zzjson) { |
---|
104 | int retval = zzjson_print2(config, zzjson, 0, 0); |
---|
105 | // if (retval >= 0) retval = config->putchar('\n', config->ohandle); |
---|
106 | #ifndef CONFIG_NO_ERROR_MESSAGES |
---|
107 | if (retval < 0) config->error(config->ehandle, "print: unable to print"); |
---|
108 | #endif |
---|
109 | return retval; |
---|
110 | } |
---|