]> git.puffer.fish Git - matthieu/frr.git/commitdiff
lib: Initial refactor pass on CLI backend
authorQuentin Young <qlyoung@cumulusnetworks.com>
Mon, 19 Sep 2016 23:46:51 +0000 (23:46 +0000)
committerQuentin Young <qlyoung@cumulusnetworks.com>
Mon, 19 Sep 2016 23:46:51 +0000 (23:46 +0000)
Shotgun commit:
* Remove shim sources from Makefile.am
* Move new types to command.c / command.h
* Rewrite command.c / command.h
* Refactor shim types to real types in matcher
  and parser
* Initial refactor pass on vty.c

Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
lib/Makefile.am
lib/command.c
lib/command.h
lib/command_match.c
lib/command_parse.y
lib/vty.c

index d12f9ed6d9651086a8203f7e938abe5901fb449d..b7bb43477649fe5a5dfe8e628c29f9d3e9f90201 100644 (file)
@@ -11,7 +11,7 @@ libzebra_la_LDFLAGS = -version-info 0:0:0
 libzebra_la_SOURCES = \
        network.c pid_output.c getopt.c getopt1.c daemon.c \
        checksum.c vector.c linklist.c vty.c \
-       graph.c command_parse.y command_lex.l command_match.c grammar_sandbox.c \
+       graph.c command_parse.y command_lex.l command_match.c \
        command.c \
        sockunion.c prefix.c thread.c if.c memory.c buffer.c table.c hash.c \
        filter.c routemap.c distribute.c stream.c str.c log.c plist.c \
@@ -28,7 +28,7 @@ libzebra_la_LIBADD = @LIB_REGEX@ @LIBCAP@
 pkginclude_HEADERS = \
        buffer.h checksum.h filter.h getopt.h hash.h \
        if.h linklist.h log.h \
-       graph.h command_match.h grammar_sandbox.h \
+       graph.h command_match.h \
        command.h \
        memory.h network.h prefix.h routemap.h distribute.h sockunion.h \
        str.h stream.h table.h thread.h vector.h version.h vty.h zebra.h \
index 5bc157c851cbfbd7839fd7eacf1bcb94871114f2..f7800aa724403ceaa653b02787e4bc0520121184 100644 (file)
@@ -5,7 +5,7 @@
    Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC")
 
 This file is part of GNU Zebra.
+
 GNU Zebra is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published
 by the Free Software Foundation; either version 2, or (at your
@@ -29,53 +29,19 @@ Boston, MA 02111-1307, USA.  */
 #include <lib/version.h>
 #include "thread.h"
 #include "vector.h"
+#include "linklist.h"
 #include "vty.h"
 #include "command.h"
 #include "workqueue.h"
 #include "vrf.h"
 
+#include "command_match.h"
+#include "command_parse.h"
+
 /* Command vector which includes some level of command lists. Normally
    each daemon maintains each own cmdvec. */
 vector cmdvec = NULL;
 
-struct cmd_token token_cr;
-char *command_cr = NULL;
-
-/**
- * Filter types. These tell the parser whether to allow
- * partial matching on tokens.
- */
-enum filter_type
-{
-  FILTER_RELAXED,
-  FILTER_STRICT
-};
-
-/**
- * Command matcher result value.
- */
-enum matcher_rv
-{
-  MATCHER_OK,
-  MATCHER_COMPLETE,
-  MATCHER_INCOMPLETE,
-  MATCHER_NO_MATCH,
-  MATCHER_AMBIGUOUS,
-  MATCHER_EXCEED_ARGC_MAX
-};
-
-/**
- * Defines which matcher_rv values constitute
- * an error. Should be used against matcher_rv
- * return values to do basic error checking.
- */
-#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;
 
@@ -129,7 +95,7 @@ static const struct facility_map {
   int facility;
   const char *name;
   size_t match;
-} syslog_facilities[] = 
+} syslog_facilities[] =
   {
     { LOG_KERN, "kern", 1 },
     { LOG_USER, "user", 2 },
@@ -181,7 +147,7 @@ static int
 level_match(const char *s)
 {
   int level ;
-  
+
   for ( level = 0 ; zlog_priority [level] != NULL ; level ++ )
     if (!strncmp (s, zlog_priority[level], 2))
       return level;
@@ -201,7 +167,7 @@ print_version (const char *progname)
 /* Utility function to concatenate argv argument into a single string
    with inserting ' ' character between each argument.  */
 char *
-argv_concat (const char **argv, int argc, int shift)
+argv_concat (struct cmd_token **argv, int argc, int shift)
 {
   int i;
   size_t len;
@@ -210,14 +176,14 @@ argv_concat (const char **argv, int argc, int shift)
 
   len = 0;
   for (i = shift; i < argc; i++)
-    len += strlen(argv[i])+1;
+    len += strlen(argv[i]->arg)+1;
   if (!len)
     return NULL;
   p = str = XMALLOC(MTYPE_TMP, len);
   for (i = shift; i < argc; i++)
     {
       size_t arglen;
-      memcpy(p, argv[i], (arglen = strlen(argv[i])));
+      memcpy(p, argv[i]->arg, (arglen = strlen(argv[i]->arg)));
       p += arglen;
       *p++ = ' ';
     }
@@ -227,12 +193,12 @@ argv_concat (const char **argv, int argc, int shift)
 
 /* Install top node of command vector. */
 void
-install_node (struct cmd_node *node, 
-             int (*func) (struct vty *))
+install_node (struct cmd_node *node,
+              int (*func) (struct vty *))
 {
   vector_set_index (cmdvec, node->node, node);
   node->func = func;
-  node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
+  node->cmdgraph = graph_new ();
 }
 
 /* Breaking up string into each command piece. I assume given
@@ -245,10 +211,10 @@ cmd_make_strvec (const char *string)
   char *token;
   int strlen;
   vector strvec;
-  
+
   if (string == NULL)
     return NULL;
-  
+
   cp = string;
 
   /* Skip white spaces. */
@@ -266,12 +232,12 @@ cmd_make_strvec (const char *string)
   strvec = vector_init (VECTOR_MIN_SIZE);
 
   /* Copy each command piece and set into vector. */
-  while (1) 
+  while (1)
     {
       start = cp;
       while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') &&
-            *cp != '\0')
-       cp++;
+             *cp != '\0')
+        cp++;
       strlen = cp - start;
       token = XMALLOC (MTYPE_STRVEC, strlen + 1);
       memcpy (token, start, strlen);
@@ -279,11 +245,11 @@ cmd_make_strvec (const char *string)
       vector_set (strvec, token);
 
       while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') &&
-            *cp != '\0')
-       cp++;
+             *cp != '\0')
+        cp++;
 
       if (*cp == '\0')
-       return strvec;
+        return strvec;
     }
 }
 
@@ -304,388 +270,6 @@ cmd_free_strvec (vector v)
   vector_free (v);
 }
 
-/**
- * State structure for command format parser. Tracks
- * parse tree position and miscellaneous state variables.
- * Used when building a command vector from format strings.
- */
-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 read 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);
-}
-
-/**
- * Reads out one section of a help string from state->dp.
- * Leading whitespace is trimmed and the string is read until
- * a newline is reached.
- *
- * @param[out] state format parser state
- * @return the help string token read
- */
-static char *
-format_parser_desc_str(struct format_parser_state *state)
-{
-  const char *cp, *start;
-  char *token;
-  int strlen;
-
-  cp = state->dp;
-
-  if (cp == NULL)
-    return NULL;
-
-  /* Skip white spaces. */
-  while (isspace ((int) *cp) && *cp != '\0')
-    cp++;
-
-  /* Return if there is only white spaces */
-  if (*cp == '\0')
-    return NULL;
-
-  start = cp;
-
-  while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
-    cp++;
-
-  strlen = cp - start;
-  token = XMALLOC (MTYPE_CMD_TOKENS, strlen + 1);
-  memcpy (token, start, strlen);
-  *(token + strlen) = '\0';
-
-  state->dp = cp;
-
-  return token;
-}
-
-/**
- * Transitions format parser state into keyword parsing mode.
- * A cmd_token struct, `token`, representing this keyword token is initialized
- * and appended to state->curvect. token->keyword is initialized as a vector of
- * vector, a new vector is initialized and added to token->keyword, and
- * state->curvect is set to point at this vector. When control returns to the
- * caller newly parsed tokens will be added to this vector.
- *
- * In short:
- *   state->curvect[HEAD]               = new cmd_token
- *   state->curvect[HEAD]->keyword[0]   = new vector
- *   state->curvect                     = state->curvect[HEAD]->keyword[0]
- *
- * @param[out] state state struct to transition
- */
-static void
-format_parser_begin_keyword(struct format_parser_state *state)
-{
-  struct cmd_token *token;
-  vector keyword_vect;
-
-  if (state->in_keyword
-      || state->in_multiple)
-    format_parser_error(state, "Unexpected '{'");
-
-  state->cp++;
-  state->in_keyword = 1;
-
-  token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
-  token->type = TOKEN_KEYWORD;
-  token->keyword = vector_init(VECTOR_MIN_SIZE);
-
-  keyword_vect = vector_init(VECTOR_MIN_SIZE);
-  vector_set(token->keyword, keyword_vect);
-
-  vector_set(state->curvect, token);
-  state->curvect = keyword_vect;
-}
-
-/**
- * Transitions format parser state into multiple parsing mode.
- * A cmd_token struct, `token`, representing this multiple token is initialized
- * and appended to state->curvect. token->multiple is initialized as a vector
- * of cmd_token and state->curvect is set to point at token->multiple. If
- * state->curvect != state->topvect (i.e. this multiple token is nested inside
- * another composite token) then a pointer to state->curvect is saved in
- * state->intvect.
- *
- * In short:
- *   state->curvect[HEAD]               = new cmd_token
- *   state->curvect[HEAD]->multiple     = new vector
- *   state->intvect                     = state->curvect IFF nested token
- *   state->curvect                     = state->curvect[HEAD]->multiple
- *
- * @param[out] state state struct to transition
- */
-static void
-format_parser_begin_multiple(struct format_parser_state *state)
-{
-  struct cmd_token *token;
-
-  if (state->in_keyword == 1)
-    format_parser_error(state, "Keyword starting with '('");
-
-  if (state->in_multiple)
-    format_parser_error(state, "Nested group");
-
-  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);
-
-  vector_set(state->curvect, token);
-  if (state->curvect != state->topvect)
-    state->intvect = state->curvect;
-  state->curvect = token->multiple;
-}
-
-/**
- * Transition format parser state out of keyword parsing mode.
- * This function is called upon encountering '}'.
- * state->curvect is reassigned to the top level vector (as
- * keywords cannot be nested) and state flags are set appropriately.
- *
- * @param[out] state state struct to transition
- */
-static void
-format_parser_end_keyword(struct format_parser_state *state)
-{
-  if (state->in_multiple
-      || !state->in_keyword)
-    format_parser_error(state, "Unexpected '}'");
-
-  if (state->in_keyword == 1)
-    format_parser_error(state, "Empty keyword group");
-
-  state->cp++;
-  state->in_keyword = 0;
-  state->curvect = state->topvect;
-}
-
-/**
- * Transition format parser state out of multiple parsing mode.
- * This function is called upon encountering ')'.
- * state->curvect is reassigned to its parent vector (state->intvect
- * if the multiple token being exited was nested inside another token,
- * state->topvect otherwise) and state flags are set appropriately.
- *
- * @param[out] state state struct to transition
- */
-static void
-format_parser_end_multiple(struct format_parser_state *state)
-{
-  char *dummy;
-
-  if (!state->in_multiple)
-    format_parser_error(state, "Unexpected ')'");
-
-  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;
-}
-
-/**
- * Format parser handler for pipe '|' character.
- * This character separates subtokens in multiple and keyword type tokens.
- * If the current token is a multiple keyword, the position pointer is
- * simply moved past the pipe and state flags are set appropriately.
- * If the current token is a keyword token, the position pointer is moved
- * past the pipe. Then the cmd_token struct for the keyword is fetched and
- * a new vector of cmd_token is appended to its vector of vector. Finally
- * state->curvect is set to point at this new vector.
- *
- * In short:
- *   state->curvect = state->topvect[HEAD]->keyword[HEAD] = new vector
- *
- * @param[out] state state struct to transition
- */
-static void
-format_parser_handle_pipe(struct format_parser_state *state)
-{
-  struct cmd_token *keyword_token;
-  vector keyword_vect;
-
-  if (state->in_multiple)
-    {
-      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 '|'");
-    }
-}
-
-/**
- * Format parser handler for terminal tokens.
- * Parses the token, appends it to state->curvect, and sets
- * state flags appropriately.
- *
- * @param[out] state state struct for current format parser state
- */
-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;
-  if (strcmp (cmd, "A.B.C.D") == 0)
-    token->terminal = TERMINAL_IPV4;
-  else if (strcmp (cmd, "A.B.C.D/M") == 0)
-    token->terminal = TERMINAL_IPV4_PREFIX;
-  else if (strcmp (cmd, "X:X::X:X") == 0)
-    token->terminal = TERMINAL_IPV6;
-  else if (strcmp (cmd, "X:X::X:X/M") == 0)
-    token->terminal = TERMINAL_IPV6_PREFIX;
-  else if (cmd[0] == '[')
-    token->terminal = TERMINAL_OPTION;
-  else if (cmd[0] == '.')
-    token->terminal = TERMINAL_VARARG;
-  else if (cmd[0] == '<')
-    token->terminal = TERMINAL_RANGE;
-  else if (cmd[0] >= 'A' && cmd[0] <= 'Z')
-    token->terminal = TERMINAL_VARIABLE;
-  else
-    token->terminal = TERMINAL_LITERAL;
-
-  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 prompt character of specified node. */
 const char *
@@ -702,23 +286,23 @@ void
 install_element (enum node_type ntype, struct cmd_element *cmd)
 {
   struct cmd_node *cnode;
-  
+
   /* cmd_init hasn't been called */
   if (!cmdvec)
     return;
-  
+
   cnode = vector_slot (cmdvec, ntype);
 
-  if (cnode == NULL) 
+  if (cnode == NULL)
     {
       fprintf (stderr, "Command node %d doesn't exist, please check it\n",
-              ntype);
-      exit (1);
+               ntype);
+      exit (EXIT_FAILURE);
     }
 
+  // add node to command graph and command vector
+  command_parse_format (cnode->cmdgraph, cmd);
   vector_set (cnode->cmd_vector, cmd);
-  if (cmd->tokens == NULL)
-    cmd->tokens = cmd_parse_format(cmd->string, cmd->doc);
 }
 
 static const unsigned char itoa64[] =
@@ -727,7 +311,7 @@ static const unsigned char itoa64[] =
 static void
 to64(char *s, long v, int n)
 {
-  while (--n >= 0) 
+  while (--n >= 0)
     {
       *s++ = itoa64[v&0x3f];
       v >>= 6;
@@ -742,7 +326,7 @@ zencrypt (const char *passwd)
   char *crypt (const char *, const char *);
 
   gettimeofday(&tv,0);
-  
+
   to64(&salt[0], random(), 3);
   to64(&salt[3], tv.tv_usec, 3);
   salt[5] = '\0';
@@ -760,9 +344,9 @@ config_write_host (struct vty *vty)
   if (host.encrypt)
     {
       if (host.password_encrypt)
-        vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE); 
+        vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE);
       if (host.enable_encrypt)
-        vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE); 
+        vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE);
     }
   else
     {
@@ -775,17 +359,17 @@ config_write_host (struct vty *vty)
   if (zlog_default->default_lvl != LOG_DEBUG)
     {
       vty_out (vty, "! N.B. The 'log trap' command is deprecated.%s",
-              VTY_NEWLINE);
+               VTY_NEWLINE);
       vty_out (vty, "log trap %s%s",
-              zlog_priority[zlog_default->default_lvl], VTY_NEWLINE);
+               zlog_priority[zlog_default->default_lvl], VTY_NEWLINE);
     }
 
   if (host.logfile && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED))
     {
       vty_out (vty, "log file %s", host.logfile);
       if (zlog_default->maxlvl[ZLOG_DEST_FILE] != zlog_default->default_lvl)
-       vty_out (vty, " %s",
-                zlog_priority[zlog_default->maxlvl[ZLOG_DEST_FILE]]);
+        vty_out (vty, " %s",
+                 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_FILE]]);
       vty_out (vty, "%s", VTY_NEWLINE);
     }
 
@@ -793,8 +377,8 @@ config_write_host (struct vty *vty)
     {
       vty_out (vty, "log stdout");
       if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != zlog_default->default_lvl)
-       vty_out (vty, " %s",
-                zlog_priority[zlog_default->maxlvl[ZLOG_DEST_STDOUT]]);
+        vty_out (vty, " %s",
+                 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_STDOUT]]);
       vty_out (vty, "%s", VTY_NEWLINE);
     }
 
@@ -802,27 +386,27 @@ config_write_host (struct vty *vty)
     vty_out(vty,"no log monitor%s",VTY_NEWLINE);
   else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] != zlog_default->default_lvl)
     vty_out(vty,"log monitor %s%s",
-           zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],VTY_NEWLINE);
+            zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],VTY_NEWLINE);
 
   if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED)
     {
       vty_out (vty, "log syslog");
       if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != zlog_default->default_lvl)
-       vty_out (vty, " %s",
-                zlog_priority[zlog_default->maxlvl[ZLOG_DEST_SYSLOG]]);
+        vty_out (vty, " %s",
+                 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_SYSLOG]]);
       vty_out (vty, "%s", VTY_NEWLINE);
     }
 
   if (zlog_default->facility != LOG_DAEMON)
     vty_out (vty, "log facility %s%s",
-            facility_name(zlog_default->facility), VTY_NEWLINE);
+             facility_name(zlog_default->facility), VTY_NEWLINE);
 
   if (zlog_default->record_priority == 1)
     vty_out (vty, "log record-priority%s", VTY_NEWLINE);
 
   if (zlog_default->timestamp_precision > 0)
     vty_out (vty, "log timestamp precision %d%s",
-            zlog_default->timestamp_precision, VTY_NEWLINE);
+             zlog_default->timestamp_precision, VTY_NEWLINE);
 
   if (host.advanced)
     vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
@@ -832,7 +416,7 @@ config_write_host (struct vty *vty)
 
   if (host.lines >= 0)
     vty_out (vty, "service terminal-length %d%s", host.lines,
-            VTY_NEWLINE);
+             VTY_NEWLINE);
 
   if (host.motdfile)
     vty_out (vty, "banner motd file %s%s", host.motdfile, VTY_NEWLINE);
@@ -850,1556 +434,152 @@ cmd_node_vector (vector v, enum node_type ntype)
   return cnode->cmd_vector;
 }
 
-/* Completion match types. */
-enum match_type 
-{
-  no_match,
-  extend_match,
-  ipv4_prefix_match,
-  ipv4_match,
-  ipv6_prefix_match,
-  ipv6_match,
-  range_match,
-  vararg_match,
-  partly_match,
-  exact_match 
-};
-
-#define IPV4_ADDR_STR       "0123456789."
-#define IPV4_PREFIX_STR     "0123456789./"
-
-/**
- * Determines whether a string is a valid ipv4 token.
- *
- * @param[in] str the string to match
- * @return exact_match if the string is an exact match, no_match/partly_match
- *         otherwise
- */
-static enum match_type
-cmd_ipv4_match (const char *str)
-{
-  struct sockaddr_in sin_dummy;
-
-  if (str == NULL)
-    return partly_match;
-
-  if (strspn (str, IPV4_ADDR_STR) != strlen (str))
-    return no_match;
-
-  if (inet_pton(AF_INET, str, &sin_dummy.sin_addr) != 1)
-    return no_match;
-
-  return exact_match;
-}
-
-static enum match_type
-cmd_ipv4_prefix_match (const char *str)
-{
-  struct sockaddr_in sin_dummy;
-  const char *delim = "/\0";
-  char *dupe, *prefix, *mask, *context, *endptr;
-  int nmask = -1;
-
-  if (str == NULL)
-    return partly_match;
-
-  if (strspn (str, IPV4_PREFIX_STR) != strlen (str))
-    return no_match;
-
-  /* tokenize to address + mask */
-  dupe = XMALLOC(MTYPE_TMP, strlen(str)+1);
-  strncpy(dupe, str, strlen(str)+1);
-  prefix = strtok_r(dupe, delim, &context);
-  mask   = strtok_r(NULL, delim, &context);
-
-  if (!mask)
-    return partly_match;
-
-  /* validate prefix */
-  if (inet_pton(AF_INET, prefix, &sin_dummy.sin_addr) != 1)
-    return no_match;
-
-  /* validate mask */
-  nmask = strtol (mask, &endptr, 10);
-  if (*endptr != '\0' || nmask < 0 || nmask > 32)
-    return no_match;
-
-  XFREE(MTYPE_TMP, dupe);
-
-  return exact_match;
-}
-
-#define IPV6_ADDR_STR       "0123456789abcdefABCDEF:."
-#define IPV6_PREFIX_STR     "0123456789abcdefABCDEF:./"
-
-#ifdef HAVE_IPV6
-
-static enum match_type
-cmd_ipv6_match (const char *str)
+/* Utility function for getting command graph. */
+static struct graph *
+cmd_node_graph (vector v, enum node_type ntype)
 {
-  struct sockaddr_in6 sin6_dummy;
-  int ret;
-
-  if (str == NULL)
-    return partly_match;
-
-  if (strspn (str, IPV6_ADDR_STR) != strlen (str))
-    return no_match;
-
-  /* use inet_pton that has a better support,
-   * for example inet_pton can support the automatic addresses:
-   *  ::1.2.3.4
-   */
-  ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
-   
-  if (ret == 1)
-    return exact_match;
-
-  return no_match;
+  struct cmd_node *cnode = vector_slot (v, ntype);
+  return cnode->cmdgraph;
 }
 
