diff --git a/cmd-parse.y b/cmd-parse.y index 65979635f..9a1fce052 100644 --- a/cmd-parse.y +++ b/cmd-parse.y @@ -756,65 +756,6 @@ cmd_parse_from_arguments_add(struct cmd_parse_node *seq, TAILQ_INSERT_TAIL(&(*cmd)->children, child, entry); } -/* - * Add one argv string, splitting unescaped ; as command separators: - * - * A single ; starts another command in the same sequence. - * A double ;; starts another sequence. - * A \; is kept as a literal semicolon in the argument. - */ -static void -cmd_parse_from_argument_string(struct cmd_parse_node *root, - struct cmd_parse_node **seq, struct cmd_parse_node **cmd, const char *s) -{ - char *buf; - size_t len = 0; - struct cmd_parse_node *child; - const char *cp; - - buf = xmalloc(1); - *buf = '\0'; - - for (cp = s; *cp != '\0'; cp++) { - if (*cp == '\\' && cp[1] != '\0') { - cp++; - buf = xrealloc(buf, len + 2); - buf[len++] = *cp; - buf[len] = '\0'; - continue; - } - - if (*cp != ';') { - buf = xrealloc(buf, len + 2); - buf[len++] = *cp; - buf[len] = '\0'; - continue; - } - - if (len != 0) { - child = cmd_parse_new_string_node(buf, 0); - cmd_parse_from_arguments_add(*seq, cmd, child); - len = 0; - *buf = '\0'; - } - - if (cp[1] == ';') { - *cmd = NULL; - *seq = cmd_parse_new_node(CMD_PARSE_SEQUENCE, 0); - TAILQ_INSERT_TAIL(&root->children, *seq, entry); - cp++; - } else - *cmd = NULL; - } - - if (len != 0) { - child = cmd_parse_new_string_node(buf, 0); - cmd_parse_from_arguments_add(*seq, cmd, child); - } - - free(buf); -} - /* Build a parse tree directly from existing argument values. */ struct cmd_parse_tree * cmd_parse_from_arguments(struct args_value *values, u_int count) @@ -822,18 +763,37 @@ cmd_parse_from_arguments(struct args_value *values, u_int count) struct cmd_parse_tree *new; struct cmd_parse_node *root, *seq, *cmd = NULL, *child; u_int i; + char *copy; + size_t size; + int end; root = cmd_parse_new_node(CMD_PARSE_ROOT, 0); seq = cmd_parse_new_node(CMD_PARSE_SEQUENCE, 0); TAILQ_INSERT_TAIL(&root->children, seq, entry); for (i = 0; i < count; i++) { + end = 0; + switch (values[i].type) { case ARGS_NONE: continue; case ARGS_STRING: - cmd_parse_from_argument_string(root, &seq, &cmd, - values[i].string); + copy = xstrdup(values[i].string); + size = strlen(copy); + + if (size != 0 && copy[size - 1] == ';') { + copy[--size] = '\0'; + if (size > 0 && copy[size - 1] == '\\') + copy[size - 1] = ';'; + else + end = 1; + } + + if (!end || size != 0) { + child = cmd_parse_new_string_node(copy, 0); + cmd_parse_from_arguments_add(seq, &cmd, child); + } + free(copy); break; case ARGS_COMMANDS: child = cmd_parse_new_commands_node(values[i].cmd, 0); @@ -842,6 +802,9 @@ cmd_parse_from_arguments(struct args_value *values, u_int count) default: fatalx("unknown argument type"); } + + if (end) + cmd = NULL; } new = xcalloc(1, sizeof *new);