diff options
| -rw-r--r-- | cfg.c | 2 | ||||
| -rw-r--r-- | client.c | 16 | ||||
| -rw-r--r-- | cmd-attach-session.c | 55 | ||||
| -rw-r--r-- | cmd-confirm-before.c | 2 | ||||
| -rw-r--r-- | cmd-find.c | 92 | ||||
| -rw-r--r-- | cmd-load-buffer.c | 2 | ||||
| -rw-r--r-- | cmd-new-session.c | 32 | ||||
| -rw-r--r-- | cmd-switch-client.c | 6 | ||||
| -rw-r--r-- | colour.c | 392 | ||||
| -rw-r--r-- | input.c | 91 | ||||
| -rw-r--r-- | key-bindings.c | 20 | ||||
| -rw-r--r-- | notify.c | 4 | ||||
| -rw-r--r-- | server-client.c | 58 | ||||
| -rw-r--r-- | server.c | 30 | ||||
| -rw-r--r-- | session.c | 31 | ||||
| -rw-r--r-- | tmux.1 | 38 | ||||
| -rw-r--r-- | tmux.c | 2 | ||||
| -rw-r--r-- | tmux.h | 10 | ||||
| -rw-r--r-- | tty-keys.c | 1 | ||||
| -rw-r--r-- | window-choose.c | 6 |
20 files changed, 624 insertions, 266 deletions
@@ -107,7 +107,7 @@ cfg_default_done(unused struct cmd_q *cmdq) */ if (!TAILQ_EMPTY(&cfg_client->cmdq->queue)) cmdq_continue(cfg_client->cmdq); - cfg_client->references--; + server_client_unref(cfg_client); cfg_client = NULL; } } @@ -222,7 +222,7 @@ client_main(int argc, char **argv, int flags) cmdflags = CMD_STARTSERVER; } else if (argc == 0) { msg = MSG_COMMAND; - cmdflags = CMD_STARTSERVER|CMD_CANTNEST; + cmdflags = CMD_STARTSERVER; } else { msg = MSG_COMMAND; @@ -240,24 +240,10 @@ client_main(int argc, char **argv, int flags) TAILQ_FOREACH(cmd, &cmdlist->list, qentry) { if (cmd->entry->flags & CMD_STARTSERVER) cmdflags |= CMD_STARTSERVER; - if (cmd->entry->flags & CMD_CANTNEST) - cmdflags |= CMD_CANTNEST; } cmd_list_free(cmdlist); } - /* - * Check if this could be a nested session, if the command can't nest: - * if the socket path matches $TMUX, this is probably the same server. - */ - if (shell_cmd == NULL && environ_path != NULL && - (cmdflags & CMD_CANTNEST) && - strcmp(socket_path, environ_path) == 0) { - fprintf(stderr, "sessions should be nested with care, " - "unset $TMUX to force\n"); - return (1); - } - /* Establish signal handlers. */ set_signals(client_signal); diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 46d568b4..b2a2f8c5 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -34,18 +34,18 @@ enum cmd_retval cmd_attach_session_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_attach_session_entry = { "attach-session", "attach", - "c:drt:", 0, 0, - "[-dr] [-c working-directory] " CMD_TARGET_SESSION_USAGE, - CMD_CANTNEST|CMD_STARTSERVER, + "c:dErt:", 0, 0, + "[-dEr] [-c working-directory] " CMD_TARGET_SESSION_USAGE, + CMD_STARTSERVER, cmd_attach_session_exec }; enum cmd_retval cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag, - const char *cflag) + const char *cflag, int Eflag) { struct session *s; - struct client *c; + struct client *c = cmdq->client, *c_loop; struct winlink *wl = NULL; struct window *w = NULL; struct window_pane *wp = NULL; @@ -79,8 +79,13 @@ cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag, wl = winlink_find_by_window(&s->windows, w); } - if (cmdq->client == NULL) + if (c == NULL) return (CMD_RETURN_NORMAL); + if (server_client_check_nested(c)) { + cmdq_error(cmdq, "sessions should be nested with care, " + "unset $TMUX to force"); + return (CMD_RETURN_ERROR); + } if (wl != NULL) { if (wp != NULL) @@ -88,18 +93,18 @@ cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag, session_set_current(s, wl); } - if (cmdq->client->session != NULL) { + if (c->session != NULL) { if (dflag) { /* * Can't use server_write_session in case attaching to * the same session as currently attached to. */ - TAILQ_FOREACH(c, &clients, entry) { - if (c->session != s || c == cmdq->client) + TAILQ_FOREACH(c_loop, &clients, entry) { + if (c_loop->session != s || c == c) continue; server_write_client(c, MSG_DETACH, - c->session->name, - strlen(c->session->name) + 1); + c_loop->session->name, + strlen(c_loop->session->name) + 1); } } @@ -121,13 +126,13 @@ cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag, s->cwd = fd; } - cmdq->client->session = s; - notify_attached_session_changed(cmdq->client); + c->session = s; + notify_attached_session_changed(c); session_update_activity(s); - server_redraw_client(cmdq->client); + server_redraw_client(c); s->curw->flags &= ~WINLINK_ALERTFLAGS; } else { - if (server_client_open(cmdq->client, &cause) != 0) { + if (server_client_open(c, &cause) != 0) { cmdq_error(cmdq, "open terminal failed: %s", cause); free(cause); return (CMD_RETURN_ERROR); @@ -152,23 +157,26 @@ cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag, } if (rflag) - cmdq->client->flags |= CLIENT_READONLY; + c->flags |= CLIENT_READONLY; if (dflag) { server_write_session(s, MSG_DETACH, s->name, strlen(s->name) + 1); } - update = options_get_string(&s->options, "update-environment"); - environ_update(update, &cmdq->client->environ, &s->environ); + if (!Eflag) { + update = options_get_string(&s->options, + "update-environment"); + environ_update(update, &c->environ, &s->environ); + } - cmdq->client->session = s; - notify_attached_session_changed(cmdq->client); + c->session = s; + notify_attached_session_changed(c); session_update_activity(s); - server_redraw_client(cmdq->client); + server_redraw_client(c); s->curw->flags &= ~WINLINK_ALERTFLAGS; - server_write_ready(cmdq->client); + server_write_ready(c); cmdq->client_exit = 0; } recalculate_sizes(); @@ -183,5 +191,6 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_q *cmdq) struct args *args = self->args; return (cmd_attach_session(cmdq, args_get(args, 't'), - args_has(args, 'd'), args_has(args, 'r'), args_get(args, 'c'))); + args_has(args, 'd'), args_has(args, 'r'), args_get(args, 'c'), + args_has(args, 'E'))); } diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c index 5e4816ed..248515cd 100644 --- a/cmd-confirm-before.c +++ b/cmd-confirm-before.c @@ -117,7 +117,7 @@ cmd_confirm_before_free(void *data) struct cmd_confirm_before_data *cdata = data; struct client *c = cdata->client; - c->references--; + server_client_unref(c); free(cdata->cmd); free(cdata); @@ -29,6 +29,8 @@ #define CMD_FIND_QUIET 0x2 #define CMD_FIND_WINDOW_INDEX 0x4 #define CMD_FIND_DEFAULT_MARKED 0x8 +#define CMD_FIND_EXACT_SESSION 0x10 +#define CMD_FIND_EXACT_WINDOW 0x20 enum cmd_find_type { CMD_FIND_PANE, @@ -380,6 +382,10 @@ cmd_find_get_session(struct cmd_find_state *fs, const char *session) if (fs->s != NULL) return (0); + /* Stop now if exact only. */ + if (fs->flags & CMD_FIND_EXACT_SESSION) + return (-1); + /* Otherwise look for prefix. */ s = NULL; RB_FOREACH(s_loop, sessions, &sessions) { @@ -454,10 +460,11 @@ cmd_find_get_window_with_session(struct cmd_find_state *fs, const char *window) { struct winlink *wl; const char *errstr; - int idx, n; + int idx, n, exact; struct session *s; log_debug("%s: %s", __func__, window); + exact = (fs->flags & CMD_FIND_EXACT_WINDOW); /* Check for window ids starting with @. */ if (*window == '@') { @@ -468,7 +475,7 @@ cmd_find_get_window_with_session(struct cmd_find_state *fs, const char *window) } /* Try as an offset. */ - if (window[0] == '+' || window[0] == '-') { + if (!exact && (window[0] == '+' || window[0] == '-')) { if (window[1] != '\0') n = strtonum(window + 1, 1, INT_MAX, NULL); else @@ -498,43 +505,47 @@ cmd_find_get_window_with_session(struct cmd_find_state *fs, const char *window) } /* Try special characters. */ - if (strcmp(window, "!") == 0) { - fs->wl = TAILQ_FIRST(&fs->s->lastw); - if (fs->wl == NULL) - return (-1); - fs->idx = fs->wl->idx; - fs->w = fs->wl->window; - return (0); - } else if (strcmp(window, "^") == 0) { - fs->wl = RB_MIN(winlinks, &fs->s->windows); - if (fs->wl == NULL) - return (-1); - fs->idx = fs->wl->idx; - fs->w = fs->wl->window; - return (0); - } else if (strcmp(window, "$") == 0) { - fs->wl = RB_MAX(winlinks, &fs->s->windows); - if (fs->wl == NULL) - return (-1); - fs->idx = fs->wl->idx; - fs->w = fs->wl->window; - return (0); - } - - /* First see if this is a valid window index in this session. */ - idx = strtonum(window, 0, INT_MAX, &errstr); - if (errstr == NULL) { - if (fs->flags & CMD_FIND_WINDOW_INDEX) { - fs->idx = idx; + if (!exact) { + if (strcmp(window, "!") == 0) { + fs->wl = TAILQ_FIRST(&fs->s->lastw); + if (fs->wl == NULL) + return (-1); + fs->idx = fs->wl->idx; + fs->w = fs->wl->window; return (0); - } - fs->wl = winlink_find_by_index(&fs->s->windows, idx); - if (fs->wl != NULL) { + } else if (strcmp(window, "^") == 0) { + fs->wl = RB_MIN(winlinks, &fs->s->windows); + if (fs->wl == NULL) + return (-1); + fs->idx = fs->wl->idx; + fs->w = fs->wl->window; + return (0); + } else if (strcmp(window, "$") == 0) { + fs->wl = RB_MAX(winlinks, &fs->s->windows); + if (fs->wl == NULL) + return (-1); + fs->idx = fs->wl->idx; fs->w = fs->wl->window; return (0); } } + /* First see if this is a valid window index in this session. */ + if (window[0] != '+' && window[0] != '-') { + idx = strtonum(window, 0, INT_MAX, &errstr); + if (errstr == NULL) { + if (fs->flags & CMD_FIND_WINDOW_INDEX) { + fs->idx = idx; + return (0); + } + fs->wl = winlink_find_by_index(&fs->s->windows, idx); + if (fs->wl != NULL) { + fs->w = fs->wl->window; + return (0); + } + } + } + /* Look for exact matches, error if more than one. */ fs->wl = NULL; RB_FOREACH(wl, winlinks, &fs->s->windows) { @@ -550,6 +561,11 @@ cmd_find_get_window_with_session(struct cmd_find_state *fs, const char *window) return (0); } + + /* Stop now if exact only. */ + if (exact) + return (-1); + /* Try as the start of a window name, error if multiple. */ fs->wl = NULL; RB_FOREACH(wl, winlinks, &fs->s->windows) { @@ -867,6 +883,16 @@ cmd_find_target(struct cmd_q *cmdq, const char *target, enum cmd_find_type type, } } + /* Set exact match flags. */ + if (session != NULL && *session == '=') { + session++; + fs.flags |= CMD_FIND_EXACT_SESSION; + } + if (window != NULL && *window == '=') { + window++; + fs.flags |= CMD_FIND_EXACT_WINDOW; + } + /* Empty is the same as NULL. */ if (session != NULL && *session == '\0') session = NULL; diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index 3a26db39..897807d0 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -132,7 +132,7 @@ cmd_load_buffer_callback(struct client *c, int closed, void *data) return; c->stdin_callback = NULL; - c->references--; + server_client_unref(c); if (c->flags & CLIENT_DEAD) return; diff --git a/cmd-new-session.c b/cmd-new-session.c index 9c767489..1533e5f0 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -37,11 +37,11 @@ enum cmd_retval cmd_new_session_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_new_session_entry = { "new-session", "new", - "Ac:dDF:n:Ps:t:x:y:", 0, -1, - "[-AdDP] [-c start-directory] [-F format] [-n window-name] " + "Ac:dDEF:n:Ps:t:x:y:", 0, -1, + "[-AdDEP] [-c start-directory] [-F format] [-n window-name] " "[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] " "[-y height] [command]", - CMD_STARTSERVER|CMD_CANTNEST, + CMD_STARTSERVER, cmd_new_session_exec }; @@ -91,7 +91,8 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) if (session_find(newname) != NULL) { if (args_has(args, 'A')) { return (cmd_attach_session(cmdq, newname, - args_has(args, 'D'), 0, NULL)); + args_has(args, 'D'), 0, NULL, + args_has(args, 'E'))); } cmdq_error(cmdq, "duplicate session: %s", newname); return (CMD_RETURN_ERROR); @@ -145,15 +146,20 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) } /* - * Save the termios settings, part of which is used for new windows in - * this session. + * If this is a new client, check for nesting and save the termios + * settings (part of which is used for new windows in this session). * - * This is read again with tcgetattr() rather than using tty.tio as if - * detached, tty_open won't be called. Because of this, it must be done - * before opening the terminal as that calls tcsetattr() to prepare for - * tmux taking over. + * tcgetattr() is used rather than using tty.tio since if the client is + * detached, tty_open won't be called. It must be done before opening + * the terminal as that calls tcsetattr() to prepare for tmux taking + * over. */ if (!detached && !already_attached && c->tty.fd != -1) { + if (server_client_check_nested(cmdq->client)) { + cmdq_error(cmdq, "sessions should be nested with care, " + "unset $TMUX to force"); + return (CMD_RETURN_ERROR); + } if (tcgetattr(c->tty.fd, &tio) != 0) fatal("tcgetattr failed"); tiop = &tio; @@ -225,9 +231,11 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) /* Construct the environment. */ environ_init(&env); - update = options_get_string(&global_s_options, "update-environment"); - if (c != NULL) + if (c != NULL && !args_has(args, 'E')) { + update = options_get_string(&global_s_options, + "update-environment"); environ_update(update, &c->environ, &env); + } /* Create the new session. */ idx = -1 - options_get_number(&global_s_options, "base-index"); diff --git a/cmd-switch-client.c b/cmd-switch-client.c index 369fc917..23751d73 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -31,8 +31,8 @@ enum cmd_retval cmd_switch_client_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_switch_client_entry = { "switch-client", "switchc", - "lc:npt:rT:", 0, 0, - "[-lnpr] [-c target-client] [-t target-session] [-T key-table]", + "lc:Enpt:rT:", 0, 0, + "[-Elnpr] [-c target-client] [-t target-session] [-T key-table]", CMD_READONLY, cmd_switch_client_exec }; @@ -119,7 +119,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq) } } - if (c != NULL && s != c->session) { + if (c != NULL && s != c->session && !args_has(args, 'E')) { update = options_get_string(&s->options, "update-environment"); environ_update(update, &c->environ, &s->environ); } @@ -29,91 +29,305 @@ * of the 256 colour palette. */ -/* An RGB colour. */ struct colour_rgb { + u_char i; u_char r; u_char g; u_char b; }; -/* 256 colour RGB table, generated on first use. */ -struct colour_rgb *colour_rgb_256; +const struct colour_rgb colour_from_256[] = { + { 0, 0x00, 0x00, 0x00 }, { 1, 0x00, 0x00, 0x5f }, + { 2, 0x00, 0x00, 0x87 }, { 3, 0x00, 0x00, 0xaf }, + { 4, 0x00, 0x00, 0xd7 }, { 5, 0x00, 0x00, 0xff }, + { 6, 0x00, 0x5f, 0x00 }, { 7, 0x00, 0x5f, 0x5f }, + { 8, 0x00, 0x5f, 0x87 }, { 9, 0x00, 0x5f, 0xaf }, + { 10, 0x00, 0x5f, 0xd7 }, { 11, 0x00, 0x5f, 0xff }, + { 12, 0x00, 0x87, 0x00 }, { 13, 0x00, 0x87, 0x5f }, + { 14, 0x00, 0x87, 0x87 }, { 15, 0x00, 0x87, 0xaf }, + { 16, 0x00, 0x87, 0xd7 }, { 17, 0x00, 0x87, 0xff }, + { 18, 0x00, 0xaf, 0x00 }, { 19, 0x00, 0xaf, 0x5f }, + { 20, 0x00, 0xaf, 0x87 }, { 21, 0x00, 0xaf, 0xaf }, + { 22, 0x00, 0xaf, 0xd7 }, { 23, 0x00, 0xaf, 0xff }, + { 24, 0x00, 0xd7, 0x00 }, { 25, 0x00, 0xd7, 0x5f }, + { 26, 0x00, 0xd7, 0x87 }, { 27, 0x00, 0xd7, 0xaf }, + { 28, 0x00, 0xd7, 0xd7 }, { 29, 0x00, 0xd7, 0xff }, + { 30, 0x00, 0xff, 0x00 }, { 31, 0x00, 0xff, 0x5f }, + { 32, 0x00, 0xff, 0x87 }, { 33, 0x00, 0xff, 0xaf }, + { 34, 0x00, 0xff, 0xd7 }, { 35, 0x00, 0xff, 0xff }, + { 36, 0x5f, 0x00, 0x00 }, { 37, 0x5f, 0x00, 0x5f }, + { 38, 0x5f, 0x00, 0x87 }, { 39, 0x5f, 0x00, 0xaf }, + { 40, 0x5f, 0x00, 0xd7 }, { 41, 0x5f, 0x00, 0xff }, + { 42, 0x5f, 0x5f, 0x00 }, { 43, 0x5f, 0x5f, 0x5f }, + { 44, 0x5f, 0x5f, 0x87 }, { 45, 0x5f, 0x5f, 0xaf }, + { 46, 0x5f, 0x5f, 0xd7 }, { 47, 0x5f, 0x5f, 0xff }, + { 48, 0x5f, 0x87, 0x00 }, { 49, 0x5f, 0x87, 0x5f }, + { 50, 0x5f, 0x87, 0x87 }, { 51, 0x5f, 0x87, 0xaf }, + { 52, 0x5f, 0x87, 0xd7 }, { 53, 0x5f, 0x87, 0xff }, + { 54, 0x5f, 0xaf, 0x00 }, { 55, 0x5f, 0xaf, 0x5f }, + { 56, 0x5f, 0xaf, 0x87 }, { 57, 0x5f, 0xaf, 0xaf }, + { 58, 0x5f, 0xaf, 0xd7 }, { 59, 0x5f, 0xaf, 0xff }, + { 60, 0x5f, 0xd7, 0x00 }, { 61, 0x5f, 0xd7, 0x5f }, + { 62, 0x5f, 0xd7, 0x87 }, { 63, 0x5f, 0xd7, 0xaf }, + { 64, 0x5f, 0xd7, 0xd7 }, { 65, 0x5f, 0xd7, 0xff }, + { 66, 0x5f, 0xff, 0x00 }, { 67, 0x5f, 0xff, 0x5f }, + { 68, 0x5f, 0xff, 0x87 }, { 69, 0x5f, 0xff, 0xaf }, + { 70, 0x5f, 0xff, 0xd7 }, { 71, 0x5f, 0xff, 0xff }, + { 72, 0x87, 0x00, 0x00 }, { 73, 0x87, 0x00, 0x5f }, + { 74, 0x87, 0x00, 0x87 }, { 75, 0x87, 0x00, 0xaf }, + { 76, 0x87, 0x00, 0xd7 }, { 77, 0x87, 0x00, 0xff }, + { 78, 0x87, 0x5f, 0x00 }, { 79, 0x87, 0x5f, 0x5f }, + { 80, 0x87, 0x5f, 0x87 }, { 81, 0x87, 0x5f, 0xaf }, + { 82, 0x87, 0x5f, 0xd7 }, { 83, 0x87, 0x5f, 0xff }, + { 84, 0x87, 0x87, 0x00 }, { 85, 0x87, 0x87, 0x5f }, + { 86, 0x87, 0x87, 0x87 }, { 87, 0x87, 0x87, 0xaf }, + { 88, 0x87, 0x87, 0xd7 }, { 89, 0x87, 0x87, 0xff }, + { 90, 0x87, 0xaf, 0x00 }, { 91, 0x87, 0xaf, 0x5f }, + { 92, 0x87, 0xaf, 0x87 }, { 93, 0x87, 0xaf, 0xaf }, + { 94, 0x87, 0xaf, 0xd7 }, { 95, 0x87, 0xaf, 0xff }, + { 96, 0x87, 0xd7, 0x00 }, { 97, 0x87, 0xd7, 0x5f }, + { 98, 0x87, 0xd7, 0x87 }, { 99, 0x87, 0xd7, 0xaf }, + { 100, 0x87, 0xd7, 0xd7 }, { 101, 0x87, 0xd7, 0xff }, + { 102, 0x87, 0xff, 0x00 }, { 103, 0x87, 0xff, 0x5f }, + { 104, 0x87, 0xff, 0x87 }, { 105, 0x87, 0xff, 0xaf }, + { 106, 0x87, 0xff, 0xd7 }, { 107, 0x87, 0xff, 0xff }, + { 108, 0xaf, 0x00, 0x00 }, { 109, 0xaf, 0x00, 0x5f }, + { 110, 0xaf, 0x00, 0x87 }, { 111, 0xaf, 0x00, 0xaf }, + { 112, 0xaf, 0x00, 0xd7 }, { 113, 0xaf, 0x00, 0xff }, + { 114, 0xaf, 0x5f, 0x00 }, { 115, 0xaf, 0x5f, 0x5f }, + { 116, 0xaf, 0x5f, 0x87 }, { 117, 0xaf, 0x5f, 0xaf }, + { 118, 0xaf, 0x5f, 0xd7 }, { 119, 0xaf, 0x5f, 0xff }, + { 120, 0xaf, 0x87, 0x00 }, { 121, 0xaf, 0x87, 0x5f }, + { 122, 0xaf, 0x87, 0x87 }, { 123, 0xaf, 0x87, 0xaf }, + { 124, 0xaf, 0x87, 0xd7 }, { 125, 0xaf, 0x87, 0xff }, + { 126, 0xaf, 0xaf, 0x00 }, { 127, 0xaf, 0xaf, 0x5f }, + { 128, 0xaf, 0xaf, 0x87 }, { 129, 0xaf, 0xaf, 0xaf }, + { 130, 0xaf, 0xaf, 0xd7 }, { 131, 0xaf, 0xaf, 0xff }, + { 132, 0xaf, 0xd7, 0x00 }, { 133, 0xaf, 0xd7, 0x5f }, + { 134, 0xaf, 0xd7, 0x87 }, { 135, 0xaf, 0xd7, 0xaf }, + { 136, 0xaf, 0xd7, 0xd7 }, { 137, 0xaf, 0xd7, 0xff }, + { 138, 0xaf, 0xff, 0x00 }, { 139, 0xaf, 0xff, 0x5f }, + { 140, 0xaf, 0xff, 0x87 }, { 141, 0xaf, 0xff, 0xaf }, + { 142, 0xaf, 0xff, 0xd7 }, { 143, 0xaf, 0xff, 0xff }, + { 144, 0xd7, 0x00, 0x00 }, { 145, 0xd7, 0x00, 0x5f }, + { 146, 0xd7, 0x00, 0x87 }, { 147, 0xd7, 0x00, 0xaf }, + { 148, 0xd7, 0x00, 0xd7 }, { 149, 0xd7, 0x00, 0xff }, + { 150, 0xd7, 0x5f, 0x00 }, { 151, 0xd7, 0x5f, 0x5f }, + { 152, 0xd7, 0x5f, 0x87 }, { 153, 0xd7, 0x5f, 0xaf }, + { 154, 0xd7, 0x5f, 0xd7 }, { 155, 0xd7, 0x5f, 0xff }, + { 156, 0xd7, 0x87, 0x00 }, { 157, 0xd7, 0x87, 0x5f }, + { 158, 0xd7, 0x87, 0x87 }, { 159, 0xd7, 0x87, 0xaf }, + { 160, 0xd7, 0x87, 0xd7 }, { 161, 0xd7, 0x87, 0xff }, + { 162, 0xd7, 0xaf, 0x00 }, { 163, 0xd7, 0xaf, 0x5f }, + { 164, 0xd7, 0xaf, 0x87 }, { 165, 0xd7, 0xaf, 0xaf }, + { 166, 0xd7, 0xaf, 0xd7 }, { 167, 0xd7, 0xaf, 0xff }, + { 168, 0xd7, 0xd7, 0x00 }, { 169, 0xd7, 0xd7, 0x5f }, + { 170, 0xd7, 0xd7, 0x87 }, { 171, 0xd7, 0xd7, 0xaf }, + { 172, 0xd7, 0xd7, 0xd7 }, { 173, 0xd7, 0xd7, 0xff }, + { 174, 0xd7, 0xff, 0x00 }, { 175, 0xd7, 0xff, 0x5f }, + { 176, 0xd7, 0xff, 0x87 }, { 177, 0xd7, 0xff, 0xaf }, + { 178, 0xd7, 0xff, 0xd7 }, { 179, 0xd7, 0xff, 0xff }, + { 180, 0xff, 0x00, 0x00 }, { 181, 0xff, 0x00, 0x5f }, + { 182, 0xff, 0x00, 0x87 }, { 183, 0xff, 0x00, 0xaf }, + { 184, 0xff, 0x00, 0xd7 }, { 185, 0xff, 0x00, 0xff }, + { 186, 0xff, 0x5f, 0x00 }, { 187, 0xff, 0x5f, 0x5f }, + { 188, 0xff, 0x5f, 0x87 }, { 189, 0xff, 0x5f, 0xaf }, + { 190, 0xff, 0x5f, 0xd7 }, { 191, 0xff, 0x5f, 0xff }, + { 192, 0xff, 0x87, 0x00 }, { 193, 0xff, 0x87, 0x5f }, + { 194, 0xff, 0x87, 0x87 }, { 195, 0xff, 0x87, 0xaf }, + { 196, 0xff, 0x87, 0xd7 }, { 197, 0xff, 0x87, 0xff }, + { 198, 0xff, 0xaf, 0x00 }, { 199, 0xff, 0xaf, 0x5f }, + { 200, 0xff, 0xaf, 0x87 }, { 201, 0xff, 0xaf, 0xaf }, + { 202, 0xff, 0xaf, 0xd7 }, { 203, 0xff, 0xaf, 0xff }, + { 204, 0xff, 0xd7, 0x00 }, { 205, 0xff, 0xd7, 0x5f }, + { 206, 0xff, 0xd7, 0x87 }, { 207, 0xff, 0xd7, 0xaf }, + { 208, 0xff, 0xd7, 0xd7 }, { 209, 0xff, 0xd7, 0xff }, + { 210, 0xff, 0xff, 0x00 }, { 211, 0xff, 0xff, 0x5f }, + { 212, 0xff, 0xff, 0x87 }, { 213, 0xff, 0xff, 0xaf }, + { 214, 0xff, 0xff, 0xd7 }, { 215, 0xff, 0xff, 0xff }, + { 216, 0x08, 0x08, 0x08 }, { 217, 0x12, 0x12, 0x12 }, + { 218, 0x1c, 0x1c, 0x1c }, { 219, 0x26, 0x26, 0x26 }, + { 220, 0x30, 0x30, 0x30 }, { 221, 0x3a, 0x3a, 0x3a }, + { 222, 0x44, 0x44, 0x44 }, { 223, 0x4e, 0x4e, 0x4e }, + { 224, 0x58, 0x58, 0x58 }, { 225, 0x62, 0x62, 0x62 }, + { 226, 0x6c, 0x6c, 0x6c }, { 227, 0x76, 0x76, 0x76 }, + { 228, 0x80, 0x80, 0x80 }, { 229, 0x8a, 0x8a, 0x8a }, + { 230, 0x94, 0x94, 0x94 }, { 231, 0x9e, 0x9e, 0x9e }, + { 232, 0xa8, 0xa8, 0xa8 }, { 233, 0xb2, 0xb2, 0xb2 }, + { 234, 0xbc, 0xbc, 0xbc }, { 235, 0xc6, 0xc6, 0xc6 }, + { 236, 0xd0, 0xd0, 0xd0 }, { 237, 0xda, 0xda, 0xda }, + { 238, 0xe4, 0xe4, 0xe4 }, { 239, 0xee, 0xee, 0xee }, +}; +const struct colour_rgb colour_to_256[] = { + { 0, 0x00, 0x00, 0x00 }, { 1, 0x00, 0x00, 0x5f }, + { 2, 0x00, 0x00, 0x87 }, { 3, 0x00, 0x00, 0xaf }, + { 4, 0x00, 0x00, 0xd7 }, { 5, 0x00, 0x00, 0xff }, + { 6, 0x00, 0x5f, 0x00 }, { 7, 0x00, 0x5f, 0x5f }, + { 8, 0x00, 0x5f, 0x87 }, { 9, 0x00, 0x5f, 0xaf }, + { 10, 0x00, 0x5f, 0xd7 }, { 11, 0x00, 0x5f, 0xff }, + { 12, 0x00, 0x87, 0x00 }, { 13, 0x00, 0x87, 0x5f }, + { 14, 0x00, 0x87, 0x87 }, { 15, 0x00, 0x87, 0xaf }, + { 16, 0x00, 0x87, 0xd7 }, { 17, 0x00, 0x87, 0xff }, + { 18, 0x00, 0xaf, 0x00 }, { 19, 0x00, 0xaf, 0x5f }, + { 20, 0x00, 0xaf, 0x87 }, { 21, 0x00, 0xaf, 0xaf }, + { 22, 0x00, 0xaf, 0xd7 }, { 23, 0x00, 0xaf, 0xff }, + { 24, 0x00, 0xd7, 0x00 }, { 25, 0x00, 0xd7, 0x5f }, + { 26, 0x00, 0xd7, 0x87 }, { 27, 0x00, 0xd7, 0xaf }, + { 28, 0x00, 0xd7, 0xd7 }, { 29, 0x00, 0xd7, 0xff }, + { 30, 0x00, 0xff, 0x00 }, { 31, 0x00, 0xff, 0x5f }, + { 32, 0x00, 0xff, 0x87 }, { 33, 0x00, 0xff, 0xaf }, + { 34, 0x00, 0xff, 0xd7 }, { 35, 0x00, 0xff, 0xff }, + { 216, 0x08, 0x08, 0x08 }, { 217, 0x12, 0x12, 0x12 }, + { 218, 0x1c, 0x1c, 0x1c }, { 219, 0x26, 0x26, 0x26 }, + { 220, 0x30, 0x30, 0x30 }, { 221, 0x3a, 0x3a, 0x3a }, + { 222, 0x44, 0x44, 0x44 }, { 223, 0x4e, 0x4e, 0x4e }, + { 224, 0x58, 0x58, 0x58 }, { 36, 0x5f, 0x00, 0x00 }, + { 37, 0x5f, 0x00, 0x5f }, { 38, 0x5f, 0x00, 0x87 }, + { 39, 0x5f, 0x00, 0xaf }, { 40, 0x5f, 0x00, 0xd7 }, + { 41, 0x5f, 0x00, 0xff }, { 42, 0x5f, 0x5f, 0x00 }, + { 43, 0x5f, 0x5f, 0x5f }, { 44, 0x5f, 0x5f, 0x87 }, + { 45, 0x5f, 0x5f, 0xaf }, { 46, 0x5f, 0x5f, 0xd7 }, + { 47, 0x5f, 0x5f, 0xff }, { 48, 0x5f, 0x87, 0x00 }, + { 49, 0x5f, 0x87, 0x5f }, { 50, 0x5f, 0x87, 0x87 }, + { 51, 0x5f, 0x87, 0xaf }, { 52, 0x5f, 0x87, 0xd7 }, + { 53, 0x5f, 0x87, 0xff }, { 54, 0x5f, 0xaf, 0x00 }, + { 55, 0x5f, 0xaf, 0x5f }, { 56, 0x5f, 0xaf, 0x87 }, + { 57, 0x5f, 0xaf, 0xaf }, { 58, 0x5f, 0xaf, 0xd7 }, + { 59, 0x5f, 0xaf, 0xff }, { 60, 0x5f, 0xd7, 0x00 }, + { 61, 0x5f, 0xd7, 0x5f }, { 62, 0x5f, 0xd7, 0x87 }, + { 63, 0x5f, 0xd7, 0xaf }, { 64, 0x5f, 0xd7, 0xd7 }, + { 65, 0x5f, 0xd7, 0xff }, { 66, 0x5f, 0xff, 0x00 }, + { 67, 0x5f, 0xff, 0x5f }, { 68, 0x5f, 0xff, 0x87 }, + { 69, 0x5f, 0xff, 0xaf }, { 70, 0x5f, 0xff, 0xd7 }, + { 71, 0x5f, 0xff, 0xff }, { 225, 0x62, 0x62, 0x62 }, + { 226, 0x6c, 0x6c, 0x6c }, { 227, 0x76, 0x76, 0x76 }, + { 228, 0x80, 0x80, 0x80 }, { 72, 0x87, 0x00, 0x00 }, + { 73, 0x87, 0x00, 0x5f }, { 74, 0x87, 0x00, 0x87 }, + { 75, 0x87, 0x00, 0xaf }, { 76, 0x87, 0x00, 0xd7 }, + { 77, 0x87, 0x00, 0xff }, { 78, 0x87, 0x5f, 0x00 }, + { 79, 0x87, 0x5f, 0x5f }, { 80, 0x87, 0x5f, 0x87 }, + { 81, 0x87, 0x5f, 0xaf }, { 82, 0x87, 0x5f, 0xd7 }, + { 83, 0x87, 0x5f, 0xff }, { 84, 0x87, 0x87, 0x00 }, + { 85, 0x87, 0x87, 0x5f }, { 86, 0x87, 0x87, 0x87 }, + { 87, 0x87, 0x87, 0xaf }, { 88, 0x87, 0x87, 0xd7 }, + { 89, 0x87, 0x87, 0xff }, { 90, 0x87, 0xaf, 0x00 }, + { 91, 0x87, 0xaf, 0x5f }, { 92, 0x87, 0xaf, 0x87 }, + { 93, 0x87, 0xaf, 0xaf }, { 94, 0x87, 0xaf, 0xd7 }, + { 95, 0x87, 0xaf, 0xff }, { 96, 0x87, 0xd7, 0x00 }, + { 97, 0x87, 0xd7, 0x5f }, { 98, 0x87, 0xd7, 0x87 }, + { 99, 0x87, 0xd7, 0xaf }, { 100, 0x87, 0xd7, 0xd7 }, + { 101, 0x87, 0xd7, 0xff }, { 102, 0x87, 0xff, 0x00 }, + { 103, 0x87, 0xff, 0x5f }, { 104, 0x87, 0xff, 0x87 }, + { 105, 0x87, 0xff, 0xaf }, { 106, 0x87, 0xff, 0xd7 }, + { 107, 0x87, 0xff, 0xff }, { 229, 0x8a, 0x8a, 0x8a }, + { 230, 0x94, 0x94, 0x94 }, { 231, 0x9e, 0x9e, 0x9e }, + { 232, 0xa8, 0xa8, 0xa8 }, { 108, 0xaf, 0x00, 0x00 }, + { 109, 0xaf, 0x00, 0x5f }, { 110, 0xaf, 0x00, 0x87 }, + { 111, 0xaf, 0x00, 0xaf }, { 112, 0xaf, 0x00, 0xd7 }, + { 113, 0xaf, 0x00, 0xff }, { 114, 0xaf, 0x5f, 0x00 }, + { 115, 0xaf, 0x5f, 0x5f }, { 116, 0xaf, 0x5f, 0x87 }, + { 117, 0xaf, 0x5f, 0xaf }, { 118, 0xaf, 0x5f, 0xd7 }, + { 119, 0xaf, 0x5f, 0xff }, { 120, 0xaf, 0x87, 0x00 }, + { 121, 0xaf, 0x87, 0x5f }, { 122, 0xaf, 0x87, 0x87 }, + { 123, 0xaf, 0x87, 0xaf }, { 124, 0xaf, 0x87, 0xd7 }, + { 125, 0xaf, 0x87, 0xff }, { 126, 0xaf, 0xaf, 0x00 }, + { 127, 0xaf, 0xaf, 0x5f }, { 128, 0xaf, 0xaf, 0x87 }, + { 129, 0xaf, 0xaf, 0xaf }, { 130, 0xaf, 0xaf, 0xd7 }, + { 131, 0xaf, 0xaf, 0xff }, { 132, 0xaf, 0xd7, 0x00 }, + { 133, 0xaf, 0xd7, 0x5f }, { 134, 0xaf, 0xd7, 0x87 }, + { 135, 0xaf, 0xd7, 0xaf }, { 136, 0xaf, 0xd7, 0xd7 }, + { 137, 0xaf, 0xd7, 0xff }, { 138, 0xaf, 0xff, 0x00 }, + { 139, 0xaf, 0xff, 0x5f }, { 140, 0xaf, 0xff, 0x87 }, + { 141, 0xaf, 0xff, 0xaf }, { 142, 0xaf, 0xff, 0xd7 }, + { 143, 0xaf, 0xff, 0xff }, { 233, 0xb2, 0xb2, 0xb2 }, + { 234, 0xbc, 0xbc, 0xbc }, { 235, 0xc6, 0xc6, 0xc6 }, + { 236, 0xd0, 0xd0, 0xd0 }, { 144, 0xd7, 0x00, 0x00 }, + { 145, 0xd7, 0x00, 0x5f }, { 146, 0xd7, 0x00, 0x87 }, + { 147, 0xd7, 0x00, 0xaf }, { 148, 0xd7, 0x00, 0xd7 }, + { 149, 0xd7, 0x00, 0xff }, { 150, 0xd7, 0x5f, 0x00 }, + { 151, 0xd7, 0x5f, 0x5f }, { 152, 0xd7, 0x5f, 0x87 }, + { 153, 0xd7, 0x5f, 0xaf }, { 154, 0xd7, 0x5f, 0xd7 }, + { 155, 0xd7, 0x5f, 0xff }, { 156, 0xd7, 0x87, 0x00 }, + { 157, 0xd7, 0x87, 0x5f }, { 158, 0xd7, 0x87, 0x87 }, + { 159, 0xd7, 0x87, 0xaf }, { 160, 0xd7, 0x87, 0xd7 }, + { 161, 0xd7, 0x87, 0xff }, { 162, 0xd7, 0xaf, 0x00 }, + { 163, 0xd7, 0xaf, 0x5f }, { 164, 0xd7, 0xaf, 0x87 }, + { 165, 0xd7, 0xaf, 0xaf }, { 166, 0xd7, 0xaf, 0xd7 }, + { 167, 0xd7, 0xaf, 0xff }, { 168, 0xd7, 0xd7, 0x00 }, + { 169, 0xd7, 0xd7, 0x5f }, { 170, 0xd7, 0xd7, 0x87 }, + { 171, 0xd7, 0xd7, 0xaf }, { 172, 0xd7, 0xd7, 0xd7 }, + { 173, 0xd7, 0xd7, 0xff }, { 174, 0xd7, 0xff, 0x00 }, + { 175, 0xd7, 0xff, 0x5f }, { 176, 0xd7, 0xff, 0x87 }, + { 177, 0xd7, 0xff, 0xaf }, { 178, 0xd7, 0xff, 0xd7 }, + { 179, 0xd7, 0xff, 0xff }, { 237, 0xda, 0xda, 0xda }, + { 238, 0xe4, 0xe4, 0xe4 }, { 239, 0xee, 0xee, 0xee }, + { 180, 0xff, 0x00, 0x00 }, { 181, 0xff, 0x00, 0x5f }, + { 182, 0xff, 0x00, 0x87 }, { 183, 0xff, 0x00, 0xaf }, + { 184, 0xff, 0x00, 0xd7 }, { 185, 0xff, 0x00, 0xff }, + { 186, 0xff, 0x5f, 0x00 }, { 187, 0xff, 0x5f, 0x5f }, + { 188, 0xff, 0x5f, 0x87 }, { 189, 0xff, 0x5f, 0xaf }, + { 190, 0xff, 0x5f, 0xd7 }, { 191, 0xff, 0x5f, 0xff }, + { 192, 0xff, 0x87, 0x00 }, { 193, 0xff, 0x87, 0x5f }, + { 194, 0xff, 0x87, 0x87 }, { 195, 0xff, 0x87, 0xaf }, + { 196, 0xff, 0x87, 0xd7 }, { 197, 0xff, 0x87, 0xff }, + { 198, 0xff, 0xaf, 0x00 }, { 199, 0xff, 0xaf, 0x5f }, + { 200, 0xff, 0xaf, 0x87 }, { 201, 0xff, 0xaf, 0xaf }, + { 202, 0xff, 0xaf, 0xd7 }, { 203, 0xff, 0xaf, 0xff }, + { 204, 0xff, 0xd7, 0x00 }, { 205, 0xff, 0xd7, 0x5f }, + { 206, 0xff, 0xd7, 0x87 }, { 207, 0xff, 0xd7, 0xaf }, + { 208, 0xff, 0xd7, 0xd7 }, { 209, 0xff, 0xd7, 0xff }, + { 210, 0xff, 0xff, 0x00 }, { 211, 0xff, 0xff, 0x5f }, + { 212, 0xff, 0xff, 0x87 }, { 213, 0xff, 0xff, 0xaf }, + { 214, 0xff, 0xff, 0xd7 }, { 215, 0xff, 0xff, 0xff }, +}; -void colour_rgb_generate256(void); -u_int colour_rgb_distance(struct colour_rgb *, struct colour_rgb *); -int colour_rgb_find(struct colour_rgb *); +int colour_cmp_rgb(const void *, const void *); -/* Generate 256 colour RGB table. */ -void -colour_rgb_generate256(void) +/* Compare function for bsearch(). */ +int +colour_cmp_rgb(const void *lhs0, const void *rhs0) { - struct colour_rgb *rgb; - u_int i, r, g, b; - - /* - * Allocate the table. The first 16 colours are often changed by users - * and terminals so don't include them. - */ - colour_rgb_256 = xcalloc(240, sizeof *colour_rgb_256); - - /* Add the colours first. */ - r = g = b = 0; - for (i = 240; i > 24; i--) { - rgb = &colour_rgb_256[240 - i]; - - if (r != 0) - rgb->r = (r * 40) + 55; - if (g != 0) - rgb->g = (g * 40) + 55; - if (b != 0) - rgb->b = (b * 40) + 55; - - b++; - if (b > 5) { - b = 0; - g++; - } - if (g > 5) { - g = 0; - r++; - } - } + const struct colour_rgb *lhs = lhs0, *rhs = rhs0; - /* Then add the greys. */ - for (i = 24; i > 0; i--) { - rgb = &colour_rgb_256[240 - i]; + if (lhs->r < rhs->r) + return (-1); + if (lhs->r > rhs->r) + return (1); - rgb->r = 8 + (24 - i) * 10; - rgb->g = 8 + (24 - i) * 10; - rgb->b = 8 + (24 - i) * 10; - } -} + if (lhs->g < rhs->g) + return (-1); + if (lhs->g > rhs->g) + return (1); -/* Get colour RGB distance. */ -u_int -colour_rgb_distance(struct colour_rgb *rgb1, struct colour_rgb *rgb2) -{ - int r, g, b; + if (lhs->b < rhs->b) + return (-1); + if (lhs->b > rhs->b) + return (1); - r = rgb1->r - rgb2->r; - g = rgb1->g - rgb2->g; - b = rgb1->b - rgb2->b; - return (r * r + g * g + b * b); + return (0); } /* Work out the nearest colour from the 256 colour set. */ int -colour_rgb_find(struct colour_rgb *rgb) +colour_find_rgb(u_char r, u_char g, u_char b) { - u_int distance, lowest, colour, i; + struct colour_rgb rgb = { .r = r, .g = g, .b = b }, *found; + u_int distance, lowest, colour, i; + int dr, dg, db; - if (colour_rgb_256 == NULL) - colour_rgb_generate256(); + found = bsearch(&rgb, colour_to_256, nitems(colour_to_256), + sizeof colour_to_256[0], colour_cmp_rgb); + if (found != NULL) + return (16 + found->i); colour = 16; lowest = UINT_MAX; for (i = 0; i < 240; i++) { - distance = colour_rgb_distance(&colour_rgb_256[i], rgb); + dr = (int)colour_from_256[i].r - r; + dg = (int)colour_from_256[i].g - g; + db = (int)colour_from_256[i].b - b; + + distance = dr * dr + dg * dg + db * db; if (distance < lowest) { lowest = distance; colour = 16 + i; @@ -194,20 +408,20 @@ colour_tostring(int c) int colour_fromstring(const char *s) { - const char *errstr; - const char *cp; - struct colour_rgb rgb; - int n; + const char *errstr; + const char *cp; + int n; + u_char r, g, b; if (*s == '#' && strlen(s) == 7) { for (cp = s + 1; isxdigit((u_char) *cp); cp++) ; if (*cp != '\0') return (-1); - n = sscanf(s + 1, "%2hhx%2hhx%2hhx", &rgb.r, &rgb.g, &rgb.b); + n = sscanf(s + 1, "%2hhx%2hhx%2hhx", &r, &g, &b); if (n != 3) return (-1); - return (colour_rgb_find(&rgb) | 0x100); + return (colour_find_rgb(r, g, b) | 0x100); } if (strncasecmp(s, "colour", (sizeof "colour") - 1) == 0) { @@ -217,47 +431,39 @@ colour_fromstring(const char *s) return (n | 0x100); } - if (strcasecmp(s, "black") == 0 || (s[0] == '0' && s[1] == '\0')) + if (strcasecmp(s, "black") == 0 || strcmp(s, "0") == 0) return (0); - if (strcasecmp(s, "red") == 0 || (s[0] == '1' && s[1] == '\0')) + if (strcasecmp(s, "red") == 0 || strcmp(s, "1") == 0) return (1); - if (strcasecmp(s, "green") == 0 || (s[0] == '2' && s[1] == '\0')) + if (strcasecmp(s, "green") == 0 || strcmp(s, "2") == 0) return (2); - if (strcasecmp(s, "yellow") == 0 || (s[0] == '3' && s[1] == '\0')) + if (strcasecmp(s, "yellow") == 0 || strcmp(s, "3") == 0) return (3); - if (strcasecmp(s, "blue") == 0 || (s[0] == '4' && s[1] == '\0')) + if (strcasecmp(s, "blue") == 0 || strcmp(s, "4") == 0) return (4); - if (strcasecmp(s, "magenta") == 0 || (s[0] == '5' && s[1] == '\0')) + if (strcasecmp(s, "magenta") == 0 || strcmp(s, "5") == 0) return (5); - if (strcasecmp(s, "cyan") == 0 || (s[0] == '6' && s[1] == '\0')) + if (strcasecmp(s, "cyan") == 0 || strcmp(s, "6") == 0) return (6); - if (strcasecmp(s, "white") == 0 || (s[0] == '7' && s[1] == '\0')) + if ( |