123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 |
- /*
- * Simple streaming JSON writer
- *
- * This takes care of the annoying bits of JSON syntax like the commas
- * after elements
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * Authors: Stephen Hemminger <stephen@networkplumber.org>
- */
- #include <stdio.h>
- #include <stdbool.h>
- #include <stdarg.h>
- #include <assert.h>
- #include <malloc.h>
- #include <inttypes.h>
- #include <stdint.h>
- #include "json_writer.h"
- struct json_writer {
- FILE *out; /* output file */
- unsigned depth; /* nesting */
- bool pretty; /* optional whitepace */
- char sep; /* either nul or comma */
- };
- /* indentation for pretty print */
- static void jsonw_indent(json_writer_t *self)
- {
- unsigned i;
- for (i = 0; i < self->depth; ++i)
- fputs(" ", self->out);
- }
- /* end current line and indent if pretty printing */
- static void jsonw_eol(json_writer_t *self)
- {
- if (!self->pretty)
- return;
- putc('\n', self->out);
- jsonw_indent(self);
- }
- /* If current object is not empty print a comma */
- static void jsonw_eor(json_writer_t *self)
- {
- if (self->sep != '\0')
- putc(self->sep, self->out);
- self->sep = ',';
- }
- /* Output JSON encoded string */
- /* Handles C escapes, does not do Unicode */
- static void jsonw_puts(json_writer_t *self, const char *str)
- {
- putc('"', self->out);
- for (; *str; ++str)
- switch (*str) {
- case '\t':
- fputs("\\t", self->out);
- break;
- case '\n':
- fputs("\\n", self->out);
- break;
- case '\r':
- fputs("\\r", self->out);
- break;
- case '\f':
- fputs("\\f", self->out);
- break;
- case '\b':
- fputs("\\b", self->out);
- break;
- case '\\':
- fputs("\\n", self->out);
- break;
- case '"':
- fputs("\\\"", self->out);
- break;
- case '\'':
- fputs("\\\'", self->out);
- break;
- default:
- putc(*str, self->out);
- }
- putc('"', self->out);
- }
- /* Create a new JSON stream */
- json_writer_t *jsonw_new(FILE *f)
- {
- json_writer_t *self = malloc(sizeof(*self));
- if (self) {
- self->out = f;
- self->depth = 0;
- self->pretty = false;
- self->sep = '\0';
- }
- return self;
- }
- /* End output to JSON stream */
- void jsonw_destroy(json_writer_t **self_p)
- {
- json_writer_t *self = *self_p;
- assert(self->depth == 0);
- fputs("\n", self->out);
- fflush(self->out);
- free(self);
- *self_p = NULL;
- }
- void jsonw_pretty(json_writer_t *self, bool on)
- {
- self->pretty = on;
- }
- /* Basic blocks */
- static void jsonw_begin(json_writer_t *self, int c)
- {
- jsonw_eor(self);
- putc(c, self->out);
- ++self->depth;
- self->sep = '\0';
- }
- static void jsonw_end(json_writer_t *self, int c)
- {
- assert(self->depth > 0);
- --self->depth;
- if (self->sep != '\0')
- jsonw_eol(self);
- putc(c, self->out);
- self->sep = ',';
- }
- /* Add a JSON property name */
- void jsonw_name(json_writer_t *self, const char *name)
- {
- jsonw_eor(self);
- jsonw_eol(self);
- self->sep = '\0';
- jsonw_puts(self, name);
- putc(':', self->out);
- if (self->pretty)
- putc(' ', self->out);
- }
- void jsonw_vprintf_enquote(json_writer_t *self, const char *fmt, va_list ap)
- {
- jsonw_eor(self);
- putc('"', self->out);
- vfprintf(self->out, fmt, ap);
- putc('"', self->out);
- }
- void jsonw_printf(json_writer_t *self, const char *fmt, ...)
- {
- va_list ap;
- va_start(ap, fmt);
- jsonw_eor(self);
- vfprintf(self->out, fmt, ap);
- va_end(ap);
- }
- /* Collections */
- void jsonw_start_object(json_writer_t *self)
- {
- jsonw_begin(self, '{');
- }
- void jsonw_end_object(json_writer_t *self)
- {
- jsonw_end(self, '}');
- }
- void jsonw_start_array(json_writer_t *self)
- {
- jsonw_begin(self, '[');
- }
- void jsonw_end_array(json_writer_t *self)
- {
- jsonw_end(self, ']');
- }
- /* JSON value types */
- void jsonw_string(json_writer_t *self, const char *value)
- {
- jsonw_eor(self);
- jsonw_puts(self, value);
- }
- void jsonw_bool(json_writer_t *self, bool val)
- {
- jsonw_printf(self, "%s", val ? "true" : "false");
- }
- void jsonw_null(json_writer_t *self)
- {
- jsonw_printf(self, "null");
- }
- void jsonw_float_fmt(json_writer_t *self, const char *fmt, double num)
- {
- jsonw_printf(self, fmt, num);
- }
- #ifdef notused
- void jsonw_float(json_writer_t *self, double num)
- {
- jsonw_printf(self, "%g", num);
- }
- #endif
- void jsonw_hu(json_writer_t *self, unsigned short num)
- {
- jsonw_printf(self, "%hu", num);
- }
- void jsonw_uint(json_writer_t *self, uint64_t num)
- {
- jsonw_printf(self, "%"PRIu64, num);
- }
- void jsonw_lluint(json_writer_t *self, unsigned long long int num)
- {
- jsonw_printf(self, "%llu", num);
- }
- void jsonw_int(json_writer_t *self, int64_t num)
- {
- jsonw_printf(self, "%"PRId64, num);
- }
- /* Basic name/value objects */
- void jsonw_string_field(json_writer_t *self, const char *prop, const char *val)
- {
- jsonw_name(self, prop);
- jsonw_string(self, val);
- }
- void jsonw_bool_field(json_writer_t *self, const char *prop, bool val)
- {
- jsonw_name(self, prop);
- jsonw_bool(self, val);
- }
- #ifdef notused
- void jsonw_float_field(json_writer_t *self, const char *prop, double val)
- {
- jsonw_name(self, prop);
- jsonw_float(self, val);
- }
- #endif
- void jsonw_float_field_fmt(json_writer_t *self,
- const char *prop,
- const char *fmt,
- double val)
- {
- jsonw_name(self, prop);
- jsonw_float_fmt(self, fmt, val);
- }
- void jsonw_uint_field(json_writer_t *self, const char *prop, uint64_t num)
- {
- jsonw_name(self, prop);
- jsonw_uint(self, num);
- }
- void jsonw_hu_field(json_writer_t *self, const char *prop, unsigned short num)
- {
- jsonw_name(self, prop);
- jsonw_hu(self, num);
- }
- void jsonw_lluint_field(json_writer_t *self,
- const char *prop,
- unsigned long long int num)
- {
- jsonw_name(self, prop);
- jsonw_lluint(self, num);
- }
- void jsonw_int_field(json_writer_t *self, const char *prop, int64_t num)
- {
- jsonw_name(self, prop);
- jsonw_int(self, num);
- }
- void jsonw_null_field(json_writer_t *self, const char *prop)
- {
- jsonw_name(self, prop);
- jsonw_null(self);
- }
- #ifdef TEST
- int main(int argc, char **argv)
- {
- json_writer_t *wr = jsonw_new(stdout);
- jsonw_start_object(wr);
- jsonw_pretty(wr, true);
- jsonw_name(wr, "Vyatta");
- jsonw_start_object(wr);
- jsonw_string_field(wr, "url", "http://vyatta.com");
- jsonw_uint_field(wr, "downloads", 2000000ul);
- jsonw_float_field(wr, "stock", 8.16);
- jsonw_name(wr, "ARGV");
- jsonw_start_array(wr);
- while (--argc)
- jsonw_string(wr, *++argv);
- jsonw_end_array(wr);
- jsonw_name(wr, "empty");
- jsonw_start_array(wr);
- jsonw_end_array(wr);
- jsonw_name(wr, "NIL");
- jsonw_start_object(wr);
- jsonw_end_object(wr);
- jsonw_null_field(wr, "my_null");
- jsonw_name(wr, "special chars");
- jsonw_start_array(wr);
- jsonw_string_field(wr, "slash", "/");
- jsonw_string_field(wr, "newline", "\n");
- jsonw_string_field(wr, "tab", "\t");
- jsonw_string_field(wr, "ff", "\f");
- jsonw_string_field(wr, "quote", "\"");
- jsonw_string_field(wr, "tick", "\'");
- jsonw_string_field(wr, "backslash", "\\");
- jsonw_end_array(wr);
- jsonw_end_object(wr);
- jsonw_end_object(wr);
- jsonw_destroy(&wr);
- return 0;
- }
- #endif
|