diff options
Diffstat (limited to 'src/tools/vppapigen/vppapigen_c.py')
-rw-r--r-- | src/tools/vppapigen/vppapigen_c.py | 286 |
1 files changed, 286 insertions, 0 deletions
diff --git a/src/tools/vppapigen/vppapigen_c.py b/src/tools/vppapigen/vppapigen_c.py new file mode 100644 index 00000000000..b56e0722122 --- /dev/null +++ b/src/tools/vppapigen/vppapigen_c.py @@ -0,0 +1,286 @@ +# C generation +import datetime +import os +import time + +datestring = datetime.datetime.utcfromtimestamp(int(os.environ.get('SOURCE_DATE_EPOCH', time.time()))) +input_filename = 'inputfil' +top_boilerplate = '''\ +/* + * VLIB API definitions {datestring} + * Input file: {input_filename} + * Automatically generated: please edit the input file NOT this file! + */ + +#if defined(vl_msg_id)||defined(vl_union_id) \\ + || defined(vl_printfun) ||defined(vl_endianfun) \\ + || defined(vl_api_version)||defined(vl_typedefs) \\ + || defined(vl_msg_name)||defined(vl_msg_name_crc_list) \\ + || defined(vl_api_version_tuple) +/* ok, something was selected */ +#else +#warning no content included from {input_filename} +#endif + +#define VL_API_PACKED(x) x __attribute__ ((packed)) +''' + +bottom_boilerplate = '''\ +/****** API CRC (whole file) *****/ + +#ifdef vl_api_version +vl_api_version({input_filename}, {file_crc:#08x}) + +#endif +''' + + +def msg_ids(s): + output = '''\ + +/****** Message ID / handler enum ******/ + +#ifdef vl_msg_id +''' + + for t in s['Define']: + output += "vl_msg_id(VL_API_%s, vl_api_%s_t_handler)\n" % \ + (t.name.upper(), t.name) + output += "#endif" + + return output + + +def msg_names(s): + output = '''\ + +/****** Message names ******/ + +#ifdef vl_msg_name +''' + + for t in s['Define']: + dont_trace = 0 if t.dont_trace else 1 + output += "vl_msg_name(vl_api_%s_t, %d)\n" % (t.name, dont_trace) + output += "#endif" + + return output + + +def msg_name_crc_list(s, suffix): + output = '''\ + +/****** Message name, crc list ******/ + +#ifdef vl_msg_name_crc_list +''' + output += "#define foreach_vl_msg_name_crc_%s " % suffix + + for t in s['Define']: + output += "\\\n_(VL_API_%s, %s, %08x) " % \ + (t.name.upper(), t.name, t.crc) + output += "\n#endif" + + return output + + +def duplicate_wrapper_head(name): + s = "#ifndef defined_%s\n" % name + s += "#define defined_%s\n" % name + return s + + +def duplicate_wrapper_tail(): + return '#endif\n\n' + + +def typedefs(objs, filename): + name = filename.replace('.', '_') + output = '''\ + + +/****** Typedefs ******/ + +#ifdef vl_typedefs +#ifndef included_{module} +#define included_{module} +''' + output = output.format(module=name) + for o in objs: + tname = o.__class__.__name__ + output += duplicate_wrapper_head(o.name) + if tname == 'Enum': + output += "typedef enum {\n" + for b in o.block: + output += " %s = %s,\n" % (b[0], b[1]) + output += '} vl_api_%s_t;\n' % o.name + else: + if tname == 'Union': + output += "typedef VL_API_PACKED(union _vl_api_%s {\n" % o.name + else: + 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) + elif b.type == 'Array': + if b.lengthfield: + output += " %s %s[0];\n" % (b.fieldtype, b.fieldname) + else: + output += " %s %s[%s];\n" % (b.fieldtype, b.fieldname, + b.length) + else: + raise ValueError("Error in processing array type %s" % b) + + output += '}) vl_api_%s_t;\n' % o.name + output += duplicate_wrapper_tail() + + output += "\n#endif" + output += "\n#endif\n\n" + + return output + + +format_strings = {'u8': '%u', + 'i8': '%d', + 'u16': '%u', + 'i16': '%d', + 'u32': '%u', + 'i32': '%ld', + 'u64': '%llu', + 'i64': '%llu', + 'f64': '%.2f', } + + +def printfun(objs): + output = '''\ +/****** Print functions *****/ +#ifdef vl_printfun + +#ifdef LP64 +#define _uword_fmt \"%lld\" +#define _uword_cast (long long) +#else +#define _uword_fmt \"%ld\" +#define _uword_cast long +#endif + +''' + for t in objs: + if t.__class__.__name__ == 'Enum': + continue + if t.manual_print: + output += "/***** manual: vl_api_%s_t_print *****/\n\n" % t.name + continue + output += duplicate_wrapper_head(t.name + '_t_print') + output += "static inline void *vl_api_%s_t_print (vl_api_%s_t *a," % \ + (t.name, t.name) + output += "void *handle)\n{\n" + output += " vl_print(handle, \"vl_api_%s_t:\\n\");\n" % t.name + + for o in t.block: + if o.type != 'Field': + continue + if o.fieldtype in format_strings: + output += " vl_print(handle, \"%s: %s\\n\", a->%s);\n" % \ + (o.fieldname, format_strings[o.fieldtype], + o.fieldname) + + output += ' return handle;\n' + output += '}\n\n' + output += duplicate_wrapper_tail() + + output += "\n#endif /* vl_printfun */\n" + + return output + + +endian_strings = { + 'u16': 'clib_net_to_host_u16', + 'u32': 'clib_net_to_host_u32', + 'u64': 'clib_net_to_host_u64', + 'i16': 'clib_net_to_host_u16', + 'i32': 'clib_net_to_host_u32', + 'i64': 'clib_net_to_host_u64', +} + + +def endianfun(objs): + output = '''\ + +/****** Endian swap functions *****/\n\ +#ifdef vl_endianfun + +#undef clib_net_to_host_uword +#ifdef LP64 +#define clib_net_to_host_uword clib_net_to_host_u64 +#else +#define clib_net_to_host_uword clib_net_to_host_u32 +#endif + +''' + + for t in objs: + if t.__class__.__name__ == 'Enum': + continue + if t.manual_endian: + output += "/***** manual: vl_api_%s_t_endian *****/\n\n" % t.name + continue + output += duplicate_wrapper_head(t.name + '_t_endian') + output += "static inline void vl_api_%s_t_endian (vl_api_%s_t *a)" % \ + (t.name, t.name) + output += "\n{\n" + + for o in t.block: + if o.type != 'Field': + continue + if o.fieldtype in endian_strings: + output += " a->%s = %s(a->%s);\n" % \ + (o.fieldname, endian_strings[o.fieldtype], o.fieldname) + else: + output += " /* a->%s = a->%s (no-op) */\n" % \ + (o.fieldname, o.fieldname) + + output += '}\n\n' + output += duplicate_wrapper_tail() + output += "\n#endif /* vl_endianfun */\n\n" + + return output + + +def version_tuple(s, module): + output = '''\ +/****** Version tuple *****/ + +#ifdef vl_api_version_tuple + +''' + if 'version' in s['Option']: + v = s['Option']['version'] + (major, minor, patch) = v.split('.') + output += "vl_api_version_tuple(%s, %s, %s, %s)\n" % \ + (module, major, minor, patch) + + output += "\n#endif /* vl_api_version_tuple */\n\n" + + return output + + +# +# Plugin entry point +# +def run(input_filename, s, file_crc): + basename = os.path.basename(input_filename) + filename, file_extension = os.path.splitext(basename) + output = top_boilerplate.format(datestring=datestring, + input_filename=basename) + 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 += 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) + + return output |