-static enum match_type
-cmd_ipv6_prefix_match (const char *str)
-{
-  struct sockaddr_in6 sin6_dummy;
-  const char *delim = "/\0";
-  char *dupe, *prefix, *mask, *context, *endptr;
-  int nmask = -1;
-
-  if (str == NULL)
-    return partly_match;
-
-  if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
-    return no_match;
-
-  /* tokenize to address + mask */
-  dupe = XMALLOC(MTYPE_TMP, strlen(str)+1);
-  strncpy(dupe, str, strlen(str)+1);
-  prefix = strtok_r(dupe, delim, &context);
-  mask   = strtok_r(NULL, delim, &context);
-
-  if (!mask)
-    return partly_match;
-
-  /* validate prefix */
-  if (inet_pton(AF_INET6, prefix, &sin6_dummy.sin6_addr) != 1)
-    return no_match;
-
-  /* validate mask */
-  nmask = strtol (mask, &endptr, 10);
-  if (*endptr != '\0' || nmask < 0 || nmask > 128)
-    return no_match;
-
-  XFREE(MTYPE_TMP, dupe);
-
-  return exact_match;
+static int
+cmd_try_do_shortcut (enum node_type node, char* first_word) {
+  if ( first_word != NULL &&
+       node != AUTH_NODE &&
+       node != VIEW_NODE &&
+       node != AUTH_ENABLE_NODE &&
+       node != ENABLE_NODE &&
+       node != RESTRICTED_NODE &&
+       0 == strcmp( "do", first_word ) )
+    return 1;
+  return 0;
 }
 
-#endif /* HAVE_IPV6  */
-
-#define DECIMAL_STRLEN_MAX 20
-
+/**
+ * Compare function for cmd_token.
+ * Used with qsort to sort command completions.
+ */
 static int
-cmd_range_match (const char *range, const char *str)
+compare_completions (const void *fst, const void *snd)
 {
-  char *p;
-  char buf[DECIMAL_STRLEN_MAX + 1];
-  char *endptr = NULL;
-  signed long long min, max, val;
-
-  if (str == NULL)
-    return 1;
-
-  val = strtoll (str, &endptr, 10);
-  if (*endptr != '\0')
-    return 0;
-  val = llabs(val);
-
-  range++;
-  p = strchr (range, '-');
-  if (p == NULL)
-    return 0;
-  if (p - range > DECIMAL_STRLEN_MAX)
-    return 0;
-  strncpy (buf, range, p - range);
-  buf[p - range] = '\0';
-  min = strtoll (buf, &endptr, 10);
-  if (*endptr != '\0')
-    return 0;
-
-  range = p + 1;
-  p = strchr (range, '>');
-  if (p == NULL)
-    return 0;
-  if (p - range > DECIMAL_STRLEN_MAX)
-    return 0;
-  strncpy (buf, range, p - range);
-  buf[p - range] = '\0';
-  max = strtoll (buf, &endptr, 10);
-  if (*endptr != '\0')
-    return 0;
-
-  if (val < min || val > max)
-    return 0;
-
-  return 1;
+  struct cmd_token *first = *(struct cmd_token **) fst,
+                     *secnd = *(struct cmd_token **) snd;
+  return strcmp (first->text, secnd->text);
 }
 
-static enum match_type
-cmd_word_match(struct cmd_token *token,
-               enum filter_type filter,
-               const char *word)
+/**
+ * Takes a list of completions returned by command_complete,
+ * dedeuplicates them based on both text and description,
+ * and returns them as a vector.
+ */
+static vector
+completions_to_vec (struct list *completions)
 {
-  const char *str;
-  enum match_type match_type;
-
-  str = token->cmd;
-
-  if (filter == FILTER_RELAXED)
-    if (!word || !strlen(word))
-      return partly_match;
+  vector comps = vector_init (VECTOR_MIN_SIZE);
 
-  if (!word)
-    return no_match;
-
-  switch (token->terminal)
+  struct listnode *ln;
+  struct cmd_token *token;
+  unsigned int i, exists;
+  for (ALL_LIST_ELEMENTS_RO(completions,ln,token))
+  {
+    // linear search for token in completions vector
+    exists = 0;
+    for (i = 0; i < vector_active (comps) && !exists; i++)
     {
-      case TERMINAL_VARARG:
-        return vararg_match;
-
-      case TERMINAL_RANGE:
-        if (cmd_range_match(str, word))
-          return range_match;
-        break;
-
-      case TERMINAL_IPV6:
-        match_type = cmd_ipv6_match(word);
-        if ((filter == FILTER_RELAXED && match_type != no_match)
-          || (filter == FILTER_STRICT && match_type == exact_match))
-          return ipv6_match;
-        break;
-
-      case TERMINAL_IPV6_PREFIX:
-        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;
-        break;
-
-      case TERMINAL_IPV4:
-        match_type = cmd_ipv4_match(word);
-        if ((filter == FILTER_RELAXED && match_type != no_match)
-            || (filter == FILTER_STRICT && match_type == exact_match))
-          return ipv4_match;
-        break;
-
-      case TERMINAL_IPV4_PREFIX:
-        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;
-        break;
-
-      case TERMINAL_OPTION:
-      case TERMINAL_VARIABLE:
-        return extend_match;
-
-      case TERMINAL_LITERAL:
-        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;
-        break;
-
-      default:
-        assert (0);
+      struct cmd_token *curr = vector_slot (comps, i);
+      exists = !strcmp (curr->text, token->text) &&
+               !strcmp (curr->desc, token->desc);
     }
 
-  return no_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 */
-
-  /* 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 (!exists)
+      vector_set (comps, copy_cmd_token (token));
+  }
 
-  if (*argc >= CMD_ARGC_MAX)
-    return -1;
+  // sort completions
+  qsort (comps->index,
+         vector_active (comps),
+         sizeof (void *),
+         &compare_completions);
 
-  argv[(*argc)++] = arg;
-  return 0;
+  return comps;
 }
-
-static void
-cmd_matcher_record_match(struct cmd_matcher *matcher,
-                         enum match_type match_type,
-                         struct cmd_token *token)
+/**
+ * Generates a vector of cmd_token representing possible completions
+ * on the current input.
+ *
+ * @param vline the vectorized input line
+ * @param vty the vty with the node to match on
+ * @param status pointer to matcher status code
+ */
+static vector
+cmd_complete_command_real (vector vline, struct vty *vty, int *status)
 {
-  if (matcher->word_index != matcher->index)
-    return;
+  struct list *completions;
+  struct graph *cmdgraph = cmd_node_graph (cmdvec, vty->node);
 
-  if (matcher->match)
-    {
-      if (!*matcher->match)
-        *matcher->match = vector_init(VECTOR_MIN_SIZE);
-      vector_set(*matcher->match, token);
-    }
+  enum matcher_rv rv = command_complete (cmdgraph, vline, &completions);
 
-  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 (token->terminal == TERMINAL_OPTION)
-        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 (TERMINAL_RECORD (token->terminal))
-    {
-      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 (token->terminal == TERMINAL_VARARG)
-    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 MATCHER_OK;
-}
-
-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 = NULL;
-  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;
-  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 = MATCHER_OK;
-
-  keyword_mask = 0;
-  while (1)
-    {
-      if (!cmd_matcher_words_left(matcher))
-        return MATCHER_OK;
-
-      word = cmd_matcher_get_word(matcher);
-
-      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;
-            }
-        }
-
-      if (keyword_found == (unsigned int)-1)
-        return MATCHER_NO_MATCH;
-
-      matcher->word_index++;
-
-      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
-                       && TERMINAL_RECORD (word_token->terminal))
-                      || 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 = MATCHER_OK;
-
-  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;
-          }
-      }
-  *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 (vector cmd_vector,
-                  const char *command,
-                  vector matches,
-                  enum match_type type)
-{
-  unsigned int i;
-  unsigned int j;
-  const char *str = NULL;
-  const char *matched = NULL;
-  vector match_vector;
-  struct cmd_token *cmd_token;
-
-  if (command == NULL)
-    command = "";
-
-  for (i = 0; i < vector_active (matches); i++)
-    if ((match_vector = vector_slot (matches, i)) != NULL)
-      {
-       int match = 0;
-
-       for (j = 0; j < vector_active (match_vector); j++)
-         if ((cmd_token = vector_slot (match_vector, j)) != NULL)
-           {
-             enum match_type ret;
-
-             assert(cmd_token->type == TOKEN_TERMINAL);
-             if (cmd_token->type != TOKEN_TERMINAL)
-               continue;
-
-             str = cmd_token->cmd;
-
-             switch (type)
-               {
-               case exact_match:
-                 if (!TERMINAL_RECORD (cmd_token->terminal)
-                     && strcmp (command, str) == 0)
-                   match++;
-                 break;
-               case partly_match:
-                 if (!TERMINAL_RECORD (cmd_token->terminal)
-                     && strncmp (command, str, strlen (command)) == 0)
-                   {
-                     if (matched && strcmp (matched, str) != 0)
-                       return 1;       /* There is ambiguous match. */
-                     else
-                       matched = str;
-                     match++;
-                   }
-                 break;
-               case range_match:
-                 if (cmd_range_match (str, command))
-                   {
-                     if (matched && strcmp (matched, str) != 0)
-                       return 1;
-                     else
-                       matched = str;
-                     match++;
-                   }
-                 break;
-#ifdef HAVE_IPV6
-               case ipv6_match:
-                 if (cmd_token->terminal == TERMINAL_IPV6)
-                   match++;
-                 break;
-               case ipv6_prefix_match:
-                 if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
-                   {
-                     if (ret == partly_match)
-                       return 2;       /* There is incomplete match. */
-
-                     match++;
-                   }
-                 break;
-#endif /* HAVE_IPV6 */
-               case ipv4_match:
-                 if (cmd_token->terminal == TERMINAL_IPV4)
-                   match++;
-                 break;
-               case ipv4_prefix_match:
-                 if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
-                   {
-                     if (ret == partly_match)
-                       return 2;       /* There is incomplete match. */
-
-                     match++;
-                   }
-                 break;
-               case extend_match:
-                 if (TERMINAL_RECORD (cmd_token->terminal))
-                   match++;
-                 break;
-               case no_match:
-               default:
-                 break;
-               }
-           }
-       if (!match)
-         vector_slot (cmd_vector, i) = NULL;
-      }
-  return 0;
-}
-
-/* If src matches dst return dst string, otherwise return NULL */
-static const char *
-cmd_entry_function (const char *src, struct cmd_token *token)
-{
-  const char *dst = token->cmd;
-
-  /* Skip variable arguments. */
-  if (TERMINAL_RECORD (token->terminal))
-    return NULL;
-
-  /* In case of 'command \t', given src is NULL string. */
-  if (src == NULL)
-    return dst;
-
-  /* Matched with input string. */
-  if (strncmp (src, dst, strlen (src)) == 0)
-    return dst;
-
-  return NULL;
-}
-
-/* If src matches dst return dst string, otherwise return NULL */
-/* This version will return the dst string always if it is
-   CMD_VARIABLE for '?' key processing */
-static const char *
-cmd_entry_function_desc (const char *src, struct cmd_token *token)
-{
-  const char *dst = token->cmd;
-
-  switch (token->terminal)
+  if (MATCHER_ERROR(rv))
+  {
+    switch (rv)
     {
-      case TERMINAL_VARARG:
-        return dst;
-
-      case TERMINAL_RANGE:
-        if (cmd_range_match (dst, src))
-          return dst;
-        else
-          return NULL;
-
-      case TERMINAL_IPV6:
-        if (cmd_ipv6_match (src))
-          return dst;
-        else
-          return NULL;
-
-      case TERMINAL_IPV6_PREFIX:
-        if (cmd_ipv6_prefix_match (src))
-          return dst;
-        else
-          return NULL;
-
-      case TERMINAL_IPV4:
-        if (cmd_ipv4_match (src))
-          return dst;
-        else
-          return NULL;
-
-      case TERMINAL_IPV4_PREFIX:
-        if (cmd_ipv4_prefix_match (src))
-          return dst;
-        else
-          return NULL;
-
-      /* Optional or variable commands always match on '?' */
-      case TERMINAL_OPTION:
-      case TERMINAL_VARIABLE:
-        return dst;
-
-      case TERMINAL_LITERAL:
-        /* In case of 'command \t', given src is NULL string. */
-        if (src == NULL)
-          return dst;
-
-        if (strncmp (src, dst, strlen (src)) == 0)
-          return dst;
-        else
-          return NULL;
-
+      case MATCHER_AMBIGUOUS:
+        *status = CMD_ERR_AMBIGUOUS;
       default:
-        assert(0);
-        return NULL;
-    }
-}
-
-/**
- * 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)
-{
-  unsigned int i;
-  char *match;
-
-  for (i = 0; i < vector_active (v); i++)
-    if ((match = vector_slot (v, i)) != NULL)
-      if (strcmp (match, str) == 0)
-       return 0;
-  return 1;
-}
-
-/**
- * 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 cmd_token *token;
-
-  for (i = 0; i < vector_active (v); i++)
-    if ((token = vector_slot (v, i)) != NULL)
-      if (strcmp (token->cmd, str) == 0)
-       return 0;
-  return 1;
-}
-
-static int 
-cmd_try_do_shortcut (enum node_type node, char* first_word) {
-  if ( first_word != NULL &&
-       node != AUTH_NODE &&
-       node != VIEW_NODE &&
-       node != AUTH_ENABLE_NODE &&
-       node != ENABLE_NODE &&
-       node != RESTRICTED_NODE &&
-       0 == strcmp( "do", first_word ) )
-    return 1;
-  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)
-{
-  unsigned int i;
-  vector cmd_vector;
-#define INIT_MATCHVEC_SIZE 10
-  vector matchvec;
-  struct cmd_element *cmd_element;
-  unsigned int index;
-  int ret;
-  enum match_type match;
-  char *command;
-  vector matches = NULL;
-  vector match_vector;
-  uint32_t command_found = 0;
-  const char *last_word;
-
-  /* Set index. */
-  if (vector_active (vline) == 0)
-    {
-      *status = CMD_ERR_NO_MATCH;
-      return NULL;
-    }
-
-  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 and build a list how they could possibly continue. */
-  for (i = 0; i <= index; i++)
-    {
-      command = vector_slot (vline, i);
-
-      if (matches)
-       cmd_matches_free(&matches);
-
-      ret = cmd_vector_filter(cmd_vector,
-                             FILTER_RELAXED,
-                             vline, i,
-                             &match,
-                             &matches);
-
-      if (ret != CMD_SUCCESS)
-       {
-         vector_free (cmd_vector);
-         vector_free (matchvec);
-         cmd_matches_free(&matches);
-         *status = ret;
-         return NULL;
-       }
-
-      /* 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;
-       }
-
-      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 (matches); i++) {
-    if ((cmd_element = vector_slot (cmd_vector, i)) != NULL &&
-        !(cmd_element->attr == CMD_ATTR_DEPRECATED ||
-          cmd_element->attr == CMD_ATTR_HIDDEN))
-      {
-        unsigned int j;
-        vector vline_trimmed;
-
-       command_found++;
-        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);
-              if (string && desc_unique_string(matchvec, string))
-                vector_set(matchvec, token);
-            }
-      }
-  }
-
-  /*
-   * We can get into this situation when the command is complete
-   * but the last part of the command is an optional piece of
-   * cli.
-   */
-  last_word = vector_slot(vline, vector_active(vline) - 1);
-  if (command_found == 0 && (last_word == NULL || !strlen(last_word))) {
-    vector_set(matchvec, &token_cr);
-  }
-
-  vector_free (cmd_vector);
-  cmd_matches_free(&matches);
-
-  if (vector_slot (matchvec, 0) == NULL)
-    {
-      vector_free (matchvec);
-      *status = CMD_ERR_NO_MATCH;
-      return NULL;
+        *status = CMD_ERR_NO_MATCH;
     }
-
-  *status = CMD_SUCCESS;
-  cmd_describe_sort(matchvec);
-  return matchvec;
-}
-
-vector
-cmd_describe_command (vector vline, struct vty *vty, int *status)
-{
-  vector ret;
-
-  if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
-    {
-      enum node_type onode;
-      vector shifted_vline;
-      unsigned int index;
-
-      onode = vty->node;
-      vty->node = ENABLE_NODE;
-      /* We can try it on enable node, cos' the vty is authenticated */
-
-      shifted_vline = vector_init (vector_count(vline));
-      /* use memcpy? */
-      for (index = 1; index < vector_active (vline); index++) 
-       {
-         vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
-       }
-
-      ret = cmd_describe_command_real (shifted_vline, vty, status);
-
-      vector_free(shifted_vline);
-      vty->node = onode;
-      return ret;
+    return NULL;
   }
 
+  vector comps = completions_to_vec (completions);
+  list_delete (completions);
 
-  return cmd_describe_command_real (vline, vty, status);
-}
-
-
-/* Check LCD of matched command. */
-static int
-cmd_lcd (char **matched)
-{
-  int i;
-  int j;
-  int lcd = -1;
-  char *s1, *s2;
-  char c1, c2;
-
-  if (matched[0] == NULL || matched[1] == NULL)
-    return 0;
-
-  for (i = 1; matched[i] != NULL; i++)
-    {
-      s1 = matched[i - 1];
-      s2 = matched[i];
-
-      for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
-       if (c1 != c2)
-         break;
-
-      if (lcd < 0)
-       lcd = j;
-      else
-       {
-         if (lcd > j)
-           lcd = j;
-       }
-    }
-  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, int islib)
-{
-  unsigned int i;
-  vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
-#define INIT_MATCHVEC_SIZE 10
-  vector matchvec;
-  unsigned int index;
-  char **match_str;
-  struct cmd_token *token;
-  char *command;
-  int lcd;
-  vector matches = NULL;
-  vector match_vector;
-
-  if (vector_active (vline) == 0)
-    {
-      vector_free (cmd_vector);
-      *status = CMD_ERR_NO_MATCH;
-      return NULL;
-    }
-  else
-    index = vector_active (vline) - 1;
-
-  /* First, filter by command string */
-  for (i = 0; i <= index; i++)
-    {
-      command = vector_slot (vline, i);
-      enum match_type match;
-      int ret;
-
-      if (matches)
-        cmd_matches_free(&matches);
-
-      /* 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;
-       }
-    }
-  
-  /* Prepare match vector. */
-  matchvec = vector_init (INIT_MATCHVEC_SIZE);
-
-  /* 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;
-       unsigned int j;
+  // set status code appropriately
+  switch (vector_active (comps))
+  {
+    case 0:
+      *status = CMD_ERR_NO_MATCH;
+      break;
+    case 1:
+      *status = CMD_COMPLETE_FULL_MATCH;
+      break;
+    default:
+      *status = CMD_COMPLETE_LIST_MATCH;
+  }
 
-       for (j = 0; j < vector_active (match_vector); j++)
-         if ((token = vector_slot (match_vector, j)))
-            {
-              string = cmd_entry_function (vector_slot (vline, index),
-                                           token);
-              if (string && cmd_unique_string (matchvec, string))
-                vector_set (matchvec, (islib != 0 ?
-                                      XSTRDUP (MTYPE_TMP, string) :
-                                      strdup (string) /* rl freed */));
-            }
-      }
+  return comps;
+}
 
-  /* We don't need cmd_vector any more. */
-  vector_free (cmd_vector);
-  cmd_matches_free(&matches);
+vector
+cmd_describe_command (vector vline, struct vty *vty, int *status)
+{
+  vector ret;
 
-  /* No matched command */
-  if (vector_slot (matchvec, 0) == NULL)
+  if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
     {
-      vector_free (matchvec);
+      enum node_type onode;
+      vector shifted_vline;
+      unsigned int index;
 
-      /* In case of 'command \t' pattern.  Do you need '?' command at
-         the end of the line. */
-      if (vector_slot (vline, index) == '\0')
-       *status = CMD_ERR_NOTHING_TODO;
-      else
-       *status = CMD_ERR_NO_MATCH;
-      return NULL;
-    }
+      onode = vty->node;
+      vty->node = ENABLE_NODE;
+      /* We can try it on enable node, cos' the vty is authenticated */
 
-  /* Only one matched */
-  if (vector_slot (matchvec, 1) == NULL)
-    {
-      match_str = (char **) matchvec->index;
-      vector_only_wrapper_free (matchvec);
-      *status = CMD_COMPLETE_FULL_MATCH;
-      return match_str;
-    }
-  /* Make it sure last element is NULL. */
-  vector_set (matchvec, NULL);
+      shifted_vline = vector_init (vector_count(vline));
+      /* use memcpy? */
+      for (index = 1; index < vector_active (vline); index++)
+        {
+          vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
+        }
 
-  /* Check LCD of matched strings. */
-  if (vector_slot (vline, index) != NULL)
-    {
-      lcd = cmd_lcd ((char **) matchvec->index);
-
-      if (lcd)
-       {
-         int len = strlen (vector_slot (vline, index));
-
-         if (len < lcd)
-           {
-             char *lcdstr;
-
-             lcdstr = (islib != 0 ?
-                        XMALLOC (MTYPE_TMP, lcd + 1) :
-                        malloc(lcd + 1));
-             memcpy (lcdstr, matchvec->index[0], lcd);
-             lcdstr[lcd] = '\0';
-
-             /* Free matchvec. */
-             for (i = 0; i < vector_active (matchvec); i++)
-                {
-                  if (vector_slot (matchvec, i))
-                    {
-                      if (islib != 0)
-                        XFREE (MTYPE_TMP, vector_slot (matchvec, i));
-                      else
-                        free (vector_slot (matchvec, i));
-                    }
-                }
-             vector_free (matchvec);
-
-             /* Make new matchvec. */
-             matchvec = vector_init (INIT_MATCHVEC_SIZE);
-             vector_set (matchvec, lcdstr);
-             match_str = (char **) matchvec->index;
-             vector_only_wrapper_free (matchvec);
-
-             *status = CMD_COMPLETE_MATCH;
-             return match_str;
-           }
-       }
-    }
+      ret = cmd_complete_command_real (shifted_vline, vty, status);
+
+      vector_free(shifted_vline);
+      vty->node = onode;
+      return ret;
+  }
 
