-/* $OpenBSD: cmd-parse.y,v 1.35 2021/08/20 06:30:57 nicm Exp $ */
+/* $OpenBSD: cmd-parse.y,v 1.36 2021/08/20 09:06:26 nicm Exp $ */
/*
* Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
u_int line;
struct cmd_parse_arguments arguments;
- int argc;
- char **argv;
-
TAILQ_ENTRY(cmd_parse_command) entry;
};
TAILQ_HEAD(cmd_parse_commands, cmd_parse_command);
static void cmd_parse_free_command(struct cmd_parse_command *);
static struct cmd_parse_commands *cmd_parse_new_commands(void);
static void cmd_parse_free_commands(struct cmd_parse_commands *);
-static char *cmd_parse_commands_to_string(struct cmd_parse_commands *);
-static void cmd_parse_print_commands(struct cmd_parse_input *, u_int,
+static void cmd_parse_build_commands(struct cmd_parse_commands *,
+ struct cmd_parse_input *, struct cmd_parse_result *);
+static void cmd_parse_print_commands(struct cmd_parse_input *,
struct cmd_list *);
-static void cmd_parse_flatten_command(struct cmd_parse_command *);
%}
}
static void
-cmd_parse_print_commands(struct cmd_parse_input *pi, u_int line,
- struct cmd_list *cmdlist)
+cmd_parse_print_commands(struct cmd_parse_input *pi, struct cmd_list *cmdlist)
{
char *s;
- if (pi->item != NULL && (pi->flags & CMD_PARSE_VERBOSE)) {
- s = cmd_list_print(cmdlist, 0);
- if (pi->file != NULL)
- cmdq_print(pi->item, "%s:%u: %s", pi->file, line, s);
- else
- cmdq_print(pi->item, "%u: %s", line, s);
- free(s);
+ if (pi->item == NULL || (~pi->flags & CMD_PARSE_VERBOSE))
+ return;
+ s = cmd_list_print(cmdlist, 0);
+ if (pi->file != NULL)
+ cmdq_print(pi->item, "%s:%u: %s", pi->file, pi->line, s);
+ else
+ cmdq_print(pi->item, "%u: %s", pi->line, s);
+ free(s);
+}
+
+static void
+cmd_parse_free_argument(struct cmd_parse_argument *arg)
+{
+ switch (arg->type) {
+ case CMD_PARSE_STRING:
+ free(arg->string);
+ break;
+ case CMD_PARSE_COMMANDS:
+ cmd_parse_free_commands(arg->commands);
+ break;
}
+ free(arg);
}
static void
struct cmd_parse_argument *arg, *arg1;
TAILQ_FOREACH_SAFE(arg, args, entry, arg1) {
- switch (arg->type) {
- case CMD_PARSE_STRING:
- free(arg->string);
- break;
- case CMD_PARSE_COMMANDS:
- cmd_parse_free_commands(arg->commands);
- break;
- }
TAILQ_REMOVE(args, arg, entry);
- free(arg);
+ cmd_parse_free_argument(arg);
}
}
static void
cmd_parse_free_command(struct cmd_parse_command *cmd)
{
- cmd_free_argv(cmd->argc, cmd->argv);
cmd_parse_free_arguments(&cmd->arguments);
free(cmd);
}
}
}
-static char *
-cmd_parse_commands_to_string(struct cmd_parse_commands *cmds)
+static int
+cmd_parse_expand_alias(struct cmd_parse_command *cmd,
+ struct cmd_parse_input *pi, struct cmd_parse_result *pr,
+ struct cmd_list **cmdlist)
{
- struct cmd_parse_command *cmd;
- char *string = NULL, *s, *line;
+ struct cmd_parse_argument *arg, *arg1, *first, *after;
+ struct cmd_parse_commands *cmds;
+ struct cmd_parse_command *last;
+ char *alias, *name, *cause;
- TAILQ_FOREACH(cmd, cmds, entry) {
- cmd_parse_flatten_command(cmd);
+ *cmdlist = NULL;
- line = cmd_stringify_argv(cmd->argc, cmd->argv);
- if (string == NULL)
- s = line;
- else {
- xasprintf(&s, "%s ; %s", s, line);
- free(line);
- }
+ first = TAILQ_FIRST(&cmd->arguments);
+ if (first == NULL || first->type != CMD_PARSE_STRING) {
+ pr->status = CMD_PARSE_EMPTY;
+ return (1);
+ }
+ name = first->string;
+
+ alias = cmd_get_alias(name);
+ if (alias == NULL)
+ return (0);
+ log_debug("%s: %u alias %s = %s", __func__, pi->line, name, alias);
+
+ cmds = cmd_parse_do_buffer(alias, strlen(alias), pi, &cause);
+ free(alias);
+ if (cmds == NULL) {
+ pr->status = CMD_PARSE_ERROR;
+ pr->error = cause;
+ return (1);
+ }
+
+ last = TAILQ_LAST(cmds, cmd_parse_commands);
+ if (last == NULL) {
+ *cmdlist = cmd_list_new();
+ return (1);
+ }
- free(string);
- string = s;
+ TAILQ_REMOVE(&cmd->arguments, first, entry);
+ cmd_parse_free_argument(first);
+
+ after = TAILQ_NEXT(TAILQ_FIRST(&last->arguments), entry);
+ TAILQ_FOREACH_SAFE(arg, &cmd->arguments, entry, arg1) {
+ TAILQ_REMOVE(&cmd->arguments, arg, entry);
+ if (after == NULL)
+ TAILQ_INSERT_TAIL(&last->arguments, arg, entry);
+ else
+ TAILQ_INSERT_AFTER(&last->arguments, after, arg, entry);
+ after = arg;
}
- if (string == NULL)
- string = xstrdup("");
- log_debug("%s: %s", __func__, string);
- return (string);
+ cmd_parse_log_commands(cmds, __func__);
+
+ cmd_parse_build_commands(cmds, pi, pr);
+ if (pr->status != CMD_PARSE_SUCCESS)
+ *cmdlist = pr->cmdlist;
+ return (1);
}
-static void
-cmd_parse_flatten_command(struct cmd_parse_command *cmd)
+static struct cmd_list *
+cmd_parse_build_command(struct cmd_parse_command *cmd,
+ struct cmd_parse_input *pi, struct cmd_parse_result *pr)
{
struct cmd_parse_argument *arg;
- char *s;
+ struct cmd_list *cmdlist;
+ struct cmd *add;
+ char *s, **argv = NULL, *cause;
+ int argc = 0;
- cmd->argc = 0;
- cmd->argv = NULL;
+ if (cmd_parse_expand_alias(cmd, pi, pr, &cmdlist))
+ return (cmdlist);
TAILQ_FOREACH(arg, &cmd->arguments, entry) {
switch (arg->type) {
case CMD_PARSE_STRING:
- cmd_append_argv(&cmd->argc, &cmd->argv, arg->string);
+ cmd_append_argv(&argc, &argv, arg->string);
break;
case CMD_PARSE_COMMANDS:
- s = cmd_parse_commands_to_string(arg->commands);
- cmd_append_argv(&cmd->argc, &cmd->argv, s);
+ cmd_parse_build_commands(arg->commands, pi, pr);
+ if (pr->status != CMD_PARSE_SUCCESS)
+ return (NULL);
+ s = cmd_list_print(pr->cmdlist, 0);
+ cmd_append_argv(&argc, &argv, s);
free(s);
break;
}
}
-}
-static struct cmd *
-cmd_parse_build_command(struct cmd_parse_command *cmd,
- struct cmd_parse_input *pi, u_int line, struct cmd_parse_result *pr)
-{
- struct cmd *add;
- char *cause;
-
- add = cmd_parse(cmd->argc, cmd->argv, pi->file, line, &cause);
+ add = cmd_parse(argc, argv, pi->file, pi->line, &cause);
if (add == NULL) {
pr->status = CMD_PARSE_ERROR;
- pr->error = cmd_parse_get_error(pi->file, line, cause);
+ pr->error = cmd_parse_get_error(pi->file, pi->line, cause);
free(cause);
return (NULL);
}
- return (add);
+ cmdlist = cmd_list_new();
+ cmd_list_append(cmdlist, add);
+ return (cmdlist);
}
-static struct cmd_parse_result *
+static void
cmd_parse_build_commands(struct cmd_parse_commands *cmds,
- struct cmd_parse_input *pi)
+ struct cmd_parse_input *pi, struct cmd_parse_result *pr)
{
- static struct cmd_parse_result pr;
- struct cmd_parse_commands *cmds2;
- struct cmd_parse_command *cmd, *cmd2, *next, *next2, *after;
+ struct cmd_parse_command *cmd;
u_int line = UINT_MAX;
- int i;
- struct cmd_list *current = NULL, *result;
- struct cmd *add;
- char *name, *alias, *cause, *s;
+ struct cmd_list *current = NULL, *result, *add;
+ char *s;
/* Check for an empty list. */
if (TAILQ_EMPTY(cmds)) {
- cmd_parse_free_commands(cmds);
- pr.status = CMD_PARSE_EMPTY;
- return (&pr);
- }
-
- /* Flatten command arguments. */
- cmd_parse_log_commands(cmds, __func__);
- TAILQ_FOREACH(cmd, cmds, entry)
- cmd_parse_flatten_command(cmd);
-
- /*
- * Walk the commands and expand any aliases. Each alias is parsed
- * individually to a new command list, any trailing arguments appended
- * to the last command, and all commands inserted into the original
- * command list.
- */
- TAILQ_FOREACH_SAFE(cmd, cmds, entry, next) {
- name = cmd->argv[0];
-
- alias = cmd_get_alias(name);
- if (alias == NULL)
- continue;
-
- line = cmd->line;
- log_debug("%s: %u %s = %s", __func__, line, name, alias);
-
- pi->line = line;
- cmds2 = cmd_parse_do_buffer(alias, strlen(alias), pi, &cause);
- free(alias);
- if (cmds2 == NULL) {
- pr.status = CMD_PARSE_ERROR;
- pr.error = cause;
- goto out;
- }
-
- cmd2 = TAILQ_LAST(cmds2, cmd_parse_commands);
- if (cmd2 == NULL) {
- TAILQ_REMOVE(cmds, cmd, entry);
- cmd_parse_free_command(cmd);
- continue;
- }
- cmd_parse_flatten_command(cmd2);
- for (i = 1; i < cmd->argc; i++)
- cmd_append_argv(&cmd2->argc, &cmd2->argv, cmd->argv[i]);
-
- after = cmd;
- TAILQ_FOREACH_SAFE(cmd2, cmds2, entry, next2) {
- cmd2->line = line;
- TAILQ_REMOVE(cmds2, cmd2, entry);
- TAILQ_INSERT_AFTER(cmds, after, cmd2, entry);
- after = cmd2;
- }
- cmd_parse_free_commands(cmds2);
-
- TAILQ_REMOVE(cmds, cmd, entry);
- cmd_parse_free_command(cmd);
+ pr->status = CMD_PARSE_EMPTY;
+ return;
}
+ cmd_parse_log_commands(cmds, __func__);
/*
* Parse each command into a command list. Create a new command list
TAILQ_FOREACH(cmd, cmds, entry) {
if (((~pi->flags & CMD_PARSE_ONEGROUP) && cmd->line != line)) {
if (current != NULL) {
- cmd_parse_print_commands(pi, line, current);
+ cmd_parse_print_commands(pi, current);
cmd_list_move(result, current);
cmd_list_free(current);
}
}
if (current == NULL)
current = cmd_list_new();
- line = cmd->line;
+ line = pi->line = cmd->line;
- add = cmd_parse_build_command(cmd, pi, line, &pr);
+ add = cmd_parse_build_command(cmd, pi, pr);
if (add == NULL) {
cmd_list_free(result);
cmd_list_free(current);
- goto out;
+ return;
}
- cmd_list_append(current, add);
+ cmd_list_move(current, add);
+ cmd_list_free(add);
}
if (current != NULL) {
- cmd_parse_print_commands(pi, line, current);
+ cmd_parse_print_commands(pi, current);
cmd_list_move(result, current);
cmd_list_free(current);
}
log_debug("%s: %s", __func__, s);
free(s);
- pr.status = CMD_PARSE_SUCCESS;
- pr.cmdlist = result;
-
-out:
- cmd_parse_free_commands(cmds);
-
- return (&pr);
+ pr->status = CMD_PARSE_SUCCESS;
+ pr->cmdlist = result;
}
struct cmd_parse_result *
pr.error = cause;
return (&pr);
}
- return (cmd_parse_build_commands(cmds, pi));
+ cmd_parse_build_commands(cmds, pi, &pr);
+ cmd_parse_free_commands(cmds);
+ return (&pr);
+
}
struct cmd_parse_result *
pr.error = cause;
return (&pr);
}
- return (cmd_parse_build_commands(cmds, pi));
+ cmd_parse_build_commands(cmds, pi, &pr);
+ cmd_parse_free_commands(cmds);
+ return (&pr);
}
static void
struct cmd_parse_result *
cmd_parse_from_arguments(int argc, char **argv, struct cmd_parse_input *pi)
{
+ static struct cmd_parse_result pr;
struct cmd_parse_input input;
struct cmd_parse_commands *cmds;
char **copy, **new_argv;
}
cmd_free_argv(argc, copy);
- return (cmd_parse_build_commands(cmds, pi));
+ cmd_parse_build_commands(cmds, pi, &pr);
+ cmd_parse_free_commands(cmds);
+ return (&pr);
}
static int printflike(1, 2)