Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.1-rc2 354 lines 6.8 kB view raw
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 11#include <stdio.h> 12#include <stdbool.h> 13#include <stdarg.h> 14#include <assert.h> 15#include <malloc.h> 16#include <inttypes.h> 17#include <stdint.h> 18#include <linux/compiler.h> 19 20#include "json_writer.h" 21 22struct json_writer { 23 FILE *out; /* output file */ 24 unsigned depth; /* nesting */ 25 bool pretty; /* optional whitepace */ 26 char sep; /* either nul or comma */ 27}; 28 29/* indentation for pretty print */ 30static void jsonw_indent(json_writer_t *self) 31{ 32 unsigned i; 33 for (i = 0; i < self->depth; ++i) 34 fputs(" ", self->out); 35} 36 37/* end current line and indent if pretty printing */ 38static void jsonw_eol(json_writer_t *self) 39{ 40 if (!self->pretty) 41 return; 42 43 putc('\n', self->out); 44 jsonw_indent(self); 45} 46 47/* If current object is not empty print a comma */ 48static void jsonw_eor(json_writer_t *self) 49{ 50 if (self->sep != '\0') 51 putc(self->sep, self->out); 52 self->sep = ','; 53} 54 55 56/* Output JSON encoded string */ 57/* Handles C escapes, does not do Unicode */ 58static void jsonw_puts(json_writer_t *self, const char *str) 59{ 60 putc('"', self->out); 61 for (; *str; ++str) 62 switch (*str) { 63 case '\t': 64 fputs("\\t", self->out); 65 break; 66 case '\n': 67 fputs("\\n", self->out); 68 break; 69 case '\r': 70 fputs("\\r", self->out); 71 break; 72 case '\f': 73 fputs("\\f", self->out); 74 break; 75 case '\b': 76 fputs("\\b", self->out); 77 break; 78 case '\\': 79 fputs("\\n", self->out); 80 break; 81 case '"': 82 fputs("\\\"", self->out); 83 break; 84 case '\'': 85 fputs("\\\'", self->out); 86 break; 87 default: 88 putc(*str, self->out); 89 } 90 putc('"', self->out); 91} 92 93/* Create a new JSON stream */ 94json_writer_t *jsonw_new(FILE *f) 95{ 96 json_writer_t *self = malloc(sizeof(*self)); 97 if (self) { 98 self->out = f; 99 self->depth = 0; 100 self->pretty = false; 101 self->sep = '\0'; 102 } 103 return self; 104} 105 106/* End output to JSON stream */ 107void jsonw_destroy(json_writer_t **self_p) 108{ 109 json_writer_t *self = *self_p; 110 111 assert(self->depth == 0); 112 fputs("\n", self->out); 113 fflush(self->out); 114 free(self); 115 *self_p = NULL; 116} 117 118void jsonw_pretty(json_writer_t *self, bool on) 119{ 120 self->pretty = on; 121} 122 123/* Basic blocks */ 124static void jsonw_begin(json_writer_t *self, int c) 125{ 126 jsonw_eor(self); 127 putc(c, self->out); 128 ++self->depth; 129 self->sep = '\0'; 130} 131 132static void jsonw_end(json_writer_t *self, int c) 133{ 134 assert(self->depth > 0); 135 136 --self->depth; 137 if (self->sep != '\0') 138 jsonw_eol(self); 139 putc(c, self->out); 140 self->sep = ','; 141} 142 143 144/* Add a JSON property name */ 145void jsonw_name(json_writer_t *self, const char *name) 146{ 147 jsonw_eor(self); 148 jsonw_eol(self); 149 self->sep = '\0'; 150 jsonw_puts(self, name); 151 putc(':', self->out); 152 if (self->pretty) 153 putc(' ', self->out); 154} 155 156void __printf(2, 0) 157jsonw_vprintf_enquote(json_writer_t *self, const char *fmt, va_list ap) 158{ 159 jsonw_eor(self); 160 putc('"', self->out); 161 vfprintf(self->out, fmt, ap); 162 putc('"', self->out); 163} 164 165void __printf(2, 3) jsonw_printf(json_writer_t *self, const char *fmt, ...) 166{ 167 va_list ap; 168 169 va_start(ap, fmt); 170 jsonw_eor(self); 171 vfprintf(self->out, fmt, ap); 172 va_end(ap); 173} 174 175/* Collections */ 176void jsonw_start_object(json_writer_t *self) 177{ 178 jsonw_begin(self, '{'); 179} 180 181void jsonw_end_object(json_writer_t *self) 182{ 183 jsonw_end(self, '}'); 184} 185 186void jsonw_start_array(json_writer_t *self) 187{ 188 jsonw_begin(self, '['); 189} 190 191void jsonw_end_array(json_writer_t *self) 192{ 193 jsonw_end(self, ']'); 194} 195 196/* JSON value types */ 197void jsonw_string(json_writer_t *self, const char *value) 198{ 199 jsonw_eor(self); 200 jsonw_puts(self, value); 201} 202 203void jsonw_bool(json_writer_t *self, bool val) 204{ 205 jsonw_printf(self, "%s", val ? "true" : "false"); 206} 207 208void jsonw_null(json_writer_t *self) 209{ 210 jsonw_printf(self, "null"); 211} 212 213void jsonw_float_fmt(json_writer_t *self, const char *fmt, double num) 214{ 215 jsonw_printf(self, fmt, num); 216} 217 218#ifdef notused 219void jsonw_float(json_writer_t *self, double num) 220{ 221 jsonw_printf(self, "%g", num); 222} 223#endif 224 225void jsonw_hu(json_writer_t *self, unsigned short num) 226{ 227 jsonw_printf(self, "%hu", num); 228} 229 230void jsonw_uint(json_writer_t *self, uint64_t num) 231{ 232 jsonw_printf(self, "%"PRIu64, num); 233} 234 235void jsonw_lluint(json_writer_t *self, unsigned long long int num) 236{ 237 jsonw_printf(self, "%llu", num); 238} 239 240void jsonw_int(json_writer_t *self, int64_t num) 241{ 242 jsonw_printf(self, "%"PRId64, num); 243} 244 245/* Basic name/value objects */ 246void jsonw_string_field(json_writer_t *self, const char *prop, const char *val) 247{ 248 jsonw_name(self, prop); 249 jsonw_string(self, val); 250} 251 252void jsonw_bool_field(json_writer_t *self, const char *prop, bool val) 253{ 254 jsonw_name(self, prop); 255 jsonw_bool(self, val); 256} 257 258#ifdef notused 259void jsonw_float_field(json_writer_t *self, const char *prop, double val) 260{ 261 jsonw_name(self, prop); 262 jsonw_float(self, val); 263} 264#endif 265 266void jsonw_float_field_fmt(json_writer_t *self, 267 const char *prop, 268 const char *fmt, 269 double val) 270{ 271 jsonw_name(self, prop); 272 jsonw_float_fmt(self, fmt, val); 273} 274 275void jsonw_uint_field(json_writer_t *self, const char *prop, uint64_t num) 276{ 277 jsonw_name(self, prop); 278 jsonw_uint(self, num); 279} 280 281void jsonw_hu_field(json_writer_t *self, const char *prop, unsigned short num) 282{ 283 jsonw_name(self, prop); 284 jsonw_hu(self, num); 285} 286 287void jsonw_lluint_field(json_writer_t *self, 288 const char *prop, 289 unsigned long long int num) 290{ 291 jsonw_name(self, prop); 292 jsonw_lluint(self, num); 293} 294 295void jsonw_int_field(json_writer_t *self, const char *prop, int64_t num) 296{ 297 jsonw_name(self, prop); 298 jsonw_int(self, num); 299} 300 301void jsonw_null_field(json_writer_t *self, const char *prop) 302{ 303 jsonw_name(self, prop); 304 jsonw_null(self); 305} 306 307#ifdef TEST 308int main(int argc, char **argv) 309{ 310 json_writer_t *wr = jsonw_new(stdout); 311 312 jsonw_start_object(wr); 313 jsonw_pretty(wr, true); 314 jsonw_name(wr, "Vyatta"); 315 jsonw_start_object(wr); 316 jsonw_string_field(wr, "url", "http://vyatta.com"); 317 jsonw_uint_field(wr, "downloads", 2000000ul); 318 jsonw_float_field(wr, "stock", 8.16); 319 320 jsonw_name(wr, "ARGV"); 321 jsonw_start_array(wr); 322 while (--argc) 323 jsonw_string(wr, *++argv); 324 jsonw_end_array(wr); 325 326 jsonw_name(wr, "empty"); 327 jsonw_start_array(wr); 328 jsonw_end_array(wr); 329 330 jsonw_name(wr, "NIL"); 331 jsonw_start_object(wr); 332 jsonw_end_object(wr); 333 334 jsonw_null_field(wr, "my_null"); 335 336 jsonw_name(wr, "special chars"); 337 jsonw_start_array(wr); 338 jsonw_string_field(wr, "slash", "/"); 339 jsonw_string_field(wr, "newline", "\n"); 340 jsonw_string_field(wr, "tab", "\t"); 341 jsonw_string_field(wr, "ff", "\f"); 342 jsonw_string_field(wr, "quote", "\""); 343 jsonw_string_field(wr, "tick", "\'"); 344 jsonw_string_field(wr, "backslash", "\\"); 345 jsonw_end_array(wr); 346 347 jsonw_end_object(wr); 348 349 jsonw_end_object(wr); 350 jsonw_destroy(&wr); 351 return 0; 352} 353 354#endif