diff options
Diffstat (limited to 'vpp-api-test/vat/json_format.c')
-rw-r--r-- | vpp-api-test/vat/json_format.c | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/vpp-api-test/vat/json_format.c b/vpp-api-test/vat/json_format.c new file mode 100644 index 00000000000..70447ed916c --- /dev/null +++ b/vpp-api-test/vat/json_format.c @@ -0,0 +1,261 @@ +/* + *------------------------------------------------------------------ + * json_format.c + * + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------ + +*/ +#include <inttypes.h> +#include <vat/json_format.h> +#include <vnet/ip/ip.h> +#include <vppinfra/vec.h> + +#define VAT_TAB_WIDTH 2 + +typedef struct vat_print_ctx_s { + FILE *ofp; + u32 indent; +} vat_print_ctx_t; + +/* Format an IP4 address. */ +static u8 * vat_json_format_ip4_address (u8 * s, va_list * args) +{ + u8 * a = va_arg (*args, u8 *); + return format (s, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]); +} + +/* Format an IP6 address. */ +static u8 * vat_json_format_ip6_address (u8 * s, va_list * args) +{ + ip6_address_t * a = va_arg (*args, ip6_address_t *); + u32 i, i_max_n_zero, max_n_zeros, i_first_zero, n_zeros, last_double_colon; + + i_max_n_zero = ARRAY_LEN (a->as_u16); + max_n_zeros = 0; + i_first_zero = i_max_n_zero; + n_zeros = 0; + for (i = 0; i < ARRAY_LEN (a->as_u16); i++) + { + u32 is_zero = a->as_u16[i] == 0; + if (is_zero && i_first_zero >= ARRAY_LEN (a->as_u16)) + { + i_first_zero = i; + n_zeros = 0; + } + n_zeros += is_zero; + if ((! is_zero && n_zeros > max_n_zeros) + || (i + 1 >= ARRAY_LEN (a->as_u16) && n_zeros > max_n_zeros)) + { + i_max_n_zero = i_first_zero; + max_n_zeros = n_zeros; + i_first_zero = ARRAY_LEN (a->as_u16); + n_zeros = 0; + } + } + + last_double_colon = 0; + for (i = 0; i < ARRAY_LEN (a->as_u16); i++) + { + if (i == i_max_n_zero && max_n_zeros > 1) + { + s = format (s, "::"); + i += max_n_zeros - 1; + last_double_colon = 1; + } + else + { + s = format (s, "%s%x", + (last_double_colon || i == 0) ? "" : ":", + clib_net_to_host_u16 (a->as_u16[i])); + last_double_colon = 0; + } + } + + return s; +} + +static void +vat_json_indent_print (vat_print_ctx_t *ctx) +{ + int i; + for (i=0; i<ctx->indent * VAT_TAB_WIDTH; i++) { + fformat(ctx->ofp, " "); + } +} + +static void +vat_json_indent_line (vat_print_ctx_t * ctx, char * fmt, ...) +{ + va_list va; + + vat_json_indent_print(ctx); + va_start(va, fmt); + va_fformat(ctx->ofp, fmt, &va); + va_end(va); +} + +static u8 +is_num_only (vat_json_node_t * p) +{ + vat_json_node_t * elem; + vec_foreach(elem, p) { + if (VAT_JSON_INT != elem->type && + VAT_JSON_UINT != elem->type) { + return 0; + } + } + return 1; +} + +static void +vat_json_print_internal (vat_print_ctx_t *ctx, vat_json_node_t *node) +{ +#define P(fmt,...) fformat(ctx->ofp, fmt, ##__VA_ARGS__) +#define PL(fmt,...) fformat(ctx->ofp, fmt"\n", ##__VA_ARGS__) +#define PPL(fmt,...) vat_json_indent_line(ctx, fmt"\n", ##__VA_ARGS__) +#define PP(fmt,...) vat_json_indent_line(ctx, fmt, ##__VA_ARGS__) +#define INCR (ctx->indent++) +#define DECR (ctx->indent--) + + vat_json_pair_t *pair; + u32 i, count; + vat_json_node_t *elem; + u8 num_only = 0; + + if (!node) { + return; + } + + switch (node->type) { + case VAT_JSON_OBJECT: + count = vec_len(node->pairs); + if (count >= 1) { + PL("{"); + INCR; + for (i=0; i<count; i++) { + pair = &node->pairs[i]; + PP("\"%s\": ", pair->name); + vat_json_print_internal(ctx, &pair->value); + if (i < count - 1) { + P(","); + } + PL(); + } + DECR; + PP("}"); + } else { P("{}"); } + break; + case VAT_JSON_ARRAY: + num_only = is_num_only(node->array); + count = vec_len(node->array); + if (count >= 1) { + if (num_only) + P("["); + else + PL("[ "); + INCR; + for (i=0; i<count; i++) { + elem = &node->array[i]; + if (!num_only) { + vat_json_indent_print(ctx); + } + vat_json_print_internal(ctx, elem); + if (i < count - 1) { + if (num_only) { + P(", "); + } else { + P(","); + } + } + if (!num_only) PL(); + } + DECR; + if (!num_only) + PP("]"); + else + P("]"); + } else { P("[]"); } + break; + case VAT_JSON_INT: + P("%d", node->sint); + break; + case VAT_JSON_UINT: + P("%"PRIu64, node->uint); + break; + case VAT_JSON_REAL: + P("%f", node->real); + break; + case VAT_JSON_STRING: + P("\"%s\"", node->string); + break; + case VAT_JSON_IPV4: + P("\"%U\"", vat_json_format_ip4_address, &node->ip4); + break; + case VAT_JSON_IPV6: + P("\"%U\"", vat_json_format_ip6_address, &node->ip6); + break; + default: + break; + } +#undef PPL +#undef PP +#undef PL +#undef P +} + +void vat_json_print(FILE *ofp, vat_json_node_t *node) +{ + vat_print_ctx_t ctx; + memset(&ctx, 0, sizeof ctx); + ctx.indent = 0; + ctx.ofp = ofp; + fformat(ofp, "\n"); + vat_json_print_internal(&ctx, node); + fformat(ofp, "\n"); +} + +void vat_json_free (vat_json_node_t *node) +{ + int i = 0; + + if (NULL == node) { + return; + } + switch (node->type) { + case VAT_JSON_OBJECT: + for (i = 0; i < vec_len(node->pairs); i++) { + vat_json_free(&node->pairs[i].value); + } + if (NULL != node->pairs) { + vec_free(node->pairs); + } + break; + case VAT_JSON_ARRAY: + for (i = 0; i < vec_len(node->array); i++) { + vat_json_free(&node->array[i]); + } + if (NULL != node->array) { + vec_free(node->array); + } + break; + case VAT_JSON_STRING: + if (NULL != node->string) { + vec_free(node->string); + } + break; + default: + break; + } +} |