api: enforce vla is last and fixed string type
[vpp.git] / src / tools / vppapigen / vppapigen_c.py
index b56e072..c1bc11d 100644 (file)
@@ -3,7 +3,8 @@ import datetime
 import os
 import time
 
-datestring = datetime.datetime.utcfromtimestamp(int(os.environ.get('SOURCE_DATE_EPOCH', time.time())))
+datestring = datetime.datetime.utcfromtimestamp(
+    int(os.environ.get('SOURCE_DATE_EPOCH', time.time())))
 input_filename = 'inputfil'
 top_boilerplate = '''\
 /*
@@ -12,6 +13,7 @@ top_boilerplate = '''\
  * Automatically generated: please edit the input file NOT this file!
  */
 
+#include <stdbool.h>
 #if defined(vl_msg_id)||defined(vl_union_id) \\
     || defined(vl_printfun) ||defined(vl_endianfun) \\
     || defined(vl_api_version)||defined(vl_typedefs) \\
@@ -85,8 +87,8 @@ def msg_name_crc_list(s, suffix):
 
 
 def duplicate_wrapper_head(name):
-    s = "#ifndef defined_%s\n" % name
-    s += "#define defined_%s\n" % name
+    s = "#ifndef _vl_api_defined_%s\n" % name
+    s += "#define _vl_api_defined_%s\n" % name
     return s
 
 
@@ -94,7 +96,14 @@ def duplicate_wrapper_tail():
     return '#endif\n\n'
 
 
-def typedefs(objs, filename):
+def api2c(fieldtype):
+    mappingtable = {'string': 'vl_api_string_t', }
+    if fieldtype in mappingtable:
+        return mappingtable[fieldtype]
+    return fieldtype
+
+
+def typedefs(objs, aliases, filename):
     name = filename.replace('.', '_')
     output = '''\
 
@@ -106,14 +115,32 @@ def typedefs(objs, filename):
 #define included_{module}
 '''
     output = output.format(module=name)
+
+    for k, v in aliases.items():
+        output += duplicate_wrapper_head(k)
+        if 'length' in v:
+            output +=  'typedef %s vl_api_%s_t[%s];\n' % (v['type'], k, v['length'])
+        else:
+            output += 'typedef %s vl_api_%s_t;\n' % (v['type'], k)
+        output += duplicate_wrapper_tail()
+
     for o in objs:
         tname = o.__class__.__name__
         output += duplicate_wrapper_head(o.name)
         if tname == 'Enum':
-            output += "typedef enum {\n"
+            if o.enumtype == 'u32':
+                output += "typedef enum {\n"
+            else:
+                output += "typedef enum __attribute__((__packed__)) {\n"
+
             for b in o.block:
                 output += "    %s = %s,\n" % (b[0], b[1])
             output += '} vl_api_%s_t;\n' % o.name
+            if o.enumtype != 'u32':
+                size1 = 'sizeof(vl_api_%s_t)' % o.name
+                size2 = 'sizeof(%s)' % o.enumtype
+                err_str = 'size of API enum %s is wrong' % o.name
+                output += 'STATIC_ASSERT(%s == %s, "%s");\n' % (size1, size2, err_str)
         else:
             if tname == 'Union':
                 output += "typedef VL_API_PACKED(union _vl_api_%s {\n" % o.name
@@ -121,13 +148,20 @@ def typedefs(objs, filename):
                 output += "typedef VL_API_PACKED(struct _vl_api_%s {\n" % o.name
             for b in o.block:
                 if b.type == 'Field':
-                    output += "    %s %s;\n" % (b.fieldtype, b.fieldname)
+                    output += "    %s %s;\n" % (api2c(b.fieldtype), b.fieldname)
                 elif b.type == 'Array':
                     if b.lengthfield:
-                        output += "    %s %s[0];\n" % (b.fieldtype, b.fieldname)
+                        output += "    %s %s[0];\n" % (api2c(b.fieldtype), b.fieldname)
                     else:
-                        output += "    %s %s[%s];\n" % (b.fieldtype, b.fieldname,
-                                                        b.length)
+                        # Fixed length strings decay to nul terminated u8
+                        if b.fieldtype == 'string':
+                            if b.modern_vla:
+                                output += '    {} {};\n'.format(api2c(b.fieldtype), b.fieldname)
+                            else:
+                                output += '    u8 {}[{}];\n'.format(b.fieldname, b.length)
+                        else:
+                            output += "    %s %s[%s];\n" % (api2c(b.fieldtype), b.fieldname,
+                                                            b.length)
                 else:
                     raise ValueError("Error in processing array type %s" % b)
 
@@ -201,6 +235,7 @@ endian_strings = {
     'i16': 'clib_net_to_host_u16',
     'i32': 'clib_net_to_host_u32',
     'i64': 'clib_net_to_host_u64',
+    'f64': 'clib_net_to_host_u64',
 }
 
 
@@ -268,7 +303,7 @@ def version_tuple(s, module):
 #
 # Plugin entry point
 #
-def run(input_filename, s, file_crc):
+def run(input_filename, s):
     basename = os.path.basename(input_filename)
     filename, file_extension = os.path.splitext(basename)
     output = top_boilerplate.format(datestring=datestring,
@@ -276,11 +311,11 @@ def run(input_filename, s, file_crc):
     output += msg_ids(s)
     output += msg_names(s)
     output += msg_name_crc_list(s, filename)
-    output += typedefs(s['types'] + s['Define'], filename + file_extension)
+    output += typedefs(s['types'] + s['Define'], s['Alias'], filename + file_extension)
     output += printfun(s['types'] + s['Define'])
     output += endianfun(s['types'] + s['Define'])
     output += version_tuple(s, basename)
     output += bottom_boilerplate.format(input_filename=basename,
-                                        file_crc=file_crc)
+                                        file_crc=s['file_crc'])
 
     return output