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