Add client-side msg_name_and_crc -> msg_index table

vppapigen now generates per-message crcs. Verified that whitespace
and real changes in message A don't change the crc for message B, etc.

Fixed the sample and flowperpkt plugins to participate. Others need
the same treatment. They don't build due to python/java language binding
build issues.

To use the scheme:

Client connects as usual.

Then call: u32 vl_api_get_msg_index(char * name_and_crc)
name_and_crc is a string like: "flowperpkt_tx_interface_add_del_753301f3",
aka the message name with _%08x <expected crc> appended.

Try these vpp-api-test commands to play with it:

vat# dump_msg_api_table
     <snip>
 [366]: punt_reply_cca27fbe
 [367]: ipsec_spd_dump_5e9ae88e
 [368]: ipsec_spd_details_6f7821b0
 [369]: sample_macswap_enable_disable_0f2813e2
 [370]: sample_macswap_enable_disable_reply_476738e5
 [371]: flowperpkt_tx_interface_add_del_753301f3
 [372]: flowperpkt_tx_interface_add_del_reply_d47e6e0b

vat# get_msg_id sample_macswap_enable_disable_reply_476738e5
 'sample_macswap_enable_disable_reply_476738e5' has message index 370

vat# get_msg_id sample_macswap_enable_disable_reply_476738e3
 'sample_macswap_enable_disable_reply_476738e3' not found

CRCs may vary, etc.

vppapigen is used to build a set of JSON representations
of each API file from vpp-api/Makefile.am and that is in
turn used by each language binding (Java, Python, Lua).

Change-Id: I3d64582e779dac5f20cddec79c562c288d8fd9c6
Signed-off-by: Dave Barach <dave@barachs.net>
Signed-off-by: Ole Troan <ot@cisco.com>
diff --git a/vppapigen/lex.c b/vppapigen/lex.c
index b011044..e807d46 100644
--- a/vppapigen/lex.c
+++ b/vppapigen/lex.c
@@ -28,7 +28,7 @@
 #include "node.h"
 #include "gram.h"
 
-FILE *ifp, *ofp, *pythonfp;
+FILE *ifp, *ofp, *pythonfp, *jsonfp;
 char *vlib_app_name = "vpp";
 int dump_tree;
 time_t starttime;
@@ -36,6 +36,7 @@
 char *current_filename;
 int current_filename_allocated;
 unsigned long input_crc;
+unsigned long message_crc;
 int yydebug;
 
 /*
@@ -258,6 +259,7 @@
     int curarg = 1;
     char *ofile=0;
     char *pythonfile=0;
+    char *jsonfile=0;
     char *show_name=0;
 
     while (curarg < argc) {
@@ -349,6 +351,27 @@
             }
             continue;
         }
+        if (!strncmp (argv [curarg], "--json", 6)) {
+            curarg++;
+            if (curarg < argc) {
+	        if (!strcmp(argv[curarg], "-")) {
+		    jsonfp = stdout;
+		} else {
+		    jsonfp = fopen(argv[curarg], "w");
+		    jsonfile = argv[curarg];
+		}
+                if (jsonfp == NULL) {
+                    fprintf (stderr, "Couldn't open JSON output file %s\n",
+                         argv[curarg]);
+                    exit (1);
+                }
+                curarg++;
+            } else {
+                fprintf(stderr, "Missing filename after --json\n");
+                exit(1);
+            }
+            continue;
+        }
         if (!strncmp (argv [curarg], "--app", 4)) {
             curarg++;
             if (curarg < argc) {
@@ -370,6 +393,9 @@
     if (pythonfp == NULL) {
         pythonfile = 0;
     }
+    if (jsonfp == NULL) {
+        jsonfile = 0;
+    }
     if (ifp == NULL) {
         fprintf(stderr, "No input file specified...\n");
         exit(1);
@@ -391,6 +417,10 @@
             printf ("Python bindings written to %s\n", pythonfile);
             fclose (pythonfp);
         }
+        if (jsonfile) {
+            printf ("JSON bindings written to %s\n", jsonfile);
+            fclose (jsonfp);
+        }
     }
     else {
         fclose (ifp);
@@ -404,6 +434,10 @@
             printf ("Removing %s\n", pythonfile);
             unlink (pythonfile);
         }
+        if (jsonfile) {
+            printf ("Removing %s\n", jsonfile);
+            unlink (jsonfile);
+        }
         exit (1);
     }
     exit (0);
@@ -415,7 +449,8 @@
 static void usage (char *progname)
 {
     fprintf (stderr, 
-             "usage: %s --input <filename> [--output <filename>] [--python <filename>]\n%s",
+             "usage: %s --input <filename> [--output <filename>] "
+	     "[--json <filename>] [--python <filename>]\n%s",
              progname,
              "          [--yydebug] [--dump-tree]\n");
     exit (1);
@@ -818,18 +853,18 @@
      */
     unsigned long crc = input_crc;
     int node_type = yylex_1 ();
