plan9port

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

json.c (2935B)


      1 #include <u.h>
      2 #include <libc.h>
      3 
      4 #include <bio.h>
      5 #include <str.h>
      6 #include <vec.h>
      7 #include <json.h>
      8 
      9 static JsonType
     10 err(Json *j, char *msg)
     11 {
     12 	ulong i, n;
     13 
     14 	if (!j->cur->k.s)
     15 		Strinit(&j->cur->k);
     16 	if (j->cur->t == JStr)
     17 		Strclose(&j->cur->v.s);
     18 	Strdup(&j->cur->k, Str(msg));
     19 	n = 1;
     20 	for (i = 0; i < j->pos; ++i)
     21 		if (j->s.s[i] == '\n')
     22 			++n;
     23 	j->cur->v.n = n;
     24 	j->cur->t = JErr;
     25 	return JNone;
     26 }
     27 
     28 static void
     29 JObjclose(JsonObj *o)
     30 {
     31 	if (o->k.s)
     32 		Strclose(&o->k);
     33 	if (o->t == JStr)
     34 		Strclose(&o->v.s);
     35 }
     36 
     37 void
     38 json_close(Json *j)
     39 {
     40 	Strclose(&j->s);
     41 	Vecclose(&j->o);
     42 }
     43 
     44 int
     45 json_init(Json *j, char *file)
     46 {
     47 	int fd;
     48 
     49 	fd = 0;
     50 	memset(j, 0, sizeof(*j));
     51 	Strinit(&j->s);
     52 	if (file) {
     53 		fd = open(file, OREAD);
     54 		if (fd == -1)
     55 			return 0;
     56 	}
     57 	Strgetf(&j->s, fd);
     58 	Vecinitf(&j->o, nil, JObjclose);
     59 	close(fd);
     60 	return 1;
     61 }
     62 
     63 int
     64 json_next(Json *j, JsonType t)
     65 {
     66 	JsonObj *o;
     67 	ulong i;
     68 	char c, *p, *q;
     69 
     70 	if (j->cur && j->cur->t == JErr)
     71 		return JNone;
     72 next:
     73 	if (j->pos == j->s.n)
     74 		return JNone;
     75 	j->cur = Vecadd(&j->o);
     76 loop:
     77 	for (;j->pos < j->s.n && isspace(j->s.s[j->pos]); ++j->pos);
     78 	c = j->s.s[j->pos++];
     79 	switch (c) {
     80 	case '{':
     81 	case '[':
     82 		if (j->cur->t != JNone)
     83 			return err(j, "double value");
     84 		if (j->n + 1 >= nelem(j->st))
     85 			return err(j, "Stack too big!"
     86 				" Fix your damn data");
     87 		j->st[j->n++] = j->cur - j->o;
     88 		j->cur->v.c = c;
     89 		j->cur->t = JObj;
     90 		break;
     91 	case ']':
     92 		c = '[';
     93 		if (0)
     94 	case '}':
     95 		c = '{';
     96 		if (!j->n)
     97 			return err(j, "bad stack");
     98 		o = j->o + j->st[j->n - 1];
     99 		if (o->v.c != c)
    100 			return err(j, "mismatch");
    101 		if (j->cur->t != JNone) {
    102 			--j->pos;
    103 			break;
    104 		}
    105 		--j->n;
    106 	case ',':
    107 		if (j->cur->k.s && j->cur->t == JNone)
    108 			return err(j, "missing value");
    109 		if (j->cur->t == JNone)
    110 			goto loop;
    111 		break;
    112 	case '"':
    113 		if (j->cur->t != JNone)
    114 			return err(j, "double value");
    115 		for (i = j->pos; i < j->s.n; ++i) {
    116 			c = j->s.s[i];
    117 			if (c == '\n')
    118 				return err(j, "invalid value");
    119 			if (c == '"')
    120 				break;
    121 			if (c != '\\')
    122 				continue;
    123 			/* there is no escape in Ba Sing Se */
    124 			c = j->s.s[i + 1];
    125 			if (c == '\\' || c == '"')
    126 				++i;
    127 		}
    128 		Strinit(&j->cur->v.s);
    129 		Stradds(&j->cur->v.s
    130 			, Strn(j->s.s + j->pos, i - j->pos));
    131 		j->pos = i + 1;
    132 		j->cur->t = JStr;
    133 		goto loop;
    134 	case ':':
    135 		if (j->cur->k.s)
    136 			return err(j, "double colon");
    137 		if (j->cur->t != JStr)
    138 			return err(j, "invalid key");
    139 		j->cur->k = j->cur->v.s;
    140 		memset(&j->cur->v, 0, sizeof(j->cur->v));
    141 		j->cur->t = JNone;
    142 		goto loop;
    143 	default:
    144 		if (--j->pos == j->s.n)
    145 			break;
    146 		if (j->cur->t != JNone)
    147 			return err(j, "double value");
    148 		p = j->s.s + j->pos;
    149 		j->cur->v.n = strtod(p, &q);
    150 		if (p != q) {
    151 			j->pos += q - p;
    152 			j->cur->t = JNum;
    153 			goto loop;
    154 		}
    155 		i = strcspn(p, "{[:,]} \n\r\t");
    156 		Strinit(&j->cur->v.s);
    157 		Stradds(&j->cur->v.s, Strn(p, i));
    158 		j->pos += i;
    159 		j->cur->t = JStr;
    160 		goto loop;
    161 	}
    162 	if (!t || (t & j->cur->t))
    163 		return j->cur->t;
    164 	goto next;
    165 }