From 2db6a388619f8be004243d57b5f1b15578033771 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 23 Aug 2021 12:33:55 +0000 Subject: [PATCH] Move command argument parsing common functions and don't bother to parse again if given a command rather than a string. --- usr.bin/tmux/arguments.c | 139 +++++++++++++++++++++- usr.bin/tmux/cmd-command-prompt.c | 184 +++++++++++++++--------------- usr.bin/tmux/cmd-confirm-before.c | 51 ++++----- usr.bin/tmux/cmd-display-panes.c | 40 ++++--- usr.bin/tmux/cmd-if-shell.c | 114 +++++++----------- usr.bin/tmux/cmd-run-shell.c | 55 ++++----- usr.bin/tmux/tmux.h | 11 +- 7 files changed, 339 insertions(+), 255 deletions(-) diff --git a/usr.bin/tmux/arguments.c b/usr.bin/tmux/arguments.c index f4c1e1fc4b7..1738c5cc50a 100644 --- a/usr.bin/tmux/arguments.c +++ b/usr.bin/tmux/arguments.c @@ -1,4 +1,4 @@ -/* $OpenBSD: arguments.c,v 1.44 2021/08/21 20:57:52 nicm Exp $ */ +/* $OpenBSD: arguments.c,v 1.45 2021/08/23 12:33:55 nicm Exp $ */ /* * Copyright (c) 2010 Nicholas Marriott @@ -29,8 +29,10 @@ * Manipulate command arguments. */ +/* List of argument values. */ TAILQ_HEAD(args_values, args_value); +/* Single arguments flag. */ struct args_entry { u_char flag; struct args_values values; @@ -38,12 +40,20 @@ struct args_entry { RB_ENTRY(args_entry) entry; }; +/* Parsed argument flags and values. */ struct args { struct args_tree tree; u_int count; struct args_value *values; }; +/* Prepared command state. */ +struct args_command_state { + struct cmd_list *cmdlist; + char *cmd; + struct cmd_parse_input pi; +}; + static struct args_entry *args_find(struct args *, u_char); static int args_cmp(struct args_entry *, struct args_entry *); @@ -477,6 +487,133 @@ args_string(struct args *args, u_int idx) return (args_value_as_string(&args->values[idx])); } +/* Make a command now. */ +struct cmd_list * +args_make_commands_now(struct cmd *self, struct cmdq_item *item, u_int idx) +{ + struct args_command_state *state; + char *error; + struct cmd_list *cmdlist; + + state = args_make_commands_prepare(self, item, idx, NULL, 0, 0); + cmdlist = args_make_commands(state, 0, NULL, &error); + args_make_commands_free(state); + if (cmdlist == NULL) { + cmdq_error(item, "%s", error); + free(error); + } + return (cmdlist); +} + +/* Save bits to make a command later. */ +struct args_command_state * +args_make_commands_prepare(struct cmd *self, struct cmdq_item *item, u_int idx, + const char *default_command, int wait, int expand) +{ + struct args *args = cmd_get_args(self); + struct cmd_find_state *target = cmdq_get_target(item); + struct client *tc = cmdq_get_target_client(item); + struct args_value *value; + struct args_command_state *state; + const char *cmd; + + state = xcalloc(1, sizeof *state); + + if (idx < args->count) { + value = &args->values[idx]; + if (value->type == ARGS_COMMANDS) { + state->cmdlist = value->cmdlist; + state->cmdlist->references++; + return (state); + } + cmd = value->string; + } else { + if (default_command == NULL) + fatalx("argument out of range"); + cmd = default_command; + } + + + if (expand) + state->cmd = format_single_from_target(item, cmd); + else + state->cmd = xstrdup(cmd); + log_debug("%s: %s", __func__, state->cmd); + + if (wait) + state->pi.item = item; + cmd_get_source(self, &state->pi.file, &state->pi.line); + state->pi.c = tc; + if (state->pi.c != NULL) + state->pi.c->references++; + cmd_find_copy_state(&state->pi.fs, target); + + return (state); +} + +/* Return argument as command. */ +struct cmd_list * +args_make_commands(struct args_command_state *state, int argc, char **argv, + char **error) +{ + struct cmd_parse_result *pr; + char *cmd, *new_cmd; + int i; + + if (state->cmdlist != NULL) + return (state->cmdlist); + + cmd = xstrdup(state->cmd); + for (i = 0; i < argc; i++) { + new_cmd = cmd_template_replace(cmd, argv[i], i + 1); + log_debug("%s: %%%u %s: %s", __func__, i + 1, argv[i], new_cmd); + free(cmd); + cmd = new_cmd; + } + log_debug("%s: %s", __func__, cmd); + + pr = cmd_parse_from_string(cmd, &state->pi); + free(cmd); + switch (pr->status) { + case CMD_PARSE_ERROR: + *error = pr->error; + return (NULL); + case CMD_PARSE_SUCCESS: + return (pr->cmdlist); + } +} + +/* Free commands state. */ +void +args_make_commands_free(struct args_command_state *state) +{ + if (state->cmdlist != NULL) + cmd_list_free(state->cmdlist); + if (state->pi.c != NULL) + server_client_unref(state->pi.c); + free(state->cmd); + free(state); +} + +/* Get prepared command. */ +char * +args_make_commands_get_command(struct args_command_state *state) +{ + struct cmd *first; + int n; + char *s; + + if (state->cmdlist != NULL) { + first = cmd_list_first(state->cmdlist); + if (first == NULL) + return (xstrdup("")); + return (xstrdup(cmd_get_entry(first)->name)); + } + n = strcspn(state->cmd, " ,"); + xasprintf(&s, "%.*s", n, state->cmd); + return (s); +} + /* Get first value in argument. */ struct args_value * args_first_value(struct args *args, u_char flag) diff --git a/usr.bin/tmux/cmd-command-prompt.c b/usr.bin/tmux/cmd-command-prompt.c index e65974e46e7..5f3930e7fb7 100644 --- a/usr.bin/tmux/cmd-command-prompt.c +++ b/usr.bin/tmux/cmd-command-prompt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-command-prompt.c,v 1.59 2021/08/21 10:22:38 nicm Exp $ */ +/* $OpenBSD: cmd-command-prompt.c,v 1.60 2021/08/23 12:33:55 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -48,21 +48,24 @@ const struct cmd_entry cmd_command_prompt_entry = { .exec = cmd_command_prompt_exec }; -struct cmd_command_prompt_cdata { - struct cmdq_item *item; - struct cmd_parse_input pi; +struct cmd_command_prompt_prompt { + char *input; + char *prompt; +}; - int flags; - enum prompt_type prompt_type; +struct cmd_command_prompt_cdata { + struct cmdq_item *item; + struct args_command_state *state; - char *inputs; - char *next_input; + int flags; + enum prompt_type prompt_type; - char *prompts; - char *next_prompt; + struct cmd_command_prompt_prompt *prompts; + u_int count; + u_int current; - char *template; - int idx; + int argc; + char **argv; }; static enum cmd_retval @@ -71,12 +74,12 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item) struct args *args = cmd_get_args(self); struct client *tc = cmdq_get_target_client(item); struct cmd_find_state *target = cmdq_get_target(item); - const char *inputs, *prompts, *type, *s; + const char *type, *s, *input; struct cmd_command_prompt_cdata *cdata; - char *prompt, *comma, *input = NULL; + char *tmp, *prompts, *prompt, *next_prompt; + char *inputs, *next_input; u_int count = args_count(args); - size_t n; - int wait = !args_has(args, 'b'); + int wait = !args_has(args, 'b'), space = 1; if (tc->prompt_string != NULL) return (CMD_RETURN_NORMAL); @@ -84,50 +87,49 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item) wait = 0; cdata = xcalloc(1, sizeof *cdata); - cdata->idx = 1; - - cmd_get_source(self, &cdata->pi.file, &cdata->pi.line); - if (wait) - cdata->pi.item = item; - cdata->pi.c = tc; - cmd_find_copy_state(&cdata->pi.fs, target); - if (wait) cdata->item = item; - - if (count != 0) { - s = args_string(args, 0); - if (args_has(args, 'F')) - cdata->template = format_single_from_target(item, s); - else - cdata->template = xstrdup(s); - } else - cdata->template = xstrdup("%1"); - - if ((prompts = args_get(args, 'p')) != NULL) - cdata->prompts = xstrdup(prompts); - else if (count != 0) { - n = strcspn(cdata->template, " ,"); - xasprintf(&cdata->prompts, "(%.*s) ", (int)n, cdata->template); + cdata->state = args_make_commands_prepare(self, item, 0, "%1", wait, + args_has(args, 'F')); + + if ((s = args_get(args, 'p')) == NULL) { + if (count != 0) { + tmp = args_make_commands_get_command(cdata->state); + xasprintf(&prompts, "(%s)", tmp); + free(tmp); + } else { + prompts = xstrdup(":"); + space = 0; + } + next_prompt = prompts; } else - cdata->prompts = xstrdup(":"); - - /* Get first prompt. */ - cdata->next_prompt = cdata->prompts; - comma = strsep(&cdata->next_prompt, ","); - if (prompts == NULL) - prompt = xstrdup(comma); + next_prompt = prompts = xstrdup (s); + if ((s = args_get(args, 'I')) != NULL) + next_input = inputs = xstrdup(s); else - xasprintf(&prompt, "%s ", comma); - - /* Get initial prompt input. */ - if ((inputs = args_get(args, 'I')) != NULL) { - cdata->inputs = xstrdup(inputs); - cdata->next_input = cdata->inputs; - input = strsep(&cdata->next_input, ","); + next_input = NULL; + while ((prompt = strsep(&next_prompt, ",")) != NULL) { + cdata->prompts = xreallocarray(cdata->prompts, cdata->count + 1, + sizeof *cdata->prompts); + if (!space) + tmp = xstrdup(prompt); + else + xasprintf(&tmp, "%s ", prompt); + cdata->prompts[cdata->count].prompt = tmp; + + if (next_input != NULL) { + input = strsep(&next_input, ","); + if (input == NULL) + input = ""; + } else + input = ""; + cdata->prompts[cdata->count].input = xstrdup(input); + + cdata->count++; } + free(inputs); + free(prompts); - /* Get prompt type. */ if ((type = args_get(args, 'T')) != NULL) { cdata->prompt_type = status_prompt_type(type); if (cdata->prompt_type == PROMPT_TYPE_INVALID) { @@ -145,10 +147,9 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item) cdata->flags |= PROMPT_INCREMENTAL; else if (args_has(args, 'k')) cdata->flags |= PROMPT_KEY; - status_prompt_set(tc, target, prompt, input, - cmd_command_prompt_callback, cmd_command_prompt_free, cdata, - cdata->flags, cdata->prompt_type); - free(prompt); + status_prompt_set(tc, target, cdata->prompts[0].prompt, + cdata->prompts[0].input, cmd_command_prompt_callback, + cmd_command_prompt_free, cdata, cdata->flags, cdata->prompt_type); if (!wait) return (CMD_RETURN_NORMAL); @@ -159,51 +160,39 @@ static int cmd_command_prompt_callback(struct client *c, void *data, const char *s, int done) { - struct cmd_command_prompt_cdata *cdata = data; - char *new_template, *prompt, *comma, *error; - char *input = NULL; - struct cmdq_item *item = cdata->item; - enum cmd_parse_status status; + struct cmd_command_prompt_cdata *cdata = data; + char *error; + struct cmdq_item *item = cdata->item, *new_item; + struct cmd_list *cmdlist; + struct cmd_command_prompt_prompt *prompt; if (s == NULL) goto out; - if (done && (cdata->flags & PROMPT_INCREMENTAL)) - goto out; - - new_template = cmd_template_replace(cdata->template, s, cdata->idx); if (done) { - free(cdata->template); - cdata->template = new_template; - } - - /* - * Check if there are more prompts; if so, get its respective input - * and update the prompt data. - */ - if (done && (comma = strsep(&cdata->next_prompt, ",")) != NULL) { - xasprintf(&prompt, "%s ", comma); - input = strsep(&cdata->next_input, ","); - status_prompt_update(c, prompt, input); - - free(prompt); - cdata->idx++; - return (1); + if (cdata->flags & PROMPT_INCREMENTAL) + goto out; + + cmd_append_argv(&cdata->argc, &cdata->argv, s); + if (++cdata->current != cdata->count) { + prompt = &cdata->prompts[cdata->current]; + status_prompt_update(c, prompt->prompt, prompt->input); + return (1); + } } - if (item != NULL) { - status = cmd_parse_and_insert(new_template, &cdata->pi, item, - cmdq_get_state(item), &error); - } else { - status = cmd_parse_and_append(new_template, &cdata->pi, c, NULL, - &error); - } - if (status == CMD_PARSE_ERROR) { + cmdlist = args_make_commands(cdata->state, cdata->argc, cdata->argv, + &error); + if (cmdlist == NULL) { cmdq_append(c, cmdq_get_error(error)); free(error); + } else if (item == NULL) { + new_item = cmdq_get_command(cmdlist, NULL); + cmdq_append(c, new_item); + } else { + new_item = cmdq_get_command(cmdlist, cmdq_get_state(item)); + cmdq_insert_after(item, new_item); } - if (!done) - free(new_template); if (c->prompt_inputcb != cmd_command_prompt_callback) return (1); @@ -217,9 +206,14 @@ static void cmd_command_prompt_free(void *data) { struct cmd_command_prompt_cdata *cdata = data; + u_int i; - free(cdata->inputs); + for (i = 0; i < cdata->count; i++) { + free(cdata->prompts[i].prompt); + free(cdata->prompts[i].input); + } free(cdata->prompts); - free(cdata->template); + cmd_free_argv(cdata->argc, cdata->argv); + args_make_commands_free(cdata->state); free(cdata); } diff --git a/usr.bin/tmux/cmd-confirm-before.c b/usr.bin/tmux/cmd-confirm-before.c index b87e3c1c153..7f2fd8c1066 100644 --- a/usr.bin/tmux/cmd-confirm-before.c +++ b/usr.bin/tmux/cmd-confirm-before.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-confirm-before.c,v 1.48 2021/08/21 10:22:38 nicm Exp $ */ +/* $OpenBSD: cmd-confirm-before.c,v 1.49 2021/08/23 12:33:55 nicm Exp $ */ /* * Copyright (c) 2009 Tiago Cunha @@ -47,9 +47,8 @@ const struct cmd_entry cmd_confirm_before_entry = { }; struct cmd_confirm_before_data { - char *cmd; struct cmdq_item *item; - struct cmd_parse_input pi; + struct cmd_list *cmdlist; }; static enum cmd_retval @@ -59,31 +58,25 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item) struct cmd_confirm_before_data *cdata; struct client *tc = cmdq_get_target_client(item); struct cmd_find_state *target = cmdq_get_target(item); - char *cmd, *copy, *new_prompt, *tmp; - const char *prompt; + char *new_prompt; + const char *prompt, *cmd; int wait = !args_has(args, 'b'); cdata = xcalloc(1, sizeof *cdata); - cdata->cmd = xstrdup(args_string(args, 0)); + cdata->cmdlist = args_make_commands_now(self, item, 0); + if (cdata->cmdlist == NULL) + return (CMD_RETURN_ERROR); + + if (wait) + cdata->item = item; if ((prompt = args_get(args, 'p')) != NULL) xasprintf(&new_prompt, "%s ", prompt); else { - tmp = copy = xstrdup(cdata->cmd); - cmd = strsep(&tmp, " \t"); + cmd = cmd_get_entry(cmd_list_first(cdata->cmdlist))->name; xasprintf(&new_prompt, "Confirm '%s'? (y/n) ", cmd); - free(copy); } - cmd_get_source(self, &cdata->pi.file, &cdata->pi.line); - if (wait) - cdata->pi.item = item; - cdata->pi.c = tc; - cmd_find_copy_state(&cdata->pi.fs, target); - - if (wait) - cdata->item = item; - status_prompt_set(tc, target, new_prompt, NULL, cmd_confirm_before_callback, cmd_confirm_before_free, cdata, PROMPT_SINGLE, PROMPT_TYPE_COMMAND); @@ -99,10 +92,7 @@ cmd_confirm_before_callback(struct client *c, void *data, const char *s, __unused int done) { struct cmd_confirm_before_data *cdata = data; - const char *cmd = cdata->cmd; - char *error; - struct cmdq_item *item = cdata->item; - enum cmd_parse_status status; + struct cmdq_item *item = cdata->item, *new_item; int retcode = 1; if (c->flags & CLIENT_DEAD) @@ -114,14 +104,13 @@ cmd_confirm_before_callback(struct client *c, void *data, const char *s, goto out; retcode = 0; - if (item != NULL) { - status = cmd_parse_and_insert(cmd, &cdata->pi, item, - cmdq_get_state(item), &error); - } else - status = cmd_parse_and_append(cmd, &cdata->pi, c, NULL, &error); - if (status == CMD_PARSE_ERROR) { - cmdq_append(c, cmdq_get_error(error)); - free(error); + if (item == NULL) { + new_item = cmdq_get_command(cdata->cmdlist, NULL); + cmdq_append(c, new_item); + } else { + new_item = cmdq_get_command(cdata->cmdlist, + cmdq_get_state(item)); + cmdq_insert_after(item, new_item); } out: @@ -139,6 +128,6 @@ cmd_confirm_before_free(void *data) { struct cmd_confirm_before_data *cdata = data; - free(cdata->cmd); + cmd_list_free(cdata->cmdlist); free(cdata); } diff --git a/usr.bin/tmux/cmd-display-panes.c b/usr.bin/tmux/cmd-display-panes.c index 729b908f161..9906debd5bd 100644 --- a/usr.bin/tmux/cmd-display-panes.c +++ b/usr.bin/tmux/cmd-display-panes.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-display-panes.c,v 1.42 2021/08/21 10:22:39 nicm Exp $ */ +/* $OpenBSD: cmd-display-panes.c,v 1.43 2021/08/23 12:33:55 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -42,8 +42,8 @@ const struct cmd_entry cmd_display_panes_entry = { }; struct cmd_display_panes_data { - struct cmdq_item *item; - char *command; + struct cmdq_item *item; + struct args_command_state *state; }; static void @@ -207,7 +207,7 @@ cmd_display_panes_free(__unused struct client *c, void *data) if (cdata->item != NULL) cmdq_continue(cdata->item); - free(cdata->command); + args_make_commands_free(cdata->state); free(cdata); } @@ -215,10 +215,11 @@ static int cmd_display_panes_key(struct client *c, void *data, struct key_event *event) { struct cmd_display_panes_data *cdata = data; - char *cmd, *expanded, *error; + char *expanded, *error; + struct cmdq_item *item = cdata->item, *new_item; + struct cmd_list *cmdlist; struct window *w = c->session->curw->window; struct window_pane *wp; - enum cmd_parse_status status; u_int index; key_code key; @@ -239,15 +240,19 @@ cmd_display_panes_key(struct client *c, void *data, struct key_event *event) window_unzoom(w); xasprintf(&expanded, "%%%u", wp->id); - cmd = cmd_template_replace(cdata->command, expanded, 1); - status = cmd_parse_and_append(cmd, NULL, c, NULL, &error); - if (status == CMD_PARSE_ERROR) { + cmdlist = args_make_commands(cdata->state, 1, &expanded, &error); + if (cmdlist == NULL) { cmdq_append(c, cmdq_get_error(error)); free(error); + } else if (item == NULL) { + new_item = cmdq_get_command(cmdlist, NULL); + cmdq_append(c, new_item); + } else { + new_item = cmdq_get_command(cmdlist, cmdq_get_state(item)); + cmdq_insert_after(item, new_item); } - free(cmd); free(expanded); return (1); } @@ -261,6 +266,7 @@ cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item) u_int delay; char *cause; struct cmd_display_panes_data *cdata; + int wait = !args_has(args, 'b'); if (tc->overlay_draw != NULL) return (CMD_RETURN_NORMAL); @@ -275,15 +281,11 @@ cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item) } else delay = options_get_number(s->options, "display-panes-time"); - cdata = xmalloc(sizeof *cdata); - if (args_count(args)) - cdata->command = xstrdup(args_string(args, 0)); - else - cdata->command = xstrdup("select-pane -t '%%'"); - if (args_has(args, 'b')) - cdata->item = NULL; - else + cdata = xcalloc(1, sizeof *cdata); + if (wait) cdata->item = item; + cdata->state = args_make_commands_prepare(self, item, 0, + "select-pane -t \"%%%\"", wait, 0); if (args_has(args, 'N')) { server_client_set_overlay(tc, delay, NULL, NULL, @@ -295,7 +297,7 @@ cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item) cmd_display_panes_free, NULL, cdata); } - if (args_has(args, 'b')) + if (!wait) return (CMD_RETURN_NORMAL); return (CMD_RETURN_WAIT); } diff --git a/usr.bin/tmux/cmd-if-shell.c b/usr.bin/tmux/cmd-if-shell.c index 60832901cb4..54f239f5cb9 100644 --- a/usr.bin/tmux/cmd-if-shell.c +++ b/usr.bin/tmux/cmd-if-shell.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-if-shell.c,v 1.79 2021/08/21 17:25:32 nicm Exp $ */ +/* $OpenBSD: cmd-if-shell.c,v 1.80 2021/08/23 12:33:55 nicm Exp $ */ /* * Copyright (c) 2009 Tiago Cunha @@ -31,8 +31,8 @@ static enum cmd_retval cmd_if_shell_exec(struct cmd *, struct cmdq_item *); -static void cmd_if_shell_callback(struct job *); -static void cmd_if_shell_free(void *); +static void cmd_if_shell_callback(struct job *); +static void cmd_if_shell_free(void *); const struct cmd_entry cmd_if_shell_entry = { .name = "if-shell", @@ -49,10 +49,8 @@ const struct cmd_entry cmd_if_shell_entry = { }; struct cmd_if_shell_data { - struct cmd_parse_input input; - - char *cmd_if; - char *cmd_else; + struct cmd_list *cmd_if; + struct cmd_list *cmd_else; struct client *client; struct cmdq_item *item; @@ -63,46 +61,42 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item) { struct args *args = cmd_get_args(self); struct cmd_find_state *target = cmdq_get_target(item); - struct cmdq_state *state = cmdq_get_state(item); struct cmd_if_shell_data *cdata; - char *shellcmd, *error; - const char *cmd = NULL, *file; + struct cmdq_item *new_item; + char *shellcmd; struct client *tc = cmdq_get_target_client(item); struct session *s = target->s; - struct cmd_parse_input pi; - enum cmd_parse_status status; + struct cmd_list *cmdlist = NULL; u_int count = args_count(args); shellcmd = format_single_from_target(item, args_string(args, 0)); if (args_has(args, 'F')) { if (*shellcmd != '0' && *shellcmd != '\0') - cmd = args_string(args, 1); + cmdlist = args_make_commands_now(self, item, 1); else if (count == 3) - cmd = args_string(args, 2); - free(shellcmd); - if (cmd == NULL) + cmdlist = args_make_commands_now(self, item, 2); + else { + free(shellcmd); return (CMD_RETURN_NORMAL); - - memset(&pi, 0, sizeof pi); - cmd_get_source(self, &pi.file, &pi.line); - pi.item = item; - pi.c = tc; - cmd_find_copy_state(&pi.fs, target); - - status = cmd_parse_and_insert(cmd, &pi, item, state, &error); - if (status == CMD_PARSE_ERROR) { - cmdq_error(item, "%s", error); - free(error); - return (CMD_RETURN_ERROR); } + free(shellcmd); + if (cmdlist == NULL) + return (CMD_RETURN_ERROR); + new_item = cmdq_get_command(cmdlist, cmdq_get_state(item)); + cmdq_insert_after(item, new_item); return (CMD_RETURN_NORMAL); } cdata = xcalloc(1, sizeof *cdata); - cdata->cmd_if = xstrdup(args_string(args, 1)); - if (count == 3) - cdata->cmd_else = xstrdup(args_string(args, 2)); + cdata->cmd_if = args_make_commands_now(self, item, 1); + if (cdata->cmd_if == NULL) + return (CMD_RETURN_ERROR); + if (count == 3) { + cdata->cmd_else = args_make_commands_now(self, item, 2); + if (cdata->cmd_else == NULL) + return (CMD_RETURN_ERROR); + } if (!args_has(args, 'b')) cdata->client = cmdq_get_client(item); @@ -114,14 +108,6 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item) if (!args_has(args, 'b')) cdata->item = item; - cmd_get_source(self, &file, &cdata->input.line); - if (file != NULL) - cdata->input.file = xstrdup(file); - cdata->input.c = tc; - if (cdata->input.c != NULL) - cdata->input.c->references++; - cmd_find_copy_state(&cdata->input.fs, target); - if (job_run(shellcmd, 0, NULL, s, server_client_get_cwd(cmdq_get_client(item), s), NULL, cmd_if_shell_callback, cmd_if_shell_free, cdata, 0, -1, @@ -143,43 +129,24 @@ cmd_if_shell_callback(struct job *job) { struct cmd_if_shell_data *cdata = job_get_data(job); struct client *c = cdata->client; - struct cmdq_item *new_item = NULL; - struct cmdq_state *new_state = NULL; - char *cmd; + struct cmdq_item *item = cdata->item, *new_item; + struct cmd_list *cmdlist; int status; - struct cmd_parse_result *pr; status = job_get_status(job); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) - cmd = cdata->cmd_else; + cmdlist = cdata->cmd_else; else - cmd = cdata->cmd_if; - if (cmd == NULL) + cmdlist = cdata->cmd_if; + if (cmdlist == NULL) goto out; - pr = cmd_parse_from_string(cmd, &cdata->input); - switch (pr->status) { - case CMD_PARSE_ERROR: - if (cdata->item != NULL) - cmdq_error(cdata->item, "%s", pr->error); - free(pr->error); - break; - case CMD_PARSE_SUCCESS: - if (cdata->item == NULL) - new_state = cmdq_new_state(NULL, NULL, 0); - else - new_state = cmdq_get_state(cdata->item); - new_item = cmdq_get_command(pr->cmdlist, new_state); - if (cdata->item == NULL) - cmdq_free_state(new_state); - cmd_list_free(pr->cmdlist); - break; - } - if (new_item != NULL) { - if (cdata->item == NULL) - cmdq_append(c, new_item); - else - cmdq_insert_after(cdata->item, new_item); + if (item == NULL) { + new_item = cmdq_get_command(cmdlist, NULL); + cmdq_append(c, new_item); + } else { + new_item = cmdq_get_command(cmdlist, cmdq_get_state(item)); + cmdq_insert_after(item, new_item); } out: @@ -195,12 +162,9 @@ cmd_if_shell_free(void *data) if (cdata->client != NULL) server_client_unref(cdata->client); - free(cdata->cmd_else); - free(cdata->cmd_if); - - if (cdata->input.c != NULL) - server_client_unref(cdata->input.c); - free((void *)cdata->input.file); + if (cdata->cmd_else != NULL) + cmd_list_free(cdata->cmd_else); + cmd_list_free(cdata->cmd_if); free(cdata); } diff --git a/usr.bin/tmux/cmd-run-shell.c b/usr.bin/tmux/cmd-run-shell.c index c533b28bdff..35c98d4dc2d 100644 --- a/usr.bin/tmux/cmd-run-shell.c +++ b/usr.bin/tmux/cmd-run-shell.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-run-shell.c,v 1.76 2021/08/21 10:22:39 nicm Exp $ */ +/* $OpenBSD: cmd-run-shell.c,v 1.77 2021/08/23 12:33:55 nicm Exp $ */ /* * Copyright (c) 2009 Tiago Cunha @@ -53,14 +53,13 @@ const struct cmd_entry cmd_run_shell_entry = { struct cmd_run_shell_data { struct client *client; char *cmd; - int shell; + struct cmd_list *cmdlist; char *cwd; struct cmdq_item *item; struct session *s; int wp_id; struct event timer; int flags; - struct cmd_parse_input pi; }; static void @@ -100,11 +99,10 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item) struct client *tc = cmdq_get_target_client(item); struct session *s = target->s; struct window_pane *wp = target->wp; - const char *delay; + const char *delay, *cmd; double d; struct timeval tv; char *end; - const char *cmd = args_string(args, 0); int wait = !args_has(args, 'b'); if ((delay = args_get(args, 'd')) != NULL) { @@ -117,16 +115,14 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item) return (CMD_RETURN_NORMAL); cdata = xcalloc(1, sizeof *cdata); - if (cmd != NULL) - cdata->cmd = format_single_from_target(item, cmd); - - cdata->shell = !args_has(args, 'C'); - if (!cdata->shell) { - cmd_get_source(self, &cdata->pi.file, &cdata->pi.line); - if (wait) - cdata->pi.item = item; - cdata->pi.c = tc; - cmd_find_copy_state(&cdata->pi.fs, target); + if (!args_has(args, 'C')) { + cmd = args_string(args, 0); + if (cmd != NULL) + cdata->cmd = format_single_from_target(item, cmd); + } else { + cdata->cmdlist = args_make_commands_now(self, item, 0); + if (cdata->cmdlist == NULL) + return (CMD_RETURN_ERROR); } if (args_has(args, 't') && wp != NULL) @@ -170,11 +166,9 @@ cmd_run_shell_timer(__unused int fd, __unused short events, void* arg) struct cmd_run_shell_data *cdata = arg; struct client *c = cdata->client; const char *cmd = cdata->cmd; - char *error; - struct cmdq_item *item = cdata->item; - enum cmd_parse_status status; + struct cmdq_item *item = cdata->item, *new_item; - if (cmd != NULL && cdata->shell) { + if (cdata->cmdlist == NULL && cmd != NULL) { if (job_run(cmd, 0, NULL, cdata->s, cdata->cwd, NULL, cmd_run_shell_callback, cmd_run_shell_free, cdata, cdata->flags, -1, -1) == NULL) @@ -182,21 +176,14 @@ cmd_run_shell_timer(__unused int fd, __unused short events, void* arg) return; } - if (cmd != NULL) { - if (item != NULL) { - status = cmd_parse_and_insert(cmd, &cdata->pi, item, - cmdq_get_state(item), &error); + if (cdata->cmdlist != NULL) { + if (item == NULL) { + new_item = cmdq_get_command(cdata->cmdlist, NULL); + cmdq_append(c, new_item); } else { - status = cmd_parse_and_append(cmd, &cdata->pi, c, NULL, - &error); - } - if (status == CMD_PARSE_ERROR) { - if (cdata->item == NULL) { - *error = toupper((u_char)*error); - status_message_set(c, -1, 1, 0, "%s", error); - } else - cmdq_error(cdata->item, "%s", error); - free(error); + new_item = cmdq_get_command(cdata->cmdlist, + cmdq_get_state(item)); + cmdq_insert_after(item, new_item); } } @@ -265,6 +252,8 @@ cmd_run_shell_free(void *data) session_remove_ref(cdata->s, __func__); if (cdata->client != NULL) server_client_unref(cdata->client); + if (cdata->cmdlist != NULL) + cmd_list_free(cdata->cmdlist); free(cdata->cwd); free(cdata->cmd); free(cdata); diff --git a/usr.bin/tmux/tmux.h b/usr.bin/tmux/tmux.h index 2d8881234d0..92587f21e54 100644 --- a/usr.bin/tmux/tmux.h +++ b/usr.bin/tmux/tmux.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tmux.h,v 1.1134 2021/08/21 20:46:43 nicm Exp $ */ +/* $OpenBSD: tmux.h,v 1.1135 2021/08/23 12:33:55 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -37,6 +37,7 @@ extern char **environ; struct args; +struct args_command_state; struct client; struct cmd; struct cmd_find_state; @@ -2213,6 +2214,14 @@ u_char args_next(struct args_entry **); u_int args_count(struct args *); struct args_value *args_value(struct args *, u_int); const char *args_string(struct args *, u_int); +struct cmd_list *args_make_commands_now(struct cmd *, struct cmdq_item *, + u_int); +struct args_command_state *args_make_commands_prepare(struct cmd *, + struct cmdq_item *, u_int, const char *, int, int); +struct cmd_list *args_make_commands(struct args_command_state *, int, char **, + char **); +void args_make_commands_free(struct args_command_state *); +char *args_make_commands_get_command(struct args_command_state *); struct args_value *args_first_value(struct args *, u_char); struct args_value *args_next_value(struct args_value *); long long args_strtonum(struct args *, u_char, long long, long long, -- 2.20.1