+    unsigned long crc2 = message_crc;
+    int use_helper_string = 0;
+    unsigned short code;
 
     switch (node_type) {
     case PRIMTYPE:
     case NAME:
     case NUMBER:
     case STRING:
-    case HELPER_STRING: {
-        /* We know these types accumulated token text into namebuf */
-        /* HELPER_STRING may still contain C comments.  Argh. */
-        crc = crc_eliding_c_comments (namebuf, crc);
+    case HELPER_STRING: 
+        use_helper_string = 1;
         break;
-    }
 
      /* Other node types have no "substate" */
      /* This code is written in this curious fashion because we
@@ -837,30 +872,25 @@
       * values a particular version of lex/bison assigned to various states.
       */
 
-    /* case NAME:            crc = CRC16 (crc, 257); break; */
-    case RPAR:               crc = CRC16 (crc, 258); break;
-    case LPAR:               crc = CRC16 (crc, 259); break;
-    case SEMI:               crc = CRC16 (crc, 260); break;
-    case LBRACK:             crc = CRC16 (crc, 261); break;
-    case RBRACK:             crc = CRC16 (crc, 262); break;
-    /* case NUMBER:          crc = CRC16 (crc, 263); break; */
-    /* case PRIMTYPE:        crc = CRC16 (crc, 264); break; */
-    case BARF:               crc = CRC16 (crc, 265); break;
-    case TPACKED:            crc = CRC16 (crc, 266); break;
-    case DEFINE:             crc = CRC16 (crc, 267); break;
-    case LCURLY:             crc = CRC16 (crc, 268); break;
-    case RCURLY:             crc = CRC16 (crc, 269); break;
-    /* case STRING:          crc = CRC16 (crc, 270); break; */
-    case UNION:              crc = CRC16 (crc, 271); break;
-    /* case HELPER_STRING:   crc = CRC16 (crc, 272); break; */
-    case COMMA:              crc = CRC16 (crc, 273); break;
-    case NOVERSION:          crc = CRC16 (crc, 274); break;
-    case MANUAL_PRINT:       crc = CRC16 (crc, 275); break;
-    case MANUAL_ENDIAN:      crc = CRC16 (crc, 276); break;
-    case TYPEONLY:           crc = CRC16 (crc, 278); break;
-    case DONT_TRACE:         crc = CRC16 (crc, 279); break;
+    case RPAR:               code = 258; break;
+    case LPAR:               code = 259; break;
+    case SEMI:               code = 260; break;
+    case LBRACK:             code = 261; break;
+    case RBRACK:             code = 262; break;
+    case BARF:               code = 265; break;
+    case TPACKED:            code = 266; break;
+    case DEFINE:             code = 267; break;
+    case LCURLY:             code = 268; break;
+    case RCURLY:             code = 269; break;
+    case UNION:              code = 271; break;
+    case COMMA:              code = 273; break;
+    case NOVERSION:          code = 274; break;
+    case MANUAL_PRINT:       code = 275; break;
+    case MANUAL_ENDIAN:      code = 276; break;
+    case TYPEONLY:           code = 278; break;
+    case DONT_TRACE:         code = 279; break;
         
-    case EOF: crc = CRC16 (crc, ~0); break; /* hysterical compatibility */
+    case EOF: code = ~0; break; /* hysterical compatibility */
 
     default:
         fprintf(stderr, "yylex: node_type %d missing state CRC cookie\n",
@@ -868,11 +898,23 @@
         exit(1);
     }
 
+    if (use_helper_string)
+    {
+        /* We know these types accumulated token text into namebuf */
+        /* HELPER_STRING may still contain C comments.  Argh. */
+        crc = crc_eliding_c_comments (namebuf, crc);
+        crc2 = crc_eliding_c_comments (namebuf, crc2);
+    } else
+    {
+        crc = CRC16 (crc, code);
+        crc2 = CRC16 (crc2, code);
+    }
+
     input_crc = crc;
+    message_crc = crc2;
     return (node_type);
 }
 
-
 /*
  * name_check -- see if the name we just ate
  * matches a known keyword.  If so, set yylval
@@ -943,6 +985,7 @@
                 return (TPACKED);
 
             case NODE_DEFINE:
+                message_crc = 0;
                 *token_value = make_node(subclass_id);
                 return(DEFINE);