From 04f4e4219b63187630aab706f65245e2ea1ade5a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 27 Aug 2007 13:45:26 +0000 Subject: [PATCH] Change command format. --- NOTES | 29 +++++- command.c | 14 +-- server.c | 122 +++++++++++++++-------- session.c | 20 ++-- tmux.c | 292 ++++++++++++++++++++++++++++++++---------------------- tmux.h | 122 +++++++---------------- 6 files changed, 337 insertions(+), 262 deletions(-) diff --git a/NOTES b/NOTES index ff4904ed..20064ee5 100644 --- a/NOTES +++ b/NOTES @@ -11,10 +11,31 @@ Commands: d detach There is one default server process per user which puts its socket in /tmp/tmux-UID. It is created the first time tmux is run and subsequent invocations will connect to the same server. The server holds multiple -sessions, call tmux with "-n " to create a session or attach to -an existing session. All the sessions may be listed with -l, or the windows of -a single session with "-ln ". Sessions are destroyed when no -windows remain attached to them. +sessions. + +Syntax is: tmux [-v] [-n name] [-s path] command + +The command is either list, new or attach. Create a new session with: + + tmux new + +Optionally giving it a name with: + + tmux -n new + +Attach to a previous session with: + + tmux -n attach + +List all sessions with: + + tmux list + +Or the windows of a single session with: + + tmux -n list + +Sessions are destroyed when no windows remain attached to them. Another server process can be used by specifying an alternative socket path with "-s " but it shouldn't normally be required. diff --git a/command.c b/command.c index 5c8e18ef..35c05779 100644 --- a/command.c +++ b/command.c @@ -1,4 +1,4 @@ -/* $Id: command.c,v 1.2 2007-08-27 10:30:28 nicm Exp $ */ +/* $Id: command.c,v 1.3 2007-08-27 13:45:26 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -83,7 +83,7 @@ cmd_fn_select(struct buffer *srv_out, int arg) struct hdr hdr; struct select_data data; - hdr.code = MSG_SELECT; + hdr.type = MSG_SELECT; hdr.size = sizeof data; buffer_write(srv_out, &hdr, sizeof hdr); data.idx = arg; @@ -98,7 +98,7 @@ cmd_fn_create(struct buffer *srv_out, unused int arg) { struct hdr hdr; - hdr.code = MSG_CREATE; + hdr.type = MSG_CREATE; hdr.size = 0; buffer_write(srv_out, &hdr, sizeof hdr); @@ -118,7 +118,7 @@ cmd_fn_next(struct buffer *srv_out, unused int arg) { struct hdr hdr; - hdr.code = MSG_NEXT; + hdr.type = MSG_NEXT; hdr.size = 0; buffer_write(srv_out, &hdr, sizeof hdr); @@ -131,7 +131,7 @@ cmd_fn_previous(struct buffer *srv_out, unused int arg) { struct hdr hdr; - hdr.code = MSG_PREVIOUS; + hdr.type = MSG_PREVIOUS; hdr.size = 0; buffer_write(srv_out, &hdr, sizeof hdr); @@ -144,7 +144,7 @@ cmd_fn_refresh(struct buffer *srv_out, unused int arg) { struct hdr hdr; - hdr.code = MSG_REFRESH; + hdr.type = MSG_REFRESH; hdr.size = 0; buffer_write(srv_out, &hdr, sizeof hdr); @@ -157,7 +157,7 @@ cmd_fn_rename(struct buffer *srv_out, unused int arg) { struct hdr hdr; - hdr.code = MSG_RENAME; + hdr.type = MSG_RENAME; hdr.size = 0; buffer_write(srv_out, &hdr, sizeof hdr); diff --git a/server.c b/server.c index e16816fd..c24fb956 100644 --- a/server.c +++ b/server.c @@ -1,4 +1,4 @@ -/* $Id: server.c,v 1.5 2007-08-27 12:05:15 nicm Exp $ */ +/* $Id: server.c,v 1.6 2007-08-27 13:45:26 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -63,7 +63,8 @@ void lost_window(struct window *); void changed_window(struct client *); void draw_client(struct client *, u_int, u_int); void process_client(struct client *); -void process_identify_msg(struct client *, struct hdr *); +void process_new_msg(struct client *, struct hdr *); +void process_attach_msg(struct client *, struct hdr *); void process_create_msg(struct client *, struct hdr *); void process_next_msg(struct client *, struct hdr *); void process_previous_msg(struct client *, struct hdr *); @@ -388,11 +389,11 @@ write_message(struct client *c, const char *fmt, ...) input_store8(c->out, ' '); size = BUFFER_USED(c->out) - size; - hdr.code = MSG_OUTPUT; + hdr.type = MSG_OUTPUT; hdr.size = size; memcpy(BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr); - hdr.code = MSG_PAUSE; + hdr.type = MSG_PAUSE; hdr.size = 0; buffer_write(c->out, &hdr, sizeof hdr); @@ -403,7 +404,7 @@ write_message(struct client *c, const char *fmt, ...) screen_draw(&c->session->window->screen, c->out, c->sy - 1, c->sy - 1); size = BUFFER_USED(c->out) - size; - hdr.code = MSG_OUTPUT; + hdr.type = MSG_OUTPUT; hdr.size = size; memcpy(BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr); } @@ -452,7 +453,7 @@ user_start(struct client *c, const char *prompt, const char *now, input_store_zero(c->out, CODE_CURSORON); size = BUFFER_USED(c->out) - size; - hdr.code = MSG_OUTPUT; + hdr.type = MSG_OUTPUT; hdr.size = size; memcpy(BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr); } @@ -589,7 +590,7 @@ user_input(struct client *c, size_t in) size = BUFFER_USED(c->out) - size; if (size != 0) { - hdr.code = MSG_OUTPUT; + hdr.type = MSG_OUTPUT; hdr.size = size; memcpy(BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr); } else @@ -602,7 +603,7 @@ write_client(struct client *c, u_int cmd, void *buf, size_t len) { struct hdr hdr; - hdr.code = cmd; + hdr.type = cmd; hdr.size = len; buffer_write(c->out, &hdr, sizeof hdr); @@ -617,7 +618,7 @@ write_client2(struct client *c, { struct hdr hdr; - hdr.code = cmd; + hdr.type = cmd; hdr.size = len1 + len2; buffer_write(c->out, &hdr, sizeof hdr); @@ -635,7 +636,7 @@ write_clients(struct window *w, u_int cmd, void *buf, size_t len) struct hdr hdr; u_int i; - hdr.code = cmd; + hdr.type = cmd; hdr.size = len; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { @@ -714,7 +715,7 @@ draw_client(struct client *c, u_int py_upper, u_int py_lower) size = BUFFER_USED(c->out) - size; log_debug("redrawing screen, %zu bytes", size); if (size != 0) { - hdr.code = MSG_OUTPUT; + hdr.type = MSG_OUTPUT; hdr.size = size; memcpy( BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr); @@ -735,9 +736,12 @@ process_client(struct client *c) return; buffer_remove(c->in, sizeof hdr); - switch (hdr.code) { - case MSG_IDENTIFY: - process_identify_msg(c, &hdr); + switch (hdr.type) { + case MSG_NEW: + process_new_msg(c, &hdr); + break; + case MSG_ATTACH: + process_attach_msg(c, &hdr); break; case MSG_CREATE: process_create_msg(c, &hdr); @@ -769,19 +773,23 @@ process_client(struct client *c) case MSG_RENAME: process_rename_msg(c, &hdr); break; + default: + fatalx("unexpected message"); } } -/* Identify message from client. */ +/* New message from client. */ void -process_identify_msg(struct client *c, struct hdr *hdr) +process_new_msg(struct client *c, struct hdr *hdr) { - struct identify_data data; - const char *shell; - char *cmd; + struct new_data data; + const char *shell; + char *cmd, *msg; + if (c->session != NULL) + return; if (hdr->size != sizeof data) - fatalx("bad MSG_IDENTIFY size"); + fatalx("bad MSG_NEW size"); buffer_read(c->in, &data, hdr->size); c->sx = data.sx; @@ -790,21 +798,57 @@ process_identify_msg(struct client *c, struct hdr *hdr) c->sy = data.sy; if (c->sy == 0) c->sy = 25; - - /* Try and find session or create if not found. */ - c->session = session_find(data.name); - if (c->session == NULL) { - shell = getenv("SHELL"); - if (shell == NULL) - shell = "/bin/ksh"; - xasprintf(&cmd, "%s -l", shell); - c->session = - session_create(data.name, cmd, c->sx, c->sy); - xfree(cmd); + + if (*data.name != '\0' && session_find(data.name) != NULL) { + xasprintf(&msg, "duplicate session: %s", data.name); + write_client(c, MSG_READY, msg, strlen(msg)); + xfree(msg); + return; } + + shell = getenv("SHELL"); + if (shell == NULL) + shell = "/bin/ksh"; + xasprintf(&cmd, "%s -l", shell); + c->session = session_create(data.name, cmd, c->sx, c->sy); if (c->session == NULL) fatalx("session_create failed"); + xfree(cmd); + + write_client(c, MSG_READY, NULL, 0); + draw_client(c, 0, c->sy - 1); +} +/* Attach message from client. */ +void +process_attach_msg(struct client *c, struct hdr *hdr) +{ + struct attach_data data; + char *msg; + + if (c->session != NULL) + return; + if (hdr->size != sizeof data) + fatalx("bad MSG_ATTACH size"); + buffer_read(c->in, &data, hdr->size); + + c->sx = data.sx; + if (c->sx == 0) + c->sx = 80; + c->sy = data.sy; + if (c->sy == 0) + c->sy = 25; + + if (*data.name != '\0') + c->session = session_find(data.name); + if (c->session == NULL) { + xasprintf(&msg, "session not found: %s", data.name); + write_client(c, MSG_READY, msg, strlen(msg)); + xfree(msg); + return; + } + + write_client(c, MSG_READY, NULL, 0); draw_client(c, 0, c->sy - 1); } @@ -816,7 +860,7 @@ process_create_msg(struct client *c, struct hdr *hdr) char *cmd; if (c->session == NULL) - fatalx("MSG_CREATE before identified"); + return; if (hdr->size != 0) fatalx("bad MSG_CREATE size"); @@ -836,7 +880,7 @@ void process_next_msg(struct client *c, struct hdr *hdr) { if (c->session == NULL) - fatalx("MSG_NEXT before identified"); + return; if (hdr->size != 0) fatalx("bad MSG_NEXT size"); @@ -851,7 +895,7 @@ void process_previous_msg(struct client *c, struct hdr *hdr) { if (c->session == NULL) - fatalx("MSG_PREVIOUS before identified"); + return; if (hdr->size != 0) fatalx("bad MSG_PREVIOUS size"); @@ -868,7 +912,7 @@ process_size_msg(struct client *c, struct hdr *hdr) struct size_data data; if (c->session == NULL) - fatalx("MSG_SIZE before identified"); + return; if (hdr->size != sizeof data) fatalx("bad MSG_SIZE size"); buffer_read(c->in, &data, hdr->size); @@ -889,7 +933,7 @@ void process_input_msg(struct client *c, struct hdr *hdr) { if (c->session == NULL) - fatalx("MSG_INPUT before identified"); + return; if (c->prompt == NULL) window_input(c->session->window, c->in, hdr->size); @@ -904,7 +948,7 @@ process_refresh_msg(struct client *c, struct hdr *hdr) struct refresh_data data; if (c->session == NULL) - fatalx("MSG_REFRESH before identified"); + return; if (hdr->size != 0 && hdr->size != sizeof data) fatalx("bad MSG_REFRESH size"); @@ -918,7 +962,7 @@ process_select_msg(struct client *c, struct hdr *hdr) struct select_data data; if (c->session == NULL) - fatalx("MSG_SELECT before identified"); + return; if (hdr->size != sizeof data) fatalx("bad MSG_SELECT size"); buffer_read(c->in, &data, hdr->size); @@ -1014,7 +1058,7 @@ void process_rename_msg(struct client *c, struct hdr *hdr) { if (c->session == NULL) - fatalx("MSG_RENAME before identified"); + return; if (hdr->size != 0) fatalx("bad MSG_RENAME size"); diff --git a/session.c b/session.c index 7066d624..cb0e90e1 100644 --- a/session.c +++ b/session.c @@ -1,4 +1,4 @@ -/* $Id: session.c,v 1.4 2007-08-27 12:05:15 nicm Exp $ */ +/* $Id: session.c,v 1.5 2007-08-27 13:45:26 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -50,8 +50,7 @@ session_create(const char *name, const char *cmd, u_int sx, u_int sy) u_int i; s = xmalloc(sizeof *s); - s->tim = time(NULL); - strlcpy(s->name, name, sizeof s->name); + s->tim = time(NULL); ARRAY_INIT(&s->windows); if (session_new(s, cmd, sx, sy) != 0) { @@ -60,13 +59,19 @@ session_create(const char *name, const char *cmd, u_int sx, u_int sy) } for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - s = ARRAY_ITEM(&sessions, i); - if (s == NULL) { + if (ARRAY_ITEM(&sessions, i) == NULL) { ARRAY_SET(&sessions, i, s); - return (s); + break; } } - ARRAY_ADD(&sessions, s); + if (i == ARRAY_LENGTH(&sessions)) + ARRAY_ADD(&sessions, s); + + if (*name != '\0') + strlcpy(s->name, name, sizeof s->name); + else + xsnprintf(s->name, sizeof s->name, "session-%u", i); + return (s); } @@ -128,7 +133,6 @@ session_detach(struct session *s, struct window *w) } window_remove(&s->windows, w); - return (0); } /* Flush session if it is empty. */ diff --git a/tmux.c b/tmux.c index 9a5dffdb..19435ced 100644 --- a/tmux.c +++ b/tmux.c @@ -1,4 +1,4 @@ -/* $Id: tmux.c,v 1.2 2007-07-25 23:13:18 nicm Exp $ */ +/* $Id: tmux.c,v 1.3 2007-08-27 13:45:26 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -40,13 +40,15 @@ const char *malloc_options = "AFGJPX"; #endif +void op_new(char *, struct winsize *); +void op_attach(char *, struct winsize *); int connect_server(void); -int process_server(struct buffer *); -int process_local(struct buffer *, struct buffer *); +int process_server(char **); +int process_local(void); void sighandler(int); __dead void usage(void); __dead void main_list(char *); -void process_list(struct buffer *, const char *); +void process_list(const char *); /* SIGWINCH received flag. */ volatile sig_atomic_t sigwinch; @@ -60,11 +62,21 @@ int debug_level; /* Path to server socket. */ char socket_path[MAXPATHLEN]; +/* Server socket and buffers. */ +int server_fd = -1; +struct buffer *server_in; +struct buffer *server_out; + +/* Local socket and buffers. */ +int local_fd = -1; +struct buffer *local_in; +struct buffer *local_out; + __dead void usage(void) { fprintf(stderr, - "usage: %s [-v] [-n name] [-s path]\n", __progname); + "usage: %s [-v] [-n name] [-s path] command\n", __progname); exit(1); } @@ -87,13 +99,12 @@ sighandler(int sig) int main(int argc, char **argv) { - int opt, srv_fd, loc_fd, mode, listf, n; - char *path, name[MAXNAMELEN]; + int opt, mode, n; + char *path, *error, name[MAXNAMELEN]; FILE *f; - struct buffer *srv_in, *srv_out, *loc_in, *loc_out; + enum op op; struct pollfd pfds[2]; struct hdr hdr; - struct identify_data id; struct size_data sd; struct winsize ws; struct sigaction act; @@ -101,13 +112,9 @@ main(int argc, char **argv) *name = '\0'; path = NULL; - listf = 0; - while ((opt = getopt(argc, argv, "ln:s:v?")) != EOF) { + while ((opt = getopt(argc, argv, "n:s:v?")) != EOF) { switch (opt) { - case 'l': - listf = 1; - break; case 'n': if (strlcpy(name, optarg, sizeof name) >= sizeof name) errx(1, "name too long"); @@ -125,7 +132,17 @@ main(int argc, char **argv) } argc -= optind; argv += optind; - if (argc != 0) + if (argc != 1) + usage(); + + /* Determine command. */ + if (strncmp(argv[0], "list", strlen(argv[0])) == 0) + op = OP_LIST; + else if (strncmp(argv[0], "new", strlen(argv[0])) == 0) + op = OP_NEW; + else if (strncmp(argv[0], "attach", strlen(argv[0])) == 0) + op = OP_ATTACH; + else usage(); /* Sort out socket path. */ @@ -137,18 +154,33 @@ main(int argc, char **argv) err(1, "realpath"); xfree(path); - /* Skip to list function if listing. */ - if (listf) { - if (*name == '\0') - main_list(NULL); - else - main_list(name); + /* Start server if necessary. */ + if (stat(socket_path, &sb) != 0) { + if (errno != ENOENT) + err(1, "%s", socket_path); + else if (op != OP_LIST) { + if (server_start() != 0) + errx(1, "couldn't start server"); + sleep(1); + } + } else { + if (!S_ISSOCK(sb.st_mode)) + errx(1, "%s: not a socket", socket_path); } - /* And fill name. */ - if (*name == '\0') - xsnprintf(name, sizeof name, "s-%lu", (u_long) getpid()); - + /* Connect to server. */ + if ((server_fd = connect_server()) == -1) + errx(1, "couldn't find server"); + if ((mode = fcntl(server_fd, F_GETFL)) == -1) + err(1, "fcntl"); + if (fcntl(server_fd, F_SETFL, mode|O_NONBLOCK) == -1) + err(1, "fcntl"); + server_in = buffer_create(BUFSIZ); + server_out = buffer_create(BUFSIZ); + + if (op == OP_LIST) + main_list(name); + /* Check stdin/stdout. */ if (!isatty(STDIN_FILENO)) errx(1, "stdin is not a tty"); @@ -181,42 +213,21 @@ main(int argc, char **argv) if (sigaction(SIGCHLD, &act, NULL) != 0) err(1, "sigaction"); - /* Start server if necessary. */ - if (stat(socket_path, &sb) != 0) { - if (errno != ENOENT) - err(1, "%s", socket_path); - else { - if (server_start() != 0) - errx(1, "couldn't start server"); - sleep(1); - } - } else { - if (!S_ISSOCK(sb.st_mode)) - errx(1, "%s: not a socket", socket_path); - } - - /* Connect to server. */ - if ((srv_fd = connect_server()) == -1) - errx(1, "couldn't find server"); - if ((mode = fcntl(srv_fd, F_GETFL)) == -1) - err(1, "fcntl"); - if (fcntl(srv_fd, F_SETFL, mode|O_NONBLOCK) == -1) - err(1, "fcntl"); - srv_in = buffer_create(BUFSIZ); - srv_out = buffer_create(BUFSIZ); - /* Find window size. */ if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) err(1, "ioctl(TIOCGWINSZ)"); /* Send initial data. */ - hdr.code = MSG_IDENTIFY; - hdr.size = sizeof id; - buffer_write(srv_out, &hdr, sizeof hdr); - strlcpy(id.name, name, sizeof id.name); - id.sx = ws.ws_col; - id.sy = ws.ws_row; - buffer_write(srv_out, &id, hdr.size); + switch (op) { + case OP_NEW: + op_new(name, &ws); + break; + case OP_ATTACH: + op_attach(name, &ws); + break; + default: + fatalx("unknown op"); + } /* Start logging to file. */ if (debug_level > 0) { @@ -226,39 +237,36 @@ main(int argc, char **argv) log_open(f, LOG_USER, debug_level); xfree(path); } - - /* Initialise terminal. */ - loc_fd = local_init(&loc_in, &loc_out); setproctitle("client (%s)", name); /* Main loop. */ n = 0; while (!sigterm) { /* Handle SIGWINCH if necessary. */ - if (sigwinch) { + if (local_fd != -1 && sigwinch) { if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) fatal("ioctl failed"); - hdr.code = MSG_SIZE; + hdr.type = MSG_SIZE; hdr.size = sizeof sd; - buffer_write(srv_out, &hdr, sizeof hdr); + buffer_write(server_out, &hdr, sizeof hdr); sd.sx = ws.ws_col; sd.sy = ws.ws_row; - buffer_write(srv_out, &sd, hdr.size); + buffer_write(server_out, &sd, hdr.size); sigwinch = 0; } /* Set up pollfds. */ - pfds[0].fd = srv_fd; + pfds[0].fd = server_fd; pfds[0].events = POLLIN; - if (BUFFER_USED(srv_out) > 0) + if (BUFFER_USED(server_out) > 0) pfds[0].events |= POLLOUT; - pfds[1].fd = loc_fd; + pfds[1].fd = local_fd; pfds[1].events = POLLIN; - if (BUFFER_USED(loc_out) > 0) + if (local_fd != -1 && BUFFER_USED(local_out) > 0) pfds[1].events |= POLLOUT; - + /* Do the poll. */ if (poll(pfds, 2, INFTIM) == -1) { if (errno == EAGAIN || errno == EINTR) @@ -267,9 +275,10 @@ main(int argc, char **argv) } /* Read/write from sockets. */ - if (buffer_poll(&pfds[0], srv_in, srv_out) != 0) + if (buffer_poll(&pfds[0], server_in, server_out) != 0) goto server_dead; - if (buffer_poll(&pfds[1], loc_in, loc_out) != 0) + if (local_fd != -1 && + buffer_poll(&pfds[1], local_in, local_out) != 0) fatalx("lost local socket"); /* Output flushed; pause if requested. */ @@ -277,13 +286,17 @@ main(int argc, char **argv) usleep(750000); /* Process any data. */ - if ((n = process_server(srv_in)) == -1) + if ((n = process_server(&error)) == -1) break; - if (process_local(loc_in, srv_out) == -1) + if (process_local() == -1) break; } - local_done(); + if (local_fd != -1) + local_done(); + + if (error != NULL) + errx(1, "%s", error); if (!sigterm) printf("[detached]\n"); @@ -292,12 +305,47 @@ main(int argc, char **argv) exit(0); server_dead: - local_done(); + if (local_fd != -1) + local_done(); printf("[lost server]\n"); exit(1); } +/* New command. */ +void +op_new(char *name, struct winsize *ws) +{ + struct new_data data; + struct hdr hdr; + + hdr.type = MSG_NEW; + hdr.size = sizeof data; + buffer_write(server_out, &hdr, sizeof hdr); + + strlcpy(data.name, name, sizeof data.name); + data.sx = ws->ws_col; + data.sy = ws->ws_row; + buffer_write(server_out, &data, hdr.size); +} + +/* Attach command. */ +void +op_attach(char *name, struct winsize *ws) +{ + struct attach_data data; + struct hdr hdr; + + hdr.type = MSG_ATTACH; + hdr.size = sizeof data; + buffer_write(server_out, &hdr, sizeof hdr); + + strlcpy(data.name, name, sizeof data.name); + data.sx = ws->ws_col; + data.sy = ws->ws_row; + buffer_write(server_out, &data, hdr.size); +} + /* Connect to server socket from PID. */ int connect_server(void) @@ -323,21 +371,30 @@ connect_server(void) /* Handle data from server. */ int -process_server(struct buffer *srv_in) +process_server(char **error) { struct hdr hdr; + *error = NULL; for (;;) { - if (BUFFER_USED(srv_in) < sizeof hdr) + if (BUFFER_USED(server_in) < sizeof hdr) break; - memcpy(&hdr, BUFFER_OUT(srv_in), sizeof hdr); - if (BUFFER_USED(srv_in) < (sizeof hdr) + hdr.size) + memcpy(&hdr, BUFFER_OUT(server_in), sizeof hdr); + if (BUFFER_USED(server_in) < (sizeof hdr) + hdr.size) break; - buffer_remove(srv_in, sizeof hdr); + buffer_remove(server_in, sizeof hdr); - switch (hdr.code) { + switch (hdr.type) { + case MSG_READY: + if (hdr.size != 0) { + xasprintf(error, "%.*s", + (int) hdr.size, BUFFER_OUT(server_in)); + return (-1); + } + local_fd = local_init(&local_in, &local_out); + break; case MSG_OUTPUT: - local_output(srv_in, hdr.size); + local_output(server_in, hdr.size); break; case MSG_PAUSE: if (hdr.size != 0) @@ -345,6 +402,8 @@ process_server(struct buffer *srv_in) return (1); case MSG_EXIT: return (-1); + default: + fatalx("unexpected message"); } } @@ -353,13 +412,16 @@ process_server(struct buffer *srv_in) /* Handle data from local terminal. */ int -process_local(struct buffer *loc_in, struct buffer *srv_out) +process_local(void) { struct buffer *b; struct hdr hdr; size_t size; int n, key; + if (local_fd == -1) + return (0); + n = 0; b = buffer_create(BUFSIZ); @@ -368,10 +430,10 @@ process_local(struct buffer *loc_in, struct buffer *srv_out) if (key == cmd_prefix) { if ((key = local_key(NULL)) == KEYC_NONE) { - buffer_reverse_remove(loc_in, size); + buffer_reverse_remove(local_in, size); break; } - n = cmd_execute(key, srv_out); + n = cmd_execute(key, server_out); break; } @@ -385,10 +447,10 @@ process_local(struct buffer *loc_in, struct buffer *srv_out) } log_debug("transmitting %zu bytes of input", BUFFER_USED(b)); - hdr.code = MSG_INPUT; + hdr.type = MSG_INPUT; hdr.size = BUFFER_USED(b); - buffer_write(srv_out, &hdr, sizeof hdr); - buffer_write(srv_out, BUFFER_OUT(b), BUFFER_USED(b)); + buffer_write(server_out, &hdr, sizeof hdr); + buffer_write(server_out, BUFFER_OUT(b), BUFFER_USED(b)); buffer_destroy(b); return (n); @@ -400,41 +462,29 @@ main_list(char *name) { struct sessions_data sd; struct windows_data wd; - int srv_fd, mode; - struct buffer *srv_in, *srv_out; struct pollfd pfd; struct hdr hdr; - /* Connect to server. */ - if ((srv_fd = connect_server()) == -1) - errx(1, "couldn't find server"); - if ((mode = fcntl(srv_fd, F_GETFL)) == -1) - err(1, "fcntl"); - if (fcntl(srv_fd, F_SETFL, mode|O_NONBLOCK) == -1) - err(1, "fcntl"); - srv_in = buffer_create(BUFSIZ); - srv_out = buffer_create(BUFSIZ); - /* Send query data. */ - if (name == NULL) { - hdr.code = MSG_SESSIONS; + if (*name == '\0') { + hdr.type = MSG_SESSIONS; hdr.size = sizeof sd; - buffer_write(srv_out, &hdr, sizeof hdr); - buffer_write(srv_out, &sd, hdr.size); + buffer_write(server_out, &hdr, sizeof hdr); + buffer_write(server_out, &sd, hdr.size); } else { - hdr.code = MSG_WINDOWS; + hdr.type = MSG_WINDOWS; hdr.size = sizeof wd; - buffer_write(srv_out, &hdr, sizeof hdr); + buffer_write(server_out, &hdr, sizeof hdr); strlcpy(wd.name, name, sizeof wd.name); - buffer_write(srv_out, &wd, hdr.size); + buffer_write(server_out, &wd, hdr.size); } /* Main loop. */ for (;;) { /* Set up pollfd. */ - pfd.fd = srv_fd; + pfd.fd = server_fd; pfd.events = POLLIN; - if (BUFFER_USED(srv_out) > 0) + if (BUFFER_USED(server_out) > 0) pfd.events |= POLLOUT; /* Do the poll. */ @@ -445,16 +495,16 @@ main_list(char *name) } /* Read/write from sockets. */ - if (buffer_poll(&pfd, srv_in, srv_out) != 0) + if (buffer_poll(&pfd, server_in, server_out) != 0) errx(1, "lost server"); /* Process data. */ - process_list(srv_in, name); + process_list(name); } } void -process_list(struct buffer *srv_in, const char *name) +process_list(const char *name) { struct sessions_data sd; struct sessions_entry se; @@ -464,25 +514,25 @@ process_list(struct buffer *srv_in, const char *name) char *tim; for (;;) { - if (BUFFER_USED(srv_in) < sizeof hdr) + if (BUFFER_USED(server_in) < sizeof hdr) break; - memcpy(&hdr, BUFFER_OUT(srv_in), sizeof hdr); - if (BUFFER_USED(srv_in) < (sizeof hdr) + hdr.size) + memcpy(&hdr, BUFFER_OUT(server_in), sizeof hdr); + if (BUFFER_USED(server_in) < (sizeof hdr) + hdr.size) break; - buffer_remove(srv_in, sizeof hdr); + buffer_remove(server_in, sizeof hdr); - switch (hdr.code) { + switch (hdr.type) { case MSG_SESSIONS: if (hdr.size < sizeof sd) errx(1, "bad MSG_SESSIONS size"); - buffer_read(srv_in, &sd, sizeof sd); + buffer_read(server_in, &sd, sizeof sd); hdr.size -= sizeof sd; if (sd.sessions == 0 && hdr.size == 0) exit(0); if (hdr.size < sd.sessions * sizeof se) errx(1, "bad MSG_SESSIONS size"); while (sd.sessions-- > 0) { - buffer_read(srv_in, &se, sizeof se); + buffer_read(server_in, &se, sizeof se); tim = ctime(&se.tim); *strchr(tim, '\n') = '\0'; printf("%s: %u windows (created %s)\n", @@ -492,14 +542,14 @@ process_list(struct buffer *srv_in, const char *name) case MSG_WINDOWS: if (hdr.size < sizeof wd) errx(1, "bad MSG_WINDOWS size"); - buffer_read(srv_in, &wd, sizeof wd); + buffer_read(server_in, &wd, sizeof wd); hdr.size -= sizeof wd; if (wd.windows == 0 && hdr.size == 0) errx(1, "session \"%s\" not found", name); if (hdr.size < wd.windows * sizeof we) errx(1, "bad MSG_WINDOWS size"); while (wd.windows-- > 0) { - buffer_read(srv_in, &we, sizeof we); + buffer_read(server_in, &we, sizeof we); if (*we.title != '\0') { printf("%u: %s \"%s\" (%s)\n", we.idx, we.name, we.title, we.tty); @@ -509,6 +559,8 @@ process_list(struct buffer *srv_in, const char *name) } } exit(0); + default: + fatalx("unexpected message"); } } } diff --git a/tmux.h b/tmux.h index a5b64b2f..478cc5de 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $Id: tmux.h,v 1.4 2007-08-27 12:05:15 nicm Exp $ */ +/* $Id: tmux.h,v 1.5 2007-08-27 13:45:26 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -226,68 +226,6 @@ struct buffer { #define KEYC_UP -149 #define KEYC_MOUSE -150 -/* Escape codes. */ -/* - AL=\E[%dL parm_insert_line - DC=\E[%dP parm_dch - DL=\E[%dM parm_delete_line - DO=\E[%dB parm_down_cursor - IC=\E[%d@ parm_ich - Km=\E[M key_mouse - LE=\E[%dD parm_left_cursor - RI=\E[%dC parm_right_cursor - UP=\E[%dA parm_up_cursor - ac=++,,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~ - acs_chars - ae=^O exit_alt_charset_mode - al=\E[L insert_line - as=^N enter_alt_charset_mode - bl=^G bell - bt=\E[Z back_tab - cb=\E[1K clear_bol - cd=\E[J clear_eos - ce=\E[K clear_eol - cl=\E[H\E[J clear_screen - cm=\E[%i%d;%dH cursor_address - cr=^M carriage_return - cs=\E[%i%d;%dr change_scroll_region - ct=\E[3g clear_all_tabs - dc=\E[P delete_character - dl=\E[M delete_line - do=^J cursor_down - eA=\E(B\E)0 ena_acs - ei=\E[4l exit_insert_mode - ho=\E[H cursor_home - im=\E[4h enter_insert_mode - is=\E)0 init_2string - le=^H cursor_left - mb=\E[5m enter_blink_mode - md=\E[1m enter_bold_mode - me=\E[m exit_attrbute_mode - mr=\E[7m enter_reverse_mode - nd=\E[C cursor_right - nw=\EE newline - rc=\E8 restore_cursor - rs=\Ec reset_string - sc=\E7 save_cursor - se=\E[23m exit_standout_mode - sf=^J scroll_forward - so=\E[3m enter_standout_mode - sr=\EM scroll_reverse - st=\EH set_tab - ta=^I tab - ue=\E[24m exit_underline_mode - up=\EM cursor_up - s=\E[4m - vb=\Eg flash_screen - ve=\E[34h\E[?25h - cursor_normal - vi=\E[?25l cursor_invisible - vs=\E[34l cursor_visible - E0=\E(B - S0=\E(%p1%c - */ - /* Translated escape codes. */ #define CODE_CURSORUP 0 #define CODE_CURSORDOWN 1 @@ -317,25 +255,47 @@ struct buffer { #define CODE_KKEYPADON 25 #define CODE_TITLE 26 +/* Command-line commands. */ +enum op { + OP_LIST = 0, + OP_NEW, + OP_ATTACH +}; + /* Message codes. */ -#define MSG_IDENTIFY 0 -#define MSG_CREATE 1 -#define MSG_EXIT 2 -#define MSG_SIZE 3 -#define MSG_NEXT 4 -#define MSG_PREVIOUS 5 -#define MSG_INPUT 6 /* input from client to server */ -#define MSG_OUTPUT 7 /* output from server to client */ -#define MSG_REFRESH 8 -#define MSG_SELECT 9 -#define MSG_SESSIONS 10 -#define MSG_WINDOWS 11 -#define MSG_PAUSE 12 -#define MSG_RENAME 13 +enum hdrtype { + MSG_NEW = 0, + MSG_ATTACH, + MSG_READY, + MSG_CREATE, + MSG_EXIT, + MSG_SIZE, + MSG_NEXT, + MSG_PREVIOUS, + MSG_INPUT, + MSG_OUTPUT, + MSG_REFRESH, + MSG_SELECT, + MSG_SESSIONS, + MSG_WINDOWS, + MSG_PAUSE, + MSG_RENAME +}; -struct identify_data { +/* Message header structure. */ +struct hdr { + enum hdrtype type; + size_t size; +}; + +struct new_data { char name[MAXNAMELEN]; + u_int sx; + u_int sy; +}; +struct attach_data { + char name[MAXNAMELEN]; u_int sx; u_int sy; }; @@ -377,12 +337,6 @@ struct refresh_data { u_int py_lower; }; -/* Message header structure. */ -struct hdr { - u_int code; - size_t size; -}; - /* Attributes. */ #define ATTR_BRIGHT 0x1 #define ATTR_DIM 0x2