From 0b84f294904959a4be58db6fe0e89d71b2c1f401 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 16 Nov 2016 15:00:52 +0900 Subject: [PATCH 1/9] *: make DEFUN installations file-local This moves all install_element calls into the file where the DEFUNs are located. This fixes several small related bugs: - ospf6d wasn't installing a "no interface FOO" command - zebra had a useless copy of "interface FOO" - pimd's copy of "interface FOO" was not setting qobj_index, which means "description LINE" commands would fail with an error The next commit will do the actual act of making "foo_cmd" static. Signed-off-by: David Lamparter --- isisd/isis_circuit.c | 7 +----- ldpd/ldp_vty_conf.c | 9 +------- lib/command.c | 37 ++++++++++++++++++------------ lib/command.h | 7 ++---- lib/if.c | 18 +++++++++++++++ lib/if.h | 18 +++------------ lib/thread.c | 7 ++++++ lib/thread.h | 3 +-- lib/vty.c | 2 +- lib/workqueue.c | 6 +++++ lib/workqueue.h | 4 +++- ospf6d/ospf6_interface.c | 5 +--- ospfd/ospf_vty.c | 9 +------- pimd/pim_cmd.c | 49 +--------------------------------------- ripd/rip_interface.c | 6 +---- ripngd/ripng_interface.c | 8 +------ vtysh/vtysh.c | 9 ++++++++ zebra/interface.c | 38 ++++--------------------------- 18 files changed, 84 insertions(+), 158 deletions(-) diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index c5812a658d..8479d7f31a 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -1418,12 +1418,7 @@ isis_circuit_init () /* Install interface node */ install_node (&interface_node, isis_interface_config_write); - install_element (CONFIG_NODE, &interface_cmd); - install_element (CONFIG_NODE, &no_interface_cmd); - - install_default (INTERFACE_NODE); - install_element (INTERFACE_NODE, &interface_desc_cmd); - install_element (INTERFACE_NODE, &no_interface_desc_cmd); + if_cmd_init (); isis_vty_init (); } diff --git a/ldpd/ldp_vty_conf.c b/ldpd/ldp_vty_conf.c index e5acada180..f2b21d8175 100644 --- a/ldpd/ldp_vty_conf.c +++ b/ldpd/ldp_vty_conf.c @@ -1618,14 +1618,7 @@ ldp_vty_if_init(void) { /* Install interface node. */ install_node (&interface_node, interface_config_write); - - install_element(CONFIG_NODE, &interface_cmd); - install_element(CONFIG_NODE, &no_interface_cmd); - install_default(INTERFACE_NODE); - - /* "description" commands. */ - install_element(INTERFACE_NODE, &interface_desc_cmd); - install_element(INTERFACE_NODE, &no_interface_desc_cmd); + if_cmd_init (); } struct iface * diff --git a/lib/command.c b/lib/command.c index 3c429ce1a7..8e935acf92 100644 --- a/lib/command.c +++ b/lib/command.c @@ -1050,6 +1050,13 @@ DEFUN (config_exit, config_exit_cmd, "exit", "Exit current mode and down to previous mode\n") +{ + cmd_exit (vty); + return CMD_SUCCESS; +} + +void +cmd_exit (struct vty *vty) { switch (vty->node) { @@ -1118,7 +1125,6 @@ DEFUN (config_exit, default: break; } - return CMD_SUCCESS; } /* ALIAS_FIXME */ @@ -1264,17 +1270,12 @@ permute (struct graph_node *start, struct vty *vty) list_delete_node (position, listtail(position)); } -/* Help display function for all node. */ -DEFUN (config_list, - config_list_cmd, - "list [permutations]", - "Print command list\n" - "Print all possible command permutations\n") +int +cmd_list_cmds (struct vty *vty, int do_permute) { struct cmd_node *node = vector_slot (cmdvec, vty->node); - if ((strmatch (argv[0]->text, "list") && argc == 2) || - (strmatch (argv[0]->text, "show") && argc == 3)) + if (do_permute) permute (vector_slot (node->cmdgraph->nodes, 0), vty); else { @@ -1289,13 +1290,23 @@ DEFUN (config_list, return CMD_SUCCESS; } +/* Help display function for all node. */ +DEFUN (config_list, + config_list_cmd, + "list [permutations]", + "Print command list\n" + "Print all possible command permutations\n") +{ + return cmd_list_cmds (vty, argc == 2); +} + DEFUN (show_commandtree, show_commandtree_cmd, "show commandtree [permutations]", SHOW_STR "Show command tree\n") { - return config_list (self, vty, argc, argv); + return cmd_list_cmds (vty, argc == 3); } /* Write current configuration into file. */ @@ -2352,10 +2363,8 @@ cmd_init (int terminal) install_element (ENABLE_NODE, &config_logmsg_cmd); install_default (CONFIG_NODE); - install_element (VIEW_NODE, &show_thread_cpu_cmd); - install_element (ENABLE_NODE, &clear_thread_cpu_cmd); - - install_element (VIEW_NODE, &show_work_queues_cmd); + thread_cmd_init (); + workqueue_cmd_init (); } install_element (CONFIG_NODE, &hostname_cmd); diff --git a/lib/command.h b/lib/command.h index f120063ea9..a170a9549d 100644 --- a/lib/command.h +++ b/lib/command.h @@ -414,6 +414,8 @@ extern int cmd_execute_command (vector, struct vty *, const struct cmd_element * extern int cmd_execute_command_strict (vector, struct vty *, const struct cmd_element **); extern void cmd_init (int); extern void cmd_terminate (void); +extern void cmd_exit (struct vty *vty); +extern int cmd_list_cmds (struct vty *vty, int do_permute); /* memory management for cmd_element */ void @@ -430,11 +432,6 @@ struct cmd_token * copy_cmd_token (struct cmd_token *); /* Export typical functions. */ -extern struct cmd_element config_end_cmd; -extern struct cmd_element config_exit_cmd; -extern struct cmd_element config_quit_cmd; -extern struct cmd_element config_help_cmd; -extern struct cmd_element config_list_cmd; extern const char *host_config_get (void); extern void host_config_set (const char *); diff --git a/lib/if.c b/lib/if.c index dadf35574e..c323ae9da2 100644 --- a/lib/if.c +++ b/lib/if.c @@ -832,6 +832,17 @@ DEFUN_NOSH (no_interface, return CMD_SUCCESS; } +void +if_cmd_init (void) +{ + install_element (CONFIG_NODE, &interface_cmd); + install_element (CONFIG_NODE, &no_interface_cmd); + + install_default (INTERFACE_NODE); + install_element (INTERFACE_NODE, &interface_desc_cmd); + install_element (INTERFACE_NODE, &no_interface_desc_cmd); +} + DEFUN (vrf, vrf_cmd, "vrf NAME", @@ -890,6 +901,13 @@ DEFUN_NOSH (no_vrf, return CMD_SUCCESS; } +void +vrf_cmd_init (void) +{ + install_element (CONFIG_NODE, &vrf_cmd); + install_element (CONFIG_NODE, &no_vrf_cmd); + install_default (VRF_NODE); +} /* For debug purpose. */ DEFUN (show_address, diff --git a/lib/if.h b/lib/if.h index 7fdd46d3f2..cf6f3bc006 100644 --- a/lib/if.h +++ b/lib/if.h @@ -445,11 +445,14 @@ extern int if_is_pointopoint (struct interface *); extern int if_is_multicast (struct interface *); extern void if_add_hook (int, int (*)(struct interface *)); extern void if_init (struct list **); +extern void if_cmd_init (void); extern void if_terminate (struct list **); extern void if_dump_all (void); extern const char *if_flag_dump(unsigned long); extern const char *if_link_type_str (enum zebra_link_type); +extern void vrf_cmd_init (void); + /* Please use ifindex2ifname instead of if_indextoname where possible; ifindex2ifname uses internal interface info, whereas if_indextoname must make a system call. */ @@ -483,19 +486,4 @@ struct nbr_connected *nbr_connected_check (struct interface *, struct prefix *); struct if_link_params *if_link_params_get (struct interface *); void if_link_params_free (struct interface *); -/* Exported variables. */ -extern struct cmd_element interface_desc_cmd; -extern struct cmd_element no_interface_desc_cmd; -extern struct cmd_element interface_cmd; -extern struct cmd_element no_interface_cmd; -extern struct cmd_element interface_vrf_cmd; -extern struct cmd_element no_interface_vrf_cmd; -extern struct cmd_element interface_pseudo_cmd; -extern struct cmd_element no_interface_pseudo_cmd; -extern struct cmd_element show_address_cmd; -extern struct cmd_element show_address_vrf_cmd; -extern struct cmd_element show_address_vrf_all_cmd; -extern struct cmd_element vrf_cmd; -extern struct cmd_element no_vrf_cmd; - #endif /* _ZEBRA_IF_H */ diff --git a/lib/thread.c b/lib/thread.c index ce93530ff1..eac7f3250b 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -423,6 +423,13 @@ DEFUN (clear_thread_cpu, return CMD_SUCCESS; } +void +thread_cmd_init (void) +{ + install_element (VIEW_NODE, &show_thread_cpu_cmd); + install_element (ENABLE_NODE, &clear_thread_cpu_cmd); +} + static int thread_timer_cmp(void *a, void *b) { diff --git a/lib/thread.h b/lib/thread.h index e41e96dec2..5c6b96a32d 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -244,8 +244,7 @@ extern void thread_set_yield_time (struct thread *, unsigned long); /* Internal libzebra exports */ extern void thread_getrusage (RUSAGE_T *); -extern struct cmd_element show_thread_cpu_cmd; -extern struct cmd_element clear_thread_cpu_cmd; +extern void thread_cmd_init (void); /* replacements for the system gettimeofday(), clock_gettime() and * time() functions, providing support for non-decrementing clock on diff --git a/lib/vty.c b/lib/vty.c index 54399b0238..d5ecb1db5b 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -715,7 +715,7 @@ static void vty_down_level (struct vty *vty) { vty_out (vty, "%s", VTY_NEWLINE); - (*config_exit_cmd.func)(NULL, vty, 0, NULL); + cmd_exit (vty); vty_prompt (vty); vty->cp = 0; } diff --git a/lib/workqueue.c b/lib/workqueue.c index 549bb2360a..51017b34ea 100644 --- a/lib/workqueue.c +++ b/lib/workqueue.c @@ -222,6 +222,12 @@ DEFUN (show_work_queues, return CMD_SUCCESS; } +void +workqueue_cmd_init (void) +{ + install_element (VIEW_NODE, &show_work_queues_cmd); +} + /* 'plug' a queue: Stop it from being scheduled, * ie: prevent the queue from draining. */ diff --git a/lib/workqueue.h b/lib/workqueue.h index eaf8574907..548f96d8b0 100644 --- a/lib/workqueue.h +++ b/lib/workqueue.h @@ -129,5 +129,7 @@ bool work_queue_is_scheduled (struct work_queue *); /* Helpers, exported for thread.c and command.c */ extern int work_queue_run (struct thread *); -extern struct cmd_element show_work_queues_cmd; + +extern void workqueue_cmd_init (void); + #endif /* _QUAGGA_WORK_QUEUE_H */ diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 8ea4b16957..74c9ac739f 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -1845,15 +1845,12 @@ ospf6_interface_init (void) { /* Install interface node. */ install_node (&interface_node, config_write_ospf6_interface); + if_cmd_init (); install_element (VIEW_NODE, &show_ipv6_ospf6_interface_prefix_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_prefix_cmd); - install_element (CONFIG_NODE, &interface_cmd); - install_default (INTERFACE_NODE); - install_element (INTERFACE_NODE, &interface_desc_cmd); - install_element (INTERFACE_NODE, &no_interface_desc_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_cost_cmd); install_element (INTERFACE_NODE, &no_ipv6_ospf6_cost_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_ifmtu_cmd); diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 8662eb4259..8173835d94 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -9250,14 +9250,7 @@ ospf_vty_if_init (void) { /* Install interface node. */ install_node (&interface_node, config_write_interface); - - install_element (CONFIG_NODE, &interface_cmd); - install_element (CONFIG_NODE, &no_interface_cmd); - install_default (INTERFACE_NODE); - - /* "description" commands. */ - install_element (INTERFACE_NODE, &interface_desc_cmd); - install_element (INTERFACE_NODE, &no_interface_desc_cmd); + if_cmd_init (); /* "ip ospf authentication" commands. */ install_element (INTERFACE_NODE, &ip_ospf_authentication_args_addr_cmd); diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index afc42a9561..8d7579aafc 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -1527,47 +1527,6 @@ static void clear_interfaces() clear_pim_interfaces(); } -DEFUN (pim_interface, - pim_interface_cmd, - "interface IFNAME", - "Select an interface to configure\n" - "Interface's name\n") -{ - int idx_ifname = 1; - struct interface *ifp; - const char *ifname = argv[idx_ifname]->arg; - size_t sl; - - sl = strlen(ifname); - if (sl > INTERFACE_NAMSIZ) { - vty_out(vty, "%% Interface name %s is invalid: length exceeds " - "%d characters%s", - ifname, INTERFACE_NAMSIZ, VTY_NEWLINE); - return CMD_WARNING; - } - - ifp = if_lookup_by_name_len(ifname, sl); - if (!ifp) { - vty_out(vty, "%% Interface %s does not exist%s", ifname, VTY_NEWLINE); - - /* Returning here would prevent pimd from booting when there are - interface commands in pimd.conf, since all interfaces are - unknown at pimd boot time (the zebra daemon has not been - contacted for interface discovery). */ - - ifp = if_get_by_name_len(ifname, sl); - if (!ifp) { - vty_out(vty, "%% Could not create interface %s%s", ifname, VTY_NEWLINE); - return CMD_WARNING; - } - } - - vty->index = ifp; - vty->node = INTERFACE_NODE; - - return CMD_SUCCESS; -} - DEFUN (clear_ip_interfaces, clear_ip_interfaces_cmd, "clear ip interfaces", @@ -4832,6 +4791,7 @@ void pim_cmd_init() { install_node (&pim_global_node, pim_global_config_write); /* PIM_NODE */ install_node (&interface_node, pim_interface_config_write); /* INTERFACE_NODE */ + if_cmd_init (); install_element (CONFIG_NODE, &ip_multicast_routing_cmd); install_element (CONFIG_NODE, &no_ip_multicast_routing_cmd); @@ -4839,14 +4799,7 @@ void pim_cmd_init() install_element (CONFIG_NODE, &no_ip_pim_rp_cmd); install_element (CONFIG_NODE, &ip_ssmpingd_cmd); install_element (CONFIG_NODE, &no_ip_ssmpingd_cmd); -#if 0 - install_element (CONFIG_NODE, &interface_cmd); /* from if.h */ -#else - install_element (CONFIG_NODE, &pim_interface_cmd); -#endif - install_element (CONFIG_NODE, &no_interface_cmd); /* from if.h */ - install_default (INTERFACE_NODE); install_element (INTERFACE_NODE, &interface_ip_igmp_cmd); install_element (INTERFACE_NODE, &interface_no_ip_igmp_cmd); install_element (INTERFACE_NODE, &interface_ip_igmp_join_cmd); diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index 8c5092d787..f2ce7e760d 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -2004,13 +2004,9 @@ rip_if_init (void) /* Install interface node. */ install_node (&interface_node, rip_interface_config_write); + if_cmd_init (); /* Install commands. */ - install_element (CONFIG_NODE, &interface_cmd); - install_element (CONFIG_NODE, &no_interface_cmd); - install_default (INTERFACE_NODE); - install_element (INTERFACE_NODE, &interface_desc_cmd); - install_element (INTERFACE_NODE, &no_interface_desc_cmd); install_element (RIP_NODE, &rip_network_cmd); install_element (RIP_NODE, &no_rip_network_cmd); install_element (RIP_NODE, &rip_neighbor_cmd); diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c index 7bee7625d1..393ca2e7a6 100644 --- a/ripngd/ripng_interface.c +++ b/ripngd/ripng_interface.c @@ -1190,13 +1190,7 @@ ripng_if_init () /* Install interface node. */ install_node (&interface_node, interface_config_write); - - /* Install commands. */ - install_element (CONFIG_NODE, &interface_cmd); - install_element (CONFIG_NODE, &no_interface_cmd); - install_default (INTERFACE_NODE); - install_element (INTERFACE_NODE, &interface_desc_cmd); - install_element (INTERFACE_NODE, &no_interface_desc_cmd); + if_cmd_init (); install_element (RIPNG_NODE, &ripng_network_cmd); install_element (RIPNG_NODE, &no_ripng_network_cmd); diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index b622fa9743..0a83b56be0 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -2796,6 +2796,15 @@ DEFUN (vtysh_start_zsh, } #endif +DEFUN (config_list, + config_list_cmd, + "list [permutations]", + "Print command list\n" + "Print all possible command permutations\n") +{ + return cmd_list_cmds (vty, argc == 2); +} + static void vtysh_install_default (enum node_type node) { diff --git a/zebra/interface.c b/zebra/interface.c index 91dbe52764..e9cbd72af9 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1223,32 +1223,6 @@ if_dump_vty (struct vty *vty, struct interface *ifp) #endif /* HAVE_NET_RT_IFLIST */ } -/* Wrapper hook point for zebra daemon so that ifindex can be set - * DEFUN macro not used as extract.pl HAS to ignore this - * See also interface_cmd in lib/if.c - */ -DEFUN_NOSH (zebra_interface, - zebra_interface_cmd, - "interface IFNAME", - "Select an interface to configure\n" - "Interface's name\n") -{ - int ret; - - /* Call lib interface() */ - if ((ret = interface_cmd.func (self, vty, argc, argv)) != CMD_SUCCESS) - return ret; - - VTY_DECLVAR_CONTEXT (interface, ifp); - - if (ifp->ifindex == IFINDEX_INTERNAL) - /* Is this really necessary? Shouldn't status be initialized to 0 - in that case? */ - UNSET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE); - - return ret; -} - static void interface_update_stats (void) { @@ -1269,6 +1243,7 @@ struct cmd_node interface_node = 1 }; +#if 0 /* Wrapper hook point for zebra daemon so that ifindex can be set * DEFUN macro not used as extract.pl HAS to ignore this * See also interface_cmd in lib/if.c @@ -1288,6 +1263,7 @@ DEFUN_NOSH (zebra_vrf, return ret; } +#endif struct cmd_node vrf_node = { @@ -2934,6 +2910,7 @@ zebra_if_init (void) install_node (&interface_node, if_config_write); install_node (&link_params_node, NULL); install_node (&vrf_node, vrf_config_write); + if_cmd_init (); install_element (VIEW_NODE, &show_interface_cmd); install_element (VIEW_NODE, &show_interface_vrf_all_cmd); @@ -2942,11 +2919,6 @@ zebra_if_init (void) install_element (ENABLE_NODE, &show_interface_desc_cmd); install_element (ENABLE_NODE, &show_interface_desc_vrf_all_cmd); - install_element (CONFIG_NODE, &zebra_interface_cmd); - install_element (CONFIG_NODE, &no_interface_cmd); - install_default (INTERFACE_NODE); - install_element (INTERFACE_NODE, &interface_desc_cmd); - install_element (INTERFACE_NODE, &no_interface_desc_cmd); install_element (INTERFACE_NODE, &multicast_cmd); install_element (INTERFACE_NODE, &no_multicast_cmd); install_element (INTERFACE_NODE, &linkdetect_cmd); @@ -2991,7 +2963,5 @@ zebra_if_init (void) install_element(LINK_PARAMS_NODE, &no_link_params_use_bw_cmd); install_element(LINK_PARAMS_NODE, &exit_link_params_cmd); - install_element (CONFIG_NODE, &zebra_vrf_cmd); - install_element (CONFIG_NODE, &no_vrf_cmd); - install_default (VRF_NODE); + vrf_cmd_init(); } From 555a5bfe1541ba77ccfe410dd515c9f9037a0a07 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 16 Nov 2016 15:02:04 +0900 Subject: [PATCH 2/9] lib: make DEFUN foobar_cmd symbols static These are not externally referenced anymore; this reduces the symbol count of libzebra by quite a bit. Signed-off-by: David Lamparter --- lib/command.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/command.h b/lib/command.h index a170a9549d..a38f436884 100644 --- a/lib/command.h +++ b/lib/command.h @@ -237,7 +237,7 @@ struct cmd_element /* helper defines for end-user DEFUN* macros */ #define DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attrs, dnum) \ - struct cmd_element cmdname = \ + static struct cmd_element cmdname = \ { \ .string = cmdstr, \ .func = funcname, \ From 8af5502876b9e6e0701f51ccdd2c708e6a971197 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Fri, 18 Nov 2016 11:34:28 +0100 Subject: [PATCH 3/9] lib: allow all characters in WORD tokens WORD tokens (which are also used for "LINE..." input) should really accept all characters. Signed-off-by: David Lamparter --- lib/command_match.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/command_match.c b/lib/command_match.c index 06a50656b6..93f898da7b 100644 --- a/lib/command_match.c +++ b/lib/command_match.c @@ -855,14 +855,9 @@ match_word (struct cmd_token *token, const char *word) return no_match; } -#define VARIABLE_ALPHABET \ -"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890:/._-" - static enum match_type match_variable (struct cmd_token *token, const char *word) { assert (token->type == VARIABLE_TKN); - - return strlen (word) == strspn(word, VARIABLE_ALPHABET) ? - exact_match : no_match; + return exact_match; } From 2ab402707ff0ebe4b7b87ef0ffb3233e791cb92f Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 23 Nov 2016 08:42:27 +0100 Subject: [PATCH 4/9] lib: move command_parse_format prototype The function prototype for command_parse_format() is better left in command.h, so that the bison-generated header file doesn't need to be included for that. Signed-off-by: David Lamparter --- lib/command.c | 1 - lib/command.h | 2 ++ lib/command_match.c | 1 - lib/command_parse.y | 2 -- tools/permutations.c | 1 - 5 files changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/command.c b/lib/command.c index 8e935acf92..3ad0ca92d7 100644 --- a/lib/command.c +++ b/lib/command.c @@ -39,7 +39,6 @@ #include "workqueue.h" #include "vrf.h" #include "command_match.h" -#include "command_parse.h" #include "qobj.h" DEFINE_MTYPE( LIB, HOST, "Host config") diff --git a/lib/command.h b/lib/command.h index a38f436884..c9b3440b02 100644 --- a/lib/command.h +++ b/lib/command.h @@ -431,6 +431,8 @@ del_cmd_token (struct cmd_token *); struct cmd_token * copy_cmd_token (struct cmd_token *); +extern void command_parse_format (struct graph *graph, struct cmd_element *cmd); + /* Export typical functions. */ extern const char *host_config_get (void); extern void host_config_set (const char *); diff --git a/lib/command_match.c b/lib/command_match.c index 93f898da7b..d4996f634d 100644 --- a/lib/command_match.c +++ b/lib/command_match.c @@ -25,7 +25,6 @@ #include #include "command_match.h" -#include "command_parse.h" #include "memory.h" DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command Tokens") diff --git a/lib/command_parse.y b/lib/command_parse.y index e381507cc3..ac8e060113 100644 --- a/lib/command_parse.y +++ b/lib/command_parse.y @@ -51,8 +51,6 @@ /* functionality this unit exports */ %code provides { - void - command_parse_format (struct graph *, struct cmd_element *); /* maximum length of a number, lexer will not match anything longer */ #define DECIMAL_STRLEN_MAX 20 diff --git a/tools/permutations.c b/tools/permutations.c index 49f9416b21..8db51ee037 100644 --- a/tools/permutations.c +++ b/tools/permutations.c @@ -23,7 +23,6 @@ #include "command.h" #include "graph.h" -#include "command_parse.h" #include "vector.h" #define USAGE "usage: permutations " From b07a15f82dc1dd60316ab92edc4f612eced7ffa3 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 23 Nov 2016 09:02:08 +0100 Subject: [PATCH 5/9] lib: parser: wrap state in struct parser_ctx This encapsulates all parser state into a new "struct parser_ctx", which is allocated on stack and passed around as pointer. The parser no longer has any global variables with this. Signed-off-by: David Lamparter --- lib/command_parse.y | 162 +++++++++++++++++++++++--------------------- 1 file changed, 83 insertions(+), 79 deletions(-) diff --git a/lib/command_parse.y b/lib/command_parse.y index ac8e060113..aac4a74666 100644 --- a/lib/command_parse.y +++ b/lib/command_parse.y @@ -47,6 +47,16 @@ extern void cleanup_lexer (void); + + struct parser_ctx { + struct cmd_element *el; + + struct graph *graph; + struct graph_node *currnode, *startnode; + + /* pointers to copy of command docstring */ + char *docstr_start, *docstr; + }; } /* functionality this unit exports */ @@ -91,21 +101,16 @@ %code { /* bison declarations */ void - yyerror (struct graph *, struct cmd_element *el, char const *msg); + yyerror (struct parser_ctx *ctx, char const *msg); /* subgraph semantic value */ struct subgraph { struct graph_node *start, *end; }; - struct graph_node *currnode, *startnode; - - /* pointers to copy of command docstring */ - char *docstr_start, *docstr; - /* helper functions for parser */ static char * - doc_next (struct cmd_element *); + doc_next (struct parser_ctx *ctx); static struct graph_node * node_adjacent (struct graph_node *, struct graph_node *); @@ -117,47 +122,45 @@ cmp_token (struct cmd_token *, struct cmd_token *); static struct graph_node * - new_token_node (struct graph *, + new_token_node (struct parser_ctx *, enum cmd_token_type type, - u_char attr, char *text, + char *text, char *doc); static void - terminate_graph (struct graph *, - struct graph_node *, - struct cmd_element *); + terminate_graph (struct parser_ctx *ctx, + struct graph_node *); static void - cleanup (void); + cleanup (struct parser_ctx *ctx); } /* yyparse parameters */ -%parse-param { struct graph *graph } -%parse-param { struct cmd_element *el } +%parse-param { struct parser_ctx *ctx } /* called automatically before yyparse */ %initial-action { /* clear state pointers */ - currnode = startnode = NULL; + ctx->currnode = ctx->startnode = NULL; - startnode = vector_slot (graph->nodes, 0); + ctx->startnode = vector_slot (ctx->graph->nodes, 0); /* set string to parse */ - set_lexer_string (el->string); + set_lexer_string (ctx->el->string); /* copy docstring and keep a pointer to the copy */ - if (el->doc) + if (ctx->el->doc) { // allocate a new buffer, making room for a flag - size_t length = (size_t) strlen (el->doc) + 2; - docstr = malloc (length); - memcpy (docstr, el->doc, strlen (el->doc)); + size_t length = (size_t) strlen (ctx->el->doc) + 2; + ctx->docstr = malloc (length); + memcpy (ctx->docstr, ctx->el->doc, strlen (ctx->el->doc)); // set the flag so doc_next knows when to print a warning - docstr[length - 2] = 0x03; + ctx->docstr[length - 2] = 0x03; // null terminate - docstr[length - 1] = 0x00; + ctx->docstr[length - 1] = 0x00; } - docstr_start = docstr; + ctx->docstr_start = ctx->docstr; } %% @@ -166,32 +169,32 @@ start: sentence_root cmd_token_seq { // tack on the command element - terminate_graph (graph, currnode, el); + terminate_graph (ctx, ctx->currnode); } | sentence_root cmd_token_seq placeholder_token '.' '.' '.' { - if ((currnode = add_edge_dedup (currnode, $3)) != $3) - graph_delete_node (graph, $3); + if ((ctx->currnode = add_edge_dedup (ctx->currnode, $3)) != $3) + graph_delete_node (ctx->graph, $3); // adding a node as a child of itself accepts any number // of the same token, which is what we want for variadics - add_edge_dedup (currnode, currnode); + add_edge_dedup (ctx->currnode, ctx->currnode); // tack on the command element - terminate_graph (graph, currnode, el); + terminate_graph (ctx, ctx->currnode); } ; sentence_root: WORD { struct graph_node *root = - new_token_node (graph, WORD_TKN, el->attr, strdup ($1), doc_next(el)); + new_token_node (ctx, WORD_TKN, strdup ($1), doc_next(ctx)); - if ((currnode = add_edge_dedup (startnode, root)) != root) - graph_delete_node (graph, root); + if ((ctx->currnode = add_edge_dedup (ctx->startnode, root)) != root) + graph_delete_node (ctx->graph, root); free ($1); - $$ = currnode; + $$ = ctx->currnode; } ; @@ -203,13 +206,13 @@ cmd_token_seq: cmd_token: simple_token { - if ((currnode = add_edge_dedup (currnode, $1)) != $1) - graph_delete_node (graph, $1); + if ((ctx->currnode = add_edge_dedup (ctx->currnode, $1)) != $1) + graph_delete_node (ctx->graph, $1); } | compound_token { - graph_add_edge (currnode, $1->start); - currnode = $1->end; + graph_add_edge (ctx->currnode, $1->start); + ctx->currnode = $1->end; free ($1); } ; @@ -226,7 +229,7 @@ compound_token: literal_token: WORD { - $$ = new_token_node (graph, WORD_TKN, el->attr, strdup($1), doc_next(el)); + $$ = new_token_node (ctx, WORD_TKN, strdup($1), doc_next(ctx)); free ($1); } ; @@ -234,32 +237,32 @@ literal_token: WORD placeholder_token: IPV4 { - $$ = new_token_node (graph, IPV4_TKN, el->attr, strdup($1), doc_next(el)); + $$ = new_token_node (ctx, IPV4_TKN, strdup($1), doc_next(ctx)); free ($1); } | IPV4_PREFIX { - $$ = new_token_node (graph, IPV4_PREFIX_TKN, el->attr, strdup($1), doc_next(el)); + $$ = new_token_node (ctx, IPV4_PREFIX_TKN, strdup($1), doc_next(ctx)); free ($1); } | IPV6 { - $$ = new_token_node (graph, IPV6_TKN, el->attr, strdup($1), doc_next(el)); + $$ = new_token_node (ctx, IPV6_TKN, strdup($1), doc_next(ctx)); free ($1); } | IPV6_PREFIX { - $$ = new_token_node (graph, IPV6_PREFIX_TKN, el->attr, strdup($1), doc_next(el)); + $$ = new_token_node (ctx, IPV6_PREFIX_TKN, strdup($1), doc_next(ctx)); free ($1); } | VARIABLE { - $$ = new_token_node (graph, VARIABLE_TKN, el->attr, strdup($1), doc_next(el)); + $$ = new_token_node (ctx, VARIABLE_TKN, strdup($1), doc_next(ctx)); free ($1); } | RANGE { - $$ = new_token_node (graph, RANGE_TKN, el->attr, strdup($1), doc_next(el)); + $$ = new_token_node (ctx, RANGE_TKN, strdup($1), doc_next(ctx)); struct cmd_token *token = $$->data; // get the numbers out @@ -269,7 +272,7 @@ placeholder_token: token->max = strtoll (yylval.string, &yylval.string, 10); // validate range - if (token->min > token->max) yyerror (graph, el, "Invalid range."); + if (token->min > token->max) yyerror (ctx, "Invalid range."); free ($1); } @@ -278,8 +281,8 @@ placeholder_token: selector: '<' selector_seq_seq '>' { $$ = malloc (sizeof (struct subgraph)); - $$->start = new_token_node (graph, SELECTOR_TKN, el->attr, NULL, NULL); - $$->end = new_token_node (graph, NUL_TKN, el->attr, NULL, NULL); + $$->start = new_token_node (ctx, SELECTOR_TKN, NULL, NULL); + $$->end = new_token_node (ctx, NUL_TKN, NULL, NULL); for (unsigned int i = 0; i < vector_active ($2->start->to); i++) { struct graph_node *sn = vector_slot ($2->start->to, i), @@ -287,8 +290,8 @@ selector: '<' selector_seq_seq '>' graph_add_edge ($$->start, sn); graph_add_edge (en, $$->end); } - graph_delete_node (graph, $2->start); - graph_delete_node (graph, $2->end); + graph_delete_node (ctx->graph, $2->start); + graph_delete_node (ctx->graph, $2->end); free ($2); }; @@ -296,8 +299,8 @@ selector_seq_seq: selector_seq_seq '|' selector_token_seq { $$ = malloc (sizeof (struct subgraph)); - $$->start = graph_new_node (graph, NULL, NULL); - $$->end = graph_new_node (graph, NULL, NULL); + $$->start = graph_new_node (ctx->graph, NULL, NULL); + $$->end = graph_new_node (ctx->graph, NULL, NULL); // link in last sequence graph_add_edge ($$->start, $3->start); @@ -310,16 +313,16 @@ selector_seq_seq: graph_add_edge ($$->start, sn); graph_add_edge (en, $$->end); } - graph_delete_node (graph, $1->start); - graph_delete_node (graph, $1->end); + graph_delete_node (ctx->graph, $1->start); + graph_delete_node (ctx->graph, $1->end); free ($1); free ($3); } | selector_token_seq '|' selector_token_seq { $$ = malloc (sizeof (struct subgraph)); - $$->start = graph_new_node (graph, NULL, NULL); - $$->end = graph_new_node (graph, NULL, NULL); + $$->start = graph_new_node (ctx->graph, NULL, NULL); + $$->end = graph_new_node (ctx->graph, NULL, NULL); graph_add_edge ($$->start, $1->start); graph_add_edge ($1->end, $$->end); graph_add_edge ($$->start, $3->start); @@ -361,8 +364,8 @@ option: '[' option_token_seq ']' { // make a new option $$ = malloc (sizeof (struct subgraph)); - $$->start = new_token_node (graph, OPTION_TKN, el->attr, NULL, NULL); - $$->end = new_token_node (graph, NUL_TKN, el->attr, NULL, NULL); + $$->start = new_token_node (ctx, OPTION_TKN, NULL, NULL); + $$->end = new_token_node (ctx, NUL_TKN, NULL, NULL); // add a path through the sequence to the end graph_add_edge ($$->start, $2->start); graph_add_edge ($2->end, $$->end); @@ -399,69 +402,70 @@ option_token: void command_parse_format (struct graph *graph, struct cmd_element *cmd) { + struct parser_ctx ctx = { .graph = graph, .el = cmd }; + // set to 1 to enable parser traces yydebug = 0; // parse command into DFA - yyparse (graph, cmd); + yyparse (&ctx); // cleanup - cleanup (); + cleanup (&ctx); } /* parser helper functions */ void -yyerror (struct graph *graph, struct cmd_element *el, char const *msg) +yyerror (struct parser_ctx *ctx, char const *msg) { zlog_err ("%s: FATAL parse error: %s", __func__, msg); - zlog_err ("while parsing this command definition: \n\t%s\n", el->string); + zlog_err ("while parsing this command definition: \n\t%s\n", ctx->el->string); //exit(EXIT_FAILURE); } static void -cleanup() +cleanup (struct parser_ctx *ctx) { /* free resources */ - free (docstr_start); + free (ctx->docstr_start); /* cleanup lexer */ cleanup_lexer (); /* clear state pointers */ - currnode = NULL; - docstr_start = docstr = NULL; + ctx->currnode = NULL; + ctx->docstr_start = ctx->docstr = NULL; } static void -terminate_graph (struct graph *graph, struct graph_node *finalnode, - struct cmd_element *element) +terminate_graph (struct parser_ctx *ctx, struct graph_node *finalnode) { // end of graph should look like this // * -> finalnode -> END_TKN -> cmd_element + struct cmd_element *element = ctx->el; struct graph_node *end_token_node = - new_token_node (graph, + new_token_node (ctx, END_TKN, - element->attr, strdup (CMD_CR_TEXT), strdup ("")); struct graph_node *end_element_node = - graph_new_node (graph, element, (void (*)(void *)) &del_cmd_element); + graph_new_node (ctx->graph, element, (void (*)(void *)) &del_cmd_element); if (node_adjacent (finalnode, end_token_node)) - yyerror (graph, element, "Duplicate command."); + yyerror (ctx, "Duplicate command."); graph_add_edge (finalnode, end_token_node); graph_add_edge (end_token_node, end_element_node); } static char * -doc_next (struct cmd_element *el) +doc_next (struct parser_ctx *ctx) { - const char *piece = docstr ? strsep (&docstr, "\n") : ""; + const char *piece = ctx->docstr ? strsep (&ctx->docstr, "\n") : ""; if (*piece == 0x03) { - zlog_debug ("Ran out of docstring while parsing '%s'", el->string); + zlog_debug ("Ran out of docstring while parsing '%s'", ctx->el->string); piece = ""; } @@ -469,11 +473,11 @@ doc_next (struct cmd_element *el) } static struct graph_node * -new_token_node (struct graph *graph, enum cmd_token_type type, - u_char attr, char *text, char *doc) +new_token_node (struct parser_ctx *ctx, enum cmd_token_type type, + char *text, char *doc) { - struct cmd_token *token = new_cmd_token (type, attr, text, doc); - return graph_new_node (graph, token, (void (*)(void *)) &del_cmd_token); + struct cmd_token *token = new_cmd_token (type, ctx->el->attr, text, doc); + return graph_new_node (ctx->graph, token, (void (*)(void *)) &del_cmd_token); } /** From e9484f70b21ed49d0ca6dbf2899b3a6306ffd2e9 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 16 Nov 2016 15:03:51 +0900 Subject: [PATCH 6/9] lib: parser: use reentrant mode on flex & bison This removes remaining global variables from the lexer, pushing the lexer state into struct parser_ctx too. At the same time, "cmd_yy" is used as prefix for all parser & lexer routines. The result is that (a) there is no collision anymore if a program uses flex/bison and links libzebra, and (b) the parser is fully encapsulated and could be called in parallel from multiple threads. Signed-off-by: David Lamparter --- lib/command_lex.l | 38 +++++++++++++++++++--------------- lib/command_parse.y | 50 ++++++++++++++++++++++++++------------------- 2 files changed, 50 insertions(+), 38 deletions(-) diff --git a/lib/command_lex.l b/lib/command_lex.l index 5c709dce22..e978803b22 100644 --- a/lib/command_lex.l +++ b/lib/command_lex.l @@ -24,10 +24,7 @@ %{ #include "command_parse.h" - -extern void set_lexer_string (const char *); -extern void cleanup_lexer (void); -YY_BUFFER_STATE buffer; +#define YYSTYPE CMD_YYSTYPE %} WORD (\-|\+)?[a-z\*][-+_a-zA-Z0-9\*]* @@ -45,27 +42,34 @@ RANGE \({NUMBER}[ ]?\-[ ]?{NUMBER}\) %option nounput %option noinput %option outfile="command_lex.c" +%option header-file="command_lex.h" +%option prefix="cmd_yy" +%option reentrant +%option bison-bridge %% [ /t] /* ignore whitespace */; -{WORD} {yylval.string = XSTRDUP(MTYPE_TMP, yytext); return WORD;} -{IPV4} {yylval.string = XSTRDUP(MTYPE_TMP, yytext); return IPV4;} -{IPV4_PREFIX} {yylval.string = XSTRDUP(MTYPE_TMP, yytext); return IPV4_PREFIX;} -{IPV6} {yylval.string = XSTRDUP(MTYPE_TMP, yytext); return IPV6;} -{IPV6_PREFIX} {yylval.string = XSTRDUP(MTYPE_TMP, yytext); return IPV6_PREFIX;} -{VARIABLE} {yylval.string = XSTRDUP(MTYPE_TMP, yytext); return VARIABLE;} -{RANGE} {yylval.string = XSTRDUP(MTYPE_TMP, yytext); return RANGE;} +{WORD} {yylval->string = XSTRDUP(MTYPE_TMP, yytext); return WORD;} +{IPV4} {yylval->string = XSTRDUP(MTYPE_TMP, yytext); return IPV4;} +{IPV4_PREFIX} {yylval->string = XSTRDUP(MTYPE_TMP, yytext); return IPV4_PREFIX;} +{IPV6} {yylval->string = XSTRDUP(MTYPE_TMP, yytext); return IPV6;} +{IPV6_PREFIX} {yylval->string = XSTRDUP(MTYPE_TMP, yytext); return IPV6_PREFIX;} +{VARIABLE} {yylval->string = XSTRDUP(MTYPE_TMP, yytext); return VARIABLE;} +{RANGE} {yylval->string = XSTRDUP(MTYPE_TMP, yytext); return RANGE;} . {return yytext[0];} %% -void -set_lexer_string (const char *string) +YY_BUFFER_STATE buffer; + +void set_lexer_string (yyscan_t *scn, const char *string) { - buffer = yy_scan_string (string); + *scn = NULL; + yylex_init(scn); + buffer = yy_scan_string (string, *scn); } -void -cleanup_lexer () +void cleanup_lexer (yyscan_t *scn) { - yy_delete_buffer (buffer); + // yy_delete_buffer (buffer, *scn); + yylex_destroy(*scn); } diff --git a/lib/command_parse.y b/lib/command_parse.y index aac4a74666..d084ddd73f 100644 --- a/lib/command_parse.y +++ b/lib/command_parse.y @@ -23,10 +23,18 @@ */ %{ + +typedef union CMD_YYSTYPE CMD_YYSTYPE; +#define YYSTYPE CMD_YYSTYPE +#include "command_lex.h" + // compile with debugging facilities #define YYDEBUG 1 %} +%define api.pure full +%define api.prefix {cmd_yy} + /* names for generated header and parser files */ %defines "command_parse.h" %output "command_parse.c" @@ -39,16 +47,9 @@ #include "log.h" #include "graph.h" - extern int - yylex (void); - - extern void - set_lexer_string (const char *); - - extern void - cleanup_lexer (void); - struct parser_ctx { + yyscan_t scanner; + struct cmd_element *el; struct graph *graph; @@ -61,7 +62,6 @@ /* functionality this unit exports */ %code provides { - /* maximum length of a number, lexer will not match anything longer */ #define DECIMAL_STRLEN_MAX 20 } @@ -99,9 +99,13 @@ %type compound_token %code { + + extern void set_lexer_string (yyscan_t *scn, const char *string); + extern void cleanup_lexer (yyscan_t *scn); + /* bison declarations */ void - yyerror (struct parser_ctx *ctx, char const *msg); + cmd_yyerror (struct parser_ctx *ctx, char const *msg); /* subgraph semantic value */ struct subgraph { @@ -133,10 +137,13 @@ static void cleanup (struct parser_ctx *ctx); + + #define scanner ctx->scanner } /* yyparse parameters */ -%parse-param { struct parser_ctx *ctx } +%lex-param {yyscan_t scanner} +%parse-param {struct parser_ctx *ctx} /* called automatically before yyparse */ %initial-action { @@ -145,9 +152,6 @@ ctx->startnode = vector_slot (ctx->graph->nodes, 0); - /* set string to parse */ - set_lexer_string (ctx->el->string); - /* copy docstring and keep a pointer to the copy */ if (ctx->el->doc) { @@ -272,7 +276,7 @@ placeholder_token: token->max = strtoll (yylval.string, &yylval.string, 10); // validate range - if (token->min > token->max) yyerror (ctx, "Invalid range."); + if (token->min > token->max) cmd_yyerror (ctx, "Invalid range."); free ($1); } @@ -399,6 +403,8 @@ option_token: %% +#undef scanner + void command_parse_format (struct graph *graph, struct cmd_element *cmd) { @@ -407,8 +413,13 @@ command_parse_format (struct graph *graph, struct cmd_element *cmd) // set to 1 to enable parser traces yydebug = 0; + set_lexer_string (&ctx.scanner, cmd->string); + // parse command into DFA - yyparse (&ctx); + cmd_yyparse (&ctx); + + /* cleanup lexer */ + cleanup_lexer (&ctx.scanner); // cleanup cleanup (&ctx); @@ -430,9 +441,6 @@ cleanup (struct parser_ctx *ctx) /* free resources */ free (ctx->docstr_start); - /* cleanup lexer */ - cleanup_lexer (); - /* clear state pointers */ ctx->currnode = NULL; ctx->docstr_start = ctx->docstr = NULL; @@ -453,7 +461,7 @@ terminate_graph (struct parser_ctx *ctx, struct graph_node *finalnode) graph_new_node (ctx->graph, element, (void (*)(void *)) &del_cmd_element); if (node_adjacent (finalnode, end_token_node)) - yyerror (ctx, "Duplicate command."); + cmd_yyerror (ctx, "Duplicate command."); graph_add_edge (finalnode, end_token_node); graph_add_edge (end_token_node, end_element_node); From b5a1e9ef5c7b1e505e6d82ea9c542748005afe63 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 23 Nov 2016 12:06:34 +0100 Subject: [PATCH 7/9] lib: remove misleading copy/del_cmd_element struct cmd_element items are static global variables, they are never allocated, copied or freed. Signed-off-by: David Lamparter --- lib/command.c | 21 --------------------- lib/command.h | 6 ------ lib/command_parse.y | 2 +- 3 files changed, 1 insertion(+), 28 deletions(-) diff --git a/lib/command.c b/lib/command.c index 3ad0ca92d7..85053aaa8a 100644 --- a/lib/command.c +++ b/lib/command.c @@ -2445,27 +2445,6 @@ copy_cmd_token (struct cmd_token *token) return copy; } -void -del_cmd_element(struct cmd_element *cmd) -{ - if (!cmd) return; - free ((char *) cmd->string); - free ((char *) cmd->doc); - free (cmd); -} - -struct cmd_element * -copy_cmd_element(const struct cmd_element *cmd) -{ - struct cmd_element *el = XMALLOC(MTYPE_CMD_TOKENS, sizeof (struct cmd_element)); - el->string = cmd->string ? XSTRDUP(MTYPE_CMD_TOKENS, cmd->string) : NULL; - el->func = cmd->func; - el->doc = cmd->doc ? XSTRDUP(MTYPE_CMD_TOKENS, cmd->doc) : NULL; - el->daemon = cmd->daemon; - el->attr = cmd->attr; - return el; -} - void cmd_terminate () { diff --git a/lib/command.h b/lib/command.h index c9b3440b02..ba6fd9b7b0 100644 --- a/lib/command.h +++ b/lib/command.h @@ -417,12 +417,6 @@ extern void cmd_terminate (void); extern void cmd_exit (struct vty *vty); extern int cmd_list_cmds (struct vty *vty, int do_permute); -/* memory management for cmd_element */ -void -del_cmd_element(struct cmd_element *); -struct cmd_element * -copy_cmd_element(const struct cmd_element *cmd); - /* memory management for cmd_token */ struct cmd_token * new_cmd_token (enum cmd_token_type, u_char attr, char *, char *); diff --git a/lib/command_parse.y b/lib/command_parse.y index d084ddd73f..a5e582c73b 100644 --- a/lib/command_parse.y +++ b/lib/command_parse.y @@ -458,7 +458,7 @@ terminate_graph (struct parser_ctx *ctx, struct graph_node *finalnode) strdup (CMD_CR_TEXT), strdup ("")); struct graph_node *end_element_node = - graph_new_node (ctx->graph, element, (void (*)(void *)) &del_cmd_element); + graph_new_node (ctx->graph, element, NULL); if (node_adjacent (finalnode, end_token_node)) cmd_yyerror (ctx, "Duplicate command."); From d6c9cdd0ddc0eff9cd320ce887bf6f8e822bfaac Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Fri, 2 Dec 2016 18:26:10 +0000 Subject: [PATCH 8/9] lib: Add back prototypes for lexer helper funcs Signed-off-by: Quentin Young --- lib/command_parse.y | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/command_parse.y b/lib/command_parse.y index a5e582c73b..339e6be8f9 100644 --- a/lib/command_parse.y +++ b/lib/command_parse.y @@ -58,6 +58,9 @@ typedef union CMD_YYSTYPE CMD_YYSTYPE; /* pointers to copy of command docstring */ char *docstr_start, *docstr; }; + + extern void set_lexer_string (yyscan_t *scn, const char *string); + extern void cleanup_lexer (yyscan_t *scn); } /* functionality this unit exports */ @@ -100,9 +103,6 @@ typedef union CMD_YYSTYPE CMD_YYSTYPE; %code { - extern void set_lexer_string (yyscan_t *scn, const char *string); - extern void cleanup_lexer (yyscan_t *scn); - /* bison declarations */ void cmd_yyerror (struct parser_ctx *ctx, char const *msg); From 54c5dce6a5e46717ad52c80f2dc99fc36a372e28 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Fri, 2 Dec 2016 18:26:47 +0000 Subject: [PATCH 9/9] lib: Macroize CLI matcher tracing Signed-off-by: Quentin Young --- lib/command_match.c | 71 ++++++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 33 deletions(-) diff --git a/lib/command_match.c b/lib/command_match.c index d4996f634d..25309654f3 100644 --- a/lib/command_match.c +++ b/lib/command_match.c @@ -27,6 +27,15 @@ #include "command_match.h" #include "memory.h" +#ifdef TRACE_MATCHER +#define TM 1 +#else +#define TM 0 +#endif + +#define trace_matcher(...) \ + do { if (TM) fprintf (stderr, __VA_ARGS__); } while (0); + DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command Tokens") /* matcher helper prototypes */ @@ -115,12 +124,12 @@ command_match (struct graph *cmdgraph, assert (*el); } -#ifdef TRACE_MATCHER - if (!*el) - fprintf (stdout, "No match\n"); - else - fprintf (stdout, "Matched command\n->string %s\n->desc %s\n", (*el)->string, (*el)->doc); -#endif + if (!*el) { + trace_matcher ("No match"); + } + else { + trace_matcher ("Matched command\n->string %s\n->desc %s\n", (*el)->string, (*el)->doc); + } // free the leader token we alloc'd XFREE (MTYPE_TMP, vector_slot (vvline, 0)); @@ -193,28 +202,26 @@ command_match_r (struct graph_node *start, vector vline, unsigned int n) // get the current operating input token char *input_token = vector_slot (vline, n); -#ifdef TRACE_MATCHER - fprintf (stdout, "\"%-20s\" matches \"%-30s\" ? ", input_token, token->text); + trace_matcher ("\"%-20s\" matches \"%-30s\" ? ", input_token, token->text); enum match_type mt = match_token (token, input_token); - fprintf (stdout, "min: %d - ", minmatch); + trace_matcher ("min: %d - ", minmatch); switch (mt) { case trivial_match: - fprintf (stdout, "trivial_match "); + trace_matcher ("trivial_match "); break; case no_match: - fprintf (stdout, "no_match "); + trace_matcher ("no_match "); break; case partly_match: - fprintf (stdout, "partly_match "); + trace_matcher ("partly_match "); break; case exact_match: - fprintf (stdout, "exact_match "); + trace_matcher ("exact_match "); break; } - if (mt >= minmatch) fprintf (stdout, " MATCH"); - fprintf (stdout, "\n"); -#endif + if (mt >= minmatch) { trace_matcher (" MATCH") }; + trace_matcher ("\n"); // if we don't match this node, die if (match_token (token, input_token) < minmatch) @@ -344,37 +351,35 @@ command_complete (struct graph *graph, continue; enum match_type minmatch = min_match_level (token->type); -#ifdef TRACE_MATCHER - fprintf (stdout, "\"%s\" matches \"%s\" (%d) ? ", input_token, token->text, token->type); -#endif + trace_matcher ("\"%s\" matches \"%s\" (%d) ? ", input_token, token->text, token->type); switch (match_token (token, input_token)) { case trivial_match: -#ifdef TRACE_MATCHER - fprintf (stdout, "trivial_match\n"); -#endif + trace_matcher ("trivial_match\n"); + assert(idx == vector_active (vline) - 1); + listnode_add (next, gn); + break; case partly_match: -#ifdef TRACE_MATCHER - fprintf (stdout, "partly_match\n"); -#endif + trace_matcher ("partly_match\n"); + // last token on line is partial and + // not a space if (idx == vector_active (vline) - 1) { listnode_add (next, gn); break; } - if (minmatch > partly_match) - break; + if (minmatch <= partly_match) + add_nexthops (next, gn); + + break; case exact_match: -#ifdef TRACE_MATCHER - fprintf (stdout, "exact_match\n"); -#endif + trace_matcher ("exact_match\n"); add_nexthops (next, gn); + listnode_add (next, gn); break; default: -#ifdef TRACE_MATCHER - fprintf (stdout, "no_match\n"); -#endif + trace_matcher ("no_match\n"); break; } }