vppapigen: support per-file (major,minor,patch) version stamps

Add one of these statements to foo.api:

  vl_api_version 1.2.3

to generate a version tuple stanza in foo.api.h:

/****** Version tuple *****/

vl_api_version_tuple(foo, 1, 2, 3)

Change-Id: Ic514439e4677999daa8463a94f948f76b132ff15
Signed-off-by: Dave Barach <dave@barachs.net>
Signed-off-by: Ole Troan <ot@cisco.com>
diff --git a/src/tools/vppapigen/gram.y b/src/tools/vppapigen/gram.y
index 52bb65c..5c5d46f 100644
--- a/src/tools/vppapigen/gram.y
+++ b/src/tools/vppapigen/gram.y
@@ -33,11 +33,12 @@
  YYSTYPE add_vector_vbl(YYSTYPE, YYSTYPE);
  YYSTYPE add_variable_length_vector_vbl(YYSTYPE, YYSTYPE);
  YYSTYPE set_flags(YYSTYPE, YYSTYPE);
+ YYSTYPE add_version(YYSTYPE, YYSTYPE, YYSTYPE);
 %}
 
 %token NAME RPAR LPAR SEMI LBRACK RBRACK NUMBER PRIMTYPE BARF
 %token TPACKED DEFINE LCURLY RCURLY STRING UNION
-%token HELPER_STRING COMMA 
+%token HELPER_STRING COMMA DOT VL_API_VERSION
 %token NOVERSION MANUAL_PRINT MANUAL_ENDIAN TYPEONLY DONT_TRACE AUTOREPLY
 
 %%
@@ -51,6 +52,7 @@
 
 stmt:     flist defn            {$$ = set_flags($1, $2);}
         | defn                  {$$ = $1;}
+        | api_version           {$$ = $1;}
           ;
 
 flist:    flist flag            {$$ = (YYSTYPE)(unsigned long)
@@ -89,3 +91,6 @@
         | NAME LBRACK NUMBER RBRACK {$$ = add_vector_vbl($1, $3);}
         | NAME LBRACK NAME RBRACK {$$ = add_variable_length_vector_vbl($1, $3);}
           ;
+
+api_version:  VL_API_VERSION NUMBER DOT NUMBER DOT NUMBER 
+                                    {$$ = add_version ($2, $4, $6);}
diff --git a/src/tools/vppapigen/lex.c b/src/tools/vppapigen/lex.c
index e635814..d9f82c2 100644
--- a/src/tools/vppapigen/lex.c
+++ b/src/tools/vppapigen/lex.c
@@ -581,6 +581,9 @@
         case ',':
             return (COMMA);
 
+        case '.':
+            return (DOT);
+
         case '"':
             nameidx = 0;
             the_lexer_state = STRING_STATE;
@@ -937,6 +940,8 @@
     case TYPEONLY:           code = 278; break;
     case DONT_TRACE:         code = 279; break;
     case AUTOREPLY:          code = 280; break;
+    case DOT:                code = 281; break;
+    case VL_API_VERSION:     code = 282; break;
         
     case EOF: code = ~0; break; /* hysterical compatibility */
 
@@ -996,6 +1001,7 @@
     {"u8", 		NODE_U8},
     {"union",           NODE_UNION},
     {"uword",           NODE_UWORD},
+    {"vl_api_version", 	NODE_VERSION},
 };
  
 static int name_check (const char *s, YYSTYPE *token_value)
@@ -1061,6 +1067,9 @@
             case NODE_NOVERSION:
                 return(NOVERSION);
 
+            case NODE_VERSION:
+                return(VL_API_VERSION);
+
             case NODE_UNION:
                 return(UNION);
 
diff --git a/src/tools/vppapigen/node.c b/src/tools/vppapigen/node.c
index 4c85a11..37ba493 100644
--- a/src/tools/vppapigen/node.c
+++ b/src/tools/vppapigen/node.c
@@ -832,6 +832,22 @@
     0,
 };
 
+void node_version_print (node_t *this)
+{
+    primtype_recursive_print (this, "version ");
+}
+
+void node_version_generate (node_t *this, enum passid which, FILE *ofp)
+{
+    fprintf(stderr, "node_version_generate called...\n");
+}
+
+node_vft_t node_version_vft = {
+    node_version_print,
+    node_version_generate,
+    0,
+};
+
 void node_uword_print (node_t *this)
 {
     primtype_recursive_print(this, "uword ");
@@ -866,6 +882,7 @@
     &node_vector_vft,
     &node_complex_vft,
     &node_noversion_vft,
+    &node_version_vft,
     &node_uword_vft,
 };
 
