Initial commit of vpp code.
[vpp.git] / vpp-api-test / 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     FILE *ofp;
29     u32 indent;
30 } vat_print_ctx_t;
31
32 /* Format an IP4 address. */
33 static u8 * vat_json_format_ip4_address (u8 * s, va_list * args)
34 {
35   u8 * a = va_arg (*args, u8 *);
36   return format (s, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]);
37 }
38
39 /* Format an IP6 address. */
40 static u8 * vat_json_format_ip6_address (u8 * s, va_list * args)
41 {
42   ip6_address_t * a = va_arg (*args, ip6_address_t *);
43   u32 i, i_max_n_zero, max_n_zeros, i_first_zero, n_zeros, last_double_colon;
44
45   i_max_n_zero = ARRAY_LEN (a->as_u16);
46   max_n_zeros = 0;
47   i_first_zero = i_max_n_zero;
48   n_zeros = 0;
49   for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
50     {
51       u32 is_zero = a->as_u16[i] == 0;
52       if (is_zero && i_first_zero >= ARRAY_LEN (a->as_u16))
53         {
54           i_first_zero = i;
55           n_zeros = 0;
56         }
57       n_zeros += is_zero;
58       if ((! is_zero && n_zeros > max_n_zeros)
59           || (i + 1 >= ARRAY_LEN (a->as_u16) && n_zeros > max_n_zeros))
60         {
61           i_max_n_zero = i_first_zero;
62           max_n_zeros = n_zeros;
63           i_first_zero = ARRAY_LEN (a->as_u16);
64           n_zeros = 0;
65         }
66     }
67
68   last_double_colon = 0;
69   for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
70     {
71       if (i == i_max_n_zero && max_n_zeros > 1)
72         {
73           s = format (s, "::");
74           i += max_n_zeros - 1;
75           last_double_colon = 1;
76         }
77       else
78         {
79           s = format (s, "%s%x",
80                       (last_double_colon || i == 0) ? "" : ":",
81                       clib_net_to_host_u16 (a->as_u16[i]));
82           last_double_colon = 0;
83         }
84     }
85
86   return s;
87 }
88
89 static void
90 vat_json_indent_print (vat_print_ctx_t *ctx)
91 {
92     int i;
93     for (i=0; i<ctx->indent * VAT_TAB_WIDTH; i++) {
94         fformat(ctx->ofp, " ");
95     }
96 }
97
98 static void
99 vat_json_indent_line (vat_print_ctx_t * ctx, char * fmt, ...)
100 {
101     va_list va;
102
103     vat_json_indent_print(ctx);
104     va_start(va, fmt);
105     va_fformat(ctx->ofp, fmt, &va);
106     va_end(va);
107 }
108
109 static u8
110 is_num_only (vat_json_node_t * p)
111 {
112     vat_json_node_t * elem;
113     vec_foreach(elem, p) {
114         if (VAT_JSON_INT != elem->type &&
115                 VAT_JSON_UINT != elem->type) {
116             return 0;
117         }
118     }
119     return 1;
120 }
121
122 static void
123 vat_json_print_internal (vat_print_ctx_t *ctx, vat_json_node_t *node)
124 {
125 #define P(fmt,...) fformat(ctx->ofp, fmt, ##__VA_ARGS__)
126 #define PL(fmt,...) fformat(ctx->ofp, fmt"\n", ##__VA_ARGS__)
127 #define PPL(fmt,...) vat_json_indent_line(ctx, fmt"\n", ##__VA_ARGS__)
128 #define PP(fmt,...) vat_json_indent_line(ctx, fmt, ##__VA_ARGS__)
129 #define INCR (ctx->indent++)
130 #define DECR (ctx->indent--)
131
132     vat_json_pair_t *pair;
133     u32 i, count;
134     vat_json_node_t *elem;
135     u8 num_only = 0;
136
137     if (!node) {
138         return;
139     }
140
141     switch (node->type) {
142     case VAT_JSON_OBJECT:
143         count = vec_len(node->pairs);
144         if (count >= 1) {
145             PL("{");
146             INCR;
147             for (i=0; i<count; i++) {
148                 pair = &node->pairs[i];
149                 PP("\"%s\": ", pair->name);
150                 vat_json_print_internal(ctx, &pair->value);
151                 if (i < count - 1) {
152                     P(",");
153                 }
154                 PL();
155             }
156             DECR;
157             PP("}");
158         } else { P("{}"); }
159         break;
160     case VAT_JSON_ARRAY:
161         num_only = is_num_only(node->array);
162         count = vec_len(node->array);
163         if (count >= 1) {
164             if (num_only)
165                 P("[");
166             else
167                 PL("[ ");
168             INCR;
169             for (i=0; i<count; i++) {
170                 elem = &node->array[i];
171                 if (!num_only) {
172                     vat_json_indent_print(ctx);
173                 }
174                 vat_json_print_internal(ctx, elem);
175                 if (i < count - 1) {
176                     if (num_only) {
177                         P(", ");
178                     } else {
179                         P(",");
180                     }
181                 }
182                 if (!num_only) PL();
183             }
184             DECR;
185             if (!num_only)
186                 PP("]");
187             else
188                 P("]");
189         } else { P("[]"); }
190         break;
191     case VAT_JSON_INT:
192         P("%d", node->sint);
193         break;
194     case VAT_JSON_UINT:
195         P("%"PRIu64, node->uint);
196         break;
197     case VAT_JSON_REAL:
198         P("%f", node->real);
199         break;
200     case VAT_JSON_STRING:
201         P("\"%s\"", node->string);
202         break;
203     case VAT_JSON_IPV4:
204         P("\"%U\"", vat_json_format_ip4_address, &node->ip4);
205         break;
206     case VAT_JSON_IPV6:
207         P("\"%U\"", vat_json_format_ip6_address, &node->ip6);
208         break;
209     default:
210         break;
211     }
212 #undef PPL
213 #undef PP
214 #undef PL
215 #undef P
216 }
217
218 void vat_json_print(FILE *ofp, vat_json_node_t *node)
219 {
220     vat_print_ctx_t ctx;
221     memset(&ctx, 0, sizeof ctx);
222     ctx.indent = 0;
223     ctx.ofp = ofp;
224     fformat(ofp, "\n");
225     vat_json_print_internal(&ctx, node);
226     fformat(ofp, "\n");
227 }
228
229 void vat_json_free (vat_json_node_t *node)
230 {
231     int i = 0;
232
233     if (NULL == node) {
234         return;
235     }
236     switch (node->type) {
237     case VAT_JSON_OBJECT:
238         for (i = 0; i < vec_len(node->pairs); i++) {
239             vat_json_free(&node->pairs[i].value);
240         }
241         if (NULL != node->pairs) {
242             vec_free(node->pairs);
243         }
244         break;
245     case VAT_JSON_ARRAY:
246         for (i = 0; i < vec_len(node->array); i++) {
247             vat_json_free(&node->array[i]);
248         }
249         if (NULL != node->array) {
250             vec_free(node->array);
251         }
252         break;
253     case VAT_JSON_STRING:
254         if (NULL != node->string) {
255             vec_free(node->string);
256         }
257         break;
258     default:
259         break;
260     }
261 }