diff options
author | Chris Hall <chris.hall@highwayman.com> | 2010-12-21 11:12:30 +0000 |
---|---|---|
committer | Chris Hall <chris.hall@highwayman.com> | 2010-12-21 11:12:30 +0000 |
commit | 121f2f888e02a28e7896f84dde019cb320f0b11d (patch) | |
tree | 99c3913759b80894b1cb83a508036223b9c98f5a /lib/command.c | |
parent | d475a0f198f880595eb27e44008e5de3aad25d73 (diff) | |
download | quagga-121f2f888e02a28e7896f84dde019cb320f0b11d.tar.bz2 quagga-121f2f888e02a28e7896f84dde019cb320f0b11d.tar.xz |
Creation of pipework branch
Diffstat (limited to 'lib/command.c')
-rw-r--r-- | lib/command.c | 1767 |
1 files changed, 605 insertions, 1162 deletions
diff --git a/lib/command.c b/lib/command.c index a78ac05c..3c4f056a 100644 --- a/lib/command.c +++ b/lib/command.c @@ -36,6 +36,7 @@ Boston, MA 02111-1307, USA. */ #include "command_execute.h" #include "workqueue.h" #include "command_queue.h" +#include "command_parse.h" /* Command vector which includes some level of command lists. Normally each daemon maintains each own cmdvec. */ @@ -47,10 +48,13 @@ char *command_cr = NULL; /* Host information structure. */ struct host host; +/* Store of qstrings, used for parsing. */ +token_vector_t spare_token_strings ; + /* Standard command node structures. */ static struct cmd_node auth_node = { - AUTH_NODE, + .node = AUTH_NODE, "Password: ", }; @@ -104,16 +108,16 @@ static const struct facility_map { size_t match; } syslog_facilities[] = { - { LOG_KERN, "kern", 1 }, - { LOG_USER, "user", 2 }, - { LOG_MAIL, "mail", 1 }, + { LOG_KERN, "kern", 1 }, + { LOG_USER, "user", 2 }, + { LOG_MAIL, "mail", 1 }, { LOG_DAEMON, "daemon", 1 }, - { LOG_AUTH, "auth", 1 }, + { LOG_AUTH, "auth", 1 }, { LOG_SYSLOG, "syslog", 1 }, - { LOG_LPR, "lpr", 2 }, - { LOG_NEWS, "news", 1 }, - { LOG_UUCP, "uucp", 2 }, - { LOG_CRON, "cron", 1 }, + { LOG_LPR, "lpr", 2 }, + { LOG_NEWS, "news", 1 }, + { LOG_UUCP, "uucp", 2 }, + { LOG_CRON, "cron", 1 }, #ifdef LOG_FTP { LOG_FTP, "ftp", 1 }, #endif @@ -128,6 +132,20 @@ static const struct facility_map { { 0, NULL, 0 }, }; +static struct cmd_element cmd_pipe = +{ + .string = "< or <|", /* Dummy */ + .func = cmd_pipe_func, + .doc = "Pipe input to command processor", + .daemon = 0, + .strvec = NULL, + .cmdsize = 0, + .config = NULL, + .subconfig = NULL, + .attr = CMD_ATTR_SIMPLE, +} ; + + static const char * facility_name(int facility) { @@ -284,144 +302,16 @@ sort_node () } ; /*------------------------------------------------------------------------------ - * Take string and break it into tokens. - * - * Discards leading and trailing white-space. - * - * Treats lines that start with '!' or '#' (after any leading white-space) - * as empty -- these are comment lines. - * - * Tokens are non-whitespace separated by one or more white-space. - * - * White-space is anything that isspace() thinks is a space. (Which in the - * 'C' locale is ' ', '\t', '\r, '\n', '\f' and '\v'.) + * Take string and break it into tokens -- see cmd_make_tokens(). * * Returns: NULL => empty line (after white-space trimming) or comment line. - * otherwise: is vector containing one or more tokens. - * - * .... - * - * - * Note: all the tokens in the vector have at least one character, and no - * entries are NULL. - * - * NB: it is the caller's responsibility to release the vector and its contents, - * see cmd_free_strvec(). - */ -static vector -cmd_make_vline(vector vline, qstring qs, const char *string) -{ - char *token, *tp ; - const char *cp, *sp, *ep, *op ; - - /* Reset any existing vline, and empty the qstring if given. */ - if (vline != NULL) - vector_set_length(vline, 0) ; - - qs_clear(qs) ; - - /* Strip leading and trailing white-space and deal with empty or effectively - * empty lines -- comment lines are treated as effectively empty. - */ - cp = string; - - if (string == NULL) - return NULL; - - while (isspace((int) *cp)) - cp++; - - ep = cp + strlen(cp) ; - - while ((ep > cp) && (isspace((int)*(ep - 1)))) - --ep ; - - if ((cp == ep) || (*cp == '!') || (*cp == '#')) - return NULL; - - /* Prepare return vector -- expect some reasonable number of tokens. */ - if (vline == NULL) - vline = vector_init(10) ; - - /* If writing the words to a qstring, copy the body of the original (less - * any leading/trailing whitespace) to the qstring and '\0' terminate. - */ - if (qs != NULL) - { - qs_set_n(qs, cp, ep - cp) ; - tp = (char*)qs->body ; /* start at the beginning */ - } - else - tp = NULL ; /* not used, but not undefined */ - - op = cp ; /* original start position */ - - /* Now have string cp..ep with no leading/trailing whitespace. - * - * If using a qstring, a copy of that exists at tp, complete with terminating - * '\0'. Writes '\0' terminators after each word found -- overwriting first - * separating white-space or the '\0' at the end. - * - * If not using a qstring, construct a new MTYPE_STRVEC for each word. - */ - while (cp < ep) - { - while (isspace((int) *cp)) - cp++ ; /* skip white-space */ - - sp = cp ; - while ((cp < ep) && !isspace((int) *cp)) - cp++ ; /* eat token characters */ - - if (qs == NULL) - { - /* creating array of MTYPE_STRVEC */ - size_t len ; - - len = cp - sp ; - token = XMALLOC (MTYPE_STRVEC, len + 1); - memcpy (token, sp, len); - *(token + len) = '\0'; - } - else - { - /* using qstring */ - token = tp + (sp - op) ; /* token in qstring */ - *(tp + (cp - op)) = '\0' ; /* terminate */ - } ; - - vector_push_item(vline, token); - } ; - - return vline ; -} - -/*------------------------------------------------------------------------------ - * Take string and break it into tokens. - * - * Discards leading and trailing white-space. - * - * Treats lines that start with '!' or '#' (after any leading white-space) - * as empty -- these are comment lines. - * - * Tokens are non-whitespace separated by one or more white-space. - * - * White-space is anything that isspace() thinks is a space. (Which in the - * 'C' locale is ' ', '\t', '\r, '\n', '\f' and '\v'.) - * - * Returns: NULL => empty line (after white-space trimming) or comment line. - * otherwise: is vector containing one or more tokens. - * - * Note: all the tokens in the vector have at least one character, and no - * entries are NULL. - * - * NB: it is the caller's responsibility to release the vector and its contents, - * see cmd_free_strvec(). + * otherwise: is vector containing one or more tokens in qstrings. */ extern vector cmd_make_strvec (const char *string) { - return cmd_make_vline(NULL, NULL, string) ; + return cmd_tokenise(NULL, string) ; +#error sort this one out } ; /*------------------------------------------------------------------------------ @@ -451,7 +341,7 @@ cmd_free_strvec (vector strvec) char *cp; /* Note that vector_ream_free() returns NULL if strvec == NULL */ - while((cp = vector_ream_free(strvec)) != NULL) + while((cp = vector_ream(strvec, free_it)) != NULL) XFREE (MTYPE_STRVEC, cp); } ; @@ -554,7 +444,7 @@ cmd_make_descvec (const char *string, const char *descstr) sp = cp; - while (! (isspace ((int) *cp) || *cp == '\r' || *cp == '\n' || *cp == ')' || *cp == '|') && *cp != '\0') + while (! (isspace ((int) *cp) || *cp == ')' || *cp == '|') && *cp != '\0') cp++; len = cp - sp; @@ -846,522 +736,6 @@ cmd_filter_by_symbol (char *command, char *symbol) #endif /*============================================================================== - * Match functions. - * - * Is the given string a, possibly incomplete, value of the required kind ? - */ - -/* Completion match types. */ -enum match_type -{ - no_match, /* nope */ - extend_match, - - ipv4_prefix_match, - ipv4_match, - ipv6_prefix_match, - ipv6_match, - range_match, - vararg_match, - - partly_match, /* OK as far as it went */ - exact_match /* Syntactically complete */ -}; - -/*------------------------------------------------------------------------------ - * Is this an IPv4 Address: - * - * 999.999.999.999 -- where no part may be > 255 - * - * TODO: cmd_ipv4_match() seems to accept leading '.' ? - * TODO: cmd_ipv4_match() seems to accept leading zeros ? - * - * Returns: no_match -- improperly formed - * partly_match -- accepts empty string - * exact_match -- syntactically complete - */ -static enum match_type -cmd_ipv4_match (const char *str) -{ - const char *sp; - int dots = 0, nums = 0; - char buf[4]; - - if (str == NULL) - return partly_match; - - for (;;) - { - memset (buf, 0, sizeof (buf)); - sp = str; - while (*str != '\0') - { - if (*str == '.') - { - if (dots >= 3) - return no_match; - - if (*(str + 1) == '.') - return no_match; - - if (*(str + 1) == '\0') - return partly_match; - - dots++; - break; - } - if (!isdigit ((int) *str)) - return no_match; - - str++; - } - - if (str - sp > 3) - return no_match; - - strncpy (buf, sp, str - sp); - if (atoi (buf) > 255) - return no_match; - - nums++; - - if (*str == '\0') - break; - - str++; - } - - if (nums < 4) - return partly_match; - - return exact_match; -} - -/*------------------------------------------------------------------------------ - * Is this an IPv4 Prefix: - * - * 999.999.999.999/99 -- where no part may be > 255, - * and prefix length may not be > 32 - * - * TODO: cmd_ipv4_prefix_match() seems to accept leading '.' ? - * TODO: cmd_ipv4_prefix_match() seems to accept leading zeros ? - * - * Returns: no_match -- improperly formed - * partly_match -- accepts empty string - * exact_match -- syntactically complete - * - * NB: partly_match is returned for anything valid before the '/', but which - * has no '/' or no number after the '/'. - */ -static enum match_type -cmd_ipv4_prefix_match (const char *str) -{ - const char *sp; - int dots = 0; - char buf[4]; - - if (str == NULL) - return partly_match; - - for (;;) - { - memset (buf, 0, sizeof (buf)); - sp = str; - while (*str != '\0' && *str != '/') - { - if (*str == '.') - { - if (dots == 3) - return no_match; - - if (*(str + 1) == '.' || *(str + 1) == '/') - return no_match; - - if (*(str + 1) == '\0') - return partly_match; - - dots++; - break; - } - - if (!isdigit ((int) *str)) - return no_match; - - str++; - } - - if (str - sp > 3) - return no_match; - - strncpy (buf, sp, str - sp); - if (atoi (buf) > 255) - return no_match; - - if (dots == 3) - { - if (*str == '/') - { - if (*(str + 1) == '\0') - return partly_match; - - str++; - break; - } - else if (*str == '\0') - return partly_match; - } - - if (*str == '\0') - return partly_match; - - str++; - } - - sp = str; - while (*str != '\0') - { - if (!isdigit ((int) *str)) - return no_match; - - str++; - } - - if (atoi (sp) > 32) - return no_match; - - return exact_match; -} - -/*------------------------------------------------------------------------------ - * Is this an IPv6 Address: - * - * TODO: cmd_ipv6_match() only returns "partly_match" for empty string ? - * - * Returns: no_match -- improperly formed - * partly_match -- accepts empty string - * exact_match -- syntactically complete - */ - -#define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%" -#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/" -#define STATE_START 1 -#define STATE_COLON 2 -#define STATE_DOUBLE 3 -#define STATE_ADDR 4 -#define STATE_DOT 5 -#define STATE_SLASH 6 -#define STATE_MASK 7 - -#ifdef HAVE_IPV6 - -static enum match_type -cmd_ipv6_match (const char *str) -{ - int state = STATE_START; - int colons = 0, nums = 0, double_colon = 0; - const char *sp = NULL; - struct sockaddr_in6 sin6_dummy; - int ret; - - if (str == NULL) - return partly_match; - - if (strspn (str, IPV6_ADDR_STR) != strlen (str)) - return no_match; - - /* use inet_pton that has a better support, - * for example inet_pton can support the automatic addresses: - * ::1.2.3.4 - */ - ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr); - - if (ret == 1) - return exact_match; - - while (*str != '\0') - { - switch (state) - { - case STATE_START: - if (*str == ':') - { - if (*(str + 1) != ':' && *(str + 1) != '\0') - return no_match; - colons--; - state = STATE_COLON; - } - else - { - sp = str; - state = STATE_ADDR; - } - - continue; - case STATE_COLON: - colons++; - if (*(str + 1) == ':') - state = STATE_DOUBLE; - else - { - sp = str + 1; - state = STATE_ADDR; - } - break; - case STATE_DOUBLE: - if (double_colon) - return no_match; - - if (*(str + 1) == ':') - return no_match; - else - { - if (*(str + 1) != '\0') - colons++; - sp = str + 1; - state = STATE_ADDR; - } - - double_colon++; - nums++; - break; - case STATE_ADDR: - if (*(str + 1) == ':' || *(str + 1) == '\0') - { - if (str - sp > 3) - return no_match; - - nums++; - state = STATE_COLON; - } - if (*(str + 1) == '.') - state = STATE_DOT; - break; - case STATE_DOT: - state = STATE_ADDR; - break; - default: - break; - } - - if (nums > 8) - return no_match; - - if (colons > 7) - return no_match; - - str++; - } - -#if 0 - if (nums < 11) - return partly_match; -#endif /* 0 */ - - return exact_match; -} - -/*------------------------------------------------------------------------------ - * Is this an IPv6 Prefix: - * - * TODO: cmd_ipv6_prefix_match() hardly returns "partly_match" ? - * TODO: cmd_ipv6_prefix_match() possibly accepts invalid address before '/' ? - * - * Returns: no_match -- improperly formed - * partly_match -- accepts empty string - * exact_match -- syntactically complete - * - * NB: partly_match is returned for anything valid before the '/', but which - * has no '/' or no number after the '/'. - */ -static enum match_type -cmd_ipv6_prefix_match (const char *str) -{ - int state = STATE_START; - int colons = 0, nums = 0, double_colon = 0; - int mask; - const char *sp = NULL; - char *endptr = NULL; - - if (str == NULL) - return partly_match; - - if (strspn (str, IPV6_PREFIX_STR) != strlen (str)) - return no_match; - - while (*str != '\0' && state != STATE_MASK) - { - switch (state) - { - case STATE_START: - if (*str == ':') - { - if (*(str + 1) != ':' && *(str + 1) != '\0') - return no_match; - colons--; - state = STATE_COLON; - } - else - { - sp = str; - state = STATE_ADDR; - } - - continue; - case STATE_COLON: - colons++; - if (*(str + 1) == '/') - return no_match; - else if (*(str + 1) == ':') - state = STATE_DOUBLE; - else - { - sp = str + 1; - state = STATE_ADDR; - } - break; - case STATE_DOUBLE: - if (double_colon) - return no_match; - - if (*(str + 1) == ':') - return no_match; - else - { - if (*(str + 1) != '\0' && *(str + 1) != '/') - colons++; - sp = str + 1; - - if (*(str + 1) == '/') - state = STATE_SLASH; - else - state = STATE_ADDR; - } - - double_colon++; - nums += 1; - break; - case STATE_ADDR: - if (*(str + 1) == ':' || *(str + 1) == '.' - || *(str + 1) == '\0' || *(str + 1) == '/') - { - if (str - sp > 3) - return no_match; - - for (; sp <= str; sp++) - if (*sp == '/') - return no_match; - - nums++; - - if (*(str + 1) == ':') - state = STATE_COLON; - else if (*(str + 1) == '.') - state = STATE_DOT; - else if (*(str + 1) == '/') - state = STATE_SLASH; - } - break; - case STATE_DOT: - state = STATE_ADDR; - break; - case STATE_SLASH: - if (*(str + 1) == '\0') - return partly_match; - - state = STATE_MASK; - break; - default: - break; - } - - if (nums > 11) - return no_match; - - if (colons > 7) - return no_match; - - str++; - } - - if (state < STATE_MASK) - return partly_match; - - mask = strtol (str, &endptr, 10); - if (*endptr != '\0') - return no_match; - - if (mask < 0 || mask > 128) - return no_match; - -/* I don't know why mask < 13 makes command match partly. - Forgive me to make this comments. I Want to set static default route - because of lack of function to originate default in ospf6d; sorry - yasu - if (mask < 13) - return partly_match; -*/ - - return exact_match; -} - -#endif /* HAVE_IPV6 */ - -/*------------------------------------------------------------------------------ - * Is this a decimal number in the allowed range: - * - * Returns: 1 => OK -- *including* empty string - * 0 => not a valid number, or not in required range - * (or invalid range !!) - */ - -#define DECIMAL_STRLEN_MAX 10 - -static int -cmd_range_match (const char *range, const char *str) -{ - char *p; - char buf[DECIMAL_STRLEN_MAX + 1]; - char *endptr = NULL; - unsigned long min, max, val; - - if (str == NULL) - return 1; - - val = strtoul (str, &endptr, 10); - if (*endptr != '\0') - return 0; - - range++; - p = strchr (range, '-'); - if (p == NULL) - return 0; - if (p - range > DECIMAL_STRLEN_MAX) - return 0; - strncpy (buf, range, p - range); - buf[p - range] = '\0'; - min = strtoul (buf, &endptr, 10); - if (*endptr != '\0') - return 0; - - range = p + 1; - p = strchr (range, '>'); - if (p == NULL) - return 0; - if (p - range > DECIMAL_STRLEN_MAX) - return 0; - strncpy (buf, range, p - range); - buf[p - range] = '\0'; - max = strtoul (buf, &endptr, 10); - if (*endptr != '\0') - return 0; - - if (val < min || val > max) - return 0; - - return 1; -} - -/*============================================================================== * Command "filtering". * * The command parsing process starts with a (shallow) copy of the cmd_vector @@ -1379,11 +753,13 @@ cmd_range_match (const char *range, const char *str) */ /*------------------------------------------------------------------------------ - * Make completion match and return match type flag. + * Make strict or completion match and return match type flag. * * Takes: command -- address of candidate token * cmd_v -- vector of commands that is being reduced/filtered * index -- index of token (position in line -- 0 == first) + * min_match -- any_match => allow partial matching + * exact_match => must match completely * * Returns: any of the enum match_type values: * @@ -1405,15 +781,18 @@ cmd_range_match (const char *range, const char *str) * furthest down this list. */ static enum match_type -cmd_filter_by_completion (char *command, vector cmd_v, unsigned int index) +cmd_filter(const char *command, vector cmd_v, unsigned int index, + match_type_t min_match) { unsigned int i; unsigned int k; - enum match_type match_type; + enum match_type best_match; + size_t c_len ; - match_type = no_match; + best_match = no_match ; + c_len = strlen(command) ; - /* If command and cmd_element string does not match, remove from vector */ + /* If command and cmd_element string do match, keep in vector */ k = 0 ; for (i = 0; i < vector_length (cmd_v); i++) { @@ -1422,11 +801,11 @@ cmd_filter_by_completion (char *command, vector cmd_v, unsigned int index) vector descvec; struct desc *desc; unsigned int j; - int matched ; + bool matched ; cmd_element = vector_get_item(cmd_v, i) ; - /* Skip past cmd_v entries that have already been set NULL */ + /* Skip past NULL cmd_v entries (just in case) */ if (cmd_element == NULL) continue ; @@ -1447,205 +826,78 @@ cmd_filter_by_completion (char *command, vector cmd_v, unsigned int index) if (CMD_VARARG (str)) { - if (match_type < vararg_match) - match_type = vararg_match; - matched++; + if (best_match < vararg_match) + best_match = vararg_match; + matched = true ; } else if (CMD_RANGE (str)) { if (cmd_range_match (str, command)) { - if (match_type < range_match) - match_type = range_match; - - matched++; + if (best_match < range_match) + best_match = range_match; + matched = true ; } } #ifdef HAVE_IPV6 else if (CMD_IPV6 (str)) { - if (cmd_ipv6_match (command)) + if (cmd_ipv6_match (command) >= min_match) { - if (match_type < ipv6_match) - match_type = ipv6_match; - - matched++; + if (best_match < ipv6_match) + best_match = ipv6_match; + matched = true ; } } else if (CMD_IPV6_PREFIX (str)) { - if (cmd_ipv6_prefix_match (command)) + if (cmd_ipv6_prefix_match (command) >= min_match) { - if (match_type < ipv6_prefix_match) - match_type = ipv6_prefix_match; - - matched++; + if (best_match < ipv6_prefix_match) + best_match = ipv6_prefix_match; + matched = true ; } } #endif /* HAVE_IPV6 */ else if (CMD_IPV4 (str)) { - if (cmd_ipv4_match (command)) + if (cmd_ipv4_match (command) >= min_match) { - if (match_type < ipv4_match) - match_type = ipv4_match; - - matched++; + if (best_match < ipv4_match) + best_match = ipv4_match; + matched = true ; } } else if (CMD_IPV4_PREFIX (str)) { - if (cmd_ipv4_prefix_match (command)) + if (cmd_ipv4_prefix_match (command) >= min_match) { - if (match_type < ipv4_prefix_match) - match_type = ipv4_prefix_match; - matched++; + if (best_match < ipv4_prefix_match) + best_match = ipv4_prefix_match; + matched = true ; } } else if (CMD_OPTION (str) || CMD_VARIABLE (str)) - /* Check is this point's argument optional ? */ { - if (match_type < extend_match) - match_type = extend_match; - matched++; + if (best_match < extend_match) + best_match = extend_match; + matched = true ; } - else if (strncmp (command, str, strlen (command)) == 0) + else { if (strcmp (command, str) == 0) - match_type = exact_match; - else { - if (match_type < partly_match) - match_type = partly_match; + best_match = exact_match ; + matched = true ; } - matched++; - } ; - } ; - - /* Keep cmd_v entry that has a match at this position */ - if (matched) - vector_set_item(cmd_v, k++, cmd_element) ; - } ; - - vector_set_length(cmd_v, k) ; /* discard what did not keep */ - - return match_type; -} ; - -/*------------------------------------------------------------------------------ - * Filter vector by command character with index. - * - * This appears to be identical to cmd_filter_by_completion(), except that - * when matching keywords, requires an exact match. - * - * TODO: see if can merge cmd_filter_by_completion() & cmd_filter_by_string() - */ -static enum match_type -cmd_filter_by_string (char *command, vector cmd_v, unsigned int index) -{ - unsigned int i ; - unsigned int k ; - enum match_type match_type; - - match_type = no_match; - - /* If command and cmd_element string do match, keep in vector */ - k = 0 ; - for (i = 0; i < vector_length(cmd_v); i++) - { - unsigned int j; - int matched ; - const char *str; - struct cmd_element *cmd_element; - vector descvec; - struct desc *desc; - - cmd_element = vector_get_item(cmd_v, i) ; - - /* Skip past NULL cmd_v entries (just in case) */ - if (cmd_element == NULL) - continue ; - - /* Discard cmd_v entry that has no token at the current position */ - descvec = vector_get_item (cmd_element->strvec, index) ; - if (descvec == NULL) - continue ; - - /* See if have a match against any of the current possibilities */ - matched = 0 ; - for (j = 0; j < vector_length(descvec); j++) - { - desc = vector_get_item (descvec, j) ; - if (desc == NULL) - continue ; - - str = desc->cmd; - - if (CMD_VARARG (str)) - { - if (match_type < vararg_match) - match_type = vararg_match; - matched++; - } - else if (CMD_RANGE (str)) - { - if (cmd_range_match (str, command)) - { - if (match_type < range_match) - match_type = range_match; - matched++; - } - } -#ifdef HAVE_IPV6 - else if (CMD_IPV6 (str)) - { - if (cmd_ipv6_match (command) == exact_match) - { - if (match_type < ipv6_match) - match_type = ipv6_match; - matched++; - } - } - else if (CMD_IPV6_PREFIX (str)) - { - if (cmd_ipv6_prefix_match (command) == exact_match) - { - if (match_type < ipv6_prefix_match) - match_type = ipv6_prefix_match; - matched++; - } - } -#endif /* HAVE_IPV6 */ - else if (CMD_IPV4 (str)) - { - if (cmd_ipv4_match (command) == exact_match) - { - if (match_type < ipv4_match) - match_type = ipv4_match; - matched++; - } - } - else if (CMD_IPV4_PREFIX (str)) - { - if (cmd_ipv4_prefix_match (command) == exact_match) + else if (min_match <= partly_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 (strncmp (command, str, c_len) == 0) + { + if (best_match < partly_match) + best_match = partly_match ; + matched = true ; + } ; } ; } ; } ; @@ -1657,8 +909,8 @@ cmd_filter_by_string (char *command, vector cmd_v, unsigned int index) vector_set_length(cmd_v, k) ; /* discard what did not keep */ - return match_type; -} + return best_match; +} ; /*------------------------------------------------------------------------------ * Check for ambiguous match @@ -1699,7 +951,8 @@ cmd_filter_by_string (char *command, vector cmd_v, unsigned int index) * returns 1 in preference. */ static int -is_cmd_ambiguous (char *command, vector cmd_v, int index, enum match_type type) +is_cmd_ambiguous (const char *command, vector cmd_v, int index, + enum match_type type) { unsigned int i; unsigned int k; @@ -1715,7 +968,7 @@ is_cmd_ambiguous (char *command, vector cmd_v, int index, enum match_type type) const char *str_matched ; vector descvec; struct desc *desc; - int matched ; + bool matched ; enum match_type mt ; cmd_element = vector_get_item (cmd_v, i) ; @@ -1754,7 +1007,7 @@ is_cmd_ambiguous (char *command, vector cmd_v, int index, enum match_type type) case exact_match: if (!(CMD_OPTION (str) || CMD_VARIABLE (str)) && strcmp (command, str) == 0) - matched++; + matched = true ; break; case partly_match: @@ -1765,7 +1018,7 @@ is_cmd_ambiguous (char *command, vector cmd_v, int index, enum match_type type) ret = 1; /* There is ambiguous match. */ else str_matched = str; - matched++; + matched = true ; } break; @@ -1776,47 +1029,43 @@ is_cmd_ambiguous (char *command, vector cmd_v, int index, enum match_type type) ret = 1; else str_matched = str; - matched++; + matched = true ; } break; #ifdef HAVE_IPV6 case ipv6_match: if (CMD_IPV6 (str)) - matched++; + matched = true ; break; case ipv6_prefix_match: if ((mt = cmd_ipv6_prefix_match (command)) != no_match) { - if (mt == partly_match) - if (ret != 1) - ret = 2; /* There is incomplete match. */ - - matched++; + if ((mt == partly_match) && (ret != 1)) + ret = 2; /* There is incomplete match. */ + matched = true ; } break; #endif /* HAVE_IPV6 */ case ipv4_match: if (CMD_IPV4 (str)) - matched++; + matched = true ; break; case ipv4_prefix_match: if ((mt = cmd_ipv4_prefix_match (command)) != no_match) { - if (mt == partly_match) - if (ret != 1) - ret = 2; /* There is incomplete match. */ - - matched++; + if ((mt == partly_match) && (ret != 1)) + ret = 2; /* There is incomplete match. */ + matched = true ; } break; case extend_match: if (CMD_OPTION (str) || CMD_VARIABLE (str)) - matched++; + matched = true ; break; case no_match: @@ -1956,195 +1205,256 @@ desc_unique_string (vector v, const char *str) return 0; } +/*------------------------------------------------------------------------------ + * Special parsing for leading 'do', if current mode allows it. + * + * If finds a valid "do", sets current node and do_shortcut flag, and discards + * the "do" token. + * + * Returns: true <=> dealt with the "do" + * false => no do, or no do allowed. + */ static bool -cmd_try_do_shortcut (enum node_type node, char* first_word) { - return (node >= MIN_DO_SHORTCUT_NODE) - && (first_word != NULL) - && (strcmp( "do", first_word) == 0) ? 1 : 0 ; -} +cmd_try_do_shortcut(cmd_parsed parsed) +{ + const char* ts ; -/* '?' describe command support. */ -static vector -cmd_describe_command_real (vector vline, int node, int *status) + if (parsed->cnode < MIN_DO_SHORTCUT_NODE) + return false ; + + ts = cmd_token_string(cmd_token_get(&parsed->tokens, 0)) ; + if (strcmp("do", ts) != 0) + return false ; + + parsed->cnode = ENABLE_NODE ; + parsed->do_shortcut = true ; + cmd_token_discard(cmd_token_shift(&parsed->tokens)) ; + + return true ; +} ; + +/*============================================================================== + * '?' describe command support. + */ + +/*------------------------------------------------------------------------------ + * Get description of current (partial) command + * + * Returns: NULL => no description available + * + * status set to CMD_ERR_NO_MATCH or CMD_ERR_AMBIGUOUS + * + * or: address of vector of "struct desc" values available. + * + * NB: when a vector is returned it is the caller's responsibility to + * vector_free() it. (The contents are all effectively const, so do not + * themselves need to be freed.) + */ +extern vector +cmd_describe_command (const char* line, node_type_t node, + cmd_return_code_t* status) { - unsigned int i; - vector cmd_vector; -#define INIT_MATCHVEC_SIZE 10 - vector matchvec; - struct cmd_element *cmd_element; - unsigned int index; - int ret; - enum match_type match; - char *command; + vector ret ; + struct cmd_parsed parsed_s ; + cmd_parsed parsed ; + cmd_token_type_t tok_total ; - /* Set index. */ - if (vector_length (vline) == 0) - { - *status = CMD_ERR_NO_MATCH; - return NULL; - } - else - index = vector_length (vline) - 1; + /* Set up a parser object and tokenise the command line */ + parsed = cmd_parse_init_new(&parsed_s) ; + tok_total = cmd_tokenise(parsed, line, node) ; - /* Make copy vector of current node's command vector. */ - cmd_vector = vector_copy (cmd_node_vector (cmdvec, node)); - /* Prepare match vector */ - matchvec = vector_init (INIT_MATCHVEC_SIZE); - /* Filter commands. */ - /* Only words precedes current word will be checked in this loop. */ - for (i = 0; i < index; i++) - if ((command = vector_get_item (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_length (cmd_vector); j++) - if ((cmd_element = vector_get_item (cmd_vector, j)) != NULL - && (vector_length (cmd_element->strvec))) - { - descvec = vector_get_item (cmd_element->strvec, - vector_length (cmd_element->strvec) - 1); - for (k = 0; k < vector_length (descvec); k++) - { - struct desc *desc = vector_get_item (descvec, k); - vector_set (matchvec, desc); - } - } - - vector_set (matchvec, &desc_cr); - vector_free (cmd_vector); - - return matchvec; - } - if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1) - { - vector_free (cmd_vector); - vector_free (matchvec); - *status = CMD_ERR_AMBIGUOUS; - return NULL; - } - else if (ret == 2) - { - vector_free (cmd_vector); - vector_free (matchvec); - *status = CMD_ERR_NO_MATCH; - return NULL; - } - } - /* Prepare match vector */ - /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */ - /* Make sure that cmd_vector is filtered based on current word */ - command = vector_get_item (vline, index); - if (command) - match = cmd_filter_by_completion (command, cmd_vector, index); + /* Stop immediately if line is empty apart from comment */ + if ((tok_total & ~cmd_tok_comment) == cmd_tok_null) + return CMD_EMPTY ; /* NB: parsed->cmd == NULL */ - /* Make description vector. */ - for (i = 0; i < vector_length (cmd_vector); i++) + /* Level 1 parsing + * + * Strip quotes and escapes from all the tokens. + */ + if (tok_total != cmd_tok_simple) { - vector strvec ; + ret = cmd_parse_phase_one(parsed) ; + if (ret != CMD_SUCCESS) + return ret ; + } ; - cmd_element = vector_get_item (cmd_vector, i) ; - if (cmd_element == NULL) - continue ; + /* If allowed to 'do', see if there. + * + * 'do' forces command to be parsed in ENABLE_NODE (if allowed) + */ + if (type & cmd_parse_do) + cmd_try_do_shortcut(parsed) ; - /* Ignore cmd_element if no tokens at index position. - * - * Deal with special case of possible <cr> completion. - */ - strvec = cmd_element->strvec; - if (index >= vector_length (strvec)) + + + + return cmd_describe_command_real (tokens, node, status); + + + + static vector + cmd_describe_command_real (vector tokens, int node, int *status) + { + unsigned int i; + vector cmd_vector; + #define INIT_MATCHVEC_SIZE 10 + vector matchvec; + struct cmd_element *cmd_element; + unsigned int index; + int ret; + enum match_type match; + char *command; + + /* Set index. */ + if (vector_length (tokens) == 0) + { + *status = CMD_ERR_NO_MATCH; + return NULL; + } + else + index = vector_length (tokens) - 1; + + /* Make copy vector of current node's command vector. */ + cmd_vector = vector_copy (cmd_node_vector (cmdvec, node)); + + /* Prepare match vector */ + matchvec = vector_init (INIT_MATCHVEC_SIZE); + + /* Filter commands. */ + /* Only words precedes current word will be checked in this loop. */ + for (i = 0; i < index; i++) + if ((command = vector_get_item (tokens, i))) { - if (command == NULL && index == vector_length (strvec)) + match = cmd_filter(command, cmd_vector, i, any_match) ; + + if (match == vararg_match) { - if (!desc_unique_string (matchvec, command_cr)) - vector_push_item(matchvec, &desc_cr); - } - continue ; - } ; + struct cmd_element *cmd_element; + vector descvec; + unsigned int j, k; + + for (j = 0; j < vector_length (cmd_vector); j++) + if ((cmd_element = vector_get_item (cmd_vector, j)) != NULL + && (vector_length (cmd_element->strvec))) + { + descvec = vector_get_item (cmd_element->strvec, + vector_length (cmd_element->strvec) - 1); + for (k = 0; k < vector_length (descvec); k++) + { + struct desc *desc = vector_get_item (descvec, k); + vector_set (matchvec, desc); + } + } + + vector_set (matchvec, &desc_cr); + vector_free (cmd_vector); + + return matchvec; + } ; - /* Check if command is completed. */ - unsigned int j; - vector descvec = vector_get_item (strvec, index); - struct desc *desc; + ret = is_cmd_ambiguous (command, cmd_vector, i, match) ; + if (ret != 0) + { + vector_free (cmd_vector); + vector_free (matchvec); + *status = (ret == 1) ? CMD_ERR_AMBIGUOUS + : CMD_ERR_NO_MATCH ; + return NULL ; + } ; + } - for (j = 0; j < vector_length (descvec); j++) - if ((desc = vector_get_item (descvec, j))) - { - const char *string; + /* Prepare match vector */ + /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */ - string = cmd_entry_function_desc (command, desc->cmd); - if (string) + /* Make sure that cmd_vector is filtered based on current word */ + command = vector_get_item (tokens, index); + if (command) + match = cmd_filter(command, cmd_vector, index, any_match); + + /* Make description vector. */ + for (i = 0; i < vector_length (cmd_vector); i++) + { + vector strvec ; + + cmd_element = vector_get_item (cmd_vector, i) ; + if (cmd_element == NULL) + continue ; + + /* Ignore cmd_element if no tokens at index position. + * + * Deal with special case of possible <cr> completion. + */ + strvec = cmd_element->strvec; + if (index >= vector_length (strvec)) + { + if (command == NULL && index == vector_length (strvec)) { - /* Uniqueness check */ - if (!desc_unique_string (matchvec, string)) - vector_push_item(matchvec, desc); + if (!desc_unique_string (matchvec, command_cr)) + vector_push_item(matchvec, &desc_cr); } + continue ; } ; - } ; - vector_free (cmd_vector); + /* Check if command is completed. */ + unsigned int j; + vector descvec = vector_get_item (strvec, index); + struct desc *desc; + + for (j = 0; j < vector_length (descvec); j++) + if ((desc = vector_get_item (descvec, j))) + { + const char *string; + + string = cmd_entry_function_desc (command, desc->cmd); + if (string) + { + /* Uniqueness check */ + if (!desc_unique_string (matchvec, string)) + vector_push_item(matchvec, desc); + } + } ; + } ; + + vector_free (cmd_vector); + + if (vector_length(matchvec) == 0) + { + vector_free (matchvec); + *status = CMD_ERR_NO_MATCH; + return NULL; + } + + *status = CMD_SUCCESS; + return matchvec; + } + + + + - if (vector_length(matchvec) == 0) - { - vector_free (matchvec); - *status = CMD_ERR_NO_MATCH; - return NULL; - } - *status = CMD_SUCCESS; - return matchvec; -} -/*------------------------------------------------------------------------------ - * Get description of current (partial) command - * - * Returns: NULL => no description available - * - * status set to CMD_ERR_NO_MATCH or CMD_ERR_AMBIGUOUS - * - * or: address of vector of "struct desc" values available. - * - * NB: when a vector is returned it is the caller's responsibility to - * vector_free() it. (The contents are all effectively const, so do not - * themselves need to be freed.) - */ -vector -cmd_describe_command (vector vline, int node, int *status) -{ - vector ret; - if ( cmd_try_do_shortcut(node, vector_get_item(vline, 0) ) ) - { - vector shifted_vline; - unsigned int index; - /* We can try it on enable node, cos' the vty is authenticated */ - shifted_vline = vector_init (vector_count(vline)); - /* use memcpy? */ - for (index = 1; index < vector_length (vline); index++) - { - vector_set_index (shifted_vline, index-1, vector_lookup(vline, index)); - } - ret = cmd_describe_command_real (shifted_vline, ENABLE_NODE, status); - vector_free(shifted_vline); - return ret; - } - return cmd_describe_command_real (vline, node, status); -} + + + + + + cmd_parse_reset(parsed, false) ; + + return +} ; /*------------------------------------------------------------------------------ * Check LCD of matched command. @@ -2192,7 +1502,7 @@ cmd_lcd (vector matchvec) * Command line completion support. */ static vector -cmd_complete_command_real (vector vline, int node, int *status) +cmd_complete_command_real (vector tokens, int node, int *status) { unsigned int i; unsigned int ivl ; @@ -2207,8 +1517,8 @@ cmd_complete_command_real (vector vline, int node, int *status) char *token; int n ; - /* Stop immediately if the vline is empty. */ - if (vector_length (vline) == 0) + /* Stop immediately if the tokens is empty. */ + if (vector_length (tokens) == 0) { *status = CMD_ERR_NO_MATCH; return NULL; @@ -2218,7 +1528,7 @@ cmd_complete_command_real (vector vline, int node, int *status) cmd_v = vector_copy (cmd_node_vector (cmdvec, node)); /* First, filter upto, but excluding last token */ - last_ivl = vector_length (vline) - 1; + last_ivl = vector_length (tokens) - 1; for (ivl = 0; ivl < last_ivl; ivl++) { @@ -2226,7 +1536,7 @@ cmd_complete_command_real (vector vline, int node, int *status) int ret; /* TODO: does this test make any sense ? */ - if ((token = vector_get_item (vline, ivl)) == NULL) + if ((token = vector_get_item (tokens, ivl)) == NULL) continue ; /* First try completion match, return best kind of match */ @@ -2263,7 +1573,7 @@ cmd_complete_command_real (vector vline, int node, int *status) /* Now we got into completion */ index = last_ivl ; - token = vector_get_item(vline, last_ivl) ; /* is now the last token */ + token = vector_get_item(tokens, last_ivl) ; /* is now the last token */ for (i = 0; i < vector_length (cmd_v); i++) { @@ -2349,31 +1659,32 @@ cmd_complete_command_real (vector vline, int node, int *status) * Can the current command be completed ? */ extern vector -cmd_complete_command (vector vline, int node, int *status) +cmd_complete_command (vector tokens, int node, int *status) { vector ret; - if ( cmd_try_do_shortcut(node, vector_get_item(vline, 0) ) ) + if ( cmd_try_do_shortcut(node, vector_get_item(tokens, 0) ) ) { - vector shifted_vline; + vector shifted_tokens; unsigned int index; /* We can try it on enable node, cos' the vty is authenticated */ - shifted_vline = vector_init (vector_count(vline)); + shifted_tokens = vector_init (vector_count(tokens)); /* use memcpy? */ - for (index = 1; index < vector_length (vline); index++) + for (index = 1; index < vector_length (tokens); index++) { - vector_set_index (shifted_vline, index-1, vector_lookup(vline, index)); + vector_set_index (shifted_tokens, index-1, + vector_lookup(tokens, index)) ; } - ret = cmd_complete_command_real (shifted_vline, ENABLE_NODE, status); + ret = cmd_complete_command_real (shifted_tokens, ENABLE_NODE, status); - vector_free(shifted_vline); + vector_free(shifted_tokens); return ret; } - return cmd_complete_command_real (vline, node, status); + return cmd_complete_command_real (tokens, node, status); } /*------------------------------------------------------------------------------ @@ -2400,58 +1711,12 @@ node_parent ( enum node_type node ) default: return CONFIG_NODE; - } -} - -/*------------------------------------------------------------------------------ - * Initialise a new struct cmd_parsed, allocating if required - */ -extern cmd_parsed -cmd_parse_init_new(cmd_parsed parsed) -{ - if (parsed == NULL) - parsed = XCALLOC(MTYPE_CMD_PARSED, sizeof(*parsed)) ; - else - memset(parsed, 0, sizeof(*parsed)) ; - - /* Zeroising the structure has set: - * - * cmd = NULL -- no command parsed, yet - * cnode -- no node set, yet - * - * do_shortcut -- false - * onode -- not material (do_shortcut is false) - * - * line = zeroised qstring -- empty - * words = zeroised qstring -- empty - * - * vline = zeroised vector -- empty - * - * so nothing else to do - */ - - return parsed ; + } ; } ; -/*------------------------------------------------------------------------------ - * Initialise a new struct cmd_parsed, allocating if required +/*============================================================================== + * Parsing of command lines */ -extern cmd_parsed -cmd_parse_reset(cmd_parsed parsed, bool free_structure) -{ - if (parsed != NULL) - { - qs_reset_keep(&parsed->words) ; - vector_reset_keep(&parsed->vline) ; - - if (free_structure) - XFREE(MTYPE_CMD_PARSED, parsed) ; /* sets parsed = NULL */ - else - cmd_parse_init_new(parsed) ; - } ; - - return parsed ; -} ; /*------------------------------------------------------------------------------ * Parse a command in the given "node", if possible, ready for execution. @@ -2465,8 +1730,9 @@ cmd_parse_reset(cmd_parsed parsed, bool free_structure) * current node. */ -static enum cmd_return_code -cmd_parse_this(struct cmd_parsed* parsed, bool strict) ; +static enum cmd_return_code cmd_parse_phase_one(cmd_parsed parsed) ; +static enum cmd_return_code cmd_parse_phase_two(struct cmd_parsed* parsed, + bool strict) ; /*------------------------------------------------------------------------------ * Parse a command in the given "node", or (if required) any of its ancestors. @@ -2502,41 +1768,61 @@ cmd_parse_this(struct cmd_parsed* parsed, bool strict) ; * See elsewhere for description of parsed structure. */ extern enum cmd_return_code -cmd_parse_command(struct vty* vty, enum cmd_parse_type type) +cmd_parse_command(struct vty* vty, cmd_parse_type_t type) { enum cmd_return_code ret ; enum cmd_return_code first_ret ; cmd_parsed parsed ; + cmd_token_type_t tok_total ; + bool varflag ; + unsigned int i, ivl ; /* Initialise the parsed structure -- assuming no 'do' */ if (vty->parsed == NULL) - vty->parsed = cmd_parse_init_new(NULL) ; - parsed = vty->parsed ; + parsed = vty->parsed = cmd_parse_init_new(NULL) ; + else + { + parsed = vty->parsed ; - parsed->onode = parsed->cnode = vty->node ; + parsed->cmd = NULL ; + parsed->do_shortcut = false ; - parsed->cmd = NULL ; - parsed->do_shortcut = 0 ; + if (parsed->pipes != cmd_pipe_none) + { + parsed->pipes = cmd_pipe_none ; + cmd_empty_parsed_tokens(parsed) ; + } ; + } ; - /* Parse the line into words -- set up parsed->words and parsed->vline */ - cmd_make_vline(&parsed->vline, &parsed->words, vty->buf) ; + /* Parse the line into tokens, set parsed->line, ->cnode & ->onode */ + tok_total = cmd_tokenise(parsed, vty->buf, vty->node) ; - if (vector_length(&parsed->vline) == 0) + /* Stop immediately if line is empty apart from comment */ + if ((tok_total & ~cmd_tok_comment) == cmd_tok_null) return CMD_EMPTY ; /* NB: parsed->cmd == NULL */ - /* If allowed to 'do', see if there. + /* Level 1 parsing * - * 'do' forces command to be parsed in ENABLE_NODE (if allowed) + * Strip quotes and escapes from all the tokens. */ - if ((type & cmd_parse_do) && - cmd_try_do_shortcut(parsed->cnode, vector_get_item(&parsed->vline, 0))) + if (tok_total != cmd_tok_simple) { - parsed->cnode = ENABLE_NODE ; - parsed->do_shortcut = 1 ; + ret = cmd_parse_phase_one(parsed) ; + if (ret != CMD_SUCCESS) + return ret ; } ; - /* Try in the current node */ - ret = cmd_parse_this(parsed, ((type & cmd_parse_strict) != 0)) ; + /* If allowed to 'do', see if there. + * + * 'do' forces command to be parsed in ENABLE_NODE (if allowed) + */ + if (type & cmd_parse_do) + cmd_try_do_shortcut(parsed) ; + + /* Level 2 parsing + * Try in the current node + */ + ret = cmd_parse_phase_two(parsed, type) ; if (ret != CMD_SUCCESS) { @@ -2556,72 +1842,132 @@ cmd_parse_command(struct vty* vty, enum cmd_parse_type type) } ; parsed->cnode = node_parent(parsed->cnode) ; - ret = cmd_parse_this(parsed, ((type & cmd_parse_strict) != 0)) ; + ret = cmd_parse_phase_two(parsed, type) ; } ; } ; - return vty->parsed->cmd->daemon ? CMD_SUCCESS_DAEMON - : CMD_SUCCESS ; + /* Parsed successfully -- construct the arg_vector */ + + varflag = false ; + ivl = vector_length(parsed->cmd->strvec) ; + + cmd_arg_vector_empty(parsed) ; + for (i = 0; i < ivl ; i++) + { + bool take = varflag ; + + if (!varflag) + { + vector descvec = vector_get_item (parsed->cmd->strvec, i); + + if (vector_length (descvec) == 1) + { + struct desc *desc = vector_get_item (descvec, 0); + + if (CMD_VARARG (desc->cmd)) + take = varflag = true ; + else + take = (CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd)) ; + } + else + take = true ; + } + + if (take) + cmd_arg_vector_push(parsed, + cmd_token_value(cmd_token_get(&parsed->tokens, i))) ; + } ; + + /* Return appropriate form of success */ + return parsed->cmd->daemon ? CMD_SUCCESS_DAEMON + : CMD_SUCCESS ; +} ; + +/*------------------------------------------------------------------------------ + * Phase 1 of command parsing + * + * * At start of line look for: + * + * * '<' -- pipe-in command of some sort + * + * Sets the pipe type and the read_pipe_tokens -- all tokens up to + * '>', '|', '!' or '#'.. + * + * Scan for '>', '|', '!' or '#' + * + * * '>' or '|' -- pipe-out command of some sort + * + * Collect type of pipe, and then all tokens up to '!' or '#' + * + * + * + * * '!', '#', comment -- discards + * + * Returns: CMD_SUCCESS -- parsed successfully + * CMD_ERR_NO_MATCH ) + * CMD_ERR_AMBIGUOUS ) failed to parse + * CMD_ERR_INCOMPLETE ) + */ +static enum cmd_return_code +cmd_parse_phase_one(cmd_parsed parsed) +{ + + + + + + } ; /*------------------------------------------------------------------------------ - * Work function for cmd_parse_command + * Phase 2 of command parsing * * Takes a parsed structure, with the: * * cnode -- node to parse in - * vline -- the line broken into words + * tokens -- the line broken into words * do_shortcut -- true if first word is 'do' (to be ignored) * * and parses either strictly or with command completion. * - * If successful, reduces the vline structure down to the variable portions, - * ie to the argv[] for the command function. - * * Returns: CMD_SUCCESS -- parsed successfully * CMD_ERR_NO_MATCH ) * CMD_ERR_AMBIGUOUS ) failed to parse * CMD_ERR_INCOMPLETE ) */ static enum cmd_return_code -cmd_parse_this(cmd_parsed parsed, bool strict) +cmd_parse_phase_two(cmd_parsed parsed, cmd_parse_type_t type) { unsigned int i ; unsigned int ivl ; unsigned index ; - unsigned first ; - unsigned argc ; vector cmd_v; struct cmd_element *cmd_element; struct cmd_element *matched_element; unsigned int matched_count, incomplete_count; - enum match_type match = 0; - int varflag; - char *command; - - /* Need length of vline, discounting the first entry if required */ - first = parsed->do_shortcut ? 1 : 0 ; + enum match_type match ; + enum match_type filter_level ; + const char *command; - assert(vector_length(&parsed->vline) >= first) ; - ivl = vector_length(&parsed->vline) - first ; + /* Need number of tokens */ + ivl = cmd_token_count(&parsed->tokens) ; /* Make copy of command elements. */ cmd_v = vector_copy (cmd_node_vector (cmdvec, parsed->cnode)); /* Look for an unambiguous result */ + filter_level = (type & cmd_parse_strict) ? exact_match : any_match ; + match = no_match ; /* in case of emptiness */ for (index = 0 ; index < ivl; index++) { int ret ; - command = vector_get_item(&parsed->vline, index + first) ; - if (command == NULL) - continue ; + command = cmd_token_string(cmd_token_get(&parsed->tokens, index)) ; - match = strict ? cmd_filter_by_string(command, cmd_v, index) - : cmd_filter_by_completion(command, cmd_v, index) ; + match = cmd_filter(command, cmd_v, index, filter_level) ; if (match == vararg_match) - break; + break; ret = is_cmd_ambiguous (command, cmd_v, index, match); @@ -2630,7 +1976,7 @@ cmd_parse_this(cmd_parsed parsed, bool strict) assert((ret == 1) || (ret == 2)) ; vector_free (cmd_v); return (ret == 1) ? CMD_ERR_AMBIGUOUS : CMD_ERR_NO_MATCH ; - } + } } ; /* Check matched count. */ @@ -2645,17 +1991,17 @@ cmd_parse_this(cmd_parsed parsed, bool strict) continue ; if (match == vararg_match || index >= cmd_element->cmdsize) - { - matched_element = cmd_element; + { + matched_element = cmd_element; #if 0 - printf ("DEBUG: %s\n", cmd_element->string); + printf ("DEBUG: %s\n", cmd_element->string); #endif - matched_count++; - } + matched_count++; + } else - { - incomplete_count++; - } + { + incomplete_count++; + } } ; /* Finished with cmd_v. */ @@ -2670,37 +2016,6 @@ cmd_parse_this(cmd_parsed parsed, bool strict) return CMD_ERR_AMBIGUOUS ; } ; - /* Found command -- process the arguments ready for execution */ - varflag = 0 ; - argc = 0 ; - - for (index = 0; index < ivl ; index++) - { - int take = varflag ; - - if (!varflag) - { - vector descvec = vector_get_item (matched_element->strvec, index); - - if (vector_length (descvec) == 1) - { - struct desc *desc = vector_get_item (descvec, 0); - - if (CMD_VARARG (desc->cmd)) - take = varflag = 1 ; - else - take = (CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd)) ; - } - else - take = 1 ; - } - - if (take) - vector_assign_item(&parsed->vline, argc++, index + first) ; - } ; - - vector_set_length(&parsed->vline, argc) ; /* set to new length */ - /* Everything checks out... ready to execute command */ parsed->cmd = matched_element ; @@ -2803,7 +2118,7 @@ cmd_execute_command(struct vty *vty, *cmd = vty->parsed->cmd ; /* for vtysh */ if (ret == CMD_SUCCESS) - ret = cmd_dispatch(vty, 0) ; + ret = cmd_dispatch(vty, cmd_may_queue) ; else if (ret == CMD_EMPTY) ret = CMD_SUCCESS ; @@ -2903,6 +2218,129 @@ config_from_file (struct vty *vty, FILE *fp, struct cmd_element* first_cmd, return ret ; } ; +/*============================================================================== + */ + +static cmd_return_code_t cmd_fetch_command(struct vty* vty) ; + +/*------------------------------------------------------------------------------ + * Command Loop + * + * Read and dispatch commands until can no longer do so for whatever reason: + * + * - reached end of command stream -- CMD_CLOSE + * - encounter error of some kind -- CMD_WARNING, CMD_ERROR, etc + * - waiting for input to arrive -- CMD_WAIT_INPUT + * - waiting for command to complete -- CMD_QUEUED + * - waiting for output to complete -- ?? + * + */ +extern cmd_return_code_t +cmd_command_loop(struct vty *vty, struct cmd_element* first_cmd, + qstring buf, bool ignore_warning) +{ + cmd_return_code_t ret ; + + vty->buf = buf->body ; + vty->lineno = 0 ; + + + /* + * + */ + + vty_out_clear(vty) ; + + while (1) { + + /* Fetch a command line */ + + ret = cmd_fetch_command(vty) ; + + if (ret != CMD_SUCCESS) + break ; + + ++vty->lineno ; + + /* Parse the command line we now have */ + + ret = cmd_parse_command(vty, cmd_parse_strict + cmd_parse_tree) ; + + if (ret == CMD_EMPTY) + continue ; /* skip empty/comment */ + + if (ret != CMD_SUCCESS) + break ; /* stop on *any* parsing issue */ + + /* special handling before of first command */ + if (first_cmd != NULL) + { + if (first_cmd != vty->parsed->cmd) + { + ret = (*first_cmd->func)(first_cmd, vty, 0, NULL) ; + if (ret != CMD_SUCCESS) + break ; /* stop on *any* issue with "default" */ + } ; + first_cmd = NULL ; + } ; + + /* Reflect command line if required */ + + /* Standard command handling */ + + ret = cmd_dispatch(vty, cmd_no_queue) ; + + if (ret == CMD_QUEUED) + break ; + + /* Output Handling..... */ + + + /* Return code handling.... */ + + if (ret != CMD_SUCCESS) + { + if ((ret == CMD_WARNING) && !ignore_warning) + break ; + if (ret != CMD_CLOSE) + break ; + } ; + + vty_out_clear(vty) ; + } ; + + return ret ; +} ; + + +/*------------------------------------------------------------------------------ + * Fetch the next command. + * + * + * + * + */ +static cmd_return_code_t +cmd_fetch_command(struct vty* vty) +{ + + + + +} ; + + + + + + + + + + + +/*============================================================================*/ + /*----------------------------------------------------------------------------*/ /* Configration from terminal */ @@ -2927,7 +2365,7 @@ DEFUN_CALL (enable, { /* If enable password is NULL, change to ENABLE_NODE */ if ((host.enable == NULL && host.enable_encrypt == NULL) || - vty_shell_serv(vty)) + vty_shell_server(vty)) vty_set_node(vty, ENABLE_NODE); else vty_set_node(vty, AUTH_ENABLE_NODE); @@ -4061,17 +3499,20 @@ cmd_init (int terminal) desc_cr.cmd = command_cr; desc_cr.str = XSTRDUP(MTYPE_STRVEC, ""); - /* Allocate initial top vector of commands. */ - cmdvec = vector_init (0); + /* Allocate initial top vector of commands. */ + cmdvec = vector_init(0); + + /* Allocate vector of spare qstrings for tokens */ + cmd_spare_tokens_init() ; /* Default host value settings. */ - host.name = NULL; + host.name = NULL; host.password = NULL; - host.enable = NULL; - host.logfile = NULL; - host.config = NULL; - host.lines = -1; - host.motd = default_motd; + host.enable = NULL; + host.logfile = NULL; + host.config = NULL; + host.lines = -1; + host.motd = default_motd; host.motdfile = NULL; /* Install top nodes. */ @@ -4187,6 +3628,8 @@ cmd_terminate () struct desc *desc; vector cmd_node_v, cmd_element_v, desc_v; + cmd_spare_tokens_free() ; + if (cmdvec) { for (i = 0; i < vector_length (cmdvec); i++) |