diff --git a/cmd-parse.y b/cmd-parse.y index f082b677..86cb357e 100644 --- a/cmd-parse.y +++ b/cmd-parse.y @@ -60,9 +60,6 @@ struct cmd_parse_command { 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); @@ -92,10 +89,10 @@ static char *cmd_parse_get_error(const char *, u_int, const char *); 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 *); %} @@ -587,19 +584,32 @@ cmd_parse_get_error(const char *file, u_int line, const char *error) } 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 @@ -608,23 +618,14 @@ cmd_parse_free_arguments(struct cmd_parse_arguments *args) 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); } @@ -729,144 +730,120 @@ cmd_parse_log_commands(struct cmd_parse_commands *cmds, const char *prefix) } } -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); - } - - free(string); - string = s; + first = TAILQ_FIRST(&cmd->arguments); + if (first == NULL || first->type != CMD_PARSE_STRING) { + pr->status = CMD_PARSE_EMPTY; + return (1); } - if (string == NULL) - string = xstrdup(""); - log_debug("%s: %s", __func__, string); - return (string); + 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); + } + + 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; + } + 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 @@ -878,7 +855,7 @@ cmd_parse_build_commands(struct cmd_parse_commands *cmds, 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); } @@ -886,18 +863,19 @@ cmd_parse_build_commands(struct cmd_parse_commands *cmds, } 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); } @@ -906,13 +884,8 @@ cmd_parse_build_commands(struct cmd_parse_commands *cmds, 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 * @@ -935,7 +908,10 @@ cmd_parse_from_file(FILE *f, struct cmd_parse_input *pi) 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 * @@ -1036,7 +1012,9 @@ cmd_parse_from_buffer(const void *buf, size_t len, struct cmd_parse_input *pi) 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 @@ -1066,6 +1044,7 @@ cmd_parse_add_command(struct cmd_parse_commands *cmds, 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; @@ -1115,7 +1094,9 @@ cmd_parse_from_arguments(int argc, char **argv, struct cmd_parse_input *pi) } 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)