]> git.proxmox.com Git - mirror_iproute2.git/blob - lib/json_print.c
bridge: support for nexthop id in fdb entries
[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 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 {
200 int ret = 0;
201
202 if (_IS_JSON_CONTEXT(type)) {
203 if (key)
204 jsonw_bool_field(_jw, key, value);
205 else
206 jsonw_bool(_jw, value);
207 } else if (_IS_FP_CONTEXT(type)) {
208 ret = color_fprintf(stdout, color, fmt,
209 value ? "true" : "false");
210 }
211
212 return ret;
213 }
214
215 /*
216 * In JSON context uses hardcode %#x format: 42 -> 0x2a
217 */
218 int print_color_0xhex(enum output_type type,
219 enum color_attr color,
220 const char *key,
221 const char *fmt,
222 unsigned long long hex)
223 {
224 int ret = 0;
225
226 if (_IS_JSON_CONTEXT(type)) {
227 SPRINT_BUF(b1);
228
229 snprintf(b1, sizeof(b1), "%#llx", hex);
230 print_string(PRINT_JSON, key, NULL, b1);
231 } else if (_IS_FP_CONTEXT(type)) {
232 ret = color_fprintf(stdout, color, fmt, hex);
233 }
234
235 return ret;
236 }
237
238 int print_color_hex(enum output_type type,
239 enum color_attr color,
240 const char *key,
241 const char *fmt,
242 unsigned int hex)
243 {
244 int ret = 0;
245
246 if (_IS_JSON_CONTEXT(type)) {
247 SPRINT_BUF(b1);
248
249 snprintf(b1, sizeof(b1), "%x", hex);
250 if (key)
251 jsonw_string_field(_jw, key, b1);
252 else
253 jsonw_string(_jw, b1);
254 } else if (_IS_FP_CONTEXT(type)) {
255 ret = color_fprintf(stdout, color, fmt, hex);
256 }
257
258 return ret;
259 }
260
261 /*
262 * In JSON context we don't use the argument "value" we simply call jsonw_null
263 * whereas FP context can use "value" to output anything
264 */
265 int print_color_null(enum output_type type,
266 enum color_attr color,
267 const char *key,
268 const char *fmt,
269 const char *value)
270 {
271 int ret = 0;
272
273 if (_IS_JSON_CONTEXT(type)) {
274 if (key)
275 jsonw_null_field(_jw, key);
276 else
277 jsonw_null(_jw);
278 } else if (_IS_FP_CONTEXT(type)) {
279 ret = color_fprintf(stdout, color, fmt, value);
280 }
281
282 return ret;
283 }
284
285 /* Print line separator (if not in JSON mode) */
286 void print_nl(void)
287 {
288 if (!_jw)
289 printf("%s", _SL_);
290 }