mirror of
https://github.com/tmate-io/tmate.git
synced 2025-01-22 05:48:40 +01:00
Rewrite command handling to be more generic. Not finished!
This commit is contained in:
parent
a5a17b40ee
commit
df716ecc8f
6
CHANGES
6
CHANGES
@ -1,5 +1,9 @@
|
|||||||
03 October 2007
|
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) String number arguments. So you can do: tmux bind ^Q create "blah".
|
||||||
* (nicm) Key binding. tmux bind key command [argument] and tmux unbind key.
|
* (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.
|
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
|
(including mutt, emacs). No status bar yet and no key remapping or other
|
||||||
customisation.
|
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 $
|
||||||
|
|
||||||
|
9
Makefile
9
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
|
.SUFFIXES: .c .o .y .h
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
@ -17,9 +17,10 @@ DEBUG=
|
|||||||
META?= \002 # C-b
|
META?= \002 # C-b
|
||||||
|
|
||||||
SRCS= tmux.c server.c server-msg.c server-fn.c buffer.c buffer-poll.c status.c \
|
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 \
|
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 op.c op-list.c \
|
session.c local.c log.c client.c client-msg.c client-fn.c key-string.c \
|
||||||
key-string.c
|
key-bindings.c \
|
||||||
|
cmd.c cmd-new-session.c cmd-detach-session.c cmd-list-sessions.c
|
||||||
|
|
||||||
YACC= yacc -d
|
YACC= yacc -d
|
||||||
|
|
||||||
|
5
TODO
5
TODO
@ -33,8 +33,11 @@
|
|||||||
IPC is arse-about-face: too much overhead. 8-byte header for each
|
IPC is arse-about-face: too much overhead. 8-byte header for each
|
||||||
packet... hrm. already scanning output for \e, could add an extra
|
packet... hrm. already scanning output for \e, could add an extra
|
||||||
byte to it for message
|
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?)
|
- 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 --------------------------------------------------------------------
|
-- For 0.1 --------------------------------------------------------------------
|
||||||
- man page
|
- man page
|
||||||
|
17
client-msg.c
17
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>
|
* 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_DATA, client_msg_fn_data },
|
||||||
{ MSG_DETACH, client_msg_fn_detach },
|
{ MSG_DETACH, client_msg_fn_detach },
|
||||||
{ MSG_ERROR, client_msg_fn_error },
|
{ MSG_ERROR, client_msg_fn_error },
|
||||||
{ MSG_OKAY, client_msg_fn_okay },
|
|
||||||
{ MSG_PAUSE, client_msg_fn_pause },
|
{ MSG_PAUSE, client_msg_fn_pause },
|
||||||
};
|
};
|
||||||
#define NCLIENTMSG (sizeof client_msg_table / sizeof client_msg_table[0])
|
#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
|
int
|
||||||
client_msg_fn_data(
|
client_msg_fn_data(
|
||||||
struct hdr *hdr, struct client_ctx *cctx, unused char **error)
|
struct hdr *hdr, struct client_ctx *cctx, unused char **error)
|
||||||
@ -82,7 +80,6 @@ client_msg_fn_data(
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pause message from server. */
|
|
||||||
int
|
int
|
||||||
client_msg_fn_pause(
|
client_msg_fn_pause(
|
||||||
struct hdr *hdr, unused struct client_ctx *cctx, unused char **error)
|
struct hdr *hdr, unused struct client_ctx *cctx, unused char **error)
|
||||||
@ -92,17 +89,6 @@ client_msg_fn_pause(
|
|||||||
return (1);
|
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
|
int
|
||||||
client_msg_fn_error(struct hdr *hdr, struct client_ctx *cctx, char **error)
|
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);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Detach message from server. */
|
|
||||||
int
|
int
|
||||||
client_msg_fn_detach(
|
client_msg_fn_detach(
|
||||||
struct hdr *hdr, unused struct client_ctx *cctx, char **error)
|
struct hdr *hdr, unused struct client_ctx *cctx, char **error)
|
||||||
|
93
client.c
93
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>
|
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||||
@ -38,33 +38,19 @@ int client_process_local(struct client_ctx *, char **);
|
|||||||
int
|
int
|
||||||
client_init(char *path, struct client_ctx *cctx, int start_server)
|
client_init(char *path, struct client_ctx *cctx, int start_server)
|
||||||
{
|
{
|
||||||
struct sockaddr_un sa;
|
struct sockaddr_un sa;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
size_t sz;
|
struct msg_identify_data data;
|
||||||
int mode;
|
struct winsize ws;
|
||||||
u_int retries;
|
size_t sz;
|
||||||
|
int mode;
|
||||||
|
u_int retries;
|
||||||
|
|
||||||
if (path == NULL) {
|
if (path == NULL) {
|
||||||
xasprintf(&path,
|
xasprintf(&path,
|
||||||
"%s/%s-%lu", _PATH_TMP, __progname, (u_long) getuid());
|
"%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;
|
retries = 0;
|
||||||
retry:
|
retry:
|
||||||
if (stat(path, &sb) != 0) {
|
if (stat(path, &sb) != 0) {
|
||||||
@ -121,50 +107,18 @@ retry:
|
|||||||
cctx->srv_in = buffer_create(BUFSIZ);
|
cctx->srv_in = buffer_create(BUFSIZ);
|
||||||
cctx->srv_out = buffer_create(BUFSIZ);
|
cctx->srv_out = buffer_create(BUFSIZ);
|
||||||
|
|
||||||
return (0);
|
if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) {
|
||||||
}
|
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) {
|
||||||
|
log_warn("ioctl(TIOCGWINSZ)");
|
||||||
int
|
return (-1);
|
||||||
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) {
|
data.sx = ws.ws_col;
|
||||||
log_warnx("lost server");
|
data.sy = ws.ws_row;
|
||||||
return (1);
|
client_write_server(cctx, MSG_IDENTIFY, &data, sizeof data);
|
||||||
}
|
|
||||||
|
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -244,14 +198,15 @@ local_dead:
|
|||||||
void
|
void
|
||||||
client_handle_winch(struct client_ctx *cctx)
|
client_handle_winch(struct client_ctx *cctx)
|
||||||
{
|
{
|
||||||
struct size_data data;
|
struct msg_resize_data data;
|
||||||
|
struct winsize ws;
|
||||||
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &cctx->ws) == -1)
|
|
||||||
|
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
|
||||||
fatal("ioctl failed");
|
fatal("ioctl failed");
|
||||||
|
|
||||||
data.sx = cctx->ws.ws_col;
|
data.sx = ws.ws_col;
|
||||||
data.sy = cctx->ws.ws_row;
|
data.sy = ws.ws_row;
|
||||||
client_write_server(cctx, MSG_SIZE, &data, sizeof data);
|
client_write_server(cctx, MSG_RESIZE, &data, sizeof data);
|
||||||
|
|
||||||
sigwinch = 0;
|
sigwinch = 0;
|
||||||
}
|
}
|
||||||
|
137
cmd-detach-session.c
Normal file
137
cmd-detach-session.c
Normal 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
70
cmd-list-sessions.c
Normal 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
162
cmd-new-session.c
Normal 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
330
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>
|
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||||
@ -18,243 +18,163 @@
|
|||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <getopt.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
|
||||||
int cmd_prefix = META;
|
const struct cmd_entry *cmd_table[] = {
|
||||||
|
&cmd_detach_session_entry,
|
||||||
void cmd_fn_detach(struct client *, struct cmd *);
|
&cmd_list_sessions_entry,
|
||||||
void cmd_fn_last(struct client *, struct cmd *);
|
&cmd_new_session_entry,
|
||||||
void cmd_fn_meta(struct client *, struct cmd *);
|
NULL
|
||||||
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[] = {
|
struct cmd *
|
||||||
{ "detach", cmd_fn_detach, 0 },
|
cmd_parse(int argc, char **argv, char **cause)
|
||||||
{ "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)
|
|
||||||
{
|
{
|
||||||
const struct bind *bind;
|
const struct cmd_entry **this, *entry;
|
||||||
u_int i;
|
struct cmd *cmd;
|
||||||
|
int opt;
|
||||||
|
|
||||||
for (i = 0; i < NCMDBIND; i++) {
|
*cause = NULL;
|
||||||
bind = cmd_bind_table + i;
|
if (argc == 0)
|
||||||
if (strcmp(bind->name, name) == 0)
|
return (NULL);
|
||||||
return (bind);
|
|
||||||
|
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);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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;
|
return (cmd->entry->exec(cmd->data, ctx));
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
cmd_remove_bind(int key)
|
cmd_send(struct cmd *cmd, struct buffer *b)
|
||||||
{
|
{
|
||||||
struct cmd *cmd;
|
buffer_write(b, &cmd->entry->type, sizeof cmd->entry->type);
|
||||||
u_int i;
|
|
||||||
|
|
||||||
for (i = 0; i < cmd_count; i++) {
|
if (cmd->entry->send == NULL)
|
||||||
cmd = cmd_table + i;
|
return;
|
||||||
if (cmd->key == key) {
|
return (cmd->entry->send(cmd->data, b));
|
||||||
cmd->key = KEYC_NONE;
|
}
|
||||||
|
|
||||||
|
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;
|
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
|
void
|
||||||
cmd_init(void)
|
cmd_free(struct cmd *cmd)
|
||||||
{
|
{
|
||||||
cmd_table = xmalloc(sizeof cmd_default);
|
if (cmd->entry->free != NULL)
|
||||||
memcpy(cmd_table, cmd_default, sizeof cmd_default);
|
cmd->entry->free(cmd->data);
|
||||||
|
xfree(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
cmd_free(void)
|
cmd_send_string(struct buffer *b, const char *s)
|
||||||
{
|
{
|
||||||
/* XXX free strings */
|
size_t n;
|
||||||
xfree(cmd_table);
|
|
||||||
}
|
if (s == NULL) {
|
||||||
|
n = 0;
|
||||||
void
|
buffer_write(b, &n, sizeof n);
|
||||||
cmd_dispatch(struct client *c, int key)
|
return;
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
n = strlen(s) + 1;
|
||||||
|
buffer_write(b, &n, sizeof n);
|
||||||
|
|
||||||
|
buffer_write(b, s, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
char *
|
||||||
cmd_fn_new(struct client *c, struct cmd *cmd)
|
cmd_recv_string(struct buffer *b)
|
||||||
{
|
{
|
||||||
char *s;
|
char *s;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
s = cmd->str;
|
buffer_read(b, &n, sizeof n);
|
||||||
if (s == NULL)
|
|
||||||
s = default_command;
|
if (n == 0)
|
||||||
if (session_new(c->session, s, c->sx, c->sy) != 0)
|
return (NULL);
|
||||||
server_write_message(c, "%s failed", s); /* XXX */
|
|
||||||
else
|
s = xmalloc(n);
|
||||||
server_draw_client(c, 0, c->sy - 1);
|
buffer_read(b, s, n);
|
||||||
}
|
s[n - 1] = '\0';
|
||||||
|
|
||||||
void
|
return (s);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
214
key-bindings.c
Normal file
214
key-bindings.c
Normal 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
199
op-list.c
@ -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
271
op.c
@ -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));
|
|
||||||
}
|
|
17
server-fn.c
17
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>
|
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||||
@ -64,7 +64,7 @@ server_find_sessid(struct sessid *sid, char **cause)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (s == NULL) {
|
if (s == NULL) {
|
||||||
xasprintf(cause, "no sessions");
|
xasprintf(cause, "no sessions found");
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
if (n != 1) {
|
if (n != 1) {
|
||||||
@ -125,6 +125,8 @@ server_write_clients(
|
|||||||
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
|
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
|
||||||
c = ARRAY_ITEM(&clients, i);
|
c = ARRAY_ITEM(&clients, i);
|
||||||
if (c != NULL && c->session != NULL) {
|
if (c != NULL && c->session != NULL) {
|
||||||
|
if (c->flags & CLIENT_HOLD) /* XXX OUTPUT only */
|
||||||
|
continue;
|
||||||
if (c->session->window == w) {
|
if (c->session->window == w) {
|
||||||
log_debug(
|
log_debug(
|
||||||
"writing %d to clients: %d", type, c->fd);
|
"writing %d to clients: %d", type, c->fd);
|
||||||
@ -145,21 +147,22 @@ server_window_changed(struct client *c)
|
|||||||
w = c->session->window;
|
w = c->session->window;
|
||||||
if (c->sx != w->screen.sx || c->sy != w->screen.sy)
|
if (c->sx != w->screen.sx || c->sy != w->screen.sy)
|
||||||
window_resize(w, c->sx, c->sy);
|
window_resize(w, c->sx, c->sy);
|
||||||
server_draw_client(c, 0, c->sy - 1);
|
server_draw_client(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Draw window on client. */
|
/* Draw window on client. */
|
||||||
void
|
void
|
||||||
server_draw_client(struct client *c, u_int py_upper, u_int py_lower)
|
server_draw_client(struct client *c)
|
||||||
{
|
{
|
||||||
struct hdr hdr;
|
struct hdr hdr;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
struct screen *s = &c->session->window->screen;
|
||||||
|
|
||||||
buffer_ensure(c->out, sizeof hdr);
|
buffer_ensure(c->out, sizeof hdr);
|
||||||
buffer_add(c->out, sizeof hdr);
|
buffer_add(c->out, sizeof hdr);
|
||||||
size = BUFFER_USED(c->out);
|
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;
|
size = BUFFER_USED(c->out) - size;
|
||||||
log_debug("redrawing screen, %zu bytes", size);
|
log_debug("redrawing screen, %zu bytes", size);
|
||||||
|
404
server-msg.c
404
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>
|
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||||
@ -24,16 +24,13 @@
|
|||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
|
||||||
int server_msg_fn_attach(struct hdr *, struct client *);
|
int server_msg_fn_command(struct hdr *, struct client *);
|
||||||
int server_msg_fn_bindkey(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_keys(struct hdr *, struct client *);
|
||||||
int server_msg_fn_new(struct hdr *, struct client *);
|
int server_msg_fn_resize(struct hdr *, struct client *);
|
||||||
int server_msg_fn_rename(struct hdr *, struct client *);
|
|
||||||
int server_msg_fn_sessions(struct hdr *, struct client *);
|
void server_msg_fn_command_error(struct cmd_ctx *, const char *, ...);
|
||||||
int server_msg_fn_size(struct hdr *, struct client *);
|
void server_msg_fn_command_print(struct cmd_ctx *, const char *, ...);
|
||||||
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 *);
|
|
||||||
|
|
||||||
struct server_msg {
|
struct server_msg {
|
||||||
enum hdrtype type;
|
enum hdrtype type;
|
||||||
@ -41,16 +38,10 @@ struct server_msg {
|
|||||||
int (*fn)(struct hdr *, struct client *);
|
int (*fn)(struct hdr *, struct client *);
|
||||||
};
|
};
|
||||||
const struct server_msg server_msg_table[] = {
|
const struct server_msg server_msg_table[] = {
|
||||||
{ MSG_ATTACH, server_msg_fn_attach },
|
{ MSG_IDENTIFY, server_msg_fn_identify },
|
||||||
{ MSG_BINDKEY, server_msg_fn_bindkey },
|
{ MSG_COMMAND, server_msg_fn_command },
|
||||||
|
{ MSG_RESIZE, server_msg_fn_resize },
|
||||||
{ MSG_KEYS, server_msg_fn_keys },
|
{ 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])
|
#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
|
||||||
int
|
server_msg_fn_command_error(struct cmd_ctx *ctx, const char *fmt, ...)
|
||||||
server_msg_fn_new(struct hdr *hdr, struct client *c)
|
|
||||||
{
|
{
|
||||||
struct new_data data;
|
va_list ap;
|
||||||
char *msg;
|
char *msg;
|
||||||
|
|
||||||
if (c->session != NULL)
|
va_start(ap, fmt);
|
||||||
return (0);
|
xvasprintf(&msg, fmt, ap);
|
||||||
if (hdr->size != sizeof data)
|
va_end(ap);
|
||||||
fatalx("bad MSG_NEW size");
|
|
||||||
|
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);
|
buffer_read(c->in, &data, sizeof data);
|
||||||
|
|
||||||
c->sx = data.sx;
|
cmd = cmd_recv(c->in);
|
||||||
if (c->sx == 0)
|
log_debug("got command %u %s from client %d",
|
||||||
c->sx = 80;
|
cmd->entry->type, cmd->entry->name, c->fd);
|
||||||
c->sy = data.sy;
|
|
||||||
if (c->sy == 0)
|
|
||||||
c->sy = 25;
|
|
||||||
|
|
||||||
if (c->sy >= status_lines)
|
if (cmd->entry->flags & CMD_NOSESSION)
|
||||||
c->sy -= status_lines;
|
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';
|
ctx.error = server_msg_fn_command_error;
|
||||||
if (*data.name != '\0' && session_find(data.name) != NULL) {
|
ctx.print = server_msg_fn_command_print;
|
||||||
xasprintf(&msg, "duplicate session: %s", data.name);
|
|
||||||
server_write_client(c, MSG_ERROR, msg, strlen(msg));
|
|
||||||
xfree(msg);
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
c->session = session_create(data.name, default_command, c->sx, c->sy);
|
ctx.client = c;
|
||||||
if (c->session == NULL)
|
ctx.flags = 0;
|
||||||
fatalx("session_create failed");
|
|
||||||
|
|
||||||
server_write_client(c, MSG_OKAY, NULL, 0);
|
cmd_exec(cmd, &ctx);
|
||||||
server_draw_client(c, 0, c->sy - 1);
|
cmd_free(cmd);
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Attach message from client. */
|
|
||||||
int
|
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;
|
struct msg_identify_data data;
|
||||||
char *cause;
|
|
||||||
|
if (hdr->size < sizeof data)
|
||||||
if (c->session != NULL)
|
fatalx("bad MSG_IDENTIFY size");
|
||||||
return (0);
|
|
||||||
if (hdr->size != sizeof data)
|
|
||||||
fatalx("bad MSG_ATTACH size");
|
|
||||||
buffer_read(c->in, &data, sizeof data);
|
buffer_read(c->in, &data, sizeof data);
|
||||||
|
|
||||||
|
log_debug("got identify msg from client: %u,%u", data.sx, data.sy);
|
||||||
|
|
||||||
c->sx = data.sx;
|
c->sx = data.sx;
|
||||||
if (c->sx == 0)
|
|
||||||
c->sx = 80;
|
|
||||||
c->sy = data.sy;
|
c->sy = data.sy;
|
||||||
if (c->sy == 0)
|
|
||||||
c->sy = 25;
|
|
||||||
|
|
||||||
if (c->sy >= status_lines)
|
c->flags |= CLIENT_TERMINAL;
|
||||||
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);
|
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Size message from client. */
|
|
||||||
int
|
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)
|
if (hdr->size != sizeof data)
|
||||||
fatalx("bad MSG_SIZE size");
|
fatalx("bad MSG_SIZE size");
|
||||||
buffer_read(c->in, &data, sizeof data);
|
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)
|
if (c->sy == 0)
|
||||||
c->sy = 25;
|
c->sy = 25;
|
||||||
|
|
||||||
if (c->sy >= status_lines)
|
sy = c->sy;
|
||||||
c->sy -= status_lines;
|
if (sy < status_lines)
|
||||||
|
sy = status_lines + 1;
|
||||||
|
sy -= status_lines;
|
||||||
|
|
||||||
if (window_resize(c->session->window, c->sx, c->sy) != 0)
|
if (window_resize(c->session->window, c->sx, sy) != 0)
|
||||||
server_draw_client(c, 0, c->sy - 1);
|
server_draw_client(c);
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Keys message from client. */
|
|
||||||
int
|
int
|
||||||
server_msg_fn_keys(struct hdr *hdr, struct client *c)
|
server_msg_fn_keys(struct hdr *hdr, struct client *c)
|
||||||
{
|
{
|
||||||
int key;
|
int key;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
||||||
if (c->session == NULL)
|
|
||||||
return (0);
|
|
||||||
if (hdr->size & 0x1)
|
if (hdr->size & 0x1)
|
||||||
fatalx("bad MSG_KEYS size");
|
fatalx("bad MSG_KEYS size");
|
||||||
|
|
||||||
|
if (c->flags & CLIENT_HOLD) {
|
||||||
|
server_draw_client(c);
|
||||||
|
c->flags &= ~CLIENT_HOLD;
|
||||||
|
}
|
||||||
|
|
||||||
size = hdr->size;
|
size = hdr->size;
|
||||||
while (size != 0) {
|
while (size != 0) {
|
||||||
key = (int16_t) input_extract16(c->in);
|
key = (int16_t) input_extract16(c->in);
|
||||||
size -= 2;
|
size -= 2;
|
||||||
|
|
||||||
if (c->prefix) {
|
if (c->flags & CLIENT_PREFIX) {
|
||||||
cmd_dispatch(c, key);
|
key_bindings_dispatch(key, c);
|
||||||
c->prefix = 0;
|
c->flags &= ~CLIENT_PREFIX;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key == cmd_prefix)
|
if (key == prefix_key)
|
||||||
c->prefix = 1;
|
c->flags |= CLIENT_PREFIX;
|
||||||
else
|
else
|
||||||
window_key(c->session->window, key);
|
window_key(c->session->window, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (0);
|
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);
|
|
||||||
}
|
|
||||||
|
6
server.c
6
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>
|
* 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(&clients);
|
||||||
ARRAY_INIT(&sessions);
|
ARRAY_INIT(&sessions);
|
||||||
|
|
||||||
cmd_init();
|
key_bindings_init();
|
||||||
|
|
||||||
pfds = NULL;
|
pfds = NULL;
|
||||||
while (!sigterm) {
|
while (!sigterm) {
|
||||||
@ -171,7 +171,7 @@ server_main(char *srv_path, int srv_fd)
|
|||||||
server_handle_clients(&pfd);
|
server_handle_clients(&pfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd_free();
|
key_bindings_free();
|
||||||
|
|
||||||
close(srv_fd);
|
close(srv_fd);
|
||||||
unlink(srv_path);
|
unlink(srv_path);
|
||||||
|
10
session.c
10
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>
|
* 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))
|
if (i == ARRAY_LENGTH(&sessions))
|
||||||
ARRAY_ADD(&sessions, s);
|
ARRAY_ADD(&sessions, s);
|
||||||
|
|
||||||
if (*name != '\0')
|
if (name != NULL)
|
||||||
strlcpy(s->name, name, sizeof s->name);
|
s->name = xstrdup(name);
|
||||||
else
|
else
|
||||||
xsnprintf(s->name, sizeof s->name, "%u", i);
|
xasprintf(&s->name, "%u", i);
|
||||||
|
|
||||||
if (session_new(s, cmd, sx, sy) != 0) {
|
if (session_new(s, cmd, sx, sy) != 0) {
|
||||||
session_destroy(s);
|
session_destroy(s);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
@ -92,6 +91,7 @@ session_destroy(struct session *s)
|
|||||||
while (!ARRAY_EMPTY(&s->windows))
|
while (!ARRAY_EMPTY(&s->windows))
|
||||||
window_remove(&s->windows, ARRAY_FIRST(&s->windows));
|
window_remove(&s->windows, ARRAY_FIRST(&s->windows));
|
||||||
|
|
||||||
|
xfree(s->name);
|
||||||
xfree(s);
|
xfree(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
148
tmux.c
148
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>
|
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||||
@ -19,7 +19,10 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
|
#include <poll.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -35,45 +38,29 @@ const char *malloc_options = "AFGJPX";
|
|||||||
volatile sig_atomic_t sigwinch;
|
volatile sig_atomic_t sigwinch;
|
||||||
volatile sig_atomic_t sigterm;
|
volatile sig_atomic_t sigterm;
|
||||||
int debug_level;
|
int debug_level;
|
||||||
|
int prefix_key = META;
|
||||||
u_int status_lines;
|
u_int status_lines;
|
||||||
char *default_command;
|
char *default_command;
|
||||||
|
|
||||||
void sighandler(int);
|
void sighandler(int);
|
||||||
|
|
||||||
struct op {
|
void
|
||||||
const char *cmd;
|
usage(char **ptr, const char *fmt, ...)
|
||||||
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, ...)
|
|
||||||
{
|
{
|
||||||
char *msg;
|
char *msg;
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
if (fmt == NULL) {
|
if (fmt == NULL) {
|
||||||
fprintf(stderr,
|
xasprintf(ptr,
|
||||||
"usage: %s [-v] [-S path] command [flags]\n", __progname);
|
"usage: %s [-v] [-S path] command [flags]", __progname);
|
||||||
return (1);
|
} else {
|
||||||
}
|
va_start(ap, fmt);
|
||||||
|
xvasprintf(&msg, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
va_start(ap, fmt);
|
xasprintf(ptr, "usage: %s [-v] [-S path] %s", __progname, msg);
|
||||||
xvasprintf(&msg, fmt, ap);
|
xfree(msg);
|
||||||
va_end(ap);
|
}
|
||||||
fprintf(stderr, "usage: %s [-v] [-S path] %s\n", __progname, msg);
|
|
||||||
xfree(msg);
|
|
||||||
return (1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -172,30 +159,39 @@ sigreset(void)
|
|||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
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;
|
const char *shell;
|
||||||
char *path;
|
char *path, *cause, name[MAXNAMELEN];
|
||||||
int opt;
|
int opt;
|
||||||
u_int i;
|
|
||||||
|
|
||||||
|
*name = '\0';
|
||||||
path = NULL;
|
path = NULL;
|
||||||
while ((opt = getopt(argc, argv, "S:v?")) != EOF) {
|
while ((opt = getopt(argc, argv, "S:s:v?")) != EOF) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'S':
|
case 'S':
|
||||||
path = xstrdup(optarg);
|
path = xstrdup(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 's':
|
||||||
|
if (strlcpy(name, optarg, sizeof name) >= sizeof name)
|
||||||
|
errx(1, "session name too long: %s", optarg);
|
||||||
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
debug_level++;
|
debug_level++;
|
||||||
break;
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
default:
|
default:
|
||||||
exit(usage(NULL));
|
goto usage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
argc -= optind;
|
argc -= optind;
|
||||||
argv += optind;
|
argv += optind;
|
||||||
if (argc == 0)
|
if (argc == 0)
|
||||||
exit(usage(NULL));
|
goto usage;
|
||||||
|
|
||||||
log_open(stderr, LOG_USER, debug_level);
|
log_open(stderr, LOG_USER, debug_level);
|
||||||
|
|
||||||
@ -206,21 +202,75 @@ main(int argc, char **argv)
|
|||||||
shell = "/bin/ksh";
|
shell = "/bin/ksh";
|
||||||
xasprintf(&default_command, "exec %s -l", shell);
|
xasprintf(&default_command, "exec %s -l", shell);
|
||||||
|
|
||||||
found = NULL;
|
if ((cmd = cmd_parse(argc, argv, &cause)) == NULL) {
|
||||||
for (i = 0; i < NOP; i++) {
|
if (cause == NULL)
|
||||||
op = op_table + i;
|
goto usage;
|
||||||
if (op->alias != NULL && strcmp(argv[0], op->alias) == 0)
|
log_warnx("%s", cause);
|
||||||
exit(op->fn(path, argc, argv));
|
exit(1);
|
||||||
if (strncmp(argv[0], op->cmd, strlen(argv[0])) == 0) {
|
}
|
||||||
if (found != NULL) {
|
|
||||||
log_warnx("ambiguous command: %s", argv[0]);
|
if (!(cmd->entry->flags & CMD_NOSESSION))
|
||||||
exit(1);
|
client_fill_sessid(&data.sid, name);
|
||||||
}
|
if (client_init(path, &cctx, cmd->entry->flags & CMD_STARTSERVER) != 0)
|
||||||
found = op;
|
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)
|
/* NOTREACHED */
|
||||||
exit(found->fn(path, argc, argv));
|
|
||||||
|
|
||||||
exit(usage(NULL));
|
usage:
|
||||||
|
usage(&cause, NULL);
|
||||||
|
fprintf(stderr, "%s\n", cause);
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
|
194
tmux.h
194
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>
|
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||||
@ -259,28 +259,17 @@ struct buffer {
|
|||||||
|
|
||||||
/* Message codes. */
|
/* Message codes. */
|
||||||
enum hdrtype {
|
enum hdrtype {
|
||||||
MSG_ATTACH,
|
MSG_COMMAND,
|
||||||
MSG_DATA,
|
|
||||||
MSG_DETACH,
|
|
||||||
MSG_ERROR,
|
MSG_ERROR,
|
||||||
|
MSG_PRINT,
|
||||||
MSG_EXIT,
|
MSG_EXIT,
|
||||||
|
MSG_IDENTIFY,
|
||||||
|
MSG_READY,
|
||||||
|
MSG_DETACH,
|
||||||
|
MSG_RESIZE,
|
||||||
|
MSG_DATA,
|
||||||
MSG_KEYS,
|
MSG_KEYS,
|
||||||
MSG_NEW,
|
|
||||||
MSG_OKAY,
|
|
||||||
MSG_PAUSE,
|
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. */
|
/* Session identification. */
|
||||||
@ -290,61 +279,26 @@ struct sessid {
|
|||||||
char name[MAXNAMELEN]; /* empty for current */
|
char name[MAXNAMELEN]; /* empty for current */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct new_data {
|
/* Message header structure. */
|
||||||
char name[MAXNAMELEN];
|
struct hdr {
|
||||||
|
enum hdrtype type;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct msg_command_data {
|
||||||
|
struct sessid sid;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct msg_identify_data {
|
||||||
u_int sx;
|
u_int sx;
|
||||||
u_int sy;
|
u_int sy;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct attach_data {
|
struct msg_resize_data {
|
||||||
struct sessid sid;
|
|
||||||
u_int sx;
|
u_int sx;
|
||||||
u_int sy;
|
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. */
|
/* Attributes. */
|
||||||
#define ATTR_BRIGHT 0x1
|
#define ATTR_BRIGHT 0x1
|
||||||
#define ATTR_DIM 0x2
|
#define ATTR_DIM 0x2
|
||||||
@ -460,7 +414,7 @@ ARRAY_DECL(windows, struct window *);
|
|||||||
|
|
||||||
/* Client session. */
|
/* Client session. */
|
||||||
struct session {
|
struct session {
|
||||||
char name[MAXNAMELEN];
|
char *name;
|
||||||
time_t tim;
|
time_t tim;
|
||||||
|
|
||||||
struct window *window;
|
struct window *window;
|
||||||
@ -478,7 +432,10 @@ struct client {
|
|||||||
u_int sx;
|
u_int sx;
|
||||||
u_int sy;
|
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;
|
struct session *session;
|
||||||
};
|
};
|
||||||
@ -493,50 +450,85 @@ struct client_ctx {
|
|||||||
int loc_fd;
|
int loc_fd;
|
||||||
struct buffer *loc_in;
|
struct buffer *loc_in;
|
||||||
struct buffer *loc_out;
|
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 {
|
struct cmd {
|
||||||
int key;
|
const struct cmd_entry *entry;
|
||||||
void (*fn)(struct client *, struct cmd *);
|
void *data;
|
||||||
u_int num;
|
|
||||||
char *str;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Key binding. */
|
/* Key binding. */
|
||||||
struct bind {
|
struct binding {
|
||||||
const char *name;
|
int key;
|
||||||
void (*fn)(struct client *, struct cmd *);
|
struct cmd *cmd;
|
||||||
|
|
||||||
#define BIND_USER 0x1
|
|
||||||
#define BIND_NUMBER 0x2
|
|
||||||
#define BIND_STRING 0x4
|
|
||||||
int flags;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* tmux.c */
|
/* tmux.c */
|
||||||
extern volatile sig_atomic_t sigwinch;
|
extern volatile sig_atomic_t sigwinch;
|
||||||
extern volatile sig_atomic_t sigterm;
|
extern volatile sig_atomic_t sigterm;
|
||||||
|
extern int prefix_key;
|
||||||
extern int debug_level;
|
extern int debug_level;
|
||||||
extern u_int status_lines;
|
extern u_int status_lines;
|
||||||
extern char *default_command;
|
extern char *default_command;
|
||||||
int usage(const char *, ...);
|
void usage(char **, const char *, ...);
|
||||||
void logfile(const char *);
|
void logfile(const char *);
|
||||||
void siginit(void);
|
void siginit(void);
|
||||||
void sigreset(void);
|
void sigreset(void);
|
||||||
|
|
||||||
/* op.c */
|
/* cmd.c */
|
||||||
int op_new_session(char *, int, char **);
|
struct cmd *cmd_parse(int, char **, char **);
|
||||||
int op_attach(char *, int, char **);
|
void cmd_exec(struct cmd *, struct cmd_ctx *);
|
||||||
int op_rename_window(char *, int, char **);
|
void cmd_send(struct cmd *, struct buffer *);
|
||||||
int op_bind_key(char *, int, char **);
|
struct cmd *cmd_recv(struct buffer *);
|
||||||
int op_unbind_key(char *, int, char **);
|
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 */
|
/* bind.c */
|
||||||
int op_list_sessions(char *, int, char **);
|
const struct bind *cmdx_lookup_bind(const char *);
|
||||||
int op_list_windows(char *, int, 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 */
|
/* client.c */
|
||||||
int client_init(char *, struct client_ctx *, int);
|
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);
|
struct client_ctx *, enum hdrtype, void *, size_t, void *, size_t);
|
||||||
void client_fill_sessid(struct sessid *, char [MAXNAMELEN]);
|
void client_fill_sessid(struct sessid *, char [MAXNAMELEN]);
|
||||||
|
|
||||||
/* cmd.c */
|
/* key-bindings.c */
|
||||||
extern int cmd_prefix;
|
void key_bindings_add(int, struct cmd *);
|
||||||
const struct bind *cmd_lookup_bind(const char *);
|
void key_bindings_remove(int);
|
||||||
void cmd_add_bind(int, u_int, char *, const struct bind *);
|
void key_bindings_init(void);
|
||||||
void cmd_remove_bind(int);
|
void key_bindings_free(void);
|
||||||
void cmd_init(void);
|
void key_bindings_dispatch(int, struct client *);
|
||||||
void cmd_free(void);
|
|
||||||
void cmd_dispatch(struct client *, int);
|
|
||||||
|
|
||||||
/* key-string.c */
|
/* key-string.c */
|
||||||
int key_string_lookup(const char *);
|
int key_string_lookup(const char *);
|
||||||
@ -582,7 +572,7 @@ void server_write_client2(struct client *,
|
|||||||
void server_write_clients(
|
void server_write_clients(
|
||||||
struct window *, enum hdrtype, const void *, size_t);
|
struct window *, enum hdrtype, const void *, size_t);
|
||||||
void server_window_changed(struct client *);
|
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 *);
|
void server_draw_status(struct client *);
|
||||||
|
|
||||||
/* status.c */
|
/* status.c */
|
||||||
|
Loading…
Reference in New Issue
Block a user