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