xref: /NextBSD/contrib/jansson/test/bin/json_process.c (revision 33da5adc555b3bc29986eeadca03829e4ad06b1e)
1 /*
2  * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
3  *
4  * Jansson is free software; you can redistribute it and/or modify
5  * it under the terms of the MIT license. See LICENSE for details.
6  */
7 
8 #ifdef HAVE_CONFIG_H
9 #include <jansson_private_config.h>
10 #endif
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <ctype.h>
16 #include <jansson.h>
17 
18 #ifdef HAVE_LOCALE_H
19 #include <locale.h>
20  #endif
21 
22 #if _WIN32
23 #include <io.h>  /* for _setmode() */
24 #include <fcntl.h>  /* for _O_BINARY */
25 
26 static const char dir_sep = '\\';
27 #else
28 static const char dir_sep = '/';
29 #endif
30 
31 
32 struct config {
33     int indent;
34     int compact;
35     int preserve_order;
36     int ensure_ascii;
37     int sort_keys;
38     int strip;
39     int use_env;
40     int have_hashseed;
41     int hashseed;
42     int precision;
43 } conf;
44 
45 #define l_isspace(c) ((c) == ' ' || (c) == '\n' || (c) == '\r' || (c) == '\t')
46 
47 /* Return a pointer to the first non-whitespace character of str.
48    Modifies str so that all trailing whitespace characters are
49    replaced by '\0'. */
strip(char * str)50 static const char *strip(char *str)
51 {
52     size_t length;
53     char *result = str;
54     while (*result && l_isspace(*result))
55         result++;
56 
57     length = strlen(result);
58     if (length == 0)
59         return result;
60 
61     while (l_isspace(result[length - 1]))
62         result[--length] = '\0';
63 
64     return result;
65 }
66 
67 
loadfile(FILE * file)68 static char *loadfile(FILE *file)
69 {
70     long fsize, ret;
71     char *buf;
72 
73     fseek(file, 0, SEEK_END);
74     fsize = ftell(file);
75     fseek(file, 0, SEEK_SET);
76 
77     buf = malloc(fsize+1);
78     ret = fread(buf, 1, fsize, file);
79     if (ret != fsize)
80         exit(1);
81     buf[fsize] = '\0';
82 
83     return buf;
84 }
85 
86 
read_conf(FILE * conffile)87 static void read_conf(FILE *conffile)
88 {
89     char *buffer, *line, *val;
90 
91     buffer = loadfile(conffile);
92     for (line = strtok(buffer, "\r\n"); line; line = strtok(NULL, "\r\n")) {
93         if (!strncmp(line, "export ", 7))
94             continue;
95         val = strchr(line, '=');
96         if (!val) {
97             printf("invalid configuration line\n");
98             break;
99         }
100         *val++ = '\0';
101 
102         if (!strcmp(line, "JSON_INDENT"))
103             conf.indent = atoi(val);
104         if (!strcmp(line, "JSON_COMPACT"))
105             conf.compact = atoi(val);
106         if (!strcmp(line, "JSON_ENSURE_ASCII"))
107             conf.ensure_ascii = atoi(val);
108         if (!strcmp(line, "JSON_PRESERVE_ORDER"))
109             conf.preserve_order = atoi(val);
110         if (!strcmp(line, "JSON_SORT_KEYS"))
111             conf.sort_keys = atoi(val);
112         if (!strcmp(line, "JSON_REAL_PRECISION"))
113             conf.precision = atoi(val);
114         if (!strcmp(line, "STRIP"))
115             conf.strip = atoi(val);
116         if (!strcmp(line, "HASHSEED")) {
117             conf.have_hashseed = 1;
118             conf.hashseed = atoi(val);
119         } else {
120             conf.have_hashseed = 0;
121         }
122     }
123 
124     free(buffer);
125 }
126 
127 
cmpfile(const char * str,const char * path,const char * fname)128 static int cmpfile(const char *str, const char *path, const char *fname)
129 {
130     char filename[1024], *buffer;
131     int ret;
132     FILE *file;
133 
134     sprintf(filename, "%s%c%s", path, dir_sep, fname);
135     file = fopen(filename, "rb");
136     if (!file) {
137         if (conf.strip)
138             strcat(filename, ".strip");
139         else
140             strcat(filename, ".normal");
141         file = fopen(filename, "rb");
142     }
143     if (!file) {
144         printf("Error: test result file could not be opened.\n");
145         exit(1);
146     }
147 
148     buffer = loadfile(file);
149     if (strcmp(buffer, str) != 0)
150         ret = 1;
151     else
152         ret = 0;
153     free(buffer);
154     fclose(file);
155 
156     return ret;
157 }
158 
use_conf(char * test_path)159 int use_conf(char *test_path)
160 {
161     int ret;
162     size_t flags = 0;
163     char filename[1024], errstr[1024];
164     char *buffer;
165     FILE *infile, *conffile;
166     json_t *json;
167     json_error_t error;
168 
169     sprintf(filename, "%s%cinput", test_path, dir_sep);
170     if (!(infile = fopen(filename, "rb"))) {
171         fprintf(stderr, "Could not open \"%s\"\n", filename);
172         return 2;
173     }
174 
175     sprintf(filename, "%s%cenv", test_path, dir_sep);
176     conffile = fopen(filename, "rb");
177     if (conffile) {
178         read_conf(conffile);
179         fclose(conffile);
180     }
181 
182     if (conf.indent < 0 || conf.indent > 31) {
183         fprintf(stderr, "invalid value for JSON_INDENT: %d\n", conf.indent);
184         fclose(infile);
185         return 2;
186     }
187     if (conf.indent)
188         flags |= JSON_INDENT(conf.indent);
189 
190     if (conf.compact)
191         flags |= JSON_COMPACT;
192 
193     if (conf.ensure_ascii)
194         flags |= JSON_ENSURE_ASCII;
195 
196     if (conf.preserve_order)
197         flags |= JSON_PRESERVE_ORDER;
198 
199     if (conf.sort_keys)
200         flags |= JSON_SORT_KEYS;
201 
202     if (conf.precision < 0 || conf.precision > 31) {
203         fprintf(stderr, "invalid value for JSON_REAL_PRECISION: %d\n",
204                 conf.precision);
205         fclose(infile);
206         return 2;
207     }
208     if (conf.precision)
209         flags |= JSON_REAL_PRECISION(conf.precision);
210 
211     if (conf.have_hashseed)
212         json_object_seed(conf.hashseed);
213 
214     if (conf.strip) {
215         /* Load to memory, strip leading and trailing whitespace */
216         buffer = loadfile(infile);
217         json = json_loads(strip(buffer), 0, &error);
218         free(buffer);
219     }
220     else
221         json = json_loadf(infile, 0, &error);
222 
223     fclose(infile);
224 
225     if (!json) {
226         sprintf(errstr, "%d %d %d\n%s\n",
227                 error.line, error.column, error.position,
228                 error.text);
229 
230         ret = cmpfile(errstr, test_path, "error");
231         return ret;
232     }
233 
234     buffer = json_dumps(json, flags);
235     ret = cmpfile(buffer, test_path, "output");
236     free(buffer);
237     json_decref(json);
238 
239     return ret;
240 }
241 
getenv_int(const char * name)242 static int getenv_int(const char *name)
243 {
244     char *value, *end;
245     long result;
246 
247     value = getenv(name);
248     if(!value)
249         return 0;
250 
251     result = strtol(value, &end, 10);
252     if(*end != '\0')
253         return 0;
254 
255     return (int)result;
256 }
257 
use_env()258 int use_env()
259 {
260     int indent, precision;
261     size_t flags = 0;
262     json_t *json;
263     json_error_t error;
264 
265     #ifdef _WIN32
266     /* On Windows, set stdout and stderr to binary mode to avoid
267        outputting DOS line terminators */
268     _setmode(_fileno(stdout), _O_BINARY);
269     _setmode(_fileno(stderr), _O_BINARY);
270     #endif
271 
272     indent = getenv_int("JSON_INDENT");
273     if(indent < 0 || indent > 31) {
274         fprintf(stderr, "invalid value for JSON_INDENT: %d\n", indent);
275         return 2;
276     }
277     if(indent > 0)
278         flags |= JSON_INDENT(indent);
279 
280     if(getenv_int("JSON_COMPACT") > 0)
281         flags |= JSON_COMPACT;
282 
283     if(getenv_int("JSON_ENSURE_ASCII"))
284         flags |= JSON_ENSURE_ASCII;
285 
286     if(getenv_int("JSON_PRESERVE_ORDER"))
287         flags |= JSON_PRESERVE_ORDER;
288 
289     if(getenv_int("JSON_SORT_KEYS"))
290         flags |= JSON_SORT_KEYS;
291 
292     precision = getenv_int("JSON_REAL_PRECISION");
293     if(precision < 0 || precision > 31) {
294         fprintf(stderr, "invalid value for JSON_REAL_PRECISION: %d\n",
295                 precision);
296         return 2;
297     }
298 
299     if(getenv("HASHSEED"))
300         json_object_seed(getenv_int("HASHSEED"));
301 
302     if(precision > 0)
303         flags |= JSON_REAL_PRECISION(precision);
304 
305     if(getenv_int("STRIP")) {
306         /* Load to memory, strip leading and trailing whitespace */
307         size_t size = 0, used = 0;
308         char *buffer = NULL, *buf_ck = NULL;
309 
310         while(1) {
311             size_t count;
312 
313             size = (size == 0 ? 128 : size * 2);
314             buf_ck = realloc(buffer, size);
315             if(!buf_ck) {
316                 fprintf(stderr, "Unable to allocate %d bytes\n", (int)size);
317                 free(buffer);
318                 return 1;
319             }
320             buffer = buf_ck;
321 
322             count = fread(buffer + used, 1, size - used, stdin);
323             if(count < size - used) {
324                 buffer[used + count] = '\0';
325                 break;
326             }
327             used += count;
328         }
329 
330         json = json_loads(strip(buffer), 0, &error);
331         free(buffer);
332     }
333     else
334         json = json_loadf(stdin, 0, &error);
335 
336     if(!json) {
337         fprintf(stderr, "%d %d %d\n%s\n",
338             error.line, error.column,
339             error.position, error.text);
340         return 1;
341     }
342 
343     json_dumpf(json, stdout, flags);
344     json_decref(json);
345 
346     return 0;
347 }
348 
main(int argc,char * argv[])349 int main(int argc, char *argv[])
350 {
351     int i;
352     char *test_path = NULL;
353 
354     #ifdef HAVE_SETLOCALE
355     setlocale(LC_ALL, "");
356     #endif
357 
358     if (argc < 2) {
359         goto usage;
360     }
361 
362     for (i = 1; i < argc; i++) {
363         if (!strcmp(argv[i], "--strip"))
364             conf.strip = 1;
365         else if (!strcmp(argv[i], "--env"))
366             conf.use_env = 1;
367         else
368             test_path = argv[i];
369     }
370 
371     if (conf.use_env)
372         return use_env();
373     else
374     {
375         if (!test_path)
376             goto usage;
377 
378         return use_conf(test_path);
379     }
380 
381 usage:
382     fprintf(stderr, "argc =%d\n", argc);
383     fprintf(stderr, "usage: %s [--strip] [--env] test_dir\n", argv[0]);
384     return 2;
385 }
386