1 //-----------------------------------------------------------------------------
2 // Borrowed initially from https://github.com/cesanta/frozen
3 // Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
4 // Copyright (c) 2018 Cesanta Software Limited
5 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation, either version 3 of the License, or
10 // (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
17 // See LICENSE.txt for the text of the license.
18 //-----------------------------------------------------------------------------
20 #define _CRT_SECURE_NO_WARNINGS /* Disable deprecation warning in VS2005+ */
29 #define malloc(X) BigBuf_malloc(X)
33 #if (defined(__GNUC__) || defined(__TI_COMPILER_VERSION__)) && !defined(_WIN32)
34 #define WEAK __attribute__((weak))
43 #define snprintf cs_win_snprintf
44 #define vsnprintf cs_win_vsnprintf
45 int cs_win_snprintf(char *str
, size_t size
, const char *format
, ...);
46 int cs_win_vsnprintf(char *str
, size_t size
, const char *format
, va_list ap
);
50 typedef _int64
int64_t;
51 typedef unsigned _int64
uint64_t;
56 /* <inttypes.h> wants this for C++ */
57 #ifndef __STDC_FORMAT_MACROS
58 #define __STDC_FORMAT_MACROS
60 // problem specific to arm-none-gcc provided by Debian:
61 // https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=953844
62 // => include <sys/types.h> before <inttypes.h>
63 #include <sys/types.h>
68 #define INT64_FMT PRId64
71 #define UINT64_FMT PRIu64
75 #define va_copy(x, y) x = y
78 #ifndef JSON_ENABLE_ARRAY
79 #define JSON_ENABLE_ARRAY 1
89 /* For callback API */
90 char path
[JSON_MAX_PATH_LEN
];
93 json_walk_callback_t callback
;
101 #define SET_STATE(fr, ptr, str, len) \
102 struct fstate fstate = {(ptr), (fr)->path_len}; \
103 json_append_to_path((fr), (str), (len));
105 #define CALL_BACK(fr, tok, value, len) \
107 if ((fr)->callback && \
108 ((fr)->path_len == 0 || (fr)->path[(fr)->path_len - 1] != '.')) { \
109 struct json_token t = {(value), (int) (len), (tok)}; \
111 /* Call the callback with the given value and current name */ \
112 (fr)->callback((fr)->callback_data, (fr)->cur_name, (fr)->cur_name_len, \
115 /* Reset the name */ \
116 (fr)->cur_name = NULL; \
117 (fr)->cur_name_len = 0; \
121 static int json_append_to_path(struct frozen
*f
, const char *str
, int size
) {
123 int left
= sizeof(f
->path
) - n
- 1;
124 if (size
> left
) size
= left
;
125 memcpy(f
->path
+ n
, str
, size
);
126 f
->path
[n
+ size
] = '\0';
131 static void json_truncate_path(struct frozen
*f
, size_t len
) {
136 static int json_parse_object(struct frozen
*f
);
137 static int json_parse_value(struct frozen
*f
);
139 #define EXPECT(cond, err_code) \
141 if (!(cond)) return (err_code); \
147 if (_n < 0) return _n; \
150 #define END_OF_STRING (-1)
152 static int json_left(const struct frozen
*f
) {
153 return f
->end
- f
->cur
;
156 static int json_isspace(int ch
) {
157 return ch
== ' ' || ch
== '\t' || ch
== '\r' || ch
== '\n';
160 static void json_skip_whitespaces(struct frozen
*f
) {
161 while (f
->cur
< f
->end
&& json_isspace(*f
->cur
)) f
->cur
++;
164 static int json_cur(struct frozen
*f
) {
165 json_skip_whitespaces(f
);
166 return f
->cur
>= f
->end
? END_OF_STRING
: *(unsigned char *) f
->cur
;
169 static int json_test_and_skip(struct frozen
*f
, int expected
) {
170 int ch
= json_cur(f
);
171 if (ch
== expected
) {
175 return ch
== END_OF_STRING
? JSON_STRING_INCOMPLETE
: JSON_STRING_INVALID
;
178 static int json_isalpha(int ch
) {
179 return (ch
>= 'a' && ch
<= 'z') || (ch
>= 'A' && ch
<= 'Z');
182 static int json_isdigit(int ch
) {
183 return ch
>= '0' && ch
<= '9';
186 static int json_isxdigit(int ch
) {
187 return json_isdigit(ch
) || (ch
>= 'a' && ch
<= 'f') ||
188 (ch
>= 'A' && ch
<= 'F');
191 static int json_get_escape_len(const char *s
, int len
) {
194 return len
< 6 ? JSON_STRING_INCOMPLETE
195 : json_isxdigit(s
[1]) && json_isxdigit(s
[2]) &&
196 json_isxdigit(s
[3]) && json_isxdigit(s
[4])
198 : JSON_STRING_INVALID
;
207 return len
< 2 ? JSON_STRING_INCOMPLETE
: 1;
209 return JSON_STRING_INVALID
;
213 /* identifier = letter { letter | digit | '_' } */
214 static int json_parse_identifier(struct frozen
*f
) {
215 EXPECT(json_isalpha(json_cur(f
)), JSON_STRING_INVALID
);
217 SET_STATE(f
, f
->cur
, "", 0);
218 while (f
->cur
< f
->end
&&
219 (*f
->cur
== '_' || json_isalpha(*f
->cur
) || json_isdigit(*f
->cur
))) {
222 json_truncate_path(f
, fstate
.path_len
);
223 CALL_BACK(f
, JSON_TYPE_STRING
, fstate
.ptr
, f
->cur
- fstate
.ptr
);
228 static int json_get_utf8_char_len(unsigned char ch
) {
229 if ((ch
& 0x80) == 0) return 1;
240 /* string = '"' { quoted_printable_chars } '"' */
241 static int json_parse_string(struct frozen
*f
) {
243 TRY(json_test_and_skip(f
, '"'));
246 SET_STATE(f
, f
->cur
, "", 0);
247 for (; f
->cur
< f
->end
; f
->cur
+= len
) {
248 ch
= *(unsigned char *) f
->cur
;
249 len
= json_get_utf8_char_len((unsigned char) ch
);
250 EXPECT(ch
>= 32 && len
> 0, JSON_STRING_INVALID
); /* No control chars */
251 EXPECT(len
<= json_left(f
), JSON_STRING_INCOMPLETE
);
254 EXPECT((n
= json_get_escape_len(f
->cur
+ 1, json_left(f
))) > 0, n
);
256 } else if (ch
== '"') {
257 json_truncate_path(f
, fstate
.path_len
);
258 CALL_BACK(f
, JSON_TYPE_STRING
, fstate
.ptr
, f
->cur
- fstate
.ptr
);
264 return ch
== '"' ? 0 : JSON_STRING_INCOMPLETE
;
267 /* number = [ '-' ] digit+ [ '.' digit+ ] [ ['e'|'E'] ['+'|'-'] digit+ ] */
268 static int json_parse_number(struct frozen
*f
) {
269 int ch
= json_cur(f
);
270 SET_STATE(f
, f
->cur
, "", 0);
271 if (ch
== '-') f
->cur
++;
272 EXPECT(f
->cur
< f
->end
, JSON_STRING_INCOMPLETE
);
273 if (f
->cur
+ 1 < f
->end
&& f
->cur
[0] == '0' && f
->cur
[1] == 'x') {
275 EXPECT(f
->cur
< f
->end
, JSON_STRING_INCOMPLETE
);
276 EXPECT(json_isxdigit(f
->cur
[0]), JSON_STRING_INVALID
);
277 while (f
->cur
< f
->end
&& json_isxdigit(f
->cur
[0])) f
->cur
++;
279 EXPECT(json_isdigit(f
->cur
[0]), JSON_STRING_INVALID
);
280 while (f
->cur
< f
->end
&& json_isdigit(f
->cur
[0])) f
->cur
++;
281 if (f
->cur
< f
->end
&& f
->cur
[0] == '.') {
283 EXPECT(f
->cur
< f
->end
, JSON_STRING_INCOMPLETE
);
284 EXPECT(json_isdigit(f
->cur
[0]), JSON_STRING_INVALID
);
285 while (f
->cur
< f
->end
&& json_isdigit(f
->cur
[0])) f
->cur
++;
287 if (f
->cur
< f
->end
&& (f
->cur
[0] == 'e' || f
->cur
[0] == 'E')) {
289 EXPECT(f
->cur
< f
->end
, JSON_STRING_INCOMPLETE
);
290 if ((f
->cur
[0] == '+' || f
->cur
[0] == '-')) f
->cur
++;
291 EXPECT(f
->cur
< f
->end
, JSON_STRING_INCOMPLETE
);
292 EXPECT(json_isdigit(f
->cur
[0]), JSON_STRING_INVALID
);
293 while (f
->cur
< f
->end
&& json_isdigit(f
->cur
[0])) f
->cur
++;
296 json_truncate_path(f
, fstate
.path_len
);
297 CALL_BACK(f
, JSON_TYPE_NUMBER
, fstate
.ptr
, f
->cur
- fstate
.ptr
);
301 #if JSON_ENABLE_ARRAY
302 /* array = '[' [ value { ',' value } ] ']' */
303 static int json_parse_array(struct frozen
*f
) {
304 CALL_BACK(f
, JSON_TYPE_ARRAY_START
, NULL
, 0);
305 TRY(json_test_and_skip(f
, '['));
309 SET_STATE(f
, f
->cur
- 1, "", 0);
310 while (json_cur(f
) != ']') {
312 snprintf(buf
, sizeof(buf
), "[%d]", i
);
314 int current_path_len
= json_append_to_path(f
, buf
, strlen(buf
));
316 f
->path
+ strlen(f
->path
) - strlen(buf
) + 1 /*opening brace*/;
317 f
->cur_name_len
= strlen(buf
) - 2 /*braces*/;
318 TRY(json_parse_value(f
));
319 json_truncate_path(f
, current_path_len
);
320 if (json_cur(f
) == ',') f
->cur
++;
322 TRY(json_test_and_skip(f
, ']'));
323 json_truncate_path(f
, fstate
.path_len
);
324 CALL_BACK(f
, JSON_TYPE_ARRAY_END
, fstate
.ptr
, f
->cur
- fstate
.ptr
);
329 #endif /* JSON_ENABLE_ARRAY */
331 static int json_expect(struct frozen
*f
, const char *s
, int len
,
332 enum json_token_type tok_type
) {
333 int i
, n
= json_left(f
);
334 SET_STATE(f
, f
->cur
, "", 0);
335 for (i
= 0; i
< len
; i
++) {
336 if (i
>= n
) return JSON_STRING_INCOMPLETE
;
337 if (f
->cur
[i
] != s
[i
]) return JSON_STRING_INVALID
;
340 json_truncate_path(f
, fstate
.path_len
);
342 CALL_BACK(f
, tok_type
, fstate
.ptr
, f
->cur
- fstate
.ptr
);
347 /* value = 'null' | 'true' | 'false' | number | string | array | object */
348 static int json_parse_value(struct frozen
*f
) {
349 int ch
= json_cur(f
);
353 TRY(json_parse_string(f
));
356 TRY(json_parse_object(f
));
358 #if JSON_ENABLE_ARRAY
360 TRY(json_parse_array(f
));
364 TRY(json_expect(f
, "null", 4, JSON_TYPE_NULL
));
367 TRY(json_expect(f
, "true", 4, JSON_TYPE_TRUE
));
370 TRY(json_expect(f
, "false", 5, JSON_TYPE_FALSE
));
383 TRY(json_parse_number(f
));
386 return ch
== END_OF_STRING
? JSON_STRING_INCOMPLETE
: JSON_STRING_INVALID
;
392 /* key = identifier | string */
393 static int json_parse_key(struct frozen
*f
) {
394 int ch
= json_cur(f
);
395 if (json_isalpha(ch
)) {
396 TRY(json_parse_identifier(f
));
397 } else if (ch
== '"') {
398 TRY(json_parse_string(f
));
400 return ch
== END_OF_STRING
? JSON_STRING_INCOMPLETE
: JSON_STRING_INVALID
;
405 /* pair = key ':' value */
406 static int json_parse_pair(struct frozen
*f
) {
407 int current_path_len
;
409 json_skip_whitespaces(f
);
411 TRY(json_parse_key(f
));
413 f
->cur_name
= *tok
== '"' ? tok
+ 1 : tok
;
414 f
->cur_name_len
= *tok
== '"' ? f
->cur
- tok
- 2 : f
->cur
- tok
;
415 current_path_len
= json_append_to_path(f
, f
->cur_name
, f
->cur_name_len
);
417 TRY(json_test_and_skip(f
, ':'));
418 TRY(json_parse_value(f
));
419 json_truncate_path(f
, current_path_len
);
423 /* object = '{' pair { ',' pair } '}' */
424 static int json_parse_object(struct frozen
*f
) {
425 CALL_BACK(f
, JSON_TYPE_OBJECT_START
, NULL
, 0);
426 TRY(json_test_and_skip(f
, '{'));
428 SET_STATE(f
, f
->cur
- 1, ".", 1);
429 while (json_cur(f
) != '}') {
430 TRY(json_parse_pair(f
));
431 if (json_cur(f
) == ',') f
->cur
++;
433 TRY(json_test_and_skip(f
, '}'));
434 json_truncate_path(f
, fstate
.path_len
);
435 CALL_BACK(f
, JSON_TYPE_OBJECT_END
, fstate
.ptr
, f
->cur
- fstate
.ptr
);
440 static int json_doit(struct frozen
*f
) {
441 if (f
->cur
== 0 || f
->end
< f
->cur
) return JSON_STRING_INVALID
;
442 if (f
->end
== f
->cur
) return JSON_STRING_INCOMPLETE
;
443 return json_parse_value(f
);
446 int json_escape(struct json_out
*out
, const char *p
, size_t len
) WEAK
;
447 int json_escape(struct json_out
*out
, const char *str
, size_t str_len
) {
449 const char *hex_digits
= "0123456789abcdef";
450 const char *specials
= "btnvfr";
452 for (i
= 0; i
< str_len
; i
++) {
453 unsigned char ch
= ((unsigned char *) str
)[i
];
454 if (ch
== '"' || ch
== '\\') {
455 n
+= out
->printer(out
, "\\", 1);
456 n
+= out
->printer(out
, str
+ i
, 1);
457 } else if (ch
>= '\b' && ch
<= '\r') {
458 n
+= out
->printer(out
, "\\", 1);
459 n
+= out
->printer(out
, &specials
[ch
- '\b'], 1);
460 } else if (c_isprint(ch
)) {
461 n
+= out
->printer(out
, str
+ i
, 1);
462 } else if ((cl
= json_get_utf8_char_len(ch
)) == 1) {
463 n
+= out
->printer(out
, "\\u00", 4);
464 n
+= out
->printer(out
, &hex_digits
[(ch
>> 4) % 0xf], 1);
465 n
+= out
->printer(out
, &hex_digits
[ch
% 0xf], 1);
467 n
+= out
->printer(out
, str
+ i
, cl
);
475 int json_printer_buf(struct json_out
*out
, const char *buf
, size_t len
) WEAK
;
476 int json_printer_buf(struct json_out
*out
, const char *buf
, size_t len
) {
477 size_t avail
= out
->u
.buf
.size
- out
->u
.buf
.len
;
478 size_t n
= len
< avail
? len
: avail
;
479 memcpy(out
->u
.buf
.buf
+ out
->u
.buf
.len
, buf
, n
);
481 if (out
->u
.buf
.size
> 0) {
482 size_t idx
= out
->u
.buf
.len
;
483 if (idx
>= out
->u
.buf
.size
) idx
= out
->u
.buf
.size
- 1;
484 out
->u
.buf
.buf
[idx
] = '\0';
489 int json_printer_file(struct json_out
*out
, const char *buf
, size_t len
) WEAK
;
490 int json_printer_file(struct json_out
*out
, const char *buf
, size_t len
) {
491 return fwrite(buf
, 1, len
, out
->u
.fp
);
494 #if JSON_ENABLE_BASE64
495 static int b64idx(int c
) {
503 return c
== 62 ? '+' : '/';
507 static int b64rev(int c
) {
508 if (c
>= 'A' && c
<= 'Z') {
510 } else if (c
>= 'a' && c
<= 'z') {
512 } else if (c
>= '0' && c
<= '9') {
514 } else if (c
== '+') {
516 } else if (c
== '/') {
523 static int b64enc(struct json_out
*out
, const unsigned char *p
, int n
) {
526 for (i
= 0; i
< n
; i
+= 3) {
527 int a
= p
[i
], b
= i
+ 1 < n
? p
[i
+ 1] : 0, c
= i
+ 2 < n
? p
[i
+ 2] : 0;
528 buf
[0] = b64idx(a
>> 2);
529 buf
[1] = b64idx((a
& 3) << 4 | (b
>> 4));
530 buf
[2] = b64idx((b
& 15) << 2 | (c
>> 6));
531 buf
[3] = b64idx(c
& 63);
532 if (i
+ 1 >= n
) buf
[2] = '=';
533 if (i
+ 2 >= n
) buf
[3] = '=';
534 len
+= out
->printer(out
, buf
, sizeof(buf
));
539 static int b64dec(const char *src
, int n
, char *dst
) {
540 const char *end
= src
+ n
;
542 while (src
+ 3 < end
) {
543 int a
= b64rev(src
[0]), b
= b64rev(src
[1]), c
= b64rev(src
[2]),
545 dst
[len
++] = (a
<< 2) | (b
>> 4);
547 dst
[len
++] = (b
<< 4) | (c
>> 2);
549 dst
[len
++] = (c
<< 6) | d
;
556 #endif /* JSON_ENABLE_BASE64 */
558 static unsigned char hexdec(const char *s
) {
559 #define HEXTOI(x) (x >= '0' && x <= '9' ? x - '0' : x - 'W')
560 int a
= c_tolower(*(const unsigned char *) s
);
561 int b
= c_tolower(*(const unsigned char *)(s
+ 1));
562 return (HEXTOI(a
) << 4) | HEXTOI(b
);
565 int json_vprintf(struct json_out
*out
, const char *fmt
, va_list xap
) WEAK
;
566 int json_vprintf(struct json_out
*out
, const char *fmt
, va_list xap
) {
568 const char *quote
= "\"", *null
= "null";
572 while (*fmt
!= '\0') {
573 if (strchr(":, \r\n\t[]{}\"", *fmt
) != NULL
) {
574 len
+= out
->printer(out
, fmt
, 1);
576 } else if (fmt
[0] == '%') {
580 if (fmt
[1] == 'l' && fmt
[2] == 'l' && (fmt
[3] == 'd' || fmt
[3] == 'u')) {
581 int64_t val
= va_arg(ap
, int64_t);
582 const char *fmt2
= fmt
[3] == 'u' ? "%" UINT64_FMT
: "%" INT64_FMT
;
583 snprintf(buf
, sizeof(buf
), fmt2
, val
);
584 len
+= out
->printer(out
, buf
, strlen(buf
));
586 } else if (fmt
[1] == 'z' && fmt
[2] == 'u') {
587 size_t val
= va_arg(ap
, size_t);
588 snprintf(buf
, sizeof(buf
), "%lu", (unsigned long) val
);
589 len
+= out
->printer(out
, buf
, strlen(buf
));
591 } else if (fmt
[1] == 'M') {
592 json_printf_callback_t f
= va_arg(ap
, json_printf_callback_t
);
594 } else if (fmt
[1] == 'B') {
595 int val
= va_arg(ap
, int);
596 const char *str
= val
? "true" : "false";
597 len
+= out
->printer(out
, str
, strlen(str
));
598 } else if (fmt
[1] == 'H') {
600 const char *hex
= "0123456789abcdef";
601 int i
, n
= va_arg(ap
, int);
602 const unsigned char *p
= va_arg(ap
, const unsigned char *);
603 len
+= out
->printer(out
, quote
, 1);
604 for (i
= 0; i
< n
; i
++) {
605 len
+= out
->printer(out
, &hex
[(p
[i
] >> 4) & 0xf], 1);
606 len
+= out
->printer(out
, &hex
[p
[i
] & 0xf], 1);
608 len
+= out
->printer(out
, quote
, 1);
609 #endif /* JSON_ENABLE_HEX */
610 } else if (fmt
[1] == 'V') {
611 #if JSON_ENABLE_BASE64
612 const unsigned char *p
= va_arg(ap
, const unsigned char *);
613 int n
= va_arg(ap
, int);
614 len
+= out
->printer(out
, quote
, 1);
615 len
+= b64enc(out
, p
, n
);
616 len
+= out
->printer(out
, quote
, 1);
617 #endif /* JSON_ENABLE_BASE64 */
618 } else if (fmt
[1] == 'Q' ||
619 (fmt
[1] == '.' && fmt
[2] == '*' && fmt
[3] == 'Q')) {
624 l
= (size_t) va_arg(ap
, int);
627 p
= va_arg(ap
, char *);
630 len
+= out
->printer(out
, null
, 4);
635 len
+= out
->printer(out
, quote
, 1);
636 len
+= json_escape(out
, p
, l
);
637 len
+= out
->printer(out
, quote
, 1);
641 * we delegate printing to the system printf.
642 * The goal here is to delegate all modifiers parsing to the system
643 * printf, as you can see below we still have to parse the format
646 * Currently, %s with strings longer than 20 chars will require
647 * double-buffering (an auxiliary buffer will be allocated from heap).
648 * TODO(dfrank): reimplement %s and %.*s in order to avoid that.
651 const char *end_of_format_specifier
= "sdfFeEgGlhuIcx.*-0123456789";
652 int n
= strspn(fmt
+ 1, end_of_format_specifier
);
654 int need_len
, size
= sizeof(buf
);
658 n
+ 1 > (int) sizeof(fmt2
) ? sizeof(fmt2
) : (size_t) n
+ 1);
661 va_copy(ap_copy
, ap
);
662 need_len
= vsnprintf(pbuf
, size
, fmt2
, ap_copy
);
667 * Windows & eCos vsnprintf implementation return -1 on overflow
668 * instead of needed size.
671 while (need_len
< 0) {
674 if ((pbuf
= (char *) malloc(size
)) == NULL
) break;
675 va_copy(ap_copy
, ap
);
676 need_len
= vsnprintf(pbuf
, size
, fmt2
, ap_copy
);
679 } else if (need_len
>= (int) sizeof(buf
)) {
681 * resulting string doesn't fit into a stack-allocated buffer `buf`,
682 * so we need to allocate a new buffer from heap and use it
684 if ((pbuf
= (char *) malloc(need_len
+ 1)) != NULL
) {
685 va_copy(ap_copy
, ap
);
686 vsnprintf(pbuf
, need_len
+ 1, fmt2
, ap_copy
);
696 * however we need to parse the type ourselves in order to advance
697 * the va_list by the correct amount; there is no portable way to
698 * inherit the advancement made by vprintf.
699 * 32-bit (linux or windows) passes va_list by value.
701 if ((n
+ 1 == strlen("%" PRId64
) && strcmp(fmt2
, "%" PRId64
) == 0) ||
702 (n
+ 1 == strlen("%" PRIu64
) && strcmp(fmt2
, "%" PRIu64
) == 0)) {
703 (void) va_arg(ap
, int64_t);
704 } else if (strcmp(fmt2
, "%.*s") == 0) {
705 (void) va_arg(ap
, int);
706 (void) va_arg(ap
, char *);
711 (void) va_arg(ap
, int);
715 (void) va_arg(ap
, double);
718 (void) va_arg(ap
, void *);
721 /* many types are promoted to int */
722 (void) va_arg(ap
, int);
726 len
+= out
->printer(out
, pbuf
, strlen(pbuf
));
729 /* If buffer was allocated from heap, free it */
736 } else if (*fmt
== '_' || json_isalpha(*fmt
)) {
737 len
+= out
->printer(out
, quote
, 1);
738 while (*fmt
== '_' || json_isalpha(*fmt
) || json_isdigit(*fmt
)) {
739 len
+= out
->printer(out
, fmt
, 1);
742 len
+= out
->printer(out
, quote
, 1);
744 len
+= out
->printer(out
, fmt
, 1);
753 int json_printf(struct json_out
*out
, const char *fmt
, ...) WEAK
;
754 int json_printf(struct json_out
*out
, const char *fmt
, ...) {
758 n
= json_vprintf(out
, fmt
, ap
);
763 int json_printf_array(struct json_out
*out
, va_list *ap
) WEAK
;
764 int json_printf_array(struct json_out
*out
, va_list *ap
) {
766 char *arr
= va_arg(*ap
, char *);
767 size_t i
, arr_size
= va_arg(*ap
, size_t);
768 size_t elem_size
= va_arg(*ap
, size_t);
769 const char *fmt
= va_arg(*ap
, char *);
770 len
+= json_printf(out
, "[", 1);
771 for (i
= 0; arr
!= NULL
&& i
< arr_size
/ elem_size
; i
++) {
776 memcpy(&val
, arr
+ i
* elem_size
,
777 elem_size
> sizeof(val
) ? sizeof(val
) : elem_size
);
778 if (i
> 0) len
+= json_printf(out
, ", ");
779 if (strpbrk(fmt
, "efg") != NULL
) {
780 len
+= json_printf(out
, fmt
, val
.d
);
782 len
+= json_printf(out
, fmt
, val
.i
);
785 len
+= json_printf(out
, "]", 1);
790 int cs_win_vsnprintf(char *str
, size_t size
, const char *format
, va_list ap
) WEAK
;
791 int cs_win_vsnprintf(char *str
, size_t size
, const char *format
, va_list ap
) {
792 int res
= _vsnprintf(str
, size
, format
, ap
);
795 str
[size
- 1] = '\0';
800 int cs_win_snprintf(char *str
, size_t size
, const char *format
, ...) WEAK
;
801 int cs_win_snprintf(char *str
, size_t size
, const char *format
, ...) {
804 va_start(ap
, format
);
805 res
= vsnprintf(str
, size
, format
, ap
);
811 int json_walk(const char *json_string
, int json_string_length
,
812 json_walk_callback_t callback
, void *callback_data
) WEAK
;
813 int json_walk(const char *json_string
, int json_string_length
,
814 json_walk_callback_t callback
, void *callback_data
) {
815 struct frozen frozen
;
817 memset(&frozen
, 0, sizeof(frozen
));
818 frozen
.end
= json_string
+ json_string_length
;
819 frozen
.cur
= json_string
;
820 frozen
.callback_data
= callback_data
;
821 frozen
.callback
= callback
;
823 TRY(json_doit(&frozen
));
825 return frozen
.cur
- json_string
;
828 struct scan_array_info
{
830 char path
[JSON_MAX_PATH_LEN
];
831 struct json_token
*token
;
834 static void json_scanf_array_elem_cb(void *callback_data
, const char *name
,
835 size_t name_len
, const char *path
,
836 const struct json_token
*token
) {
837 struct scan_array_info
*info
= (struct scan_array_info
*) callback_data
;
842 if (strcmp(path
, info
->path
) == 0) {
843 *info
->token
= *token
;
848 int json_scanf_array_elem(const char *s
, int len
, const char *path
, int idx
,
849 struct json_token
*token
) WEAK
;
850 int json_scanf_array_elem(const char *s
, int len
, const char *path
, int idx
,
851 struct json_token
*token
) {
852 struct scan_array_info info
;
855 memset(token
, 0, sizeof(*token
));
856 snprintf(info
.path
, sizeof(info
.path
), "%s[%d]", path
, idx
);
857 json_walk(s
, len
, json_scanf_array_elem_cb
, &info
);
858 return info
.found
? token
->len
: -1;
861 struct json_scanf_info
{
870 int json_unescape(const char *src
, int slen
, char *dst
, int dlen
) WEAK
;
871 int json_unescape(const char *src
, int slen
, char *dst
, int dlen
) {
872 if (dst
== NULL
|| dlen
== 0)
873 return JSON_STRING_INVALID
;
875 char *send
= (char *) src
+ slen
;
876 char *dend
= dst
+ dlen
;
877 char *orig_dst
= dst
;
879 const char *esc1
= "\"\\/bfnrt", *esc2
= "\"\\/\b\f\n\r\t";
883 if (++src
>= send
) { return JSON_STRING_INCOMPLETE
; }
886 if (send
- src
< 5) { return JSON_STRING_INCOMPLETE
; }
887 /* Here we go: this is a \u.... escape. Process simple one-byte chars */
888 if (src
[1] == '0' && src
[2] == '0') {
889 /* This is \u00xx character from the ASCII range */
890 if (dst
< dend
) *dst
= hexdec(src
+ 3);
893 /* Complex \uXXXX escapes drag utf8 lib... Do it at some stage */
894 return JSON_STRING_INVALID
;
896 } else if ((p
= (char *) strchr(esc1
, *src
)) != NULL
) {
898 *dst
= esc2
[p
- esc1
];
901 return JSON_STRING_INVALID
;
912 return dst
- orig_dst
;
915 static void json_scanf_cb(void *callback_data
, const char *name
,
916 size_t name_len
, const char *path
,
917 const struct json_token
*token
) {
918 struct json_scanf_info
*info
= (struct json_scanf_info
*) callback_data
;
919 char buf
[32]; /* Must be enough to hold numbers */
924 if (token
->ptr
== NULL
) {
926 * We're not interested here in the events for which we have no value;
927 * namely, JSON_TYPE_OBJECT_START and JSON_TYPE_ARRAY_START
932 if (strcmp(path
, info
->path
) != 0) {
933 /* It's not the path we're looking for, so, just ignore this callback */
937 switch (info
->type
) {
939 info
->num_conversions
++;
940 switch (sizeof(bool)) {
942 *(char *) info
->target
= (token
->type
== JSON_TYPE_TRUE
? 1 : 0);
945 *(int *) info
->target
= (token
->type
== JSON_TYPE_TRUE
? 1 : 0);
948 /* should never be here */
956 } u
= {info
->target
};
957 info
->num_conversions
++;
958 u
.f(token
->ptr
, token
->len
, info
->user_data
);
962 char **dst
= (char **) info
->target
;
963 if (token
->type
== JSON_TYPE_NULL
) {
966 int unescaped_len
= json_unescape(token
->ptr
, token
->len
, NULL
, 0);
967 if (unescaped_len
>= 0 &&
968 (*dst
= (char *) malloc(unescaped_len
+ 1)) != NULL
) {
969 info
->num_conversions
++;
970 if (json_unescape(token
->ptr
, token
->len
, *dst
, unescaped_len
) ==
972 (*dst
)[unescaped_len
] = '\0';
983 char **dst
= (char **) info
->user_data
;
984 int i
, len
= token
->len
/ 2;
985 *(int *) info
->target
= len
;
986 if ((*dst
= (char *) malloc(len
+ 1)) != NULL
) {
987 for (i
= 0; i
< len
; i
++) {
988 (*dst
)[i
] = hexdec(token
->ptr
+ 2 * i
);
991 info
->num_conversions
++;
993 #endif /* JSON_ENABLE_HEX */
997 #if JSON_ENABLE_BASE64
998 char **dst
= (char **) info
->target
;
999 int len
= token
->len
* 4 / 3 + 2;
1000 if ((*dst
= (char *) malloc(len
+ 1)) != NULL
) {
1001 int n
= b64dec(token
->ptr
, token
->len
, *dst
);
1003 *(int *) info
->user_data
= n
;
1004 info
->num_conversions
++;
1006 #endif /* JSON_ENABLE_BASE64 */
1010 info
->num_conversions
++;
1011 *(struct json_token
*) info
->target
= *token
;
1014 if (token
->len
>= (int) sizeof(buf
)) break;
1015 /* Before converting, copy into tmp buffer in order to 0-terminate it */
1016 memcpy(buf
, token
->ptr
, token
->len
);
1017 buf
[token
->len
] = '\0';
1018 /* NB: Use of base 0 for %d, %ld, %u and %lu is intentional. */
1019 if (info
->fmt
[1] == 'd' || (info
->fmt
[1] == 'l' && info
->fmt
[2] == 'd') ||
1020 info
->fmt
[1] == 'i') {
1021 char *endptr
= NULL
;
1022 long r
= strtol(buf
, &endptr
, 0 /* base */);
1023 if (*endptr
== '\0') {
1024 if (info
->fmt
[1] == 'l') {
1025 *((long *) info
->target
) = r
;
1027 *((int *) info
->target
) = (int) r
;
1029 info
->num_conversions
++;
1031 } else if (info
->fmt
[1] == 'u' ||
1032 (info
->fmt
[1] == 'l' && info
->fmt
[2] == 'u')) {
1033 char *endptr
= NULL
;
1034 unsigned long r
= strtoul(buf
, &endptr
, 0 /* base */);
1035 if (*endptr
== '\0') {
1036 if (info
->fmt
[1] == 'l') {
1037 *((unsigned long *) info
->target
) = r
;
1039 *((unsigned int *) info
->target
) = (unsigned int) r
;
1041 info
->num_conversions
++;
1045 info
->num_conversions
+= sscanf(buf
, info
->fmt
, info
->target
);
1052 int json_vscanf(const char *str
, int len
, const char *fmt
, va_list ap
) WEAK
;
1053 int json_vscanf(const char *str
, int len
, const char *fmt
, va_list ap
) {
1054 char path
[JSON_MAX_PATH_LEN
] = "", fmtbuf
[20];
1057 struct json_scanf_info info
= {0, path
, fmtbuf
, NULL
, NULL
, 0};
1059 while (fmt
[i
] != '\0') {
1060 if (fmt
[i
] == '{') {
1063 } else if (fmt
[i
] == '}') {
1064 if ((p
= strrchr(path
, '.')) != NULL
) * p
= '\0';
1066 } else if (fmt
[i
] == '%') {
1067 info
.target
= va_arg(ap
, void *);
1068 info
.type
= fmt
[i
+ 1];
1069 switch (fmt
[i
+ 1]) {
1073 info
.user_data
= va_arg(ap
, void *);
1081 const char *delims
= ", \t\r\n]}";
1082 int conv_len
= strcspn(fmt
+ i
+ 1, delims
) + 1;
1083 memcpy(fmtbuf
, fmt
+ i
, conv_len
);
1084 fmtbuf
[conv_len
] = '\0';
1086 i
+= strspn(fmt
+ i
, delims
);
1090 json_walk(str
, len
, json_scanf_cb
, &info
);
1091 } else if (json_isalpha(fmt
[i
]) || json_get_utf8_char_len(fmt
[i
]) > 1) {
1093 const char *delims
= ": \r\n\t";
1094 int key_len
= strcspn(&fmt
[i
], delims
);
1095 if ((p
= strrchr(path
, '.')) != NULL
) p
[1] = '\0';
1096 pe
= path
+ strlen(path
);
1097 memcpy(pe
, fmt
+ i
, key_len
);
1099 i
+= key_len
+ strspn(fmt
+ i
+ key_len
, delims
);
1104 return info
.num_conversions
;
1107 int json_scanf(const char *str
, int len
, const char *fmt
, ...) WEAK
;
1108 int json_scanf(const char *str
, int len
, const char *fmt
, ...) {
1112 result
= json_vscanf(str
, len
, fmt
, ap
);
1117 int json_vfprintf(const char *file_name
, const char *fmt
, va_list ap
) WEAK
;
1118 int json_vfprintf(const char *file_name
, const char *fmt
, va_list ap
) {
1120 FILE *fp
= fopen(file_name
, "wb");
1122 struct json_out out
= JSON_OUT_FILE(fp
);
1123 res
= json_vprintf(&out
, fmt
, ap
);
1130 int json_fprintf(const char *file_name
, const char *fmt
, ...) WEAK
;
1131 int json_fprintf(const char *file_name
, const char *fmt
, ...) {
1135 result
= json_vfprintf(file_name
, fmt
, ap
);
1140 char *json_fread(const char *path
) WEAK
;
1141 char *json_fread(const char *path
) {
1144 if ((fp
= fopen(path
, "rb")) == NULL
) {
1145 } else if (fseek(fp
, 0, SEEK_END
) != 0) {
1148 long size
= ftell(fp
);
1149 if (size
> 0 && (data
= (char *) malloc(size
+ 1)) != NULL
) {
1150 fseek(fp
, 0, SEEK_SET
); /* Some platforms might not have rewind(), Oo */
1151 if (fread(data
, 1, size
, fp
) != (size_t) size
) {
1163 struct json_setf_data
{
1164 const char *json_path
;
1165 const char *base
; /* Pointer to the source JSON string */
1166 int matched
; /* Matched part of json_path */
1167 int pos
; /* Offset of the mutated value begin */
1168 int end
; /* Offset of the mutated value end */
1169 int prev
; /* Offset of the previous token end */
1172 static int get_matched_prefix_len(const char *s1
, const char *s2
) {
1174 while (s1
[i
] && s2
[i
] && s1
[i
] == s2
[i
]) i
++;
1178 static void json_vsetf_cb(void *userdata
, const char *name
, size_t name_len
,
1179 const char *path
, const struct json_token
*t
) {
1180 struct json_setf_data
*data
= (struct json_setf_data
*) userdata
;
1181 int off
, len
= get_matched_prefix_len(path
, data
->json_path
);
1182 if (t
->ptr
== NULL
) return;
1183 off
= t
->ptr
- data
->base
;
1184 if (len
> data
->matched
) data
->matched
= len
;
1187 * If there is no exact path match, set the mutation position to tbe end
1188 * of the object or array
1190 if (len
< data
->matched
&& data
->pos
== 0 &&
1191 (t
->type
== JSON_TYPE_OBJECT_END
|| t
->type
== JSON_TYPE_ARRAY_END
)) {
1192 data
->pos
= data
->end
= data
->prev
;
1195 /* Exact path match. Set mutation position to the value of this token */
1196 if (strcmp(path
, data
->json_path
) == 0 && t
->type
!= JSON_TYPE_OBJECT_START
&&
1197 t
->type
!= JSON_TYPE_ARRAY_START
) {
1199 data
->end
= off
+ t
->len
;
1203 * For deletion, we need to know where the previous value ends, because
1204 * we don't know where matched value key starts.
1205 * When the mutation position is not yet set, remember each value end.
1206 * When the mutation position is already set, but it is at the beginning
1207 * of the object/array, we catch the end of the object/array and see
1208 * whether the object/array start is closer then previously stored prev.
1210 if (data
->pos
== 0) {
1211 data
->prev
= off
+ t
->len
; /* pos is not yet set */
1212 } else if ((t
->ptr
[0] == '[' || t
->ptr
[0] == '{') && off
+ 1 < data
->pos
&&
1213 off
+ 1 > data
->prev
) {
1214 data
->prev
= off
+ 1;
1220 int json_vsetf(const char *s
, int len
, struct json_out
*out
,
1221 const char *json_path
, const char *json_fmt
, va_list ap
) WEAK
;
1222 int json_vsetf(const char *s
, int len
, struct json_out
*out
,
1223 const char *json_path
, const char *json_fmt
, va_list ap
) {
1224 struct json_setf_data data
;
1225 memset(&data
, 0, sizeof(data
));
1226 data
.json_path
= json_path
;
1229 json_walk(s
, len
, json_vsetf_cb
, &data
);
1230 if (json_fmt
== NULL
) {
1231 /* Deletion codepath */
1232 json_printf(out
, "%.*s", data
.prev
, s
);
1233 /* Trim comma after the value that begins at object/array start */
1234 if (s
[data
.prev
- 1] == '{' || s
[data
.prev
- 1] == '[') {
1236 while (i
< len
&& json_isspace(s
[i
])) i
++;
1237 if (s
[i
] == ',') data
.end
= i
+ 1; /* Point after comma */
1239 json_printf(out
, "%.*s", len
- data
.end
, s
+ data
.end
);
1241 /* Modification codepath */
1242 int n
, off
= data
.matched
, depth
= 0;
1244 /* Print the unchanged beginning */
1245 json_printf(out
, "%.*s", data
.pos
, s
);
1247 /* Add missing keys */
1248 while ((n
= strcspn(&json_path
[off
], ".[")) > 0) {
1249 if (s
[data
.prev
- 1] != '{' && s
[data
.prev
- 1] != '[' && depth
== 0) {
1250 json_printf(out
, ",");
1252 if (off
> 0 && json_path
[off
- 1] != '.') break;
1253 json_printf(out
, "%.*Q:", n
, json_path
+ off
);
1255 if (json_path
[off
] != '\0') {
1256 json_printf(out
, "%c", json_path
[off
] == '.' ? '{' : '[');
1261 /* Print the new value */
1262 json_vprintf(out
, json_fmt
, ap
);
1264 /* Close brackets/braces of the added missing keys */
1265 for (; off
> data
.matched
; off
--) {
1266 int ch
= json_path
[off
];
1267 const char *p
= ch
== '.' ? "}" : ch
== '[' ? "]" : "";
1268 json_printf(out
, "%s", p
);
1271 /* Print the rest of the unchanged string */
1272 json_printf(out
, "%.*s", len
- data
.end
, s
+ data
.end
);
1274 return data
.end
> data
.pos
? 1 : 0;
1277 int json_setf(const char *s
, int len
, struct json_out
*out
,
1278 const char *json_path
, const char *json_fmt
, ...) WEAK
;
1279 int json_setf(const char *s
, int len
, struct json_out
*out
,
1280 const char *json_path
, const char *json_fmt
, ...) {
1283 va_start(ap
, json_fmt
);
1284 result
= json_vsetf(s
, len
, out
, json_path
, json_fmt
, ap
);
1289 struct prettify_data
{
1290 struct json_out
*out
;
1295 static void indent(struct json_out
*out
, int level
) {
1296 while (level
-- > 0) out
->printer(out
, " ", 2);
1299 static void print_key(struct prettify_data
*pd
, const char *path
,
1300 const char *name
, int name_len
) {
1301 if (pd
->last_token
!= JSON_TYPE_INVALID
&&
1302 pd
->last_token
!= JSON_TYPE_ARRAY_START
&&
1303 pd
->last_token
!= JSON_TYPE_OBJECT_START
) {
1304 pd
->out
->printer(pd
->out
, ",", 1);
1306 if (path
[0] != '\0') pd
->out
->printer(pd
->out
, "\n", 1);
1307 indent(pd
->out
, pd
->level
);
1308 if (path
[0] != '\0' && path
[strlen(path
) - 1] != ']') {
1309 pd
->out
->printer(pd
->out
, "\"", 1);
1310 pd
->out
->printer(pd
->out
, name
, (int) name_len
);
1311 pd
->out
->printer(pd
->out
, "\"", 1);
1312 pd
->out
->printer(pd
->out
, ": ", 2);
1316 static void prettify_cb(void *userdata
, const char *name
, size_t name_len
,
1317 const char *path
, const struct json_token
*t
) {
1318 struct prettify_data
*pd
= (struct prettify_data
*) userdata
;
1320 case JSON_TYPE_OBJECT_START
:
1321 case JSON_TYPE_ARRAY_START
:
1322 print_key(pd
, path
, name
, name_len
);
1323 pd
->out
->printer(pd
->out
, t
->type
== JSON_TYPE_ARRAY_START
? "[" : "{",
1327 case JSON_TYPE_OBJECT_END
:
1328 case JSON_TYPE_ARRAY_END
:
1330 if (pd
->last_token
!= JSON_TYPE_INVALID
&&
1331 pd
->last_token
!= JSON_TYPE_ARRAY_START
&&
1332 pd
->last_token
!= JSON_TYPE_OBJECT_START
) {
1333 pd
->out
->printer(pd
->out
, "\n", 1);
1334 indent(pd
->out
, pd
->level
);
1336 pd
->out
->printer(pd
->out
, t
->type
== JSON_TYPE_ARRAY_END
? "]" : "}", 1);
1338 case JSON_TYPE_NUMBER
:
1339 case JSON_TYPE_NULL
:
1340 case JSON_TYPE_TRUE
:
1341 case JSON_TYPE_FALSE
:
1342 case JSON_TYPE_STRING
:
1343 print_key(pd
, path
, name
, name_len
);
1344 if (t
->type
== JSON_TYPE_STRING
) pd
->out
->printer(pd
->out
, "\"", 1);
1345 pd
->out
->printer(pd
->out
, t
->ptr
, t
->len
);
1346 if (t
->type
== JSON_TYPE_STRING
) pd
->out
->printer(pd
->out
, "\"", 1);
1351 pd
->last_token
= t
->type
;
1354 int json_prettify(const char *s
, int len
, struct json_out
*out
) WEAK
;
1355 int json_prettify(const char *s
, int len
, struct json_out
*out
) {
1356 struct prettify_data pd
= {out
, 0, JSON_TYPE_INVALID
};
1357 return json_walk(s
, len
, prettify_cb
, &pd
);
1360 int json_prettify_file(const char *file_name
) WEAK
;
1361 int json_prettify_file(const char *file_name
) {
1363 char *s
= json_fread(file_name
);
1365 if (s
!= NULL
&& (fp
= fopen(file_name
, "wb")) != NULL
) {
1366 struct json_out out
= JSON_OUT_FILE(fp
);
1367 res
= json_prettify(s
, strlen(s
), &out
);
1369 /* On error, restore the old content */
1371 fp
= fopen(file_name
, "wb");
1372 fseek(fp
, 0, SEEK_SET
);
1373 fwrite(s
, 1, strlen(s
), fp
);
1384 void *handle
; // Passed handle. Changed if a next entry is found
1385 const char *path
; // Path to the iterated object/array
1386 int path_len
; // Path length - optimisation
1387 int found
; // Non-0 if found the next entry
1388 struct json_token
*key
; // Object's key
1389 struct json_token
*val
; // Object's value
1390 int *idx
; // Array index
1393 static void next_set_key(struct next_data
*d
, const char *name
, int name_len
,
1396 /* Array. Set index and reset key */
1397 if (d
->key
!= NULL
) {
1401 if (d
->idx
!= NULL
) *d
->idx
= atoi(name
);
1403 /* Object. Set key and make index -1 */
1404 if (d
->key
!= NULL
) {
1406 d
->key
->len
= name_len
;
1408 if (d
->idx
!= NULL
) *d
->idx
= -1;
1412 static void json_next_cb(void *userdata
, const char *name
, size_t name_len
,
1413 const char *path
, const struct json_token
*t
) {
1414 struct next_data
*d
= (struct next_data
*) userdata
;
1415 const char *p
= path
+ d
->path_len
;
1416 if (d
->found
) return;
1417 if (d
->path_len
>= (int) strlen(path
)) return;
1418 if (strncmp(d
->path
, path
, d
->path_len
) != 0) return;
1419 if (strchr(p
+ 1, '.') != NULL
) return; /* More nested objects - skip */
1420 if (strchr(p
+ 1, '[') != NULL
) return; /* Ditto for arrays */
1421 // {OBJECT,ARRAY}_END types do not pass name, _START does. Save key.
1422 if (t
->type
== JSON_TYPE_OBJECT_START
|| t
->type
== JSON_TYPE_ARRAY_START
) {
1423 next_set_key(d
, name
, name_len
, p
[0] == '[');
1424 } else if (d
->handle
== NULL
|| d
->handle
< (void *) t
->ptr
) {
1425 if (t
->type
!= JSON_TYPE_OBJECT_END
&& t
->type
!= JSON_TYPE_ARRAY_END
) {
1426 next_set_key(d
, name
, name_len
, p
[0] == '[');
1428 if (d
->val
!= NULL
) *d
->val
= *t
;
1429 d
->handle
= (void *) t
->ptr
;
1434 static void *json_next(const char *s
, int len
, void *handle
, const char *path
,
1435 struct json_token
*key
, struct json_token
*val
, int *i
) {
1436 struct json_token tmpval
;
1437 struct json_token
*v
= val
== NULL
? &tmpval
: val
;
1438 struct json_token tmpkey
;
1439 struct json_token
*k
= key
== NULL
? &tmpkey
: key
;
1441 int *pidx
= i
== NULL
? &tmpidx
: i
;
1442 struct next_data data
= {handle
, path
, (int) strlen(path
), 0, k
, v
, pidx
};
1443 json_walk(s
, len
, json_next_cb
, &data
);
1444 return data
.found
? data
.handle
: NULL
;
1447 void *json_next_key(const char *s
, int len
, void *handle
, const char *path
,
1448 struct json_token
*key
, struct json_token
*val
) WEAK
;
1449 void *json_next_key(const char *s
, int len
, void *handle
, const char *path
,
1450 struct json_token
*key
, struct json_token
*val
) {
1451 return json_next(s
, len
, handle
, path
, key
, val
, NULL
);
1454 void *json_next_elem(const char *s
, int len
, void *handle
, const char *path
,
1455 int *idx
, struct json_token
*val
) WEAK
;
1456 void *json_next_elem(const char *s
, int len
, void *handle
, const char *path
,
1457 int *idx
, struct json_token
*val
) {
1458 return json_next(s
, len
, handle
, path
, NULL
, val
, idx
);
1461 static int json_sprinter(struct json_out
*out
, const char *str
, size_t len
) {
1462 size_t old_len
= out
->u
.buf
.buf
== NULL
? 0 : strlen(out
->u
.buf
.buf
);
1463 size_t new_len
= len
+ old_len
;
1464 char *p
= (char *) realloc(out
->u
.buf
.buf
, new_len
+ 1);
1466 memcpy(p
+ old_len
, str
, len
);
1473 char *json_vasprintf(const char *fmt
, va_list ap
) WEAK
;
1474 char *json_vasprintf(const char *fmt
, va_list ap
) {
1475 struct json_out out
;
1476 memset(&out
, 0, sizeof(out
));
1477 out
.printer
= json_sprinter
;
1478 json_vprintf(&out
, fmt
, ap
);
1479 return out
.u
.buf
.buf
;
1482 char *json_asprintf(const char *fmt
, ...) WEAK
;
1483 char *json_asprintf(const char *fmt
, ...) {
1486 char *result
= json_vasprintf(fmt
, ap
);