enum {
TEOF,
- TSTRING = (1<<(8*sizeof(Rune)))+1,
+ TSTRING = Runemax+1,
TNUM,
TNULL,
TFALSE,
struct Lex
{
char *s;
+ ulong slen;
int t;
double n;
- char buf[4096];
+ char *buf;
Rune peeked;
- jmp_buf jmp;
- int canjmp;
};
static Rune
l->peeked = 0;
return r;
}
+ if(l->s[0] == '\0')
+ return 0;
l->s += chartorune(&r, l->s);
return r;
}
return l->peeked;
}
-static int
-lex(Lex *l)
+static Rune
+peeknonspace(Lex *l)
{
Rune r;
- char *t;
- int i;
- char c;
for(;;){
r = peekch(l);
break;
getch(l);
}
+ return r;
+}
+
+static int
+fixsurrogate(Rune *rp, Rune r2)
+{
+ Rune r1;
+
+ r1 = *rp;
+ if(r1 >= 0xD800 && r1 <= 0xDBFF){
+ if(r2 >= 0xDC00 && r2 <= 0xDFFF){
+ *rp = 0x10000 + (((r1 - 0xD800)<<10) | (r2 - 0xDC00));
+ return 0;
+ }
+ return 1;
+ } else
+ if(r1 >= 0xDC00 && r1 <= 0xDFFF){
+ if(r2 >= 0xD800 && r2 <= 0xDBFF){
+ *rp = 0x10000 + (((r2 - 0xD800)<<10) | (r1 - 0xDC00));
+ return 0;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+static int
+lex(Lex *l)
+{
+ Rune r, r2;
+ char *t;
+ int i;
+ char c;
+
+ peeknonspace(l);
r = getch(l);
- if(r == ']' && l->canjmp)
- longjmp(l->jmp, 1);
- l->canjmp = 0;
if(r == 0 || r == '{' || r == '[' || r == ']' || r == '}' || r == ':' || r == ','){
l->t = r;
return 0;
t = l->buf;
for(;;){
t += runetochar(t, &r);
- if(t >= l->buf + sizeof(l->buf)){
+ if(t >= l->buf + l->slen){
werrstr("json: literal too long");
return -1;
}
return 0;
}
if(r == '"'){
+ r2 = 0;
t = l->buf;
for(;;){
r = getch(l);
c = getch(l);
r *= 16;
- if(c > '0' && c < '9') r += c - '0';
- else if(c > 'a' && c < 'f') r += c - 'a' + 10;
- else if(c > 'A' && c < 'F') r += c - 'A' + 10;
+ if(c >= '0' && c <= '9')
+ r += c - '0';
+ else if(c >= 'a' && c <= 'f')
+ r += c - 'a' + 10;
+ else if(c >= 'A' && c <= 'F')
+ r += c - 'A' + 10;
+ }
+ if(fixsurrogate(&r, r2)){
+ r2 = r;
+ continue;
}
break;
case 't':
return -1;
}
}
+ r2 = 0;
t += runetochar(t, &r);
- if(t >= l->buf + sizeof(l->buf)){
+ if(t >= l->buf + l->slen){
werrstr("json: string too long");
return -1;
}
JSONEl *e;
JSONEl **ln;
int obj;
-
- j = mallocz(sizeof(*j), 1);
- if(j == nil)
+
+ if((j = mallocz(sizeof(*j), 1)) == nil)
return nil;
+
if(lex(l) < 0){
error:
free(j);
break;
case TSTRING:
j->t = JSONString;
- j->s = strdup(l->buf);
- if(j->s == nil)
+ if((j->s = strdup(l->buf)) == nil)
goto error;
break;
case TNUM:
case '[':
obj = l->t == '{';
ln = &j->first;
- e = nil;
if(obj){
j->t = JSONObject;
if(lex(l) < 0)
goto firstobj;
}else{
j->t = JSONArray;
- l->canjmp = 1;
- if(setjmp(l->jmp) > 0){
- free(e);
+ if(peeknonspace(l) == ']'){
+ getch(l);
return j;
}
}
werrstr("json: syntax error, not string");
goto abort;
}
- e = mallocz(sizeof(*e), 1);
- if(e == nil)
+ if((e = mallocz(sizeof(*e), 1)) == nil)
goto abort;
e->name = strdup(l->buf);
if(e->name == nil || lex(l) < 0){
goto abort;
}
}else{
- e = mallocz(sizeof(*e), 1);
- if(e == nil)
+ if((e = mallocz(sizeof(*e), 1)) == nil)
goto abort;
}
e->val = jsonobj(l);
JSON*
jsonparse(char *s)
{
+ JSON *j;
Lex l;
memset(&l, 0, sizeof(l));
l.s = s;
- return jsonobj(&l);
+ l.slen = strlen(s);
+ if((l.buf = mallocz(l.slen+UTFmax+1, 1)) == nil)
+ return nil;
+
+ j = jsonobj(&l);
+ free(l.buf);
+ return j;
}
void
{
JSONEl *e, *f;
+ if(j == nil)
+ return;
switch(j->t){
case JSONString:
if(j->s)