]> git.proxmox.com Git - mirror_iproute2.git/blob - lib/json_print.c
8e7f32dca2ce18c6d1ffa91aabcd188e274ac296
[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 void 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 if (_IS_JSON_CONTEXT(t)) { \
133 if (!key) \
134 jsonw_##type_name(_jw, value); \
135 else \
136 jsonw_##type_name##_field(_jw, key, value); \
137 } else if (_IS_FP_CONTEXT(t)) { \
138 color_fprintf(stdout, color, fmt, value); \
139 } \
140 }
141 _PRINT_FUNC(int, int);
142 _PRINT_FUNC(s64, int64_t);
143 _PRINT_FUNC(hhu, unsigned char);
144 _PRINT_FUNC(hu, unsigned short);
145 _PRINT_FUNC(uint, unsigned int);
146 _PRINT_FUNC(u64, uint64_t);
147 _PRINT_FUNC(luint, unsigned long);
148 _PRINT_FUNC(lluint, unsigned long long);
149 _PRINT_FUNC(float, double);
150 #undef _PRINT_FUNC
151
152 #define _PRINT_NAME_VALUE_FUNC(type_name, type, format_char) \
153 void print_##type_name##_name_value(const char *name, type value)\
154 { \
155 SPRINT_BUF(format); \
156 \
157 snprintf(format, SPRINT_BSIZE, \
158 "%s %%"#format_char, name); \
159 print_##type_name(PRINT_ANY, name, format, value); \
160 }
161 _PRINT_NAME_VALUE_FUNC(uint, unsigned int, u);
162 _PRINT_NAME_VALUE_FUNC(string, const char*, s);
163 #undef _PRINT_NAME_VALUE_FUNC
164
165 void print_color_string(enum output_type type,
166 enum color_attr color,
167 const char *key,
168 const char *fmt,
169 const char *value)
170 {
171 if (_IS_JSON_CONTEXT(type)) {
172 if (key && !value)
173 jsonw_name(_jw, key);
174 else if (!key && value)
175 jsonw_string(_jw, value);
176 else
177 jsonw_string_field(_jw, key, value);
178 } else if (_IS_FP_CONTEXT(type)) {
179 color_fprintf(stdout, color, fmt, value);
180 }
181 }
182
183 /*
184 * value's type is bool. When using this function in FP context you can't pass
185 * a value to it, you will need to use "is_json_context()" to have different
186 * branch for json and regular output. grep -r "print_bool" for example
187 */
188 void print_color_bool(enum output_type type,
189 enum color_attr color,
190 const char *key,
191 const char *fmt,
192 bool value)
193 {
194 if (_IS_JSON_CONTEXT(type)) {
195 if (key)
196 jsonw_bool_field(_jw, key, value);
197 else
198 jsonw_bool(_jw, value);
199 } else if (_IS_FP_CONTEXT(type)) {
200 color_fprintf(stdout, color, fmt, value ? "true" : "false");
201 }
202 }
203
204 /*
205 * In JSON context uses hardcode %#x format: 42 -> 0x2a
206 */
207 void print_color_0xhex(enum output_type type,
208 enum color_attr color,
209 const char *key,
210 const char *fmt,
211 unsigned long long hex)
212 {
213 if (_IS_JSON_CONTEXT(type)) {
214 SPRINT_BUF(b1);
215
216 snprintf(b1, sizeof(b1), "%#llx", hex);
217 print_string(PRINT_JSON, key, NULL, b1);
218 } else if (_IS_FP_CONTEXT(type)) {
219 color_fprintf(stdout, color, fmt, hex);
220 }
221 }
222
223 void print_color_hex(enum output_type type,
224 enum color_attr color,
225 const char *key,
226 const char *fmt,
227 unsigned int hex)
228 {
229 if (_IS_JSON_CONTEXT(type)) {
230 SPRINT_BUF(b1);
231
232 snprintf(b1, sizeof(b1), "%x", hex);
233 if (key)
234 jsonw_string_field(_jw, key, b1);
235 else
236 jsonw_string(_jw, b1);
237 } else if (_IS_FP_CONTEXT(type)) {
238 color_fprintf(stdout, color, fmt, hex);
239 }
240 }
241
242 /*
243 * In JSON context we don't use the argument "value" we simply call jsonw_null
244 * whereas FP context can use "value" to output anything
245 */
246 void print_color_null(enum output_type type,
247 enum color_attr color,
248 const char *key,
249 const char *fmt,
250 const char *value)
251 {
252 if (_IS_JSON_CONTEXT(type)) {
253 if (key)
254 jsonw_null_field(_jw, key);
255 else
256 jsonw_null(_jw);
257 } else if (_IS_FP_CONTEXT(type)) {
258 color_fprintf(stdout, color, fmt, value);
259 }
260 }
261
262 /* Print line separator (if not in JSON mode) */
263 void print_nl(void)
264 {
265 if (!_jw)
266 printf("%s", _SL_);
267 }