2 * Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
3 * Copyright (c) 2018 Cesanta Software Limited
6 * Licensed under the Apache License, Version 2.0 (the ""License"");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an ""AS IS"" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 #define _CRT_SECURE_NO_WARNINGS /* Disable deprecation warning in VS2005+ */
28 #define malloc(X) BigBuf_malloc(X)
32 #if (defined(__GNUC__) || defined(__TI_COMPILER_VERSION__)) && !defined(_WIN32)
33 #define WEAK __attribute__((weak))
42 #define snprintf cs_win_snprintf
43 #define vsnprintf cs_win_vsnprintf
44 int cs_win_snprintf(char *str
, size_t size
, const char *format
, ...);
45 int cs_win_vsnprintf(char *str
, size_t size
, const char *format
, va_list ap
);
49 typedef _int64
int64_t;
50 typedef unsigned _int64
uint64_t;
55 /* <inttypes.h> wants this for C++ */
56 #ifndef __STDC_FORMAT_MACROS
57 #define __STDC_FORMAT_MACROS
63 #define INT64_FMT PRId64
66 #define UINT64_FMT PRIu64
70 #define va_copy(x, y) x = y
73 #ifndef JSON_ENABLE_ARRAY
74 #define JSON_ENABLE_ARRAY 1
84 /* For callback API */
85 char path
[JSON_MAX_PATH_LEN
];
88 json_walk_callback_t callback
;
96 #define SET_STATE(fr, ptr, str, len) \
97 struct fstate fstate = {(ptr), (fr)->path_len}; \
98 json_append_to_path((fr), (str), (len));
100 #define CALL_BACK(fr, tok, value, len) \
102 if ((fr)->callback && \
103 ((fr)->path_len == 0 || (fr)->path[(fr)->path_len - 1] != '.')) { \
104 struct json_token t = {(value), (int) (len), (tok)}; \
106 /* Call the callback with the given value and current name */ \
107 (fr)->callback((fr)->callback_data, (fr)->cur_name, (fr)->cur_name_len, \
110 /* Reset the name */ \
111 (fr)->cur_name = NULL; \
112 (fr)->cur_name_len = 0; \
116 static int json_append_to_path(struct frozen
*f
, const char *str
, int size
) {
118 int left
= sizeof(f
->path
) - n
- 1;
119 if (size
> left
) size
= left
;
120 memcpy(f
->path
+ n
, str
, size
);
121 f
->path
[n
+ size
] = '\0';
126 static void json_truncate_path(struct frozen
*f
, size_t len
) {
131 static int json_parse_object(struct frozen
*f
);
132 static int json_parse_value(struct frozen
*f
);
134 #define EXPECT(cond, err_code) \
136 if (!(cond)) return (err_code); \
142 if (_n < 0) return _n; \
145 #define END_OF_STRING (-1)
147 static int json_left(const struct frozen
*f
) {
148 return f
->end
- f
->cur
;
151 static int json_isspace(int ch
) {
152 return ch
== ' ' || ch
== '\t' || ch
== '\r' || ch
== '\n';
155 static void json_skip_whitespaces(struct frozen
*f
) {
156 while (f
->cur
< f
->end
&& json_isspace(*f
->cur
)) f
->cur
++;
159 static int json_cur(struct frozen
*f
) {
160 json_skip_whitespaces(f
);
161 return f
->cur
>= f
->end
? END_OF_STRING
: *(unsigned char *) f
->cur
;
164 static int json_test_and_skip(struct frozen
*f
, int expected
) {
165 int ch
= json_cur(f
);
166 if (ch
== expected
) {
170 return ch
== END_OF_STRING
? JSON_STRING_INCOMPLETE
: JSON_STRING_INVALID
;
173 static int json_isalpha(int ch
) {
174 return (ch
>= 'a' && ch
<= 'z') || (ch
>= 'A' && ch
<= 'Z');
177 static int json_isdigit(int ch
) {
178 return ch
>= '0' && ch
<= '9';
181 static int json_isxdigit(int ch
) {
182 return json_isdigit(ch
) || (ch
>= 'a' && ch
<= 'f') ||
183 (ch
>= 'A' && ch
<= 'F');
186 static int json_get_escape_len(const char *s
, int len
) {
189 return len
< 6 ? JSON_STRING_INCOMPLETE
190 : json_isxdigit(s
[1]) && json_isxdigit(s
[2]) &&
191 json_isxdigit(s
[3]) && json_isxdigit(s
[4])
193 : JSON_STRING_INVALID
;
202 return len
< 2 ? JSON_STRING_INCOMPLETE
: 1;
204 return JSON_STRING_INVALID
;
208 /* identifier = letter { letter | digit | '_' } */
209 static int json_parse_identifier(struct frozen
*f
) {
210 EXPECT(json_isalpha(json_cur(f
)), JSON_STRING_INVALID
);
212 SET_STATE(f
, f
->cur
, "", 0);
213 while (f
->cur
< f
->end
&&
214 (*f
->cur
== '_' || json_isalpha(*f
->cur
) || json_isdigit(*f
->cur
))) {
217 json_truncate_path(f
, fstate
.path_len
);
218 CALL_BACK(f
, JSON_TYPE_STRING
, fstate
.ptr
, f
->cur
- fstate
.ptr
);
223 static int json_get_utf8_char_len(unsigned char ch
) {
224 if ((ch
& 0x80) == 0) return 1;
235 /* string = '"' { quoted_printable_chars } '"' */
236 static int json_parse_string(struct frozen
*f
) {
237 int n
, ch
= 0, len
= 0;
238 TRY(json_test_and_skip(f
, '"'));
240 SET_STATE(f
, f
->cur
, "", 0);
241 for (; f
->cur
< f
->end
; f
->cur
+= len
) {
242 ch
= *(unsigned char *) f
->cur
;
243 len
= json_get_utf8_char_len((unsigned char) ch
);
244 EXPECT(ch
>= 32 && len
> 0, JSON_STRING_INVALID
); /* No control chars */
245 EXPECT(len
<= json_left(f
), JSON_STRING_INCOMPLETE
);
247 EXPECT((n
= json_get_escape_len(f
->cur
+ 1, json_left(f
))) > 0, n
);
249 } else if (ch
== '"') {
250 json_truncate_path(f
, fstate
.path_len
);
251 CALL_BACK(f
, JSON_TYPE_STRING
, fstate
.ptr
, f
->cur
- fstate
.ptr
);
257 return ch
== '"' ? 0 : JSON_STRING_INCOMPLETE
;
260 /* number = [ '-' ] digit+ [ '.' digit+ ] [ ['e'|'E'] ['+'|'-'] digit+ ] */
261 static int json_parse_number(struct frozen
*f
) {
262 int ch
= json_cur(f
);
263 SET_STATE(f
, f
->cur
, "", 0);
264 if (ch
== '-') f
->cur
++;
265 EXPECT(f
->cur
< f
->end
, JSON_STRING_INCOMPLETE
);
266 if (f
->cur
+ 1 < f
->end
&& f
->cur
[0] == '0' && f
->cur
[1] == 'x') {
268 EXPECT(f
->cur
< f
->end
, JSON_STRING_INCOMPLETE
);
269 EXPECT(json_isxdigit(f
->cur
[0]), JSON_STRING_INVALID
);
270 while (f
->cur
< f
->end
&& json_isxdigit(f
->cur
[0])) f
->cur
++;
272 EXPECT(json_isdigit(f
->cur
[0]), JSON_STRING_INVALID
);
273 while (f
->cur
< f
->end
&& json_isdigit(f
->cur
[0])) f
->cur
++;
274 if (f
->cur
< f
->end
&& f
->cur
[0] == '.') {
276 EXPECT(f
->cur
< f
->end
, JSON_STRING_INCOMPLETE
);
277 EXPECT(json_isdigit(f
->cur
[0]), JSON_STRING_INVALID
);
278 while (f
->cur
< f
->end
&& json_isdigit(f
->cur
[0])) f
->cur
++;
280 if (f
->cur
< f
->end
&& (f
->cur
[0] == 'e' || f
->cur
[0] == 'E')) {
282 EXPECT(f
->cur
< f
->end
, JSON_STRING_INCOMPLETE
);
283 if ((f
->cur
[0] == '+' || f
->cur
[0] == '-')) f
->cur
++;
284 EXPECT(f
->cur
< f
->end
, JSON_STRING_INCOMPLETE
);
285 EXPECT(json_isdigit(f
->cur
[0]), JSON_STRING_INVALID
);
286 while (f
->cur
< f
->end
&& json_isdigit(f
->cur
[0])) f
->cur
++;
289 json_truncate_path(f
, fstate
.path_len
);
290 CALL_BACK(f
, JSON_TYPE_NUMBER
, fstate
.ptr
, f
->cur
- fstate
.ptr
);
294 #if JSON_ENABLE_ARRAY
295 /* array = '[' [ value { ',' value } ] ']' */
296 static int json_parse_array(struct frozen
*f
) {
297 int i
= 0, current_path_len
;
299 CALL_BACK(f
, JSON_TYPE_ARRAY_START
, NULL
, 0);
300 TRY(json_test_and_skip(f
, '['));
303 SET_STATE(f
, f
->cur
- 1, "", 0);
304 while (json_cur(f
) != ']') {
305 snprintf(buf
, sizeof(buf
), "[%d]", i
);
307 current_path_len
= json_append_to_path(f
, buf
, strlen(buf
));
309 f
->path
+ strlen(f
->path
) - strlen(buf
) + 1 /*opening brace*/;
310 f
->cur_name_len
= strlen(buf
) - 2 /*braces*/;
311 TRY(json_parse_value(f
));
312 json_truncate_path(f
, current_path_len
);
313 if (json_cur(f
) == ',') f
->cur
++;
315 TRY(json_test_and_skip(f
, ']'));
316 json_truncate_path(f
, fstate
.path_len
);
317 CALL_BACK(f
, JSON_TYPE_ARRAY_END
, fstate
.ptr
, f
->cur
- fstate
.ptr
);
322 #endif /* JSON_ENABLE_ARRAY */
324 static int json_expect(struct frozen
*f
, const char *s
, int len
,
325 enum json_token_type tok_type
) {
326 int i
, n
= json_left(f
);
327 SET_STATE(f
, f
->cur
, "", 0);
328 for (i
= 0; i
< len
; i
++) {
329 if (i
>= n
) return JSON_STRING_INCOMPLETE
;
330 if (f
->cur
[i
] != s
[i
]) return JSON_STRING_INVALID
;
333 json_truncate_path(f
, fstate
.path_len
);
335 CALL_BACK(f
, tok_type
, fstate
.ptr
, f
->cur
- fstate
.ptr
);
340 /* value = 'null' | 'true' | 'false' | number | string | array | object */
341 static int json_parse_value(struct frozen
*f
) {
342 int ch
= json_cur(f
);
346 TRY(json_parse_string(f
));
349 TRY(json_parse_object(f
));
351 #if JSON_ENABLE_ARRAY
353 TRY(json_parse_array(f
));
357 TRY(json_expect(f
, "null", 4, JSON_TYPE_NULL
));
360 TRY(json_expect(f
, "true", 4, JSON_TYPE_TRUE
));
363 TRY(json_expect(f
, "false", 5, JSON_TYPE_FALSE
));
376 TRY(json_parse_number(f
));
379 return ch
== END_OF_STRING
? JSON_STRING_INCOMPLETE
: JSON_STRING_INVALID
;
385 /* key = identifier | string */
386 static int json_parse_key(struct frozen
*f
) {
387 int ch
= json_cur(f
);
388 if (json_isalpha(ch
)) {
389 TRY(json_parse_identifier(f
));
390 } else if (ch
== '"') {
391 TRY(json_parse_string(f
));
393 return ch
== END_OF_STRING
? JSON_STRING_INCOMPLETE
: JSON_STRING_INVALID
;
398 /* pair = key ':' value */
399 static int json_parse_pair(struct frozen
*f
) {
400 int current_path_len
;
402 json_skip_whitespaces(f
);
404 TRY(json_parse_key(f
));
406 f
->cur_name
= *tok
== '"' ? tok
+ 1 : tok
;
407 f
->cur_name_len
= *tok
== '"' ? f
->cur
- tok
- 2 : f
->cur
- tok
;
408 current_path_len
= json_append_to_path(f
, f
->cur_name
, f
->cur_name_len
);
410 TRY(json_test_and_skip(f
, ':'));
411 TRY(json_parse_value(f
));
412 json_truncate_path(f
, current_path_len
);
416 /* object = '{' pair { ',' pair } '}' */
417 static int json_parse_object(struct frozen
*f
) {
418 CALL_BACK(f
, JSON_TYPE_OBJECT_START
, NULL
, 0);
419 TRY(json_test_and_skip(f
, '{'));
421 SET_STATE(f
, f
->cur
- 1, ".", 1);
422 while (json_cur(f
) != '}') {
423 TRY(json_parse_pair(f
));
424 if (json_cur(f
) == ',') f
->cur
++;
426 TRY(json_test_and_skip(f
, '}'));
427 json_truncate_path(f
, fstate
.path_len
);
428 CALL_BACK(f
, JSON_TYPE_OBJECT_END
, fstate
.ptr
, f
->cur
- fstate
.ptr
);
433 static int json_doit(struct frozen
*f
) {
434 if (f
->cur
== 0 || f
->end
< f
->cur
) return JSON_STRING_INVALID
;
435 if (f
->end
== f
->cur
) return JSON_STRING_INCOMPLETE
;
436 return json_parse_value(f
);
439 int json_escape(struct json_out
*out
, const char *p
, size_t len
) WEAK
;
440 int json_escape(struct json_out
*out
, const char *str
, size_t str_len
) {
442 const char *hex_digits
= "0123456789abcdef";
443 const char *specials
= "btnvfr";
445 for (i
= 0; i
< str_len
; i
++) {
446 unsigned char ch
= ((unsigned char *) str
)[i
];
447 if (ch
== '"' || ch
== '\\') {
448 n
+= out
->printer(out
, "\\", 1);
449 n
+= out
->printer(out
, str
+ i
, 1);
450 } else if (ch
>= '\b' && ch
<= '\r') {
451 n
+= out
->printer(out
, "\\", 1);
452 n
+= out
->printer(out
, &specials
[ch
- '\b'], 1);
453 } else if (c_isprint(ch
)) {
454 n
+= out
->printer(out
, str
+ i
, 1);
455 } else if ((cl
= json_get_utf8_char_len(ch
)) == 1) {
456 n
+= out
->printer(out
, "\\u00", 4);
457 n
+= out
->printer(out
, &hex_digits
[(ch
>> 4) % 0xf], 1);
458 n
+= out
->printer(out
, &hex_digits
[ch
% 0xf], 1);
460 n
+= out
->printer(out
, str
+ i
, cl
);
468 int json_printer_buf(struct json_out
*out
, const char *buf
, size_t len
) WEAK
;
469 int json_printer_buf(struct json_out
*out
, const char *buf
, size_t len
) {
470 size_t avail
= out
->u
.buf
.size
- out
->u
.buf
.len
;
471 size_t n
= len
< avail
? len
: avail
;
472 memcpy(out
->u
.buf
.buf
+ out
->u
.buf
.len
, buf
, n
);
474 if (out
->u
.buf
.size
> 0) {
475 size_t idx
= out
->u
.buf
.len
;
476 if (idx
>= out
->u
.buf
.size
) idx
= out
->u
.buf
.size
- 1;
477 out
->u
.buf
.buf
[idx
] = '\0';
482 int json_printer_file(struct json_out
*out
, const char *buf
, size_t len
) WEAK
;
483 int json_printer_file(struct json_out
*out
, const char *buf
, size_t len
) {
484 return fwrite(buf
, 1, len
, out
->u
.fp
);
487 #if JSON_ENABLE_BASE64
488 static int b64idx(int c
) {
496 return c
== 62 ? '+' : '/';
500 static int b64rev(int c
) {
501 if (c
>= 'A' && c
<= 'Z') {
503 } else if (c
>= 'a' && c
<= 'z') {
505 } else if (c
>= '0' && c
<= '9') {
507 } else if (c
== '+') {
509 } else if (c
== '/') {
516 static int b64enc(struct json_out
*out
, const unsigned char *p
, int n
) {
519 for (i
= 0; i
< n
; i
+= 3) {
520 int a
= p
[i
], b
= i
+ 1 < n
? p
[i
+ 1] : 0, c
= i
+ 2 < n
? p
[i
+ 2] : 0;
521 buf
[0] = b64idx(a
>> 2);
522 buf
[1] = b64idx((a
& 3) << 4 | (b
>> 4));
523 buf
[2] = b64idx((b
& 15) << 2 | (c
>> 6));
524 buf
[3] = b64idx(c
& 63);
525 if (i
+ 1 >= n
) buf
[2] = '=';
526 if (i
+ 2 >= n
) buf
[3] = '=';
527 len
+= out
->printer(out
, buf
, sizeof(buf
));
532 static int b64dec(const char *src
, int n
, char *dst
) {
533 const char *end
= src
+ n
;
535 while (src
+ 3 < end
) {
536 int a
= b64rev(src
[0]), b
= b64rev(src
[1]), c
= b64rev(src
[2]),
538 dst
[len
++] = (a
<< 2) | (b
>> 4);
540 dst
[len
++] = (b
<< 4) | (c
>> 2);
542 dst
[len
++] = (c
<< 6) | d
;
549 #endif /* JSON_ENABLE_BASE64 */
551 static unsigned char hexdec(const char *s
) {
552 #define HEXTOI(x) (x >= '0' && x <= '9' ? x - '0' : x - 'W')
553 int a
= c_tolower(*(const unsigned char *) s
);
554 int b
= c_tolower(*(const unsigned char *)(s
+ 1));
555 return (HEXTOI(a
) << 4) | HEXTOI(b
);
558 int json_vprintf(struct json_out
*out
, const char *fmt
, va_list xap
) WEAK
;
559 int json_vprintf(struct json_out
*out
, const char *fmt
, va_list xap
) {
561 const char *quote
= "\"", *null
= "null";
565 while (*fmt
!= '\0') {
566 if (strchr(":, \r\n\t[]{}\"", *fmt
) != NULL
) {
567 len
+= out
->printer(out
, fmt
, 1);
569 } else if (fmt
[0] == '%') {
573 if (fmt
[1] == 'l' && fmt
[2] == 'l' && (fmt
[3] == 'd' || fmt
[3] == 'u')) {
574 int64_t val
= va_arg(ap
, int64_t);
575 const char *fmt2
= fmt
[3] == 'u' ? "%" UINT64_FMT
: "%" INT64_FMT
;
576 snprintf(buf
, sizeof(buf
), fmt2
, val
);
577 len
+= out
->printer(out
, buf
, strlen(buf
));
579 } else if (fmt
[1] == 'z' && fmt
[2] == 'u') {
580 size_t val
= va_arg(ap
, size_t);
581 snprintf(buf
, sizeof(buf
), "%lu", (unsigned long) val
);
582 len
+= out
->printer(out
, buf
, strlen(buf
));
584 } else if (fmt
[1] == 'M') {
585 json_printf_callback_t f
= va_arg(ap
, json_printf_callback_t
);
587 } else if (fmt
[1] == 'B') {
588 int val
= va_arg(ap
, int);
589 const char *str
= val
? "true" : "false";
590 len
+= out
->printer(out
, str
, strlen(str
));
591 } else if (fmt
[1] == 'H') {
593 const char *hex
= "0123456789abcdef";
594 int i
, n
= va_arg(ap
, int);
595 const unsigned char *p
= va_arg(ap
, const unsigned char *);
596 len
+= out
->printer(out
, quote
, 1);
597 for (i
= 0; i
< n
; i
++) {
598 len
+= out
->printer(out
, &hex
[(p
[i
] >> 4) & 0xf], 1);
599 len
+= out
->printer(out
, &hex
[p
[i
] & 0xf], 1);
601 len
+= out
->printer(out
, quote
, 1);
602 #endif /* JSON_ENABLE_HEX */
603 } else if (fmt
[1] == 'V') {
604 #if JSON_ENABLE_BASE64
605 const unsigned char *p
= va_arg(ap
, const unsigned char *);
606 int n
= va_arg(ap
, int);
607 len
+= out
->printer(out
, quote
, 1);
608 len
+= b64enc(out
, p
, n
);
609 len
+= out
->printer(out
, quote
, 1);
610 #endif /* JSON_ENABLE_BASE64 */
611 } else if (fmt
[1] == 'Q' ||
612 (fmt
[1] == '.' && fmt
[2] == '*' && fmt
[3] == 'Q')) {
617 l
= (size_t) va_arg(ap
, int);
620 p
= va_arg(ap
, char *);
623 len
+= out
->printer(out
, null
, 4);
628 len
+= out
->printer(out
, quote
, 1);
629 len
+= json_escape(out
, p
, l
);
630 len
+= out
->printer(out
, quote
, 1);
634 * we delegate printing to the system printf.
635 * The goal here is to delegate all modifiers parsing to the system
636 * printf, as you can see below we still have to parse the format
639 * Currently, %s with strings longer than 20 chars will require
640 * double-buffering (an auxiliary buffer will be allocated from heap).
641 * TODO(dfrank): reimplement %s and %.*s in order to avoid that.
644 const char *end_of_format_specifier
= "sdfFeEgGlhuIcx.*-0123456789";
645 int n
= strspn(fmt
+ 1, end_of_format_specifier
);
647 int need_len
, size
= sizeof(buf
);
651 n
+ 1 > (int) sizeof(fmt2
) ? sizeof(fmt2
) : (size_t) n
+ 1);
654 va_copy(ap_copy
, ap
);
655 need_len
= vsnprintf(pbuf
, size
, fmt2
, ap_copy
);
660 * Windows & eCos vsnprintf implementation return -1 on overflow
661 * instead of needed size.
664 while (need_len
< 0) {
667 if ((pbuf
= (char *) malloc(size
)) == NULL
) break;
668 va_copy(ap_copy
, ap
);
669 need_len
= vsnprintf(pbuf
, size
, fmt2
, ap_copy
);
672 } else if (need_len
>= (int) sizeof(buf
)) {
674 * resulting string doesn't fit into a stack-allocated buffer `buf`,
675 * so we need to allocate a new buffer from heap and use it
677 if ((pbuf
= (char *) malloc(need_len
+ 1)) != NULL
) {
678 va_copy(ap_copy
, ap
);
679 vsnprintf(pbuf
, need_len
+ 1, fmt2
, ap_copy
);
689 * however we need to parse the type ourselves in order to advance
690 * the va_list by the correct amount; there is no portable way to
691 * inherit the advancement made by vprintf.
692 * 32-bit (linux or windows) passes va_list by value.
694 if ((n
+ 1 == strlen("%" PRId64
) && strcmp(fmt2
, "%" PRId64
) == 0) ||
695 (n
+ 1 == strlen("%" PRIu64
) && strcmp(fmt2
, "%" PRIu64
) == 0)) {
696 (void) va_arg(ap
, int64_t);
697 } else if (strcmp(fmt2
, "%.*s") == 0) {
698 (void) va_arg(ap
, int);
699 (void) va_arg(ap
, char *);
704 (void) va_arg(ap
, int);
708 (void) va_arg(ap
, double);
711 (void) va_arg(ap
, void *);
714 /* many types are promoted to int */
715 (void) va_arg(ap
, int);
719 len
+= out
->printer(out
, pbuf
, strlen(pbuf
));
722 /* If buffer was allocated from heap, free it */
729 } else if (*fmt
== '_' || json_isalpha(*fmt
)) {
730 len
+= out
->printer(out
, quote
, 1);
731 while (*fmt
== '_' || json_isalpha(*fmt
) || json_isdigit(*fmt
)) {
732 len
+= out
->printer(out
, fmt
, 1);
735 len
+= out
->printer(out
, quote
, 1);
737 len
+= out
->printer(out
, fmt
, 1);
746 int json_printf(struct json_out
*out
, const char *fmt
, ...) WEAK
;
747 int json_printf(struct json_out
*out
, const char *fmt
, ...) {
751 n
= json_vprintf(out
, fmt
, ap
);
756 int json_printf_array(struct json_out
*out
, va_list *ap
) WEAK
;
757 int json_printf_array(struct json_out
*out
, va_list *ap
) {
759 char *arr
= va_arg(*ap
, char *);
760 size_t i
, arr_size
= va_arg(*ap
, size_t);
761 size_t elem_size
= va_arg(*ap
, size_t);
762 const char *fmt
= va_arg(*ap
, char *);
763 len
+= json_printf(out
, "[", 1);
764 for (i
= 0; arr
!= NULL
&& i
< arr_size
/ elem_size
; i
++) {
769 memcpy(&val
, arr
+ i
* elem_size
,
770 elem_size
> sizeof(val
) ? sizeof(val
) : elem_size
);
771 if (i
> 0) len
+= json_printf(out
, ", ");
772 if (strpbrk(fmt
, "efg") != NULL
) {
773 len
+= json_printf(out
, fmt
, val
.d
);
775 len
+= json_printf(out
, fmt
, val
.i
);
778 len
+= json_printf(out
, "]", 1);
783 int cs_win_vsnprintf(char *str
, size_t size
, const char *format
, va_list ap
) WEAK
;
784 int cs_win_vsnprintf(char *str
, size_t size
, const char *format
, va_list ap
) {
785 int res
= _vsnprintf(str
, size
, format
, ap
);
788 str
[size
- 1] = '\0';
793 int cs_win_snprintf(char *str
, size_t size
, const char *format
, ...) WEAK
;
794 int cs_win_snprintf(char *str
, size_t size
, const char *format
, ...) {
797 va_start(ap
, format
);
798 res
= vsnprintf(str
, size
, format
, ap
);
804 int json_walk(const char *json_string
, int json_string_length
,
805 json_walk_callback_t callback
, void *callback_data
) WEAK
;
806 int json_walk(const char *json_string
, int json_string_length
,
807 json_walk_callback_t callback
, void *callback_data
) {
808 struct frozen frozen
;
810 memset(&frozen
, 0, sizeof(frozen
));
811 frozen
.end
= json_string
+ json_string_length
;
812 frozen
.cur
= json_string
;
813 frozen
.callback_data
= callback_data
;
814 frozen
.callback
= callback
;
816 TRY(json_doit(&frozen
));
818 return frozen
.cur
- json_string
;
821 struct scan_array_info
{
823 char path
[JSON_MAX_PATH_LEN
];
824 struct json_token
*token
;
827 static void json_scanf_array_elem_cb(void *callback_data
, const char *name
,
828 size_t name_len
, const char *path
,
829 const struct json_token
*token
) {
830 struct scan_array_info
*info
= (struct scan_array_info
*) callback_data
;
835 if (strcmp(path
, info
->path
) == 0) {
836 *info
->token
= *token
;
841 int json_scanf_array_elem(const char *s
, int len
, const char *path
, int idx
,
842 struct json_token
*token
) WEAK
;
843 int json_scanf_array_elem(const char *s
, int len
, const char *path
, int idx
,
844 struct json_token
*token
) {
845 struct scan_array_info info
;
848 memset(token
, 0, sizeof(*token
));
849 snprintf(info
.path
, sizeof(info
.path
), "%s[%d]", path
, idx
);
850 json_walk(s
, len
, json_scanf_array_elem_cb
, &info
);
851 return info
.found
? token
->len
: -1;
854 struct json_scanf_info
{
863 int json_unescape(const char *src
, int slen
, char *dst
, int dlen
) WEAK
;
864 int json_unescape(const char *src
, int slen
, char *dst
, int dlen
) {
865 if (dst
== NULL
|| dlen
== 0)
866 return JSON_STRING_INVALID
;
868 char *send
= (char *) src
+ slen
;
869 char *dend
= dst
+ dlen
;
870 char *orig_dst
= dst
;
872 const char *esc1
= "\"\\/bfnrt", *esc2
= "\"\\/\b\f\n\r\t";
876 if (++src
>= send
) { return JSON_STRING_INCOMPLETE
; }
879 if (send
- src
< 5) { return JSON_STRING_INCOMPLETE
; }
880 /* Here we go: this is a \u.... escape. Process simple one-byte chars */
881 if (src
[1] == '0' && src
[2] == '0') {
882 /* This is \u00xx character from the ASCII range */
883 if (dst
< dend
) *dst
= hexdec(src
+ 3);
886 /* Complex \uXXXX escapes drag utf8 lib... Do it at some stage */
887 return JSON_STRING_INVALID
;
889 } else if ((p
= (char *) strchr(esc1
, *src
)) != NULL
) {
891 *dst
= esc2
[p
- esc1
];
894 return JSON_STRING_INVALID
;
905 return dst
- orig_dst
;
908 static void json_scanf_cb(void *callback_data
, const char *name
,
909 size_t name_len
, const char *path
,
910 const struct json_token
*token
) {
911 struct json_scanf_info
*info
= (struct json_scanf_info
*) callback_data
;
912 char buf
[32]; /* Must be enough to hold numbers */
917 if (token
->ptr
== NULL
) {
919 * We're not interested here in the events for which we have no value;
920 * namely, JSON_TYPE_OBJECT_START and JSON_TYPE_ARRAY_START
925 if (strcmp(path
, info
->path
) != 0) {
926 /* It's not the path we're looking for, so, just ignore this callback */
930 switch (info
->type
) {
932 info
->num_conversions
++;
933 switch (sizeof(bool)) {
935 *(char *) info
->target
= (token
->type
== JSON_TYPE_TRUE
? 1 : 0);
938 *(int *) info
->target
= (token
->type
== JSON_TYPE_TRUE
? 1 : 0);
941 /* should never be here */
949 } u
= {info
->target
};
950 info
->num_conversions
++;
951 u
.f(token
->ptr
, token
->len
, info
->user_data
);
955 char **dst
= (char **) info
->target
;
956 if (token
->type
== JSON_TYPE_NULL
) {
959 int unescaped_len
= json_unescape(token
->ptr
, token
->len
, NULL
, 0);
960 if (unescaped_len
>= 0 &&
961 (*dst
= (char *) malloc(unescaped_len
+ 1)) != NULL
) {
962 info
->num_conversions
++;
963 if (json_unescape(token
->ptr
, token
->len
, *dst
, unescaped_len
) ==
965 (*dst
)[unescaped_len
] = '\0';
976 char **dst
= (char **) info
->user_data
;
977 int i
, len
= token
->len
/ 2;
978 *(int *) info
->target
= len
;
979 if ((*dst
= (char *) malloc(len
+ 1)) != NULL
) {
980 for (i
= 0; i
< len
; i
++) {
981 (*dst
)[i
] = hexdec(token
->ptr
+ 2 * i
);
984 info
->num_conversions
++;
986 #endif /* JSON_ENABLE_HEX */
990 #if JSON_ENABLE_BASE64
991 char **dst
= (char **) info
->target
;
992 int len
= token
->len
* 4 / 3 + 2;
993 if ((*dst
= (char *) malloc(len
+ 1)) != NULL
) {
994 int n
= b64dec(token
->ptr
, token
->len
, *dst
);
996 *(int *) info
->user_data
= n
;
997 info
->num_conversions
++;
999 #endif /* JSON_ENABLE_BASE64 */
1003 info
->num_conversions
++;
1004 *(struct json_token
*) info
->target
= *token
;
1007 if (token
->len
>= (int) sizeof(buf
)) break;
1008 /* Before converting, copy into tmp buffer in order to 0-terminate it */
1009 memcpy(buf
, token
->ptr
, token
->len
);
1010 buf
[token
->len
] = '\0';
1011 /* NB: Use of base 0 for %d, %ld, %u and %lu is intentional. */
1012 if (info
->fmt
[1] == 'd' || (info
->fmt
[1] == 'l' && info
->fmt
[2] == 'd') ||
1013 info
->fmt
[1] == 'i') {
1014 char *endptr
= NULL
;
1015 long r
= strtol(buf
, &endptr
, 0 /* base */);
1016 if (*endptr
== '\0') {
1017 if (info
->fmt
[1] == 'l') {
1018 *((long *) info
->target
) = r
;
1020 *((int *) info
->target
) = (int) r
;
1022 info
->num_conversions
++;
1024 } else if (info
->fmt
[1] == 'u' ||
1025 (info
->fmt
[1] == 'l' && info
->fmt
[2] == 'u')) {
1026 char *endptr
= NULL
;
1027 unsigned long r
= strtoul(buf
, &endptr
, 0 /* base */);
1028 if (*endptr
== '\0') {
1029 if (info
->fmt
[1] == 'l') {
1030 *((unsigned long *) info
->target
) = r
;
1032 *((unsigned int *) info
->target
) = (unsigned int) r
;
1034 info
->num_conversions
++;
1038 info
->num_conversions
+= sscanf(buf
, info
->fmt
, info
->target
);
1045 int json_vscanf(const char *str
, int len
, const char *fmt
, va_list ap
) WEAK
;
1046 int json_vscanf(const char *str
, int len
, const char *fmt
, va_list ap
) {
1047 char path
[JSON_MAX_PATH_LEN
] = "", fmtbuf
[20];
1050 struct json_scanf_info info
= {0, path
, fmtbuf
, NULL
, NULL
, 0};
1052 while (fmt
[i
] != '\0') {
1053 if (fmt
[i
] == '{') {
1056 } else if (fmt
[i
] == '}') {
1057 if ((p
= strrchr(path
, '.')) != NULL
) * p
= '\0';
1059 } else if (fmt
[i
] == '%') {
1060 info
.target
= va_arg(ap
, void *);
1061 info
.type
= fmt
[i
+ 1];
1062 switch (fmt
[i
+ 1]) {
1066 info
.user_data
= va_arg(ap
, void *);
1074 const char *delims
= ", \t\r\n]}";
1075 int conv_len
= strcspn(fmt
+ i
+ 1, delims
) + 1;
1076 memcpy(fmtbuf
, fmt
+ i
, conv_len
);
1077 fmtbuf
[conv_len
] = '\0';
1079 i
+= strspn(fmt
+ i
, delims
);
1083 json_walk(str
, len
, json_scanf_cb
, &info
);
1084 } else if (json_isalpha(fmt
[i
]) || json_get_utf8_char_len(fmt
[i
]) > 1) {
1086 const char *delims
= ": \r\n\t";
1087 int key_len
= strcspn(&fmt
[i
], delims
);
1088 if ((p
= strrchr(path
, '.')) != NULL
) p
[1] = '\0';
1089 pe
= path
+ strlen(path
);
1090 memcpy(pe
, fmt
+ i
, key_len
);
1092 i
+= key_len
+ strspn(fmt
+ i
+ key_len
, delims
);
1097 return info
.num_conversions
;
1100 int json_scanf(const char *str
, int len
, const char *fmt
, ...) WEAK
;
1101 int json_scanf(const char *str
, int len
, const char *fmt
, ...) {
1105 result
= json_vscanf(str
, len
, fmt
, ap
);
1110 int json_vfprintf(const char *file_name
, const char *fmt
, va_list ap
) WEAK
;
1111 int json_vfprintf(const char *file_name
, const char *fmt
, va_list ap
) {
1113 FILE *fp
= fopen(file_name
, "wb");
1115 struct json_out out
= JSON_OUT_FILE(fp
);
1116 res
= json_vprintf(&out
, fmt
, ap
);
1123 int json_fprintf(const char *file_name
, const char *fmt
, ...) WEAK
;
1124 int json_fprintf(const char *file_name
, const char *fmt
, ...) {
1128 result
= json_vfprintf(file_name
, fmt
, ap
);
1133 char *json_fread(const char *path
) WEAK
;
1134 char *json_fread(const char *path
) {
1137 if ((fp
= fopen(path
, "rb")) == NULL
) {
1138 } else if (fseek(fp
, 0, SEEK_END
) != 0) {
1141 long size
= ftell(fp
);
1142 if (size
> 0 && (data
= (char *) malloc(size
+ 1)) != NULL
) {
1143 fseek(fp
, 0, SEEK_SET
); /* Some platforms might not have rewind(), Oo */
1144 if (fread(data
, 1, size
, fp
) != (size_t) size
) {
1156 struct json_setf_data
{
1157 const char *json_path
;
1158 const char *base
; /* Pointer to the source JSON string */
1159 int matched
; /* Matched part of json_path */
1160 int pos
; /* Offset of the mutated value begin */
1161 int end
; /* Offset of the mutated value end */
1162 int prev
; /* Offset of the previous token end */
1165 static int get_matched_prefix_len(const char *s1
, const char *s2
) {
1167 while (s1
[i
] && s2
[i
] && s1
[i
] == s2
[i
]) i
++;
1171 static void json_vsetf_cb(void *userdata
, const char *name
, size_t name_len
,
1172 const char *path
, const struct json_token
*t
) {
1173 struct json_setf_data
*data
= (struct json_setf_data
*) userdata
;
1174 int off
, len
= get_matched_prefix_len(path
, data
->json_path
);
1175 if (t
->ptr
== NULL
) return;
1176 off
= t
->ptr
- data
->base
;
1177 if (len
> data
->matched
) data
->matched
= len
;
1180 * If there is no exact path match, set the mutation position to tbe end
1181 * of the object or array
1183 if (len
< data
->matched
&& data
->pos
== 0 &&
1184 (t
->type
== JSON_TYPE_OBJECT_END
|| t
->type
== JSON_TYPE_ARRAY_END
)) {
1185 data
->pos
= data
->end
= data
->prev
;
1188 /* Exact path match. Set mutation position to the value of this token */
1189 if (strcmp(path
, data
->json_path
) == 0 && t
->type
!= JSON_TYPE_OBJECT_START
&&
1190 t
->type
!= JSON_TYPE_ARRAY_START
) {
1192 data
->end
= off
+ t
->len
;
1196 * For deletion, we need to know where the previous value ends, because
1197 * we don't know where matched value key starts.
1198 * When the mutation position is not yet set, remember each value end.
1199 * When the mutation position is already set, but it is at the beginning
1200 * of the object/array, we catch the end of the object/array and see
1201 * whether the object/array start is closer then previously stored prev.
1203 if (data
->pos
== 0) {
1204 data
->prev
= off
+ t
->len
; /* pos is not yet set */
1205 } else if ((t
->ptr
[0] == '[' || t
->ptr
[0] == '{') && off
+ 1 < data
->pos
&&
1206 off
+ 1 > data
->prev
) {
1207 data
->prev
= off
+ 1;
1213 int json_vsetf(const char *s
, int len
, struct json_out
*out
,
1214 const char *json_path
, const char *json_fmt
, va_list ap
) WEAK
;
1215 int json_vsetf(const char *s
, int len
, struct json_out
*out
,
1216 const char *json_path
, const char *json_fmt
, va_list ap
) {
1217 struct json_setf_data data
;
1218 memset(&data
, 0, sizeof(data
));
1219 data
.json_path
= json_path
;
1222 json_walk(s
, len
, json_vsetf_cb
, &data
);
1223 if (json_fmt
== NULL
) {
1224 /* Deletion codepath */
1225 json_printf(out
, "%.*s", data
.prev
, s
);
1226 /* Trim comma after the value that begins at object/array start */
1227 if (s
[data
.prev
- 1] == '{' || s
[data
.prev
- 1] == '[') {
1229 while (i
< len
&& json_isspace(s
[i
])) i
++;
1230 if (s
[i
] == ',') data
.end
= i
+ 1; /* Point after comma */
1232 json_printf(out
, "%.*s", len
- data
.end
, s
+ data
.end
);
1234 /* Modification codepath */
1235 int n
, off
= data
.matched
, depth
= 0;
1237 /* Print the unchanged beginning */
1238 json_printf(out
, "%.*s", data
.pos
, s
);
1240 /* Add missing keys */
1241 while ((n
= strcspn(&json_path
[off
], ".[")) > 0) {
1242 if (s
[data
.prev
- 1] != '{' && s
[data
.prev
- 1] != '[' && depth
== 0) {
1243 json_printf(out
, ",");
1245 if (off
> 0 && json_path
[off
- 1] != '.') break;
1246 json_printf(out
, "%.*Q:", n
, json_path
+ off
);
1248 if (json_path
[off
] != '\0') {
1249 json_printf(out
, "%c", json_path
[off
] == '.' ? '{' : '[');
1254 /* Print the new value */
1255 json_vprintf(out
, json_fmt
, ap
);
1257 /* Close brackets/braces of the added missing keys */
1258 for (; off
> data
.matched
; off
--) {
1259 int ch
= json_path
[off
];
1260 const char *p
= ch
== '.' ? "}" : ch
== '[' ? "]" : "";
1261 json_printf(out
, "%s", p
);
1264 /* Print the rest of the unchanged string */
1265 json_printf(out
, "%.*s", len
- data
.end
, s
+ data
.end
);
1267 return data
.end
> data
.pos
? 1 : 0;
1270 int json_setf(const char *s
, int len
, struct json_out
*out
,
1271 const char *json_path
, const char *json_fmt
, ...) WEAK
;
1272 int json_setf(const char *s
, int len
, struct json_out
*out
,
1273 const char *json_path
, const char *json_fmt
, ...) {
1276 va_start(ap
, json_fmt
);
1277 result
= json_vsetf(s
, len
, out
, json_path
, json_fmt
, ap
);
1282 struct prettify_data
{
1283 struct json_out
*out
;
1288 static void indent(struct json_out
*out
, int level
) {
1289 while (level
-- > 0) out
->printer(out
, " ", 2);
1292 static void print_key(struct prettify_data
*pd
, const char *path
,
1293 const char *name
, int name_len
) {
1294 if (pd
->last_token
!= JSON_TYPE_INVALID
&&
1295 pd
->last_token
!= JSON_TYPE_ARRAY_START
&&
1296 pd
->last_token
!= JSON_TYPE_OBJECT_START
) {
1297 pd
->out
->printer(pd
->out
, ",", 1);
1299 if (path
[0] != '\0') pd
->out
->printer(pd
->out
, "\n", 1);
1300 indent(pd
->out
, pd
->level
);
1301 if (path
[0] != '\0' && path
[strlen(path
) - 1] != ']') {
1302 pd
->out
->printer(pd
->out
, "\"", 1);
1303 pd
->out
->printer(pd
->out
, name
, (int) name_len
);
1304 pd
->out
->printer(pd
->out
, "\"", 1);
1305 pd
->out
->printer(pd
->out
, ": ", 2);
1309 static void prettify_cb(void *userdata
, const char *name
, size_t name_len
,
1310 const char *path
, const struct json_token
*t
) {
1311 struct prettify_data
*pd
= (struct prettify_data
*) userdata
;
1313 case JSON_TYPE_OBJECT_START
:
1314 case JSON_TYPE_ARRAY_START
:
1315 print_key(pd
, path
, name
, name_len
);
1316 pd
->out
->printer(pd
->out
, t
->type
== JSON_TYPE_ARRAY_START
? "[" : "{",
1320 case JSON_TYPE_OBJECT_END
:
1321 case JSON_TYPE_ARRAY_END
:
1323 if (pd
->last_token
!= JSON_TYPE_INVALID
&&
1324 pd
->last_token
!= JSON_TYPE_ARRAY_START
&&
1325 pd
->last_token
!= JSON_TYPE_OBJECT_START
) {
1326 pd
->out
->printer(pd
->out
, "\n", 1);
1327 indent(pd
->out
, pd
->level
);
1329 pd
->out
->printer(pd
->out
, t
->type
== JSON_TYPE_ARRAY_END
? "]" : "}", 1);
1331 case JSON_TYPE_NUMBER
:
1332 case JSON_TYPE_NULL
:
1333 case JSON_TYPE_TRUE
:
1334 case JSON_TYPE_FALSE
:
1335 case JSON_TYPE_STRING
:
1336 print_key(pd
, path
, name
, name_len
);
1337 if (t
->type
== JSON_TYPE_STRING
) pd
->out
->printer(pd
->out
, "\"", 1);
1338 pd
->out
->printer(pd
->out
, t
->ptr
, t
->len
);
1339 if (t
->type
== JSON_TYPE_STRING
) pd
->out
->printer(pd
->out
, "\"", 1);
1344 pd
->last_token
= t
->type
;
1347 int json_prettify(const char *s
, int len
, struct json_out
*out
) WEAK
;
1348 int json_prettify(const char *s
, int len
, struct json_out
*out
) {
1349 struct prettify_data pd
= {out
, 0, JSON_TYPE_INVALID
};
1350 return json_walk(s
, len
, prettify_cb
, &pd
);
1353 int json_prettify_file(const char *file_name
) WEAK
;
1354 int json_prettify_file(const char *file_name
) {
1356 char *s
= json_fread(file_name
);
1358 if (s
!= NULL
&& (fp
= fopen(file_name
, "wb")) != NULL
) {
1359 struct json_out out
= JSON_OUT_FILE(fp
);
1360 res
= json_prettify(s
, strlen(s
), &out
);
1362 /* On error, restore the old content */
1364 fp
= fopen(file_name
, "wb");
1365 fseek(fp
, 0, SEEK_SET
);
1366 fwrite(s
, 1, strlen(s
), fp
);
1377 void *handle
; // Passed handle. Changed if a next entry is found
1378 const char *path
; // Path to the iterated object/array
1379 int path_len
; // Path length - optimisation
1380 int found
; // Non-0 if found the next entry
1381 struct json_token
*key
; // Object's key
1382 struct json_token
*val
; // Object's value
1383 int *idx
; // Array index
1386 static void next_set_key(struct next_data
*d
, const char *name
, int name_len
,
1389 /* Array. Set index and reset key */
1390 if (d
->key
!= NULL
) {
1394 if (d
->idx
!= NULL
) *d
->idx
= atoi(name
);
1396 /* Object. Set key and make index -1 */
1397 if (d
->key
!= NULL
) {
1399 d
->key
->len
= name_len
;
1401 if (d
->idx
!= NULL
) *d
->idx
= -1;
1405 static void json_next_cb(void *userdata
, const char *name
, size_t name_len
,
1406 const char *path
, const struct json_token
*t
) {
1407 struct next_data
*d
= (struct next_data
*) userdata
;
1408 const char *p
= path
+ d
->path_len
;
1409 if (d
->found
) return;
1410 if (d
->path_len
>= (int) strlen(path
)) return;
1411 if (strncmp(d
->path
, path
, d
->path_len
) != 0) return;
1412 if (strchr(p
+ 1, '.') != NULL
) return; /* More nested objects - skip */
1413 if (strchr(p
+ 1, '[') != NULL
) return; /* Ditto for arrays */
1414 // {OBJECT,ARRAY}_END types do not pass name, _START does. Save key.
1415 if (t
->type
== JSON_TYPE_OBJECT_START
|| t
->type
== JSON_TYPE_ARRAY_START
) {
1416 next_set_key(d
, name
, name_len
, p
[0] == '[');
1417 } else if (d
->handle
== NULL
|| d
->handle
< (void *) t
->ptr
) {
1418 if (t
->type
!= JSON_TYPE_OBJECT_END
&& t
->type
!= JSON_TYPE_ARRAY_END
) {
1419 next_set_key(d
, name
, name_len
, p
[0] == '[');
1421 if (d
->val
!= NULL
) *d
->val
= *t
;
1422 d
->handle
= (void *) t
->ptr
;
1427 static void *json_next(const char *s
, int len
, void *handle
, const char *path
,
1428 struct json_token
*key
, struct json_token
*val
, int *i
) {
1429 struct json_token tmpval
, *v
= val
== NULL
? &tmpval
: val
;
1430 struct json_token tmpkey
, *k
= key
== NULL
? &tmpkey
: key
;
1431 int tmpidx
, *pidx
= i
== NULL
? &tmpidx
: i
;
1432 struct next_data data
= {handle
, path
, (int) strlen(path
), 0, k
, v
, pidx
};
1433 json_walk(s
, len
, json_next_cb
, &data
);
1434 return data
.found
? data
.handle
: NULL
;
1437 void *json_next_key(const char *s
, int len
, void *handle
, const char *path
,
1438 struct json_token
*key
, struct json_token
*val
) WEAK
;
1439 void *json_next_key(const char *s
, int len
, void *handle
, const char *path
,
1440 struct json_token
*key
, struct json_token
*val
) {
1441 return json_next(s
, len
, handle
, path
, key
, val
, NULL
);
1444 void *json_next_elem(const char *s
, int len
, void *handle
, const char *path
,
1445 int *idx
, struct json_token
*val
) WEAK
;
1446 void *json_next_elem(const char *s
, int len
, void *handle
, const char *path
,
1447 int *idx
, struct json_token
*val
) {
1448 return json_next(s
, len
, handle
, path
, NULL
, val
, idx
);
1451 static int json_sprinter(struct json_out
*out
, const char *str
, size_t len
) {
1452 size_t old_len
= out
->u
.buf
.buf
== NULL
? 0 : strlen(out
->u
.buf
.buf
);
1453 size_t new_len
= len
+ old_len
;
1454 char *p
= (char *) realloc(out
->u
.buf
.buf
, new_len
+ 1);
1456 memcpy(p
+ old_len
, str
, len
);
1463 char *json_vasprintf(const char *fmt
, va_list ap
) WEAK
;
1464 char *json_vasprintf(const char *fmt
, va_list ap
) {
1465 struct json_out out
;
1466 memset(&out
, 0, sizeof(out
));
1467 out
.printer
= json_sprinter
;
1468 json_vprintf(&out
, fmt
, ap
);
1469 return out
.u
.buf
.buf
;
1472 char *json_asprintf(const char *fmt
, ...) WEAK
;
1473 char *json_asprintf(const char *fmt
, ...) {
1476 char *result
= json_vasprintf(fmt
, ap
);