0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <stdio.h>
0012 #include <stdbool.h>
0013 #include <stdarg.h>
0014 #include <assert.h>
0015 #include <malloc.h>
0016 #include <inttypes.h>
0017 #include <stdint.h>
0018
0019 #include "json_writer.h"
0020
0021 struct json_writer {
0022 FILE *out;
0023 unsigned depth;
0024 bool pretty;
0025 char sep;
0026 };
0027
0028
0029 static void jsonw_indent(json_writer_t *self)
0030 {
0031 unsigned i;
0032 for (i = 0; i < self->depth; ++i)
0033 fputs(" ", self->out);
0034 }
0035
0036
0037 static void jsonw_eol(json_writer_t *self)
0038 {
0039 if (!self->pretty)
0040 return;
0041
0042 putc('\n', self->out);
0043 jsonw_indent(self);
0044 }
0045
0046
0047 static void jsonw_eor(json_writer_t *self)
0048 {
0049 if (self->sep != '\0')
0050 putc(self->sep, self->out);
0051 self->sep = ',';
0052 }
0053
0054
0055
0056
0057 static void jsonw_puts(json_writer_t *self, const char *str)
0058 {
0059 putc('"', self->out);
0060 for (; *str; ++str)
0061 switch (*str) {
0062 case '\t':
0063 fputs("\\t", self->out);
0064 break;
0065 case '\n':
0066 fputs("\\n", self->out);
0067 break;
0068 case '\r':
0069 fputs("\\r", self->out);
0070 break;
0071 case '\f':
0072 fputs("\\f", self->out);
0073 break;
0074 case '\b':
0075 fputs("\\b", self->out);
0076 break;
0077 case '\\':
0078 fputs("\\n", self->out);
0079 break;
0080 case '"':
0081 fputs("\\\"", self->out);
0082 break;
0083 case '\'':
0084 fputs("\\\'", self->out);
0085 break;
0086 default:
0087 putc(*str, self->out);
0088 }
0089 putc('"', self->out);
0090 }
0091
0092
0093 json_writer_t *jsonw_new(FILE *f)
0094 {
0095 json_writer_t *self = malloc(sizeof(*self));
0096 if (self) {
0097 self->out = f;
0098 self->depth = 0;
0099 self->pretty = false;
0100 self->sep = '\0';
0101 }
0102 return self;
0103 }
0104
0105
0106 void jsonw_destroy(json_writer_t **self_p)
0107 {
0108 json_writer_t *self = *self_p;
0109
0110 assert(self->depth == 0);
0111 fputs("\n", self->out);
0112 fflush(self->out);
0113 free(self);
0114 *self_p = NULL;
0115 }
0116
0117 void jsonw_pretty(json_writer_t *self, bool on)
0118 {
0119 self->pretty = on;
0120 }
0121
0122 void jsonw_reset(json_writer_t *self)
0123 {
0124 assert(self->depth == 0);
0125 self->sep = '\0';
0126 }
0127
0128
0129 static void jsonw_begin(json_writer_t *self, int c)
0130 {
0131 jsonw_eor(self);
0132 putc(c, self->out);
0133 ++self->depth;
0134 self->sep = '\0';
0135 }
0136
0137 static void jsonw_end(json_writer_t *self, int c)
0138 {
0139 assert(self->depth > 0);
0140
0141 --self->depth;
0142 if (self->sep != '\0')
0143 jsonw_eol(self);
0144 putc(c, self->out);
0145 self->sep = ',';
0146 }
0147
0148
0149
0150 void jsonw_name(json_writer_t *self, const char *name)
0151 {
0152 jsonw_eor(self);
0153 jsonw_eol(self);
0154 self->sep = '\0';
0155 jsonw_puts(self, name);
0156 putc(':', self->out);
0157 if (self->pretty)
0158 putc(' ', self->out);
0159 }
0160
0161 void jsonw_vprintf_enquote(json_writer_t *self, const char *fmt, va_list ap)
0162 {
0163 jsonw_eor(self);
0164 putc('"', self->out);
0165 vfprintf(self->out, fmt, ap);
0166 putc('"', self->out);
0167 }
0168
0169 void jsonw_printf(json_writer_t *self, const char *fmt, ...)
0170 {
0171 va_list ap;
0172
0173 va_start(ap, fmt);
0174 jsonw_eor(self);
0175 vfprintf(self->out, fmt, ap);
0176 va_end(ap);
0177 }
0178
0179
0180 void jsonw_start_object(json_writer_t *self)
0181 {
0182 jsonw_begin(self, '{');
0183 }
0184
0185 void jsonw_end_object(json_writer_t *self)
0186 {
0187 jsonw_end(self, '}');
0188 }
0189
0190 void jsonw_start_array(json_writer_t *self)
0191 {
0192 jsonw_begin(self, '[');
0193 }
0194
0195 void jsonw_end_array(json_writer_t *self)
0196 {
0197 jsonw_end(self, ']');
0198 }
0199
0200
0201 void jsonw_string(json_writer_t *self, const char *value)
0202 {
0203 jsonw_eor(self);
0204 jsonw_puts(self, value);
0205 }
0206
0207 void jsonw_bool(json_writer_t *self, bool val)
0208 {
0209 jsonw_printf(self, "%s", val ? "true" : "false");
0210 }
0211
0212 void jsonw_null(json_writer_t *self)
0213 {
0214 jsonw_printf(self, "null");
0215 }
0216
0217 void jsonw_float_fmt(json_writer_t *self, const char *fmt, double num)
0218 {
0219 jsonw_printf(self, fmt, num);
0220 }
0221
0222 #ifdef notused
0223 void jsonw_float(json_writer_t *self, double num)
0224 {
0225 jsonw_printf(self, "%g", num);
0226 }
0227 #endif
0228
0229 void jsonw_hu(json_writer_t *self, unsigned short num)
0230 {
0231 jsonw_printf(self, "%hu", num);
0232 }
0233
0234 void jsonw_uint(json_writer_t *self, uint64_t num)
0235 {
0236 jsonw_printf(self, "%"PRIu64, num);
0237 }
0238
0239 void jsonw_lluint(json_writer_t *self, unsigned long long int num)
0240 {
0241 jsonw_printf(self, "%llu", num);
0242 }
0243
0244 void jsonw_int(json_writer_t *self, int64_t num)
0245 {
0246 jsonw_printf(self, "%"PRId64, num);
0247 }
0248
0249
0250 void jsonw_string_field(json_writer_t *self, const char *prop, const char *val)
0251 {
0252 jsonw_name(self, prop);
0253 jsonw_string(self, val);
0254 }
0255
0256 void jsonw_bool_field(json_writer_t *self, const char *prop, bool val)
0257 {
0258 jsonw_name(self, prop);
0259 jsonw_bool(self, val);
0260 }
0261
0262 #ifdef notused
0263 void jsonw_float_field(json_writer_t *self, const char *prop, double val)
0264 {
0265 jsonw_name(self, prop);
0266 jsonw_float(self, val);
0267 }
0268 #endif
0269
0270 void jsonw_float_field_fmt(json_writer_t *self,
0271 const char *prop,
0272 const char *fmt,
0273 double val)
0274 {
0275 jsonw_name(self, prop);
0276 jsonw_float_fmt(self, fmt, val);
0277 }
0278
0279 void jsonw_uint_field(json_writer_t *self, const char *prop, uint64_t num)
0280 {
0281 jsonw_name(self, prop);
0282 jsonw_uint(self, num);
0283 }
0284
0285 void jsonw_hu_field(json_writer_t *self, const char *prop, unsigned short num)
0286 {
0287 jsonw_name(self, prop);
0288 jsonw_hu(self, num);
0289 }
0290
0291 void jsonw_lluint_field(json_writer_t *self,
0292 const char *prop,
0293 unsigned long long int num)
0294 {
0295 jsonw_name(self, prop);
0296 jsonw_lluint(self, num);
0297 }
0298
0299 void jsonw_int_field(json_writer_t *self, const char *prop, int64_t num)
0300 {
0301 jsonw_name(self, prop);
0302 jsonw_int(self, num);
0303 }
0304
0305 void jsonw_null_field(json_writer_t *self, const char *prop)
0306 {
0307 jsonw_name(self, prop);
0308 jsonw_null(self);
0309 }
0310
0311 #ifdef TEST
0312 int main(int argc, char **argv)
0313 {
0314 json_writer_t *wr = jsonw_new(stdout);
0315
0316 jsonw_start_object(wr);
0317 jsonw_pretty(wr, true);
0318 jsonw_name(wr, "Vyatta");
0319 jsonw_start_object(wr);
0320 jsonw_string_field(wr, "url", "http://vyatta.com");
0321 jsonw_uint_field(wr, "downloads", 2000000ul);
0322 jsonw_float_field(wr, "stock", 8.16);
0323
0324 jsonw_name(wr, "ARGV");
0325 jsonw_start_array(wr);
0326 while (--argc)
0327 jsonw_string(wr, *++argv);
0328 jsonw_end_array(wr);
0329
0330 jsonw_name(wr, "empty");
0331 jsonw_start_array(wr);
0332 jsonw_end_array(wr);
0333
0334 jsonw_name(wr, "NIL");
0335 jsonw_start_object(wr);
0336 jsonw_end_object(wr);
0337
0338 jsonw_null_field(wr, "my_null");
0339
0340 jsonw_name(wr, "special chars");
0341 jsonw_start_array(wr);
0342 jsonw_string_field(wr, "slash", "/");
0343 jsonw_string_field(wr, "newline", "\n");
0344 jsonw_string_field(wr, "tab", "\t");
0345 jsonw_string_field(wr, "ff", "\f");
0346 jsonw_string_field(wr, "quote", "\"");
0347 jsonw_string_field(wr, "tick", "\'");
0348 jsonw_string_field(wr, "backslash", "\\");
0349 jsonw_end_array(wr);
0350
0351 jsonw_end_object(wr);
0352
0353 jsonw_end_object(wr);
0354 jsonw_destroy(&wr);
0355 return 0;
0356 }
0357
0358 #endif