xref: /dpdk/buildtools/dpdk-cmdline-gen.py (revision 1cd1716b0959652a22f4d3dfe1cc15428ba6bfce)
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
1037666691SBruce Richardsonimport sys
1137666691SBruce Richardson
1237666691SBruce RichardsonPARSE_FN_PARAMS = "void *parsed_result, struct cmdline *cl, void *data"
1337666691SBruce RichardsonPARSE_FN_BODY = """
1437666691SBruce Richardson    /* TODO: command action */
1537666691SBruce Richardson    RTE_SET_USED(parsed_result);
1637666691SBruce Richardson    RTE_SET_USED(cl);
1737666691SBruce Richardson    RTE_SET_USED(data);
1837666691SBruce Richardson"""
1937666691SBruce RichardsonNUMERIC_TYPES = [
2037666691SBruce Richardson    "UINT8",
2137666691SBruce Richardson    "UINT16",
2237666691SBruce Richardson    "UINT32",
2337666691SBruce Richardson    "UINT64",
2437666691SBruce Richardson    "INT8",
2537666691SBruce Richardson    "INT16",
2637666691SBruce Richardson    "INT32",
2737666691SBruce Richardson    "INT64",
2837666691SBruce Richardson]
2937666691SBruce Richardson
3037666691SBruce Richardson
3137666691SBruce Richardsondef process_command(lineno, tokens, comment):
3237666691SBruce Richardson    """Generate the structures and definitions for a single command."""
3337666691SBruce Richardson    out = []
3437666691SBruce Richardson    cfile_out = []
3537666691SBruce Richardson
3637666691SBruce Richardson    if tokens[0].startswith("<"):
3737666691SBruce Richardson        raise ValueError(f"Error line {lineno + 1}: command must start with a literal string")
3837666691SBruce Richardson
3937666691SBruce Richardson    name_tokens = []
4037666691SBruce Richardson    for t in tokens:
4137666691SBruce Richardson        if t.startswith("<"):
4237666691SBruce Richardson            break
4337666691SBruce Richardson        name_tokens.append(t)
4437666691SBruce Richardson    name = "_".join(name_tokens)
4537666691SBruce Richardson
4637666691SBruce Richardson    result_struct = []
4737666691SBruce Richardson    initializers = []
4837666691SBruce Richardson    token_list = []
4937666691SBruce Richardson    for t in tokens:
5037666691SBruce Richardson        if t.startswith("<"):
5137666691SBruce Richardson            t_type, t_name = t[1:].split(">")
5237666691SBruce Richardson            t_val = "NULL"
5337666691SBruce Richardson        else:
5437666691SBruce Richardson            t_type = "STRING"
5537666691SBruce Richardson            t_name = t
5637666691SBruce Richardson            t_val = f'"{t}"'
5737666691SBruce Richardson
5837666691SBruce Richardson        if t_type == "STRING":
5937666691SBruce Richardson            result_struct.append(f"\tcmdline_fixed_string_t {t_name};")
6037666691SBruce Richardson            initializers.append(
6137666691SBruce Richardson                f"static cmdline_parse_token_string_t cmd_{name}_{t_name}_tok =\n"
6237666691SBruce Richardson                f"\tTOKEN_STRING_INITIALIZER(struct cmd_{name}_result, {t_name}, {t_val});"
6337666691SBruce Richardson            )
6437666691SBruce Richardson        elif t_type in NUMERIC_TYPES:
6537666691SBruce Richardson            result_struct.append(f"\t{t_type.lower()}_t {t_name};")
6637666691SBruce Richardson            initializers.append(
6737666691SBruce Richardson                f"static cmdline_parse_token_num_t cmd_{name}_{t_name}_tok =\n"
6837666691SBruce Richardson                f"\tTOKEN_NUM_INITIALIZER(struct cmd_{name}_result, {t_name}, RTE_{t_type});"
6937666691SBruce Richardson            )
7037666691SBruce Richardson        elif t_type in ["IP", "IP_ADDR", "IPADDR"]:
7137666691SBruce Richardson            result_struct.append(f"\tcmdline_ipaddr_t {t_name};")
7237666691SBruce Richardson            initializers.append(
7337666691SBruce Richardson                f"cmdline_parse_token_ipaddr_t cmd_{name}_{t_name}_tok =\n"
7437666691SBruce Richardson                f"\tTOKEN_IPV4_INITIALIZER(struct cmd_{name}_result, {t_name});"
7537666691SBruce Richardson            )
76*1cd1716bSBruce Richardson        elif t_type.startswith("(") and t_type.endswith(")"):
77*1cd1716bSBruce Richardson            result_struct.append(f"\tcmdline_fixed_string_t {t_name};")
78*1cd1716bSBruce Richardson            t_val = f'"{t_type[1:-1].replace(",","#")}"'
79*1cd1716bSBruce Richardson            initializers.append(
80*1cd1716bSBruce Richardson                f"static cmdline_parse_token_string_t cmd_{name}_{t_name}_tok =\n"
81*1cd1716bSBruce Richardson                f"\tTOKEN_STRING_INITIALIZER(struct cmd_{name}_result, {t_name}, {t_val});"
82*1cd1716bSBruce Richardson            )
8337666691SBruce Richardson        else:
8437666691SBruce Richardson            raise TypeError(f"Error line {lineno + 1}: unknown token type '{t_type}'")
8537666691SBruce Richardson        token_list.append(f"cmd_{name}_{t_name}_tok")
8637666691SBruce Richardson
8737666691SBruce Richardson    out.append(f'/* Auto-generated handling for command "{" ".join(tokens)}" */')
8837666691SBruce Richardson    # output function prototype
8937666691SBruce Richardson    func_sig = f"void\ncmd_{name}_parsed({PARSE_FN_PARAMS})"
9037666691SBruce Richardson    out.append(f"extern {func_sig};\n")
9137666691SBruce Richardson    # output result data structure
9237666691SBruce Richardson    out.append(f"struct cmd_{name}_result {{\n" + "\n".join(result_struct) + "\n};\n")
9337666691SBruce Richardson    # output the initializer tokens
9437666691SBruce Richardson    out.append("\n".join(initializers) + "\n")
9537666691SBruce Richardson    # output the instance structure
9637666691SBruce Richardson    inst_elems = "\n".join([f"\t\t(void *)&{t}," for t in token_list])
9737666691SBruce Richardson    out.append(
9837666691SBruce Richardson        f"""\
9937666691SBruce Richardsonstatic cmdline_parse_inst_t cmd_{name} = {{
10037666691SBruce Richardson\t.f = cmd_{name}_parsed,
10137666691SBruce Richardson\t.data = NULL,
10237666691SBruce Richardson\t.help_str = "{comment}",
10337666691SBruce Richardson\t.tokens = {{
10437666691SBruce Richardson{inst_elems}
10537666691SBruce Richardson\t\tNULL,
10637666691SBruce Richardson\t}}
10737666691SBruce Richardson}};
10837666691SBruce Richardson"""
10937666691SBruce Richardson    )
11037666691SBruce Richardson    # output function template if C file being written
11137666691SBruce Richardson    cfile_out.append(f"{func_sig}\n{{{PARSE_FN_BODY}}}\n")
11237666691SBruce Richardson
11337666691SBruce Richardson    # return the instance structure name
11437666691SBruce Richardson    return (f"cmd_{name}", out, cfile_out)
11537666691SBruce Richardson
11637666691SBruce Richardson
11737666691SBruce Richardsondef process_commands(infile, hfile, cfile, ctxname):
11837666691SBruce Richardson    """Generate boilerplate output for a list of commands from infile."""
11937666691SBruce Richardson    instances = []
12037666691SBruce Richardson
12137666691SBruce Richardson    hfile.write(
12237666691SBruce Richardson        f"""\
12337666691SBruce Richardson/* File autogenerated by {sys.argv[0]} */
12437666691SBruce Richardson#ifndef GENERATED_COMMANDS_H
12537666691SBruce Richardson#define GENERATED_COMMANDS_H
12637666691SBruce Richardson#include <rte_common.h>
12737666691SBruce Richardson#include <cmdline.h>
12837666691SBruce Richardson#include <cmdline_parse_string.h>
12937666691SBruce Richardson#include <cmdline_parse_num.h>
13037666691SBruce Richardson#include <cmdline_parse_ipaddr.h>
13137666691SBruce Richardson
13237666691SBruce Richardson"""
13337666691SBruce Richardson    )
13437666691SBruce Richardson
13537666691SBruce Richardson    for lineno, line in enumerate(infile.readlines()):
13637666691SBruce Richardson        if line.lstrip().startswith("#"):
13737666691SBruce Richardson            continue
13837666691SBruce Richardson        if "#" not in line:
13937666691SBruce Richardson            line = line + "#"  # ensure split always works, even if no help text
14037666691SBruce Richardson        tokens, comment = line.split("#", 1)
14137666691SBruce Richardson        cmd_inst, h_out, c_out = process_command(lineno, tokens.strip().split(), comment.strip())
14237666691SBruce Richardson        hfile.write("\n".join(h_out))
14337666691SBruce Richardson        if cfile:
14437666691SBruce Richardson            cfile.write("\n".join(c_out))
14537666691SBruce Richardson        instances.append(cmd_inst)
14637666691SBruce Richardson
14737666691SBruce Richardson    inst_join_str = ",\n\t&"
14837666691SBruce Richardson    hfile.write(
14937666691SBruce Richardson        f"""
15037666691SBruce Richardsonstatic __rte_used cmdline_parse_ctx_t {ctxname}[] = {{
15137666691SBruce Richardson\t&{inst_join_str.join(instances)},
15237666691SBruce Richardson\tNULL
15337666691SBruce Richardson}};
15437666691SBruce Richardson
15537666691SBruce Richardson#endif /* GENERATED_COMMANDS_H */
15637666691SBruce Richardson"""
15737666691SBruce Richardson    )
15837666691SBruce Richardson
15937666691SBruce Richardson
16037666691SBruce Richardsondef main():
16137666691SBruce Richardson    """Application main entry point."""
16237666691SBruce Richardson    ap = argparse.ArgumentParser(description=__doc__)
16337666691SBruce Richardson    ap.add_argument(
16437666691SBruce Richardson        "--stubs",
16537666691SBruce Richardson        action="store_true",
16637666691SBruce Richardson        help="Produce C file with empty function stubs for each command",
16737666691SBruce Richardson    )
16837666691SBruce Richardson    ap.add_argument(
16937666691SBruce Richardson        "--output-file",
17037666691SBruce Richardson        "-o",
17137666691SBruce Richardson        default="-",
17237666691SBruce Richardson        help="Output header filename [default to stdout]",
17337666691SBruce Richardson    )
17437666691SBruce Richardson    ap.add_argument(
17537666691SBruce Richardson        "--context-name",
17637666691SBruce Richardson        default="ctx",
17737666691SBruce Richardson        help="Name given to the cmdline context variable in the output header [default=ctx]",
17837666691SBruce Richardson    )
17937666691SBruce Richardson    ap.add_argument("infile", type=argparse.FileType("r"), help="File with list of commands")
18037666691SBruce Richardson    args = ap.parse_args()
18137666691SBruce Richardson
18237666691SBruce Richardson    if not args.stubs:
18337666691SBruce Richardson        if args.output_file == "-":
18437666691SBruce Richardson            process_commands(args.infile, sys.stdout, None, args.context_name)
18537666691SBruce Richardson        else:
18637666691SBruce Richardson            with open(args.output_file, "w") as hfile:
18737666691SBruce Richardson                process_commands(args.infile, hfile, None, args.context_name)
18837666691SBruce Richardson    else:
18937666691SBruce Richardson        if not args.output_file.endswith(".h"):
19037666691SBruce Richardson            ap.error(
19137666691SBruce Richardson                "-o/--output-file: specify an output filename ending with .h when creating stubs"
19237666691SBruce Richardson            )
19337666691SBruce Richardson
19437666691SBruce Richardson        cfilename = args.output_file[:-2] + ".c"
19537666691SBruce Richardson        with open(args.output_file, "w") as hfile:
19637666691SBruce Richardson            with open(cfilename, "w") as cfile:
19737666691SBruce Richardson                cfile.write(f'#include "{args.output_file}"\n\n')
19837666691SBruce Richardson                process_commands(args.infile, hfile, cfile, args.context_name)
19937666691SBruce Richardson
20037666691SBruce Richardson
20137666691SBruce Richardsonif __name__ == "__main__":
20237666691SBruce Richardson    main()
203