Line data Source code
1 : /*
2 : *------------------------------------------------------------------
3 : * json_format.c
4 : *
5 : * Copyright (c) 2015 Cisco and/or its affiliates.
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at:
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : *------------------------------------------------------------------
18 :
19 : */
20 : #include <inttypes.h>
21 : #include "json_format.h"
22 : #include <vnet/ip/ip.h>
23 : #include <vppinfra/vec.h>
24 :
25 : #define VAT_TAB_WIDTH 2
26 :
27 : typedef struct vat_print_ctx_s
28 : {
29 : FILE *ofp;
30 : u32 indent;
31 : } vat_print_ctx_t;
32 :
33 : /* Format an IP4 address. */
34 : static u8 *
35 0 : vat_json_format_ip4_address (u8 * s, va_list * args)
36 : {
37 0 : u8 *a = va_arg (*args, u8 *);
38 0 : return format (s, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]);
39 : }
40 :
41 : /* Format an IP6 address. */
42 : static u8 *
43 0 : vat_json_format_ip6_address (u8 * s, va_list * args)
44 : {
45 0 : ip6_address_t *a = va_arg (*args, ip6_address_t *);
46 : u32 i, i_max_n_zero, max_n_zeros, i_first_zero, n_zeros, last_double_colon;
47 :
48 0 : i_max_n_zero = ARRAY_LEN (a->as_u16);
49 0 : max_n_zeros = 0;
50 0 : i_first_zero = i_max_n_zero;
51 0 : n_zeros = 0;
52 0 : for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
53 : {
54 0 : u32 is_zero = a->as_u16[i] == 0;
55 0 : if (is_zero && i_first_zero >= ARRAY_LEN (a->as_u16))
56 : {
57 0 : i_first_zero = i;
58 0 : n_zeros = 0;
59 : }
60 0 : n_zeros += is_zero;
61 0 : if ((!is_zero && n_zeros > max_n_zeros)
62 0 : || (i + 1 >= ARRAY_LEN (a->as_u16) && n_zeros > max_n_zeros))
63 : {
64 0 : i_max_n_zero = i_first_zero;
65 0 : max_n_zeros = n_zeros;
66 0 : i_first_zero = ARRAY_LEN (a->as_u16);
67 0 : n_zeros = 0;
68 : }
69 : }
70 :
71 0 : last_double_colon = 0;
72 0 : for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
73 : {
74 0 : if (i == i_max_n_zero && max_n_zeros > 1)
75 : {
76 0 : s = format (s, "::");
77 0 : i += max_n_zeros - 1;
78 0 : last_double_colon = 1;
79 : }
80 : else
81 : {
82 0 : s = format (s, "%s%x",
83 0 : (last_double_colon || i == 0) ? "" : ":",
84 0 : clib_net_to_host_u16 (a->as_u16[i]));
85 0 : last_double_colon = 0;
86 : }
87 : }
88 :
89 0 : return s;
90 : }
91 :
92 : static void
93 0 : vat_json_indent_print (vat_print_ctx_t * ctx)
94 : {
95 : int i;
96 0 : for (i = 0; i < ctx->indent * VAT_TAB_WIDTH; i++)
97 : {
98 0 : fformat (ctx->ofp, " ");
99 : }
100 0 : }
101 :
102 : static void
103 0 : vat_json_indent_line (vat_print_ctx_t * ctx, char *fmt, ...)
104 : {
105 : va_list va;
106 :
107 0 : vat_json_indent_print (ctx);
108 0 : va_start (va, fmt);
109 0 : va_fformat (ctx->ofp, fmt, &va);
110 0 : va_end (va);
111 0 : }
112 :
113 : static u8
114 0 : is_num_only (vat_json_node_t * p)
115 : {
116 : vat_json_node_t *elem;
117 0 : vec_foreach (elem, p)
118 : {
119 0 : if (VAT_JSON_INT != elem->type && VAT_JSON_UINT != elem->type)
120 : {
121 0 : return 0;
122 : }
123 : }
124 0 : return 1;
125 : }
126 :
127 : static void
128 0 : vat_json_print_internal (vat_print_ctx_t * ctx, vat_json_node_t * node)
129 : {
130 : #define P(fmt,...) fformat(ctx->ofp, fmt, ##__VA_ARGS__)
131 : #define PL(fmt,...) fformat(ctx->ofp, fmt"\n", ##__VA_ARGS__)
132 : #define PPL(fmt,...) vat_json_indent_line(ctx, fmt"\n", ##__VA_ARGS__)
133 : #define PP(fmt,...) vat_json_indent_line(ctx, fmt, ##__VA_ARGS__)
134 : #define INCR (ctx->indent++)
135 : #define DECR (ctx->indent--)
136 :
137 : vat_json_pair_t *pair;
138 : u32 i, count;
139 : vat_json_node_t *elem;
140 0 : u8 num_only = 0;
141 :
142 0 : if (!node)
143 : {
144 0 : return;
145 : }
146 :
147 0 : switch (node->type)
148 : {
149 0 : case VAT_JSON_OBJECT:
150 0 : count = vec_len (node->pairs);
151 0 : if (count >= 1)
152 : {
153 0 : PL ("{");
154 0 : INCR;
155 0 : for (i = 0; i < count; i++)
156 : {
157 0 : pair = &node->pairs[i];
158 0 : PP ("\"%s\": ", pair->name);
159 0 : vat_json_print_internal (ctx, &pair->value);
160 0 : if (i < count - 1)
161 : {
162 0 : P (",");
163 : }
164 0 : PL ();
165 : }
166 0 : DECR;
167 0 : PP ("}");
168 : }
169 : else
170 : {
171 0 : P ("{}");
172 : }
173 0 : break;
174 0 : case VAT_JSON_ARRAY:
175 0 : num_only = is_num_only (node->array);
176 0 : count = vec_len (node->array);
177 0 : if (count >= 1)
178 : {
179 0 : if (num_only)
180 0 : P ("[");
181 : else
182 0 : PL ("[ ");
183 0 : INCR;
184 0 : for (i = 0; i < count; i++)
185 : {
186 0 : elem = &node->array[i];
187 0 : if (!num_only)
188 : {
189 0 : vat_json_indent_print (ctx);
190 : }
191 0 : vat_json_print_internal (ctx, elem);
192 0 : if (i < count - 1)
193 : {
194 0 : if (num_only)
195 : {
196 0 : P (", ");
197 : }
198 : else
199 : {
200 0 : P (",");
201 : }
202 : }
203 0 : if (!num_only)
204 0 : PL ();
205 : }
206 0 : DECR;
207 0 : if (!num_only)
208 0 : PP ("]");
209 : else
210 0 : P ("]");
211 : }
212 : else
213 : {
214 0 : P ("[]");
215 : }
216 0 : break;
217 0 : case VAT_JSON_INT:
218 0 : P ("%d", node->sint);
219 0 : break;
220 0 : case VAT_JSON_UINT:
221 0 : P ("%" PRIu64, node->uint);
222 0 : break;
223 0 : case VAT_JSON_REAL:
224 0 : P ("%f", node->real);
225 0 : break;
226 0 : case VAT_JSON_STRING:
227 0 : P ("\"%s\"", node->string);
228 0 : break;
229 0 : case VAT_JSON_IPV4:
230 0 : P ("\"%U\"", vat_json_format_ip4_address, &node->ip4);
231 0 : break;
232 0 : case VAT_JSON_IPV6:
233 0 : P ("\"%U\"", vat_json_format_ip6_address, &node->ip6);
234 0 : break;
235 0 : default:
236 0 : break;
237 : }
238 : #undef PPL
239 : #undef PP
240 : #undef PL
241 : #undef P
242 : }
243 :
244 : void
245 0 : vat_json_print (FILE * ofp, vat_json_node_t * node)
246 : {
247 : vat_print_ctx_t ctx;
248 0 : clib_memset (&ctx, 0, sizeof ctx);
249 0 : ctx.indent = 0;
250 0 : ctx.ofp = ofp;
251 0 : fformat (ofp, "\n");
252 0 : vat_json_print_internal (&ctx, node);
253 0 : fformat (ofp, "\n");
254 0 : }
255 :
256 : void
257 0 : vat_json_free (vat_json_node_t * node)
258 : {
259 0 : int i = 0;
260 :
261 0 : if (NULL == node)
262 : {
263 0 : return;
264 : }
265 0 : switch (node->type)
266 : {
267 0 : case VAT_JSON_OBJECT:
268 0 : for (i = 0; i < vec_len (node->pairs); i++)
269 : {
270 0 : vat_json_free (&node->pairs[i].value);
271 : }
272 0 : if (NULL != node->pairs)
273 : {
274 0 : vec_free (node->pairs);
275 : }
276 0 : break;
277 0 : case VAT_JSON_ARRAY:
278 0 : for (i = 0; i < vec_len (node->array); i++)
279 : {
280 0 : vat_json_free (&node->array[i]);
281 : }
282 0 : if (NULL != node->array)
283 : {
284 0 : vec_free (node->array);
285 : }
286 0 : break;
287 0 : case VAT_JSON_STRING:
288 0 : if (NULL != node->string)
289 : {
290 0 : vec_free (node->string);
291 : }
292 0 : break;
293 0 : default:
294 0 : break;
295 : }
296 : }
297 :
298 : /*
299 : * fd.io coding-style-patch-verification: ON
300 : *
301 : * Local Variables:
302 : * eval: (c-set-style "gnu")
303 : * End:
304 : */
|