cb9cadad57
Change-Id: Ib246f1fbfce93274020ee93ce461e3d8bd8b9f17 Signed-off-by: Ed Warnicke <eaw@cisco.com>
262 lines
6.5 KiB
C
262 lines
6.5 KiB
C
/*
|
|
*------------------------------------------------------------------
|
|
* 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;
|
|
}
|
|
}
|