diff options
Diffstat (limited to 'python')
-rw-r--r-- | python/firstheader.py | 2 | ||||
-rw-r--r-- | python/makefile.py | 2 | ||||
-rw-r--r-- | python/xref2vtysh.py | 166 | ||||
-rw-r--r-- | python/xrelfo.py | 18 |
4 files changed, 173 insertions, 15 deletions
diff --git a/python/firstheader.py b/python/firstheader.py index 06e28958..1a3cadfd 100644 --- a/python/firstheader.py +++ b/python/firstheader.py @@ -15,7 +15,7 @@ argp.add_argument("--autofix", action="store_const", const=True) argp.add_argument("--warn-empty", action="store_const", const=True) argp.add_argument("--pipe", action="store_const", const=True) -include_re = re.compile('^#\s*include\s+["<]([^ ">]+)[">]', re.M) +include_re = re.compile(r'^#\s*include\s+["<]([^ ">]+)[">]', re.M) ignore = [ lambda fn: fn.startswith("tools/"), diff --git a/python/makefile.py b/python/makefile.py index 573871fb..45f03229 100644 --- a/python/makefile.py +++ b/python/makefile.py @@ -91,7 +91,7 @@ lines = before.splitlines() autoderp = "#AUTODERP# " out_lines = [] bcdeps = [] -make_rule_re = re.compile("^([^:\s]+):\s*([^:\s]+)\s*($|\n)") +make_rule_re = re.compile(r"^([^:\s]+):\s*([^:\s]+)\s*($|\n)") while lines: line = lines.pop(0) diff --git a/python/xref2vtysh.py b/python/xref2vtysh.py index 75d9ccf3..0cfb11e7 100644 --- a/python/xref2vtysh.py +++ b/python/xref2vtysh.py @@ -26,6 +26,8 @@ try: except ImportError: pass +import _clippy + frr_top_src = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # vtysh needs to know which daemon(s) to send commands to. For lib/, this is @@ -58,6 +60,16 @@ vtysh_cmd_head = """/* autogenerated file, DO NOT EDIT! */ #include "linklist.h" #include "vtysh/vtysh.h" + +#pragma GCC visibility push(internal) + +#define MAKE_VECTOR(name, len, ...) \\ + static void * name ## _vitems[] = { __VA_ARGS__ }; \\ + static struct _vector name = { \\ + .active = len, \\ + .count = len, \\ + .index = name ## _vitems, \\ + } """ if sys.stderr.isatty(): @@ -335,23 +347,159 @@ class CommandEntry: ofd.write(entry.get_def()) @classmethod - def output_install(cls, ofd, nodes): - ofd.write("\nvoid vtysh_init_cmd(void)\n{\n") + def output_node_graph(cls, ofd, node, cmds, splitfile): + graph = _clippy.Graph(None) + + for _, cmd in sorted(cmds.items()): + cg = _clippy.Graph(cmd.cmd, cmd._spec["doc"], cmd.name) + graph.merge(cg) + + if len(graph) <= 2: + return [] + + ofd.write("\n") + ofd.write(f"static struct cmd_token ctkn_{node}[];\n") + ofd.write(f"static struct graph_node gn_{node}[];\n") + ofd.write("\n") + + vectors = [] + cmdels = set() + + ofd.write(f"static struct cmd_token ctkn_{node}[] = {'{'}\n") + for i, token in enumerate(graph): + vectors.append( + ( + list(i.idx for i in token.next()), + list(i.idx for i in token.prev()), + ) + ) - for name, items in sorted(nodes.items_named()): - for item in sorted(items.values(), key=lambda i: i.name): - ofd.write("\tinstall_element(%s, &%s_vtysh);\n" % (name, item.name)) + if token.type == "CMD_ELEMENT_TKN": + ofd.write(f"\t{'{'} /* [{i}] = {token.text} */ {'}'},\n") + cmdels.add(token.text) + continue + + ofd.write(f"\t{'{'} /* [{i}] */\n\t\t.type = {token.type},\n") + if token.attr: + ofd.write(f"\t\t.attr = {token.attr},\n") + if token.allowrepeat: + ofd.write(f"\t\t.allowrepeat = true,\n") + if token.varname_src: + ofd.write(f"\t\t.varname_src = {token.varname_src},\n") + if token.text: + ofd.write(f'\t\t.text = (char *)"{c_escape(token.text)}",\n') + if token.desc: + ofd.write(f'\t\t.desc = (char *)"{c_escape(token.desc)}",\n') + if token.min: + ofd.write(f"\t\t.min = {token.min},\n") + if token.max: + ofd.write(f"\t\t.max = {token.max},\n") + if token.varname: + ofd.write(f'\t\t.varname = (char *)"{c_escape(token.varname)}",\n') + + if token.type == "FORK_TKN": + fj = token.join() + ofd.write(f"\t\t.forkjoin = &gn_{node}[{fj.idx}],\n") + if token.type == "JOIN_TKN": + fj = token.fork() + ofd.write(f"\t\t.forkjoin = &gn_{node}[{fj.idx}],\n") + + ofd.write(f"\t{'}'},\n") + + ofd.write("};\n\n") + + if splitfile: + for cmdel in sorted(cmdels): + ofd.write(f"extern struct cmd_element {cmdel}_vtysh;\n") + ofd.write("\n") + + for i, next_prev in enumerate(vectors): + n, p = next_prev + items = ", ".join(f"&gn_{node}[{i}]" for i in n) + ofd.write(f"MAKE_VECTOR(gn_{node}_{i}_next, {len(n)}, {items});\n") + items = ", ".join(f"&gn_{node}[{i}]" for i in p) + ofd.write(f"MAKE_VECTOR(gn_{node}_{i}_prev, {len(p)}, {items});\n") + + ofd.write(f"\nstatic struct graph_node gn_{node}[] = {'{'}\n") + for i, token in enumerate(graph): + ofd.write("\t{\n") + ofd.write(f"\t\t.from = &gn_{node}_{i}_prev,\n") + ofd.write(f"\t\t.to = &gn_{node}_{i}_next,\n") + if token.type == "CMD_ELEMENT_TKN": + ofd.write(f"\t\t.data = (void *)&{token.text}_vtysh,\n") + else: + ofd.write(f"\t\t.data = &ctkn_{node}[{i}],\n") + ofd.write("\t},\n") + ofd.write("};\n") + + items = ", ".join(f"&gn_{node}[{i}]" for i in range(0, len(graph))) + ofd.write(f"MAKE_VECTOR(gvec_{node}, {len(graph)}, {items});\n") + + ofd.write( + f""" +{"extern " if splitfile else "static "}void install_{node}(void);\n +{"" if splitfile else "static "}void install_{node}(void)\n +{'{'} + unsigned node_id = {node}; + struct cmd_node *node; + + assert(node_id < vector_active(cmdvec)); + node = vector_slot(cmdvec, node_id); + assert(node); + assert(vector_active(node->cmdgraph->nodes) == 1); + graph_delete_node(node->cmdgraph, vector_slot(node->cmdgraph->nodes, 0)); + vector_free(node->cmdgraph->nodes); + node->cmdgraph->nodes = &gvec_{node}; +{'}'} +""" + ) - ofd.write("}\n") + return [node] @classmethod - def run(cls, xref, ofd): - ofd.write(vtysh_cmd_head) + def run(cls, xref, ofds): + for ofd in ofds: + ofd.write(vtysh_cmd_head) + + ofd = ofds.pop(0) NodeDict.load_nodenames() nodes = cls.load(xref) cls.output_defs(ofd) - cls.output_install(ofd, nodes) + + out_nodes = [] + for nodeid, cmds in nodes.items(): + node = nodes.nodename(nodeid) + + if ofds: + gfd, splitfile = ofds[nodeid % len(ofds)], True + else: + gfd, splitfile = ofd, False + + # install_element(VIEW_NODE, x) implies install_element(ENABLE_NODE, x) + # this needs to be handled here. + if node == "ENABLE_NODE": + nodeid_view = list( + k for k, v in nodes.nodenames.items() if v == "VIEW_NODE" + ) + assert len(nodeid_view) == 1 + cmds.update(nodes[nodeid_view[0]]) + + out_nodes.extend(cls.output_node_graph(gfd, node, cmds, splitfile)) + + out_nodes.sort() + + if ofds: + ofd.write("\n") + for name in out_nodes: + ofd.write(f"extern void install_{name}(void);\n") + + ofd.write("\nvoid vtysh_init_cmd(void)\n{\n") + + for name in out_nodes: + ofd.write(f"\tinstall_{name}();\n") + + ofd.write("}\n") def main(): diff --git a/python/xrelfo.py b/python/xrelfo.py index 07cd7407..5f7616f2 100644 --- a/python/xrelfo.py +++ b/python/xrelfo.py @@ -447,7 +447,9 @@ def main(): argp = argparse.ArgumentParser(description="FRR xref ELF extractor") argp.add_argument("-o", dest="output", type=str, help="write JSON output") argp.add_argument("--out-by-file", type=str, help="write by-file JSON output") - argp.add_argument("-c", dest="vtysh_cmds", type=str, help="write vtysh_cmd.c") + argp.add_argument( + "-c", dest="vtysh_cmds", type=str, help="write vtysh_cmd.c", nargs="*" + ) argp.add_argument("-Wlog-format", action="store_const", const=True) argp.add_argument("-Wlog-args", action="store_const", const=True) argp.add_argument("-Werror", action="store_const", const=True) @@ -528,9 +530,17 @@ def _main(args): os.rename(args.out_by_file + ".tmp", args.out_by_file) if args.vtysh_cmds: - with open(args.vtysh_cmds + ".tmp", "w") as fd: - CommandEntry.run(out, fd) - os.rename(args.vtysh_cmds + ".tmp", args.vtysh_cmds) + fds = [] + for filename in args.vtysh_cmds: + fds.append(open(filename + ".tmp", "w")) + + CommandEntry.run(out, fds) + + while fds: + fds.pop(0).close() + for filename in args.vtysh_cmds: + os.rename(filename + ".tmp", filename) + if args.Werror and CommandEntry.warn_counter: sys.exit(1) |