-  match_str = (char **) matchvec->index;
-  cmd_complete_sort(matchvec);
-  vector_only_wrapper_free (matchvec);
-  *status = CMD_COMPLETE_LIST_MATCH;
-  return match_str;
+  return cmd_complete_command_real (vline, vty, status);
 }
 
 char **
@@ -2419,19 +599,41 @@ cmd_complete_command_lib (vector vline, struct vty *vty, int *status, int islib)
 
       shifted_vline = vector_init (vector_count(vline));
       /* use memcpy? */
-      for (index = 1; index < vector_active (vline); index++) 
-       {
-         vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
-       }
+      for (index = 1; index < vector_active (vline); index++)
+        {
+          vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
+        }
 
-      ret = cmd_complete_command_real (shifted_vline, vty, status, islib);
+      // get token completions
+      vector comps = cmd_complete_command_real (shifted_vline, vty, status);
+      ret = XMALLOC (MTYPE_TMP, vector_active (comps) * sizeof (char *));
+      for (unsigned int i = 0; i < vector_active (comps); i++)
+        {
+          struct cmd_token *token = vector_slot (comps, i);
+          ret[i] = XSTRDUP (MTYPE_TMP, token->text);
+          vector_unset (comps, i);
+          del_cmd_token (token);
+        }
+      vector_free (comps);
 
       vector_free(shifted_vline);
       vty->node = onode;
       return ret;
   }
 
-  return cmd_complete_command_real (vline, vty, status, islib);
+  // get token completions
+  vector comps = cmd_complete_command_real (vline, vty, status);
+  ret = XMALLOC (MTYPE_TMP, vector_active (comps) * sizeof (char *));
+  for (unsigned int i = 0; i < vector_active (comps); i++)
+    {
+      struct cmd_token *token = vector_slot (comps, i);
+      ret[i] = XSTRDUP (MTYPE_TMP, token->text);
+      vector_unset (comps, i);
+      del_cmd_token (token);
+    }
+  vector_free (comps);
+
+  return ret;
 }
 
 char **
@@ -2474,109 +676,47 @@ node_parent ( enum node_type node )
 /* Execute command by argument vline vector. */
 static int
 cmd_execute_command_real (vector vline,
-                         enum filter_type filter,
-                         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];
-  enum match_type match = 0;
-  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++)
-    {
-      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)
-       {
-         cmd_matches_free(&matches);
-         break;
-       }
-
-      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;
-  matched_count = 0;
-  incomplete_count = 0;
-
-  for (i = 0; i < vector_active (cmd_vector); i++)
-    if ((cmd_element = vector_slot (cmd_vector, i)))
-      {
-       if (cmd_is_complete(cmd_element, vline))
-         {
-           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;
+                          enum filter_type filter,
+                          struct vty *vty,
+                          struct cmd_element **cmd)
+{
+  struct list *argv_list;
+  enum matcher_rv status;
+  struct graph *cmdgraph = cmd_node_graph (cmdvec, vty->node);
+  status = command_match (cmdgraph, vline, &argv_list, cmd);
+
+  // if matcher error, return corresponding CMD_ERR
+  if (MATCHER_ERROR(status))
+    switch (status)
+    {
+      case MATCHER_INCOMPLETE:
+        return CMD_ERR_INCOMPLETE;
+      case MATCHER_AMBIGUOUS:
+        return CMD_ERR_AMBIGUOUS;
+      default:
+        return CMD_ERR_NO_MATCH;
     }
 
-  if (matched_count > 1)
-    return CMD_ERR_AMBIGUOUS;
+  // build argv array from argv list
+  struct cmd_token **argv = XMALLOC (MTYPE_TMP, argv_list->count * sizeof (struct cmd_token *));
+  struct listnode *ln;
+  struct cmd_token *token;
+  unsigned int i = 0;
+  for (ALL_LIST_ELEMENTS_RO(argv_list,ln,token))
+    argv[i++] = token;
 
-  ret = cmd_parse(matched_element, vline, &argc, argv);
-  if (ret != CMD_SUCCESS)
-    return ret;
+  int argc = argv_list->count;
 
-  /* For vtysh execution. */
-  if (cmd)
-    *cmd = matched_element;
+  int ret;
+  if ((*cmd)->daemon)
+    ret = CMD_SUCCESS_DAEMON;
+  else
+    ret = (*cmd)->func (*cmd, vty, argc, argv);
 
-  if (matched_element->daemon)
-    return CMD_SUCCESS_DAEMON;
+  // delete list and cmd_token's in it
+  list_delete (argv_list);
 
-  /* Execute matched command. */
-  return (*matched_element->func) (matched_element, vty, argc, argv);
+  return ret;
 }
 
 /**
@@ -2596,7 +736,7 @@ cmd_execute_command_real (vector vline,
  */
 int
 cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
-                    int vtysh) {
+                     int vtysh) {
   int ret, saved_ret = 0;
   enum node_type onode, try_node;
 
@@ -2612,7 +752,7 @@ cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
 
       shifted_vline = vector_init (vector_count(vline));
       /* use memcpy? */
-      for (index = 1; index < vector_active (vline); index++) 
+      for (index = 1; index < vector_active (vline); index++)
         vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
 
       ret = cmd_execute_command_real (shifted_vline, FILTER_RELAXED, vty, cmd);
@@ -2662,7 +802,7 @@ cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
  */
 int
 cmd_execute_command_strict (vector vline, struct vty *vty,
-                           struct cmd_element **cmd)
+                            struct cmd_element **cmd)
 {
   return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd);
 }
@@ -2706,7 +846,7 @@ command_config_read_one_line (struct vty *vty, struct cmd_element **cmd, int use
 
     while (!(use_daemon && ret == CMD_SUCCESS_DAEMON) &&
            !(!use_daemon && ret == CMD_ERR_NOTHING_TODO) &&
-          ret != CMD_SUCCESS &&
+           ret != CMD_SUCCESS &&
            ret != CMD_WARNING &&
            vty->node > CONFIG_NODE) {
       vty->node = node_parent(vty->node);
@@ -2717,11 +857,11 @@ command_config_read_one_line (struct vty *vty, struct cmd_element **cmd, int use
     // stay at the same node
     if (!(use_daemon && ret == CMD_SUCCESS_DAEMON) &&
         !(!use_daemon && ret == CMD_ERR_NOTHING_TODO) &&
-       ret != CMD_SUCCESS &&
+        ret != CMD_SUCCESS &&
         ret != CMD_WARNING)
       {
-       vty->node = saved_node;
-       memcpy(vty->error_buf, vty->buf, VTY_BUFSIZ);
+        vty->node = saved_node;
+        memcpy(vty->error_buf, vty->buf, VTY_BUFSIZ);
       }
   }
 
@@ -2740,13 +880,13 @@ config_from_file (struct vty *vty, FILE *fp, unsigned int *line_num)
   while (fgets (vty->buf, VTY_BUFSIZ, fp))
     {
       if (!error_ret)
-       ++(*line_num);
+        ++(*line_num);
 
       ret = command_config_read_one_line (vty, NULL, 0);
 
       if (ret != CMD_SUCCESS && ret != CMD_WARNING &&
-         ret != CMD_ERR_NOTHING_TODO)
-       error_ret = ret;
+          ret != CMD_ERR_NOTHING_TODO)
+        error_ret = ret;
     }
 
   if (error_ret) {
@@ -2774,7 +914,7 @@ DEFUN (config_terminal,
 }
 
 /* Enable command */
-DEFUN (enable, 
+DEFUN (enable,
        config_enable_cmd,
        "enable",
        "Turn on privileged mode command\n")
@@ -2790,7 +930,7 @@ DEFUN (enable,
 }
 
 /* Disable command */
-DEFUN (disable, 
+DEFUN (disable,
        config_disable_cmd,
        "disable",
        "Turn off privileged mode command\n")
@@ -2812,9 +952,9 @@ DEFUN (config_exit,
     case ENABLE_NODE:
     case RESTRICTED_NODE:
       if (vty_shell (vty))
-       exit (0);
+        exit (0);
       else
-       vty->status = VTY_CLOSE;
+        vty->status = VTY_CLOSE;
       break;
     case CONFIG_NODE:
       vty->node = ENABLE_NODE;
@@ -2860,7 +1000,7 @@ ALIAS (config_exit,
        config_quit_cmd,
        "quit",
        "Exit current mode and down to previous mode\n")
-       
+
 /* End of configuration. */
 DEFUN (config_end,
        config_end_cmd,
@@ -2915,7 +1055,7 @@ DEFUN (show_version,
        "Displays zebra version\n")
 {
   vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
-          VTY_NEWLINE);
+           VTY_NEWLINE);
   vty_out (vty, "%s%s%s", QUAGGA_COPYRIGHT, GIT_INFO, VTY_NEWLINE);
   vty_out (vty, "configured with:%s    %s%s", VTY_NEWLINE,
            QUAGGA_CONFIG_ARGS, VTY_NEWLINE);
@@ -2929,8 +1069,8 @@ DEFUN (config_help,
        "help",
        "Description of the interactive help system\n")
 {
-  vty_out (vty, 
-          "Quagga VTY provides advanced help feature.  When you need help,%s\
+  vty_out (vty,
+           "Quagga VTY provides advanced help feature.  When you need help,%s\
 anytime at the command line please press '?'.%s\
 %s\
 If nothing matches, the help list will be empty and you must backup%s\
@@ -2942,8 +1082,8 @@ argument.%s\
 2. Partial help is provided when an abbreviated argument is entered%s\
    and you want to know what arguments match the input%s\
    (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
-          VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
-          VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+           VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
+           VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
   return CMD_SUCCESS;
 }
 
@@ -2962,16 +1102,18 @@ DEFUN (config_list,
         && !(cmd->attr == CMD_ATTR_DEPRECATED
              || cmd->attr == CMD_ATTR_HIDDEN))
       vty_out (vty, "  %s%s", cmd->string,
-              VTY_NEWLINE);
+               VTY_NEWLINE);
   return CMD_SUCCESS;
 }
 
 /* Write current configuration into file. */
-DEFUN (config_write_file, 
-       config_write_file_cmd,
-       "write file",  
+DEFUN (config_write,
+       config_write_cmd,
+       "write [<file|memory|terminal>]",
        "Write running configuration to memory, network, or terminal\n"
-       "Write to configuration file\n")
+       "Write to configuration file\n"
+       "Write configuration currently in memory\n"
+       "Write configuration to terminal\n")
 {
   unsigned int i;
   int fd;
@@ -2983,17 +1125,47 @@ DEFUN (config_write_file,
   struct vty *file_vty;
   struct stat conf_stat;
 
+  // if command was 'write terminal' or 'show running-config'
+  if (argc == 2 && (!strcmp(argv[1]->arg, "terminal") ||
+                    !strcmp(argv[1]->arg, "running-config")))
+  {
+    if (vty->type == VTY_SHELL_SERV)
+      {
+        for (i = 0; i < vector_active (cmdvec); i++)
+          if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
+            {
+              if ((*node->func) (vty))
+                vty_out (vty, "!%s", VTY_NEWLINE);
+            }
+      }
+    else
+      {
+        vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
+                 VTY_NEWLINE);
+        vty_out (vty, "!%s", VTY_NEWLINE);
+
+        for (i = 0; i < vector_active (cmdvec); i++)
+          if ((node = vector_slot (cmdvec, i)) && node->func)
+            {
+              if ((*node->func) (vty))
+                vty_out (vty, "!%s", VTY_NEWLINE);
+            }
+        vty_out (vty, "end%s",VTY_NEWLINE);
+      }
+    return CMD_SUCCESS;
+  }
+
   /* Check and see if we are operating under vtysh configuration */
   if (host.config == NULL)
     {
       vty_out (vty, "Can't save to configuration file, using vtysh.%s",
-              VTY_NEWLINE);
+               VTY_NEWLINE);
       return CMD_WARNING;
     }
 
   /* Get filename. */
   config_file = host.config;
-  
+
   config_file_sav =
     XMALLOC (MTYPE_TMP, strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
   strcpy (config_file_sav, config_file);
@@ -3002,16 +1174,16 @@ DEFUN (config_write_file,
 
   config_file_tmp = XMALLOC (MTYPE_TMP, strlen (config_file) + 8);
   sprintf (config_file_tmp, "%s.XXXXXX", config_file);
-  
+
   /* Open file to configuration write. */
   fd = mkstemp (config_file_tmp);
   if (fd < 0)
     {
       vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
-              VTY_NEWLINE);
+               VTY_NEWLINE);
       goto finished;
     }
-  
+
   /* Make vty for configuration file. */
   file_vty = vty_new ();
   file_vty->wfd = fd;
@@ -3025,51 +1197,51 @@ DEFUN (config_write_file,
   for (i = 0; i < vector_active (cmdvec); i++)
     if ((node = vector_slot (cmdvec, i)) && node->func)
       {
-       if ((*node->func) (file_vty))
-         vty_out (file_vty, "!\n");
+        if ((*node->func) (file_vty))
+          vty_out (file_vty, "!\n");
       }
   vty_close (file_vty);
 
   if (stat(config_file, &conf_stat) >= 0)
     {
       if (unlink (config_file_sav) != 0)
-       if (errno != ENOENT)
-         {
-           vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
-                    VTY_NEWLINE);
-           goto finished;
-         }
+        if (errno != ENOENT)
+          {
+            vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
+                     VTY_NEWLINE);
+            goto finished;
+          }
       if (link (config_file, config_file_sav) != 0)
-       {
-         vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
-                  VTY_NEWLINE);
-         goto finished;
-       }
+        {
+          vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
+                   VTY_NEWLINE);
+          goto finished;
+        }
       sync ();
       if (unlink (config_file) != 0)
-       {
-         vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
-                  VTY_NEWLINE);
-         goto finished;
-       }
+        {
+          vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
+                   VTY_NEWLINE);
+          goto finished;
+        }
     }
   if (link (config_file_tmp, config_file) != 0)
     {
       vty_out (vty, "Can't save configuration file %s.%s", config_file,
-              VTY_NEWLINE);
+               VTY_NEWLINE);
       goto finished;
     }
   sync ();
-  
+
   if (chmod (config_file, CONFIGFILE_MASK) != 0)
     {
-      vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s", 
-       config_file, safe_strerror(errno), errno, VTY_NEWLINE);
+      vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
+        config_file, safe_strerror(errno), errno, VTY_NEWLINE);
       goto finished;
     }
 
   vty_out (vty, "Configuration saved to %s%s", config_file,
-          VTY_NEWLINE);
+           VTY_NEWLINE);
   ret = CMD_SUCCESS;
 
 finished:
@@ -3079,62 +1251,15 @@ finished:
   return ret;
 }
 
