plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

json.c (8526B)


      1 #include "a.h"
      2 
      3 static Json *parsevalue(char**);
      4 
      5 static char*
      6 wskip(char *p)
      7 {
      8 	while(*p == ' ' || *p == '\t' || *p == '\n' || *p == '\v')
      9 		p++;
     10 	return p;
     11 }
     12 
     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 }
     20 
     21 static Json*
     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*
     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*
     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*
    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*
    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*
    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*
    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*
    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*
    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*
    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
    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
    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*
    442 jincref(Json *v)
    443 {
    444 	if(v == nil)
    445 		return nil;
    446 	++v->ref;
    447 	return v;
    448 }
    449 
    450 void
    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*
    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*
    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*
    523 jstring(Json *jv)
    524 {
    525 	if(jv == nil || jv->type != Jstring)
    526 		return nil;
    527 	return jv->string;
    528 }
    529 
    530 vlong
    531 jint(Json *jv)
    532 {
    533 	if(jv == nil || jv->type != Jnumber)
    534 		return -1;
    535 	return jv->number;
    536 }
    537 
    538 double
    539 jnumber(Json *jv)
    540 {
    541 	if(jv == nil || jv->type != Jnumber)
    542 		return 0;
    543 	return jv->number;
    544 }
    545 
    546 int
    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 }