]> gitweb.ps.run Git - matrix_esp_thesis/blob - ext/mjson/src/mjson.c
add dependencies to repo
[matrix_esp_thesis] / ext / mjson / src / mjson.c
1 // Copyright (c) 2018-2020 Cesanta Software Limited
2 // All rights reserved
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 // SOFTWARE.
21
22 #include <float.h>
23 #include <math.h>
24
25 #include "mjson.h"
26
27 #if defined(_MSC_VER)
28 #define alloca(x) _alloca(x)
29 #endif
30
31 #if defined(_MSC_VER) && _MSC_VER < 1700
32 #define va_copy(x, y) (x) = (y)
33 #define isinf(x) !_finite(x)
34 #define isnan(x) _isnan(x)
35 #endif
36
37 static double mystrtod(const char *str, const char **end);
38
39 static int mjson_esc(int c, int esc) {
40   const char *p, *esc1 = "\b\f\n\r\t\\\"", *esc2 = "bfnrt\\\"";
41   for (p = esc ? esc1 : esc2; *p != '\0'; p++) {
42     if (*p == c) return esc ? esc2[p - esc1] : esc1[p - esc2];
43   }
44   return 0;
45 }
46
47 static int mjson_escape(int c) {
48   return mjson_esc(c, 1);
49 }
50
51 static int mjson_pass_string(const char *s, int len) {
52   int i;
53   for (i = 0; i < len; i++) {
54     if (s[i] == '\\' && i + 1 < len && mjson_escape(s[i + 1])) {
55       i++;
56     } else if (s[i] == '\0') {
57       return MJSON_ERROR_INVALID_INPUT;
58     } else if (s[i] == '"') {
59       return i;
60     }
61   }
62   return MJSON_ERROR_INVALID_INPUT;
63 }
64
65 int mjson(const char *s, int len, mjson_cb_t cb, void *ud) {
66   enum { S_VALUE, S_KEY, S_COLON, S_COMMA_OR_EOO } expecting = S_VALUE;
67   unsigned char nesting[MJSON_MAX_DEPTH];
68   int i, depth = 0;
69 #define MJSONCALL(ev) \
70   if (cb != NULL && cb(ev, s, start, i - start + 1, ud)) return i + 1;
71
72 // In the ascii table, the distance between `[` and `]` is 2.
73 // Ditto for `{` and `}`. Hence +2 in the code below.
74 #define MJSONEOO()                                                     \
75   do {                                                                 \
76     if (c != nesting[depth - 1] + 2) return MJSON_ERROR_INVALID_INPUT; \
77     depth--;                                                           \
78     if (depth == 0) {                                                  \
79       MJSONCALL(tok);                                                  \
80       return i + 1;                                                    \
81     }                                                                  \
82   } while (0)
83
84   for (i = 0; i < len; i++) {
85     int start = i;
86     unsigned char c = ((const unsigned char *) s)[i];
87     int tok = c;
88     if (c == ' ' || c == '\t' || c == '\n' || c == '\r') continue;
89     // printf("- %c [%.*s] %d %d\n", c, i, s, depth, expecting);
90     switch (expecting) {
91       case S_VALUE:
92         if (c == '{') {
93           if (depth >= (int) sizeof(nesting)) return MJSON_ERROR_TOO_DEEP;
94           nesting[depth++] = c;
95           expecting = S_KEY;
96           break;
97         } else if (c == '[') {
98           if (depth >= (int) sizeof(nesting)) return MJSON_ERROR_TOO_DEEP;
99           nesting[depth++] = c;
100           break;
101         } else if (c == ']' && depth > 0) {  // Empty array
102           MJSONEOO();
103         } else if (c == 't' && i + 3 < len && memcmp(&s[i], "true", 4) == 0) {
104           i += 3;
105           tok = MJSON_TOK_TRUE;
106         } else if (c == 'n' && i + 3 < len && memcmp(&s[i], "null", 4) == 0) {
107           i += 3;
108           tok = MJSON_TOK_NULL;
109         } else if (c == 'f' && i + 4 < len && memcmp(&s[i], "false", 5) == 0) {
110           i += 4;
111           tok = MJSON_TOK_FALSE;
112         } else if (c == '-' || ((c >= '0' && c <= '9'))) {
113           const char *end = NULL;
114           mystrtod(&s[i], &end);
115           if (end != NULL) i += (int) (end - &s[i] - 1);
116           tok = MJSON_TOK_NUMBER;
117         } else if (c == '"') {
118           int n = mjson_pass_string(&s[i + 1], len - i - 1);
119           if (n < 0) return n;
120           i += n + 1;
121           tok = MJSON_TOK_STRING;
122         } else {
123           return MJSON_ERROR_INVALID_INPUT;
124         }
125         if (depth == 0) {
126           MJSONCALL(tok);
127           return i + 1;
128         }
129         expecting = S_COMMA_OR_EOO;
130         break;
131
132       case S_KEY:
133         if (c == '"') {
134           int n = mjson_pass_string(&s[i + 1], len - i - 1);
135           if (n < 0) return n;
136           i += n + 1;
137           tok = MJSON_TOK_KEY;
138           expecting = S_COLON;
139         } else if (c == '}') {  // Empty object
140           MJSONEOO();
141           expecting = S_COMMA_OR_EOO;
142         } else {
143           return MJSON_ERROR_INVALID_INPUT;
144         }
145         break;
146
147       case S_COLON:
148         if (c == ':') {
149           expecting = S_VALUE;
150         } else {
151           return MJSON_ERROR_INVALID_INPUT;
152         }
153         break;
154
155       case S_COMMA_OR_EOO:
156         if (depth <= 0) return MJSON_ERROR_INVALID_INPUT;
157         if (c == ',') {
158           expecting = (nesting[depth - 1] == '{') ? S_KEY : S_VALUE;
159         } else if (c == ']' || c == '}') {
160           MJSONEOO();
161         } else {
162           return MJSON_ERROR_INVALID_INPUT;
163         }
164         break;
165     }
166     MJSONCALL(tok);
167   }
168   return MJSON_ERROR_INVALID_INPUT;
169 }
170
171 struct msjon_get_data {
172   const char *path;     // Lookup json path
173   int pos;              // Current path position
174   int d1;               // Current depth of traversal
175   int d2;               // Expected depth of traversal
176   int i1;               // Index in an array
177   int i2;               // Expected index in an array
178   int obj;              // If the value is array/object, offset where it starts
179   const char **tokptr;  // Destination
180   int *toklen;          // Destination length
181   int tok;              // Returned token
182 };
183
184 #include <stdio.h>
185
186 static int plen1(const char *s) {
187   int i = 0, n = 0;
188   while (s[i] != '\0' && s[i] != '.' && s[i] != '[')
189     n++, i += s[i] == '\\' ? 2 : 1;
190   // printf("PLEN: s: [%s], [%.*s] => %d\n", s, i, s, n);
191   return n;
192 }
193
194 static int plen2(const char *s) {
195   int i = 0;
196   while (s[i] != '\0' && s[i] != '.' && s[i] != '[')
197     i += s[i] == '\\' ? 2 : 1;
198   // printf("PLEN: s: [%s], [%.*s] => %d\n", s, i, s, n);
199   return i;
200 }
201
202 static int kcmp(const char *a, const char *b, int n) {
203   int i = 0, j = 0, r = 0;
204   for (i = 0, j = 0; j < n; i++, j++) {
205     if (b[i] == '\\') i++;
206     if ((r = a[j] - b[i]) != 0) return r;
207   }
208   // printf("KCMP: a: [%.*s], b:[%.*s] ==> %d\n", n, a, i, b, r);
209   return r;
210 }
211
212 static int mjson_get_cb(int tok, const char *s, int off, int len, void *ud) {
213   struct msjon_get_data *d = (struct msjon_get_data *) ud;
214 #if 0
215   printf("--> %2x %2d %2d %2d %2d\t %2d %2d\t'%s' '%s' '%s' '%s'\n", tok, d->d1,
216          d->d2, d->i1, d->i2, (int) off, (int) d->pos, s, d->path, s + off,
217          d->path + d->pos);
218 #endif
219   if (d->tok != MJSON_TOK_INVALID) return 1;  // Found
220   if (tok == '{' || tok == '[') {
221     if (d->d1 < d->d2) d->obj = -1;
222     if (d->d1 == d->d2) d->obj = off;
223     if (d->d1 == d->d2 && tok == '[' && d->path[d->pos] == '[') {
224       d->i1 = 0;
225       d->i2 = (int) mystrtod(&d->path[d->pos + 1], NULL);
226       if (d->i1 == d->i2) {
227         while (d->path[d->pos] && d->path[d->pos] != ']') d->pos++;
228         if (d->path[d->pos] == ']') d->pos++;
229         d->d2++;
230       }
231     }
232     d->d1++;
233   } else if (tok == '}' || tok == ']') {
234     if (tok == ']' && d->d1 == d->d2) d->i1 = 0;
235     d->d1--;
236     // printf("X %s %d %d %d %d %d\n", d->path + d->pos, d->d1, d->d2, d->i1,
237     //       d->i2, d->obj);
238     if (!d->path[d->pos] && d->d1 == d->d2 && d->obj != -1) {
239       d->tok = tok - 2;
240       if (d->tokptr) *d->tokptr = s + d->obj;
241       if (d->toklen) *d->toklen = off - d->obj + 1;
242       return 1;
243     }
244   } else if (tok == ',' && d->d1 == d->d2 && d->pos &&
245              d->path[d->pos - 1] == ']') {
246     return 1;  // Not found in the current elem array
247   } else if (tok == ',' && d->d1 == d->d2 + 1 && d->path[d->pos] == '[') {
248     // printf("GG '%s' '%s'\n", d->path, &d->path[d->pos]);
249     d->i1++;
250     if (d->i1 == d->i2) {
251       while (d->path[d->pos] && d->path[d->pos] != ']') d->pos++;
252       if (d->path[d->pos] == ']') d->pos++;
253       d->d2++;
254     }
255   } else if (tok == MJSON_TOK_KEY && d->d1 == d->d2 + 1 &&
256              d->path[d->pos] == '.' && s[off] == '"' &&
257              s[off + len - 1] == '"' &&
258              plen1(&d->path[d->pos + 1]) == len - 2 &&
259              kcmp(s + off + 1, &d->path[d->pos + 1], len - 2) == 0) {
260     d->d2++;
261     d->pos += plen2(&d->path[d->pos + 1]) + 1;
262   } else if (tok == MJSON_TOK_KEY && d->d1 == d->d2) {
263     return 1;  // Exhausted path, not found
264   } else if (MJSON_TOK_IS_VALUE(tok)) {
265     // printf("T %d %d %d %d %d\n", tok, d->d1, d->d2, d->i1, d->i2);
266     if (d->d1 == d->d2 && d->i1 == d->i2 && !d->path[d->pos]) {
267       d->tok = tok;
268       if (d->tokptr) *d->tokptr = s + off;
269       if (d->toklen) *d->toklen = len;
270       return 1;
271     }
272   }
273   return 0;
274 }
275
276 int mjson_find(const char *s, int n, const char *jp, const char **tp, int *tl) {
277   struct msjon_get_data data = {jp, 1,  0,  0,  0,
278                                 0,  -1, tp, tl, MJSON_TOK_INVALID};
279   if (jp[0] != '$') return MJSON_TOK_INVALID;
280   if (mjson(s, n, mjson_get_cb, &data) < 0) return MJSON_TOK_INVALID;
281   return data.tok;
282 }
283
284 int mjson_get_number(const char *s, int len, const char *path, double *v) {
285   const char *p;
286   int tok, n;
287   if ((tok = mjson_find(s, len, path, &p, &n)) == MJSON_TOK_NUMBER) {
288     if (v != NULL) *v = mystrtod(p, NULL);
289   }
290   return tok == MJSON_TOK_NUMBER ? 1 : 0;
291 }
292
293 int mjson_get_bool(const char *s, int len, const char *path, int *v) {
294   int tok = mjson_find(s, len, path, NULL, NULL);
295   if (tok == MJSON_TOK_TRUE && v != NULL) *v = 1;
296   if (tok == MJSON_TOK_FALSE && v != NULL) *v = 0;
297   return tok == MJSON_TOK_TRUE || tok == MJSON_TOK_FALSE ? 1 : 0;
298 }
299
300 static unsigned char unhex(unsigned char c) {
301   return (c >= '0' && c <= '9')   ? (unsigned char) (c - '0')
302          : (c >= 'A' && c <= 'F') ? (unsigned char) (c - '7')
303                                   : (unsigned char) (c - 'W');
304 }
305
306 static unsigned char mjson_unhex_nimble(const char *s) {
307   const unsigned char *u = (const unsigned char *) s;
308   return (unsigned char) (((unsigned char) (unhex(u[0]) << 4)) | unhex(u[1]));
309 }
310
311 static int mjson_unescape(const char *s, int len, char *to, int n) {
312   int i, j;
313   for (i = 0, j = 0; i < len && j < n; i++, j++) {
314     if (s[i] == '\\' && i + 5 < len && s[i + 1] == 'u') {
315       //  \uXXXX escape. We could process a simple one-byte chars
316       // \u00xx from the ASCII range. More complex chars would require
317       // dragging in a UTF8 library, which is too much for us
318       if (s[i + 2] != '0' || s[i + 3] != '0') return -1;  // Too much, give up
319       ((unsigned char *) to)[j] = mjson_unhex_nimble(s + i + 4);
320       i += 5;
321     } else if (s[i] == '\\' && i + 1 < len) {
322       int c = mjson_esc(s[i + 1], 0);
323       if (c == 0) return -1;
324       to[j] = (char) (unsigned char) c;
325       i++;
326     } else {
327       to[j] = s[i];
328     }
329   }
330   if (j >= n) return -1;
331   if (n > 0) to[j] = '\0';
332   return j;
333 }
334
335 int mjson_get_string(const char *s, int len, const char *path, char *to,
336                      int n) {
337   const char *p;
338   int sz;
339   if (mjson_find(s, len, path, &p, &sz) != MJSON_TOK_STRING) return -1;
340   return mjson_unescape(p + 1, sz - 2, to, n);
341 }
342
343 int mjson_get_hex(const char *s, int len, const char *x, char *to, int n) {
344   const char *p;
345   int i, j, sz;
346   if (mjson_find(s, len, x, &p, &sz) != MJSON_TOK_STRING) return -1;
347   for (i = j = 0; i < sz - 3 && j < n; i += 2, j++) {
348     ((unsigned char *) to)[j] = mjson_unhex_nimble(p + i + 1);
349   }
350   if (j < n) to[j] = '\0';
351   return j;
352 }
353
354 #if MJSON_ENABLE_BASE64
355 static unsigned char mjson_base64rev(int c) {
356   if (c >= 'A' && c <= 'Z') {
357     return (unsigned char) (c - 'A');
358   } else if (c >= 'a' && c <= 'z') {
359     return (unsigned char) (c + 26 - 'a');
360   } else if (c >= '0' && c <= '9') {
361     return (unsigned char) (c + 52 - '0');
362   } else if (c == '+') {
363     return 62;
364   } else if (c == '/') {
365     return 63;
366   } else {
367     return 64;
368   }
369 }
370
371 int mjson_base64_dec(const char *src, int n, char *dst, int dlen) {
372   const char *end = src + n;
373   int len = 0;
374   while (src + 3 < end && len < dlen) {
375     unsigned char a = mjson_base64rev(src[0]), b = mjson_base64rev(src[1]),
376                   c = mjson_base64rev(src[2]), d = mjson_base64rev(src[3]);
377     dst[len++] = (char) (unsigned char) ((a << 2) | (b >> 4));
378     if (src[2] != '=' && len < dlen) {
379       dst[len++] = (char) (unsigned char) ((b << 4) | (c >> 2));
380       if (src[3] != '=' && len < dlen) {
381         dst[len++] = (char) (unsigned char) ((c << 6) | d);
382       }
383     }
384     src += 4;
385   }
386   if (len < dlen) dst[len] = '\0';
387   return len;
388 }
389
390 int mjson_get_base64(const char *s, int len, const char *path, char *to,
391                      int n) {
392   const char *p;
393   int sz;
394   if (mjson_find(s, len, path, &p, &sz) != MJSON_TOK_STRING) return 0;
395   return mjson_base64_dec(p + 1, sz - 2, to, n);
396 }
397 #endif  // MJSON_ENABLE_BASE64
398
399 #if MJSON_ENABLE_NEXT
400 struct nextdata {
401   int off, len, depth, t, vo, arrayindex;
402   int *koff, *klen, *voff, *vlen, *vtype;
403 };
404
405 static int next_cb(int tok, const char *s, int off, int len, void *ud) {
406   struct nextdata *d = (struct nextdata *) ud;
407   // int i;
408   switch (tok) {
409     case '{':
410     case '[':
411       if (d->depth == 0 && tok == '[') d->arrayindex = 0;
412       if (d->depth == 1 && off > d->off) {
413         d->vo = off;
414         d->t = tok == '{' ? MJSON_TOK_OBJECT : MJSON_TOK_ARRAY;
415         if (d->voff) *d->voff = off;
416         if (d->vtype) *d->vtype = d->t;
417       }
418       d->depth++;
419       break;
420     case '}':
421     case ']':
422       d->depth--;
423       if (d->depth == 1 && d->vo) {
424         d->len = off + len;
425         if (d->vlen) *d->vlen = d->len - d->vo;
426         if (d->arrayindex >= 0) {
427           if (d->koff) *d->koff = d->arrayindex;  // koff holds array index
428           if (d->klen) *d->klen = 0;              // klen holds 0
429         }
430         return 1;
431       }
432       if (d->depth == 1 && d->arrayindex >= 0) d->arrayindex++;
433       break;
434     case ',':
435     case ':':
436       break;
437     case MJSON_TOK_KEY:
438       if (d->depth == 1 && d->off < off) {
439         if (d->koff) *d->koff = off;  // And report back to the user
440         if (d->klen) *d->klen = len;  // If we have to
441       }
442       break;
443     default:
444       if (d->depth != 1) break;
445       // If we're iterating over the array
446       if (off > d->off) {
447         d->len = off + len;
448         if (d->vlen) *d->vlen = len;    // value length
449         if (d->voff) *d->voff = off;    // value offset
450         if (d->vtype) *d->vtype = tok;  // value type
451         if (d->arrayindex >= 0) {
452           if (d->koff) *d->koff = d->arrayindex;  // koff holds array index
453           if (d->klen) *d->klen = 0;              // klen holds 0
454         }
455         return 1;
456       }
457       if (d->arrayindex >= 0) d->arrayindex++;
458       break;
459   }
460   (void) s;
461   return 0;
462 }
463
464 int mjson_next(const char *s, int n, int off, int *koff, int *klen, int *voff,
465                int *vlen, int *vtype) {
466   struct nextdata d = {off, 0, 0, 0, 0, -1, koff, klen, voff, vlen, vtype};
467   mjson(s, n, next_cb, &d);
468   return d.len;
469 }
470 #endif
471
472 #if MJSON_ENABLE_PRINT
473 int mjson_print_fixed_buf(const char *ptr, int len, void *fn_data) {
474   struct mjson_fixedbuf *fb = (struct mjson_fixedbuf *) fn_data;
475   int i, left = fb->size - 1 - fb->len;
476   if (left < len) len = left;
477   for (i = 0; i < len; i++) fb->ptr[fb->len + i] = ptr[i];
478   fb->len += len;
479   fb->ptr[fb->len] = '\0';
480   return len;
481 }
482
483 // This function allocates memory in chunks of size MJSON_DYNBUF_CHUNK
484 // to decrease memory fragmentation, when many calls are executed to
485 // print e.g. a base64 string or a hex string.
486 int mjson_print_dynamic_buf(const char *ptr, int len, void *fn_data) {
487   char *s, *buf = *(char **) fn_data;
488   size_t curlen = buf == NULL ? 0 : strlen(buf);
489   size_t new_size = curlen + (size_t) len + 1 + MJSON_DYNBUF_CHUNK;
490   new_size -= new_size % MJSON_DYNBUF_CHUNK;
491
492   if ((s = (char *) MJSON_REALLOC(buf, new_size)) == NULL) {
493     return 0;
494   } else {
495     memcpy(s + curlen, ptr, (size_t) len);
496     s[curlen + (size_t) len] = '\0';
497     *(char **) fn_data = s;
498     return len;
499   }
500 }
501
502 int mjson_snprintf(char *buf, size_t len, const char *fmt, ...) {
503   va_list ap;
504   struct mjson_fixedbuf fb = {buf, (int) len, 0};
505   va_start(ap, fmt);
506   mjson_vprintf(mjson_print_fixed_buf, &fb, fmt, &ap);
507   va_end(ap);
508   return fb.len;
509 }
510
511 char *mjson_aprintf(const char *fmt, ...) {
512   va_list ap;
513   char *result = NULL;
514   va_start(ap, fmt);
515   mjson_vprintf(mjson_print_dynamic_buf, &result, fmt, &ap);
516   va_end(ap);
517   return result;
518 }
519
520 int mjson_print_null(const char *ptr, int len, void *userdata) {
521   (void) ptr;
522   (void) userdata;
523   return len;
524 }
525
526 int mjson_print_buf(mjson_print_fn_t fn, void *fnd, const char *buf, int len) {
527   return fn(buf, len, fnd);
528 }
529
530 int mjson_print_long(mjson_print_fn_t fn, void *fnd, long val, int is_signed) {
531   unsigned long v = (unsigned long) val, s = 0, n, i;
532   char buf[20], t;
533   if (is_signed && val < 0) buf[s++] = '-', v = (unsigned long) (-val);
534   // This loop prints a number in reverse order. I guess this is because we
535   // write numbers from right to left: least significant digit comes last.
536   // Maybe because we use Arabic numbers, and Arabs write RTL?
537   for (n = 0; v > 0; v /= 10) buf[s + n++] = "0123456789"[v % 10];
538   // Reverse a string
539   for (i = 0; i < n / 2; i++)
540     t = buf[s + i], buf[s + i] = buf[s + n - i - 1], buf[s + n - i - 1] = t;
541   if (val == 0) buf[n++] = '0';  // Handle special case
542   return fn(buf, (int) (s + n), fnd);
543 }
544
545 int mjson_print_int(mjson_print_fn_t fn, void *fnd, int v, int s) {
546   return mjson_print_long(fn, fnd, s ? (long) v : (long) (unsigned) v, s);
547 }
548
549 static int addexp(char *buf, int e, int sign) {
550   int n = 0;
551   buf[n++] = 'e';
552   buf[n++] = (char) sign;
553   if (e > 400) return 0;
554   if (e < 10) buf[n++] = '0';
555   if (e >= 100) buf[n++] = (char) (e / 100 + '0'), e -= 100 * (e / 100);
556   if (e >= 10) buf[n++] = (char) (e / 10 + '0'), e -= 10 * (e / 10);
557   buf[n++] = (char) (e + '0');
558   return n;
559 }
560
561 int mjson_print_dbl(mjson_print_fn_t fn, void *fnd, double d, int width) {
562   char buf[40];
563   int i, s = 0, n = 0, e = 0;
564   double t, mul, saved;
565   if (d == 0.0) return fn("0", 1, fnd);
566   if (isinf(d)) return fn(d > 0 ? "inf" : "-inf", d > 0 ? 3 : 4, fnd);
567   if (isnan(d)) return fn("nan", 3, fnd);
568   if (d < 0.0) d = -d, buf[s++] = '-';
569
570   // Round
571   saved = d;
572   mul = 1.0;
573   while (d >= 10.0 && d / mul >= 10.0) mul *= 10.0;
574   while (d <= 1.0 && d / mul <= 1.0) mul /= 10.0;
575   for (i = 0, t = mul * 5; i < width; i++) t /= 10.0;
576   d += t;
577   // Calculate exponent, and 'mul' for scientific representation
578   mul = 1.0;
579   while (d >= 10.0 && d / mul >= 10.0) mul *= 10.0, e++;
580   while (d < 1.0 && d / mul < 1.0) mul /= 10.0, e--;
581   // printf(" --> %g %d %g %g\n", saved, e, t, mul);
582
583   if (e >= width) {
584     struct mjson_fixedbuf fb = {buf + s, (int) sizeof(buf) - s, 0};
585     n = mjson_print_dbl(mjson_print_fixed_buf, &fb, saved / mul, width);
586     // printf(" --> %.*g %d [%.*s]\n", 10, d / t, e, fb.len, fb.ptr);
587     n += addexp(buf + s + n, e, '+');
588     return fn(buf, s + n, fnd);
589   } else if (e <= -width) {
590     struct mjson_fixedbuf fb = {buf + s, (int) sizeof(buf) - s, 0};
591     n = mjson_print_dbl(mjson_print_fixed_buf, &fb, saved / mul, width);
592     // printf(" --> %.*g %d [%.*s]\n", 10, d / mul, e, fb.len, fb.ptr);
593     n += addexp(buf + s + n, -e, '-');
594     return fn(buf, s + n, fnd);
595   } else {
596     for (i = 0, t = mul; t >= 1.0 && s + n < (int) sizeof(buf); i++) {
597       int ch = (int) (d / t);
598       if (n > 0 || ch > 0) buf[s + n++] = (char) (ch + '0');
599       d -= ch * t;
600       t /= 10.0;
601     }
602     // printf(" --> [%g] -> %g %g (%d) [%.*s]\n", saved, d, t, n, s + n, buf);
603     if (n == 0) buf[s++] = '0';
604     while (t >= 1.0 && n + s < (int) sizeof(buf)) buf[n++] = '0', t /= 10.0;
605     if (s + n < (int) sizeof(buf)) buf[n + s++] = '.';
606     // printf(" 1--> [%g] -> [%.*s]\n", saved, s + n, buf);
607     for (i = 0, t = 0.1; s + n < (int) sizeof(buf) && n < width; i++) {
608       int ch = (int) (d / t);
609       buf[s + n++] = (char) (ch + '0');
610       d -= ch * t;
611       t /= 10.0;
612     }
613   }
614   while (n > 0 && buf[s + n - 1] == '0') n--;  // Trim trailing zeros
615   if (n > 0 && buf[s + n - 1] == '.') n--;     // Trim trailing dot
616   buf[s + n] = '\0';
617   return fn(buf, s + n, fnd);
618 }
619
620 int mjson_print_str(mjson_print_fn_t fn, void *fnd, const char *s, int len) {
621   int i, n = fn("\"", 1, fnd);
622   for (i = 0; i < len; i++) {
623     char c = (char) (unsigned char) mjson_escape(s[i]);
624     if (c) {
625       n += fn("\\", 1, fnd);
626       n += fn(&c, 1, fnd);
627     } else {
628       n += fn(&s[i], 1, fnd);
629     }
630   }
631   return n + fn("\"", 1, fnd);
632 }
633
634 #if MJSON_ENABLE_BASE64
635 int mjson_print_b64(mjson_print_fn_t fn, void *fnd, const unsigned char *s,
636                     int n) {
637   const char *t =
638       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
639   int i, len = fn("\"", 1, fnd);
640   for (i = 0; i < n; i += 3) {
641     int a = s[i], b = i + 1 < n ? s[i + 1] : 0, c = i + 2 < n ? s[i + 2] : 0;
642     char buf[4] = {t[a >> 2], t[(a & 3) << 4 | (b >> 4)], '=', '='};
643     if (i + 1 < n) buf[2] = t[(b & 15) << 2 | (c >> 6)];
644     if (i + 2 < n) buf[3] = t[c & 63];
645     len += fn(buf, sizeof(buf), fnd);
646   }
647   return len + fn("\"", 1, fnd);
648 }
649 #endif /* MJSON_ENABLE_BASE64 */
650
651 int mjson_vprintf(mjson_print_fn_t fn, void *fnd, const char *fmt,
652                   va_list *ap) {
653   int i = 0, n = 0;
654   while (fmt[i] != '\0') {
655     if (fmt[i] == '%') {
656       char fc = fmt[++i];
657       int is_long = 0;
658       if (fc == 'l') {
659         is_long = 1;
660         fc = fmt[i + 1];
661       }
662       if (fc == 'Q') {
663         char *buf = va_arg(*ap, char *);
664         n += mjson_print_str(fn, fnd, buf ? buf : "",
665                              buf ? (int) strlen(buf) : 0);
666       } else if (strncmp(&fmt[i], ".*Q", 3) == 0) {
667         int len = va_arg(*ap, int);
668         char *buf = va_arg(*ap, char *);
669         n += mjson_print_str(fn, fnd, buf, len);
670         i += 2;
671       } else if (fc == 'd' || fc == 'u') {
672         int is_signed = (fc == 'd');
673         if (is_long) {
674           long val = va_arg(*ap, long);
675           n += mjson_print_long(fn, fnd, val, is_signed);
676           i++;
677         } else {
678           int val = va_arg(*ap, int);
679           n += mjson_print_int(fn, fnd, val, is_signed);
680         }
681       } else if (fc == 'B') {
682         const char *s = va_arg(*ap, int) ? "true" : "false";
683         n += mjson_print_buf(fn, fnd, s, (int) strlen(s));
684       } else if (fc == 's') {
685         char *buf = va_arg(*ap, char *);
686         n += mjson_print_buf(fn, fnd, buf, (int) strlen(buf));
687       } else if (strncmp(&fmt[i], ".*s", 3) == 0) {
688         int len = va_arg(*ap, int);
689         char *buf = va_arg(*ap, char *);
690         n += mjson_print_buf(fn, fnd, buf, len);
691         i += 2;
692       } else if (fc == 'g') {
693         n += mjson_print_dbl(fn, fnd, va_arg(*ap, double), 6);
694       } else if (strncmp(&fmt[i], ".*g", 3) == 0) {
695         int width = va_arg(*ap, int);
696         n += mjson_print_dbl(fn, fnd, va_arg(*ap, double), width);
697         i += 2;
698 #if MJSON_ENABLE_BASE64
699       } else if (fc == 'V') {
700         int len = va_arg(*ap, int);
701         const char *buf = va_arg(*ap, const char *);
702         n += mjson_print_b64(fn, fnd, (const unsigned char *) buf, len);
703 #endif
704       } else if (fc == 'H') {
705         const char *hex = "0123456789abcdef";
706         int j, len = va_arg(*ap, int);
707         const unsigned char *p = va_arg(*ap, const unsigned char *);
708         n += fn("\"", 1, fnd);
709         for (j = 0; j < len; j++) {
710           n += fn(&hex[(p[j] >> 4) & 15], 1, fnd);
711           n += fn(&hex[p[j] & 15], 1, fnd);
712         }
713         n += fn("\"", 1, fnd);
714       } else if (fc == 'M') {
715         mjson_vprint_fn_t vfn = va_arg(*ap, mjson_vprint_fn_t);
716         n += vfn(fn, fnd, ap);
717       }
718       i++;
719     } else {
720       n += mjson_print_buf(fn, fnd, &fmt[i++], 1);
721     }
722   }
723   return n;
724 }
725
726 int mjson_printf(mjson_print_fn_t fn, void *fnd, const char *fmt, ...) {
727   va_list ap;
728   int len;
729   va_start(ap, fmt);
730   len = mjson_vprintf(fn, fnd, fmt, &ap);
731   va_end(ap);
732   return len;
733 }
734 #endif /* MJSON_ENABLE_PRINT */
735
736 static int is_digit(int c) {
737   return c >= '0' && c <= '9';
738 }
739
740 /* NOTE: strtod() implementation by Yasuhiro Matsumoto. */
741 static double mystrtod(const char *str, const char **end) {
742   double d = 0.0;
743   int sign = 1;
744   const char *p = str, *a = str;
745
746   /* decimal part */
747   if (*p == '-') {
748     sign = -1;
749     ++p;
750   } else if (*p == '+') {
751     ++p;
752   }
753   if (is_digit(*p)) {
754     d = (double) (*p++ - '0');
755     while (*p && is_digit(*p)) {
756       d = d * 10.0 + (double) (*p - '0');
757       ++p;
758     }
759     a = p;
760   } else if (*p != '.') {
761     goto done;
762   }
763   d *= sign;
764
765   /* fraction part */
766   if (*p == '.') {
767     double f = 0.0;
768     double base = 0.1;
769     ++p;
770
771     if (is_digit(*p)) {
772       while (*p && is_digit(*p)) {
773         f += base * (*p - '0');
774         base /= 10.0;
775         ++p;
776       }
777     }
778     d += f * sign;
779     a = p;
780   }
781
782   /* exponential part */
783   if ((*p == 'E') || (*p == 'e')) {
784     int i, e = 0, neg = 0;
785     p++;
786     if (*p == '-') p++, neg++;
787     if (*p == '+') p++;
788     while (is_digit(*p)) e = e * 10 + *p++ - '0';
789     if (neg) e = -e;
790 #if 0
791     if (d == 2.2250738585072011 && e == -308) {
792       d = 0.0;
793       a = p;
794       goto done;
795     }
796     if (d == 2.2250738585072012 && e <= -308) {
797       d *= 1.0e-308;
798       a = p;
799       goto done;
800     }
801 #endif
802     for (i = 0; i < e; i++) d *= 10;
803     for (i = 0; i < -e; i++) d /= 10;
804     a = p;
805   } else if (p > str && !is_digit(*(p - 1))) {
806     a = str;
807     goto done;
808   }
809
810 done:
811   if (end) *end = a;
812   return d;
813 }
814
815 #if MJSON_ENABLE_MERGE
816 int mjson_merge(const char *s, int n, const char *s2, int n2,
817                 mjson_print_fn_t fn, void *userdata) {
818   int koff, klen, voff, vlen, t, t2, k, off = 0, len = 0, comma = 0;
819   if (n < 2) return len;
820   len += fn("{", 1, userdata);
821   while ((off = mjson_next(s, n, off, &koff, &klen, &voff, &vlen, &t)) != 0) {
822     char *path = (char *) alloca((size_t) klen + 1);
823     const char *val;
824     memcpy(path, "$.", 2);
825     memcpy(path + 2, s + koff + 1, (size_t) (klen - 2));
826     path[klen] = '\0';
827     if ((t2 = mjson_find(s2, n2, path, &val, &k)) != MJSON_TOK_INVALID) {
828       if (t2 == MJSON_TOK_NULL) continue;  // null deletes the key
829     } else {
830       val = s + voff;  // Key is not found in the update. Copy the old value.
831     }
832     if (comma) len += fn(",", 1, userdata);
833     len += fn(s + koff, klen, userdata);
834     len += fn(":", 1, userdata);
835     if (t == MJSON_TOK_OBJECT && t2 == MJSON_TOK_OBJECT) {
836       len += mjson_merge(s + voff, vlen, val, k, fn, userdata);
837     } else {
838       if (t2 != MJSON_TOK_INVALID) vlen = k;
839       len += fn(val, vlen, userdata);
840     }
841     comma = 1;
842   }
843   // Add missing keys
844   off = 0;
845   while ((off = mjson_next(s2, n2, off, &koff, &klen, &voff, &vlen, &t)) != 0) {
846     char *path = (char *) alloca((size_t) klen + 1);
847     const char *val;
848     if (t == MJSON_TOK_NULL) continue;
849     memcpy(path, "$.", 2);
850     memcpy(path + 2, s2 + koff + 1, (size_t) (klen - 2));
851     path[klen] = '\0';
852     if (mjson_find(s, n, path, &val, &vlen) != MJSON_TOK_INVALID) continue;
853     if (comma) len += fn(",", 1, userdata);
854     len += fn(s2 + koff, klen, userdata);
855     len += fn(":", 1, userdata);
856     len += fn(s2 + voff, vlen, userdata);
857     comma = 1;
858   }
859   len += fn("}", 1, userdata);
860   return len;
861 }
862 #endif  // MJSON_ENABLE_MERGE
863
864 #if MJSON_ENABLE_PRETTY
865 struct prettydata {
866   int level;
867   int len;
868   int prev;
869   const char *pad;
870   int padlen;
871   mjson_print_fn_t fn;
872   void *userdata;
873 };
874
875 static int pretty_cb(int ev, const char *s, int off, int len, void *ud) {
876   struct prettydata *d = (struct prettydata *) ud;
877   int i;
878   switch (ev) {
879     case '{':
880     case '[':
881       d->level++;
882       d->len += d->fn(s + off, len, d->userdata);
883       break;
884     case '}':
885     case ']':
886       d->level--;
887       if (d->prev != '[' && d->prev != '{' && d->padlen > 0) {
888         d->len += d->fn("\n", 1, d->userdata);
889         for (i = 0; i < d->level; i++)
890           d->len += d->fn(d->pad, d->padlen, d->userdata);
891       }
892       d->len += d->fn(s + off, len, d->userdata);
893       break;
894     case ',':
895       d->len += d->fn(s + off, len, d->userdata);
896       if (d->padlen > 0) {
897         d->len += d->fn("\n", 1, d->userdata);
898         for (i = 0; i < d->level; i++)
899           d->len += d->fn(d->pad, d->padlen, d->userdata);
900       }
901       break;
902     case ':':
903       d->len += d->fn(s + off, len, d->userdata);
904       if (d->padlen > 0) d->len += d->fn(" ", 1, d->userdata);
905       break;
906     case MJSON_TOK_KEY:
907       if (d->prev == '{' && d->padlen > 0) {
908         d->len += d->fn("\n", 1, d->userdata);
909         for (i = 0; i < d->level; i++)
910           d->len += d->fn(d->pad, d->padlen, d->userdata);
911       }
912       d->len += d->fn(s + off, len, d->userdata);
913       break;
914     default:
915       if (d->prev == '[' && d->padlen > 0) {
916         d->len += d->fn("\n", 1, d->userdata);
917         for (i = 0; i < d->level; i++)
918           d->len += d->fn(d->pad, d->padlen, d->userdata);
919       }
920       d->len += d->fn(s + off, len, d->userdata);
921       break;
922   }
923   d->prev = ev;
924   return 0;
925 }
926
927 int mjson_pretty(const char *s, int n, const char *pad, mjson_print_fn_t fn,
928                  void *userdata) {
929   struct prettydata d = {0, 0, 0, pad, (int) strlen(pad), fn, userdata};
930   if (mjson(s, n, pretty_cb, &d) < 0) return -1;
931   return d.len;
932 }
933 #endif  // MJSON_ENABLE_PRETTY
934
935 #if MJSON_ENABLE_RPC
936 struct jsonrpc_ctx jsonrpc_default_context;
937
938 int mjson_globmatch(const char *s1, int n1, const char *s2, int n2) {
939   int i = 0, j = 0, ni = 0, nj = 0;
940   while (i < n1 || j < n2) {
941     if (i < n1 && j < n2 && (s1[i] == '?' || s2[j] == s1[i])) {
942       i++, j++;
943     } else if (i < n1 && (s1[i] == '*' || s1[i] == '#')) {
944       ni = i, nj = j + 1, i++;
945     } else if (nj > 0 && nj <= n2 && (s1[i - 1] == '#' || s2[j] != '/')) {
946       i = ni, j = nj;
947     } else {
948       return 0;
949     }
950   }
951   return 1;
952 }
953
954 void jsonrpc_return_errorv(struct jsonrpc_request *r, int code,
955                            const char *message, const char *data_fmt,
956                            va_list *ap) {
957   if (r->id_len == 0) return;
958   mjson_printf(r->fn, r->fn_data,
959                "{\"id\":%.*s,\"error\":{\"code\":%d,\"message\":%Q", r->id_len,
960                r->id, code, message == NULL ? "" : message);
961   if (data_fmt != NULL) {
962     mjson_printf(r->fn, r->fn_data, ",\"data\":");
963     mjson_vprintf(r->fn, r->fn_data, data_fmt, ap);
964   }
965   mjson_printf(r->fn, r->fn_data, "}}\n");
966 }
967
968 void jsonrpc_return_error(struct jsonrpc_request *r, int code,
969                           const char *message, const char *data_fmt, ...) {
970   va_list ap;
971   va_start(ap, data_fmt);
972   jsonrpc_return_errorv(r, code, message, data_fmt, &ap);
973   va_end(ap);
974 }
975
976 void jsonrpc_return_successv(struct jsonrpc_request *r, const char *result_fmt,
977                              va_list *ap) {
978   if (r->id_len == 0) return;
979   mjson_printf(r->fn, r->fn_data, "{\"id\":%.*s,\"result\":", r->id_len, r->id);
980   if (result_fmt != NULL) {
981     mjson_vprintf(r->fn, r->fn_data, result_fmt, ap);
982   } else {
983     mjson_printf(r->fn, r->fn_data, "%s", "null");
984   }
985   mjson_printf(r->fn, r->fn_data, "}\n");
986 }
987
988 void jsonrpc_return_success(struct jsonrpc_request *r, const char *result_fmt,
989                             ...) {
990   va_list ap;
991   va_start(ap, result_fmt);
992   jsonrpc_return_successv(r, result_fmt, &ap);
993   va_end(ap);
994 }
995
996 void jsonrpc_ctx_process(struct jsonrpc_ctx *ctx, const char *buf, int len,
997                          mjson_print_fn_t fn, void *fn_data, void *ud) {
998   const char *result = NULL, *error = NULL;
999   int result_sz = 0, error_sz = 0;
1000   struct jsonrpc_method *m = NULL;
1001   struct jsonrpc_request r = {ctx, buf, len, 0, 0, 0, 0, 0, 0, fn, fn_data, ud};
1002
1003   // Is is a response frame?
1004   mjson_find(buf, len, "$.result", &result, &result_sz);
1005   if (result == NULL) mjson_find(buf, len, "$.error", &error, &error_sz);
1006   if (result_sz > 0 || error_sz > 0) {
1007     if (ctx->response_cb) ctx->response_cb(buf, len, ctx->response_cb_data);
1008     return;
1009   }
1010
1011   // Method must exist and must be a string
1012   if (mjson_find(buf, len, "$.method", &r.method, &r.method_len) !=
1013       MJSON_TOK_STRING) {
1014     mjson_printf(fn, fn_data,
1015                  "{\"error\":{\"code\":-32700,\"message\":%.*Q}}\n", len, buf);
1016     return;
1017   }
1018
1019   // id and params are optional
1020   mjson_find(buf, len, "$.id", &r.id, &r.id_len);
1021   mjson_find(buf, len, "$.params", &r.params, &r.params_len);
1022
1023   for (m = ctx->methods; m != NULL; m = m->next) {
1024     if (mjson_globmatch(m->method, m->method_sz, r.method + 1,
1025                         r.method_len - 2) > 0) {
1026       if (r.params == NULL) r.params = "";
1027       m->cb(&r);
1028       break;
1029     }
1030   }
1031   if (m == NULL) {
1032     jsonrpc_return_error(&r, JSONRPC_ERROR_NOT_FOUND, "method not found", NULL);
1033   }
1034 }
1035
1036 static int jsonrpc_print_methods(mjson_print_fn_t fn, void *fn_data,
1037                                  va_list *ap) {
1038   struct jsonrpc_ctx *ctx = va_arg(*ap, struct jsonrpc_ctx *);
1039   struct jsonrpc_method *m;
1040   int len = 0;
1041   for (m = ctx->methods; m != NULL; m = m->next) {
1042     if (m != ctx->methods) len += mjson_print_buf(fn, fn_data, ",", 1);
1043     len += mjson_print_str(fn, fn_data, m->method, (int) strlen(m->method));
1044   }
1045   return len;
1046 }
1047
1048 void jsonrpc_list(struct jsonrpc_request *r) {
1049   jsonrpc_return_success(r, "[%M]", jsonrpc_print_methods, r->ctx);
1050 }
1051
1052 void jsonrpc_ctx_init(struct jsonrpc_ctx *ctx, mjson_print_fn_t response_cb,
1053                       void *response_cb_data) {
1054   ctx->methods = NULL;
1055   ctx->response_cb = response_cb;
1056   ctx->response_cb_data = response_cb_data;
1057 }
1058
1059 void jsonrpc_init(mjson_print_fn_t response_cb, void *userdata) {
1060   struct jsonrpc_ctx *ctx = &jsonrpc_default_context;
1061   jsonrpc_ctx_init(ctx, response_cb, userdata);
1062   jsonrpc_ctx_export(ctx, MJSON_RPC_LIST_NAME, jsonrpc_list);
1063 }
1064 #endif  // MJSON_ENABLE_RPC