1
0

json_writer.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
  2. /*
  3. * Simple streaming JSON writer
  4. *
  5. * This takes care of the annoying bits of JSON syntax like the commas
  6. * after elements
  7. *
  8. * Authors: Stephen Hemminger <stephen@networkplumber.org>
  9. */
  10. #include <stdio.h>
  11. #include <stdbool.h>
  12. #include <stdarg.h>
  13. #include <assert.h>
  14. #include <malloc.h>
  15. #include <inttypes.h>
  16. #include <stdint.h>
  17. #include "json_writer.h"
  18. struct json_writer {
  19. FILE *out;
  20. unsigned depth;
  21. bool pretty;
  22. char sep;
  23. };
  24. static void jsonw_indent(json_writer_t *self)
  25. {
  26. unsigned i;
  27. for (i = 0; i < self->depth; ++i)
  28. fputs(" ", self->out);
  29. }
  30. static void jsonw_eol(json_writer_t *self)
  31. {
  32. if (!self->pretty)
  33. return;
  34. putc('\n', self->out);
  35. jsonw_indent(self);
  36. }
  37. static void jsonw_eor(json_writer_t *self)
  38. {
  39. if (self->sep != '\0')
  40. putc(self->sep, self->out);
  41. self->sep = ',';
  42. }
  43. static void jsonw_puts(json_writer_t *self, const char *str)
  44. {
  45. putc('"', self->out);
  46. for (; *str; ++str)
  47. switch (*str) {
  48. case '\t':
  49. fputs("\\t", self->out);
  50. break;
  51. case '\n':
  52. fputs("\\n", self->out);
  53. break;
  54. case '\r':
  55. fputs("\\r", self->out);
  56. break;
  57. case '\f':
  58. fputs("\\f", self->out);
  59. break;
  60. case '\b':
  61. fputs("\\b", self->out);
  62. break;
  63. case '\\':
  64. fputs("\\\\", self->out);
  65. break;
  66. case '"':
  67. fputs("\\\"", self->out);
  68. break;
  69. default:
  70. putc(*str, self->out);
  71. }
  72. putc('"', self->out);
  73. }
  74. json_writer_t *jsonw_new(FILE *f)
  75. {
  76. json_writer_t *self = malloc(sizeof(*self));
  77. if (self) {
  78. self->out = f;
  79. self->depth = 0;
  80. self->pretty = false;
  81. self->sep = '\0';
  82. }
  83. return self;
  84. }
  85. void jsonw_destroy(json_writer_t **self_p)
  86. {
  87. json_writer_t *self = *self_p;
  88. assert(self->depth == 0);
  89. fputs("\n", self->out);
  90. fflush(self->out);
  91. free(self);
  92. *self_p = NULL;
  93. }
  94. void jsonw_pretty(json_writer_t *self, bool on)
  95. {
  96. self->pretty = on;
  97. }
  98. void jsonw_reset(json_writer_t *self)
  99. {
  100. assert(self->depth == 0);
  101. self->sep = '\0';
  102. }
  103. static void jsonw_begin(json_writer_t *self, int c)
  104. {
  105. jsonw_eor(self);
  106. putc(c, self->out);
  107. ++self->depth;
  108. self->sep = '\0';
  109. }
  110. static void jsonw_end(json_writer_t *self, int c)
  111. {
  112. assert(self->depth > 0);
  113. --self->depth;
  114. if (self->sep != '\0')
  115. jsonw_eol(self);
  116. putc(c, self->out);
  117. self->sep = ',';
  118. }
  119. void jsonw_name(json_writer_t *self, const char *name)
  120. {
  121. jsonw_eor(self);
  122. jsonw_eol(self);
  123. self->sep = '\0';
  124. jsonw_puts(self, name);
  125. putc(':', self->out);
  126. if (self->pretty)
  127. putc(' ', self->out);
  128. }
  129. void jsonw_vprintf_enquote(json_writer_t *self, const char *fmt, va_list ap)
  130. {
  131. jsonw_eor(self);
  132. putc('"', self->out);
  133. vfprintf(self->out, fmt, ap);
  134. putc('"', self->out);
  135. }
  136. void jsonw_printf(json_writer_t *self, const char *fmt, ...)
  137. {
  138. va_list ap;
  139. va_start(ap, fmt);
  140. jsonw_eor(self);
  141. vfprintf(self->out, fmt, ap);
  142. va_end(ap);
  143. }
  144. void jsonw_start_object(json_writer_t *self)
  145. {
  146. jsonw_begin(self, '{');
  147. }
  148. void jsonw_end_object(json_writer_t *self)
  149. {
  150. jsonw_end(self, '}');
  151. }
  152. void jsonw_start_array(json_writer_t *self)
  153. {
  154. jsonw_begin(self, '[');
  155. }
  156. void jsonw_end_array(json_writer_t *self)
  157. {
  158. jsonw_end(self, ']');
  159. }
  160. void jsonw_string(json_writer_t *self, const char *value)
  161. {
  162. jsonw_eor(self);
  163. jsonw_puts(self, value);
  164. }
  165. void jsonw_bool(json_writer_t *self, bool val)
  166. {
  167. jsonw_printf(self, "%s", val ? "true" : "false");
  168. }
  169. void jsonw_null(json_writer_t *self)
  170. {
  171. jsonw_printf(self, "null");
  172. }
  173. void jsonw_float_fmt(json_writer_t *self, const char *fmt, double num)
  174. {
  175. jsonw_printf(self, fmt, num);
  176. }
  177. void jsonw_float(json_writer_t *self, double num)
  178. {
  179. jsonw_printf(self, "%g", num);
  180. }
  181. void jsonw_hu(json_writer_t *self, unsigned short num)
  182. {
  183. jsonw_printf(self, "%hu", num);
  184. }
  185. void jsonw_uint(json_writer_t *self, uint64_t num)
  186. {
  187. jsonw_printf(self, "%"PRIu64, num);
  188. }
  189. void jsonw_lluint(json_writer_t *self, unsigned long long int num)
  190. {
  191. jsonw_printf(self, "%llu", num);
  192. }
  193. void jsonw_int(json_writer_t *self, int64_t num)
  194. {
  195. jsonw_printf(self, "%"PRId64, num);
  196. }
  197. void jsonw_string_field(json_writer_t *self, const char *prop, const char *val)
  198. {
  199. jsonw_name(self, prop);
  200. jsonw_string(self, val);
  201. }
  202. void jsonw_bool_field(json_writer_t *self, const char *prop, bool val)
  203. {
  204. jsonw_name(self, prop);
  205. jsonw_bool(self, val);
  206. }
  207. void jsonw_float_field(json_writer_t *self, const char *prop, double val)
  208. {
  209. jsonw_name(self, prop);
  210. jsonw_float(self, val);
  211. }
  212. void jsonw_float_field_fmt(json_writer_t *self,
  213. const char *prop,
  214. const char *fmt,
  215. double val)
  216. {
  217. jsonw_name(self, prop);
  218. jsonw_float_fmt(self, fmt, val);
  219. }
  220. void jsonw_uint_field(json_writer_t *self, const char *prop, uint64_t num)
  221. {
  222. jsonw_name(self, prop);
  223. jsonw_uint(self, num);
  224. }
  225. void jsonw_hu_field(json_writer_t *self, const char *prop, unsigned short num)
  226. {
  227. jsonw_name(self, prop);
  228. jsonw_hu(self, num);
  229. }
  230. void jsonw_lluint_field(json_writer_t *self,
  231. const char *prop,
  232. unsigned long long int num)
  233. {
  234. jsonw_name(self, prop);
  235. jsonw_lluint(self, num);
  236. }
  237. void jsonw_int_field(json_writer_t *self, const char *prop, int64_t num)
  238. {
  239. jsonw_name(self, prop);
  240. jsonw_int(self, num);
  241. }
  242. void jsonw_null_field(json_writer_t *self, const char *prop)
  243. {
  244. jsonw_name(self, prop);
  245. jsonw_null(self);
  246. }