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