diff options
author | Nicholas Marriott <nicm@cvs.openbsd.org> | 2019-04-28 20:05:51 +0000 |
---|---|---|
committer | Nicholas Marriott <nicm@cvs.openbsd.org> | 2019-04-28 20:05:51 +0000 |
commit | 33d544b49816a3e9c53b23a441cbbb44ca3e7104 (patch) | |
tree | 1158b262afa2b9ef235acca14ebdf29f2362fad2 | |
parent | 85a27b2729a3964babaadc7ed78346074dbc638c (diff) |
Support multiple occurances of the same argument. Use this for a new
flag -e to new-window, split-window, respawn-window, respawn-pane to
pass environment variables into the newly created process. From Steffen
Christgau in GitHub issue 1697.
-rw-r--r-- | usr.bin/tmux/arguments.c | 159 | ||||
-rw-r--r-- | usr.bin/tmux/cmd-new-window.c | 19 | ||||
-rw-r--r-- | usr.bin/tmux/cmd-respawn-pane.c | 18 | ||||
-rw-r--r-- | usr.bin/tmux/cmd-respawn-window.c | 18 | ||||
-rw-r--r-- | usr.bin/tmux/cmd-split-window.c | 17 | ||||
-rw-r--r-- | usr.bin/tmux/spawn.c | 4 | ||||
-rw-r--r-- | usr.bin/tmux/tmux.1 | 32 | ||||
-rw-r--r-- | usr.bin/tmux/tmux.h | 6 |
8 files changed, 201 insertions, 72 deletions
diff --git a/usr.bin/tmux/arguments.c b/usr.bin/tmux/arguments.c index 5f8bfa633ae..051adf26dd9 100644 --- a/usr.bin/tmux/arguments.c +++ b/usr.bin/tmux/arguments.c @@ -1,4 +1,4 @@ -/* $OpenBSD: arguments.c,v 1.20 2017/08/23 09:14:21 nicm Exp $ */ +/* $OpenBSD: arguments.c,v 1.21 2019/04/28 20:05:50 nicm Exp $ */ /* * Copyright (c) 2010 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -29,9 +29,15 @@ * Manipulate command arguments. */ +struct args_value { + char *value; + TAILQ_ENTRY(args_value) entry; +}; +TAILQ_HEAD(args_values, args_value); + struct args_entry { u_char flag; - char *value; + struct args_values values; RB_ENTRY(args_entry) entry; }; @@ -93,12 +99,18 @@ args_free(struct args *args) { struct args_entry *entry; struct args_entry *entry1; + struct args_value *value; + struct args_value *value1; cmd_free_argv(args->argc, args->argv); RB_FOREACH_SAFE(entry, args_tree, &args->tree, entry1) { RB_REMOVE(args_tree, &args->tree, entry); - free(entry->value); + TAILQ_FOREACH_SAFE(value, &entry->values, entry, value1) { + TAILQ_REMOVE(&entry->values, value, entry); + free(value->value); + free(value); + } free(entry); } @@ -124,22 +136,69 @@ args_print_add(char **buf, size_t *len, const char *fmt, ...) free(s); } +/* Add value to string. */ +static void +args_print_add_value(char **buf, size_t *len, struct args_entry *entry, + struct args_value *value) +{ + static const char quoted[] = " #\"';$"; + char *escaped; + int flags; + + if (**buf != '\0') + args_print_add(buf, len, " -%c ", entry->flag); + else + args_print_add(buf, len, "-%c ", entry->flag); + + flags = VIS_OCTAL|VIS_TAB|VIS_NL; + if (value->value[strcspn(value->value, quoted)] != '\0') + flags |= VIS_DQ; + utf8_stravis(&escaped, value->value, flags); + if (flags & VIS_DQ) + args_print_add(buf, len, "\"%s\"", escaped); + else + args_print_add(buf, len, "%s", escaped); + free(escaped); +} + +/* Add argument to string. */ +static void +args_print_add_argument(char **buf, size_t *len, const char *argument) +{ + static const char quoted[] = " #\"';$"; + char *escaped; + int flags; + + if (**buf != '\0') + args_print_add(buf, len, " "); + + flags = VIS_OCTAL|VIS_TAB|VIS_NL; + if (argument[strcspn(argument, quoted)] != '\0') + flags |= VIS_DQ; + utf8_stravis(&escaped, argument, flags); + if (flags & VIS_DQ) + args_print_add(buf, len, "\"%s\"", escaped); + else + args_print_add(buf, len, "%s", escaped); + free(escaped); +} + /* Print a set of arguments. */ char * args_print(struct args *args) { size_t len; - char *buf, *escaped; - int i, flags; + char *buf; + int i; struct args_entry *entry; - static const char quoted[] = " #\"';$"; + struct args_value *value; len = 1; buf = xcalloc(1, len); /* Process the flags first. */ RB_FOREACH(entry, args_tree, &args->tree) { - if (entry->value != NULL) + if (!TAILQ_EMPTY(&entry->values)) continue; if (*buf == '\0') @@ -149,40 +208,13 @@ args_print(struct args *args) /* Then the flags with arguments. */ RB_FOREACH(entry, args_tree, &args->tree) { - if (entry->value == NULL) - continue; - - if (*buf != '\0') - args_print_add(&buf, &len, " -%c ", entry->flag); - else - args_print_add(&buf, &len, "-%c ", entry->flag); - - flags = VIS_OCTAL|VIS_TAB|VIS_NL; - if (entry->value[strcspn(entry->value, quoted)] != '\0') - flags |= VIS_DQ; - utf8_stravis(&escaped, entry->value, flags); - if (flags & VIS_DQ) - args_print_add(&buf, &len, "\"%s\"", escaped); - else - args_print_add(&buf, &len, "%s", escaped); - free(escaped); + TAILQ_FOREACH(value, &entry->values, entry) + args_print_add_value(&buf, &len, entry, value); } /* And finally the argument vector. */ - for (i = 0; i < args->argc; i++) { - if (*buf != '\0') - args_print_add(&buf, &len, " "); - - flags = VIS_OCTAL|VIS_TAB|VIS_NL; - if (args->argv[i][strcspn(args->argv[i], quoted)] != '\0') - flags |= VIS_DQ; - utf8_stravis(&escaped, args->argv[i], flags); - if (flags & VIS_DQ) - args_print_add(&buf, &len, "\"%s\"", escaped); - else - args_print_add(&buf, &len, "%s", escaped); - free(escaped); - } + for (i = 0; i < args->argc; i++) + args_print_add_argument(&buf, &len, args->argv[i]); return (buf); } @@ -196,22 +228,24 @@ args_has(struct args *args, u_char ch) /* Set argument value in the arguments tree. */ void -args_set(struct args *args, u_char ch, const char *value) +args_set(struct args *args, u_char ch, const char *s) { struct args_entry *entry; + struct args_value *value; - /* Replace existing argument. */ - if ((entry = args_find(args, ch)) != NULL) { - free(entry->value); - entry->value = NULL; - } else { + entry = args_find(args, ch); + if (entry == NULL) { entry = xcalloc(1, sizeof *entry); entry->flag = ch; + TAILQ_INIT(&entry->values); RB_INSERT(args_tree, &args->tree, entry); } - if (value != NULL) - entry->value = xstrdup(value); + if (s != NULL) { + value = xcalloc(1, sizeof *value); + value->value = xstrdup(s); + TAILQ_INSERT_TAIL(&entry->values, value, entry); + } } /* Get argument value. Will be NULL if it isn't present. */ @@ -222,7 +256,34 @@ args_get(struct args *args, u_char ch) if ((entry = args_find(args, ch)) == NULL) return (NULL); - return (entry->value); + return (TAILQ_LAST(&entry->values, args_values)->value); +} + +/* Get first value in argument. */ +const char * +args_first_value(struct args *args, u_char ch, struct args_value **value) +{ + struct args_entry *entry; + + if ((entry = args_find(args, ch)) == NULL) + return (NULL); + + *value = TAILQ_FIRST(&entry->values); + if (*value == NULL) + return (NULL); + return ((*value)->value); +} + +/* Get next value in argument. */ +const char * +args_next_value(struct args_value **value) +{ + if (*value == NULL) + return (NULL); + *value = TAILQ_NEXT(*value, entry); + if (*value == NULL) + return (NULL); + return ((*value)->value); } /* Convert an argument value to a number. */ @@ -233,13 +294,15 @@ args_strtonum(struct args *args, u_char ch, long long minval, long long maxval, const char *errstr; long long ll; struct args_entry *entry; + struct args_value *value; if ((entry = args_find(args, ch)) == NULL) { *cause = xstrdup("missing"); return (0); } + value = TAILQ_LAST(&entry->values, args_values); - ll = strtonum(entry->value, minval, maxval, &errstr); + ll = strtonum(value->value, minval, maxval, &errstr); if (errstr != NULL) { *cause = xstrdup(errstr); return (0); diff --git a/usr.bin/tmux/cmd-new-window.c b/usr.bin/tmux/cmd-new-window.c index e096f340391..bc2c370bc78 100644 --- a/usr.bin/tmux/cmd-new-window.c +++ b/usr.bin/tmux/cmd-new-window.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-new-window.c,v 1.78 2019/04/26 11:38:51 nicm Exp $ */ +/* $OpenBSD: cmd-new-window.c,v 1.79 2019/04/28 20:05:50 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -38,9 +38,9 @@ const struct cmd_entry cmd_new_window_entry = { .name = "new-window", .alias = "neww", - .args = { "ac:dF:kn:Pt:", 0, -1 }, - .usage = "[-adkP] [-c start-directory] [-F format] [-n window-name] " - CMD_TARGET_WINDOW_USAGE " [command]", + .args = { "ac:de:F:kn:Pt:", 0, -1 }, + .usage = "[-adkP] [-c start-directory] [-e environment] [-F format] " + "[-n window-name] " CMD_TARGET_WINDOW_USAGE " [command]", .target = { 't', CMD_FIND_WINDOW, CMD_FIND_WINDOW_INDEX }, @@ -60,8 +60,9 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item) int idx = item->target.idx; struct winlink *new_wl; char *cause = NULL, *cp; - const char *template; + const char *template, *add; struct cmd_find_state fs; + struct args_value *value; if (args_has(args, 'a') && (idx = winlink_shuffle_up(s, wl)) == -1) { cmdq_error(item, "couldn't get a window index"); @@ -75,6 +76,13 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item) sc.name = args_get(args, 'n'); sc.argc = args->argc; sc.argv = args->argv; + sc.environ = environ_create(); + + add = args_first_value(args, 'e', &value); + while (add != NULL) { + environ_put(sc.environ, add); + add = args_next_value(&value); + } sc.idx = idx; sc.cwd = args_get(args, 'c'); @@ -107,5 +115,6 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item) cmd_find_from_winlink(&fs, new_wl, 0); cmdq_insert_hook(s, item, &fs, "after-new-window"); + environ_free(sc.environ); return (CMD_RETURN_NORMAL); } diff --git a/usr.bin/tmux/cmd-respawn-pane.c b/usr.bin/tmux/cmd-respawn-pane.c index 31492f10dec..22cfbeff629 100644 --- a/usr.bin/tmux/cmd-respawn-pane.c +++ b/usr.bin/tmux/cmd-respawn-pane.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-respawn-pane.c,v 1.28 2019/04/17 14:37:48 nicm Exp $ */ +/* $OpenBSD: cmd-respawn-pane.c,v 1.29 2019/04/28 20:05:50 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -34,9 +34,9 @@ const struct cmd_entry cmd_respawn_pane_entry = { .name = "respawn-pane", .alias = "respawnp", - .args = { "c:kt:", 0, -1 }, - .usage = "[-c start-directory] [-k] " CMD_TARGET_PANE_USAGE - " [command]", + .args = { "c:e:kt:", 0, -1 }, + .usage = "[-k] [-c start-directory] [-e environment] " + CMD_TARGET_PANE_USAGE " [command]", .target = { 't', CMD_FIND_PANE, 0 }, @@ -53,6 +53,8 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item) struct winlink *wl = item->target.wl; struct window_pane *wp = item->target.wp; char *cause = NULL; + const char *add; + struct args_value *value; memset(&sc, 0, sizeof sc); sc.item = item; @@ -65,6 +67,13 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item) sc.name = NULL; sc.argc = args->argc; sc.argv = args->argv; + sc.environ = environ_create(); + + add = args_first_value(args, 'e', &value); + while (add != NULL) { + environ_put(sc.environ, add); + add = args_next_value(&value); + } sc.idx = -1; sc.cwd = args_get(args, 'c'); @@ -82,5 +91,6 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item) wp->flags |= PANE_REDRAW; server_status_window(wp->window); + environ_free(sc.environ); return (CMD_RETURN_NORMAL); } diff --git a/usr.bin/tmux/cmd-respawn-window.c b/usr.bin/tmux/cmd-respawn-window.c index fc9b3214683..6d5ccef222a 100644 --- a/usr.bin/tmux/cmd-respawn-window.c +++ b/usr.bin/tmux/cmd-respawn-window.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-respawn-window.c,v 1.38 2019/04/17 14:37:48 nicm Exp $ */ +/* $OpenBSD: cmd-respawn-window.c,v 1.39 2019/04/28 20:05:50 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -34,9 +34,9 @@ const struct cmd_entry cmd_respawn_window_entry = { .name = "respawn-window", .alias = "respawnw", - .args = { "c:kt:", 0, -1 }, - .usage = "[-c start-directory] [-k] " CMD_TARGET_WINDOW_USAGE - " [command]", + .args = { "c:e:kt:", 0, -1 }, + .usage = "[-k] [-c start-directory] [-e environment] " + CMD_TARGET_WINDOW_USAGE " [command]", .target = { 't', CMD_FIND_WINDOW, 0 }, @@ -52,6 +52,8 @@ cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item) struct session *s = item->target.s; struct winlink *wl = item->target.wl; char *cause = NULL; + const char *add; + struct args_value *value; memset(&sc, 0, sizeof sc); sc.item = item; @@ -61,6 +63,13 @@ cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item) sc.name = NULL; sc.argc = args->argc; sc.argv = args->argv; + sc.environ = environ_create(); + + add = args_first_value(args, 'e', &value); + while (add != NULL) { + environ_put(sc.environ, add); + add = args_next_value(&value); + } sc.idx = -1; sc.cwd = args_get(args, 'c'); @@ -77,5 +86,6 @@ cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item) server_redraw_window(wl->window); + environ_free(sc.environ); return (CMD_RETURN_NORMAL); } diff --git a/usr.bin/tmux/cmd-split-window.c b/usr.bin/tmux/cmd-split-window.c index 65473c36446..25ee7bd1a69 100644 --- a/usr.bin/tmux/cmd-split-window.c +++ b/usr.bin/tmux/cmd-split-window.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-split-window.c,v 1.93 2019/04/26 11:38:51 nicm Exp $ */ +/* $OpenBSD: cmd-split-window.c,v 1.94 2019/04/28 20:05:50 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -40,8 +40,8 @@ const struct cmd_entry cmd_split_window_entry = { .name = "split-window", .alias = "splitw", - .args = { "bc:dfF:l:hp:Pt:v", 0, -1 }, - .usage = "[-bdfhvP] [-c start-directory] [-F format] " + .args = { "bc:de:fF:l:hp:Pt:v", 0, -1 }, + .usage = "[-bdefhvP] [-c start-directory] [-e environment] [-F format] " "[-p percentage|-l size] " CMD_TARGET_PANE_USAGE " [command]", .target = { 't', CMD_FIND_PANE, 0 }, @@ -64,8 +64,9 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) struct layout_cell *lc; struct cmd_find_state fs; int size, percentage, flags; - const char *template; + const char *template, *add; char *cause, *cp; + struct args_value *value; if (args_has(args, 'h')) type = LAYOUT_LEFTRIGHT; @@ -117,6 +118,13 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) sc.name = NULL; sc.argc = args->argc; sc.argv = args->argv; + sc.environ = environ_create(); + + add = args_first_value(args, 'e', &value); + while (add != NULL) { + environ_put(sc.environ, add); + add = args_next_value(&value); + } sc.idx = -1; sc.cwd = args_get(args, 'c'); @@ -146,5 +154,6 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) cmd_find_from_winlink_pane(&fs, wl, new_wp, 0); cmdq_insert_hook(s, item, &fs, "after-split-window"); + environ_free(sc.environ); return (CMD_RETURN_NORMAL); } diff --git a/usr.bin/tmux/spawn.c b/usr.bin/tmux/spawn.c index 5109c432311..0bdf061f976 100644 --- a/usr.bin/tmux/spawn.c +++ b/usr.bin/tmux/spawn.c @@ -1,4 +1,4 @@ -/* $OpenBSD: spawn.c,v 1.1 2019/04/17 14:37:48 nicm Exp $ */ +/* $OpenBSD: spawn.c,v 1.2 2019/04/28 20:05:50 nicm Exp $ */ /* * Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -293,6 +293,8 @@ spawn_pane(struct spawn_context *sc, char **cause) /* Create an environment for this pane. */ child = environ_for_session(s, 0); + if (sc->environ != NULL) + environ_copy(sc->environ, child); environ_set(child, "TMUX_PANE", "%%%u", new_wp->id); /* diff --git a/usr.bin/tmux/tmux.1 b/usr.bin/tmux/tmux.1 index 6659f45a157..914c38f59cd 100644 --- a/usr.bin/tmux/tmux.1 +++ b/usr.bin/tmux/tmux.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: tmux.1,v 1.640 2019/04/26 11:38:51 nicm Exp $ +.\" $OpenBSD: tmux.1,v 1.641 2019/04/28 20:05:50 nicm Exp $ .\" .\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> .\" @@ -14,7 +14,7 @@ .\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING .\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: April 26 2019 $ +.Dd $Mdocdate: April 28 2019 $ .Dt TMUX 1 .Os .Sh NAME @@ -1784,6 +1784,7 @@ option. .It Xo Ic new-window .Op Fl adkP .Op Fl c Ar start-directory +.Op Fl e Ar environment .Op Fl F Ar format .Op Fl n Ar window-name .Op Fl t Ar target-window @@ -1823,6 +1824,12 @@ See the .Ic remain-on-exit option to change this behaviour. .Pp +.Fl e +takes the form +.Ql VARIABLE=value +and sets an environment variable for the newly created window; it may be +specified multiple times. +.Pp The .Ev TERM environment variable must be set to @@ -1835,7 +1842,9 @@ for all programs running New windows will automatically have .Ql TERM=screen added to their environment, but care must be taken not to reset this in shell -start-up files. +start-up files or by the +.Fl e +option. .Pp The .Fl P @@ -1994,8 +2003,9 @@ This command will automatically set .Ic window-size to manual in the window options. .It Xo Ic respawn-pane -.Op Fl c Ar start-directory .Op Fl k +.Op Fl c Ar start-directory +.Op Fl e Ar environment .Op Fl t Ar target-pane .Op Ar shell-command .Xc @@ -2011,9 +2021,15 @@ The pane must be already inactive, unless is given, in which case any existing command is killed. .Fl c specifies a new working directory for the pane. +The +.Fl e +option has the same meaning as for the +.Ic new-window +command. .It Xo Ic respawn-window -.Op Fl c Ar start-directory .Op Fl k +.Op Fl c Ar start-directory +.Op Fl e Ar environment .Op Fl t Ar target-window .Op Ar shell-command .Xc @@ -2029,6 +2045,11 @@ The window must be already inactive, unless is given, in which case any existing command is killed. .Fl c specifies a new working directory for the window. +The +.Fl e +option has the same meaning as for the +.Ic new-window +command. .It Xo Ic rotate-window .Op Fl DU .Op Fl t Ar target-window @@ -2147,6 +2168,7 @@ the command behaves like .It Xo Ic split-window .Op Fl bdfhvP .Op Fl c Ar start-directory +.Op Fl e Ar environment .Oo Fl l .Ar size | .Fl p Ar percentage Oc diff --git a/usr.bin/tmux/tmux.h b/usr.bin/tmux/tmux.h index 39e20e0df28..2a5d97efe6d 100644 --- a/usr.bin/tmux/tmux.h +++ b/usr.bin/tmux/tmux.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tmux.h,v 1.883 2019/04/26 11:38:51 nicm Exp $ */ +/* $OpenBSD: tmux.h,v 1.884 2019/04/28 20:05:50 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -37,6 +37,7 @@ extern char **environ; struct args; +struct args_value; struct client; struct cmd_find_state; struct cmdq_item; @@ -1578,6 +1579,7 @@ struct spawn_context { const char *name; char **argv; int argc; + struct environ *environ; int idx; const char *cwd; @@ -1871,6 +1873,8 @@ void args_free(struct args *); char *args_print(struct args *); int args_has(struct args *, u_char); const char *args_get(struct args *, u_char); +const char *args_first_value(struct args *, u_char, struct args_value **); +const char *args_next_value(struct args_value **); long long args_strtonum(struct args *, u_char, long long, long long, char **); |