Reorganize source tree to use single autotools instance
[vpp.git] / src / vat / json_format.c
diff --git a/src/vat/json_format.c b/src/vat/json_format.c
new file mode 100644 (file)
index 0000000..6f316d9
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ *------------------------------------------------------------------
+ * 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;
+    }
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */