aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2014-06-25 11:54:52 +0300
committerTimo Teräs <timo.teras@iki.fi>2014-06-25 11:56:25 +0300
commit18ea80fb4ac96d340e2de9b1a3ec730dcea0b0ba (patch)
tree1d66e8ec8cba4859cf7833d56728df7f3033cea1
parent912433c5facc905a7ef866e272eb0f7704186ea7 (diff)
downloadaports-18ea80fb4ac96d340e2de9b1a3ec730dcea0b0ba.tar.bz2
aports-18ea80fb4ac96d340e2de9b1a3ec730dcea0b0ba.tar.xz
main/quagga: upgrade to 0.99.23
remove patches present in upstream
-rw-r--r--main/quagga/0001-vtysh-don-t-append-superflous-spaces-BZ-750.patch50
-rw-r--r--main/quagga/0002-bgpd-ospfd-zebra-fix-some-DEFUN-definitions.patch362
-rw-r--r--main/quagga/0003-lib-rewrite-command-matching.patch2979
-rw-r--r--main/quagga/APKBUILD32
-rw-r--r--main/quagga/musl-fix-headers.patch10
-rw-r--r--main/quagga/quagga-readline-6.3.patch14
6 files changed, 8 insertions, 3439 deletions
diff --git a/main/quagga/0001-vtysh-don-t-append-superflous-spaces-BZ-750.patch b/main/quagga/0001-vtysh-don-t-append-superflous-spaces-BZ-750.patch
deleted file mode 100644
index 610e96aacb..0000000000
--- a/main/quagga/0001-vtysh-don-t-append-superflous-spaces-BZ-750.patch
+++ /dev/null
@@ -1,50 +0,0 @@
-From 67e7a2127c05a8c7dfddd7ffc6378edf6b666d55 Mon Sep 17 00:00:00 2001
-From: Christian Franke <chris@opensourcerouting.org>
-Date: Mon, 4 Mar 2013 09:23:30 +0000
-Subject: [PATCH] vtysh: don't append superflous spaces (BZ#750)
-
-rl_completion_append_character is reset to space every time the completion
-function is entered. So we would have to set it to '\0' every time
-new_completion() is called. We can make this conditional and avoid using
-rl_pending_input.
-
-This code path is most relevant when there are multiple completion
-matches with the same prefix, e.g. in router bgp context: "neighbor 1.2.3.4
-pa"<ssive|ssword> would have been completed to "neighbor 1.2.3.4 pass "
-instead of "neighbor 1.2.3.4 pass".
-
-Signed-off-by: Christian Franke <chris@opensourcerouting.org>
-Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
----
- vtysh/vtysh.c | 8 +++-----
- 1 file changed, 3 insertions(+), 5 deletions(-)
-
-diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
-index e3709e0..c575902 100644
---- a/vtysh/vtysh.c
-+++ b/vtysh/vtysh.c
-@@ -677,8 +677,9 @@ new_completion (char *text, int start, int end)
- if (matches)
- {
- rl_point = rl_end;
-- if (complete_status == CMD_COMPLETE_FULL_MATCH)
-- rl_pending_input = ' ';
-+ if (complete_status != CMD_COMPLETE_FULL_MATCH)
-+ /* only append a space on full match */
-+ rl_completion_append_character = '\0';
- }
-
- return matches;
-@@ -2214,9 +2215,6 @@ vtysh_readline_init (void)
- rl_bind_key ('?', (Function *) vtysh_rl_describe);
- rl_completion_entry_function = vtysh_completion_entry_function;
- rl_attempted_completion_function = (CPPFunction *)new_completion;
-- /* do not append space after completion. It will be appended
-- * in new_completion() function explicitly. */
-- rl_completion_append_character = '\0';
- }
-
- char *
---
-1.9.2
-
diff --git a/main/quagga/0002-bgpd-ospfd-zebra-fix-some-DEFUN-definitions.patch b/main/quagga/0002-bgpd-ospfd-zebra-fix-some-DEFUN-definitions.patch
deleted file mode 100644
index f326fbed5c..0000000000
--- a/main/quagga/0002-bgpd-ospfd-zebra-fix-some-DEFUN-definitions.patch
+++ /dev/null
@@ -1,362 +0,0 @@
-From 2b00515a9b639fd1e057f3ebf10ded2dde920764 Mon Sep 17 00:00:00 2001
-From: Christian Franke <chris@opensourcerouting.org>
-Date: Mon, 30 Sep 2013 12:27:49 +0000
-Subject: [PATCH] bgpd, ospfd, zebra: fix some DEFUN definitions
-
-Fixup some DEFUNS with incorrect command strings or mixed up helpstrings.
-
-Signed-off-by: Christian Franke <chris@opensourcerouting.org>
-Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
----
- bgpd/bgp_route.c | 58 +++++++++++++++++++++++++++----------------------------
- ospfd/ospf_vty.c | 2 ++
- zebra/debug.c | 6 +++---
- zebra/rtadv.c | 2 +-
- zebra/zebra_vty.c | 8 ++++----
- 5 files changed, 39 insertions(+), 37 deletions(-)
-
-diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
-index fb35fab..335543e 100644
---- a/bgpd/bgp_route.c
-+++ b/bgpd/bgp_route.c
-@@ -4375,7 +4375,7 @@ ALIAS_DEPRECATED (bgp_network_mask_natural,
- "AS-Pathlimit TTL, in number of AS-Path hops\n")
- ALIAS_DEPRECATED (bgp_network_mask_natural_backdoor,
- bgp_network_mask_natural_backdoor_ttl_cmd,
-- "network A.B.C.D backdoor pathlimit (1-255>",
-+ "network A.B.C.D backdoor pathlimit <1-255>",
- "Specify a network to announce via BGP\n"
- "Network number\n"
- "Specify a BGP backdoor route\n"
-@@ -6796,7 +6796,7 @@ DEFUN (show_ip_bgp_view,
- IP_STR
- BGP_STR
- "BGP view\n"
-- "BGP view name\n")
-+ "View name\n")
- {
- struct bgp *bgp;
-
-@@ -6818,7 +6818,7 @@ DEFUN (show_ip_bgp_view_route,
- IP_STR
- BGP_STR
- "BGP view\n"
-- "BGP view name\n"
-+ "View name\n"
- "Network in the BGP routing table to display\n")
- {
- return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 0);
-@@ -6831,7 +6831,7 @@ DEFUN (show_ip_bgp_view_prefix,
- IP_STR
- BGP_STR
- "BGP view\n"
-- "BGP view name\n"
-+ "View name\n"
- "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
- {
- return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 1);
-@@ -7904,14 +7904,14 @@ DEFUN (show_bgp_view_afi_safi_community_all,
- SHOW_STR
- BGP_STR
- "BGP view\n"
-- "BGP view name\n"
-+ "View name\n"
- "Address family\n"
- #ifdef HAVE_IPV6
- "Address family\n"
- #endif
- "Address Family modifier\n"
- "Address Family modifier\n"
-- "Display routes containing communities\n")
-+ "Display routes matching the communities\n")
- {
- int afi;
- int safi;
-@@ -7945,7 +7945,7 @@ DEFUN (show_bgp_view_afi_safi_community,
- SHOW_STR
- BGP_STR
- "BGP view\n"
-- "BGP view name\n"
-+ "View name\n"
- "Address family\n"
- #ifdef HAVE_IPV6
- "Address family\n"
-@@ -7982,7 +7982,7 @@ ALIAS (show_bgp_view_afi_safi_community,
- SHOW_STR
- BGP_STR
- "BGP view\n"
-- "BGP view name\n"
-+ "View name\n"
- "Address family\n"
- #ifdef HAVE_IPV6
- "Address family\n"
-@@ -8009,7 +8009,7 @@ ALIAS (show_bgp_view_afi_safi_community,
- SHOW_STR
- BGP_STR
- "BGP view\n"
-- "BGP view name\n"
-+ "View name\n"
- "Address family\n"
- #ifdef HAVE_IPV6
- "Address family\n"
-@@ -8040,7 +8040,7 @@ ALIAS (show_bgp_view_afi_safi_community,
- SHOW_STR
- BGP_STR
- "BGP view\n"
-- "BGP view name\n"
-+ "View name\n"
- "Address family\n"
- #ifdef HAVE_IPV6
- "Address family\n"
-@@ -10198,7 +10198,7 @@ DEFUN (show_bgp_view_afi_safi_neighbor_adv_recd_routes,
- SHOW_STR
- BGP_STR
- "BGP view\n"
-- "BGP view name\n"
-+ "View name\n"
- "Address family\n"
- #ifdef HAVE_IPV6
- "Address family\n"
-@@ -10613,7 +10613,7 @@ DEFUN (show_ip_bgp_view_rsclient,
- IP_STR
- BGP_STR
- "BGP view\n"
-- "BGP view name\n"
-+ "View name\n"
- "Information about Route Server Client\n"
- NEIGHBOR_ADDR_STR)
- {
-@@ -10663,7 +10663,7 @@ DEFUN (show_bgp_view_ipv4_safi_rsclient,
- SHOW_STR
- BGP_STR
- "BGP view\n"
-- "BGP view name\n"
-+ "View name\n"
- "Address family\n"
- "Address Family modifier\n"
- "Address Family modifier\n"
-@@ -10723,7 +10723,7 @@ DEFUN (show_ip_bgp_view_rsclient_route,
- IP_STR
- BGP_STR
- "BGP view\n"
-- "BGP view name\n"
-+ "View name\n"
- "Information about Route Server Client\n"
- NEIGHBOR_ADDR_STR
- "Network in the BGP routing table to display\n")
-@@ -10795,7 +10795,7 @@ DEFUN (show_bgp_view_ipv4_safi_rsclient_route,
- SHOW_STR
- BGP_STR
- "BGP view\n"
-- "BGP view name\n"
-+ "View name\n"
- "Address family\n"
- "Address Family modifier\n"
- "Address Family modifier\n"
-@@ -10877,7 +10877,7 @@ DEFUN (show_ip_bgp_view_rsclient_prefix,
- IP_STR
- BGP_STR
- "BGP view\n"
-- "BGP view name\n"
-+ "View name\n"
- "Information about Route Server Client\n"
- NEIGHBOR_ADDR_STR
- "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
-@@ -10949,7 +10949,7 @@ DEFUN (show_bgp_view_ipv4_safi_rsclient_prefix,
- SHOW_STR
- BGP_STR
- "BGP view\n"
-- "BGP view name\n"
-+ "View name\n"
- "Address family\n"
- "Address Family modifier\n"
- "Address Family modifier\n"
-@@ -11031,7 +11031,7 @@ DEFUN (show_bgp_view_neighbor_routes,
- SHOW_STR
- BGP_STR
- "BGP view\n"
-- "BGP view name\n"
-+ "View name\n"
- "Detailed information on TCP and BGP neighbor connections\n"
- "Neighbor to display information about\n"
- "Neighbor to display information about\n"
-@@ -11057,7 +11057,7 @@ ALIAS (show_bgp_view_neighbor_routes,
- SHOW_STR
- BGP_STR
- "BGP view\n"
-- "BGP view name\n"
-+ "View name\n"
- "Address family\n"
- "Detailed information on TCP and BGP neighbor connections\n"
- "Neighbor to display information about\n"
-@@ -11070,7 +11070,7 @@ DEFUN (show_bgp_view_neighbor_damp,
- SHOW_STR
- BGP_STR
- "BGP view\n"
-- "BGP view name\n"
-+ "View name\n"
- "Detailed information on TCP and BGP neighbor connections\n"
- "Neighbor to display information about\n"
- "Neighbor to display information about\n"
-@@ -11096,7 +11096,7 @@ ALIAS (show_bgp_view_neighbor_damp,
- SHOW_STR
- BGP_STR
- "BGP view\n"
-- "BGP view name\n"
-+ "View name\n"
- "Address family\n"
- "Detailed information on TCP and BGP neighbor connections\n"
- "Neighbor to display information about\n"
-@@ -11109,7 +11109,7 @@ DEFUN (show_bgp_view_neighbor_flap,
- SHOW_STR
- BGP_STR
- "BGP view\n"
-- "BGP view name\n"
-+ "View name\n"
- "Detailed information on TCP and BGP neighbor connections\n"
- "Neighbor to display information about\n"
- "Neighbor to display information about\n"
-@@ -11135,7 +11135,7 @@ ALIAS (show_bgp_view_neighbor_flap,
- SHOW_STR
- BGP_STR
- "BGP view\n"
-- "BGP view name\n"
-+ "View name\n"
- "Address family\n"
- "Detailed information on TCP and BGP neighbor connections\n"
- "Neighbor to display information about\n"
-@@ -11246,7 +11246,7 @@ DEFUN (show_bgp_view_rsclient,
- SHOW_STR
- BGP_STR
- "BGP view\n"
-- "BGP view name\n"
-+ "View name\n"
- "Information about Route Server Client\n"
- NEIGHBOR_ADDR_STR)
- {
-@@ -11295,7 +11295,7 @@ DEFUN (show_bgp_view_ipv6_safi_rsclient,
- SHOW_STR
- BGP_STR
- "BGP view\n"
-- "BGP view name\n"
-+ "View name\n"
- "Address family\n"
- "Address Family modifier\n"
- "Address Family modifier\n"
-@@ -11354,7 +11354,7 @@ DEFUN (show_bgp_view_rsclient_route,
- SHOW_STR
- BGP_STR
- "BGP view\n"
-- "BGP view name\n"
-+ "View name\n"
- "Information about Route Server Client\n"
- NEIGHBOR_ADDR_STR
- "Network in the BGP routing table to display\n")
-@@ -11425,7 +11425,7 @@ DEFUN (show_bgp_view_ipv6_safi_rsclient_route,
- SHOW_STR
- BGP_STR
- "BGP view\n"
-- "BGP view name\n"
-+ "View name\n"
- "Address family\n"
- "Address Family modifier\n"
- "Address Family modifier\n"
-@@ -11506,7 +11506,7 @@ DEFUN (show_bgp_view_rsclient_prefix,
- SHOW_STR
- BGP_STR
- "BGP view\n"
-- "BGP view name\n"
-+ "View name\n"
- "Information about Route Server Client\n"
- NEIGHBOR_ADDR_STR
- "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
-@@ -11577,7 +11577,7 @@ DEFUN (show_bgp_view_ipv6_safi_rsclient_prefix,
- SHOW_STR
- BGP_STR
- "BGP view\n"
-- "BGP view name\n"
-+ "View name\n"
- "Address family\n"
- "Address Family modifier\n"
- "Address Family modifier\n"
-diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
-index 2ba8188..5e5a0b0 100644
---- a/ospfd/ospf_vty.c
-+++ b/ospfd/ospf_vty.c
-@@ -1976,6 +1976,8 @@ DEFUN (ospf_area_authentication_message_digest,
- ospf_area_authentication_message_digest_cmd,
- "area (A.B.C.D|<0-4294967295>) authentication message-digest",
- "OSPF area parameters\n"
-+ "OSPF area ID in IP address format\n"
-+ "OSPF area ID as a decimal value\n"
- "Enable authentication\n"
- "Use message-digest authentication\n")
- {
-diff --git a/zebra/debug.c b/zebra/debug.c
-index 7bfdb77..c3b00e0 100644
---- a/zebra/debug.c
-+++ b/zebra/debug.c
-@@ -35,8 +35,8 @@ DEFUN (show_debugging_zebra,
- show_debugging_zebra_cmd,
- "show debugging zebra",
- SHOW_STR
-- "Zebra configuration\n"
-- "Debugging information\n")
-+ "Debugging information\n"
-+ "Zebra configuration\n")
- {
- vty_out (vty, "Zebra debugging status:%s", VTY_NEWLINE);
-
-@@ -128,7 +128,7 @@ DEFUN (debug_zebra_packet_detail,
- "Debug option set for zebra packet\n"
- "Debug option set for receive packet\n"
- "Debug option set for send packet\n"
-- "Debug option set detaied information\n")
-+ "Debug option set detailed information\n")
- {
- zebra_debug_packet = ZEBRA_DEBUG_PACKET;
- if (strncmp ("send", argv[0], strlen (argv[0])) == 0)
-diff --git a/zebra/rtadv.c b/zebra/rtadv.c
-index ae5c5a1..91d7b32 100644
---- a/zebra/rtadv.c
-+++ b/zebra/rtadv.c
-@@ -1483,7 +1483,7 @@ DEFUN (no_ipv6_nd_router_preference,
-
- ALIAS (no_ipv6_nd_router_preference,
- no_ipv6_nd_router_preference_val_cmd,
-- "no ipv6 nd router-preference (high|medium|low",
-+ "no ipv6 nd router-preference (high|medium|low)",
- NO_STR
- "Interface IPv6 config commands\n"
- "Neighbor discovery\n"
-diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
-index 45928e9..f4946f4 100644
---- a/zebra/zebra_vty.c
-+++ b/zebra/zebra_vty.c
-@@ -280,9 +280,9 @@ DEFUN (ip_route_mask_flags_distance,
- "IP destination prefix mask\n"
- "IP gateway address\n"
- "IP gateway interface name\n"
-- "Distance value for this route\n"
- "Emit an ICMP unreachable when matched\n"
-- "Silently discard pkts when matched\n")
-+ "Silently discard pkts when matched\n"
-+ "Distance value for this route\n")
- {
- return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4]);
- }
-@@ -294,9 +294,9 @@ DEFUN (ip_route_mask_flags_distance2,
- "Establish static routes\n"
- "IP destination prefix\n"
- "IP destination prefix mask\n"
-- "Distance value for this route\n"
- "Emit an ICMP unreachable when matched\n"
-- "Silently discard pkts when matched\n")
-+ "Silently discard pkts when matched\n"
-+ "Distance value for this route\n")
- {
- return zebra_static_ipv4 (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3]);
- }
---
-1.9.2
-
diff --git a/main/quagga/0003-lib-rewrite-command-matching.patch b/main/quagga/0003-lib-rewrite-command-matching.patch
deleted file mode 100644
index 9cd21ddb38..0000000000
--- a/main/quagga/0003-lib-rewrite-command-matching.patch
+++ /dev/null
@@ -1,2979 +0,0 @@
-From cd40b329a2e4da882bcad0431c048c876bbeafbd Mon Sep 17 00:00:00 2001
-From: Christian Franke <chris@opensourcerouting.org>
-Date: Mon, 30 Sep 2013 12:27:51 +0000
-Subject: [PATCH] lib/command.c: rewrite command matching/parsing
-
-Add support for keyword commands.
-
-Includes new documentation for DEFUN() in lib/command.h, for preexisting
-features as well as new keyword specification.
-
-Signed-off-by: Christian Franke <chris@opensourcerouting.org>
-Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
----
- babeld/babel_main.c | 3 -
- bgpd/bgp_main.c | 3 -
- isisd/isis_main.c | 2 -
- lib/command.c | 1977 +++++++++++++++++++++++++++++++------------------
- lib/command.h | 193 ++++-
- lib/memtypes.c | 2 +-
- lib/vty.c | 54 +-
- ospf6d/ospf6_main.c | 3 -
- ospfd/ospf_main.c | 2 -
- ripd/rip_main.c | 3 -
- ripngd/ripng_main.c | 3 -
- tests/main.c | 2 -
- vtysh/vtysh.c | 22 +-
- vtysh/vtysh_main.c | 2 -
- zebra/main.c | 3 -
- zebra/test_main.c | 3 -
- 17 files changed, 1495 insertions(+), 788 deletions(-)
-
-diff --git a/babeld/babel_main.c b/babeld/babel_main.c
-index 7b1d879..529c3f2 100644
---- a/babeld/babel_main.c
-+++ b/babeld/babel_main.c
-@@ -277,9 +277,6 @@ babel_init(int argc, char **argv)
- /* this replace kernel_setup && kernel_setup_socket */
- babelz_zebra_init ();
-
-- /* Sort all installed commands. */
-- sort_node ();
--
- /* Get zebra configuration file. */
- zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
- vty_read_config (babel_config_file, babel_config_default);
-diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c
-index 1ff1ac9..1be6504 100644
---- a/bgpd/bgp_main.c
-+++ b/bgpd/bgp_main.c
-@@ -431,9 +431,6 @@ main (int argc, char **argv)
- /* BGP related initialization. */
- bgp_init ();
-
-- /* Sort CLI commands. */
-- sort_node ();
--
- /* Parse config file. */
- vty_read_config (config_file, config_default);
-
-diff --git a/isisd/isis_main.c b/isisd/isis_main.c
-index 96816eb..283b7ea 100644
---- a/isisd/isis_main.c
-+++ b/isisd/isis_main.c
-@@ -339,8 +339,6 @@ main (int argc, char **argv, char **envp)
-
- isis_zebra_init ();
-
-- sort_node ();
--
- /* parse config file */
- /* this is needed three times! because we have interfaces before the areas */
- vty_read_config (config_file, config_default);
-diff --git a/lib/command.c b/lib/command.c
-index 3b3fada..a237364 100644
---- a/lib/command.c
-+++ b/lib/command.c
-@@ -1,6 +1,8 @@
- /*
- Command interpreter routine for virtual terminal [aka TeletYpe]
- Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
-+ Copyright (C) 2013 by Open Source Routing.
-+ Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC")
-
- This file is part of GNU Zebra.
-
-@@ -35,9 +37,32 @@ Boston, MA 02111-1307, USA. */
- each daemon maintains each own cmdvec. */
- vector cmdvec = NULL;
-
--struct desc desc_cr;
-+struct cmd_token token_cr;
- char *command_cr = NULL;
-
-+enum filter_type
-+{
-+ FILTER_RELAXED,
-+ FILTER_STRICT
-+};
-+
-+enum matcher_rv
-+{
-+ MATCHER_OK,
-+ MATCHER_COMPLETE,
-+ MATCHER_INCOMPLETE,
-+ MATCHER_NO_MATCH,
-+ MATCHER_AMBIGUOUS,
-+ MATCHER_EXCEED_ARGC_MAX
-+};
-+
-+#define MATCHER_ERROR(matcher_rv) \
-+ ( (matcher_rv) == MATCHER_INCOMPLETE \
-+ || (matcher_rv) == MATCHER_NO_MATCH \
-+ || (matcher_rv) == MATCHER_AMBIGUOUS \
-+ || (matcher_rv) == MATCHER_EXCEED_ARGC_MAX \
-+ )
-+
- /* Host information structure. */
- struct host host;
-
-@@ -196,53 +221,6 @@ install_node (struct cmd_node *node,
- node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
- }
-
--/* Compare two command's string. Used in sort_node (). */
--static int
--cmp_node (const void *p, const void *q)
--{
-- const struct cmd_element *a = *(struct cmd_element * const *)p;
-- const struct cmd_element *b = *(struct cmd_element * const *)q;
--
-- return strcmp (a->string, b->string);
--}
--
--static int
--cmp_desc (const void *p, const void *q)
--{
-- const struct desc *a = *(struct desc * const *)p;
-- const struct desc *b = *(struct desc * const *)q;
--
-- return strcmp (a->cmd, b->cmd);
--}
--
--/* Sort each node's command element according to command string. */
--void
--sort_node ()
--{
-- unsigned int i, j;
-- struct cmd_node *cnode;
-- vector descvec;
-- struct cmd_element *cmd_element;
--
-- for (i = 0; i < vector_active (cmdvec); i++)
-- if ((cnode = vector_slot (cmdvec, i)) != NULL)
-- {
-- vector cmd_vector = cnode->cmd_vector;
-- qsort (cmd_vector->index, vector_active (cmd_vector),
-- sizeof (void *), cmp_node);
--
-- for (j = 0; j < vector_active (cmd_vector); j++)
-- if ((cmd_element = vector_slot (cmd_vector, j)) != NULL
-- && vector_active (cmd_element->strvec))
-- {
-- descvec = vector_slot (cmd_element->strvec,
-- vector_active (cmd_element->strvec) - 1);
-- qsort (descvec->index, vector_active (descvec),
-- sizeof (void *), cmp_desc);
-- }
-- }
--}
--
- /* Breaking up string into each command piece. I assume given
- character is separated by a space character. Return value is a
- vector which includes char ** data element. */
-@@ -312,15 +290,46 @@ cmd_free_strvec (vector v)
- vector_free (v);
- }
-
--/* Fetch next description. Used in cmd_make_descvec(). */
-+struct format_parser_state
-+{
-+ vector topvect; /* Top level vector */
-+ vector intvect; /* Intermediate level vector, used when there's
-+ * a multiple in a keyword. */
-+ vector curvect; /* current vector where read tokens should be
-+ appended. */
-+
-+ const char *string; /* pointer to command string, not modified */
-+ const char *cp; /* pointer in command string, moved along while
-+ parsing */
-+ const char *dp; /* pointer in description string, moved along while
-+ parsing */
-+
-+ int in_keyword; /* flag to remember if we are in a keyword group */
-+ int in_multiple; /* flag to remember if we are in a multiple group */
-+ int just_read_word; /* flag to remember if the last thing we red was a
-+ * real word and not some abstract token */
-+};
-+
-+static void
-+format_parser_error(struct format_parser_state *state, const char *message)
-+{
-+ int offset = state->cp - state->string + 1;
-+
-+ fprintf(stderr, "\nError parsing command: \"%s\"\n", state->string);
-+ fprintf(stderr, " %*c\n", offset, '^');
-+ fprintf(stderr, "%s at offset %d.\n", message, offset);
-+ fprintf(stderr, "This is a programming error. Check your DEFUNs etc.\n");
-+ exit(1);
-+}
-+
- static char *
--cmd_desc_str (const char **string)
-+format_parser_desc_str(struct format_parser_state *state)
- {
- const char *cp, *start;
- char *token;
- int strlen;
--
-- cp = *string;
-+
-+ cp = state->dp;
-
- if (cp == NULL)
- return NULL;
-@@ -339,132 +348,226 @@ cmd_desc_str (const char **string)
- cp++;
-
- strlen = cp - start;
-- token = XMALLOC (MTYPE_STRVEC, strlen + 1);
-+ token = XMALLOC (MTYPE_CMD_TOKENS, strlen + 1);
- memcpy (token, start, strlen);
- *(token + strlen) = '\0';
-
-- *string = cp;
-+ state->dp = cp;
-
- return token;
- }
-
--/* New string vector. */
--static vector
--cmd_make_descvec (const char *string, const char *descstr)
-+static void
-+format_parser_begin_keyword(struct format_parser_state *state)
- {
-- int multiple = 0;
-- const char *sp;
-- char *token;
-- int len;
-- const char *cp;
-- const char *dp;
-- vector allvec;
-- vector strvec = NULL;
-- struct desc *desc;
-+ struct cmd_token *token;
-+ vector keyword_vect;
-
-- cp = string;
-- dp = descstr;
-+ if (state->in_keyword
-+ || state->in_multiple)
-+ format_parser_error(state, "Unexpected '{'");
-
-- if (cp == NULL)
-- return NULL;
-+ state->cp++;
-+ state->in_keyword = 1;
-
-- allvec = vector_init (VECTOR_MIN_SIZE);
-+ token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
-+ token->type = TOKEN_KEYWORD;
-+ token->keyword = vector_init(VECTOR_MIN_SIZE);
-
-- while (1)
-- {
-- while (isspace ((int) *cp) && *cp != '\0')
-- cp++;
-+ keyword_vect = vector_init(VECTOR_MIN_SIZE);
-+ vector_set(token->keyword, keyword_vect);
-
-- if (*cp == '(')
-- {
-- multiple = 1;
-- cp++;
-- }
-- if (*cp == ')')
-- {
-- multiple = 0;
-- cp++;
-- }
-- if (*cp == '|')
-- {
-- if (! multiple)
-- {
-- fprintf (stderr, "Command parse error!: %s\n", string);
-- exit (1);
-- }
-- cp++;
-- }
--
-- while (isspace ((int) *cp) && *cp != '\0')
-- cp++;
-+ vector_set(state->curvect, token);
-+ state->curvect = keyword_vect;
-+}
-
-- if (*cp == '(')
-- {
-- multiple = 1;
-- cp++;
-- }
-+static void
-+format_parser_begin_multiple(struct format_parser_state *state)
-+{
-+ struct cmd_token *token;
-
-- if (*cp == '\0')
-- return allvec;
-+ if (state->in_keyword == 1)
-+ format_parser_error(state, "Keyword starting with '('");
-
-- sp = cp;
-+ if (state->in_multiple)
-+ format_parser_error(state, "Nested group");
-
-- while (! (isspace ((int) *cp) || *cp == '\r' || *cp == '\n' || *cp == ')' || *cp == '|') && *cp != '\0')
-- cp++;
-+ state->cp++;
-+ state->in_multiple = 1;
-+ state->just_read_word = 0;
-+
-+ token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
-+ token->type = TOKEN_MULTIPLE;
-+ token->multiple = vector_init(VECTOR_MIN_SIZE);
-
-- len = cp - sp;
-+ vector_set(state->curvect, token);
-+ if (state->curvect != state->topvect)
-+ state->intvect = state->curvect;
-+ state->curvect = token->multiple;
-+}
-
-- token = XMALLOC (MTYPE_STRVEC, len + 1);
-- memcpy (token, sp, len);
-- *(token + len) = '\0';
-+static void
-+format_parser_end_keyword(struct format_parser_state *state)
-+{
-+ if (state->in_multiple
-+ || !state->in_keyword)
-+ format_parser_error(state, "Unexpected '}'");
-
-- desc = XCALLOC (MTYPE_DESC, sizeof (struct desc));
-- desc->cmd = token;
-- desc->str = cmd_desc_str (&dp);
-+ if (state->in_keyword == 1)
-+ format_parser_error(state, "Empty keyword group");
-
-- if (multiple)
-- {
-- if (multiple == 1)
-- {
-- strvec = vector_init (VECTOR_MIN_SIZE);
-- vector_set (allvec, strvec);
-- }
-- multiple++;
-- }
-- else
-- {
-- strvec = vector_init (VECTOR_MIN_SIZE);
-- vector_set (allvec, strvec);
-- }
-- vector_set (strvec, desc);
-+ state->cp++;
-+ state->in_keyword = 0;
-+ state->curvect = state->topvect;
-+}
-+
-+static void
-+format_parser_end_multiple(struct format_parser_state *state)
-+{
-+ char *dummy;
-+
-+ if (!state->in_multiple)
-+ format_parser_error(state, "Unepexted ')'");
-+
-+ if (vector_active(state->curvect) == 0)
-+ format_parser_error(state, "Empty multiple section");
-+
-+ if (!state->just_read_word)
-+ {
-+ /* There are constructions like
-+ * 'show ip ospf database ... (self-originate|)'
-+ * in use.
-+ * The old parser reads a description string for the
-+ * word '' between |) which will never match.
-+ * Simulate this behvaior by dropping the next desc
-+ * string in such a case. */
-+
-+ dummy = format_parser_desc_str(state);
-+ XFREE(MTYPE_CMD_TOKENS, dummy);
- }
-+
-+ state->cp++;
-+ state->in_multiple = 0;
-+
-+ if (state->intvect)
-+ state->curvect = state->intvect;
-+ else
-+ state->curvect = state->topvect;
- }
-
--/* Count mandantory string vector size. This is to determine inputed
-- command has enough command length. */
--static int
--cmd_cmdsize (vector strvec)
-+static void
-+format_parser_handle_pipe(struct format_parser_state *state)
- {
-- unsigned int i;
-- int size = 0;
-- vector descvec;
-- struct desc *desc;
-+ struct cmd_token *keyword_token;
-+ vector keyword_vect;
-
-- for (i = 0; i < vector_active (strvec); i++)
-- if ((descvec = vector_slot (strvec, i)) != NULL)
-+ if (state->in_multiple)
- {
-- if ((vector_active (descvec)) == 1
-- && (desc = vector_slot (descvec, 0)) != NULL)
-- {
-- if (desc->cmd == NULL || CMD_OPTION (desc->cmd))
-- return size;
-- else
-- size++;
-- }
-- else
-- size++;
-+ state->just_read_word = 0;
-+ state->cp++;
-+ }
-+ else if (state->in_keyword)
-+ {
-+ state->in_keyword = 1;
-+ state->cp++;
-+
-+ keyword_token = vector_slot(state->topvect,
-+ vector_active(state->topvect) - 1);
-+ keyword_vect = vector_init(VECTOR_MIN_SIZE);
-+ vector_set(keyword_token->keyword, keyword_vect);
-+ state->curvect = keyword_vect;
-+ }
-+ else
-+ {
-+ format_parser_error(state, "Unexpected '|'");
-+ }
-+}
-+
-+static void
-+format_parser_read_word(struct format_parser_state *state)
-+{
-+ const char *start;
-+ int len;
-+ char *cmd;
-+ struct cmd_token *token;
-+
-+ start = state->cp;
-+
-+ while (state->cp[0] != '\0'
-+ && !strchr("\r\n(){}|", state->cp[0])
-+ && !isspace((int)state->cp[0]))
-+ state->cp++;
-+
-+ len = state->cp - start;
-+ cmd = XMALLOC(MTYPE_CMD_TOKENS, len + 1);
-+ memcpy(cmd, start, len);
-+ cmd[len] = '\0';
-+
-+ token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
-+ token->type = TOKEN_TERMINAL;
-+ token->cmd = cmd;
-+ token->desc = format_parser_desc_str(state);
-+ vector_set(state->curvect, token);
-+
-+ if (state->in_keyword == 1)
-+ state->in_keyword = 2;
-+
-+ state->just_read_word = 1;
-+}
-+
-+/**
-+ * Parse a given command format string and build a tree of tokens from
-+ * it that is suitable to be used by the command subsystem.
-+ *
-+ * @param string Command format string.
-+ * @param descstr Description string.
-+ * @return A vector of struct cmd_token representing the given command,
-+ * or NULL on error.
-+ */
-+static vector
-+cmd_parse_format(const char *string, const char *descstr)
-+{
-+ struct format_parser_state state;
-+
-+ if (string == NULL)
-+ return NULL;
-+
-+ memset(&state, 0, sizeof(state));
-+ state.topvect = state.curvect = vector_init(VECTOR_MIN_SIZE);
-+ state.cp = state.string = string;
-+ state.dp = descstr;
-+
-+ while (1)
-+ {
-+ while (isspace((int)state.cp[0]) && state.cp[0] != '\0')
-+ state.cp++;
-+
-+ switch (state.cp[0])
-+ {
-+ case '\0':
-+ if (state.in_keyword
-+ || state.in_multiple)
-+ format_parser_error(&state, "Unclosed group/keyword");
-+ return state.topvect;
-+ case '{':
-+ format_parser_begin_keyword(&state);
-+ break;
-+ case '(':
-+ format_parser_begin_multiple(&state);
-+ break;
-+ case '}':
-+ format_parser_end_keyword(&state);
-+ break;
-+ case ')':
-+ format_parser_end_multiple(&state);
-+ break;
-+ case '|':
-+ format_parser_handle_pipe(&state);
-+ break;
-+ default:
-+ format_parser_read_word(&state);
-+ }
- }
-- return size;
- }
-
- /* Return prompt character of specified node. */
-@@ -497,11 +600,8 @@ install_element (enum node_type ntype, struct cmd_element *cmd)
- }
-
- vector_set (cnode->cmd_vector, cmd);
--
-- if (cmd->strvec == NULL)
-- cmd->strvec = cmd_make_descvec (cmd->string, cmd->doc);
--
-- cmd->cmdsize = cmd_cmdsize (cmd->strvec);
-+ if (cmd->tokens == NULL)
-+ cmd->tokens = cmd_parse_format(cmd->string, cmd->doc);
- }
-
- static const unsigned char itoa64[] =
-@@ -847,9 +947,6 @@ cmd_ipv4_prefix_match (const char *str)
- static enum match_type
- cmd_ipv6_match (const char *str)
- {
-- int state = STATE_START;
-- int colons = 0, nums = 0, double_colon = 0;
-- const char *sp = NULL;
- struct sockaddr_in6 sin6_dummy;
- int ret;
-
-@@ -1056,254 +1153,700 @@ cmd_range_match (const char *range, const char *str)
- return 1;
- }
-
--/* Make completion match and return match type flag. */
- static enum match_type
--cmd_filter_by_completion (char *command, vector v, unsigned int index)
-+cmd_word_match(struct cmd_token *token,
-+ enum filter_type filter,
-+ const char *word)
- {
-- unsigned int i;
- const char *str;
-- struct cmd_element *cmd_element;
- enum match_type match_type;
-- vector descvec;
-- struct desc *desc;
-
-- match_type = no_match;
-+ str = token->cmd;
-
-- /* If command and cmd_element string does not match set NULL to vector */
-- for (i = 0; i < vector_active (v); i++)
-- if ((cmd_element = vector_slot (v, i)) != NULL)
-- {
-- if (index >= vector_active (cmd_element->strvec))
-- vector_slot (v, i) = NULL;
-- else
-- {
-- unsigned int j;
-- int matched = 0;
-+ if (filter == FILTER_RELAXED)
-+ if (!word || !strlen(word))
-+ return partly_match;
-
-- descvec = vector_slot (cmd_element->strvec, index);
--
-- for (j = 0; j < vector_active (descvec); j++)
-- if ((desc = vector_slot (descvec, j)))
-- {
-- str = desc->cmd;
--
-- if (CMD_VARARG (str))
-- {
-- if (match_type < vararg_match)
-- match_type = vararg_match;
-- matched++;
-- }
-- else if (CMD_RANGE (str))
-- {
-- if (cmd_range_match (str, command))
-- {
-- if (match_type < range_match)
-- match_type = range_match;
-+ if (!word)
-+ return no_match;
-
-- matched++;
-- }
-- }
-+ if (CMD_VARARG(str))
-+ {
-+ return vararg_match;
-+ }
-+ else if (CMD_RANGE(str))
-+ {
-+ if (cmd_range_match(str, word))
-+ return range_match;
-+ }
- #ifdef HAVE_IPV6
-- else if (CMD_IPV6 (str))
-- {
-- if (cmd_ipv6_match (command))
-- {
-- if (match_type < ipv6_match)
-- match_type = ipv6_match;
-+ else if (CMD_IPV6(str))
-+ {
-+ match_type = cmd_ipv6_match(word);
-+ if ((filter == FILTER_RELAXED && match_type != no_match)
-+ || (filter == FILTER_STRICT && match_type == exact_match))
-+ return ipv6_match;
-+ }
-+ else if (CMD_IPV6_PREFIX(str))
-+ {
-+ match_type = cmd_ipv6_prefix_match(word);
-+ if ((filter == FILTER_RELAXED && match_type != no_match)
-+ || (filter == FILTER_STRICT && match_type == exact_match))
-+ return ipv6_prefix_match;
-+ }
-+#endif /* HAVE_IPV6 */
-+ else if (CMD_IPV4(str))
-+ {
-+ match_type = cmd_ipv4_match(word);
-+ if ((filter == FILTER_RELAXED && match_type != no_match)
-+ || (filter == FILTER_STRICT && match_type == exact_match))
-+ return ipv4_match;
-+ }
-+ else if (CMD_IPV4_PREFIX(str))
-+ {
-+ match_type = cmd_ipv4_prefix_match(word);
-+ if ((filter == FILTER_RELAXED && match_type != no_match)
-+ || (filter == FILTER_STRICT && match_type == exact_match))
-+ return ipv4_prefix_match;
-+ }
-+ else if (CMD_OPTION(str) || CMD_VARIABLE(str))
-+ {
-+ return extend_match;
-+ }
-+ else
-+ {
-+ if (filter == FILTER_RELAXED && !strncmp(str, word, strlen(word)))
-+ {
-+ if (!strcmp(str, word))
-+ return exact_match;
-+ return partly_match;
-+ }
-+ if (filter == FILTER_STRICT && !strcmp(str, word))
-+ return exact_match;
-+ }
-
-- matched++;
-- }
-- }
-- else if (CMD_IPV6_PREFIX (str))
-- {
-- if (cmd_ipv6_prefix_match (command))
-- {
-- if (match_type < ipv6_prefix_match)
-- match_type = ipv6_prefix_match;
-+ return no_match;
-+}
-
-- matched++;
-- }
-- }
--#endif /* HAVE_IPV6 */
-- else if (CMD_IPV4 (str))
-- {
-- if (cmd_ipv4_match (command))
-- {
-- if (match_type < ipv4_match)
-- match_type = ipv4_match;
-+struct cmd_matcher
-+{
-+ struct cmd_element *cmd; /* The command element the matcher is using */
-+ enum filter_type filter; /* Whether to use strict or relaxed matching */
-+ vector vline; /* The tokenized commandline which is to be matched */
-+ unsigned int index; /* The index up to which matching should be done */
-
-- matched++;
-- }
-- }
-- else if (CMD_IPV4_PREFIX (str))
-- {
-- if (cmd_ipv4_prefix_match (command))
-- {
-- if (match_type < ipv4_prefix_match)
-- match_type = ipv4_prefix_match;
-- matched++;
-- }
-- }
-- else
-- /* Check is this point's argument optional ? */
-- if (CMD_OPTION (str) || CMD_VARIABLE (str))
-- {
-- if (match_type < extend_match)
-- match_type = extend_match;
-- matched++;
-- }
-- else if (strncmp (command, str, strlen (command)) == 0)
-- {
-- if (strcmp (command, str) == 0)
-- match_type = exact_match;
-- else
-- {
-- if (match_type < partly_match)
-- match_type = partly_match;
-- }
-- matched++;
-- }
-- }
-- if (!matched)
-- vector_slot (v, i) = NULL;
-- }
-+ /* If set, construct a list of matches at the position given by index */
-+ enum match_type *match_type;
-+ vector *match;
-+
-+ unsigned int word_index; /* iterating over vline */
-+};
-+
-+static int
-+push_argument(int *argc, const char **argv, const char *arg)
-+{
-+ if (!arg || !strlen(arg))
-+ arg = NULL;
-+
-+ if (!argc || !argv)
-+ return 0;
-+
-+ if (*argc >= CMD_ARGC_MAX)
-+ return -1;
-+
-+ argv[(*argc)++] = arg;
-+ return 0;
-+}
-+
-+static void
-+cmd_matcher_record_match(struct cmd_matcher *matcher,
-+ enum match_type match_type,
-+ struct cmd_token *token)
-+{
-+ if (matcher->word_index != matcher->index)
-+ return;
-+
-+ if (matcher->match)
-+ {
-+ if (!*matcher->match)
-+ *matcher->match = vector_init(VECTOR_MIN_SIZE);
-+ vector_set(*matcher->match, token);
-+ }
-+
-+ if (matcher->match_type)
-+ {
-+ if (match_type > *matcher->match_type)
-+ *matcher->match_type = match_type;
-+ }
-+}
-+
-+static int
-+cmd_matcher_words_left(struct cmd_matcher *matcher)
-+{
-+ return matcher->word_index < vector_active(matcher->vline);
-+}
-+
-+static const char*
-+cmd_matcher_get_word(struct cmd_matcher *matcher)
-+{
-+ assert(cmd_matcher_words_left(matcher));
-+
-+ return vector_slot(matcher->vline, matcher->word_index);
-+}
-+
-+static enum matcher_rv
-+cmd_matcher_match_terminal(struct cmd_matcher *matcher,
-+ struct cmd_token *token,
-+ int *argc, const char **argv)
-+{
-+ const char *word;
-+ enum match_type word_match;
-+
-+ assert(token->type == TOKEN_TERMINAL);
-+
-+ if (!cmd_matcher_words_left(matcher))
-+ {
-+ if (CMD_OPTION(token->cmd))
-+ return MATCHER_OK; /* missing optional args are NOT pushed as NULL */
-+ else
-+ return MATCHER_INCOMPLETE;
-+ }
-+
-+ word = cmd_matcher_get_word(matcher);
-+ word_match = cmd_word_match(token, matcher->filter, word);
-+ if (word_match == no_match)
-+ return MATCHER_NO_MATCH;
-+
-+ /* We have to record the input word as argument if it matched
-+ * against a variable. */
-+ if (CMD_VARARG(token->cmd)
-+ || CMD_VARIABLE(token->cmd)
-+ || CMD_OPTION(token->cmd))
-+ {
-+ if (push_argument(argc, argv, word))
-+ return MATCHER_EXCEED_ARGC_MAX;
-+ }
-+
-+ cmd_matcher_record_match(matcher, word_match, token);
-+
-+ matcher->word_index++;
-+
-+ /* A vararg token should consume all left over words as arguments */
-+ if (CMD_VARARG(token->cmd))
-+ while (cmd_matcher_words_left(matcher))
-+ {
-+ word = cmd_matcher_get_word(matcher);
-+ if (word && strlen(word))
-+ push_argument(argc, argv, word);
-+ matcher->word_index++;
- }
-- return match_type;
-+
-+ return MATCHER_OK;
- }
-
--/* Filter vector by command character with index. */
--static enum match_type
--cmd_filter_by_string (char *command, vector v, unsigned int index)
-+static enum matcher_rv
-+cmd_matcher_match_multiple(struct cmd_matcher *matcher,
-+ struct cmd_token *token,
-+ int *argc, const char **argv)
-+{
-+ enum match_type multiple_match;
-+ unsigned int multiple_index;
-+ const char *word;
-+ const char *arg;
-+ struct cmd_token *word_token;
-+ enum match_type word_match;
-+
-+ assert(token->type == TOKEN_MULTIPLE);
-+
-+ multiple_match = no_match;
-+
-+ if (!cmd_matcher_words_left(matcher))
-+ return MATCHER_INCOMPLETE;
-+
-+ word = cmd_matcher_get_word(matcher);
-+ for (multiple_index = 0;
-+ multiple_index < vector_active(token->multiple);
-+ multiple_index++)
-+ {
-+ word_token = vector_slot(token->multiple, multiple_index);
-+
-+ word_match = cmd_word_match(word_token, matcher->filter, word);
-+ if (word_match == no_match)
-+ continue;
-+
-+ cmd_matcher_record_match(matcher, word_match, word_token);
-+
-+ if (word_match > multiple_match)
-+ {
-+ multiple_match = word_match;
-+ arg = word;
-+ }
-+ /* To mimic the behavior of the old command implementation, we
-+ * tolerate any ambiguities here :/ */
-+ }
-+
-+ matcher->word_index++;
-+
-+ if (multiple_match == no_match)
-+ return MATCHER_NO_MATCH;
-+
-+ if (push_argument(argc, argv, arg))
-+ return MATCHER_EXCEED_ARGC_MAX;
-+
-+ return MATCHER_OK;
-+}
-+
-+static enum matcher_rv
-+cmd_matcher_read_keywords(struct cmd_matcher *matcher,
-+ struct cmd_token *token,
-+ vector args_vector)
- {
- unsigned int i;
-- const char *str;
-- struct cmd_element *cmd_element;
-- enum match_type match_type;
-- vector descvec;
-- struct desc *desc;
-+ unsigned long keyword_mask;
-+ unsigned int keyword_found;
-+ enum match_type keyword_match;
-+ enum match_type word_match;
-+ vector keyword_vector;
-+ struct cmd_token *word_token;
-+ const char *word;
-+ int keyword_argc;
-+ const char **keyword_argv;
-+ enum matcher_rv rv;
-+
-+ keyword_mask = 0;
-+ while (1)
-+ {
-+ if (!cmd_matcher_words_left(matcher))
-+ return MATCHER_OK;
-
-- match_type = no_match;
-+ word = cmd_matcher_get_word(matcher);
-
-- /* If command and cmd_element string does not match set NULL to vector */
-- for (i = 0; i < vector_active (v); i++)
-- if ((cmd_element = vector_slot (v, i)) != NULL)
-- {
-- /* If given index is bigger than max string vector of command,
-- set NULL */
-- if (index >= vector_active (cmd_element->strvec))
-- vector_slot (v, i) = NULL;
-- else
-- {
-- unsigned int j;
-- int matched = 0;
-+ keyword_found = -1;
-+ keyword_match = no_match;
-+ for (i = 0; i < vector_active(token->keyword); i++)
-+ {
-+ if (keyword_mask & (1 << i))
-+ continue;
-+
-+ keyword_vector = vector_slot(token->keyword, i);
-+ word_token = vector_slot(keyword_vector, 0);
-+
-+ word_match = cmd_word_match(word_token, matcher->filter, word);
-+ if (word_match == no_match)
-+ continue;
-+
-+ cmd_matcher_record_match(matcher, word_match, word_token);
-+
-+ if (word_match > keyword_match)
-+ {
-+ keyword_match = word_match;
-+ keyword_found = i;
-+ }
-+ else if (word_match == keyword_match)
-+ {
-+ if (matcher->word_index != matcher->index || args_vector)
-+ return MATCHER_AMBIGUOUS;
-+ }
-+ }
-
-- descvec = vector_slot (cmd_element->strvec, index);
-+ if (keyword_found == (unsigned int)-1)
-+ return MATCHER_NO_MATCH;
-
-- for (j = 0; j < vector_active (descvec); j++)
-- if ((desc = vector_slot (descvec, j)))
-- {
-- str = desc->cmd;
-+ matcher->word_index++;
-
-- if (CMD_VARARG (str))
-- {
-- if (match_type < vararg_match)
-- match_type = vararg_match;
-- matched++;
-- }
-- else if (CMD_RANGE (str))
-- {
-- if (cmd_range_match (str, command))
-- {
-- if (match_type < range_match)
-- match_type = range_match;
-- matched++;
-- }
-- }
--#ifdef HAVE_IPV6
-- else if (CMD_IPV6 (str))
-- {
-- if (cmd_ipv6_match (command) == exact_match)
-- {
-- if (match_type < ipv6_match)
-- match_type = ipv6_match;
-- matched++;
-- }
-- }
-- else if (CMD_IPV6_PREFIX (str))
-- {
-- if (cmd_ipv6_prefix_match (command) == exact_match)
-- {
-- if (match_type < ipv6_prefix_match)
-- match_type = ipv6_prefix_match;
-- matched++;
-- }
-- }
--#endif /* HAVE_IPV6 */
-- else if (CMD_IPV4 (str))
-- {
-- if (cmd_ipv4_match (command) == exact_match)
-- {
-- if (match_type < ipv4_match)
-- match_type = ipv4_match;
-- matched++;
-- }
-- }
-- else if (CMD_IPV4_PREFIX (str))
-- {
-- if (cmd_ipv4_prefix_match (command) == exact_match)
-- {
-- if (match_type < ipv4_prefix_match)
-- match_type = ipv4_prefix_match;
-- matched++;
-- }
-- }
-- else if (CMD_OPTION (str) || CMD_VARIABLE (str))
-- {
-- if (match_type < extend_match)
-- match_type = extend_match;
-- matched++;
-- }
-- else
-- {
-- if (strcmp (command, str) == 0)
-- {
-- match_type = exact_match;
-- matched++;
-- }
-- }
-- }
-- if (!matched)
-- vector_slot (v, i) = NULL;
-- }
-+ if (matcher->word_index > matcher->index)
-+ return MATCHER_OK;
-+
-+ keyword_mask |= (1 << keyword_found);
-+
-+ if (args_vector)
-+ {
-+ keyword_argc = 0;
-+ keyword_argv = XMALLOC(MTYPE_TMP, (CMD_ARGC_MAX + 1) * sizeof(char*));
-+ /* We use -1 as a marker for unused fields as NULL might be a valid value */
-+ for (i = 0; i < CMD_ARGC_MAX + 1; i++)
-+ keyword_argv[i] = (void*)-1;
-+ vector_set_index(args_vector, keyword_found, keyword_argv);
-+ }
-+ else
-+ {
-+ keyword_argv = NULL;
-+ }
-+
-+ keyword_vector = vector_slot(token->keyword, keyword_found);
-+ /* the keyword itself is at 0. We are only interested in the arguments,
-+ * so start counting at 1. */
-+ for (i = 1; i < vector_active(keyword_vector); i++)
-+ {
-+ word_token = vector_slot(keyword_vector, i);
-+
-+ switch (word_token->type)
-+ {
-+ case TOKEN_TERMINAL:
-+ rv = cmd_matcher_match_terminal(matcher, word_token,
-+ &keyword_argc, keyword_argv);
-+ break;
-+ case TOKEN_MULTIPLE:
-+ rv = cmd_matcher_match_multiple(matcher, word_token,
-+ &keyword_argc, keyword_argv);
-+ break;
-+ case TOKEN_KEYWORD:
-+ assert(!"Keywords should never be nested.");
-+ break;
-+ }
-+
-+ if (MATCHER_ERROR(rv))
-+ return rv;
-+
-+ if (matcher->word_index > matcher->index)
-+ return MATCHER_OK;
-+ }
-+ }
-+ /* not reached */
-+}
-+
-+static enum matcher_rv
-+cmd_matcher_build_keyword_args(struct cmd_matcher *matcher,
-+ struct cmd_token *token,
-+ int *argc, const char **argv,
-+ vector keyword_args_vector)
-+{
-+ unsigned int i, j;
-+ const char **keyword_args;
-+ vector keyword_vector;
-+ struct cmd_token *word_token;
-+ const char *arg;
-+ enum matcher_rv rv;
-+
-+ rv = MATCHER_OK;
-+
-+ if (keyword_args_vector == NULL)
-+ return rv;
-+
-+ for (i = 0; i < vector_active(token->keyword); i++)
-+ {
-+ keyword_vector = vector_slot(token->keyword, i);
-+ keyword_args = vector_lookup(keyword_args_vector, i);
-+
-+ if (vector_active(keyword_vector) == 1)
-+ {
-+ /* this is a keyword without arguments */
-+ if (keyword_args)
-+ {
-+ word_token = vector_slot(keyword_vector, 0);
-+ arg = word_token->cmd;
-+ }
-+ else
-+ {
-+ arg = NULL;
-+ }
-+
-+ if (push_argument(argc, argv, arg))
-+ rv = MATCHER_EXCEED_ARGC_MAX;
-+ }
-+ else
-+ {
-+ /* this is a keyword with arguments */
-+ if (keyword_args)
-+ {
-+ /* the keyword was present, so just fill in the arguments */
-+ for (j = 0; keyword_args[j] != (void*)-1; j++)
-+ if (push_argument(argc, argv, keyword_args[j]))
-+ rv = MATCHER_EXCEED_ARGC_MAX;
-+ XFREE(MTYPE_TMP, keyword_args);
-+ }
-+ else
-+ {
-+ /* the keyword was not present, insert NULL for the arguments
-+ * the keyword would have taken. */
-+ for (j = 1; j < vector_active(keyword_vector); j++)
-+ {
-+ word_token = vector_slot(keyword_vector, j);
-+ if ((word_token->type == TOKEN_TERMINAL
-+ && (CMD_VARARG(word_token->cmd)
-+ || CMD_VARIABLE(word_token->cmd)
-+ || CMD_OPTION(word_token->cmd)))
-+ || word_token->type == TOKEN_MULTIPLE)
-+ {
-+ if (push_argument(argc, argv, NULL))
-+ rv = MATCHER_EXCEED_ARGC_MAX;
-+ }
-+ }
-+ }
-+ }
-+ }
-+ vector_free(keyword_args_vector);
-+ return rv;
-+}
-+
-+static enum matcher_rv
-+cmd_matcher_match_keyword(struct cmd_matcher *matcher,
-+ struct cmd_token *token,
-+ int *argc, const char **argv)
-+{
-+ vector keyword_args_vector;
-+ enum matcher_rv reader_rv;
-+ enum matcher_rv builder_rv;
-+
-+ assert(token->type == TOKEN_KEYWORD);
-+
-+ if (argc && argv)
-+ keyword_args_vector = vector_init(VECTOR_MIN_SIZE);
-+ else
-+ keyword_args_vector = NULL;
-+
-+ reader_rv = cmd_matcher_read_keywords(matcher, token, keyword_args_vector);
-+ builder_rv = cmd_matcher_build_keyword_args(matcher, token, argc,
-+ argv, keyword_args_vector);
-+ /* keyword_args_vector is consumed by cmd_matcher_build_keyword_args */
-+
-+ if (!MATCHER_ERROR(reader_rv) && MATCHER_ERROR(builder_rv))
-+ return builder_rv;
-+
-+ return reader_rv;
-+}
-+
-+static void
-+cmd_matcher_init(struct cmd_matcher *matcher,
-+ struct cmd_element *cmd,
-+ enum filter_type filter,
-+ vector vline,
-+ unsigned int index,
-+ enum match_type *match_type,
-+ vector *match)
-+{
-+ memset(matcher, 0, sizeof(*matcher));
-+
-+ matcher->cmd = cmd;
-+ matcher->filter = filter;
-+ matcher->vline = vline;
-+ matcher->index = index;
-+
-+ matcher->match_type = match_type;
-+ if (matcher->match_type)
-+ *matcher->match_type = no_match;
-+ matcher->match = match;
-+
-+ matcher->word_index = 0;
-+}
-+
-+static enum matcher_rv
-+cmd_element_match(struct cmd_element *cmd_element,
-+ enum filter_type filter,
-+ vector vline,
-+ unsigned int index,
-+ enum match_type *match_type,
-+ vector *match,
-+ int *argc,
-+ const char **argv)
-+{
-+ struct cmd_matcher matcher;
-+ unsigned int token_index;
-+ enum matcher_rv rv;
-+
-+ cmd_matcher_init(&matcher, cmd_element, filter,
-+ vline, index, match_type, match);
-+
-+ if (argc != NULL)
-+ *argc = 0;
-+
-+ for (token_index = 0;
-+ token_index < vector_active(cmd_element->tokens);
-+ token_index++)
-+ {
-+ struct cmd_token *token = vector_slot(cmd_element->tokens, token_index);
-+
-+ switch (token->type)
-+ {
-+ case TOKEN_TERMINAL:
-+ rv = cmd_matcher_match_terminal(&matcher, token, argc, argv);
-+ break;
-+ case TOKEN_MULTIPLE:
-+ rv = cmd_matcher_match_multiple(&matcher, token, argc, argv);
-+ break;
-+ case TOKEN_KEYWORD:
-+ rv = cmd_matcher_match_keyword(&matcher, token, argc, argv);
-+ }
-+
-+ if (MATCHER_ERROR(rv))
-+ return rv;
-+
-+ if (matcher.word_index > index)
-+ return MATCHER_OK;
-+ }
-+
-+ /* return MATCHER_COMPLETE if all words were consumed */
-+ if (matcher.word_index >= vector_active(vline))
-+ return MATCHER_COMPLETE;
-+
-+ /* return MATCHER_COMPLETE also if only an empty word is left. */
-+ if (matcher.word_index == vector_active(vline) - 1
-+ && (!vector_slot(vline, matcher.word_index)
-+ || !strlen((char*)vector_slot(vline, matcher.word_index))))
-+ return MATCHER_COMPLETE;
-+
-+ return MATCHER_NO_MATCH; /* command is too long to match */
-+}
-+
-+/**
-+ * Filter a given vector of commands against a given commandline and
-+ * calculate possible completions.
-+ *
-+ * @param commands A vector of struct cmd_element*. Commands that don't
-+ * match against the given command line will be overwritten
-+ * with NULL in that vector.
-+ * @param filter Either FILTER_RELAXED or FILTER_STRICT. This basically
-+ * determines how incomplete commands are handled, compare with
-+ * cmd_word_match for details.
-+ * @param vline A vector of char* containing the tokenized commandline.
-+ * @param index Only match up to the given token of the commandline.
-+ * @param match_type Record the type of the best match here.
-+ * @param matches Record the matches here. For each cmd_element in the commands
-+ * vector, a match vector will be created in the matches vector.
-+ * That vector will contain all struct command_token* of the
-+ * cmd_element which matched against the given vline at the given
-+ * index.
-+ * @return A code specifying if an error occured. If all went right, it's
-+ * CMD_SUCCESS.
-+ */
-+static int
-+cmd_vector_filter(vector commands,
-+ enum filter_type filter,
-+ vector vline,
-+ unsigned int index,
-+ enum match_type *match_type,
-+ vector *matches)
-+{
-+ unsigned int i;
-+ struct cmd_element *cmd_element;
-+ enum match_type best_match;
-+ enum match_type element_match;
-+ enum matcher_rv matcher_rv;
-+
-+ best_match = no_match;
-+ *matches = vector_init(VECTOR_MIN_SIZE);
-+
-+ for (i = 0; i < vector_active (commands); i++)
-+ if ((cmd_element = vector_slot (commands, i)) != NULL)
-+ {
-+ vector_set_index(*matches, i, NULL);
-+ matcher_rv = cmd_element_match(cmd_element, filter,
-+ vline, index,
-+ &element_match,
-+ (vector*)&vector_slot(*matches, i),
-+ NULL, NULL);
-+ if (MATCHER_ERROR(matcher_rv))
-+ {
-+ vector_slot(commands, i) = NULL;
-+ if (matcher_rv == MATCHER_AMBIGUOUS)
-+ return CMD_ERR_AMBIGUOUS;
-+ if (matcher_rv == MATCHER_EXCEED_ARGC_MAX)
-+ return CMD_ERR_EXEED_ARGC_MAX;
-+ }
-+ else if (element_match > best_match)
-+ {
-+ best_match = element_match;
-+ }
- }
-- return match_type;
-+ *match_type = best_match;
-+ return CMD_SUCCESS;
-+}
-+
-+/**
-+ * Check whether a given commandline is complete if used for a specific
-+ * cmd_element.
-+ *
-+ * @param cmd_element A cmd_element against which the commandline should be
-+ * checked.
-+ * @param vline The tokenized commandline.
-+ * @return 1 if the given commandline is complete, 0 otherwise.
-+ */
-+static int
-+cmd_is_complete(struct cmd_element *cmd_element,
-+ vector vline)
-+{
-+ enum matcher_rv rv;
-+
-+ rv = cmd_element_match(cmd_element,
-+ FILTER_RELAXED,
-+ vline, -1,
-+ NULL, NULL,
-+ NULL, NULL);
-+ return (rv == MATCHER_COMPLETE);
-+}
-+
-+/**
-+ * Parse a given commandline and construct a list of arguments for the
-+ * given command_element.
-+ *
-+ * @param cmd_element The cmd_element for which we want to construct arguments.
-+ * @param vline The tokenized commandline.
-+ * @param argc Where to store the argument count.
-+ * @param argv Where to store the argument list. Should be at least
-+ * CMD_ARGC_MAX elements long.
-+ * @return CMD_SUCCESS if everything went alright, an error otherwise.
-+ */
-+static int
-+cmd_parse(struct cmd_element *cmd_element,
-+ vector vline,
-+ int *argc, const char **argv)
-+{
-+ enum matcher_rv rv = cmd_element_match(cmd_element,
-+ FILTER_RELAXED,
-+ vline, -1,
-+ NULL, NULL,
-+ argc, argv);
-+ switch (rv)
-+ {
-+ case MATCHER_COMPLETE:
-+ return CMD_SUCCESS;
-+
-+ case MATCHER_NO_MATCH:
-+ return CMD_ERR_NO_MATCH;
-+
-+ case MATCHER_AMBIGUOUS:
-+ return CMD_ERR_AMBIGUOUS;
-+
-+ case MATCHER_EXCEED_ARGC_MAX:
-+ return CMD_ERR_EXEED_ARGC_MAX;
-+
-+ default:
-+ return CMD_ERR_INCOMPLETE;
-+ }
- }
-
- /* Check ambiguous match */
- static int
--is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
-+is_cmd_ambiguous (vector cmd_vector,
-+ const char *command,
-+ vector matches,
-+ enum match_type type)
- {
- unsigned int i;
- unsigned int j;
- const char *str = NULL;
-- struct cmd_element *cmd_element;
- const char *matched = NULL;
-- vector descvec;
-- struct desc *desc;
-+ vector match_vector;
-+ struct cmd_token *cmd_token;
-
-- for (i = 0; i < vector_active (v); i++)
-- if ((cmd_element = vector_slot (v, i)) != NULL)
-+ if (command == NULL)
-+ command = "";
-+
-+ for (i = 0; i < vector_active (matches); i++)
-+ if ((match_vector = vector_slot (matches, i)) != NULL)
- {
- int match = 0;
-
-- descvec = vector_slot (cmd_element->strvec, index);
--
-- for (j = 0; j < vector_active (descvec); j++)
-- if ((desc = vector_slot (descvec, j)))
-+ for (j = 0; j < vector_active (match_vector); j++)
-+ if ((cmd_token = vector_slot (match_vector, j)) != NULL)
- {
- enum match_type ret;
--
-- str = desc->cmd;
-+
-+ assert(cmd_token->type == TOKEN_TERMINAL);
-+ if (cmd_token->type != TOKEN_TERMINAL)
-+ continue;
-+
-+ str = cmd_token->cmd;
-
- switch (type)
- {
-@@ -1371,7 +1914,7 @@ is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
- }
- }
- if (!match)
-- vector_slot (v, i) = NULL;
-+ vector_slot (cmd_vector, i) = NULL;
- }
- return 0;
- }
-@@ -1461,8 +2004,12 @@ cmd_entry_function_desc (const char *src, const char *dst)
- return NULL;
- }
-
--/* Check same string element existence. If it isn't there return
-- 1. */
-+/**
-+ * Check whether a string is already present in a vector of strings.
-+ * @param v A vector of char*.
-+ * @param str A char*.
-+ * @return 0 if str is already present in the vector, 1 otherwise.
-+ */
- static int
- cmd_unique_string (vector v, const char *str)
- {
-@@ -1476,19 +2023,25 @@ cmd_unique_string (vector v, const char *str)
- return 1;
- }
-
--/* Compare string to description vector. If there is same string
-- return 1 else return 0. */
-+/**
-+ * Check whether a struct cmd_token matching a given string is already
-+ * present in a vector of struct cmd_token.
-+ * @param v A vector of struct cmd_token*.
-+ * @param str A char* which should be searched for.
-+ * @return 0 if there is a struct cmd_token* with its cmd matching str,
-+ * 1 otherwise.
-+ */
- static int
- desc_unique_string (vector v, const char *str)
- {
- unsigned int i;
-- struct desc *desc;
-+ struct cmd_token *token;
-
- for (i = 0; i < vector_active (v); i++)
-- if ((desc = vector_slot (v, i)) != NULL)
-- if (strcmp (desc->cmd, str) == 0)
-- return 1;
-- return 0;
-+ if ((token = vector_slot (v, i)) != NULL)
-+ if (strcmp (token->cmd, str) == 0)
-+ return 0;
-+ return 1;
- }
-
- static int
-@@ -1504,6 +2057,35 @@ cmd_try_do_shortcut (enum node_type node, char* first_word) {
- return 0;
- }
-
-+static void
-+cmd_matches_free(vector *matches)
-+{
-+ unsigned int i;
-+ vector cmd_matches;
-+
-+ for (i = 0; i < vector_active(*matches); i++)
-+ if ((cmd_matches = vector_slot(*matches, i)) != NULL)
-+ vector_free(cmd_matches);
-+ vector_free(*matches);
-+ *matches = NULL;
-+}
-+
-+static int
-+cmd_describe_cmp(const void *a, const void *b)
-+{
-+ const struct cmd_token *first = *(struct cmd_token * const *)a;
-+ const struct cmd_token *second = *(struct cmd_token * const *)b;
-+
-+ return strcmp(first->cmd, second->cmd);
-+}
-+
-+static void
-+cmd_describe_sort(vector matchvec)
-+{
-+ qsort(matchvec->index, vector_active(matchvec),
-+ sizeof(void*), cmd_describe_cmp);
-+}
-+
- /* '?' describe command support. */
- static vector
- cmd_describe_command_real (vector vline, struct vty *vty, int *status)
-@@ -1517,6 +2099,8 @@ cmd_describe_command_real (vector vline, struct vty *vty, int *status)
- int ret;
- enum match_type match;
- char *command;
-+ vector matches = NULL;
-+ vector match_vector;
-
- /* Set index. */
- if (vector_active (vline) == 0)
-@@ -1524,111 +2108,121 @@ cmd_describe_command_real (vector vline, struct vty *vty, int *status)
- *status = CMD_ERR_NO_MATCH;
- return NULL;
- }
-- else
-- index = vector_active (vline) - 1;
--
-+
-+ index = vector_active (vline) - 1;
-+
- /* Make copy vector of current node's command vector. */
- cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
-
- /* Prepare match vector */
- matchvec = vector_init (INIT_MATCHVEC_SIZE);
-
-- /* Filter commands. */
-- /* Only words precedes current word will be checked in this loop. */
-- for (i = 0; i < index; i++)
-- if ((command = vector_slot (vline, i)))
-- {
-- match = cmd_filter_by_completion (command, cmd_vector, i);
--
-- if (match == vararg_match)
-- {
-- struct cmd_element *cmd_element;
-- vector descvec;
-- unsigned int j, k;
-+ /* Filter commands and build a list how they could possibly continue. */
-+ for (i = 0; i <= index; i++)
-+ {
-+ command = vector_slot (vline, i);
-
-- for (j = 0; j < vector_active (cmd_vector); j++)
-- if ((cmd_element = vector_slot (cmd_vector, j)) != NULL
-- && (vector_active (cmd_element->strvec)))
-- {
-- descvec = vector_slot (cmd_element->strvec,
-- vector_active (cmd_element->strvec) - 1);
-- for (k = 0; k < vector_active (descvec); k++)
-- {
-- struct desc *desc = vector_slot (descvec, k);
-- vector_set (matchvec, desc);
-- }
-- }
--
-- vector_set (matchvec, &desc_cr);
-- vector_free (cmd_vector);
-+ if (matches)
-+ cmd_matches_free(&matches);
-
-- return matchvec;
-- }
-+ ret = cmd_vector_filter(cmd_vector,
-+ FILTER_RELAXED,
-+ vline, i,
-+ &match,
-+ &matches);
-
-- if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
-- {
-- vector_free (cmd_vector);
-- vector_free (matchvec);
-- *status = CMD_ERR_AMBIGUOUS;
-- return NULL;
-- }
-- else if (ret == 2)
-- {
-- vector_free (cmd_vector);
-- vector_free (matchvec);
-- *status = CMD_ERR_NO_MATCH;
-- return NULL;
-- }
-- }
-+ if (ret != CMD_SUCCESS)
-+ {
-+ vector_free (cmd_vector);
-+ vector_free (matchvec);
-+ cmd_matches_free(&matches);
-+ *status = ret;
-+ return NULL;
-+ }
-
-- /* Prepare match vector */
-- /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
-+ /* The last match may well be ambigious, so break here */
-+ if (i == index)
-+ break;
-+
-+ if (match == vararg_match)
-+ {
-+ /* We found a vararg match - so we can throw out the current matches here
-+ * and don't need to continue checking the command input */
-+ unsigned int j, k;
-+
-+ for (j = 0; j < vector_active (matches); j++)
-+ if ((match_vector = vector_slot (matches, j)) != NULL)
-+ for (k = 0; k < vector_active (match_vector); k++)
-+ {
-+ struct cmd_token *token = vector_slot (match_vector, k);
-+ vector_set (matchvec, token);
-+ }
-+
-+ *status = CMD_SUCCESS;
-+ vector_set(matchvec, &token_cr);
-+ vector_free (cmd_vector);
-+ cmd_matches_free(&matches);
-+ cmd_describe_sort(matchvec);
-+ return matchvec;
-+ }
-
-- /* Make sure that cmd_vector is filtered based on current word */
-- command = vector_slot (vline, index);
-- if (command)
-- match = cmd_filter_by_completion (command, cmd_vector, index);
-+ ret = is_cmd_ambiguous(cmd_vector, command, matches, match);
-+ if (ret == 1)
-+ {
-+ vector_free (cmd_vector);
-+ vector_free (matchvec);
-+ cmd_matches_free(&matches);
-+ *status = CMD_ERR_AMBIGUOUS;
-+ return NULL;
-+ }
-+ else if (ret == 2)
-+ {
-+ vector_free (cmd_vector);
-+ vector_free (matchvec);
-+ cmd_matches_free(&matches);
-+ *status = CMD_ERR_NO_MATCH;
-+ return NULL;
-+ }
-+ }
-
- /* Make description vector. */
-- for (i = 0; i < vector_active (cmd_vector); i++)
-+ for (i = 0; i < vector_active (matches); i++)
- if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
- {
-- vector strvec = cmd_element->strvec;
-+ unsigned int j;
-+ const char *last_word;
-+ vector vline_trimmed;
-
-- /* if command is NULL, index may be equal to vector_active */
-- if (command && index >= vector_active (strvec))
-- vector_slot (cmd_vector, i) = NULL;
-- else
-- {
-- /* Check if command is completed. */
-- if (command == NULL && index == vector_active (strvec))
-- {
-- if (!desc_unique_string (matchvec, command_cr))
-- vector_set (matchvec, &desc_cr);
-- }
-- else
-- {
-- unsigned int j;
-- vector descvec = vector_slot (strvec, index);
-- struct desc *desc;
--
-- for (j = 0; j < vector_active (descvec); j++)
-- if ((desc = vector_slot (descvec, j)))
-- {
-- const char *string;
--
-- string = cmd_entry_function_desc (command, desc->cmd);
-- if (string)
-- {
-- /* Uniqueness check */
-- if (!desc_unique_string (matchvec, string))
-- vector_set (matchvec, desc);
-- }
-- }
-- }
-- }
-+ last_word = vector_slot(vline, vector_active(vline) - 1);
-+ if (last_word == NULL || !strlen(last_word))
-+ {
-+ vline_trimmed = vector_copy(vline);
-+ vector_unset(vline_trimmed, vector_active(vline_trimmed) - 1);
-+
-+ if (cmd_is_complete(cmd_element, vline_trimmed)
-+ && desc_unique_string(matchvec, command_cr))
-+ {
-+ if (match != vararg_match)
-+ vector_set(matchvec, &token_cr);
-+ }
-+
-+ vector_free(vline_trimmed);
-+ }
-+
-+ match_vector = vector_slot (matches, i);
-+ if (match_vector)
-+ for (j = 0; j < vector_active(match_vector); j++)
-+ {
-+ struct cmd_token *token = vector_slot(match_vector, j);
-+ const char *string;
-+
-+ string = cmd_entry_function_desc(command, token->cmd);
-+ if (string && desc_unique_string(matchvec, string))
-+ vector_set(matchvec, token);
-+ }
- }
- vector_free (cmd_vector);
-+ cmd_matches_free(&matches);
-
- if (vector_slot (matchvec, 0) == NULL)
- {
-@@ -1638,6 +2232,7 @@ cmd_describe_command_real (vector vline, struct vty *vty, int *status)
- }
-
- *status = CMD_SUCCESS;
-+ cmd_describe_sort(matchvec);
- return matchvec;
- }
-
-@@ -1708,6 +2303,31 @@ cmd_lcd (char **matched)
- return lcd;
- }
-
-+static int
-+cmd_complete_cmp(const void *a, const void *b)
-+{
-+ const char *first = *(char * const *)a;
-+ const char *second = *(char * const *)b;
-+
-+ if (!first)
-+ {
-+ if (!second)
-+ return 0;
-+ return 1;
-+ }
-+ if (!second)
-+ return -1;
-+
-+ return strcmp(first, second);
-+}
-+
-+static void
-+cmd_complete_sort(vector matchvec)
-+{
-+ qsort(matchvec->index, vector_active(matchvec),
-+ sizeof(void*), cmd_complete_cmp);
-+}
-+
- /* Command line completion support. */
- static char **
- cmd_complete_command_real (vector vline, struct vty *vty, int *status)
-@@ -1716,13 +2336,13 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status)
- vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
- #define INIT_MATCHVEC_SIZE 10
- vector matchvec;
-- struct cmd_element *cmd_element;
- unsigned int index;
- char **match_str;
-- struct desc *desc;
-- vector descvec;
-+ struct cmd_token *token;
- char *command;
- int lcd;
-+ vector matches = NULL;
-+ vector match_vector;
-
- if (vector_active (vline) == 0)
- {
-@@ -1733,66 +2353,80 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status)
- else
- index = vector_active (vline) - 1;
-
-- /* First, filter by preceeding command string */
-- for (i = 0; i < index; i++)
-- if ((command = vector_slot (vline, i)))
-- {
-- enum match_type match;
-- int ret;
-+ /* First, filter by command string */
-+ for (i = 0; i <= index; i++)
-+ {
-+ command = vector_slot (vline, i);
-+ enum match_type match;
-+ int ret;
-
-- /* First try completion match, if there is exactly match return 1 */
-- match = cmd_filter_by_completion (command, cmd_vector, i);
-+ if (matches)
-+ cmd_matches_free(&matches);
-
-- /* If there is exact match then filter ambiguous match else check
-- ambiguousness. */
-- if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
-- {
-- vector_free (cmd_vector);
-- *status = CMD_ERR_AMBIGUOUS;
-- return NULL;
-- }
-- /*
-+ /* First try completion match, if there is exactly match return 1 */
-+ ret = cmd_vector_filter(cmd_vector,
-+ FILTER_RELAXED,
-+ vline, i,
-+ &match,
-+ &matches);
-+
-+ if (ret != CMD_SUCCESS)
-+ {
-+ vector_free(cmd_vector);
-+ cmd_matches_free(&matches);
-+ *status = ret;
-+ return NULL;
-+ }
-+
-+ /* Break here - the completion mustn't be checked to be non-ambiguous */
-+ if (i == index)
-+ break;
-+
-+ /* If there is exact match then filter ambiguous match else check
-+ ambiguousness. */
-+ ret = is_cmd_ambiguous (cmd_vector, command, matches, match);
-+ if (ret == 1)
-+ {
-+ vector_free (cmd_vector);
-+ cmd_matches_free(&matches);
-+ *status = CMD_ERR_AMBIGUOUS;
-+ return NULL;
-+ }
-+ /*
- else if (ret == 2)
- {
- vector_free (cmd_vector);
-+ cmd_matches_free(&matches);
- *status = CMD_ERR_NO_MATCH;
- return NULL;
- }
- */
-- }
-+ }
-
- /* Prepare match vector. */
- matchvec = vector_init (INIT_MATCHVEC_SIZE);
-
-- /* Now we got into completion */
-- for (i = 0; i < vector_active (cmd_vector); i++)
-- if ((cmd_element = vector_slot (cmd_vector, i)))
-+ /* Build the possible list of continuations into a list of completions */
-+ for (i = 0; i < vector_active (matches); i++)
-+ if ((match_vector = vector_slot (matches, i)))
- {
- const char *string;
-- vector strvec = cmd_element->strvec;
--
-- /* Check field length */
-- if (index >= vector_active (strvec))
-- vector_slot (cmd_vector, i) = NULL;
-- else
-- {
-- unsigned int j;
-+ unsigned int j;
-
-- descvec = vector_slot (strvec, index);
-- for (j = 0; j < vector_active (descvec); j++)
-- if ((desc = vector_slot (descvec, j)))
-+ for (j = 0; j < vector_active (match_vector); j++)
-+ if ((token = vector_slot (match_vector, j)))
- {
- if ((string =
- cmd_entry_function (vector_slot (vline, index),
-- desc->cmd)))
-+ token->cmd)))
- if (cmd_unique_string (matchvec, string))
- vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
- }
-- }
- }
-
- /* We don't need cmd_vector any more. */
- vector_free (cmd_vector);
-+ cmd_matches_free(&matches);
-
- /* No matched command */
- if (vector_slot (matchvec, 0) == NULL)
-@@ -1832,7 +2466,7 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status)
- {
- char *lcdstr;
-
-- lcdstr = XMALLOC (MTYPE_STRVEC, lcd + 1);
-+ lcdstr = XMALLOC (MTYPE_TMP, lcd + 1);
- memcpy (lcdstr, matchvec->index[0], lcd);
- lcdstr[lcd] = '\0';
-
-@@ -1842,7 +2476,7 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status)
- for (i = 0; i < vector_active (matchvec); i++)
- {
- if (vector_slot (matchvec, i))
-- XFREE (MTYPE_STRVEC, vector_slot (matchvec, i));
-+ XFREE (MTYPE_TMP, vector_slot (matchvec, i));
- }
- vector_free (matchvec);
-
-@@ -1859,6 +2493,7 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status)
- }
-
- match_str = (char **) matchvec->index;
-+ cmd_complete_sort(matchvec);
- vector_only_wrapper_free (matchvec);
- *status = CMD_COMPLETE_LIST_MATCH;
- return match_str;
-@@ -1927,7 +2562,9 @@ node_parent ( enum node_type node )
-
- /* Execute command by argument vline vector. */
- static int
--cmd_execute_command_real (vector vline, struct vty *vty,
-+cmd_execute_command_real (vector vline,
-+ enum filter_type filter,
-+ struct vty *vty,
- struct cmd_element **cmd)
- {
- unsigned int i;
-@@ -1939,35 +2576,48 @@ cmd_execute_command_real (vector vline, struct vty *vty,
- int argc;
- const char *argv[CMD_ARGC_MAX];
- enum match_type match = 0;
-- int varflag;
- char *command;
-+ int ret;
-+ vector matches;
-
- /* Make copy of command elements. */
- cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
-
- for (index = 0; index < vector_active (vline); index++)
-- if ((command = vector_slot (vline, index)))
-- {
-- int ret;
--
-- match = cmd_filter_by_completion (command, cmd_vector, index);
-+ {
-+ command = vector_slot (vline, index);
-+ ret = cmd_vector_filter(cmd_vector,
-+ filter,
-+ vline, index,
-+ &match,
-+ &matches);
-+
-+ if (ret != CMD_SUCCESS)
-+ {
-+ cmd_matches_free(&matches);
-+ return ret;
-+ }
-
-- if (match == vararg_match)
-+ if (match == vararg_match)
-+ {
-+ cmd_matches_free(&matches);
- break;
--
-- ret = is_cmd_ambiguous (command, cmd_vector, index, match);
-+ }
-
-- if (ret == 1)
-- {
-- vector_free (cmd_vector);
-- return CMD_ERR_AMBIGUOUS;
-- }
-- else if (ret == 2)
-- {
-- vector_free (cmd_vector);
-- return CMD_ERR_NO_MATCH;
-- }
-- }
-+ ret = is_cmd_ambiguous (cmd_vector, command, matches, match);
-+ cmd_matches_free(&matches);
-+
-+ if (ret == 1)
-+ {
-+ vector_free(cmd_vector);
-+ return CMD_ERR_AMBIGUOUS;
-+ }
-+ else if (ret == 2)
-+ {
-+ vector_free(cmd_vector);
-+ return CMD_ERR_NO_MATCH;
-+ }
-+ }
-
- /* Check matched count. */
- matched_element = NULL;
-@@ -1977,12 +2627,9 @@ cmd_execute_command_real (vector vline, struct vty *vty,
- for (i = 0; i < vector_active (cmd_vector); i++)
- if ((cmd_element = vector_slot (cmd_vector, i)))
- {
-- if (match == vararg_match || index >= cmd_element->cmdsize)
-+ if (cmd_is_complete(cmd_element, vline))
- {
- matched_element = cmd_element;
--#if 0
-- printf ("DEBUG: %s\n", cmd_element->string);
--#endif
- matched_count++;
- }
- else
-@@ -2006,35 +2653,9 @@ cmd_execute_command_real (vector vline, struct vty *vty,
- if (matched_count > 1)
- return CMD_ERR_AMBIGUOUS;
-
-- /* Argument treatment */
-- varflag = 0;
-- argc = 0;
--
-- for (i = 0; i < vector_active (vline); i++)
-- {
-- if (varflag)
-- argv[argc++] = vector_slot (vline, i);
-- else
-- {
-- vector descvec = vector_slot (matched_element->strvec, i);
--
-- if (vector_active (descvec) == 1)
-- {
-- struct desc *desc = vector_slot (descvec, 0);
--
-- if (CMD_VARARG (desc->cmd))
-- varflag = 1;
--
-- if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
-- argv[argc++] = vector_slot (vline, i);
-- }
-- else
-- argv[argc++] = vector_slot (vline, i);
-- }
--
-- if (argc >= CMD_ARGC_MAX)
-- return CMD_ERR_EXEED_ARGC_MAX;
-- }
-+ ret = cmd_parse(matched_element, vline, &argc, argv);
-+ if (ret != CMD_SUCCESS)
-+ return ret;
-
- /* For vtysh execution. */
- if (cmd)
-@@ -2047,6 +2668,21 @@ cmd_execute_command_real (vector vline, struct vty *vty,
- return (*matched_element->func) (matched_element, vty, argc, argv);
- }
-
-+/**
-+ * Execute a given command, handling things like "do ..." and checking
-+ * whether the given command might apply at a parent node if doesn't
-+ * apply for the current node.
-+ *
-+ * @param vline Command line input, vector of char* where each element is
-+ * one input token.
-+ * @param vty The vty context in which the command should be executed.
-+ * @param cmd Pointer where the struct cmd_element of the matched command
-+ * will be stored, if any. May be set to NULL if this info is
-+ * not needed.
-+ * @param vtysh If set != 0, don't lookup the command at parent nodes.
-+ * @return The status of the command that has been executed or an error code
-+ * as to why no command could be executed.
-+ */
- int
- cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
- int vtysh) {
-@@ -2070,7 +2706,7 @@ cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
- vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
- }
-
-- ret = cmd_execute_command_real (shifted_vline, vty, cmd);
-+ ret = cmd_execute_command_real (shifted_vline, FILTER_RELAXED, vty, cmd);
-
- vector_free(shifted_vline);
- vty->node = onode;
-@@ -2078,7 +2714,7 @@ cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
- }
-
-
-- saved_ret = ret = cmd_execute_command_real (vline, vty, cmd);
-+ saved_ret = ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd);
-
- if (vtysh)
- return saved_ret;
-@@ -2089,7 +2725,7 @@ cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
- {
- try_node = node_parent(try_node);
- vty->node = try_node;
-- ret = cmd_execute_command_real (vline, vty, cmd);
-+ ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd);
- tried = 1;
- if (ret == CMD_SUCCESS || ret == CMD_WARNING)
- {
-@@ -2104,123 +2740,24 @@ cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
- return saved_ret;
- }
-
--/* Execute command by argument readline. */
-+/**
-+ * Execute a given command, matching it strictly against the current node.
-+ * This mode is used when reading config files.
-+ *
-+ * @param vline Command line input, vector of char* where each element is
-+ * one input token.
-+ * @param vty The vty context in which the command should be executed.
-+ * @param cmd Pointer where the struct cmd_element* of the matched command
-+ * will be stored, if any. May be set to NULL if this info is
-+ * not needed.
-+ * @return The status of the command that has been executed or an error code
-+ * as to why no command could be executed.
-+ */
- int
- cmd_execute_command_strict (vector vline, struct vty *vty,
- struct cmd_element **cmd)
- {
-- unsigned int i;
-- unsigned int index;
-- vector cmd_vector;
-- struct cmd_element *cmd_element;
-- struct cmd_element *matched_element;
-- unsigned int matched_count, incomplete_count;
-- int argc;
-- const char *argv[CMD_ARGC_MAX];
-- int varflag;
-- enum match_type match = 0;
-- char *command;
--
-- /* Make copy of command element */
-- cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
--
-- for (index = 0; index < vector_active (vline); index++)
-- if ((command = vector_slot (vline, index)))
-- {
-- int ret;
--
-- match = cmd_filter_by_string (vector_slot (vline, index),
-- cmd_vector, index);
--
-- /* If command meets '.VARARG' then finish matching. */
-- if (match == vararg_match)
-- break;
--
-- ret = is_cmd_ambiguous (command, cmd_vector, index, match);
-- if (ret == 1)
-- {
-- vector_free (cmd_vector);
-- return CMD_ERR_AMBIGUOUS;
-- }
-- if (ret == 2)
-- {
-- vector_free (cmd_vector);
-- return CMD_ERR_NO_MATCH;
-- }
-- }
--
-- /* Check matched count. */
-- matched_element = NULL;
-- matched_count = 0;
-- incomplete_count = 0;
-- for (i = 0; i < vector_active (cmd_vector); i++)
-- if (vector_slot (cmd_vector, i) != NULL)
-- {
-- cmd_element = vector_slot (cmd_vector, i);
--
-- if (match == vararg_match || index >= cmd_element->cmdsize)
-- {
-- matched_element = cmd_element;
-- matched_count++;
-- }
-- else
-- incomplete_count++;
-- }
--
-- /* Finish of using cmd_vector. */
-- vector_free (cmd_vector);
--
-- /* To execute command, matched_count must be 1. */
-- if (matched_count == 0)
-- {
-- if (incomplete_count)
-- return CMD_ERR_INCOMPLETE;
-- else
-- return CMD_ERR_NO_MATCH;
-- }
--
-- if (matched_count > 1)
-- return CMD_ERR_AMBIGUOUS;
--
-- /* Argument treatment */
-- varflag = 0;
-- argc = 0;
--
-- for (i = 0; i < vector_active (vline); i++)
-- {
-- if (varflag)
-- argv[argc++] = vector_slot (vline, i);
-- else
-- {
-- vector descvec = vector_slot (matched_element->strvec, i);
--
-- if (vector_active (descvec) == 1)
-- {
-- struct desc *desc = vector_slot (descvec, 0);
--
-- if (CMD_VARARG (desc->cmd))
-- varflag = 1;
--
-- if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
-- argv[argc++] = vector_slot (vline, i);
-- }
-- else
-- argv[argc++] = vector_slot (vline, i);
-- }
--
-- if (argc >= CMD_ARGC_MAX)
-- return CMD_ERR_EXEED_ARGC_MAX;
-- }
--
-- /* For vtysh execution. */
-- if (cmd)
-- *cmd = matched_element;
--
-- if (matched_element->daemon)
-- return CMD_SUCCESS_DAEMON;
--
-- /* Now execute matched command */
-- return (*matched_element->func) (matched_element, vty, argc, argv);
-+ return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd);
- }
-
- /* Configration make from file. */
-@@ -3461,9 +3998,10 @@ install_default (enum node_type node)
- void
- cmd_init (int terminal)
- {
-- command_cr = XSTRDUP(MTYPE_STRVEC, "<cr>");
-- desc_cr.cmd = command_cr;
-- desc_cr.str = XSTRDUP(MTYPE_STRVEC, "");
-+ command_cr = XSTRDUP(MTYPE_CMD_TOKENS, "<cr>");
-+ token_cr.type = TOKEN_TERMINAL;
-+ token_cr.cmd = command_cr;
-+ token_cr.desc = XSTRDUP(MTYPE_CMD_TOKENS, "");
-
- /* Allocate initial top vector of commands. */
- cmdvec = vector_init (VECTOR_MIN_SIZE);
-@@ -3584,14 +4122,61 @@ cmd_init (int terminal)
- srand(time(NULL));
- }
-
-+static void
-+cmd_terminate_token(struct cmd_token *token)
-+{
-+ unsigned int i, j;
-+ vector keyword_vect;
-+
-+ if (token->multiple)
-+ {
-+ for (i = 0; i < vector_active(token->multiple); i++)
-+ cmd_terminate_token(vector_slot(token->multiple, i));
-+ vector_free(token->multiple);
-+ token->multiple = NULL;
-+ }
-+
-+ if (token->keyword)
-+ {
-+ for (i = 0; i < vector_active(token->keyword); i++)
-+ {
-+ keyword_vect = vector_slot(token->keyword, i);
-+ for (j = 0; j < vector_active(keyword_vect); j++)
-+ cmd_terminate_token(vector_slot(keyword_vect, j));
-+ vector_free(keyword_vect);
-+ }
-+ vector_free(token->keyword);
-+ token->keyword = NULL;
-+ }
-+
-+ XFREE(MTYPE_CMD_TOKENS, token->cmd);
-+ XFREE(MTYPE_CMD_TOKENS, token->desc);
-+
-+ XFREE(MTYPE_CMD_TOKENS, token);
-+}
-+
-+static void
-+cmd_terminate_element(struct cmd_element *cmd)
-+{
-+ unsigned int i;
-+
-+ if (cmd->tokens == NULL)
-+ return;
-+
-+ for (i = 0; i < vector_active(cmd->tokens); i++)
-+ cmd_terminate_token(vector_slot(cmd->tokens, i));
-+
-+ vector_free(cmd->tokens);
-+ cmd->tokens = NULL;
-+}
-+
- void
- cmd_terminate ()
- {
-- unsigned int i, j, k, l;
-+ unsigned int i, j;
- struct cmd_node *cmd_node;
- struct cmd_element *cmd_element;
-- struct desc *desc;
-- vector cmd_node_v, cmd_element_v, desc_v;
-+ vector cmd_node_v;
-
- if (cmdvec)
- {
-@@ -3601,30 +4186,8 @@ cmd_terminate ()
- cmd_node_v = cmd_node->cmd_vector;
-
- for (j = 0; j < vector_active (cmd_node_v); j++)
-- if ((cmd_element = vector_slot (cmd_node_v, j)) != NULL &&
-- cmd_element->strvec != NULL)
-- {
-- cmd_element_v = cmd_element->strvec;
--
-- for (k = 0; k < vector_active (cmd_element_v); k++)
-- if ((desc_v = vector_slot (cmd_element_v, k)) != NULL)
-- {
-- for (l = 0; l < vector_active (desc_v); l++)
-- if ((desc = vector_slot (desc_v, l)) != NULL)
-- {
-- if (desc->cmd)
-- XFREE (MTYPE_STRVEC, desc->cmd);
-- if (desc->str)
-- XFREE (MTYPE_STRVEC, desc->str);
--
-- XFREE (MTYPE_DESC, desc);
-- }
-- vector_free (desc_v);
-- }
--
-- cmd_element->strvec = NULL;
-- vector_free (cmd_element_v);
-- }
-+ if ((cmd_element = vector_slot (cmd_node_v, j)) != NULL)
-+ cmd_terminate_element(cmd_element);
-
- vector_free (cmd_node_v);
- }
-@@ -3634,9 +4197,9 @@ cmd_terminate ()
- }
-
- if (command_cr)
-- XFREE(MTYPE_STRVEC, command_cr);
-- if (desc_cr.str)
-- XFREE(MTYPE_STRVEC, desc_cr.str);
-+ XFREE(MTYPE_CMD_TOKENS, command_cr);
-+ if (token_cr.desc)
-+ XFREE(MTYPE_CMD_TOKENS, token_cr.desc);
- if (host.name)
- XFREE (MTYPE_HOST, host.name);
- if (host.password)
-diff --git a/lib/command.h b/lib/command.h
-index 2d708d8..e47c425 100644
---- a/lib/command.h
-+++ b/lib/command.h
-@@ -138,18 +138,32 @@ struct cmd_element
- int (*func) (struct cmd_element *, struct vty *, int, const char *[]);
- const char *doc; /* Documentation of this command. */
- int daemon; /* Daemon to which this command belong. */
-- vector strvec; /* Pointing out each description vector. */
-- unsigned int cmdsize; /* Command index count. */
-- char *config; /* Configuration string */
-- vector subconfig; /* Sub configuration string */
-+ vector tokens; /* Vector of cmd_tokens */
- u_char attr; /* Command attributes */
- };
-
-+
-+enum cmd_token_type
-+{
-+ TOKEN_TERMINAL = 0,
-+ TOKEN_MULTIPLE,
-+ TOKEN_KEYWORD,
-+};
-+
- /* Command description structure. */
--struct desc
-+struct cmd_token
- {
-+ enum cmd_token_type type;
-+
-+ /* Used for type == MULTIPLE */
-+ vector multiple; /* vector of cmd_token, type == FINAL */
-+
-+ /* Used for type == KEYWORD */
-+ vector keyword; /* vector of vector of cmd_tokens */
-+
-+ /* Used for type == TERMINAL */
- char *cmd; /* Command string. */
-- char *str; /* Command's description. */
-+ char *desc; /* Command's description. */
- };
-
- /* Return value of the commands. */
-@@ -192,7 +206,170 @@ struct desc
- int argc __attribute__ ((unused)), \
- const char *argv[] __attribute__ ((unused)) )
-
--/* DEFUN for vty command interafce. Little bit hacky ;-). */
-+/* DEFUN for vty command interafce. Little bit hacky ;-).
-+ *
-+ * DEFUN(funcname, cmdname, cmdstr, helpstr)
-+ *
-+ * funcname
-+ * ========
-+ *
-+ * Name of the function that will be defined.
-+ *
-+ * cmdname
-+ * =======
-+ *
-+ * Name of the struct that will be defined for the command.
-+ *
-+ * cmdstr
-+ * ======
-+ *
-+ * The cmdstr defines the command syntax. It is used by the vty subsystem
-+ * and vtysh to perform matching and completion in the cli. So you have to take
-+ * care to construct it adhering to the following grammar. The names used
-+ * for the production rules losely represent the names used in lib/command.c
-+ *
-+ * cmdstr = cmd_token , { " " , cmd_token } ;
-+ *
-+ * cmd_token = cmd_terminal
-+ * | cmd_multiple
-+ * | cmd_keyword ;
-+ *
-+ * cmd_terminal_fixed = fixed_string
-+ * | variable
-+ * | range
-+ * | ipv4
-+ * | ipv4_prefix
-+ * | ipv6
-+ * | ipv6_prefix ;
-+ *
-+ * cmd_terminal = cmd_terminal_fixed
-+ * | option
-+ * | vararg ;
-+ *
-+ * multiple_part = cmd_terminal_fixed ;
-+ * cmd_multiple = "(" , multiple_part , ( "|" | { "|" , multiple_part } ) , ")" ;
-+ *
-+ * keyword_part = fixed_string , { " " , ( cmd_terminal_fixed | cmd_multiple ) } ;
-+ * cmd_keyword = "{" , keyword_part , { "|" , keyword_part } , "}" ;
-+ *
-+ * lowercase = "a" | ... | "z" ;
-+ * uppercase = "A" | ... | "Z" ;
-+ * digit = "0" | ... | "9" ;
-+ * number = digit , { digit } ;
-+ *
-+ * fixed_string = (lowercase | digit) , { lowercase | digit | uppercase | "-" | "_" } ;
-+ * variable = uppercase , { uppercase | "_" } ;
-+ * range = "<" , number , "-" , number , ">" ;
-+ * ipv4 = "A.B.C.D" ;
-+ * ipv4_prefix = "A.B.C.D/M" ;
-+ * ipv6 = "X:X::X:X" ;
-+ * ipv6_prefix = "X:X::X:X/M" ;
-+ * option = "[" , variable , "]" ;
-+ * vararg = "." , variable ;
-+ *
-+ * To put that all in a textual description: A cmdstr is a sequence of tokens,
-+ * separated by spaces.
-+ *
-+ * Terminal Tokens:
-+ *
-+ * A very simple cmdstring would be something like: "show ip bgp". It consists
-+ * of three Terminal Tokens, each containing a fixed string. When this command
-+ * is called, no arguments will be passed down to the function implementing it,
-+ * as it only consists of fixed strings.
-+ *
-+ * Apart from fixed strings, Terminal Tokens can also contain variables:
-+ * An example would be "show ip bgp A.B.C.D". This command expects an IPv4
-+ * as argument. As this is a variable, the IP address entered by the user will
-+ * be passed down as an argument. Apart from two exceptions, the other options
-+ * for Terminal Tokens behave exactly as we just discussed and only make a
-+ * difference for the CLI. The two exceptions will be discussed in the next
-+ * paragraphs.
-+ *
-+ * A Terminal Token can contain a so called option match. This is a simple
-+ * string variable that the user may omit. An example would be:
-+ * "show interface [IFNAME]". If the user calls this without an interface as
-+ * argument, no arguments will be passed down to the function implementing
-+ * this command. Otherwise, the interface name will be provided to the function
-+ * as a regular argument.
-+
-+ * Also, a Terminal Token can contain a so called vararg. This is used e.g. in
-+ * "show ip bgp regexp .LINE". The last token is a vararg match and will
-+ * consume all the arguments the user inputs on the command line and append
-+ * those to the list of arguments passed down to the function implementing this
-+ * command. (Therefore, it doesn't make much sense to have any tokens after a
-+ * vararg because the vararg will already consume all the words the user entered
-+ * in the CLI)
-+ *
-+ * Multiple Tokens:
-+ *
-+ * The Multiple Token type can be used if there are multiple possibilities what
-+ * arguments may be used for a command, but it should map to the same function
-+ * nonetheless. An example would be "ip route A.B.C.D/M (reject|blackhole)"
-+ * In that case both "reject" and "blackhole" would be acceptable as last
-+ * arguments. The words matched by Multiple Tokens are always added to the
-+ * argument list, even if they are matched by fixed strings. Such a Multiple
-+ * Token can contain almost any type of token that would also be acceptable
-+ * for a Terminal Token, the exception are optional variables and varag.
-+ *
-+ * There is one special case that is used in some places of Quagga that should be
-+ * pointed out here shortly. An example would be "password (8|) WORD". This
-+ * construct is used to have fixed strings communicated as arguments. (The "8"
-+ * will be passed down as an argument in this case) It does not mean that
-+ * the "8" is optional. Another historic and possibly surprising property of
-+ * this construct is that it consumes two parts of helpstr. (Help
-+ * strings will be explained later)
-+ *
-+ * Keyword Tokens:
-+ *
-+ * There are commands that take a lot of different and possibly optional arguments.
-+ * An example from ospf would be the "default-information originate" command. This
-+ * command takes a lot of optional arguments that may be provided in any order.
-+ * To accomodate such commands, the Keyword Token has been implemented.
-+ * Using the keyword token, the "default-information originate" command and all
-+ * its possible options can be represented using this single cmdstr:
-+ * "default-information originate \
-+ * {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}"
-+ *
-+ * Keywords always start with a fixed string and may be followed by arguments.
-+ * Except optional variables and vararg, everything is permitted here.
-+ *
-+ * For the special case of a keyword without arguments, either NULL or the
-+ * keyword itself will be pushed as an argument, depending on whether the
-+ * keyword is present.
-+ * For the other keywords, arguments will be only pushed for
-+ * variables/Multiple Tokens. If the keyword is not present, the arguments that
-+ * would have been pushed will be substituted by NULL.
-+ *
-+ * A few examples:
-+ * "default information originate metric-type 1 metric 1000"
-+ * would yield the following arguments:
-+ * { NULL, "1000", "1", NULL }
-+ *
-+ * "default information originate always route-map RMAP-DEFAULT"
-+ * would yield the following arguments:
-+ * { "always", NULL, NULL, "RMAP-DEFAULT" }
-+ *
-+ * helpstr
-+ * =======
-+ *
-+ * The helpstr is used to show a short explantion for the commands that
-+ * are available when the user presses '?' on the CLI. It is the concatenation
-+ * of the helpstrings for all the tokens that make up the command.
-+ *
-+ * There should be one helpstring for each token in the cmdstr except those
-+ * containing other tokens, like Multiple or Keyword Tokens. For those, there
-+ * will only be the helpstrings of the contained tokens.
-+ *
-+ * The individual helpstrings are expected to be in the same order as their
-+ * respective Tokens appear in the cmdstr. They should each be terminated with
-+ * a linefeed. The last helpstring should be terminated with a linefeed as well.
-+ *
-+ * Care should also be taken to avoid having similar tokens with different
-+ * helpstrings. Imagine e.g. the commands "show ip ospf" and "show ip bgp".
-+ * they both contain a helpstring for "show", but only one will be displayed
-+ * when the user enters "sh?". If those two helpstrings differ, it is not
-+ * defined which one will be shown and the behavior is therefore unpredictable.
-+ */
- #define DEFUN(funcname, cmdname, cmdstr, helpstr) \
- DEFUN_CMD_FUNC_DECL(funcname) \
- DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0) \
-@@ -330,7 +507,6 @@ struct desc
- extern void install_node (struct cmd_node *, int (*) (struct vty *));
- extern void install_default (enum node_type);
- extern void install_element (enum node_type, struct cmd_element *);
--extern void sort_node (void);
-
- /* Concatenates argv[shift] through argv[argc-1] into a single NUL-terminated
- string with a space between each element (allocated using
-@@ -346,7 +522,6 @@ extern int config_from_file (struct vty *, FILE *);
- extern enum node_type node_parent (enum node_type);
- extern int cmd_execute_command (vector, struct vty *, struct cmd_element **, int);
- extern int cmd_execute_command_strict (vector, struct vty *, struct cmd_element **);
--extern void config_replace_string (struct cmd_element *, char *, ...);
- extern void cmd_init (int);
- extern void cmd_terminate (void);
-
-diff --git a/lib/memtypes.c b/lib/memtypes.c
-index 50b6fa4..47a3438 100644
---- a/lib/memtypes.c
-+++ b/lib/memtypes.c
-@@ -54,7 +54,7 @@ struct memory_list memory_list_lib[] =
- { MTYPE_ROUTE_MAP_RULE, "Route map rule" },
- { MTYPE_ROUTE_MAP_RULE_STR, "Route map rule str" },
- { MTYPE_ROUTE_MAP_COMPILED, "Route map compiled" },
-- { MTYPE_DESC, "Command desc" },
-+ { MTYPE_CMD_TOKENS, "Command desc" },
- { MTYPE_KEY, "Key" },
- { MTYPE_KEYCHAIN, "Key chain" },
- { MTYPE_IF_RMAP, "Interface route map" },
-diff --git a/lib/vty.c b/lib/vty.c
-index 96cb1e4..9908b02 100644
---- a/lib/vty.c
-+++ b/lib/vty.c
-@@ -931,23 +931,23 @@ vty_complete_command (struct vty *vty)
-
- static void
- vty_describe_fold (struct vty *vty, int cmd_width,
-- unsigned int desc_width, struct desc *desc)
-+ unsigned int desc_width, struct cmd_token *token)
- {
- char *buf;
- const char *cmd, *p;
- int pos;
-
-- cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd;
-+ cmd = token->cmd[0] == '.' ? token->cmd + 1 : token->cmd;
-
- if (desc_width <= 0)
- {
-- vty_out (vty, " %-*s %s%s", cmd_width, cmd, desc->str, VTY_NEWLINE);
-+ vty_out (vty, " %-*s %s%s", cmd_width, cmd, token->desc, VTY_NEWLINE);
- return;
- }
-
-- buf = XCALLOC (MTYPE_TMP, strlen (desc->str) + 1);
-+ buf = XCALLOC (MTYPE_TMP, strlen (token->desc) + 1);
-
-- for (p = desc->str; strlen (p) > desc_width; p += pos + 1)
-+ for (p = token->desc; strlen (p) > desc_width; p += pos + 1)
- {
- for (pos = desc_width; pos > 0; pos--)
- if (*(p + pos) == ' ')
-@@ -976,7 +976,7 @@ vty_describe_command (struct vty *vty)
- vector vline;
- vector describe;
- unsigned int i, width, desc_width;
-- struct desc *desc, *desc_cr = NULL;
-+ struct cmd_token *token, *token_cr = NULL;
-
- vline = cmd_make_strvec (vty->buf);
-
-@@ -1010,15 +1010,15 @@ vty_describe_command (struct vty *vty)
- /* Get width of command string. */
- width = 0;
- for (i = 0; i < vector_active (describe); i++)
-- if ((desc = vector_slot (describe, i)) != NULL)
-+ if ((token = vector_slot (describe, i)) != NULL)
- {
- unsigned int len;
-
-- if (desc->cmd[0] == '\0')
-+ if (token->cmd[0] == '\0')
- continue;
-
-- len = strlen (desc->cmd);
-- if (desc->cmd[0] == '.')
-+ len = strlen (token->cmd);
-+ if (token->cmd[0] == '.')
- len--;
-
- if (width < len)
-@@ -1030,27 +1030,27 @@ vty_describe_command (struct vty *vty)
-
- /* Print out description. */
- for (i = 0; i < vector_active (describe); i++)
-- if ((desc = vector_slot (describe, i)) != NULL)
-+ if ((token = vector_slot (describe, i)) != NULL)
- {
-- if (desc->cmd[0] == '\0')
-+ if (token->cmd[0] == '\0')
- continue;
-
-- if (strcmp (desc->cmd, command_cr) == 0)
-+ if (strcmp (token->cmd, command_cr) == 0)
- {
-- desc_cr = desc;
-+ token_cr = token;
- continue;
- }
-
-- if (!desc->str)
-+ if (!token->desc)
- vty_out (vty, " %-s%s",
-- desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
-+ token->cmd[0] == '.' ? token->cmd + 1 : token->cmd,
- VTY_NEWLINE);
-- else if (desc_width >= strlen (desc->str))
-+ else if (desc_width >= strlen (token->desc))
- vty_out (vty, " %-*s %s%s", width,
-- desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
-- desc->str, VTY_NEWLINE);
-+ token->cmd[0] == '.' ? token->cmd + 1 : token->cmd,
-+ token->desc, VTY_NEWLINE);
- else
-- vty_describe_fold (vty, width, desc_width, desc);
-+ vty_describe_fold (vty, width, desc_width, token);
-
- #if 0
- vty_out (vty, " %-*s %s%s", width
-@@ -1059,18 +1059,18 @@ vty_describe_command (struct vty *vty)
- #endif /* 0 */
- }
-
-- if ((desc = desc_cr))
-+ if ((token = token_cr))
- {
-- if (!desc->str)
-+ if (!token->desc)
- vty_out (vty, " %-s%s",
-- desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
-+ token->cmd[0] == '.' ? token->cmd + 1 : token->cmd,
- VTY_NEWLINE);
-- else if (desc_width >= strlen (desc->str))
-+ else if (desc_width >= strlen (token->desc))
- vty_out (vty, " %-*s %s%s", width,
-- desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
-- desc->str, VTY_NEWLINE);
-+ token->cmd[0] == '.' ? token->cmd + 1 : token->cmd,
-+ token->desc, VTY_NEWLINE);
- else
-- vty_describe_fold (vty, width, desc_width, desc);
-+ vty_describe_fold (vty, width, desc_width, token);
- }
-
- out:
-diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c
-index e991971..4f6d9e5 100644
---- a/ospf6d/ospf6_main.c
-+++ b/ospf6d/ospf6_main.c
-@@ -325,9 +325,6 @@ main (int argc, char *argv[], char *envp[])
- /* initialize ospf6 */
- ospf6_init ();
-
-- /* sort command vector */
-- sort_node ();
--
- /* parse config file */
- vty_read_config (config_file, config_default);
-
-diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c
-index 6d58b4e..c68aa4d 100644
---- a/ospfd/ospf_main.c
-+++ b/ospfd/ospf_main.c
-@@ -310,8 +310,6 @@ main (int argc, char **argv)
- ospf_opaque_init ();
- #endif /* HAVE_OPAQUE_LSA */
-
-- sort_node ();
--
- /* Get configuration file. */
- vty_read_config (config_file, config_default);
-
-diff --git a/ripd/rip_main.c b/ripd/rip_main.c
-index 6a9fa71..a512fbc 100644
---- a/ripd/rip_main.c
-+++ b/ripd/rip_main.c
-@@ -287,9 +287,6 @@ main (int argc, char **argv)
- rip_zclient_init ();
- rip_peer_init ();
-
-- /* Sort all installed commands. */
-- sort_node ();
--
- /* Get configuration file. */
- vty_read_config (config_file, config_default);
-
-diff --git a/ripngd/ripng_main.c b/ripngd/ripng_main.c
-index 20225b7..7525a26 100644
---- a/ripngd/ripng_main.c
-+++ b/ripngd/ripng_main.c
-@@ -282,9 +282,6 @@ main (int argc, char **argv)
- zebra_init ();
- ripng_peer_init ();
-
-- /* Sort all installed commands. */
-- sort_node ();
--
- /* Get configuration file. */
- vty_read_config (config_file, config_default);
-
-diff --git a/tests/main.c b/tests/main.c
-index e0fbb4d..2d8cb0c 100644
---- a/tests/main.c
-+++ b/tests/main.c
-@@ -171,8 +171,6 @@ main (int argc, char **argv)
- /* OSPF vty inits. */
- test_vty_init ();
-
-- sort_node ();
--
- /* Change to the daemon program. */
- if (daemon_mode && daemon (0, 0) < 0)
- {
-diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
-index c575902..34c3bd6 100644
---- a/vtysh/vtysh.c
-+++ b/vtysh/vtysh.c
-@@ -554,7 +554,7 @@ vtysh_rl_describe (void)
- vector vline;
- vector describe;
- int width;
-- struct desc *desc;
-+ struct cmd_token *token;
-
- vline = cmd_make_strvec (rl_line_buffer);
-
-@@ -592,15 +592,15 @@ vtysh_rl_describe (void)
- /* Get width of command string. */
- width = 0;
- for (i = 0; i < vector_active (describe); i++)
-- if ((desc = vector_slot (describe, i)) != NULL)
-+ if ((token = vector_slot (describe, i)) != NULL)
- {
- int len;
-
-- if (desc->cmd[0] == '\0')
-+ if (token->cmd[0] == '\0')
- continue;
-
-- len = strlen (desc->cmd);
-- if (desc->cmd[0] == '.')
-+ len = strlen (token->cmd);
-+ if (token->cmd[0] == '.')
- len--;
-
- if (width < len)
-@@ -608,19 +608,19 @@ vtysh_rl_describe (void)
- }
-
- for (i = 0; i < vector_active (describe); i++)
-- if ((desc = vector_slot (describe, i)) != NULL)
-+ if ((token = vector_slot (describe, i)) != NULL)
- {
-- if (desc->cmd[0] == '\0')
-+ if (token->cmd[0] == '\0')
- continue;
-
-- if (! desc->str)
-+ if (! token->desc)
- fprintf (stdout," %-s\n",
-- desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd);
-+ token->cmd[0] == '.' ? token->cmd + 1 : token->cmd);
- else
- fprintf (stdout," %-*s %s\n",
- width,
-- desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
-- desc->str);
-+ token->cmd[0] == '.' ? token->cmd + 1 : token->cmd,
-+ token->desc);
- }
-
- cmd_free_strvec (vline);
-diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c
-index 4a315a5..48958f0 100644
---- a/vtysh/vtysh_main.c
-+++ b/vtysh/vtysh_main.c
-@@ -299,8 +299,6 @@ main (int argc, char **argv, char **env)
-
- vty_init_vtysh ();
-
-- sort_node ();
--
- /* Read vtysh configuration file before connecting to daemons. */
- vtysh_read_config (config_default);
-
-diff --git a/zebra/main.c b/zebra/main.c
-index 742e029..523b191 100644
---- a/zebra/main.c
-+++ b/zebra/main.c
-@@ -343,9 +343,6 @@ main (int argc, char **argv)
- interface_list ();
- route_read ();
-
-- /* Sort VTY commands. */
-- sort_node ();
--
- #ifdef HAVE_SNMP
- zebra_snmp_init ();
- #endif /* HAVE_SNMP */
-diff --git a/zebra/test_main.c b/zebra/test_main.c
-index a951863..c695172 100644
---- a/zebra/test_main.c
-+++ b/zebra/test_main.c
-@@ -298,9 +298,6 @@ main (int argc, char **argv)
- route_read ();
- zebra_vty_init();
-
-- /* Sort VTY commands. */
-- sort_node ();
--
- /* Configuration file read*/
- vty_read_config (config_file, config_default);
-
---
-1.9.2
-
diff --git a/main/quagga/APKBUILD b/main/quagga/APKBUILD
index 7546e6f906..f8fbca12ac 100644
--- a/main/quagga/APKBUILD
+++ b/main/quagga/APKBUILD
@@ -1,7 +1,7 @@
# Maintainer: Natanael Copa <ncopa@alpinelinux.org>
pkgname=quagga
-pkgver=0.99.22.4
-pkgrel=6
+pkgver=0.99.23
+pkgrel=0
pkgdesc="A free routing daemon replacing Zebra supporting RIP, OSPF and BGP."
url="http://quagga.net/"
arch="all"
@@ -13,12 +13,8 @@ subpackages="$pkgname-dev $pkgname-doc"
pkgusers="quagga"
pkggroups="quagga"
source="http://download.savannah.gnu.org/releases/quagga/quagga-$pkgver.tar.xz
- 0001-vtysh-don-t-append-superflous-spaces-BZ-750.patch
- 0002-bgpd-ospfd-zebra-fix-some-DEFUN-definitions.patch
- 0003-lib-rewrite-command-matching.patch
1001-bgpd-implement-next-hop-self-all.patch
musl-fix-headers.patch
- quagga-readline-6.3.patch
bgpd.initd
zebra.initd
zebra.confd
@@ -75,33 +71,21 @@ package() {
install -Dm644 "$srcdir/zebra.confd" "$pkgdir"/etc/conf.d/zebra
install -o quagga -g quagga -d -m755 "$pkgdir"/etc/quagga
}
-md5sums="03ef24a448be47beba80efa2152f8a28 quagga-0.99.22.4.tar.xz
-e943bdde8ba1a2896672b634d554f504 0001-vtysh-don-t-append-superflous-spaces-BZ-750.patch
-1a5c657062304c2b1764fef0882ca0ca 0002-bgpd-ospfd-zebra-fix-some-DEFUN-definitions.patch
-22612b753bd4842ffc63a96b87beb67e 0003-lib-rewrite-command-matching.patch
+md5sums="92dff03272aa9127ac13c6bea9c66187 quagga-0.99.23.tar.xz
2e78b3ea20041f94ff99798d37e1456e 1001-bgpd-implement-next-hop-self-all.patch
-27812f0aaaf8507c4338371aca1bd08d musl-fix-headers.patch
-67bea3d72089733c031885cfa843b972 quagga-readline-6.3.patch
+df62890cccdb7d9c7cc9b96167b9da8c musl-fix-headers.patch
e80a3df594eba8b09e19aa28d9283698 bgpd.initd
33d0e34f11460881161ab930d3d3b987 zebra.initd
34e06a1d2bc602ce691abc9ed169dd15 zebra.confd"
-sha256sums="5e12056692e2dbc272a929f96d0e98d9873f4e7f7ffcca62434b58f6660a6386 quagga-0.99.22.4.tar.xz
-29f35175dd1e22ba5f3c18c8ef4addaa5894bf4b942bcd84875c4512a0999139 0001-vtysh-don-t-append-superflous-spaces-BZ-750.patch
-1d0a162da4b09472d677d6edb13c32c84fecbfbc9b4c043846199979aa67fe0b 0002-bgpd-ospfd-zebra-fix-some-DEFUN-definitions.patch
-6a71d3d48de7cf8f9c4b554e1b455e9734ee71cb36d770a001843ed79411af38 0003-lib-rewrite-command-matching.patch
+sha256sums="7f374da7bab275b9dd2be864ac6fb4e0552d455d6b15a7f1d7128f5208eadeee quagga-0.99.23.tar.xz
979ed4f7a3e3b604a2cd3c717df467e253a4b75160f870343e6d96af0c9687ec 1001-bgpd-implement-next-hop-self-all.patch
-19068f58f034891c07b8a1324d0645e0f078e3dc98d1360d51c677cecaae8c9e musl-fix-headers.patch
-e4f6c38b3124df2ae328f37bcc2fbc43eeb10b6d8887ca2e38e19e5536aae0d1 quagga-readline-6.3.patch
+f59f1f654e80ae9c80e6ea150e210d82aa799d44624fa361348fc242849d0ebc musl-fix-headers.patch
41471bfda120cb57bc0f40e87ec23a4f150d2b97c97ececdda6c408eab7cf9a3 bgpd.initd
d6cc9280df63859ba711ad2071b38b9ce317d718c34840a2b101debef3fa7b56 zebra.initd
f7a52d383f60270a5a8fee5d4ac522c5c0ec2b7c4b5252cff54e260f32d9b323 zebra.confd"
-sha512sums="bcf429e71073e4fc71efc364a21a6c8b70871a17c66bd1328bc57b57962c2c15182436183b2e363c9c1c0e85d84c49d304d4049d40129272f52d6140db330b8a quagga-0.99.22.4.tar.xz
-b34db681155ade1e6dab4df733acb512cdb9adf42fd7ce06bd70fead1572c68d0845c0de5a2411257242c6ad9ce04bc428c4bb0fc2ab7192415fd6a957755039 0001-vtysh-don-t-append-superflous-spaces-BZ-750.patch
-e6eee34f13850205e4494c607ccd6bcc7f66b6456ecb986a83910e6c5f4f3f388e1cd7974f28cb591429b0a63e61ab2e21dfb3b1787f8844bfccebb4a1f3276e 0002-bgpd-ospfd-zebra-fix-some-DEFUN-definitions.patch
-d1274367fb9dcf8ead73b003569291b462c4d5eab26a8f85c98eb7539c12a9c64063b487bb88aa8fe55469da607f09ea55f02691931cdc77e18d5b622b19d5c3 0003-lib-rewrite-command-matching.patch
+sha512sums="c8072da8cec96e023ba8a53da7b2bbe6d709d13a7d03204245f6a15b70be81f88106be4864ecd552d84660cd40e89cf52260bc850f948352a3068fb08fd918e0 quagga-0.99.23.tar.xz
44677f3852b31f2f2776507b0da004431d12253b5897336d49525114a87945283a21d6dfe6162a73ff1f006fc235e31a753ac591aa70e6b8f4fbb3adb75e00f9 1001-bgpd-implement-next-hop-self-all.patch
-28a1695bd77991790df3b1b5a2c8ced929e6413e9acb87c4a8286569d05b20e65cba466e118fc16a11c264ba11dd1581e4143031ce3bbb478177e900ea68cb07 musl-fix-headers.patch
-587c5597fad4f54fb2ed21bc06c86b1e78ed9543a363b6b39ac688112dc08b2264ea59caa3a209718a7f07abf47bf3dea8055afb3da139c6197cfe19fa8503bf quagga-readline-6.3.patch
+b0cbef2d1544efa8a194aa4f05bd17225073dff7526bfa84a6068d7ae5806ff045c62c914999e1ecae04c4b251713aed5d5b0a6a98db6c3176ddf122d76894c7 musl-fix-headers.patch
d2bf7e8f2da49d0b039e72e76a77860b5b49d41a80550d6dc84791bbdec1d52e579393c5d42b45aa615991742421fef53ec1b92a5e740779b6060e20f5dd0413 bgpd.initd
a4955fe54729ec8cb17b72f3d2205d0a4ba814a51a5eb3635a85339de9a2d2342e4814ef8b1e011803fa1dc3c6f9a23b178848e0812576876343104854feb723 zebra.initd
900972c6f98e561dfacf384111251db262326e8764b8c763a5ef639fa11c7949c03eef5e3bce324a4b1964fe45416d2db74ae1b6bc967f7d4ba48c2eeda017c4 zebra.confd"
diff --git a/main/quagga/musl-fix-headers.patch b/main/quagga/musl-fix-headers.patch
index 12e96ece3d..b3e797c3b4 100644
--- a/main/quagga/musl-fix-headers.patch
+++ b/main/quagga/musl-fix-headers.patch
@@ -9,16 +9,6 @@
/*
* This file defines four types of data structures: singly-linked lists,
* singly-linked tail queues, lists and tail queues.
---- quagga-0.99.22.4.orig/lib/zebra.h
-+++ quagga-0.99.22.4/lib/zebra.h
-@@ -51,7 +51,6 @@
- #ifdef HAVE_STROPTS_H
- #include <stropts.h>
- #endif /* HAVE_STROPTS_H */
--#include <sys/fcntl.h>
- #ifdef HAVE_SYS_SELECT_H
- #include <sys/select.h>
- #endif /* HAVE_SYS_SELECT_H */
--- quagga-0.99.22.4.orig/isisd/include-netbsd/iso.h
+++ quagga-0.99.22.4/isisd/include-netbsd/iso.h
@@ -192,7 +192,7 @@
diff --git a/main/quagga/quagga-readline-6.3.patch b/main/quagga/quagga-readline-6.3.patch
deleted file mode 100644
index c75b430f6b..0000000000
--- a/main/quagga/quagga-readline-6.3.patch
+++ /dev/null
@@ -1,14 +0,0 @@
---- quagga-0.99.22.4.orig/vtysh/vtysh.c
-+++ quagga-0.99.22.4/vtysh/vtysh.c
-@@ -2211,9 +2211,9 @@
- vtysh_readline_init (void)
- {
- /* readline related settings. */
-- rl_bind_key ('?', (Function *) vtysh_rl_describe);
-+ rl_bind_key ('?', (rl_command_func_t *) vtysh_rl_describe);
- rl_completion_entry_function = vtysh_completion_entry_function;
-- rl_attempted_completion_function = (CPPFunction *)new_completion;
-+ rl_attempted_completion_function = (rl_completion_func_t *) new_completion;
- }
-
- char *