Make the lexer not depend on locale
[profile/ivi/jansson.git] / src / load.c
1 #define _GNU_SOURCE
2 #include <ctype.h>
3 #include <errno.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <stdarg.h>
8 #include <unistd.h>
9 #include <assert.h>
10
11 #include <jansson.h>
12 #include "strbuffer.h"
13
14
15 #define JSON_TOKEN_INVALID         -1
16 #define JSON_TOKEN_EOF              0
17 #define JSON_TOKEN_STRING         256
18 #define JSON_TOKEN_INTEGER        257
19 #define JSON_TOKEN_REAL           258
20 #define JSON_TOKEN_TRUE           259
21 #define JSON_TOKEN_FALSE          260
22 #define JSON_TOKEN_NULL           261
23
24 typedef struct {
25     const char *input;
26     const char *start;
27     int token;
28     int line, column;
29     union {
30         char *string;
31         int integer;
32         double real;
33     } value;
34 } json_lex;
35
36
37 /*** error reporting ***/
38
39 static void json_set_error(json_error_t *error, const json_lex *lex,
40                            const char *msg, ...)
41 {
42     va_list ap;
43     char text[JSON_ERROR_TEXT_LENGTH];
44
45     if(!error)
46         return;
47
48     va_start(ap, msg);
49     vsnprintf(text, JSON_ERROR_TEXT_LENGTH, msg, ap);
50     va_end(ap);
51
52     if(lex)
53     {
54         error->line = lex->line;
55         if(*lex->start)
56         {
57             int n = (int)(lex->input - lex->start);
58             snprintf(error->text, JSON_ERROR_TEXT_LENGTH,
59                      "%s near '%.*s'", text, n, lex->start);
60         }
61         else
62         {
63             snprintf(error->text, JSON_ERROR_TEXT_LENGTH,
64                      "%s near end of file", text);
65         }
66     }
67     else
68     {
69         error->line = -1;
70         snprintf(error->text, JSON_ERROR_TEXT_LENGTH, "%s", text);
71     }
72 }
73
74
75 /*** lexical analyzer ***/
76
77 static void json_scan_string(json_lex *lex)
78 {
79     /* skip the " */
80     const char *p = lex->input + 1;
81     char *t;
82
83     lex->token = JSON_TOKEN_INVALID;
84
85     while(*p != '"') {
86         if(*p == '\0') {
87             /* unterminated string literal */
88             goto out;
89         }
90
91         if(0 <= *p && *p <= 0x1F) {
92             /* control character */
93             goto out;
94         }
95         else if(*p == '\\') {
96             p++;
97             if(*p == 'u') {
98                 p++;
99                 for(int i = 0; i < 4; i++, p++) {
100                     if(!isxdigit(*p))
101                         goto out;
102                 }
103             }
104             else if(*p == '"' || *p == '\\' || *p == '/' || *p == 'b' ||
105                     *p == 'f' || *p == 'n' || *p == 'r' || *p == 't')
106                 p++;
107             else
108                 goto out;
109         }
110         else
111             p++;
112     }
113
114     /* the actual value is at most of the same length as the source
115        string */
116     lex->value.string = malloc(p - lex->start);
117     if(!lex->value.string) {
118         /* this is not very nice, since TOKEN_INVALID is returned */
119         goto out;
120     }
121
122     /* the target */
123     t = lex->value.string;
124
125     p = lex->input + 1;
126     while(*p != '"') {
127         if(*p == '\\') {
128             p++;
129             if(*p == 'u') {
130                 /* TODO: \uXXXX not supported yet */
131                 free(lex->value.string);
132                 lex->value.string = NULL;
133                 goto out;
134             } else {
135                 switch(*p) {
136                     case '"': case '\\': case '/':
137                         *t = *p; break;
138                     case 'b': *t = '\b'; break;
139                     case 'f': *t = '\f'; break;
140                     case 'n': *t = '\n'; break;
141                     case 'r': *t = '\r'; break;
142                     case 't': *t = '\t'; break;
143                     default: assert(0);
144                 }
145             }
146         }
147         else
148             *t = *p;
149
150         t++;
151         p++;
152     }
153     /* skip the " */
154     p++;
155
156     *t = '\0';
157     lex->token = JSON_TOKEN_STRING;
158
159 out:
160     lex->input = p;
161 }
162
163 static void json_scan_number(json_lex *lex)
164 {
165     const char *p = lex->input;
166     char *end;
167
168     lex->token = JSON_TOKEN_INVALID;
169
170     if(*p == '-')
171         p++;
172
173     if(*p == '0') {
174         p++;
175         if(isdigit(*p))
176           goto out;
177     }
178     else /* *p != '0' */ {
179         p++;
180         while(isdigit(*p))
181             p++;
182     }
183
184     if(*p != '.' && *p != 'E' && *p != 'e') {
185         lex->token = JSON_TOKEN_INTEGER;
186
187         lex->value.integer = strtol(lex->start, &end, 10);
188         assert(end == p);
189
190         goto out;
191     }
192
193     if(*p == '.') {
194         p++;
195         if(!isdigit(*p))
196             goto out;
197
198         p++;
199         while(isdigit(*p))
200             p++;
201     }
202
203     if(*p == 'E' || *p == 'e') {
204         p++;
205         if(*p == '+' || *p == '-')
206             p++;
207
208         if(!isdigit(*p))
209             goto out;
210
211         p++;
212         while(isdigit(*p))
213             p++;
214     }
215
216     lex->token = JSON_TOKEN_REAL;
217
218     lex->value.real = strtod(lex->start, &end);
219     assert(end == p);
220
221 out:
222     lex->input = p;
223 }
224
225 static int json_lex_scan(json_lex *lex)
226 {
227     char c;
228
229     if(lex->token == JSON_TOKEN_STRING) {
230       free(lex->value.string);
231       lex->value.string = NULL;
232     }
233
234     c = *lex->input;
235     while(c == ' ' || c == '\t' || c == '\n' || c == '\r')
236     {
237         if(c == '\n')
238             lex->line++;
239
240         lex->input++;
241         c = *lex->input;
242     }
243
244     lex->start = lex->input;
245     c = *lex->input;
246
247     if(c == '\0')
248         lex->token = JSON_TOKEN_EOF;
249
250     else if(c == '{' || c == '}' || c == '[' || c == ']' ||
251             c == ':' || c == ',')
252     {
253         lex->token = c;
254         lex->input++;
255     }
256
257     else if(c == '"')
258         json_scan_string(lex);
259
260     else if(isdigit(c) || c == '-')
261         json_scan_number(lex);
262
263     else if(isupper(c) || islower(c)) {
264         /* eat up the whole identifier for clearer error messages */
265         int len;
266
267         while(isupper(*lex->input) || islower(*lex->input))
268             lex->input++;
269         len = lex->input - lex->start;
270
271         if(strncmp(lex->start, "true", len) == 0)
272             lex->token = JSON_TOKEN_TRUE;
273         else if(strncmp(lex->start, "false", len) == 0)
274             lex->token = JSON_TOKEN_FALSE;
275         else if(strncmp(lex->start, "null", len) == 0)
276             lex->token = JSON_TOKEN_NULL;
277         else
278             lex->token = JSON_TOKEN_INVALID;
279     }
280
281     else {
282         lex->token = JSON_TOKEN_INVALID;
283         lex->input++;
284     }
285
286     return lex->token;
287 }
288
289 static int json_lex_init(json_lex *lex, const char *input)
290 {
291     lex->input = input;
292     lex->token = JSON_TOKEN_INVALID;
293     lex->line = 1;
294
295     json_lex_scan(lex);
296     return 0;
297 }
298
299 static void json_lex_close(json_lex *lex)
300 {
301     if(lex->token == JSON_TOKEN_STRING)
302         free(lex->value.string);
303 }
304
305
306 /*** parser ***/
307
308 static json_t *json_parse(json_lex *lex, json_error_t *error);
309
310 static json_t *json_parse_object(json_lex *lex, json_error_t *error)
311 {
312     json_t *object = json_object();
313     if(!object)
314         return NULL;
315
316     json_lex_scan(lex);
317     if(lex->token == '}')
318         return object;
319
320     while(lex->token) {
321         char *key;
322         json_t *value;
323
324         if(lex->token != JSON_TOKEN_STRING) {
325             json_set_error(error, lex, "string expected");
326             goto error;
327         }
328
329         key = strdup(lex->value.string);
330         if(!key)
331             return NULL;
332
333         json_lex_scan(lex);
334         if(lex->token != ':') {
335             free(key);
336             json_set_error(error, lex, "':' expected");
337             goto error;
338         }
339
340         json_lex_scan(lex);
341
342         value = json_parse(lex, error);
343         if(!value) {
344             free(key);
345             goto error;
346         }
347
348         if(json_object_set(object, key, value)) {
349             free(key);
350             json_decref(value);
351             goto error;
352         }
353
354         json_decref(value);
355         free(key);
356
357         if(lex->token != ',')
358             break;
359
360         json_lex_scan(lex);
361     }
362
363     if(lex->token != '}') {
364         json_set_error(error, lex, "'}' expected");
365         goto error;
366     }
367
368     return object;
369
370 error:
371     json_decref(object);
372     return NULL;
373 }
374
375 static json_t *json_parse_array(json_lex *lex, json_error_t *error)
376 {
377     json_t *array = json_array();
378     if(!array)
379         return NULL;
380
381     json_lex_scan(lex);
382     if(lex->token == ']')
383         return array;
384
385     while(lex->token) {
386         json_t *elem = json_parse(lex, error);
387         if(!elem)
388             goto error;
389
390         if(json_array_append(array, elem)) {
391             json_decref(elem);
392             goto error;
393         }
394         json_decref(elem);
395
396         if(lex->token != ',')
397             break;
398
399         json_lex_scan(lex);
400     }
401
402
403     if(lex->token != ']') {
404         json_set_error(error, lex, "']' expected");
405         goto error;
406     }
407
408     return array;
409
410 error:
411     json_decref(array);
412     return NULL;
413 }
414
415 static json_t *json_parse(json_lex *lex, json_error_t *error)
416 {
417     json_t *json;
418
419     switch(lex->token) {
420         case JSON_TOKEN_STRING: {
421             json = json_string(lex->value.string);
422             break;
423         }
424
425         case JSON_TOKEN_INTEGER: {
426             json = json_integer(lex->value.integer);
427             break;
428         }
429
430         case JSON_TOKEN_REAL: {
431             json = json_real(lex->value.real);
432             break;
433         }
434
435         case JSON_TOKEN_TRUE:
436             json = json_true();
437             break;
438
439         case JSON_TOKEN_FALSE:
440             json = json_false();
441             break;
442
443         case JSON_TOKEN_NULL:
444             json = json_null();
445             break;
446
447         case '{':
448           json = json_parse_object(lex, error);
449             break;
450
451         case '[':
452             json = json_parse_array(lex, error);
453             break;
454
455         case JSON_TOKEN_INVALID:
456             json_set_error(error, lex, "invalid token");
457             return NULL;
458
459         default:
460             json_set_error(error, lex, "unexpected token");
461             return NULL;
462     }
463
464     if(!json)
465         return NULL;
466
467     json_lex_scan(lex);
468     return json;
469 }
470
471 json_t *json_load(const char *path, json_error_t *error)
472 {
473     json_t *result;
474     FILE *fp;
475
476     fp = fopen(path, "r");
477     if(!fp)
478     {
479         json_set_error(error, NULL, "unable to open %s: %s",
480                        path, strerror(errno));
481         return NULL;
482     }
483
484     result = json_loadf(fp, error);
485
486     fclose(fp);
487     return result;
488 }
489
490 json_t *json_loads(const char *string, json_error_t *error)
491 {
492     json_lex lex;
493     json_t *result = NULL;
494
495     if(json_lex_init(&lex, string))
496         return NULL;
497
498     if(lex.token != '[' && lex.token != '{') {
499         json_set_error(error, &lex, "'[' or '{' expected");
500         goto out;
501     }
502
503     result = json_parse(&lex, error);
504     if(!result)
505         goto out;
506
507     if(lex.token != JSON_TOKEN_EOF) {
508         json_set_error(error, &lex, "end of file expected");
509         json_decref(result);
510         result = NULL;
511     }
512
513 out:
514     json_lex_close(&lex);
515     return result;
516 }
517
518 #define BUFFER_SIZE 4096
519
520 json_t *json_loadf(FILE *input, json_error_t *error)
521 {
522     strbuffer_t strbuff;
523     char buffer[BUFFER_SIZE];
524     size_t length;
525     json_t *result = NULL;
526
527     if(strbuffer_init(&strbuff))
528       return NULL;
529
530     while(1)
531     {
532         length = fread(buffer, 1, BUFFER_SIZE, input);
533         if(length == 0)
534         {
535             if(ferror(input))
536             {
537                 json_set_error(error, NULL, "read error");
538                 goto out;
539             }
540             break;
541         }
542         if(strbuffer_append_bytes(&strbuff, buffer, length))
543             goto out;
544     }
545
546     result = json_loads(strbuffer_value(&strbuff), error);
547
548 out:
549     strbuffer_close(&strbuff);
550     return result;
551 }
552
553 json_t *json_loadfd(int fd, json_error_t *error)
554 {
555     strbuffer_t strbuff;
556     char buffer[BUFFER_SIZE];
557     ssize_t length;
558     json_t *result = NULL;
559
560     if(strbuffer_init(&strbuff))
561       return NULL;
562
563     while(1)
564     {
565         length = read(fd, buffer, BUFFER_SIZE);
566         if(length == -1)
567         {
568             json_set_error(error, NULL, "read error: %s", strerror(errno));
569             goto out;
570         }
571         else if(length == 0)
572             break;
573
574         if(strbuffer_append_bytes(&strbuff, buffer, length))
575         {
576             json_set_error(error, NULL, "error allocating memory");
577             goto out;
578         }
579     }
580
581     result = json_loads(strbuffer_value(&strbuff), error);
582
583 out:
584     strbuffer_close(&strbuff);
585     return result;
586 }