summaryrefslogtreecommitdiffstats
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/firstheader.py2
-rw-r--r--python/makefile.py2
-rw-r--r--python/xref2vtysh.py166
-rw-r--r--python/xrelfo.py18
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)