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 }