From 829fe38ab1429671044a428a2760a9746a73bff6 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 12 Jan 2018 10:16:03 +0000 Subject: [PATCH 1/9] Improve logging for layout cells. --- layout.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/layout.c b/layout.c index 2c6fe2b2..4ccd6d79 100644 --- a/layout.c +++ b/layout.c @@ -97,9 +97,24 @@ void layout_print_cell(struct layout_cell *lc, const char *hdr, u_int n) { struct layout_cell *lcchild; + const char *type; - log_debug("%s:%*s%p type %u [parent %p] wp=%p [%u,%u %ux%u]", hdr, n, - " ", lc, lc->type, lc->parent, lc->wp, lc->xoff, lc->yoff, lc->sx, + switch (lc->type) { + case LAYOUT_LEFTRIGHT: + type = "LEFTRIGHT"; + break; + case LAYOUT_TOPBOTTOM: + type = "TOPBOTTOM"; + break; + case LAYOUT_WINDOWPANE: + type = "WINDOWPANE"; + break; + default: + type = "UNKNOWN"; + break; + } + log_debug("%s:%*s%p type %s [parent %p] wp=%p [%u,%u %ux%u]", hdr, n, + " ", lc, type, lc->parent, lc->wp, lc->xoff, lc->yoff, lc->sx, lc->sy); switch (lc->type) { case LAYOUT_LEFTRIGHT: From f32fd2df69d4fec0476507e600a0363b35059f2b Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 12 Jan 2018 10:22:02 +0000 Subject: [PATCH 2/9] Improve error message if creating socket parent directory fails, from Thomas Adam for GitHub issue 1215. --- tmux.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/tmux.c b/tmux.c index b8ecfecc..dd986783 100644 --- a/tmux.c +++ b/tmux.c @@ -47,7 +47,7 @@ int ptm_fd = -1; const char *shell_command; static __dead void usage(void); -static char *make_label(const char *); +static char *make_label(const char *, char **); static const char *getshell(void); static int checkshell(const char *); @@ -109,12 +109,13 @@ areshell(const char *shell) } static char * -make_label(const char *label) +make_label(const char *label, char **cause) { char *base, resolved[PATH_MAX], *path, *s; struct stat sb; uid_t uid; - int saved_errno; + + *cause = NULL; if (label == NULL) label = "default"; @@ -124,11 +125,16 @@ make_label(const char *label) xasprintf(&base, "%s/tmux-%ld", s, (long)uid); else xasprintf(&base, "%s/tmux-%ld", _PATH_TMP, (long)uid); - - if (mkdir(base, S_IRWXU) != 0 && errno != EEXIST) + if (realpath(base, resolved) == NULL && + strlcpy(resolved, base, sizeof resolved) >= sizeof resolved) { + errno = ERANGE; + free(base); goto fail; + } - if (lstat(base, &sb) != 0) + if (mkdir(resolved, S_IRWXU) != 0 && errno != EEXIST) + goto fail; + if (lstat(resolved, &sb) != 0) goto fail; if (!S_ISDIR(sb.st_mode)) { errno = ENOTDIR; @@ -138,18 +144,11 @@ make_label(const char *label) errno = EACCES; goto fail; } - - if (realpath(base, resolved) == NULL) - strlcpy(resolved, base, sizeof resolved); xasprintf(&path, "%s/%s", resolved, label); - - free(base); return (path); fail: - saved_errno = errno; - free(base); - errno = saved_errno; + xasprintf(cause, "error creating %s (%s)", resolved, strerror(errno)); return (NULL); } @@ -191,7 +190,7 @@ find_home(void) int main(int argc, char **argv) { - char *path, *label, **var; + char *path, *label, *cause, **var; char tmp[PATH_MAX]; const char *s, *shell, *cwd; int opt, flags, keys; @@ -341,8 +340,11 @@ main(int argc, char **argv) path[strcspn(path, ",")] = '\0'; } } - if (path == NULL && (path = make_label(label)) == NULL) { - fprintf(stderr, "can't create socket: %s\n", strerror(errno)); + if (path == NULL && (path = make_label(label, &cause)) == NULL) { + if (cause != NULL) { + fprintf(stderr, "%s\n", cause); + free(cause); + } exit(1); } socket_path = path; From c03565611e41649ce9295012faec2f0eddb2a822 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 12 Jan 2018 16:32:12 +0000 Subject: [PATCH 3/9] Simplify UTF-8 states down into one state. --- input.c | 122 +++++++++++--------------------------------------------- 1 file changed, 23 insertions(+), 99 deletions(-) diff --git a/input.c b/input.c index 42ff7f3b..cce4df1f 100644 --- a/input.c +++ b/input.c @@ -85,6 +85,7 @@ struct input_ctx { u_int param_list_len; struct utf8_data utf8data; + int utf8started; int ch; int last; @@ -146,9 +147,7 @@ static void input_csi_dispatch_sgr_256(struct input_ctx *, int, u_int *); static void input_csi_dispatch_sgr_rgb(struct input_ctx *, int, u_int *); static void input_csi_dispatch_sgr(struct input_ctx *); static int input_dcs_dispatch(struct input_ctx *); -static int input_utf8_open(struct input_ctx *); -static int input_utf8_add(struct input_ctx *); -static int input_utf8_close(struct input_ctx *); +static int input_top_bit_set(struct input_ctx *); /* Command table comparison function. */ static int input_table_compare(const void *, const void *); @@ -314,9 +313,6 @@ static const struct input_transition input_state_osc_string_table[]; static const struct input_transition input_state_apc_string_table[]; static const struct input_transition input_state_rename_string_table[]; static const struct input_transition input_state_consume_st_table[]; -static const struct input_transition input_state_utf8_three_table[]; -static const struct input_transition input_state_utf8_two_table[]; -static const struct input_transition input_state_utf8_one_table[]; /* ground state definition. */ static const struct input_state input_state_ground = { @@ -437,27 +433,6 @@ static const struct input_state input_state_consume_st = { input_state_consume_st_table }; -/* utf8_three state definition. */ -static const struct input_state input_state_utf8_three = { - "utf8_three", - NULL, NULL, - input_state_utf8_three_table -}; - -/* utf8_two state definition. */ -static const struct input_state input_state_utf8_two = { - "utf8_two", - NULL, NULL, - input_state_utf8_two_table -}; - -/* utf8_one state definition. */ -static const struct input_state input_state_utf8_one = { - "utf8_one", - NULL, NULL, - input_state_utf8_one_table -}; - /* ground state table. */ static const struct input_transition input_state_ground_table[] = { INPUT_STATE_ANYWHERE, @@ -467,11 +442,7 @@ static const struct input_transition input_state_ground_table[] = { { 0x1c, 0x1f, input_c0_dispatch, NULL }, { 0x20, 0x7e, input_print, NULL }, { 0x7f, 0x7f, NULL, NULL }, - { 0x80, 0xc1, NULL, NULL }, - { 0xc2, 0xdf, input_utf8_open, &input_state_utf8_one }, - { 0xe0, 0xef, input_utf8_open, &input_state_utf8_two }, - { 0xf0, 0xf4, input_utf8_open, &input_state_utf8_three }, - { 0xf5, 0xff, NULL, NULL }, + { 0x80, 0xff, input_top_bit_set, NULL }, { -1, -1, NULL, NULL } }; @@ -717,39 +688,6 @@ static const struct input_transition input_state_consume_st_table[] = { { -1, -1, NULL, NULL } }; -/* utf8_three state table. */ -static const struct input_transition input_state_utf8_three_table[] = { - /* No INPUT_STATE_ANYWHERE */ - - { 0x00, 0x7f, NULL, &input_state_ground }, - { 0x80, 0xbf, input_utf8_add, &input_state_utf8_two }, - { 0xc0, 0xff, NULL, &input_state_ground }, - - { -1, -1, NULL, NULL } -}; - -/* utf8_two state table. */ -static const struct input_transition input_state_utf8_two_table[] = { - /* No INPUT_STATE_ANYWHERE */ - - { 0x00, 0x7f, NULL, &input_state_ground }, - { 0x80, 0xbf, input_utf8_add, &input_state_utf8_one }, - { 0xc0, 0xff, NULL, &input_state_ground }, - - { -1, -1, NULL, NULL } -}; - -/* utf8_one state table. */ -static const struct input_transition input_state_utf8_one_table[] = { - /* No INPUT_STATE_ANYWHERE */ - - { 0x00, 0x7f, NULL, &input_state_ground }, - { 0x80, 0xbf, input_utf8_close, &input_state_ground }, - { 0xc0, 0xff, NULL, &input_state_ground }, - - { -1, -1, NULL, NULL } -}; - /* Input table compare. */ static int input_table_compare(const void *key, const void *value) @@ -1059,6 +997,8 @@ input_print(struct input_ctx *ictx) { int set; + ictx->utf8started = 0; /* can't be valid UTF-8 */ + set = ictx->cell.set == 0 ? ictx->cell.g0set : ictx->cell.g1set; if (set == 1) ictx->cell.cell.attr |= GRID_ATTR_CHARSET; @@ -1132,6 +1072,8 @@ input_c0_dispatch(struct input_ctx *ictx) struct window_pane *wp = ictx->wp; struct screen *s = sctx->s; + ictx->utf8started = 0; /* can't be valid UTF-8 */ + log_debug("%s: '%c'", __func__, ictx->ch); switch (ictx->ch) { @@ -2064,48 +2006,30 @@ input_exit_rename(struct input_ctx *ictx) /* Open UTF-8 character. */ static int -input_utf8_open(struct input_ctx *ictx) +input_top_bit_set(struct input_ctx *ictx) { struct utf8_data *ud = &ictx->utf8data; - if (utf8_open(ud, ictx->ch) != UTF8_MORE) - fatalx("UTF-8 open invalid %#x", ictx->ch); - - log_debug("%s %hhu", __func__, ud->size); ictx->last = -1; - return (0); -} - -/* Append to UTF-8 character. */ -static int -input_utf8_add(struct input_ctx *ictx) -{ - struct utf8_data *ud = &ictx->utf8data; - - if (utf8_append(ud, ictx->ch) != UTF8_MORE) - fatalx("UTF-8 add invalid %#x", ictx->ch); - - log_debug("%s", __func__); - - return (0); -} - -/* Close UTF-8 string. */ -static int -input_utf8_close(struct input_ctx *ictx) -{ - struct utf8_data *ud = &ictx->utf8data; - - if (utf8_append(ud, ictx->ch) != UTF8_DONE) { - /* - * An error here could be invalid UTF-8 or it could be a - * nonprintable character for which we can't get the - * width. Drop it. - */ + if (!ictx->utf8started) { + if (utf8_open(ud, ictx->ch) != UTF8_MORE) + return (0); + ictx->utf8started = 1; return (0); } + switch (utf8_append(ud, ictx->ch)) { + case UTF8_MORE: + return (0); + case UTF8_ERROR: + ictx->utf8started = 0; + return (0); + case UTF8_DONE: + break; + } + ictx->utf8started = 0; + log_debug("%s %hhu '%*s' (width %hhu)", __func__, ud->size, (int)ud->size, ud->data, ud->width); From 2c5a6f9af599f09d3445dd7ac40af31013e85d77 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 12 Jan 2018 16:41:00 +0000 Subject: [PATCH 4/9] Simplify character replacement on non-UTF-8 terminals and make a common function. --- tty.c | 90 ++++++++++++++++++++++++++++++----------------------------- 1 file changed, 46 insertions(+), 44 deletions(-) diff --git a/tty.c b/tty.c index 0dee5008..9c47ad6d 100644 --- a/tty.c +++ b/tty.c @@ -878,12 +878,37 @@ tty_draw_pane(struct tty *tty, const struct window_pane *wp, u_int py, u_int ox, tty_draw_line(tty, wp, wp->screen, py, ox, oy); } +static const struct grid_cell * +tty_check_codeset(struct tty *tty, const struct grid_cell *gc) +{ + static struct grid_cell new; + u_int n; + + /* Characters less than 0x7f are always fine, no matter what. */ + if (gc->data.size == 1 && *gc->data.data < 0x7f) + return (gc); + + /* UTF-8 terminal and a UTF-8 character - fine. */ + if (tty->flags & TTY_UTF8) + return (gc); + + /* Replace by the right number of underscores. */ + n = gc->data.width; + if (n > UTF8_SIZE) + n = UTF8_SIZE; + memcpy(&new, gc, sizeof new); + new.data.size = n; + memset(new.data.data, '_', n); + return (&new); +} + void tty_draw_line(struct tty *tty, const struct window_pane *wp, struct screen *s, u_int py, u_int ox, u_int oy) { struct grid *gd = s->grid; struct grid_cell gc, last; + const struct grid_cell *gcp; u_int i, j, ux, sx, nx, width; int flags, cleared = 0; char buf[512]; @@ -934,18 +959,15 @@ tty_draw_line(struct tty *tty, const struct window_pane *wp, for (i = 0; i < sx; i++) { grid_view_get_cell(gd, i, py, &gc); + gcp = tty_check_codeset(tty, &gc); if (len != 0 && - (((~tty->flags & TTY_UTF8) && - (gc.data.size != 1 || - *gc.data.data >= 0x7f || - gc.data.width != 1)) || - (gc.attr & GRID_ATTR_CHARSET) || - gc.flags != last.flags || - gc.attr != last.attr || - gc.fg != last.fg || - gc.bg != last.bg || - ux + width + gc.data.width >= screen_size_x(s) || - (sizeof buf) - len < gc.data.size)) { + ((gcp->attr & GRID_ATTR_CHARSET) || + gcp->flags != last.flags || + gcp->attr != last.attr || + gcp->fg != last.fg || + gcp->bg != last.bg || + ux + width + gcp->data.width >= screen_size_x(s) || + (sizeof buf) - len < gcp->data.size)) { tty_attributes(tty, &last, wp); tty_putn(tty, buf, len, width); ux += width; @@ -954,35 +976,21 @@ tty_draw_line(struct tty *tty, const struct window_pane *wp, width = 0; } - if (gc.flags & GRID_FLAG_SELECTED) + if (gcp->flags & GRID_FLAG_SELECTED) screen_select_cell(s, &last, &gc); else memcpy(&last, &gc, sizeof last); - if (ux + gc.data.width > screen_size_x(s)) - for (j = 0; j < gc.data.width; j++) { + if (ux + gcp->data.width > screen_size_x(s)) + for (j = 0; j < gcp->data.width; j++) { if (ux + j > screen_size_x(s)) break; tty_putc(tty, ' '); ux++; } - else if (((~tty->flags & TTY_UTF8) && - (gc.data.size != 1 || - *gc.data.data >= 0x7f || - gc.data.width != 1)) || - (gc.attr & GRID_ATTR_CHARSET)) { - tty_attributes(tty, &last, wp); - if (~tty->flags & TTY_UTF8) { - for (j = 0; j < gc.data.width; j++) - tty_putc(tty, '_'); - } else { - for (j = 0; j < gc.data.size; j++) - tty_putc(tty, gc.data.data[j]); - } - ux += gc.data.width; - } else { - memcpy(buf + len, gc.data.data, gc.data.size); - len += gc.data.size; - width += gc.data.width; + else { + memcpy(buf + len, gcp->data.data, gcp->data.size); + len += gcp->data.size; + width += gcp->data.width; } } if (len != 0) { @@ -1409,7 +1417,7 @@ static void tty_cell(struct tty *tty, const struct grid_cell *gc, const struct window_pane *wp) { - u_int i; + const struct grid_cell *gcp; /* Skip last character if terminal is stupid. */ if ((tty->term->flags & TERM_EARLYWRAP) && @@ -1425,22 +1433,16 @@ tty_cell(struct tty *tty, const struct grid_cell *gc, tty_attributes(tty, gc, wp); /* Get the cell and if ASCII write with putc to do ACS translation. */ - if (gc->data.size == 1) { - if (*gc->data.data < 0x20 || *gc->data.data == 0x7f) + gcp = tty_check_codeset(tty, gc); + if (gcp->data.size == 1) { + if (*gcp->data.data < 0x20 || *gcp->data.data == 0x7f) return; - tty_putc(tty, *gc->data.data); - return; - } - - /* If not UTF-8, write _. */ - if (!(tty->flags & TTY_UTF8)) { - for (i = 0; i < gc->data.width; i++) - tty_putc(tty, '_'); + tty_putc(tty, *gcp->data.data); return; } /* Write the data. */ - tty_putn(tty, gc->data.data, gc->data.size, gc->data.width); + tty_putn(tty, gcp->data.data, gcp->data.size, gcp->data.width); } void From b0c1cefeda9d11910dd4a174e82c9f57ff8bc495 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 12 Jan 2018 16:43:47 +0000 Subject: [PATCH 5/9] Do not collect top-bit-set characters in case they need to be replaced. --- screen-write.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/screen-write.c b/screen-write.c index 1687e8c8..75080d8b 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1297,10 +1297,12 @@ screen_write_collect_end(struct screen_write_ctx *ctx) grid_view_get_cell(s->grid, xx, s->cy, &gc); if (~gc.flags & GRID_FLAG_PADDING) break; - grid_view_set_cell(s->grid, xx, s->cy, &grid_default_cell); + grid_view_set_cell(s->grid, xx, s->cy, + &grid_default_cell); } if (gc.data.width > 1) - grid_view_set_cell(s->grid, xx, s->cy, &grid_default_cell); + grid_view_set_cell(s->grid, xx, s->cy, + &grid_default_cell); } memcpy(&gc, &ci->gc, sizeof gc); @@ -1333,7 +1335,7 @@ screen_write_collect_add(struct screen_write_ctx *ctx, */ collect = 1; - if (gc->data.width != 1 || gc->data.size != 1) + if (gc->data.width != 1 || gc->data.size != 1 || *gc->data.data >= 0x7f) collect = 0; else if (gc->attr & GRID_ATTR_CHARSET) collect = 0; From 481703d6698467e459d5b3ff3cd4322bd0385798 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 15 Jan 2018 15:27:03 +0000 Subject: [PATCH 6/9] Some unused code, GitHub issue 1219. --- cfg.c | 2 -- cmd-find.c | 2 -- cmd-load-buffer.c | 6 +++--- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/cfg.c b/cfg.c index 86901e6a..a448c4b1 100644 --- a/cfg.c +++ b/cfg.c @@ -287,8 +287,6 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int quiet) } free(buf); - if (cmdlist == NULL) - continue; new_item = cmdq_get_command(cmdlist, NULL, NULL, 0); if (item != NULL) cmdq_insert_after(item, new_item); diff --git a/cmd-find.c b/cmd-find.c index 358161a9..3c583d79 100644 --- a/cmd-find.c +++ b/cmd-find.c @@ -588,8 +588,6 @@ cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane) /* Try special characters. */ if (strcmp(pane, "!") == 0) { - if (fs->w->last == NULL) - return (-1); fs->wp = fs->w->last; if (fs->wp == NULL) return (-1); diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index a3cabdc0..74f97d1d 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -59,7 +59,8 @@ cmd_load_buffer_exec(struct cmd *self, struct cmdq_item *item) struct client *c = item->client; FILE *f; const char *path, *bufname; - char *pdata, *new_pdata, *cause, *file; + char *pdata = NULL, *new_pdata, *cause; + char *file; size_t psize; int ch, error; @@ -89,8 +90,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmdq_item *item) f = fopen(file, "rb"); if (f == NULL) { cmdq_error(item, "%s: %s", file, strerror(errno)); - free(file); - return (CMD_RETURN_ERROR); + goto error; } pdata = NULL; From 53b25635da9656577e28a45f328798c417b50cb4 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 15 Jan 2018 15:30:03 +0000 Subject: [PATCH 7/9] Another redundant check, GitHub issue 1219. --- cmd-find.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/cmd-find.c b/cmd-find.c index 3c583d79..7c52c71c 100644 --- a/cmd-find.c +++ b/cmd-find.c @@ -911,16 +911,12 @@ cmd_find_from_client(struct cmd_find_state *fs, struct client *c, int flags) */ fs->w = wp->window; if (cmd_find_best_session_with_window(fs) != 0) { - if (wp != NULL) { - /* - * The window may have been destroyed but the pane - * still on all_window_panes due to something else - * holding a reference. - */ - goto unknown_pane; - } - cmd_find_clear_state(fs, 0); - return (-1); + /* + * The window may have been destroyed but the pane + * still on all_window_panes due to something else + * holding a reference. + */ + goto unknown_pane; } fs->wl = fs->s->curw; fs->w = fs->wl->window; From 5849b73b81c1218e57e9931c44e82f0d7c468cb1 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 16 Jan 2018 09:00:38 +0000 Subject: [PATCH 8/9] Add -I to pipe-pane to connect pane stdin as well as stdout, suggested by Kristof Kovacs in GitHub issue 1186. --- cmd-pipe-pane.c | 74 +++++++++++++++++++++++++++++++++++++------------ tmux.1 | 27 +++++++++++++++--- 2 files changed, 79 insertions(+), 22 deletions(-) diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c index 8e8019e1..199dd575 100644 --- a/cmd-pipe-pane.c +++ b/cmd-pipe-pane.c @@ -36,6 +36,7 @@ static enum cmd_retval cmd_pipe_pane_exec(struct cmd *, struct cmdq_item *); +static void cmd_pipe_pane_read_callback(struct bufferevent *, void *); static void cmd_pipe_pane_write_callback(struct bufferevent *, void *); static void cmd_pipe_pane_error_callback(struct bufferevent *, short, void *); @@ -43,8 +44,8 @@ const struct cmd_entry cmd_pipe_pane_entry = { .name = "pipe-pane", .alias = "pipep", - .args = { "ot:", 0, 1 }, - .usage = "[-o] " CMD_TARGET_PANE_USAGE " [command]", + .args = { "IOot:", 0, 1 }, + .usage = "[-IOo] " CMD_TARGET_PANE_USAGE " [command]", .target = { 't', CMD_FIND_PANE, 0 }, @@ -61,7 +62,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item) struct session *s = item->target.s; struct winlink *wl = item->target.wl; char *cmd; - int old_fd, pipe_fd[2], null_fd; + int old_fd, pipe_fd[2], null_fd, in, out; struct format_tree *ft; sigset_t set, oldset; @@ -91,6 +92,15 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item) if (args_has(self->args, 'o') && old_fd != -1) return (CMD_RETURN_NORMAL); + /* What do we want to do? Neither -I or -O is -O. */ + if (args_has(self->args, 'I')) { + in = 1; + out = args_has(self->args, 'O'); + } else { + in = 0; + out = 1; + } + /* Open the new pipe. */ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_fd) != 0) { cmdq_error(item, "socketpair error: %s", strerror(errno)); @@ -119,19 +129,25 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item) sigprocmask(SIG_SETMASK, &oldset, NULL); close(pipe_fd[0]); - if (dup2(pipe_fd[1], STDIN_FILENO) == -1) - _exit(1); - if (pipe_fd[1] != STDIN_FILENO) - close(pipe_fd[1]); - null_fd = open(_PATH_DEVNULL, O_WRONLY, 0); - if (dup2(null_fd, STDOUT_FILENO) == -1) - _exit(1); + if (out) { + if (dup2(pipe_fd[1], STDIN_FILENO) == -1) + _exit(1); + } else { + if (dup2(null_fd, STDIN_FILENO) == -1) + _exit(1); + } + if (in) { + if (dup2(pipe_fd[1], STDOUT_FILENO) == -1) + _exit(1); + if (pipe_fd[1] != STDOUT_FILENO) + close(pipe_fd[1]); + } else { + if (dup2(null_fd, STDOUT_FILENO) == -1) + _exit(1); + } if (dup2(null_fd, STDERR_FILENO) == -1) _exit(1); - if (null_fd != STDOUT_FILENO && null_fd != STDERR_FILENO) - close(null_fd); - closefrom(STDERR_FILENO + 1); execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL); @@ -144,24 +160,46 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item) wp->pipe_fd = pipe_fd[0]; wp->pipe_off = EVBUFFER_LENGTH(wp->event->input); - wp->pipe_event = bufferevent_new(wp->pipe_fd, NULL, - cmd_pipe_pane_write_callback, cmd_pipe_pane_error_callback, - wp); - bufferevent_enable(wp->pipe_event, EV_WRITE); - setblocking(wp->pipe_fd, 0); + wp->pipe_event = bufferevent_new(wp->pipe_fd, + cmd_pipe_pane_read_callback, + cmd_pipe_pane_write_callback, + cmd_pipe_pane_error_callback, + wp); + if (out) + bufferevent_enable(wp->pipe_event, EV_WRITE); + if (in) + bufferevent_enable(wp->pipe_event, EV_READ); free(cmd); return (CMD_RETURN_NORMAL); } } +static void +cmd_pipe_pane_read_callback(__unused struct bufferevent *bufev, void *data) +{ + struct window_pane *wp = data; + struct evbuffer *evb = wp->pipe_event->input; + size_t available; + + available = EVBUFFER_LENGTH(evb); + log_debug("%%%u pipe read %zu", wp->id, available); + + bufferevent_write(wp->event, EVBUFFER_DATA(evb), available); + evbuffer_drain(evb, available); + + if (window_pane_destroy_ready(wp)) + server_destroy_pane(wp, 1); +} + static void cmd_pipe_pane_write_callback(__unused struct bufferevent *bufev, void *data) { struct window_pane *wp = data; log_debug("%%%u pipe empty", wp->id); + if (window_pane_destroy_ready(wp)) server_destroy_pane(wp, 1); } diff --git a/tmux.1 b/tmux.1 index 4e48d4a6..7eb228cb 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1800,15 +1800,15 @@ If .Fl a is used, move to the next window with an alert. .It Xo Ic pipe-pane -.Op Fl o +.Op Fl IOo .Op Fl t Ar target-pane .Op Ar shell-command .Xc .D1 (alias: Ic pipep ) -Pipe any output sent by the program in +Pipe output sent by the program in .Ar target-pane -to a shell command. -A pane may only be piped to one command at a time, any existing pipe is +to a shell command or vice versa. +A pane may only be connected to one command at a time, any existing pipe is closed before .Ar shell-command is executed. @@ -1821,6 +1821,25 @@ If no .Ar shell-command is given, the current pipe (if any) is closed. .Pp +.Fl I +and +.Fl O +specify which of the +.Ar shell-command +output streams are connected to the pane: +with +.Fl I +stdout is connected (so anything +.Ar shell-command +prints is written to the pane as if it were typed); +with +.Fl O +stdin is connected (so any output in the pane is piped to +.Ar shell-command ) . +Both may be used together and if neither are specified, +.Fl O +is used. +.Pp The .Fl o option only opens a new pipe if no previous pipe exists, allowing a pipe to From 75842bfe66d983580dddf11b676445d5b9fa9f8a Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 16 Jan 2018 17:03:18 +0000 Subject: [PATCH 9/9] Fix drawing of ACS characters (they need to go character-at-a-time), accidentally broken in last commit. --- tty.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tty.c b/tty.c index 9c47ad6d..01208a25 100644 --- a/tty.c +++ b/tty.c @@ -977,17 +977,23 @@ tty_draw_line(struct tty *tty, const struct window_pane *wp, } if (gcp->flags & GRID_FLAG_SELECTED) - screen_select_cell(s, &last, &gc); + screen_select_cell(s, &last, gcp); else - memcpy(&last, &gc, sizeof last); - if (ux + gcp->data.width > screen_size_x(s)) + memcpy(&last, gcp, sizeof last); + if (ux + gcp->data.width > screen_size_x(s)) { + tty_attributes(tty, &last, wp); for (j = 0; j < gcp->data.width; j++) { if (ux + j > screen_size_x(s)) break; tty_putc(tty, ' '); ux++; } - else { + } else if (gcp->attr & GRID_ATTR_CHARSET) { + tty_attributes(tty, &last, wp); + for (j = 0; j < gcp->data.size; j++) + tty_putc(tty, gcp->data.data[j]); + ux += gc.data.width; + } else { memcpy(buf + len, gcp->data.data, gcp->data.size); len += gcp->data.size; width += gcp->data.width;