-ALIAS (config_write_file, 
-       config_write_cmd,
-       "write",  
-       "Write running configuration to memory, network, or terminal\n")
-
-ALIAS (config_write_file, 
-       config_write_memory_cmd,
-       "write memory",  
-       "Write running configuration to memory, network, or terminal\n"
-       "Write configuration to the file (same as write file)\n")
-
-ALIAS (config_write_file, 
+ALIAS (config_write,
        copy_runningconfig_startupconfig_cmd,
-       "copy running-config startup-config",  
+       "copy running-config startup-config",
        "Copy configuration\n"
        "Copy running config to... \n"
        "Copy running config to startup config (same as write file)\n")
 
 /* Write current configuration into the terminal. */
-DEFUN (config_write_terminal,
-       config_write_terminal_cmd,
-       "write terminal",
-       "Write running configuration to memory, network, or terminal\n"
-       "Write to terminal\n")
-{
-  unsigned int i;
-  struct cmd_node *node;
-
-  if (vty->type == VTY_SHELL_SERV)
-    {
-      for (i = 0; i < vector_active (cmdvec); i++)
-       if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
-         {
-           if ((*node->func) (vty))
-             vty_out (vty, "!%s", VTY_NEWLINE);
-         }
-    }
-  else
-    {
-      vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
-              VTY_NEWLINE);
-      vty_out (vty, "!%s", VTY_NEWLINE);
-
-      for (i = 0; i < vector_active (cmdvec); i++)
-       if ((node = vector_slot (cmdvec, i)) && node->func)
-         {
-           if ((*node->func) (vty))
-             vty_out (vty, "!%s", VTY_NEWLINE);
-         }
-      vty_out (vty, "end%s",VTY_NEWLINE);
-    }
-  return CMD_SUCCESS;
-}
-
-/* Write current configuration into the terminal. */
-ALIAS (config_write_terminal,
+ALIAS (config_write,
        show_running_config_cmd,
        "show running-config",
        SHOW_STR
@@ -3145,7 +1270,7 @@ DEFUN (show_startup_config,
        show_startup_config_cmd,
        "show startup-config",
        SHOW_STR
-       "Contentes of startup configuration\n")
+       "Contents of startup configuration\n")
 {
   char buf[BUFSIZ];
   FILE *confp;
@@ -3154,7 +1279,7 @@ DEFUN (show_startup_config,
   if (confp == NULL)
     {
       vty_out (vty, "Can't open configuration file [%s] due to '%s'%s",
-              host.config, safe_strerror(errno), VTY_NEWLINE);
+               host.config, safe_strerror(errno), VTY_NEWLINE);
       return CMD_WARNING;
     }
 
@@ -3163,7 +1288,7 @@ DEFUN (show_startup_config,
       char *cp = buf;
 
       while (*cp != '\r' && *cp != '\n' && *cp != '\0')
-       cp++;
+        cp++;
       *cp = '\0';
 
       vty_out (vty, "%s%s", buf, VTY_NEWLINE);
@@ -3175,13 +1300,15 @@ DEFUN (show_startup_config,
 }
 
 /* Hostname configuration */
-DEFUN (config_hostname, 
+DEFUN (config_hostname,
        hostname_cmd,
        "hostname WORD",
        "Set system's network name\n"
        "This system's network name\n")
 {
-  if (!isalpha((int) *argv[0]))
+  struct cmd_token *word = argv[1];
+
+  if (!isalpha((int) word->arg[0]))
     {
       vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
       return CMD_WARNING;
@@ -3189,12 +1316,12 @@ DEFUN (config_hostname,
 
   if (host.name)
     XFREE (MTYPE_HOST, host.name);
-    
-  host.name = XSTRDUP (MTYPE_HOST, argv[0]);
+
+  host.name = XSTRDUP (MTYPE_HOST, word->arg);
   return CMD_SUCCESS;
 }
 
-DEFUN (config_no_hostname, 
+DEFUN (config_no_hostname,
        no_hostname_cmd,
        "no hostname [HOSTNAME]",
        NO_STR
@@ -3209,42 +1336,26 @@ DEFUN (config_no_hostname,
 
 /* VTY interface password set. */
 DEFUN (config_password, password_cmd,
-       "password (8|) WORD",
+       "password [8] WORD",
        "Assign the terminal connection password\n"
        "Specifies a HIDDEN password will follow\n"
-       "dummy string \n"
-       "The HIDDEN line password string\n")
+       "The password string\n")
 {
-  /* Argument check. */
-  if (argc == 0)
-    {
-      vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
-      return CMD_WARNING;
-    }
-
-  if (argc == 2)
-    {
-      if (*argv[0] == '8')
-       {
-         if (host.password)
-           XFREE (MTYPE_HOST, host.password);
-         host.password = NULL;
-         if (host.password_encrypt)
-           XFREE (MTYPE_HOST, host.password_encrypt);
-         host.password_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
-         return CMD_SUCCESS;
-       }
-      else
-       {
-         vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
-         return CMD_WARNING;
-       }
-    }
+  if (argc == 3) // '8' was specified
+  {
+    if (host.password)
+      XFREE (MTYPE_HOST, host.password);
+    host.password = NULL;
+    if (host.password_encrypt)
+      XFREE (MTYPE_HOST, host.password_encrypt);
+    host.password_encrypt = XSTRDUP (MTYPE_HOST, argv[2]->arg);
+    return CMD_SUCCESS;
+  }
 
-  if (!isalnum ((int) *argv[0]))
+  if (!isalnum (argv[1]->arg[0]))
     {
-      vty_out (vty, 
-              "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
+      vty_out (vty,
+               "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
       return CMD_WARNING;
     }
 
@@ -3255,62 +1366,50 @@ DEFUN (config_password, password_cmd,
   if (host.encrypt)
     {
       if (host.password_encrypt)
-       XFREE (MTYPE_HOST, host.password_encrypt);
-      host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
+        XFREE (MTYPE_HOST, host.password_encrypt);
+      host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[1]->arg));
     }
   else
-    host.password = XSTRDUP (MTYPE_HOST, argv[0]);
+    host.password = XSTRDUP (MTYPE_HOST, argv[1]->arg);
 
   return CMD_SUCCESS;
 }
 
-ALIAS (config_password, password_text_cmd,
-       "password LINE",
-       "Assign the terminal connection password\n"
-       "The UNENCRYPTED (cleartext) line password\n")
-
 /* VTY enable password set. */
 DEFUN (config_enable_password, enable_password_cmd,
-       "enable password (8|) WORD",
+       "enable password [8] WORD",
        "Modify enable password parameters\n"
        "Assign the privileged level password\n"
        "Specifies a HIDDEN password will follow\n"
        "dummy string \n"
        "The HIDDEN 'enable' password string\n")
 {
-  /* Argument check. */
-  if (argc == 0)
-    {
-      vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
-      return CMD_WARNING;
-    }
-
   /* Crypt type is specified. */
-  if (argc == 2)
+  if (argc == 4)
     {
-      if (*argv[0] == '8')
-       {
-         if (host.enable)
-           XFREE (MTYPE_HOST, host.enable);
-         host.enable = NULL;
-
-         if (host.enable_encrypt)
-           XFREE (MTYPE_HOST, host.enable_encrypt);
-         host.enable_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
-
-         return CMD_SUCCESS;
-       }
+      if (argv[2]->arg[0] == '8')
+        {
+          if (host.enable)
+            XFREE (MTYPE_HOST, host.enable);
+          host.enable = NULL;
+
+          if (host.enable_encrypt)
+            XFREE (MTYPE_HOST, host.enable_encrypt);
+          host.enable_encrypt = XSTRDUP (MTYPE_HOST, argv[3]->arg);
+
+          return CMD_SUCCESS;
+        }
       else
-       {
-         vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
-         return CMD_WARNING;
-       }
+        {
+          vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
+          return CMD_WARNING;
+        }
     }
 
-  if (!isalnum ((int) *argv[0]))
+  if (!isalnum (argv[2]->arg[0]))
     {
-      vty_out (vty, 
-              "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
+      vty_out (vty,
+               "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
       return CMD_WARNING;
     }
 
@@ -3322,22 +1421,15 @@ DEFUN (config_enable_password, enable_password_cmd,
   if (host.encrypt)
     {
       if (host.enable_encrypt)
-       XFREE (MTYPE_HOST, host.enable_encrypt);
-      host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
+        XFREE (MTYPE_HOST, host.enable_encrypt);
+      host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[2]->arg));
     }
   else
-    host.enable = XSTRDUP (MTYPE_HOST, argv[0]);
+    host.enable = XSTRDUP (MTYPE_HOST, argv[2]->arg);
 
   return CMD_SUCCESS;
 }
 
-ALIAS (config_enable_password,
-       enable_password_text_cmd,
-       "enable password LINE",
-       "Modify enable password parameters\n"
-       "Assign the privileged level password\n"
-       "The UNENCRYPTED (cleartext) 'enable' password\n")
-
 /* VTY enable password delete. */
 DEFUN (no_config_enable_password, no_enable_password_cmd,
        "no enable password",
@@ -3355,7 +1447,7 @@ DEFUN (no_config_enable_password, no_enable_password_cmd,
 
   return CMD_SUCCESS;
 }
-       
+
 DEFUN (service_password_encrypt,
        service_password_encrypt_cmd,
        "service password-encryption",
@@ -3370,13 +1462,13 @@ DEFUN (service_password_encrypt,
   if (host.password)
     {
       if (host.password_encrypt)
-       XFREE (MTYPE_HOST, host.password_encrypt);
+        XFREE (MTYPE_HOST, host.password_encrypt);
       host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.password));
     }
   if (host.enable)
     {
       if (host.enable_encrypt)
-       XFREE (MTYPE_HOST, host.enable_encrypt);
+        XFREE (MTYPE_HOST, host.enable_encrypt);
       host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.enable));
     }
 
@@ -3407,7 +1499,7 @@ DEFUN (no_service_password_encrypt,
 }
 
 DEFUN (config_terminal_length, config_terminal_length_cmd,
-       "terminal length <0-512>",
+       "terminal length (0-512)",
        "Set terminal line parameters\n"
        "Set number of lines on a screen\n"
        "Number of lines on screen (0 for no pausing)\n")
@@ -3415,7 +1507,7 @@ DEFUN (config_terminal_length, config_terminal_length_cmd,
   int lines;
   char *endptr = NULL;
 
-  lines = strtol (argv[0], &endptr, 10);
+  lines = strtol (argv[2]->arg, &endptr, 10);
   if (lines < 0 || lines > 512 || *endptr != '\0')
     {
       vty_out (vty, "length is malformed%s", VTY_NEWLINE);
@@ -3437,7 +1529,7 @@ DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
 }
 
 DEFUN (service_terminal_length, service_terminal_length_cmd,
-       "service terminal-length <0-512>",
+       "service terminal-length (0-512)",
        "Set up miscellaneous service\n"
        "System wide terminal length configuration\n"
        "Number of lines of VTY (0 means no line control)\n")
@@ -3445,7 +1537,7 @@ DEFUN (service_terminal_length, service_terminal_length_cmd,
   int lines;
   char *endptr = NULL;
 
-  lines = strtol (argv[0], &endptr, 10);
+  lines = strtol (argv[2]->arg, &endptr, 10);
   if (lines < 0 || lines > 512 || *endptr != '\0')
     {
       vty_out (vty, "length is malformed%s", VTY_NEWLINE);
@@ -3457,7 +1549,7 @@ DEFUN (service_terminal_length, service_terminal_length_cmd,
 }
 
 DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
-       "no service terminal-length [<0-512>]",
+       "no service terminal-length [(0-512)]",
        NO_STR
        "Set up miscellaneous service\n"
        "System wide terminal length configuration\n"
@@ -3468,15 +1560,15 @@ DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
 }
 
 DEFUN_HIDDEN (do_echo,
-             echo_cmd,
-             "echo .MESSAGE",
-             "Echo a message back to the vty\n"
-             "The message to echo\n")
+              echo_cmd,
+              "echo MESSAGE...",
+              "Echo a message back to the vty\n"
+              "The message to echo\n")
 {
   char *message;
 
-  vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""),
-          VTY_NEWLINE);
+  vty_out (vty, "%s%s", ((message = argv_concat (argv, argc, 0)) ? message : ""),
+           VTY_NEWLINE);
   if (message)
     XFREE(MTYPE_TMP, message);
   return CMD_SUCCESS;
@@ -3484,7 +1576,7 @@ DEFUN_HIDDEN (do_echo,
 
 DEFUN (config_logmsg,
        config_logmsg_cmd,
-       "logmsg "LOG_LEVELS" .MESSAGE",
+       "logmsg "LOG_LEVELS" MESSAGE...",
        "Send a message to enabled logging destinations\n"
        LOG_LEVEL_DESC
        "The message to send\n")
@@ -3492,7 +1584,7 @@ DEFUN (config_logmsg,
   int level;
   char *message;
 
-  if ((level = level_match(argv[0])) == ZLOG_DISABLED)
+  if ((level = level_match(argv[1]->arg)) == ZLOG_DISABLED)
     return CMD_ERR_NO_MATCH;
 
   zlog(NULL, level, "%s", ((message = argv_concat(argv, argc, 1)) ? message : ""));
@@ -3514,8 +1606,8 @@ DEFUN (show_logging,
     vty_out (vty, "disabled");
   else
     vty_out (vty, "level %s, facility %s, ident %s",
-            zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
-            facility_name(zl->facility), zl->ident);
+             zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
+             facility_name(zl->facility), zl->ident);
   vty_out (vty, "%s", VTY_NEWLINE);
 
   vty_out (vty, "Stdout logging: ");
@@ -3523,7 +1615,7 @@ DEFUN (show_logging,
     vty_out (vty, "disabled");
   else
     vty_out (vty, "level %s",
-            zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
+             zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
   vty_out (vty, "%s", VTY_NEWLINE);
 
   vty_out (vty, "Monitor logging: ");
@@ -3531,7 +1623,7 @@ DEFUN (show_logging,
     vty_out (vty, "disabled");
   else
     vty_out (vty, "level %s",
-            zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
+             zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
   vty_out (vty, "%s", VTY_NEWLINE);
 
   vty_out (vty, "File logging: ");
@@ -3540,40 +1632,35 @@ DEFUN (show_logging,
     vty_out (vty, "disabled");
   else
     vty_out (vty, "level %s, filename %s",
-            zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
-            zl->filename);
+             zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
+             zl->filename);
   vty_out (vty, "%s", VTY_NEWLINE);
 
   vty_out (vty, "Protocol name: %s%s",
-          zlog_proto_names[zl->protocol], VTY_NEWLINE);
+           zlog_proto_names[zl->protocol], VTY_NEWLINE);
   vty_out (vty, "Record priority: %s%s",
-          (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
+           (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
   vty_out (vty, "Timestamp precision: %d%s",
-          zl->timestamp_precision, VTY_NEWLINE);
+           zl->timestamp_precision, VTY_NEWLINE);
 
   return CMD_SUCCESS;
 }
 
 DEFUN (config_log_stdout,
        config_log_stdout_cmd,
-       "log stdout",
-       "Logging control\n"
-       "Set stdout logging level\n")
-{
-  zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
-  return CMD_SUCCESS;
-}
-
-DEFUN (config_log_stdout_level,
-       config_log_stdout_level_cmd,
-       "log stdout "LOG_LEVELS,
+       "log stdout ["LOG_LEVELS"]",
        "Logging control\n"
        "Set stdout logging level\n"
        LOG_LEVEL_DESC)
 {
+  if (argc == 2)
+  {
+    zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
+    return CMD_SUCCESS;
+  }
   int level;
 
-  if ((level = level_match(argv[0])) == ZLOG_DISABLED)
+  if ((level = level_match(argv[2]->arg)) == ZLOG_DISABLED)
     return CMD_ERR_NO_MATCH;
   zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
   return CMD_SUCCESS;
@@ -3581,11 +1668,11 @@ DEFUN (config_log_stdout_level,
 
 DEFUN (no_config_log_stdout,
        no_config_log_stdout_cmd,
-       "no log stdout [LEVEL]",
+       "no log stdout ["LOG_LEVELS"]",
        NO_STR
        "Logging control\n"
        "Cancel logging to stdout\n"
-       "Logging level\n")
+       LOG_LEVEL_DESC)
 {
   zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
   return CMD_SUCCESS;
@@ -3593,24 +1680,19 @@ DEFUN (no_config_log_stdout,
 
 DEFUN (config_log_monitor,
        config_log_monitor_cmd,
-       "log monitor",
-       "Logging control\n"
-       "Set terminal line (monitor) logging level\n")
-{
-  zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
-  return CMD_SUCCESS;
-}
-
-DEFUN (config_log_monitor_level,
-       config_log_monitor_level_cmd,
-       "log monitor "LOG_LEVELS,
+       "log monitor ["LOG_LEVELS"]",
        "Logging control\n"
        "Set terminal line (monitor) logging level\n"
        LOG_LEVEL_DESC)
 {
+  if (argc == 2)
+  {
+    zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
+    return CMD_SUCCESS;
+  }
   int level;
 
-  if ((level = level_match(argv[0])) == ZLOG_DISABLED)
+  if ((level = level_match(argv[2]->arg)) == ZLOG_DISABLED)
     return CMD_ERR_NO_MATCH;
   zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
   return CMD_SUCCESS;
@@ -3618,11 +1700,11 @@ DEFUN (config_log_monitor_level,
 
 DEFUN (no_config_log_monitor,
        no_config_log_monitor_cmd,
-       "no log monitor [LEVEL]",
+       "no log monitor ["LOG_LEVELS"]",
        NO_STR
        "Logging control\n"
        "Disable terminal line (monitor) logging\n"
-       "Logging level\n")
+       LOG_LEVEL_DESC)
 {
   zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
   return CMD_SUCCESS;
@@ -3634,19 +1716,19 @@ set_log_file(struct vty *vty, const char *fname, int loglevel)
   int ret;
   char *p = NULL;
   const char *fullpath;
-  
+
   /* Path detection. */
   if (! IS_DIRECTORY_SEP (*fname))
     {
       char cwd[MAXPATHLEN+1];
       cwd[MAXPATHLEN] = '\0';
-      
+
       if (getcwd (cwd, MAXPATHLEN) == NULL)
         {
           zlog_err ("config_log_file: Unable to alloc mem!");
           return CMD_WARNING;
         }
-      
+
       if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
           == NULL)
         {
@@ -3680,36 +1762,32 @@ set_log_file(struct vty *vty, const char *fname, int loglevel)
 
 DEFUN (config_log_file,
        config_log_file_cmd,
-       "log file FILENAME",
-       "Logging control\n"
-       "Logging to file\n"
-       "Logging filename\n")
-{
-  return set_log_file(vty, argv[0], zlog_default->default_lvl);
-}
-
-DEFUN (config_log_file_level,
-       config_log_file_level_cmd,
-       "log file FILENAME "LOG_LEVELS,
+       "log file FILENAME [" LOG_LEVELS "]",
        "Logging control\n"
        "Logging to file\n"
        "Logging filename\n"
        LOG_LEVEL_DESC)
 {
-  int level;
-
-  if ((level = level_match(argv[1])) == ZLOG_DISABLED)
-    return CMD_ERR_NO_MATCH;
-  return set_log_file(vty, argv[0], level);
+  if (argc == 4)
+  {
+    int level;
+    if ((level = level_match(argv[3]->arg)) == ZLOG_DISABLED)
+      return CMD_ERR_NO_MATCH;
+    return set_log_file(vty, argv[2]->arg, level);
+  }
+  else
+    return set_log_file(vty, argv[2]->arg, zlog_default->default_lvl);
 }
 
 DEFUN (no_config_log_file,
        no_config_log_file_cmd,
-       "no log file [FILENAME]",
+       "no log file [FILENAME [LEVEL]]",
        NO_STR
        "Logging control\n"
        "Cancel logging to file\n"
-       "Logging file name\n")
+       "Logging file name\n"
+       "Logging file name\n"
+       "Logging level\n")
 {
   zlog_reset_file (NULL);
 
@@ -3721,52 +1799,37 @@ DEFUN (no_config_log_file,
   return CMD_SUCCESS;
 }
 
-ALIAS (no_config_log_file,
-       no_config_log_file_level_cmd,
-       "no log file FILENAME LEVEL",
-       NO_STR
-       "Logging control\n"
-       "Cancel logging to file\n"
-       "Logging file name\n"
-       "Logging level\n")
-
 DEFUN (config_log_syslog,
        config_log_syslog_cmd,
-       "log syslog",
-       "Logging control\n"
-       "Set syslog logging level\n")
-{
-  zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
-  return CMD_SUCCESS;
-}
-
-DEFUN (config_log_syslog_level,
-       config_log_syslog_level_cmd,
-       "log syslog "LOG_LEVELS,
+       "log syslog [" LOG_LEVELS "]",
        "Logging control\n"
        "Set syslog logging level\n"
        LOG_LEVEL_DESC)
 {
-  int level;
-
-  if ((level = level_match(argv[0])) == ZLOG_DISABLED)
-    return CMD_ERR_NO_MATCH;
-  zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
-  return CMD_SUCCESS;
+  if (argc == 3)
+  {
+    int level;
+    if ((level = level_match (argv[2]->arg)) == ZLOG_DISABLED)
+      return CMD_ERR_NO_MATCH;
+    zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
+    return CMD_SUCCESS;
+  }
+  else
+  {
+    zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
+    return CMD_SUCCESS;
+  }
 }
 
 DEFUN_DEPRECATED (config_log_syslog_facility,
-                 config_log_syslog_facility_cmd,
-                 "log syslog facility "LOG_FACILITIES,
-                 "Logging control\n"
-                 "Logging goes to syslog\n"
-                 "(Deprecated) Facility parameter for syslog messages\n"
-                 LOG_FACILITY_DESC)
+                  config_log_syslog_facility_cmd,
+                  "log syslog facility "LOG_FACILITIES,
+                  "Logging control\n"
+                  "Logging goes to syslog\n"
+                  "(Deprecated) Facility parameter for syslog messages\n"
+                  LOG_FACILITY_DESC)
 {
-  int facility;
-
-  if ((facility = facility_match(argv[0])) < 0)
-    return CMD_ERR_NO_MATCH;
+  int facility = facility_match(argv[3]->arg);
 
   zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
   zlog_default->facility = facility;
@@ -3775,25 +1838,17 @@ DEFUN_DEPRECATED (config_log_syslog_facility,
 
 DEFUN (no_config_log_syslog,
        no_config_log_syslog_cmd,
-       "no log syslog [LEVEL]",
+       "no log syslog [" LOG_FACILITIES "] ["LOG_LEVELS"]",
        NO_STR
        "Logging control\n"
        "Cancel logging to syslog\n"
-       "Logging level\n")
+       LOG_FACILITY_DESC
+       LOG_LEVEL_DESC)
 {
   zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
   return CMD_SUCCESS;
 }
 
-ALIAS (no_config_log_syslog,
-       no_config_log_syslog_facility_cmd,
-       "no log syslog facility "LOG_FACILITIES,
-       NO_STR
-       "Logging control\n"
-       "Logging goes to syslog\n"
-       "Facility parameter for syslog messages\n"
-       LOG_FACILITY_DESC)
-
 DEFUN (config_log_facility,
        config_log_facility_cmd,
        "log facility "LOG_FACILITIES,
@@ -3801,37 +1856,35 @@ DEFUN (config_log_facility,
        "Facility parameter for syslog messages\n"
        LOG_FACILITY_DESC)
 {
-  int facility;
+  int facility = facility_match(argv[2]->arg);
 
-  if ((facility = facility_match(argv[0])) < 0)
-    return CMD_ERR_NO_MATCH;
   zlog_default->facility = facility;
   return CMD_SUCCESS;
 }
 
 DEFUN (no_config_log_facility,
        no_config_log_facility_cmd,
-       "no log facility [FACILITY]",
+       "no log facility ["LOG_FACILITIES"]",
        NO_STR
        "Logging control\n"
        "Reset syslog facility to default (daemon)\n"
-       "Syslog facility\n")
+       LOG_FACILITY_DESC)
 {
   zlog_default->facility = LOG_DAEMON;
   return CMD_SUCCESS;
 }
 
 DEFUN_DEPRECATED (config_log_trap,
-                 config_log_trap_cmd,
-                 "log trap "LOG_LEVELS,
-                 "Logging control\n"
-                 "(Deprecated) Set logging level and default for all destinations\n"
-                 LOG_LEVEL_DESC)
+                  config_log_trap_cmd,
+                  "log trap "LOG_LEVELS,
+                  "Logging control\n"
+                  "(Deprecated) Set logging level and default for all destinations\n"
+                  LOG_LEVEL_DESC)
 {
   int new_level ;
   int i;
-  
-  if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
+
+  if ((new_level = level_match(argv[2]->arg)) == ZLOG_DISABLED)
     return CMD_ERR_NO_MATCH;
 
   zlog_default->default_lvl = new_level;
@@ -3842,12 +1895,12 @@ DEFUN_DEPRECATED (config_log_trap,
 }
 
 DEFUN_DEPRECATED (no_config_log_trap,
-                 no_config_log_trap_cmd,
-                 "no log trap [LEVEL]",
-                 NO_STR
-                 "Logging control\n"
-                 "Permit all logging information\n"
-                 "Logging level\n")
+                  no_config_log_trap_cmd,
+                  "no log trap ["LOG_LEVELS"]",
+                  NO_STR
+                  "Logging control\n"
+                  "Permit all logging information\n"
+                  LOG_LEVEL_DESC)
 {
   zlog_default->default_lvl = LOG_DEBUG;
   return CMD_SUCCESS;
@@ -3882,14 +1935,8 @@ DEFUN (config_log_timestamp_precision,
        "Set the timestamp precision\n"
        "Number of subsecond digits\n")
 {
-  if (argc != 1)
-    {
-      vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE);
-      return CMD_WARNING;
-    }
-
   VTY_GET_INTEGER_RANGE("Timestamp Precision",
-                       zlog_default->timestamp_precision, argv[0], 0, 6);
+                        zlog_default->timestamp_precision, argv[3]->arg, 0, 6);
   return CMD_SUCCESS;
 }
 
@@ -3923,7 +1970,7 @@ DEFUN (banner_motd_file,
        "Banner from a file\n"
        "Filename\n")
 {
-  return cmd_banner_motd_file (argv[0]);
+  return cmd_banner_motd_file (argv[3]->arg);
 }
 
 DEFUN (banner_motd_default,
@@ -3945,7 +1992,7 @@ DEFUN (no_banner_motd,
        "Strings for motd\n")
 {
   host.motd = NULL;
-  if (host.motdfile) 
+  if (host.motdfile)
     XFREE (MTYPE_HOST, host.motdfile);
   host.motdfile = NULL;
   return CMD_SUCCESS;
@@ -4000,9 +2047,6 @@ install_default (enum node_type node)
   install_element (node, &config_help_cmd);
   install_element (node, &config_list_cmd);
 
-  install_element (node, &config_write_terminal_cmd);
-  install_element (node, &config_write_file_cmd);
-  install_element (node, &config_write_memory_cmd);
   install_element (node, &config_write_cmd);
   install_element (node, &show_running_config_cmd);
 }
@@ -4011,12 +2055,6 @@ install_default (enum node_type node)
 void
 cmd_init (int terminal)
 {
-  command_cr = XSTRDUP(MTYPE_CMD_TOKENS, "<cr>");
-  token_cr.type = TOKEN_TERMINAL;
-  token_cr.terminal = TERMINAL_LITERAL;
-  token_cr.cmd = command_cr;
-  token_cr.desc = XSTRDUP(MTYPE_CMD_TOKENS, "");
-
   /* Allocate initial top vector of commands. */
   cmdvec = vector_init (VECTOR_MIN_SIZE);
 
@@ -4085,33 +2123,24 @@ cmd_init (int terminal)
 
       install_default (CONFIG_NODE);
     }
-  
+
   install_element (CONFIG_NODE, &hostname_cmd);
   install_element (CONFIG_NODE, &no_hostname_cmd);
 
   if (terminal)
     {
       install_element (CONFIG_NODE, &password_cmd);
-      install_element (CONFIG_NODE, &password_text_cmd);
       install_element (CONFIG_NODE, &enable_password_cmd);
-      install_element (CONFIG_NODE, &enable_password_text_cmd);
       install_element (CONFIG_NODE, &no_enable_password_cmd);
 
       install_element (CONFIG_NODE, &config_log_stdout_cmd);
-      install_element (CONFIG_NODE, &config_log_stdout_level_cmd);
       install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
       install_element (CONFIG_NODE, &config_log_monitor_cmd);
-      install_element (CONFIG_NODE, &config_log_monitor_level_cmd);
       install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
       install_element (CONFIG_NODE, &config_log_file_cmd);
-      install_element (CONFIG_NODE, &config_log_file_level_cmd);
       install_element (CONFIG_NODE, &no_config_log_file_cmd);
-      install_element (CONFIG_NODE, &no_config_log_file_level_cmd);
       install_element (CONFIG_NODE, &config_log_syslog_cmd);
-      install_element (CONFIG_NODE, &config_log_syslog_level_cmd);
-      install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
       install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
-      install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
       install_element (CONFIG_NODE, &config_log_facility_cmd);
       install_element (CONFIG_NODE, &no_config_log_facility_cmd);
       install_element (CONFIG_NODE, &config_log_trap_cmd);
@@ -4131,7 +2160,7 @@ cmd_init (int terminal)
       install_element (VIEW_NODE, &show_thread_cpu_cmd);
       install_element (ENABLE_NODE, &show_thread_cpu_cmd);
       install_element (RESTRICTED_NODE, &show_thread_cpu_cmd);
-      
+
       install_element (ENABLE_NODE, &clear_thread_cpu_cmd);
       install_element (VIEW_NODE, &show_work_queues_cmd);
       install_element (ENABLE_NODE, &show_work_queues_cmd);
@@ -4142,62 +2171,54 @@ cmd_init (int terminal)
   srandom(time(NULL));
 }
 
-static void
-cmd_terminate_token(struct cmd_token *token)
+struct cmd_token *
+new_cmd_token (enum cmd_token_type type, char *text, char *desc)
 {
-  unsigned int i, j;
-  vector keyword_vect;
+  struct cmd_token *token = XMALLOC (MTYPE_CMD_TOKENS, sizeof (struct cmd_token));
+  token->type = type;
+  token->text = text;
+  token->desc = desc;
+  token->arg  = NULL;
 
-  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;
-    }
+  return token;
+}
 
-  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;
-    }
+void
+del_cmd_token (struct cmd_token *token)
+{
+  if (!token) return;
 
-  XFREE(MTYPE_CMD_TOKENS, token->cmd);
-  XFREE(MTYPE_CMD_TOKENS, token->desc);
+  if (token->text)
+    XFREE (MTYPE_CMD_TOKENS, token->text);
+  if (token->desc)
+    XFREE (MTYPE_CMD_TOKENS, token->desc);
+  if (token->arg)
+    XFREE (MTYPE_CMD_TOKENS, token->arg);
 
-  XFREE(MTYPE_CMD_TOKENS, token);
+  XFREE (MTYPE_CMD_TOKENS, token);
 }
 
-static void
-cmd_terminate_element(struct cmd_element *cmd)
+struct cmd_token *
+copy_cmd_token (struct cmd_token *token)
 {
-  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));
+  struct cmd_token *copy = new_cmd_token (token->type, NULL, NULL);
+  copy->value = token->value;
+  copy->max   = token->max;
+  copy->min   = token->min;
+  copy->text  = token->text ? XSTRDUP (MTYPE_CMD_TOKENS, token->text) : NULL;
+  copy->desc  = token->desc ? XSTRDUP (MTYPE_CMD_TOKENS, token->desc) : NULL;
+  copy->arg   = token->arg  ? XSTRDUP (MTYPE_CMD_TOKENS, token->arg) : NULL;
 
-  vector_free(cmd->tokens);
-  cmd->tokens = NULL;
+  return copy;
 }
 
 void
 del_cmd_element(struct cmd_element *cmd)
 {
   if (!cmd) return;
-  free ((char*) cmd->string);
-  free ((char*) cmd->doc);
-  cmd_terminate_element(cmd);
-  free (cmd);
+  XFREE (MTYPE_CMD_TOKENS, cmd->string);
+  XFREE (MTYPE_CMD_TOKENS, cmd->doc);
+  XFREE (MTYPE_CMD_TOKENS, cmd);
 }
 
 struct cmd_element *
@@ -4208,7 +2229,6 @@ copy_cmd_element(struct cmd_element *cmd)
   el->func = cmd->func;
   el->doc = cmd->doc ? XSTRDUP(MTYPE_CMD_TOKENS, cmd->doc) : NULL;
   el->daemon = cmd->daemon;
-  el->tokens = cmd->tokens ? vector_copy(cmd->tokens) : NULL;
   el->attr = cmd->attr;
   return el;
 }
@@ -4216,33 +2236,22 @@ copy_cmd_element(struct cmd_element *cmd)
 void
 cmd_terminate ()
 {
-  unsigned int i, j;
   struct cmd_node *cmd_node;
-  struct cmd_element *cmd_element;
-  vector cmd_node_v;
 
   if (cmdvec)
     {
-      for (i = 0; i < vector_active (cmdvec); i++) 
+      for (unsigned int i = 0; i < vector_active (cmdvec); i++)
         if ((cmd_node = vector_slot (cmdvec, i)) != NULL)
-          {
-            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_terminate_element(cmd_element);
-
-            vector_free (cmd_node_v);
-          }
+        {
+          // deleting the graph delets the cmd_element as well
+          graph_delete_graph (cmd_node->cmdgraph);
+          vector_free (cmd_node->cmd_vector);
+        }
 
       vector_free (cmdvec);
       cmdvec = NULL;
     }
 
-  if (command_cr)
-    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)
index 6d0fb180617d3589e2de7822383de38b0a427073..786539034bfcb90e5dc5c609e1d9c1e3523422d3 100644 (file)
@@ -8,7 +8,7 @@
  * it under the terms of the GNU General Public License as published
  * by the Free Software Foundation; either version 2, or (at your
  * option) any later version.
- * 
+ *
  * GNU Zebra is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
@@ -26,6 +26,7 @@
 #include "vector.h"
 #include "vty.h"
 #include "lib/route_types.h"
+#include "graph.h"
 
 /* Host configuration variable */
 struct host
@@ -60,133 +61,136 @@ struct host
 };
 
 /* There are some command levels which called from command node. */
-enum node_type 
+enum node_type
 {
-  AUTH_NODE,                   /* Authentication mode of vty interface. */
-  RESTRICTED_NODE,             /* Restricted view mode */ 
-  VIEW_NODE,                   /* View node. Default mode of vty interface. */
-  AUTH_ENABLE_NODE,            /* Authentication mode for change enable. */
-  ENABLE_NODE,                 /* Enable node. */
-  CONFIG_NODE,                 /* Config node. Default mode of config file. */
-  SERVICE_NODE,                /* Service node. */
-  DEBUG_NODE,                  /* Debug node. */
+  AUTH_NODE,                    /* Authentication mode of vty interface. */
+  RESTRICTED_NODE,              /* Restricted view mode */
+  VIEW_NODE,                    /* View node. Default mode of vty interface. */
+  AUTH_ENABLE_NODE,             /* Authentication mode for change enable. */
+  ENABLE_NODE,                  /* Enable node. */
+  CONFIG_NODE,                  /* Config node. Default mode of config file. */
+  SERVICE_NODE,                 /* Service node. */
+  DEBUG_NODE,                   /* Debug node. */
   VRF_DEBUG_NODE,               /* Vrf Debug node. */
-  AAA_NODE,                    /* AAA node. */
-  KEYCHAIN_NODE,               /* Key-chain node. */
-  KEYCHAIN_KEY_NODE,           /* Key-chain key node. */
-  VRF_NODE,                    /* VRF mode node. */
-  INTERFACE_NODE,              /* Interface mode node. */
-  ZEBRA_NODE,                  /* zebra connection node. */
-  TABLE_NODE,                  /* rtm_table selection node. */
-  RIP_NODE,                    /* RIP protocol mode node. */ 
-  RIPNG_NODE,                  /* RIPng protocol mode node. */
-  BGP_NODE,                    /* BGP protocol mode which includes BGP4+ */
-  BGP_VPNV4_NODE,              /* BGP MPLS-VPN PE exchange. */
-  BGP_VPNV6_NODE,              /* BGP MPLS-VPN PE exchange. */
-  BGP_IPV4_NODE,               /* BGP IPv4 unicast address family.  */
-  BGP_IPV4M_NODE,              /* BGP IPv4 multicast address family.  */
-  BGP_IPV6_NODE,               /* BGP IPv6 address family */
-  BGP_IPV6M_NODE,              /* BGP IPv6 multicast address family. */
-  BGP_ENCAP_NODE,              /* BGP ENCAP SAFI */
-  BGP_ENCAPV6_NODE,            /* BGP ENCAP SAFI */
-  OSPF_NODE,                   /* OSPF protocol mode */
-  OSPF6_NODE,                  /* OSPF protocol for IPv6 mode */
-  ISIS_NODE,                   /* ISIS protocol mode */
-  PIM_NODE,                    /* PIM protocol mode */
-  MASC_NODE,                   /* MASC for multicast.  */
-  IRDP_NODE,                   /* ICMP Router Discovery Protocol mode. */ 
-  IP_NODE,                     /* Static ip route node. */
-  ACCESS_NODE,                 /* Access list node. */
-  PREFIX_NODE,                 /* Prefix list node. */
-  ACCESS_IPV6_NODE,            /* Access list node. */
-  PREFIX_IPV6_NODE,            /* Prefix list node. */
-  AS_LIST_NODE,                        /* AS list node. */
-  COMMUNITY_LIST_NODE,         /* Community list node. */
-  RMAP_NODE,                   /* Route map node. */
-  SMUX_NODE,                   /* SNMP configuration node. */
-  DUMP_NODE,                   /* Packet dump node. */
-  FORWARDING_NODE,             /* IP forwarding node. */
+  AAA_NODE,                     /* AAA node. */
+  KEYCHAIN_NODE,                /* Key-chain node. */
+  KEYCHAIN_KEY_NODE,            /* Key-chain key node. */
+  VRF_NODE,                     /* VRF mode node. */
+  INTERFACE_NODE,               /* Interface mode node. */
+  ZEBRA_NODE,                   /* zebra connection node. */
+  TABLE_NODE,                   /* rtm_table selection node. */
+  RIP_NODE,                     /* RIP protocol mode node. */
+  RIPNG_NODE,                   /* RIPng protocol mode node. */
+  BGP_NODE,                     /* BGP protocol mode which includes BGP4+ */
+  BGP_VPNV4_NODE,               /* BGP MPLS-VPN PE exchange. */
+  BGP_VPNV6_NODE,               /* BGP MPLS-VPN PE exchange. */
+  BGP_IPV4_NODE,                /* BGP IPv4 unicast address family.  */
+  BGP_IPV4M_NODE,               /* BGP IPv4 multicast address family.  */
+  BGP_IPV6_NODE,                /* BGP IPv6 address family */
+  BGP_IPV6M_NODE,               /* BGP IPv6 multicast address family. */
+  BGP_ENCAP_NODE,               /* BGP ENCAP SAFI */
+  BGP_ENCAPV6_NODE,             /* BGP ENCAP SAFI */
+  OSPF_NODE,                    /* OSPF protocol mode */
+  OSPF6_NODE,                   /* OSPF protocol for IPv6 mode */
+  ISIS_NODE,                    /* ISIS protocol mode */
+  PIM_NODE,                     /* PIM protocol mode */
+  MASC_NODE,                    /* MASC for multicast.  */
+  IRDP_NODE,                    /* ICMP Router Discovery Protocol mode. */
+  IP_NODE,                      /* Static ip route node. */
+  ACCESS_NODE,                  /* Access list node. */
+  PREFIX_NODE,                  /* Prefix list node. */
+  ACCESS_IPV6_NODE,             /* Access list node. */
+  PREFIX_IPV6_NODE,             /* Prefix list node. */
+  AS_LIST_NODE,                 /* AS list node. */
+  COMMUNITY_LIST_NODE,          /* Community list node. */
+  RMAP_NODE,                    /* Route map node. */
+  SMUX_NODE,                    /* SNMP configuration node. */
+  DUMP_NODE,                    /* Packet dump node. */
+  FORWARDING_NODE,              /* IP forwarding node. */
   PROTOCOL_NODE,                /* protocol filtering node */
-  VTY_NODE,                    /* Vty node. */
+  VTY_NODE,                     /* Vty node. */
 };
 
 /* Node which has some commands and prompt string and configuration
    function pointer . */
-struct cmd_node 
+struct cmd_node
 {
   /* Node index. */
-  enum node_type node;         
+  enum node_type node;
 
   /* Prompt character at vty interface. */
-  const char *prompt;                  
+  const char *prompt;
 
   /* Is this node's configuration goes to vtysh ? */
   int vtysh;
-  
+
   /* Node's configuration write function */
   int (*func) (struct vty *);
 
+  /* Node's command graph */
+  struct graph *cmdgraph;
+
   /* Vector of this node's command list. */
-  vector cmd_vector;   
+  vector cmd_vector;
 };
 
-enum
+/**
+ * Types for tokens.
+ *
+ * The type determines what kind of data the token can match (in the
+ * matching use case) or hold (in the argv use case).
+ */
+enum cmd_token_type
 {
-  CMD_ATTR_DEPRECATED = 1,
-  CMD_ATTR_HIDDEN,
+  WORD_TKN,         // words
+  NUMBER_TKN,       // integral numbers
+  VARIABLE_TKN,     // almost anything
+  RANGE_TKN,        // integer range
+  IPV4_TKN,         // IPV4 addresses
+  IPV4_PREFIX_TKN,  // IPV4 network prefixes
+  IPV6_TKN,         // IPV6 prefixes
+  IPV6_PREFIX_TKN,  // IPV6 network prefixes
+
+  /* plumbing types */
+  SELECTOR_TKN,     // marks beginning of selector
+  OPTION_TKN,       // marks beginning of option
+  NUL_TKN,          // dummy token
+  START_TKN,        // first token in line
+  END_TKN,          // last token in line
 };
 
-/* Structure of command element. */
-struct cmd_element 
+/**
+ * Token struct.
+ */
+struct cmd_token
 {
-  const char *string;                  /* Command specification by string. */
-  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 tokens;               /* Vector of cmd_tokens */
-  u_char attr;                 /* Command attributes */
-};
+  enum cmd_token_type type;   // token type
 
+  char *text;                   // token text
+  char *desc;                   // token description
 
-enum cmd_token_type
-{
-  TOKEN_TERMINAL = 0,
-  TOKEN_MULTIPLE,
-  TOKEN_KEYWORD,
+  long long value;              // for numeric types
+  long long min, max;           // for ranges
+
+  char *arg;                    // user input that matches this token
 };
 
-enum cmd_terminal_type
+enum
 {
-  _TERMINAL_BUG = 0,
-  TERMINAL_LITERAL,
-  TERMINAL_OPTION,
-  TERMINAL_VARIABLE,
-  TERMINAL_VARARG,
-  TERMINAL_RANGE,
-  TERMINAL_IPV4,
-  TERMINAL_IPV4_PREFIX,
-  TERMINAL_IPV6,
-  TERMINAL_IPV6_PREFIX,
+  CMD_ATTR_DEPRECATED = 1,
+  CMD_ATTR_HIDDEN,
 };
 
-/* argument to be recorded on argv[] if it's not a literal */
-#define TERMINAL_RECORD(t) ((t) >= TERMINAL_OPTION)
-
-/* Command description structure. */
-struct cmd_token
+/* Structure of command element. */
+struct cmd_element
 {
-  enum cmd_token_type type;
-  enum cmd_terminal_type terminal;
-
-  /* Used for type == MULTIPLE */
-  vector multiple; /* vector of cmd_token, type == FINAL */
-
-  /* Used for type == KEYWORD */
-  vector keyword; /* vector of vector of cmd_tokens */
+  const char *string;           /* Command specification by string. */
+  const char *doc;              /* Documentation of this command. */
+  int daemon;                   /* Daemon to which this command belong. */
+  u_char attr;                  /* Command attributes */
 
-  /* Used for type == TERMINAL */
-  char *cmd;                    /* Command string. */
-  char *desc;                    /* Command's description. */
+  /* handler function for command */
+  int (*func) (struct cmd_element *, struct vty *, int, struct cmd_token *[]);
 };
 
 /* Return value of the commands. */
@@ -207,7 +211,7 @@ struct cmd_token
 #define CMD_ARGC_MAX   25
 
 /* Turn off these macros when uisng cpp with extract.pl */
-#ifndef VTYSH_EXTRACT_PL  
+#ifndef VTYSH_EXTRACT_PL
 
 /* helper defines for end-user DEFUN* macros */
 #define DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attrs, dnum) \
@@ -221,179 +225,15 @@ struct cmd_token
   };
 
 #define DEFUN_CMD_FUNC_DECL(funcname) \
-  static int funcname (struct cmd_element *, struct vty *, int, const char *[]);
+  static int funcname (struct cmd_element *, struct vty *, int, struct cmd_token *[]);
 
 #define DEFUN_CMD_FUNC_TEXT(funcname) \
   static int funcname \
     (struct cmd_element *self __attribute__ ((unused)), \
      struct vty *vty __attribute__ ((unused)), \
      int argc __attribute__ ((unused)), \
-     const char *argv[] __attribute__ ((unused)) )
+     struct cmd_token *argv[] __attribute__ ((unused)) )
 
-/* 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) \
@@ -506,41 +346,41 @@ struct cmd_token
 #define IP6_STR "IPv6 Information\n"
 #define OSPF6_STR "Open Shortest Path First (OSPF) for IPv6\n"
 #define OSPF6_ROUTER_STR "Enable a routing process\n"
-#define OSPF6_INSTANCE_STR "<1-65535> Instance ID\n"
-#define SECONDS_STR "<1-65535> Seconds\n"
+#define OSPF6_INSTANCE_STR "(1-65535) Instance ID\n"
+#define SECONDS_STR "(1-65535) Seconds\n"
 #define ROUTE_STR "Routing Table\n"
 #define PREFIX_LIST_STR "Build a prefix list\n"
 #define OSPF6_DUMP_TYPE_LIST \
-"(neighbor|interface|area|lsa|zebra|config|dbex|spf|route|lsdb|redistribute|hook|asbr|prefix|abr)"
+"<neighbor|interface|area|lsa|zebra|config|dbex|spf|route|lsdb|redistribute|hook|asbr|prefix|abr>"
 #define ISIS_STR "IS-IS information\n"
 #define AREA_TAG_STR "[area tag]\n"
-#define COMMUNITY_AANN_STR "Community number where AA and NN are <0-65535>\n"
-#define COMMUNITY_VAL_STR  "Community number in AA:NN format (where AA and NN are <0-65535>) or local-AS|no-advertise|no-export|internet or additive\n"
+#define COMMUNITY_AANN_STR "Community number where AA and NN are (0-65535)\n"
+#define COMMUNITY_VAL_STR  "Community number in AA:NN format (where AA and NN are (0-65535)) or local-AS|no-advertise|no-export|internet or additive\n"
 
 #define CONF_BACKUP_EXT ".sav"
 
 /* IPv4 only machine should not accept IPv6 address for peer's IP
    address.  So we replace VTY command string like below. */
 #ifdef HAVE_IPV6
-#define NEIGHBOR_CMD       "neighbor (A.B.C.D|X:X::X:X) "
-#define NO_NEIGHBOR_CMD    "no neighbor (A.B.C.D|X:X::X:X) "
+#define NEIGHBOR_CMD       "neighbor <A.B.C.D|X:X::X:X> "
+#define NO_NEIGHBOR_CMD    "no neighbor <A.B.C.D|X:X::X:X> "
 #define NEIGHBOR_ADDR_STR  "Neighbor address\nIPv6 address\n"
-#define NEIGHBOR_CMD2      "neighbor (A.B.C.D|X:X::X:X|WORD) "
-#define NO_NEIGHBOR_CMD2   "no neighbor (A.B.C.D|X:X::X:X|WORD) "
+#define NEIGHBOR_CMD2      "neighbor <A.B.C.D|X:X::X:X|WORD> "
+#define NO_NEIGHBOR_CMD2   "no neighbor <A.B.C.D|X:X::X:X|WORD> "
 #define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor IPv6 address\nInterface name or neighbor tag\n"
 #define NEIGHBOR_ADDR_STR3 "Neighbor address\nIPv6 address\nInterface name\n"
 #else
 #define NEIGHBOR_CMD       "neighbor A.B.C.D "
 #define NO_NEIGHBOR_CMD    "no neighbor A.B.C.D "
 #define NEIGHBOR_ADDR_STR  "Neighbor address\n"
-#define NEIGHBOR_CMD2      "neighbor (A.B.C.D|WORD) "
-#define NO_NEIGHBOR_CMD2   "no neighbor (A.B.C.D|WORD) "
+#define NEIGHBOR_CMD2      "neighbor <A.B.C.D|WORD> "
+#define NO_NEIGHBOR_CMD2   "no neighbor <A.B.C.D|WORD> "
 #define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor tag\n"
 #endif /* HAVE_IPV6 */
 
 /* Dynamic neighbor (listen range) configuration */
 #ifdef HAVE_IPV6
-#define LISTEN_RANGE_CMD      "bgp listen range (A.B.C.D/M|X:X::X:X/M) "
+#define LISTEN_RANGE_CMD      "bgp listen range <A.B.C.D/M|X:X::X:X/M> "
 #define LISTEN_RANGE_ADDR_STR "Neighbor address\nNeighbor IPv6 address\n"
 #else
 #define LISTEN_RANGE_CMD      "bgp listen range A.B.C.D/M "
@@ -555,7 +395,7 @@ extern void install_element (enum node_type, struct cmd_element *);
 /* Concatenates argv[shift] through argv[argc-1] into a single NUL-terminated
    string with a space between each element (allocated using
    XMALLOC(MTYPE_TMP)).  Returns NULL if shift >= argc. */
-extern char *argv_concat (const char **argv, int argc, int shift);
+extern char *argv_concat (struct cmd_token **argv, int argc, int shift);
 
 extern vector cmd_make_strvec (const char *);
 extern void cmd_free_strvec (vector);
@@ -577,6 +417,14 @@ del_cmd_element(struct cmd_element *);
 struct cmd_element *
 copy_cmd_element(struct cmd_element *cmd);
 
+/* memory management for cmd_token */
+struct cmd_token *
+new_cmd_token (enum cmd_token_type, char *, char *);
+void
+del_cmd_token (struct cmd_token *);
+struct cmd_token *
+copy_cmd_token (struct cmd_token *);
+
 /* Export typical functions. */
 extern struct cmd_element config_end_cmd;
 extern struct cmd_element config_exit_cmd;
@@ -591,8 +439,9 @@ extern void print_version (const char *);
 extern int cmd_banner_motd_file (const char *);
 
 /* struct host global, ick */
-extern struct host host; 
+extern struct host host;
+
+/* text for <cr> command */
+#define CMD_CR_TEXT "<cr>"
 
-/* "<cr>" global */
-extern char *command_cr;
 #endif /* _ZEBRA_COMMAND_H */
index dce3292709ddef6f1a2ae18648292f1ffa173c2c..d7c2222ce6a0c572aa0e2fd87f9a907aff6da8a9 100644 (file)
@@ -25,7 +25,6 @@
 #include <zebra.h>
 #include "command_match.h"
 #include "command_parse.h"
-#include "grammar_sandbox.h"
 #include "memory.h"
 
 /* matcher helper prototypes */
@@ -36,16 +35,16 @@ static struct list *
 command_match_r (struct graph_node *, vector, unsigned int);
 
 static int
-score_precedence (enum cmd_token_type_t);
+score_precedence (enum cmd_token_type);
 
 static enum match_type
-min_match_level (enum cmd_token_type_t);
+min_match_level (enum cmd_token_type);
 
 static void
 del_arglist (struct list *);
 
-static struct cmd_token_t *
-disambiguate_tokens (struct cmd_token_t *, struct cmd_token_t *, char *);
+static struct cmd_token *
+disambiguate_tokens (struct cmd_token *, struct cmd_token *, char *);
 
 static struct list *
 disambiguate (struct list *, struct list *, vector, unsigned int);
@@ -55,7 +54,7 @@ compare_completions (const void *, const void *);
 
 /* token matcher prototypes */
 static enum match_type
-match_token (struct cmd_token_t *, char *);
+match_token (struct cmd_token *, char *);
 
 static enum match_type
 match_ipv4 (const char *);
@@ -70,16 +69,16 @@ static enum match_type
 match_ipv6_prefix (const char *);
 
 static enum match_type
-match_range (struct cmd_token_t *, const char *);
+match_range (struct cmd_token *, const char *);
 
 static enum match_type
-match_word (struct cmd_token_t *, const char *);
+match_word (struct cmd_token *, const char *);
 
 static enum match_type
-match_number (struct cmd_token_t *, const char *);
+match_number (struct cmd_token *, const char *);
 
 static enum match_type
-match_variable (struct cmd_token_t *, const char *);
+match_variable (struct cmd_token *, const char *);
 
 /* matching functions */
 static enum matcher_rv matcher_rv;
@@ -105,7 +104,7 @@ command_match (struct graph *cmdgraph,
       struct listnode *tail = listtail (*argv);
 
       // delete dummy start node
-      del_cmd_token ((struct cmd_token_t *) head->data);
+      del_cmd_token ((struct cmd_token *) head->data);
       list_delete_node (*argv, head);
 
       // get cmd_element out of list tail
@@ -179,7 +178,7 @@ command_match_r (struct graph_node *start, vector vline, unsigned int n)
   assert (n < vector_active (vline));
 
   // get the minimum match level that can count as a full match
-  struct cmd_token_t *token = start->data;
+  struct cmd_token *token = start->data;
   enum match_type minmatch = min_match_level (token->type);
 
   // get the current operating input token
@@ -205,7 +204,7 @@ command_match_r (struct graph_node *start, vector vline, unsigned int n)
       // if we've matched all input we're looking for END_TKN
       if (n+1 == vector_active (vline))
         {
-          struct cmd_token_t *tok = gn->data;
+          struct cmd_token *tok = gn->data;
           if (tok->type == END_TKN)
             {
               currbest = list_new();
@@ -255,8 +254,8 @@ command_match_r (struct graph_node *start, vector vline, unsigned int n)
       else
         {
           // copy token, set arg and prepend to currbest
-          struct cmd_token_t *token = start->data;
-          struct cmd_token_t *copy = copy_cmd_token (token);
+          struct cmd_token *token = start->data;
+          struct cmd_token *copy = copy_cmd_token (token);
           copy->arg = XSTRDUP (MTYPE_CMD_TOKENS, input_token);
           list_add_node_prev (currbest, currbest->head, copy);
           matcher_rv = MATCHER_OK;
@@ -301,7 +300,7 @@ command_complete (struct graph *graph,
 
       for (ALL_LIST_ELEMENTS_RO (current,node,gn))
         {
-          struct cmd_token_t *token = gn->data;
+          struct cmd_token *token = gn->data;
           switch (match_token (token, input_token))
             {
               case partly_match:
@@ -359,7 +358,7 @@ add_nexthops (struct list *list, struct graph_node *node)
   for (unsigned int i = 0; i < vector_active (node->to); i++)
     {
       child = vector_slot (node->to, i);
-      struct cmd_token_t *token = child->data;
+      struct cmd_token *token = child->data;
       switch (token->type)
         {
           case OPTION_TKN:
@@ -384,7 +383,7 @@ add_nexthops (struct list *list, struct graph_node *node)
  * @return minimum match level needed to for a token to fully match
  */
 static enum match_type
-min_match_level (enum cmd_token_type_t type)
+min_match_level (enum cmd_token_type type)
 {
   switch (type)
     {
@@ -406,7 +405,7 @@ min_match_level (enum cmd_token_type_t type)
  * @return precedence score
  */
 static int
-score_precedence (enum cmd_token_type_t type)
+score_precedence (enum cmd_token_type type)
 {
   switch (type)
     {
@@ -437,9 +436,9 @@ score_precedence (enum cmd_token_type_t type)
  * @param[in] token the token being matched
  * @return the best-matching node, or NULL if the two are entirely ambiguous
  */
-static struct cmd_token_t *
-disambiguate_tokens (struct cmd_token_t *first,
-                     struct cmd_token_t *second,
+static struct cmd_token *
+disambiguate_tokens (struct cmd_token *first,
+                     struct cmd_token *second,
                      char *input_token)
 {
   // if the types are different, simply go off of type precedence
@@ -465,8 +464,8 @@ disambiguate_tokens (struct cmd_token_t *first,
 /**
  * Picks the better of two possible matches for an input line.
  *
- * @param[in] first candidate list of cmd_token_t matching vline
- * @param[in] second candidate list of cmd_token_t matching vline
+ * @param[in] first candidate list of cmd_token matching vline
+ * @param[in] second candidate list of cmd_token matching vline
  * @param[in] vline the input line being matched
  * @param[in] n index into vline to start comparing at
  * @return the best-matching list, or NULL if the two are entirely ambiguous
@@ -483,7 +482,7 @@ disambiguate (struct list *first,
 
   struct listnode *fnode = listhead (first),
                   *snode = listhead (second);
-  struct cmd_token_t *ftok = listgetdata (fnode),
+  struct cmd_token *ftok = listgetdata (fnode),
                      *stok = listgetdata (snode),
                      *best = NULL;
 
@@ -527,7 +526,7 @@ del_arglist (struct list *list)
 /*---------- token level matching functions ----------*/
 
 static enum match_type
-match_token (struct cmd_token_t *token, char *input_token)
+match_token (struct cmd_token *token, char *input_token)
 {
   switch (token->type) {
     case WORD_TKN:
@@ -761,7 +760,7 @@ match_ipv6_prefix (const char *str)
 #endif
 
 static enum match_type
-match_range (struct cmd_token_t *token, const char *str)
+match_range (struct cmd_token *token, const char *str)
 {
   assert (token->type == RANGE_TKN);
 
@@ -782,7 +781,7 @@ match_range (struct cmd_token_t *token, const char *str)
 }
 
 static enum match_type
-match_word (struct cmd_token_t *token, const char *word)
+match_word (struct cmd_token *token, const char *word)
 {
   assert (token->type == WORD_TKN);
 
@@ -804,7 +803,7 @@ match_word (struct cmd_token_t *token, const char *word)
 }
 
 static enum match_type
-match_number (struct cmd_token_t *token, const char *word)
+match_number (struct cmd_token *token, const char *word)
 {
   assert (token->type == NUMBER_TKN);
 
@@ -819,7 +818,7 @@ match_number (struct cmd_token_t *token, const char *word)
 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890:"
 
 static enum match_type
-match_variable (struct cmd_token_t *token, const char *word)
+match_variable (struct cmd_token *token, const char *word)
 {
   assert (token->type == VARIABLE_TKN);
 
index 1922ba2297fbf2535959d5c476ef317a7b40ebd0..089b506b0322e12f066d64616849c562e32cc689 100644 (file)
@@ -36,7 +36,6 @@
   #include "command.h"
   #include "graph.h"
   #include "memory.h"
-  #include "grammar_sandbox.h"
 
   extern int
   yylex (void);
   add_edge_dedup (struct graph_node *, struct graph_node *);
 
   static int
-  cmp_token (struct cmd_token_t *, struct cmd_token_t *);
+  cmp_token (struct cmd_token *, struct cmd_token *);
 
   static struct graph_node *
   new_token_node (struct graph *,
-                  enum cmd_token_type_t type,
+                  enum cmd_token_type type,
                   char *text, char *doc);
 
   static void
@@ -250,7 +249,7 @@ placeholder_token:
 | RANGE
 {
   $$ = new_token_node (graph, RANGE_TKN, XSTRDUP(MTYPE_CMD_TOKENS, $1), doc_next());
-  struct cmd_token_t *token = $$->data;
+  struct cmd_token *token = $$->data;
 
   // get the numbers out
   yylval.string++;
@@ -263,7 +262,6 @@ placeholder_token:
 
   free ($1);
 }
-;
 
 /* <selector|set> productions */
 selector: '<' selector_seq_seq '>'
@@ -453,9 +451,9 @@ doc_next()
 }
 
 static struct graph_node *
-new_token_node (struct graph *graph, enum cmd_token_type_t type, char *text, char *doc)
+new_token_node (struct graph *graph, enum cmd_token_type type, char *text, char *doc)
 {
-  struct cmd_token_t *token = new_cmd_token (type, text, doc);
+  struct cmd_token *token = new_cmd_token (type, text, doc);
   return graph_new_node (graph, token, (void (*)(void *)) &del_cmd_token);
 }
 
@@ -469,7 +467,7 @@ node_adjacent (struct graph_node *first, struct graph_node *second)
   for (unsigned int i = 0; i < vector_active (first->to); i++)
     {
       adj = vector_slot (first->to, i);
-      struct cmd_token_t *ftok = adj->data,
+      struct cmd_token *ftok = adj->data,
                          *stok = second->data;
       if (cmp_token (ftok, stok))
         return adj;
@@ -503,7 +501,7 @@ add_edge_dedup (struct graph_node *from, struct graph_node *to)
  * for parsing purposes and determines overall graph structure.
  */
 static int
-cmp_token (struct cmd_token_t *first, struct cmd_token_t *second)
+cmp_token (struct cmd_token *first, struct cmd_token *second)
 {
   // compare types
   if (first->type != second->type) return 0;
index 831ae8e55638f69e2dd7968a971c28a11852275c..61b0c3b4be6ec4c0da105c7e36c63f59b66ca417 100644 (file)
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -17,7 +17,7 @@
  * You should have received a copy of the GNU General Public License
  * along with GNU Zebra; see the file COPYING.  If not, write to the Free
  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.  
+ * 02111-1307, USA.
  */
 
 #include <zebra.h>
@@ -41,7 +41,7 @@
 #include <termios.h>
 
 /* Vty events */
-enum event 
+enum event
 {
   VTY_SERV,
   VTY_READ,
@@ -117,37 +117,37 @@ vty_out (struct vty *vty, const char *format, ...)
 
       /* Initial buffer is not enough.  */
       if (len < 0 || len >= size)
-       {
-         while (1)
-           {
-             if (len > -1)
-               size = len + 1;
-             else
-               size = size * 2;
-
-             p = XREALLOC (MTYPE_VTY_OUT_BUF, p, size);
-             if (! p)
-               return -1;
-
-             va_start (args, format);
-             len = vsnprintf (p, size, format, args);
-             va_end (args);
-
-             if (len > -1 && len < size)
-               break;
-           }
-       }
+        {
+          while (1)
+            {
+              if (len > -1)
+                size = len + 1;
+              else
+                size = size * 2;
+
+              p = XREALLOC (MTYPE_VTY_OUT_BUF, p, size);
+              if (! p)
+                return -1;
+
+              va_start (args, format);
+              len = vsnprintf (p, size, format, args);
+              va_end (args);
+
+              if (len > -1 && len < size)
+                break;
+            }
+        }
 
       /* When initial buffer is enough to store all output.  */
       if (! p)
-       p = buf;
+        p = buf;
 
       /* Pointer p must point out buffer. */
       buffer_put (vty->obuf, (u_char *) p, len);
 
       /* If p is not different with buf, it is allocated buffer.  */
       if (p != buf)
-       XFREE (MTYPE_VTY_OUT_BUF, p);
+        XFREE (MTYPE_VTY_OUT_BUF, p);
     }
 
   return len;
@@ -155,7 +155,7 @@ vty_out (struct vty *vty, const char *format, ...)
 
 static int
 vty_log_out (struct vty *vty, const char *level, const char *proto_str,
-            const char *format, struct timestamp_control *ctl, va_list va)
+             const char *format, struct timestamp_control *ctl, va_list va)
 {
   int ret;
   int len;
@@ -189,13 +189,13 @@ vty_log_out (struct vty *vty, const char *level, const char *proto_str,
   if (write(vty->wfd, buf, len) < 0)
     {
       if (ERRNO_IO_RETRY(errno))
-       /* Kernel buffer is full, probably too much debugging output, so just
-          drop the data and ignore. */
-       return -1;
+        /* Kernel buffer is full, probably too much debugging output, so just
+           drop the data and ignore. */
+        return -1;
       /* Fatal I/O error. */
       vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
       zlog_warn("%s: write failed to vty client fd %d, closing: %s",
-               __func__, vty->fd, safe_strerror(errno));
+                __func__, vty->fd, safe_strerror(errno));
       buffer_reset(vty->obuf);
       /* cannot call vty_close, because a parent routine may still try
          to access the vty struct */
@@ -211,7 +211,7 @@ void
 vty_time_print (struct vty *vty, int cr)
 {
   char buf[QUAGGA_TIMESTAMP_LEN];
-  
+
   if (quagga_timestamp(0, buf, sizeof(buf)) == 0)
     {
       zlog (NULL, LOG_INFO, "quagga_timestamp error");
@@ -236,20 +236,20 @@ vty_hello (struct vty *vty)
 
       f = fopen (host.motdfile, "r");
       if (f)
-       {
-         while (fgets (buf, sizeof (buf), f))
-           {
-             char *s;
-             /* work backwards to ignore trailling isspace() */
-             for (s = buf + strlen (buf); (s > buf) && isspace ((int)*(s - 1));
-                  s--);
-             *s = '\0';
-             vty_out (vty, "%s%s", buf, VTY_NEWLINE);
-           }
-         fclose (f);
-       }
+        {
+          while (fgets (buf, sizeof (buf), f))
+            {
+              char *s;
+              /* work backwards to ignore trailling isspace() */
+              for (s = buf + strlen (buf); (s > buf) && isspace ((int)*(s - 1));
+                   s--);
+              *s = '\0';
+              vty_out (vty, "%s%s", buf, VTY_NEWLINE);
+            }
+          fclose (f);
+        }
       else
-       vty_out (vty, "MOTD file not found%s", VTY_NEWLINE);
+        vty_out (vty, "MOTD file not found%s", VTY_NEWLINE);
     }
   else if (host.motd)
     vty_out (vty, "%s", host.motd);
@@ -266,10 +266,10 @@ vty_prompt (struct vty *vty)
     {
       hostname = host.name;
       if (!hostname)
-       {
-         uname (&names);
-         hostname = names.nodename;
-       }
+        {
+          uname (&names);
+          hostname = names.nodename;
+        }
       vty_out (vty, cmd_prompt (vty->node), hostname);
     }
 }
@@ -322,7 +322,7 @@ vty_new ()
 {
   struct vty *new = XCALLOC (MTYPE_VTY, sizeof (struct vty));
 
-  new->obuf = buffer_new(0);   /* Use default buffer size. */
+  new->obuf = buffer_new(0);    /* Use default buffer size. */
   new->buf = XCALLOC (MTYPE_VTY, VTY_BUFSIZ);
   new->error_buf = XCALLOC (MTYPE_VTY, VTY_BUFSIZ);
   new->max = VTY_BUFSIZ;
@@ -343,19 +343,19 @@ vty_auth (struct vty *vty, char *buf)
     {
     case AUTH_NODE:
       if (host.encrypt)
-       passwd = host.password_encrypt;
+        passwd = host.password_encrypt;
       else
-       passwd = host.password;
+        passwd = host.password;
       if (host.advanced)
-       next_node = host.enable ? VIEW_NODE : ENABLE_NODE;
+        next_node = host.enable ? VIEW_NODE : ENABLE_NODE;
       else
-       next_node = VIEW_NODE;
+        next_node = VIEW_NODE;
       break;
     case AUTH_ENABLE_NODE:
       if (host.encrypt)
-       passwd = host.enable_encrypt;
+        passwd = host.enable_encrypt;
       else
-       passwd = host.enable;
+        passwd = host.enable;
       next_node = ENABLE_NODE;
       break;
     }
@@ -363,9 +363,9 @@ vty_auth (struct vty *vty, char *buf)
   if (passwd)
     {
       if (host.encrypt)
-       fail = strcmp (crypt(buf, passwd), passwd);
+        fail = strcmp (crypt(buf, passwd), passwd);
       else
-       fail = strcmp (buf, passwd);
+        fail = strcmp (buf, passwd);
     }
   else
     fail = 1;
@@ -373,26 +373,26 @@ vty_auth (struct vty *vty, char *buf)
   if (! fail)
     {
       vty->fail = 0;
-      vty->node = next_node;   /* Success ! */
+      vty->node = next_node;    /* Success ! */
     }
   else
     {
       vty->fail++;
       if (vty->fail >= 3)
-       {
-         if (vty->node == AUTH_NODE)
-           {
-             vty_out (vty, "%% Bad passwords, too many failures!%s", VTY_NEWLINE);
-             vty->status = VTY_CLOSE;
-           }
-         else                  
-           {
-             /* AUTH_ENABLE_NODE */
-             vty->fail = 0;
-             vty_out (vty, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE);
-             vty->node = restricted_mode ? RESTRICTED_NODE : VIEW_NODE;
-           }
-       }
+        {
+          if (vty->node == AUTH_NODE)
+            {
+              vty_out (vty, "%% Bad passwords, too many failures!%s", VTY_NEWLINE);
+              vty->status = VTY_CLOSE;
+            }
+          else
+            {
+              /* AUTH_ENABLE_NODE */
+              vty->fail = 0;
+              vty_out (vty, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE);
+              vty->node = restricted_mode ? RESTRICTED_NODE : VIEW_NODE;
+            }
+        }
     }
 }
 
@@ -419,7 +419,7 @@ vty_command (struct vty *vty, char *buf)
   if (cp != NULL && *cp != '\0')
     {
       unsigned i;
-      char     vty_str[VTY_BUFSIZ];
+      char      vty_str[VTY_BUFSIZ];
       char        prompt_str[VTY_BUFSIZ];
 
       /* format the base vty info */
@@ -461,14 +461,14 @@ vty_command (struct vty *vty, char *buf)
       protocolname = zlog_proto_names[zlog_default->protocol];
   else
       protocolname = zlog_proto_names[ZLOG_NONE];
-                                                                           
+
 #ifdef CONSUMED_TIME_CHECK
     GETRUSAGE(&after);
     if ((realtime = thread_consumed_time(&after, &before, &cputime)) >
-       CONSUMED_TIME_CHECK)
+        CONSUMED_TIME_CHECK)
       /* Warn about CPU hog that must be fixed. */
       zlog_warn("SLOW COMMAND: command took %lums (cpu time %lums): %s",
-               realtime/1000, cputime/1000, buf);
+                realtime/1000, cputime/1000, buf);
   }
 #endif /* CONSUMED_TIME_CHECK */
 
@@ -476,18 +476,18 @@ vty_command (struct vty *vty, char *buf)
     switch (ret)
       {
       case CMD_WARNING:
-       if (vty->type == VTY_FILE)
-         vty_out (vty, "Warning...%s", VTY_NEWLINE);
-       break;
+        if (vty->type == VTY_FILE)
+          vty_out (vty, "Warning...%s", VTY_NEWLINE);
+        break;
       case CMD_ERR_AMBIGUOUS:
-       vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
-       break;
+        vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
+        break;
       case CMD_ERR_NO_MATCH:
-       vty_out (vty, "%% [%s] Unknown command: %s%s", protocolname, buf, VTY_NEWLINE);
-       break;
+        vty_out (vty, "%% [%s] Unknown command: %s%s", protocolname, buf, VTY_NEWLINE);
+        break;
       case CMD_ERR_INCOMPLETE:
-       vty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE);
-       break;
+        vty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE);
+        break;
       }
   cmd_free_strvec (vline);
 
@@ -685,7 +685,7 @@ vty_forward_word (struct vty *vty)
 {
   while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
     vty_forward_char (vty);
-  
+
   while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
     vty_forward_char (vty);
 }
@@ -782,14 +782,14 @@ vty_delete_char (struct vty *vty)
     }
 
   if (vty->cp == vty->length)
-    return;                    /* completion need here? */
+    return;                     /* completion need here? */
 
   size = vty->length - vty->cp;
 
   vty->length--;
   memmove (&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1);
   vty->buf[vty->length] = '\0';
-  
+
   if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
     return;
 
@@ -819,7 +819,7 @@ vty_kill_line (struct vty *vty)
   int size;
 
   size = vty->length - vty->cp;
-  
+
   if (size == 0)
     return;
 
@@ -914,7 +914,7 @@ vty_complete_command (struct vty *vty)
     vector_set (vline, NULL);
 
   matched = cmd_complete_command_lib (vline, vty, &ret, 1);
-  
+
   cmd_free_strvec (vline);
 
   vty_out (vty, "%s", VTY_NEWLINE);
@@ -949,12 +949,12 @@ vty_complete_command (struct vty *vty)
       break;
     case CMD_COMPLETE_LIST_MATCH:
       for (i = 0; matched[i] != NULL; i++)
-       {
-         if (i != 0 && ((i % 6) == 0))
-           vty_out (vty, "%s", VTY_NEWLINE);
-         vty_out (vty, "%-10s ", matched[i]);
-         XFREE (MTYPE_TMP, matched[i]);
-       }
+        {
+          if (i != 0 && ((i % 6) == 0))
+            vty_out (vty, "%s", VTY_NEWLINE);
+          vty_out (vty, "%-10s ", matched[i]);
+          XFREE (MTYPE_TMP, matched[i]);
+        }
       vty_out (vty, "%s", VTY_NEWLINE);
 
       vty_prompt (vty);
@@ -973,14 +973,12 @@ vty_complete_command (struct vty *vty)
 
 static void
 vty_describe_fold (struct vty *vty, int cmd_width,
-                  unsigned int desc_width, struct cmd_token *token)
+                   unsigned int desc_width, struct cmd_token *token)
 {
   char *buf;
   const char *cmd, *p;
   int pos;
 
-  cmd = token->cmd[0] == '.' ? token->cmd + 1 : token->cmd;
-
   if (desc_width <= 0)
     {
       vty_out (vty, "  %-*s  %s%s", cmd_width, cmd, token->desc, VTY_NEWLINE);
@@ -1028,7 +1026,7 @@ vty_describe_command (struct vty *vty)
       vline = vector_init (1);
       vector_set (vline, NULL);
     }
-  else 
+  else
     if (isspace ((int) vty->buf[vty->length - 1]))
       vector_set (vline, NULL);
 
@@ -1047,24 +1045,22 @@ vty_describe_command (struct vty *vty)
       vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE);
       goto out;
       break;
-    }  
+    }
 
   /* Get width of command string. */
   width = 0;
   for (i = 0; i < vector_active (describe); i++)
     if ((token = vector_slot (describe, i)) != NULL)
       {
-       unsigned int len;
+        unsigned int len;
 
-       if (token->cmd[0] == '\0')
-         continue;
+        if (token->text[0] == '\0')
+          continue;
 
-       len = strlen (token->cmd);
-       if (token->cmd[0] == '.')
-         len--;
+        len = strlen (token->text);
 
-       if (width < len)
-         width = len;
+        if (width < len)
+          width = len;
       }
 
   /* Get width of description string. */
@@ -1074,45 +1070,45 @@ vty_describe_command (struct vty *vty)
   for (i = 0; i < vector_active (describe); i++)
     if ((token = vector_slot (describe, i)) != NULL)
       {
-       if (token->cmd[0] == '\0')
-         continue;
-       
-       if (strcmp (token->cmd, command_cr) == 0)
-         {
-           token_cr = token;
-           continue;
-         }
-
-       if (!token->desc)
-         vty_out (vty, "  %-s%s",
-                  token->cmd[0] == '.' ? token->cmd + 1 : token->cmd,
-                  VTY_NEWLINE);
-       else if (desc_width >= strlen (token->desc))
-         vty_out (vty, "  %-*s  %s%s", width,
-                  token->cmd[0] == '.' ? token->cmd + 1 : token->cmd,
-                  token->desc, VTY_NEWLINE);
-       else
-         vty_describe_fold (vty, width, desc_width, token);
+        if (token->text[0] == '\0')
+          continue;
+
+        if (strcmp (token->text, CMD_CR_TEXT) == 0)
+          {
+            token_cr = token;
+            continue;
+          }
+
+        if (!token->desc)
+          vty_out (vty, "  %-s%s",
+                   token->text,
+                   VTY_NEWLINE);
+        else if (desc_width >= strlen (token->desc))
+          vty_out (vty, "  %-*s  %s%s", width,
+                   token->text,
+                   token->desc, VTY_NEWLINE);
+        else
+          vty_describe_fold (vty, width, desc_width, token);
 
 #if 0
-       vty_out (vty, "  %-*s %s%s", width
-                desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
-                desc->str ? desc->str : "", VTY_NEWLINE);
+        vty_out (vty, "  %-*s %s%s", width
+                 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
+                 desc->str ? desc->str : "", VTY_NEWLINE);
 #endif /* 0 */
       }
 
   if ((token = token_cr))
     {
       if (!token->desc)
-       vty_out (vty, "  %-s%s",
-                token->cmd[0] == '.' ? token->cmd + 1 : token->cmd,
-                VTY_NEWLINE);
+        vty_out (vty, "  %-s%s",
+                 token->text,
+                 VTY_NEWLINE);
       else if (desc_width >= strlen (token->desc))
-       vty_out (vty, "  %-*s  %s%s", width,
-                token->cmd[0] == '.' ? token->cmd + 1 : token->cmd,
-                token->desc, VTY_NEWLINE);
+        vty_out (vty, "  %-*s  %s%s", width,
+                 token->text,
+                 token->desc, VTY_NEWLINE);
       else
-       vty_describe_fold (vty, width, desc_width, token);
+        vty_describe_fold (vty, width, desc_width, token);
     }
 
 out:
@@ -1217,41 +1213,41 @@ vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes)
   for (i = 0; i < nbytes; i++)
     {
       switch (buf[i])
-       {
-       case IAC:
-         vty_out (vty, "IAC ");
-         break;
-       case WILL:
-         vty_out (vty, "WILL ");
-         break;
-       case WONT:
-         vty_out (vty, "WONT ");
-         break;
-       case DO:
-         vty_out (vty, "DO ");
-         break;
-       case DONT:
-         vty_out (vty, "DONT ");
-         break;
-       case SB:
-         vty_out (vty, "SB ");
-         break;
-       case SE:
-         vty_out (vty, "SE ");
-         break;
-       case TELOPT_ECHO:
-         vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE);
-         break;
-       case TELOPT_SGA:
-         vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE);
-         break;
-       case TELOPT_NAWS:
-         vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE);
-         break;
-       default:
-         vty_out (vty, "%x ", buf[i]);
-         break;
-       }
+        {
+        case IAC:
+          vty_out (vty, "IAC ");
+          break;
+        case WILL:
+          vty_out (vty, "WILL ");
+          break;
+        case WONT:
+          vty_out (vty, "WONT ");
+          break;
+        case DO:
+          vty_out (vty, "DO ");
+          break;
+        case DONT:
+          vty_out (vty, "DONT ");
+          break;
+        case SB:
+          vty_out (vty, "SB ");
+          break;
+        case SE:
+          vty_out (vty, "SE ");
+          break;
+        case TELOPT_ECHO:
+          vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE);
+          break;
+        case TELOPT_SGA:
+          vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE);
+          break;
+        case TELOPT_NAWS:
+          vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE);
+          break;
+        default:
+          vty_out (vty, "%x ", buf[i]);
+          break;
+        }
     }
   vty_out (vty, "%s", VTY_NEWLINE);
 
@@ -1264,42 +1260,42 @@ vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes)
       vty->iac_sb_in_progress = 1;
       return 0;
       break;
-    case SE: 
+    case SE:
       {
-       if (!vty->iac_sb_in_progress)
-         return 0;
-
-       if ((vty->sb_len == 0) || (vty->sb_buf[0] == '\0'))
-         {
-           vty->iac_sb_in_progress = 0;
-           return 0;
-         }
-       switch (vty->sb_buf[0])
-         {
-         case TELOPT_NAWS:
-           if (vty->sb_len != TELNET_NAWS_SB_LEN)
-             zlog_warn("RFC 1073 violation detected: telnet NAWS option "
-                       "should send %d characters, but we received %lu",
-                       TELNET_NAWS_SB_LEN, (u_long)vty->sb_len);
-           else if (sizeof(vty->sb_buf) < TELNET_NAWS_SB_LEN)
-             zlog_err("Bug detected: sizeof(vty->sb_buf) %lu < %d, "
-                      "too small to handle the telnet NAWS option",
-                      (u_long)sizeof(vty->sb_buf), TELNET_NAWS_SB_LEN);
-           else
-             {
-               vty->width = ((vty->sb_buf[1] << 8)|vty->sb_buf[2]);
-               vty->height = ((vty->sb_buf[3] << 8)|vty->sb_buf[4]);
+        if (!vty->iac_sb_in_progress)
+          return 0;
+
+        if ((vty->sb_len == 0) || (vty->sb_buf[0] == '\0'))
+          {
+            vty->iac_sb_in_progress = 0;
+            return 0;
+          }
+        switch (vty->sb_buf[0])
+          {
+          case TELOPT_NAWS:
+            if (vty->sb_len != TELNET_NAWS_SB_LEN)
+              zlog_warn("RFC 1073 violation detected: telnet NAWS option "
+                        "should send %d characters, but we received %lu",
+                        TELNET_NAWS_SB_LEN, (u_long)vty->sb_len);
+            else if (sizeof(vty->sb_buf) < TELNET_NAWS_SB_LEN)
+              zlog_err("Bug detected: sizeof(vty->sb_buf) %lu < %d, "
+                       "too small to handle the telnet NAWS option",
+                       (u_long)sizeof(vty->sb_buf), TELNET_NAWS_SB_LEN);
+            else
+              {
+                vty->width = ((vty->sb_buf[1] << 8)|vty->sb_buf[2]);
+                vty->height = ((vty->sb_buf[3] << 8)|vty->sb_buf[4]);
 #ifdef TELNET_OPTION_DEBUG
-               vty_out(vty, "TELNET NAWS window size negotiation completed: "
-                             "width %d, height %d%s",
-                       vty->width, vty->height, VTY_NEWLINE);
+                vty_out(vty, "TELNET NAWS window size negotiation completed: "
+                              "width %d, height %d%s",
+                        vty->width, vty->height, VTY_NEWLINE);
 #endif
-             }
-           break;
-         }
-       vty->iac_sb_in_progress = 0;
-       return 0;
-       break;
+              }
+            break;
+          }
+        vty->iac_sb_in_progress = 0;
+        return 0;
+        break;
       }
     default:
       break;
@@ -1324,7 +1320,7 @@ vty_execute (struct vty *vty)
     default:
       ret = vty_command (vty, vty->buf);
       if (vty->type == VTY_TERM)
-       vty_hist_add (vty);
+        vty_hist_add (vty);
       break;
     }
 
@@ -1394,187 +1390,187 @@ vty_read (struct thread *thread)
   if ((nbytes = read (vty->fd, buf, VTY_READ_BUFSIZ)) <= 0)
     {
       if (nbytes < 0)
-       {
-         if (ERRNO_IO_RETRY(errno))
-           {
-             vty_event (VTY_READ, vty_sock, vty);
-             return 0;
-           }
-         vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
-         zlog_warn("%s: read error on vty client fd %d, closing: %s",
-                   __func__, vty->fd, safe_strerror(errno));
+        {
+          if (ERRNO_IO_RETRY(errno))
+            {
+              vty_event (VTY_READ, vty_sock, vty);
+              return 0;
+            }
+          vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
+          zlog_warn("%s: read error on vty client fd %d, closing: %s",
+                    __func__, vty->fd, safe_strerror(errno));
           buffer_reset(vty->obuf);
-       }
+        }
       vty->status = VTY_CLOSE;
     }
 
-  for (i = 0; i < nbytes; i++) 
+  for (i = 0; i < nbytes; i++)
     {
       if (buf[i] == IAC)
-       {
-         if (!vty->iac)
-           {
-             vty->iac = 1;
-             continue;
-           }
-         else
-           {
-             vty->iac = 0;
-           }
-       }
-      
+        {
+          if (!vty->iac)
+            {
+              vty->iac = 1;
+              continue;
+            }
+          else
+            {
+              vty->iac = 0;
+            }
+        }
+
       if (vty->iac_sb_in_progress && !vty->iac)
-       {
-           if (vty->sb_len < sizeof(vty->sb_buf))
-             vty->sb_buf[vty->sb_len] = buf[i];
-           vty->sb_len++;
-           continue;
-       }
+        {
+            if (vty->sb_len < sizeof(vty->sb_buf))
+              vty->sb_buf[vty->sb_len] = buf[i];
+            vty->sb_len++;
+            continue;
+        }
 
       if (vty->iac)
-       {
-         /* In case of telnet command */
-         int ret = 0;
-         ret = vty_telnet_option (vty, buf + i, nbytes - i);
-         vty->iac = 0;
-         i += ret;
-         continue;
-       }
-               
+        {
+          /* In case of telnet command */
+          int ret = 0;
+          ret = vty_telnet_option (vty, buf + i, nbytes - i);
+          vty->iac = 0;
+          i += ret;
+          continue;
+        }
+
 
       if (vty->status == VTY_MORE)
-       {
-         switch (buf[i])
-           {
-           case CONTROL('C'):
-           case 'q':
-           case 'Q':
-             vty_buffer_reset (vty);
-             break;
+        {
+          switch (buf[i])
+            {
+            case CONTROL('C'):
+            case 'q':
+            case 'Q':
+              vty_buffer_reset (vty);
+              break;
 #if 0 /* More line does not work for "show ip bgp".  */
-           case '\n':
-           case '\r':
-             vty->status = VTY_MORELINE;
-             break;
+            case '\n':
+            case '\r':
+              vty->status = VTY_MORELINE;
+              break;
 #endif
-           default:
-             break;
-           }
-         continue;
-       }
+            default:
+              break;
+            }
+          continue;
+        }
 
       /* Escape character. */
       if (vty->escape == VTY_ESCAPE)
-       {
-         vty_escape_map (buf[i], vty);
-         continue;
-       }
+        {
+          vty_escape_map (buf[i], vty);
+          continue;
+        }
 
       /* Pre-escape status. */
       if (vty->escape == VTY_PRE_ESCAPE)
-       {
-         switch (buf[i])
-           {
-           case '[':
-             vty->escape = VTY_ESCAPE;
-             break;
-           case 'b':
-             vty_backward_word (vty);
-             vty->escape = VTY_NORMAL;
-             break;
-           case 'f':
-             vty_forward_word (vty);
-             vty->escape = VTY_NORMAL;
-             break;
-           case 'd':
-             vty_forward_kill_word (vty);
-             vty->escape = VTY_NORMAL;
-             break;
-           case CONTROL('H'):
-           case 0x7f:
-             vty_backward_kill_word (vty);
-             vty->escape = VTY_NORMAL;
-             break;
-           default:
-             vty->escape = VTY_NORMAL;
-             break;
-           }
-         continue;
-       }
+        {
+          switch (buf[i])
+            {
+            case '[':
+              vty->escape = VTY_ESCAPE;
+              break;
+            case 'b':
+              vty_backward_word (vty);
+              vty->escape = VTY_NORMAL;
+              break;
+            case 'f':
+              vty_forward_word (vty);
+              vty->escape = VTY_NORMAL;
+              break;
+            case 'd':
+              vty_forward_kill_word (vty);
+              vty->escape = VTY_NORMAL;
+              break;
+            case CONTROL('H'):
+            case 0x7f:
+              vty_backward_kill_word (vty);
+              vty->escape = VTY_NORMAL;
+              break;
+            default:
+              vty->escape = VTY_NORMAL;
+              break;
+            }
+          continue;
+        }
 
       switch (buf[i])
-       {
-       case CONTROL('A'):
-         vty_beginning_of_line (vty);
-         break;
-       case CONTROL('B'):
-         vty_backward_char (vty);
-         break;
-       case CONTROL('C'):
-         vty_stop_input (vty);
-         break;
-       case CONTROL('D'):
-         vty_delete_char (vty);
-         break;
-       case CONTROL('E'):
-         vty_end_of_line (vty);
-         break;
-       case CONTROL('F'):
-         vty_forward_char (vty);
-         break;
-       case CONTROL('H'):
-       case 0x7f:
-         vty_delete_backward_char (vty);
-         break;
-       case CONTROL('K'):
-         vty_kill_line (vty);
-         break;
-       case CONTROL('N'):
-         vty_next_line (vty);
-         break;
-       case CONTROL('P'):
-         vty_previous_line (vty);
-         break;
-       case CONTROL('T'):
-         vty_transpose_chars (vty);
-         break;
-       case CONTROL('U'):
-         vty_kill_line_from_beginning (vty);
-         break;
-       case CONTROL('W'):
-         vty_backward_kill_word (vty);
-         break;
-       case CONTROL('Z'):
-         vty_end_config (vty);
-         break;
-       case '\n':
-       case '\r':
-         vty_out (vty, "%s", VTY_NEWLINE);
-         vty_execute (vty);
-         break;
-       case '\t':
-         vty_complete_command (vty);
-         break;
-       case '?':
-         if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
-           vty_self_insert (vty, buf[i]);
-         else
-           vty_describe_command (vty);
-         break;
-       case '\033':
-         if (i + 1 < nbytes && buf[i + 1] == '[')
-           {
-             vty->escape = VTY_ESCAPE;
-             i++;
-           }
-         else
-           vty->escape = VTY_PRE_ESCAPE;
-         break;
-       default:
-         if (buf[i] > 31 && buf[i] < 127)
-           vty_self_insert (vty, buf[i]);
-         break;
-       }
+        {
+        case CONTROL('A'):
+          vty_beginning_of_line (vty);
+          break;
+        case CONTROL('B'):
+          vty_backward_char (vty);
+          break;
+        case CONTROL('C'):
+          vty_stop_input (vty);
+          break;
+        case CONTROL('D'):
+          vty_delete_char (vty);
+          break;
+        case CONTROL('E'):
+          vty_end_of_line (vty);
+          break;
+        case CONTROL('F'):
+          vty_forward_char (vty);
+          break;
+        case CONTROL('H'):
+        case 0x7f:
+          vty_delete_backward_char (vty);
+          break;
+        case CONTROL('K'):
+          vty_kill_line (vty);
+          break;
+        case CONTROL('N'):
+          vty_next_line (vty);
+          break;
+        case CONTROL('P'):
+          vty_previous_line (vty);
+          break;
+        case CONTROL('T'):
+          vty_transpose_chars (vty);
+          break;
+        case CONTROL('U'):
+          vty_kill_line_from_beginning (vty);
+          break;
+        case CONTROL('W'):
+          vty_backward_kill_word (vty);
+          break;
+        case CONTROL('Z'):
+          vty_end_config (vty);
+          break;
+        case '\n':
+        case '\r':
+          vty_out (vty, "%s", VTY_NEWLINE);
+          vty_execute (vty);
+          break;
+        case '\t':
+          vty_complete_command (vty);
+          break;
+        case '?':
+          if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
+            vty_self_insert (vty, buf[i]);
+          else
+            vty_describe_command (vty);
+          break;
+        case '\033':
+          if (i + 1 < nbytes && buf[i + 1] == '[')
+            {
+              vty->escape = VTY_ESCAPE;
+              i++;
+            }
+          else
+            vty->escape = VTY_PRE_ESCAPE;
+          break;
+        default:
+          if (buf[i] > 31 && buf[i] < 127)
+            vty_self_insert (vty, buf[i]);
+          break;
+        }
     }
 
   /* Check status. */
@@ -1614,36 +1610,36 @@ vty_flush (struct thread *thread)
     flushrc = buffer_flush_available(vty->obuf, vty_sock);
   else if (vty->status == VTY_MORELINE)
     flushrc = buffer_flush_window(vty->obuf, vty_sock, vty->width,
-                                 1, erase, 0);
+                                  1, erase, 0);
   else
     flushrc = buffer_flush_window(vty->obuf, vty_sock, vty->width,
-                                 vty->lines >= 0 ? vty->lines :
-                                                   vty->height,
-                                 erase, 0);
+                                  vty->lines >= 0 ? vty->lines :
+                                                    vty->height,
+                                  erase, 0);
   switch (flushrc)
     {
     case BUFFER_ERROR:
       vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
       zlog_warn("buffer_flush failed on vty client fd %d, closing",
-               vty->fd);
+                vty->fd);
       buffer_reset(vty->obuf);
       vty_close(vty);
       return 0;
     case BUFFER_EMPTY:
       if (vty->status == VTY_CLOSE)
-       vty_close (vty);
+        vty_close (vty);
       else
-       {
-         vty->status = VTY_NORMAL;
-         if (vty->lines == 0)
-           vty_event (VTY_READ, vty_sock, vty);
-       }
+        {
+          vty->status = VTY_NORMAL;
+          if (vty->lines == 0)
+            vty_event (VTY_READ, vty_sock, vty);
+        }
       break;
     case BUFFER_PENDING:
       /* There is more data waiting to be written. */
       vty->status = VTY_MORE;
       if (vty->lines == 0)
-       vty_event (VTY_WRITE, vty_sock, vty);
+        vty_event (VTY_WRITE, vty_sock, vty);
       break;
     }
 
@@ -1698,9 +1694,9 @@ vty_create (int vty_sock, union sockunion *su)
       if (restricted_mode)
         vty->node = RESTRICTED_NODE;
       else if (host.advanced)
-       vty->node = ENABLE_NODE;
+        vty->node = ENABLE_NODE;
       else
-       vty->node = VIEW_NODE;
+        vty->node = VIEW_NODE;
     }
   if (host.lines >= 0)
     vty->lines = host.lines;
@@ -1709,12 +1705,12 @@ vty_create (int vty_sock, union sockunion *su)
     {
       /* Vty is not available if password isn't set. */
       if (host.password == NULL && host.password_encrypt == NULL)
-       {
-         vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
-         vty->status = VTY_CLOSE;
-         vty_close (vty);
-         return NULL;
-       }
+        {
+          vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
+          vty->status = VTY_CLOSE;
+          vty_close (vty);
+          return NULL;
+        }
     }
 
   /* Say hello to the world. */
@@ -1834,17 +1830,17 @@ vty_accept (struct thread *thread)
   if (p.family == AF_INET && vty_accesslist_name)
     {
       if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) &&
-         (access_list_apply (acl, &p) == FILTER_DENY))
-       {
-         zlog (NULL, LOG_INFO, "Vty connection refused from %s",
-               sockunion2str (&su, buf, SU_ADDRSTRLEN));
-         close (vty_sock);
-         
-         /* continue accepting connections */
-         vty_event (VTY_SERV, accept_sock, NULL);
-         
-         return 0;
-       }
+          (access_list_apply (acl, &p) == FILTER_DENY))
+        {
+          zlog (NULL, LOG_INFO, "Vty connection refused from %s",
+                sockunion2str (&su, buf, SU_ADDRSTRLEN));
+          close (vty_sock);
+
+          /* continue accepting connections */
+          vty_event (VTY_SERV, accept_sock, NULL);
+
+          return 0;
+        }
     }
 
 #ifdef HAVE_IPV6
@@ -1852,29 +1848,29 @@ vty_accept (struct thread *thread)
   if (p.family == AF_INET6 && vty_ipv6_accesslist_name)
     {
       if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) &&
-         (access_list_apply (acl, &p) == FILTER_DENY))
-       {
-         zlog (NULL, LOG_INFO, "Vty connection refused from %s",
-               sockunion2str (&su, buf, SU_ADDRSTRLEN));
-         close (vty_sock);
-         
-         /* continue accepting connections */
-         vty_event (VTY_SERV, accept_sock, NULL);
-         
-         return 0;
-       }
+          (access_list_apply (acl, &p) == FILTER_DENY))
+        {
+          zlog (NULL, LOG_INFO, "Vty connection refused from %s",
+                sockunion2str (&su, buf, SU_ADDRSTRLEN));
+          close (vty_sock);
+
+          /* continue accepting connections */
+          vty_event (VTY_SERV, accept_sock, NULL);
+
+          return 0;
+        }
     }
 #endif /* HAVE_IPV6 */
-  
+
   on = 1;
-  ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY, 
-                   (char *) &on, sizeof (on));
+  ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY,
+                    (char *) &on, sizeof (on));
   if (ret < 0)
-    zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s", 
-         safe_strerror (errno));
+    zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s",
+          safe_strerror (errno));
 
   zlog (NULL, LOG_INFO, "Vty connection from %s",
-       sockunion2str (&su, buf, SU_ADDRSTRLEN));
+        sockunion2str (&su, buf, SU_ADDRSTRLEN));
 
   vty_create (vty_sock, &su);
 
@@ -1913,14 +1909,14 @@ vty_serv_sock_addrinfo (const char *hostname, unsigned short port)
     {
       if (ainfo->ai_family != AF_INET
 #ifdef HAVE_IPV6
-         && ainfo->ai_family != AF_INET6
+          && ainfo->ai_family != AF_INET6
 #endif /* HAVE_IPV6 */
-         )
-       continue;
+          )
+        continue;
 
       sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
       if (sock < 0)
-       continue;
+        continue;
 
       sockopt_v6only (ainfo->ai_family, sock);
       sockopt_reuseaddr (sock);
@@ -1928,17 +1924,17 @@ vty_serv_sock_addrinfo (const char *hostname, unsigned short port)
 
       ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen);
       if (ret < 0)
-       {
-         close (sock); /* Avoid sd leak. */
-       continue;
-       }
+        {
+          close (sock); /* Avoid sd leak. */
+        continue;
+        }
 
       ret = listen (sock, 3);
-      if (ret < 0) 
-       {
-         close (sock); /* Avoid sd leak. */
-       continue;
-       }
+      if (ret < 0)
+        {
+          close (sock); /* Avoid sd leak. */
+        continue;
+        }
 
       vty_event (VTY_SERV, sock, NULL);
     }
