Diff for /embedaddon/quagga/lib/command.c between versions 1.1.1.3 and 1.1.1.4

version 1.1.1.3, 2013/07/21 23:54:39 version 1.1.1.4, 2016/11/02 10:09:11
Line 1 Line 1
 /*  /*
    Command interpreter routine for virtual terminal [aka TeletYpe]     Command interpreter routine for virtual terminal [aka TeletYpe]
    Copyright (C) 1997, 98, 99 Kunihiro Ishiguro     Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
      Copyright (C) 2013 by Open Source Routing.
      Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC")
   
 This file is part of GNU Zebra.  This file is part of GNU Zebra.
     
Line 35  Boston, MA 02111-1307, USA.  */ Line 37  Boston, MA 02111-1307, USA.  */
    each daemon maintains each own cmdvec. */     each daemon maintains each own cmdvec. */
 vector cmdvec = NULL;  vector cmdvec = NULL;
   
struct desc desc_cr;struct cmd_token token_cr;
 char *command_cr = NULL;  char *command_cr = NULL;
   
   enum filter_type
   {
     FILTER_RELAXED,
     FILTER_STRICT
   };
   
   enum matcher_rv
   {
     MATCHER_OK,
     MATCHER_COMPLETE,
     MATCHER_INCOMPLETE,
     MATCHER_NO_MATCH,
     MATCHER_AMBIGUOUS,
     MATCHER_EXCEED_ARGC_MAX
   };
   
   #define MATCHER_ERROR(matcher_rv) \
     (   (matcher_rv) == MATCHER_INCOMPLETE \
      || (matcher_rv) == MATCHER_NO_MATCH \
      || (matcher_rv) == MATCHER_AMBIGUOUS \
      || (matcher_rv) == MATCHER_EXCEED_ARGC_MAX \
     )
   
 /* Host information structure. */  /* Host information structure. */
 struct host host;  struct host host;
   
Line 156  print_version (const char *progname) Line 181  print_version (const char *progname)
 {  {
   printf ("%s version %s\n", progname, QUAGGA_VERSION);    printf ("%s version %s\n", progname, QUAGGA_VERSION);
   printf ("%s\n", QUAGGA_COPYRIGHT);    printf ("%s\n", QUAGGA_COPYRIGHT);
     printf ("configured with:\n\t%s\n", QUAGGA_CONFIG_ARGS);
 }  }
   
 /* Utility function to concatenate argv argument into a single string  /* Utility function to concatenate argv argument into a single string
    with inserting ' ' character between each argument.  */     with inserting ' ' character between each argument.  */
 char *  char *
Line 196  install_node (struct cmd_node *node,  Line 222  install_node (struct cmd_node *node, 
   node->cmd_vector = vector_init (VECTOR_MIN_SIZE);    node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
 }  }
   
 /* Compare two command's string.  Used in sort_node (). */  
 static int  
 cmp_node (const void *p, const void *q)  
 {  
   const struct cmd_element *a = *(struct cmd_element * const *)p;  
   const struct cmd_element *b = *(struct cmd_element * const *)q;  
   
   return strcmp (a->string, b->string);  
 }  
   
 static int  
 cmp_desc (const void *p, const void *q)  
 {  
   const struct desc *a = *(struct desc * const *)p;  
   const struct desc *b = *(struct desc * const *)q;  
   
   return strcmp (a->cmd, b->cmd);  
 }  
   
 /* Sort each node's command element according to command string. */  
 void  
 sort_node ()  
 {  
   unsigned int i, j;  
   struct cmd_node *cnode;  
   vector descvec;  
   struct cmd_element *cmd_element;  
   
   for (i = 0; i < vector_active (cmdvec); i++)  
     if ((cnode = vector_slot (cmdvec, i)) != NULL)  
       {   
         vector cmd_vector = cnode->cmd_vector;  
         qsort (cmd_vector->index, vector_active (cmd_vector),   
                sizeof (void *), cmp_node);  
   
         for (j = 0; j < vector_active (cmd_vector); j++)  
           if ((cmd_element = vector_slot (cmd_vector, j)) != NULL  
               && vector_active (cmd_element->strvec))  
             {  
               descvec = vector_slot (cmd_element->strvec,  
                                      vector_active (cmd_element->strvec) - 1);  
               qsort (descvec->index, vector_active (descvec),   
                      sizeof (void *), cmp_desc);  
             }  
       }  
 }  
   
 /* Breaking up string into each command piece. I assume given  /* Breaking up string into each command piece. I assume given
    character is separated by a space character. Return value is a     character is separated by a space character. Return value is a
    vector which includes char ** data element. */     vector which includes char ** data element. */
Line 312  cmd_free_strvec (vector v) Line 291  cmd_free_strvec (vector v)
   vector_free (v);    vector_free (v);
 }  }
   
/* Fetch next description.  Used in cmd_make_descvec(). */struct format_parser_state
 {
   vector topvect; /* Top level vector */
   vector intvect; /* Intermediate level vector, used when there's
                    * a multiple in a keyword. */
   vector curvect; /* current vector where read tokens should be
                      appended. */
 
   const char *string; /* pointer to command string, not modified */
   const char *cp; /* pointer in command string, moved along while
                      parsing */
   const char *dp;  /* pointer in description string, moved along while
                      parsing */
 
   int in_keyword; /* flag to remember if we are in a keyword group */
   int in_multiple; /* flag to remember if we are in a multiple group */
   int just_read_word; /* flag to remember if the last thing we red was a
                        * real word and not some abstract token */
 };
 
 static void
 format_parser_error(struct format_parser_state *state, const char *message)
 {
   int offset = state->cp - state->string + 1;
 
   fprintf(stderr, "\nError parsing command: \"%s\"\n", state->string);
   fprintf(stderr, "                        %*c\n", offset, '^');
   fprintf(stderr, "%s at offset %d.\n", message, offset);
   fprintf(stderr, "This is a programming error. Check your DEFUNs etc.\n");
   exit(1);
 }
 
 static char *  static char *
cmd_desc_str (const char **string)format_parser_desc_str(struct format_parser_state *state)
 {  {
   const char *cp, *start;    const char *cp, *start;
   char *token;    char *token;
   int strlen;    int strlen;
     
   cp = *string;  
   
     cp = state->dp;
   
   if (cp == NULL)    if (cp == NULL)
     return NULL;      return NULL;
   
Line 339  cmd_desc_str (const char **string) Line 349  cmd_desc_str (const char **string)
     cp++;      cp++;
   
   strlen = cp - start;    strlen = cp - start;
  token = XMALLOC (MTYPE_STRVEC, strlen + 1);  token = XMALLOC (MTYPE_CMD_TOKENS, strlen + 1);
   memcpy (token, start, strlen);    memcpy (token, start, strlen);
   *(token + strlen) = '\0';    *(token + strlen) = '\0';
   
  *string = cp;  state->dp = cp;
   
   return token;    return token;
 }  }
   
/* New string vector. */static void
static vectorformat_parser_begin_keyword(struct format_parser_state *state)
cmd_make_descvec (const char *string, const char *descstr) 
 {  {
  int multiple = 0;  struct cmd_token *token;
  const char *sp;  vector keyword_vect;
  char *token; 
  int len; 
  const char *cp; 
  const char *dp; 
  vector allvec; 
  vector strvec = NULL; 
  struct desc *desc; 
   
  cp = string;  if (state->in_keyword
  dp = descstr;      || state->in_multiple)
     format_parser_error(state, "Unexpected '{'");
   
  if (cp == NULL)  state->cp++;
    return NULL;  state->in_keyword = 1;
   
  allvec = vector_init (VECTOR_MIN_SIZE);  token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
   token->type = TOKEN_KEYWORD;
   token->keyword = vector_init(VECTOR_MIN_SIZE);
   
  while (1)  keyword_vect = vector_init(VECTOR_MIN_SIZE);
    {  vector_set(token->keyword, keyword_vect);
      while (isspace ((int) *cp) && *cp != '\0') 
        cp++; 
   
      if (*cp == '(')  vector_set(state->curvect, token);
        {  state->curvect = keyword_vect;
          multiple = 1;}
          cp++; 
        } 
      if (*cp == ')') 
        { 
          multiple = 0; 
          cp++; 
        } 
      if (*cp == '|') 
        { 
          if (! multiple) 
            { 
              fprintf (stderr, "Command parse error!: %s\n", string); 
              exit (1); 
            } 
          cp++; 
        } 
       
      while (isspace ((int) *cp) && *cp != '\0') 
        cp++; 
   
      if (*cp == '(')static void
        {format_parser_begin_multiple(struct format_parser_state *state)
          multiple = 1;{
          cp++;  struct cmd_token *token;
        } 
   
      if (*cp == '\0')   if (state->in_keyword == 1)
        return allvec;    format_parser_error(state, "Keyword starting with '('");
   
      sp = cp;  if (state->in_multiple)
     format_parser_error(state, "Nested group");
   
      while (! (isspace ((int) *cp) || *cp == '\r' || *cp == '\n' || *cp == ')' || *cp == '|') && *cp != '\0')  state->cp++;
        cp++;  state->in_multiple = 1;
   state->just_read_word = 0;
   
      len = cp - sp;  token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
   token->type = TOKEN_MULTIPLE;
   token->multiple = vector_init(VECTOR_MIN_SIZE);
   
      token = XMALLOC (MTYPE_STRVEC, len + 1);  vector_set(state->curvect, token);
      memcpy (token, sp, len);  if (state->curvect != state->topvect)
      *(token + len) = '\0';    state->intvect = state->curvect;
   state->curvect = token->multiple;
 }
   
      desc = XCALLOC (MTYPE_DESC, sizeof (struct desc));static void
      desc->cmd = token;format_parser_end_keyword(struct format_parser_state *state)
      desc->str = cmd_desc_str (&dp);{
   if (state->in_multiple
       || !state->in_keyword)
     format_parser_error(state, "Unexpected '}'");
   
      if (multiple)  if (state->in_keyword == 1)
        {    format_parser_error(state, "Empty keyword group");
          if (multiple == 1)
            {  state->cp++;
              strvec = vector_init (VECTOR_MIN_SIZE);  state->in_keyword = 0;
              vector_set (allvec, strvec);  state->curvect = state->topvect;
            }}
          multiple++;
        }static void
      elseformat_parser_end_multiple(struct format_parser_state *state)
        {{
          strvec = vector_init (VECTOR_MIN_SIZE);  char *dummy;
          vector_set (allvec, strvec);
        }  if (!state->in_multiple)
      vector_set (strvec, desc);    format_parser_error(state, "Unepexted ')'");
 
   if (vector_active(state->curvect) == 0)
     format_parser_error(state, "Empty multiple section");
 
   if (!state->just_read_word)
     {
       /* There are constructions like
        * 'show ip ospf database ... (self-originate|)'
        * in use.
        * The old parser reads a description string for the
        * word '' between |) which will never match.
        * Simulate this behvaior by dropping the next desc
        * string in such a case. */
 
       dummy = format_parser_desc_str(state);
       XFREE(MTYPE_CMD_TOKENS, dummy);
     }      }
   
     state->cp++;
     state->in_multiple = 0;
   
     if (state->intvect)
       state->curvect = state->intvect;
     else
       state->curvect = state->topvect;
 }  }
   
