Handle aliases.

This commit is contained in:
Nicholas Marriott
2026-07-01 00:02:10 +01:00
parent bce30eefd3
commit ab3da84e34
3 changed files with 164 additions and 19 deletions

View File

@@ -27,6 +27,7 @@
/* One frame in the parse tree stack. */ /* One frame in the parse tree stack. */
struct cmd_invoke_frame { struct cmd_invoke_frame {
struct cmd_parse_tree *tree;
struct cmd_parse_node *node; struct cmd_parse_node *node;
struct cmd_parse_node *next; struct cmd_parse_node *next;
struct cmd_parse_node *end; struct cmd_parse_node *end;
@@ -36,6 +37,7 @@ struct cmd_invoke_frame {
struct cmd_invoke_state { struct cmd_invoke_state {
u_int references; u_int references;
struct cmd_parse_tree *tree; struct cmd_parse_tree *tree;
struct cmd_parse_tree *current_tree;
struct cmd_invoke_frame *stack; struct cmd_invoke_frame *stack;
u_int nstack; u_int nstack;
@@ -48,8 +50,9 @@ struct cmd_invoke_state {
}; };
static void cmd_invoke_push(struct cmd_invoke_state *, static void cmd_invoke_push(struct cmd_invoke_state *,
struct cmd_parse_node *, struct cmd_parse_node *, struct cmd_parse_tree *, struct cmd_parse_node *,
struct cmd_parse_node *); struct cmd_parse_node *, struct cmd_parse_node *);
static struct cmd_parse_tree *cmd_invoke_tree(struct cmd_invoke_state *);
static struct cmd_parse_node *cmd_invoke_next(struct cmd_invoke_state *); static struct cmd_parse_node *cmd_invoke_next(struct cmd_invoke_state *);
static void cmd_invoke_skip_sequence(struct cmd_invoke_state *); static void cmd_invoke_skip_sequence(struct cmd_invoke_state *);
static int cmd_invoke_expand_string(struct cmdq_item *, static int cmd_invoke_expand_string(struct cmdq_item *,
@@ -60,23 +63,33 @@ static int cmd_invoke_assignment(struct cmdq_item *,
static int cmd_invoke_if(struct cmdq_item *, struct cmd_invoke_state *, static int cmd_invoke_if(struct cmdq_item *, struct cmd_invoke_state *,
struct cmd_parse_node *); struct cmd_parse_node *);
static struct cmd *cmd_invoke_build_command(struct cmdq_item *, static struct cmd *cmd_invoke_build_command(struct cmdq_item *,
struct cmd_invoke_state *, struct cmd_parse_node *); struct cmd_invoke_state *, struct cmd_parse_node *);
static int cmd_invoke_read_only(struct cmdq_item *, struct cmd *); static int cmd_invoke_read_only(struct cmdq_item *, struct cmd *);
/* Push a node's child range onto the traversal stack. */ /* Push a node's child range onto the traversal stack. */
static void static void
cmd_invoke_push(struct cmd_invoke_state *is, struct cmd_parse_node *node, cmd_invoke_push(struct cmd_invoke_state *is, struct cmd_parse_tree *tree,
struct cmd_parse_node *first, struct cmd_parse_node *end) struct cmd_parse_node *node, struct cmd_parse_node *first,
struct cmd_parse_node *end)
{ {
u_int n = is->nstack + 1; u_int n = is->nstack + 1;
is->stack = xreallocarray(is->stack, n, sizeof *is->stack); is->stack = xreallocarray(is->stack, n, sizeof *is->stack);
is->stack[is->nstack].tree = cmd_parse_add_ref(tree);
is->stack[is->nstack].node = node; is->stack[is->nstack].node = node;
is->stack[is->nstack].next = first; is->stack[is->nstack].next = first;
is->stack[is->nstack].end = end; is->stack[is->nstack].end = end;
is->nstack = n; is->nstack = n;
} }
static struct cmd_parse_tree *
cmd_invoke_tree(struct cmd_invoke_state *is)
{
if (is->current_tree != NULL)
return (is->current_tree);
return (is->tree);
}
/* Return the next node to execute from the traversal stack. */ /* Return the next node to execute from the traversal stack. */
static struct cmd_parse_node * static struct cmd_parse_node *
cmd_invoke_next(struct cmd_invoke_state *is) cmd_invoke_next(struct cmd_invoke_state *is)
@@ -90,11 +103,13 @@ cmd_invoke_next(struct cmd_invoke_state *is)
frame = &is->stack[is->nstack - 1]; frame = &is->stack[is->nstack - 1];
if (frame->next != NULL && frame->next != frame->end) if (frame->next != NULL && frame->next != frame->end)
break; break;
cmd_parse_free(frame->tree);
is->nstack--; is->nstack--;
} }
node = frame->next; node = frame->next;
frame->next = cmd_parse_node_next(node); frame->next = cmd_parse_node_next(node);
is->current_tree = frame->tree;
return (node); return (node);
} }
@@ -113,6 +128,8 @@ cmd_invoke_skip_sequence(struct cmd_invoke_state *is)
type = cmd_parse_node_type(is->stack[i - 1].node); type = cmd_parse_node_type(is->stack[i - 1].node);
if (type == CMD_PARSE_SEQUENCE) { if (type == CMD_PARSE_SEQUENCE) {
is->stack[i - 1].next = is->stack[i - 1].end; is->stack[i - 1].next = is->stack[i - 1].end;
while (is->nstack > i)
cmd_parse_free(is->stack[--is->nstack].tree);
is->nstack = i; is->nstack = i;
break; break;
} }
@@ -274,6 +291,7 @@ static int
cmd_invoke_if(struct cmdq_item *item, struct cmd_invoke_state *is, cmd_invoke_if(struct cmdq_item *item, struct cmd_invoke_state *is,
struct cmd_parse_node *node) struct cmd_parse_node *node)
{ {
struct cmd_parse_tree *tree = cmd_invoke_tree(is);
struct cmd_parse_node *child, *first, *next; struct cmd_parse_node *child, *first, *next;
int r; int r;
@@ -285,7 +303,7 @@ cmd_invoke_if(struct cmdq_item *item, struct cmd_invoke_state *is,
return (-1); return (-1);
if (r) { if (r) {
next = cmd_invoke_if_branch_end(first); next = cmd_invoke_if_branch_end(first);
cmd_invoke_push(is, node, first, next); cmd_invoke_push(is, tree, node, first, next);
return (0); return (0);
} }
@@ -299,13 +317,13 @@ cmd_invoke_if(struct cmdq_item *item, struct cmd_invoke_state *is,
return (-1); return (-1);
if (r) { if (r) {
next = cmd_parse_node_next(next); next = cmd_parse_node_next(next);
cmd_invoke_push(is, child, next, NULL); cmd_invoke_push(is, tree, child, next, NULL);
return (0); return (0);
} }
break; break;
case CMD_PARSE_ELSE: case CMD_PARSE_ELSE:
next = cmd_parse_node_first_child(child); next = cmd_parse_node_first_child(child);
cmd_invoke_push(is, child, next, NULL); cmd_invoke_push(is, tree, child, next, NULL);
return (0); return (0);
default: default:
break; break;
@@ -319,8 +337,9 @@ static void
cmd_invoke_error(struct cmdq_item *item, struct cmd_invoke_state *is, cmd_invoke_error(struct cmdq_item *item, struct cmd_invoke_state *is,
struct cmd_parse_node *node, const char *cause) struct cmd_parse_node *node, const char *cause)
{ {
const char *file = cmd_parse_file(is->tree); struct cmd_parse_tree *tree = cmd_invoke_tree(is);
u_int line = cmd_parse_node_line(node); const char *file = cmd_parse_file(tree);
u_int line = cmd_parse_node_line(node);
if (cmdq_get_client(item) != NULL) { if (cmdq_get_client(item) != NULL) {
cmdq_error(item, "%s", cause); cmdq_error(item, "%s", cause);
@@ -338,7 +357,7 @@ static struct cmd *
cmd_invoke_build_command(struct cmdq_item *item, struct cmd_invoke_state *is, cmd_invoke_build_command(struct cmdq_item *item, struct cmd_invoke_state *is,
struct cmd_parse_node *node) struct cmd_parse_node *node)
{ {
struct cmd_parse_tree *tree = is->tree; struct cmd_parse_tree *tree = cmd_invoke_tree(is);
struct cmd_parse_node *child; struct cmd_parse_node *child;
struct args_value *values = NULL; struct args_value *values = NULL;
struct cmd *cmd; struct cmd *cmd;
@@ -426,7 +445,7 @@ cmd_invoke_get(struct cmd_parse_tree *tree, struct cmdq_state *state,
} }
first = cmd_parse_node_first_child(root); first = cmd_parse_node_first_child(root);
cmd_invoke_push(is, root, first, NULL); cmd_invoke_push(is, tree, root, first, NULL);
item = cmdq_get_invoke(is, state); item = cmdq_get_invoke(is, state);
cmd_invoke_state_free(is); cmd_invoke_state_free(is);
@@ -446,6 +465,7 @@ void
cmd_invoke_state_free(struct cmd_invoke_state *is) cmd_invoke_state_free(struct cmd_invoke_state *is)
{ {
int i; int i;
u_int j;
if (is == NULL) if (is == NULL)
return; return;
@@ -455,6 +475,8 @@ cmd_invoke_state_free(struct cmd_invoke_state *is)
for (i = 0; i < is->argc; i++) for (i = 0; i < is->argc; i++)
free(is->argv[i]); free(is->argv[i]);
free(is->argv); free(is->argv);
for (j = 0; j < is->nstack; j++)
cmd_parse_free(is->stack[j].tree);
cmd_parse_free(is->tree); cmd_parse_free(is->tree);
free(is->stack); free(is->stack);
@@ -473,10 +495,13 @@ cmd_invoke_result(struct cmd_invoke_state *is, enum cmd_retval retval)
enum cmd_retval enum cmd_retval
cmd_invoke_fire(struct cmdq_item *item, struct cmd_invoke_state *is) cmd_invoke_fire(struct cmdq_item *item, struct cmd_invoke_state *is)
{ {
struct cmd_parse_node *node; struct cmd_parse_node *node, *first;
struct cmd_parse_tree *tree, *alias;
struct cmdq_item *new_item, *next; struct cmdq_item *new_item, *next;
struct cmdq_state *state; struct cmdq_state *state;
struct cmd *cmd; struct cmd *cmd;
char *cause;
int r;
if (is->have_last && is->last == CMD_RETURN_ERROR) if (is->have_last && is->last == CMD_RETURN_ERROR)
cmd_invoke_skip_sequence(is); cmd_invoke_skip_sequence(is);
@@ -489,11 +514,12 @@ cmd_invoke_fire(struct cmdq_item *item, struct cmd_invoke_state *is)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
cmd_parse_log_node(__func__, node); cmd_parse_log_node(__func__, node);
tree = cmd_invoke_tree(is);
switch (cmd_parse_node_type(node)) { switch (cmd_parse_node_type(node)) {
case CMD_PARSE_ROOT: case CMD_PARSE_ROOT:
case CMD_PARSE_SEQUENCE: case CMD_PARSE_SEQUENCE:
cmd_invoke_push(is, node, first = cmd_parse_node_first_child(node);
cmd_parse_node_first_child(node), NULL); cmd_invoke_push(is, tree, node, first, NULL);
break; break;
case CMD_PARSE_ASSIGN: case CMD_PARSE_ASSIGN:
case CMD_PARSE_HIDDEN_ASSIGN: case CMD_PARSE_HIDDEN_ASSIGN:
@@ -512,6 +538,21 @@ cmd_invoke_fire(struct cmdq_item *item, struct cmd_invoke_state *is)
case CMD_PARSE_ELSE: case CMD_PARSE_ELSE:
break; break;
case CMD_PARSE_COMMAND: case CMD_PARSE_COMMAND:
r = cmd_parse_expand_alias(tree, node, &alias, &cause);
if (r == 1) {
node = cmd_parse_root(alias);
first = cmd_parse_node_first_child(node);
cmd_invoke_push(is, alias, node, first, NULL);
cmd_parse_free(alias);
break;
}
if (r == -1) {
cmd_invoke_error(item, is, node, cause);
free(cause);
cmd_invoke_skip_sequence(is);
break;
}
cmd = cmd_invoke_build_command(item, is, node); cmd = cmd_invoke_build_command(item, is, node);
if (cmd == NULL) { if (cmd == NULL) {
cmd_invoke_skip_sequence(is); cmd_invoke_skip_sequence(is);

View File

@@ -714,6 +714,81 @@ cmd_parse_from_node(struct cmd_parse_tree *tree, struct cmd_parse_node *node)
return (new); return (new);
} }
/* Find the last command node in tree order. */
static struct cmd_parse_node *
cmd_parse_last_command(struct cmd_parse_node *node)
{
struct cmd_parse_node *child, *last = NULL, *found;
if (node->type == CMD_PARSE_COMMAND)
last = node;
TAILQ_FOREACH(child, &node->children, entry) {
found = cmd_parse_last_command(child);
if (found != NULL)
last = found;
}
return (last);
}
/*
* If cmd names an alias, parse the alias text as command language and append
* the original arguments after the alias name to the last expanded command.
*/
int
cmd_parse_expand_alias(struct cmd_parse_tree *src, struct cmd_parse_node *cmd,
struct cmd_parse_tree **out, char **cause)
{
struct cmd_parse_input pi;
struct cmd_parse_tree *tree;
struct cmd_parse_node *first, *node, *last, *loop, *copy;
char *alias;
*out = NULL;
*cause = NULL;
if (cmd->type != CMD_PARSE_COMMAND)
return (0);
if (cmd_parse_flags(src) & CMD_PARSE_NOALIAS)
return (0);
first = TAILQ_FIRST(&cmd->children);
if (first == NULL)
return (0);
if (first->type != CMD_PARSE_STRING)
return (0);
node = TAILQ_FIRST(&first->children);
if (node == NULL || TAILQ_NEXT(node, entry) != NULL)
return (0);
if (node->type != CMD_PARSE_TEXT)
return (0);
alias = cmd_get_alias(node->value);
if (alias == NULL)
return (0);
memset(&pi, 0, sizeof pi);
pi.file = cmd_parse_file(src);
pi.line = cmd_parse_node_line(cmd);
pi.flags = cmd_parse_flags(src) | CMD_PARSE_NOALIAS;
tree = cmd_parse_from_string(alias, &pi, cause);
free(alias);
if (tree == NULL)
return (-1);
last = cmd_parse_last_command(cmd_parse_root(tree));
if (last != NULL) {
loop = TAILQ_NEXT(first, entry);
while (loop != NULL) {
copy = cmd_parse_copy_node(loop);
TAILQ_INSERT_TAIL(&last->children, copy, entry);
loop = TAILQ_NEXT(loop, entry);
}
}
*out = tree;
return (1);
}
/* Build a string node with a single literal text child. */ /* Build a string node with a single literal text child. */
static struct cmd_parse_node * static struct cmd_parse_node *
cmd_parse_new_string_node(const char *s, u_int line) cmd_parse_new_string_node(const char *s, u_int line)
@@ -1274,16 +1349,40 @@ static int
cmd_parse_command_any_have(struct cmd_parse_tree *tree, cmd_parse_command_any_have(struct cmd_parse_tree *tree,
struct cmd_parse_node *node, int flag) struct cmd_parse_node *node, int flag)
{ {
struct cmd_parse_node *child; struct cmd_parse_node *child, *first, *text;
int flags = tree->flags; int flags = tree->flags;
struct args_value *values = NULL; struct args_value *values = NULL;
struct cmd *cmd; struct cmd *cmd;
char *cause = NULL; char *cause = NULL;
const char *file = tree->file;
u_int count = 0; u_int count = 0;
int found = 0; int found = 0, r;
if (node->type != CMD_PARSE_COMMAND) if (node->type != CMD_PARSE_COMMAND)
return (0); return (0);
r = cmd_parse_expand_alias(tree, node, &tree, &cause);
if (r == 1) {
found = cmd_parse_any_have(tree, flag);
cmd_parse_free(tree);
return (found);
}
if (r == -1) {
free(cause);
return (-1);
}
first = TAILQ_FIRST(&node->children);
if (first != NULL && first->type == CMD_PARSE_STRING) {
text = TAILQ_FIRST(&first->children);
if (text != NULL && TAILQ_NEXT(text, entry) == NULL &&
text->type == CMD_PARSE_TEXT) {
if (cmd_find(text->value, &cause) == NULL) {
free(cause);
return (-1);
}
free(cause);
cause = NULL;
}
}
TAILQ_FOREACH(child, &node->children, entry) { TAILQ_FOREACH(child, &node->children, entry) {
values = xreallocarray(values, count + 1, sizeof *values); values = xreallocarray(values, count + 1, sizeof *values);
@@ -1308,7 +1407,9 @@ cmd_parse_command_any_have(struct cmd_parse_tree *tree,
count++; count++;
} }
cmd = cmd_parse(values, count, tree->file, node->line, flags, &cause); if (file == NULL)
file = "";
cmd = cmd_parse(values, count, file, node->line, flags, &cause);
if (cmd == NULL) { if (cmd == NULL) {
free(cause); free(cause);
found = -1; found = -1;
@@ -1338,7 +1439,7 @@ cmd_parse_any_have(struct cmd_parse_tree *tree, int flag)
if (node->type != CMD_PARSE_COMMAND) if (node->type != CMD_PARSE_COMMAND)
continue; continue;
r = cmd_parse_command_any_have(tree, node, flag); r = cmd_parse_command_any_have(tree, node, flag);
if (r < 0) if (r < 0 && !found)
return (0); return (0);
if (r) if (r)
found = 1; found = 1;

View File

@@ -79,6 +79,9 @@ struct cmd_parse_tree *cmd_parse_from_string(const char *,
struct cmd_parse_input *, char **); struct cmd_parse_input *, char **);
struct cmd_parse_tree *cmd_parse_from_node(struct cmd_parse_tree *, struct cmd_parse_tree *cmd_parse_from_node(struct cmd_parse_tree *,
struct cmd_parse_node *); struct cmd_parse_node *);
int cmd_parse_expand_alias(struct cmd_parse_tree *,
struct cmd_parse_node *, struct cmd_parse_tree **,
char **);
struct cmd_parse_tree *cmd_parse_from_arguments(struct args_value *, u_int); struct cmd_parse_tree *cmd_parse_from_arguments(struct args_value *, u_int);
struct cmd_parse_tree *cmd_parse_add_ref(struct cmd_parse_tree *); struct cmd_parse_tree *cmd_parse_add_ref(struct cmd_parse_tree *);
int cmd_parse_any_have(struct cmd_parse_tree *, int); int cmd_parse_any_have(struct cmd_parse_tree *, int);