]> git.proxmox.com Git - mirror_iproute2.git/blob - lib/json_print.c
62eeb1f1fb3159ee1984a9d3e0835255e12f6c6c
[mirror_iproute2.git] / lib / json_print.c
1 /*
2 * json_print.c "print regular or json output, based on json_writer".
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: Julien Fortin, <julien@cumulusnetworks.com>
10 */
11
12 #include <stdarg.h>
13 #include <stdio.h>
14
15 #include "utils.h"
16 #include "json_print.h"
17
18 static json_writer_t *_jw;
19
20 #define _IS_JSON_CONTEXT(type) ((type & PRINT_JSON || type & PRINT_ANY) && _jw)
21 #define _IS_FP_CONTEXT(type) (!_jw && (type & PRINT_FP || type & PRINT_ANY))
22
23 static void __new_json_obj(int json, bool have_array)
24 {
25 if (json) {
26 _jw = jsonw_new(stdout);
27 if (!_jw) {
28 perror("json object");
29 exit(1);
30 }
31 if (pretty)
32 jsonw_pretty(_jw, true);
33 if (have_array)
34 jsonw_start_array(_jw);
35 }
36 }
37
38 static void __delete_json_obj(bool have_array)
39 {
40 if (_jw) {
41 if (have_array)
42 jsonw_end_array(_jw);
43 jsonw_destroy(&_jw);
44 }
45 }
46
47 void new_json_obj(int json)
48 {
49 __new_json_obj(json, true);
50 }
51
52 void delete_json_obj(void)
53 {
54 __delete_json_obj(true);
55 }
56
57 void new_json_obj_plain(int json)
58 {
59 __new_json_obj(json, false);
60 }
61
62 void delete_json_obj_plain(void)
63 {
64 __delete_json_obj(false);
65 }
66
67 bool is_json_context(void)
68 {
69 return _jw != NULL;
70 }
71
72 json_writer_t *get_json_writer(void)
73 {
74 return _jw;
75 }
76
77 void open_json_object(const char *str)
78 {
79 if (_IS_JSON_CONTEXT(PRINT_JSON)) {
80 if (str)
81 jsonw_name(_jw, str);
82 jsonw_start_object(_jw);
83 }
84 }
85
86 void close_json_object(void)
87 {
88 if (_IS_JSON_CONTEXT(PRINT_JSON))
89 jsonw_end_object(_jw);
90 }
91
92 /*
93 * Start json array or string array using
94 * the provided string as json key (if not null)
95 * or as array delimiter in non-json context.
96 */
97 void open_json_array(enum output_type type, const char *str)
98 {
99 if (_IS_JSON_CONTEXT(type)) {
100 if (str)
101 jsonw_name(_jw, str);
102 jsonw_start_array(_jw);
103 } else if (_IS_FP_CONTEXT(type)) {
104 printf("%s", str);
105 }
106 }
107
108 /*
109 * End json array or string array
110 */
111 void close_json_array(enum output_type type, const char *str)
112 {
113 if (_IS_JSON_CONTEXT(type)) {
114 jsonw_end_array(_jw);
115 } else if (_IS_FP_CONTEXT(type)) {
116 printf("%s", str);
117 }
118 }
119
120 /*
121 * pre-processor directive to generate similar
122 * functions handling different types
123 */
124 #define _PRINT_FUNC(type_name, type) \
125 __attribute__((format(printf, 4, 0))) \
126 int print_color_##type_name(enum output_type t, \
127 enum color_attr color, \
128 const char *key, \
129 const char *fmt, \
130 type value) \
131 { \
132 int ret = 0; \
133 if (_IS_JSON_CONTEXT(t)) { \
134 if (!key) \
135 jsonw_##type_name(_jw, value); \
136 else \
137 jsonw_##type_name##_field(_jw, key, value); \
138 } else if (_IS_FP_CONTEXT(t)) { \
139 ret = color_fprintf(stdout, color, fmt, value); \
140 } \
141 return ret; \
142 }
143 _PRINT_FUNC(int, int);
144 _PRINT_FUNC(s64, int64_t);
145 _PRINT_FUNC(hhu, unsigned char);
146 _PRINT_FUNC(hu, unsigned short);
147 _PRINT_FUNC(uint, unsigned int);
148 _PRINT_FUNC(u64, uint64_t);
149 _PRINT_FUNC(luint, unsigned long);
150 _PRINT_FUNC(lluint, unsigned long long);
151 _PRINT_FUNC(float, double);
152 #undef _PRINT_FUNC
153
154 #define _PRINT_NAME_VALUE_FUNC(type_name, type, format_char) \
155 void print_##type_name##_name_value(const char *name, type value)\
156 { \
157 SPRINT_BUF(format); \
158 \
159 snprintf(format, SPRINT_BSIZE, \
160 "%s %%"#format_char, name); \
161 print_##type_name(PRINT_ANY, name, format, value); \
162 }
163 _PRINT_NAME_VALUE_FUNC(uint, unsigned int, u);
164 _PRINT_NAME_VALUE_FUNC(string, const char*, s);
165 #undef _PRINT_NAME_VALUE_FUNC
166
167 int print_color_string(enum output_type type,
168 enum color_attr color,
169 const char *key,
170 const char *fmt,
171 const char *value)
172 {
173 int ret = 0;
174
175 if (_IS_JSON_CONTEXT(type)) {
176 if (key && !value)
177 jsonw_name(_jw, key);
178 else if (!key && value)
179 jsonw_string(_jw, value);
180 else
181 jsonw_string_field(_jw, key, value);
182 } else if (_IS_FP_CONTEXT(type)) {
183 ret = color_fprintf(stdout, color, fmt, value);
184 }
185
186 return ret;
187 }
188
189 /*
190 * value's type is bool. When using this function in FP context you can't pass
191 * a value to it, you will need to use "is_json_context()" to have different
192 * branch for json and regular output. grep -r "print_bool" for example
193 */
194 static int __print_color_bool(enum output_type type,
195 enum color_attr color,
196 const char *key,
197 const char *fmt,
198 bool value,
199 const char *str)
200 {
201 int ret = 0;
202
203 if (_IS_JSON_CONTEXT(type)) {
204 if (key)
205 jsonw_bool_field(_jw, key, value);
206 else
207 jsonw_bool(_jw, value);
208 } else if (_IS_FP_CONTEXT(type)) {
209 ret = color_fprintf(stdout, color, fmt, str);
210 }
211
212 return ret;
213 }
214
215 int print_color_bool(enum output_type type,
216 enum color_attr color,
217 const char *key,
218 const char *fmt,
219 bool value)
220 {
221 return __print_color_bool(type, color, key, fmt, value,
222 value ? "true" : "false");
223 }
224
225 int print_color_on_off(enum output_type type,
226 enum color_attr color,
227 const char *key,
228 const char *fmt,
229 bool value)
230 {
231 return __print_color_bool(type, color, key, fmt, value,
232 value ? "on" : "off");
233 }
234
235 /*
236 * In JSON context uses hardcode %#x format: 42 -> 0x2a
237 */
238 int print_color_0xhex(enum output_type type,
239 enum color_attr color,
240 const char *key,
241 const char *fmt,
242 unsigned long long hex)
243 {
244 int ret = 0;
245
246 if (_IS_JSON_CONTEXT(type)) {
247 SPRINT_BUF(b1);
248
249 snprintf(b1, sizeof(b1), "%#llx", hex);
250 print_string(PRINT_JSON, key, NULL, b1);
251 } else if (_IS_FP_CONTEXT(type)) {
252 ret = color_fprintf(stdout, color, fmt, hex);
253 }
254
255 return ret;
256 }
257
258 int print_color_hex(enum output_type type,
259 enum color_attr color,
260 const char *key,
261 const char *fmt,
262 unsigned int hex)
263 {
264 int ret = 0;
265
266 if (_IS_JSON_CONTEXT(type)) {
267 SPRINT_BUF(b1);
268
269 snprintf(b1, sizeof(b1), "%x", hex);
270 if (key)
271 jsonw_string_field(_jw, key, b1);
272 else
273 jsonw_string(_jw, b1);
274 } else if (_IS_FP_CONTEXT(type)) {
275 ret = color_fprintf(stdout, color, fmt, hex);
276 }
277
278 return ret;
279 }
280
281 /*
282 * In JSON context we don't use the argument "value" we simply call jsonw_null
283 * whereas FP context can use "value" to output anything
284 */
285 int print_color_null(enum output_type type,
286 enum color_attr color,
287 const char *key,
288 const char *fmt,
289 const char *value)
290 {
291 int ret = 0;
292
293 if (_IS_JSON_CONTEXT(type)) {
294 if (key)
295 jsonw_null_field(_jw, key);
296 else
297 jsonw_null(_jw);
298 } else if (_IS_FP_CONTEXT(type)) {
299 ret = color_fprintf(stdout, color, fmt, value);
300 }
301
302 return ret;
303 }
304
305 /* Print line separator (if not in JSON mode) */
306 void print_nl(void)
307 {
308 if (!_jw)
309 printf("%s", _SL_);
310 }