/* Count mandantory string vector size.  This is to determine inputedstatic void
   command has enough command length. */format_parser_handle_pipe(struct format_parser_state *state)
static int 
cmd_cmdsize (vector strvec) 
 {  {
  unsigned int i;  struct cmd_token *keyword_token;
  int size = 0;  vector keyword_vect;
  vector descvec; 
  struct desc *desc; 
   
  for (i = 0; i < vector_active (strvec); i++)  if (state->in_multiple)
    if ((descvec = vector_slot (strvec, i)) != NULL) 
     {      {
      if ((vector_active (descvec)) == 1      state->just_read_word = 0;
        && (desc = vector_slot (descvec, 0)) != NULL)      state->cp++;
        { 
          if (desc->cmd == NULL || CMD_OPTION (desc->cmd)) 
            return size; 
          else 
            size++; 
        } 
      else 
        size++; 
     }      }
  return size;  else if (state->in_keyword)
     {
       state->in_keyword = 1;
       state->cp++;
 
       keyword_token = vector_slot(state->topvect,
                                   vector_active(state->topvect) - 1);
       keyword_vect = vector_init(VECTOR_MIN_SIZE);
       vector_set(keyword_token->keyword, keyword_vect);
       state->curvect = keyword_vect;
     }
   else
     {
       format_parser_error(state, "Unexpected '|'");
     }
 }  }
   
   static void
   format_parser_read_word(struct format_parser_state *state)
   {
     const char *start;
     int len;
     char *cmd;
     struct cmd_token *token;
   
     start = state->cp;
   
     while (state->cp[0] != '\0'
            && !strchr("\r\n(){}|", state->cp[0])
            && !isspace((int)state->cp[0]))
       state->cp++;
   
     len = state->cp - start;
     cmd = XMALLOC(MTYPE_CMD_TOKENS, len + 1);
     memcpy(cmd, start, len);
     cmd[len] = '\0';
   
     token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
     token->type = TOKEN_TERMINAL;
     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. */  /* Return prompt character of specified node. */
 const char *  const char *
 cmd_prompt (enum node_type node)  cmd_prompt (enum node_type node)
Line 497  install_element (enum node_type ntype, struct cmd_elem Line 620  install_element (enum node_type ntype, struct cmd_elem
     }      }
   
   vector_set (cnode->cmd_vector, cmd);    vector_set (cnode->cmd_vector, cmd);
  if (cmd->tokens == NULL)
  if (cmd->strvec == NULL)    cmd->tokens = cmd_parse_format(cmd->string, cmd->doc);
    cmd->strvec = cmd_make_descvec (cmd->string, cmd->doc); 
 
  cmd->cmdsize = cmd_cmdsize (cmd->strvec); 
 }  }
   
 static const unsigned char itoa64[] =  static const unsigned char itoa64[] =
Line 847  cmd_ipv4_prefix_match (const char *str) Line 967  cmd_ipv4_prefix_match (const char *str)
 static enum match_type  static enum match_type
 cmd_ipv6_match (const char *str)  cmd_ipv6_match (const char *str)
 {  {
   int state = STATE_START;  
   int colons = 0, nums = 0, double_colon = 0;  
   const char *sp = NULL;  
   struct sockaddr_in6 sin6_dummy;    struct sockaddr_in6 sin6_dummy;
   int ret;    int ret;
   
Line 1056  cmd_range_match (const char *range, const char *str) Line 1173  cmd_range_match (const char *range, const char *str)
   return 1;    return 1;
 }  }
   
 /* Make completion match and return match type flag. */  
 static enum match_type  static enum match_type
