Concord - C Discord API library
A Discord API wrapper library written in C
json-build.h
Go to the documentation of this file.
1/*
2 * Special thanks to Christopher Wellons (aka skeeto) for giving valuable
3 * feedback that helped improve this lib.
4 *
5 * See: https://www.reddit.com/r/C_Programming/comments/sf95m3/comment/huojrjn
6 */
7#ifndef JSON_BUILD_H
8#define JSON_BUILD_H
9
10#include <stddef.h>
11
12#ifdef __cplusplus
13extern "C" {
14#endif
15
16#ifdef JSONB_STATIC
17#define JSONB_API static
18#else
19#define JSONB_API extern
20#endif
21
22#ifndef JSONB_MAX_DEPTH
30#define JSONB_MAX_DEPTH 128
31#endif /* JSONB_MAX_DEPTH */
32
34typedef enum jsonbcode {
48
60};
61
63typedef struct jsonb {
69 size_t pos;
71
80#define jsonb_reset(builder) ((builder)->pos = 0)
81
87JSONB_API void jsonb_init(jsonb *builder);
88
97JSONB_API jsonbcode jsonb_object(jsonb *builder, char buf[], size_t bufsize);
98
108 char *p_buf[],
109 size_t *p_bufsize);
110
120 char buf[],
121 size_t bufsize);
122
132 char *p_buf[],
133 size_t *p_bufsize);
134
146 jsonb *builder, char buf[], size_t bufsize, const char key[], size_t len);
147
159 char *p_buf[],
160 size_t *p_bufsize,
161 const char key[],
162 size_t len);
163
172JSONB_API jsonbcode jsonb_array(jsonb *builder, char buf[], size_t bufsize);
173
183 char *p_buf[],
184 size_t *p_bufsize);
185
195 char buf[],
196 size_t bufsize);
197
207 char *p_buf[],
208 size_t *p_bufsize);
209
221 char buf[],
222 size_t bufsize,
223 const char token[],
224 size_t len);
225
237 char *p_buf[],
238 size_t *p_bufsize,
239 const char token[],
240 size_t len);
241
252 char buf[],
253 size_t bufsize,
254 int boolean);
255
266 char *p_buf[],
267 size_t *p_bufsize,
268 int boolean);
269
278JSONB_API jsonbcode jsonb_null(jsonb *builder, char buf[], size_t bufsize);
279
289 char *p_buf[],
290 size_t *p_bufsize);
291
303 jsonb *builder, char buf[], size_t bufsize, const char str[], size_t len);
304
316 char *p_buf[],
317 size_t *p_bufsize,
318 const char str[],
319 size_t len);
320
331 char buf[],
332 size_t bufsize,
333 double number);
334
345 char *p_buf[],
346 size_t *p_bufsize,
347 double number);
348
349#ifndef JSONB_HEADER
350#include <stdio.h>
351#include <stdlib.h>
352#ifndef JSONB_DEBUG
353#define TRACE(prev, next) next
354#define DECORATOR(a)
355#else
356static const char *
357_jsonb_eval_state(enum jsonbstate state)
358{
359 switch (state) {
360 case JSONB_ARRAY_OR_OBJECT_OR_VALUE: return "array or object or value";
361 case JSONB_OBJECT_KEY_OR_CLOSE: return "object key or close";
362 case JSONB_OBJECT_NEXT_KEY_OR_CLOSE: return "object next key or close";
363 case JSONB_OBJECT_VALUE: return "object value";
364 case JSONB_ARRAY_VALUE_OR_CLOSE: return "array value or close";
365 case JSONB_ARRAY_NEXT_VALUE_OR_CLOSE: return "array next value or close";
366 case JSONB_ERROR: return "error";
367 case JSONB_DONE: return "done";
368 default: return "unknown";
369 }
370}
371#define TRACE(prev, next) \
372 do { \
373 enum jsonbstate _prev = prev, _next = next; \
374 fprintf(stderr, "%s():L%d | %s -> %s\n", __func__, __LINE__, \
375 _jsonb_eval_state(_prev), _jsonb_eval_state(_next)); \
376 } while (0)
377#define DECORATOR(d) d
378#endif /* JSONB_DEBUG */
379
380#define STACK_HEAD(b, state) *(b)->top = (state)
381#define STACK_PUSH(b, state) TRACE(*(b)->top, *++(b)->top = (state))
382#define STACK_POP(b) TRACE(*(b)->top, DECORATOR(*)--(b)->top)
383
384#define BUFFER_COPY_CHAR_STATIC(b, c, _pos, buf, bufsize) \
385 do { \
386 if ((b)->pos + (_pos) + 1 + 1 > (bufsize)) { \
387 (buf)[(b)->pos] = '\0'; \
388 return JSONB_ERROR_NOMEM; \
389 } \
390 (buf)[(b)->pos + (_pos)++] = (c); \
391 (buf)[(b)->pos + (_pos)] = '\0'; \
392 } while (0)
393#define BUFFER_COPY_STATIC(b, value, len, _pos, buf, bufsize) \
394 do { \
395 size_t i; \
396 if ((b)->pos + (_pos) + (len) + 1 > (bufsize)) { \
397 (buf)[(b)->pos] = '\0'; \
398 return JSONB_ERROR_NOMEM; \
399 } \
400 for (i = 0; i < (len); ++i) \
401 (buf)[(b)->pos + (_pos) + i] = (value)[i]; \
402 (_pos) += (len); \
403 (buf)[(b)->pos + (_pos)] = '\0'; \
404 } while (0)
405#define BUFFER_COPY_CHAR_REALLOC(b, c, _pos, p_buf, p_bufsize) \
406 do { \
407 if ((b)->pos + (_pos) + 1 + 1 > *p_bufsize) { \
408 char *new_buf = NULL; \
409 const size_t needed = (b)->pos + (_pos) + 1 + 1; \
410 size_t new_size = *p_bufsize + (*p_bufsize >> 1); /* 1.5x */ \
411 if (new_size < needed) new_size = needed; \
412 if (new_size < *p_bufsize) return JSONB_ERROR_OVERFLOW; \
413 new_buf = realloc(*p_buf, new_size); \
414 if (!new_buf) return JSONB_ERROR_NOMEM; \
415 *p_buf = new_buf; \
416 *p_bufsize = new_size; \
417 } \
418 (*p_buf)[(b)->pos + (_pos)++] = (c); \
419 (*p_buf)[(b)->pos + (_pos)] = '\0'; \
420 } while (0)
421#define BUFFER_COPY_REALLOC(b, value, len, _pos, p_buf, p_bufsize) \
422 do { \
423 size_t i; \
424 if ((b)->pos + (_pos) + (len) + 1 > *p_bufsize) { \
425 char *new_buf = NULL; \
426 const size_t needed = (b)->pos + (_pos) + (len) + 1; \
427 size_t new_size = *p_bufsize + (*p_bufsize >> 1); /* 1.5x */ \
428 if (new_size < needed) new_size = needed; \
429 if (new_size < *p_bufsize) return JSONB_ERROR_OVERFLOW; \
430 new_buf = realloc(*p_buf, new_size); \
431 if (!new_buf) return JSONB_ERROR_NOMEM; \
432 *p_buf = new_buf; \
433 *p_bufsize = new_size; \
434 } \
435 for (i = 0; i < (len); ++i) \
436 (*p_buf)[(b)->pos + (_pos) + i] = (value)[i]; \
437 (_pos) += (len); \
438 (*p_buf)[(b)->pos + (_pos)] = '\0'; \
439 } while (0)
440
441JSONB_API void
443{
444 static jsonb empty_builder;
445 *b = empty_builder;
446 b->top = b->stack;
447}
448
449#define JSONB_OBJECT_EXEC(_type, buf, bufsize) \
450 enum jsonbstate new_state; \
451 size_t pos = 0; \
452 if (b->top - b->stack >= JSONB_MAX_DEPTH) return JSONB_ERROR_STACK; \
453 switch (*b->top) { \
454 case JSONB_ARRAY_NEXT_VALUE_OR_CLOSE: \
455 BUFFER_COPY_CHAR_##_type(b, ',', pos, buf, bufsize); \
456 /* fall-through */ \
457 case JSONB_ARRAY_VALUE_OR_CLOSE: \
458 new_state = JSONB_ARRAY_NEXT_VALUE_OR_CLOSE; \
459 break; \
460 case JSONB_OBJECT_VALUE: \
461 new_state = JSONB_OBJECT_NEXT_KEY_OR_CLOSE; \
462 break; \
463 case JSONB_ARRAY_OR_OBJECT_OR_VALUE: \
464 new_state = JSONB_DONE; \
465 break; \
466 default: \
467 STACK_HEAD(b, JSONB_ERROR); \
468 /* fall-through */ \
469 case JSONB_DONE: \
470 case JSONB_ERROR: \
471 return JSONB_ERROR_INPUT; \
472 } \
473 BUFFER_COPY_CHAR_##_type(b, '{', pos, buf, bufsize); \
474 STACK_HEAD(b, new_state); \
475 STACK_PUSH(b, JSONB_OBJECT_KEY_OR_CLOSE); \
476 b->pos += pos; \
477 return JSONB_OK
478
480jsonb_object(jsonb *b, char buf[], size_t bufsize)
481{
482 JSONB_OBJECT_EXEC(STATIC, buf, bufsize);
483}
484
486jsonb_object_auto(jsonb *b, char *p_buf[], size_t *p_bufsize)
487{
488 JSONB_OBJECT_EXEC(REALLOC, p_buf, p_bufsize);
489}
490
491#define JSONB_OBJECT_POP_EXEC(_type, buf, bufsize) \
492 enum jsonbcode code; \
493 size_t pos = 0; \
494 switch (*b->top) { \
495 case JSONB_OBJECT_KEY_OR_CLOSE: \
496 case JSONB_OBJECT_NEXT_KEY_OR_CLOSE: \
497 code = b->stack == b->top - 1 ? JSONB_END : JSONB_OK; \
498 break; \
499 default: \
500 STACK_HEAD(b, JSONB_ERROR); \
501 /* fall-through */ \
502 case JSONB_DONE: \
503 case JSONB_ERROR: \
504 return JSONB_ERROR_INPUT; \
505 } \
506 BUFFER_COPY_CHAR_##_type(b, '}', pos, buf, bufsize); \
507 STACK_POP(b); \
508 b->pos += pos; \
509 return code
510
512jsonb_object_pop(jsonb *b, char buf[], size_t bufsize)
513{
514 JSONB_OBJECT_POP_EXEC(STATIC, buf, bufsize);
515}
516
518jsonb_object_pop_auto(jsonb *b, char *p_buf[], size_t *p_bufsize)
519{
520 JSONB_OBJECT_POP_EXEC(REALLOC, p_buf, p_bufsize);
521}
522
523static jsonbcode
524_jsonb_escape_STATIC(size_t *pos,
525 char buf[],
526 size_t bufsize,
527 unsigned offset,
528 const char str[],
529 size_t len)
530{
531 char *esc_tok = NULL, _esc_tok[8] = "\\u00";
532 char *esc_buf = NULL;
533 int extra_bytes = 0;
534 size_t i;
535
536 buf += offset;
537 bufsize -= offset;
538second_iter:
539 /* 1st iteration, esc_buf is NULL and count extra_bytes needed for escaping
540 * 2st iteration, esc_buf is not NULL, and does escaping. */
541 for (i = 0; i < len; ++i) {
542 unsigned char c = str[i];
543 esc_tok = NULL;
544 switch (c) {
545 case 0x22: esc_tok = "\\\""; break;
546 case 0x5C: esc_tok = "\\\\"; break;
547 case '\b': esc_tok = "\\b"; break;
548 case '\f': esc_tok = "\\f"; break;
549 case '\n': esc_tok = "\\n"; break;
550 case '\r': esc_tok = "\\r"; break;
551 case '\t': esc_tok = "\\t"; break;
552 default: if (c <= 0x1F) {
553 static const char tohex[] = "0123456789abcdef";
554 _esc_tok[4] = tohex[c >> 4];
555 _esc_tok[5] = tohex[c & 0xF];
556 _esc_tok[6] = 0;
557 esc_tok = _esc_tok;
558 }
559 }
560 if (esc_tok) {
561 int j;
562 for (j = 0; esc_tok[j]; j++) {
563 if (!esc_buf) /* count how many extra bytes are needed */
564 continue;
565 *esc_buf++ = esc_tok[j];
566 }
567 extra_bytes += j - 1;
568 }
569 else if (esc_buf) {
570 *esc_buf++ = c;
571 }
572 }
573
574 if (*pos + len + extra_bytes > bufsize) {
575 *buf = '\0';
576 return JSONB_ERROR_NOMEM;
577 }
578
579 if (esc_buf) {
580 *pos += len + extra_bytes;
581 return JSONB_OK;
582 }
583 if (!extra_bytes) {
584 size_t j;
585 for (j = 0; j < len; ++j)
586 buf[*pos + j] = str[j];
587 *pos += len;
588 return JSONB_OK;
589 }
590 esc_buf = buf + *pos;
591 extra_bytes = 0;
592 goto second_iter;
593}
594
595static jsonbcode
596_jsonb_escape_REALLOC(size_t *pos,
597 char *p_buf[],
598 size_t *p_bufsize,
599 unsigned offset,
600 const char str[],
601 size_t len)
602{
603 char *esc_tok = NULL, _esc_tok[8] = "\\u00";
604 char *esc_buf = NULL;
605 int extra_bytes = 0;
606 size_t i;
607
608 int second_pass = 0;
609 ptrdiff_t esc_buf_offset = 0;
610
611 char *buf;
612 size_t bufsize;
613restart:
614 buf = *p_buf + offset;
615 bufsize = *p_bufsize - offset;
616
617 if (second_pass && esc_buf) esc_buf = buf + esc_buf_offset;
618
619second_iter:
620 /* 1st iteration, esc_buf is NULL and count extra_bytes needed for escaping
621 * 2st iteration, esc_buf is not NULL, and does escaping. */
622 for (i = 0; i < len; ++i) {
623 unsigned char c = str[i];
624 esc_tok = NULL;
625 switch (c) { case 0x22: esc_tok = "\\\""; break;
626 case 0x5C: esc_tok = "\\\\"; break;
627 case '\b': esc_tok = "\\b"; break;
628 case '\f': esc_tok = "\\f"; break;
629 case '\n': esc_tok = "\\n"; break;
630 case '\r': esc_tok = "\\r"; break;
631 case '\t': esc_tok = "\\t"; break;
632 default: if (c <= 0x1F) {
633 static const char tohex[] = "0123456789abcdef";
634 _esc_tok[4] = tohex[c >> 4];
635 _esc_tok[5] = tohex[c & 0xF];
636 _esc_tok[6] = 0;
637 esc_tok = _esc_tok;
638 }
639 }
640 if (esc_tok) {
641 int j;
642 for (j = 0; esc_tok[j]; j++) {
643 if (!esc_buf) /* count how many extra bytes are needed */
644 continue;
645 *esc_buf++ = esc_tok[j];
646 }
647 extra_bytes += j - 1;
648 }
649 else if (esc_buf) {
650 *esc_buf++ = c;
651 }
652 }
653
654 if (*pos + len + extra_bytes + 1 > bufsize) {
655 char *new_buf = NULL;
656 const size_t needed = *pos + len + extra_bytes + 1;
657 size_t new_size = *p_bufsize + (*p_bufsize >> 1); /* 1.5x */
658 if (new_size < needed) new_size = needed;
659 if (new_size < *p_bufsize) return JSONB_ERROR_OVERFLOW;
660 new_buf = realloc(*p_buf, new_size);
661 if (!new_buf) return JSONB_ERROR_NOMEM;
662 if (esc_buf) esc_buf_offset = esc_buf - buf;
663 *p_buf = new_buf;
664 *p_bufsize = new_size;
665 second_pass = 1;
666 goto restart;
667 }
668
669 if (esc_buf) {
670 *pos += len + extra_bytes;
671 return JSONB_OK;
672 }
673 if (!extra_bytes) {
674 size_t j;
675 for (j = 0; j < len; ++j)
676 buf[*pos + j] = str[j];
677 *pos += len;
678 return JSONB_OK;
679 }
680 esc_buf = buf + *pos;
681 extra_bytes = 0;
682 goto second_iter;
683}
684
685#define JSONB_KEY_EXEC(_type, buf, bufsize, key, len) \
686 size_t pos = 0; \
687 switch (*b->top) { \
688 case JSONB_OBJECT_NEXT_KEY_OR_CLOSE: \
689 BUFFER_COPY_CHAR_##_type(b, ',', pos, buf, bufsize); \
690 /* fall-through */ \
691 case JSONB_OBJECT_KEY_OR_CLOSE: { \
692 enum jsonbcode ret; \
693 BUFFER_COPY_CHAR_##_type(b, '"', pos, buf, bufsize); \
694 ret = _jsonb_escape_##_type(&pos, buf, bufsize, b->pos, key, len); \
695 if (ret != JSONB_OK) return ret; \
696 BUFFER_COPY_##_type(b, "\":", 2, pos, buf, bufsize); \
697 STACK_HEAD(b, JSONB_OBJECT_VALUE); \
698 } break; \
699 default: \
700 STACK_HEAD(b, JSONB_ERROR); \
701 /* fall-through */ \
702 case JSONB_DONE: \
703 return JSONB_ERROR_INPUT; \
704 } \
705 b->pos += pos; \
706 return JSONB_OK
707
709jsonb_key(jsonb *b, char buf[], size_t bufsize, const char key[], size_t len)
710{
711 JSONB_KEY_EXEC(STATIC, buf, bufsize, key, len);
712}
713
716 jsonb *b, char *p_buf[], size_t *p_bufsize, const char key[], size_t len)
717{
718 JSONB_KEY_EXEC(REALLOC, p_buf, p_bufsize, key, len);
719}
720
721#define JSONB_ARRAY_EXEC(_type, buf, bufsize) \
722 enum jsonbstate new_state; \
723 size_t pos = 0; \
724 if (b->top - b->stack >= JSONB_MAX_DEPTH) return JSONB_ERROR_STACK; \
725 switch (*b->top) { \
726 case JSONB_ARRAY_NEXT_VALUE_OR_CLOSE: \
727 BUFFER_COPY_CHAR_##_type(b, ',', pos, buf, bufsize); \
728 /* fall-through */ \
729 case JSONB_ARRAY_VALUE_OR_CLOSE: \
730 new_state = JSONB_ARRAY_NEXT_VALUE_OR_CLOSE; \
731 break; \
732 case JSONB_OBJECT_VALUE: \
733 new_state = JSONB_OBJECT_NEXT_KEY_OR_CLOSE; \
734 break; \
735 case JSONB_ARRAY_OR_OBJECT_OR_VALUE: \
736 new_state = JSONB_DONE; \
737 break; \
738 default: \
739 STACK_HEAD(b, JSONB_ERROR); \
740 /* fall-through */ \
741 case JSONB_DONE: \
742 case JSONB_ERROR: \
743 return JSONB_ERROR_INPUT; \
744 } \
745 BUFFER_COPY_CHAR_##_type(b, '[', pos, buf, bufsize); \
746 STACK_HEAD(b, new_state); \
747 STACK_PUSH(b, JSONB_ARRAY_VALUE_OR_CLOSE); \
748 b->pos += pos; \
749 return JSONB_OK
750
752jsonb_array(jsonb *b, char buf[], size_t bufsize)
753{
754 JSONB_ARRAY_EXEC(STATIC, buf, bufsize);
755}
756
758jsonb_array_auto(jsonb *b, char *p_buf[], size_t *p_bufsize)
759{
760 JSONB_ARRAY_EXEC(REALLOC, p_buf, p_bufsize);
761}
762
763#define JSONB_ARRAY_POP_EXEC(_type, buf, bufsize) \
764 enum jsonbcode code; \
765 size_t pos = 0; \
766 switch (*b->top) { \
767 case JSONB_ARRAY_VALUE_OR_CLOSE: \
768 case JSONB_ARRAY_NEXT_VALUE_OR_CLOSE: \
769 code = b->stack == b->top - 1 ? JSONB_END : JSONB_OK; \
770 break; \
771 default: \
772 STACK_HEAD(b, JSONB_ERROR); \
773 /* fall-through */ \
774 case JSONB_DONE: \
775 case JSONB_ERROR: \
776 return JSONB_ERROR_INPUT; \
777 } \
778 BUFFER_COPY_CHAR_##_type(b, ']', pos, buf, bufsize); \
779 STACK_POP(b); \
780 b->pos += pos; \
781 return code
782
784jsonb_array_pop(jsonb *b, char buf[], size_t bufsize)
785{
786 JSONB_ARRAY_POP_EXEC(STATIC, buf, bufsize);
787}
788
790jsonb_array_pop_auto(jsonb *b, char *p_buf[], size_t *p_bufsize)
791{
792 JSONB_ARRAY_POP_EXEC(REALLOC, p_buf, p_bufsize);
793}
794
795#define JSONB_TOKEN_EXEC(_type, buf, bufsize, token, len) \
796 enum jsonbstate next_state; \
797 enum jsonbcode code; \
798 size_t pos = 0; \
799 switch (*b->top) { \
800 case JSONB_ARRAY_OR_OBJECT_OR_VALUE: \
801 next_state = JSONB_DONE; \
802 code = JSONB_END; \
803 break; \
804 case JSONB_ARRAY_NEXT_VALUE_OR_CLOSE: \
805 BUFFER_COPY_CHAR_##_type(b, ',', pos, buf, bufsize); \
806 /* fall-through */ \
807 case JSONB_ARRAY_VALUE_OR_CLOSE: \
808 next_state = JSONB_ARRAY_NEXT_VALUE_OR_CLOSE; \
809 code = JSONB_OK; \
810 break; \
811 case JSONB_OBJECT_VALUE: \
812 next_state = JSONB_OBJECT_NEXT_KEY_OR_CLOSE; \
813 code = JSONB_OK; \
814 break; \
815 default: \
816 STACK_HEAD(b, JSONB_ERROR); \
817 /* fall-through */ \
818 case JSONB_DONE: \
819 case JSONB_ERROR: \
820 return JSONB_ERROR_INPUT; \
821 } \
822 BUFFER_COPY_##_type(b, token, len, pos, buf, bufsize); \
823 STACK_HEAD(b, next_state); \
824 b->pos += pos; \
825 return code
826
829 jsonb *b, char buf[], size_t bufsize, const char token[], size_t len)
830{
831 JSONB_TOKEN_EXEC(STATIC, buf, bufsize, token, len);
832}
833
836 jsonb *b, char *p_buf[], size_t *p_bufsize, const char token[], size_t len)
837{
838 JSONB_TOKEN_EXEC(REALLOC, p_buf, p_bufsize, token, len);
839}
840
842jsonb_bool(jsonb *b, char buf[], size_t bufsize, int boolean)
843{
844 return boolean ? jsonb_token(b, buf, bufsize, "true", 4)
845 : jsonb_token(b, buf, bufsize, "false", 5);
846}
847
849jsonb_bool_auto(jsonb *b, char *p_buf[], size_t *p_bufsize, int boolean)
850{
851 return boolean ? jsonb_token_auto(b, p_buf, p_bufsize, "true", 4)
852 : jsonb_token_auto(b, p_buf, p_bufsize, "false", 5);
853}
854
856jsonb_null(jsonb *b, char buf[], size_t bufsize)
857{
858 return jsonb_token(b, buf, bufsize, "null", 4);
859}
860
862jsonb_null_auto(jsonb *b, char *p_buf[], size_t *p_bufsize)
863{
864 return jsonb_token_auto(b, p_buf, p_bufsize, "null", 4);
865}
866
867#define JSONB_STRING_EXEC(_type, buf, bufsize, str, len) \
868 enum jsonbstate next_state; \
869 enum jsonbcode code, ret; \
870 size_t pos = 0; \
871 switch (*b->top) { \
872 case JSONB_ARRAY_OR_OBJECT_OR_VALUE: \
873 next_state = JSONB_DONE; \
874 code = JSONB_END; \
875 break; \
876 case JSONB_ARRAY_NEXT_VALUE_OR_CLOSE: \
877 BUFFER_COPY_CHAR_##_type(b, ',', pos, buf, bufsize); \
878 /* fall-through */ \
879 case JSONB_ARRAY_VALUE_OR_CLOSE: \
880 next_state = JSONB_ARRAY_NEXT_VALUE_OR_CLOSE; \
881 code = JSONB_OK; \
882 break; \
883 case JSONB_OBJECT_VALUE: \
884 next_state = JSONB_OBJECT_NEXT_KEY_OR_CLOSE; \
885 code = JSONB_OK; \
886 break; \
887 default: \
888 STACK_HEAD(b, JSONB_ERROR); \
889 /* fall-through */ \
890 case JSONB_DONE: \
891 case JSONB_ERROR: \
892 return JSONB_ERROR_INPUT; \
893 } \
894 BUFFER_COPY_CHAR_##_type(b, '"', pos, buf, bufsize); \
895 ret = _jsonb_escape_##_type(&pos, buf, bufsize, b->pos, str, len); \
896 if (ret != JSONB_OK) return ret; \
897 BUFFER_COPY_CHAR_##_type(b, '"', pos, buf, bufsize); \
898 STACK_HEAD(b, next_state); \
899 b->pos += pos; \
900 return code
901
904 jsonb *b, char buf[], size_t bufsize, const char str[], size_t len)
905{
906 JSONB_STRING_EXEC(STATIC, buf, bufsize, str, len);
907}
908
911 jsonb *b, char *p_buf[], size_t *p_bufsize, const char str[], size_t len)
912{
913 JSONB_STRING_EXEC(REALLOC, p_buf, p_bufsize, str, len);
914}
915
917jsonb_number(jsonb *b, char buf[], size_t bufsize, double number)
918{
919 char token[32];
920 const long len = sprintf(token, "%.17G", number);
921 return (len < 0) ? JSONB_ERROR_INPUT
922 : jsonb_token(b, buf, bufsize, token, len);
923}
924
926jsonb_number_auto(jsonb *b, char *p_buf[], size_t *p_bufsize, double number)
927{
928 char token[32];
929 const long len = sprintf(token, "%.17G", number);
930 return (len < 0) ? JSONB_ERROR_INPUT
931 : jsonb_token_auto(b, p_buf, p_bufsize, token, len);
932}
933
934#undef TRACE
935#undef DECORATOR
936#undef STACK_HEAD
937#undef STACK_PUSH
938#undef STACK_POP
939#undef BUFFER_COPY_CHAR_STATIC
940#undef BUFFER_COPY_STATIC
941#undef BUFFER_COPY_CHAR_REALLOC
942#undef BUFFER_COPY_REALLOC
943#undef JSONB_OBJECT_EXEC
944#undef JSONB_OBJECT_POP_EXEC
945#undef JSONB_KEY_EXEC
946#undef JSONB_ARRAY_EXEC
947#undef JSONB_ARRAY_POP_EXEC
948#undef JSONB_TOKEN_EXEC
949#undef JSONB_STRING_EXEC
950
951#endif /* JSONB_HEADER */
952
953#ifdef __cplusplus
954}
955#endif
956
957#endif /* JSON_BUILD_H */
struct jsonb jsonb
Handle for building a JSON string.
jsonbcode jsonb_array(jsonb *builder, char buf[], size_t bufsize)
Push an array to the builder.
Definition: json-build.h:752
jsonbstate
json-builder serializing state
Definition: json-build.h:50
@ JSONB_OBJECT_VALUE
Definition: json-build.h:54
@ JSONB_INIT
Definition: json-build.h:51
@ JSONB_ARRAY_VALUE_OR_CLOSE
Definition: json-build.h:56
@ JSONB_OBJECT_NEXT_KEY_OR_CLOSE
Definition: json-build.h:55
@ JSONB_ARRAY_NEXT_VALUE_OR_CLOSE
Definition: json-build.h:57
@ JSONB_ERROR
Definition: json-build.h:58
@ JSONB_DONE
Definition: json-build.h:59
@ JSONB_OBJECT_KEY_OR_CLOSE
Definition: json-build.h:53
@ JSONB_ARRAY_OR_OBJECT_OR_VALUE
Definition: json-build.h:52
#define JSONB_MAX_DEPTH
Definition: json-build.h:30
jsonbcode jsonb_bool_auto(jsonb *builder, char *p_buf[], size_t *p_bufsize, int boolean)
jsonb_bool() with dynamic buffer
Definition: json-build.h:849
jsonbcode jsonb_key(jsonb *builder, char buf[], size_t bufsize, const char key[], size_t len)
Push a key to the builder.
Definition: json-build.h:709
jsonbcode jsonb_token(jsonb *builder, char buf[], size_t bufsize, const char token[], size_t len)
Push a raw JSON token to the builder.
Definition: json-build.h:828
jsonbcode jsonb_string(jsonb *builder, char buf[], size_t bufsize, const char str[], size_t len)
Push a string token to the builder.
Definition: json-build.h:903
#define JSONB_ARRAY_POP_EXEC(_type, buf, bufsize)
Definition: json-build.h:763
#define JSONB_STRING_EXEC(_type, buf, bufsize, str, len)
Definition: json-build.h:867
jsonbcode jsonb_string_auto(jsonb *builder, char *p_buf[], size_t *p_bufsize, const char str[], size_t len)
jsonb_string() with dynamic buffer
Definition: json-build.h:910
jsonbcode jsonb_object(jsonb *builder, char buf[], size_t bufsize)
Push an object to the builder.
Definition: json-build.h:480
jsonbcode jsonb_array_pop_auto(jsonb *builder, char *p_buf[], size_t *p_bufsize)
jsonb_array_pop() with dynamic buffer
Definition: json-build.h:790
jsonbcode jsonb_token_auto(jsonb *builder, char *p_buf[], size_t *p_bufsize, const char token[], size_t len)
jsonb_token() with dynamic buffer
Definition: json-build.h:835
jsonbcode jsonb_object_pop_auto(jsonb *builder, char *p_buf[], size_t *p_bufsize)
jsonb_object_pop() with dynamic buffer
Definition: json-build.h:518
#define JSONB_KEY_EXEC(_type, buf, bufsize, key, len)
Definition: json-build.h:685
jsonbcode jsonb_bool(jsonb *builder, char buf[], size_t bufsize, int boolean)
Push a boolean token to the builder.
Definition: json-build.h:842
jsonbcode jsonb_array_pop(jsonb *builder, char buf[], size_t bufsize)
Pop an array from the builder.
Definition: json-build.h:784
#define JSONB_TOKEN_EXEC(_type, buf, bufsize, token, len)
Definition: json-build.h:795
#define JSONB_OBJECT_EXEC(_type, buf, bufsize)
Definition: json-build.h:449
jsonbcode jsonb_null_auto(jsonb *builder, char *p_buf[], size_t *p_bufsize)
jsonb_null() with dynamic buffer
Definition: json-build.h:862
jsonbcode jsonb_null(jsonb *builder, char buf[], size_t bufsize)
Push a null token to the builder.
Definition: json-build.h:856
jsonbcode jsonb_number(jsonb *builder, char buf[], size_t bufsize, double number)
Push a number token to the builder.
Definition: json-build.h:917
void jsonb_init(jsonb *builder)
Initialize a jsonb handle.
Definition: json-build.h:442
jsonbcode jsonb_object_auto(jsonb *builder, char *p_buf[], size_t *p_bufsize)
jsonb_object() with dynamic buffer
Definition: json-build.h:486
jsonbcode jsonb_number_auto(jsonb *builder, char *p_buf[], size_t *p_bufsize, double number)
jsonb_number() with dynamic buffer
Definition: json-build.h:926
jsonbcode jsonb_array_auto(jsonb *builder, char *p_buf[], size_t *p_bufsize)
jsonb_array() with dynamic buffer
Definition: json-build.h:758
jsonbcode
json-builder return codes
Definition: json-build.h:34
@ JSONB_ERROR_OVERFLOW
Definition: json-build.h:46
@ JSONB_END
Definition: json-build.h:38
@ JSONB_ERROR_INPUT
Definition: json-build.h:42
@ JSONB_ERROR_STACK
Definition: json-build.h:44
@ JSONB_ERROR_NOMEM
Definition: json-build.h:40
@ JSONB_OK
Definition: json-build.h:36
#define JSONB_ARRAY_EXEC(_type, buf, bufsize)
Definition: json-build.h:721
jsonbcode jsonb_object_pop(jsonb *builder, char buf[], size_t bufsize)
Pop an object from the builder.
Definition: json-build.h:512
jsonbcode jsonb_key_auto(jsonb *builder, char *p_buf[], size_t *p_bufsize, const char key[], size_t len)
jsonb_key() with dynamic buffer
Definition: json-build.h:715
#define JSONB_API
Definition: json-build.h:19
#define JSONB_OBJECT_POP_EXEC(_type, buf, bufsize)
Definition: json-build.h:491
Handle for building a JSON string.
Definition: json-build.h:63
enum jsonbstate * top
Definition: json-build.h:67
size_t pos
Definition: json-build.h:69
enum jsonbstate stack[128+1]
Definition: json-build.h:65