From 21b6e302789c412bdde84439b9325c76e2a5c428 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 1 Jun 2023 19:35:44 -0700 Subject: tools: ynl-gen: generate enum-to-string helpers It's sometimes useful to print the name of an enum value, flag or name of the op. Python can do it, add C helper code gen for getting names of things. Example: static const char * const netdev_xdp_act_strmap[] = { [0] = "basic", [1] = "redirect", [2] = "ndo-xmit", [3] = "xsk-zerocopy", [4] = "hw-offload", [5] = "rx-sg", [6] = "ndo-xmit-sg", }; const char *netdev_xdp_act_str(enum netdev_xdp_act value) { value = ffs(value) - 1; if (value < 0 || value >= (int)MNL_ARRAY_SIZE(netdev_xdp_act_strmap)) return NULL; return netdev_xdp_act_strmap[value]; } Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-c.py | 66 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) (limited to 'tools/net/ynl') diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 8bf4b70216d7..5318edfdb874 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -1168,6 +1168,56 @@ def put_typol(cw, struct): cw.nl() +def put_op_name_fwd(family, cw): + cw.write_func_prot('const char *', f'{family.name}_op_str', ['int op'], suffix=';') + + +def put_op_name(family, cw): + map_name = f'{family.name}_op_strmap' + cw.block_start(line=f"static const char * const {map_name}[] =") + for op_name, op in family.msgs.items(): + cw.p(f'[{op.enum_name}] = "{op_name}",') + cw.block_end(line=';') + cw.nl() + + cw.write_func_prot('const char *', f'{family.name}_op_str', ['int op']) + cw.block_start() + cw.p(f'if (op < 0 || op >= (int)MNL_ARRAY_SIZE({map_name}))') + cw.p('return NULL;') + cw.p(f'return {map_name}[op];') + cw.block_end() + cw.nl() + + +def put_enum_to_str_fwd(family, cw, enum): + args = [f'enum {enum.render_name} value'] + if 'enum-name' in enum and not enum['enum-name']: + args = ['int value'] + cw.write_func_prot('const char *', f'{enum.render_name}_str', args, suffix=';') + + +def put_enum_to_str(family, cw, enum): + map_name = f'{enum.render_name}_strmap' + cw.block_start(line=f"static const char * const {map_name}[] =") + for entry in enum.entries.values(): + cw.p(f'[{entry.value}] = "{entry.name}",') + cw.block_end(line=';') + cw.nl() + + args = [f'enum {enum.render_name} value'] + if 'enum-name' in enum and not enum['enum-name']: + args = ['int value'] + cw.write_func_prot('const char *', f'{enum.render_name}_str', args) + cw.block_start() + if enum.type == 'flags': + cw.p('value = ffs(value) - 1;') + cw.p(f'if (value < 0 || value >= (int)MNL_ARRAY_SIZE({map_name}))') + cw.p('return NULL;') + cw.p(f'return {map_name}[value];') + cw.block_end() + cw.nl() + + def put_req_nested(ri, struct): func_args = ['struct nlmsghdr *nlh', 'unsigned int attr_type', @@ -2210,6 +2260,14 @@ def main(): if args.mode == "user": has_ntf = False if args.header: + cw.p('/* Enums */') + put_op_name_fwd(parsed, cw) + + for name, const in parsed.consts.items(): + if isinstance(const, EnumSet): + put_enum_to_str_fwd(parsed, cw, const) + cw.nl() + cw.p('/* Common nested types */') for attr_set, struct in sorted(parsed.pure_nested_structs.items()): ri = RenderInfo(cw, parsed, args.mode, "", "", "", attr_set) @@ -2262,6 +2320,14 @@ def main(): print_ntf_parse_prototype(parsed, cw) cw.nl() else: + cw.p('/* Enums */') + put_op_name(parsed, cw) + + for name, const in parsed.consts.items(): + if isinstance(const, EnumSet): + put_enum_to_str(parsed, cw, const) + cw.nl() + cw.p('/* Policies */') for name, _ in parsed.attr_sets.items(): struct = Struct(parsed, name) -- cgit v1.2.3