137666691SBruce Richardson#!/usr/bin/env python3 237666691SBruce Richardson# SPDX-License-Identifier: BSD-3-Clause 337666691SBruce Richardson# Copyright(c) 2023 Intel Corporation 437666691SBruce Richardson# 537666691SBruce Richardson""" 637666691SBruce RichardsonScript to automatically generate boilerplate for using DPDK cmdline library. 737666691SBruce Richardson""" 837666691SBruce Richardson 937666691SBruce Richardsonimport argparse 106c4a69cfSRobin Jarryimport shlex 1137666691SBruce Richardsonimport sys 1237666691SBruce Richardson 1337666691SBruce RichardsonPARSE_FN_PARAMS = "void *parsed_result, struct cmdline *cl, void *data" 1437666691SBruce RichardsonPARSE_FN_BODY = """ 1537666691SBruce Richardson /* TODO: command action */ 1637666691SBruce Richardson RTE_SET_USED(parsed_result); 1737666691SBruce Richardson RTE_SET_USED(cl); 1837666691SBruce Richardson RTE_SET_USED(data); 1937666691SBruce Richardson""" 2037666691SBruce RichardsonNUMERIC_TYPES = [ 2137666691SBruce Richardson "UINT8", 2237666691SBruce Richardson "UINT16", 2337666691SBruce Richardson "UINT32", 2437666691SBruce Richardson "UINT64", 2537666691SBruce Richardson "INT8", 2637666691SBruce Richardson "INT16", 2737666691SBruce Richardson "INT32", 2837666691SBruce Richardson "INT64", 2937666691SBruce Richardson] 3037666691SBruce Richardson 3137666691SBruce Richardson 3237666691SBruce Richardsondef process_command(lineno, tokens, comment): 3337666691SBruce Richardson """Generate the structures and definitions for a single command.""" 3437666691SBruce Richardson out = [] 3537666691SBruce Richardson cfile_out = [] 3637666691SBruce Richardson 3737666691SBruce Richardson if tokens[0].startswith("<"): 3837666691SBruce Richardson raise ValueError(f"Error line {lineno + 1}: command must start with a literal string") 3937666691SBruce Richardson 4037666691SBruce Richardson name_tokens = [] 4137666691SBruce Richardson for t in tokens: 4237666691SBruce Richardson if t.startswith("<"): 43*620b2696SBruce Richardson # stop processing the name building at a variable token, 44*620b2696SBruce Richardson # UNLESS the token name starts with "__" 45*620b2696SBruce Richardson t_type, t_name = t[1:].split(">") 46*620b2696SBruce Richardson if not t_name.startswith("__"): 4737666691SBruce Richardson break 48*620b2696SBruce Richardson t = t_name[2:] # strip off the leading '__' 4937666691SBruce Richardson name_tokens.append(t) 5037666691SBruce Richardson name = "_".join(name_tokens) 5137666691SBruce Richardson 5237666691SBruce Richardson result_struct = [] 5337666691SBruce Richardson initializers = [] 5437666691SBruce Richardson token_list = [] 5537666691SBruce Richardson for t in tokens: 5637666691SBruce Richardson if t.startswith("<"): 5737666691SBruce Richardson t_type, t_name = t[1:].split(">") 5837666691SBruce Richardson t_val = "NULL" 59*620b2696SBruce Richardson if t_name.startswith("__"): 60*620b2696SBruce Richardson t_name = t_name[2:] 6137666691SBruce Richardson else: 6237666691SBruce Richardson t_type = "STRING" 6337666691SBruce Richardson t_name = t 6437666691SBruce Richardson t_val = f'"{t}"' 6537666691SBruce Richardson 6637666691SBruce Richardson if t_type == "STRING": 6737666691SBruce Richardson result_struct.append(f"\tcmdline_fixed_string_t {t_name};") 6837666691SBruce Richardson initializers.append( 6937666691SBruce Richardson f"static cmdline_parse_token_string_t cmd_{name}_{t_name}_tok =\n" 7037666691SBruce Richardson f"\tTOKEN_STRING_INITIALIZER(struct cmd_{name}_result, {t_name}, {t_val});" 7137666691SBruce Richardson ) 7237666691SBruce Richardson elif t_type in NUMERIC_TYPES: 7337666691SBruce Richardson result_struct.append(f"\t{t_type.lower()}_t {t_name};") 7437666691SBruce Richardson initializers.append( 7537666691SBruce Richardson f"static cmdline_parse_token_num_t cmd_{name}_{t_name}_tok =\n" 7637666691SBruce Richardson f"\tTOKEN_NUM_INITIALIZER(struct cmd_{name}_result, {t_name}, RTE_{t_type});" 7737666691SBruce Richardson ) 7837666691SBruce Richardson elif t_type in ["IP", "IP_ADDR", "IPADDR"]: 7937666691SBruce Richardson result_struct.append(f"\tcmdline_ipaddr_t {t_name};") 8037666691SBruce Richardson initializers.append( 81a78b8f11SBruce Richardson f"static cmdline_parse_token_ipaddr_t cmd_{name}_{t_name}_tok =\n" 827cd7850aSBruce Richardson f"\tTOKEN_IPADDR_INITIALIZER(struct cmd_{name}_result, {t_name});" 8337666691SBruce Richardson ) 84fb8a2784SBruce Richardson elif t_type in ["IPV4", "IPv4", "IPV4_ADDR"]: 85fb8a2784SBruce Richardson result_struct.append(f"\tcmdline_ipaddr_t {t_name};") 86fb8a2784SBruce Richardson initializers.append( 87fb8a2784SBruce Richardson f"static cmdline_parse_token_ipaddr_t cmd_{name}_{t_name}_tok =\n" 88fb8a2784SBruce Richardson f"\tTOKEN_IPV4_INITIALIZER(struct cmd_{name}_result, {t_name});" 89fb8a2784SBruce Richardson ) 90fb8a2784SBruce Richardson elif t_type in ["IPV6", "IPv6", "IPV6_ADDR"]: 91fb8a2784SBruce Richardson result_struct.append(f"\tcmdline_ipaddr_t {t_name};") 92fb8a2784SBruce Richardson initializers.append( 93fb8a2784SBruce Richardson f"static cmdline_parse_token_ipaddr_t cmd_{name}_{t_name}_tok =\n" 94fb8a2784SBruce Richardson f"\tTOKEN_IPV6_INITIALIZER(struct cmd_{name}_result, {t_name});" 95fb8a2784SBruce Richardson ) 961cd1716bSBruce Richardson elif t_type.startswith("(") and t_type.endswith(")"): 971cd1716bSBruce Richardson result_struct.append(f"\tcmdline_fixed_string_t {t_name};") 981cd1716bSBruce Richardson t_val = f'"{t_type[1:-1].replace(",","#")}"' 991cd1716bSBruce Richardson initializers.append( 1001cd1716bSBruce Richardson f"static cmdline_parse_token_string_t cmd_{name}_{t_name}_tok =\n" 1011cd1716bSBruce Richardson f"\tTOKEN_STRING_INITIALIZER(struct cmd_{name}_result, {t_name}, {t_val});" 1021cd1716bSBruce Richardson ) 10337666691SBruce Richardson else: 10437666691SBruce Richardson raise TypeError(f"Error line {lineno + 1}: unknown token type '{t_type}'") 10537666691SBruce Richardson token_list.append(f"cmd_{name}_{t_name}_tok") 10637666691SBruce Richardson 10737666691SBruce Richardson out.append(f'/* Auto-generated handling for command "{" ".join(tokens)}" */') 10837666691SBruce Richardson # output function prototype 10937666691SBruce Richardson func_sig = f"void\ncmd_{name}_parsed({PARSE_FN_PARAMS})" 11037666691SBruce Richardson out.append(f"extern {func_sig};\n") 11137666691SBruce Richardson # output result data structure 11237666691SBruce Richardson out.append(f"struct cmd_{name}_result {{\n" + "\n".join(result_struct) + "\n};\n") 11337666691SBruce Richardson # output the initializer tokens 11437666691SBruce Richardson out.append("\n".join(initializers) + "\n") 11537666691SBruce Richardson # output the instance structure 11637666691SBruce Richardson inst_elems = "\n".join([f"\t\t(void *)&{t}," for t in token_list]) 11737666691SBruce Richardson out.append( 11837666691SBruce Richardson f"""\ 11937666691SBruce Richardsonstatic cmdline_parse_inst_t cmd_{name} = {{ 12037666691SBruce Richardson\t.f = cmd_{name}_parsed, 12137666691SBruce Richardson\t.data = NULL, 12237666691SBruce Richardson\t.help_str = "{comment}", 12337666691SBruce Richardson\t.tokens = {{ 12437666691SBruce Richardson{inst_elems} 12537666691SBruce Richardson\t\tNULL, 12637666691SBruce Richardson\t}} 12737666691SBruce Richardson}}; 12837666691SBruce Richardson""" 12937666691SBruce Richardson ) 13037666691SBruce Richardson # output function template if C file being written 13137666691SBruce Richardson cfile_out.append(f"{func_sig}\n{{{PARSE_FN_BODY}}}\n") 13237666691SBruce Richardson 13337666691SBruce Richardson # return the instance structure name 13437666691SBruce Richardson return (f"cmd_{name}", out, cfile_out) 13537666691SBruce Richardson 13637666691SBruce Richardson 13737666691SBruce Richardsondef process_commands(infile, hfile, cfile, ctxname): 13837666691SBruce Richardson """Generate boilerplate output for a list of commands from infile.""" 13937666691SBruce Richardson instances = [] 14037666691SBruce Richardson 14137666691SBruce Richardson hfile.write( 14237666691SBruce Richardson f"""\ 14337666691SBruce Richardson/* File autogenerated by {sys.argv[0]} */ 14437666691SBruce Richardson#ifndef GENERATED_COMMANDS_H 14537666691SBruce Richardson#define GENERATED_COMMANDS_H 14637666691SBruce Richardson#include <rte_common.h> 14737666691SBruce Richardson#include <cmdline.h> 14837666691SBruce Richardson#include <cmdline_parse_string.h> 14937666691SBruce Richardson#include <cmdline_parse_num.h> 15037666691SBruce Richardson#include <cmdline_parse_ipaddr.h> 15137666691SBruce Richardson 15237666691SBruce Richardson""" 15337666691SBruce Richardson ) 15437666691SBruce Richardson 15537666691SBruce Richardson for lineno, line in enumerate(infile.readlines()): 1566c4a69cfSRobin Jarry tokens = shlex.split(line, comments=True) 1576c4a69cfSRobin Jarry if not tokens: 15837666691SBruce Richardson continue 1596c4a69cfSRobin Jarry if "#" in line: 1606c4a69cfSRobin Jarry comment = line.split("#", 1)[-1].strip() 1616c4a69cfSRobin Jarry else: 1626c4a69cfSRobin Jarry comment = "" 1636c4a69cfSRobin Jarry cmd_inst, h_out, c_out = process_command(lineno, tokens, comment) 16437666691SBruce Richardson hfile.write("\n".join(h_out)) 16537666691SBruce Richardson if cfile: 16637666691SBruce Richardson cfile.write("\n".join(c_out)) 16737666691SBruce Richardson instances.append(cmd_inst) 16837666691SBruce Richardson 16937666691SBruce Richardson inst_join_str = ",\n\t&" 17037666691SBruce Richardson hfile.write( 17137666691SBruce Richardson f""" 17237666691SBruce Richardsonstatic __rte_used cmdline_parse_ctx_t {ctxname}[] = {{ 17337666691SBruce Richardson\t&{inst_join_str.join(instances)}, 17437666691SBruce Richardson\tNULL 17537666691SBruce Richardson}}; 17637666691SBruce Richardson 17737666691SBruce Richardson#endif /* GENERATED_COMMANDS_H */ 17837666691SBruce Richardson""" 17937666691SBruce Richardson ) 18037666691SBruce Richardson 18137666691SBruce Richardson 18237666691SBruce Richardsondef main(): 18337666691SBruce Richardson """Application main entry point.""" 18437666691SBruce Richardson ap = argparse.ArgumentParser(description=__doc__) 18537666691SBruce Richardson ap.add_argument( 18637666691SBruce Richardson "--stubs", 18737666691SBruce Richardson action="store_true", 18837666691SBruce Richardson help="Produce C file with empty function stubs for each command", 18937666691SBruce Richardson ) 19037666691SBruce Richardson ap.add_argument( 19137666691SBruce Richardson "--output-file", 19237666691SBruce Richardson "-o", 19337666691SBruce Richardson default="-", 19437666691SBruce Richardson help="Output header filename [default to stdout]", 19537666691SBruce Richardson ) 19637666691SBruce Richardson ap.add_argument( 19737666691SBruce Richardson "--context-name", 19837666691SBruce Richardson default="ctx", 19937666691SBruce Richardson help="Name given to the cmdline context variable in the output header [default=ctx]", 20037666691SBruce Richardson ) 20137666691SBruce Richardson ap.add_argument("infile", type=argparse.FileType("r"), help="File with list of commands") 20237666691SBruce Richardson args = ap.parse_args() 20337666691SBruce Richardson 20437666691SBruce Richardson if not args.stubs: 20537666691SBruce Richardson if args.output_file == "-": 20637666691SBruce Richardson process_commands(args.infile, sys.stdout, None, args.context_name) 20737666691SBruce Richardson else: 20837666691SBruce Richardson with open(args.output_file, "w") as hfile: 20937666691SBruce Richardson process_commands(args.infile, hfile, None, args.context_name) 21037666691SBruce Richardson else: 21137666691SBruce Richardson if not args.output_file.endswith(".h"): 21237666691SBruce Richardson ap.error( 21337666691SBruce Richardson "-o/--output-file: specify an output filename ending with .h when creating stubs" 21437666691SBruce Richardson ) 21537666691SBruce Richardson 21637666691SBruce Richardson cfilename = args.output_file[:-2] + ".c" 21737666691SBruce Richardson with open(args.output_file, "w") as hfile: 21837666691SBruce Richardson with open(cfilename, "w") as cfile: 21937666691SBruce Richardson cfile.write(f'#include "{args.output_file}"\n\n') 22037666691SBruce Richardson process_commands(args.infile, hfile, cfile, args.context_name) 22137666691SBruce Richardson 22237666691SBruce Richardson 22337666691SBruce Richardsonif __name__ == "__main__": 22437666691SBruce Richardson main() 225