Fixed several memory leaks.
[yacjs.git] / src / yacjs.c
1 #include <stdbool.h>
2 #include <stdio.h> // for debugging
3 #include <stdlib.h>
4 #include <string.h>
5 #include <ctype.h>
6
7 #include "yacjs.h"
8 #include "yacjs_dict.h"
9 #include "yacjs_u8s.h"
10
11 #define zalloc(size) calloc(size, 1)
12
13 struct YACJS_NAME(node) {
14     enum YACJS_NAME(node_type) type;
15     union {
16         char *string;
17         int64_t number;
18         double fp;
19         struct {
20             struct YACJS_NAME(node) *entries;
21             int entries_count;
22             int entries_size;
23         } array;
24         struct YACJS_NAME(dict) *dict;
25         bool boolean;
26     } data;
27 };
28
29 enum token_type {
30     TOKEN_STRING,
31     TOKEN_NUMBER,
32     TOKEN_FLOAT,
33     TOKEN_FPNUMBER,
34     TOKEN_TRUE,
35     TOKEN_FALSE,
36     TOKEN_NULL,
37     TOKEN_OPENDICT,
38     TOKEN_CLOSEDICT,
39     TOKEN_OPENARRAY,
40     TOKEN_CLOSEARRAY,
41     TOKEN_COMMA,
42     TOKEN_COLON,
43     TOKEN_NONE,
44     TOKEN_ERROR,
45     TOKEN_TYPES
46 };
47
48 static enum YACJS_NAME(error) last_error = YACJS_NAME_CAP(ERROR_NONE);
49
50 static void destroy_helper(struct YACJS_NAME(node) *node);
51 static void skip_whitespace(const char ** const ptr);
52 static const char *next_token(const char ** const ptr, int *length,
53     enum token_type *type);
54 static const char *peek_token(const char ** const ptr, int *length,
55     enum token_type *type);
56 static struct YACJS_NAME(node) *parse_any(const char **string);
57 static struct YACJS_NAME(node) *parse_dict_contents(const char **string);
58 static struct YACJS_NAME(node) *parse_array_contents(const char **string);
59
60 enum YACJS_NAME(error) YACJS_NAME(last_error)() {
61     enum YACJS_NAME(error) err = last_error;
62     last_error = YACJS_NAME_CAP(ERROR_NONE);
63     return err;
64 }
65
66 struct YACJS_NAME(node) *YACJS_NAME(parse)(const char *string) {
67     struct YACJS_NAME(node) *ret = parse_any(&string);
68     // ensure there's nothing afterwards.
69     skip_whitespace(&string);
70     if(string[0] != 0) {
71         YACJS_NAME(destroy)(ret);
72         last_error = YACJS_NAME_CAP(ERROR_PARSE);
73         return NULL;
74     }
75     return ret;
76 }
77
78 void YACJS_NAME(destroy)(struct YACJS_NAME(node) *node) {
79     if(!node) return;
80     destroy_helper(node);
81     free(node);
82 }
83
84 static void destroy_helper(struct YACJS_NAME(node) *node) {
85     if(node->type == YACJS_NAME_CAP(NODE_ARRAY)) {
86         for(int i = 0; i < node->data.array.entries_count; i ++) {
87             destroy_helper(node->data.array.entries + i);
88         }
89         free(node->data.array.entries);
90     }
91     else if(node->type == YACJS_NAME_CAP(NODE_DICT)) {
92         YACJS_NAME(dict_destroy)(node->data.dict,
93             (YACJS_NAME(dict_visitor))YACJS_NAME(destroy));
94     }
95     else if(node->type == YACJS_NAME_CAP(NODE_STRING)) {
96         free(node->data.string);
97     }
98 }
99
100 enum YACJS_NAME(node_type) YACJS_NAME(node_type)(
101     struct YACJS_NAME(node) *node) {
102
103     return node->type;
104 }
105
106 bool YACJS_NAME(node_bool)(struct YACJS_NAME(node) *node) {
107     if(node->type != YACJS_NAME_CAP(NODE_BOOLEAN)) {
108         last_error = YACJS_NAME_CAP(ERROR_TYPE);
109         return NULL;
110     }
111     return node->data.boolean;
112 }
113
114 const char *YACJS_NAME(node_str)(struct YACJS_NAME(node) *node) {
115     if(node->type != YACJS_NAME_CAP(NODE_STRING)) {
116         last_error = YACJS_NAME_CAP(ERROR_TYPE);
117         return NULL;
118     }
119     return node->data.string;
120 }
121
122 int64_t YACJS_NAME(node_num)(struct YACJS_NAME(node) *node) {
123     if(node->type != YACJS_NAME_CAP(NODE_NUMBER)) {
124         last_error = YACJS_NAME_CAP(ERROR_TYPE);
125         return -1;
126     }
127     return node->data.number;
128 }
129
130 double YACJS_NAME(node_float)(struct YACJS_NAME(node) *node) {
131     if(node->type != YACJS_NAME_CAP(NODE_FLOAT)) {
132         last_error = YACJS_NAME_CAP(ERROR_TYPE);
133         return 1/0.0; // NaN
134     }
135     return node->data.fp;
136 }
137
138 int YACJS_NAME(node_array_size)(struct YACJS_NAME(node) *node) {
139     if(node->type != YACJS_NAME_CAP(NODE_ARRAY)) {
140         last_error = YACJS_NAME_CAP(ERROR_TYPE);
141         return -1;
142     }
143     return node->data.array.entries_count;
144 }
145
146 struct YACJS_NAME(node) *YACJS_NAME(node_array_elem)(
147     struct YACJS_NAME(node) *node, int index) {
148
149     if(node->type != YACJS_NAME_CAP(NODE_ARRAY)) {
150         last_error = YACJS_NAME_CAP(ERROR_TYPE);
151         return NULL;
152     }
153     if(index >= node->data.array.entries_count || index < 0) {
154         last_error = YACJS_NAME_CAP(ERROR_BOUNDS);
155         return NULL;
156         
157     }
158     return node->data.array.entries + index;
159 }
160
161 struct YACJS_NAME(node) *YACJS_NAME(node_dict_get)(
162     struct YACJS_NAME(node) *node, const char *key) {
163
164     if(node->type != YACJS_NAME_CAP(NODE_DICT)) {
165         last_error = YACJS_NAME_CAP(ERROR_TYPE);
166         return NULL;
167     }
168
169     return YACJS_NAME(dict_get)(node->data.dict, key);
170 }
171
172 static void skip_whitespace(const char ** const ptr) {
173     while((**ptr == ' ' || **ptr == '\t' || **ptr == '\n') && **ptr != 0) {
174         *ptr = U8S_NAME(next)(*ptr);
175     }
176 }
177
178 static const char *next_token(const char ** const ptr, int *length,
179     enum token_type *type) {
180
181     *length = 0;
182     // skip whitespace
183     skip_whitespace(ptr);
184     if(*ptr == 0) {
185         *type = TOKEN_NONE;
186         return NULL;
187     }
188
189     if(**ptr == '"') {
190         // TODO: parse string PROPERLY
191         const char *start = ++(*ptr);
192         *length = 0;
193         while(**ptr != '"' && **ptr != 0) {
194             (*ptr) ++, (*length) ++;
195         }
196         if(**ptr == 0) return NULL;
197         // skip closing quotes
198         else (*ptr)++;
199
200         *type = TOKEN_STRING;
201         return start;
202     }
203     else if(isdigit(**ptr) || **ptr == '-') {
204         const char *start = (*ptr);
205         *length = 0;
206         bool is_fp = false;
207         while((isdigit(**ptr) || **ptr == '.' || **ptr == 'e' || **ptr == '-')
208             && **ptr != 0) {
209
210             if(**ptr == '.' || **ptr == 'e') is_fp = true;
211             (*ptr) ++, (*length) ++;
212         }
213         if(*ptr == 0) return NULL;
214         if(is_fp) *type = TOKEN_FLOAT;
215         else *type = TOKEN_NUMBER;
216
217         return start;
218     }
219     else if(**ptr == '{') {
220         *type = TOKEN_OPENDICT;
221         return (*ptr)++;
222     }
223     else if(**ptr == '}') {
224         *type = TOKEN_CLOSEDICT;
225         return (*ptr)++;
226     }
227     else if(**ptr == '[') {
228         *type = TOKEN_OPENARRAY;
229         return (*ptr)++;
230     }
231     else if(**ptr == ']') {
232         *type = TOKEN_CLOSEARRAY;
233         return (*ptr)++;
234     }
235     else if(**ptr == ',') {
236         *type = TOKEN_COMMA;
237         return (*ptr)++;
238     }
239     else if(**ptr == ':') {
240         *type = TOKEN_COLON;
241         return (*ptr)++;
242     }
243     else if(!strncmp(*ptr, "false", 5)) {
244         *type = TOKEN_FALSE;
245         return (*ptr) += 5;
246     }
247     else if(!strncmp(*ptr, "true", 4)) {
248         *type = TOKEN_TRUE;
249         return (*ptr) += 4;
250     }
251     else if(!strncmp(*ptr, "null", 4)) {
252         *type = TOKEN_NULL;
253         return (*ptr) += 4;
254     }
255
256     printf("Don't know what to do with a '%c'\n", **ptr);
257     printf("context: \n\n<\n%s\n>\n\n", *ptr);
258
259     *type = TOKEN_ERROR;
260
261     return NULL;
262 }
263
264 static const char *peek_token(const char ** const ptr, int *length,
265     enum token_type *type) {
266
267     const char *s = *ptr;
268
269     return next_token(&s, length, type);
270 }
271
272 static struct YACJS_NAME(node) *parse_any(const char **string) {
273     enum token_type type;
274     const char *s;
275     int len;
276
277     s = next_token(string, &len, &type);
278     if(type == TOKEN_OPENDICT) return parse_dict_contents(string);
279     else if(type == TOKEN_OPENARRAY) return parse_array_contents(string);
280     else if(type == TOKEN_STRING) {
281         struct YACJS_NAME(node) *build = zalloc(sizeof(*build));
282         build->type = YACJS_NAME_CAP(NODE_STRING);
283         build->data.string = U8S_NAME(strndup)(s, len);
284         return build;
285     }
286     else if(type == TOKEN_NUMBER) {
287         struct YACJS_NAME(node) *build = zalloc(sizeof(*build));
288         build->type = YACJS_NAME_CAP(NODE_NUMBER);
289         build->data.number = strtoll(s, NULL, 0);
290         return build;
291     }
292     else if(type == TOKEN_FLOAT) {
293         struct YACJS_NAME(node) *build = zalloc(sizeof(*build));
294         build->type = YACJS_NAME_CAP(NODE_FLOAT);
295         char *e;
296         build->data.fp = strtod(s, &e);
297         if(e != *string) {
298             free(build);
299             // error parsing number, not everything was used
300             return NULL;
301         }
302         return build;
303     }
304     else if(type == TOKEN_FALSE || type == TOKEN_TRUE) {
305         struct YACJS_NAME(node) *build = zalloc(sizeof(*build));
306         build->type = YACJS_NAME_CAP(NODE_BOOLEAN);
307         build->data.boolean = type == TOKEN_TRUE;
308         return build;
309     }
310     else if(type == TOKEN_NULL) {
311         struct YACJS_NAME(node) *build = zalloc(sizeof(*build));
312         build->type = YACJS_NAME_CAP(NODE_NULL);
313         return build;
314     }
315
316     printf("Unknown token type %i\n", type);
317
318     return NULL;
319 }
320
321 static struct YACJS_NAME(node) *parse_dict_contents(const char **string) {
322     enum token_type type;
323     const char *s;
324     int len;
325
326     struct YACJS_NAME(node) *result = zalloc(sizeof(*result));
327     result->type = YACJS_NAME_CAP(NODE_DICT);
328     result->data.dict = YACJS_NAME(dict_make)();
329
330     while((s = next_token(string, &len, &type))) {
331         // closing dictionary token
332         if(type == TOKEN_CLOSEDICT) break;
333         // we expect a string here if it's not a closing dictionary
334         else if(type != TOKEN_STRING) {
335             YACJS_NAME(destroy)(result);
336             return NULL;
337         }
338
339         char *ds = U8S_NAME(strndup)(s, len);
340
341         // expect a colon after the name
342         next_token(string, &len, &type);
343         if(type != TOKEN_COLON) {
344             YACJS_NAME(destroy)(result);
345             free(ds);
346             return NULL;
347         }
348
349         struct YACJS_NAME(node) *value = parse_any(string);
350
351         if(value == NULL) {
352             YACJS_NAME(destroy)(result);
353             YACJS_NAME(destroy)(value);
354             free(ds);
355             return NULL;
356         }
357
358         YACJS_NAME(dict_set)(result->data.dict, ds, value);
359         free(ds);
360
361         peek_token(string, &len, &type);
362         if(type == TOKEN_COMMA) {
363             // NOTE: this means things like {"a":1,} are accepted
364             // eat the comma
365             next_token(string, &len, &type);
366         }
367     }
368     if(!s) {
369         YACJS_NAME(destroy)(result);
370         return NULL;
371     }
372
373     return result;
374 }
375
376 static struct YACJS_NAME(node) *parse_array_contents(const char **string) {
377     enum token_type type;
378     const char *s;
379     int len;
380
381     struct YACJS_NAME(node) *result = zalloc(sizeof(*result));
382     result->type = YACJS_NAME_CAP(NODE_ARRAY);
383     result->data.array.entries = NULL;
384     result->data.array.entries_size = 0;
385     result->data.array.entries_count = 0;
386
387     while((s = peek_token(string, &len, &type))) {
388         // closing dictionary token
389         if(type == TOKEN_CLOSEARRAY) {
390             // eat first
391             next_token(string, &len, &type);
392             break;
393         }
394         struct YACJS_NAME(node) *next = parse_any(string);
395         if(!next) {
396             YACJS_NAME(destroy)(result);
397             YACJS_NAME(destroy)(next);
398             return NULL;
399         }
400
401         if(result->data.array.entries_size
402             == result->data.array.entries_count) {
403
404             void *nmem = realloc(result->data.array.entries,
405                 sizeof(struct YACJS_NAME(node))
406                     * (result->data.array.entries_size * 2 + 1));
407             if(nmem == NULL) {
408                 last_error = YACJS_NAME_CAP(ERROR_MEMORY);
409                 YACJS_NAME(destroy)(result);
410                 YACJS_NAME(destroy)(next);
411                 return NULL;
412             }
413
414             result->data.array.entries_size *= 2;
415             result->data.array.entries_size ++;
416             result->data.array.entries = nmem;
417         }
418         result->data.array.entries[result->data.array.entries_count++] = *next;
419         free(next);
420
421         peek_token(string, &len, &type);
422         if(type == TOKEN_COMMA) {
423             // NOTE: this means things like [1,2,] are accepted
424             // eat the comma
425             next_token(string, &len, &type);
426         }
427     }
428     if(!s) {
429         YACJS_NAME(destroy)(result);
430         return NULL;
431     }
432
433     return result;
434 }