xref: /spdk/lib/json/json_write.c (revision cc6920a4763d4b9a43aa40583c8397d8f14fa100)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) Intel Corporation.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "spdk/json.h"
35 
36 #include "spdk_internal/utf.h"
37 
38 struct spdk_json_write_ctx {
39 	spdk_json_write_cb write_cb;
40 	void *cb_ctx;
41 	uint32_t flags;
42 	uint32_t indent;
43 	bool new_indent;
44 	bool first_value;
45 	bool failed;
46 	size_t buf_filled;
47 	uint8_t buf[4096];
48 };
49 
50 static int emit_buf_full(struct spdk_json_write_ctx *w, const void *data, size_t size);
51 
52 static int
53 fail(struct spdk_json_write_ctx *w)
54 {
55 	w->failed = true;
56 	return -1;
57 }
58 
59 static int
60 flush_buf(struct spdk_json_write_ctx *w)
61 {
62 	int rc;
63 
64 	rc = w->write_cb(w->cb_ctx, w->buf, w->buf_filled);
65 	if (rc != 0) {
66 		return fail(w);
67 	}
68 
69 	w->buf_filled = 0;
70 
71 	return 0;
72 }
73 
74 struct spdk_json_write_ctx *
75 spdk_json_write_begin(spdk_json_write_cb write_cb, void *cb_ctx, uint32_t flags)
76 {
77 	struct spdk_json_write_ctx *w;
78 
79 	w = calloc(1, sizeof(*w));
80 	if (w == NULL) {
81 		return w;
82 	}
83 
84 	w->write_cb = write_cb;
85 	w->cb_ctx = cb_ctx;
86 	w->flags = flags;
87 	w->indent = 0;
88 	w->new_indent = false;
89 	w->first_value = true;
90 	w->failed = false;
91 	w->buf_filled = 0;
92 
93 	return w;
94 }
95 
96 int
97 spdk_json_write_end(struct spdk_json_write_ctx *w)
98 {
99 	bool failed;
100 	int rc;
101 
102 	if (w == NULL) {
103 		return 0;
104 	}
105 
106 	failed = w->failed;
107 
108 	rc = flush_buf(w);
109 	if (rc != 0) {
110 		failed = true;
111 	}
112 
113 	free(w);
114 
115 	return failed ? -1 : 0;
116 }
117 
118 static inline int
119 emit(struct spdk_json_write_ctx *w, const void *data, size_t size)
120 {
121 	size_t buf_remain = sizeof(w->buf) - w->buf_filled;
122 
123 	if (spdk_unlikely(size > buf_remain)) {
124 		/* Not enough space in buffer for the new data. */
125 		return emit_buf_full(w, data, size);
126 	}
127 
128 	/* Copy the new data into buf. */
129 	memcpy(w->buf + w->buf_filled, data, size);
130 	w->buf_filled += size;
131 	return 0;
132 }
133 
134 static int
135 emit_buf_full(struct spdk_json_write_ctx *w, const void *data, size_t size)
136 {
137 	size_t buf_remain = sizeof(w->buf) - w->buf_filled;
138 	int rc;
139 
140 	assert(size > buf_remain);
141 
142 	/* Copy as much of the new data as possible into the buffer and flush it. */
143 	memcpy(w->buf + w->buf_filled, data, buf_remain);
144 	w->buf_filled += buf_remain;
145 
146 	rc = flush_buf(w);
147 	if (rc != 0) {
148 		return fail(w);
149 	}
150 
151 	/* Recurse to emit the rest of the data. */
152 	return emit(w, data + buf_remain, size - buf_remain);
153 }
154 
155 static int
156 emit_fmt(struct spdk_json_write_ctx *w, const void *data, size_t size)
157 {
158 	if (w->flags & SPDK_JSON_WRITE_FLAG_FORMATTED) {
159 		return emit(w, data, size);
160 	}
161 	return 0;
162 }
163 
164 static int
165 emit_indent(struct spdk_json_write_ctx *w)
166 {
167 	uint32_t i;
168 
169 	if (w->flags & SPDK_JSON_WRITE_FLAG_FORMATTED) {
170 		for (i = 0; i < w->indent; i++) {
171 			if (emit(w, "  ", 2)) { return fail(w); }
172 		}
173 	}
174 	return 0;
175 }
176 
177 static int
178 begin_value(struct spdk_json_write_ctx *w)
179 {
180 	/* TODO: check for value state */
181 	if (w->new_indent) {
182 		if (emit_fmt(w, "\n", 1)) { return fail(w); }
183 		if (emit_indent(w)) { return fail(w); }
184 	}
185 	if (!w->first_value) {
186 		if (emit(w, ",", 1)) { return fail(w); }
187 		if (emit_fmt(w, "\n", 1)) { return fail(w); }
188 		if (emit_indent(w)) { return fail(w); }
189 	}
190 	w->first_value = false;
191 	w->new_indent = false;
192 	return 0;
193 }
194 
195 int
196 spdk_json_write_val_raw(struct spdk_json_write_ctx *w, const void *data, size_t len)
197 {
198 	if (begin_value(w)) { return fail(w); }
199 	return emit(w, data, len);
200 }
201 
202 int
203 spdk_json_write_null(struct spdk_json_write_ctx *w)
204 {
205 	if (begin_value(w)) { return fail(w); }
206 	return emit(w, "null", 4);
207 }
208 
209 int
210 spdk_json_write_bool(struct spdk_json_write_ctx *w, bool val)
211 {
212 	if (begin_value(w)) { return fail(w); }
213 	if (val) {
214 		return emit(w, "true", 4);
215 	} else {
216 		return emit(w, "false", 5);
217 	}
218 }
219 
220 int
221 spdk_json_write_uint8(struct spdk_json_write_ctx *w, uint8_t val)
222 {
223 	char buf[32];
224 	int count;
225 
226 	if (begin_value(w)) { return fail(w); }
227 	count = snprintf(buf, sizeof(buf), "%" PRIu8, val);
228 	if (count <= 0 || (size_t)count >= sizeof(buf)) { return fail(w); }
229 	return emit(w, buf, count);
230 }
231 
232 int
233 spdk_json_write_uint16(struct spdk_json_write_ctx *w, uint16_t val)
234 {
235 	char buf[32];
236 	int count;
237 
238 	if (begin_value(w)) { return fail(w); }
239 	count = snprintf(buf, sizeof(buf), "%" PRIu16, val);
240 	if (count <= 0 || (size_t)count >= sizeof(buf)) { return fail(w); }
241 	return emit(w, buf, count);
242 }
243 
244 int
245 spdk_json_write_int32(struct spdk_json_write_ctx *w, int32_t val)
246 {
247 	char buf[32];
248 	int count;
249 
250 	if (begin_value(w)) { return fail(w); }
251 	count = snprintf(buf, sizeof(buf), "%" PRId32, val);
252 	if (count <= 0 || (size_t)count >= sizeof(buf)) { return fail(w); }
253 	return emit(w, buf, count);
254 }
255 
256 int
257 spdk_json_write_uint32(struct spdk_json_write_ctx *w, uint32_t val)
258 {
259 	char buf[32];
260 	int count;
261 
262 	if (begin_value(w)) { return fail(w); }
263 	count = snprintf(buf, sizeof(buf), "%" PRIu32, val);
264 	if (count <= 0 || (size_t)count >= sizeof(buf)) { return fail(w); }
265 	return emit(w, buf, count);
266 }
267 
268 int
269 spdk_json_write_int64(struct spdk_json_write_ctx *w, int64_t val)
270 {
271 	char buf[32];
272 	int count;
273 
274 	if (begin_value(w)) { return fail(w); }
275 	count = snprintf(buf, sizeof(buf), "%" PRId64, val);
276 	if (count <= 0 || (size_t)count >= sizeof(buf)) { return fail(w); }
277 	return emit(w, buf, count);
278 }
279 
280 int
281 spdk_json_write_uint64(struct spdk_json_write_ctx *w, uint64_t val)
282 {
283 	char buf[32];
284 	int count;
285 
286 	if (begin_value(w)) { return fail(w); }
287 	count = snprintf(buf, sizeof(buf), "%" PRIu64, val);
288 	if (count <= 0 || (size_t)count >= sizeof(buf)) { return fail(w); }
289 	return emit(w, buf, count);
290 }
291 
292 int
293 spdk_json_write_uint128(struct spdk_json_write_ctx *w, uint64_t low_val, uint64_t high_val)
294 {
295 	char buf[128] = {'\0'};
296 	uint64_t low = low_val, high = high_val;
297 	int count = 0;
298 
299 	if (begin_value(w)) { return fail(w); }
300 
301 	if (high != 0) {
302 		char temp_buf[128] = {'\0'};
303 		uint64_t seg;
304 		unsigned __int128 total = (unsigned __int128)low +
305 					  ((unsigned __int128)high << 64);
306 
307 		while (total) {
308 			seg = total % 10000000000;
309 			total = total / 10000000000;
310 			if (total) {
311 				count = snprintf(temp_buf, 128, "%010" PRIu64 "%s", seg, buf);
312 			} else {
313 				count = snprintf(temp_buf, 128, "%" PRIu64 "%s", seg, buf);
314 			}
315 
316 			if (count <= 0 || (size_t)count >= sizeof(temp_buf)) {
317 				return fail(w);
318 			}
319 
320 			snprintf(buf, 128, "%s", temp_buf);
321 		}
322 	} else {
323 		count = snprintf(buf, sizeof(buf), "%" PRIu64, low);
324 
325 		if (count <= 0 || (size_t)count >= sizeof(buf)) { return fail(w); }
326 	}
327 
328 	return emit(w, buf, count);
329 }
330 
331 int
332 spdk_json_write_named_uint128(struct spdk_json_write_ctx *w, const char *name,
333 			      uint64_t low_val, uint64_t high_val)
334 {
335 	int rc = spdk_json_write_name(w, name);
336 
337 	return rc ? rc : spdk_json_write_uint128(w, low_val, high_val);
338 }
339 
340 static void
341 write_hex_4(void *dest, uint16_t val)
342 {
343 	uint8_t *p = dest;
344 	char hex[] = "0123456789ABCDEF";
345 
346 	p[0] = hex[(val >> 12)];
347 	p[1] = hex[(val >> 8) & 0xF];
348 	p[2] = hex[(val >> 4) & 0xF];
349 	p[3] = hex[val & 0xF];
350 }
351 
352 static inline int
353 write_codepoint(struct spdk_json_write_ctx *w, uint32_t codepoint)
354 {
355 	static const uint8_t escapes[] = {
356 		['\b'] = 'b',
357 		['\f'] = 'f',
358 		['\n'] = 'n',
359 		['\r'] = 'r',
360 		['\t'] = 't',
361 		['"'] = '"',
362 		['\\'] = '\\',
363 		/*
364 		 * Forward slash (/) is intentionally not converted to an escape
365 		 *  (it is valid unescaped).
366 		 */
367 	};
368 	uint16_t high, low;
369 	char out[13];
370 	size_t out_len;
371 
372 	if (codepoint < sizeof(escapes) && escapes[codepoint]) {
373 		out[0] = '\\';
374 		out[1] = escapes[codepoint];
375 		out_len = 2;
376 	} else if (codepoint >= 0x20 && codepoint < 0x7F) {
377 		/*
378 		 * Encode plain ASCII directly (except 0x7F, since it is really
379 		 *  a control character, despite the JSON spec not considering it one).
380 		 */
381 		out[0] = (uint8_t)codepoint;
382 		out_len = 1;
383 	} else if (codepoint < 0x10000) {
384 		out[0] = '\\';
385 		out[1] = 'u';
386 		write_hex_4(&out[2], (uint16_t)codepoint);
387 		out_len = 6;
388 	} else {
389 		utf16_encode_surrogate_pair(codepoint, &high, &low);
390 		out[0] = '\\';
391 		out[1] = 'u';
392 		write_hex_4(&out[2], high);
393 		out[6] = '\\';
394 		out[7] = 'u';
395 		write_hex_4(&out[8], low);
396 		out_len = 12;
397 	}
398 
399 	return emit(w, out, out_len);
400 }
401 
402 static int
403 write_string_or_name(struct spdk_json_write_ctx *w, const char *val, size_t len)
404 {
405 	const uint8_t *p = val;
406 	const uint8_t *end = val + len;
407 
408 	if (emit(w, "\"", 1)) { return fail(w); }
409 
410 	while (p != end) {
411 		int codepoint_len;
412 		uint32_t codepoint;
413 
414 		codepoint_len = utf8_valid(p, end);
415 		switch (codepoint_len) {
416 		case 1:
417 			codepoint = utf8_decode_unsafe_1(p);
418 			break;
419 		case 2:
420 			codepoint = utf8_decode_unsafe_2(p);
421 			break;
422 		case 3:
423 			codepoint = utf8_decode_unsafe_3(p);
424 			break;
425 		case 4:
426 			codepoint = utf8_decode_unsafe_4(p);
427 			break;
428 		default:
429 			return fail(w);
430 		}
431 
432 		if (write_codepoint(w, codepoint)) { return fail(w); }
433 		p += codepoint_len;
434 	}
435 
436 	return emit(w, "\"", 1);
437 }
438 
439 static int
440 write_string_or_name_utf16le(struct spdk_json_write_ctx *w, const uint16_t *val, size_t len)
441 {
442 	const uint16_t *p = val;
443 	const uint16_t *end = val + len;
444 
445 	if (emit(w, "\"", 1)) { return fail(w); }
446 
447 	while (p != end) {
448 		int codepoint_len;
449 		uint32_t codepoint;
450 
451 		codepoint_len = utf16le_valid(p, end);
452 		switch (codepoint_len) {
453 		case 1:
454 			codepoint = from_le16(&p[0]);
455 			break;
456 		case 2:
457 			codepoint = utf16_decode_surrogate_pair(from_le16(&p[0]), from_le16(&p[1]));
458 			break;
459 		default:
460 			return fail(w);
461 		}
462 
463 		if (write_codepoint(w, codepoint)) { return fail(w); }
464 		p += codepoint_len;
465 	}
466 
467 	return emit(w, "\"", 1);
468 }
469 
470 int
471 spdk_json_write_string_raw(struct spdk_json_write_ctx *w, const char *val, size_t len)
472 {
473 	if (begin_value(w)) { return fail(w); }
474 	return write_string_or_name(w, val, len);
475 }
476 
477 int
478 spdk_json_write_string(struct spdk_json_write_ctx *w, const char *val)
479 {
480 	return spdk_json_write_string_raw(w, val, strlen(val));
481 }
482 
483 int
484 spdk_json_write_string_utf16le_raw(struct spdk_json_write_ctx *w, const uint16_t *val, size_t len)
485 {
486 	if (begin_value(w)) { return fail(w); }
487 	return write_string_or_name_utf16le(w, val, len);
488 }
489 
490 int
491 spdk_json_write_string_utf16le(struct spdk_json_write_ctx *w, const uint16_t *val)
492 {
493 	const uint16_t *p;
494 	size_t len;
495 
496 	for (len = 0, p = val; *p; p++) {
497 		len++;
498 	}
499 
500 	return spdk_json_write_string_utf16le_raw(w, val, len);
501 }
502 
503 int
504 spdk_json_write_string_fmt(struct spdk_json_write_ctx *w, const char *fmt, ...)
505 {
506 	va_list args;
507 	int rc;
508 
509 	va_start(args, fmt);
510 	rc = spdk_json_write_string_fmt_v(w, fmt, args);
511 	va_end(args);
512 
513 	return rc;
514 }
515 
516 int
517 spdk_json_write_string_fmt_v(struct spdk_json_write_ctx *w, const char *fmt, va_list args)
518 {
519 	char *s;
520 	int rc;
521 
522 	s = spdk_vsprintf_alloc(fmt, args);
523 	if (s == NULL) {
524 		return -1;
525 	}
526 
527 	rc = spdk_json_write_string(w, s);
528 	free(s);
529 	return rc;
530 }
531 
532 int
533 spdk_json_write_array_begin(struct spdk_json_write_ctx *w)
534 {
535 	if (begin_value(w)) { return fail(w); }
536 	w->first_value = true;
537 	w->new_indent = true;
538 	w->indent++;
539 	if (emit(w, "[", 1)) { return fail(w); }
540 	return 0;
541 }
542 
543 int
544 spdk_json_write_array_end(struct spdk_json_write_ctx *w)
545 {
546 	w->first_value = false;
547 	if (w->indent == 0) { return fail(w); }
548 	w->indent--;
549 	if (!w->new_indent) {
550 		if (emit_fmt(w, "\n", 1)) { return fail(w); }
551 		if (emit_indent(w)) { return fail(w); }
552 	}
553 	w->new_indent = false;
554 	return emit(w, "]", 1);
555 }
556 
557 int
558 spdk_json_write_object_begin(struct spdk_json_write_ctx *w)
559 {
560 	if (begin_value(w)) { return fail(w); }
561 	w->first_value = true;
562 	w->new_indent = true;
563 	w->indent++;
564 	if (emit(w, "{", 1)) { return fail(w); }
565 	return 0;
566 }
567 
568 int
569 spdk_json_write_object_end(struct spdk_json_write_ctx *w)
570 {
571 	w->first_value = false;
572 	w->indent--;
573 	if (!w->new_indent) {
574 		if (emit_fmt(w, "\n", 1)) { return fail(w); }
575 		if (emit_indent(w)) { return fail(w); }
576 	}
577 	w->new_indent = false;
578 	return emit(w, "}", 1);
579 }
580 
581 int
582 spdk_json_write_name_raw(struct spdk_json_write_ctx *w, const char *name, size_t len)
583 {
584 	/* TODO: check that container is an object */
585 	if (begin_value(w)) { return fail(w); }
586 	if (write_string_or_name(w, name, len)) { return fail(w); }
587 	w->first_value = true;
588 	if (emit(w, ":", 1)) { return fail(w); }
589 	return emit_fmt(w, " ", 1);
590 }
591 
592 int
593 spdk_json_write_name(struct spdk_json_write_ctx *w, const char *name)
594 {
595 	return spdk_json_write_name_raw(w, name, strlen(name));
596 }
597 
598 int
599 spdk_json_write_val(struct spdk_json_write_ctx *w, const struct spdk_json_val *val)
600 {
601 	size_t num_values, i;
602 
603 	switch (val->type) {
604 	case SPDK_JSON_VAL_NUMBER:
605 		return spdk_json_write_val_raw(w, val->start, val->len);
606 
607 	case SPDK_JSON_VAL_STRING:
608 		return spdk_json_write_string_raw(w, val->start, val->len);
609 
610 	case SPDK_JSON_VAL_NAME:
611 		return spdk_json_write_name_raw(w, val->start, val->len);
612 
613 	case SPDK_JSON_VAL_TRUE:
614 		return spdk_json_write_bool(w, true);
615 
616 	case SPDK_JSON_VAL_FALSE:
617 		return spdk_json_write_bool(w, false);
618 
619 	case SPDK_JSON_VAL_NULL:
620 		return spdk_json_write_null(w);
621 
622 	case SPDK_JSON_VAL_ARRAY_BEGIN:
623 	case SPDK_JSON_VAL_OBJECT_BEGIN:
624 		num_values = val[0].len;
625 
626 		if (val[0].type == SPDK_JSON_VAL_OBJECT_BEGIN) {
627 			if (spdk_json_write_object_begin(w)) {
628 				return fail(w);
629 			}
630 		} else {
631 			if (spdk_json_write_array_begin(w)) {
632 				return fail(w);
633 			}
634 		}
635 
636 		/* Loop up to and including the _END value */
637 		for (i = 0; i < num_values + 1;) {
638 			if (spdk_json_write_val(w, &val[i + 1])) {
639 				return fail(w);
640 			}
641 			if (val[i + 1].type == SPDK_JSON_VAL_ARRAY_BEGIN ||
642 			    val[i + 1].type == SPDK_JSON_VAL_OBJECT_BEGIN) {
643 				i += val[i + 1].len + 2;
644 			} else {
645 				i++;
646 			}
647 		}
648 		return 0;
649 
650 	case SPDK_JSON_VAL_ARRAY_END:
651 		return spdk_json_write_array_end(w);
652 
653 	case SPDK_JSON_VAL_OBJECT_END:
654 		return spdk_json_write_object_end(w);
655 
656 	case SPDK_JSON_VAL_INVALID:
657 		/* Handle INVALID to make the compiler happy (and catch other unhandled types) */
658 		return fail(w);
659 	}
660 
661 	return fail(w);
662 }
663 
664 int spdk_json_write_named_null(struct spdk_json_write_ctx *w, const char *name)
665 {
666 	int rc = spdk_json_write_name(w, name);
667 	return rc ? rc : spdk_json_write_null(w);
668 }
669 
670 int spdk_json_write_named_bool(struct spdk_json_write_ctx *w, const char *name, bool val)
671 {
672 	int rc = spdk_json_write_name(w, name);
673 
674 	return rc ? rc : spdk_json_write_bool(w, val);
675 }
676 
677 int spdk_json_write_named_uint8(struct spdk_json_write_ctx *w, const char *name, uint8_t val)
678 {
679 	int rc = spdk_json_write_name(w, name);
680 
681 	return rc ? rc : spdk_json_write_uint8(w, val);
682 }
683 
684 int spdk_json_write_named_uint16(struct spdk_json_write_ctx *w, const char *name, uint16_t val)
685 {
686 	int rc = spdk_json_write_name(w, name);
687 
688 	return rc ? rc : spdk_json_write_uint16(w, val);
689 }
690 
691 int spdk_json_write_named_int32(struct spdk_json_write_ctx *w, const char *name, int32_t val)
692 {
693 	int rc = spdk_json_write_name(w, name);
694 
695 	return rc ? rc : spdk_json_write_int32(w, val);
696 }
697 
698 int spdk_json_write_named_uint32(struct spdk_json_write_ctx *w, const char *name, uint32_t val)
699 {
700 	int rc = spdk_json_write_name(w, name);
701 
702 	return rc ? rc : spdk_json_write_uint32(w, val);
703 }
704 
705 int spdk_json_write_named_int64(struct spdk_json_write_ctx *w, const char *name, int64_t val)
706 {
707 	int rc = spdk_json_write_name(w, name);
708 
709 	return rc ? rc : spdk_json_write_int64(w, val);
710 }
711 
712 int spdk_json_write_named_uint64(struct spdk_json_write_ctx *w, const char *name, uint64_t val)
713 {
714 	int rc = spdk_json_write_name(w, name);
715 
716 	return rc ? rc : spdk_json_write_uint64(w, val);
717 }
718 
719 int spdk_json_write_named_string(struct spdk_json_write_ctx *w, const char *name, const char *val)
720 {
721 	int rc = spdk_json_write_name(w, name);
722 
723 	return rc ? rc : spdk_json_write_string(w, val);
724 }
725 
726 int spdk_json_write_named_string_fmt(struct spdk_json_write_ctx *w, const char *name,
727 				     const char *fmt, ...)
728 {
729 	va_list args;
730 	int rc;
731 
732 	va_start(args, fmt);
733 	rc = spdk_json_write_named_string_fmt_v(w, name, fmt, args);
734 	va_end(args);
735 
736 	return rc;
737 }
738 
739 int spdk_json_write_named_string_fmt_v(struct spdk_json_write_ctx *w, const char *name,
740 				       const char *fmt, va_list args)
741 {
742 	char *s;
743 	int rc;
744 
745 	rc = spdk_json_write_name(w, name);
746 	if (rc) {
747 		return rc;
748 	}
749 
750 	s = spdk_vsprintf_alloc(fmt, args);
751 
752 	if (s == NULL) {
753 		return -1;
754 	}
755 
756 	rc = spdk_json_write_string(w, s);
757 	free(s);
758 	return rc;
759 }
760 
761 int spdk_json_write_named_array_begin(struct spdk_json_write_ctx *w, const char *name)
762 {
763 	int rc = spdk_json_write_name(w, name);
764 
765 	return rc ? rc : spdk_json_write_array_begin(w);
766 }
767 
768 int spdk_json_write_named_object_begin(struct spdk_json_write_ctx *w, const char *name)
769 {
770 	int rc = spdk_json_write_name(w, name);
771 
772 	return rc ? rc : spdk_json_write_object_begin(w);
773 }
774