@@ -1969,7 +1965,7 @@ vty_serv_sock_family (const char* addr, unsigned short port, int family)
       case AF_INET6:
         naddr=&su.sin6.sin6_addr;
         break;
-#endif 
+#endif
     }
 
   if(naddr)
@@ -1977,11 +1973,11 @@ vty_serv_sock_family (const char* addr, unsigned short port, int family)
     {
       case -1:
         zlog_err("bad address %s",addr);
-       naddr=NULL;
-       break;
+        naddr=NULL;
+        break;
       case 0:
         zlog_err("error translating address %s: %s",addr,safe_strerror(errno));
-       naddr=NULL;
+        naddr=NULL;
     }
 
   /* Make new socket. */
@@ -1998,16 +1994,16 @@ vty_serv_sock_family (const char* addr, unsigned short port, int family)
   if (ret < 0)
     {
       zlog_warn("can't bind socket");
-      close (accept_sock);     /* Avoid sd leak. */
+      close (accept_sock);      /* Avoid sd leak. */
       return;
     }
 
   /* Listen socket under queue 3. */
   ret = listen (accept_sock, 3);
-  if (ret < 0) 
+  if (ret < 0)
     {
       zlog (NULL, LOG_WARNING, "can't listen socket");
-      close (accept_sock);     /* Avoid sd leak. */
+      close (accept_sock);      /* Avoid sd leak. */
       return;
     }
 
