// if the entire string was whitespace or a comment, return
if (*copy == '\0' || *copy == '!' || *copy == '#')
+ {
+ XFREE (MTYPE_TMP, copystart);
return NULL;
+ }
vector strvec = vector_init (VECTOR_MIN_SIZE);
const char *delim = " \n\r\t", *tok = NULL;
}
if (!exists)
- vector_set (comps, copy_cmd_token (token));
+ vector_set (comps, token);
}
// sort completions
{
vector_set_index (comps, vector_active (comps), NULL);
memmove (comps->index + 1, comps->index, (comps->alloced - 1) * sizeof (void *));
- vector_set_index (comps, 0, copy_cmd_token (cr));
+ vector_set_index (comps, 0, cr);
}
return comps;
if (MATCHER_ERROR(rv))
{
- switch (rv)
- {
- case MATCHER_AMBIGUOUS:
- *status = CMD_ERR_AMBIGUOUS;
- default:
- *status = CMD_ERR_NO_MATCH;
- }
+ *status = CMD_ERR_NO_MATCH;
return NULL;
}
struct cmd_token *token = vector_slot (initial_comps, i);
if (token->type == WORD_TKN)
vector_set (comps, token);
- else
- del_cmd_token (token);
}
vector_free (initial_comps);
// copy completions text into an array of char*
- ret = XMALLOC (MTYPE_TMP, vector_active (comps) * sizeof (char *) + 1);
+ ret = XMALLOC (MTYPE_TMP, (vector_active (comps)+1) * sizeof (char *));
unsigned int i;
for (i = 0; i < vector_active (comps); i++)
{
struct cmd_token *token = vector_slot (comps, i);
ret[i] = XSTRDUP (MTYPE_TMP, token->text);
vector_unset (comps, i);
- del_cmd_token (token);
}
// set the last element to NULL, because this array is used in
// a Readline completion_generator function which expects NULL
cmd_execute_command_real (vector vline,
enum filter_type filter,
struct vty *vty,
- struct cmd_element **cmd)
+ const struct cmd_element **cmd)
{
struct list *argv_list;
enum matcher_rv status;
- struct cmd_element *matched_element = NULL;
+ const struct cmd_element *matched_element = NULL;
struct graph *cmdgraph = cmd_node_graph (cmdvec, vty->node);
status = command_match (cmdgraph, vline, &argv_list, &matched_element);
// if matcher error, return corresponding CMD_ERR
if (MATCHER_ERROR(status))
+ {
switch (status)
{
case MATCHER_INCOMPLETE:
default:
return CMD_ERR_NO_MATCH;
}
+ }
// build argv array from argv list
struct cmd_token **argv = XMALLOC (MTYPE_TMP, argv_list->count * sizeof (struct cmd_token *));
// delete list and cmd_token's in it
list_delete (argv_list);
+ XFREE (MTYPE_TMP, argv);
return ret;
}
* as to why no command could be executed.
*/
int
-cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
- int vtysh) {
+cmd_execute_command (vector vline, struct vty *vty,
+ const struct cmd_element **cmd,
+ int vtysh)
+{
int ret, saved_ret = 0;
enum node_type onode, try_node;
onode = try_node = vty->node;
- if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
+ if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0)))
{
vector shifted_vline;
unsigned int index;
return ret;
}
-
saved_ret = ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd);
if (vtysh)
*/
int
cmd_execute_command_strict (vector vline, struct vty *vty,
- struct cmd_element **cmd)
+ const struct cmd_element **cmd)
{
return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd);
}
* as to why no command could be executed.
*/
int
-command_config_read_one_line (struct vty *vty, struct cmd_element **cmd, int use_daemon)
+command_config_read_one_line (struct vty *vty, const struct cmd_element **cmd, int use_daemon)
{
vector vline;
int saved_node;
if (!token) return;
if (token->text)
- free (token->text);
+ XFREE (MTYPE_CMD_TOKENS, token->text);
if (token->desc)
- free (token->desc);
+ XFREE (MTYPE_CMD_TOKENS, token->desc);
if (token->arg)
- free (token->arg);
+ XFREE (MTYPE_CMD_TOKENS, token->arg);
- free (token);
+ XFREE (MTYPE_CMD_TOKENS, token);
}
struct cmd_token *
}
struct cmd_element *
-copy_cmd_element(struct cmd_element *cmd)
+copy_cmd_element(const struct cmd_element *cmd)
{
struct cmd_element *el = XMALLOC(MTYPE_CMD_TOKENS, sizeof (struct cmd_element));
el->string = cmd->string ? XSTRDUP(MTYPE_CMD_TOKENS, cmd->string) : NULL;
u_char attr; /* Command attributes */
/* handler function for command */
- int (*func) (struct cmd_element *, struct vty *, int, struct cmd_token *[]);
+ int (*func) (const struct cmd_element *, struct vty *, int, struct cmd_token *[]);
};
/* Return value of the commands. */
};
#define DEFUN_CMD_FUNC_DECL(funcname) \
- static int funcname (struct cmd_element *, struct vty *, int, struct cmd_token *[]);
+ static int funcname (const struct cmd_element *, struct vty *, int, struct cmd_token *[]);
#define DEFUN_CMD_FUNC_TEXT(funcname) \
static int funcname \
- (struct cmd_element *self __attribute__ ((unused)), \
+ (const struct cmd_element *self __attribute__ ((unused)), \
struct vty *vty __attribute__ ((unused)), \
int argc __attribute__ ((unused)), \
struct cmd_token *argv[] __attribute__ ((unused)) )
extern vector cmd_describe_command (vector, struct vty *, int *status);
extern char **cmd_complete_command (vector, struct vty *, int *status);
extern const char *cmd_prompt (enum node_type);
-extern int command_config_read_one_line (struct vty *vty, struct cmd_element **, int use_config_node);
+extern int command_config_read_one_line (struct vty *vty, const struct cmd_element **, int use_config_node);
extern int config_from_file (struct vty *, FILE *, unsigned int *line_num);
extern enum node_type node_parent (enum node_type);
-extern int cmd_execute_command (vector, struct vty *, struct cmd_element **, int);
-extern int cmd_execute_command_strict (vector, struct vty *, struct cmd_element **);
+extern int cmd_execute_command (vector, struct vty *, const struct cmd_element **, int);
+extern int cmd_execute_command_strict (vector, struct vty *, const struct cmd_element **);
extern void cmd_init (int);
extern void cmd_terminate (void);
void
del_cmd_element(struct cmd_element *);
struct cmd_element *
-copy_cmd_element(struct cmd_element *cmd);
+copy_cmd_element(const struct cmd_element *cmd);
/* memory management for cmd_token */
struct cmd_token *
command_match (struct graph *cmdgraph,
vector vline,
struct list **argv,
- struct cmd_element **el)
+ const struct cmd_element **el)
{
matcher_rv = MATCHER_NO_MATCH;
* In the event that two children are found to match with the same precedence,
* then the input is ambiguous for the passed cmd_element and NULL is returned.
*
- * The ultimate return value is an ordered linked list of nodes that comprise
- * the best match for the command, each with their `arg` fields pointing to the
- * matching token string.
- *
* @param[in] start the start node.
* @param[in] vline the vectorized input line.
* @param[in] n the index of the first input token.
+ * @return A linked list of n elements. The first n-1 elements are pointers to
+ * struct cmd_token and represent the sequence of tokens matched by the input.
+ * The ->arg field of each token points to a copy of the input matched on it.
+ * The final nth element is a pointer to struct cmd_element, which is the
+ * command that was matched.
+ *
+ * If no match was found, the return value is NULL.
*/
static struct list *
command_match_r (struct graph_node *start, vector vline, unsigned int n)
// deleting this list the last node must be
// manually deleted
struct cmd_element *el = leaf->data;
- listnode_add (currbest, copy_cmd_element (el));
+ listnode_add (currbest, el);
currbest->del = (void (*)(void *)) &del_cmd_token;
break;
}
MATCHER_OK :
MATCHER_NO_MATCH;
- // extract cmd_token into list
- *completions = list_new ();
- for (ALL_LIST_ELEMENTS_RO (next,node,gn))
- listnode_add (*completions, gn->data);
+ *completions = NULL;
+ if (!MATCHER_ERROR(matcher_rv))
+ {
+ // extract cmd_token into list
+ *completions = list_new ();
+ for (ALL_LIST_ELEMENTS_RO (next,node,gn))
+ listnode_add (*completions, gn->data);
+ }
list_delete (current);
list_delete (next);
* but arglists have cmd_element as the data for the tail, this function
* manually deletes the tail before deleting the rest of the list as usual.
*
+ * The cmd_element at the end is *not* a copy. It is the one and only.
+ *
* @param list the arglist to delete
*/
static void
{
// manually delete last node
struct listnode *tail = listtail (list);
- del_cmd_element (tail->data);
tail->data = NULL;
list_delete_node (list, tail);
*
* @param[in] cmdgraph command graph to match against
* @param[in] vline vectorized input string
- * @param[out] argv pointer to argument list if successful match
- * @param[out] element pointer to matched cmd_element if successful match
+ * @param[out] argv pointer to argument list if successful match, NULL
+ * otherwise. The elements of this list are pointers to struct cmd_token
+ * and represent the sequence of tokens matched by the inpu. The ->arg
+ * field of each token points to a copy of the input matched on it. These
+ * may be safely deleted or modified.
+ * @param[out] element pointer to matched cmd_element if successful match,
+ * or NULL when MATCHER_ERROR(rv) is true. The cmd_element may *not* be
+ * safely deleted or modified; it is the instance initialized on startup.
* @return matcher status
*/
enum matcher_rv
command_match (struct graph *cmdgraph,
vector vline,
struct list **argv,
- struct cmd_element **element);
+ const struct cmd_element **element);
/**
* Compiles possible completions for a given line of user input.
*
* @param[in] start the start node of the DFA to match against
* @param[in] vline vectorized input string
- * @param[in] completions pointer to list of cmd_token representing
- * acceptable next inputs
+ * @param[out] completions pointer to list of cmd_token representing
+ * acceptable next inputs, or NULL when MATCHER_ERROR(rv) is true.
+ * The elements of this list are pointers to struct cmd_token and take on a
+ * variety of forms depending on the passed vline. If the last element in vline
+ * is NULL, all previous elements are considered to be complete words (the case
+ * when a space is the last token of the line) and completions are generated
+ * based on what could follow that input. If the last element in vline is not
+ * NULL and each sequential element matches the corresponding tokens of one or
+ * more commands exactly (e.g. 'encapv4' and not 'en') the same result is
+ * generated. If the last element is not NULL and the best possible match is a
+ * partial match, then the result generated will be all possible continuations
+ * of that element (e.g. 'encapv4', 'encapv6', etc for input 'en').
+ * @return matcher status
*/
enum matcher_rv
command_complete (struct graph *cmdgraph,
$$->start = $1->start;
$$->end = $2->end;
free ($1);
+ free ($2);
}
;
int ret, cmd_stat;
u_int i;
vector vline;
- struct cmd_element *cmd;
+ const struct cmd_element *cmd;
FILE *fp = NULL;
int closepager = 0;
int tried = 0;
int ret;
vector vline;
int tried = 0;
- struct cmd_element *cmd;
+ const struct cmd_element *cmd;
int saved_ret, prev_node;
int lineno = 0;
char *vty_buf_copy = NULL;
vtysh_config_from_file (struct vty *vty, FILE *fp)
{
int ret;
- struct cmd_element *cmd;
+ const struct cmd_element *cmd;
int lineno = 0;
int retcode = CMD_SUCCESS;