aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES6
-rw-r--r--Makefile9
-rw-r--r--TODO5
-rw-r--r--client-msg.c17
-rw-r--r--client.c93
-rw-r--r--cmd-detach-session.c137
-rw-r--r--cmd-list-sessions.c70
-rw-r--r--cmd-new-session.c162
-rw-r--r--cmd.c306
-rw-r--r--key-bindings.c214
-rw-r--r--op-list.c199
-rw-r--r--op.c271
-rw-r--r--server-fn.c17
-rw-r--r--server-msg.c402
-rw-r--r--server.c6
-rw-r--r--session.c10
-rw-r--r--tmux.c148
-rw-r--r--tmux.h190
18 files changed, 1034 insertions, 1228 deletions
diff --git a/CHANGES b/CHANGES
index 2f84a8c9..e50acaff 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,9 @@
03 October 2007
+* (nicm) Rewrite command handling so commands are much more generic and the
+ same commands are used for command line and keys (although most will probably
+ need to check how they are called). Currently incomplete (only new/detach/ls
+ implemented).
* (nicm) String number arguments. So you can do: tmux bind ^Q create "blah".
* (nicm) Key binding. tmux bind key command [argument] and tmux unbind key.
Key names are in a table in key-string.c, plus A is A, ^A is ctrl-A.
@@ -99,5 +103,5 @@
(including mutt, emacs). No status bar yet and no key remapping or other
customisation.
-$Id: CHANGES,v 1.25 2007-10-03 12:34:16 nicm Exp $
+$Id: CHANGES,v 1.26 2007-10-03 21:31:06 nicm Exp $
diff --git a/Makefile b/Makefile
index 5da175b0..b1d68369 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.12 2007-10-03 11:26:34 nicm Exp $
+# $Id: Makefile,v 1.13 2007-10-03 21:31:07 nicm Exp $
.SUFFIXES: .c .o .y .h
.PHONY: clean
@@ -17,9 +17,10 @@ DEBUG=
META?= \002 # C-b
SRCS= tmux.c server.c server-msg.c server-fn.c buffer.c buffer-poll.c status.c \
- xmalloc.c xmalloc-debug.c cmd.c input.c input-keys.c screen.c window.c \
- session.c local.c log.c client.c client-msg.c client-fn.c op.c op-list.c \
- key-string.c
+ xmalloc.c xmalloc-debug.c input.c input-keys.c screen.c window.c \
+ session.c local.c log.c client.c client-msg.c client-fn.c key-string.c \
+ key-bindings.c \
+ cmd.c cmd-new-session.c cmd-detach-session.c cmd-list-sessions.c
YACC= yacc -d
diff --git a/TODO b/TODO
index 9ee064ee..2d696923 100644
--- a/TODO
+++ b/TODO
@@ -33,8 +33,11 @@
IPC is arse-about-face: too much overhead. 8-byte header for each
packet... hrm. already scanning output for \e, could add an extra
byte to it for message
-- could use bsearch all over the place
+- could use bsearch all over the place or get rid of smaller tables (clientmsg)
- better errors when creating new windows/sessions (how?)
+- commands should have to care less about CMD_KEY
+- CLIENT_HOLD sucks
+- session with CMD_NOSESSION should be an error
-- For 0.1 --------------------------------------------------------------------
- man page
diff --git a/client-msg.c b/client-msg.c
index 0a17d67e..6bcd8173 100644
--- a/client-msg.c
+++ b/client-msg.c
@@ -1,4 +1,4 @@
-/* $Id: client-msg.c,v 1.5 2007-10-03 10:18:31 nicm Exp $ */
+/* $Id: client-msg.c,v 1.6 2007-10-03 21:31:07 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -39,7 +39,6 @@ struct client_msg client_msg_table[] = {
{ MSG_DATA, client_msg_fn_data },
{ MSG_DETACH, client_msg_fn_detach },
{ MSG_ERROR, client_msg_fn_error },
- { MSG_OKAY, client_msg_fn_okay },
{ MSG_PAUSE, client_msg_fn_pause },
};
#define NCLIENTMSG (sizeof client_msg_table / sizeof client_msg_table[0])
@@ -73,7 +72,6 @@ client_msg_dispatch(struct client_ctx *cctx, char **error)
}
}
-/* Data message from server. */
int
client_msg_fn_data(
struct hdr *hdr, struct client_ctx *cctx, unused char **error)
@@ -82,7 +80,6 @@ client_msg_fn_data(
return (0);
}
-/* Pause message from server. */
int
client_msg_fn_pause(
struct hdr *hdr, unused struct client_ctx *cctx, unused char **error)
@@ -92,17 +89,6 @@ client_msg_fn_pause(
return (1);
}
-/* Okay message from server. */
-int
-client_msg_fn_okay(
- struct hdr *hdr, unused struct client_ctx *cctx, unused char **error)
-{
- if (hdr->size != 0)
- fatalx("bad MSG_OKAY size");
- return (0);
-}
-
-/* Error message from server. */
int
client_msg_fn_error(struct hdr *hdr, struct client_ctx *cctx, char **error)
{
@@ -116,7 +102,6 @@ client_msg_fn_error(struct hdr *hdr, struct client_ctx *cctx, char **error)
return (-1);
}
-/* Detach message from server. */
int
client_msg_fn_detach(
struct hdr *hdr, unused struct client_ctx *cctx, char **error)
diff --git a/client.c b/client.c
index 77a1fb68..0c60d540 100644
--- a/client.c
+++ b/client.c
@@ -1,4 +1,4 @@
-/* $Id: client.c,v 1.10 2007-10-03 10:18:32 nicm Exp $ */
+/* $Id: client.c,v 1.11 2007-10-03 21:31:07 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -38,33 +38,19 @@ int client_process_local(struct client_ctx *, char **);
int
client_init(char *path, struct client_ctx *cctx, int start_server)
{
- struct sockaddr_un sa;
- struct stat sb;
- size_t sz;
- int mode;
- u_int retries;
+ struct sockaddr_un sa;
+ struct stat sb;
+ struct msg_identify_data data;
+ struct winsize ws;
+ size_t sz;
+ int mode;
+ u_int retries;
if (path == NULL) {
xasprintf(&path,
"%s/%s-%lu", _PATH_TMP, __progname, (u_long) getuid());
}
- if (start_server) {
- if (!isatty(STDIN_FILENO)) {
- log_warnx("stdin is not a tty");
- return (-1);
- }
- if (!isatty(STDOUT_FILENO)) {
- log_warnx("stdout is not a tty");
- return (-1);
- }
-
- if (ioctl(STDIN_FILENO, TIOCGWINSZ, &cctx->ws) == -1) {
- log_warn("ioctl(TIOCGWINSZ)");
- return (-1);
- }
- }
-
retries = 0;
retry:
if (stat(path, &sb) != 0) {
@@ -121,50 +107,18 @@ retry:
cctx->srv_in = buffer_create(BUFSIZ);
cctx->srv_out = buffer_create(BUFSIZ);
- return (0);
-}
-
-int
-client_flush(struct client_ctx *cctx)
-{
- struct pollfd pfd;
- struct hdr hdr;
-
- for (;;) {
- pfd.fd = cctx->srv_fd;
- pfd.events = POLLIN;
- if (BUFFER_USED(cctx->srv_out) > 0)
- pfd.events |= POLLOUT;
-
- if (poll(&pfd, 1, INFTIM) == -1) {
- if (errno == EAGAIN || errno == EINTR)
- continue;
- fatal("poll failed");
- }
-
- if (buffer_poll(&pfd, cctx->srv_in, cctx->srv_out) != 0) {
- log_warnx("lost server");
- return (1);
+ if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) {
+ if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) {
+ log_warn("ioctl(TIOCGWINSZ)");
+ return (-1);
}
- if (BUFFER_USED(cctx->srv_in) < sizeof hdr)
- continue;
- memcpy(&hdr, BUFFER_OUT(cctx->srv_in), sizeof hdr);
- if (BUFFER_USED(cctx->srv_in) < (sizeof hdr) + hdr.size)
- continue;
- buffer_remove(cctx->srv_in, sizeof hdr);
-
- if (hdr.type == MSG_OKAY)
- return (0);
- if (hdr.type == MSG_ERROR) {
- if (hdr.size > INT_MAX - 1)
- fatalx("bad MSG_ERROR size");
- log_warnx(
- "%.*s", (int) hdr.size, BUFFER_OUT(cctx->srv_in));
- return (1);
- }
- fatalx("unexpected message");
+ data.sx = ws.ws_col;
+ data.sy = ws.ws_row;
+ client_write_server(cctx, MSG_IDENTIFY, &data, sizeof data);
}
+
+ return (0);
}
int
@@ -244,14 +198,15 @@ local_dead:
void
client_handle_winch(struct client_ctx *cctx)
{
- struct size_data data;
-
- if (ioctl(STDIN_FILENO, TIOCGWINSZ, &cctx->ws) == -1)
+ struct msg_resize_data data;
+ struct winsize ws;
+
+ if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
fatal("ioctl failed");
- data.sx = cctx->ws.ws_col;
- data.sy = cctx->ws.ws_row;
- client_write_server(cctx, MSG_SIZE, &data, sizeof data);
+ data.sx = ws.ws_col;
+ data.sy = ws.ws_row;
+ client_write_server(cctx, MSG_RESIZE, &data, sizeof data);
sigwinch = 0;
}
diff --git a/cmd-detach-session.c b/cmd-detach-session.c
new file mode 100644
index 00000000..bcb858a7
--- /dev/null
+++ b/cmd-detach-session.c
@@ -0,0 +1,137 @@
+/* $Id: cmd-detach-session.c,v 1.1 2007-10-03 21:31:07 nicm Exp $ */
+
+/*
+ * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <getopt.h>
+
+#include "tmux.h"
+
+/*
+ * Detach session. If called with -a detach all clients attached to specified
+ * session, otherwise detach current session on key press only.
+ */
+
+int cmd_detach_session_parse(void **, int, char **, char **);
+const char *cmd_detach_session_usage(void);
+void cmd_detach_session_exec(void *, struct cmd_ctx *);
+void cmd_detach_session_send(void *, struct buffer *);
+void cmd_detach_session_recv(void **, struct buffer *);
+void cmd_detach_session_free(void *);
+
+struct cmd_detach_session_data {
+ int flag_all;
+};
+
+const struct cmd_entry cmd_detach_session_entry = {
+ CMD_DETACHSESSION, "detach-session", "detach", 0,
+ cmd_detach_session_parse,
+ cmd_detach_session_usage,
+ cmd_detach_session_exec,
+ cmd_detach_session_send,
+ cmd_detach_session_recv,
+ cmd_detach_session_free
+};
+
+int
+cmd_detach_session_parse(void **ptr, int argc, char **argv, char **cause)
+{
+ struct cmd_detach_session_data *data;
+ int opt;
+
+ *ptr = data = xmalloc(sizeof *data);
+ data->flag_all = 0;
+
+ while ((opt = getopt(argc, argv, "a")) != EOF) {
+ switch (opt) {
+ case 'a':
+ data->flag_all = 1;
+ break;
+ default:
+ goto usage;
+ }
+ }
+ argc -= optind;
+ argv -= optind;
+ if (argc != 0)
+ goto usage;
+
+ return (0);
+
+usage:
+ usage(cause, "%s", cmd_detach_session_usage());
+
+ xfree(data);
+ return (-1);
+}
+
+const char *
+cmd_detach_session_usage(void)
+{
+ return ("detach-session [-a]");
+}
+
+void
+cmd_detach_session_exec(void *ptr, struct cmd_ctx *ctx)
+{
+ struct cmd_detach_session_data *data = ptr, std = { 0 };
+ struct client *c = ctx->client, *cp;
+ struct session *s = ctx->session;
+ u_int i;
+
+ if (data == NULL)
+ data = &std;
+
+ if (data->flag_all) {
+ for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
+ cp = ARRAY_ITEM(&clients, i);
+ if (cp == NULL || cp->session != s)
+ continue;
+ server_write_client(cp, MSG_DETACH, NULL, 0);
+ }
+ } else if (ctx->flags & CMD_KEY)
+ server_write_client(c, MSG_DETACH, NULL, 0);
+
+ if (!(ctx->flags & CMD_KEY))
+ server_write_client(c, MSG_EXIT, NULL, 0);
+}
+
+void
+cmd_detach_session_send(void *ptr, struct buffer *b)
+{
+ struct cmd_detach_session_data *data = ptr;
+
+ buffer_write(b, data, sizeof *data);
+}
+
+void
+cmd_detach_session_recv(void **ptr, struct buffer *b)
+{
+ struct cmd_detach_session_data *data;
+
+ *ptr = data = xmalloc(sizeof *data);
+ buffer_read(b, data, sizeof *data);
+}
+
+void
+cmd_detach_session_free(void *ptr)
+{
+ struct cmd_detach_session_data *data = ptr;
+
+ xfree(data);
+}
diff --git a/cmd-list-sessions.c b/cmd-list-sessions.c
new file mode 100644
index 00000000..47f3f0a0
--- /dev/null
+++ b/cmd-list-sessions.c
@@ -0,0 +1,70 @@
+/* $Id: cmd-list-sessions.c,v 1.1 2007-10-03 21:31:07 nicm Exp $ */
+
+/*
+ * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <getopt.h>
+#include <string.h>
+
+#include "tmux.h"
+
+/*
+ * List all sessions.
+ */
+
+int cmd_list_sessions_parse(void **, int, char **, char **);
+const char *cmd_list_sessions_usage(void);
+void cmd_list_sessions_exec(void *, struct cmd_ctx *);
+
+const struct cmd_entry cmd_list_sessions_entry = {
+ CMD_LISTSESSIONS, "list-sessions", "ls", CMD_NOSESSION,
+ NULL,
+ NULL,
+ cmd_list_sessions_exec,
+ NULL,
+ NULL,
+ NULL
+};
+
+void
+cmd_list_sessions_exec(unused void *ptr, struct cmd_ctx *ctx)
+{
+ struct client *c = ctx->client;
+ struct session *s = ctx->session;
+ char *tim;
+ u_int i, j, n;
+
+ for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
+ s = ARRAY_ITEM(&sessions, i);
+ if (s == NULL)
+ continue;
+
+ n = 0;
+ for (j = 0; j < ARRAY_LENGTH(&s->windows); j++) {
+ if (ARRAY_ITEM(&s->windows, j) != NULL)
+ n++;
+ }
+ tim = ctime(&s->tim);
+ *strchr(tim, '\n') = '\0';
+
+ ctx->print(ctx, "%s: %u windows (created %s)", s->name, n, tim);
+ }
+
+ if (!(ctx->flags & CMD_KEY))
+ server_write_client(c, MSG_EXIT, NULL, 0);
+}
diff --git a/cmd-new-session.c b/cmd-new-session.c
new file mode 100644
index 00000000..6ed04ed8
--- /dev/null
+++ b/cmd-new-session.c
@@ -0,0 +1,162 @@
+/* $Id: cmd-new-session.c,v 1.1 2007-10-03 21:31:07 nicm Exp $ */
+
+/*
+ * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <getopt.h>
+
+#include "tmux.h"
+
+/*
+ * Create a new session and attach to the current terminal unless -d is given.
+ */
+
+int cmd_new_session_parse(void **, int, char **, char **);
+const char *cmd_new_session_usage(void);
+void cmd_new_session_exec(void *, struct cmd_ctx *);
+void cmd_new_session_send(void *, struct buffer *);
+void cmd_new_session_recv(void **, struct buffer *);
+void cmd_new_session_free(void *);
+
+struct cmd_new_session_data {
+ char *name;
+ int flag_detached;
+};
+
+const struct cmd_entry cmd_new_session_entry = {
+ CMD_NEWSESSION, "new-session", "new", CMD_STARTSERVER|CMD_NOSESSION,
+ cmd_new_session_parse,
+ cmd_new_session_usage,
+ cmd_new_session_exec,
+ cmd_new_session_send,
+ cmd_new_session_recv,
+ cmd_new_session_free
+};
+
+int
+cmd_new_session_parse(void **ptr, int argc, char **argv, char **cause)
+{
+ struct cmd_new_session_data *data;
+ int opt;
+
+ *ptr = data = xmalloc(sizeof *data);
+ data->flag_detached = 0;
+ data->name = NULL;
+
+ while ((opt = getopt(argc, argv, "ds:")) != EOF) {
+ switch (opt) {
+ case 'd':
+ data->flag_detached = 1;
+ break;
+ case 's':
+ data->name = xstrdup(optarg);
+ break;
+ default:
+ goto usage;
+ }
+ }
+ argc -= optind;
+ argv -= optind;
+ if (argc != 0)
+ goto usage;
+
+ return (0);
+
+usage:
+ usage(cause, "%s", cmd_new_session_usage());
+
+ if (data->name != NULL)
+ xfree(data->name);
+ xfree(data);
+ return (-1);
+}
+
+const char *
+cmd_new_session_usage(void)
+{
+ return ("new-session [-d] [-n session name]");
+}
+
+void
+cmd_new_session_exec(void *ptr, struct cmd_ctx *ctx)
+{
+ struct cmd_new_session_data *data = ptr, std = { NULL, 0 };
+ struct client *c = ctx->client;
+ u_int sy;
+
+ if (data == NULL)
+ data = &std;
+
+ if (ctx->flags & CMD_KEY)
+ return;
+
+ if (!data->flag_detached && !(c->flags & CLIENT_TERMINAL)) {
+ ctx->error(ctx, "not a terminal");
+ return;
+ }
+
+ if (data->name != NULL && session_find(data->name) != NULL) {
+ ctx->error(ctx, "duplicate session: %s", data->name);
+ return;
+ }
+
+ sy = c->sy;
+ if (sy < status_lines)
+ sy = status_lines + 1;
+ sy -= status_lines;
+
+ c->session = session_create(data->name, default_command, c->sx, sy);
+ if (c->session == NULL)
+ fatalx("session_create failed");
+
+ if (data->flag_detached)
+ server_write_client(c, MSG_EXIT, NULL, 0);
+ else {
+ server_write_client(c, MSG_READY, NULL, 0);
+ server_draw_client(c);
+ }
+}
+
+void
+cmd_new_session_send(void *ptr, struct buffer *b)
+{
+ struct cmd_new_session_data *data = ptr;
+
+ buffer_write(b, data, sizeof *data);
+ cmd_send_string(b, data->name);
+}
+
+void
+cmd_new_session_recv(void **ptr, struct buffer *b)
+{
+ struct cmd_new_session_data *data;
+
+ *ptr = data = xmalloc(sizeof *data);
+ buffer_read(b, data, sizeof *data);
+ data->name = cmd_recv_string(b);
+}
+
+void
+cmd_new_session_free(void *ptr)
+{
+ struct cmd_new_session_data *data = ptr;
+
+ if (data->name != NULL)
+ xfree(data->name);
+ xfree(data);
+}
diff --git a/cmd.c b/cmd.c
index c5823f3b..cf171de4 100644
--- a/cmd.c
+++ b/cmd.c
@@ -1,4 +1,4 @@
-/* $Id: cmd.c,v 1.4 2007-10-03 12:43:47 nicm Exp $ */
+/* $Id: cmd.c,v 1.5 2007-10-03 21:31:07 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,243 +18,163 @@
#include <sys/types.h>
-#include <stdlib.h>
+#include <getopt.h>
#include <string.h>
#include "tmux.h"
-int cmd_prefix = META;
-
-void cmd_fn_detach(struct client *, struct cmd *);
-void cmd_fn_last(struct client *, struct cmd *);
-void cmd_fn_meta(struct client *, struct cmd *);
-void cmd_fn_new(struct client *, struct cmd *);
-void cmd_fn_next(struct client *, struct cmd *);
-void cmd_fn_previous(struct client *, struct cmd *);
-void cmd_fn_refresh(struct client *, struct cmd *);
-void cmd_fn_select(struct client *, struct cmd *);
-void cmd_fn_info(struct client *, struct cmd *);
-
-const struct cmd cmd_default[] = {
- { '0', cmd_fn_select, 0, NULL },
- { '1', cmd_fn_select, 1, NULL },
- { '2', cmd_fn_select, 2, NULL },
- { '3', cmd_fn_select, 3, NULL },
- { '4', cmd_fn_select, 4, NULL },
- { '5', cmd_fn_select, 5, NULL },
- { '6', cmd_fn_select, 6, NULL },
- { '7', cmd_fn_select, 7, NULL },
- { '8', cmd_fn_select, 8, NULL },
- { '9', cmd_fn_select, 9, NULL },
- { 'C', cmd_fn_new, 0, NULL },
- { 'c', cmd_fn_new, 0, NULL },
- { 'D', cmd_fn_detach, 0, NULL },
- { 'd', cmd_fn_detach, 0, NULL },
- { 'N', cmd_fn_next, 0, NULL },
- { 'n', cmd_fn_next, 0, NULL },
- { 'P', cmd_fn_previous, 0, NULL },
- { 'p', cmd_fn_previous, 0, NULL },
- { 'R', cmd_fn_refresh, 0, NULL },
- { 'r', cmd_fn_refresh, 0, NULL },
- { 'L', cmd_fn_last, 0, NULL },
- { 'l', cmd_fn_last, 0, NULL },
- { 'I', cmd_fn_info, 0, NULL },
- { 'i', cmd_fn_info, 0, NULL },
- { META, cmd_fn_meta, 0, NULL },
-};
-u_int cmd_count = (sizeof cmd_default / sizeof cmd_default[0]);
-struct cmd *cmd_table;
-
-const struct bind cmd_bind_table[] = {
- { "detach", cmd_fn_detach, 0 },
- { "info", cmd_fn_info, 0 },
- { "last", cmd_fn_last, 0 },
- { "meta", cmd_fn_meta, 0 },
- { "new", cmd_fn_new, BIND_STRING|BIND_USER },
- { "next", cmd_fn_next, 0 },
- { "previous", cmd_fn_previous, 0 },
- { "refresh", cmd_fn_refresh, 0 },
- { "select", cmd_fn_select, BIND_NUMBER|BIND_USER },
+const struct cmd_entry *cmd_table[] = {
+ &cmd_detach_session_entry,
+ &cmd_list_sessions_entry,
+ &cmd_new_session_entry,
+ NULL
};
-#define NCMDBIND (sizeof cmd_bind_table / sizeof cmd_bind_table[0])
-
-const struct bind *
-cmd_lookup_bind(const char *name)
-{
- const struct bind *bind;
- u_int i;
-
- for (i = 0; i < NCMDBIND; i++) {
- bind = cmd_bind_table + i;
- if (strcmp(bind->name, name) == 0)
- return (bind);
- }
- return (NULL);
-}
-void
-cmd_add_bind(int key, u_int num, char *str, const struct bind *bind)
+struct cmd *
+cmd_parse(int argc, char **argv, char **cause)
{
- struct cmd *cmd = NULL;
- u_int i;
-
- for (i = 0; i < cmd_count; i++) {
- cmd = cmd_table + i;
- if (cmd->key == key)
+ const struct cmd_entry **this, *entry;
+ struct cmd *cmd;
+ int opt;
+
+ *cause = NULL;
+ if (argc == 0)
+ return (NULL);
+
+ entry = NULL;
+ for (this = cmd_table; *this != NULL; this++) {
+ if (strcmp((*this)->alias, argv[0]) == 0) {
+ entry = *this;
break;
- }
- if (i == cmd_count) {
- for (i = 0; i < cmd_count; i++) {
- cmd = cmd_table + i;
- if (cmd->key == KEYC_NONE)
- break;
}
- if (i == cmd_count) {
- cmd_count++;
- cmd_table = xrealloc(cmd_table,
- cmd_count, sizeof cmd_table[0]);
- cmd = cmd_table + cmd_count - 1;
+
+ if (strncmp((*this)->name, argv[0], strlen(argv[0])) != 0)
+ continue;
+ if (entry != NULL) {
+ xasprintf(cause, "ambiguous command: %s", argv[0]);
+ return (NULL);
}
+ entry = *this;
}
-
- cmd->key = key;
- cmd->fn = bind->fn;
- if (bind->flags & BIND_USER) {
- if (bind->flags & BIND_STRING)
- cmd->str = xstrdup(str);
- if (bind->flags & BIND_NUMBER)
- cmd->num = num;
+ if (entry == NULL) {
+ xasprintf(cause, "unknown command: %s", argv[0]);
+ return (NULL);
}
-}
-void
-cmd_remove_bind(int key)
-{
- struct cmd *cmd;
- u_int i;
-
- for (i = 0; i < cmd_count; i++) {
- cmd = cmd_table + i;
- if (cmd->key == key) {
- cmd->key = KEYC_NONE;
- break;
+ optind = 1;
+ if (entry->parse == NULL) {
+ while ((opt = getopt(argc, argv, "")) != EOF) {
+ switch (opt) {
+ default:
+ goto usage;
+ }
}
+ argc -= optind;
+ argv += optind;
+ if (argc != 0)
+ goto usage;
}
-}
-void
-cmd_init(void)
-{
- cmd_table = xmalloc(sizeof cmd_default);
- memcpy(cmd_table, cmd_default, sizeof cmd_default);
-}
+ cmd = xmalloc(sizeof *cmd);
+ cmd->entry = entry;
+ if (entry->parse != NULL) {
+ if (entry->parse(&cmd->data, argc, argv, cause) != 0) {
+ xfree(cmd);
+ return (NULL);
+ }
+ }
+ return (cmd);
-void
-cmd_free(void)
-{
- /* XXX free strings */
- xfree(cmd_table);
+usage:
+ if (entry->usage == NULL)
+ usage(cause, "%s", entry->name);
+ else
+ usage(cause, "%s", entry->usage());
+ return (NULL);
}
void
-cmd_dispatch(struct client *c, int key)
+cmd_exec(struct cmd *cmd, struct cmd_ctx *ctx)
{
- struct cmd *cmd;
- u_int i;
-
- for (i = 0; i < cmd_count; i++) {
- cmd = cmd_table + i;
- if (cmd->key != KEYC_NONE && cmd->key == key)
- cmd->fn(c, cmd);
- }
+ return (cmd->entry->exec(cmd->data, ctx));
}
void
-cmd_fn_new(struct client *c, struct cmd *cmd)
+cmd_send(struct cmd *cmd, struct buffer *b)
{
- char *s;
+ buffer_write(b, &cmd->entry->type, sizeof cmd->entry->type);
- s = cmd->str;
- if (s == NULL)
- s = default_command;
- if (session_new(c->session, s, c->sx, c->sy) != 0)
- server_write_message(c, "%s failed", s); /* XXX */
- else
- server_draw_client(c, 0, c->sy - 1);
+ if (cmd->entry->send == NULL)
+ return;
+ return (cmd->entry->send(cmd->data, b));
}
-void
-cmd_fn_detach(struct client *c, unused struct cmd *cmd)
+struct cmd *
+cmd_recv(struct buffer *b)
{
- server_write_client(c, MSG_DETACH, NULL, 0);
-}
+ const struct cmd_entry **this, *entry;
+ struct cmd *cmd;
+ enum cmd_type type;
+
+ buffer_read(b, &type, sizeof type);
+
+ entry = NULL;
+ for (this = cmd_table; *this != NULL; this++) {
+ if ((*this)->type == type) {
+ entry = *this;
+ break;
+ }
+ }
+ if (*this == NULL)
+ return (NULL);
-void
-cmd_fn_last(struct client *c, unused struct cmd *cmd)
-{
- if (session_last(c->session) == 0)
- server_window_changed(c);
- else
- server_write_message(c, "No last window");
-}
+ cmd = xmalloc(sizeof *cmd);
+ cmd->entry = entry;
-void
-cmd_fn_meta(struct client *c, unused struct cmd *cmd)
-{
- window_key(c->session->window, cmd_prefix);
+ if (cmd->entry->recv != NULL)
+ cmd->entry->recv(&cmd->data, b);
+ return (cmd);
}
void
-cmd_fn_next(struct client *c, unused struct cmd *cmd)
+cmd_free(struct cmd *cmd)
{
- if (session_next(c->session) == 0)
- server_window_changed(c);
- else
- server_write_message(c, "No next window");
+ if (cmd->entry->free != NULL)
+ cmd->entry->free(cmd->data);
+ xfree(cmd);
}
void
-cmd_fn_previous(struct client *c, unused struct cmd *cmd)
+cmd_send_string(struct buffer *b, const char *s)
{
- if (session_previous(c->session) == 0)
- server_window_changed(c);
- else
- server_write_message(c, "No previous window");
-}
+ size_t n;
+
+ if (s == NULL) {
+ n = 0;
+ buffer_write(b, &n, sizeof n);
+ return;
+ }
-void
-cmd_fn_refresh(struct client *c, unused struct cmd *cmd)
-{
- server_draw_client(c, 0, c->sy - 1);
-}
+ n = strlen(s) + 1;
+ buffer_write(b, &n, sizeof n);
-void
-cmd_fn_select(struct client *c, struct cmd *cmd)
-{
- if (session_select(c->session, cmd->num) == 0)
- server_window_changed(c);
- else
- server_write_message(c, "Window %u not present", cmd->num);
+ buffer_write(b, s, n);
}
-void
-cmd_fn_info(struct client *c, unused struct cmd *cmd)
+char *
+cmd_recv_string(struct buffer *b)
{
- struct window *w;
- char *buf;
- size_t len;
- u_int i;
+ char *s;
+ size_t n;
- len = c->sx + 1;
- buf = xmalloc(len);
+ buffer_read(b, &n, sizeof n);
- w = c->session->window;
- window_index(&c->session->windows, w, &i);
- xsnprintf(buf, len, "%u:%s \"%s\" (size %u,%u) (cursor %u,%u) "
- "(region %u,%u)", i, w->name, w->screen.title, w->screen.sx,
- w->screen.sy, w->screen.cx, w->screen.cy, w->screen.ry_upper,
- w->screen.ry_lower);
+ if (n == 0)
+ return (NULL);
+
+ s = xmalloc(n);
+ buffer_read(b, s, n);
+ s[n - 1] = '\0';
- server_write_message(c, "%s", buf);
- xfree(buf);
+ return (s);
}
diff --git a/key-bindings.c b/key-bindings.c
new file mode 100644
index 00000000..7cbd556b
--- /dev/null
+++ b/key-bindings.c
@@ -0,0 +1,214 @@
+/* $Id: key-bindings.c,v 1.1 2007-10-03 21:31:07 nicm Exp $ */
+
+/*
+ * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "tmux.h"
+
+ARRAY_DECL(, struct binding *) key_bindings;
+
+void key_bindings_error(struct cmd_ctx *, const char *, ...);
+void key_bindings_print(struct cmd_ctx *, const char *, ...);
+
+void
+key_bindings_add(int key, struct cmd *cmd)
+{
+ struct binding *bd;
+ u_int i;
+
+ bd = NULL;
+ for (i = 0; i < ARRAY_LENGTH(&key_bindings); i++) {
+ bd = ARRAY_ITEM(&key_bindings, i);
+ if (bd->key == key)
+ break;
+ }
+ if (i == ARRAY_LENGTH(&key_bindings)) {
+ bd = xmalloc(sizeof *bd);
+ ARRAY_ADD(&key_bindings, bd);
+ }
+
+ bd->key = key;
+ bd->cmd = cmd;
+}
+
+void
+key_bindings_remove(int key)
+{
+ struct binding *bd;
+ u_int i;
+
+ bd = NULL;
+ for (i = 0; i < ARRAY_LENGTH(&key_bindings); i++) {
+ bd = ARRAY_ITEM(&key_bindings, i);
+ if (bd->key == key)
+ break;
+ }
+ if (i == ARRAY_LENGTH(&key_bindings))
+ return;
+
+ cmd_free(bd->cmd);
+ xfree(bd);
+}
+
+void
+key_bindings_init(void)
+{
+ struct {
+ int key;
+ const struct cmd_entry *entry;
+ } table[] = {
+ { 'D', &cmd_detach_session_entry },
+ { 'd', &cmd_detach_session_entry },
+ { 'S', &cmd_list_sessions_entry },
+ { 's', &cmd_list_sessions_entry },
+/* { 'C', &cmd_new_window },
+ { 'c', &cmd_new_window },
+ { 'N', &cmd_next_window },
+ { 'n', &cmd_next_window },
+ { 'P', &cmd_previous_window },
+ { 'p', &cmd_previous_window },
+ { 'R', &cmd_refresh_client },
+ { 'r', &cmd_refresh_client },
+ { 'L', &cmd_last_window },
+ { 'l', &cmd_last_window },
+ { 'I', &cmd_windo_info },
+ { 'i', &cmd_window_info },
+ { META, &cmd_meta_entry },
+*//* { '0', cmdx_fn_select, 0, NULL },
+ { '1', cmdx_fn_select, 1, NULL },
+ { '2', cmdx_fn_select, 2, NULL },
+ { '3', cmdx_fn_select, 3, NULL },
+ { '4', cmdx_fn_select, 4, NULL },
+ { '5', cmdx_fn_select, 5, NULL },
+ { '6', cmdx_fn_select, 6, NULL },
+ { '7', cmdx_fn_select, 7, NULL },
+ { '8', cmdx_fn_select, 8, NULL },
+ { '9', cmdx_fn_select, 9, NULL },
+*/
+ };
+ u_int i;
+ struct cmd *cmd;
+
+ for (i = 0; i < (sizeof table / sizeof table[0]); i++) {
+ cmd = xmalloc(sizeof *cmd);
+ cmd->entry = table[i].entry;
+ cmd->data = NULL;
+ key_bindings_add(table[i].key, cmd);
+ }
+}
+
+void
+key_bindings_free(void)
+{
+ struct binding *bd;
+ u_int i;
+
+ for (i = 0; i < ARRAY_LENGTH(&key_bindings); i++) {
+ bd = ARRAY_ITEM(&key_bindings, i);
+
+ cmd_free(bd->cmd);
+ xfree(bd);
+ }
+
+ ARRAY_FREEALL(&key_bindings);
+}
+
+void
+key_bindings_error(struct cmd_ctx *ctx, const char *fmt, ...)
+{
+ va_list ap;
+ char *msg;
+
+ va_start(ap, fmt);
+ xvasprintf(&msg, fmt, ap);
+ va_end(ap);
+
+ server_write_message(ctx->client, msg);
+ xfree(msg);
+}
+
+void
+key_bindings_print(struct cmd_ctx *ctx, const char *fmt, ...)
+{
+ struct client *c = ctx->client;
+ struct hdr hdr;
+ va_list ap;
+ char *msg;
+ size_t size;
+ u_int i;
+
+ buffer_ensure(c->out, sizeof hdr);
+ buffer_add(c->out, sizeof hdr);
+ size = BUFFER_USED(c->out);
+
+ if (!(c->flags & CLIENT_HOLD)) {
+ input_store_zero(c->out, CODE_CURSOROFF);
+ for (i = 0; i < c->session->window->screen.sy; i++) {
+ input_store_two(c->out, CODE_CURSORMOVE, i + 1, 1);
+ input_store_zero(c->out, CODE_CLEARLINE);
+ }
+ input_store_two(c->out, CODE_CURSORMOVE, 1, 1);
+ input_store_two(c->out, CODE_ATTRIBUTES, 0, 0x88);
+
+ c->flags |= CLIENT_HOLD;
+ }
+
+ va_start(ap, fmt);
+ xvasprintf(&msg, fmt, ap);
+ va_end(ap);
+
+ buffer_write(c->out, msg, strlen(msg));
+ input_store8(c->out, '\r');
+ input_store8(c->out, '\n');
+ xfree(msg);
+
+ size = BUFFER_USED(c->out) - size;
+ hdr.type = MSG_DATA;
+ hdr.size = size;
+ memcpy(BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr);
+}
+
+void
+key_bindings_dispatch(int key, struct client *c)
+{
+ struct cmd_ctx ctx;
+ struct binding *bd;
+ u_int i;
+
+ bd = NULL;
+ for (i = 0; i < ARRAY_LENGTH(&key_bindings); i++) {
+ bd = ARRAY_ITEM(&key_bindings, i);
+ if (bd->key == key)
+ break;
+ }
+ if (i == ARRAY_LENGTH(&key_bindings))
+ return;
+
+ ctx.session = c->session;
+
+ ctx.error = key_bindings_error;
+ ctx.print = key_bindings_print;
+
+ ctx.client = c;
+ ctx.flags = CMD_KEY;
+
+ cmd_exec(bd->cmd, &ctx);
+}
diff --git a/op-list.c b/op-list.c
deleted file mode 100644
index a8405d7c..00000000
--- a/op-list.c
+++ /dev/null
@@ -1,199 +0,0 @@
-/* $Id: op-list.c,v 1.6 2007-09-29 15:06:00 nicm Exp $ */
-
-/*
- * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
- * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
- * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/types.h>
-
-#include <errno.h>
-#include <getopt.h>
-#include <string.h>
-
-#include "tmux.h"
-
-int
-op_list_sessions(char *path, int argc, unused char **argv)
-{
- struct client_ctx cctx;
- char *tim;
- struct sessions_data data;
- struct sessions_entry ent;
- struct pollfd pfd;
- struct hdr hdr;
-
- if (argc != 1)
- return (usage("list-sessions"));
-
- if (client_init(path, &cctx, 0) != 0)
- return (1);
- client_write_server(&cctx, MSG_SESSIONS, &data, sizeof data);
-
- for (;;) {
- pfd.fd = cctx.srv_fd;
- pfd.events = POLLIN;
- if (BUFFER_USED(cctx.srv_out) > 0)
- pfd.events |= POLLOUT;
-
- if (poll(&pfd, 1, INFTIM) == -1) {
- if (errno == EAGAIN || errno == EINTR)
- continue;
- log_warn("poll");
- return (-1);
- }
-
- if (buffer_poll(&pfd, cctx.srv_in, cctx.srv_out) != 0) {
- log_warnx("lost server");
- return (-1);
- }
-
- if (BUFFER_USED(cctx.srv_in) < sizeof hdr)
- continue;
- memcpy(&hdr, BUFFER_OUT(cctx.srv_in), sizeof hdr);
- if (BUFFER_USED(cctx.srv_in) < (sizeof hdr) + hdr.size)
- continue;
- buffer_remove(cctx.srv_in, sizeof hdr);
-
- if (hdr.type == MSG_ERROR) {
- if (hdr.size > INT_MAX - 1)
- fatalx("bad MSG_ERROR size");
- log_warnx(
- "%.*s", (int) hdr.size, BUFFER_OUT(cctx.srv_in));
- return (1);
- }
- if (hdr.type != MSG_SESSIONS)
- fatalx("unexpected message");
-
- if (hdr.size < sizeof data)
- fatalx("bad MSG_SESSIONS size");
- buffer_read(cctx.srv_in, &data, sizeof data);
- hdr.size -= sizeof data;
- if (data.sessions == 0 && hdr.size == 0)
- return (0);
- if (hdr.size < data.sessions * sizeof ent)
- fatalx("bad MSG_SESSIONS size");
-
- while (data.sessions-- > 0) {
- buffer_read(cctx.srv_in, &ent, sizeof ent);
-
- tim = ctime(&ent.tim);
- *strchr(tim, '\n') = '\0';
-
- printf("%s: %u windows "
- "(created %s)\n", ent.name, ent.windows, tim);
- }
-
- return (0);
- }
-}
-
-int
-op_list_windows(char *path, int argc, char **argv)
-{
- struct client_ctx cctx;
- char name[MAXNAMELEN];
- int opt;
- struct windows_data data;
- struct windows_entry ent;
- struct pollfd pfd;
- struct hdr hdr;
-
- *name = '\0';
- optind = 1;
- while ((opt = getopt(argc, argv, "s:?")) != EOF) {
- switch (opt) {
- case 's':
- if (strlcpy(name, optarg, sizeof name) >= sizeof name) {
- log_warnx("%s: session name too long", optarg);
- return (1);
- }
- break;
- case '?':
- default:
- return (usage("list-windows [-s session]"));
- }
- }
- argc -= optind;
- argv += optind;
- if (argc != 0)
- return (usage("list-windows [-s session]"));
-
- if (client_init(path, &cctx, 0) != 0)
- return (1);
-
- client_fill_sessid(&data.sid, name);
- client_write_server(&cctx, MSG_WINDOWS, &data, sizeof data);
-
- for (;;) {
- pfd.fd = cctx.srv_fd;
- pfd.events = POLLIN;
- if (BUFFER_USED(cctx.srv_out) > 0)
- pfd.events |= POLLOUT;
-
- if (poll(&pfd, 1, INFTIM) == -1) {
- if (errno == EAGAIN || errno == EINTR)
- continue;
- log_warn("poll");
- return (-1);
- }
-
- if (buffer_poll(&pfd, cctx.srv_in, cctx.srv_out) != 0) {
- log_warnx("lost server");
- return (-1);
- }
-
- if (BUFFER_USED(cctx.srv_in) < sizeof hdr)
- continue;
- memcpy(&hdr, BUFFER_OUT(cctx.srv_in), sizeof hdr);
- if (BUFFER_USED(cctx.srv_in) < (sizeof hdr) + hdr.size)
- continue;
- buffer_remove(cctx.srv_in, sizeof hdr);
-
- if (hdr.type == MSG_ERROR) {
- if (hdr.size > INT_MAX - 1)
- fatalx("bad MSG_ERROR size");
- log_warnx(
- "%.*s", (int) hdr.size, BUFFER_OUT(cctx.srv_in));
- return (1);
- }
- if (hdr.type != MSG_WINDOWS)
- fatalx("unexpected message");
-
- if (hdr.size < sizeof data)
- fatalx("bad MSG_WINDOWS size");
- buffer_read(cctx.srv_in, &data, sizeof data);
- hdr.size -= sizeof data;
- if (data.windows == 0 && hdr.size == 0) {
- log_warnx("session not found: %s", name);
- return (1);
- }
- if (hdr.size < data.windows * sizeof ent)
- fatalx("bad MSG_WINDOWS size");
-
- while (data.windows-- > 0) {
- buffer_read(cctx.srv_in, &ent, sizeof ent);
-
- if (*ent.title != '\0') {
- printf("%u: %s \"%s\" (%s)\n", ent.idx,
- ent.name, ent.title, ent.tty);
- } else {
- printf("%u: %s (%s)\n",
- ent.idx, ent.name, ent.tty);
- }
- }
-
- return (0);
- }
-}
diff --git a/op.c b/op.c
deleted file mode 100644
index 80ab66a6..00000000
--- a/op.c
+++ /dev/null
@@ -1,271 +0,0 @@
-/* $Id: op.c,v 1.12 2007-10-03 12:43:47 nicm Exp $ */
-
-/*
- * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
- * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
- * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/types.h>
-
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "tmux.h"
-
-int
-op_new_session(char *path, int argc, char **argv)
-{
- struct new_data data;
- struct client_ctx cctx;
- char name[MAXNAMELEN];
- int opt, detached;
-
- *name = '\0';
- detached = 0;
- optind = 1;
- while ((opt = getopt(argc, argv, "s:d?")) != EOF) {
- switch (opt) {
- case 's':
- if (strlcpy(name, optarg, sizeof name) >= sizeof name) {
- log_warnx("session name too long: %s", optarg);
- return (1);
- }
- break;
- case 'd':
- detached = 1;
- break;
- case '?':
- default:
- return (usage("new-session [-d] [-s session]"));
- }
- }
- argc -= optind;
- argv += optind;
- if (argc != 0)
- return (usage("new-session [-s session]"));
-
- if (client_init(path, &cctx, 1) != 0)
- return (1);
-
- strlcpy(data.name, name, sizeof data.name);
- data.sx = cctx.ws.ws_col;
- data.sy = cctx.ws.ws_row;
- client_write_server(&cctx, MSG_NEW, &data, sizeof data);
-
- if (detached)
- return (client_flush(&cctx));
- return (client_main(&cctx));
-}
-
-int
-op_attach(char *path, int argc, char **argv)
-{
- struct attach_data data;
- struct client_ctx cctx;
- char name[MAXNAMELEN];
- int opt;
-
- *name = '\0';
- optind = 1;
- while ((opt = getopt(argc, argv, "s:?")) != EOF) {
- switch (opt) {
- case 's':
- if (strlcpy(name, optarg, sizeof name) >= sizeof name) {
- log_warnx("session name too long: %s", optarg);
- return (1);
- }
- break;
- case '?':
- default:
- return (usage("attach [-s session]"));
- }
- }
- argc -= optind;
- argv += optind;
- if (argc != 0)
- return (usage("attach [-s session]"));
-
- if (client_init(path, &cctx, 1) != 0)
- return (1);
-
- client_fill_sessid(&data.sid, name);
- data.sx = cctx.ws.ws_col;
- data.sy = cctx.ws.ws_row;
- client_write_server(&cctx, MSG_ATTACH, &data, sizeof data);
-
- return (client_main(&cctx));
-}
-
-int
-op_rename_window(char *path, int argc, char **argv)
-{
- struct rename_data data;
- struct client_ctx cctx;
- char sname[MAXNAMELEN];
- int opt;
- const char *errstr;
-
- *sname = '\0';
- data.idx = -1;
- optind = 1;
- while ((opt = getopt(argc, argv, "i:s:?")) != EOF) {
- switch (opt) {
- case 's':
- if (strlcpy(sname, optarg, sizeof sname)
- >= sizeof sname) {
- log_warnx("session name too long: %s", optarg);
- return (1);
- }
- break;
- case 'i':
- data.idx = strtonum(optarg, 0, INT_MAX, &errstr);
- if (errstr != NULL) {
- log_warnx(
- "window index %s: %s", errstr, optarg);
- return (1);
- }
- break;
- case '?':
- default:
- return (usage(
- "rename-window [-s session] [-i index] name"));
- }
- }
- argc -= optind;
- argv += optind;
- if (argc != 1)
- return (usage("rename-window [-s session] [-i index] name"));
-
- if (client_init(path, &cctx, 1) != 0)
- return (1);
-
- client_fill_sessid(&data.sid, sname);
- if ((strlcpy(data.newname, argv[0], sizeof data.newname)
- >= sizeof data.newname)) {
- log_warnx("new window name too long: %s", argv[0]);
- return (1);
- }
- client_write_server(&cctx, MSG_RENAME, &data, sizeof data);
-
- return (client_flush(&cctx));
-}
-
-int
-op_bind_key(char *path, int argc, char **argv)
-{
- struct bind_data data;
- struct client_ctx cctx;
- int opt;
- const char *errstr;
- char *str;
- size_t len;
- const struct bind *bind;
-
- optind = 1;
- while ((opt = getopt(argc, argv, "?")) != EOF) {
- switch (opt) {
- default:
- return (usage("bind-key key command [argument]"));
- }
- }
- argc -= optind;
- argv += optind;
- if (argc != 2 && argc != 3)
- return (usage("bind-key key command [argument]"));
-
- if ((data.key = key_string_lookup(argv[0])) == KEYC_NONE) {
- log_warnx("unknown key: %s", argv[0]);
- return (1);
- }
- if (strlcpy(data.cmd, argv[1], sizeof data.cmd) >= sizeof data.cmd) {
- log_warnx("command too long: %s", argv[1]);
- return (1);
- }
-
- if ((bind = cmd_lookup_bind(data.cmd)) == NULL) {
- log_warnx("unknown command: %s", data.cmd);
- return (1);
- }
-
- str = NULL;
- len = 0;
- if (bind->flags & BIND_USER) {
- if (argc != 3) {
- log_warnx("%s requires an argument", data.cmd);
- return (1);
- }
-
- data.flags |= BIND_USER;
- if (bind->flags & BIND_STRING) {
- data.flags |= BIND_STRING;
- str = argv[2];
- len = strlen(str);
- } else if (bind->flags & BIND_NUMBER) {
- data.flags |= BIND_NUMBER;
- data.num = strtonum(argv[2], 0, UINT_MAX, &errstr);
- if (errstr != NULL) {
- log_warnx("argument %s: %s", errstr, argv[2]);
- return (1);
- }
- } else
- fatalx("no argument type");
- } else {
- if (argc != 2) {
- log_warnx("%s cannot have an argument", data.cmd);
- return (1);
- }
-
- data.flags = 0;
- }
-
- if (client_init(path, &cctx, 1) != 0)
- return (1);
-
- client_write_server2(&cctx, MSG_BINDKEY, &data, sizeof data, str, len);
-
- return (client_flush(&cctx));
-}
-
-int
-op_unbind_key(char *path, int argc, char **argv)
-{
- struct bind_data data;
- struct client_ctx cctx;
- int opt;
-
- optind = 1;
- while ((opt = getopt(argc, argv, "?")) != EOF) {
- switch (opt) {
- default:
- return (usage("unbind-key key"));
- }
- }
- argc -= optind;
- argv += optind;
- if (argc != 1)
- return (usage("unbind-key key"));
-
- if ((data.key = key_string_lookup(argv[0])) == KEYC_NONE) {
- log_warnx("unknown key: %s", argv[0]);
- return (1);
- }
-
- if (client_init(path, &cctx, 1) != 0)
- return (1);
-
- client_write_server(&cctx, MSG_UNBINDKEY, &data, sizeof data);
-
- return (client_flush(&cctx));
-}
diff --git a/server-fn.c b/server-fn.c
index f46a4715..7af77146 100644
--- a/server-fn.c
+++ b/server-fn.c
@@ -1,4 +1,4 @@
-/* $Id: server-fn.c,v 1.13 2007-10-03 12:34:16 nicm Exp $ */
+/* $Id: server-fn.c,v 1.14 2007-10-03 21:31:07 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -64,7 +64,7 @@ server_find_sessid(struct sessid *sid, char **cause)
}
}
if (s == NULL) {
- xasprintf(cause, "no sessions");
+ xasprintf(cause, "no sessions found");
return (NULL);
}
if (n != 1) {
@@ -125,6 +125,8 @@ server_write_clients(
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c != NULL && c->session != NULL) {
+ if (c->flags & CLIENT_HOLD) /* XXX OUTPUT only */
+ continue;
if (c->session->window == w) {
log_debug(
"writing %d to clients: %d", type, c->fd);
@@ -145,21 +147,22 @@ server_window_changed(struct client *c)
w = c->session->window;
if (c->sx != w->screen.sx || c->sy != w->screen.sy)
window_resize(w, c->sx, c->sy);
- server_draw_client(c, 0, c->sy - 1);
+ server_draw_client(c);
}
/* Draw window on client. */
void
-server_draw_client(struct client *c, u_int py_upper, u_int py_lower)
+server_draw_client(struct client *c)
{
- struct hdr hdr;
- size_t size;
+ struct hdr hdr;
+ size_t size;
+ struct screen *s = &c->session->window->screen;
buffer_ensure(c->out, sizeof hdr);
buffer_add(c->out, sizeof hdr);
size = BUFFER_USED(c->out);
- screen_draw(&c->session->window->screen, c->out, py_upper, py_lower);
+ screen_draw(s, c->out, 0, s->sy - 1);
size = BUFFER_USED(c->out) - size;
log_debug("redrawing screen, %zu bytes", size);
diff --git a/server-msg.c b/server-msg.c
index 6de3d34c..89d57b0f 100644
--- a/server-msg.c
+++ b/server-msg.c
@@ -1,4 +1,4 @@
-/* $Id: server-msg.c,v 1.19 2007-10-03 13:07:42 nicm Exp $ */
+/* $Id: server-msg.c,v 1.20 2007-10-03 21:31:07 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -24,16 +24,13 @@
#include "tmux.h"
-int server_msg_fn_attach(struct hdr *, struct client *);
-int server_msg_fn_bindkey(struct hdr *, struct client *);
+int server_msg_fn_command(struct hdr *, struct client *);
+int server_msg_fn_identify(struct hdr *, struct client *);
int server_msg_fn_keys(struct hdr *, struct client *);
-int server_msg_fn_new(struct hdr *, struct client *);
-int server_msg_fn_rename(struct hdr *, struct client *);
-int server_msg_fn_sessions(struct hdr *, struct client *);
-int server_msg_fn_size(struct hdr *, struct client *);
-int server_msg_fn_unbindkey(struct hdr *, struct client *);
-int server_msg_fn_windowlist(struct hdr *, struct client *);
-int server_msg_fn_windows(struct hdr *, struct client *);
+int server_msg_fn_resize(struct hdr *, struct client *);
+
+void server_msg_fn_command_error(struct cmd_ctx *, const char *, ...);
+void server_msg_fn_command_print(struct cmd_ctx *, const char *, ...);
struct server_msg {
enum hdrtype type;
@@ -41,16 +38,10 @@ struct server_msg {
int (*fn)(struct hdr *, struct client *);
};
const struct server_msg server_msg_table[] = {
- { MSG_ATTACH, server_msg_fn_attach },
- { MSG_BINDKEY, server_msg_fn_bindkey },
+ { MSG_IDENTIFY, server_msg_fn_identify },
+ { MSG_COMMAND, server_msg_fn_command },
+ { MSG_RESIZE, server_msg_fn_resize },
{ MSG_KEYS, server_msg_fn_keys },
- { MSG_NEW, server_msg_fn_new },
- { MSG_RENAME, server_msg_fn_rename },
- { MSG_SESSIONS, server_msg_fn_sessions },
- { MSG_SIZE, server_msg_fn_size },
- { MSG_UNBINDKEY, server_msg_fn_unbindkey },
- { MSG_WINDOWLIST, server_msg_fn_windowlist },
- { MSG_WINDOWS, server_msg_fn_windows },
};
#define NSERVERMSG (sizeof server_msg_table / sizeof server_msg_table[0])
@@ -83,89 +74,98 @@ server_msg_dispatch(struct client *c)
}
}
-/* New message from client. */
+void
+server_msg_fn_command_error(struct cmd_ctx *ctx, const char *fmt, ...)
+{
+ va_list ap;
+ char *msg;
+
+ va_start(ap, fmt);
+ xvasprintf(&msg, fmt, ap);
+ va_end(ap);
+
+ server_write_client(ctx->client, MSG_ERROR, msg, strlen(msg));
+ xfree(msg);
+}
+
+void
+server_msg_fn_command_print(struct cmd_ctx *ctx, const char *fmt, ...)
+{
+ va_list ap;
+ char *msg;
+
+ va_start(ap, fmt);
+ xvasprintf(&msg, fmt, ap);
+ va_end(ap);
+
+ server_write_client(ctx->client, MSG_PRINT, msg, strlen(msg));
+ xfree(msg);
+}
+
int
-server_msg_fn_new(struct hdr *hdr, struct client *c)
+server_msg_fn_command(struct hdr *hdr, struct client *c)
{
- struct new_data data;
- char *msg;
-
- if (c->session != NULL)
- return (0);
- if (hdr->size != sizeof data)
- fatalx("bad MSG_NEW size");
+ struct msg_command_data data;
+ struct cmd_ctx ctx;
+ struct cmd *cmd;
+ char *cause;
+
+ if (hdr->size < sizeof data)
+ fatalx("bad MSG_COMMAND size");
buffer_read(c->in, &data, sizeof data);
- c->sx = data.sx;
- if (c->sx == 0)
- c->sx = 80;
- c->sy = data.sy;
- if (c->sy == 0)
- c->sy = 25;
+ cmd = cmd_recv(c->in);
+ log_debug("got command %u %s from client %d",
+ cmd->entry->type, cmd->entry->name, c->fd);
- if (c->sy >= status_lines)
- c->sy -= status_lines;
+ if (cmd->entry->flags & CMD_NOSESSION)
+ ctx.session = NULL;
+ else {
+ ctx.session = server_find_sessid(&data.sid, &cause);
+ if (ctx.session == NULL) {
+ server_write_error(c, "%s", cause);
+ xfree(cause);
+ return (0);
+ }
+ }
- data.name[(sizeof data.name) - 1] = '\0';
- if (*data.name != '\0' && session_find(data.name) != NULL) {
- xasprintf(&msg, "duplicate session: %s", data.name);
- server_write_client(c, MSG_ERROR, msg, strlen(msg));
- xfree(msg);
- return (0);
- }
+ ctx.error = server_msg_fn_command_error;
+ ctx.print = server_msg_fn_command_print;
- c->session = session_create(data.name, default_command, c->sx, c->sy);
- if (c->session == NULL)
- fatalx("session_create failed");
+ ctx.client = c;
+ ctx.flags = 0;
- server_write_client(c, MSG_OKAY, NULL, 0);
- server_draw_client(c, 0, c->sy - 1);
+ cmd_exec(cmd, &ctx);
+ cmd_free(cmd);
return (0);
}
-/* Attach message from client. */
int
-server_msg_fn_attach(struct hdr *hdr, struct client *c)
+server_msg_fn_identify(struct hdr *hdr, struct client *c)
{
- struct attach_data data;
- char *cause;
-
- if (c->session != NULL)
- return (0);
- if (hdr->size != sizeof data)
- fatalx("bad MSG_ATTACH size");
+ struct msg_identify_data data;
+
+ if (hdr->size < sizeof data)
+ fatalx("bad MSG_IDENTIFY size");
buffer_read(c->in, &data, sizeof data);
+ log_debug("got identify msg from client: %u,%u", data.sx, data.sy);
+
c->sx = data.sx;
- if (c->sx == 0)
- c->sx = 80;
c->sy = data.sy;
- if (c->sy == 0)
- c->sy = 25;
-
- if (c->sy >= status_lines)
- c->sy -= status_lines;
-
- if ((c->session = server_find_sessid(&data.sid, &cause)) == NULL) {
- server_write_error(c, "%s", cause);
- xfree(cause);
- return (0);
- }
- server_draw_client(c, 0, c->sy - 1);
+ c->flags |= CLIENT_TERMINAL;
return (0);
}
-/* Size message from client. */
int
-server_msg_fn_size(struct hdr *hdr, struct client *c)
+server_msg_fn_resize(struct hdr *hdr, struct client *c)
{
- struct size_data data;
+ struct msg_resize_data data;
+ u_int sy;
- if (c->session == NULL)
- return (0);
if (hdr->size != sizeof data)
fatalx("bad MSG_SIZE size");
buffer_read(c->in, &data, sizeof data);
@@ -177,265 +177,47 @@ server_msg_fn_size(struct hdr *hdr, struct client *c)
if (c->sy == 0)
c->sy = 25;
- if (c->sy >= status_lines)
- c->sy -= status_lines;
+ sy = c->sy;
+ if (sy < status_lines)
+ sy = status_lines + 1;
+ sy -= status_lines;
- if (window_resize(c->session->window, c->sx, c->sy) != 0)
- server_draw_client(c, 0, c->sy - 1);
+ if (window_resize(c->session->window, c->sx, sy) != 0)
+ server_draw_client(c);
return (0);
}
-/* Keys message from client. */
int
server_msg_fn_keys(struct hdr *hdr, struct client *c)
{
int key;
size_t size;
- if (c->session == NULL)
- return (0);
if (hdr->size & 0x1)
fatalx("bad MSG_KEYS size");
+ if (c->flags & CLIENT_HOLD) {
+ server_draw_client(c);
+ c->flags &= ~CLIENT_HOLD;
+ }
+
size = hdr->size;
while (size != 0) {
key = (int16_t) input_extract16(c->in);
size -= 2;
- if (c->prefix) {
- cmd_dispatch(c, key);
- c->prefix = 0;
+ if (c->flags & CLIENT_PREFIX) {
+ key_bindings_dispatch(key, c);
+ c->flags &= ~CLIENT_PREFIX;
continue;
}
- if (key == cmd_prefix)
- c->prefix = 1;
+ if (key == prefix_key)
+ c->flags |= CLIENT_PREFIX;
else
window_key(c->session->window, key);
}
return (0);
}
-
-/* Sessions message from client. */
-int
-server_msg_fn_sessions(struct hdr *hdr, struct client *c)
-{
- struct sessions_data data;
- struct sessions_entry entry;
- struct session *s;
- u_int i, j;
-
- if (hdr->size != sizeof data)
- fatalx("bad MSG_SESSIONS size");
- buffer_read(c->in, &data, sizeof data);
-
- data.sessions = 0;
- for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
- if (ARRAY_ITEM(&sessions, i) != NULL)
- data.sessions++;
- }
- server_write_client2(c, MSG_SESSIONS,
- &data, sizeof data, NULL, data.sessions * sizeof entry);
-
- for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
- s = ARRAY_ITEM(&sessions, i);
- if (s == NULL)
- continue;
- strlcpy(entry.name, s->name, sizeof entry.name);
- entry.tim = s->tim;
- entry.windows = 0;
- for (j = 0; j < ARRAY_LENGTH(&s->windows); j++) {
- if (ARRAY_ITEM(&s->windows, j) != NULL)
- entry.windows++;
- }
- buffer_write(c->out, &entry, sizeof entry);
- }
-
- return (0);
-}
-
-/* Windows message from client. */
-int
-server_msg_fn_windows(struct hdr *hdr, struct client *c)
-{
- struct windows_data data;
- struct windows_entry entry;
- struct session *s;
- struct window *w;
- u_int i;
- char *cause;
-
- if (hdr->size != sizeof data)
- fatalx("bad MSG_WINDOWS size");
- buffer_read(c->in, &data, sizeof data);
-
- if ((s = server_find_sessid(&data.sid, &cause)) == NULL) {
- server_write_error(c, "%s", cause);
- xfree(cause);
- return (0);
- }
-
- data.windows = 0;
- for (i = 0; i < ARRAY_LENGTH(&s->windows); i++) {
- if (ARRAY_ITEM(&s->windows, i) != NULL)
- data.windows++;
- }
- server_write_client2(c, MSG_WINDOWS,
- &data, sizeof data, NULL, data.windows * sizeof entry);
-
- for (i = 0; i < ARRAY_LENGTH(&s->windows); i++) {
- w = ARRAY_ITEM(&s->windows, i);
- if (w == NULL)
- continue;
- entry.idx = i;
- strlcpy(entry.name, w->name, sizeof entry.name);
- strlcpy(entry.title, w->screen.title, sizeof entry.title);
- if (ttyname_r(w->fd, entry.tty, sizeof entry.tty) != 0)
- *entry.tty = '\0';
- buffer_write(c->out, &entry, sizeof entry);
- }
-
- return (0);
-}
-
-/* Rename message from client. */
-int
-server_msg_fn_rename(struct hdr *hdr, struct client *c)
-{
- struct rename_data data;
- char *cause;
- struct window *w;
- struct session *s;
- u_int i;
-
- if (hdr->size != sizeof data)
- fatalx("bad MSG_RENAME size");
- buffer_read(c->in, &data, sizeof data);
-
- data.newname[(sizeof data.newname) - 1] = '\0';
- if ((s = server_find_sessid(&data.sid, &cause)) == NULL) {
- server_write_error(c, "%s", cause);
- xfree(cause);
- return (0);
- }
-
- if (data.idx == -1)
- w = s->window;
- else {
- if (data.idx < 0)
- fatalx("bad window index");
- w = window_at(&s->windows, data.idx);
- if (w == NULL) {
- server_write_error(c, "window not found: %d", data.idx);
- return (0);
- }
- }
-
- strlcpy(w->name, data.newname, sizeof w->name);
-
- server_write_client(c, MSG_OKAY, NULL, 0);
- for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
- c = ARRAY_ITEM(&clients, i);
- if (c != NULL && c->session != NULL) {
- if (session_has(c->session, w))
- server_draw_status(c);
- }
- }
-
- return (0);
-}
-
-/* Window list message from client */
-int
-server_msg_fn_windowlist(struct hdr *hdr, struct client *c)
-{
- struct window *w;
- char *buf;
- size_t len, off;
- u_int i;
-
- if (c->session == NULL)
- return (0);
- if (hdr->size != 0)
- fatalx("bad MSG_WINDOWLIST size");
-
- len = c->sx + 1;
- buf = xmalloc(len);
- off = 0;
-
- *buf = '\0';
- for (i = 0; i < ARRAY_LENGTH(&c->session->windows); i++) {
- w = ARRAY_ITEM(&c->session->windows, i);
- if (w == NULL)
- continue;
- off += xsnprintf(buf + off, len - off, "%u:%s%s ", i, w->name,
- w == c->session->window ? "*" : "");
- if (off >= len)
- break;
- }
-
- server_write_message(c, "%s", buf);
- xfree(buf);
-
- return (0);
-}
-
-/* Bind key message from client */
-int
-server_msg_fn_bindkey(struct hdr *hdr, struct client *c)
-{
- struct bind_data data;
- const struct bind *bind;
- char *str;
-
- if (hdr->size < sizeof data)
- fatalx("bad MSG_BINDKEY size");
- buffer_read(c->in, &data, sizeof data);
-
- str = NULL;
- if (data.flags & BIND_STRING) {
- hdr->size -= sizeof data;
-
- str = xmemstrdup(BUFFER_OUT(c->in), hdr->size);
- if (hdr->size > 0)
- buffer_remove(c->in, hdr->size);
- }
-
- data.cmd[(sizeof data.cmd) - 1] = '\0';
- if ((bind = cmd_lookup_bind(data.cmd)) == NULL)
- fatalx("unknown command");
- if (!(bind->flags & BIND_USER) &&
- (data.flags & (BIND_NUMBER|BIND_STRING)) != 0)
- fatalx("argument missing");
- if ((bind->flags & BIND_USER) &&
- (data.flags & (BIND_NUMBER|BIND_STRING)) == 0)
- fatalx("argument required");
-
- cmd_add_bind(data.key, data.num, str, bind);
- if (str != NULL)
- xfree(str);
-
- server_write_client(c, MSG_OKAY, NULL, 0);
-
- return (0);
-}
-
-/* Unbind key message from client */
-int
-server_msg_fn_unbindkey(struct hdr *hdr, struct client *c)
-{
- struct bind_data data;
-
- if (hdr->size != sizeof data)
- fatalx("bad MSG_UNBINDKEY size");
-
- buffer_read(c->in, &data, hdr->size);
-
- cmd_remove_bind(data.key);
-
- server_write_client(c, MSG_OKAY, NULL, 0);
-
- return (0);
-}
diff --git a/server.c b/server.c
index 8cdbd793..8fe25f5a 100644
--- a/server.c
+++ b/server.c
@@ -1,4 +1,4 @@
-/* $Id: server.c,v 1.19 2007-10-03 11:26:34 nicm Exp $ */
+/* $Id: server.c,v 1.20 2007-10-03 21:31:07 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -127,7 +127,7 @@ server_main(char *srv_path, int srv_fd)
ARRAY_INIT(&clients);
ARRAY_INIT(&sessions);
- cmd_init();
+ key_bindings_init();
pfds = NULL;
while (!sigterm) {
@@ -171,7 +171,7 @@ server_main(char *srv_path, int srv_fd)
server_handle_clients(&pfd);
}
- cmd_free();
+ key_bindings_free();
close(srv_fd);
unlink(srv_path);
diff --git a/session.c b/session.c
index a12f715e..69b528ed 100644
--- a/session.c
+++ b/session.c
@@ -1,4 +1,4 @@
-/* $Id: session.c,v 1.19 2007-09-29 21:02:26 nicm Exp $ */
+/* $Id: session.c,v 1.20 2007-10-03 21:31:07 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -64,11 +64,10 @@ session_create(const char *name, const char *cmd, u_int sx, u_int sy)
if (i == ARRAY_LENGTH(&sessions))
ARRAY_ADD(&sessions, s);
- if (*name != '\0')
- strlcpy(s->name, name, sizeof s->name);
+ if (name != NULL)
+ s->name = xstrdup(name);
else
- xsnprintf(s->name, sizeof s->name, "%u", i);
-
+ xasprintf(&s->name, "%u", i);
if (session_new(s, cmd, sx, sy) != 0) {
session_destroy(s);
return (NULL);
@@ -92,6 +91,7 @@ session_destroy(struct session *s)
while (!ARRAY_EMPTY(&s->windows))
window_remove(&s->windows, ARRAY_FIRST(&s->windows));
+ xfree(s->name);
xfree(s);
}
diff --git a/tmux.c b/tmux.c
index 13dbbb0e..b47bff65 100644
--- a/tmux.c
+++ b/tmux.c
@@ -1,4 +1,4 @@
-/* $Id: tmux.c,v 1.24 2007-10-03 12:56:02 nicm Exp $ */
+/* $Id: tmux.c,v 1.25 2007-10-03 21:31:07 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -19,7 +19,10 @@
#include <sys/types.h>
#include <sys/wait.h>
+#include <err.h>
+#include <errno.h>
#include <paths.h>
+#include <poll.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
@@ -35,45 +38,29 @@ const char *malloc_options = "AFGJPX";
volatile sig_atomic_t sigwinch;
volatile sig_atomic_t sigterm;
int debug_level;
+int prefix_key = META;
u_int status_lines;
char *default_command;
void sighandler(int);
-struct op {
- const char *cmd;
- const char *alias;
- int (*fn)(char *, int, char **);
-};
-const struct op op_table[] = {
- { "attach", NULL, op_attach },
- { "bind-key", "bind", op_bind_key },
- { "list-sessions", "ls", op_list_sessions },
- { "list-windows", "lsw", op_list_windows },
- { "new-session", "new", op_new_session },
- { "rename-window", "renw", op_rename_window },
- { "unbind-key", "unbind", op_unbind_key },
-};
-#define NOP (sizeof op_table / sizeof op_table[0])
-
-int
-usage(const char *fmt, ...)
+void
+usage(char **ptr, const char *fmt, ...)
{
char *msg;
va_list ap;
if (fmt == NULL) {
- fprintf(stderr,
- "usage: %s [-v] [-S path] command [flags]\n", __progname);
- return (1);
- }
+ xasprintf(ptr,
+ "usage: %s [-v] [-S path] command [flags]", __progname);
+ } else {
+ va_start(ap, fmt);
+ xvasprintf(&msg, fmt, ap);
+ va_end(ap);
- va_start(ap, fmt);
- xvasprintf(&msg, fmt, ap);
- va_end(ap);
- fprintf(stderr, "usage: %s [-v] [-S path] %s\n", __progname, msg);
- xfree(msg);
- return (1);
+ xasprintf(ptr, "usage: %s [-v] [-S path] %s", __progname, msg);
+ xfree(msg);
+ }
}
void
@@ -172,30 +159,39 @@ sigreset(void)
int
main(int argc, char **argv)
{
- const struct op *op, *found;
+ struct client_ctx cctx;
+ struct msg_command_data data;
+ struct buffer *b;
+ struct cmd *cmd;
+ struct pollfd pfd;
+ struct hdr hdr;
const char *shell;
- char *path;
+ char *path, *cause, name[MAXNAMELEN];
int opt;
- u_int i;
+ *name = '\0';
path = NULL;
- while ((opt = getopt(argc, argv, "S:v?")) != EOF) {
+ while ((opt = getopt(argc, argv, "S:s:v?")) != EOF) {
switch (opt) {
case 'S':
path = xstrdup(optarg);
break;
+ case 's':
+ if (strlcpy(name, optarg, sizeof name) >= sizeof name)
+ errx(1, "session name too long: %s", optarg);
+ break;
case 'v':
debug_level++;
break;
case '?':
default:
- exit(usage(NULL));
+ goto usage;
}
}
argc -= optind;
argv += optind;
if (argc == 0)
- exit(usage(NULL));
+ goto usage;
log_open(stderr, LOG_USER, debug_level);
@@ -206,21 +202,75 @@ main(int argc, char **argv)
shell = "/bin/ksh";
xasprintf(&default_command, "exec %s -l", shell);
- found = NULL;
- for (i = 0; i < NOP; i++) {
- op = op_table + i;
- if (op->alias != NULL && strcmp(argv[0], op->alias) == 0)
- exit(op->fn(path, argc, argv));
- if (strncmp(argv[0], op->cmd, strlen(argv[0])) == 0) {
- if (found != NULL) {
- log_warnx("ambiguous command: %s", argv[0]);
- exit(1);
- }
- found = op;
+ if ((cmd = cmd_parse(argc, argv, &cause)) == NULL) {
+ if (cause == NULL)
+ goto usage;
+ log_warnx("%s", cause);
+ exit(1);
+ }
+
+ if (!(cmd->entry->flags & CMD_NOSESSION))
+ client_fill_sessid(&data.sid, name);
+ if (client_init(path, &cctx, cmd->entry->flags & CMD_STARTSERVER) != 0)
+ exit(1);
+ b = buffer_create(BUFSIZ);
+ cmd_send(cmd, b);
+ cmd_free(cmd);
+
+ client_write_server2(&cctx,
+ MSG_COMMAND, &data, sizeof data, BUFFER_OUT(b), BUFFER_USED(b));
+ buffer_destroy(b);
+
+ for (;;) {
+ pfd.fd = cctx.srv_fd;
+ pfd.events = POLLIN;
+ if (BUFFER_USED(cctx.srv_out) > 0)
+ pfd.events |= POLLOUT;
+
+ if (poll(&pfd, 1, INFTIM) == -1) {
+ if (errno == EAGAIN || errno == EINTR)
+ continue;
+ fatal("poll failed");
+ }
+
+ if (buffer_poll(&pfd, cctx.srv_in, cctx.srv_out) != 0)
+ fatalx("lost server");
+
+ restart:
+ if (BUFFER_USED(cctx.srv_in) < sizeof hdr)
+ continue;
+ memcpy(&hdr, BUFFER_OUT(cctx.srv_in), sizeof hdr);
+ if (BUFFER_USED(cctx.srv_in) < (sizeof hdr) + hdr.size)
+ continue;
+ buffer_remove(cctx.srv_in, sizeof hdr);
+
+ switch (hdr.type) {
+ case MSG_EXIT:
+ exit(0);
+ case MSG_PRINT:
+ if (hdr.size > INT_MAX - 1)
+ fatalx("bad MSG_PRINT size");
+ log_info(
+ "%.*s", (int) hdr.size, BUFFER_OUT(cctx.srv_in));
+ buffer_remove(cctx.srv_in, hdr.size);
+ goto restart;
+ case MSG_ERROR:
+ if (hdr.size > INT_MAX - 1)
+ fatalx("bad MSG_ERROR size");
+ log_warnx("%s: %.*s", __progname,
+ (int) hdr.size, BUFFER_OUT(cctx.srv_in));
+ buffer_remove(cctx.srv_in, hdr.size);
+ exit(1);
+ case MSG_READY:
+ exit(client_main(&cctx));
+ default:
+ fatalx("unexpected command");
}
}
- if (found != NULL)
- exit(found->fn(path, argc, argv));
+ /* NOTREACHED */
- exit(usage(NULL));
+usage:
+ usage(&cause, NULL);
+ fprintf(stderr, "%s\n", cause);
+ exit(1);
}
diff --git a/tmux.h b/tmux.h
index 97b5df8c..0169b161 100644
--- a/tmux.h
+++ b/tmux.h
@@ -1,4 +1,4 @@
-/* $Id: tmux.h,v 1.37 2007-10-03 12:43:47 nicm Exp $ */
+/* $Id: tmux.h,v 1.38 2007-10-03 21:31:07 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -259,28 +259,17 @@ struct buffer {
/* Message codes. */
enum hdrtype {
- MSG_ATTACH,
- MSG_DATA,
- MSG_DETACH,
+ MSG_COMMAND,
MSG_ERROR,
+ MSG_PRINT,
MSG_EXIT,
+ MSG_IDENTIFY,
+ MSG_READY,
+ MSG_DETACH,
+ MSG_RESIZE,
+ MSG_DATA,
MSG_KEYS,
- MSG_NEW,
- MSG_OKAY,
MSG_PAUSE,
- MSG_RENAME,
- MSG_SESSIONS,
- MSG_SIZE,
- MSG_WINDOWLIST,
- MSG_WINDOWS,
- MSG_BINDKEY,
- MSG_UNBINDKEY,
-};
-
-/* Message header structure. */
-struct hdr {
- enum hdrtype type;
- size_t size;
};
/* Session identification. */
@@ -290,59 +279,24 @@ struct sessid {
char name[MAXNAMELEN]; /* empty for current */
};
-struct new_data {
- char name[MAXNAMELEN];
- u_int sx;
- u_int sy;
-};
-
-struct attach_data {
- struct sessid sid;
- u_int sx;
- u_int sy;
-};
-
-struct sessions_data {
- u_int sessions;
-};
-
-struct sessions_entry {
- char name[MAXNAMELEN];
- time_t tim;
- u_int windows;
-};
-
-struct windows_data {
- struct sessid sid;
- u_int windows;
+/* Message header structure. */
+struct hdr {
+ enum hdrtype type;
+ size_t size;
};
-struct windows_entry {
- u_int idx;
- char tty[TTY_NAME_MAX];
-
- char name[MAXNAMELEN];
- char title[MAXTITLELEN];
+struct msg_command_data {
+ struct sessid sid;
};
-struct size_data {
+struct msg_identify_data {
u_int sx;
u_int sy;
};
-struct rename_data {
- int idx;
- struct sessid sid;
- char newname[MAXNAMELEN];
-};
-
-struct bind_data {
- int key;
- char cmd[MAXNAMELEN];
-
- int flags;
-
- u_int num;
+struct msg_resize_data {
+ u_int sx;
+ u_int sy;
};
/* Attributes. */
@@ -460,7 +414,7 @@ ARRAY_DECL(windows, struct window *);
/* Client session. */
struct session {
- char name[MAXNAMELEN];
+ char *name;
time_t tim;
struct window *window;
@@ -478,7 +432,10 @@ struct client {
u_int sx;
u_int sy;
- int prefix; /* waiting for command */
+#define CLIENT_TERMINAL 0x1
+#define CLIENT_PREFIX 0x2
+#define CLIENT_HOLD 0x4
+ int flags;
struct session *session;
};
@@ -493,50 +450,85 @@ struct client_ctx {
int loc_fd;
struct buffer *loc_in;
struct buffer *loc_out;
+};
- struct winsize ws;
+/* Key/command line command. */
+enum cmd_type {
+ CMD_NEWSESSION,
+ CMD_DETACHSESSION,
+ CMD_LISTSESSIONS,
};
-/* Key command. */
-struct cmd {
- int key;
- void (*fn)(struct client *, struct cmd *);
- u_int num;
- char *str;
+struct cmd_ctx {
+ struct client *client;
+ struct session *session;
+
+ void (*print)(struct cmd_ctx *, const char *, ...);
+ void (*error)(struct cmd_ctx *, const char *, ...);
+
+#define CMD_KEY 0x1
+ int flags;
};
-/* Key binding. */
-struct bind {
+struct cmd_entry {
+ enum cmd_type type;
const char *name;
- void (*fn)(struct client *, struct cmd *);
-
-#define BIND_USER 0x1
-#define BIND_NUMBER 0x2
-#define BIND_STRING 0x4
+ const char *alias;
+
+#define CMD_STARTSERVER 0x1
+#define CMD_NOSESSION 0x2
int flags;
+
+ int (*parse)(void **, int, char **, char **);
+ const char *(*usage)(void);
+ void (*exec)(void *, struct cmd_ctx *);
+ void (*send)(void *, struct buffer *);
+ void (*recv)(void **, struct buffer *);
+ void (*free)(void *);
+};
+
+struct cmd {
+ const struct cmd_entry *entry;
+ void *data;
+};
+
+/* Key binding. */
+struct binding {
+ int key;
+ struct cmd *cmd;
};
/* tmux.c */
extern volatile sig_atomic_t sigwinch;
extern volatile sig_atomic_t sigterm;
+extern int prefix_key;
extern int debug_level;
extern u_int status_lines;
extern char *default_command;
-int usage(const char *, ...);
+void usage(char **, const char *, ...);
void logfile(const char *);
void siginit(void);
void sigreset(void);
-/* op.c */
-int op_new_session(char *, int, char **);
-int op_attach(char *, int, char **);
-int op_rename_window(char *, int, char **);
-int op_bind_key(char *, int, char **);
-int op_unbind_key(char *, int, char **);
-
-/* op-list.c */
-int op_list_sessions(char *, int, char **);
-int op_list_windows(char *, int, char **);
+/* cmd.c */
+struct cmd *cmd_parse(int, char **, char **);
+void cmd_exec(struct cmd *, struct cmd_ctx *);
+void cmd_send(struct cmd *, struct buffer *);
+struct cmd *cmd_recv(struct buffer *);
+void cmd_free(struct cmd *);
+void cmd_send_string(struct buffer *, const char *);
+char *cmd_recv_string(struct buffer *);
+extern const struct cmd_entry cmd_new_session_entry;
+extern const struct cmd_entry cmd_detach_session_entry;
+extern const struct cmd_entry cmd_list_sessions_entry;
+
+/* bind.c */
+const struct bind *cmdx_lookup_bind(const char *);
+void cmdx_add_bind(int, u_int, char *, const struct bind *);
+void cmdx_remove_bind(int);
+void cmdx_init(void);
+void cmdx_free(void);
+void cmdx_dispatch(struct client *, int);
/* client.c */
int client_init(char *, struct client_ctx *, int);
@@ -552,14 +544,12 @@ void client_write_server2(
struct client_ctx *, enum hdrtype, void *, size_t, void *, size_t);
void client_fill_sessid(struct sessid *, char [MAXNAMELEN]);
-/* cmd.c */
-extern int cmd_prefix;
-const struct bind *cmd_lookup_bind(const char *);
-void cmd_add_bind(int, u_int, char *, const struct bind *);
-void cmd_remove_bind(int);
-void cmd_init(void);
-void cmd_free(void);
-void cmd_dispatch(struct client *, int);
+/* key-bindings.c */
+void key_bindings_add(int, struct cmd *);
+void key_bindings_remove(int);
+void key_bindings_init(void);
+void key_bindings_free(void);
+void key_bindings_dispatch(int, struct client *);
/* key-string.c */
int key_string_lookup(const char *);
@@ -582,7 +572,7 @@ void server_write_client2(struct client *,
void server_write_clients(
struct window *, enum hdrtype, const void *, size_t);
void server_window_changed(struct client *);
-void server_draw_client(struct client *, u_int, u_int);
+void server_draw_client(struct client *);
void server_draw_status(struct client *);
/* status.c */