@@ -2029,7 +2025,7 @@ vty_serv_un (const char *path)
   struct sockaddr_un serv;
   mode_t old_mask;
   struct zprivs_ids_t ids;
-  
+
   /* First of all, unlink existing socket */
   unlink (path);
 
@@ -2058,7 +2054,7 @@ vty_serv_un (const char *path)
   if (ret < 0)
     {
       zlog_err("Cannot bind path %s: %s", path, safe_strerror(errno));
-      close (sock);    /* Avoid sd leak. */
+      close (sock);     /* Avoid sd leak. */
       return;
     }
 
@@ -2066,14 +2062,14 @@ vty_serv_un (const char *path)
   if (ret < 0)
     {
       zlog_err("listen(fd %d) failed: %s", sock, safe_strerror(errno));
-      close (sock);    /* Avoid sd leak. */
+      close (sock);     /* Avoid sd leak. */
       return;
     }
 
   umask (old_mask);
 
   zprivs_get_ids(&ids);
-  
+
   if (ids.gid_vty > 0)
     {
       /* set group of socket */
@@ -2097,7 +2093,7 @@ vtysh_accept (struct thread *thread)
   int client_len;
   struct sockaddr_un client;
   struct vty *vty;
-  
+
   accept_sock = THREAD_FD (thread);
 
   vty_event (VTYSH_SERV, accept_sock, NULL);
@@ -2106,7 +2102,7 @@ vtysh_accept (struct thread *thread)
   client_len = sizeof (struct sockaddr_un);
 
   sock = accept (accept_sock, (struct sockaddr *) &client,
-                (socklen_t *) &client_len);
+                 (socklen_t *) &client_len);
 
   if (sock < 0)
     {
@@ -2121,7 +2117,7 @@ vtysh_accept (struct thread *thread)
       close (sock);
       return -1;
     }
