Python-API: Inital commit of Python bindings for the VPP API.
See: https://wiki.fd.io/view/VPP/Python_API

Change-Id: If135fc32208c7031787e1935b399d930e0e1ea1f
Signed-off-by: Ole Troan <ot@cisco.com>
diff --git a/vppapigen/lex.c b/vppapigen/lex.c
index b41eb5e..f1d49a8 100644
--- a/vppapigen/lex.c
+++ b/vppapigen/lex.c
@@ -28,7 +28,7 @@
 #include "node.h"
 #include "gram.h"
 
-FILE *ifp, *ofp, *javafp, *jnifp;
+FILE *ifp, *ofp, *javafp, *jnifp, *pythonfp;
 char *java_class = "vppApi";
 char *vlib_app_name = "vpp";
 int dump_tree;
@@ -260,6 +260,7 @@
     char *ofile=0;
     char *jofile=0;
     char *jnifile=0;
+    char *pythonfile=0;
     char *show_name=0;
 
     while (curarg < argc) {
@@ -364,6 +365,23 @@
             }
             continue;
         }
+        if (!strncmp (argv [curarg], "--python", 8)) {
+            curarg++;
+            if (curarg < argc) {
+                pythonfp = fopen (argv[curarg], "w");
+                if (pythonfp == NULL) {
+                    fprintf (stderr, "Couldn't open python output file %s\n",
+                         argv[curarg]);
+                    exit (1);
+                }
+                pythonfile = argv[curarg];
+                curarg++;
+            } else {
+                fprintf(stderr, "Missing filename after --python\n");
+                exit(1);
+            }
+            continue;
+        }
         if (!strncmp (argv [curarg], "--app", 4)) {
             curarg++;
             if (curarg < argc) {
@@ -399,6 +417,9 @@
     if (jnifp == NULL) {
         jnifile = 0;
     }
+    if (pythonfp == NULL) {
+        pythonfile = 0;
+    }
     if (ifp == NULL) {
         fprintf(stderr, "No input file specified...\n");
         exit(1);
@@ -424,6 +445,10 @@
             printf ("Java native bindings written to %s\n", jnifile);
             fclose (jnifp);
         }
+        if (pythonfile) {
+            printf ("Python bindings written to %s\n", pythonfile);
+            fclose (pythonfp);
+        }
     }
     else {
         fclose (ifp);
@@ -441,6 +466,10 @@
             printf ("Removing %s\n", jnifile);
             unlink (jnifile);
         }
+        if (pythonfile) {
+            printf ("Removing %s\n", pythonfile);
+            unlink (pythonfile);
+        }
         exit (1);
     }
     exit (0);
@@ -452,7 +481,7 @@
 static void usage (char *progname)
 {
     fprintf (stderr, 
-             "usage: %s --input <filename> [--output <filename>]\n%s",
+             "usage: %s --input <filename> [--output <filename>] [--python <filename>]\n%s",
              progname,
              "          [--yydebug] [--dump-tree]\n");
     exit (1);
diff --git a/vppapigen/node.c b/vppapigen/node.c
index 3a32abe..ffe5d77 100644
--- a/vppapigen/node.c
+++ b/vppapigen/node.c
@@ -34,6 +34,7 @@
 FILE *ofp;
 FILE *javafp;
 FILE *jnifp;
+FILE *pythonfp;
 char *java_class;
 time_t starttime;
 char *vlib_app_name;
@@ -161,6 +162,12 @@
         current_java_methodfun = vftp->java_method_function;
         break;
 
+    case PYTHON_PASS:
+        fputs("('", pythonfp);
+        fputs((char *)type_name, pythonfp);
+        fputs("', ", pythonfp);
+        break;
+
     default:
         fprintf(stderr, "primtype_recursive_generate: unimp pass %d\n", which);
         break;
@@ -876,6 +883,20 @@
         fprintf (fp, "}\n\n");
         break;
 
+    case PYTHON_PASS:
+      fprintf(fp, "('%s',\n", CDATA0);
+        child = this->deeper;
+        indent += 4;
+        while (child) {
+            node_vft_t *vftp = the_vft[child->type];
+            indent_me(fp);
+            vftp->generate(child, which, fp);
+            child = child->peer;
+        }
+        indent -= 4;
+        fprintf(fp, "),\n\n");
+        break;
+
     default:
         fprintf(stderr, "node_define_generate: unimp pass %d\n", which);
         break;
@@ -1032,6 +1053,9 @@
             }
         }
         break;
