]>
Commit | Line | Data |
---|---|---|
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 | void new_json_obj(int json) | |
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 | jsonw_start_array(_jw); | |
34 | } | |
35 | } | |
36 | ||
37 | void delete_json_obj(void) | |
38 | { | |
39 | if (_jw) { | |
40 | jsonw_end_array(_jw); | |
41 | jsonw_destroy(&_jw); | |
42 | } | |
43 | } | |
44 | ||
45 | bool is_json_context(void) | |
46 | { | |
47 | return _jw != NULL; | |
48 | } | |
49 | ||
50 | json_writer_t *get_json_writer(void) | |
51 | { | |
52 | return _jw; | |
53 | } | |
54 | ||
55 | void open_json_object(const char *str) | |
56 | { | |
57 | if (_IS_JSON_CONTEXT(PRINT_JSON)) { | |
58 | if (str) | |
59 | jsonw_name(_jw, str); | |
60 | jsonw_start_object(_jw); | |
61 | } | |
62 | } | |
63 | ||
64 | void close_json_object(void) | |
65 | { | |
66 | if (_IS_JSON_CONTEXT(PRINT_JSON)) | |
67 | jsonw_end_object(_jw); | |
68 | } | |
69 | ||
70 | /* | |
71 | * Start json array or string array using | |
72 | * the provided string as json key (if not null) | |
73 | * or as array delimiter in non-json context. | |
74 | */ | |
75 | void open_json_array(enum output_type type, const char *str) | |
76 | { | |
77 | if (_IS_JSON_CONTEXT(type)) { | |
78 | if (str) | |
79 | jsonw_name(_jw, str); | |
80 | jsonw_start_array(_jw); | |
81 | } else if (_IS_FP_CONTEXT(type)) { | |
82 | printf("%s", str); | |
83 | } | |
84 | } | |
85 | ||
86 | /* | |
87 | * End json array or string array | |
88 | */ | |
89 | void close_json_array(enum output_type type, const char *str) | |
90 | { | |
91 | if (_IS_JSON_CONTEXT(type)) { | |
92 | jsonw_end_array(_jw); | |
93 | } else if (_IS_FP_CONTEXT(type)) { | |
94 | printf("%s", str); | |
95 | } | |
96 | } | |
97 | ||
98 | /* | |
99 | * pre-processor directive to generate similar | |
100 | * functions handling different types | |
101 | */ | |
102 | #define _PRINT_FUNC(type_name, type) \ | |
103 | __attribute__((format(printf, 4, 0))) \ | |
104 | void print_color_##type_name(enum output_type t, \ | |
105 | enum color_attr color, \ | |
106 | const char *key, \ | |
107 | const char *fmt, \ | |
108 | type value) \ | |
109 | { \ | |
110 | if (_IS_JSON_CONTEXT(t)) { \ | |
111 | if (!key) \ | |
112 | jsonw_##type_name(_jw, value); \ | |
113 | else \ | |
114 | jsonw_##type_name##_field(_jw, key, value); \ | |
115 | } else if (_IS_FP_CONTEXT(t)) { \ | |
116 | color_fprintf(stdout, color, fmt, value); \ | |
117 | } \ | |
118 | } | |
119 | _PRINT_FUNC(int, int); | |
120 | _PRINT_FUNC(s64, int64_t); | |
121 | _PRINT_FUNC(hu, unsigned short); | |
122 | _PRINT_FUNC(uint, unsigned int); | |
123 | _PRINT_FUNC(u64, uint64_t); | |
124 | _PRINT_FUNC(luint, unsigned long int); | |
125 | _PRINT_FUNC(lluint, unsigned long long int); | |
126 | _PRINT_FUNC(float, double); | |
127 | #undef _PRINT_FUNC | |
128 | ||
129 | void print_color_string(enum output_type type, | |
130 | enum color_attr color, | |
131 | const char *key, | |
132 | const char *fmt, | |
133 | const char *value) | |
134 | { | |
135 | if (_IS_JSON_CONTEXT(type)) { | |
136 | if (key && !value) | |
137 | jsonw_name(_jw, key); | |
138 | else if (!key && value) | |
139 | jsonw_string(_jw, value); | |
140 | else | |
141 | jsonw_string_field(_jw, key, value); | |
142 | } else if (_IS_FP_CONTEXT(type)) { | |
143 | color_fprintf(stdout, color, fmt, value); | |
144 | } | |
145 | } | |
146 | ||
147 | /* | |
148 | * value's type is bool. When using this function in FP context you can't pass | |
149 | * a value to it, you will need to use "is_json_context()" to have different | |
150 | * branch for json and regular output. grep -r "print_bool" for example | |
151 | */ | |
152 | void print_color_bool(enum output_type type, | |
153 | enum color_attr color, | |
154 | const char *key, | |
155 | const char *fmt, | |
156 | bool value) | |
157 | { | |
158 | if (_IS_JSON_CONTEXT(type)) { | |
159 | if (key) | |
160 | jsonw_bool_field(_jw, key, value); | |
161 | else | |
162 | jsonw_bool(_jw, value); | |
163 | } else if (_IS_FP_CONTEXT(type)) { | |
164 | color_fprintf(stdout, color, fmt, value ? "true" : "false"); | |
165 | } | |
166 | } | |
167 | ||
168 | /* | |
169 | * In JSON context uses hardcode %#x format: 42 -> 0x2a | |
170 | */ | |
171 | void print_color_0xhex(enum output_type type, | |
172 | enum color_attr color, | |
173 | const char *key, | |
174 | const char *fmt, | |
175 | unsigned long long hex) | |
176 | { | |
177 | if (_IS_JSON_CONTEXT(type)) { | |
178 | SPRINT_BUF(b1); | |
179 | ||
180 | snprintf(b1, sizeof(b1), "%#llx", hex); | |
181 | print_string(PRINT_JSON, key, NULL, b1); | |
182 | } else if (_IS_FP_CONTEXT(type)) { | |
183 | color_fprintf(stdout, color, fmt, hex); | |
184 | } | |
185 | } | |
186 | ||
187 | void print_color_hex(enum output_type type, | |
188 | enum color_attr color, | |
189 | const char *key, | |
190 | const char *fmt, | |
191 | unsigned int hex) | |
192 | { | |
193 | if (_IS_JSON_CONTEXT(type)) { | |
194 | SPRINT_BUF(b1); | |
195 | ||
196 | snprintf(b1, sizeof(b1), "%x", hex); | |
197 | if (key) | |
198 | jsonw_string_field(_jw, key, b1); | |
199 | else | |
200 | jsonw_string(_jw, b1); | |
201 | } else if (_IS_FP_CONTEXT(type)) { | |
202 | color_fprintf(stdout, color, fmt, hex); | |
203 | } | |
204 | } | |
205 | ||
206 | /* | |
207 | * In JSON context we don't use the argument "value" we simply call jsonw_null | |
208 | * whereas FP context can use "value" to output anything | |
209 | */ | |
210 | void print_color_null(enum output_type type, | |
211 | enum color_attr color, | |
212 | const char *key, | |
213 | const char *fmt, | |
214 | const char *value) | |
215 | { | |
216 | if (_IS_JSON_CONTEXT(type)) { | |
217 | if (key) | |
218 | jsonw_null_field(_jw, key); | |
219 | else | |
220 | jsonw_null(_jw); | |
221 | } else if (_IS_FP_CONTEXT(type)) { | |
222 | color_fprintf(stdout, color, fmt, value); | |
223 | } | |
224 | } | |
225 | ||
226 | /* Print line seperator (if not in JSON mode) */ | |
227 | void print_nl(void) | |
228 | { | |
229 | if (!_jw) | |
230 | printf("%s", _SL_); | |
231 | } |