GCC Code Coverage Report


Directory: ./
File: src/json.c
Date: 2021-09-04 00:13:15
Exec Total Coverage
Lines: 261 274 95.3%
Branches: 136 156 87.2%

Line Branch Exec Source
1 /***************************************************************************/ /**
2
3 @file json.c
4
5 @author Stephen Brennan
6
7 @date Created Sunday, 22 November 2015
8
9 @brief JSON parsing!
10
11 @copyright Copyright (c) 2015, Stephen Brennan. Released under the
12 Revised BSD License. See LICENSE.txt for details.
13
14 *******************************************************************************/
15
16 #include <assert.h>
17 #include <stdbool.h>
18 #include <stddef.h>
19 #include <stdio.h>
20 #include <string.h>
21
22 #include "json_private.h"
23 #include "nosj.h"
24
25 // forward declaration of the main parser
26 static struct json_parser json_parse_rec(char *text, struct json_token *arr,
27 size_t maxtoken, struct json_parser p);
28
29 /**
30 @brief Return true if c is a whitespace character according to the JSON spec.
31 */
32 2417 static bool json_isspace(char c)
33 {
34
8/8
✓ Branch 0 taken 1183 times.
✓ Branch 1 taken 1234 times.
✓ Branch 2 taken 1182 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1181 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 213 times.
✓ Branch 7 taken 968 times.
2417 return (c == ' ' || c == '\t' || c == '\r' || c == '\n');
35 }
36
37 /**
38 @brief Return true if c could be the beginning of a JSON number.
39 */
40 99 static bool json_isnumber(char c)
41 {
42
5/6
✓ Branch 0 taken 93 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 93 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 92 times.
✓ Branch 5 taken 1 times.
99 return (c == '-' || ('0' <= c && c <= '9'));
43 }
44
45 /**
46 @brief Place a token in the next open slot of arr.
47
48 If arr is null, we do nothing (so that the parser can be called for an
49 initial memory estimate). Otherwise, if we've run past the end of the token
50 buffer, return an error.
51 @param arr The token buffer. May be null.
52 @param tok The token to add.
53 @param p The parser state.
54 */
55 497 void json_settoken(struct json_token *arr, struct json_token tok,
56 struct json_parser p, size_t maxtoken)
57 {
58
3/4
✓ Branch 0 taken 253 times.
✓ Branch 1 taken 244 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 253 times.
497 if (arr == NULL || p.tokenidx >= maxtoken) {
59 244 return;
60 }
61 253 arr[p.tokenidx] = tok;
62 }
63
64 /**
65 @brief Set the "next" pointer in a token to be a new value.
66
67 If arr is null, this does nothing. If we've run past the end of the buffer,
68 do nothing.
69 @param arr The token buffer. May be null.
70 @param tokidx The index of the token to update.
71 @param next New value for next.
72 */
73 177 static void json_setnext(struct json_token *arr, size_t tokidx, size_t next,
74 size_t maxtoken)
75 {
76
3/4
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 85 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 92 times.
177 if (arr == NULL || tokidx >= maxtoken) {
77 85 return;
78 }
79 92 struct json_token tok = arr[tokidx];
80 92 tok.next = next;
81 92 arr[tokidx] = tok;
82 }
83
84 /**
85 @brief Set the "child" pointer in a token to be a new value.
86
87 If arr is null, this does nothing. If we've run past the end of the buffer,
88 do nothing.
89 @param arr The token buffer. May be null.
90 @param tokidx The index of the token to update.
91 @param child New value for child.
92 */
93 208 static void json_setchild(struct json_token *arr, size_t tokidx, size_t child,
94 size_t maxtoken)
95 {
96
3/4
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 100 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 108 times.
208 if (arr == NULL || tokidx >= maxtoken) {
97 100 return;
98 }
99 108 struct json_token tok = arr[tokidx];
100 108 tok.child = child;
101 108 arr[tokidx] = tok;
102 }
103
104 /**
105 @brief Set the "end" index in a token to be a new value.
106
107 If arr is null, this does nothing. If we've run past the end of the buffer,
108 do nothing.
109 @param arr The token buffer. May be null.
110 @param tokidx The index of the token to update.
111 @param end New value for end.
112 */
113 52 static void json_setend(struct json_token *arr, size_t tokidx, size_t end,
114 size_t maxtoken)
115 {
116
3/4
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 32 times.
52 if (arr == NULL || tokidx >= maxtoken) {
117 20 return;
118 }
119 32 struct json_token tok = arr[tokidx];
120 32 tok.end = end;
121 32 arr[tokidx] = tok;
122 }
123
124 /**
125 @brief Set the "length" index in a token to be a new value.
126
127 If arr is null, this does nothing. If we've run past the end of the buffer,
128 do nothing.
129 @param arr The token buffer. May be null.
130 @param tokidx The index of the token to update.
131 @param length New value for end.
132 */
133 52 static void json_setlength(struct json_token *arr, size_t tokidx, size_t length,
134 size_t maxtoken)
135 {
136
3/4
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 32 times.
52 if (arr == NULL || tokidx >= maxtoken) {
137 20 return;
138 }
139 32 struct json_token tok = arr[tokidx];
140 32 tok.length = length;
141 32 arr[tokidx] = tok;
142 }
143
144 /**
145 @brief Return the parser state with textidx pointed at the next non-ws char.
146 @param text The text we're parsing.
147 @param p The current parser state
148 @returns The new parser state
149 */
150 968 static struct json_parser json_skip_whitespace(char *text, struct json_parser p)
151 {
152
3/4
✓ Branch 1 taken 1449 times.
✓ Branch 2 taken 968 times.
✓ Branch 3 taken 1449 times.
✗ Branch 4 not taken.
2417 while (json_isspace(text[p.textidx]) && text[p.textidx] != '\0') {
153 1449 p.textidx++;
154 }
155 968 return p;
156 }
157
158 /**
159 @brief Parse the "true" literal.
160 @param text The text we're parsing.
161 @param arr The token buffer.
162 @param maxtoken The length of the token buffer.
163 @param p The parser state.
164 @returns Parser state after parsing true.
165 */
166 17 static struct json_parser json_parse_true(char *text, struct json_token *arr,
167 size_t maxtoken, struct json_parser p)
168 {
169 struct json_token tok;
170 17 tok.type = JSON_TRUE;
171 17 tok.start = p.textidx;
172 17 tok.end = p.textidx + 3;
173 17 tok.length = 0;
174 17 tok.child = 0;
175 17 tok.next = 0;
176
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 1 times.
17 if (strncmp("true", text + p.textidx, 4) == 0) {
177 16 json_settoken(arr, tok, p, maxtoken);
178 16 p.textidx += 4;
179 16 p.tokenidx += 1;
180 16 return p;
181 } else {
182 1 p.error = JSONERR_UNEXPECTED_TOKEN;
183 1 return p;
184 }
185 }
186
187 /**
188 @brief Parse the "false" literal.
189 @param text The text we're parsing.
190 @param arr The token buffer.
191 @param maxtoken The length of the token buffer.
192 @param p The parser state.
193 @returns Parser state after parsing false.
194 */
195 20 static struct json_parser json_parse_false(char *text, struct json_token *arr,
196 size_t maxtoken,
197 struct json_parser p)
198 {
199 (void)maxtoken; // unused
200 struct json_token tok;
201 20 tok.type = JSON_FALSE;
202 20 tok.start = p.textidx;
203 20 tok.end = p.textidx + 4;
204 20 tok.length = 0;
205 20 tok.child = 0;
206 20 tok.next = 0;
207
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 1 times.
20 if (strncmp("false", text + p.textidx, 5) == 0) {
208 19 json_settoken(arr, tok, p, maxtoken);
209 19 p.textidx += 5;
210 19 p.tokenidx += 1;
211 19 return p;
212 } else {
213 1 p.error = JSONERR_UNEXPECTED_TOKEN;
214 1 return p;
215 }
216 }
217
218 /**
219 @brief Parse the "null" literal.
220 @param text The text we're parsing.
221 @param arr The token buffer.
222 @param maxtoken The length of the token buffer.
223 @param p The parser state.
224 @returns Parser state after parsing null.
225 */
226 23 static struct json_parser json_parse_null(char *text, struct json_token *arr,
227 size_t maxtoken, struct json_parser p)
228 {
229 struct json_token tok;
230 23 tok.type = JSON_NULL;
231 23 tok.start = p.textidx;
232 23 tok.end = p.textidx + 3;
233 23 tok.length = 0;
234 23 tok.child = 0;
235 23 tok.next = 0;
236
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 1 times.
23 if (strncmp("null", text + p.textidx, 4) == 0) {
237 22 json_settoken(arr, tok, p, maxtoken);
238 22 p.textidx += 4;
239 22 p.tokenidx += 1;
240 22 return p;
241 } else {
242 1 p.error = JSONERR_UNEXPECTED_TOKEN;
243 1 return p;
244 }
245 }
246
247 /**
248 @brief Parse an array.
249 @param text The text we're parsing.
250 @param arr The token buffer.
251 @param maxtoken The length of the token buffer.
252 @param p The parser state.
253 @returns Parser state after parsing the array.
254 */
255 31 static struct json_parser json_parse_array(char *text, struct json_token *arr,
256 size_t maxtoken,
257 struct json_parser p)
258 {
259 31 size_t array_tokenidx = p.tokenidx, prev_tokenidx, curr_tokenidx,
260 31 length = 0;
261 31 struct json_token tok = {
262 .type = JSON_ARRAY,
263 31 .start = p.textidx,
264 .length = 0,
265 .end = 0,
266 .child = 0,
267 .next = 0,
268 };
269 31 json_settoken(arr, tok, p, maxtoken);
270
271 // current char is [, so we need to go past it.
272 31 p.textidx++;
273 31 p.tokenidx++;
274
275 // Skip through whitespace.
276 31 p = json_skip_whitespace(text, p);
277
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 28 times.
95 while (text[p.textidx] != ']') {
278
279
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 66 times.
67 if (text[p.textidx] == '\0') {
280 1 p.error = JSONERR_PREMATURE_EOF;
281 1 return p;
282 }
283 // Parse a value.
284 66 prev_tokenidx = curr_tokenidx;
285 66 curr_tokenidx = p.tokenidx;
286 66 p = json_parse_rec(text, arr, maxtoken, p);
287
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 65 times.
66 if (p.error != JSONERR_NO_ERROR) {
288 1 return p;
289 }
290
291 // Now set some bookkeeping of previous values.
292
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 41 times.
65 if (tok.child == 0) {
293 // If this is the first element of the list, set the
294 // list's child to point to it.
295 24 tok.child = curr_tokenidx;
296 24 json_setchild(arr, array_tokenidx, curr_tokenidx,
297 maxtoken);
298 } else {
299 // Otherwise set the previous element's next pointer to
300 // point to it.
301 41 json_setnext(arr, prev_tokenidx, curr_tokenidx,
302 maxtoken);
303 }
304
305 65 length++;
306
307 // Skip whitespace.
308 65 p = json_skip_whitespace(text, p);
309
2/2
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 22 times.
65 if (text[p.textidx] == ',') {
310 43 p.textidx++;
311 43 p = json_skip_whitespace(text, p);
312
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 21 times.
22 } else if (text[p.textidx] != ']') {
313 // If there was no comma, this better be the end of the
314 // object.
315 1 p.error = JSONERR_EXPECTED_TOKEN;
316 1 p.errorarg = ',';
317 1 return p;
318 }
319 }
320
321 // Set the end of the array token to point to the closing bracket, then
322 // move it up.
323 28 json_setend(arr, array_tokenidx, p.textidx, maxtoken);
324 28 json_setlength(arr, array_tokenidx, length, maxtoken);
325 28 p.textidx++;
326 28 return p;
327 }
328
329 /**
330 @brief Parse an object.
331 @param text The text we're parsing.
332 @param arr The token buffer.
333 @param maxtoken The length of the token buffer.
334 @param p The parser state.
335 @returns Parser state after parsing the object.
336 */
337 35 static struct json_parser json_parse_object(char *text, struct json_token *arr,
338 size_t maxtoken,
339 struct json_parser p)
340 {
341 35 size_t object_tokenidx = p.tokenidx, prev_keyidx, curr_keyidx,
342 35 length = 0;
343 35 struct json_token tok = {
344 .type = JSON_OBJECT,
345 35 .start = p.textidx,
346 .length = 0,
347 .end = 0,
348 .child = 0,
349 .next = 0,
350 };
351 35 json_settoken(arr, tok, p, maxtoken);
352
353 // current char is {, so we need to go past it.
354 35 p.textidx++;
355 35 p.tokenidx++;
356
357 // Skip through whitespace.
358 35 p = json_skip_whitespace(text, p);
359
2/2
✓ Branch 0 taken 170 times.
✓ Branch 1 taken 24 times.
194 while (text[p.textidx] != '}') {
360 // Make sure the string didn't end.
361
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 169 times.
170 if (text[p.textidx] == '\0') {
362 1 p.error = JSONERR_PREMATURE_EOF;
363 1 return p;
364 }
365
366 // Parse a string (key) and value.
367 169 prev_keyidx = curr_keyidx;
368 169 curr_keyidx = p.tokenidx;
369 169 p = json_parse_string(text, arr, maxtoken, p);
370
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 162 times.
169 if (p.error != JSONERR_NO_ERROR) {
371 7 return p;
372 }
373 162 p = json_skip_whitespace(text, p);
374
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 161 times.
162 if (text[p.textidx] != ':') {
375 1 p.error = JSONERR_EXPECTED_TOKEN;
376 1 p.errorarg = ':';
377 1 return p;
378 }
379 161 p.textidx++;
380 161 p = json_parse_rec(text, arr, maxtoken, p);
381
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 160 times.
161 if (p.error != JSONERR_NO_ERROR) {
382 1 return p;
383 }
384
385 // Now set some bookkeeping of previous values.
386
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 136 times.
160 if (tok.child == 0) {
387 // If this is the first element of the list, set the
388 // list's child to point to it.
389 24 tok.child = curr_keyidx;
390 24 json_setchild(arr, object_tokenidx, curr_keyidx,
391 maxtoken);
392 } else {
393 // Otherwise set the previous element's next pointer to
394 // point to it.
395 136 json_setnext(arr, prev_keyidx, curr_keyidx, maxtoken);
396 }
397 // Set the key's child pointer to point at its value. Just
398 // cause we can.
399 160 json_setchild(arr, curr_keyidx, curr_keyidx + 1, maxtoken);
400
401 160 length++;
402
403 // Skip whitespace.
404 160 p = json_skip_whitespace(text, p);
405
2/2
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 22 times.
160 if (text[p.textidx] == ',') {
406 138 p.textidx++;
407 138 p = json_skip_whitespace(text, p);
408
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 21 times.
22 } else if (text[p.textidx] != '}') {
409 // If there was no comma, this better be the end of the
410 // object.
411 1 p.error = JSONERR_EXPECTED_TOKEN;
412 1 p.errorarg = ',';
413 1 return p;
414 }
415 }
416
417 // Set the end of the array token to point to the closing bracket, then
418 // move it up.
419 24 json_setend(arr, object_tokenidx, p.textidx, maxtoken);
420 24 json_setlength(arr, object_tokenidx, length, maxtoken);
421 24 p.textidx++;
422 24 return p;
423 }
424
425 char *parse_number_state[] = {
426 "START", "MINUS", "ZERO",
427 "DIGIT", "DECIMAL", "DECIMAL_ACCEPT",
428 "EXPONENT", "EXPONENT_DIGIT", "EXPONENT_DIGIT_ACCEPT",
429 "END"
430 };
431
432 /**
433 @brief Parse a string number.
434 @param text The text we're parsing.
435 @param arr The token buffer.
436 @param maxtoken The length of the token buffer.
437 @param p The parser state.
438 @returns Parser state after parsing the number.
439 */
440 98 static struct json_parser json_parse_number(char *text, struct json_token *arr,
441 size_t maxtoken,
442 struct json_parser p)
443 {
444 98 struct json_token tok = { .type = JSON_NUMBER,
445 98 .start = p.textidx,
446 .length = 0, // not used
447 .end = 0,
448 .child = 0,
449 .next = 0 };
450 enum state {
451 START,
452 MINUS,
453 ZERO,
454 DIGIT,
455 DECIMAL,
456 DECIMAL_ACCEPT,
457 EXPONENT,
458 EXPONENT_DIGIT,
459 EXPONENT_DIGIT_ACCEPT,
460 END
461 98 } state = START;
462
463 /*
464 This function is completely described by this FSM. States marked by
465 asterisk are accepting. Unexpected input at accepting states ends the
466 number, and unexpected input at rejecting states causes an error. This
467 state machine is designed to accept any input given by the diagram in
468 the ECMA JSON spec.
469
470 -----START-----
471 / | (-) \
472 / v \
473 (0) | +----MINUS----+ | (1-9)
474 v v (0) (1-9) v v
475 *ZERO* *DIGIT*--------
476 | \ (.) (.) / |-\ (0-9) \
477 | --->DECIMAL<--- \
478 | | \
479 | v (0-9) /----\ (0-9) |
480 | *DECIMAL_ACCEPT* ----/ |
481 | | /
482 |(e,E) v (e,E) (e,E) /
483 +-----> EXPONENT <-------------
484 / \
485 (+,-)v v (0-9)
486 EXPONENT_DIGIT *EXPONENT_DIGIT_ACCEPT*
487 \-----------/ \ /(0-9)
488 (0-9) \--/
489 */
490
491 // printf("input: %s\n", text + p.textidx);
492
2/2
✓ Branch 0 taken 346 times.
✓ Branch 1 taken 98 times.
444 while (state != END) {
493 346 char c = text[p.textidx];
494 // printf("state: %s\n", parse_number_state[state]);
495
9/11
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 199 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 10 times.
✓ Branch 7 taken 4 times.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
346 switch (state) {
496 98 case START:
497
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 88 times.
98 if (c == '0') {
498 10 state = ZERO;
499
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 82 times.
88 } else if (c == '-') {
500 6 state = MINUS;
501
2/4
✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 82 times.
✗ Branch 3 not taken.
82 } else if ('1' <= c && c <= '9') {
502 82 state = DIGIT;
503 } else {
504 p.error = JSONERR_INVALID_NUMBER;
505 state = END; // ERROR
506 }
507 98 break;
508 6 case MINUS:
509
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
6 if (c == '0') {
510 1 state = ZERO;
511
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
5 } else if ('1' <= c && c <= '9') {
512 4 state = DIGIT;
513 } else {
514 1 p.error = JSONERR_INVALID_NUMBER;
515 1 state = END; // ERROR
516 }
517 6 break;
518 11 case ZERO:
519
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 10 times.
11 if (c == '.') {
520 1 state = DECIMAL;
521
3/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
10 } else if (c == 'e' || c == 'E') {
522 1 state = EXPONENT;
523 } else {
524 9 state = END;
525 }
526 11 break;
527 199 case DIGIT:
528
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 195 times.
199 if (c == '.') {
529 4 state = DECIMAL;
530
4/4
✓ Branch 0 taken 188 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 187 times.
195 } else if (c == 'e' || c == 'E') {
531 8 state = EXPONENT;
532
4/4
✓ Branch 0 taken 119 times.
✓ Branch 1 taken 68 times.
✓ Branch 2 taken 113 times.
✓ Branch 3 taken 6 times.
187 } else if ('0' <= c && c <= '9') {
533 113 state = DIGIT;
534 } else {
535 74 state = END;
536 }
537 199 break;
538 5 case DECIMAL:
539
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
5 if ('0' <= c && c <= '9') {
540 4 state = DECIMAL_ACCEPT;
541 } else {
542 1 p.error = JSONERR_INVALID_NUMBER;
543 1 state = END; // ERROR
544 }
545 5 break;
546 5 case DECIMAL_ACCEPT:
547
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
5 if ('0' <= c && c <= '9') {
548 1 state = DECIMAL_ACCEPT;
549
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
4 } else if (c == 'e' || c == 'E') {
550 1 state = EXPONENT;
551 } else {
552 3 state = END;
553 }
554 5 break;
555 10 case EXPONENT:
556
4/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 6 times.
10 if (c == '+' || c == '-') {
557 4 state = EXPONENT_DIGIT;
558
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
6 } else if ('0' <= c && c <= '9') {
559 4 state = EXPONENT_DIGIT_ACCEPT;
560 } else {
561 2 p.error = JSONERR_INVALID_NUMBER;
562 2 state = END; // ERROR
563 }
564 10 break;
565 4 case EXPONENT_DIGIT:
566
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
4 if ('0' <= c && c <= '9') {
567 3 state = EXPONENT_DIGIT_ACCEPT;
568 } else {
569 1 p.error = JSONERR_INVALID_NUMBER;
570 1 state = END; // ERROR
571 }
572 4 break;
573 8 case EXPONENT_DIGIT_ACCEPT:
574
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
8 if ('0' <= c && c <= '9') {
575 1 state = EXPONENT_DIGIT_ACCEPT;
576 } else {
577 7 state = END;
578 }
579 8 break;
580 case END:
581 // never happens
582 assert(false);
583 }
584 346 p.textidx++;
585 }
586
587 98 p.textidx--; // the character we failed on
588 98 tok.end = p.textidx - 1; // the previous character
589 98 json_settoken(arr, tok, p, maxtoken);
590 98 p.tokenidx++;
591 98 return p;
592 }
593
594 /**
595 @brief Parse any JSON value.
596 @param text The text we're parsing.
597 @param arr The token buffer.
598 @param maxtoken The length of the token buffer.
599 @param p The parser state.
600 @returns Parser state after parsing the value.
601 */
602 334 static struct json_parser json_parse_rec(char *text, struct json_token *arr,
603 size_t maxtoken, struct json_parser p)
604 {
605 334 p = json_skip_whitespace(text, p);
606
607
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 332 times.
334 if (text[p.textidx] == '\0') {
608 2 p.error = JSONERR_PREMATURE_EOF;
609 2 return p;
610 }
611
612
7/7
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 31 times.
✓ Branch 2 taken 107 times.
✓ Branch 3 taken 17 times.
✓ Branch 4 taken 20 times.
✓ Branch 5 taken 23 times.
✓ Branch 6 taken 99 times.
332 switch (text[p.textidx]) {
613 35 case '{':
614 35 return json_parse_object(text, arr, maxtoken, p);
615 31 case '[':
616 31 return json_parse_array(text, arr, maxtoken, p);
617 107 case '"':
618 107 return json_parse_string(text, arr, maxtoken, p);
619 17 case 't':
620 17 return json_parse_true(text, arr, maxtoken, p);
621 20 case 'f':
622 20 return json_parse_false(text, arr, maxtoken, p);
623 23 case 'n':
624 23 return json_parse_null(text, arr, maxtoken, p);
625 99 default:
626
2/2
✓ Branch 1 taken 98 times.
✓ Branch 2 taken 1 times.
99 if (json_isnumber(text[p.textidx])) {
627 98 return json_parse_number(text, arr, maxtoken, p);
628 } else {
629 1 p.error = JSONERR_UNEXPECTED_TOKEN;
630 1 return p;
631 }
632 }
633 }
634
635 char *json_type_str[] = { "object", "array", "number", "string",
636 "true", "false", "null" };
637
638 char *json_error_str[] = {
639 "no error",
640 "encountered an invalid numeric literal",
641 "string ended prematurely",
642 "unexpected token",
643 "invalid surrogate pair",
644 "expected token '%c'",
645 };
646
647 107 struct json_parser json_parse(char *text, struct json_token *arr,
648 size_t maxtoken)
649 {
650 107 struct json_parser parser = { .textidx = 0,
651 .tokenidx = 0,
652 .error = JSONERR_NO_ERROR,
653 .errorarg = 0 };
654 107 return json_parse_rec(text, arr, maxtoken, parser);
655 }
656
657 void json_print(struct json_token *arr, size_t n)
658 {
659 size_t i;
660 for (i = 0; i < n; i++) {
661 printf("%03lu: "
662 "%6s\t%04lu-%04lu,\tlength=%lu,\tchild=%lu,\tnext=%lu\n",
663 i, json_type_str[arr[i].type], arr[i].start, arr[i].end,
664 arr[i].length, arr[i].child, arr[i].next);
665 }
666 }
667
668 void json_print_error(FILE *f, struct json_parser p)
669 {
670 fprintf(f, "at character %lu: ", p.textidx);
671 fprintf(f, json_error_str[p.error], p.errorarg);
672 fprintf(f, "\n");
673 }
674