@@ -1133,7 +1150,8 @@
     fprintf (fp, "#if defined(vl_msg_id)||defined(vl_union_id)||");
     fprintf (fp, "defined(vl_printfun) \\\n ||defined(vl_endianfun)||");
     fprintf (fp, " defined(vl_api_version)||defined(vl_typedefs) \\\n");
-    fprintf (fp, " ||defined(vl_msg_name)||defined(vl_msg_name_crc_list)\n");
+    fprintf (fp, " ||defined(vl_msg_name)||defined(vl_msg_name_crc_list) \\\n");
+    fprintf (fp, " ||defined(vl_api_version_tuple)\n");
     fprintf (fp, "/* ok, something was selected */\n");
     fprintf (fp, "#else\n");
     fprintf (fp, "#warning no content included from %s\n", input_filename);
@@ -1144,7 +1162,8 @@
 void generate_bottom_boilerplate(FILE *fp)
 
 {
-    fprintf (fp, "\n#ifdef vl_api_version\n");
+    fprintf(fp, "/****** API CRC (whole file) *****/\n\n");
+    fprintf (fp, "#ifdef vl_api_version\n");
 
     if (dont_output_version) {
         fprintf (fp, "/* WARNING: API FILE VERSION CHECK DISABLED */\n");
@@ -1153,6 +1172,7 @@
 
     fprintf (fp, "vl_api_version(%s, 0x%08x)\n\n", 
              fixed_name, (unsigned int)input_crc);
+
     fprintf (fp, "#endif\n\n");
 }
 
@@ -1416,6 +1436,20 @@
     }
 }
 
+/*
+ * add_scalar_vbl (char *name)
+ */
+YYSTYPE add_version (YYSTYPE a1, YYSTYPE a2, YYSTYPE a3)
+{
+    node_t *np;
+
+    np = make_node(NODE_VERSION);
+    np->data[0] = (void *) a1;
+    np->data[1] = (void *) a2;
+    np->data[2] = (void *) a3;
+    return ((YYSTYPE) np);
+}
+
 void generate_python_msg_definitions(YYSTYPE a1, FILE *fp)
 {
     node_t *np = (node_t *)a1;
@@ -1517,6 +1551,26 @@
     fprintf (fp, "}\n");
 }
 
+void generate_version_tuple(YYSTYPE a1, FILE *fp)
+{
+    node_t *this = (node_t *)a1;
+
+    fprintf(fp, "/****** Version tuple *****/\n\n");
+
+    fprintf(fp, "#ifdef vl_api_version_tuple\n\n");
+
+    /* Walk the top-level node-list */
+    while (this) {
+        if (this->type == NODE_VERSION) {
+            fprintf (fp, "vl_api_version_tuple(%s, %d, %d, %d)\n",
+                     fixed_name, IDATA0, IDATA1, IDATA2);
+        }
+        this = this->peer;
+    }
+
+    fprintf(fp, "\n#endif /* vl_api_version_tuple */\n\n");
+}
+
 void generate(YYSTYPE a1)
 {
     if (dump_tree) {
@@ -1535,6 +1589,7 @@
         generate_uniondefs(a1, ofp);
         generate_printfun(a1, ofp);
         generate_endianfun(a1, ofp);
+        generate_version_tuple(a1, ofp);
         
         generate_bottom_boilerplate(ofp);
     }
diff --git a/src/tools/vppapigen/node.h b/src/tools/vppapigen/node.h
index 65bd5d1..58570d8 100644
--- a/src/tools/vppapigen/node.h
+++ b/src/tools/vppapigen/node.h
@@ -44,6 +44,7 @@
     NODE_VECTOR,
     NODE_COMPLEX,
     NODE_NOVERSION,
+    NODE_VERSION,
     NODE_UWORD,
     NODE_N_TYPES,  /* number of node types with VFT's */
 
@@ -77,10 +78,15 @@
 
 /* To shut up gcc-4.2.x warnings */
 #define CDATA0 ((char *)(this->data[0]))
-#define IDATA1 ((int)(uword)(this->data[1]))
+#define CDATA1 ((char *)(this->data[0]))
 #define CDATA2 ((char *)(this->data[2]))
 #define CDATA3 ((char *)(this->data[3]))
 
+#define IDATA0 ((int)(uword)(this->data[0]))
+#define IDATA1 ((int)(uword)(this->data[1]))
+#define IDATA2 ((int)(uword)(this->data[2]))
+#define IDATA3 ((int)(uword)(this->data[3]))
+
 #define NODE_FLAG_MANUAL_PRINT (1<<0)
 #define NODE_FLAG_MANUAL_ENDIAN (1<<1)
 #define NODE_FLAG_TYPEONLY (1<<3)