Bump hashtable, allocate object->hashtable statically
[jansson.git] / src / load.c
1 #define _GNU_SOURCE
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <ctype.h>
6 #include <assert.h>
7
8 #include <jansson.h>
9
10
11 #define JSON_TOKEN_INVALID         -1
12 #define JSON_TOKEN_EOF              0
13 #define JSON_TOKEN_STRING         256
14 #define JSON_TOKEN_NUMBER         257
15 #define JSON_TOKEN_TRUE           258
16 #define JSON_TOKEN_FALSE          259
17 #define JSON_TOKEN_NULL           260
18
19 typedef struct {
20     const char *input;
21     const char *start;
22     int token;
23     int line, column;
24     union {
25         char *string;
26         double number;
27     } value;
28 } json_lex;
29
30
31 /*** error reporting ***/
32
33 static __thread char *json_error_msg = NULL;
34
35 static void json_set_error(const json_lex *lex, const char *msg)
36 {
37     free(json_error_msg);
38     if(*lex->start)
39         asprintf(&json_error_msg, "%s near '%.*s' on line %d", msg,
40                  (int)(lex->input - lex->start), lex->start, lex->line);
41     else
42         asprintf(&json_error_msg, "%s near end of file", msg);
43 }
44
45 const char *json_get_error(void)
46 {
47     if(!json_error_msg)
48         json_error_msg = strdup("success");
49     return json_error_msg;
50 }
51
52
53 /*** lexical analyzer ***/
54
55 static void json_scan_string(json_lex *lex)
56 {
57     /* skip the " */
58     const char *p = lex->input + 1;
59     char *t;
60
61     lex->token = JSON_TOKEN_INVALID;
62
63     while(*p != '"') {
64         if(*p == '\0') {
65             /* unterminated string literal */
66             goto out;
67         }
68
69         if(0 <= *p && *p <= 31) {
70             /* control character */
71             goto out;
72         }
73         else if(*p == '\\') {
74             p++;
75             if(*p == 'u') {
76                 p++;
77                 for(int i = 0; i < 4; i++, p++) {
78                     if(!isxdigit(*p))
79                         goto out;
80                 }
81             }
82             if(*p == '"' || *p == '\\' || *p == '/' || *p == 'b' ||
83                *p == 'f' || *p == 'n' || *p == 'r' || *p == 't')
84                 p++;
85             else
86                 goto out;
87         }
88         else
89             p++;
90     }
91
92     /* the actual value is at most of the same length as the source
93        string */
94     lex->value.string = malloc(p - lex->start);
95     if(!lex->value.string) {
96         /* this is not very nice, since TOKEN_INVALID is returned */
97         goto out;
98     }
99
100     /* the target */
101     t = lex->value.string;
102
103     p = lex->input + 1;
104     while(*p != '"') {
105         if(*p == '\\') {
106             p++;
107             if(*p == 'u') {
108                 /* TODO: \uXXXX not supported yet */
109                 free(lex->value.string);
110                 lex->value.string = NULL;
111                 goto out;
112             } else {
113                 switch(*p) {
114                     case '"': case '\\': case '/':
115                         *t = *p; break;
116                     case 'b': *t = '\b'; break;
117                     case 'f': *t = '\f'; break;
118                     case 'n': *t = '\n'; break;
119                     case 'r': *t = '\r'; break;
120                     case 't': *t = '\t'; break;
121                     default: assert(0);
122                 }
123             }
124         }
125         else
126             *t = *p;
127
128         t++;
129         p++;
130     }
131     /* skip the " */
132     p++;
133
134     *t = '\0';
135     lex->token = JSON_TOKEN_STRING;
136
137 out:
138     lex->input = p;
139 }
140
141 static void json_scan_number(json_lex *lex)
142 {
143     const char *p = lex->input;
144     char *end;
145
146     lex->token = JSON_TOKEN_INVALID;
147
148     if(*p == '-')
149         p++;
150
151     if(*p == '0')
152         p++;
153     else /* *p != '0' */ {
154         p++;
155         while(isdigit(*p))
156             p++;
157     }
158
159     if(*p == '.') {
160         p++;
161         if(!isdigit(*(p++)))
162             goto out;
163
164         while(isdigit(*p))
165             p++;
166     }
167
168     if(*p == 'E' || *p == 'e') {
169         p++;
170         if(*p == '+' || *p == '-')
171             p++;
172
173         if(!isdigit(*(p++)))
174             goto out;
175
176         while(isdigit(*p))
177             p++;
178     }
179
180     lex->token = JSON_TOKEN_NUMBER;
181
182     lex->value.number = strtod(lex->start, &end);
183     assert(end == p);
184
185 out:
186     lex->input = p;
187 }
188
189 static int json_lex_scan(json_lex *lex)
190 {
191     char c;
192
193     if(lex->token == JSON_TOKEN_STRING) {
194       free(lex->value.string);
195       lex->value.string = NULL;
196     }
197
198     while(isspace(*lex->input)) {
199         if(*lex->input == '\n')
200             lex->line++;
201
202         lex->input++;
203     }
204
205     lex->start = lex->input;
206     c = *lex->input;
207
208     if(c == '\0')
209         lex->token = JSON_TOKEN_EOF;
210
211     else if(c == '{' || c == '}' || c == '[' || c == ']' ||
212             c == ':' || c == ',') {
213         lex->token = c;
214         lex->input++;
215     }
216
217     else if(c == '"')
218         json_scan_string(lex);
219
220     else if(isdigit(c) || c == '-')
221         json_scan_number(lex);
222
223     else if(isalpha(c)) {
224         /* eat up the whole identifier for clearer error messages */
225         int len;
226
227         while(isalpha(*lex->input))
228             lex->input++;
229         len = lex->input - lex->start;
230
231         if(strncmp(lex->start, "true", len) == 0)
232             lex->token = JSON_TOKEN_TRUE;
233         else if(strncmp(lex->start, "false", len) == 0)
234             lex->token = JSON_TOKEN_FALSE;
235         else if(strncmp(lex->start, "null", len) == 0)
236             lex->token = JSON_TOKEN_NULL;
237         else
238             lex->token = JSON_TOKEN_INVALID;
239     }
240
241     else {
242         lex->token = JSON_TOKEN_INVALID;
243         lex->input++;
244     }
245
246     return lex->token;
247 }
248
249 static int json_lex_init(json_lex *lex, const char *input)
250 {
251     lex->input = input;
252     lex->token = JSON_TOKEN_INVALID;
253     lex->line = 1;
254
255     json_lex_scan(lex);
256     return 0;
257 }
258
259 static void json_lex_close(json_lex *lex)
260 {
261     if(lex->token == JSON_TOKEN_STRING)
262         free(lex->value.string);
263 }
264
265
266 /*** parser ***/
267
268 static json_t *json_parse(json_lex *lex);
269
270 static json_t *json_parse_object(json_lex *lex)
271 {
272     json_t *object = json_object();
273     if(!object)
274         return NULL;
275
276     json_lex_scan(lex);
277     while(1) {
278         char *key;
279         json_t *value;
280
281         if(lex->token != JSON_TOKEN_STRING) {
282             json_set_error(lex, "string expected");
283             goto error;
284         }
285
286         key = strdup(lex->value.string);
287         if(!key)
288             return NULL;
289
290         json_lex_scan(lex);
291         if(lex->token != ':') {
292             json_set_error(lex, "':' expected");
293             goto error;
294         }
295
296         json_lex_scan(lex);
297
298         value = json_parse(lex);
299         if(!value)
300             goto error;
301
302         if(json_object_set(object, key, value)) {
303             json_decref(value);
304             goto error;
305         }
306
307         json_decref(value);
308         free(key);
309
310         if(lex->token != ',')
311             break;
312
313         json_lex_scan(lex);
314     }
315
316     if(lex->token != '}') {
317         json_set_error(lex, "'}' expected");
318         goto error;
319     }
320
321     return object;
322
323 error:
324     json_decref(object);
325     return NULL;
326 }
327
328 static json_t *json_parse_array(json_lex *lex)
329 {
330     json_t *array = json_array();
331     if(!array)
332         return NULL;
333
334     json_lex_scan(lex);
335     if(lex->token != ']') {
336         while(1) {
337             json_t *elem = json_parse(lex);
338             if(!elem)
339                 goto error;
340
341             if(json_array_append(array, elem)) {
342                 json_decref(elem);
343                 goto error;
344             }
345             json_decref(elem);
346
347             if(lex->token != ',')
348                 break;
349
350             json_lex_scan(lex);
351         }
352     }
353
354     if(lex->token != ']') {
355         json_set_error(lex, "']' expected");
356         goto error;
357     }
358
359     return array;
360
361 error:
362     json_decref(array);
363     return NULL;
364 }
365
366 static json_t *json_parse(json_lex *lex)
367 {
368     json_t *json;
369
370     switch(lex->token) {
371         case JSON_TOKEN_STRING: {
372             json = json_string(lex->value.string);
373             break;
374         }
375
376         case JSON_TOKEN_NUMBER: {
377             json = json_number(lex->value.number);
378             break;
379         }
380
381         case JSON_TOKEN_TRUE:
382             json = json_true();
383             break;
384
385         case JSON_TOKEN_FALSE:
386             json = json_false();
387             break;
388
389         case JSON_TOKEN_NULL:
390             json = json_null();
391             break;
392
393         case '{':
394             json = json_parse_object(lex);
395             break;
396
397         case '[':
398             json = json_parse_array(lex);
399             break;
400
401         case JSON_TOKEN_INVALID:
402             json_set_error(lex, "invalid token");
403             return NULL;
404
405         default:
406             json_set_error(lex, "unexpected token");
407             return NULL;
408     }
409
410     if(!json)
411         return NULL;
412
413     json_lex_scan(lex);
414     return json;
415 }
416
417 json_t *json_loads(const char *string)
418 {
419     json_lex lex;
420     json_t *result = NULL;
421
422     if(json_lex_init(&lex, string))
423         return NULL;
424
425     if(lex.token != '[' && lex.token != '{') {
426         json_set_error(&lex, "'[' or '{' expected");
427         goto out;
428     }
429
430     result = json_parse(&lex);
431     if(!result)
432         goto out;
433
434     if(lex.token != JSON_TOKEN_EOF) {
435         json_set_error(&lex, "end of file expected");
436         json_decref(result);
437         result = NULL;
438     }
439
440 out:
441     json_lex_close(&lex);
442     return result;
443 }