-  
+
 #ifdef VTYSH_DEBUG
   printf ("VTY shell accept\n");
 #endif /* VTYSH_DEBUG */
@@ -2176,16 +2172,16 @@ vtysh_read (struct thread *thread)
   if ((nbytes = read (sock, buf, VTY_READ_BUFSIZ)) <= 0)
     {
       if (nbytes < 0)
-       {
-         if (ERRNO_IO_RETRY(errno))
-           {
-             vty_event (VTYSH_READ, sock, vty);
-             return 0;
-           }
-         vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
-         zlog_warn("%s: read failed on vtysh client fd %d, closing: %s",
-                   __func__, sock, safe_strerror(errno));
-       }
+        {
+          if (ERRNO_IO_RETRY(errno))
+            {
+              vty_event (VTYSH_READ, sock, vty);
+              return 0;
+            }
+          vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
+          zlog_warn("%s: read failed on vtysh client fd %d, closing: %s",
+                    __func__, sock, safe_strerror(errno));
+        }
       buffer_reset(vty->obuf);
       vty_close (vty);
 #ifdef VTYSH_DEBUG
@@ -2203,25 +2199,25 @@ vtysh_read (struct thread *thread)
       vty_ensure(vty, vty->length+1);
       vty->buf[vty->length++] = *p;
       if (*p == '\0')
-       {
-         /* Pass this line to parser. */
-         ret = vty_execute (vty);
-         /* Note that vty_execute clears the command buffer and resets
-            vty->length to 0. */
+        {
+          /* Pass this line to parser. */
+          ret = vty_execute (vty);
+          /* Note that vty_execute clears the command buffer and resets
+             vty->length to 0. */
 
-         /* Return result. */
+          /* Return result. */
 #ifdef VTYSH_DEBUG
-         printf ("result: %d\n", ret);
-         printf ("vtysh node: %d\n", vty->node);
+          printf ("result: %d\n", ret);
+          printf ("vtysh node: %d\n", vty->node);
 #endif /* VTYSH_DEBUG */
 
-         header[3] = ret;
-         buffer_put(vty->obuf, header, 4);
+          header[3] = ret;
+          buffer_put(vty->obuf, header, 4);
 
-         if (!vty->t_write && (vtysh_flush(vty) < 0))
-           /* Try to flush results; exit if a write error occurs. */
-           return 0;
-       }
+          if (!vty->t_write && (vtysh_flush(vty) < 0))
+            /* Try to flush results; exit if a write error occurs. */
+            return 0;
+        }
     }
 
   vty_event (VTYSH_READ, sock, vty);
