xref: /dpdk/buildtools/dpdk-cmdline-gen.py (revision 620b269600244c269e1f3698b18c47c84d9d2a25)
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