mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 00:56:10 +00:00 
			
		
		
		
	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.
This commit is contained in:
		
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							@@ -1,7 +1,7 @@
 | 
			
		||||
# $OpenBSD$
 | 
			
		||||
 | 
			
		||||
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 \
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										194
									
								
								arg.c
									
									
									
									
									
								
							
							
						
						
									
										194
									
								
								arg.c
									
									
									
									
									
								
							@@ -1,194 +0,0 @@
 | 
			
		||||
/* $OpenBSD$ */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * 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);
 | 
			
		||||
}
 | 
			
		||||
@@ -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);
 | 
			
		||||
	if ((idx = cmd_find_index(ctx, data->dst, &dst)) == -2)
 | 
			
		||||
		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);
 | 
			
		||||
		return (-1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wl_dst = NULL;
 | 
			
		||||
	if (idx != -1)
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
	if ((idx = cmd_find_index(ctx, data->dst, &dst)) == -2)
 | 
			
		||||
		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);
 | 
			
		||||
		return (-1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wl_dst = NULL;
 | 
			
		||||
	if (idx != -1)
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										420
									
								
								cmd.c
									
									
									
									
									
								
							
							
						
						
									
										420
									
								
								cmd.c
									
									
									
									
									
								
							@@ -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 (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;
 | 
			
		||||
	const char	*winptr;
 | 
			
		||||
	char		*sessptr = NULL;
 | 
			
		||||
	int		 ambiguous = 0;
 | 
			
		||||
 | 
			
		||||
	wl = NULL;
 | 
			
		||||
	if (arg_parse_window(arg, &s, &idx) != 0) {
 | 
			
		||||
		ctx->error(ctx, "bad window: %s", arg);
 | 
			
		||||
	/*
 | 
			
		||||
	 * 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);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										41
									
								
								tmux.1
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								tmux.1
									
									
									
									
									
								
							@@ -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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										9
									
								
								tmux.h
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								tmux.h
									
									
									
									
									
								
							@@ -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;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user