xref: /aosp_15_r20/external/ethtool/json_print.c (revision 1b481fc3bb1b45d4cf28d1ec12969dc1055f555d)
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, <[email protected]>
10  */
11 
12 #include <stdarg.h>
13 #include <stdio.h>
14 #include <unistd.h>
15 #include <stdlib.h>
16 
17 #include "json_print.h"
18 
19 #define SPRINT_BSIZE 64
20 #define SPRINT_BUF(x)   char x[SPRINT_BSIZE]
21 
22 static json_writer_t *_jw;
23 
24 #define _IS_JSON_CONTEXT(type) ((type & PRINT_JSON || type & PRINT_ANY) && _jw)
25 #define _IS_FP_CONTEXT(type) (!_jw && (type & PRINT_FP || type & PRINT_ANY))
26 
new_json_obj(int json)27 void new_json_obj(int json)
28 {
29 	if (json) {
30 		_jw = jsonw_new(stdout);
31 		if (!_jw) {
32 			perror("json object");
33 			exit(1);
34 		}
35 		jsonw_pretty(_jw, true);
36 		jsonw_start_array(_jw);
37 	}
38 }
39 
delete_json_obj(void)40 void delete_json_obj(void)
41 {
42 	if (_jw) {
43 		jsonw_end_array(_jw);
44 		jsonw_destroy(&_jw);
45 	}
46 }
47 
is_json_context(void)48 bool is_json_context(void)
49 {
50 	return _jw != NULL;
51 }
52 
get_json_writer(void)53 json_writer_t *get_json_writer(void)
54 {
55 	return _jw;
56 }
57 
open_json_object(const char * str)58 void open_json_object(const char *str)
59 {
60 	if (_IS_JSON_CONTEXT(PRINT_JSON)) {
61 		if (str)
62 			jsonw_name(_jw, str);
63 		jsonw_start_object(_jw);
64 	}
65 }
66 
close_json_object(void)67 void close_json_object(void)
68 {
69 	if (_IS_JSON_CONTEXT(PRINT_JSON))
70 		jsonw_end_object(_jw);
71 }
72 
73 /*
74  * Start json array or string array using
75  * the provided string as json key (if not null)
76  * or array delimiter in non-json context.
77  */
open_json_array(const char * key,const char * str)78 void open_json_array(const char *key, const char *str)
79 {
80 	if (is_json_context()) {
81 		if (key)
82 			jsonw_name(_jw, key);
83 		jsonw_start_array(_jw);
84 	} else {
85 		printf("%s", str);
86 	}
87 }
88 
89 /*
90  * End json array or string array
91  */
close_json_array(const char * delim)92 void close_json_array(const char *delim)
93 {
94 	if (is_json_context())
95 		jsonw_end_array(_jw);
96 	else
97 		printf("%s", delim);
98 }
99 
100 /*
101  * pre-processor directive to generate similar
102  * functions handling different types
103  */
104 #define _PRINT_FUNC(type_name, type)					\
105 	__attribute__((format(printf, 3, 0)))				\
106 	void print_##type_name(enum output_type t,			\
107 			       const char *key,				\
108 			       const char *fmt,				\
109 			       type value)				\
110 	{								\
111 		if (_IS_JSON_CONTEXT(t)) {				\
112 			if (!key)					\
113 				jsonw_##type_name(_jw, value);		\
114 			else						\
115 				jsonw_##type_name##_field(_jw, key, value); \
116 		} else if (_IS_FP_CONTEXT(t)) {				\
117 			fprintf(stdout, fmt, value);			\
118 		}							\
119 	}
120 _PRINT_FUNC(int, int);
121 _PRINT_FUNC(s64, int64_t);
122 _PRINT_FUNC(hhu, unsigned char);
123 _PRINT_FUNC(hu, unsigned short);
124 _PRINT_FUNC(uint, unsigned int);
125 _PRINT_FUNC(u64, uint64_t);
126 _PRINT_FUNC(luint, unsigned long);
127 _PRINT_FUNC(lluint, unsigned long long);
128 _PRINT_FUNC(float, double);
129 #undef _PRINT_FUNC
130 
print_string(enum output_type type,const char * key,const char * fmt,const char * value)131 void print_string(enum output_type type,
132 		  const char *key,
133 		  const char *fmt,
134 		  const char *value)
135 {
136 	if (_IS_JSON_CONTEXT(type)) {
137 		if (key && !value)
138 			jsonw_name(_jw, key);
139 		else if (!key && value)
140 			jsonw_string(_jw, value);
141 		else
142 			jsonw_string_field(_jw, key, value);
143 	} else if (_IS_FP_CONTEXT(type)) {
144 		fprintf(stdout, fmt, value);
145 	}
146 }
147 
148 /*
149  * value's type is bool. When using this function in FP context you can't pass
150  * a value to it, you will need to use "is_json_context()" to have different
151  * branch for json and regular output. grep -r "print_bool" for example
152  */
print_bool(enum output_type type,const char * key,const char * fmt,bool value)153 void print_bool(enum output_type type,
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 		fprintf(stdout, fmt, value ? "true" : "false");
165 	}
166 }
167 
168 /*
169  * In JSON context uses hardcode %#x format: 42 -> 0x2a
170  */
print_0xhex(enum output_type type,const char * key,const char * fmt,unsigned long long hex)171 void print_0xhex(enum output_type type,
172 		 const char *key,
173 		 const char *fmt,
174 		 unsigned long long hex)
175 {
176 	if (_IS_JSON_CONTEXT(type)) {
177 		SPRINT_BUF(b1);
178 
179 		snprintf(b1, sizeof(b1), "%#llx", hex);
180 		print_string(PRINT_JSON, key, NULL, b1);
181 	} else if (_IS_FP_CONTEXT(type)) {
182 		fprintf(stdout, fmt, hex);
183 	}
184 }
185 
print_hex(enum output_type type,const char * key,const char * fmt,unsigned int hex)186 void print_hex(enum output_type type,
187 	       const char *key,
188 	       const char *fmt,
189 	       unsigned int hex)
190 {
191 	if (_IS_JSON_CONTEXT(type)) {
192 		SPRINT_BUF(b1);
193 
194 		snprintf(b1, sizeof(b1), "%x", hex);
195 		if (key)
196 			jsonw_string_field(_jw, key, b1);
197 		else
198 			jsonw_string(_jw, b1);
199 	} else if (_IS_FP_CONTEXT(type)) {
200 		fprintf(stdout, fmt, hex);
201 	}
202 }
203 
204 /*
205  * In JSON context we don't use the argument "value" we simply call jsonw_null
206  * whereas FP context can use "value" to output anything
207  */
print_null(enum output_type type,const char * key,const char * fmt,const char * value)208 void print_null(enum output_type type,
209 		const char *key,
210 		const char *fmt,
211 		const char *value)
212 {
213 	if (_IS_JSON_CONTEXT(type)) {
214 		if (key)
215 			jsonw_null_field(_jw, key);
216 		else
217 			jsonw_null(_jw);
218 	} else if (_IS_FP_CONTEXT(type)) {
219 		fprintf(stdout, fmt, value);
220 	}
221 }
222 
223 /* Print line separator (if not in JSON mode) */
print_nl(void)224 void print_nl(void)
225 {
226 	if (!_jw)
227 		printf("%s", "\n");
228 }
229