]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/libjson/json.c
etheriwl: don't break controller on command flush timeout
[plan9front.git] / sys / src / libjson / json.c
index 0e1de4ca4bc2d43149a0676131c28518d39ead5c..74fd5eeb0cd9e9f264b22d58064fbe84d4c8ce9f 100644 (file)
@@ -7,7 +7,7 @@ typedef struct Lex Lex;
 
 enum {
        TEOF,
-       TSTRING = (1<<(8*sizeof(Rune)))+1,
+       TSTRING = Runemax+1,
        TNUM,
        TNULL,
        TFALSE,
@@ -17,12 +17,11 @@ enum {
 struct Lex
 {
        char *s;
+       ulong slen;
        int t;
        double n;
-       char buf[4096];
+       char *buf;
        Rune peeked;
-       jmp_buf jmp;
-       int canjmp;
 };
 
 static Rune
@@ -35,6 +34,8 @@ getch(Lex *l)
                l->peeked = 0;
                return r;
        }
+       if(l->s[0] == '\0')
+               return 0;
        l->s += chartorune(&r, l->s);
        return r;
 }
@@ -47,13 +48,10 @@ peekch(Lex *l)
        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);
@@ -61,10 +59,42 @@ lex(Lex *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;
@@ -73,7 +103,7 @@ lex(Lex *l)
                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;
                        }
@@ -101,6 +131,7 @@ lex(Lex *l)
                return 0;
        }
        if(r == '"'){
+               r2 = 0;
                t = l->buf;
                for(;;){
                        r = getch(l);
@@ -127,9 +158,16 @@ lex(Lex *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':
@@ -148,8 +186,9 @@ lex(Lex *l)
                                        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;
                        }
@@ -169,10 +208,10 @@ jsonobj(Lex *l)
        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);
@@ -195,8 +234,7 @@ error:
                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:
@@ -207,7 +245,6 @@ error:
        case '[':
                obj = l->t == '{';
                ln = &j->first;
-               e = nil;
                if(obj){
                        j->t = JSONObject;
                        if(lex(l) < 0)
@@ -217,9 +254,8 @@ error:
                        goto firstobj;
                }else{
                        j->t = JSONArray;
-                       l->canjmp = 1;
-                       if(setjmp(l->jmp) > 0){
-                               free(e);
+                       if(peeknonspace(l) == ']'){
+                               getch(l);
                                return j;
                        }
                }
@@ -232,8 +268,7 @@ error:
                                        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){
@@ -246,8 +281,7 @@ error:
                                        goto abort;
                                }
                        }else{
-                               e = mallocz(sizeof(*e), 1);
-                               if(e == nil)
+                               if((e = mallocz(sizeof(*e), 1)) == nil)
                                        goto abort;
                        }
                        e->val = jsonobj(l);
@@ -283,11 +317,18 @@ error:
 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
@@ -295,6 +336,8 @@ jsonfree(JSON *j)
 {
        JSONEl *e, *f;
 
+       if(j == nil)
+               return;
        switch(j->t){
        case JSONString:
                if(j->s)