summaryrefslogtreecommitdiffstats
path: root/vpp-api-test/vat/json_format.c
diff options
context:
space:
mode:
Diffstat (limited to 'vpp-api-test/vat/json_format.c')
-rw-r--r--vpp-api-test/vat/json_format.c261
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;
+ }
+}