Skip to content

Commit

Permalink
Replace %% in command lists (by copying them) for template arguments ,
Browse files Browse the repository at this point in the history
this means they can be used with {} as well. Also make argument
processing from an existing vector preserve commands. GitHub issue 2858.
  • Loading branch information
nicm committed Aug 27, 2021
1 parent fd756a1 commit daec63e
Show file tree
Hide file tree
Showing 16 changed files with 324 additions and 150 deletions.
115 changes: 103 additions & 12 deletions arguments.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ args_parse(const struct args_parse *parse, struct args_value *values,
}
argument = *++found;
if (argument != ':') {
log_debug("%s: add -%c", __func__, flag);
log_debug("%s: -%c", __func__, flag);
args_set(args, flag, NULL);
continue;
}
Expand All @@ -192,7 +192,7 @@ args_parse(const struct args_parse *parse, struct args_value *values,
args_copy_value(new, &values[i++]);
}
s = args_value_as_string(new);
log_debug("%s: add -%c = %s", __func__, flag, s);
log_debug("%s: -%c = %s", __func__, flag, s);
args_set(args, flag, new);
break;
}
Expand All @@ -203,7 +203,8 @@ args_parse(const struct args_parse *parse, struct args_value *values,
value = &values[i];

s = args_value_as_string(value);
log_debug("%s: %u = %s", __func__, i, s);
log_debug("%s: %u = %s (type %d)", __func__, i, s,
value->type);

if (parse->cb != NULL) {
type = parse->cb(args, args->count, cause);
Expand Down Expand Up @@ -265,6 +266,63 @@ args_parse(const struct args_parse *parse, struct args_value *values,
return (args);
}

/* Copy and expand a value. */
static void
args_copy_copy_value(struct args_value *to, struct args_value *from, int argc,
char **argv)
{
char *s, *expanded;
int i;

to->type = from->type;
switch (from->type) {
case ARGS_NONE:
break;
case ARGS_STRING:
expanded = xstrdup(from->string);
for (i = 0; i < argc; i++) {
s = cmd_template_replace(expanded, argv[i], i + 1);
free(expanded);
expanded = s;
}
to->string = expanded;
break;
case ARGS_COMMANDS:
to->cmdlist = cmd_list_copy(from->cmdlist, argc, argv);
break;
}
}

/* Copy an arguments set. */
struct args *
args_copy(struct args *args, int argc, char **argv)
{
struct args *new_args;
struct args_entry *entry;
struct args_value *value, *new_value;
u_int i;

new_args = args_create();
RB_FOREACH(entry, args_tree, &args->tree) {
if (entry->count == 1) {
args_set(new_args, entry->flag, NULL);
continue;
}
TAILQ_FOREACH(value, &entry->values, entry) {
new_value = xcalloc(1, sizeof *new_value);
args_copy_copy_value(new_value, value, argc, argv);
args_set(new_args, entry->flag, new_value);
}
}
new_args->count = args->count;
new_args->values = xcalloc(args->count, sizeof *new_args->values);
for (i = 0; i < args->count; i++) {
new_value = &new_args->values[i];
args_copy_copy_value(new_value, &args->values[i], argc, argv);
}
return (new_args);
}

/* Free a value. */
void
args_free_value(struct args_value *value)
Expand All @@ -282,6 +340,16 @@ args_free_value(struct args_value *value)
free(value->cached);
}

/* Free values. */
void
args_free_values(struct args_value *values, u_int count)
{
u_int i;

for (i = 0; i < count; i++)
args_free_value(&values[i]);
}

/* Free an arguments set. */
void
args_free(struct args *args)
Expand All @@ -290,10 +358,8 @@ args_free(struct args *args)
struct args_entry *entry1;
struct args_value *value;
struct args_value *value1;
u_int i;

for (i = 0; i < args->count; i++)
args_free_value(&args->values[i]);
args_free_values(args->values, args->count);
free(args->values);

RB_FOREACH_SAFE(entry, args_tree, &args->tree, entry1) {
Expand All @@ -311,7 +377,7 @@ args_free(struct args *args)

/* Convert arguments to vector. */
void
args_vector(struct args *args, int *argc, char ***argv)
args_to_vector(struct args *args, int *argc, char ***argv)
{
char *s;
u_int i;
Expand All @@ -335,6 +401,21 @@ args_vector(struct args *args, int *argc, char ***argv)
}
}

/* Convert arguments from vector. */
struct args_value *
args_from_vector(int argc, char **argv)
{
struct args_value *values;
int i;

values = xcalloc(argc, sizeof *values);
for (i = 0; i < argc; i++) {
values[i].type = ARGS_STRING;
values[i].string = xstrdup(argv[i]);
}
return (values);
}

/* Add to string. */
static void printflike(3, 4)
args_print_add(char **buf, size_t *len, const char *fmt, ...)
Expand Down Expand Up @@ -424,7 +505,7 @@ args_print(struct args *args)
char *
args_escape(const char *s)
{
static const char dquoted[] = " #';${}";
static const char dquoted[] = " #';${}%";
static const char squoted[] = " \"";
char *escaped, *result;
int flags, quotes = 0;
Expand Down Expand Up @@ -538,6 +619,13 @@ args_count(struct args *args)
return (args->count);
}

/* Get argument values. */
struct args_value *
args_values(struct args *args)
{
return (args->values);
}

/* Get argument value. */
struct args_value *
args_value(struct args *args, u_int idx)
Expand Down Expand Up @@ -570,8 +658,8 @@ args_make_commands_now(struct cmd *self, struct cmdq_item *item, u_int idx)
cmdq_error(item, "%s", error);
free(error);
}
else
cmdlist->references++;
else
cmdlist->references++;
args_make_commands_free(state);
return (cmdlist);
}
Expand Down Expand Up @@ -631,8 +719,11 @@ args_make_commands(struct args_command_state *state, int argc, char **argv,
char *cmd, *new_cmd;
int i;

if (state->cmdlist != NULL)
return (state->cmdlist);
if (state->cmdlist != NULL) {
if (argc == 0)
return (state->cmdlist);
return (cmd_list_copy(state->cmdlist, argc, argv));
}

cmd = xstrdup(state->cmd);
for (i = 0; i < argc; i++) {
Expand Down
12 changes: 8 additions & 4 deletions client.c
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
ssize_t linelen;
char *line = NULL, **caps = NULL, *cause;
u_int ncaps = 0;
struct args_value *values;

/* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */
signal(SIGCHLD, SIG_IGN);
Expand All @@ -259,17 +260,20 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
msg = MSG_COMMAND;

/*
* It sucks parsing the command string twice (in client and
* later in server) but it is necessary to get the start server
* flag.
* It's annoying parsing the command string twice (in client
* and later in server) but it is necessary to get the start
* server flag.
*/
pr = cmd_parse_from_arguments(argc, argv, NULL);
values = args_from_vector(argc, argv);
pr = cmd_parse_from_arguments(values, argc, NULL);
if (pr->status == CMD_PARSE_SUCCESS) {
if (cmd_list_any_have(pr->cmdlist, CMD_STARTSERVER))
flags |= CLIENT_STARTSERVER;
cmd_list_free(pr->cmdlist);
} else
free(pr->error);
args_free_values(values, argc);
free(values);
}

/* Create client process structure (starts logging). */
Expand Down
8 changes: 3 additions & 5 deletions cmd-bind-key.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@ cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
key_code key;
const char *tablename, *note = args_get(args, 'N');
struct cmd_parse_result *pr;
char **argv;
int argc, repeat;
int repeat;
struct args_value *value;
u_int count = args_count(args);

Expand Down Expand Up @@ -92,9 +91,8 @@ cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
if (count == 2)
pr = cmd_parse_from_string(args_string(args, 1), NULL);
else {
args_vector(args, &argc, &argv);
pr = cmd_parse_from_arguments(argc - 1, argv + 1, NULL);
cmd_free_argv(argc, argv);
pr = cmd_parse_from_arguments(args_values(args) + 1, count - 1,
NULL);
}
switch (pr->status) {
case CMD_PARSE_ERROR:
Expand Down
18 changes: 14 additions & 4 deletions cmd-choose-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,16 @@
* Enter a mode.
*/

static enum cmd_retval cmd_choose_tree_exec(struct cmd *, struct cmdq_item *);
static enum args_parse_type cmd_choose_tree_args_parse(struct args *args,
u_int idx, char **cause);
static enum cmd_retval cmd_choose_tree_exec(struct cmd *,
struct cmdq_item *);

const struct cmd_entry cmd_choose_tree_entry = {
.name = "choose-tree",
.alias = NULL,

.args = { "F:f:GK:NO:rst:wZ", 0, 1, NULL },
.args = { "F:f:GK:NO:rst:wZ", 0, 1, cmd_choose_tree_args_parse },
.usage = "[-GNrswZ] [-F format] [-f filter] [-K key-format] "
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",

Expand All @@ -44,7 +47,7 @@ const struct cmd_entry cmd_choose_client_entry = {
.name = "choose-client",
.alias = NULL,

.args = { "F:f:K:NO:rt:Z", 0, 1, NULL },
.args = { "F:f:K:NO:rt:Z", 0, 1, cmd_choose_tree_args_parse },
.usage = "[-NrZ] [-F format] [-f filter] [-K key-format] "
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",

Expand All @@ -58,7 +61,7 @@ const struct cmd_entry cmd_choose_buffer_entry = {
.name = "choose-buffer",
.alias = NULL,

.args = { "F:f:K:NO:rt:Z", 0, 1, NULL },
.args = { "F:f:K:NO:rt:Z", 0, 1, cmd_choose_tree_args_parse },
.usage = "[-NrZ] [-F format] [-f filter] [-K key-format] "
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",

Expand All @@ -81,6 +84,13 @@ const struct cmd_entry cmd_customize_mode_entry = {
.exec = cmd_choose_tree_exec
};

static enum args_parse_type
cmd_choose_tree_args_parse(__unused struct args *args, __unused u_int idx,
__unused char **cause)
{
return (ARGS_PARSE_COMMANDS_OR_STRING);
}

static enum cmd_retval
cmd_choose_tree_exec(struct cmd *self, struct cmdq_item *item)
{
Expand Down
25 changes: 17 additions & 8 deletions cmd-command-prompt.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,28 +169,36 @@ static int
cmd_command_prompt_callback(struct client *c, void *data, const char *s,
int done)
{
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;
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;
int argc = 0;
char **argv = NULL;

if (s == NULL)
goto out;
if (done) {
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);
}
}

cmdlist = args_make_commands(cdata->state, cdata->argc, cdata->argv,
&error);
argc = cdata->argc;
argv = cmd_copy_argv(cdata->argc, cdata->argv);
cmd_append_argv(&argc, &argv, s);
if (done) {
cdata->argc = argc;
cdata->argv = cmd_copy_argv(argc, argv);
}

cmdlist = args_make_commands(cdata->state, argc, argv, &error);
if (cmdlist == NULL) {
cmdq_append(c, cmdq_get_error(error));
free(error);
Expand All @@ -201,6 +209,7 @@ cmd_command_prompt_callback(struct client *c, void *data, const char *s,
new_item = cmdq_get_command(cmdlist, cmdq_get_state(item));
cmdq_insert_after(item, new_item);
}
cmd_free_argv(argc, argv);

if (c->prompt_inputcb != cmd_command_prompt_callback)
return (1);
Expand Down
2 changes: 1 addition & 1 deletion cmd-display-menu.c
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
shell = _PATH_BSHELL;
cmd_append_argv(&argc, &argv, shell);
} else
args_vector(args, &argc, &argv);
args_to_vector(args, &argc, &argv);

if (args_has(args, 'E') > 1)
flags |= POPUP_CLOSEEXITZERO;
Expand Down
5 changes: 3 additions & 2 deletions cmd-new-session.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ const struct cmd_entry cmd_new_session_entry = {
.args = { "Ac:dDe:EF:f:n:Ps:t:x:Xy:", 0, -1, NULL },
.usage = "[-AdDEPX] [-c start-directory] [-e environment] [-F format] "
"[-f flags] [-n window-name] [-s session-name] "
CMD_TARGET_SESSION_USAGE " [-x width] [-y height] [command]",
CMD_TARGET_SESSION_USAGE " [-x width] [-y height] "
"[shell-command]",

.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },

Expand Down Expand Up @@ -283,7 +284,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
sc.tc = c;

sc.name = args_get(args, 'n');
args_vector(args, &sc.argc, &sc.argv);
args_to_vector(args, &sc.argc, &sc.argv);

sc.idx = -1;
sc.cwd = args_get(args, 'c');
Expand Down
Loading

0 comments on commit daec63e

Please sign in to comment.