]>
Commit | Line | Data |
---|---|---|
6377572f | 1 | /* |
0b4b35e1 | 2 | * json_print.c "print regular or json output, based on json_writer". |
6377572f JF |
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> | |
6377572f JF |
10 | */ |
11 | ||
12 | #include <stdarg.h> | |
13 | #include <stdio.h> | |
14 | ||
15 | #include "utils.h" | |
0b4b35e1 | 16 | #include "json_print.h" |
6377572f JF |
17 | |
18 | static json_writer_t *_jw; | |
6377572f | 19 | |
98e48e7d | 20 | static void __new_json_obj(int json, bool have_array) |
6377572f JF |
21 | { |
22 | if (json) { | |
429f314e | 23 | _jw = jsonw_new(stdout); |
6377572f JF |
24 | if (!_jw) { |
25 | perror("json object"); | |
26 | exit(1); | |
27 | } | |
54336567 | 28 | if (pretty) |
a233caa0 | 29 | jsonw_pretty(_jw, true); |
98e48e7d RD |
30 | if (have_array) |
31 | jsonw_start_array(_jw); | |
6377572f | 32 | } |
6377572f JF |
33 | } |
34 | ||
98e48e7d | 35 | static void __delete_json_obj(bool have_array) |
6377572f JF |
36 | { |
37 | if (_jw) { | |
98e48e7d RD |
38 | if (have_array) |
39 | jsonw_end_array(_jw); | |
6377572f JF |
40 | jsonw_destroy(&_jw); |
41 | } | |
42 | } | |
43 | ||
98e48e7d RD |
44 | void new_json_obj(int json) |
45 | { | |
46 | __new_json_obj(json, true); | |
47 | } | |
48 | ||
49 | void delete_json_obj(void) | |
50 | { | |
51 | __delete_json_obj(true); | |
52 | } | |
53 | ||
54 | void new_json_obj_plain(int json) | |
55 | { | |
56 | __new_json_obj(json, false); | |
57 | } | |
58 | ||
59 | void delete_json_obj_plain(void) | |
60 | { | |
61 | __delete_json_obj(false); | |
62 | } | |
63 | ||
6377572f JF |
64 | bool is_json_context(void) |
65 | { | |
66 | return _jw != NULL; | |
67 | } | |
68 | ||
6377572f JF |
69 | json_writer_t *get_json_writer(void) |
70 | { | |
71 | return _jw; | |
72 | } | |
73 | ||
74 | void open_json_object(const char *str) | |
75 | { | |
76 | if (_IS_JSON_CONTEXT(PRINT_JSON)) { | |
77 | if (str) | |
78 | jsonw_name(_jw, str); | |
79 | jsonw_start_object(_jw); | |
80 | } | |
81 | } | |
82 | ||
83 | void close_json_object(void) | |
84 | { | |
85 | if (_IS_JSON_CONTEXT(PRINT_JSON)) | |
86 | jsonw_end_object(_jw); | |
87 | } | |
88 | ||
89 | /* | |
90 | * Start json array or string array using | |
91 | * the provided string as json key (if not null) | |
92 | * or as array delimiter in non-json context. | |
93 | */ | |
94 | void open_json_array(enum output_type type, const char *str) | |
95 | { | |
96 | if (_IS_JSON_CONTEXT(type)) { | |
97 | if (str) | |
98 | jsonw_name(_jw, str); | |
99 | jsonw_start_array(_jw); | |
100 | } else if (_IS_FP_CONTEXT(type)) { | |
429f314e | 101 | printf("%s", str); |
6377572f JF |
102 | } |
103 | } | |
104 | ||
105 | /* | |
106 | * End json array or string array | |
107 | */ | |
108 | void close_json_array(enum output_type type, const char *str) | |
109 | { | |
110 | if (_IS_JSON_CONTEXT(type)) { | |
6377572f | 111 | jsonw_end_array(_jw); |
6377572f | 112 | } else if (_IS_FP_CONTEXT(type)) { |
429f314e | 113 | printf("%s", str); |
6377572f JF |
114 | } |
115 | } | |
116 | ||
117 | /* | |
118 | * pre-processor directive to generate similar | |
119 | * functions handling different types | |
120 | */ | |
121 | #define _PRINT_FUNC(type_name, type) \ | |
5d5586b0 | 122 | __attribute__((format(printf, 4, 0))) \ |
5a07a5df BP |
123 | int print_color_##type_name(enum output_type t, \ |
124 | enum color_attr color, \ | |
125 | const char *key, \ | |
126 | const char *fmt, \ | |
127 | type value) \ | |
6377572f | 128 | { \ |
5a07a5df | 129 | int ret = 0; \ |
6377572f JF |
130 | if (_IS_JSON_CONTEXT(t)) { \ |
131 | if (!key) \ | |
132 | jsonw_##type_name(_jw, value); \ | |
133 | else \ | |
134 | jsonw_##type_name##_field(_jw, key, value); \ | |
135 | } else if (_IS_FP_CONTEXT(t)) { \ | |
5a07a5df | 136 | ret = color_fprintf(stdout, color, fmt, value); \ |
6377572f | 137 | } \ |
5a07a5df | 138 | return ret; \ |
6377572f JF |
139 | } |
140 | _PRINT_FUNC(int, int); | |
4db2ff0d | 141 | _PRINT_FUNC(s64, int64_t); |
b640e85d | 142 | _PRINT_FUNC(hhu, unsigned char); |
6377572f | 143 | _PRINT_FUNC(hu, unsigned short); |
4db2ff0d THJ |
144 | _PRINT_FUNC(uint, unsigned int); |
145 | _PRINT_FUNC(u64, uint64_t); | |
3a1f602a SH |
146 | _PRINT_FUNC(luint, unsigned long); |
147 | _PRINT_FUNC(lluint, unsigned long long); | |
097415d5 | 148 | _PRINT_FUNC(float, double); |
6377572f JF |
149 | #undef _PRINT_FUNC |
150 | ||
31ca29b2 RD |
151 | #define _PRINT_NAME_VALUE_FUNC(type_name, type, format_char) \ |
152 | void print_##type_name##_name_value(const char *name, type value)\ | |
153 | { \ | |
154 | SPRINT_BUF(format); \ | |
155 | \ | |
156 | snprintf(format, SPRINT_BSIZE, \ | |
157 | "%s %%"#format_char, name); \ | |
158 | print_##type_name(PRINT_ANY, name, format, value); \ | |
159 | } | |
160 | _PRINT_NAME_VALUE_FUNC(uint, unsigned int, u); | |
161 | _PRINT_NAME_VALUE_FUNC(string, const char*, s); | |
162 | #undef _PRINT_NAME_VALUE_FUNC | |
163 | ||
5a07a5df BP |
164 | int print_color_string(enum output_type type, |
165 | enum color_attr color, | |
166 | const char *key, | |
167 | const char *fmt, | |
168 | const char *value) | |
6377572f | 169 | { |
5a07a5df BP |
170 | int ret = 0; |
171 | ||
6377572f JF |
172 | if (_IS_JSON_CONTEXT(type)) { |
173 | if (key && !value) | |
174 | jsonw_name(_jw, key); | |
175 | else if (!key && value) | |
176 | jsonw_string(_jw, value); | |
177 | else | |
178 | jsonw_string_field(_jw, key, value); | |
179 | } else if (_IS_FP_CONTEXT(type)) { | |
5a07a5df | 180 | ret = color_fprintf(stdout, color, fmt, value); |
6377572f | 181 | } |
5a07a5df BP |
182 | |
183 | return ret; | |
6377572f JF |
184 | } |
185 | ||
186 | /* | |
187 | * value's type is bool. When using this function in FP context you can't pass | |
188 | * a value to it, you will need to use "is_json_context()" to have different | |
189 | * branch for json and regular output. grep -r "print_bool" for example | |
190 | */ | |
9091ff02 PM |
191 | static int __print_color_bool(enum output_type type, |
192 | enum color_attr color, | |
193 | const char *key, | |
194 | const char *fmt, | |
195 | bool value, | |
196 | const char *str) | |
6377572f | 197 | { |
5a07a5df BP |
198 | int ret = 0; |
199 | ||
6377572f JF |
200 | if (_IS_JSON_CONTEXT(type)) { |
201 | if (key) | |
202 | jsonw_bool_field(_jw, key, value); | |
203 | else | |
204 | jsonw_bool(_jw, value); | |
205 | } else if (_IS_FP_CONTEXT(type)) { | |
9091ff02 | 206 | ret = color_fprintf(stdout, color, fmt, str); |
6377572f | 207 | } |
5a07a5df BP |
208 | |
209 | return ret; | |
6377572f JF |
210 | } |
211 | ||
9091ff02 PM |
212 | int print_color_bool(enum output_type type, |
213 | enum color_attr color, | |
214 | const char *key, | |
215 | const char *fmt, | |
216 | bool value) | |
217 | { | |
218 | return __print_color_bool(type, color, key, fmt, value, | |
219 | value ? "true" : "false"); | |
220 | } | |
221 | ||
222 | int print_color_on_off(enum output_type type, | |
223 | enum color_attr color, | |
224 | const char *key, | |
225 | const char *fmt, | |
226 | bool value) | |
227 | { | |
228 | return __print_color_bool(type, color, key, fmt, value, | |
229 | value ? "on" : "off"); | |
230 | } | |
231 | ||
6377572f JF |
232 | /* |
233 | * In JSON context uses hardcode %#x format: 42 -> 0x2a | |
234 | */ | |
5a07a5df BP |
235 | int print_color_0xhex(enum output_type type, |
236 | enum color_attr color, | |
237 | const char *key, | |
238 | const char *fmt, | |
239 | unsigned long long hex) | |
6377572f | 240 | { |
5a07a5df BP |
241 | int ret = 0; |
242 | ||
6377572f JF |
243 | if (_IS_JSON_CONTEXT(type)) { |
244 | SPRINT_BUF(b1); | |
245 | ||
45ec4771 | 246 | snprintf(b1, sizeof(b1), "%#llx", hex); |
6377572f JF |
247 | print_string(PRINT_JSON, key, NULL, b1); |
248 | } else if (_IS_FP_CONTEXT(type)) { | |
5a07a5df | 249 | ret = color_fprintf(stdout, color, fmt, hex); |
6377572f | 250 | } |
5a07a5df BP |
251 | |
252 | return ret; | |
6377572f JF |
253 | } |
254 | ||
5a07a5df BP |
255 | int print_color_hex(enum output_type type, |
256 | enum color_attr color, | |
257 | const char *key, | |
258 | const char *fmt, | |
259 | unsigned int hex) | |
6377572f | 260 | { |
5a07a5df BP |
261 | int ret = 0; |
262 | ||
6377572f JF |
263 | if (_IS_JSON_CONTEXT(type)) { |
264 | SPRINT_BUF(b1); | |
265 | ||
266 | snprintf(b1, sizeof(b1), "%x", hex); | |
267 | if (key) | |
268 | jsonw_string_field(_jw, key, b1); | |
269 | else | |
270 | jsonw_string(_jw, b1); | |
271 | } else if (_IS_FP_CONTEXT(type)) { | |
5a07a5df | 272 | ret = color_fprintf(stdout, color, fmt, hex); |
6377572f | 273 | } |
5a07a5df BP |
274 | |
275 | return ret; | |
6377572f JF |
276 | } |
277 | ||
278 | /* | |
279 | * In JSON context we don't use the argument "value" we simply call jsonw_null | |
280 | * whereas FP context can use "value" to output anything | |
281 | */ | |
5a07a5df BP |
282 | int print_color_null(enum output_type type, |
283 | enum color_attr color, | |
284 | const char *key, | |
285 | const char *fmt, | |
286 | const char *value) | |
6377572f | 287 | { |
5a07a5df BP |
288 | int ret = 0; |
289 | ||
6377572f JF |
290 | if (_IS_JSON_CONTEXT(type)) { |
291 | if (key) | |
292 | jsonw_null_field(_jw, key); | |
293 | else | |
294 | jsonw_null(_jw); | |
295 | } else if (_IS_FP_CONTEXT(type)) { | |
5a07a5df | 296 | ret = color_fprintf(stdout, color, fmt, value); |
6377572f | 297 | } |
5a07a5df BP |
298 | |
299 | return ret; | |
6377572f | 300 | } |
b85076cd | 301 | |
260dc56a | 302 | /* Print line separator (if not in JSON mode) */ |
b85076cd SH |
303 | void print_nl(void) |
304 | { | |
305 | if (!_jw) | |
306 | printf("%s", _SL_); | |
307 | } | |
60265cc2 PM |
308 | |
309 | int print_color_rate(bool use_iec, enum output_type type, enum color_attr color, | |
310 | const char *key, const char *fmt, unsigned long long rate) | |
311 | { | |
312 | unsigned long kilo = use_iec ? 1024 : 1000; | |
313 | const char *str = use_iec ? "i" : ""; | |
314 | static char *units[5] = {"", "K", "M", "G", "T"}; | |
315 | char *buf; | |
316 | int rc; | |
317 | int i; | |
318 | ||
319 | if (_IS_JSON_CONTEXT(type)) | |
320 | return print_color_lluint(type, color, key, "%llu", rate); | |
321 | ||
322 | rate <<= 3; /* bytes/sec -> bits/sec */ | |
323 | ||
324 | for (i = 0; i < ARRAY_SIZE(units) - 1; i++) { | |
325 | if (rate < kilo) | |
326 | break; | |
327 | if (((rate % kilo) != 0) && rate < 1000*kilo) | |
328 | break; | |
329 | rate /= kilo; | |
330 | } | |
331 | ||
aaeda2a7 PM |
332 | rc = asprintf(&buf, "%.0f%s%sbit", (double)rate, units[i], |
333 | i > 0 ? str : ""); | |
60265cc2 PM |
334 | if (rc < 0) |
335 | return -1; | |
336 | ||
337 | rc = print_color_string(type, color, key, fmt, buf); | |
338 | free(buf); | |
339 | return rc; | |
340 | } |