summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@cvs.openbsd.org>2009-07-13 17:47:47 +0000
committerNicholas Marriott <nicm@cvs.openbsd.org>2009-07-13 17:47:47 +0000
commitc2c663e118deaaeb506c6b6fdd8d7c672ce0c680 (patch)
treed096eba061c552bc79881ce87d35a568697dc746
parent05c6d0668eda3213f427d840f5f588636d06a4d2 (diff)
Tidy up and improve target (-t) argument parsing:
- move the code back into cmd.c and merge with the existing functions where possible; - accept "-tttyp0" as well as "-t/dev/ttyp0" for clients; - when looking up session names, try an exact match first, and if that fails look for it as an fnmatch pattern and then as the start of a name - if more that one session matches an error is given; so if there is one session called "mysession", -tmysession, -tmysess, -tmysess* are equivalent but if there is also "mysession2", the last two are errors; - similarly for windows, if the argument is not a valid index or exact window name match, try it against the window names as an fnmatch pattern and a prefix.
-rw-r--r--usr.bin/tmux/Makefile4
-rw-r--r--usr.bin/tmux/arg.c194
-rw-r--r--usr.bin/tmux/cmd-link-window.c15
-rw-r--r--usr.bin/tmux/cmd-move-window.c15
-rw-r--r--usr.bin/tmux/cmd-new-window.c14
-rw-r--r--usr.bin/tmux/cmd.c422
-rw-r--r--usr.bin/tmux/tmux.145
-rw-r--r--usr.bin/tmux/tmux.h11
8 files changed, 414 insertions, 306 deletions
diff --git a/usr.bin/tmux/Makefile b/usr.bin/tmux/Makefile
index 88bff2ff7ec..ddcc1479e99 100644
--- a/usr.bin/tmux/Makefile
+++ b/usr.bin/tmux/Makefile
@@ -1,7 +1,7 @@
-# $OpenBSD: Makefile,v 1.5 2009/07/09 15:47:49 nicm Exp $
+# $OpenBSD: Makefile,v 1.6 2009/07/13 17:47:46 nicm Exp $
PROG= tmux
-SRCS= arg.c attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \
+SRCS= attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \
client-msg.c client.c clock.c cmd-attach-session.c cmd-bind-key.c \
cmd-break-pane.c cmd-choose-session.c cmd-choose-window.c \
cmd-clear-history.c cmd-clock-mode.c cmd-command-prompt.c \
diff --git a/usr.bin/tmux/arg.c b/usr.bin/tmux/arg.c
deleted file mode 100644
index e45a5887a0e..00000000000
--- a/usr.bin/tmux/arg.c
+++ /dev/null
@@ -1,194 +0,0 @@
-/* $OpenBSD: arg.c,v 1.2 2009/06/02 11:18:59 ray Exp $ */
-
-/*
- * Copyright (c) 2008 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 <fnmatch.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "tmux.h"
-
-struct client *arg_lookup_client(const char *);
-struct session *arg_lookup_session(const char *);
-
-struct client *
-arg_lookup_client(const char *name)
-{
- struct client *c;
- u_int i;
-
- for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
- c = ARRAY_ITEM(&clients, i);
- if (c != NULL && strcmp(name, c->tty.path) == 0)
- return (c);
- }
-
- return (NULL);
-}
-
-struct session *
-arg_lookup_session(const char *name)
-{
- struct session *s, *newest = NULL;
- struct timeval *tv;
- u_int i;
-
- tv = NULL;
- for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
- s = ARRAY_ITEM(&sessions, i);
- if (s == NULL || fnmatch(name, s->name, 0) != 0)
- continue;
-
- if (tv == NULL || timercmp(&s->tv, tv, >)) {
- newest = s;
- tv = &s->tv;
- }
- }
-
- return (newest);
-}
-
-struct client *
-arg_parse_client(const char *arg)
-{
- struct client *c;
- char *arg2;
- size_t n;
-
- if (arg != NULL && (arg[0] != ':' || arg[1] != '\0')) {
- arg2 = xstrdup(arg);
-
- /* Trim a trailing : if any from the argument. */
- n = strlen(arg2);
- if (n && arg2[n - 1] == ':')
- arg2[n - 1] = '\0';
-
- /* Try and look up the client name. */
- c = arg_lookup_client(arg2);
- xfree(arg2);
- return (c);
- }
-
- return (NULL);
-}
-
-struct session *
-arg_parse_session(const char *arg)
-{
- struct session *s;
- struct client *c;
- char *arg2;
- size_t n;
-
- if (arg != NULL && (arg[0] != ':' || arg[1] != '\0')) {
- arg2 = xstrdup(arg);
-
- /* Trim a trailing : if any from the argument. */
- n = strlen(arg2);
- if (n && arg2[n - 1] == ':')
- arg2[n - 1] = '\0';
-
- /* See if the argument matches a session. */
- if ((s = arg_lookup_session(arg2)) != NULL) {
- xfree(arg2);
- return (s);
- }
-
- /* If not try a client. */
- if ((c = arg_lookup_client(arg2)) != NULL) {
- xfree(arg2);
- return (c->session);
- }
-
- xfree(arg2);
- }
-
- return (NULL);
-}
-
-int
-arg_parse_window(const char *arg, struct session **s, int *idx)
-{
- char *arg2, *ptr;
- const char *errstr;
-
- *idx = -1;
-
- /* Handle no argument or a single :. */
- if (arg == NULL || (arg[0] == ':' && arg[1] == '\0')) {
- *s = arg_parse_session(NULL);
- return (0);
- }
-
- /* Find the separator if any. */
- arg2 = xstrdup(arg);
- ptr = strrchr(arg2, ':');
-
- /*
- * If it is first, this means no session name, so use current session
- * and try to convert the rest as index.
- */
- if (ptr == arg2) {
- *idx = strtonum(ptr + 1, 0, INT_MAX, &errstr);
- if (errstr != NULL) {
- xfree(arg2);
- return (1);
- }
-
- xfree(arg2);
- *s = arg_parse_session(NULL);
- return (0);
- }
-
- /* If missing, try as an index, else look up immediately. */
- if (ptr == NULL) {
- *idx = strtonum(arg2, 0, INT_MAX, &errstr);
- if (errstr == NULL) {
- /* This is good as an index; use current session. */
- xfree(arg2);
- *s = arg_parse_session(NULL);
- return (0);
- }
-
- *idx = -1;
- goto lookup;
- }
-
- /* If last, strip it and look up as a session. */
- if (ptr[1] == '\0') {
- *ptr = '\0';
- goto lookup;
- }
-
- /* Present but not first and not last. Break and convert both. */
- *ptr = '\0';
- *idx = strtonum(ptr + 1, 0, INT_MAX, &errstr);
- if (errstr != NULL) {
- xfree(arg2);
- return (1);
- }
-
-lookup:
- /* Look up as session. */
- *s = arg_parse_session(arg2);
- xfree(arg2);
- if (*s == NULL)
- return (1);
- return (0);
-}
diff --git a/usr.bin/tmux/cmd-link-window.c b/usr.bin/tmux/cmd-link-window.c
index 32144859fcf..29d18ab88a0 100644
--- a/usr.bin/tmux/cmd-link-window.c
+++ b/usr.bin/tmux/cmd-link-window.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-link-window.c,v 1.1 2009/06/01 22:58:49 nicm Exp $ */
+/* $OpenBSD: cmd-link-window.c,v 1.2 2009/07/13 17:47:46 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -52,19 +52,8 @@ cmd_link_window_exec(struct cmd *self, struct cmd_ctx *ctx)
if ((wl_src = cmd_find_window(ctx, data->src, NULL)) == NULL)
return (-1);
-
- if (arg_parse_window(data->dst, &dst, &idx) != 0) {
- ctx->error(ctx, "bad window: %s", data->dst);
- return (-1);
- }
- if (dst == NULL)
- dst = ctx->cursession;
- if (dst == NULL)
- dst = cmd_current_session(ctx);
- if (dst == NULL) {
- ctx->error(ctx, "session not found: %s", data->dst);
+ if ((idx = cmd_find_index(ctx, data->dst, &dst)) == -2)
return (-1);
- }
wl_dst = NULL;
if (idx != -1)
diff --git a/usr.bin/tmux/cmd-move-window.c b/usr.bin/tmux/cmd-move-window.c
index bde3ed61380..b818beaa141 100644
--- a/usr.bin/tmux/cmd-move-window.c
+++ b/usr.bin/tmux/cmd-move-window.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-move-window.c,v 1.1 2009/06/01 22:58:49 nicm Exp $ */
+/* $OpenBSD: cmd-move-window.c,v 1.2 2009/07/13 17:47:46 nicm Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -54,19 +54,8 @@ cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx)
if ((wl_src = cmd_find_window(ctx, data->src, &src)) == NULL)
return (-1);
-
- if (arg_parse_window(data->dst, &dst, &idx) != 0) {
- ctx->error(ctx, "bad window: %s", data->dst);
- return (-1);
- }
- if (dst == NULL)
- dst = ctx->cursession;
- if (dst == NULL)
- dst = cmd_current_session(ctx);
- if (dst == NULL) {
- ctx->error(ctx, "session not found: %s", data->dst);
+ if ((idx = cmd_find_index(ctx, data->dst, &dst)) == -2)
return (-1);
- }
wl_dst = NULL;
if (idx != -1)
diff --git a/usr.bin/tmux/cmd-new-window.c b/usr.bin/tmux/cmd-new-window.c
index fe0729f71cd..eefbebe7e29 100644
--- a/usr.bin/tmux/cmd-new-window.c
+++ b/usr.bin/tmux/cmd-new-window.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-new-window.c,v 1.2 2009/07/07 06:58:49 nicm Exp $ */
+/* $OpenBSD: cmd-new-window.c,v 1.3 2009/07/13 17:47:46 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -126,18 +126,8 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
if (data == NULL)
return (0);
- if (arg_parse_window(data->target, &s, &idx) != 0) {
- ctx->error(ctx, "bad window: %s", data->target);
+ if ((idx = cmd_find_index(ctx, data->target, &s)) == -2)
return (-1);
- }
- if (s == NULL)
- s = ctx->cursession;
- if (s == NULL)
- s = cmd_current_session(ctx);
- if (s == NULL) {
- ctx->error(ctx, "session not found: %s", data->target);
- return (-1);
- }
wl = NULL;
if (idx != -1)
diff --git a/usr.bin/tmux/cmd.c b/usr.bin/tmux/cmd.c
index b4cdd0ec5d8..1ac380ffd34 100644
--- a/usr.bin/tmux/cmd.c
+++ b/usr.bin/tmux/cmd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd.c,v 1.4 2009/07/09 15:47:49 nicm Exp $ */
+/* $OpenBSD: cmd.c,v 1.5 2009/07/13 17:47:46 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -19,6 +19,8 @@
#include <sys/types.h>
#include <sys/time.h>
+#include <fnmatch.h>
+#include <paths.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -100,6 +102,11 @@ const struct cmd_entry *cmd_table[] = {
NULL
};
+struct session *cmd_newest_session(void);
+struct client *cmd_lookup_client(const char *);
+struct session *cmd_lookup_session(const char *, int *);
+struct winlink *cmd_lookup_window(struct session *, const char *, int *);
+
struct cmd *
cmd_parse(int argc, char **argv, char **cause)
{
@@ -294,106 +301,421 @@ cmd_recv_string(struct buffer *b)
return (s);
}
+/*
+ * Figure out the current session. Use: 1) the current session, if the command
+ * context has one; 2) the session specified in the TMUX variable from the
+ * environment (as passed from the client); 3) the newest session.
+ */
struct session *
cmd_current_session(struct cmd_ctx *ctx)
{
struct msg_command_data *data = ctx->msgdata;
- struct timeval *tv;
- struct session *s, *newest = NULL;
- u_int i;
+ struct session *s;
if (ctx->cursession != NULL)
return (ctx->cursession);
if (data != NULL && data->pid != -1) {
- if (data->pid != getpid()) {
- ctx->error(ctx, "wrong server: %ld", (long) data->pid);
+ if (data->pid != getpid())
return (NULL);
- }
- if (data->idx > ARRAY_LENGTH(&sessions)) {
- ctx->error(ctx, "index out of range: %d", data->idx);
+ if (data->idx > ARRAY_LENGTH(&sessions))
return (NULL);
- }
- if ((s = ARRAY_ITEM(&sessions, data->idx)) == NULL) {
- ctx->error(ctx, "session doesn't exist: %u", data->idx);
+ if ((s = ARRAY_ITEM(&sessions, data->idx)) == NULL)
return (NULL);
- }
return (s);
}
- tv = NULL;
+ return (cmd_newest_session());
+}
+
+/* Find the newest session. */
+struct session *
+cmd_newest_session(void)
+{
+ struct session *s, *snewest;
+ struct timeval *tv = NULL;
+ u_int i;
+
+ snewest = NULL;
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
- s = ARRAY_ITEM(&sessions, i);
- if (s != NULL && (tv == NULL || timercmp(&s->tv, tv, >))) {
- newest = ARRAY_ITEM(&sessions, i);
+ if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
+ continue;
+
+ if (tv == NULL || timercmp(&s->tv, tv, >)) {
+ snewest = s;
tv = &s->tv;
}
}
- return (newest);
+
+ return (snewest);
}
+/* Find the target client or report an error and return NULL. */
struct client *
cmd_find_client(struct cmd_ctx *ctx, const char *arg)
{
struct client *c;
+ char *tmparg;
+ size_t arglen;
+ /* A NULL argument means the current client. */
if (arg == NULL)
- c = ctx->curclient;
- else {
- if ((c = arg_parse_client(arg)) == NULL) {
- if (arg != NULL)
- ctx->error(ctx, "client not found: %s", arg);
- else
- ctx->error(ctx, "no client found");
+ return (ctx->curclient);
+ tmparg = xstrdup(arg);
+
+ /* Trim a single trailing colon if any. */
+ arglen = strlen(tmparg);
+ if (arglen != 0 && tmparg[arglen - 1] == ':')
+ tmparg[arglen - 1] = '\0';
+
+ /* Find the client, if any. */
+ c = cmd_lookup_client(tmparg);
+
+ /* If no client found, report an error. */
+ if (c == NULL)
+ ctx->error(ctx, "client not found: %s", tmparg);
+
+ xfree(tmparg);
+ return (c);
+}
+
+/*
+ * Lookup a client by device path. Either of a full match and a match without a
+ * leading _PATH_DEV ("/dev/") is accepted.
+ */
+struct client *
+cmd_lookup_client(const char *name)
+{
+ struct client *c;
+ const char *path;
+ u_int i;
+
+ for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
+ if ((c = ARRAY_ITEM(&clients, i)) == NULL)
+ continue;
+ path = c->tty.path;
+
+ /* Check for exact matches. */
+ if (strcmp(name, path) == 0)
+ return (c);
+
+ /* Check without leading /dev if present. */
+ if (strncmp(path, _PATH_DEV, (sizeof _PATH_DEV) - 1) != 0)
+ continue;
+ if (strcmp(name, path + (sizeof _PATH_DEV) - 1) == 0)
+ return (c);
+ }
+
+ return (NULL);
+}
+
+/* Lookup a session by name. If no session is found, NULL is returned. */
+struct session *
+cmd_lookup_session(const char *name, int *ambiguous)
+{
+ struct session *s, *sfound;
+ u_int i;
+
+ *ambiguous = 0;
+
+ /*
+ * Look for matches. Session names must be unique so an exact match
+ * can't be ambigious and can just be returned.
+ */
+ sfound = NULL;
+ for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
+ if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
+ continue;
+
+ /* Check for an exact match and return it if found. */
+ if (strcmp(name, s->name) == 0)
+ return (s);
+
+ /* Then check for pattern matches. */
+ if (strncmp(name, s->name, strlen(name)) == 0 ||
+ fnmatch(name, s->name, 0) == 0) {
+ if (sfound != NULL) {
+ *ambiguous = 1;
+ return (NULL);
+ }
+ sfound = s;
}
}
- return (c);
+
+ return (sfound);
}
+/*
+ * Lookup a window or return -1 if not found or ambigious. First try as an index
+ * and if invalid, use fnmatch or leading prefix.
+ */
+struct winlink *
+cmd_lookup_window(struct session *s, const char *name, int *ambiguous)
+{
+ struct winlink *wl, *wlfound;
+ struct window *w;
+ const char *errstr;
+ u_int idx;
+
+ *ambiguous = 0;
+
+ /* First see if this is a valid window index in this session. */
+ idx = strtonum(name, 0, INT_MAX, &errstr);
+ if (errstr == NULL) {
+ if ((wl = winlink_find_by_index(&s->windows, idx)) != NULL)
+ return (wl);
+ }
+
+ /* Look for exact matches, error if more than one. */
+ wlfound = NULL;
+ RB_FOREACH(wl, winlinks, &s->windows) {
+ w = wl->window;
+ if (strcmp(name, w->name) == 0) {
+ if (wlfound != NULL) {
+ *ambiguous = 1;
+ return (NULL);
+ }
+ wlfound = wl;
+ }
+ }
+ if (wlfound != NULL)
+ return (wlfound);
+
+ /* Now look for pattern matches, again error if multiple. */
+ wlfound = NULL;
+ RB_FOREACH(wl, winlinks, &s->windows) {
+ w = wl->window;
+ if (strncmp(name, w->name, strlen(name)) == 0 ||
+ fnmatch(name, w->name, 0) == 0) {
+ if (wlfound != NULL) {
+ *ambiguous = 1;
+ return (NULL);
+ }
+ wlfound = wl;
+ }
+ }
+ if (wlfound != NULL)
+ return (wlfound);
+
+ return (NULL);
+}
+
+/* Find the target session or report an error and return NULL. */
struct session *
cmd_find_session(struct cmd_ctx *ctx, const char *arg)
{
struct session *s;
+ struct client *c;
+ char *tmparg;
+ size_t arglen;
+ int ambiguous;
+ /* A NULL argument means the current session. */
if (arg == NULL)
- s = cmd_current_session(ctx);
- else {
- if ((s = arg_parse_session(arg)) == NULL) {
- if (arg != NULL)
- ctx->error(ctx, "session not found: %s", arg);
- else
- ctx->error(ctx, "no session found");
- }
+ return (cmd_current_session(ctx));
+ tmparg = xstrdup(arg);
+
+ /* Trim a single trailing colon if any. */
+ arglen = strlen(tmparg);
+ if (arglen != 0 && tmparg[arglen - 1] == ':')
+ tmparg[arglen - 1] = '\0';
+
+ /* Find the session, if any. */
+ s = cmd_lookup_session(tmparg, &ambiguous);
+
+ /* If it doesn't, try to match it as a client. */
+ if (s == NULL && (c = cmd_lookup_client(tmparg)) != NULL)
+ s = c->session;
+
+ /* If no session found, report an error. */
+ if (s == NULL) {
+ if (ambiguous)
+ ctx->error(ctx, "more than one session: %s", tmparg);
+ else
+ ctx->error(ctx, "session not found: %s", tmparg);
}
+
+ xfree(tmparg);
return (s);
}
+/* Find the target session and window or report an error and return NULL. */
struct winlink *
cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp)
{
struct session *s;
struct winlink *wl;
- int idx;
-
- wl = NULL;
- if (arg_parse_window(arg, &s, &idx) != 0) {
- ctx->error(ctx, "bad window: %s", arg);
+ const char *winptr;
+ char *sessptr = NULL;
+ int ambiguous = 0;
+
+ /*
+ * Find the current session. There must always be a current session, if
+ * it can't be found, report an error.
+ */
+ if ((s = cmd_current_session(ctx)) == NULL) {
+ ctx->error(ctx, "can't establish current session");
return (NULL);
}
- if (s == NULL)
- s = ctx->cursession;
- if (s == NULL)
- s = cmd_current_session(ctx);
- if (s == NULL)
- return (NULL);
+
+ /* A NULL argument means the current session and window. */
+ if (arg == NULL) {
+ if (sp != NULL)
+ *sp = s;
+ return (s->curw);
+ }
+
+ /* Time to look at the argument. If it is empty, that is an error. */
+ if (*arg == '\0')
+ goto not_found;
+
+ /* Find the separating colon. If none, assume the current session. */
+ winptr = strchr(arg, ':');
+ if (winptr == NULL)
+ winptr = xstrdup(arg);
+ else {
+ winptr++; /* skip : */
+ sessptr = xstrdup(arg);
+ *strchr(sessptr, ':') = '\0';
+ }
+
+ log_debug("%s: winptr=%s, sessptr=%s", __func__, winptr, sessptr);
+
+ /* Try to lookup the session if present. */
+ if (sessptr != NULL && *sessptr != '\0') {
+ if ((s = cmd_lookup_session(sessptr, &ambiguous)) == NULL)
+ goto no_session;
+ }
if (sp != NULL)
*sp = s;
- if (idx == -1)
+ /*
+ * Then work out the window. An empty string is the current window,
+ * otherwise try to look it up in the session.
+ */
+ if (winptr == NULL || *winptr == '\0')
wl = s->curw;
- else
- wl = winlink_find_by_index(&s->windows, idx);
- if (wl == NULL)
- ctx->error(ctx, "window not found: %s:%d", s->name, idx);
+ else if ((wl = cmd_lookup_window(s, winptr, &ambiguous)) == NULL)
+ goto not_found;
+
+ if (sessptr != NULL)
+ xfree(sessptr);
return (wl);
+
+no_session:
+ if (ambiguous)
+ ctx->error(ctx, "multiple sessions: %s", sessptr);
+ else
+ ctx->error(ctx, "session not found: %s", sessptr);
+ if (sessptr != NULL)
+ xfree(sessptr);
+ return (NULL);
+
+not_found:
+ if (ambiguous)
+ ctx->error(ctx, "multiple windows: %s", arg);
+ else
+ ctx->error(ctx, "window not found: %s", arg);
+ if (sessptr != NULL)
+ xfree(sessptr);
+ return (NULL);
+}
+
+/*
+ * Find the target session and window index, whether or not it exists in the
+ * session. Return -2 on error or -1 if no window index is specified. This is
+ * used when parsing an argument for a window target that may not be exist (for
+ * example it is going to be created).
+ */
+int
+cmd_find_index(struct cmd_ctx *ctx, const char *arg, struct session **sp)
+{
+ struct session *s;
+ struct winlink *wl;
+ const char *winptr, *errstr;
+ char *sessptr = NULL;
+ int idx, ambiguous = 0;
+
+ /*
+ * Find the current session. There must always be a current session, if
+ * it can't be found, report an error.
+ */
+ if ((s = cmd_current_session(ctx)) == NULL) {
+ ctx->error(ctx, "can't establish current session");
+ return (NULL);
+ }
+
+ /* A NULL argument means the current session and "no window" (-1). */
+ if (arg == NULL) {
+ if (sp != NULL)
+ *sp = s;
+ return (-1);
+ }
+
+ /* Time to look at the argument. If it is empty, that is an error. */
+ if (*arg == '\0')
+ goto not_found;
+
+ /* Find the separating colon. If none, assume the current session. */
+ winptr = strchr(arg, ':');
+ if (winptr == NULL)
+ winptr = xstrdup(arg);
+ else {
+ winptr++; /* skip : */
+ sessptr = xstrdup(arg);
+ *strchr(sessptr, ':') = '\0';
+ }
+
+ log_debug("%s: winptr=%s, sessptr=%s", __func__, winptr, sessptr);
+
+ /* Try to lookup the session if present. */
+ if (sessptr != NULL && *sessptr != '\0') {
+ if ((s = cmd_lookup_session(sessptr, &ambiguous)) == NULL)
+ goto no_session;
+ }
+ if (sp != NULL)
+ *sp = s;
+
+ /*
+ * Then work out the window. No : means "no window" (-1), an empty
+ * string is the current window, otherwise try to look it up in the
+ * session.
+ */
+ if (winptr == NULL)
+ idx = -1;
+ else if (*winptr == '\0')
+ idx = s->curw->idx;
+ else if ((wl = cmd_lookup_window(s, winptr, &ambiguous)) == NULL) {
+ if (ambiguous)
+ goto not_found;
+ /* Don't care it doesn't exist if this is a valid index. */
+ idx = strtonum(winptr, 0, INT_MAX, &errstr);
+ if (errstr != NULL) {
+ ctx->error(ctx, "index %s: %s", errstr, winptr);
+ idx = -2;
+ }
+ } else
+ idx = wl->idx;
+
+ if (sessptr != NULL)
+ xfree(sessptr);
+ return (idx);
+
+no_session:
+ if (ambiguous)
+ ctx->error(ctx, "multiple sessions: %s", sessptr);
+ else
+ ctx->error(ctx, "session not found: %s", sessptr);
+ if (sessptr != NULL)
+ xfree(sessptr);
+ return (-2);
+
+not_found:
+ if (ambiguous)
+ ctx->error(ctx, "multiple windows: %s", arg);
+ else
+ ctx->error(ctx, "window not found: %s", arg);
+ if (sessptr != NULL)
+ xfree(sessptr);
+ return (-2);
}
diff --git a/usr.bin/tmux/tmux.1 b/usr.bin/tmux/tmux.1
index d52574444ff..8b9d2306501 100644
--- a/usr.bin/tmux/tmux.1
+++ b/usr.bin/tmux/tmux.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: tmux.1,v 1.28 2009/07/12 23:45:03 nicm Exp $
+.\" $OpenBSD: tmux.1,v 1.29 2009/07/13 17:47:46 nicm Exp $
.\"
.\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
.\"
@@ -14,7 +14,7 @@
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: July 12 2009 $
+.Dd $Mdocdate: July 13 2009 $
.Dt TMUX 1
.Os
.Sh NAME
@@ -500,8 +500,14 @@ These specify the client, session or window which a command should affect.
.Ar target-client
is the name of the
.Xr pty 4
-file to which the client is connected, for example
+file to which the client is connected, for example either of
+.Pa /dev/ttyp1
+or
+.Pa ttyp1
+for the client attached to
.Pa /dev/ttyp1 .
+If no client is specified, the current client is chosen, if possible, or an
+error is reported.
Clients may be listed with the
.Ic list-clients
command.
@@ -509,23 +515,32 @@ command.
.Ar target-session
is either the name of a session (as listed by the
.Ic list-sessions
-command) or the name of a client,
+command) or the name of a client with the same syntax as
.Ar target-client ,
in which case the session attached to the client is used.
-An
+When looking for the session name,
+.Nm
+initially searches for an exact match; if none is found, the session names
+are checked for any for which
+.Ar target-session
+is a prefix or for which it matches as an
.Xr fnmatch 3
-pattern may be used to match the session name.
-If a session is omitted when required,
-.Nm tmux
-attempts to use the current session; if no current session is available, the
-most recently created is chosen.
-If no client is specified, the current client is chosen, if possible, or an
-error is reported.
+pattern.
+If a single match is found, it is used as the target session; multiple matches
+produce an error
+If a session is omitted, the current session is used if available; if no
+current session is available, the most recently created is chosen.
.Pp
.Ar target-window
specifies a window in the form
-.Em session Ns \&: Ns Em index ,
-for example mysession:1.
+.Em session Ns \&: Ns Em window ,
+where
+.Em window
+is a window index, for example mysession:1, or a window name,
+.Xr fnmatch 3
+pattern, or prefix, such as mysession:mywin[0-3].
+If the latter, the window is looked up in a similar fashion to session name
+searches described above.
The session is in the same form as for
.Ar target-session .
.Em session ,
@@ -536,7 +551,7 @@ If
is omitted, the same rules as for
.Ar target-session
are followed; if
-.Em index
+.Em window
is not present, the current window for the given session is used.
When the argument does not contain a colon,
.Nm
diff --git a/usr.bin/tmux/tmux.h b/usr.bin/tmux/tmux.h
index 6264ace2c87..4eb3aa3aa17 100644
--- a/usr.bin/tmux/tmux.h
+++ b/usr.bin/tmux/tmux.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.h,v 1.25 2009/07/13 10:43:52 nicm Exp $ */
+/* $OpenBSD: tmux.h,v 1.26 2009/07/13 17:47:46 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -1076,11 +1076,6 @@ int paste_replace(struct paste_stack *, u_int, char *);
/* clock.c */
void clock_draw(struct screen_write_ctx *, u_int, int);
-/* arg.c */
-struct client *arg_parse_client(const char *);
-struct session *arg_parse_session(const char *);
-int arg_parse_window(const char *, struct session **, int *);
-
/* cmd.c */
struct cmd *cmd_parse(int, char **, char **);
int cmd_exec(struct cmd *, struct cmd_ctx *);
@@ -1094,7 +1089,9 @@ struct session *cmd_current_session(struct cmd_ctx *);
struct client *cmd_find_client(struct cmd_ctx *, const char *);
struct session *cmd_find_session(struct cmd_ctx *, const char *);
struct winlink *cmd_find_window(
- struct cmd_ctx *, const char *, struct session **);
+ struct cmd_ctx *, const char *, struct session **);
+int cmd_find_index(
+ struct cmd_ctx *, const char *, struct session **);
extern const struct cmd_entry *cmd_table[];
extern const struct cmd_entry cmd_attach_session_entry;
extern const struct cmd_entry cmd_bind_key_entry;