1
0
mirror of https://github.com/tmux/tmux.git synced 2025-03-30 19:48:48 +00:00

Merge branch 'obsd-master'

This commit is contained in:
Thomas Adam 2019-04-28 23:02:30 +01:00
commit 3ab229da70
8 changed files with 192 additions and 63 deletions

View File

@ -28,9 +28,15 @@
* Manipulate command arguments. * Manipulate command arguments.
*/ */
struct args_value {
char *value;
TAILQ_ENTRY(args_value) entry;
};
TAILQ_HEAD(args_values, args_value);
struct args_entry { struct args_entry {
u_char flag; u_char flag;
char *value; struct args_values values;
RB_ENTRY(args_entry) entry; RB_ENTRY(args_entry) entry;
}; };
@ -92,12 +98,18 @@ args_free(struct args *args)
{ {
struct args_entry *entry; struct args_entry *entry;
struct args_entry *entry1; struct args_entry *entry1;
struct args_value *value;
struct args_value *value1;
cmd_free_argv(args->argc, args->argv); cmd_free_argv(args->argc, args->argv);
RB_FOREACH_SAFE(entry, args_tree, &args->tree, entry1) { RB_FOREACH_SAFE(entry, args_tree, &args->tree, entry1) {
RB_REMOVE(args_tree, &args->tree, entry); 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); free(entry);
} }
@ -123,22 +135,69 @@ args_print_add(char **buf, size_t *len, const char *fmt, ...)
free(s); 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. */ /* Print a set of arguments. */
char * char *
args_print(struct args *args) args_print(struct args *args)
{ {
size_t len; size_t len;
char *buf, *escaped; char *buf;
int i, flags; int i;
struct args_entry *entry; struct args_entry *entry;
static const char quoted[] = " #\"';$"; struct args_value *value;
len = 1; len = 1;
buf = xcalloc(1, len); buf = xcalloc(1, len);
/* Process the flags first. */ /* Process the flags first. */
RB_FOREACH(entry, args_tree, &args->tree) { RB_FOREACH(entry, args_tree, &args->tree) {
if (entry->value != NULL) if (!TAILQ_EMPTY(&entry->values))
continue; continue;
if (*buf == '\0') if (*buf == '\0')
@ -148,40 +207,13 @@ args_print(struct args *args)
/* Then the flags with arguments. */ /* Then the flags with arguments. */
RB_FOREACH(entry, args_tree, &args->tree) { RB_FOREACH(entry, args_tree, &args->tree) {
if (entry->value == NULL) TAILQ_FOREACH(value, &entry->values, entry)
continue; args_print_add_value(&buf, &len, entry, value);
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);
} }
/* And finally the argument vector. */ /* And finally the argument vector. */
for (i = 0; i < args->argc; i++) { for (i = 0; i < args->argc; i++)
if (*buf != '\0') args_print_add_argument(&buf, &len, args->argv[i]);
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);
}
return (buf); return (buf);
} }
@ -195,22 +227,24 @@ args_has(struct args *args, u_char ch)
/* Set argument value in the arguments tree. */ /* Set argument value in the arguments tree. */
void 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_entry *entry;
struct args_value *value;
/* Replace existing argument. */ entry = args_find(args, ch);
if ((entry = args_find(args, ch)) != NULL) { if (entry == NULL) {
free(entry->value);
entry->value = NULL;
} else {
entry = xcalloc(1, sizeof *entry); entry = xcalloc(1, sizeof *entry);
entry->flag = ch; entry->flag = ch;
TAILQ_INIT(&entry->values);
RB_INSERT(args_tree, &args->tree, entry); RB_INSERT(args_tree, &args->tree, entry);
} }
if (value != NULL) if (s != NULL) {
entry->value = xstrdup(value); 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. */ /* Get argument value. Will be NULL if it isn't present. */
@ -221,7 +255,34 @@ args_get(struct args *args, u_char ch)
if ((entry = args_find(args, ch)) == NULL) if ((entry = args_find(args, ch)) == NULL)
return (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. */ /* Convert an argument value to a number. */
@ -232,13 +293,15 @@ args_strtonum(struct args *args, u_char ch, long long minval, long long maxval,
const char *errstr; const char *errstr;
long long ll; long long ll;
struct args_entry *entry; struct args_entry *entry;
struct args_value *value;
if ((entry = args_find(args, ch)) == NULL) { if ((entry = args_find(args, ch)) == NULL) {
*cause = xstrdup("missing"); *cause = xstrdup("missing");
return (0); 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) { if (errstr != NULL) {
*cause = xstrdup(errstr); *cause = xstrdup(errstr);
return (0); return (0);

View File

@ -38,9 +38,9 @@ const struct cmd_entry cmd_new_window_entry = {
.name = "new-window", .name = "new-window",
.alias = "neww", .alias = "neww",
.args = { "ac:dF:kn:Pt:", 0, -1 }, .args = { "ac:de:F:kn:Pt:", 0, -1 },
.usage = "[-adkP] [-c start-directory] [-F format] [-n window-name] " .usage = "[-adkP] [-c start-directory] [-e environment] [-F format] "
CMD_TARGET_WINDOW_USAGE " [command]", "[-n window-name] " CMD_TARGET_WINDOW_USAGE " [command]",
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_WINDOW_INDEX }, .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; int idx = item->target.idx;
struct winlink *new_wl; struct winlink *new_wl;
char *cause = NULL, *cp; char *cause = NULL, *cp;
const char *template; const char *template, *add;
struct cmd_find_state fs; struct cmd_find_state fs;
struct args_value *value;
if (args_has(args, 'a') && (idx = winlink_shuffle_up(s, wl)) == -1) { if (args_has(args, 'a') && (idx = winlink_shuffle_up(s, wl)) == -1) {
cmdq_error(item, "couldn't get a window index"); 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.name = args_get(args, 'n');
sc.argc = args->argc; sc.argc = args->argc;
sc.argv = args->argv; 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.idx = idx;
sc.cwd = args_get(args, 'c'); 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); cmd_find_from_winlink(&fs, new_wl, 0);
cmdq_insert_hook(s, item, &fs, "after-new-window"); cmdq_insert_hook(s, item, &fs, "after-new-window");
environ_free(sc.environ);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@ -34,9 +34,9 @@ const struct cmd_entry cmd_respawn_pane_entry = {
.name = "respawn-pane", .name = "respawn-pane",
.alias = "respawnp", .alias = "respawnp",
.args = { "c:kt:", 0, -1 }, .args = { "c:e:kt:", 0, -1 },
.usage = "[-c start-directory] [-k] " CMD_TARGET_PANE_USAGE .usage = "[-k] [-c start-directory] [-e environment] "
" [command]", CMD_TARGET_PANE_USAGE " [command]",
.target = { 't', CMD_FIND_PANE, 0 }, .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 winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp; struct window_pane *wp = item->target.wp;
char *cause = NULL; char *cause = NULL;
const char *add;
struct args_value *value;
memset(&sc, 0, sizeof sc); memset(&sc, 0, sizeof sc);
sc.item = item; sc.item = item;
@ -65,6 +67,13 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
sc.name = NULL; sc.name = NULL;
sc.argc = args->argc; sc.argc = args->argc;
sc.argv = args->argv; 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.idx = -1;
sc.cwd = args_get(args, 'c'); 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; wp->flags |= PANE_REDRAW;
server_status_window(wp->window); server_status_window(wp->window);
environ_free(sc.environ);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@ -34,9 +34,9 @@ const struct cmd_entry cmd_respawn_window_entry = {
.name = "respawn-window", .name = "respawn-window",
.alias = "respawnw", .alias = "respawnw",
.args = { "c:kt:", 0, -1 }, .args = { "c:e:kt:", 0, -1 },
.usage = "[-c start-directory] [-k] " CMD_TARGET_WINDOW_USAGE .usage = "[-k] [-c start-directory] [-e environment] "
" [command]", CMD_TARGET_WINDOW_USAGE " [command]",
.target = { 't', CMD_FIND_WINDOW, 0 }, .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 session *s = item->target.s;
struct winlink *wl = item->target.wl; struct winlink *wl = item->target.wl;
char *cause = NULL; char *cause = NULL;
const char *add;
struct args_value *value;
memset(&sc, 0, sizeof sc); memset(&sc, 0, sizeof sc);
sc.item = item; sc.item = item;
@ -61,6 +63,13 @@ cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
sc.name = NULL; sc.name = NULL;
sc.argc = args->argc; sc.argc = args->argc;
sc.argv = args->argv; 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.idx = -1;
sc.cwd = args_get(args, 'c'); 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); server_redraw_window(wl->window);
environ_free(sc.environ);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@ -39,8 +39,8 @@ const struct cmd_entry cmd_split_window_entry = {
.name = "split-window", .name = "split-window",
.alias = "splitw", .alias = "splitw",
.args = { "bc:dfF:l:hp:Pt:v", 0, -1 }, .args = { "bc:de:fF:l:hp:Pt:v", 0, -1 },
.usage = "[-bdfhvP] [-c start-directory] [-F format] " .usage = "[-bdefhvP] [-c start-directory] [-e environment] [-F format] "
"[-p percentage|-l size] " CMD_TARGET_PANE_USAGE " [command]", "[-p percentage|-l size] " CMD_TARGET_PANE_USAGE " [command]",
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@ -63,8 +63,9 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
struct layout_cell *lc; struct layout_cell *lc;
struct cmd_find_state fs; struct cmd_find_state fs;
int size, percentage, flags; int size, percentage, flags;
const char *template; const char *template, *add;
char *cause, *cp; char *cause, *cp;
struct args_value *value;
if (args_has(args, 'h')) if (args_has(args, 'h'))
type = LAYOUT_LEFTRIGHT; type = LAYOUT_LEFTRIGHT;
@ -116,6 +117,13 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
sc.name = NULL; sc.name = NULL;
sc.argc = args->argc; sc.argc = args->argc;
sc.argv = args->argv; 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.idx = -1;
sc.cwd = args_get(args, 'c'); sc.cwd = args_get(args, 'c');
@ -145,5 +153,6 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
cmd_find_from_winlink_pane(&fs, wl, new_wp, 0); cmd_find_from_winlink_pane(&fs, wl, new_wp, 0);
cmdq_insert_hook(s, item, &fs, "after-split-window"); cmdq_insert_hook(s, item, &fs, "after-split-window");
environ_free(sc.environ);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@ -291,6 +291,8 @@ spawn_pane(struct spawn_context *sc, char **cause)
/* Create an environment for this pane. */ /* Create an environment for this pane. */
child = environ_for_session(s, 0); child = environ_for_session(s, 0);
if (sc->environ != NULL)
environ_copy(sc->environ, child);
environ_set(child, "TMUX_PANE", "%%%u", new_wp->id); environ_set(child, "TMUX_PANE", "%%%u", new_wp->id);
/* /*

28
tmux.1
View File

@ -1827,6 +1827,7 @@ option.
.It Xo Ic new-window .It Xo Ic new-window
.Op Fl adkP .Op Fl adkP
.Op Fl c Ar start-directory .Op Fl c Ar start-directory
.Op Fl e Ar environment
.Op Fl F Ar format .Op Fl F Ar format
.Op Fl n Ar window-name .Op Fl n Ar window-name
.Op Fl t Ar target-window .Op Fl t Ar target-window
@ -1866,6 +1867,12 @@ See the
.Ic remain-on-exit .Ic remain-on-exit
option to change this behaviour. option to change this behaviour.
.Pp .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 The
.Ev TERM .Ev TERM
environment variable must be set to environment variable must be set to
@ -1878,7 +1885,9 @@ for all programs running
New windows will automatically have New windows will automatically have
.Ql TERM=screen .Ql TERM=screen
added to their environment, but care must be taken not to reset this in shell 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 .Pp
The The
.Fl P .Fl P
@ -2037,8 +2046,9 @@ This command will automatically set
.Ic window-size .Ic window-size
to manual in the window options. to manual in the window options.
.It Xo Ic respawn-pane .It Xo Ic respawn-pane
.Op Fl c Ar start-directory
.Op Fl k .Op Fl k
.Op Fl c Ar start-directory
.Op Fl e Ar environment
.Op Fl t Ar target-pane .Op Fl t Ar target-pane
.Op Ar shell-command .Op Ar shell-command
.Xc .Xc
@ -2054,9 +2064,15 @@ The pane must be already inactive, unless
is given, in which case any existing command is killed. is given, in which case any existing command is killed.
.Fl c .Fl c
specifies a new working directory for the pane. 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 .It Xo Ic respawn-window
.Op Fl c Ar start-directory
.Op Fl k .Op Fl k
.Op Fl c Ar start-directory
.Op Fl e Ar environment
.Op Fl t Ar target-window .Op Fl t Ar target-window
.Op Ar shell-command .Op Ar shell-command
.Xc .Xc
@ -2072,6 +2088,11 @@ The window must be already inactive, unless
is given, in which case any existing command is killed. is given, in which case any existing command is killed.
.Fl c .Fl c
specifies a new working directory for the window. 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 .It Xo Ic rotate-window
.Op Fl DU .Op Fl DU
.Op Fl t Ar target-window .Op Fl t Ar target-window
@ -2190,6 +2211,7 @@ the command behaves like
.It Xo Ic split-window .It Xo Ic split-window
.Op Fl bdfhvP .Op Fl bdfhvP
.Op Fl c Ar start-directory .Op Fl c Ar start-directory
.Op Fl e Ar environment
.Oo Fl l .Oo Fl l
.Ar size | .Ar size |
.Fl p Ar percentage Oc .Fl p Ar percentage Oc

4
tmux.h
View File

@ -39,6 +39,7 @@
extern char **environ; extern char **environ;
struct args; struct args;
struct args_value;
struct client; struct client;
struct cmd_find_state; struct cmd_find_state;
struct cmdq_item; struct cmdq_item;
@ -1580,6 +1581,7 @@ struct spawn_context {
const char *name; const char *name;
char **argv; char **argv;
int argc; int argc;
struct environ *environ;
int idx; int idx;
const char *cwd; const char *cwd;
@ -1873,6 +1875,8 @@ void args_free(struct args *);
char *args_print(struct args *); char *args_print(struct args *);
int args_has(struct args *, u_char); int args_has(struct args *, u_char);
const char *args_get(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, long long args_strtonum(struct args *, u_char, long long, long long,
char **); char **);