+    case PYTHON_PASS:
+        fprintf(fp, "'%s'),\n", CDATA0);
+        break;
 
     default:
         fprintf(stderr, "node_scalar_generate: unimp pass %d\n", which);
@@ -1136,6 +1160,9 @@
         indent_me(fp);
         fprintf(fp, "}\n");
         break;
+    case PYTHON_PASS:
+        fprintf(fp, "'%s', '%d'),\n", CDATA0, IDATA1);
+        break;
 
     default:
         fprintf(stderr, "node_vector_generate: unimp pass %d\n", which);
@@ -1216,6 +1243,14 @@
         fprintf(fp, "%s_endian(&a->%s%s);\n", 
                 CDATA0, union_prefix, member_name);
         break;
+    case PYTHON_PASS:
+        fprintf(fp, "('%s',", CDATA0);
+        deeper = this->deeper;
+        if (deeper) {
+            vftp = the_vft[deeper->type];
+            vftp->generate(deeper, which, fp);
+        }
+        break;
 
     default:
         fprintf(stderr, "node_complex_generate unimp pass %d...\n", which);
@@ -1767,14 +1802,14 @@
     while (np) {
         if (np->type == NODE_DEFINE) {
             if (!(np->flags & NODE_FLAG_TYPEONLY)) {
-                /* add the parse tree for "u16 _vl_msg_id" */
+	        /* add the parse tree for "u16 _vl_msg_id" */
                 new_u16 = make_node(NODE_U16);
                 new_u16->peer = np->deeper;
                 np->deeper = new_u16;
                 new_vbl = make_node(NODE_SCALAR);
                 new_vbl->data[0] = sxerox("_vl_msg_id");
                 new_u16->deeper = new_vbl;
-            }
+	    }
         }
         np = np->peer;
     }
@@ -1988,6 +2023,23 @@
     fputs (hookup_boilerplate, fp);
 }
 
+void generate_python (YYSTYPE a1, FILE *fp)
+{
+  node_t *np = (node_t *)a1;
+  node_vft_t *vftp;
+  fprintf (fp, "vppapidef = [\n");
+  /* Walk the top-level node-list */
+  while (np) {
+    if (np->type == NODE_DEFINE && !(np->flags & NODE_FLAG_TYPEONLY)) {
+      /* Yeah, this is pedantic */
+      vftp = the_vft[np->type];
+      vftp->generate(np, PYTHON_PASS, fp);
+    }
+    np = np->peer;
+  }
+  fprintf (fp, "\n]\n");
+}
+
 void generate(YYSTYPE a1)
 {
     if (dump_tree) {
@@ -2020,4 +2072,7 @@
         generate_jni_code(a1, jnifp);
         generate_jni_bottom_boilerplate(jnifp);
     }
+    if (pythonfp) {
+      generate_python(a1, pythonfp);
+    }
 }
diff --git a/vppapigen/node.h b/vppapigen/node.h
index 670b5af..1f5a153 100644
--- a/vppapigen/node.h
+++ b/vppapigen/node.h
@@ -63,6 +63,7 @@
     PRINTFUN_PASS,
     JAVA_METHOD_PASS,
     JAVA_JNI_PASS,
+    PYTHON_PASS,
 };
 
 extern void *make_node (enum node_subclass type);