]> git.proxmox.com Git - mirror_iproute2.git/blame - lib/json_print.c
build: Fix link errors on some systems
[mirror_iproute2.git] / lib / json_print.c
CommitLineData
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
18static json_writer_t *_jw;
6377572f 19
98e48e7d 20static 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 35static 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
44void new_json_obj(int json)
45{
46 __new_json_obj(json, true);
47}
48
49void delete_json_obj(void)
50{
51 __delete_json_obj(true);
52}
53
54void new_json_obj_plain(int json)
55{
56 __new_json_obj(json, false);
57}
58
59void delete_json_obj_plain(void)
60{
61 __delete_json_obj(false);
62}
63
6377572f
JF
64bool is_json_context(void)
65{
66 return _jw != NULL;
67}
68
6377572f
JF
69json_writer_t *get_json_writer(void)
70{
71 return _jw;
72}
73
74void 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
83void 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 */
94void 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 */
108void 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
164int 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
191static 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
212int 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
222int 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
235int 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
255int 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
282int 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
303void print_nl(void)
304{
305 if (!_jw)
306 printf("%s", _SL_);
307}
60265cc2
PM
308
309int 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}