Reorganize source tree to use single autotools instance
[vpp.git] / src / vat / json_format.c
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 <vat/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 vat_json_format_ip4_address (u8 * s, va_list * args)
36 {
37   u8 *a = va_arg (*args, u8 *);
38   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 vat_json_format_ip6_address (u8 * s, va_list * args)
44 {
45   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   i_max_n_zero = ARRAY_LEN (a->as_u16);
49   max_n_zeros = 0;
50   i_first_zero = i_max_n_zero;
51   n_zeros = 0;
52   for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
53     {
54       u32 is_zero = a->as_u16[i] == 0;
55       if (is_zero && i_first_zero >= ARRAY_LEN (a->as_u16))
56         {
57           i_first_zero = i;
58           n_zeros = 0;
59         }
60       n_zeros += is_zero;
61       if ((!is_zero && n_zeros > max_n_zeros)
62           || (i + 1 >= ARRAY_LEN (a->as_u16) && n_zeros > max_n_zeros))
63         {
64           i_max_n_zero = i_first_zero;
65           max_n_zeros = n_zeros;
66           i_first_zero = ARRAY_LEN (a->as_u16);
67           n_zeros = 0;
68         }
69     }
70
71   last_double_colon = 0;
72   for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
73     {
74       if (i == i_max_n_zero && max_n_zeros > 1)
75         {
76           s = format (s, "::");
77           i += max_n_zeros - 1;
78           last_double_colon = 1;
79         }
80       else
81         {
82           s = format (s, "%s%x",
83                       (last_double_colon || i == 0) ? "" : ":",
84                       clib_net_to_host_u16 (a->as_u16[i]));
85           last_double_colon = 0;
86         }
87     }
88
89   return s;
90 }
91
92 static void
93 vat_json_indent_print (vat_print_ctx_t * ctx)
94 {
95   int i;
96   for (i = 0; i < ctx->indent * VAT_TAB_WIDTH; i++)
97     {
98       fformat (ctx->ofp, " ");
99     }
100 }
101
102 static void
103 vat_json_indent_line (vat_print_ctx_t * ctx, char *fmt, ...)
104 {
105   va_list va;
106
107   vat_json_indent_print (ctx);
108   va_start (va, fmt);
109   va_fformat (ctx->ofp, fmt, &va);
110   va_end (va);
111 }
112
113 static u8
114 is_num_only (vat_json_node_t * p)
115 {
116   vat_json_node_t *elem;
117   vec_foreach (elem, p)
118   {
119     if (VAT_JSON_INT != elem->type && VAT_JSON_UINT != elem->type)
120       {
121         return 0;
122       }
123   }
124   return 1;
125 }
126
127 static void
128 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   u8 num_only = 0;
141
142   if (!node)
143     {
144       return;
145     }
146
147   switch (node->type)
148     {
149     case VAT_JSON_OBJECT:
150       count = vec_len (node->pairs);
151       if (count >= 1)
152         {
153           PL ("{");
154           INCR;
155           for (i = 0; i < count; i++)
156             {
157               pair = &node->pairs[i];
158               PP ("\"%s\": ", pair->name);
159               vat_json_print_internal (ctx, &pair->value);
160               if (i < count - 1)
161                 {
162                   P (",");
163                 }
164               PL ();
165             }
166           DECR;
167           PP ("}");
168         }
169       else
170         {
171           P ("{}");
172         }
173       break;
174     case VAT_JSON_ARRAY:
175       num_only = is_num_only (node->array);
176       count = vec_len (node->array);
177       if (count >= 1)
178         {
179           if (num_only)
180             P ("[");
181           else
182             PL ("[ ");
183           INCR;
184           for (i = 0; i < count; i++)
185             {
186               elem = &node->array[i];
187               if (!num_only)
188                 {
189                   vat_json_indent_print (ctx);
190                 }
191               vat_json_print_internal (ctx, elem);
192               if (i < count - 1)
193                 {
194                   if (num_only)
195                     {
196                       P (", ");
197                     }
198                   else
199                     {
200                       P (",");
201                     }
202                 }
203               if (!num_only)
204                 PL ();
205             }
206           DECR;
207           if (!num_only)
208             PP ("]");
209           else
210             P ("]");
211         }
212       else
213         {
214           P ("[]");
215         }
216       break;
217     case VAT_JSON_INT:
218       P ("%d", node->sint);
219       break;
220     case VAT_JSON_UINT:
221       P ("%" PRIu64, node->uint);
222       break;
223     case VAT_JSON_REAL:
224       P ("%f", node->real);
225       break;
226     case VAT_JSON_STRING:
227       P ("\"%s\"", node->string);
228       break;
229     case VAT_JSON_IPV4:
230       P ("\"%U\"", vat_json_format_ip4_address, &node->ip4);
231       break;
232     case VAT_JSON_IPV6:
233       P ("\"%U\"", vat_json_format_ip6_address, &node->ip6);
234       break;
235     default:
236       break;
237     }
238 #undef PPL
239 #undef PP
240 #undef PL
241 #undef P
242 }
243
244 void
245 vat_json_print (FILE * ofp, vat_json_node_t * node)
246 {
247   vat_print_ctx_t ctx;
248   memset (&ctx, 0, sizeof ctx);
249   ctx.indent = 0;
250   ctx.ofp = ofp;
251   fformat (ofp, "\n");
252   vat_json_print_internal (&ctx, node);
253   fformat (ofp, "\n");
254 }
255
256 void
257 vat_json_free (vat_json_node_t * node)
258 {
259   int i = 0;
260
261   if (NULL == node)
262     {
263       return;
264     }
265   switch (node->type)
266     {
267     case VAT_JSON_OBJECT:
268       for (i = 0; i < vec_len (node->pairs); i++)
269         {
270           vat_json_free (&node->pairs[i].value);
271         }
272       if (NULL != node->pairs)
273         {
274           vec_free (node->pairs);
275         }
276       break;
277     case VAT_JSON_ARRAY:
278       for (i = 0; i < vec_len (node->array); i++)
279         {
280           vat_json_free (&node->array[i]);
281         }
282       if (NULL != node->array)
283         {
284           vec_free (node->array);
285         }
286       break;
287     case VAT_JSON_STRING:
288       if (NULL != node->string)
289         {
290           vec_free (node->string);
291         }
292       break;
293     default:
294       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  */