xref: /openbsd-src/usr.bin/tmux/cmd-find.c (revision a0aa010a1e376f08e9dd6752e6f4510e98bd0daa)
1*a0aa010aSnicm /* $OpenBSD: cmd-find.c,v 1.83 2023/07/10 09:24:53 nicm Exp $ */
2f65f2164Snicm 
3f65f2164Snicm /*
498ca8272Snicm  * Copyright (c) 2015 Nicholas Marriott <nicholas.marriott@gmail.com>
5f65f2164Snicm  *
6f65f2164Snicm  * Permission to use, copy, modify, and distribute this software for any
7f65f2164Snicm  * purpose with or without fee is hereby granted, provided that the above
8f65f2164Snicm  * copyright notice and this permission notice appear in all copies.
9f65f2164Snicm  *
10f65f2164Snicm  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11f65f2164Snicm  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12f65f2164Snicm  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13f65f2164Snicm  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14f65f2164Snicm  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15f65f2164Snicm  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16f65f2164Snicm  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17f65f2164Snicm  */
18f65f2164Snicm 
19f65f2164Snicm #include <sys/types.h>
20f65f2164Snicm 
21f65f2164Snicm #include <fnmatch.h>
22f65f2164Snicm #include <limits.h>
23f65f2164Snicm #include <stdlib.h>
24f65f2164Snicm #include <string.h>
25f65f2164Snicm #include <paths.h>
269bdf6084Snicm #include <unistd.h>
27f65f2164Snicm 
28f65f2164Snicm #include "tmux.h"
29f65f2164Snicm 
30dc1f0f5fSnicm static int	cmd_find_session_better(struct session *, struct session *,
31f65f2164Snicm 		    int);
32dc1f0f5fSnicm static struct session *cmd_find_best_session(struct session **, u_int, int);
33dc1f0f5fSnicm static int	cmd_find_best_session_with_window(struct cmd_find_state *);
34dc1f0f5fSnicm static int	cmd_find_best_winlink_with_window(struct cmd_find_state *);
35f65f2164Snicm 
36dc1f0f5fSnicm static const char *cmd_find_map_table(const char *[][2], const char *);
37f65f2164Snicm 
384e325abeSnicm static void	cmd_find_log_state(const char *, struct cmd_find_state *);
39dc1f0f5fSnicm static int	cmd_find_get_session(struct cmd_find_state *, const char *);
4010f437f1Snicm static int	cmd_find_get_window(struct cmd_find_state *, const char *, int);
41dc1f0f5fSnicm static int	cmd_find_get_window_with_session(struct cmd_find_state *,
42dc1f0f5fSnicm 		    const char *);
4310f437f1Snicm static int	cmd_find_get_pane(struct cmd_find_state *, const char *, int);
44dc1f0f5fSnicm static int	cmd_find_get_pane_with_session(struct cmd_find_state *,
45dc1f0f5fSnicm 		    const char *);
46dc1f0f5fSnicm static int	cmd_find_get_pane_with_window(struct cmd_find_state *,
47dc1f0f5fSnicm 		    const char *);
48f65f2164Snicm 
49dc1f0f5fSnicm static const char *cmd_find_session_table[][2] = {
50f65f2164Snicm 	{ NULL, NULL }
51f65f2164Snicm };
52dc1f0f5fSnicm static const char *cmd_find_window_table[][2] = {
53f65f2164Snicm 	{ "{start}", "^" },
54f65f2164Snicm 	{ "{last}", "!" },
55f65f2164Snicm 	{ "{end}", "$" },
56f65f2164Snicm 	{ "{next}", "+" },
57f65f2164Snicm 	{ "{previous}", "-" },
58f65f2164Snicm 	{ NULL, NULL }
59f65f2164Snicm };
60dc1f0f5fSnicm static const char *cmd_find_pane_table[][2] = {
61f65f2164Snicm 	{ "{last}", "!" },
62f65f2164Snicm 	{ "{next}", "+" },
63f65f2164Snicm 	{ "{previous}", "-" },
64f65f2164Snicm 	{ "{top}", "top" },
65f65f2164Snicm 	{ "{bottom}", "bottom" },
66f65f2164Snicm 	{ "{left}", "left" },
67f65f2164Snicm 	{ "{right}", "right" },
68f65f2164Snicm 	{ "{top-left}", "top-left" },
69f65f2164Snicm 	{ "{top-right}", "top-right" },
70f65f2164Snicm 	{ "{bottom-left}", "bottom-left" },
71f65f2164Snicm 	{ "{bottom-right}", "bottom-right" },
72baf68abeSnicm 	{ "{up-of}", "{up-of}" },
73baf68abeSnicm 	{ "{down-of}", "{down-of}" },
74baf68abeSnicm 	{ "{left-of}", "{left-of}" },
75baf68abeSnicm 	{ "{right-of}", "{right-of}" },
76f65f2164Snicm 	{ NULL, NULL }
77f65f2164Snicm };
78f65f2164Snicm 
796b339e7dSnicm /* Find pane containing client if any. */
806b339e7dSnicm static struct window_pane *
cmd_find_inside_pane(struct client * c)816b339e7dSnicm cmd_find_inside_pane(struct client *c)
826b339e7dSnicm {
836b339e7dSnicm 	struct window_pane	*wp;
84403a76d5Snicm 	struct environ_entry	*envent;
856b339e7dSnicm 
866b339e7dSnicm 	if (c == NULL)
876b339e7dSnicm 		return (NULL);
886b339e7dSnicm 
896b339e7dSnicm 	RB_FOREACH(wp, window_pane_tree, &all_window_panes) {
907fe37febSnicm 		if (wp->fd != -1 && strcmp(wp->tty, c->ttyname) == 0)
916b339e7dSnicm 			break;
926b339e7dSnicm 	}
93403a76d5Snicm 	if (wp == NULL) {
94403a76d5Snicm 		envent = environ_find(c->environ, "TMUX_PANE");
95403a76d5Snicm 		if (envent != NULL)
96403a76d5Snicm 			wp = window_pane_find_by_id_str(envent->value);
97403a76d5Snicm 	}
982fe539a5Snicm 	if (wp != NULL)
992fe539a5Snicm 		log_debug("%s: got pane %%%u (%s)", __func__, wp->id, wp->tty);
1006b339e7dSnicm 	return (wp);
1016b339e7dSnicm }
1026b339e7dSnicm 
103f65f2164Snicm /* Is this client better? */
104dc1f0f5fSnicm static int
cmd_find_client_better(struct client * c,struct client * than)105f65f2164Snicm cmd_find_client_better(struct client *c, struct client *than)
106f65f2164Snicm {
107f65f2164Snicm 	if (than == NULL)
108f65f2164Snicm 		return (1);
109f65f2164Snicm 	return (timercmp(&c->activity_time, &than->activity_time, >));
110f65f2164Snicm }
111f65f2164Snicm 
11293e732aaSnicm /* Find best client for session. */
113b6908644Snicm struct client *
cmd_find_best_client(struct session * s)11493e732aaSnicm cmd_find_best_client(struct session *s)
115f65f2164Snicm {
116f65f2164Snicm 	struct client	*c_loop, *c;
11793e732aaSnicm 
118647c5c18Snicm 	if (s->attached == 0)
11993e732aaSnicm 		s = NULL;
120f65f2164Snicm 
121f65f2164Snicm 	c = NULL;
122f65f2164Snicm 	TAILQ_FOREACH(c_loop, &clients, entry) {
1233826ac9fSnicm 		if (c_loop->session == NULL)
1243826ac9fSnicm 			continue;
12593e732aaSnicm 		if (s != NULL && c_loop->session != s)
12693e732aaSnicm 			continue;
127f65f2164Snicm 		if (cmd_find_client_better(c_loop, c))
1283a7a224fSnicm 			c = c_loop;
129f65f2164Snicm 	}
130f65f2164Snicm 	return (c);
131f65f2164Snicm }
132f65f2164Snicm 
133f65f2164Snicm /* Is this session better? */
134dc1f0f5fSnicm static int
cmd_find_session_better(struct session * s,struct session * than,int flags)135f65f2164Snicm cmd_find_session_better(struct session *s, struct session *than, int flags)
136f65f2164Snicm {
137f65f2164Snicm 	int	attached;
138f65f2164Snicm 
139f65f2164Snicm 	if (than == NULL)
140f65f2164Snicm 		return (1);
141f65f2164Snicm 	if (flags & CMD_FIND_PREFER_UNATTACHED) {
142647c5c18Snicm 		attached = (than->attached != 0);
143647c5c18Snicm 		if (attached && s->attached == 0)
144f65f2164Snicm 			return (1);
145647c5c18Snicm 		else if (!attached && s->attached != 0)
146f65f2164Snicm 			return (0);
147f65f2164Snicm 	}
148f65f2164Snicm 	return (timercmp(&s->activity_time, &than->activity_time, >));
149f65f2164Snicm }
150f65f2164Snicm 
151f65f2164Snicm /* Find best session from a list, or all if list is NULL. */
152dc1f0f5fSnicm static struct session *
cmd_find_best_session(struct session ** slist,u_int ssize,int flags)153f65f2164Snicm cmd_find_best_session(struct session **slist, u_int ssize, int flags)
154f65f2164Snicm {
155f65f2164Snicm 	struct session	 *s_loop, *s;
156f65f2164Snicm 	u_int		  i;
157f65f2164Snicm 
1582fe539a5Snicm 	log_debug("%s: %u sessions to try", __func__, ssize);
1592fe539a5Snicm 
160f65f2164Snicm 	s = NULL;
161f65f2164Snicm 	if (slist != NULL) {
162f65f2164Snicm 		for (i = 0; i < ssize; i++) {
163f65f2164Snicm 			if (cmd_find_session_better(slist[i], s, flags))
164f65f2164Snicm 				s = slist[i];
165f65f2164Snicm 		}
166f65f2164Snicm 	} else {
167f65f2164Snicm 		RB_FOREACH(s_loop, sessions, &sessions) {
168f65f2164Snicm 			if (cmd_find_session_better(s_loop, s, flags))
169f65f2164Snicm 				s = s_loop;
170f65f2164Snicm 		}
171f65f2164Snicm 	}
172f65f2164Snicm 	return (s);
173f65f2164Snicm }
174f65f2164Snicm 
175f65f2164Snicm /* Find best session and winlink for window. */
176dc1f0f5fSnicm static int
cmd_find_best_session_with_window(struct cmd_find_state * fs)177f65f2164Snicm cmd_find_best_session_with_window(struct cmd_find_state *fs)
178f65f2164Snicm {
179f65f2164Snicm 	struct session	**slist = NULL;
180f65f2164Snicm 	u_int		  ssize;
181f65f2164Snicm 	struct session	 *s;
182f65f2164Snicm 
1832fe539a5Snicm 	log_debug("%s: window is @%u", __func__, fs->w->id);
1842fe539a5Snicm 
185f65f2164Snicm 	ssize = 0;
186f65f2164Snicm 	RB_FOREACH(s, sessions, &sessions) {
187f65f2164Snicm 		if (!session_has(s, fs->w))
188f65f2164Snicm 			continue;
189f65f2164Snicm 		slist = xreallocarray(slist, ssize + 1, sizeof *slist);
190f65f2164Snicm 		slist[ssize++] = s;
191f65f2164Snicm 	}
192f65f2164Snicm 	if (ssize == 0)
193f65f2164Snicm 		goto fail;
194f65f2164Snicm 	fs->s = cmd_find_best_session(slist, ssize, fs->flags);
195f65f2164Snicm 	if (fs->s == NULL)
196f65f2164Snicm 		goto fail;
197f65f2164Snicm 	free(slist);
198f65f2164Snicm 	return (cmd_find_best_winlink_with_window(fs));
199f65f2164Snicm 
200f65f2164Snicm fail:
201f65f2164Snicm 	free(slist);
202f65f2164Snicm 	return (-1);
203f65f2164Snicm }
204f65f2164Snicm 
205f65f2164Snicm /*
2067fe37febSnicm  * Find the best winlink for a window (the current if it contains the window,
207f65f2164Snicm  * otherwise the first).
208f65f2164Snicm  */
209dc1f0f5fSnicm static int
cmd_find_best_winlink_with_window(struct cmd_find_state * fs)210f65f2164Snicm cmd_find_best_winlink_with_window(struct cmd_find_state *fs)
211f65f2164Snicm {
212f65f2164Snicm 	struct winlink	 *wl, *wl_loop;
213f65f2164Snicm 
2142fe539a5Snicm 	log_debug("%s: window is @%u", __func__, fs->w->id);
2152fe539a5Snicm 
216f65f2164Snicm 	wl = NULL;
2172ae124feSnicm 	if (fs->s->curw != NULL && fs->s->curw->window == fs->w)
218f65f2164Snicm 		wl = fs->s->curw;
219f65f2164Snicm 	else {
220f65f2164Snicm 		RB_FOREACH(wl_loop, winlinks, &fs->s->windows) {
221f65f2164Snicm 			if (wl_loop->window == fs->w) {
222f65f2164Snicm 				wl = wl_loop;
223f65f2164Snicm 				break;
224f65f2164Snicm 			}
225f65f2164Snicm 		}
226f65f2164Snicm 	}
227f65f2164Snicm 	if (wl == NULL)
228f65f2164Snicm 		return (-1);
229f65f2164Snicm 	fs->wl = wl;
230f65f2164Snicm 	fs->idx = fs->wl->idx;
231f65f2164Snicm 	return (0);
232f65f2164Snicm }
233f65f2164Snicm 
234f65f2164Snicm /* Maps string in table. */
235dc1f0f5fSnicm static const char *
cmd_find_map_table(const char * table[][2],const char * s)236f65f2164Snicm cmd_find_map_table(const char *table[][2], const char *s)
237f65f2164Snicm {
238f65f2164Snicm 	u_int	i;
239f65f2164Snicm 
240f65f2164Snicm 	for (i = 0; table[i][0] != NULL; i++) {
241f65f2164Snicm 		if (strcmp(s, table[i][0]) == 0)
242f65f2164Snicm 			return (table[i][1]);
243f65f2164Snicm 	}
244f65f2164Snicm 	return (s);
245f65f2164Snicm }
246f65f2164Snicm 
247f65f2164Snicm /* Find session from string. Fills in s. */
248dc1f0f5fSnicm static int
cmd_find_get_session(struct cmd_find_state * fs,const char * session)249f65f2164Snicm cmd_find_get_session(struct cmd_find_state *fs, const char *session)
250f65f2164Snicm {
251f65f2164Snicm 	struct session	*s, *s_loop;
2527fb2b001Snicm 	struct client	*c;
253f65f2164Snicm 
254f65f2164Snicm 	log_debug("%s: %s", __func__, session);
255f65f2164Snicm 
256f65f2164Snicm 	/* Check for session ids starting with $. */
257f65f2164Snicm 	if (*session == '$') {
258f65f2164Snicm 		fs->s = session_find_by_id_str(session);
259f65f2164Snicm 		if (fs->s == NULL)
260f65f2164Snicm 			return (-1);
261f65f2164Snicm 		return (0);
262f65f2164Snicm 	}
263f65f2164Snicm 
264f65f2164Snicm 	/* Look for exactly this session. */
265f65f2164Snicm 	fs->s = session_find(session);
266f65f2164Snicm 	if (fs->s != NULL)
267f65f2164Snicm 		return (0);
268f65f2164Snicm 
2697fb2b001Snicm 	/* Look for as a client. */
2707fb2b001Snicm 	c = cmd_find_client(NULL, session, 1);
2717fb2b001Snicm 	if (c != NULL && c->session != NULL) {
2727fb2b001Snicm 		fs->s = c->session;
2737fb2b001Snicm 		return (0);
2747fb2b001Snicm 	}
2757fb2b001Snicm 
276a7f2e23cSnicm 	/* Stop now if exact only. */
277a7f2e23cSnicm 	if (fs->flags & CMD_FIND_EXACT_SESSION)
278a7f2e23cSnicm 		return (-1);
279a7f2e23cSnicm 
280f65f2164Snicm 	/* Otherwise look for prefix. */
281f65f2164Snicm 	s = NULL;
282f65f2164Snicm 	RB_FOREACH(s_loop, sessions, &sessions) {
283f65f2164Snicm 		if (strncmp(session, s_loop->name, strlen(session)) == 0) {
284f65f2164Snicm 			if (s != NULL)
285f65f2164Snicm 				return (-1);
286f65f2164Snicm 			s = s_loop;
287f65f2164Snicm 		}
288f65f2164Snicm 	}
289f65f2164Snicm 	if (s != NULL) {
290f65f2164Snicm 		fs->s = s;
291f65f2164Snicm 		return (0);
292f65f2164Snicm 	}
293f65f2164Snicm 
294f65f2164Snicm 	/* Then as a pattern. */
295f65f2164Snicm 	s = NULL;
296f65f2164Snicm 	RB_FOREACH(s_loop, sessions, &sessions) {
297f65f2164Snicm 		if (fnmatch(session, s_loop->name, 0) == 0) {
298f65f2164Snicm 			if (s != NULL)
299f65f2164Snicm 				return (-1);
300f65f2164Snicm 			s = s_loop;
301f65f2164Snicm 		}
302f65f2164Snicm 	}
303f65f2164Snicm 	if (s != NULL) {
304f65f2164Snicm 		fs->s = s;
305f65f2164Snicm 		return (0);
306f65f2164Snicm 	}
307f65f2164Snicm 
308f65f2164Snicm 	return (-1);
309f65f2164Snicm }
310f65f2164Snicm 
311f65f2164Snicm /* Find window from string. Fills in s, wl, w. */
312dc1f0f5fSnicm static int
cmd_find_get_window(struct cmd_find_state * fs,const char * window,int only)31310f437f1Snicm cmd_find_get_window(struct cmd_find_state *fs, const char *window, int only)
314f65f2164Snicm {
315f65f2164Snicm 	log_debug("%s: %s", __func__, window);
316f65f2164Snicm 
317f65f2164Snicm 	/* Check for window ids starting with @. */
318f65f2164Snicm 	if (*window == '@') {
319f65f2164Snicm 		fs->w = window_find_by_id_str(window);
320f65f2164Snicm 		if (fs->w == NULL)
321f65f2164Snicm 			return (-1);
322f65f2164Snicm 		return (cmd_find_best_session_with_window(fs));
323f65f2164Snicm 	}
324f65f2164Snicm 
325f65f2164Snicm 	/* Not a window id, so use the current session. */
326f65f2164Snicm 	fs->s = fs->current->s;
327f65f2164Snicm 
328f65f2164Snicm 	/* We now only need to find the winlink in this session. */
329d296cf69Snicm 	if (cmd_find_get_window_with_session(fs, window) == 0)
330d296cf69Snicm 		return (0);
331d296cf69Snicm 
33238f80cb9Snicm 	/* Otherwise try as a session itself. */
33310f437f1Snicm 	if (!only && cmd_find_get_session(fs, window) == 0) {
334d296cf69Snicm 		fs->wl = fs->s->curw;
335d296cf69Snicm 		fs->w = fs->wl->window;
33659d5062aSnicm 		if (~fs->flags & CMD_FIND_WINDOW_INDEX)
337a4443f9dSnicm 			fs->idx = fs->wl->idx;
338d296cf69Snicm 		return (0);
339d296cf69Snicm 	}
340d296cf69Snicm 
341d296cf69Snicm 	return (-1);
342f65f2164Snicm }
343f65f2164Snicm 
344f65f2164Snicm /*
345f65f2164Snicm  * Find window from string, assuming it is in given session. Needs s, fills in
346f65f2164Snicm  * wl and w.
347f65f2164Snicm  */
348dc1f0f5fSnicm static int
cmd_find_get_window_with_session(struct cmd_find_state * fs,const char * window)349f65f2164Snicm cmd_find_get_window_with_session(struct cmd_find_state *fs, const char *window)
350f65f2164Snicm {
351f65f2164Snicm 	struct winlink	*wl;
352f65f2164Snicm 	const char	*errstr;
353a7f2e23cSnicm 	int		 idx, n, exact;
354f65f2164Snicm 	struct session	*s;
355f65f2164Snicm 
356f65f2164Snicm 	log_debug("%s: %s", __func__, window);
357a7f2e23cSnicm 	exact = (fs->flags & CMD_FIND_EXACT_WINDOW);
358f65f2164Snicm 
35959d5062aSnicm 	/*
36059d5062aSnicm 	 * Start with the current window as the default. So if only an index is
36159d5062aSnicm 	 * found, the window will be the current.
36259d5062aSnicm 	 */
36359d5062aSnicm 	fs->wl = fs->s->curw;
36459d5062aSnicm 	fs->w = fs->wl->window;
36559d5062aSnicm 
366f65f2164Snicm 	/* Check for window ids starting with @. */
367f65f2164Snicm 	if (*window == '@') {
368f65f2164Snicm 		fs->w = window_find_by_id_str(window);
369f65f2164Snicm 		if (fs->w == NULL || !session_has(fs->s, fs->w))
370f65f2164Snicm 			return (-1);
371f65f2164Snicm 		return (cmd_find_best_winlink_with_window(fs));
372f65f2164Snicm 	}
373f65f2164Snicm 
374f65f2164Snicm 	/* Try as an offset. */
375e0456e38Snicm 	if (!exact && (window[0] == '+' || window[0] == '-')) {
376f65f2164Snicm 		if (window[1] != '\0')
377f65f2164Snicm 			n = strtonum(window + 1, 1, INT_MAX, NULL);
378f65f2164Snicm 		else
379f65f2164Snicm 			n = 1;
380f65f2164Snicm 		s = fs->s;
381f65f2164Snicm 		if (fs->flags & CMD_FIND_WINDOW_INDEX) {
382f65f2164Snicm 			if (window[0] == '+') {
383f65f2164Snicm 				if (INT_MAX - s->curw->idx < n)
384f65f2164Snicm 					return (-1);
385f65f2164Snicm 				fs->idx = s->curw->idx + n;
386f65f2164Snicm 			} else {
387ccbc1512Snicm 				if (n > s->curw->idx)
388f65f2164Snicm 					return (-1);
389f65f2164Snicm 				fs->idx = s->curw->idx - n;
390f65f2164Snicm 			}
391f65f2164Snicm 			return (0);
392f65f2164Snicm 		}
393f65f2164Snicm 		if (window[0] == '+')
394f65f2164Snicm 			fs->wl = winlink_next_by_number(s->curw, s, n);
395f65f2164Snicm 		else
396f65f2164Snicm 			fs->wl = winlink_previous_by_number(s->curw, s, n);
397f65f2164Snicm 		if (fs->wl != NULL) {
398f65f2164Snicm 			fs->idx = fs->wl->idx;
399f65f2164Snicm 			fs->w = fs->wl->window;
400f65f2164Snicm 			return (0);
401f65f2164Snicm 		}
402f65f2164Snicm 	}
403f65f2164Snicm 
404f65f2164Snicm 	/* Try special characters. */
405a7f2e23cSnicm 	if (!exact) {
406f65f2164Snicm 		if (strcmp(window, "!") == 0) {
407f65f2164Snicm 			fs->wl = TAILQ_FIRST(&fs->s->lastw);
408f65f2164Snicm 			if (fs->wl == NULL)
409f65f2164Snicm 				return (-1);
410f65f2164Snicm 			fs->idx = fs->wl->idx;
411f65f2164Snicm 			fs->w = fs->wl->window;
412f65f2164Snicm 			return (0);
413f65f2164Snicm 		} else if (strcmp(window, "^") == 0) {
414f65f2164Snicm 			fs->wl = RB_MIN(winlinks, &fs->s->windows);
415f65f2164Snicm 			if (fs->wl == NULL)
416f65f2164Snicm 				return (-1);
417f65f2164Snicm 			fs->idx = fs->wl->idx;
418f65f2164Snicm 			fs->w = fs->wl->window;
419f65f2164Snicm 			return (0);
420f65f2164Snicm 		} else if (strcmp(window, "$") == 0) {
421f65f2164Snicm 			fs->wl = RB_MAX(winlinks, &fs->s->windows);
422f65f2164Snicm 			if (fs->wl == NULL)
423f65f2164Snicm 				return (-1);
424f65f2164Snicm 			fs->idx = fs->wl->idx;
425f65f2164Snicm 			fs->w = fs->wl->window;
426f65f2164Snicm 			return (0);
427f65f2164Snicm 		}
428a7f2e23cSnicm 	}
429f65f2164Snicm 
430f65f2164Snicm 	/* First see if this is a valid window index in this session. */
431a7f2e23cSnicm 	if (window[0] != '+' && window[0] != '-') {
432f65f2164Snicm 		idx = strtonum(window, 0, INT_MAX, &errstr);
433f65f2164Snicm 		if (errstr == NULL) {
434f65f2164Snicm 			fs->wl = winlink_find_by_index(&fs->s->windows, idx);
435f65f2164Snicm 			if (fs->wl != NULL) {
43638f68d44Snicm 				fs->idx = fs->wl->idx;
437f65f2164Snicm 				fs->w = fs->wl->window;
438f65f2164Snicm 				return (0);
439f65f2164Snicm 			}
4404bd93a15Snicm 			if (fs->flags & CMD_FIND_WINDOW_INDEX) {
4414bd93a15Snicm 				fs->idx = idx;
4424bd93a15Snicm 				return (0);
4434bd93a15Snicm 			}
444f65f2164Snicm 		}
445a7f2e23cSnicm 	}
446f65f2164Snicm 
447f65f2164Snicm 	/* Look for exact matches, error if more than one. */
448f65f2164Snicm 	fs->wl = NULL;
449f65f2164Snicm 	RB_FOREACH(wl, winlinks, &fs->s->windows) {
450f65f2164Snicm 		if (strcmp(window, wl->window->name) == 0) {
451f65f2164Snicm 			if (fs->wl != NULL)
452f65f2164Snicm 				return (-1);
453f65f2164Snicm 			fs->wl = wl;
454f65f2164Snicm 		}
455f65f2164Snicm 	}
456f65f2164Snicm 	if (fs->wl != NULL) {
457f65f2164Snicm 		fs->idx = fs->wl->idx;
458f65f2164Snicm 		fs->w = fs->wl->window;
459f65f2164Snicm 		return (0);
460f65f2164Snicm 	}
461f65f2164Snicm 
462a7f2e23cSnicm 	/* Stop now if exact only. */
463a7f2e23cSnicm 	if (exact)
464a7f2e23cSnicm 		return (-1);
465a7f2e23cSnicm 
466f65f2164Snicm 	/* Try as the start of a window name, error if multiple. */
467f65f2164Snicm 	fs->wl = NULL;
468f65f2164Snicm 	RB_FOREACH(wl, winlinks, &fs->s->windows) {
469f65f2164Snicm 		if (strncmp(window, wl->window->name, strlen(window)) == 0) {
470f65f2164Snicm 			if (fs->wl != NULL)
471f65f2164Snicm 				return (-1);
472f65f2164Snicm 			fs->wl = wl;
473f65f2164Snicm 		}
474f65f2164Snicm 	}
475f65f2164Snicm 	if (fs->wl != NULL) {
476f65f2164Snicm 		fs->idx = fs->wl->idx;
477f65f2164Snicm 		fs->w = fs->wl->window;
478f65f2164Snicm 		return (0);
479f65f2164Snicm 	}
480f65f2164Snicm 
481f65f2164Snicm 	/* Now look for pattern matches, again error if multiple. */
482f65f2164Snicm 	fs->wl = NULL;
483f65f2164Snicm 	RB_FOREACH(wl, winlinks, &fs->s->windows) {
484f65f2164Snicm 		if (fnmatch(window, wl->window->name, 0) == 0) {
485f65f2164Snicm 			if (fs->wl != NULL)
486f65f2164Snicm 				return (-1);
487f65f2164Snicm 			fs->wl = wl;
488f65f2164Snicm 		}
489f65f2164Snicm 	}
490f65f2164Snicm 	if (fs->wl != NULL) {
491f65f2164Snicm 		fs->idx = fs->wl->idx;
492f65f2164Snicm 		fs->w = fs->wl->window;
493f65f2164Snicm 		return (0);
494f65f2164Snicm 	}
495f65f2164Snicm 
496f65f2164Snicm 	return (-1);
497f65f2164Snicm }
498f65f2164Snicm 
499f65f2164Snicm /* Find pane from string. Fills in s, wl, w, wp. */
500dc1f0f5fSnicm static int
cmd_find_get_pane(struct cmd_find_state * fs,const char * pane,int only)50110f437f1Snicm cmd_find_get_pane(struct cmd_find_state *fs, const char *pane, int only)
502f65f2164Snicm {
503f65f2164Snicm 	log_debug("%s: %s", __func__, pane);
504f65f2164Snicm 
505f65f2164Snicm 	/* Check for pane ids starting with %. */
506f65f2164Snicm 	if (*pane == '%') {
507f65f2164Snicm 		fs->wp = window_pane_find_by_id_str(pane);
508b81c3e5bSnicm 		if (fs->wp == NULL)
509f65f2164Snicm 			return (-1);
510f65f2164Snicm 		fs->w = fs->wp->window;
511f65f2164Snicm 		return (cmd_find_best_session_with_window(fs));
512f65f2164Snicm 	}
513f65f2164Snicm 
514d296cf69Snicm 	/* Not a pane id, so try the current session and window. */
515f65f2164Snicm 	fs->s = fs->current->s;
516f65f2164Snicm 	fs->wl = fs->current->wl;
517f65f2164Snicm 	fs->idx = fs->current->idx;
518f65f2164Snicm 	fs->w = fs->current->w;
519f65f2164Snicm 
520f65f2164Snicm 	/* We now only need to find the pane in this window. */
521d296cf69Snicm 	if (cmd_find_get_pane_with_window(fs, pane) == 0)
522d296cf69Snicm 		return (0);
523d296cf69Snicm 
52438f80cb9Snicm 	/* Otherwise try as a window itself (this will also try as session). */
52510f437f1Snicm 	if (!only && cmd_find_get_window(fs, pane, 0) == 0) {
526d296cf69Snicm 		fs->wp = fs->w->active;
527d296cf69Snicm 		return (0);
528d296cf69Snicm 	}
529d296cf69Snicm 
530d296cf69Snicm 	return (-1);
531f65f2164Snicm }
532f65f2164Snicm 
533f65f2164Snicm /*
534f65f2164Snicm  * Find pane from string, assuming it is in given session. Needs s, fills in wl
535f65f2164Snicm  * and w and wp.
536f65f2164Snicm  */
537dc1f0f5fSnicm static int
cmd_find_get_pane_with_session(struct cmd_find_state * fs,const char * pane)538f65f2164Snicm cmd_find_get_pane_with_session(struct cmd_find_state *fs, const char *pane)
539f65f2164Snicm {
540f65f2164Snicm 	log_debug("%s: %s", __func__, pane);
541f65f2164Snicm 
542f65f2164Snicm 	/* Check for pane ids starting with %. */
543f65f2164Snicm 	if (*pane == '%') {
544f65f2164Snicm 		fs->wp = window_pane_find_by_id_str(pane);
545b81c3e5bSnicm 		if (fs->wp == NULL)
546f65f2164Snicm 			return (-1);
547f65f2164Snicm 		fs->w = fs->wp->window;
548f65f2164Snicm 		return (cmd_find_best_winlink_with_window(fs));
549f65f2164Snicm 	}
550f65f2164Snicm 
551f65f2164Snicm 	/* Otherwise use the current window. */
552f65f2164Snicm 	fs->wl = fs->s->curw;
553f65f2164Snicm 	fs->idx = fs->wl->idx;
554f65f2164Snicm 	fs->w = fs->wl->window;
555f65f2164Snicm 
556f65f2164Snicm 	/* Now we just need to look up the pane. */
557f65f2164Snicm 	return (cmd_find_get_pane_with_window(fs, pane));
558f65f2164Snicm }
559f65f2164Snicm 
560f65f2164Snicm /*
561f65f2164Snicm  * Find pane from string, assuming it is in the given window. Needs w, fills in
562f65f2164Snicm  * wp.
563f65f2164Snicm  */
564dc1f0f5fSnicm static int
cmd_find_get_pane_with_window(struct cmd_find_state * fs,const char * pane)565f65f2164Snicm cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane)
566f65f2164Snicm {
567f65f2164Snicm 	const char		*errstr;
568f65f2164Snicm 	int			 idx;
569f65f2164Snicm 	struct window_pane	*wp;
570f65f2164Snicm 	u_int			 n;
571f65f2164Snicm 
572f65f2164Snicm 	log_debug("%s: %s", __func__, pane);
573f65f2164Snicm 
574f65f2164Snicm 	/* Check for pane ids starting with %. */
575f65f2164Snicm 	if (*pane == '%') {
576f65f2164Snicm 		fs->wp = window_pane_find_by_id_str(pane);
577b81c3e5bSnicm 		if (fs->wp == NULL)
578315f8009Snicm 			return (-1);
579315f8009Snicm 		if (fs->wp->window != fs->w)
580f65f2164Snicm 			return (-1);
581f65f2164Snicm 		return (0);
582f65f2164Snicm 	}
583f65f2164Snicm 
584f65f2164Snicm 	/* Try special characters. */
585f65f2164Snicm 	if (strcmp(pane, "!") == 0) {
586*a0aa010aSnicm 		fs->wp = TAILQ_FIRST(&fs->w->last_panes);
587b81c3e5bSnicm 		if (fs->wp == NULL)
588315f8009Snicm 			return (-1);
589f65f2164Snicm 		return (0);
590baf68abeSnicm 	} else if (strcmp(pane, "{up-of}") == 0) {
591c2b9e1d8Snicm 		fs->wp = window_pane_find_up(fs->w->active);
592b81c3e5bSnicm 		if (fs->wp == NULL)
593f65f2164Snicm 			return (-1);
594f65f2164Snicm 		return (0);
595baf68abeSnicm 	} else if (strcmp(pane, "{down-of}") == 0) {
596c2b9e1d8Snicm 		fs->wp = window_pane_find_down(fs->w->active);
597b81c3e5bSnicm 		if (fs->wp == NULL)
598f65f2164Snicm 			return (-1);
599f65f2164Snicm 		return (0);
600baf68abeSnicm 	} else if (strcmp(pane, "{left-of}") == 0) {
601c2b9e1d8Snicm 		fs->wp = window_pane_find_left(fs->w->active);
602b81c3e5bSnicm 		if (fs->wp == NULL)
603f65f2164Snicm 			return (-1);
604f65f2164Snicm 		return (0);
605baf68abeSnicm 	} else if (strcmp(pane, "{right-of}") == 0) {
606c2b9e1d8Snicm 		fs->wp = window_pane_find_right(fs->w->active);
607b81c3e5bSnicm 		if (fs->wp == NULL)
608f65f2164Snicm 			return (-1);
609f65f2164Snicm 		return (0);
610f65f2164Snicm 	}
611f65f2164Snicm 
612f65f2164Snicm 	/* Try as an offset. */
613f65f2164Snicm 	if (pane[0] == '+' || pane[0] == '-') {
614f65f2164Snicm 		if (pane[1] != '\0')
615f65f2164Snicm 			n = strtonum(pane + 1, 1, INT_MAX, NULL);
616f65f2164Snicm 		else
617f65f2164Snicm 			n = 1;
618c2b9e1d8Snicm 		wp = fs->w->active;
619f65f2164Snicm 		if (pane[0] == '+')
620f65f2164Snicm 			fs->wp = window_pane_next_by_number(fs->w, wp, n);
621f65f2164Snicm 		else
622f65f2164Snicm 			fs->wp = window_pane_previous_by_number(fs->w, wp, n);
623b81c3e5bSnicm 		if (fs->wp != NULL)
624f65f2164Snicm 			return (0);
625f65f2164Snicm 	}
626f65f2164Snicm 
627f65f2164Snicm 	/* Get pane by index. */
628f65f2164Snicm 	idx = strtonum(pane, 0, INT_MAX, &errstr);
629f65f2164Snicm 	if (errstr == NULL) {
630f65f2164Snicm 		fs->wp = window_pane_at_index(fs->w, idx);
631b81c3e5bSnicm 		if (fs->wp != NULL)
632f65f2164Snicm 			return (0);
633f65f2164Snicm 	}
634f65f2164Snicm 
635f65f2164Snicm 	/* Try as a description. */
636f65f2164Snicm 	fs->wp = window_find_string(fs->w, pane);
637b81c3e5bSnicm 	if (fs->wp != NULL)
638f65f2164Snicm 		return (0);
639f65f2164Snicm 
640f65f2164Snicm 	return (-1);
641f65f2164Snicm }
642f65f2164Snicm 
643f65f2164Snicm /* Clear state. */
644f65f2164Snicm void
cmd_find_clear_state(struct cmd_find_state * fs,int flags)64593e732aaSnicm cmd_find_clear_state(struct cmd_find_state *fs, int flags)
646f65f2164Snicm {
647f65f2164Snicm 	memset(fs, 0, sizeof *fs);
648f65f2164Snicm 
649f65f2164Snicm 	fs->flags = flags;
650f65f2164Snicm 
651f65f2164Snicm 	fs->idx = -1;
652f65f2164Snicm }
653f65f2164Snicm 
65493e732aaSnicm /* Check if state is empty. */
655788e192fSnicm int
cmd_find_empty_state(struct cmd_find_state * fs)656788e192fSnicm cmd_find_empty_state(struct cmd_find_state *fs)
657788e192fSnicm {
658788e192fSnicm 	if (fs->s == NULL && fs->wl == NULL && fs->w == NULL && fs->wp == NULL)
659788e192fSnicm 		return (1);
660788e192fSnicm 	return (0);
661788e192fSnicm }
662788e192fSnicm 
6637519eda3Snicm /* Check if a state if valid. */
6647519eda3Snicm int
cmd_find_valid_state(struct cmd_find_state * fs)6657519eda3Snicm cmd_find_valid_state(struct cmd_find_state *fs)
6667519eda3Snicm {
6677519eda3Snicm 	struct winlink	*wl;
6687519eda3Snicm 
6697519eda3Snicm 	if (fs->s == NULL || fs->wl == NULL || fs->w == NULL || fs->wp == NULL)
6707519eda3Snicm 		return (0);
6717519eda3Snicm 
6727519eda3Snicm 	if (!session_alive(fs->s))
6737519eda3Snicm 		return (0);
6747519eda3Snicm 
6757519eda3Snicm 	RB_FOREACH(wl, winlinks, &fs->s->windows) {
6767519eda3Snicm 		if (wl->window == fs->w && wl == fs->wl)
6777519eda3Snicm 			break;
6787519eda3Snicm 	}
6797519eda3Snicm 	if (wl == NULL)
6807519eda3Snicm 		return (0);
6817519eda3Snicm 
6827519eda3Snicm 	if (fs->w != fs->wl->window)
6837519eda3Snicm 		return (0);
6847519eda3Snicm 
685b81c3e5bSnicm 	return (window_has_pane(fs->w, fs->wp));
6867519eda3Snicm }
6877519eda3Snicm 
6887519eda3Snicm /* Copy a state. */
6897519eda3Snicm void
cmd_find_copy_state(struct cmd_find_state * dst,struct cmd_find_state * src)6907519eda3Snicm cmd_find_copy_state(struct cmd_find_state *dst, struct cmd_find_state *src)
6917519eda3Snicm {
6927519eda3Snicm 	dst->s = src->s;
6937519eda3Snicm 	dst->wl = src->wl;
6941d19b2ecSnicm 	dst->idx = src->idx;
6951d19b2ecSnicm 	dst->w = src->w;
6967519eda3Snicm 	dst->wp = src->wp;
6977519eda3Snicm }
6987519eda3Snicm 
6997519eda3Snicm /* Log the result. */
7004e325abeSnicm static void
cmd_find_log_state(const char * prefix,struct cmd_find_state * fs)7017519eda3Snicm cmd_find_log_state(const char *prefix, struct cmd_find_state *fs)
7027519eda3Snicm {
7037519eda3Snicm 	if (fs->s != NULL)
7042fe539a5Snicm 		log_debug("%s: s=$%u %s", prefix, fs->s->id, fs->s->name);
7057519eda3Snicm 	else
7067519eda3Snicm 		log_debug("%s: s=none", prefix);
7077519eda3Snicm 	if (fs->wl != NULL) {
7087519eda3Snicm 		log_debug("%s: wl=%u %d w=@%u %s", prefix, fs->wl->idx,
7097519eda3Snicm 		    fs->wl->window == fs->w, fs->w->id, fs->w->name);
7107519eda3Snicm 	} else
7117519eda3Snicm 		log_debug("%s: wl=none", prefix);
7127519eda3Snicm 	if (fs->wp != NULL)
7137519eda3Snicm 		log_debug("%s: wp=%%%u", prefix, fs->wp->id);
7147519eda3Snicm 	else
7157519eda3Snicm 		log_debug("%s: wp=none", prefix);
7167519eda3Snicm 	if (fs->idx != -1)
7177519eda3Snicm 		log_debug("%s: idx=%d", prefix, fs->idx);
7187519eda3Snicm 	else
7197519eda3Snicm 		log_debug("%s: idx=none", prefix);
7207519eda3Snicm }
7217519eda3Snicm 
7224fc586aaSnicm /* Find state from a session. */
7231adc95ebSnicm void
cmd_find_from_session(struct cmd_find_state * fs,struct session * s,int flags)7240772530eSnicm cmd_find_from_session(struct cmd_find_state *fs, struct session *s, int flags)
7254fc586aaSnicm {
7260772530eSnicm 	cmd_find_clear_state(fs, flags);
7274fc586aaSnicm 
7284fc586aaSnicm 	fs->s = s;
7294fc586aaSnicm 	fs->wl = fs->s->curw;
7304fc586aaSnicm 	fs->w = fs->wl->window;
7314fc586aaSnicm 	fs->wp = fs->w->active;
7324fc586aaSnicm 
7334fc586aaSnicm 	cmd_find_log_state(__func__, fs);
7344fc586aaSnicm }
7354fc586aaSnicm 
7366cd60b5aSnicm /* Find state from a winlink. */
7371adc95ebSnicm void
cmd_find_from_winlink(struct cmd_find_state * fs,struct winlink * wl,int flags)7380772530eSnicm cmd_find_from_winlink(struct cmd_find_state *fs, struct winlink *wl, int flags)
7396cd60b5aSnicm {
7400772530eSnicm 	cmd_find_clear_state(fs, flags);
7416cd60b5aSnicm 
7426aa2e59aSnicm 	fs->s = wl->session;
7436cd60b5aSnicm 	fs->wl = wl;
7446cd60b5aSnicm 	fs->w = wl->window;
7456cd60b5aSnicm 	fs->wp = wl->window->active;
7466cd60b5aSnicm 
7476cd60b5aSnicm 	cmd_find_log_state(__func__, fs);
7486cd60b5aSnicm }
7496cd60b5aSnicm 
7503938e8abSnicm /* Find state from a session and window. */
7513938e8abSnicm int
cmd_find_from_session_window(struct cmd_find_state * fs,struct session * s,struct window * w,int flags)7523938e8abSnicm cmd_find_from_session_window(struct cmd_find_state *fs, struct session *s,
7530772530eSnicm     struct window *w, int flags)
7543938e8abSnicm {
7550772530eSnicm 	cmd_find_clear_state(fs, flags);
7563938e8abSnicm 
7573938e8abSnicm 	fs->s = s;
7583938e8abSnicm 	fs->w = w;
7599a5690feSnicm 	if (cmd_find_best_winlink_with_window(fs) != 0) {
7600772530eSnicm 		cmd_find_clear_state(fs, flags);
7613938e8abSnicm 		return (-1);
7629a5690feSnicm 	}
7633938e8abSnicm 	fs->wp = fs->w->active;
7643938e8abSnicm 
7653938e8abSnicm 	cmd_find_log_state(__func__, fs);
7663938e8abSnicm 	return (0);
7673938e8abSnicm }
7683938e8abSnicm 
7694fc586aaSnicm /* Find state from a window. */
7704fc586aaSnicm int
cmd_find_from_window(struct cmd_find_state * fs,struct window * w,int flags)7710772530eSnicm cmd_find_from_window(struct cmd_find_state *fs, struct window *w, int flags)
7724fc586aaSnicm {
7730772530eSnicm 	cmd_find_clear_state(fs, flags);
7744fc586aaSnicm 
7754fc586aaSnicm 	fs->w = w;
7769a5690feSnicm 	if (cmd_find_best_session_with_window(fs) != 0) {
7770772530eSnicm 		cmd_find_clear_state(fs, flags);
7784fc586aaSnicm 		return (-1);
7799a5690feSnicm 	}
7809a5690feSnicm 	if (cmd_find_best_winlink_with_window(fs) != 0) {
7810772530eSnicm 		cmd_find_clear_state(fs, flags);
7824fc586aaSnicm 		return (-1);
7839a5690feSnicm 	}
7843938e8abSnicm 	fs->wp = fs->w->active;
7854fc586aaSnicm 
7864fc586aaSnicm 	cmd_find_log_state(__func__, fs);
7874fc586aaSnicm 	return (0);
7884fc586aaSnicm }
7894fc586aaSnicm 
7901adc95ebSnicm /* Find state from a winlink and pane. */
7911adc95ebSnicm void
cmd_find_from_winlink_pane(struct cmd_find_state * fs,struct winlink * wl,struct window_pane * wp,int flags)7921adc95ebSnicm cmd_find_from_winlink_pane(struct cmd_find_state *fs, struct winlink *wl,
7930772530eSnicm     struct window_pane *wp, int flags)
7941adc95ebSnicm {
7950772530eSnicm 	cmd_find_clear_state(fs, flags);
7961adc95ebSnicm 
7971adc95ebSnicm 	fs->s = wl->session;
7981adc95ebSnicm 	fs->wl = wl;
7991adc95ebSnicm 	fs->idx = fs->wl->idx;
8001adc95ebSnicm 	fs->w = fs->wl->window;
8011adc95ebSnicm 	fs->wp = wp;
8021adc95ebSnicm 
8031adc95ebSnicm 	cmd_find_log_state(__func__, fs);
8041adc95ebSnicm }
8051adc95ebSnicm 
8064fc586aaSnicm /* Find state from a pane. */
8074fc586aaSnicm int
cmd_find_from_pane(struct cmd_find_state * fs,struct window_pane * wp,int flags)8080772530eSnicm cmd_find_from_pane(struct cmd_find_state *fs, struct window_pane *wp, int flags)
8094fc586aaSnicm {
8100772530eSnicm 	if (cmd_find_from_window(fs, wp->window, flags) != 0)
8114fc586aaSnicm 		return (-1);
8124fc586aaSnicm 	fs->wp = wp;
8134fc586aaSnicm 
8144fc586aaSnicm 	cmd_find_log_state(__func__, fs);
8154fc586aaSnicm 	return (0);
8164fc586aaSnicm }
8174fc586aaSnicm 
81893e732aaSnicm /* Find state from nothing. */
819dead13bbSnicm int
cmd_find_from_nothing(struct cmd_find_state * fs,int flags)8200772530eSnicm cmd_find_from_nothing(struct cmd_find_state *fs, int flags)
821dead13bbSnicm {
8220772530eSnicm 	cmd_find_clear_state(fs, flags);
82393e732aaSnicm 
8240772530eSnicm 	fs->s = cmd_find_best_session(NULL, 0, flags);
8259a5690feSnicm 	if (fs->s == NULL) {
8260772530eSnicm 		cmd_find_clear_state(fs, flags);
82793e732aaSnicm 		return (-1);
8289a5690feSnicm 	}
82993e732aaSnicm 	fs->wl = fs->s->curw;
83093e732aaSnicm 	fs->idx = fs->wl->idx;
83193e732aaSnicm 	fs->w = fs->wl->window;
83293e732aaSnicm 	fs->wp = fs->w->active;
83393e732aaSnicm 
83493e732aaSnicm 	cmd_find_log_state(__func__, fs);
83593e732aaSnicm 	return (0);
83693e732aaSnicm }
83793e732aaSnicm 
83893e732aaSnicm /* Find state from mouse. */
83993e732aaSnicm int
cmd_find_from_mouse(struct cmd_find_state * fs,struct mouse_event * m,int flags)8400772530eSnicm cmd_find_from_mouse(struct cmd_find_state *fs, struct mouse_event *m, int flags)
84193e732aaSnicm {
8420772530eSnicm 	cmd_find_clear_state(fs, flags);
84393e732aaSnicm 
84493e732aaSnicm 	if (!m->valid)
84593e732aaSnicm 		return (-1);
84693e732aaSnicm 
84793e732aaSnicm 	fs->wp = cmd_mouse_pane(m, &fs->s, &fs->wl);
8489a5690feSnicm 	if (fs->wp == NULL) {
8490772530eSnicm 		cmd_find_clear_state(fs, flags);
85093e732aaSnicm 		return (-1);
8519a5690feSnicm 	}
85293e732aaSnicm 	fs->w = fs->wl->window;
85393e732aaSnicm 
85493e732aaSnicm 	cmd_find_log_state(__func__, fs);
85593e732aaSnicm 	return (0);
85693e732aaSnicm }
85793e732aaSnicm 
85893e732aaSnicm /* Find state from client. */
85993e732aaSnicm int
cmd_find_from_client(struct cmd_find_state * fs,struct client * c,int flags)8600772530eSnicm cmd_find_from_client(struct cmd_find_state *fs, struct client *c, int flags)
86193e732aaSnicm {
86293e732aaSnicm 	struct window_pane	*wp;
86393e732aaSnicm 
86493e732aaSnicm 	/* If no client, treat as from nothing. */
86593e732aaSnicm 	if (c == NULL)
8660772530eSnicm 		return (cmd_find_from_nothing(fs, flags));
86793e732aaSnicm 
86893e732aaSnicm 	/* If this is an attached client, all done. */
86993e732aaSnicm 	if (c->session != NULL) {
870249e1654Snicm 		cmd_find_clear_state(fs, flags);
871249e1654Snicm 
872249e1654Snicm 		fs->wp = server_client_get_pane(c);
873249e1654Snicm 		if (fs->wp == NULL) {
8740772530eSnicm 			cmd_find_from_session(fs, c->session, flags);
87593e732aaSnicm 			return (0);
87693e732aaSnicm 		}
877249e1654Snicm 		fs->s = c->session;
878249e1654Snicm 		fs->wl = fs->s->curw;
879249e1654Snicm 		fs->w = fs->wl->window;
880249e1654Snicm 
881249e1654Snicm 		cmd_find_log_state(__func__, fs);
882249e1654Snicm 		return (0);
883249e1654Snicm 	}
8840772530eSnicm 	cmd_find_clear_state(fs, flags);
88593e732aaSnicm 
88693e732aaSnicm 	/*
88793e732aaSnicm 	 * If this is an unattached client running in a pane, we can use that
88893e732aaSnicm 	 * to limit the list of sessions to those containing that pane.
88993e732aaSnicm 	 */
8906b339e7dSnicm 	wp = cmd_find_inside_pane(c);
89193e732aaSnicm 	if (wp == NULL)
89293e732aaSnicm 		goto unknown_pane;
89393e732aaSnicm 
89493e732aaSnicm 	/*
89593e732aaSnicm 	 * Don't have a session, or it doesn't have this pane. Try all
89693e732aaSnicm 	 * sessions.
89793e732aaSnicm 	 */
89893e732aaSnicm 	fs->w = wp->window;
89993e732aaSnicm 	if (cmd_find_best_session_with_window(fs) != 0) {
90093e732aaSnicm 		/*
90193e732aaSnicm 		 * The window may have been destroyed but the pane
90293e732aaSnicm 		 * still on all_window_panes due to something else
90393e732aaSnicm 		 * holding a reference.
90493e732aaSnicm 		 */
90593e732aaSnicm 		goto unknown_pane;
90693e732aaSnicm 	}
90793e732aaSnicm 	fs->wl = fs->s->curw;
90893e732aaSnicm 	fs->w = fs->wl->window;
90993e732aaSnicm 	fs->wp = fs->w->active; /* use active pane */
91093e732aaSnicm 
91193e732aaSnicm 	cmd_find_log_state(__func__, fs);
912dead13bbSnicm 	return (0);
91393e732aaSnicm 
91493e732aaSnicm unknown_pane:
915403a76d5Snicm 	/* We can't find the pane so need to guess. */
9160772530eSnicm 	return (cmd_find_from_nothing(fs, flags));
917dead13bbSnicm }
918dead13bbSnicm 
919ed390037Snicm /*
920ed390037Snicm  * Split target into pieces and resolve for the given type. Fills in the given
921ed390037Snicm  * state. Returns 0 on success or -1 on error.
922ed390037Snicm  */
923ed390037Snicm int
cmd_find_target(struct cmd_find_state * fs,struct cmdq_item * item,const char * target,enum cmd_find_type type,int flags)92493e732aaSnicm cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
92593e732aaSnicm     const char *target, enum cmd_find_type type, int flags)
926f65f2164Snicm {
927f65f2164Snicm 	struct mouse_event	*m;
92893e732aaSnicm 	struct cmd_find_state	 current;
929a7e27df1Snicm 	char			*colon, *period, *copy = NULL, tmp[256];
9306e8d04c2Snicm 	const char		*session, *window, *pane, *s;
93110f437f1Snicm 	int			 window_only = 0, pane_only = 0;
932f65f2164Snicm 
933bf0d297eSnicm 	/* Can fail flag implies quiet. */
934bf0d297eSnicm 	if (flags & CMD_FIND_CANFAIL)
935bf0d297eSnicm 		flags |= CMD_FIND_QUIET;
936bf0d297eSnicm 
937765d031fSnicm 	/* Log the arguments. */
9386e8d04c2Snicm 	if (type == CMD_FIND_PANE)
9396e8d04c2Snicm 		s = "pane";
9406e8d04c2Snicm 	else if (type == CMD_FIND_WINDOW)
9416e8d04c2Snicm 		s = "window";
9426e8d04c2Snicm 	else if (type == CMD_FIND_SESSION)
9436e8d04c2Snicm 		s = "session";
944765d031fSnicm 	else
9456e8d04c2Snicm 		s = "unknown";
946a7e27df1Snicm 	*tmp = '\0';
947a7e27df1Snicm 	if (flags & CMD_FIND_PREFER_UNATTACHED)
948a7e27df1Snicm 		strlcat(tmp, "PREFER_UNATTACHED,", sizeof tmp);
949a7e27df1Snicm 	if (flags & CMD_FIND_QUIET)
950a7e27df1Snicm 		strlcat(tmp, "QUIET,", sizeof tmp);
951a7e27df1Snicm 	if (flags & CMD_FIND_WINDOW_INDEX)
952a7e27df1Snicm 		strlcat(tmp, "WINDOW_INDEX,", sizeof tmp);
953a7e27df1Snicm 	if (flags & CMD_FIND_DEFAULT_MARKED)
954a7e27df1Snicm 		strlcat(tmp, "DEFAULT_MARKED,", sizeof tmp);
955a7e27df1Snicm 	if (flags & CMD_FIND_EXACT_SESSION)
956a7e27df1Snicm 		strlcat(tmp, "EXACT_SESSION,", sizeof tmp);
957a7e27df1Snicm 	if (flags & CMD_FIND_EXACT_WINDOW)
958a7e27df1Snicm 		strlcat(tmp, "EXACT_WINDOW,", sizeof tmp);
959a7e27df1Snicm 	if (flags & CMD_FIND_CANFAIL)
960a7e27df1Snicm 		strlcat(tmp, "CANFAIL,", sizeof tmp);
961a7e27df1Snicm 	if (*tmp != '\0')
962a7e27df1Snicm 		tmp[strlen(tmp) - 1] = '\0';
963403a76d5Snicm 	else
964403a76d5Snicm 		strlcat(tmp, "NONE", sizeof tmp);
965a7e27df1Snicm 	log_debug("%s: target %s, type %s, item %p, flags %s", __func__,
966a7e27df1Snicm 	    target == NULL ? "none" : target, s, item, tmp);
967765d031fSnicm 
96856d83ebbSnicm 	/* Clear new state. */
96993e732aaSnicm 	cmd_find_clear_state(fs, flags);
97056d83ebbSnicm 
971f65f2164Snicm 	/* Find current state. */
972788e192fSnicm 	if (server_check_marked() && (flags & CMD_FIND_DEFAULT_MARKED)) {
97356d83ebbSnicm 		fs->current = &marked_pane;
974691b2064Snicm 		log_debug("%s: current is marked pane", __func__);
975823b6d6dSnicm 	} else if (cmd_find_valid_state(cmdq_get_current(item))) {
976823b6d6dSnicm 		fs->current = cmdq_get_current(item);
977691b2064Snicm 		log_debug("%s: current is from queue", __func__);
978040343aeSnicm 	} else if (cmd_find_from_client(&current, cmdq_get_client(item),
979040343aeSnicm 	    flags) == 0) {
98093e732aaSnicm 		fs->current = &current;
98193e732aaSnicm 		log_debug("%s: current is from client", __func__);
9824d203398Snicm 	} else {
9834d203398Snicm 		if (~flags & CMD_FIND_QUIET)
9844d203398Snicm 			cmdq_error(item, "no current target");
985d655f083Snicm 		goto error;
9864d203398Snicm 	}
987d655f083Snicm 	if (!cmd_find_valid_state(fs->current))
988788e192fSnicm 		fatalx("invalid current find state");
989f65f2164Snicm 
990f65f2164Snicm 	/* An empty or NULL target is the current. */
991f65f2164Snicm 	if (target == NULL || *target == '\0')
992f65f2164Snicm 		goto current;
993f65f2164Snicm 
994f65f2164Snicm 	/* Mouse target is a plain = or {mouse}. */
995f65f2164Snicm 	if (strcmp(target, "=") == 0 || strcmp(target, "{mouse}") == 0) {
996823b6d6dSnicm 		m = &cmdq_get_event(item)->m;
997f65f2164Snicm 		switch (type) {
998f65f2164Snicm 		case CMD_FIND_PANE:
999ed390037Snicm 			fs->wp = cmd_mouse_pane(m, &fs->s, &fs->wl);
10009b9cde72Snicm 			if (fs->wp != NULL) {
1001ed390037Snicm 				fs->w = fs->wl->window;
1002f65f2164Snicm 				break;
10039b9cde72Snicm 			}
10049b9cde72Snicm 			/* FALLTHROUGH */
1005f65f2164Snicm 		case CMD_FIND_WINDOW:
1006f65f2164Snicm 		case CMD_FIND_SESSION:
1007ed390037Snicm 			fs->wl = cmd_mouse_window(m, &fs->s);
10089b9cde72Snicm 			if (fs->wl == NULL && fs->s != NULL)
10099b9cde72Snicm 				fs->wl = fs->s->curw;
1010ed390037Snicm 			if (fs->wl != NULL) {
1011ed390037Snicm 				fs->w = fs->wl->window;
1012ed390037Snicm 				fs->wp = fs->w->active;
1013f65f2164Snicm 			}
1014f65f2164Snicm 			break;
1015f65f2164Snicm 		}
1016ed390037Snicm 		if (fs->wp == NULL) {
1017f65f2164Snicm 			if (~flags & CMD_FIND_QUIET)
101868e0a7f2Snicm 				cmdq_error(item, "no mouse target");
1019f65f2164Snicm 			goto error;
1020f65f2164Snicm 		}
1021765d031fSnicm 		goto found;
1022f65f2164Snicm 	}
10232986c025Snicm 
10242986c025Snicm 	/* Marked target is a plain ~ or {marked}. */
10252986c025Snicm 	if (strcmp(target, "~") == 0 || strcmp(target, "{marked}") == 0) {
10262986c025Snicm 		if (!server_check_marked()) {
10272986c025Snicm 			if (~flags & CMD_FIND_QUIET)
102868e0a7f2Snicm 				cmdq_error(item, "no marked target");
10292986c025Snicm 			goto error;
10302986c025Snicm 		}
10317519eda3Snicm 		cmd_find_copy_state(fs, &marked_pane);
1032765d031fSnicm 		goto found;
10332986c025Snicm 	}
1034f65f2164Snicm 
1035f65f2164Snicm 	/* Find separators if they exist. */
10362986c025Snicm 	copy = xstrdup(target);
1037f65f2164Snicm 	colon = strchr(copy, ':');
1038f65f2164Snicm 	if (colon != NULL)
1039f65f2164Snicm 		*colon++ = '\0';
1040f65f2164Snicm 	if (colon == NULL)
1041f65f2164Snicm 		period = strchr(copy, '.');
1042f65f2164Snicm 	else
1043f65f2164Snicm 		period = strchr(colon, '.');
1044f65f2164Snicm 	if (period != NULL)
1045f65f2164Snicm 		*period++ = '\0';
1046f65f2164Snicm 
1047f65f2164Snicm 	/* Set session, window and pane parts. */
1048f65f2164Snicm 	session = window = pane = NULL;
1049f65f2164Snicm 	if (colon != NULL && period != NULL) {
1050f65f2164Snicm 		session = copy;
1051f65f2164Snicm 		window = colon;
105210f437f1Snicm 		window_only = 1;
1053f65f2164Snicm 		pane = period;
105410f437f1Snicm 		pane_only = 1;
1055f65f2164Snicm 	} else if (colon != NULL && period == NULL) {
1056f65f2164Snicm 		session = copy;
1057f65f2164Snicm 		window = colon;
105810f437f1Snicm 		window_only = 1;
1059f65f2164Snicm 	} else if (colon == NULL && period != NULL) {
1060f65f2164Snicm 		window = copy;
1061f65f2164Snicm 		pane = period;
106210f437f1Snicm 		pane_only = 1;
1063f65f2164Snicm 	} else {
1064f65f2164Snicm 		if (*copy == '$')
1065f65f2164Snicm 			session = copy;
1066f65f2164Snicm 		else if (*copy == '@')
1067f65f2164Snicm 			window = copy;
1068f65f2164Snicm 		else if (*copy == '%')
1069f65f2164Snicm 			pane = copy;
1070f65f2164Snicm 		else {
1071f65f2164Snicm 			switch (type) {
1072f65f2164Snicm 			case CMD_FIND_SESSION:
1073f65f2164Snicm 				session = copy;
1074f65f2164Snicm 				break;
1075f65f2164Snicm 			case CMD_FIND_WINDOW:
1076f65f2164Snicm 				window = copy;
1077f65f2164Snicm 				break;
1078f65f2164Snicm 			case CMD_FIND_PANE:
1079f65f2164Snicm 				pane = copy;
1080f65f2164Snicm 				break;
1081f65f2164Snicm 			}
1082f65f2164Snicm 		}
1083f65f2164Snicm 	}
1084f65f2164Snicm 
1085a7f2e23cSnicm 	/* Set exact match flags. */
1086a7f2e23cSnicm 	if (session != NULL && *session == '=') {
1087a7f2e23cSnicm 		session++;
1088ed390037Snicm 		fs->flags |= CMD_FIND_EXACT_SESSION;
1089a7f2e23cSnicm 	}
1090a7f2e23cSnicm 	if (window != NULL && *window == '=') {
1091a7f2e23cSnicm 		window++;
1092ed390037Snicm 		fs->flags |= CMD_FIND_EXACT_WINDOW;
1093a7f2e23cSnicm 	}
1094a7f2e23cSnicm 
1095f65f2164Snicm 	/* Empty is the same as NULL. */
1096f65f2164Snicm 	if (session != NULL && *session == '\0')
1097f65f2164Snicm 		session = NULL;
1098f65f2164Snicm 	if (window != NULL && *window == '\0')
1099f65f2164Snicm 		window = NULL;
1100f65f2164Snicm 	if (pane != NULL && *pane == '\0')
1101f65f2164Snicm 		pane = NULL;
1102f65f2164Snicm 
1103f65f2164Snicm 	/* Map though conversion table. */
1104f65f2164Snicm 	if (session != NULL)
1105f65f2164Snicm 		session = cmd_find_map_table(cmd_find_session_table, session);
1106f65f2164Snicm 	if (window != NULL)
1107f65f2164Snicm 		window = cmd_find_map_table(cmd_find_window_table, window);
1108f65f2164Snicm 	if (pane != NULL)
1109f65f2164Snicm 		pane = cmd_find_map_table(cmd_find_pane_table, pane);
1110f65f2164Snicm 
1111a7e27df1Snicm 	if (session != NULL || window != NULL || pane != NULL) {
1112a7e27df1Snicm 		log_debug("%s: target %s is %s%s%s%s%s%s",
1113a7e27df1Snicm 		    __func__, target,
1114a7e27df1Snicm 		    session == NULL ? "" : "session ",
1115a7e27df1Snicm 		    session == NULL ? "" : session,
1116a7e27df1Snicm 		    window == NULL ? "" : "window ",
1117a7e27df1Snicm 		    window == NULL ? "" : window,
1118a7e27df1Snicm 		    pane == NULL ? "" : "pane ",
1119a7e27df1Snicm 		    pane == NULL ? "" : pane);
1120a7e27df1Snicm 	}
1121f65f2164Snicm 
1122f65f2164Snicm 	/* No pane is allowed if want an index. */
1123f65f2164Snicm 	if (pane != NULL && (flags & CMD_FIND_WINDOW_INDEX)) {
1124f65f2164Snicm 		if (~flags & CMD_FIND_QUIET)
112568e0a7f2Snicm 			cmdq_error(item, "can't specify pane here");
1126f65f2164Snicm 		goto error;
1127f65f2164Snicm 	}
1128f65f2164Snicm 
1129f65f2164Snicm 	/* If the session isn't NULL, look it up. */
1130f65f2164Snicm 	if (session != NULL) {
1131f65f2164Snicm 		/* This will fill in session. */
1132ed390037Snicm 		if (cmd_find_get_session(fs, session) != 0)
1133f65f2164Snicm 			goto no_session;
1134f65f2164Snicm 
1135f65f2164Snicm 		/* If window and pane are NULL, use that session's current. */
1136f65f2164Snicm 		if (window == NULL && pane == NULL) {
1137ed390037Snicm 			fs->wl = fs->s->curw;
1138ed390037Snicm 			fs->idx = -1;
1139ed390037Snicm 			fs->w = fs->wl->window;
1140ed390037Snicm 			fs->wp = fs->w->active;
1141f65f2164Snicm 			goto found;
1142f65f2164Snicm 		}
1143f65f2164Snicm 
1144f65f2164Snicm 		/* If window is present but pane not, find window in session. */
1145f65f2164Snicm 		if (window != NULL && pane == NULL) {
1146f65f2164Snicm 			/* This will fill in winlink and window. */
1147ed390037Snicm 			if (cmd_find_get_window_with_session(fs, window) != 0)
1148f65f2164Snicm 				goto no_window;
11494d00024eSnicm 			if (fs->wl != NULL) /* can be NULL if index only */
1150ed390037Snicm 				fs->wp = fs->wl->window->active;
1151f65f2164Snicm 			goto found;
1152f65f2164Snicm 		}
1153f65f2164Snicm 
1154f65f2164Snicm 		/* If pane is present but window not, find pane. */
1155f65f2164Snicm 		if (window == NULL && pane != NULL) {
1156f65f2164Snicm 			/* This will fill in winlink and window and pane. */
1157ed390037Snicm 			if (cmd_find_get_pane_with_session(fs, pane) != 0)
1158f65f2164Snicm 				goto no_pane;
1159f65f2164Snicm 			goto found;
1160f65f2164Snicm 		}
1161f65f2164Snicm 
1162f65f2164Snicm 		/*
1163f65f2164Snicm 		 * If window and pane are present, find both in session. This
1164f65f2164Snicm 		 * will fill in winlink and window.
1165f65f2164Snicm 		 */
1166ed390037Snicm 		if (cmd_find_get_window_with_session(fs, window) != 0)
1167f65f2164Snicm 			goto no_window;
1168f65f2164Snicm 		/* This will fill in pane. */
1169ed390037Snicm 		if (cmd_find_get_pane_with_window(fs, pane) != 0)
1170f65f2164Snicm 			goto no_pane;
1171f65f2164Snicm 		goto found;
1172f65f2164Snicm 	}
1173f65f2164Snicm 
1174f65f2164Snicm 	/* No session. If window and pane, try them. */
1175f65f2164Snicm 	if (window != NULL && pane != NULL) {
1176f65f2164Snicm 		/* This will fill in session, winlink and window. */
117710f437f1Snicm 		if (cmd_find_get_window(fs, window, window_only) != 0)
1178f65f2164Snicm 			goto no_window;
1179f65f2164Snicm 		/* This will fill in pane. */
1180ed390037Snicm 		if (cmd_find_get_pane_with_window(fs, pane) != 0)
1181f65f2164Snicm 			goto no_pane;
1182f65f2164Snicm 		goto found;
1183f65f2164Snicm 	}
1184f65f2164Snicm 
1185f65f2164Snicm 	/* If just window is present, try it. */
1186f65f2164Snicm 	if (window != NULL && pane == NULL) {
1187f65f2164Snicm 		/* This will fill in session, winlink and window. */
118810f437f1Snicm 		if (cmd_find_get_window(fs, window, window_only) != 0)
1189f65f2164Snicm 			goto no_window;
11904bd93a15Snicm 		if (fs->wl != NULL) /* can be NULL if index only */
1191ed390037Snicm 			fs->wp = fs->wl->window->active;
1192f65f2164Snicm 		goto found;
1193f65f2164Snicm 	}
1194f65f2164Snicm 
1195f65f2164Snicm 	/* If just pane is present, try it. */
1196f65f2164Snicm 	if (window == NULL && pane != NULL) {
1197f65f2164Snicm 		/* This will fill in session, winlink, window and pane. */
119810f437f1Snicm 		if (cmd_find_get_pane(fs, pane, pane_only) != 0)
1199f65f2164Snicm 			goto no_pane;
1200f65f2164Snicm 		goto found;
1201f65f2164Snicm 	}
1202f65f2164Snicm 
1203f65f2164Snicm current:
1204ed390037Snicm 	/* Use the current session. */
120556d83ebbSnicm 	cmd_find_copy_state(fs, fs->current);
1206f65f2164Snicm 	if (flags & CMD_FIND_WINDOW_INDEX)
120756d83ebbSnicm 		fs->idx = -1;
1208ed390037Snicm 	goto found;
1209f65f2164Snicm 
1210f65f2164Snicm error:
1211ed390037Snicm 	fs->current = NULL;
1212691b2064Snicm 	log_debug("%s: error", __func__);
1213ed390037Snicm 
1214ed390037Snicm 	free(copy);
1215bf0d297eSnicm 	if (flags & CMD_FIND_CANFAIL)
1216bf0d297eSnicm 		return (0);
1217ed390037Snicm 	return (-1);
1218f65f2164Snicm 
1219f65f2164Snicm found:
1220ed390037Snicm 	fs->current = NULL;
1221ed390037Snicm 	cmd_find_log_state(__func__, fs);
1222ed390037Snicm 
1223f65f2164Snicm 	free(copy);
1224ed390037Snicm 	return (0);
1225f65f2164Snicm 
1226f65f2164Snicm no_session:
1227f65f2164Snicm 	if (~flags & CMD_FIND_QUIET)
1228fe57de0cSnicm 		cmdq_error(item, "can't find session: %s", session);
1229f65f2164Snicm 	goto error;
1230f65f2164Snicm 
1231f65f2164Snicm no_window:
1232f65f2164Snicm 	if (~flags & CMD_FIND_QUIET)
1233fe57de0cSnicm 		cmdq_error(item, "can't find window: %s", window);
1234f65f2164Snicm 	goto error;
1235f65f2164Snicm 
1236f65f2164Snicm no_pane:
1237f65f2164Snicm 	if (~flags & CMD_FIND_QUIET)
1238fe57de0cSnicm 		cmdq_error(item, "can't find pane: %s", pane);
1239f65f2164Snicm 	goto error;
1240f65f2164Snicm }
1241f65f2164Snicm 
12426b339e7dSnicm /* Find the current client. */
12436b339e7dSnicm static struct client *
cmd_find_current_client(struct cmdq_item * item,int quiet)12446b339e7dSnicm cmd_find_current_client(struct cmdq_item *item, int quiet)
1245f65f2164Snicm {
12462db665b3Snicm 	struct client		*c = NULL, *found;
124793e732aaSnicm 	struct session		*s;
12486b339e7dSnicm 	struct window_pane	*wp;
12496b339e7dSnicm 	struct cmd_find_state	 fs;
1250f65f2164Snicm 
12512db665b3Snicm 	if (item != NULL)
1252040343aeSnicm 		c = cmdq_get_client(item);
12532db665b3Snicm 	if (c != NULL && c->session != NULL)
12542db665b3Snicm 		return (c);
12556b339e7dSnicm 
12562db665b3Snicm 	found = NULL;
12572db665b3Snicm 	if (c != NULL && (wp = cmd_find_inside_pane(c)) != NULL) {
12586b339e7dSnicm 		cmd_find_clear_state(&fs, CMD_FIND_QUIET);
12596b339e7dSnicm 		fs.w = wp->window;
12606b339e7dSnicm 		if (cmd_find_best_session_with_window(&fs) == 0)
12612db665b3Snicm 			found = cmd_find_best_client(fs.s);
12626b339e7dSnicm 	} else {
126393e732aaSnicm 		s = cmd_find_best_session(NULL, 0, CMD_FIND_QUIET);
126493e732aaSnicm 		if (s != NULL)
12652db665b3Snicm 			found = cmd_find_best_client(s);
126693e732aaSnicm 	}
12672db665b3Snicm 	if (found == NULL && item != NULL && !quiet)
1268ea0386afSnicm 		cmdq_error(item, "no current client");
12692db665b3Snicm 	log_debug("%s: no target, return %p", __func__, found);
12702db665b3Snicm 	return (found);
1271f65f2164Snicm }
12726b339e7dSnicm 
12736b339e7dSnicm /* Find the target client or report an error and return NULL. */
12746b339e7dSnicm struct client *
cmd_find_client(struct cmdq_item * item,const char * target,int quiet)12756b339e7dSnicm cmd_find_client(struct cmdq_item *item, const char *target, int quiet)
12766b339e7dSnicm {
12776b339e7dSnicm 	struct client	*c;
12786b339e7dSnicm 	char		*copy;
12796b339e7dSnicm 	size_t		 size;
12806b339e7dSnicm 
12816b339e7dSnicm 	/* A NULL argument means the current client. */
12826b339e7dSnicm 	if (target == NULL)
12836b339e7dSnicm 		return (cmd_find_current_client(item, quiet));
1284f65f2164Snicm 	copy = xstrdup(target);
1285f65f2164Snicm 
1286f65f2164Snicm 	/* Trim a single trailing colon if any. */
1287f65f2164Snicm 	size = strlen(copy);
1288f65f2164Snicm 	if (size != 0 && copy[size - 1] == ':')
1289f65f2164Snicm 		copy[size - 1] = '\0';
1290f65f2164Snicm 
1291bcdd9d70Snicm 	/* Check name and path of each client. */
1292f65f2164Snicm 	TAILQ_FOREACH(c, &clients, entry) {
1293bcdd9d70Snicm 		if (c->session == NULL)
1294f65f2164Snicm 			continue;
1295bcdd9d70Snicm 		if (strcmp(copy, c->name) == 0)
1296f65f2164Snicm 			break;
1297f65f2164Snicm 
1298bcdd9d70Snicm 		if (*c->ttyname == '\0')
1299f65f2164Snicm 			continue;
1300bcdd9d70Snicm 		if (strcmp(copy, c->ttyname) == 0)
1301bcdd9d70Snicm 			break;
1302bcdd9d70Snicm 		if (strncmp(c->ttyname, _PATH_DEV, (sizeof _PATH_DEV) - 1) != 0)
1303bcdd9d70Snicm 			continue;
1304bcdd9d70Snicm 		if (strcmp(copy, c->ttyname + (sizeof _PATH_DEV) - 1) == 0)
1305f65f2164Snicm 			break;
1306f65f2164Snicm 	}
1307f65f2164Snicm 
1308f65f2164Snicm 	/* If no client found, report an error. */
1309f65f2164Snicm 	if (c == NULL && !quiet)
1310fe57de0cSnicm 		cmdq_error(item, "can't find client: %s", copy);
1311f65f2164Snicm 
1312f65f2164Snicm 	free(copy);
13135b8ac713Snicm 	log_debug("%s: target %s, return %p", __func__, target, c);
1314f65f2164Snicm 	return (c);
1315f65f2164Snicm }
1316