diff --git a/client.c b/client.c index e4c0806b..b938b402 100644 --- a/client.c +++ b/client.c @@ -222,20 +222,7 @@ client_exit_message(void) static void client_exit(void) { - struct client_file *cf; - size_t left; - int waiting = 0; - - RB_FOREACH (cf, client_files, &client_files) { - if (cf->event == NULL) - continue; - left = EVBUFFER_LENGTH(cf->event->output); - if (left != 0) { - waiting++; - log_debug("file %u %zu bytes left", cf->stream, left); - } - } - if (waiting == 0) + if (!file_write_left(&client_files)) proc_exit(client_proc); } @@ -478,257 +465,6 @@ client_send_identify(const char *ttynam, const char *cwd, int feat) proc_send(client_peer, MSG_IDENTIFY_DONE, -1, NULL, 0); } -/* File write error callback. */ -static void -client_write_error_callback(__unused struct bufferevent *bev, - __unused short what, void *arg) -{ - struct client_file *cf = arg; - - log_debug("write error file %d", cf->stream); - - bufferevent_free(cf->event); - cf->event = NULL; - - close(cf->fd); - cf->fd = -1; - - if (client_exitflag) - client_exit(); -} - -/* File write callback. */ -static void -client_write_callback(__unused struct bufferevent *bev, void *arg) -{ - struct client_file *cf = arg; - - if (cf->closed && EVBUFFER_LENGTH(cf->event->output) == 0) { - bufferevent_free(cf->event); - close(cf->fd); - RB_REMOVE(client_files, &client_files, cf); - file_free(cf); - } - - if (client_exitflag) - client_exit(); -} - -/* Open write file. */ -static void -client_write_open(void *data, size_t datalen) -{ - struct msg_write_open *msg = data; - const char *path; - struct msg_write_ready reply; - struct client_file find, *cf; - const int flags = O_NONBLOCK|O_WRONLY|O_CREAT; - int error = 0; - - if (datalen < sizeof *msg) - fatalx("bad MSG_WRITE_OPEN size"); - if (datalen == sizeof *msg) - path = "-"; - else - path = (const char *)(msg + 1); - log_debug("open write file %d %s", msg->stream, path); - - find.stream = msg->stream; - if ((cf = RB_FIND(client_files, &client_files, &find)) == NULL) { - cf = file_create(NULL, msg->stream, NULL, NULL); - RB_INSERT(client_files, &client_files, cf); - } else { - error = EBADF; - goto reply; - } - if (cf->closed) { - error = EBADF; - goto reply; - } - - cf->fd = -1; - if (msg->fd == -1) - cf->fd = open(path, msg->flags|flags, 0644); - else { - if (msg->fd != STDOUT_FILENO && msg->fd != STDERR_FILENO) - errno = EBADF; - else { - cf->fd = dup(msg->fd); - if (~client_flags & CLIENT_CONTROL) - close(msg->fd); /* can only be used once */ - } - } - if (cf->fd == -1) { - error = errno; - goto reply; - } - - cf->event = bufferevent_new(cf->fd, NULL, client_write_callback, - client_write_error_callback, cf); - bufferevent_enable(cf->event, EV_WRITE); - goto reply; - -reply: - reply.stream = msg->stream; - reply.error = error; - proc_send(client_peer, MSG_WRITE_READY, -1, &reply, sizeof reply); -} - -/* Write to client file. */ -static void -client_write_data(void *data, size_t datalen) -{ - struct msg_write_data *msg = data; - struct client_file find, *cf; - size_t size = datalen - sizeof *msg; - - if (datalen < sizeof *msg) - fatalx("bad MSG_WRITE size"); - find.stream = msg->stream; - if ((cf = RB_FIND(client_files, &client_files, &find)) == NULL) - fatalx("unknown stream number"); - log_debug("write %zu to file %d", size, cf->stream); - - if (cf->event != NULL) - bufferevent_write(cf->event, msg + 1, size); -} - -/* Close client file. */ -static void -client_write_close(void *data, size_t datalen) -{ - struct msg_write_close *msg = data; - struct client_file find, *cf; - - if (datalen != sizeof *msg) - fatalx("bad MSG_WRITE_CLOSE size"); - find.stream = msg->stream; - if ((cf = RB_FIND(client_files, &client_files, &find)) == NULL) - fatalx("unknown stream number"); - log_debug("close file %d", cf->stream); - - if (cf->event == NULL || EVBUFFER_LENGTH(cf->event->output) == 0) { - if (cf->event != NULL) - bufferevent_free(cf->event); - if (cf->fd != -1) - close(cf->fd); - RB_REMOVE(client_files, &client_files, cf); - file_free(cf); - } -} - -/* File read callback. */ -static void -client_read_callback(__unused struct bufferevent *bev, void *arg) -{ - struct client_file *cf = arg; - void *bdata; - size_t bsize; - struct msg_read_data *msg; - size_t msglen; - - msg = xmalloc(sizeof *msg); - for (;;) { - bdata = EVBUFFER_DATA(cf->event->input); - bsize = EVBUFFER_LENGTH(cf->event->input); - - if (bsize == 0) - break; - if (bsize > MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg) - bsize = MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg; - log_debug("read %zu from file %d", bsize, cf->stream); - - msglen = (sizeof *msg) + bsize; - msg = xrealloc(msg, msglen); - msg->stream = cf->stream; - memcpy(msg + 1, bdata, bsize); - proc_send(client_peer, MSG_READ, -1, msg, msglen); - - evbuffer_drain(cf->event->input, bsize); - } - free(msg); -} - -/* File read error callback. */ -static void -client_read_error_callback(__unused struct bufferevent *bev, - __unused short what, void *arg) -{ - struct client_file *cf = arg; - struct msg_read_done msg; - - log_debug("read error file %d", cf->stream); - - msg.stream = cf->stream; - msg.error = 0; - proc_send(client_peer, MSG_READ_DONE, -1, &msg, sizeof msg); - - bufferevent_free(cf->event); - close(cf->fd); - RB_REMOVE(client_files, &client_files, cf); - file_free(cf); -} - -/* Open read file. */ -static void -client_read_open(void *data, size_t datalen) -{ - struct msg_read_open *msg = data; - const char *path; - struct msg_read_done reply; - struct client_file find, *cf; - const int flags = O_NONBLOCK|O_RDONLY; - int error; - - if (datalen < sizeof *msg) - fatalx("bad MSG_READ_OPEN size"); - if (datalen == sizeof *msg) - path = "-"; - else - path = (const char *)(msg + 1); - log_debug("open read file %d %s", msg->stream, path); - - find.stream = msg->stream; - if ((cf = RB_FIND(client_files, &client_files, &find)) == NULL) { - cf = file_create(NULL, msg->stream, NULL, NULL); - RB_INSERT(client_files, &client_files, cf); - } else { - error = EBADF; - goto reply; - } - if (cf->closed) { - error = EBADF; - goto reply; - } - - cf->fd = -1; - if (msg->fd == -1) - cf->fd = open(path, flags); - else { - if (msg->fd != STDIN_FILENO) - errno = EBADF; - else { - cf->fd = dup(msg->fd); - if (~client_flags & CLIENT_CONTROL) - close(msg->fd); /* can only be used once */ - } - } - if (cf->fd == -1) { - error = errno; - goto reply; - } - - cf->event = bufferevent_new(cf->fd, client_read_callback, NULL, - client_read_error_callback, cf); - bufferevent_enable(cf->event, EV_READ); - return; - -reply: - reply.stream = msg->stream; - reply.error = error; - proc_send(client_peer, MSG_READ_DONE, -1, &reply, sizeof reply); -} - /* Run command in shell; used for -c. */ static __dead void client_exec(const char *shell, const char *shellcmd) @@ -803,13 +539,25 @@ client_signal(int sig) } } +/* Callback for file write error or close. */ +static void +client_file_check_cb(__unused struct client *c, __unused const char *path, + __unused int error, __unused int closed, __unused struct evbuffer *buffer, + __unused void *data) +{ + if (client_exitflag) + client_exit(); +} + /* Callback for client read events. */ static void client_dispatch(struct imsg *imsg, __unused void *arg) { if (imsg == NULL) { - client_exitreason = CLIENT_EXIT_LOST_SERVER; - client_exitval = 1; + if (!client_exitflag) { + client_exitreason = CLIENT_EXIT_LOST_SERVER; + client_exitval = 1; + } proc_exit(client_proc); return; } @@ -917,16 +665,20 @@ client_dispatch_wait(struct imsg *imsg) proc_exit(client_proc); break; case MSG_READ_OPEN: - client_read_open(data, datalen); + file_read_open(&client_files, client_peer, imsg, 1, + !(client_flags & CLIENT_CONTROL), client_file_check_cb, + NULL); break; case MSG_WRITE_OPEN: - client_write_open(data, datalen); + file_write_open(&client_files, client_peer, imsg, 1, + !(client_flags & CLIENT_CONTROL), client_file_check_cb, + NULL); break; case MSG_WRITE: - client_write_data(data, datalen); + file_write_data(&client_files, imsg); break; case MSG_WRITE_CLOSE: - client_write_close(data, datalen); + file_write_close(&client_files, imsg); break; case MSG_OLDSTDERR: case MSG_OLDSTDIN: diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c index ef02c202..7faea926 100644 --- a/cmd-save-buffer.c +++ b/cmd-save-buffer.c @@ -108,7 +108,7 @@ cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item) if (args_has(args, 'a')) flags = O_APPEND; else - flags = 0; + flags = O_TRUNC; file_write(cmdq_get_client(item), path, flags, bufdata, bufsize, cmd_save_buffer_done, item); free(path); diff --git a/colour.c b/colour.c index ee4b95db..1d1729ca 100644 --- a/colour.c +++ b/colour.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "tmux.h" @@ -111,6 +112,9 @@ colour_tostring(int c) static char s[32]; u_char r, g, b; + if (c == -1) + return ("invalid"); + if (c & COLOUR_FLAG_RGB) { colour_split_rgb(c, &r, &g, &b); xsnprintf(s, sizeof s, "#%02x%02x%02x", r, g, b); @@ -233,7 +237,7 @@ colour_fromstring(const char *s) return (96); if (strcasecmp(s, "brightwhite") == 0 || strcmp(s, "97") == 0) return (97); - return (-1); + return (colour_byname(s)); } /* Convert 256 colour to RGB colour. */ @@ -335,3 +339,608 @@ colour_256to16(int c) return (table[c & 0xff]); } + +/* Get colour by X11 colour name. */ +int +colour_byname(const char *name) +{ + static const struct { + const char *name; + int c; + } colours[] = { + { "AliceBlue", 0xf0f8ff }, + { "AntiqueWhite", 0xfaebd7 }, + { "AntiqueWhite1", 0xffefdb }, + { "AntiqueWhite2", 0xeedfcc }, + { "AntiqueWhite3", 0xcdc0b0 }, + { "AntiqueWhite4", 0x8b8378 }, + { "BlanchedAlmond", 0xffebcd }, + { "BlueViolet", 0x8a2be2 }, + { "CadetBlue", 0x5f9ea0 }, + { "CadetBlue1", 0x98f5ff }, + { "CadetBlue2", 0x8ee5ee }, + { "CadetBlue3", 0x7ac5cd }, + { "CadetBlue4", 0x53868b }, + { "CornflowerBlue", 0x6495ed }, + { "DarkBlue", 0x00008b }, + { "DarkCyan", 0x008b8b }, + { "DarkGoldenrod", 0xb8860b }, + { "DarkGoldenrod1", 0xffb90f }, + { "DarkGoldenrod2", 0xeead0e }, + { "DarkGoldenrod3", 0xcd950c }, + { "DarkGoldenrod4", 0x8b6508 }, + { "DarkGray", 0xa9a9a9 }, + { "DarkGreen", 0x006400 }, + { "DarkGrey", 0xa9a9a9 }, + { "DarkKhaki", 0xbdb76b }, + { "DarkMagenta", 0x8b008b }, + { "DarkOliveGreen", 0x556b2f }, + { "DarkOliveGreen1", 0xcaff70 }, + { "DarkOliveGreen2", 0xbcee68 }, + { "DarkOliveGreen3", 0xa2cd5a }, + { "DarkOliveGreen4", 0x6e8b3d }, + { "DarkOrange", 0xff8c00 }, + { "DarkOrange1", 0xff7f00 }, + { "DarkOrange2", 0xee7600 }, + { "DarkOrange3", 0xcd6600 }, + { "DarkOrange4", 0x8b4500 }, + { "DarkOrchid", 0x9932cc }, + { "DarkOrchid1", 0xbf3eff }, + { "DarkOrchid2", 0xb23aee }, + { "DarkOrchid3", 0x9a32cd }, + { "DarkOrchid4", 0x68228b }, + { "DarkRed", 0x8b0000 }, + { "DarkSalmon", 0xe9967a }, + { "DarkSeaGreen", 0x8fbc8f }, + { "DarkSeaGreen1", 0xc1ffc1 }, + { "DarkSeaGreen2", 0xb4eeb4 }, + { "DarkSeaGreen3", 0x9bcd9b }, + { "DarkSeaGreen4", 0x698b69 }, + { "DarkSlateBlue", 0x483d8b }, + { "DarkSlateGray", 0x2f4f4f }, + { "DarkSlateGray1", 0x97ffff }, + { "DarkSlateGray2", 0x8deeee }, + { "DarkSlateGray3", 0x79cdcd }, + { "DarkSlateGray4", 0x528b8b }, + { "DarkSlateGrey", 0x2f4f4f }, + { "DarkTurquoise", 0x00ced1 }, + { "DarkViolet", 0x9400d3 }, + { "DeepPink", 0xff1493 }, + { "DeepPink1", 0xff1493 }, + { "DeepPink2", 0xee1289 }, + { "DeepPink3", 0xcd1076 }, + { "DeepPink4", 0x8b0a50 }, + { "DeepSkyBlue", 0x00bfff }, + { "DeepSkyBlue1", 0x00bfff }, + { "DeepSkyBlue2", 0x00b2ee }, + { "DeepSkyBlue3", 0x009acd }, + { "DeepSkyBlue4", 0x00688b }, + { "DimGray", 0x696969 }, + { "DimGrey", 0x696969 }, + { "DodgerBlue", 0x1e90ff }, + { "DodgerBlue1", 0x1e90ff }, + { "DodgerBlue2", 0x1c86ee }, + { "DodgerBlue3", 0x1874cd }, + { "DodgerBlue4", 0x104e8b }, + { "FloralWhite", 0xfffaf0 }, + { "ForestGreen", 0x228b22 }, + { "GhostWhite", 0xf8f8ff }, + { "GreenYellow", 0xadff2f }, + { "HotPink", 0xff69b4 }, + { "HotPink1", 0xff6eb4 }, + { "HotPink2", 0xee6aa7 }, + { "HotPink3", 0xcd6090 }, + { "HotPink4", 0x8b3a62 }, + { "IndianRed", 0xcd5c5c }, + { "IndianRed1", 0xff6a6a }, + { "IndianRed2", 0xee6363 }, + { "IndianRed3", 0xcd5555 }, + { "IndianRed4", 0x8b3a3a }, + { "LavenderBlush", 0xfff0f5 }, + { "LavenderBlush1", 0xfff0f5 }, + { "LavenderBlush2", 0xeee0e5 }, + { "LavenderBlush3", 0xcdc1c5 }, + { "LavenderBlush4", 0x8b8386 }, + { "LawnGreen", 0x7cfc00 }, + { "LemonChiffon", 0xfffacd }, + { "LemonChiffon1", 0xfffacd }, + { "LemonChiffon2", 0xeee9bf }, + { "LemonChiffon3", 0xcdc9a5 }, + { "LemonChiffon4", 0x8b8970 }, + { "LightBlue", 0xadd8e6 }, + { "LightBlue1", 0xbfefff }, + { "LightBlue2", 0xb2dfee }, + { "LightBlue3", 0x9ac0cd }, + { "LightBlue4", 0x68838b }, + { "LightCoral", 0xf08080 }, + { "LightCyan", 0xe0ffff }, + { "LightCyan1", 0xe0ffff }, + { "LightCyan2", 0xd1eeee }, + { "LightCyan3", 0xb4cdcd }, + { "LightCyan4", 0x7a8b8b }, + { "LightGoldenrod", 0xeedd82 }, + { "LightGoldenrod1", 0xffec8b }, + { "LightGoldenrod2", 0xeedc82 }, + { "LightGoldenrod3", 0xcdbe70 }, + { "LightGoldenrod4", 0x8b814c }, + { "LightGoldenrodYellow", 0xfafad2 }, + { "LightGray", 0xd3d3d3 }, + { "LightGreen", 0x90ee90 }, + { "LightGrey", 0xd3d3d3 }, + { "LightPink", 0xffb6c1 }, + { "LightPink1", 0xffaeb9 }, + { "LightPink2", 0xeea2ad }, + { "LightPink3", 0xcd8c95 }, + { "LightPink4", 0x8b5f65 }, + { "LightSalmon", 0xffa07a }, + { "LightSalmon1", 0xffa07a }, + { "LightSalmon2", 0xee9572 }, + { "LightSalmon3", 0xcd8162 }, + { "LightSalmon4", 0x8b5742 }, + { "LightSeaGreen", 0x20b2aa }, + { "LightSkyBlue", 0x87cefa }, + { "LightSkyBlue1", 0xb0e2ff }, + { "LightSkyBlue2", 0xa4d3ee }, + { "LightSkyBlue3", 0x8db6cd }, + { "LightSkyBlue4", 0x607b8b }, + { "LightSlateBlue", 0x8470ff }, + { "LightSlateGray", 0x778899 }, + { "LightSlateGrey", 0x778899 }, + { "LightSteelBlue", 0xb0c4de }, + { "LightSteelBlue1", 0xcae1ff }, + { "LightSteelBlue2", 0xbcd2ee }, + { "LightSteelBlue3", 0xa2b5cd }, + { "LightSteelBlue4", 0x6e7b8b }, + { "LightYellow", 0xffffe0 }, + { "LightYellow1", 0xffffe0 }, + { "LightYellow2", 0xeeeed1 }, + { "LightYellow3", 0xcdcdb4 }, + { "LightYellow4", 0x8b8b7a }, + { "LimeGreen", 0x32cd32 }, + { "MediumAquamarine", 0x66cdaa }, + { "MediumBlue", 0x0000cd }, + { "MediumOrchid", 0xba55d3 }, + { "MediumOrchid1", 0xe066ff }, + { "MediumOrchid2", 0xd15fee }, + { "MediumOrchid3", 0xb452cd }, + { "MediumOrchid4", 0x7a378b }, + { "MediumPurple", 0x9370db }, + { "MediumPurple1", 0xab82ff }, + { "MediumPurple2", 0x9f79ee }, + { "MediumPurple3", 0x8968cd }, + { "MediumPurple4", 0x5d478b }, + { "MediumSeaGreen", 0x3cb371 }, + { "MediumSlateBlue", 0x7b68ee }, + { "MediumSpringGreen", 0x00fa9a }, + { "MediumTurquoise", 0x48d1cc }, + { "MediumVioletRed", 0xc71585 }, + { "MidnightBlue", 0x191970 }, + { "MintCream", 0xf5fffa }, + { "MistyRose", 0xffe4e1 }, + { "MistyRose1", 0xffe4e1 }, + { "MistyRose2", 0xeed5d2 }, + { "MistyRose3", 0xcdb7b5 }, + { "MistyRose4", 0x8b7d7b }, + { "NavajoWhite", 0xffdead }, + { "NavajoWhite1", 0xffdead }, + { "NavajoWhite2", 0xeecfa1 }, + { "NavajoWhite3", 0xcdb38b }, + { "NavajoWhite4", 0x8b795e }, + { "NavyBlue", 0x000080 }, + { "OldLace", 0xfdf5e6 }, + { "OliveDrab", 0x6b8e23 }, + { "OliveDrab1", 0xc0ff3e }, + { "OliveDrab2", 0xb3ee3a }, + { "OliveDrab3", 0x9acd32 }, + { "OliveDrab4", 0x698b22 }, + { "OrangeRed", 0xff4500 }, + { "OrangeRed1", 0xff4500 }, + { "OrangeRed2", 0xee4000 }, + { "OrangeRed3", 0xcd3700 }, + { "OrangeRed4", 0x8b2500 }, + { "PaleGoldenrod", 0xeee8aa }, + { "PaleGreen", 0x98fb98 }, + { "PaleGreen1", 0x9aff9a }, + { "PaleGreen2", 0x90ee90 }, + { "PaleGreen3", 0x7ccd7c }, + { "PaleGreen4", 0x548b54 }, + { "PaleTurquoise", 0xafeeee }, + { "PaleTurquoise1", 0xbbffff }, + { "PaleTurquoise2", 0xaeeeee }, + { "PaleTurquoise3", 0x96cdcd }, + { "PaleTurquoise4", 0x668b8b }, + { "PaleVioletRed", 0xdb7093 }, + { "PaleVioletRed1", 0xff82ab }, + { "PaleVioletRed2", 0xee799f }, + { "PaleVioletRed3", 0xcd6889 }, + { "PaleVioletRed4", 0x8b475d }, + { "PapayaWhip", 0xffefd5 }, + { "PeachPuff", 0xffdab9 }, + { "PeachPuff1", 0xffdab9 }, + { "PeachPuff2", 0xeecbad }, + { "PeachPuff3", 0xcdaf95 }, + { "PeachPuff4", 0x8b7765 }, + { "PowderBlue", 0xb0e0e6 }, + { "RebeccaPurple", 0x663399 }, + { "RosyBrown", 0xbc8f8f }, + { "RosyBrown1", 0xffc1c1 }, + { "RosyBrown2", 0xeeb4b4 }, + { "RosyBrown3", 0xcd9b9b }, + { "RosyBrown4", 0x8b6969 }, + { "RoyalBlue", 0x4169e1 }, + { "RoyalBlue1", 0x4876ff }, + { "RoyalBlue2", 0x436eee }, + { "RoyalBlue3", 0x3a5fcd }, + { "RoyalBlue4", 0x27408b }, + { "SaddleBrown", 0x8b4513 }, + { "SandyBrown", 0xf4a460 }, + { "SeaGreen", 0x2e8b57 }, + { "SeaGreen1", 0x54ff9f }, + { "SeaGreen2", 0x4eee94 }, + { "SeaGreen3", 0x43cd80 }, + { "SeaGreen4", 0x2e8b57 }, + { "SkyBlue", 0x87ceeb }, + { "SkyBlue1", 0x87ceff }, + { "SkyBlue2", 0x7ec0ee }, + { "SkyBlue3", 0x6ca6cd }, + { "SkyBlue4", 0x4a708b }, + { "SlateBlue", 0x6a5acd }, + { "SlateBlue1", 0x836fff }, + { "SlateBlue2", 0x7a67ee }, + { "SlateBlue3", 0x6959cd }, + { "SlateBlue4", 0x473c8b }, + { "SlateGray", 0x708090 }, + { "SlateGray1", 0xc6e2ff }, + { "SlateGray2", 0xb9d3ee }, + { "SlateGray3", 0x9fb6cd }, + { "SlateGray4", 0x6c7b8b }, + { "SlateGrey", 0x708090 }, + { "SpringGreen", 0x00ff7f }, + { "SpringGreen1", 0x00ff7f }, + { "SpringGreen2", 0x00ee76 }, + { "SpringGreen3", 0x00cd66 }, + { "SpringGreen4", 0x008b45 }, + { "SteelBlue", 0x4682b4 }, + { "SteelBlue1", 0x63b8ff }, + { "SteelBlue2", 0x5cacee }, + { "SteelBlue3", 0x4f94cd }, + { "SteelBlue4", 0x36648b }, + { "VioletRed", 0xd02090 }, + { "VioletRed1", 0xff3e96 }, + { "VioletRed2", 0xee3a8c }, + { "VioletRed3", 0xcd3278 }, + { "VioletRed4", 0x8b2252 }, + { "WebGray", 0x808080 }, + { "WebGreen", 0x008000 }, + { "WebGrey", 0x808080 }, + { "WebMaroon", 0x800000 }, + { "WebPurple", 0x800080 }, + { "WhiteSmoke", 0xf5f5f5 }, + { "X11Gray", 0xbebebe }, + { "X11Green", 0x00ff00 }, + { "X11Grey", 0xbebebe }, + { "X11Maroon", 0xb03060 }, + { "X11Purple", 0xa020f0 }, + { "YellowGreen", 0x9acd32 }, + { "alice blue", 0xf0f8ff }, + { "antique white", 0xfaebd7 }, + { "aqua", 0x00ffff }, + { "aquamarine", 0x7fffd4 }, + { "aquamarine1", 0x7fffd4 }, + { "aquamarine2", 0x76eec6 }, + { "aquamarine3", 0x66cdaa }, + { "aquamarine4", 0x458b74 }, + { "azure", 0xf0ffff }, + { "azure1", 0xf0ffff }, + { "azure2", 0xe0eeee }, + { "azure3", 0xc1cdcd }, + { "azure4", 0x838b8b }, + { "beige", 0xf5f5dc }, + { "bisque", 0xffe4c4 }, + { "bisque1", 0xffe4c4 }, + { "bisque2", 0xeed5b7 }, + { "bisque3", 0xcdb79e }, + { "bisque4", 0x8b7d6b }, + { "black", 0x000000 }, + { "blanched almond", 0xffebcd }, + { "blue violet", 0x8a2be2 }, + { "blue", 0x0000ff }, + { "blue1", 0x0000ff }, + { "blue2", 0x0000ee }, + { "blue3", 0x0000cd }, + { "blue4", 0x00008b }, + { "brown", 0xa52a2a }, + { "brown1", 0xff4040 }, + { "brown2", 0xee3b3b }, + { "brown3", 0xcd3333 }, + { "brown4", 0x8b2323 }, + { "burlywood", 0xdeb887 }, + { "burlywood1", 0xffd39b }, + { "burlywood2", 0xeec591 }, + { "burlywood3", 0xcdaa7d }, + { "burlywood4", 0x8b7355 }, + { "cadet blue", 0x5f9ea0 }, + { "chartreuse", 0x7fff00 }, + { "chartreuse1", 0x7fff00 }, + { "chartreuse2", 0x76ee00 }, + { "chartreuse3", 0x66cd00 }, + { "chartreuse4", 0x458b00 }, + { "chocolate", 0xd2691e }, + { "chocolate1", 0xff7f24 }, + { "chocolate2", 0xee7621 }, + { "chocolate3", 0xcd661d }, + { "chocolate4", 0x8b4513 }, + { "coral", 0xff7f50 }, + { "coral1", 0xff7256 }, + { "coral2", 0xee6a50 }, + { "coral3", 0xcd5b45 }, + { "coral4", 0x8b3e2f }, + { "cornflower blue", 0x6495ed }, + { "cornsilk", 0xfff8dc }, + { "cornsilk1", 0xfff8dc }, + { "cornsilk2", 0xeee8cd }, + { "cornsilk3", 0xcdc8b1 }, + { "cornsilk4", 0x8b8878 }, + { "crimson", 0xdc143c }, + { "cyan", 0x00ffff }, + { "cyan1", 0x00ffff }, + { "cyan2", 0x00eeee }, + { "cyan3", 0x00cdcd }, + { "cyan4", 0x008b8b }, + { "dark blue", 0x00008b }, + { "dark cyan", 0x008b8b }, + { "dark goldenrod", 0xb8860b }, + { "dark gray", 0xa9a9a9 }, + { "dark green", 0x006400 }, + { "dark grey", 0xa9a9a9 }, + { "dark khaki", 0xbdb76b }, + { "dark magenta", 0x8b008b }, + { "dark olive green", 0x556b2f }, + { "dark orange", 0xff8c00 }, + { "dark orchid", 0x9932cc }, + { "dark red", 0x8b0000 }, + { "dark salmon", 0xe9967a }, + { "dark sea green", 0x8fbc8f }, + { "dark slate blue", 0x483d8b }, + { "dark slate gray", 0x2f4f4f }, + { "dark slate grey", 0x2f4f4f }, + { "dark turquoise", 0x00ced1 }, + { "dark violet", 0x9400d3 }, + { "deep pink", 0xff1493 }, + { "deep sky blue", 0x00bfff }, + { "dim gray", 0x696969 }, + { "dim grey", 0x696969 }, + { "dodger blue", 0x1e90ff }, + { "firebrick", 0xb22222 }, + { "firebrick1", 0xff3030 }, + { "firebrick2", 0xee2c2c }, + { "firebrick3", 0xcd2626 }, + { "firebrick4", 0x8b1a1a }, + { "floral white", 0xfffaf0 }, + { "forest green", 0x228b22 }, + { "fuchsia", 0xff00ff }, + { "gainsboro", 0xdcdcdc }, + { "ghost white", 0xf8f8ff }, + { "gold", 0xffd700 }, + { "gold1", 0xffd700 }, + { "gold2", 0xeec900 }, + { "gold3", 0xcdad00 }, + { "gold4", 0x8b7500 }, + { "goldenrod", 0xdaa520 }, + { "goldenrod1", 0xffc125 }, + { "goldenrod2", 0xeeb422 }, + { "goldenrod3", 0xcd9b1d }, + { "goldenrod4", 0x8b6914 }, + { "green yellow", 0xadff2f }, + { "green", 0x00ff00 }, + { "green1", 0x00ff00 }, + { "green2", 0x00ee00 }, + { "green3", 0x00cd00 }, + { "green4", 0x008b00 }, + { "honeydew", 0xf0fff0 }, + { "honeydew1", 0xf0fff0 }, + { "honeydew2", 0xe0eee0 }, + { "honeydew3", 0xc1cdc1 }, + { "honeydew4", 0x838b83 }, + { "hot pink", 0xff69b4 }, + { "indian red", 0xcd5c5c }, + { "indigo", 0x4b0082 }, + { "ivory", 0xfffff0 }, + { "ivory1", 0xfffff0 }, + { "ivory2", 0xeeeee0 }, + { "ivory3", 0xcdcdc1 }, + { "ivory4", 0x8b8b83 }, + { "khaki", 0xf0e68c }, + { "khaki1", 0xfff68f }, + { "khaki2", 0xeee685 }, + { "khaki3", 0xcdc673 }, + { "khaki4", 0x8b864e }, + { "lavender blush", 0xfff0f5 }, + { "lavender", 0xe6e6fa }, + { "lawn green", 0x7cfc00 }, + { "lemon chiffon", 0xfffacd }, + { "light blue", 0xadd8e6 }, + { "light coral", 0xf08080 }, + { "light cyan", 0xe0ffff }, + { "light goldenrod yellow", 0xfafad2 }, + { "light goldenrod", 0xeedd82 }, + { "light gray", 0xd3d3d3 }, + { "light green", 0x90ee90 }, + { "light grey", 0xd3d3d3 }, + { "light pink", 0xffb6c1 }, + { "light salmon", 0xffa07a }, + { "light sea green", 0x20b2aa }, + { "light sky blue", 0x87cefa }, + { "light slate blue", 0x8470ff }, + { "light slate gray", 0x778899 }, + { "light slate grey", 0x778899 }, + { "light steel blue", 0xb0c4de }, + { "light yellow", 0xffffe0 }, + { "lime green", 0x32cd32 }, + { "lime", 0x00ff00 }, + { "linen", 0xfaf0e6 }, + { "magenta", 0xff00ff }, + { "magenta1", 0xff00ff }, + { "magenta2", 0xee00ee }, + { "magenta3", 0xcd00cd }, + { "magenta4", 0x8b008b }, + { "maroon", 0xb03060 }, + { "maroon1", 0xff34b3 }, + { "maroon2", 0xee30a7 }, + { "maroon3", 0xcd2990 }, + { "maroon4", 0x8b1c62 }, + { "medium aquamarine", 0x66cdaa }, + { "medium blue", 0x0000cd }, + { "medium orchid", 0xba55d3 }, + { "medium purple", 0x9370db }, + { "medium sea green", 0x3cb371 }, + { "medium slate blue", 0x7b68ee }, + { "medium spring green", 0x00fa9a }, + { "medium turquoise", 0x48d1cc }, + { "medium violet red", 0xc71585 }, + { "midnight blue", 0x191970 }, + { "mint cream", 0xf5fffa }, + { "misty rose", 0xffe4e1 }, + { "moccasin", 0xffe4b5 }, + { "navajo white", 0xffdead }, + { "navy blue", 0x000080 }, + { "navy", 0x000080 }, + { "old lace", 0xfdf5e6 }, + { "olive drab", 0x6b8e23 }, + { "olive", 0x808000 }, + { "orange red", 0xff4500 }, + { "orange", 0xffa500 }, + { "orange1", 0xffa500 }, + { "orange2", 0xee9a00 }, + { "orange3", 0xcd8500 }, + { "orange4", 0x8b5a00 }, + { "orchid", 0xda70d6 }, + { "orchid1", 0xff83fa }, + { "orchid2", 0xee7ae9 }, + { "orchid3", 0xcd69c9 }, + { "orchid4", 0x8b4789 }, + { "pale goldenrod", 0xeee8aa }, + { "pale green", 0x98fb98 }, + { "pale turquoise", 0xafeeee }, + { "pale violet red", 0xdb7093 }, + { "papaya whip", 0xffefd5 }, + { "peach puff", 0xffdab9 }, + { "peru", 0xcd853f }, + { "pink", 0xffc0cb }, + { "pink1", 0xffb5c5 }, + { "pink2", 0xeea9b8 }, + { "pink3", 0xcd919e }, + { "pink4", 0x8b636c }, + { "plum", 0xdda0dd }, + { "plum1", 0xffbbff }, + { "plum2", 0xeeaeee }, + { "plum3", 0xcd96cd }, + { "plum4", 0x8b668b }, + { "powder blue", 0xb0e0e6 }, + { "purple", 0xa020f0 }, + { "purple1", 0x9b30ff }, + { "purple2", 0x912cee }, + { "purple3", 0x7d26cd }, + { "purple4", 0x551a8b }, + { "rebecca purple", 0x663399 }, + { "red", 0xff0000 }, + { "red1", 0xff0000 }, + { "red2", 0xee0000 }, + { "red3", 0xcd0000 }, + { "red4", 0x8b0000 }, + { "rosy brown", 0xbc8f8f }, + { "royal blue", 0x4169e1 }, + { "saddle brown", 0x8b4513 }, + { "salmon", 0xfa8072 }, + { "salmon1", 0xff8c69 }, + { "salmon2", 0xee8262 }, + { "salmon3", 0xcd7054 }, + { "salmon4", 0x8b4c39 }, + { "sandy brown", 0xf4a460 }, + { "sea green", 0x2e8b57 }, + { "seashell", 0xfff5ee }, + { "seashell1", 0xfff5ee }, + { "seashell2", 0xeee5de }, + { "seashell3", 0xcdc5bf }, + { "seashell4", 0x8b8682 }, + { "sienna", 0xa0522d }, + { "sienna1", 0xff8247 }, + { "sienna2", 0xee7942 }, + { "sienna3", 0xcd6839 }, + { "sienna4", 0x8b4726 }, + { "silver", 0xc0c0c0 }, + { "sky blue", 0x87ceeb }, + { "slate blue", 0x6a5acd }, + { "slate gray", 0x708090 }, + { "slate grey", 0x708090 }, + { "snow", 0xfffafa }, + { "snow1", 0xfffafa }, + { "snow2", 0xeee9e9 }, + { "snow3", 0xcdc9c9 }, + { "snow4", 0x8b8989 }, + { "spring green", 0x00ff7f }, + { "steel blue", 0x4682b4 }, + { "tan", 0xd2b48c }, + { "tan1", 0xffa54f }, + { "tan2", 0xee9a49 }, + { "tan3", 0xcd853f }, + { "tan4", 0x8b5a2b }, + { "teal", 0x008080 }, + { "thistle", 0xd8bfd8 }, + { "thistle1", 0xffe1ff }, + { "thistle2", 0xeed2ee }, + { "thistle3", 0xcdb5cd }, + { "thistle4", 0x8b7b8b }, + { "tomato", 0xff6347 }, + { "tomato1", 0xff6347 }, + { "tomato2", 0xee5c42 }, + { "tomato3", 0xcd4f39 }, + { "tomato4", 0x8b3626 }, + { "turquoise", 0x40e0d0 }, + { "turquoise1", 0x00f5ff }, + { "turquoise2", 0x00e5ee }, + { "turquoise3", 0x00c5cd }, + { "turquoise4", 0x00868b }, + { "violet red", 0xd02090 }, + { "violet", 0xee82ee }, + { "web gray", 0x808080 }, + { "web green", 0x008000 }, + { "web grey", 0x808080 }, + { "web maroon", 0x800000 }, + { "web purple", 0x800080 }, + { "wheat", 0xf5deb3 }, + { "wheat1", 0xffe7ba }, + { "wheat2", 0xeed8ae }, + { "wheat3", 0xcdba96 }, + { "wheat4", 0x8b7e66 }, + { "white smoke", 0xf5f5f5 }, + { "white", 0xffffff }, + { "x11 gray", 0xbebebe }, + { "x11 green", 0x00ff00 }, + { "x11 grey", 0xbebebe }, + { "x11 maroon", 0xb03060 }, + { "x11 purple", 0xa020f0 }, + { "yellow green", 0x9acd32 }, + { "yellow", 0xffff00 }, + { "yellow1", 0xffff00 }, + { "yellow2", 0xeeee00 }, + { "yellow3", 0xcdcd00 }, + { "yellow4", 0x8b8b00 } + }; + u_int i; + int c; + + if (strncmp(name, "grey", 4) == 0 || strncmp(name, "gray", 4) == 0) { + if (!isdigit((u_char)name[4])) + return (0xbebebe|COLOUR_FLAG_RGB); + c = round(2.55 * atoi(name + 4)); + if (c < 0 || c > 255) + return (-1); + return (colour_join_rgb(c, c, c)); + } + for (i = 0; i < nitems(colours); i++) { + if (strcasecmp(colours[i].name, name) == 0) + return (colours[i].c|COLOUR_FLAG_RGB); + } + return (-1); +} diff --git a/file.c b/file.c index f7f99111..baa2bd58 100644 --- a/file.c +++ b/file.c @@ -27,10 +27,17 @@ #include "tmux.h" +/* + * IPC file handling. Both client and server use the same data structures + * (client_file and client_files) to store list of active files. Most functions + * are for use either in client or server but not both. + */ + static int file_next_stream = 3; RB_GENERATE(client_files, client_file, entry, file_cmp); +/* Get path for file, either as given or from working directory. */ static char * file_get_path(struct client *c, const char *file) { @@ -43,6 +50,7 @@ file_get_path(struct client *c, const char *file) return (path); } +/* Tree comparison function. */ int file_cmp(struct client_file *cf1, struct client_file *cf2) { @@ -53,11 +61,47 @@ file_cmp(struct client_file *cf1, struct client_file *cf2) return (0); } +/* + * Create a file object in the client process - the peer is the server to send + * messages to. Check callback is fired when the file is finished with so the + * process can decide if it needs to exit (if it is waiting for files to + * flush). + */ struct client_file * -file_create(struct client *c, int stream, client_file_cb cb, void *cbdata) +file_create_with_peer(struct tmuxpeer *peer, struct client_files *files, + int stream, client_file_cb cb, void *cbdata) { struct client_file *cf; + cf = xcalloc(1, sizeof *cf); + cf->c = NULL; + cf->references = 1; + cf->stream = stream; + + cf->buffer = evbuffer_new(); + if (cf->buffer == NULL) + fatalx("out of memory"); + + cf->cb = cb; + cf->data = cbdata; + + cf->peer = peer; + cf->tree = files; + RB_INSERT(client_files, files, cf); + + return (cf); +} + +/* Create a file object in the server, communicating with the given client. */ +struct client_file * +file_create_with_client(struct client *c, int stream, client_file_cb cb, + void *cbdata) +{ + struct client_file *cf; + + if (c != NULL && (c->flags & CLIENT_ATTACHED)) + c = NULL; + cf = xcalloc(1, sizeof *cf); cf->c = c; cf->references = 1; @@ -71,6 +115,8 @@ file_create(struct client *c, int stream, client_file_cb cb, void *cbdata) cf->data = cbdata; if (cf->c != NULL) { + cf->peer = cf->c->peer; + cf->tree = &cf->c->files; RB_INSERT(client_files, &cf->c->files, cf); cf->c->references++; } @@ -78,6 +124,7 @@ file_create(struct client *c, int stream, client_file_cb cb, void *cbdata) return (cf); } +/* Free a file. */ void file_free(struct client_file *cf) { @@ -87,13 +134,15 @@ file_free(struct client_file *cf) evbuffer_free(cf->buffer); free(cf->path); - if (cf->c != NULL) { - RB_REMOVE(client_files, &cf->c->files, cf); + if (cf->tree != NULL) + RB_REMOVE(client_files, cf->tree, cf); + if (cf->c != NULL) server_client_unref(cf->c); - } + free(cf); } +/* Event to fire the done callback. */ static void file_fire_done_cb(__unused int fd, __unused short events, void *arg) { @@ -105,21 +154,22 @@ file_fire_done_cb(__unused int fd, __unused short events, void *arg) file_free(cf); } +/* Add an event to fire the done callback (used by the server). */ void file_fire_done(struct client_file *cf) { event_once(-1, EV_TIMEOUT, file_fire_done_cb, cf, NULL); } +/* Fire the read callback. */ void file_fire_read(struct client_file *cf) { - struct client *c = cf->c; - if (cf->cb != NULL) - cf->cb(c, cf->path, cf->error, 0, cf->buffer, cf->data); + cf->cb(cf->c, cf->path, cf->error, 0, cf->buffer, cf->data); } +/* Can this file be printed to? */ int file_can_print(struct client *c) { @@ -130,6 +180,7 @@ file_can_print(struct client *c) return (1); } +/* Print a message to a file. */ void file_print(struct client *c, const char *fmt, ...) { @@ -140,6 +191,7 @@ file_print(struct client *c, const char *fmt, ...) va_end(ap); } +/* Print a message to a file. */ void file_vprint(struct client *c, const char *fmt, va_list ap) { @@ -151,7 +203,7 @@ file_vprint(struct client *c, const char *fmt, va_list ap) find.stream = 1; if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) { - cf = file_create(c, 1, NULL, NULL); + cf = file_create_with_client(c, 1, NULL, NULL); cf->path = xstrdup("-"); evbuffer_add_vprintf(cf->buffer, fmt, ap); @@ -166,6 +218,7 @@ file_vprint(struct client *c, const char *fmt, va_list ap) } } +/* Print a buffer to a file. */ void file_print_buffer(struct client *c, void *data, size_t size) { @@ -177,7 +230,7 @@ file_print_buffer(struct client *c, void *data, size_t size) find.stream = 1; if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) { - cf = file_create(c, 1, NULL, NULL); + cf = file_create_with_client(c, 1, NULL, NULL); cf->path = xstrdup("-"); evbuffer_add(cf->buffer, data, size); @@ -192,6 +245,7 @@ file_print_buffer(struct client *c, void *data, size_t size) } } +/* Report an error to a file. */ void file_error(struct client *c, const char *fmt, ...) { @@ -206,7 +260,7 @@ file_error(struct client *c, const char *fmt, ...) find.stream = 2; if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) { - cf = file_create(c, 2, NULL, NULL); + cf = file_create_with_client(c, 2, NULL, NULL); cf->path = xstrdup("-"); evbuffer_add_vprintf(cf->buffer, fmt, ap); @@ -223,19 +277,21 @@ file_error(struct client *c, const char *fmt, ...) va_end(ap); } +/* Write data to a file. */ void file_write(struct client *c, const char *path, int flags, const void *bdata, size_t bsize, client_file_cb cb, void *cbdata) { struct client_file *cf; - FILE *f; struct msg_write_open *msg; size_t msglen; int fd = -1; + u_int stream = file_next_stream++; + FILE *f; const char *mode; if (strcmp(path, "-") == 0) { - cf = file_create(c, file_next_stream++, cb, cbdata); + cf = file_create_with_client(c, stream, cb, cbdata); cf->path = xstrdup("-"); fd = STDOUT_FILENO; @@ -248,7 +304,7 @@ file_write(struct client *c, const char *path, int flags, const void *bdata, goto skip; } - cf = file_create(c, file_next_stream++, cb, cbdata); + cf = file_create_with_client(c, stream, cb, cbdata); cf->path = file_get_path(c, path); if (c == NULL || c->flags & CLIENT_ATTACHED) { @@ -283,7 +339,7 @@ skip: msg->fd = fd; msg->flags = flags; memcpy(msg + 1, cf->path, msglen - sizeof *msg); - if (proc_send(c->peer, MSG_WRITE_OPEN, -1, msg, msglen) != 0) { + if (proc_send(cf->peer, MSG_WRITE_OPEN, -1, msg, msglen) != 0) { free(msg); cf->error = EINVAL; goto done; @@ -295,18 +351,21 @@ done: file_fire_done(cf); } +/* Read a file. */ void file_read(struct client *c, const char *path, client_file_cb cb, void *cbdata) { struct client_file *cf; - FILE *f; struct msg_read_open *msg; - size_t msglen, size; + size_t msglen; int fd = -1; + u_int stream = file_next_stream++; + FILE *f; + size_t size; char buffer[BUFSIZ]; if (strcmp(path, "-") == 0) { - cf = file_create(c, file_next_stream++, cb, cbdata); + cf = file_create_with_client(c, stream, cb, cbdata); cf->path = xstrdup("-"); fd = STDIN_FILENO; @@ -319,7 +378,7 @@ file_read(struct client *c, const char *path, client_file_cb cb, void *cbdata) goto skip; } - cf = file_create(c, file_next_stream++, cb, cbdata); + cf = file_create_with_client(c, stream, cb, cbdata); cf->path = file_get_path(c, path); if (c == NULL || c->flags & CLIENT_ATTACHED) { @@ -355,7 +414,7 @@ skip: msg->stream = cf->stream; msg->fd = fd; memcpy(msg + 1, cf->path, msglen - sizeof *msg); - if (proc_send(c->peer, MSG_READ_OPEN, -1, msg, msglen) != 0) { + if (proc_send(cf->peer, MSG_READ_OPEN, -1, msg, msglen) != 0) { free(msg); cf->error = EINVAL; goto done; @@ -367,21 +426,21 @@ done: file_fire_done(cf); } +/* Push event, fired if there is more writing to be done. */ static void file_push_cb(__unused int fd, __unused short events, void *arg) { struct client_file *cf = arg; - struct client *c = cf->c; - if (~c->flags & CLIENT_DEAD) + if (cf->c == NULL || ~cf->c->flags & CLIENT_DEAD) file_push(cf); file_free(cf); } +/* Push uwritten data to the client for a file, if it will accept it. */ void file_push(struct client_file *cf) { - struct client *c = cf->c; struct msg_write_data *msg; size_t msglen, sent, left; struct msg_write_close close; @@ -397,21 +456,364 @@ file_push(struct client_file *cf) msg = xrealloc(msg, msglen); msg->stream = cf->stream; memcpy(msg + 1, EVBUFFER_DATA(cf->buffer), sent); - if (proc_send(c->peer, MSG_WRITE, -1, msg, msglen) != 0) + if (proc_send(cf->peer, MSG_WRITE, -1, msg, msglen) != 0) break; evbuffer_drain(cf->buffer, sent); left = EVBUFFER_LENGTH(cf->buffer); - log_debug("%s: file %d sent %zu, left %zu", c->name, cf->stream, - sent, left); + log_debug("file %d sent %zu, left %zu", cf->stream, sent, left); } if (left != 0) { cf->references++; event_once(-1, EV_TIMEOUT, file_push_cb, cf, NULL); } else if (cf->stream > 2) { close.stream = cf->stream; - proc_send(c->peer, MSG_WRITE_CLOSE, -1, &close, sizeof close); + proc_send(cf->peer, MSG_WRITE_CLOSE, -1, &close, sizeof close); file_fire_done(cf); } free(msg); } + +/* Check if any files have data left to write. */ +int +file_write_left(struct client_files *files) +{ + struct client_file *cf; + size_t left; + int waiting = 0; + + RB_FOREACH(cf, client_files, files) { + if (cf->event == NULL) + continue; + left = EVBUFFER_LENGTH(cf->event->output); + if (left != 0) { + waiting++; + log_debug("file %u %zu bytes left", cf->stream, left); + } + } + return (waiting != 0); +} + +/* Client file write error callback. */ +static void +file_write_error_callback(__unused struct bufferevent *bev, __unused short what, + void *arg) +{ + struct client_file *cf = arg; + + log_debug("write error file %d", cf->stream); + + if (cf->cb != NULL) + cf->cb(NULL, NULL, 0, -1, NULL, cf->data); + + bufferevent_free(cf->event); + cf->event = NULL; + + close(cf->fd); + cf->fd = -1; +} + +/* Client file write callback. */ +static void +file_write_callback(__unused struct bufferevent *bev, void *arg) +{ + struct client_file *cf = arg; + + log_debug("write check file %d", cf->stream); + + if (cf->cb != NULL) + cf->cb(NULL, NULL, 0, -1, NULL, cf->data); + + if (cf->closed && EVBUFFER_LENGTH(cf->event->output) == 0) { + bufferevent_free(cf->event); + close(cf->fd); + RB_REMOVE(client_files, cf->tree, cf); + file_free(cf); + } +} + +/* Handle a file write open message (client). */ +void +file_write_open(struct client_files *files, struct tmuxpeer *peer, + struct imsg *imsg, int allow_streams, int close_received, + client_file_cb cb, void *cbdata) +{ + struct msg_write_open *msg = imsg->data; + size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; + const char *path; + struct msg_write_ready reply; + struct client_file find, *cf; + const int flags = O_NONBLOCK|O_WRONLY|O_CREAT; + int error = 0; + + if (msglen < sizeof *msg) + fatalx("bad MSG_WRITE_OPEN size"); + if (msglen == sizeof *msg) + path = "-"; + else + path = (const char *)(msg + 1); + log_debug("open write file %d %s", msg->stream, path); + + find.stream = msg->stream; + if ((cf = RB_FIND(client_files, files, &find)) != NULL) { + error = EBADF; + goto reply; + } + cf = file_create_with_peer(peer, files, msg->stream, cb, cbdata); + if (cf->closed) { + error = EBADF; + goto reply; + } + + cf->fd = -1; + if (msg->fd == -1) + cf->fd = open(path, msg->flags|flags, 0644); + else if (allow_streams) { + if (msg->fd != STDOUT_FILENO && msg->fd != STDERR_FILENO) + errno = EBADF; + else { + cf->fd = dup(msg->fd); + if (close_received) + close(msg->fd); /* can only be used once */ + } + } else + errno = EBADF; + if (cf->fd == -1) { + error = errno; + goto reply; + } + + cf->event = bufferevent_new(cf->fd, NULL, file_write_callback, + file_write_error_callback, cf); + bufferevent_enable(cf->event, EV_WRITE); + goto reply; + +reply: + reply.stream = msg->stream; + reply.error = error; + proc_send(peer, MSG_WRITE_READY, -1, &reply, sizeof reply); +} + +/* Handle a file write data message (client). */ +void +file_write_data(struct client_files *files, struct imsg *imsg) +{ + struct msg_write_data *msg = imsg->data; + size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; + struct client_file find, *cf; + size_t size = msglen - sizeof *msg; + + if (msglen < sizeof *msg) + fatalx("bad MSG_WRITE size"); + find.stream = msg->stream; + if ((cf = RB_FIND(client_files, files, &find)) == NULL) + fatalx("unknown stream number"); + log_debug("write %zu to file %d", size, cf->stream); + + if (cf->event != NULL) + bufferevent_write(cf->event, msg + 1, size); +} + +/* Handle a file write close message (client). */ +void +file_write_close(struct client_files *files, struct imsg *imsg) +{ + struct msg_write_close *msg = imsg->data; + size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; + struct client_file find, *cf; + + if (msglen != sizeof *msg) + fatalx("bad MSG_WRITE_CLOSE size"); + find.stream = msg->stream; + if ((cf = RB_FIND(client_files, files, &find)) == NULL) + fatalx("unknown stream number"); + log_debug("close file %d", cf->stream); + + if (cf->event == NULL || EVBUFFER_LENGTH(cf->event->output) == 0) { + if (cf->event != NULL) + bufferevent_free(cf->event); + if (cf->fd != -1) + close(cf->fd); + RB_REMOVE(client_files, files, cf); + file_free(cf); + } +} + +/* Client file read error callback. */ +static void +file_read_error_callback(__unused struct bufferevent *bev, __unused short what, + void *arg) +{ + struct client_file *cf = arg; + struct msg_read_done msg; + + log_debug("read error file %d", cf->stream); + + msg.stream = cf->stream; + msg.error = 0; + proc_send(cf->peer, MSG_READ_DONE, -1, &msg, sizeof msg); + + bufferevent_free(cf->event); + close(cf->fd); + RB_REMOVE(client_files, cf->tree, cf); + file_free(cf); +} + +/* Client file read callback. */ +static void +file_read_callback(__unused struct bufferevent *bev, void *arg) +{ + struct client_file *cf = arg; + void *bdata; + size_t bsize; + struct msg_read_data *msg; + size_t msglen; + + msg = xmalloc(sizeof *msg); + for (;;) { + bdata = EVBUFFER_DATA(cf->event->input); + bsize = EVBUFFER_LENGTH(cf->event->input); + + if (bsize == 0) + break; + if (bsize > MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg) + bsize = MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg; + log_debug("read %zu from file %d", bsize, cf->stream); + + msglen = (sizeof *msg) + bsize; + msg = xrealloc(msg, msglen); + msg->stream = cf->stream; + memcpy(msg + 1, bdata, bsize); + proc_send(cf->peer, MSG_READ, -1, msg, msglen); + + evbuffer_drain(cf->event->input, bsize); + } + free(msg); +} + +/* Handle a file read open message (client). */ +void +file_read_open(struct client_files *files, struct tmuxpeer *peer, + struct imsg *imsg, int allow_streams, int close_received, client_file_cb cb, + void *cbdata) +{ + struct msg_read_open *msg = imsg->data; + size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; + const char *path; + struct msg_read_done reply; + struct client_file find, *cf; + const int flags = O_NONBLOCK|O_RDONLY; + int error; + + if (msglen < sizeof *msg) + fatalx("bad MSG_READ_OPEN size"); + if (msglen == sizeof *msg) + path = "-"; + else + path = (const char *)(msg + 1); + log_debug("open read file %d %s", msg->stream, path); + + find.stream = msg->stream; + if ((cf = RB_FIND(client_files, files, &find)) != NULL) { + error = EBADF; + goto reply; + } + cf = file_create_with_peer(peer, files, msg->stream, cb, cbdata); + if (cf->closed) { + error = EBADF; + goto reply; + } + + cf->fd = -1; + if (msg->fd == -1) + cf->fd = open(path, flags); + else if (allow_streams) { + if (msg->fd != STDIN_FILENO) + errno = EBADF; + else { + cf->fd = dup(msg->fd); + if (close_received) + close(msg->fd); /* can only be used once */ + } + } else + errno = EBADF; + if (cf->fd == -1) { + error = errno; + goto reply; + } + + cf->event = bufferevent_new(cf->fd, file_read_callback, NULL, + file_read_error_callback, cf); + bufferevent_enable(cf->event, EV_READ); + return; + +reply: + reply.stream = msg->stream; + reply.error = error; + proc_send(peer, MSG_READ_DONE, -1, &reply, sizeof reply); +} + +/* Handle a write ready message (server). */ +void +file_write_ready(struct client_files *files, struct imsg *imsg) +{ + struct msg_write_ready *msg = imsg->data; + size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; + struct client_file find, *cf; + + if (msglen != sizeof *msg) + fatalx("bad MSG_WRITE_READY size"); + find.stream = msg->stream; + if ((cf = RB_FIND(client_files, files, &find)) == NULL) + return; + if (msg->error != 0) { + cf->error = msg->error; + file_fire_done(cf); + } else + file_push(cf); +} + +/* Handle read data message (server). */ +void +file_read_data(struct client_files *files, struct imsg *imsg) +{ + struct msg_read_data *msg = imsg->data; + size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; + struct client_file find, *cf; + void *bdata = msg + 1; + size_t bsize = msglen - sizeof *msg; + + if (msglen < sizeof *msg) + fatalx("bad MSG_READ_DATA size"); + find.stream = msg->stream; + if ((cf = RB_FIND(client_files, files, &find)) == NULL) + return; + + log_debug("file %d read %zu bytes", cf->stream, bsize); + if (cf->error == 0) { + if (evbuffer_add(cf->buffer, bdata, bsize) != 0) { + cf->error = ENOMEM; + file_fire_done(cf); + } else + file_fire_read(cf); + } +} + +/* Handle a read done message (server). */ +void +file_read_done(struct client_files *files, struct imsg *imsg) +{ + struct msg_read_done *msg = imsg->data; + size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; + struct client_file find, *cf; + + if (msglen != sizeof *msg) + fatalx("bad MSG_READ_DONE size"); + find.stream = msg->stream; + if ((cf = RB_FIND(client_files, files, &find)) == NULL) + return; + + log_debug("file %d read done", cf->stream); + cf->error = msg->error; + file_fire_done(cf); +} diff --git a/format.c b/format.c index cf82b478..20a22d80 100644 --- a/format.c +++ b/format.c @@ -878,6 +878,28 @@ format_cb_pane_tabs(struct format_tree *ft) return (value); } +/* Callback for pane_fg. */ +static char * +format_cb_pane_fg(struct format_tree *ft) +{ + struct window_pane *wp = ft->wp; + struct grid_cell gc; + + tty_default_colours(&gc, wp); + return (xstrdup(colour_tostring(gc.fg))); +} + +/* Callback for pane_bg. */ +static char * +format_cb_pane_bg(struct format_tree *ft) +{ + struct window_pane *wp = ft->wp; + struct grid_cell gc; + + tty_default_colours(&gc, wp); + return (xstrdup(colour_tostring(gc.bg))); +} + /* Callback for session_group_list. */ static char * format_cb_session_group_list(struct format_tree *ft) @@ -3195,6 +3217,8 @@ format_defaults_pane(struct format_tree *ft, struct window_pane *wp) !!(wp->base.mode & MODE_MOUSE_SGR)); format_add_cb(ft, "pane_tabs", format_cb_pane_tabs); + format_add_cb(ft, "pane_fg", format_cb_pane_fg); + format_add_cb(ft, "pane_bg", format_cb_pane_bg); } /* Set default format keys for paste buffer. */ diff --git a/input.c b/input.c index 8b7ba08a..590a157d 100644 --- a/input.c +++ b/input.c @@ -138,6 +138,8 @@ static void input_osc_10(struct input_ctx *, const char *); static void input_osc_11(struct input_ctx *, const char *); static void input_osc_52(struct input_ctx *, const char *); static void input_osc_104(struct input_ctx *, const char *); +static void input_osc_110(struct input_ctx *, const char *); +static void input_osc_111(struct input_ctx *, const char *); /* Transition entry/exit handlers. */ static void input_clear(struct input_ctx *); @@ -2099,6 +2101,7 @@ input_csi_dispatch_sgr(struct input_ctx *ictx) gc->attr |= GRID_ATTR_UNDERSCORE; break; case 5: + case 6: gc->attr |= GRID_ATTR_BLINK; break; case 7: @@ -2110,6 +2113,10 @@ input_csi_dispatch_sgr(struct input_ctx *ictx) case 9: gc->attr |= GRID_ATTR_STRIKETHROUGH; break; + case 21: + gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE; + gc->attr |= GRID_ATTR_UNDERSCORE_2; + break; case 22: gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM); break; @@ -2304,6 +2311,12 @@ input_exit_osc(struct input_ctx *ictx) case 104: input_osc_104(ictx, p); break; + case 110: + input_osc_110(ictx, p); + break; + case 111: + input_osc_111(ictx, p); + break; case 112: if (*p == '\0') /* no arguments allowed */ screen_set_cursor_colour(sctx->s, ""); @@ -2422,50 +2435,41 @@ input_top_bit_set(struct input_ctx *ictx) /* Parse colour from OSC. */ static int -input_osc_parse_colour(const char *p, u_int *r, u_int *g, u_int *b) +input_osc_parse_colour(const char *p) { - u_int rsize, gsize, bsize; - const char *cp, *s = p; + double c, m, y, k = 0; + u_int r, g, b; + size_t len = strlen(p); + int colour = -1; + char *copy; - if (sscanf(p, "rgb:%x/%x/%x", r, g, b) != 3) - return (0); - p += 4; - - cp = strchr(p, '/'); - rsize = cp - p; - if (rsize == 1) - (*r) = (*r) | ((*r) << 4); - else if (rsize == 3) - (*r) >>= 4; - else if (rsize == 4) - (*r) >>= 8; - else if (rsize != 2) - return (0); - - p = cp + 1; - cp = strchr(p, '/'); - gsize = cp - p; - if (gsize == 1) - (*g) = (*g) | ((*g) << 4); - else if (gsize == 3) - (*g) >>= 4; - else if (gsize == 4) - (*g) >>= 8; - else if (gsize != 2) - return (0); - - bsize = strlen(cp + 1); - if (bsize == 1) - (*b) = (*b) | ((*b) << 4); - else if (bsize == 3) - (*b) >>= 4; - else if (bsize == 4) - (*b) >>= 8; - else if (bsize != 2) - return (0); - - log_debug("%s: %s = %02x%02x%02x", __func__, s, *r, *g, *b); - return (1); + if ((len == 12 && sscanf(p, "rgb:%02x/%02x/%02x", &r, &g, &b) == 3) || + (len == 7 && sscanf(p, "#%02x%02x%02x", &r, &g, &b) == 3) || + sscanf(p, "%d,%d,%d", &r, &g, &b) == 3) + colour = colour_join_rgb(r, g, b); + else if ((len == 18 && + sscanf(p, "rgb:%04x/%04x/%04x", &r, &g, &b) == 3) || + (len == 13 && sscanf(p, "#%04x%04x%04x", &r, &g, &b) == 3)) + colour = colour_join_rgb(r >> 8, g >> 8, b >> 8); + else if ((sscanf(p, "cmyk:%lf/%lf/%lf/%lf", &c, &m, &y, &k) == 4 || + sscanf(p, "cmy:%lf/%lf/%lf", &c, &m, &y) == 3) && + c >= 0 && c <= 1 && m >= 0 && m <= 1 && + y >= 0 && y <= 1 && k >= 0 && k <= 1) { + colour = colour_join_rgb( + (1 - c) * (1 - k) * 255, + (1 - m) * (1 - k) * 255, + (1 - y) * (1 - k) * 255); + } else { + while (*p == ' ') + p++; + while (len != 0 && p[len - 1] == ' ') + len--; + copy = xstrndup(p, len); + colour = colour_byname(copy); + free(copy); + } + log_debug("%s: %s = %s", __func__, p, colour_tostring(colour)); + return (colour); } /* Reply to a colour request. */ @@ -2493,7 +2497,7 @@ input_osc_4(struct input_ctx *ictx, const char *p) struct window_pane *wp = ictx->wp; char *copy, *s, *next = NULL; long idx; - u_int r, g, b; + int c; if (wp == NULL) return; @@ -2507,12 +2511,12 @@ input_osc_4(struct input_ctx *ictx, const char *p) goto bad; s = strsep(&next, ";"); - if (!input_osc_parse_colour(s, &r, &g, &b)) { + if ((c = input_osc_parse_colour(s)) == -1) { s = next; continue; } - window_pane_set_palette(wp, idx, colour_join_rgb(r, g, b)); + window_pane_set_palette(wp, idx, c); s = next; } @@ -2530,7 +2534,7 @@ input_osc_10(struct input_ctx *ictx, const char *p) { struct window_pane *wp = ictx->wp; struct grid_cell defaults; - u_int r, g, b; + int c; if (wp == NULL) return; @@ -2541,9 +2545,9 @@ input_osc_10(struct input_ctx *ictx, const char *p) return; } - if (!input_osc_parse_colour(p, &r, &g, &b)) + if ((c = input_osc_parse_colour(p)) == -1) goto bad; - wp->fg = colour_join_rgb(r, g, b); + wp->fg = c; wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED); return; @@ -2552,13 +2556,29 @@ bad: log_debug("bad OSC 10: %s", p); } +/* Handle the OSC 110 sequence for resetting background colour. */ +static void +input_osc_110(struct input_ctx *ictx, const char *p) +{ + struct window_pane *wp = ictx->wp; + + if (wp == NULL) + return; + + if (*p != '\0') + return; + + wp->fg = 8; + wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED); +} + /* Handle the OSC 11 sequence for setting and querying background colour. */ static void input_osc_11(struct input_ctx *ictx, const char *p) { struct window_pane *wp = ictx->wp; struct grid_cell defaults; - u_int r, g, b; + int c; if (wp == NULL) return; @@ -2569,9 +2589,9 @@ input_osc_11(struct input_ctx *ictx, const char *p) return; } - if (!input_osc_parse_colour(p, &r, &g, &b)) - goto bad; - wp->bg = colour_join_rgb(r, g, b); + if ((c = input_osc_parse_colour(p)) == -1) + goto bad; + wp->bg = c; wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED); return; @@ -2580,6 +2600,22 @@ bad: log_debug("bad OSC 11: %s", p); } +/* Handle the OSC 111 sequence for resetting background colour. */ +static void +input_osc_111(struct input_ctx *ictx, const char *p) +{ + struct window_pane *wp = ictx->wp; + + if (wp == NULL) + return; + + if (*p != '\0') + return; + + wp->bg = 8; + wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED); +} + /* Handle the OSC 52 sequence for setting the clipboard. */ static void input_osc_52(struct input_ctx *ictx, const char *p) diff --git a/proc.c b/proc.c index 6d64b0bb..a1a2b36a 100644 --- a/proc.c +++ b/proc.c @@ -17,6 +17,8 @@ */ #include +#include +#include #include #include @@ -46,6 +48,8 @@ struct tmuxproc { struct event ev_sigusr1; struct event ev_sigusr2; struct event ev_sigwinch; + + TAILQ_HEAD(, tmuxpeer) peers; }; struct tmuxpeer { @@ -59,6 +63,8 @@ struct tmuxpeer { void (*dispatchcb)(struct imsg *, void *); void *arg; + + TAILQ_ENTRY(tmuxpeer) entry; }; static int peer_check_version(struct tmuxpeer *, struct imsg *); @@ -202,6 +208,7 @@ proc_start(const char *name) tp = xcalloc(1, sizeof *tp); tp->name = xstrdup(name); + TAILQ_INIT(&tp->peers); return (tp); } @@ -219,6 +226,10 @@ proc_loop(struct tmuxproc *tp, int (*loopcb)(void)) void proc_exit(struct tmuxproc *tp) { + struct tmuxpeer *peer; + + TAILQ_FOREACH(peer, &tp->peers, entry) + imsg_flush(&peer->ibuf); tp->exit = 1; } @@ -309,6 +320,7 @@ proc_add_peer(struct tmuxproc *tp, int fd, event_set(&peer->event, fd, EV_READ, proc_event_cb, peer); log_debug("add peer %p: %d (%p)", peer, fd, arg); + TAILQ_INSERT_TAIL(&tp->peers, peer, entry); proc_update_event(peer); return (peer); @@ -317,6 +329,7 @@ proc_add_peer(struct tmuxproc *tp, int fd, void proc_remove_peer(struct tmuxpeer *peer) { + TAILQ_REMOVE(&peer->parent->peers, peer, entry); log_debug("remove peer %p", peer); event_del(&peer->event); @@ -337,3 +350,27 @@ proc_toggle_log(struct tmuxproc *tp) { log_toggle(tp->name); } + +pid_t +proc_fork_and_daemon(int *fd) +{ + pid_t pid; + int pair[2]; + + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0) + fatal("socketpair failed"); + switch (pid = fork()) { + case -1: + fatal("fork failed"); + case 0: + close(pair[0]); + *fd = pair[1]; + if (daemon(1, 0) != 0) + fatal("daemon failed"); + return (0); + default: + close(pair[1]); + *fd = pair[0]; + return (pid); + } +} diff --git a/server-client.c b/server-client.c index 748238d8..66ba2c5a 100644 --- a/server-client.c +++ b/server-client.c @@ -48,12 +48,6 @@ static void server_client_dispatch(struct imsg *, void *); static void server_client_dispatch_command(struct client *, struct imsg *); static void server_client_dispatch_identify(struct client *, struct imsg *); static void server_client_dispatch_shell(struct client *); -static void server_client_dispatch_write_ready(struct client *, - struct imsg *); -static void server_client_dispatch_read_data(struct client *, - struct imsg *); -static void server_client_dispatch_read_done(struct client *, - struct imsg *); /* Compare client windows. */ static int @@ -2067,13 +2061,13 @@ server_client_dispatch(struct imsg *imsg, void *arg) server_client_dispatch_shell(c); break; case MSG_WRITE_READY: - server_client_dispatch_write_ready(c, imsg); + file_write_ready(&c->files, imsg); break; case MSG_READ: - server_client_dispatch_read_data(c, imsg); + file_read_data(&c->files, imsg); break; case MSG_READ_DONE: - server_client_dispatch_read_done(c, imsg); + file_read_done(&c->files, imsg); break; } } @@ -2303,71 +2297,6 @@ server_client_dispatch_shell(struct client *c) proc_kill_peer(c->peer); } -/* Handle write ready message. */ -static void -server_client_dispatch_write_ready(struct client *c, struct imsg *imsg) -{ - struct msg_write_ready *msg = imsg->data; - size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; - struct client_file find, *cf; - - if (msglen != sizeof *msg) - fatalx("bad MSG_WRITE_READY size"); - find.stream = msg->stream; - if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) - return; - if (msg->error != 0) { - cf->error = msg->error; - file_fire_done(cf); - } else - file_push(cf); -} - -/* Handle read data message. */ -static void -server_client_dispatch_read_data(struct client *c, struct imsg *imsg) -{ - struct msg_read_data *msg = imsg->data; - size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; - struct client_file find, *cf; - void *bdata = msg + 1; - size_t bsize = msglen - sizeof *msg; - - if (msglen < sizeof *msg) - fatalx("bad MSG_READ_DATA size"); - find.stream = msg->stream; - if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) - return; - - log_debug("%s: file %d read %zu bytes", c->name, cf->stream, bsize); - if (cf->error == 0) { - if (evbuffer_add(cf->buffer, bdata, bsize) != 0) { - cf->error = ENOMEM; - file_fire_done(cf); - } else - file_fire_read(cf); - } -} - -/* Handle read done message. */ -static void -server_client_dispatch_read_done(struct client *c, struct imsg *imsg) -{ - struct msg_read_done *msg = imsg->data; - size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; - struct client_file find, *cf; - - if (msglen != sizeof *msg) - fatalx("bad MSG_READ_DONE size"); - find.stream = msg->stream; - if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) - return; - - log_debug("%s: file %d read done", c->name, cf->stream); - cf->error = msg->error; - file_fire_done(cf); -} - /* Get client working directory. */ const char * server_client_get_cwd(struct client *c, struct session *s) diff --git a/server.c b/server.c index 6aee61fc..0260898c 100644 --- a/server.c +++ b/server.c @@ -154,35 +154,22 @@ int server_start(struct tmuxproc *client, int flags, struct event_base *base, int lockfd, char *lockfile) { - int pair[2]; - sigset_t set, oldset; - struct client *c = NULL; - char *cause = NULL; + int fd; + sigset_t set, oldset; + struct client *c = NULL; + char *cause = NULL; sigfillset(&set); sigprocmask(SIG_BLOCK, &set, &oldset); if (~flags & CLIENT_NOFORK) { - if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0) - fatal("socketpair failed"); - - switch (fork()) { - case -1: - fatal("fork failed"); - case 0: - break; - default: + if (proc_fork_and_daemon(&fd) != 0) { sigprocmask(SIG_SETMASK, &oldset, NULL); - close(pair[1]); - return (pair[0]); + return (fd); } - close(pair[0]); - if (daemon(1, 0) != 0) - fatal("daemon failed"); } - - server_client_flags = flags; proc_clear_signals(client, 0); + server_client_flags = flags; if (event_reinit(base) != 0) fatalx("event_reinit failed"); @@ -211,7 +198,7 @@ server_start(struct tmuxproc *client, int flags, struct event_base *base, if (server_fd != -1) server_update_socket(); if (~flags & CLIENT_NOFORK) - c = server_client_create(pair[1]); + c = server_client_create(fd); else options_set_number(global_options, "exit-empty", 0); diff --git a/tmux.1 b/tmux.1 index 8a338e07..ac143a6f 100644 --- a/tmux.1 +++ b/tmux.1 @@ -4778,9 +4778,9 @@ The following variables are available, where appropriate: .It Li "client_prefix" Ta "" Ta "1 if prefix key has been pressed" .It Li "client_readonly" Ta "" Ta "1 if client is readonly" .It Li "client_session" Ta "" Ta "Name of the client's session" +.It Li "client_termfeatures" Ta "" Ta "Terminal features of client, if any" .It Li "client_termname" Ta "" Ta "Terminal name of client" .It Li "client_termtype" Ta "" Ta "Terminal type of client, if available" -.It Li "client_termfeatures" Ta "" Ta "Terminal features of client, if any" .It Li "client_tty" Ta "" Ta "Pseudo terminal of client" .It Li "client_utf8" Ta "" Ta "1 if client supports UTF-8" .It Li "client_width" Ta "" Ta "Width of client" @@ -4828,11 +4828,13 @@ The following variables are available, where appropriate: .It Li "pane_at_left" Ta "" Ta "1 if pane is at the left of window" .It Li "pane_at_right" Ta "" Ta "1 if pane is at the right of window" .It Li "pane_at_top" Ta "" Ta "1 if pane is at the top of window" +.It Li "pane_bg" Ta "" Ta "Pane background colour" .It Li "pane_bottom" Ta "" Ta "Bottom of pane" .It Li "pane_current_command" Ta "" Ta "Current command if available" .It Li "pane_current_path" Ta "" Ta "Current path if available" .It Li "pane_dead" Ta "" Ta "1 if pane is dead" .It Li "pane_dead_status" Ta "" Ta "Exit status of process in dead pane" +.It Li "pane_fg" Ta "" Ta "Pane foreground colour" .It Li "pane_format" Ta "" Ta "1 if format is for a pane" .It Li "pane_height" Ta "" Ta "Height of pane" .It Li "pane_id" Ta "#D" Ta "Unique pane ID" diff --git a/tmux.h b/tmux.h index 3c496ae0..65868760 100644 --- a/tmux.h +++ b/tmux.h @@ -1540,6 +1540,8 @@ typedef void (*client_file_cb) (struct client *, const char *, int, int, struct evbuffer *, void *); struct client_file { struct client *c; + struct tmuxpeer *peer; + struct client_files *tree; int references; int stream; @@ -1898,6 +1900,7 @@ struct tmuxpeer *proc_add_peer(struct tmuxproc *, int, void proc_remove_peer(struct tmuxpeer *); void proc_kill_peer(struct tmuxpeer *); void proc_toggle_log(struct tmuxproc *); +pid_t proc_fork_and_daemon(int *); /* cfg.c */ extern int cfg_finished; @@ -1908,6 +1911,7 @@ int load_cfg(const char *, struct client *, struct cmdq_item *, int, int load_cfg_from_buffer(const void *, size_t, const char *, struct client *, struct cmdq_item *, int, struct cmdq_item **); void set_cfg_file(const char *); +const char *get_cfg_file(void); void printflike(1, 2) cfg_add_cause(const char *, ...); void cfg_print_causes(struct cmdq_item *); void cfg_show_causes(struct session *); @@ -2371,7 +2375,10 @@ void alerts_check_session(struct session *); /* file.c */ int file_cmp(struct client_file *, struct client_file *); RB_PROTOTYPE(client_files, client_file, entry, file_cmp); -struct client_file *file_create(struct client *, int, client_file_cb, void *); +struct client_file *file_create_with_peer(struct tmuxpeer *, + struct client_files *, int, client_file_cb, void *); +struct client_file *file_create_with_client(struct client *, int, + client_file_cb, void *); void file_free(struct client_file *); void file_fire_done(struct client_file *); void file_fire_read(struct client_file *); @@ -2384,6 +2391,16 @@ void file_write(struct client *, const char *, int, const void *, size_t, client_file_cb, void *); void file_read(struct client *, const char *, client_file_cb, void *); void file_push(struct client_file *); +int file_write_left(struct client_files *); +void file_write_open(struct client_files *, struct tmuxpeer *, + struct imsg *, int, int, client_file_cb, void *); +void file_write_data(struct client_files *, struct imsg *); +void file_write_close(struct client_files *, struct imsg *); +void file_read_open(struct client_files *, struct tmuxpeer *, struct imsg *, + int, int, client_file_cb, void *); +void file_write_ready(struct client_files *, struct imsg *); +void file_read_data(struct client_files *, struct imsg *); +void file_read_done(struct client_files *, struct imsg *); /* server.c */ extern struct tmuxproc *server_proc; @@ -2510,6 +2527,7 @@ const char *colour_tostring(int); int colour_fromstring(const char *s); int colour_256toRGB(int); int colour_256to16(int); +int colour_byname(const char *); /* attributes.c */ const char *attributes_tostring(int);