@@ -2350,14 +2346,14 @@ vty_read_file (FILE *confp)
   vty->fd = STDIN_FILENO;
   vty->type = VTY_FILE;
   vty->node = CONFIG_NODE;
-  
+
   /* Execute configuration file */
   ret = config_from_file (vty, confp, &line_num);
 
   /* Flush any previous errors before printing messages below */
   buffer_flush_all (vty->obuf, vty->fd);
 
-  if ( !((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO)) ) 
+  if ( !((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO)) )
     {
       switch (ret)
        {
@@ -2369,7 +2365,7 @@ vty_read_file (FILE *confp)
            break;
        }
       fprintf (stderr, "*** Error occured processing line %u, below:\n%s\n",
-                      line_num, vty->error_buf);
+                       line_num, vty->error_buf);
     }
 
   vty_close (vty);
@@ -2384,7 +2380,7 @@ vty_use_backup_config (char *fullpath)
   int tmp, sav;
   int c;
   char buffer[512];
-  
+
   fullpath_sav = malloc (strlen (fullpath) + strlen (CONF_BACKUP_EXT) + 1);
   strcpy (fullpath_sav, fullpath);
   strcat (fullpath_sav, CONF_BACKUP_EXT);
@@ -2396,7 +2392,7 @@ vty_use_backup_config (char *fullpath)
 
   fullpath_tmp = malloc (strlen (fullpath) + 8);
   sprintf (fullpath_tmp, "%s.XXXXXX", fullpath);
-  
+
   /* Open file to configuration write. */
   tmp = mkstemp (fullpath_tmp);
   if (tmp < 0)
@@ -2414,21 +2410,21 @@ vty_use_backup_config (char *fullpath)
       free (fullpath_tmp);
       return NULL;
     }
-  
+
   while((c = read (sav, buffer, 512)) > 0)
     {
       if (write (tmp, buffer, c) <= 0)
-       {
-         free (fullpath_sav);
-         free (fullpath_tmp);
-         close (sav);
-         close (tmp);
-         return NULL;
-       }
+        {
+          free (fullpath_sav);
+          free (fullpath_tmp);
+          close (sav);
+          close (tmp);
+          return NULL;
+        }
     }
   close (sav);
   close (tmp);
-  
+
   if (chmod(fullpath_tmp, CONFIGFILE_MASK) != 0)
     {
       unlink (fullpath_tmp);
@@ -2436,12 +2432,12 @@ vty_use_backup_config (char *fullpath)
       free (fullpath_tmp);
       return NULL;
     }
-  
+
   if (link (fullpath_tmp, fullpath) == 0)
     ret = fopen (fullpath, "r");
 
   unlink (fullpath_tmp);
-  
+
   free (fullpath_sav);
   free (fullpath_tmp);
   return ret;
@@ -2463,12 +2459,12 @@ vty_read_config (char *config_file,
       if (! IS_DIRECTORY_SEP (config_file[0]))
         {
           if (getcwd (cwd, MAXPATHLEN) == NULL)
-           {
-             fprintf (stderr, "Failure to determine Current Working Directory %d!\n", errno);
-             exit (1);
-           }
-          tmp = XMALLOC (MTYPE_TMP, 
-                             strlen (cwd) + strlen (config_file) + 2);
+            {
+              fprintf (stderr, "Failure to determine Current Working Directory %d!\n", errno);
+              exit (1);
+            }
+          tmp = XMALLOC (MTYPE_TMP,
+                              strlen (cwd) + strlen (config_file) + 2);
           sprintf (tmp, "%s/%s", cwd, config_file);
           fullpath = tmp;
         }
@@ -2481,14 +2477,14 @@ vty_read_config (char *config_file,
         {
           fprintf (stderr, "%s: failed to open configuration file %s: %s\n",
                    __func__, fullpath, safe_strerror (errno));
-          
+
           confp = vty_use_backup_config (fullpath);
           if (confp)
             fprintf (stderr, "WARNING: using backup configuration file!\n");
           else
             {
-              fprintf (stderr, "can't open configuration file [%s]\n", 
-                      config_file);
+              fprintf (stderr, "can't open configuration file [%s]\n",
+                       config_file);
               exit(1);
             }
         }
@@ -2520,7 +2516,7 @@ vty_read_config (char *config_file,
         {
           ret = stat (integrate_default, &conf_stat);
           if (ret >= 0)
-           goto tmp_free_and_out;
+            goto tmp_free_and_out;
         }
 #endif /* VTYSH */
       confp = fopen (config_default_dir, "r");
@@ -2528,7 +2524,7 @@ vty_read_config (char *config_file,
         {
           fprintf (stderr, "%s: failed to open configuration file %s: %s\n",
                    __func__, config_default_dir, safe_strerror (errno));
-          
+
           confp = vty_use_backup_config (config_default_dir);
           if (confp)
             {
@@ -2538,10 +2534,10 @@ vty_read_config (char *config_file,
           else
             {
               fprintf (stderr, "can't open configuration file [%s]\n",
-                      config_default_dir);
-             goto tmp_free_and_out;
+                       config_default_dir);
+              goto tmp_free_and_out;
             }
-        }      
+        }
       else
         fullpath = config_default_dir;
     }
@@ -2560,23 +2556,23 @@ tmp_free_and_out:
 /* Small utility function which output log to the VTY. */
 void
 vty_log (const char *level, const char *proto_str,
-        const char *format, struct timestamp_control *ctl, va_list va)
+         const char *format, struct timestamp_control *ctl, va_list va)
 {
   unsigned int i;
   struct vty *vty;
-  
+
   if (!vtyvec)
     return;
 
   for (i = 0; i < vector_active (vtyvec); i++)
     if ((vty = vector_slot (vtyvec, i)) != NULL)
       if (vty->monitor)
-       {
-         va_list ac;
-         va_copy(ac, va);
-         vty_log_out (vty, level, proto_str, format, ctl, ac);
-         va_end(ac);
-       }
+        {
+          va_list ac;
+          va_copy(ac, va);
+          vty_log_out (vty, level, proto_str, format, ctl, ac);
+          va_end(ac);
+        }
 }
 
 /* Async-signal-safe version of vty_log for fixed strings. */
@@ -2590,7 +2586,7 @@ vty_log_fixed (char *buf, size_t len)
   /* vty may not have been initialised */
   if (!vtyvec)
     return;
-  
+
   iov[0].iov_base = buf;
   iov[0].iov_len = len;
   iov[1].iov_base = crlf;
@@ -2600,13 +2596,13 @@ vty_log_fixed (char *buf, size_t len)
     {
       struct vty *vty;
       if (((vty = vector_slot (vtyvec, i)) != NULL) && vty->monitor)
-       /* N.B. We don't care about the return code, since process is
-          most likely just about to die anyway. */
-       if (writev(vty->wfd, iov, 2) == -1)
-         {
-           fprintf(stderr, "Failure to writev: %d\n", errno);
-           exit(-1);
-         }
+        /* N.B. We don't care about the return code, since process is
+           most likely just about to die anyway. */
+        if (writev(vty->wfd, iov, 2) == -1)
+          {
+            fprintf(stderr, "Failure to writev: %d\n", errno);
+            exit(-1);
+          }
     }
 }
 
@@ -2663,28 +2659,28 @@ vty_event (enum event event, int sock, struct vty *vty)
 
       /* Time out treatment. */
       if (vty->v_timeout)
-       {
-         if (vty->t_timeout)
-           thread_cancel (vty->t_timeout);
-         vty->t_timeout = 
-           thread_add_timer (vty_master, vty_timeout, vty, vty->v_timeout);
-       }
+        {
+          if (vty->t_timeout)
+            thread_cancel (vty->t_timeout);
+          vty->t_timeout =
+            thread_add_timer (vty_master, vty_timeout, vty, vty->v_timeout);
+        }
       break;
     case VTY_WRITE:
       if (! vty->t_write)
-       vty->t_write = thread_add_write (vty_master, vty_flush, vty, sock);
+        vty->t_write = thread_add_write (vty_master, vty_flush, vty, sock);
       break;
     case VTY_TIMEOUT_RESET:
       if (vty->t_timeout)
-       {
-         thread_cancel (vty->t_timeout);
-         vty->t_timeout = NULL;
-       }
+        {
+          thread_cancel (vty->t_timeout);
+          vty->t_timeout = NULL;
+        }
       if (vty->v_timeout)
-       {
-         vty->t_timeout = 
-           thread_add_timer (vty_master, vty_timeout, vty, vty->v_timeout);
-       }
+        {
+          vty->t_timeout =
+            thread_add_timer (vty_master, vty_timeout, vty, vty->v_timeout);
+        }
       break;
     }
 }
@@ -2700,8 +2696,8 @@ DEFUN (config_who,
   for (i = 0; i < vector_active (vtyvec); i++)
     if ((v = vector_slot (vtyvec, i)) != NULL)
       vty_out (vty, "%svty[%d] connected from %s.%s",
-              v->config ? "*" : " ",
-              i, v->address, VTY_NEWLINE);
+               v->config ? "*" : " ",
+               i, v->address, VTY_NEWLINE);
   return CMD_SUCCESS;
 }
 
@@ -2794,7 +2790,7 @@ DEFUN (no_vty_access_class,
   if (! vty_accesslist_name || (argc && strcmp(vty_accesslist_name, argv[0])))
     {
       vty_out (vty, "Access-class is not currently applied to vty%s",
-              VTY_NEWLINE);
+               VTY_NEWLINE);
       return CMD_WARNING;
     }
 
@@ -2835,7 +2831,7 @@ DEFUN (no_vty_ipv6_access_class,
       (argc && strcmp(vty_ipv6_accesslist_name, argv[0])))
     {
       vty_out (vty, "IPv6 access-class is not currently applied to vty%s",
-              VTY_NEWLINE);
+               VTY_NEWLINE);
       return CMD_WARNING;
     }
 
@@ -2947,13 +2943,13 @@ DEFUN (show_history,
   for (index = vty->hindex + 1; index != vty->hindex;)
     {
       if (index == VTY_MAXHIST)
-       {
-         index = 0;
-         continue;
-       }
+        {
+          index = 0;
+          continue;
+        }
 
       if (vty->hist[index] != NULL)
-       vty_out (vty, "  %s%s", vty->hist[index], VTY_NEWLINE);
+        vty_out (vty, "  %s%s", vty->hist[index], VTY_NEWLINE);
 
       index++;
     }
@@ -2980,22 +2976,22 @@ vty_config_write (struct vty *vty)
 
   if (vty_accesslist_name)
     vty_out (vty, " access-class %s%s",
-            vty_accesslist_name, VTY_NEWLINE);
+             vty_accesslist_name, VTY_NEWLINE);
 
   if (vty_ipv6_accesslist_name)
     vty_out (vty, " ipv6 access-class %s%s",
-            vty_ipv6_accesslist_name, VTY_NEWLINE);
+             vty_ipv6_accesslist_name, VTY_NEWLINE);
 
   /* exec-timeout */
   if (vty_timeout_val != VTY_TIMEOUT_DEFAULT)
-    vty_out (vty, " exec-timeout %ld %ld%s", 
-            vty_timeout_val / 60,
-            vty_timeout_val % 60, VTY_NEWLINE);
+    vty_out (vty, " exec-timeout %ld %ld%s",
+             vty_timeout_val / 60,
+             vty_timeout_val % 60, VTY_NEWLINE);
 
   /* login */
   if (no_password_check)
     vty_out (vty, " no login%s", VTY_NEWLINE);
-    
+
   if (restricted_mode != restricted_mode_default)
     {
       if (restricted_mode_default)
@@ -3006,7 +3002,7 @@ vty_config_write (struct vty *vty)
 
   if (do_log_commands)
     vty_out (vty, "log commands%s", VTY_NEWLINE);
-    
+
   vty_out (vty, "!%s", VTY_NEWLINE);
 
   return CMD_SUCCESS;
@@ -3030,16 +3026,16 @@ vty_reset ()
   for (i = 0; i < vector_active (vtyvec); i++)
     if ((vty = vector_slot (vtyvec, i)) != NULL)
       {
-       buffer_reset (vty->obuf);
-       vty->status = VTY_CLOSE;
-       vty_close (vty);
+        buffer_reset (vty->obuf);
+        vty->status = VTY_CLOSE;
+        vty_close (vty);
       }
 
   for (i = 0; i < vector_active (Vvty_serv_thread); i++)
     if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
       {
-       thread_cancel (vty_serv_thread);
-       vector_slot (Vvty_serv_thread, i) = NULL;
+        thread_cancel (vty_serv_thread);
+        vector_slot (Vvty_serv_thread, i) = NULL;
         close (i);
       }
 
@@ -3074,15 +3070,15 @@ vty_save_cwd (void)
        * Hence not worrying about it too much.
        */
       if (!chdir (SYSCONFDIR))
-       {
-         fprintf(stderr, "Failure to chdir to %s, errno: %d\n", SYSCONFDIR, errno);
-         exit(-1);
-       }
+        {
+          fprintf(stderr, "Failure to chdir to %s, errno: %d\n", SYSCONFDIR, errno);
+          exit(-1);
+        }
       if (getcwd (cwd, MAXPATHLEN) == NULL)
-       {
-         fprintf(stderr, "Failure to getcwd, errno: %d\n", errno);
-         exit(-1);
-       }
+        {
+          fprintf(stderr, "Failure to getcwd, errno: %d\n", errno);
+          exit(-1);
+        }
     }
 
   vty_cwd = XMALLOC (MTYPE_TMP, strlen (cwd) + 1);