Blob


1 #include "a.h"
3 static Json *parsevalue(char**);
5 static char*
6 wskip(char *p)
7 {
8 while(*p == ' ' || *p == '\t' || *p == '\n' || *p == '\v')
9 p++;
10 return p;
11 }
13 static int
14 ishex(int c)
15 {
16 return '0' <= c && c <= '9' ||
17 'a' <= c && c <= 'f' ||
18 'A' <= c && c <= 'F';
19 }
21 static Json*
22 newjval(int type)
23 {
24 Json *v;
26 v = emalloc(sizeof *v);
27 v->ref = 1;
28 v->type = type;
29 return v;
30 }
32 static Json*
33 badjval(char **pp, char *fmt, ...)
34 {
35 char buf[ERRMAX];
36 va_list arg;
38 if(fmt){
39 va_start(arg, fmt);
40 vsnprint(buf, sizeof buf, fmt, arg);
41 va_end(arg);
42 errstr(buf, sizeof buf);
43 }
44 *pp = nil;
45 return nil;
46 }
48 static char*
49 _parsestring(char **pp, int *len)
50 {
51 char *p, *q, *w, *s, *r;
52 char buf[5];
53 Rune rune;
55 p = wskip(*pp);
56 if(*p != '"'){
57 badjval(pp, "missing opening quote for string");
58 return nil;
59 }
60 for(q=p+1; *q && *q != '\"'; q++){
61 if(*q == '\\' && *(q+1) != 0)
62 q++;
63 if((*q & 0xFF) < 0x20){ // no control chars
64 badjval(pp, "control char in string");
65 return nil;
66 }
67 }
68 if(*q == 0){
69 badjval(pp, "no closing quote in string");
70 return nil;
71 }
72 s = emalloc(q - p);
73 w = s;
74 for(r=p+1; r<q; ){
75 if(*r != '\\'){
76 *w++ = *r++;
77 continue;
78 }
79 r++;
80 switch(*r){
81 default:
82 free(s);
83 badjval(pp, "bad escape \\%c in string", *r&0xFF);
84 return nil;
85 case '\\':
86 case '\"':
87 case '/':
88 *w++ = *r++;
89 break;
90 case 'b':
91 *w++ = '\b';
92 r++;
93 break;
94 case 'f':
95 *w++ = '\f';
96 r++;
97 break;
98 case 'n':
99 *w++ = '\n';
100 r++;
101 break;
102 case 'r':
103 *w++ = '\r';
104 r++;
105 break;
106 case 't':
107 *w++ = '\t';
108 r++;
109 break;
110 case 'u':
111 r++;
112 if(!ishex(r[0]) || !ishex(r[1]) || !ishex(r[2]) || !ishex(r[3])){
113 free(s);
114 badjval(pp, "bad hex \\u%.4s", r);
115 return nil;
117 memmove(buf, r, 4);
118 buf[4] = 0;
119 rune = strtol(buf, 0, 16);
120 if(rune == 0){
121 free(s);
122 badjval(pp, "\\u0000 in string");
123 return nil;
125 r += 4;
126 w += runetochar(w, &rune);
127 break;
130 *w = 0;
131 if(len)
132 *len = w - s;
133 *pp = q+1;
134 return s;
137 static Json*
138 parsenumber(char **pp)
140 char *p, *q;
141 char *t;
142 double d;
143 Json *v;
145 /* -?(0|[1-9][0-9]*)(\.(0|[1-9][0-9]*))?([Ee][-+]?[0-9]+) */
146 p = wskip(*pp);
147 q = p;
148 if(*q == '-')
149 q++;
150 if(*q == '0')
151 q++;
152 else{
153 if(*q < '1' || *q > '9')
154 return badjval(pp, "invalid number");
155 while('0' <= *q && *q <= '9')
156 q++;
158 if(*q == '.'){
159 q++;
160 if(*q < '0' || *q > '9')
161 return badjval(pp, "invalid number");
162 while('0' <= *q && *q <= '9')
163 q++;
165 if(*q == 'e' || *q == 'E'){
166 q++;
167 if(*q == '-' || *q == '+')
168 q++;
169 if(*q < '0' || *q > '9')
170 return badjval(pp, "invalid number");
171 while('0' <= *q && *q <= '9')
172 q++;
175 t = emalloc(q-p+1);
176 memmove(t, p, q-p);
177 t[q-p] = 0;
178 errno = 0;
179 d = strtod(t, nil);
180 if(errno != 0){
181 free(t);
182 return badjval(pp, nil);
184 free(t);
185 v = newjval(Jnumber);
186 v->number = d;
187 *pp = q;
188 return v;
191 static Json*
192 parsestring(char **pp)
194 char *s;
195 Json *v;
196 int len;
198 s = _parsestring(pp, &len);
199 if(s == nil)
200 return nil;
201 v = newjval(Jstring);
202 v->string = s;
203 v->len = len;
204 return v;
207 static Json*
208 parsename(char **pp)
210 if(strncmp(*pp, "true", 4) == 0){
211 *pp += 4;
212 return newjval(Jtrue);
214 if(strncmp(*pp, "false", 5) == 0){
215 *pp += 5;
216 return newjval(Jfalse);
218 if(strncmp(*pp, "null", 4) == 0){
219 *pp += 4;
220 return newjval(Jtrue);
222 return badjval(pp, "invalid name");
225 static Json*
226 parsearray(char **pp)
228 char *p;
229 Json *v;
231 p = *pp;
232 if(*p++ != '[')
233 return badjval(pp, "missing bracket for array");
234 v = newjval(Jarray);
235 p = wskip(p);
236 if(*p != ']'){
237 for(;;){
238 if(v->len%32 == 0)
239 v->value = erealloc(v->value, (v->len+32)*sizeof v->value[0]);
240 if((v->value[v->len++] = parsevalue(&p)) == nil){
241 jclose(v);
242 return badjval(pp, nil);
244 p = wskip(p);
245 if(*p == ']')
246 break;
247 if(*p++ != ','){
248 jclose(v);
249 return badjval(pp, "missing comma in array");
253 p++;
254 *pp = p;
255 return v;
258 static Json*
259 parseobject(char **pp)
261 char *p;
262 Json *v;
264 p = *pp;
265 if(*p++ != '{')
266 return badjval(pp, "missing brace for object");
267 v = newjval(Jobject);
268 p = wskip(p);
269 if(*p != '}'){
270 for(;;){
271 if(v->len%32 == 0){
272 v->name = erealloc(v->name, (v->len+32)*sizeof v->name[0]);
273 v->value = erealloc(v->value, (v->len+32)*sizeof v->value[0]);
275 if((v->name[v->len++] = _parsestring(&p, nil)) == nil){
276 jclose(v);
277 return badjval(pp, nil);
279 p = wskip(p);
280 if(*p++ != ':'){
281 jclose(v);
282 return badjval(pp, "missing colon in object");
284 if((v->value[v->len-1] = parsevalue(&p)) == nil){
285 jclose(v);
286 return badjval(pp, nil);
288 p = wskip(p);
289 if(*p == '}')
290 break;
291 if(*p++ != ','){
292 jclose(v);
293 return badjval(pp, "missing comma in object");
297 p++;
298 *pp = p;
299 return v;
302 static Json*
303 parsevalue(char **pp)
305 *pp = wskip(*pp);
306 switch(**pp){
307 case '0':
308 case '1':
309 case '2':
310 case '3':
311 case '4':
312 case '5':
313 case '6':
314 case '7':
315 case '8':
316 case '9':
317 case '-':
318 return parsenumber(pp);
319 case 't':
320 case 'f':
321 case 'n':
322 return parsename(pp);
323 case '\"':
324 return parsestring(pp);
325 case '[':
326 return parsearray(pp);
327 case '{':
328 return parseobject(pp);
329 default:
330 return badjval(pp, "unexpected char <%02x>", **pp & 0xFF);
334 Json*
335 parsejson(char *text)
337 Json *v;
339 v = parsevalue(&text);
340 if(v && text && *wskip(text) != 0){
341 jclose(v);
342 werrstr("extra data in json");
343 return nil;
345 return v;
348 void
349 _printjval(Fmt *fmt, Json *v, int n)
351 int i;
353 if(v == nil){
354 fmtprint(fmt, "nil");
355 return;
357 switch(v->type){
358 case Jstring:
359 fmtprint(fmt, "\"%s\"", v->string);
360 break;
361 case Jnumber:
362 if(floor(v->number) == v->number)
363 fmtprint(fmt, "%.0f", v->number);
364 else
365 fmtprint(fmt, "%g", v->number);
366 break;
367 case Jobject:
368 fmtprint(fmt, "{");
369 if(n >= 0)
370 n++;
371 for(i=0; i<v->len; i++){
372 if(n > 0)
373 fmtprint(fmt, "\n%*s", n*4, "");
374 fmtprint(fmt, "\"%s\" : ", v->name[i]);
375 _printjval(fmt, v->value[i], n);
376 fmtprint(fmt, ",");
378 if(n > 0){
379 n--;
380 if(v->len > 0)
381 fmtprint(fmt, "\n%*s", n*4);
383 fmtprint(fmt, "}");
384 break;
385 case Jarray:
386 fmtprint(fmt, "[");
387 if(n >= 0)
388 n++;
389 for(i=0; i<v->len; i++){
390 if(n > 0)
391 fmtprint(fmt, "\n%*s", n*4, "");
392 _printjval(fmt, v->value[i], n);
393 fmtprint(fmt, ",");
395 if(n > 0){
396 n--;
397 if(v->len > 0)
398 fmtprint(fmt, "\n%*s", n*4);
400 fmtprint(fmt, "]");
401 break;
402 case Jtrue:
403 fmtprint(fmt, "true");
404 break;
405 case Jfalse:
406 fmtprint(fmt, "false");
407 break;
408 case Jnull:
409 fmtprint(fmt, "null");
410 break;
414 /*
415 void
416 printjval(Json *v)
418 Fmt fmt;
419 char buf[256];
421 fmtfdinit(&fmt, 1, buf, sizeof buf);
422 _printjval(&fmt, v, 0);
423 fmtprint(&fmt, "\n");
424 fmtfdflush(&fmt);
426 */
428 int
429 jsonfmt(Fmt *fmt)
431 Json *v;
433 v = va_arg(fmt->args, Json*);
434 if(fmt->flags&FmtSharp)
435 _printjval(fmt, v, 0);
436 else
437 _printjval(fmt, v, -1);
438 return 0;
441 Json*
442 jincref(Json *v)
444 if(v == nil)
445 return nil;
446 ++v->ref;
447 return v;
450 void
451 jclose(Json *v)
453 int i;
455 if(v == nil)
456 return;
457 if(--v->ref > 0)
458 return;
459 if(v->ref < 0)
460 sysfatal("jclose: ref %d", v->ref);
462 switch(v->type){
463 case Jstring:
464 free(v->string);
465 break;
466 case Jarray:
467 for(i=0; i<v->len; i++)
468 jclose(v->value[i]);
469 free(v->value);
470 break;
471 case Jobject:
472 for(i=0; i<v->len; i++){
473 free(v->name[i]);
474 jclose(v->value[i]);
476 free(v->value);
477 free(v->name);
478 break;
480 free(v);
483 Json*
484 jlookup(Json *v, char *name)
486 int i;
488 if(v->type != Jobject)
489 return nil;
490 for(i=0; i<v->len; i++)
491 if(strcmp(v->name[i], name) == 0)
492 return v->value[i];
493 return nil;
496 Json*
497 jwalk(Json *v, char *path)
499 char elem[128], *p, *next;
500 int n;
502 for(p=path; *p && v; p=next){
503 next = strchr(p, '/');
504 if(next == nil)
505 next = p+strlen(p);
506 if(next-p >= sizeof elem)
507 sysfatal("jwalk path elem too long - %s", path);
508 memmove(elem, p, next-p);
509 elem[next-p] = 0;
510 if(*next == '/')
511 next++;
512 if(v->type == Jarray && *elem && (n=strtol(elem, &p, 10)) >= 0 && *p == 0){
513 if(n >= v->len)
514 return nil;
515 v = v->value[n];
516 }else
517 v = jlookup(v, elem);
519 return v;
522 char*
523 jstring(Json *jv)
525 if(jv == nil || jv->type != Jstring)
526 return nil;
527 return jv->string;
530 vlong
531 jint(Json *jv)
533 if(jv == nil || jv->type != Jnumber)
534 return -1;
535 return jv->number;
538 double
539 jnumber(Json *jv)
541 if(jv == nil || jv->type != Jnumber)
542 return 0;
543 return jv->number;
546 int
547 jstrcmp(Json *jv, char *s)
549 char *t;
551 t = jstring(jv);
552 if(t == nil)
553 return -2;
554 return strcmp(t, s);