Rewrite command handling to be more generic. Not finished!

pull/1/head
Nicholas Marriott 2007-10-03 21:31:07 +00:00
parent a5a17b40ee
commit df716ecc8f
18 changed files with 1049 additions and 1243 deletions

View File

@ -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 $

View File

@ -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

5
TODO
View File

@ -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

View File

@ -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)

View File

@ -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 (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) {
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) {
log_warn("ioctl(TIOCGWINSZ)");
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_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;
}

137
cmd-detach-session.c Normal file
View File

@ -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);
}

70
cmd-list-sessions.c Normal file
View File

@ -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);
}

162
cmd-new-session.c Normal file
View File

@ -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);
}

330
cmd.c
View File

@ -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 },
const struct cmd_entry *cmd_table[] = {
&cmd_detach_session_entry,
&cmd_list_sessions_entry,
&cmd_new_session_entry,
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 },
};
#define NCMDBIND (sizeof cmd_bind_table / sizeof cmd_bind_table[0])
const struct bind *
cmd_lookup_bind(const char *name)
struct cmd *
cmd_parse(int argc, char **argv, char **cause)
{
const struct bind *bind;
u_int i;
const struct cmd_entry **this, *entry;
struct cmd *cmd;
int opt;
for (i = 0; i < NCMDBIND; i++) {
bind = cmd_bind_table + i;
if (strcmp(bind->name, name) == 0)
return (bind);
*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 (strncmp((*this)->name, argv[0], strlen(argv[0])) != 0)
continue;
if (entry != NULL) {
xasprintf(cause, "ambiguous command: %s", argv[0]);
return (NULL);
}
entry = *this;
}
if (entry == NULL) {
xasprintf(cause, "unknown command: %s", argv[0]);
return (NULL);
}
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;
}
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);
usage:
if (entry->usage == NULL)
usage(cause, "%s", entry->name);
else
usage(cause, "%s", entry->usage());
return (NULL);
}
void
cmd_add_bind(int key, u_int num, char *str, const struct bind *bind)
cmd_exec(struct cmd *cmd, struct cmd_ctx *ctx)
{
struct cmd *cmd = NULL;
u_int i;
for (i = 0; i < cmd_count; i++) {
cmd = cmd_table + i;
if (cmd->key == key)
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;
}
}
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;
}
return (cmd->entry->exec(cmd->data, ctx));
}
void
cmd_remove_bind(int key)
cmd_send(struct cmd *cmd, struct buffer *b)
{
struct cmd *cmd;
u_int i;
buffer_write(b, &cmd->entry->type, sizeof cmd->entry->type);
for (i = 0; i < cmd_count; i++) {
cmd = cmd_table + i;
if (cmd->key == key) {
cmd->key = KEYC_NONE;
if (cmd->entry->send == NULL)
return;
return (cmd->entry->send(cmd->data, b));
}
struct cmd *
cmd_recv(struct buffer *b)
{
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);
cmd = xmalloc(sizeof *cmd);
cmd->entry = entry;
if (cmd->entry->recv != NULL)
cmd->entry->recv(&cmd->data, b);
return (cmd);
}
void
cmd_init(void)
cmd_free(struct cmd *cmd)
{
cmd_table = xmalloc(sizeof cmd_default);
memcpy(cmd_table, cmd_default, sizeof cmd_default);
if (cmd->entry->free != NULL)
cmd->entry->free(cmd->data);
xfree(cmd);
}
void
cmd_free(void)
cmd_send_string(struct buffer *b, const char *s)
{
/* XXX free strings */
xfree(cmd_table);
}
void
cmd_dispatch(struct client *c, int key)
{
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);
size_t n;
if (s == NULL) {
n = 0;
buffer_write(b, &n, sizeof n);
return;
}
n = strlen(s) + 1;
buffer_write(b, &n, sizeof n);
buffer_write(b, s, n);
}
void
cmd_fn_new(struct client *c, struct cmd *cmd)
char *
cmd_recv_string(struct buffer *b)
{
char *s;
char *s;
size_t n;
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);
}
void
cmd_fn_detach(struct client *c, unused struct cmd *cmd)
{
server_write_client(c, MSG_DETACH, NULL, 0);
}
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");
}
void
cmd_fn_meta(struct client *c, unused struct cmd *cmd)
{
window_key(c->session->window, cmd_prefix);
}
void
cmd_fn_next(struct client *c, unused struct cmd *cmd)
{
if (session_next(c->session) == 0)
server_window_changed(c);
else
server_write_message(c, "No next window");
}
void
cmd_fn_previous(struct client *c, unused struct cmd *cmd)
{
if (session_previous(c->session) == 0)
server_window_changed(c);
else
server_write_message(c, "No previous window");
}
void
cmd_fn_refresh(struct client *c, unused struct cmd *cmd)
{
server_draw_client(c, 0, c->sy - 1);
}
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);
}
void
cmd_fn_info(struct client *c, unused struct cmd *cmd)
{
struct window *w;
char *buf;
size_t len;
u_int i;
len = c->sx + 1;
buf = xmalloc(len);
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);
server_write_message(c, "%s", buf);
xfree(buf);
buffer_read(b, &n, sizeof n);
if (n == 0)
return (NULL);
s = xmalloc(n);
buffer_read(b, s, n);
s[n - 1] = '\0';
return (s);
}

214
key-bindings.c Normal file
View File

@ -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);
}

199
op-list.c
View File

@ -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);
}
}

271
op.c
View File

@ -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));
}

View File

@ -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);

View File

@ -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. */
int
server_msg_fn_new(struct hdr *hdr, struct client *c)
void
server_msg_fn_command_error(struct cmd_ctx *ctx, const char *fmt, ...)
{
struct new_data data;
char *msg;
if (c->session != NULL)
return (0);
if (hdr->size != sizeof data)
fatalx("bad MSG_NEW size");
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_command(struct hdr *hdr, struct client *c)
{
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);
}

View File

@ -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);

View File

@ -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);
}

148
tmux.c
View File

@ -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);
}

194
tmux.h
View File

@ -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,61 +279,26 @@ struct sessid {
char name[MAXNAMELEN]; /* empty for current */
};
struct new_data {
char name[MAXNAMELEN];
/* Message header structure. */
struct hdr {
enum hdrtype type;
size_t size;
};
struct msg_command_data {
struct sessid sid;
};
struct msg_identify_data {
u_int sx;
u_int sy;
};
struct attach_data {
struct sessid sid;
struct msg_resize_data {
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;
};
struct windows_entry {
u_int idx;
char tty[TTY_NAME_MAX];
char name[MAXNAMELEN];
char title[MAXTITLELEN];
};
struct size_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;
};
/* Attributes. */
#define ATTR_BRIGHT 0x1
#define ATTR_DIM 0x2
@ -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. */
/* Key/command line command. */
enum cmd_type {
CMD_NEWSESSION,
CMD_DETACHSESSION,
CMD_LISTSESSIONS,
};
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;
};
struct cmd_entry {
enum cmd_type type;
const char *name;
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 {
int key;
void (*fn)(struct client *, struct cmd *);
u_int num;
char *str;
const struct cmd_entry *entry;
void *data;
};
/* Key binding. */
struct bind {
const char *name;
void (*fn)(struct client *, struct cmd *);
#define BIND_USER 0x1
#define BIND_NUMBER 0x2
#define BIND_STRING 0x4
int flags;
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 **);
/* 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;
/* op-list.c */
int op_list_sessions(char *, int, char **);
int op_list_windows(char *, int, char **);
/* 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 */