1 #include "a.h"
2 
3 static Json *parsevalue(char**);
4 
5 static char*
wskip(char * p)6 wskip(char *p)
7 {
8 	while(*p == ' ' || *p == '\t' || *p == '\n' || *p == '\v')
9 		p++;
10 	return p;
11 }
12 
13 static int
ishex(int c)14 ishex(int c)
15 {
16 	return '0' <= c && c <= '9' ||
17 		'a' <= c && c <= 'f' ||
18 		'A' <= c && c <= 'F';
19 }
20 
21 static Json*
newjval(int type)22 newjval(int type)
23 {
24 	Json *v;
25 
26 	v = emalloc(sizeof *v);
27 	v->ref = 1;
28 	v->type = type;
29 	return v;
30 }
31 
32 static Json*
badjval(char ** pp,char * fmt,...)33 badjval(char **pp, char *fmt, ...)
34 {
35 	char buf[ERRMAX];
36 	va_list arg;
37 
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 }
47 
48 static char*
_parsestring(char ** pp,int * len)49 _parsestring(char **pp, int *len)
50 {
51 	char *p, *q, *w, *s, *r;
52 	char buf[5];
53 	Rune rune;
54 
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;
116 			}
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;
124 			}
125 			r += 4;
126 			w += runetochar(w, &rune);
127 			break;
128 		}
129 	}
130 	*w = 0;
131 	if(len)
132 		*len = w - s;
133 	*pp = q+1;
134 	return s;
135 }
136 
137 static Json*
parsenumber(char ** pp)138 parsenumber(char **pp)
139 {
140 	char *p, *q;
141 	char *t;
142 	double d;
143 	Json *v;
144 
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++;
157 	}
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++;
164 	}
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++;
173 	}
174 
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);
183 	}
184 	free(t);
185 	v = newjval(Jnumber);
186 	v->number = d;
187 	*pp = q;
188 	return v;
189 }
190 
191 static Json*
parsestring(char ** pp)192 parsestring(char **pp)
193 {
194 	char *s;
195 	Json *v;
196 	int len;
197 
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;
205 }
206 
207 static Json*
parsename(char ** pp)208 parsename(char **pp)
209 {
210 	if(strncmp(*pp, "true", 4) == 0){
211 		*pp += 4;
212 		return newjval(Jtrue);
213 	}
214 	if(strncmp(*pp, "false", 5) == 0){
215 		*pp += 5;
216 		return newjval(Jfalse);
217 	}
218 	if(strncmp(*pp, "null", 4) == 0){
219 		*pp += 4;
220 		return newjval(Jtrue);
221 	}
222 	return badjval(pp, "invalid name");
223 }
224 
225 static Json*
parsearray(char ** pp)226 parsearray(char **pp)
227 {
228 	char *p;
229 	Json *v;
230 
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);
243 			}
244 			p = wskip(p);
245 			if(*p == ']')
246 				break;
247 			if(*p++ != ','){
248 				jclose(v);
249 				return badjval(pp, "missing comma in array");
250 			}
251 		}
252 	}
253 	p++;
254 	*pp = p;
255 	return v;
256 }
257 
258 static Json*
parseobject(char ** pp)259 parseobject(char **pp)
260 {
261 	char *p;
262 	Json *v;
263 
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]);
274 			}
275 			if((v->name[v->len++] = _parsestring(&p, nil)) == nil){
276 				jclose(v);
277 				return badjval(pp, nil);
278 			}
279 			p = wskip(p);
280 			if(*p++ != ':'){
281 				jclose(v);
282 				return badjval(pp, "missing colon in object");
283 			}
284 			if((v->value[v->len-1] = parsevalue(&p)) == nil){
285 				jclose(v);
286 				return badjval(pp, nil);
287 			}
288 			p = wskip(p);
289 			if(*p == '}')
290 				break;
291 			if(*p++ != ','){
292 				jclose(v);
293 				return badjval(pp, "missing comma in object");
294 			}
295 		}
296 	}
297 	p++;
298 	*pp = p;
299 	return v;
300 }
301 
302 static Json*
parsevalue(char ** pp)303 parsevalue(char **pp)
304 {
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);
331 	}
332 }
333 
334 Json*
parsejson(char * text)335 parsejson(char *text)
336 {
337 	Json *v;
338 
339 	v = parsevalue(&text);
340 	if(v && text && *wskip(text) != 0){
341 		jclose(v);
342 		werrstr("extra data in json");
343 		return nil;
344 	}
345 	return v;
346 }
347 
348 void
_printjval(Fmt * fmt,Json * v,int n)349 _printjval(Fmt *fmt, Json *v, int n)
350 {
351 	int i;
352 
353 	if(v == nil){
354 		fmtprint(fmt, "nil");
355 		return;
356 	}
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, ",");
377 		}
378 		if(n > 0){
379 			n--;
380 			if(v->len > 0)
381 				fmtprint(fmt, "\n%*s", n*4);
382 		}
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, ",");
394 		}
395 		if(n > 0){
396 			n--;
397 			if(v->len > 0)
398 				fmtprint(fmt, "\n%*s", n*4);
399 		}
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;
411 	}
412 }
413 
414 /*
415 void
416 printjval(Json *v)
417 {
418 	Fmt fmt;
419 	char buf[256];
420 
421 	fmtfdinit(&fmt, 1, buf, sizeof buf);
422 	_printjval(&fmt, v, 0);
423 	fmtprint(&fmt, "\n");
424 	fmtfdflush(&fmt);
425 }
426 */
427 
428 int
jsonfmt(Fmt * fmt)429 jsonfmt(Fmt *fmt)
430 {
431 	Json *v;
432 
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;
439 }
440 
441 Json*
jincref(Json * v)442 jincref(Json *v)
443 {
444 	if(v == nil)
445 		return nil;
446 	++v->ref;
447 	return v;
448 }
449 
450 void
jclose(Json * v)451 jclose(Json *v)
452 {
453 	int i;
454 
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);
461 
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]);
475 		}
476 		free(v->value);
477 		free(v->name);
478 		break;
479 	}
480 	free(v);
481 }
482 
483 Json*
jlookup(Json * v,char * name)484 jlookup(Json *v, char *name)
485 {
486 	int i;
487 
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;
494 }
495 
496 Json*
jwalk(Json * v,char * path)497 jwalk(Json *v, char *path)
498 {
499 	char elem[128], *p, *next;
500 	int n;
501 
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);
518 	}
519 	return v;
520 }
521 
522 char*
jstring(Json * jv)523 jstring(Json *jv)
524 {
525 	if(jv == nil || jv->type != Jstring)
526 		return nil;
527 	return jv->string;
528 }
529 
530 vlong
jint(Json * jv)531 jint(Json *jv)
532 {
533 	if(jv == nil || jv->type != Jnumber)
534 		return -1;
535 	return jv->number;
536 }
537 
538 double
jnumber(Json * jv)539 jnumber(Json *jv)
540 {
541 	if(jv == nil || jv->type != Jnumber)
542 		return 0;
543 	return jv->number;
544 }
545 
546 int
jstrcmp(Json * jv,char * s)547 jstrcmp(Json *jv, char *s)
548 {
549 	char *t;
550 
551 	t = jstring(jv);
552 	if(t == nil)
553 		return -2;
554 	return strcmp(t, s);
555 }
556