1 /*
2 * Copyright (c) 2007-2014, Lloyd Hilaiel <me@lloyd.io>
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include <yajl/yajl_parse.h>
18 #include <yajl/yajl_gen.h>
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23
24 /* non-zero when we're reformatting a stream */
25 static int s_streamReformat = 0;
26
27 #define GEN_AND_RETURN(func) \
28 { \
29 yajl_gen_status __stat = func; \
30 if (__stat == yajl_gen_generation_complete && s_streamReformat) { \
31 yajl_gen_reset(g, "\n"); \
32 __stat = func; \
33 } \
34 return __stat == yajl_gen_status_ok; }
35
reformat_null(void * ctx)36 static int reformat_null(void * ctx)
37 {
38 yajl_gen g = (yajl_gen) ctx;
39 GEN_AND_RETURN(yajl_gen_null(g));
40 }
41
reformat_boolean(void * ctx,int boolean)42 static int reformat_boolean(void * ctx, int boolean)
43 {
44 yajl_gen g = (yajl_gen) ctx;
45 GEN_AND_RETURN(yajl_gen_bool(g, boolean));
46 }
47
reformat_number(void * ctx,const char * s,size_t l)48 static int reformat_number(void * ctx, const char * s, size_t l)
49 {
50 yajl_gen g = (yajl_gen) ctx;
51 GEN_AND_RETURN(yajl_gen_number(g, s, l));
52 }
53
reformat_string(void * ctx,const unsigned char * stringVal,size_t stringLen)54 static int reformat_string(void * ctx, const unsigned char * stringVal,
55 size_t stringLen)
56 {
57 yajl_gen g = (yajl_gen) ctx;
58 GEN_AND_RETURN(yajl_gen_string(g, stringVal, stringLen));
59 }
60
reformat_map_key(void * ctx,const unsigned char * stringVal,size_t stringLen)61 static int reformat_map_key(void * ctx, const unsigned char * stringVal,
62 size_t stringLen)
63 {
64 yajl_gen g = (yajl_gen) ctx;
65 GEN_AND_RETURN(yajl_gen_string(g, stringVal, stringLen));
66 }
67
reformat_start_map(void * ctx)68 static int reformat_start_map(void * ctx)
69 {
70 yajl_gen g = (yajl_gen) ctx;
71 GEN_AND_RETURN(yajl_gen_map_open(g));
72 }
73
74
reformat_end_map(void * ctx)75 static int reformat_end_map(void * ctx)
76 {
77 yajl_gen g = (yajl_gen) ctx;
78 GEN_AND_RETURN(yajl_gen_map_close(g));
79 }
80
reformat_start_array(void * ctx)81 static int reformat_start_array(void * ctx)
82 {
83 yajl_gen g = (yajl_gen) ctx;
84 GEN_AND_RETURN(yajl_gen_array_open(g));
85 }
86
reformat_end_array(void * ctx)87 static int reformat_end_array(void * ctx)
88 {
89 yajl_gen g = (yajl_gen) ctx;
90 GEN_AND_RETURN(yajl_gen_array_close(g));
91 }
92
93 static yajl_callbacks callbacks = {
94 reformat_null,
95 reformat_boolean,
96 NULL,
97 NULL,
98 reformat_number,
99 reformat_string,
100 reformat_start_map,
101 reformat_map_key,
102 reformat_end_map,
103 reformat_start_array,
104 reformat_end_array
105 };
106
107 static void
usage(const char * progname)108 usage(const char * progname)
109 {
110 fprintf(stderr, "%s: reformat json from stdin\n"
111 "usage: json_reformat [options]\n"
112 " -e escape any forward slashes (for embedding in HTML)\n"
113 " -m minimize json rather than beautify (default)\n"
114 " -s reformat a stream of multiple json entites\n"
115 " -u allow invalid UTF8 inside strings during parsing\n",
116 progname);
117 exit(1);
118 }
119
120 int
main(int argc,char ** argv)121 main(int argc, char ** argv)
122 {
123 yajl_handle hand;
124 static unsigned char fileData[65536];
125 /* generator config */
126 yajl_gen g;
127 yajl_status stat;
128 size_t rd;
129 int retval = 0;
130 int a = 1;
131
132 g = yajl_gen_alloc(NULL);
133 yajl_gen_config(g, yajl_gen_beautify, 1);
134 yajl_gen_config(g, yajl_gen_validate_utf8, 1);
135
136 /* ok. open file. let's read and parse */
137 hand = yajl_alloc(&callbacks, NULL, (void *) g);
138 /* and let's allow comments by default */
139 yajl_config(hand, yajl_allow_comments, 1);
140
141 /* check arguments.*/
142 while ((a < argc) && (argv[a][0] == '-') && (strlen(argv[a]) > 1)) {
143 unsigned int i;
144 for ( i=1; i < strlen(argv[a]); i++) {
145 switch (argv[a][i]) {
146 case 'm':
147 yajl_gen_config(g, yajl_gen_beautify, 0);
148 break;
149 case 's':
150 yajl_config(hand, yajl_allow_multiple_values, 1);
151 s_streamReformat = 1;
152 break;
153 case 'u':
154 yajl_config(hand, yajl_dont_validate_strings, 1);
155 break;
156 case 'e':
157 yajl_gen_config(g, yajl_gen_escape_solidus, 1);
158 break;
159 default:
160 fprintf(stderr, "unrecognized option: '%c'\n\n",
161 argv[a][i]);
162 usage(argv[0]);
163 }
164 }
165 ++a;
166 }
167 if (a < argc) {
168 usage(argv[0]);
169 }
170
171
172 for (;;) {
173 rd = fread((void *) fileData, 1, sizeof(fileData) - 1, stdin);
174
175 if (rd == 0) {
176 if (!feof(stdin)) {
177 fprintf(stderr, "error on file read.\n");
178 retval = 1;
179 }
180 break;
181 }
182 fileData[rd] = 0;
183
184 stat = yajl_parse(hand, fileData, rd);
185
186 if (stat != yajl_status_ok) break;
187
188 {
189 const unsigned char * buf;
190 size_t len;
191 yajl_gen_get_buf(g, &buf, &len);
192 fwrite(buf, 1, len, stdout);
193 yajl_gen_clear(g);
194 }
195 }
196
197 stat = yajl_complete_parse(hand);
198
199 if (stat != yajl_status_ok) {
200 unsigned char * str = yajl_get_error(hand, 1, fileData, rd);
201 fprintf(stderr, "%s", (const char *) str);
202 yajl_free_error(hand, str);
203 retval = 1;
204 }
205
206 yajl_gen_free(g);
207 yajl_free(hand);
208
209 return retval;
210 }
211