summaryrefslogtreecommitdiff
path: root/usr.bin/tmux/arguments.c
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@cvs.openbsd.org>2021-08-23 12:33:56 +0000
committerNicholas Marriott <nicm@cvs.openbsd.org>2021-08-23 12:33:56 +0000
commitd287c0da367614373c8a6208989d560e3b01e3b5 (patch)
tree6ef7d3bfb4768ad81ee035f0090cd422dafd8c0a /usr.bin/tmux/arguments.c
parentcdaed1c111e42c475022866b4d29c3bc2a5f1848 (diff)
Move command argument parsing common functions and don't bother to parse
again if given a command rather than a string.
Diffstat (limited to 'usr.bin/tmux/arguments.c')
-rw-r--r--usr.bin/tmux/arguments.c139
1 files changed, 138 insertions, 1 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 <nicholas.marriott@gmail.com>
@@ -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)