mirror of
				https://github.com/tmux/tmux.git
				synced 2025-10-26 12:27:15 +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:
		
							
								
								
									
										194
									
								
								arg.c
									
									
									
									
									
								
							
							
						
						
									
										194
									
								
								arg.c
									
									
									
									
									
								
							| @@ -1,194 +0,0 @@ | |||||||
| /* $Id: arg.c,v 1.6 2009-06-25 15:25:45 nicm 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); |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| /* $Id: cmd-link-window.c,v 1.28 2009-01-23 16:59:14 nicm Exp $ */ | /* $Id: cmd-link-window.c,v 1.29 2009-07-14 06:42:05 nicm Exp $ */ | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> |  * 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) | 	if ((wl_src = cmd_find_window(ctx, data->src, NULL)) == NULL) | ||||||
| 		return (-1); | 		return (-1); | ||||||
|  | 	if ((idx = cmd_find_index(ctx, data->dst, &dst)) == -2) | ||||||
| 	if (arg_parse_window(data->dst, &dst, &idx) != 0) { |  | ||||||
| 		ctx->error(ctx, "bad window: %s", data->dst); |  | ||||||
| 		return (-1); | 		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; | 	wl_dst = NULL; | ||||||
| 	if (idx != -1) | 	if (idx != -1) | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| /* $Id: cmd-move-window.c,v 1.5 2009-01-23 16:59:14 nicm Exp $ */ | /* $Id: cmd-move-window.c,v 1.6 2009-07-14 06:42:05 nicm Exp $ */ | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> |  * 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) | 	if ((wl_src = cmd_find_window(ctx, data->src, &src)) == NULL) | ||||||
| 		return (-1); | 		return (-1); | ||||||
|  | 	if ((idx = cmd_find_index(ctx, data->dst, &dst)) == -2) | ||||||
| 	if (arg_parse_window(data->dst, &dst, &idx) != 0) { |  | ||||||
| 		ctx->error(ctx, "bad window: %s", data->dst); |  | ||||||
| 		return (-1); | 		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; | 	wl_dst = NULL; | ||||||
| 	if (idx != -1) | 	if (idx != -1) | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| /* $Id: cmd-new-window.c,v 1.33 2009-07-08 18:03:03 nicm Exp $ */ | /* $Id: cmd-new-window.c,v 1.34 2009-07-14 06:42:05 nicm Exp $ */ | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> |  * 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) | 	if (data == NULL) | ||||||
| 		return (0); | 		return (0); | ||||||
|  |  | ||||||
| 	if (arg_parse_window(data->target, &s, &idx) != 0) { | 	if ((idx = cmd_find_index(ctx, data->target, &s)) == -2) | ||||||
| 		ctx->error(ctx, "bad window: %s", data->target); |  | ||||||
| 		return (-1); | 		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; | 	wl = NULL; | ||||||
| 	if (idx != -1) | 	if (idx != -1) | ||||||
|   | |||||||
							
								
								
									
										420
									
								
								cmd.c
									
									
									
									
									
								
							
							
						
						
									
										420
									
								
								cmd.c
									
									
									
									
									
								
							| @@ -1,4 +1,4 @@ | |||||||
| /* $Id: cmd.c,v 1.100 2009-07-09 18:14:18 nicm Exp $ */ | /* $Id: cmd.c,v 1.101 2009-07-14 06:42:05 nicm Exp $ */ | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> |  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> | ||||||
| @@ -19,6 +19,8 @@ | |||||||
| #include <sys/types.h> | #include <sys/types.h> | ||||||
| #include <sys/time.h> | #include <sys/time.h> | ||||||
|  |  | ||||||
|  | #include <fnmatch.h> | ||||||
|  | #include <paths.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
| @@ -100,6 +102,11 @@ const struct cmd_entry *cmd_table[] = { | |||||||
| 	NULL | 	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 * | struct cmd * | ||||||
| cmd_parse(int argc, char **argv, char **cause) | cmd_parse(int argc, char **argv, char **cause) | ||||||
| { | { | ||||||
| @@ -294,106 +301,421 @@ cmd_recv_string(struct buffer *b) | |||||||
| 	return (s); | 	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 * | struct session * | ||||||
| cmd_current_session(struct cmd_ctx *ctx) | cmd_current_session(struct cmd_ctx *ctx) | ||||||
| { | { | ||||||
| 	struct msg_command_data	*data = ctx->msgdata; | 	struct msg_command_data	*data = ctx->msgdata; | ||||||
| 	struct timeval		*tv; | 	struct session		*s; | ||||||
| 	struct session		*s, *newest = NULL; |  | ||||||
| 	u_int			 i; |  | ||||||
|  |  | ||||||
| 	if (ctx->cursession != NULL) | 	if (ctx->cursession != NULL) | ||||||
| 		return (ctx->cursession); | 		return (ctx->cursession); | ||||||
|  |  | ||||||
| 	if (data != NULL && data->pid != -1) { | 	if (data != NULL && data->pid != -1) { | ||||||
| 		if (data->pid != getpid()) { | 		if (data->pid != getpid()) | ||||||
| 			ctx->error(ctx, "wrong server: %ld", (long) data->pid); |  | ||||||
| 			return (NULL); | 			return (NULL); | ||||||
| 		} | 		if (data->idx > ARRAY_LENGTH(&sessions)) | ||||||
| 		if (data->idx > ARRAY_LENGTH(&sessions)) { |  | ||||||
| 			ctx->error(ctx, "index out of range: %d", data->idx); |  | ||||||
| 			return (NULL); | 			return (NULL); | ||||||
| 		} | 		if ((s = ARRAY_ITEM(&sessions, data->idx)) == NULL) | ||||||
| 		if ((s = ARRAY_ITEM(&sessions, data->idx)) == NULL) { |  | ||||||
| 			ctx->error(ctx, "session doesn't exist: %u", data->idx); |  | ||||||
| 			return (NULL); | 			return (NULL); | ||||||
| 		} |  | ||||||
| 		return (s); | 		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++) { | 	for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { | ||||||
| 		s = ARRAY_ITEM(&sessions, i); | 		if ((s = ARRAY_ITEM(&sessions, i)) == NULL) | ||||||
| 		if (s != NULL && (tv == NULL || timercmp(&s->tv, tv, >))) { | 			continue; | ||||||
| 			newest = ARRAY_ITEM(&sessions, i); |  | ||||||
|  | 		if (tv == NULL || timercmp(&s->tv, tv, >)) { | ||||||
|  | 			snewest = s; | ||||||
| 			tv = &s->tv; | 			tv = &s->tv; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return (newest); |  | ||||||
|  | 	return (snewest); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* Find the target client or report an error and return NULL. */ | ||||||
| struct client * | struct client * | ||||||
| cmd_find_client(struct cmd_ctx *ctx, const char *arg) | cmd_find_client(struct cmd_ctx *ctx, const char *arg) | ||||||
| { | { | ||||||
| 	struct client	*c; | 	struct client	*c; | ||||||
|  | 	char		*tmparg; | ||||||
|  | 	size_t		 arglen; | ||||||
|  |  | ||||||
|  | 	/* A NULL argument means the current client. */ | ||||||
| 	if (arg == NULL) | 	if (arg == NULL) | ||||||
| 		c = ctx->curclient; | 		return (ctx->curclient); | ||||||
| 	else { | 	tmparg = xstrdup(arg); | ||||||
| 		if ((c = arg_parse_client(arg)) == NULL) { |  | ||||||
| 			if (arg != NULL) | 	/* Trim a single trailing colon if any. */ | ||||||
| 				ctx->error(ctx, "client not found: %s", arg); | 	arglen = strlen(tmparg); | ||||||
| 			else | 	if (arglen != 0 && tmparg[arglen - 1] == ':') | ||||||
| 				ctx->error(ctx, "no client found"); | 		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); | 	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 * | struct session * | ||||||
| cmd_find_session(struct cmd_ctx *ctx, const char *arg) | cmd_find_session(struct cmd_ctx *ctx, const char *arg) | ||||||
| { | { | ||||||
| 	struct session	*s; | 	struct session	*s; | ||||||
|  | 	struct client	*c; | ||||||
|  | 	char		*tmparg; | ||||||
|  | 	size_t		 arglen; | ||||||
|  | 	int		 ambiguous; | ||||||
|  |  | ||||||
|  | 	/* A NULL argument means the current session. */ | ||||||
| 	if (arg == NULL) | 	if (arg == NULL) | ||||||
| 		s = cmd_current_session(ctx); | 		return (cmd_current_session(ctx)); | ||||||
| 	else { | 	tmparg = xstrdup(arg); | ||||||
| 		if ((s = arg_parse_session(arg)) == NULL) { |  | ||||||
| 			if (arg != NULL) | 	/* Trim a single trailing colon if any. */ | ||||||
| 				ctx->error(ctx, "session not found: %s", arg); | 	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 | 		else | ||||||
| 				ctx->error(ctx, "no session found"); | 			ctx->error(ctx, "session not found: %s", tmparg); | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	xfree(tmparg); | ||||||
| 	return (s); | 	return (s); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* Find the target session and window or report an error and return NULL. */ | ||||||
| struct winlink * | struct winlink * | ||||||
| cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp) | cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp) | ||||||
| { | { | ||||||
| 	struct session	*s; | 	struct session	*s; | ||||||
| 	struct winlink	*wl; | 	struct winlink	*wl; | ||||||
| 	int		 idx; | 	const char	*winptr; | ||||||
|  | 	char		*sessptr = NULL; | ||||||
|  | 	int		 ambiguous = 0; | ||||||
|  |  | ||||||
| 	wl = NULL; | 	/* | ||||||
| 	if (arg_parse_window(arg, &s, &idx) != 0) { | 	 * Find the current session. There must always be a current session, if | ||||||
| 		ctx->error(ctx, "bad window: %s", arg); | 	 * 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); | 		return (NULL); | ||||||
| 	} | 	} | ||||||
| 	if (s == NULL) |  | ||||||
| 		s = ctx->cursession; | 	/* A NULL argument means the current session and window. */ | ||||||
| 	if (s == NULL) | 	if (arg == NULL) { | ||||||
| 		s = cmd_current_session(ctx); | 		if (sp != NULL) | ||||||
| 	if (s == NULL) | 			*sp = s; | ||||||
| 		return (NULL); | 		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) | 	if (sp != NULL) | ||||||
| 		*sp = s; | 		*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; | 		wl = s->curw; | ||||||
| 	else | 	else if ((wl = cmd_lookup_window(s, winptr, &ambiguous)) == NULL) | ||||||
| 		wl = winlink_find_by_index(&s->windows, idx); | 		goto not_found; | ||||||
| 	if (wl == NULL) | 	 | ||||||
| 		ctx->error(ctx, "window not found: %s:%d", s->name, idx); | 	if (sessptr != NULL) | ||||||
|  | 		xfree(sessptr); | ||||||
| 	return (wl); | 	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); | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										43
									
								
								tmux.1
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								tmux.1
									
									
									
									
									
								
							| @@ -1,4 +1,4 @@ | |||||||
| .\" $Id: tmux.1,v 1.115 2009-07-14 06:39:44 nicm Exp $ | .\" $Id: tmux.1,v 1.116 2009-07-14 06:42:06 nicm Exp $ | ||||||
| .\" | .\" | ||||||
| .\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> | .\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> | ||||||
| .\" | .\" | ||||||
| @@ -500,8 +500,14 @@ These specify the client, session or window which a command should affect. | |||||||
| .Ar target-client | .Ar target-client | ||||||
| is the name of the | is the name of the | ||||||
| .Xr pty 4 | .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 . | .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 | Clients may be listed with the | ||||||
| .Ic list-clients | .Ic list-clients | ||||||
| command. | command. | ||||||
| @@ -509,23 +515,32 @@ command. | |||||||
| .Ar target-session | .Ar target-session | ||||||
| is either the name of a session (as listed by the | is either the name of a session (as listed by the | ||||||
| .Ic list-sessions | .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 , | .Ar target-client , | ||||||
| in which case the session attached to the client is used. | 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 | .Xr fnmatch 3 | ||||||
| pattern may be used to match the session name. | pattern. | ||||||
| If a session is omitted when required, | If a single match is found, it is used as the target session; multiple matches | ||||||
| .Nm tmux | produce an error | ||||||
| attempts to use the current session; if no current session is available, the | If a session is omitted, the current session is used if available; if no | ||||||
| most recently created is chosen. | 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. |  | ||||||
| .Pp | .Pp | ||||||
| .Ar target-window | .Ar target-window | ||||||
| specifies a window in the form | specifies a window in the form | ||||||
| .Em session Ns \&: Ns Em index , | .Em session Ns \&: Ns Em window , | ||||||
| for example mysession:1. | 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 | The session is in the same form as for | ||||||
| .Ar target-session . | .Ar target-session . | ||||||
| .Em session , | .Em session , | ||||||
| @@ -536,7 +551,7 @@ If | |||||||
| is omitted, the same rules as for | is omitted, the same rules as for | ||||||
| .Ar target-session | .Ar target-session | ||||||
| are followed; if | are followed; if | ||||||
| .Em index | .Em window | ||||||
| is not present, the current window for the given session is used. | is not present, the current window for the given session is used. | ||||||
| When the argument does not contain a colon, | When the argument does not contain a colon, | ||||||
| .Nm | .Nm | ||||||
|   | |||||||
							
								
								
									
										9
									
								
								tmux.h
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								tmux.h
									
									
									
									
									
								
							| @@ -1,4 +1,4 @@ | |||||||
| /* $Id: tmux.h,v 1.359 2009-07-14 06:40:33 nicm Exp $ */ | /* $Id: tmux.h,v 1.360 2009-07-14 06:42:06 nicm Exp $ */ | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> |  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> | ||||||
| @@ -1075,11 +1075,6 @@ int		 paste_replace(struct paste_stack *, u_int, char *); | |||||||
| /* clock.c */ | /* clock.c */ | ||||||
| void		 clock_draw(struct screen_write_ctx *, u_int, int); | 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 */ | /* cmd.c */ | ||||||
| struct cmd	*cmd_parse(int, char **, char **); | struct cmd	*cmd_parse(int, char **, char **); | ||||||
| int		 cmd_exec(struct cmd *, struct cmd_ctx *); | int		 cmd_exec(struct cmd *, struct cmd_ctx *); | ||||||
| @@ -1094,6 +1089,8 @@ struct client	*cmd_find_client(struct cmd_ctx *, const char *); | |||||||
| struct session	*cmd_find_session(struct cmd_ctx *, const char *); | struct session	*cmd_find_session(struct cmd_ctx *, const char *); | ||||||
| struct winlink	*cmd_find_window( | 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_table[]; | ||||||
| extern const struct cmd_entry cmd_attach_session_entry; | extern const struct cmd_entry cmd_attach_session_entry; | ||||||
| extern const struct cmd_entry cmd_bind_key_entry; | extern const struct cmd_entry cmd_bind_key_entry; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Nicholas Marriott
					Nicholas Marriott