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