cmd_filter_by_completion (char *command, vector v, unsigned int index)cmd_word_match(struct cmd_token *token,
                enum filter_type filter,
                const char *word)
 {  {
   unsigned int i;  
   const char *str;    const char *str;
   struct cmd_element *cmd_element;  
   enum match_type match_type;    enum match_type match_type;
   vector descvec;  
   struct desc *desc;  
   
  match_type = no_match;  str = token->cmd;
   
  /* If command and cmd_element string does not match set NULL to vector */  if (filter == FILTER_RELAXED)
  for (i = 0; i < vector_active (v); i++)    if (!word || !strlen(word))
    if ((cmd_element = vector_slot (v, i)) != NULL)      return partly_match;
      { 
        if (index >= vector_active (cmd_element->strvec)) 
          vector_slot (v, i) = NULL; 
        else 
          { 
            unsigned int j; 
            int matched = 0; 
   
            descvec = vector_slot (cmd_element->strvec, index);  if (!word)
     return no_match;
   
            for (j = 0; j < vector_active (descvec); j++)  switch (token->terminal)
              if ((desc = vector_slot (descvec, j)))    {
                {      case TERMINAL_VARARG:
                  str = desc->cmd;        return vararg_match;
                   
                  if (CMD_VARARG (str)) 
                    { 
                      if (match_type < vararg_match) 
                        match_type = vararg_match; 
                      matched++; 
                    } 
                  else if (CMD_RANGE (str)) 
                    { 
                      if (cmd_range_match (str, command)) 
                        { 
                          if (match_type < range_match) 
                            match_type = range_match; 
   
                          matched++;      case TERMINAL_RANGE:
                        }        if (cmd_range_match(str, word))
                    }          return range_match;
#ifdef HAVE_IPV6        break;
                  else if (CMD_IPV6 (str)) 
                    { 
                      if (cmd_ipv6_match (command)) 
                        { 
                          if (match_type < ipv6_match) 
                            match_type = ipv6_match; 
   
                          matched++;      case TERMINAL_IPV6:
                        }        match_type = cmd_ipv6_match(word);
                    }        if ((filter == FILTER_RELAXED && match_type != no_match)
                  else if (CMD_IPV6_PREFIX (str))          || (filter == FILTER_STRICT && match_type == exact_match))
                    {          return ipv6_match;
                      if (cmd_ipv6_prefix_match (command))        break;
                        { 
                          if (match_type < ipv6_prefix_match) 
                            match_type = ipv6_prefix_match; 
   
                          matched++;      case TERMINAL_IPV6_PREFIX:
                        }        match_type = cmd_ipv6_prefix_match(word);
                    }        if ((filter == FILTER_RELAXED && match_type != no_match)
#endif /* HAVE_IPV6  */            || (filter == FILTER_STRICT && match_type == exact_match))
                  else if (CMD_IPV4 (str))          return ipv6_prefix_match;
                    {        break;
                      if (cmd_ipv4_match (command)) 
                        { 
                          if (match_type < ipv4_match) 
                            match_type = ipv4_match; 
   
                          matched++;      case TERMINAL_IPV4:
                        }        match_type = cmd_ipv4_match(word);
                    }        if ((filter == FILTER_RELAXED && match_type != no_match)
                  else if (CMD_IPV4_PREFIX (str))            || (filter == FILTER_STRICT && match_type == exact_match))
                    {          return ipv4_match;
                      if (cmd_ipv4_prefix_match (command))        break;
                        {
                          if (match_type < ipv4_prefix_match)      case TERMINAL_IPV4_PREFIX:
                            match_type = ipv4_prefix_match;        match_type = cmd_ipv4_prefix_match(word);
                          matched++;        if ((filter == FILTER_RELAXED && match_type != no_match)
                        }            || (filter == FILTER_STRICT && match_type == exact_match))
                    }          return ipv4_prefix_match;
                  else        break;
                    /* Check is this point's argument optional ? */
                  if (CMD_OPTION (str) || CMD_VARIABLE (str))      case TERMINAL_OPTION:
                    {      case TERMINAL_VARIABLE:
                      if (match_type < extend_match)        return extend_match;
                        match_type = extend_match;
                      matched++;      case TERMINAL_LITERAL:
                    }        if (filter == FILTER_RELAXED && !strncmp(str, word, strlen(word)))
                  else if (strncmp (command, str, strlen (command)) == 0)          {
                    {            if (!strcmp(str, word))
                      if (strcmp (command, str) == 0)              return exact_match;
                        match_type = exact_match;            return partly_match;
                      else          }
                        {        if (filter == FILTER_STRICT && !strcmp(str, word))
                          if (match_type < partly_match)          return exact_match;
                            match_type = partly_match;        break;
                        }
                      matched++;      default:
                    }        assert (0);
                }    }
            if (!matched)
              vector_slot (v, i) = NULL;  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 (*argc >= CMD_ARGC_MAX)
     return -1;
 
   argv[(*argc)++] = arg;
   return 0;
 }
 
 static void
 cmd_matcher_record_match(struct cmd_matcher *matcher,
                          enum match_type match_type,
                          struct cmd_token *token)
 {
   if (matcher->word_index != matcher->index)
     return;
 
   if (matcher->match)
     {
       if (!*matcher->match)
         *matcher->match = vector_init(VECTOR_MIN_SIZE);
       vector_set(*matcher->match, token);
     }
 
   if (matcher->match_type)
     {
       if (match_type > *matcher->match_type)
         *matcher->match_type = match_type;
     }
 }
 
 static int
 cmd_matcher_words_left(struct cmd_matcher *matcher)
 {
   return matcher->word_index < vector_active(matcher->vline);
 }
 
 static const char*
 cmd_matcher_get_word(struct cmd_matcher *matcher)
 {
   assert(cmd_matcher_words_left(matcher));
 
   return vector_slot(matcher->vline, matcher->word_index);
 }
 
 static enum matcher_rv
 cmd_matcher_match_terminal(struct cmd_matcher *matcher,
                            struct cmd_token *token,
                            int *argc, const char **argv)
 {
   const char *word;
   enum match_type word_match;
 
   assert(token->type == TOKEN_TERMINAL);
 
   if (!cmd_matcher_words_left(matcher))
     {
       if (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 match_type;
   return MATCHER_OK;
 }  }
   
/* Filter vector by command character with index. */static enum matcher_rv
static enum match_typecmd_matcher_match_multiple(struct cmd_matcher *matcher,
cmd_filter_by_string (char *command, vector v, unsigned int index)                           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 int i;
  const char *str;  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_NO_MATCH;
 
   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_NO_MATCH;
 
   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;    struct cmd_element *cmd_element;
  enum match_type match_type;  enum match_type best_match;
  vector descvec;  enum match_type element_match;
  struct desc *desc;  enum matcher_rv matcher_rv;
   
  match_type = no_match;  best_match = no_match;
   *matches = vector_init(VECTOR_MIN_SIZE);
   
  /* If command and cmd_element string does not match set NULL to vector */  for (i = 0; i < vector_active (commands); i++)
  for (i = 0; i < vector_active (v); i++)    if ((cmd_element = vector_slot (commands, i)) != NULL)
    if ((cmd_element = vector_slot (v, i)) != NULL) 
       {        {
        /* If given index is bigger than max string vector of command,        vector_set_index(*matches, i, NULL);
           set NULL */        matcher_rv = cmd_element_match(cmd_element, filter,
        if (index >= vector_active (cmd_element->strvec))                                       vline, index,
          vector_slot (v, i) = NULL;                                       &element_match,
        else                                       (vector*)&vector_slot(*matches, i),
          {                                       NULL, NULL);
            unsigned int j;        if (MATCHER_ERROR(matcher_rv))
            int matched = 0;          {
             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;
 }
   
            descvec = vector_slot (cmd_element->strvec, index);/**
  * 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;
   
            for (j = 0; j < vector_active (descvec); j++)  rv = cmd_element_match(cmd_element,
              if ((desc = vector_slot (descvec, j)))                         FILTER_RELAXED,
                {                         vline, -1,
                  str = desc->cmd;                         NULL, NULL,
                          NULL, NULL);
   return (rv == MATCHER_COMPLETE);
 }
   
                  if (CMD_VARARG (str))/**
                    { * Parse a given commandline and construct a list of arguments for the
                      if (match_type < vararg_match) * given command_element.
                        match_type = vararg_match; *
                      matched++; * @param cmd_element The cmd_element for which we want to construct arguments.
                    } * @param vline The tokenized commandline.
                  else if (CMD_RANGE (str)) * @param argc Where to store the argument count.
                    { * @param argv Where to store the argument list. Should be at least
                      if (cmd_range_match (str, command)) *             CMD_ARGC_MAX elements long.
                        { * @return CMD_SUCCESS if everything went alright, an error otherwise.
                          if (match_type < range_match) */
                            match_type = range_match;static int
                          matched++;cmd_parse(struct cmd_element *cmd_element,
                        }          vector vline,
                    }          int *argc, const char **argv)
#ifdef HAVE_IPV6{
                  else if (CMD_IPV6 (str))  enum matcher_rv rv = cmd_element_match(cmd_element,
                    {                                         FILTER_RELAXED,
                      if (cmd_ipv6_match (command) == exact_match)                                         vline, -1,
                        {                                         NULL, NULL,
                          if (match_type < ipv6_match)                                         argc, argv);
                            match_type = ipv6_match;  switch (rv)
                          matched++;    {
                        }    case MATCHER_COMPLETE:
                    }      return CMD_SUCCESS;
                  else if (CMD_IPV6_PREFIX (str))
                    {    case MATCHER_NO_MATCH:
                      if (cmd_ipv6_prefix_match (command) == exact_match)      return CMD_ERR_NO_MATCH;
                        {
                          if (match_type < ipv6_prefix_match)    case MATCHER_AMBIGUOUS:
                            match_type = ipv6_prefix_match;      return CMD_ERR_AMBIGUOUS;
                          matched++;
                        }    case MATCHER_EXCEED_ARGC_MAX:
                    }      return CMD_ERR_EXEED_ARGC_MAX;
#endif /* HAVE_IPV6  */
                  else if (CMD_IPV4 (str))    default:
                    {      return CMD_ERR_INCOMPLETE;
                      if (cmd_ipv4_match (command) == exact_match)    }
                        { 
                          if (match_type < ipv4_match) 
                            match_type = ipv4_match; 
                          matched++; 
                        } 
                    } 
                  else if (CMD_IPV4_PREFIX (str)) 
                    { 
                      if (cmd_ipv4_prefix_match (command) == exact_match) 
                        { 
                          if (match_type < ipv4_prefix_match) 
                            match_type = ipv4_prefix_match; 
                          matched++; 
                        } 
                    } 
                  else if (CMD_OPTION (str) || CMD_VARIABLE (str)) 
                    { 
                      if (match_type < extend_match) 
                        match_type = extend_match; 
                      matched++; 
                    } 
                  else 
                    { 
                      if (strcmp (command, str) == 0) 
                        { 
                          match_type = exact_match; 
                          matched++; 
                        } 
                    } 
                } 
            if (!matched) 
              vector_slot (v, i) = NULL; 
          } 
      } 
  return match_type; 
 }  }
   
 /* Check ambiguous match */  /* Check ambiguous match */
 static int  static int
is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)is_cmd_ambiguous (vector cmd_vector,
                   const char *command,
                   vector matches,
                   enum match_type type)
 {  {
   unsigned int i;    unsigned int i;
   unsigned int j;    unsigned int j;
   const char *str = NULL;    const char *str = NULL;
   struct cmd_element *cmd_element;  
   const char *matched = NULL;    const char *matched = NULL;
  vector descvec;  vector match_vector;
  struct desc *desc;  struct cmd_token *cmd_token;
   
  for (i = 0; i < vector_active (v); i++)  if (command == NULL)
    if ((cmd_element = vector_slot (v, i)) != NULL)    command = "";
 
   for (i = 0; i < vector_active (matches); i++)
     if ((match_vector = vector_slot (matches, i)) != NULL)
       {        {
         int match = 0;          int match = 0;
   
        descvec = vector_slot (cmd_element->strvec, index);        for (j = 0; j < vector_active (match_vector); j++)
          if ((cmd_token = vector_slot (match_vector, j)) != NULL)
        for (j = 0; j < vector_active (descvec); j++) 
          if ((desc = vector_slot (descvec, j))) 
             {              {
               enum match_type ret;                enum match_type ret;
                 
               str = desc->cmd;  
   
                 assert(cmd_token->type == TOKEN_TERMINAL);
                 if (cmd_token->type != TOKEN_TERMINAL)
                   continue;
   
                 str = cmd_token->cmd;
   
               switch (type)                switch (type)
                 {                  {
                 case exact_match:                  case exact_match:
                  if (!(CMD_OPTION (str) || CMD_VARIABLE (str))                  if (!TERMINAL_RECORD (cmd_token->terminal)
                       && strcmp (command, str) == 0)                        && strcmp (command, str) == 0)
                     match++;                      match++;
                   break;                    break;
                 case partly_match:                  case partly_match:
                  if (!(CMD_OPTION (str) || CMD_VARIABLE (str))                  if (!TERMINAL_RECORD (cmd_token->terminal)
                       && strncmp (command, str, strlen (command)) == 0)                        && strncmp (command, str, strlen (command)) == 0)
                     {                      {
                       if (matched && strcmp (matched, str) != 0)                        if (matched && strcmp (matched, str) != 0)
Line 1335  is_cmd_ambiguous (char *command, vector v, int index,  Line 1896  is_cmd_ambiguous (char *command, vector v, int index, 
                   break;                    break;
 #ifdef HAVE_IPV6  #ifdef HAVE_IPV6
                 case ipv6_match:                  case ipv6_match:
                  if (CMD_IPV6 (str))                  if (cmd_token->terminal == TERMINAL_IPV6)
                     match++;                      match++;
                   break;                    break;
                 case ipv6_prefix_match:                  case ipv6_prefix_match:
Line 1349  is_cmd_ambiguous (char *command, vector v, int index,  Line 1910  is_cmd_ambiguous (char *command, vector v, int index, 
                   break;                    break;
 #endif /* HAVE_IPV6 */  #endif /* HAVE_IPV6 */
                 case ipv4_match:                  case ipv4_match:
                  if (CMD_IPV4 (str))                  if (cmd_token->terminal == TERMINAL_IPV4)
                     match++;                      match++;
                   break;                    break;
                 case ipv4_prefix_match:                  case ipv4_prefix_match:
Line 1362  is_cmd_ambiguous (char *command, vector v, int index,  Line 1923  is_cmd_ambiguous (char *command, vector v, int index, 
                     }                      }
                   break;                    break;
                 case extend_match:                  case extend_match:
                  if (CMD_OPTION (str) || CMD_VARIABLE (str))                  if (TERMINAL_RECORD (cmd_token->terminal))
                     match++;                      match++;
                   break;                    break;
                 case no_match:                  case no_match:
Line 1371  is_cmd_ambiguous (char *command, vector v, int index,  Line 1932  is_cmd_ambiguous (char *command, vector v, int index, 
                 }                  }
             }              }
         if (!match)          if (!match)
          vector_slot (v, i) = NULL;          vector_slot (cmd_vector, i) = NULL;
       }        }
   return 0;    return 0;
 }  }
   
 /* If src matches dst return dst string, otherwise return NULL */  /* If src matches dst return dst string, otherwise return NULL */
 static const char *  static const char *
cmd_entry_function (const char *src, const char *dst)cmd_entry_function (const char *src, struct cmd_token *token)
 {  {
     const char *dst = token->cmd;
   
   /* Skip variable arguments. */    /* Skip variable arguments. */
  if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||  if (TERMINAL_RECORD (token->terminal))
      CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst)) 
     return NULL;      return NULL;
   
   /* In case of 'command \t', given src is NULL string. */    /* In case of 'command \t', given src is NULL string. */
Line 1400  cmd_entry_function (const char *src, const char *dst) Line 1962  cmd_entry_function (const char *src, const char *dst)
 /* This version will return the dst string always if it is  /* This version will return the dst string always if it is
    CMD_VARIABLE for '?' key processing */     CMD_VARIABLE for '?' key processing */
 static const char *  static const char *
cmd_entry_function_desc (const char *src, const char *dst)cmd_entry_function_desc (const char *src, struct cmd_token *token)
 {  {
  if (CMD_VARARG (dst))  const char *dst = token->cmd;
    return dst; 
   
  if (CMD_RANGE (dst))  switch (token->terminal)
     {      {
      if (cmd_range_match (dst, src))      case TERMINAL_VARARG:
        return dst;        return dst;
      else 
        return NULL; 
    } 
   
#ifdef HAVE_IPV6      case TERMINAL_RANGE:
  if (CMD_IPV6 (dst))        if (cmd_range_match (dst, src))
    {          return dst;
      if (cmd_ipv6_match (src))        else
        return dst;          return NULL;
      else 
        return NULL; 
    } 
   
  if (CMD_IPV6_PREFIX (dst))      case TERMINAL_IPV6:
    {        if (cmd_ipv6_match (src))
      if (cmd_ipv6_prefix_match (src))          return dst;
        return dst;        else
      else          return NULL;
        return NULL; 
    } 
#endif /* HAVE_IPV6 */ 
   
  if (CMD_IPV4 (dst))      case TERMINAL_IPV6_PREFIX:
    {        if (cmd_ipv6_prefix_match (src))
      if (cmd_ipv4_match (src))          return dst;
        return dst;        else
      else          return NULL;
        return NULL; 
    } 
   
  if (CMD_IPV4_PREFIX (dst))      case TERMINAL_IPV4:
    {        if (cmd_ipv4_match (src))
      if (cmd_ipv4_prefix_match (src))          return dst;
        return dst;        else
      else          return NULL;
        return NULL; 
    } 
   
  /* Optional or variable commands always match on '?' */      case TERMINAL_IPV4_PREFIX:
  if (CMD_OPTION (dst) || CMD_VARIABLE (dst))        if (cmd_ipv4_prefix_match (src))
    return dst;          return dst;
         else
           return NULL;
   
  /* In case of 'command \t', given src is NULL string. */      /* Optional or variable commands always match on '?' */
  if (src == NULL)      case TERMINAL_OPTION:
    return dst;      case TERMINAL_VARIABLE:
         return dst;
   
  if (strncmp (src, dst, strlen (src)) == 0)      case TERMINAL_LITERAL:
    return dst;        /* In case of 'command \t', given src is NULL string. */
  else        if (src == NULL)
    return NULL;          return dst;
 
         if (strncmp (src, dst, strlen (src)) == 0)
           return dst;
         else
           return NULL;
 
       default:
         assert(0);
         return NULL;
     }
 }  }
   
/* Check same string element existence.  If it isn't there return/**
    1. */ * Check whether a string is already present in a vector of strings.
  * @param v A vector of char*.
  * @param str A char*.
  * @return 0 if str is already present in the vector, 1 otherwise.
  */
 static int  static int
 cmd_unique_string (vector v, const char *str)  cmd_unique_string (vector v, const char *str)
 {  {
Line 1476  cmd_unique_string (vector v, const char *str) Line 2041  cmd_unique_string (vector v, const char *str)
   return 1;    return 1;
 }  }
   
/* Compare string to description vector.  If there is same string/**
   return 1 else return 0. */ * Check whether a struct cmd_token matching a given string is already
  * present in a vector of struct cmd_token.
  * @param v A vector of struct cmd_token*.
  * @param str A char* which should be searched for.
  * @return 0 if there is a struct cmd_token* with its cmd matching str,
  *         1 otherwise.
  */
 static int  static int
 desc_unique_string (vector v, const char *str)  desc_unique_string (vector v, const char *str)
 {  {
   unsigned int i;    unsigned int i;
  struct desc *desc;  struct cmd_token *token;
   
   for (i = 0; i < vector_active (v); i++)    for (i = 0; i < vector_active (v); i++)
    if ((desc = vector_slot (v, i)) != NULL)    if ((token = vector_slot (v, i)) != NULL)
      if (strcmp (desc->cmd, str) == 0)      if (strcmp (token->cmd, str) == 0)
        return 1;        return 0;
  return 0;  return 1;
 }  }
   
 static int   static int 
Line 1504  cmd_try_do_shortcut (enum node_type node, char* first_ Line 2075  cmd_try_do_shortcut (enum node_type node, char* first_
   return 0;    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. */  /* '?' describe command support. */
 static vector  static vector
 cmd_describe_command_real (vector vline, struct vty *vty, int *status)  cmd_describe_command_real (vector vline, struct vty *vty, int *status)
Line 1517  cmd_describe_command_real (vector vline, struct vty *v Line 2117  cmd_describe_command_real (vector vline, struct vty *v
   int ret;    int ret;
   enum match_type match;    enum match_type match;
   char *command;    char *command;
     vector matches = NULL;
     vector match_vector;
     uint32_t command_found = 0;
     const char *last_word;
   
   /* Set index. */    /* Set index. */
   if (vector_active (vline) == 0)    if (vector_active (vline) == 0)
Line 1524  cmd_describe_command_real (vector vline, struct vty *v Line 2128  cmd_describe_command_real (vector vline, struct vty *v
       *status = CMD_ERR_NO_MATCH;        *status = CMD_ERR_NO_MATCH;
       return NULL;        return NULL;
     }      }
  else
    index = vector_active (vline) - 1;  index = vector_active (vline) - 1;
  
   /* Make copy vector of current node's command vector. */    /* Make copy vector of current node's command vector. */
   cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));    cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
   
   /* Prepare match vector */    /* Prepare match vector */
   matchvec = vector_init (INIT_MATCHVEC_SIZE);    matchvec = vector_init (INIT_MATCHVEC_SIZE);
   
  /* Filter commands. */  /* Filter commands and build a list how they could possibly continue. */
  /* Only words precedes current word will be checked in this loop. */  for (i = 0; i <= index; i++)
  for (i = 0; i < index; i++)    {
    if ((command = vector_slot (vline, i)))      command = vector_slot (vline, i);
      { 
        match = cmd_filter_by_completion (command, cmd_vector, i); 
         
        if (match == vararg_match) 
          { 
            struct cmd_element *cmd_element; 
            vector descvec; 
            unsigned int j, k; 
   
            for (j = 0; j < vector_active (cmd_vector); j++)      if (matches)
              if ((cmd_element = vector_slot (cmd_vector, j)) != NULL        cmd_matches_free(&matches);
                  && (vector_active (cmd_element->strvec))) 
                { 
                  descvec = vector_slot (cmd_element->strvec, 
                                         vector_active (cmd_element->strvec) - 1); 
                  for (k = 0; k < vector_active (descvec); k++) 
                    { 
                      struct desc *desc = vector_slot (descvec, k); 
                      vector_set (matchvec, desc); 
                    } 
                } 
             
            vector_set (matchvec, &desc_cr); 
            vector_free (cmd_vector); 
   
            return matchvec;      ret = cmd_vector_filter(cmd_vector,
          }                              FILTER_RELAXED,
                               vline, i,
                               &match,
                               &matches);
   
        if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)      if (ret != CMD_SUCCESS)
          {        {
            vector_free (cmd_vector);          vector_free (cmd_vector);
            vector_free (matchvec);          vector_free (matchvec);
            *status = CMD_ERR_AMBIGUOUS;          cmd_matches_free(&matches);
            return NULL;          *status = ret;
          }          return NULL;
        else if (ret == 2)        }
          { 
            vector_free (cmd_vector); 
            vector_free (matchvec); 
            *status = CMD_ERR_NO_MATCH; 
            return NULL; 
          } 
      } 
   
  /* Prepare match vector */      /* The last match may well be ambigious, so break here */
  /*  matchvec = vector_init (INIT_MATCHVEC_SIZE); */      if (i == index)
         break;
   
  /* Make sure that cmd_vector is filtered based on current word */      if (match == vararg_match)
  command = vector_slot (vline, index);        {
  if (command)          /* We found a vararg match - so we can throw out the current matches here
    match = cmd_filter_by_completion (command, cmd_vector, index);           * 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. */    /* Make description vector. */
  for (i = 0; i < vector_active (cmd_vector); i++)  for (i = 0; i < vector_active (matches); i++)
    if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)    {
      {      if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
        vector strvec = cmd_element->strvec;        {
           unsigned int j;
           vector vline_trimmed;
   
        /* if command is NULL, index may be equal to vector_active */          command_found++;
        if (command && index >= vector_active (strvec))          last_word = vector_slot(vline, vector_active(vline) - 1);
          vector_slot (cmd_vector, i) = NULL;          if (last_word == NULL || !strlen(last_word))
        else            {
          {              vline_trimmed = vector_copy(vline);
            /* Check if command is completed. */              vector_unset(vline_trimmed, vector_active(vline_trimmed) - 1);
            if (command == NULL && index == vector_active (strvec)) 
              { 
                if (!desc_unique_string (matchvec, command_cr)) 
                  vector_set (matchvec, &desc_cr); 
              } 
            else 
              { 
                unsigned int j; 
                vector descvec = vector_slot (strvec, index); 
                struct desc *desc; 
   
                for (j = 0; j < vector_active (descvec); j++)              if (cmd_is_complete(cmd_element, vline_trimmed)
                  if ((desc = vector_slot (descvec, j)))                  && desc_unique_string(matchvec, command_cr))
                    {                {
                      const char *string;                  if (match != vararg_match)
                     vector_set(matchvec, &token_cr);
                 }
   
                      string = cmd_entry_function_desc (command, desc->cmd);              vector_free(vline_trimmed);
                      if (string)            }
                        {
                          /* Uniqueness check */          match_vector = vector_slot (matches, i);
                          if (!desc_unique_string (matchvec, string))          if (match_vector)
                            vector_set (matchvec, desc);            {
                        }              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
    * the 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);    vector_free (cmd_vector);
     cmd_matches_free(&matches);
   
   if (vector_slot (matchvec, 0) == NULL)    if (vector_slot (matchvec, 0) == NULL)
     {      {
Line 1638  cmd_describe_command_real (vector vline, struct vty *v Line 2266  cmd_describe_command_real (vector vline, struct vty *v
     }      }
   
   *status = CMD_SUCCESS;    *status = CMD_SUCCESS;
     cmd_describe_sort(matchvec);
   return matchvec;    return matchvec;
 }  }
   
Line 1708  cmd_lcd (char **matched) Line 2337  cmd_lcd (char **matched)
   return lcd;    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. */  /* Command line completion support. */
 static char **  static char **
cmd_complete_command_real (vector vline, struct vty *vty, int *status)cmd_complete_command_real (vector vline, struct vty *vty, int *status, int islib)
 {  {
   unsigned int i;    unsigned int i;
   vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));    vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
 #define INIT_MATCHVEC_SIZE 10  #define INIT_MATCHVEC_SIZE 10
   vector matchvec;    vector matchvec;
   struct cmd_element *cmd_element;  
   unsigned int index;    unsigned int index;
   char **match_str;    char **match_str;
  struct desc *desc;  struct cmd_token *token;
  vector descvec; 
   char *command;    char *command;
   int lcd;    int lcd;
     vector matches = NULL;
     vector match_vector;
   
   if (vector_active (vline) == 0)    if (vector_active (vline) == 0)
     {      {
Line 1733  cmd_complete_command_real (vector vline, struct vty *v Line 2387  cmd_complete_command_real (vector vline, struct vty *v
   else    else
     index = vector_active (vline) - 1;      index = vector_active (vline) - 1;
   
  /* First, filter by preceeding command string */  /* First, filter by command string */
  for (i = 0; i < index; i++)  for (i = 0; i <= index; i++)
    if ((command = vector_slot (vline, i)))    {
      {      command = vector_slot (vline, i);
        enum match_type match;      enum match_type match;
        int ret;      int ret;
   
        /* First try completion match, if there is exactly match return 1 */      if (matches)
        match = cmd_filter_by_completion (command, cmd_vector, i);        cmd_matches_free(&matches);
   
        /* If there is exact match then filter ambiguous match else check      /* First try completion match, if there is exactly match return 1 */
           ambiguousness. */      ret = cmd_vector_filter(cmd_vector,
        if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)                              FILTER_RELAXED,
          {                              vline, i,
            vector_free (cmd_vector);                              &match,
            *status = CMD_ERR_AMBIGUOUS;                              &matches);
            return NULL;
          }      if (ret != CMD_SUCCESS)
        /*        {
           vector_free(cmd_vector);
           cmd_matches_free(&matches);
           *status = ret;
           return NULL;
         }
 
       /* Break here - the completion mustn't be checked to be non-ambiguous */
       if (i == index)
         break;
 
       /* If there is exact match then filter ambiguous match else check
          ambiguousness. */
       ret = is_cmd_ambiguous (cmd_vector, command, matches, match);
       if (ret == 1)
         {
           vector_free (cmd_vector);
           cmd_matches_free(&matches);
           *status = CMD_ERR_AMBIGUOUS;
           return NULL;
         }
       /*
            else if (ret == 2)             else if (ret == 2)
            {             {
            vector_free (cmd_vector);             vector_free (cmd_vector);
              cmd_matches_free(&matches);
            *status = CMD_ERR_NO_MATCH;             *status = CMD_ERR_NO_MATCH;
            return NULL;             return NULL;
            }             }
          */           */
      }    }
       
   /* Prepare match vector. */    /* Prepare match vector. */
   matchvec = vector_init (INIT_MATCHVEC_SIZE);    matchvec = vector_init (INIT_MATCHVEC_SIZE);
   
  /* Now we got into completion */  /* Build the possible list of continuations into a list of completions */
  for (i = 0; i < vector_active (cmd_vector); i++)  for (i = 0; i < vector_active (matches); i++)
    if ((cmd_element = vector_slot (cmd_vector, i)))    if ((match_vector = vector_slot (matches, i)))
       {        {
         const char *string;          const char *string;
        vector strvec = cmd_element->strvec;        unsigned int j;
   
        /* Check field length */        for (j = 0; j < vector_active (match_vector); j++)
        if (index >= vector_active (strvec))          if ((token = vector_slot (match_vector, j)))
          vector_slot (cmd_vector, i) = NULL;            {
        else              string = cmd_entry_function (vector_slot (vline, index), token);
          {              if (string && cmd_unique_string (matchvec, string))
            unsigned int j;                vector_set (matchvec, (islib != 0 ?
                                      XSTRDUP (MTYPE_TMP, string) :
            descvec = vector_slot (strvec, index);                                      strdup (string) /* rl freed */));
            for (j = 0; j < vector_active (descvec); j++)            }
              if ((desc = vector_slot (descvec, j))) 
                { 
                  if ((string =  
                       cmd_entry_function (vector_slot (vline, index), 
                                           desc->cmd))) 
                    if (cmd_unique_string (matchvec, string)) 
                      vector_set (matchvec, XSTRDUP (MTYPE_TMP, string)); 
                } 
          } 
       }        }
   
   /* We don't need cmd_vector any more. */    /* We don't need cmd_vector any more. */
   vector_free (cmd_vector);    vector_free (cmd_vector);
     cmd_matches_free(&matches);
   
   /* No matched command */    /* No matched command */
   if (vector_slot (matchvec, 0) == NULL)    if (vector_slot (matchvec, 0) == NULL)
Line 1832  cmd_complete_command_real (vector vline, struct vty *v Line 2500  cmd_complete_command_real (vector vline, struct vty *v
             {              {
               char *lcdstr;                char *lcdstr;
   
              lcdstr = XMALLOC (MTYPE_STRVEC, lcd + 1);              lcdstr = (islib != 0 ?
                         XMALLOC (MTYPE_TMP, lcd + 1) :
                         malloc(lcd + 1));
               memcpy (lcdstr, matchvec->index[0], lcd);                memcpy (lcdstr, matchvec->index[0], lcd);
               lcdstr[lcd] = '\0';                lcdstr[lcd] = '\0';
   
Line 1840  cmd_complete_command_real (vector vline, struct vty *v Line 2510  cmd_complete_command_real (vector vline, struct vty *v
   
               /* Free matchvec. */                /* Free matchvec. */
               for (i = 0; i < vector_active (matchvec); i++)                for (i = 0; i < vector_active (matchvec); i++)
                {                {
                  if (vector_slot (matchvec, i))                  if (vector_slot (matchvec, i))
                    XFREE (MTYPE_STRVEC, vector_slot (matchvec, i));                    {
                }                      if (islib != 0)
                         XFREE (MTYPE_TMP, vector_slot (matchvec, i));
                       else
                         free (vector_slot (matchvec, i));
                     }
                 }
               vector_free (matchvec);                vector_free (matchvec);
   
               /* Make new matchvec. */                /* Make new matchvec. */
Line 1859  cmd_complete_command_real (vector vline, struct vty *v Line 2534  cmd_complete_command_real (vector vline, struct vty *v
     }      }
   
   match_str = (char **) matchvec->index;    match_str = (char **) matchvec->index;
     cmd_complete_sort(matchvec);
   vector_only_wrapper_free (matchvec);    vector_only_wrapper_free (matchvec);
   *status = CMD_COMPLETE_LIST_MATCH;    *status = CMD_COMPLETE_LIST_MATCH;
   return match_str;    return match_str;
 }  }
   
 char **  char **
cmd_complete_command (vector vline, struct vty *vty, int *status)cmd_complete_command_lib (vector vline, struct vty *vty, int *status, int islib)
 {  {
   char **ret;    char **ret;
   
Line 1886  cmd_complete_command (vector vline, struct vty *vty, i Line 2562  cmd_complete_command (vector vline, struct vty *vty, i
           vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));            vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
         }          }
   
      ret = cmd_complete_command_real (shifted_vline, vty, status);      ret = cmd_complete_command_real (shifted_vline, vty, status, islib);
   
       vector_free(shifted_vline);        vector_free(shifted_vline);
       vty->node = onode;        vty->node = onode;
       return ret;        return ret;
   }    }
   
     return cmd_complete_command_real (vline, vty, status, islib);
   }
   
  return cmd_complete_command_real (vline, vty, status);char **
 cmd_complete_command (vector vline, struct vty *vty, int *status)
 {
   return cmd_complete_command_lib (vline, vty, status, 0);
 }  }
   
 /* return parent node */  /* return parent node */
Line 1909  node_parent ( enum node_type node ) Line 2590  node_parent ( enum node_type node )
   switch (node)    switch (node)
     {      {
     case BGP_VPNV4_NODE:      case BGP_VPNV4_NODE:
       case BGP_VPNV6_NODE:
       case BGP_ENCAP_NODE:
       case BGP_ENCAPV6_NODE:
     case BGP_IPV4_NODE:      case BGP_IPV4_NODE:
     case BGP_IPV4M_NODE:      case BGP_IPV4M_NODE:
     case BGP_IPV6_NODE:      case BGP_IPV6_NODE:
Line 1927  node_parent ( enum node_type node ) Line 2611  node_parent ( enum node_type node )
   
 /* Execute command by argument vline vector. */  /* Execute command by argument vline vector. */
 static int  static int
cmd_execute_command_real (vector vline, struct vty *vty,cmd_execute_command_real (vector vline,
                           enum filter_type filter,
                           struct vty *vty,
                           struct cmd_element **cmd)                            struct cmd_element **cmd)
 {  {
   unsigned int i;    unsigned int i;
Line 1939  cmd_execute_command_real (vector vline, struct vty *vt Line 2625  cmd_execute_command_real (vector vline, struct vty *vt
   int argc;    int argc;
   const char *argv[CMD_ARGC_MAX];    const char *argv[CMD_ARGC_MAX];
   enum match_type match = 0;    enum match_type match = 0;
   int varflag;  
   char *command;    char *command;
     int ret;
     vector matches;
   
   /* Make copy of command elements. */    /* Make copy of command elements. */
   cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));    cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
   
   for (index = 0; index < vector_active (vline); index++)    for (index = 0; index < vector_active (vline); index++)
    if ((command = vector_slot (vline, index)))    {
      {      command = vector_slot (vline, index);
        int ret;      ret = cmd_vector_filter(cmd_vector,
                               filter,
                               vline, index,
                               &match,
                               &matches);
   
        match = cmd_filter_by_completion (command, cmd_vector, index);      if (ret != CMD_SUCCESS)
         {
           cmd_matches_free(&matches);
           return ret;
         }
   
        if (match == vararg_match)      if (match == vararg_match)
         {
           cmd_matches_free(&matches);
           break;            break;
                }
        ret = is_cmd_ambiguous (command, cmd_vector, index, match); 
   
        if (ret == 1)      ret = is_cmd_ambiguous (cmd_vector, command, matches, match);
          {      cmd_matches_free(&matches);
            vector_free (cmd_vector); 
            return CMD_ERR_AMBIGUOUS; 
          } 
        else if (ret == 2) 
          { 
            vector_free (cmd_vector); 
            return CMD_ERR_NO_MATCH; 
          } 
      } 
   
         if (ret == 1)
           {
             vector_free(cmd_vector);
             return CMD_ERR_AMBIGUOUS;
           }
         else if (ret == 2)
           {
             vector_free(cmd_vector);
             return CMD_ERR_NO_MATCH;
           }
       }
   
   /* Check matched count. */    /* Check matched count. */
   matched_element = NULL;    matched_element = NULL;
   matched_count = 0;    matched_count = 0;
Line 1977  cmd_execute_command_real (vector vline, struct vty *vt Line 2676  cmd_execute_command_real (vector vline, struct vty *vt
   for (i = 0; i < vector_active (cmd_vector); i++)    for (i = 0; i < vector_active (cmd_vector); i++)
     if ((cmd_element = vector_slot (cmd_vector, i)))      if ((cmd_element = vector_slot (cmd_vector, i)))
       {        {
        if (match == vararg_match || index >= cmd_element->cmdsize)        if (cmd_is_complete(cmd_element, vline))
           {            {
             matched_element = cmd_element;              matched_element = cmd_element;
 #if 0  
             printf ("DEBUG: %s\n", cmd_element->string);  
 #endif  
             matched_count++;              matched_count++;
           }            }
         else          else
Line 2006  cmd_execute_command_real (vector vline, struct vty *vt Line 2702  cmd_execute_command_real (vector vline, struct vty *vt
   if (matched_count > 1)    if (matched_count > 1)
     return CMD_ERR_AMBIGUOUS;      return CMD_ERR_AMBIGUOUS;
   
  /* Argument treatment */  ret = cmd_parse(matched_element, vline, &argc, argv);
  varflag = 0;  if (ret != CMD_SUCCESS)
  argc = 0;    return ret;
   
   for (i = 0; i < vector_active (vline); i++)  
     {  
       if (varflag)  
         argv[argc++] = vector_slot (vline, i);  
       else  
         {  
           vector descvec = vector_slot (matched_element->strvec, i);  
   
           if (vector_active (descvec) == 1)  
             {  
               struct desc *desc = vector_slot (descvec, 0);  
   
               if (CMD_VARARG (desc->cmd))  
                 varflag = 1;  
   
               if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))  
                 argv[argc++] = vector_slot (vline, i);  
             }  
           else  
             argv[argc++] = vector_slot (vline, i);  
         }  
   
       if (argc >= CMD_ARGC_MAX)  
         return CMD_ERR_EXEED_ARGC_MAX;  
     }  
   
   /* For vtysh execution. */    /* For vtysh execution. */
   if (cmd)    if (cmd)
     *cmd = matched_element;      *cmd = matched_element;
Line 2047  cmd_execute_command_real (vector vline, struct vty *vt Line 2717  cmd_execute_command_real (vector vline, struct vty *vt
   return (*matched_element->func) (matched_element, vty, argc, argv);    return (*matched_element->func) (matched_element, vty, argc, argv);
 }  }
   
   /**
    * Execute a given command, handling things like "do ..." and checking
    * whether the given command might apply at a parent node if doesn't
    * apply for the current node.
    *
    * @param vline Command line input, vector of char* where each element is
    *              one input token.
    * @param vty The vty context in which the command should be executed.
    * @param cmd Pointer where the struct cmd_element of the matched command
    *            will be stored, if any. May be set to NULL if this info is
    *            not needed.
    * @param vtysh If set != 0, don't lookup the command at parent nodes.
    * @return The status of the command that has been executed or an error code
    *         as to why no command could be executed.
    */
 int  int
 cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,  cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
                      int vtysh) {                       int vtysh) {
Line 2070  cmd_execute_command (vector vline, struct vty *vty, st Line 2755  cmd_execute_command (vector vline, struct vty *vty, st
           vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));            vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
         }          }
   
      ret = cmd_execute_command_real (shifted_vline, vty, cmd);      ret = cmd_execute_command_real (shifted_vline, FILTER_RELAXED, vty, cmd);
   
       vector_free(shifted_vline);        vector_free(shifted_vline);
       vty->node = onode;        vty->node = onode;
Line 2078  cmd_execute_command (vector vline, struct vty *vty, st Line 2763  cmd_execute_command (vector vline, struct vty *vty, st
   }    }
   
   
  saved_ret = ret = cmd_execute_command_real (vline, vty, cmd);  saved_ret = ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd);
   
   if (vtysh)    if (vtysh)
     return saved_ret;      return saved_ret;
Line 2089  cmd_execute_command (vector vline, struct vty *vty, st Line 2774  cmd_execute_command (vector vline, struct vty *vty, st
     {      {
       try_node = node_parent(try_node);        try_node = node_parent(try_node);
       vty->node = try_node;        vty->node = try_node;
      ret = cmd_execute_command_real (vline, vty, cmd);      ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd);
       tried = 1;        tried = 1;
       if (ret == CMD_SUCCESS || ret == CMD_WARNING)        if (ret == CMD_SUCCESS || ret == CMD_WARNING)
         {          {
Line 2104  cmd_execute_command (vector vline, struct vty *vty, st Line 2789  cmd_execute_command (vector vline, struct vty *vty, st
   return saved_ret;    return saved_ret;
 }  }
   
/* Execute command by argument readline. *//**
  * Execute a given command, matching it strictly against the current node.
  * This mode is used when reading config files.
  *
  * @param vline Command line input, vector of char* where each element is
  *              one input token.
  * @param vty The vty context in which the command should be executed.
  * @param cmd Pointer where the struct cmd_element* of the matched command
  *            will be stored, if any. May be set to NULL if this info is
  *            not needed.
  * @return The status of the command that has been executed or an error code
  *         as to why no command could be executed.
  */
 int  int
 cmd_execute_command_strict (vector vline, struct vty *vty,  cmd_execute_command_strict (vector vline, struct vty *vty,
                             struct cmd_element **cmd)                              struct cmd_element **cmd)
 {  {
  unsigned int i;  return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd);
  unsigned int index;}
  vector cmd_vector; 
  struct cmd_element *cmd_element; 
  struct cmd_element *matched_element; 
  unsigned int matched_count, incomplete_count; 
  int argc; 
  const char *argv[CMD_ARGC_MAX]; 
  int varflag; 
  enum match_type match = 0; 
  char *command; 
   
  /* Make copy of command element *//**
  cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node)); * Parse one line of config, walking up the parse tree attempting to find a match
  *
  * @param vty The vty context in which the command should be executed.
  * @param cmd Pointer where the struct cmd_element* of the match command
  *            will be stored, if any.  May be set to NULL if this info is
  *            not needed.
  * @param use_daemon Boolean to control whether or not we match on CMD_SUCCESS_DAEMON
  *                   or not.
  * @return The status of the command that has been executed or an error code
  *         as to why no command could be executed.
  */
 int
 command_config_read_one_line (struct vty *vty, struct cmd_element **cmd, int use_daemon)
 {
   vector vline;
   int saved_node;
   int ret;
   
  for (index = 0; index < vector_active (vline); index++)  vline = cmd_make_strvec (vty->buf);
    if ((command = vector_slot (vline, index))) 
      { 
        int ret; 
         
        match = cmd_filter_by_string (vector_slot (vline, index), 
                                      cmd_vector, index); 
   
        /* If command meets '.VARARG' then finish matching. */  /* In case of comment line */
        if (match == vararg_match)  if (vline == NULL)
          break;    return CMD_SUCCESS;
         
        ret = is_cmd_ambiguous (command, cmd_vector, index, match); 
        if (ret == 1) 
          { 
            vector_free (cmd_vector); 
            return CMD_ERR_AMBIGUOUS; 
          } 
        if (ret == 2) 
          { 
            vector_free (cmd_vector); 
            return CMD_ERR_NO_MATCH; 
          } 
      } 
   
  /* Check matched count. */  /* Execute configuration command : this is strict match */
  matched_element = NULL;  ret = cmd_execute_command_strict (vline, vty, cmd);
  matched_count = 0; 
  incomplete_count = 0; 
  for (i = 0; i < vector_active (cmd_vector); i++) 
    if (vector_slot (cmd_vector, i) != NULL) 
      { 
        cmd_element = vector_slot (cmd_vector, i); 
   
        if (match == vararg_match || index >= cmd_element->cmdsize)  saved_node = vty->node;
          { 
            matched_element = cmd_element; 
            matched_count++; 
          } 
        else 
          incomplete_count++; 
      } 
   
  /* Finish of using cmd_vector. */  while (!(use_daemon && ret == CMD_SUCCESS_DAEMON) &&
  vector_free (cmd_vector);         ret != CMD_SUCCESS && ret != CMD_WARNING &&
          ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE) {
     vty->node = node_parent(vty->node);
     ret = cmd_execute_command_strict (vline, vty, NULL);
   }
   
  /* To execute command, matched_count must be 1. */  // If climbing the tree did not work then ignore the command and
  if (matched_count == 0)  // stay at the same node
   if (!(use_daemon && ret == CMD_SUCCESS_DAEMON) &&
       ret != CMD_SUCCESS && ret != CMD_WARNING &&
       ret != CMD_ERR_NOTHING_TODO)
     {      {
      if (incomplete_count)      vty->node = saved_node;
        return CMD_ERR_INCOMPLETE; 
      else 
        return CMD_ERR_NO_MATCH; 
     }      }
   
  if (matched_count > 1)  cmd_free_strvec (vline);
    return CMD_ERR_AMBIGUOUS; 
   
  /* Argument treatment */  return ret;
  varflag = 0; 
  argc = 0; 
 
  for (i = 0; i < vector_active (vline); i++) 
    { 
      if (varflag) 
        argv[argc++] = vector_slot (vline, i); 
      else 
        { 
          vector descvec = vector_slot (matched_element->strvec, i); 
 
          if (vector_active (descvec) == 1) 
            { 
              struct desc *desc = vector_slot (descvec, 0); 
 
              if (CMD_VARARG (desc->cmd)) 
                varflag = 1; 
 
              if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd)) 
                argv[argc++] = vector_slot (vline, i); 
            } 
          else 
            argv[argc++] = vector_slot (vline, i); 
        } 
 
      if (argc >= CMD_ARGC_MAX) 
        return CMD_ERR_EXEED_ARGC_MAX; 
    } 
 
  /* For vtysh execution. */ 
  if (cmd) 
    *cmd = matched_element; 
 
  if (matched_element->daemon) 
    return CMD_SUCCESS_DAEMON; 
 
  /* Now execute matched command */ 
  return (*matched_element->func) (matched_element, vty, argc, argv); 
 }  }
   
 /* Configration make from file. */  /* Configration make from file. */
 int  int
config_from_file (struct vty *vty, FILE *fp)config_from_file (struct vty *vty, FILE *fp, unsigned int *line_num)
 {  {
   int ret;    int ret;
  vector vline;  *line_num = 0;
   
   while (fgets (vty->buf, VTY_BUFSIZ, fp))    while (fgets (vty->buf, VTY_BUFSIZ, fp))
     {      {
      vline = cmd_make_strvec (vty->buf);      ++(*line_num);
   
      /* In case of comment line */      ret = command_config_read_one_line (vty, NULL, 0);
      if (vline == NULL) 
        continue; 
      /* Execute configuration command : this is strict match */ 
      ret = cmd_execute_command_strict (vline, vty, NULL); 
   
       /* Try again with setting node to CONFIG_NODE */  
       while (ret != CMD_SUCCESS && ret != CMD_WARNING  
              && ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE)  
         {  
           vty->node = node_parent(vty->node);  
           ret = cmd_execute_command_strict (vline, vty, NULL);  
         }  
   
       cmd_free_strvec (vline);  
   
       if (ret != CMD_SUCCESS && ret != CMD_WARNING        if (ret != CMD_SUCCESS && ret != CMD_WARNING
           && ret != CMD_ERR_NOTHING_TODO)            && ret != CMD_ERR_NOTHING_TODO)
         return ret;          return ret;
Line 2333  DEFUN (config_exit, Line 2956  DEFUN (config_exit,
     case KEYCHAIN_NODE:      case KEYCHAIN_NODE:
     case MASC_NODE:      case MASC_NODE:
     case RMAP_NODE:      case RMAP_NODE:
       case PIM_NODE:
     case VTY_NODE:      case VTY_NODE:
       vty->node = CONFIG_NODE;        vty->node = CONFIG_NODE;
       break;        break;
     case BGP_VPNV4_NODE:  
     case BGP_IPV4_NODE:      case BGP_IPV4_NODE:
     case BGP_IPV4M_NODE:      case BGP_IPV4M_NODE:
       case BGP_VPNV4_NODE:
       case BGP_VPNV6_NODE:
       case BGP_ENCAP_NODE:
       case BGP_ENCAPV6_NODE:
     case BGP_IPV6_NODE:      case BGP_IPV6_NODE:
     case BGP_IPV6M_NODE:      case BGP_IPV6M_NODE:
       vty->node = BGP_NODE;        vty->node = BGP_NODE;
Line 2378  DEFUN (config_end, Line 3005  DEFUN (config_end,
     case RIPNG_NODE:      case RIPNG_NODE:
     case BABEL_NODE:      case BABEL_NODE:
     case BGP_NODE:      case BGP_NODE:
       case BGP_ENCAP_NODE:
       case BGP_ENCAPV6_NODE:
     case BGP_VPNV4_NODE:      case BGP_VPNV4_NODE:
       case BGP_VPNV6_NODE:
     case BGP_IPV4_NODE:      case BGP_IPV4_NODE:
     case BGP_IPV4M_NODE:      case BGP_IPV4M_NODE:
     case BGP_IPV6_NODE:      case BGP_IPV6_NODE:
Line 2390  DEFUN (config_end, Line 3020  DEFUN (config_end,
     case KEYCHAIN_NODE:      case KEYCHAIN_NODE:
     case KEYCHAIN_KEY_NODE:      case KEYCHAIN_KEY_NODE:
     case MASC_NODE:      case MASC_NODE:
       case PIM_NODE:
     case VTY_NODE:      case VTY_NODE:
       vty_config_unlock (vty);        vty_config_unlock (vty);
       vty->node = ENABLE_NODE;        vty->node = ENABLE_NODE;
Line 2410  DEFUN (show_version, Line 3041  DEFUN (show_version,
   vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",    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, "%s%s%s", QUAGGA_COPYRIGHT, GIT_INFO, VTY_NEWLINE);
     vty_out (vty, "configured with:%s    %s%s", VTY_NEWLINE,
              QUAGGA_CONFIG_ARGS, VTY_NEWLINE);
   
   return CMD_SUCCESS;    return CMD_SUCCESS;
 }  }
Line 2504  DEFUN (config_write_file,  Line 3137  DEFUN (config_write_file, 
       
   /* Make vty for configuration file. */    /* Make vty for configuration file. */
   file_vty = vty_new ();    file_vty = vty_new ();
  file_vty->fd = fd;  file_vty->wfd = fd;
   file_vty->type = VTY_FILE;    file_vty->type = VTY_FILE;
   
   /* Config file header print. */    /* Config file header print. */
Line 3432  DEFUN (no_banner_motd, Line 4065  DEFUN (no_banner_motd,
   return CMD_SUCCESS;    return CMD_SUCCESS;
 }  }
   
   DEFUN (show_commandtree,
          show_commandtree_cmd,
          "show commandtree",
          NO_STR
          "Show command tree\n")
   {
     /* TBD */
     vector cmd_vector;
     unsigned int i;
   
     vty_out (vty, "Current node id: %d%s", vty->node, VTY_NEWLINE);
   
     /* vector of all commands installed at this node */
     cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
   
     /* loop over all commands at this node */
     for (i = 0; i < vector_active(cmd_vector); ++i)
       {
         struct cmd_element *cmd_element;
   
         /* A cmd_element (seems to be) is an individual command */
         if ((cmd_element = vector_slot (cmd_vector, i)) == NULL)
           continue;
   
         vty_out (vty, "    %s%s", cmd_element->string, VTY_NEWLINE);
       }
   
     vector_free (cmd_vector);
     return CMD_SUCCESS;
   }
   
 /* Set config filename.  Called from vty.c */  /* Set config filename.  Called from vty.c */
 void  void
 host_config_set (char *filename)  host_config_set (char *filename)
Line 3461  install_default (enum node_type node) Line 4125  install_default (enum node_type node)
 void  void
 cmd_init (int terminal)  cmd_init (int terminal)
 {  {
  command_cr = XSTRDUP(MTYPE_STRVEC, "<cr>");  command_cr = XSTRDUP(MTYPE_CMD_TOKENS, "<cr>");
  desc_cr.cmd = command_cr;  token_cr.type = TOKEN_TERMINAL;
  desc_cr.str = XSTRDUP(MTYPE_STRVEC, "");  token_cr.terminal = TERMINAL_LITERAL;
   token_cr.cmd = command_cr;
   token_cr.desc = XSTRDUP(MTYPE_CMD_TOKENS, "");
   
   /* Allocate initial top vector of commands. */    /* Allocate initial top vector of commands. */
   cmdvec = vector_init (VECTOR_MIN_SIZE);    cmdvec = vector_init (VECTOR_MIN_SIZE);
Line 3498  cmd_init (int terminal) Line 4164  cmd_init (int terminal)
       install_element (VIEW_NODE, &config_terminal_length_cmd);        install_element (VIEW_NODE, &config_terminal_length_cmd);
       install_element (VIEW_NODE, &config_terminal_no_length_cmd);        install_element (VIEW_NODE, &config_terminal_no_length_cmd);
       install_element (VIEW_NODE, &show_logging_cmd);        install_element (VIEW_NODE, &show_logging_cmd);
         install_element (VIEW_NODE, &show_commandtree_cmd);
       install_element (VIEW_NODE, &echo_cmd);        install_element (VIEW_NODE, &echo_cmd);
   
       install_element (RESTRICTED_NODE, &config_list_cmd);        install_element (RESTRICTED_NODE, &config_list_cmd);
Line 3507  cmd_init (int terminal) Line 4174  cmd_init (int terminal)
       install_element (RESTRICTED_NODE, &config_enable_cmd);        install_element (RESTRICTED_NODE, &config_enable_cmd);
       install_element (RESTRICTED_NODE, &config_terminal_length_cmd);        install_element (RESTRICTED_NODE, &config_terminal_length_cmd);
       install_element (RESTRICTED_NODE, &config_terminal_no_length_cmd);        install_element (RESTRICTED_NODE, &config_terminal_no_length_cmd);
         install_element (RESTRICTED_NODE, &show_commandtree_cmd);
       install_element (RESTRICTED_NODE, &echo_cmd);        install_element (RESTRICTED_NODE, &echo_cmd);
     }      }
   
Line 3519  cmd_init (int terminal) Line 4187  cmd_init (int terminal)
     }      }
   install_element (ENABLE_NODE, &show_startup_config_cmd);    install_element (ENABLE_NODE, &show_startup_config_cmd);
   install_element (ENABLE_NODE, &show_version_cmd);    install_element (ENABLE_NODE, &show_version_cmd);
     install_element (ENABLE_NODE, &show_commandtree_cmd);
   
   if (terminal)    if (terminal)
     {      {
Line 3581  cmd_init (int terminal) Line 4250  cmd_init (int terminal)
       install_element (VIEW_NODE, &show_work_queues_cmd);        install_element (VIEW_NODE, &show_work_queues_cmd);
       install_element (ENABLE_NODE, &show_work_queues_cmd);        install_element (ENABLE_NODE, &show_work_queues_cmd);
     }      }
  srand(time(NULL));  install_element (CONFIG_NODE, &show_commandtree_cmd);
   srandom(time(NULL));
 }  }
   
   static void
   cmd_terminate_token(struct cmd_token *token)
   {
     unsigned int i, j;
     vector keyword_vect;
   
     if (token->multiple)
       {
         for (i = 0; i < vector_active(token->multiple); i++)
           cmd_terminate_token(vector_slot(token->multiple, i));
         vector_free(token->multiple);
         token->multiple = NULL;
       }
   
     if (token->keyword)
       {
         for (i = 0; i < vector_active(token->keyword); i++)
           {
             keyword_vect = vector_slot(token->keyword, i);
             for (j = 0; j < vector_active(keyword_vect); j++)
               cmd_terminate_token(vector_slot(keyword_vect, j));
             vector_free(keyword_vect);
           }
         vector_free(token->keyword);
         token->keyword = NULL;
       }
   
     XFREE(MTYPE_CMD_TOKENS, token->cmd);
     XFREE(MTYPE_CMD_TOKENS, token->desc);
   
     XFREE(MTYPE_CMD_TOKENS, token);
   }
   
   static void
   cmd_terminate_element(struct cmd_element *cmd)
   {
     unsigned int i;
   
     if (cmd->tokens == NULL)
       return;
   
     for (i = 0; i < vector_active(cmd->tokens); i++)
       cmd_terminate_token(vector_slot(cmd->tokens, i));
   
     vector_free(cmd->tokens);
     cmd->tokens = NULL;
   }
   
 void  void
 cmd_terminate ()  cmd_terminate ()
 {  {
  unsigned int i, j, k, l;  unsigned int i, j;
   struct cmd_node *cmd_node;    struct cmd_node *cmd_node;
   struct cmd_element *cmd_element;    struct cmd_element *cmd_element;
  struct desc *desc;  vector cmd_node_v;
  vector cmd_node_v, cmd_element_v, desc_v; 
   
   if (cmdvec)    if (cmdvec)
     {      {
Line 3601  cmd_terminate () Line 4318  cmd_terminate ()
             cmd_node_v = cmd_node->cmd_vector;              cmd_node_v = cmd_node->cmd_vector;
   
             for (j = 0; j < vector_active (cmd_node_v); j++)              for (j = 0; j < vector_active (cmd_node_v); j++)
              if ((cmd_element = vector_slot (cmd_node_v, j)) != NULL &&              if ((cmd_element = vector_slot (cmd_node_v, j)) != NULL)
                  cmd_element->strvec != NULL)                cmd_terminate_element(cmd_element);
                { 
                  cmd_element_v = cmd_element->strvec; 
   
                   for (k = 0; k < vector_active (cmd_element_v); k++)  
                     if ((desc_v = vector_slot (cmd_element_v, k)) != NULL)  
                       {  
                         for (l = 0; l < vector_active (desc_v); l++)  
                           if ((desc = vector_slot (desc_v, l)) != NULL)  
                             {  
                               if (desc->cmd)  
                                 XFREE (MTYPE_STRVEC, desc->cmd);  
                               if (desc->str)  
                                 XFREE (MTYPE_STRVEC, desc->str);  
   
                               XFREE (MTYPE_DESC, desc);  
                             }  
                         vector_free (desc_v);  
                       }  
   
                   cmd_element->strvec = NULL;  
                   vector_free (cmd_element_v);  
                 }  
   
             vector_free (cmd_node_v);              vector_free (cmd_node_v);
           }            }
   
Line 3634  cmd_terminate () Line 4329  cmd_terminate ()
     }      }
   
   if (command_cr)    if (command_cr)
    XFREE(MTYPE_STRVEC, command_cr);    XFREE(MTYPE_CMD_TOKENS, command_cr);
  if (desc_cr.str)  if (token_cr.desc)
    XFREE(MTYPE_STRVEC, desc_cr.str);    XFREE(MTYPE_CMD_TOKENS, token_cr.desc);
   if (host.name)    if (host.name)
     XFREE (MTYPE_HOST, host.name);      XFREE (MTYPE_HOST, host.name);
   if (host.password)    if (host.password)

Removed from v.1.1.1.3  
changed lines
  Added in v.1.1.1.4


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>