blob: 70447ed916cc72854cbdb1c45f1f8915873d0b5a [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
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
27typedef struct vat_print_ctx_s {
28 FILE *ofp;
29 u32 indent;
30} vat_print_ctx_t;
31
32/* Format an IP4 address. */
33static 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. */
40static 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
89static void
90vat_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
98static void
99vat_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
109static u8
110is_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
122static void
123vat_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
218void 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
229void 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}