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("<"): 4337666691SBruce Richardson break 4437666691SBruce Richardson name_tokens.append(t) 4537666691SBruce Richardson name = "_".join(name_tokens) 4637666691SBruce Richardson 4737666691SBruce Richardson result_struct = [] 4837666691SBruce Richardson initializers = [] 4937666691SBruce Richardson token_list = [] 5037666691SBruce Richardson for t in tokens: 5137666691SBruce Richardson if t.startswith("<"): 5237666691SBruce Richardson t_type, t_name = t[1:].split(">") 5337666691SBruce Richardson t_val = "NULL" 5437666691SBruce Richardson else: 5537666691SBruce Richardson t_type = "STRING" 5637666691SBruce Richardson t_name = t 5737666691SBruce Richardson t_val = f'"{t}"' 5837666691SBruce Richardson 5937666691SBruce Richardson if t_type == "STRING": 6037666691SBruce Richardson result_struct.append(f"\tcmdline_fixed_string_t {t_name};") 6137666691SBruce Richardson initializers.append( 6237666691SBruce Richardson f"static cmdline_parse_token_string_t cmd_{name}_{t_name}_tok =\n" 6337666691SBruce Richardson f"\tTOKEN_STRING_INITIALIZER(struct cmd_{name}_result, {t_name}, {t_val});" 6437666691SBruce Richardson ) 6537666691SBruce Richardson elif t_type in NUMERIC_TYPES: 6637666691SBruce Richardson result_struct.append(f"\t{t_type.lower()}_t {t_name};") 6737666691SBruce Richardson initializers.append( 6837666691SBruce Richardson f"static cmdline_parse_token_num_t cmd_{name}_{t_name}_tok =\n" 6937666691SBruce Richardson f"\tTOKEN_NUM_INITIALIZER(struct cmd_{name}_result, {t_name}, RTE_{t_type});" 7037666691SBruce Richardson ) 7137666691SBruce Richardson elif t_type in ["IP", "IP_ADDR", "IPADDR"]: 7237666691SBruce Richardson result_struct.append(f"\tcmdline_ipaddr_t {t_name};") 7337666691SBruce Richardson initializers.append( 74*a78b8f11SBruce Richardson f"static cmdline_parse_token_ipaddr_t cmd_{name}_{t_name}_tok =\n" 7537666691SBruce Richardson f"\tTOKEN_IPV4_INITIALIZER(struct cmd_{name}_result, {t_name});" 7637666691SBruce Richardson ) 771cd1716bSBruce Richardson elif t_type.startswith("(") and t_type.endswith(")"): 781cd1716bSBruce Richardson result_struct.append(f"\tcmdline_fixed_string_t {t_name};") 791cd1716bSBruce Richardson t_val = f'"{t_type[1:-1].replace(",","#")}"' 801cd1716bSBruce Richardson initializers.append( 811cd1716bSBruce Richardson f"static cmdline_parse_token_string_t cmd_{name}_{t_name}_tok =\n" 821cd1716bSBruce Richardson f"\tTOKEN_STRING_INITIALIZER(struct cmd_{name}_result, {t_name}, {t_val});" 831cd1716bSBruce Richardson ) 8437666691SBruce Richardson else: 8537666691SBruce Richardson raise TypeError(f"Error line {lineno + 1}: unknown token type '{t_type}'") 8637666691SBruce Richardson token_list.append(f"cmd_{name}_{t_name}_tok") 8737666691SBruce Richardson 8837666691SBruce Richardson out.append(f'/* Auto-generated handling for command "{" ".join(tokens)}" */') 8937666691SBruce Richardson # output function prototype 9037666691SBruce Richardson func_sig = f"void\ncmd_{name}_parsed({PARSE_FN_PARAMS})" 9137666691SBruce Richardson out.append(f"extern {func_sig};\n") 9237666691SBruce Richardson # output result data structure 9337666691SBruce Richardson out.append(f"struct cmd_{name}_result {{\n" + "\n".join(result_struct) + "\n};\n") 9437666691SBruce Richardson # output the initializer tokens 9537666691SBruce Richardson out.append("\n".join(initializers) + "\n") 9637666691SBruce Richardson # output the instance structure 9737666691SBruce Richardson inst_elems = "\n".join([f"\t\t(void *)&{t}," for t in token_list]) 9837666691SBruce Richardson out.append( 9937666691SBruce Richardson f"""\ 10037666691SBruce Richardsonstatic cmdline_parse_inst_t cmd_{name} = {{ 10137666691SBruce Richardson\t.f = cmd_{name}_parsed, 10237666691SBruce Richardson\t.data = NULL, 10337666691SBruce Richardson\t.help_str = "{comment}", 10437666691SBruce Richardson\t.tokens = {{ 10537666691SBruce Richardson{inst_elems} 10637666691SBruce Richardson\t\tNULL, 10737666691SBruce Richardson\t}} 10837666691SBruce Richardson}}; 10937666691SBruce Richardson""" 11037666691SBruce Richardson ) 11137666691SBruce Richardson # output function template if C file being written 11237666691SBruce Richardson cfile_out.append(f"{func_sig}\n{{{PARSE_FN_BODY}}}\n") 11337666691SBruce Richardson 11437666691SBruce Richardson # return the instance structure name 11537666691SBruce Richardson return (f"cmd_{name}", out, cfile_out) 11637666691SBruce Richardson 11737666691SBruce Richardson 11837666691SBruce Richardsondef process_commands(infile, hfile, cfile, ctxname): 11937666691SBruce Richardson """Generate boilerplate output for a list of commands from infile.""" 12037666691SBruce Richardson instances = [] 12137666691SBruce Richardson 12237666691SBruce Richardson hfile.write( 12337666691SBruce Richardson f"""\ 12437666691SBruce Richardson/* File autogenerated by {sys.argv[0]} */ 12537666691SBruce Richardson#ifndef GENERATED_COMMANDS_H 12637666691SBruce Richardson#define GENERATED_COMMANDS_H 12737666691SBruce Richardson#include <rte_common.h> 12837666691SBruce Richardson#include <cmdline.h> 12937666691SBruce Richardson#include <cmdline_parse_string.h> 13037666691SBruce Richardson#include <cmdline_parse_num.h> 13137666691SBruce Richardson#include <cmdline_parse_ipaddr.h> 13237666691SBruce Richardson 13337666691SBruce Richardson""" 13437666691SBruce Richardson ) 13537666691SBruce Richardson 13637666691SBruce Richardson for lineno, line in enumerate(infile.readlines()): 1376c4a69cfSRobin Jarry tokens = shlex.split(line, comments=True) 1386c4a69cfSRobin Jarry if not tokens: 13937666691SBruce Richardson continue 1406c4a69cfSRobin Jarry if "#" in line: 1416c4a69cfSRobin Jarry comment = line.split("#", 1)[-1].strip() 1426c4a69cfSRobin Jarry else: 1436c4a69cfSRobin Jarry comment = "" 1446c4a69cfSRobin Jarry cmd_inst, h_out, c_out = process_command(lineno, tokens, comment) 14537666691SBruce Richardson hfile.write("\n".join(h_out)) 14637666691SBruce Richardson if cfile: 14737666691SBruce Richardson cfile.write("\n".join(c_out)) 14837666691SBruce Richardson instances.append(cmd_inst) 14937666691SBruce Richardson 15037666691SBruce Richardson inst_join_str = ",\n\t&" 15137666691SBruce Richardson hfile.write( 15237666691SBruce Richardson f""" 15337666691SBruce Richardsonstatic __rte_used cmdline_parse_ctx_t {ctxname}[] = {{ 15437666691SBruce Richardson\t&{inst_join_str.join(instances)}, 15537666691SBruce Richardson\tNULL 15637666691SBruce Richardson}}; 15737666691SBruce Richardson 15837666691SBruce Richardson#endif /* GENERATED_COMMANDS_H */ 15937666691SBruce Richardson""" 16037666691SBruce Richardson ) 16137666691SBruce Richardson 16237666691SBruce Richardson 16337666691SBruce Richardsondef main(): 16437666691SBruce Richardson """Application main entry point.""" 16537666691SBruce Richardson ap = argparse.ArgumentParser(description=__doc__) 16637666691SBruce Richardson ap.add_argument( 16737666691SBruce Richardson "--stubs", 16837666691SBruce Richardson action="store_true", 16937666691SBruce Richardson help="Produce C file with empty function stubs for each command", 17037666691SBruce Richardson ) 17137666691SBruce Richardson ap.add_argument( 17237666691SBruce Richardson "--output-file", 17337666691SBruce Richardson "-o", 17437666691SBruce Richardson default="-", 17537666691SBruce Richardson help="Output header filename [default to stdout]", 17637666691SBruce Richardson ) 17737666691SBruce Richardson ap.add_argument( 17837666691SBruce Richardson "--context-name", 17937666691SBruce Richardson default="ctx", 18037666691SBruce Richardson help="Name given to the cmdline context variable in the output header [default=ctx]", 18137666691SBruce Richardson ) 18237666691SBruce Richardson ap.add_argument("infile", type=argparse.FileType("r"), help="File with list of commands") 18337666691SBruce Richardson args = ap.parse_args() 18437666691SBruce Richardson 18537666691SBruce Richardson if not args.stubs: 18637666691SBruce Richardson if args.output_file == "-": 18737666691SBruce Richardson process_commands(args.infile, sys.stdout, None, args.context_name) 18837666691SBruce Richardson else: 18937666691SBruce Richardson with open(args.output_file, "w") as hfile: 19037666691SBruce Richardson process_commands(args.infile, hfile, None, args.context_name) 19137666691SBruce Richardson else: 19237666691SBruce Richardson if not args.output_file.endswith(".h"): 19337666691SBruce Richardson ap.error( 19437666691SBruce Richardson "-o/--output-file: specify an output filename ending with .h when creating stubs" 19537666691SBruce Richardson ) 19637666691SBruce Richardson 19737666691SBruce Richardson cfilename = args.output_file[:-2] + ".c" 19837666691SBruce Richardson with open(args.output_file, "w") as hfile: 19937666691SBruce Richardson with open(cfilename, "w") as cfile: 20037666691SBruce Richardson cfile.write(f'#include "{args.output_file}"\n\n') 20137666691SBruce Richardson process_commands(args.infile, hfile, cfile, args.context_name) 20237666691SBruce Richardson 20337666691SBruce Richardson 20437666691SBruce Richardsonif __name__ == "__main__": 20537666691SBruce Richardson main() 206