1 /* $OpenBSD$ */
2 
3 /*
4  * Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/wait.h>
21 
22 #include <ctype.h>
23 #include <errno.h>
24 #include <fnmatch.h>
25 #include <libgen.h>
26 #include <math.h>
27 #include <regex.h>
28 #include <stdarg.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <time.h>
32 #include <unistd.h>
33 
34 #include "tmux.h"
35 
36 /*
37  * Build a list of key-value pairs and use them to expand #{key} entries in a
38  * string.
39  */
40 
41 struct format_expand_state;
42 
43 static char	*format_job_get(struct format_expand_state *, const char *);
44 static char	*format_expand1(struct format_expand_state *, const char *);
45 static int	 format_replace(struct format_expand_state *, const char *,
46 		     size_t, char **, size_t *, size_t *);
47 static void	 format_defaults_session(struct format_tree *,
48 		     struct session *);
49 static void	 format_defaults_client(struct format_tree *, struct client *);
50 static void	 format_defaults_winlink(struct format_tree *,
51 		     struct winlink *);
52 
53 /* Entry in format job tree. */
54 struct format_job {
55 	struct client		*client;
56 	u_int			 tag;
57 	const char		*cmd;
58 	const char		*expanded;
59 
60 	time_t			 last;
61 	char			*out;
62 	int			 updated;
63 
64 	struct job		*job;
65 	int			 status;
66 
67 	RB_ENTRY(format_job)	 entry;
68 };
69 
70 /* Format job tree. */
71 static int format_job_cmp(struct format_job *, struct format_job *);
72 static RB_HEAD(format_job_tree, format_job) format_jobs = RB_INITIALIZER();
73 RB_GENERATE_STATIC(format_job_tree, format_job, entry, format_job_cmp);
74 
75 /* Format job tree comparison function. */
76 static int
format_job_cmp(struct format_job * fj1,struct format_job * fj2)77 format_job_cmp(struct format_job *fj1, struct format_job *fj2)
78 {
79 	if (fj1->tag < fj2->tag)
80 		return (-1);
81 	if (fj1->tag > fj2->tag)
82 		return (1);
83 	return (strcmp(fj1->cmd, fj2->cmd));
84 }
85 
86 /* Format modifiers. */
87 #define FORMAT_TIMESTRING 0x1
88 #define FORMAT_BASENAME 0x2
89 #define FORMAT_DIRNAME 0x4
90 #define FORMAT_QUOTE_SHELL 0x8
91 #define FORMAT_LITERAL 0x10
92 #define FORMAT_EXPAND 0x20
93 #define FORMAT_EXPANDTIME 0x40
94 #define FORMAT_SESSIONS 0x80
95 #define FORMAT_WINDOWS 0x100
96 #define FORMAT_PANES 0x200
97 #define FORMAT_PRETTY 0x400
98 #define FORMAT_LENGTH 0x800
99 #define FORMAT_WIDTH 0x1000
100 #define FORMAT_QUOTE_STYLE 0x2000
101 #define FORMAT_WINDOW_NAME 0x4000
102 #define FORMAT_SESSION_NAME 0x8000
103 #define FORMAT_CHARACTER 0x10000
104 
105 /* Limit on recursion. */
106 #define FORMAT_LOOP_LIMIT 100
107 
108 /* Format expand flags. */
109 #define FORMAT_EXPAND_TIME 0x1
110 #define FORMAT_EXPAND_NOJOBS 0x2
111 
112 /* Entry in format tree. */
113 struct format_entry {
114 	char			*key;
115 	char			*value;
116 	time_t			 time;
117 	format_cb		 cb;
118 	RB_ENTRY(format_entry)	 entry;
119 };
120 
121 /* Format type. */
122 enum format_type {
123 	FORMAT_TYPE_UNKNOWN,
124 	FORMAT_TYPE_SESSION,
125 	FORMAT_TYPE_WINDOW,
126 	FORMAT_TYPE_PANE
127 };
128 
129 struct format_tree {
130 	enum format_type	 type;
131 
132 	struct client		*c;
133 	struct session		*s;
134 	struct winlink		*wl;
135 	struct window		*w;
136 	struct window_pane	*wp;
137 	struct paste_buffer	*pb;
138 
139 	struct cmdq_item	*item;
140 	struct client		*client;
141 	int			 flags;
142 	u_int			 tag;
143 
144 	struct mouse_event	 m;
145 
146 	RB_HEAD(format_entry_tree, format_entry) tree;
147 };
148 static int format_entry_cmp(struct format_entry *, struct format_entry *);
149 RB_GENERATE_STATIC(format_entry_tree, format_entry, entry, format_entry_cmp);
150 
151 /* Format expand state. */
152 struct format_expand_state {
153 	struct format_tree	*ft;
154 	u_int			 loop;
155 	time_t			 time;
156 	struct tm		 tm;
157 	int			 flags;
158 };
159 
160 /* Format modifier. */
161 struct format_modifier {
162 	char	  modifier[3];
163 	u_int	  size;
164 
165 	char	**argv;
166 	int	  argc;
167 };
168 
169 /* Format entry tree comparison function. */
170 static int
format_entry_cmp(struct format_entry * fe1,struct format_entry * fe2)171 format_entry_cmp(struct format_entry *fe1, struct format_entry *fe2)
172 {
173 	return (strcmp(fe1->key, fe2->key));
174 }
175 
176 /* Single-character uppercase aliases. */
177 static const char *format_upper[] = {
178 	NULL,		/* A */
179 	NULL,		/* B */
180 	NULL,		/* C */
181 	"pane_id",	/* D */
182 	NULL,		/* E */
183 	"window_flags",	/* F */
184 	NULL,		/* G */
185 	"host",		/* H */
186 	"window_index",	/* I */
187 	NULL,		/* J */
188 	NULL,		/* K */
189 	NULL,		/* L */
190 	NULL,		/* M */
191 	NULL,		/* N */
192 	NULL,		/* O */
193 	"pane_index",	/* P */
194 	NULL,		/* Q */
195 	NULL,		/* R */
196 	"session_name",	/* S */
197 	"pane_title",	/* T */
198 	NULL,		/* U */
199 	NULL,		/* V */
200 	"window_name",	/* W */
201 	NULL,		/* X */
202 	NULL,		/* Y */
203 	NULL 		/* Z */
204 };
205 
206 /* Single-character lowercase aliases. */
207 static const char *format_lower[] = {
208 	NULL,		/* a */
209 	NULL,		/* b */
210 	NULL,		/* c */
211 	NULL,		/* d */
212 	NULL,		/* e */
213 	NULL,		/* f */
214 	NULL,		/* g */
215 	"host_short",	/* h */
216 	NULL,		/* i */
217 	NULL,		/* j */
218 	NULL,		/* k */
219 	NULL,		/* l */
220 	NULL,		/* m */
221 	NULL,		/* n */
222 	NULL,		/* o */
223 	NULL,		/* p */
224 	NULL,		/* q */
225 	NULL,		/* r */
226 	NULL,		/* s */
227 	NULL,		/* t */
228 	NULL,		/* u */
229 	NULL,		/* v */
230 	NULL,		/* w */
231 	NULL,		/* x */
232 	NULL,		/* y */
233 	NULL		/* z */
234 };
235 
236 /* Is logging enabled? */
237 static inline int
format_logging(struct format_tree * ft)238 format_logging(struct format_tree *ft)
239 {
240 	return (log_get_level() != 0 || (ft->flags & FORMAT_VERBOSE));
241 }
242 
243 /* Log a message if verbose. */
244 static void printflike(3, 4)
format_log1(struct format_expand_state * es,const char * from,const char * fmt,...)245 format_log1(struct format_expand_state *es, const char *from, const char *fmt,
246     ...)
247 {
248 	struct format_tree	*ft = es->ft;
249 	va_list			 ap;
250 	char			*s;
251 	static const char	 spaces[] = "          ";
252 
253 	if (!format_logging(ft))
254 		return;
255 
256 	va_start(ap, fmt);
257 	xvasprintf(&s, fmt, ap);
258 	va_end(ap);
259 
260 	log_debug("%s: %s", from, s);
261 	if (ft->item != NULL && (ft->flags & FORMAT_VERBOSE))
262 		cmdq_print(ft->item, "#%.*s%s", es->loop, spaces, s);
263 
264 	free(s);
265 }
266 #define format_log(es, fmt, ...) format_log1(es, __func__, fmt, ##__VA_ARGS__)
267 
268 /* Copy expand state. */
269 static void
format_copy_state(struct format_expand_state * to,struct format_expand_state * from,int flags)270 format_copy_state(struct format_expand_state *to,
271     struct format_expand_state *from, int flags)
272 {
273 	to->ft = from->ft;
274 	to->loop = from->loop;
275 	to->time = from->time;
276 	memcpy(&to->tm, &from->tm, sizeof to->tm);
277 	to->flags = from->flags|flags;
278 }
279 
280 /* Format job update callback. */
281 static void
format_job_update(struct job * job)282 format_job_update(struct job *job)
283 {
284 	struct format_job	*fj = job_get_data(job);
285 	struct evbuffer		*evb = job_get_event(job)->input;
286 	char			*line = NULL, *next;
287 	time_t			 t;
288 
289 	while ((next = evbuffer_readline(evb)) != NULL) {
290 		free(line);
291 		line = next;
292 	}
293 	if (line == NULL)
294 		return;
295 	fj->updated = 1;
296 
297 	free(fj->out);
298 	fj->out = line;
299 
300 	log_debug("%s: %p %s: %s", __func__, fj, fj->cmd, fj->out);
301 
302 	t = time(NULL);
303 	if (fj->status && fj->last != t) {
304 		if (fj->client != NULL)
305 			server_status_client(fj->client);
306 		fj->last = t;
307 	}
308 }
309 
310 /* Format job complete callback. */
311 static void
format_job_complete(struct job * job)312 format_job_complete(struct job *job)
313 {
314 	struct format_job	*fj = job_get_data(job);
315 	struct evbuffer		*evb = job_get_event(job)->input;
316 	char			*line, *buf;
317 	size_t			 len;
318 
319 	fj->job = NULL;
320 
321 	buf = NULL;
322 	if ((line = evbuffer_readline(evb)) == NULL) {
323 		len = EVBUFFER_LENGTH(evb);
324 		buf = xmalloc(len + 1);
325 		if (len != 0)
326 			memcpy(buf, EVBUFFER_DATA(evb), len);
327 		buf[len] = '\0';
328 	} else
329 		buf = line;
330 
331 	log_debug("%s: %p %s: %s", __func__, fj, fj->cmd, buf);
332 
333 	if (*buf != '\0' || !fj->updated) {
334 		free(fj->out);
335 		fj->out = buf;
336 	} else
337 		free(buf);
338 
339 	if (fj->status) {
340 		if (fj->client != NULL)
341 			server_status_client(fj->client);
342 		fj->status = 0;
343 	}
344 }
345 
346 /* Find a job. */
347 static char *
format_job_get(struct format_expand_state * es,const char * cmd)348 format_job_get(struct format_expand_state *es, const char *cmd)
349 {
350 	struct format_tree		*ft = es->ft;
351 	struct format_job_tree		*jobs;
352 	struct format_job		 fj0, *fj;
353 	time_t				 t;
354 	char				*expanded;
355 	int				 force;
356 	struct format_expand_state	 next;
357 
358 	if (ft->client == NULL)
359 		jobs = &format_jobs;
360 	else if (ft->client->jobs != NULL)
361 		jobs = ft->client->jobs;
362 	else {
363 		jobs = ft->client->jobs = xmalloc(sizeof *ft->client->jobs);
364 		RB_INIT(jobs);
365 	}
366 
367 	fj0.tag = ft->tag;
368 	fj0.cmd = cmd;
369 	if ((fj = RB_FIND(format_job_tree, jobs, &fj0)) == NULL) {
370 		fj = xcalloc(1, sizeof *fj);
371 		fj->client = ft->client;
372 		fj->tag = ft->tag;
373 		fj->cmd = xstrdup(cmd);
374 		fj->expanded = NULL;
375 
376 		xasprintf(&fj->out, "<'%s' not ready>", fj->cmd);
377 
378 		RB_INSERT(format_job_tree, jobs, fj);
379 	}
380 
381 	format_copy_state(&next, es, FORMAT_EXPAND_NOJOBS);
382 	next.flags &= ~FORMAT_EXPAND_TIME;
383 
384 	expanded = format_expand1(&next, cmd);
385 	if (fj->expanded == NULL || strcmp(expanded, fj->expanded) != 0) {
386 		free((void *)fj->expanded);
387 		fj->expanded = xstrdup(expanded);
388 		force = 1;
389 	} else
390 		force = (ft->flags & FORMAT_FORCE);
391 
392 	t = time(NULL);
393 	if (force && fj->job != NULL)
394 	       job_free(fj->job);
395 	if (force || (fj->job == NULL && fj->last != t)) {
396 		fj->job = job_run(expanded, 0, NULL, NULL,
397 		    server_client_get_cwd(ft->client, NULL), format_job_update,
398 		    format_job_complete, NULL, fj, JOB_NOWAIT, -1, -1);
399 		if (fj->job == NULL) {
400 			free(fj->out);
401 			xasprintf(&fj->out, "<'%s' didn't start>", fj->cmd);
402 		}
403 		fj->last = t;
404 		fj->updated = 0;
405 	}
406 	free(expanded);
407 
408 	if (ft->flags & FORMAT_STATUS)
409 		fj->status = 1;
410 	return (format_expand1(&next, fj->out));
411 }
412 
413 /* Remove old jobs. */
414 static void
format_job_tidy(struct format_job_tree * jobs,int force)415 format_job_tidy(struct format_job_tree *jobs, int force)
416 {
417 	struct format_job	*fj, *fj1;
418 	time_t			 now;
419 
420 	now = time(NULL);
421 	RB_FOREACH_SAFE(fj, format_job_tree, jobs, fj1) {
422 		if (!force && (fj->last > now || now - fj->last < 3600))
423 			continue;
424 		RB_REMOVE(format_job_tree, jobs, fj);
425 
426 		log_debug("%s: %s", __func__, fj->cmd);
427 
428 		if (fj->job != NULL)
429 			job_free(fj->job);
430 
431 		free((void *)fj->expanded);
432 		free((void *)fj->cmd);
433 		free(fj->out);
434 
435 		free(fj);
436 	}
437 }
438 
439 /* Tidy old jobs for all clients. */
440 void
format_tidy_jobs(void)441 format_tidy_jobs(void)
442 {
443 	struct client	*c;
444 
445 	format_job_tidy(&format_jobs, 0);
446 	TAILQ_FOREACH(c, &clients, entry) {
447 		if (c->jobs != NULL)
448 			format_job_tidy(c->jobs, 0);
449 	}
450 }
451 
452 /* Remove old jobs for client. */
453 void
format_lost_client(struct client * c)454 format_lost_client(struct client *c)
455 {
456 	if (c->jobs != NULL)
457 		format_job_tidy(c->jobs, 1);
458 	free(c->jobs);
459 }
460 
461 /* Wrapper for asprintf. */
462 static char * printflike(1, 2)
format_printf(const char * fmt,...)463 format_printf(const char *fmt, ...)
464 {
465 	va_list	 ap;
466 	char	*s;
467 
468 	va_start(ap, fmt);
469 	xvasprintf(&s, fmt, ap);
470 	va_end(ap);
471 	return (s);
472 }
473 
474 /* Callback for host. */
475 static void *
format_cb_host(__unused struct format_tree * ft)476 format_cb_host(__unused struct format_tree *ft)
477 {
478 	char host[HOST_NAME_MAX + 1];
479 
480 	if (gethostname(host, sizeof host) != 0)
481 		return (xstrdup(""));
482 	return (xstrdup(host));
483 }
484 
485 /* Callback for host_short. */
486 static void *
format_cb_host_short(__unused struct format_tree * ft)487 format_cb_host_short(__unused struct format_tree *ft)
488 {
489 	char host[HOST_NAME_MAX + 1], *cp;
490 
491 	if (gethostname(host, sizeof host) != 0)
492 		return (xstrdup(""));
493 	if ((cp = strchr(host, '.')) != NULL)
494 		*cp = '\0';
495 	return (xstrdup(host));
496 }
497 
498 /* Callback for pid. */
499 static void *
format_cb_pid(__unused struct format_tree * ft)500 format_cb_pid(__unused struct format_tree *ft)
501 {
502 	char	*value;
503 
504 	xasprintf(&value, "%ld", (long)getpid());
505 	return (value);
506 }
507 
508 /* Callback for session_attached_list. */
509 static void *
format_cb_session_attached_list(struct format_tree * ft)510 format_cb_session_attached_list(struct format_tree *ft)
511 {
512 	struct session	*s = ft->s;
513 	struct client	*loop;
514 	struct evbuffer	*buffer;
515 	int		 size;
516 	char		*value = NULL;
517 
518 	if (s == NULL)
519 		return (NULL);
520 
521 	buffer = evbuffer_new();
522 	if (buffer == NULL)
523 		fatalx("out of memory");
524 
525 	TAILQ_FOREACH(loop, &clients, entry) {
526 		if (loop->session == s) {
527 			if (EVBUFFER_LENGTH(buffer) > 0)
528 				evbuffer_add(buffer, ",", 1);
529 			evbuffer_add_printf(buffer, "%s", loop->name);
530 		}
531 	}
532 
533 	if ((size = EVBUFFER_LENGTH(buffer)) != 0)
534 		xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer));
535 	evbuffer_free(buffer);
536 	return (value);
537 }
538 
539 /* Callback for session_alerts. */
540 static void *
format_cb_session_alerts(struct format_tree * ft)541 format_cb_session_alerts(struct format_tree *ft)
542 {
543 	struct session	*s = ft->s;
544 	struct winlink	*wl;
545 	char		 alerts[1024], tmp[16];
546 
547 	if (s == NULL)
548 		return (NULL);
549 
550 	*alerts = '\0';
551 	RB_FOREACH(wl, winlinks, &s->windows) {
552 		if ((wl->flags & WINLINK_ALERTFLAGS) == 0)
553 			continue;
554 		xsnprintf(tmp, sizeof tmp, "%u", wl->idx);
555 
556 		if (*alerts != '\0')
557 			strlcat(alerts, ",", sizeof alerts);
558 		strlcat(alerts, tmp, sizeof alerts);
559 		if (wl->flags & WINLINK_ACTIVITY)
560 			strlcat(alerts, "#", sizeof alerts);
561 		if (wl->flags & WINLINK_BELL)
562 			strlcat(alerts, "!", sizeof alerts);
563 		if (wl->flags & WINLINK_SILENCE)
564 			strlcat(alerts, "~", sizeof alerts);
565 	}
566 	return (xstrdup(alerts));
567 }
568 
569 /* Callback for session_stack. */
570 static void *
format_cb_session_stack(struct format_tree * ft)571 format_cb_session_stack(struct format_tree *ft)
572 {
573 	struct session	*s = ft->s;
574 	struct winlink	*wl;
575 	char		 result[1024], tmp[16];
576 
577 	if (s == NULL)
578 		return (NULL);
579 
580 	xsnprintf(result, sizeof result, "%u", s->curw->idx);
581 	TAILQ_FOREACH(wl, &s->lastw, sentry) {
582 		xsnprintf(tmp, sizeof tmp, "%u", wl->idx);
583 
584 		if (*result != '\0')
585 			strlcat(result, ",", sizeof result);
586 		strlcat(result, tmp, sizeof result);
587 	}
588 	return (xstrdup(result));
589 }
590 
591 /* Callback for window_stack_index. */
592 static void *
format_cb_window_stack_index(struct format_tree * ft)593 format_cb_window_stack_index(struct format_tree *ft)
594 {
595 	struct session	*s;
596 	struct winlink	*wl;
597 	u_int		 idx;
598 	char		*value = NULL;
599 
600 	if (ft->wl == NULL)
601 		return (NULL);
602 	s = ft->wl->session;
603 
604 	idx = 0;
605 	TAILQ_FOREACH(wl, &s->lastw, sentry) {
606 		idx++;
607 		if (wl == ft->wl)
608 			break;
609 	}
610 	if (wl == NULL)
611 		return (xstrdup("0"));
612 	xasprintf(&value, "%u", idx);
613 	return (value);
614 }
615 
616 /* Callback for window_linked_sessions_list. */
617 static void *
format_cb_window_linked_sessions_list(struct format_tree * ft)618 format_cb_window_linked_sessions_list(struct format_tree *ft)
619 {
620 	struct window	*w;
621 	struct winlink	*wl;
622 	struct evbuffer	*buffer;
623 	int		 size;
624 	char		*value = NULL;
625 
626 	if (ft->wl == NULL)
627 		return (NULL);
628 	w = ft->wl->window;
629 
630 	buffer = evbuffer_new();
631 	if (buffer == NULL)
632 		fatalx("out of memory");
633 
634 	TAILQ_FOREACH(wl, &w->winlinks, wentry) {
635 		if (EVBUFFER_LENGTH(buffer) > 0)
636 			evbuffer_add(buffer, ",", 1);
637 		evbuffer_add_printf(buffer, "%s", wl->session->name);
638 	}
639 
640 	if ((size = EVBUFFER_LENGTH(buffer)) != 0)
641 		xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer));
642 	evbuffer_free(buffer);
643 	return (value);
644 }
645 
646 /* Callback for window_active_sessions. */
647 static void *
format_cb_window_active_sessions(struct format_tree * ft)648 format_cb_window_active_sessions(struct format_tree *ft)
649 {
650 	struct window	*w;
651 	struct winlink	*wl;
652 	u_int		 n = 0;
653 	char		*value;
654 
655 	if (ft->wl == NULL)
656 		return (NULL);
657 	w = ft->wl->window;
658 
659 	TAILQ_FOREACH(wl, &w->winlinks, wentry) {
660 		if (wl->session->curw == wl)
661 			n++;
662 	}
663 
664 	xasprintf(&value, "%u", n);
665 	return (value);
666 }
667 
668 /* Callback for window_active_sessions_list. */
669 static void *
format_cb_window_active_sessions_list(struct format_tree * ft)670 format_cb_window_active_sessions_list(struct format_tree *ft)
671 {
672 	struct window	*w;
673 	struct winlink	*wl;
674 	struct evbuffer	*buffer;
675 	int		 size;
676 	char		*value = NULL;
677 
678 	if (ft->wl == NULL)
679 		return (NULL);
680 	w = ft->wl->window;
681 
682 	buffer = evbuffer_new();
683 	if (buffer == NULL)
684 		fatalx("out of memory");
685 
686 	TAILQ_FOREACH(wl, &w->winlinks, wentry) {
687 		if (wl->session->curw == wl) {
688 			if (EVBUFFER_LENGTH(buffer) > 0)
689 				evbuffer_add(buffer, ",", 1);
690 			evbuffer_add_printf(buffer, "%s", wl->session->name);
691 		}
692 	}
693 
694 	if ((size = EVBUFFER_LENGTH(buffer)) != 0)
695 		xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer));
696 	evbuffer_free(buffer);
697 	return (value);
698 }
699 
700 /* Callback for window_active_clients. */
701 static void *
format_cb_window_active_clients(struct format_tree * ft)702 format_cb_window_active_clients(struct format_tree *ft)
703 {
704 	struct window	*w;
705 	struct client	*loop;
706 	struct session	*client_session;
707 	u_int		 n = 0;
708 	char		*value;
709 
710 	if (ft->wl == NULL)
711 		return (NULL);
712 	w = ft->wl->window;
713 
714 	TAILQ_FOREACH(loop, &clients, entry) {
715 		client_session = loop->session;
716 		if (client_session == NULL)
717 			continue;
718 
719 		if (w == client_session->curw->window)
720 			n++;
721 	}
722 
723 	xasprintf(&value, "%u", n);
724 	return (value);
725 }
726 
727 /* Callback for window_active_clients_list. */
728 static void *
format_cb_window_active_clients_list(struct format_tree * ft)729 format_cb_window_active_clients_list(struct format_tree *ft)
730 {
731 	struct window	*w;
732 	struct client	*loop;
733 	struct session	*client_session;
734 	struct evbuffer	*buffer;
735 	int		 size;
736 	char		*value = NULL;
737 
738 	if (ft->wl == NULL)
739 		return (NULL);
740 	w = ft->wl->window;
741 
742 	buffer = evbuffer_new();
743 	if (buffer == NULL)
744 		fatalx("out of memory");
745 
746 	TAILQ_FOREACH(loop, &clients, entry) {
747 		client_session = loop->session;
748 		if (client_session == NULL)
749 			continue;
750 
751 		if (w == client_session->curw->window) {
752 			if (EVBUFFER_LENGTH(buffer) > 0)
753 				evbuffer_add(buffer, ",", 1);
754 			evbuffer_add_printf(buffer, "%s", loop->name);
755 		}
756 	}
757 
758 	if ((size = EVBUFFER_LENGTH(buffer)) != 0)
759 		xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer));
760 	evbuffer_free(buffer);
761 	return (value);
762 }
763 
764 /* Callback for window_layout. */
765 static void *
format_cb_window_layout(struct format_tree * ft)766 format_cb_window_layout(struct format_tree *ft)
767 {
768 	struct window	*w = ft->w;
769 
770 	if (w == NULL)
771 		return (NULL);
772 
773 	if (w->saved_layout_root != NULL)
774 		return (layout_dump(w->saved_layout_root));
775 	return (layout_dump(w->layout_root));
776 }
777 
778 /* Callback for window_visible_layout. */
779 static void *
format_cb_window_visible_layout(struct format_tree * ft)780 format_cb_window_visible_layout(struct format_tree *ft)
781 {
782 	struct window	*w = ft->w;
783 
784 	if (w == NULL)
785 		return (NULL);
786 
787 	return (layout_dump(w->layout_root));
788 }
789 
790 /* Callback for pane_start_command. */
791 static void *
format_cb_start_command(struct format_tree * ft)792 format_cb_start_command(struct format_tree *ft)
793 {
794 	struct window_pane	*wp = ft->wp;
795 
796 	if (wp == NULL)
797 		return (NULL);
798 
799 	return (cmd_stringify_argv(wp->argc, wp->argv));
800 }
801 
802 /* Callback for pane_current_command. */
803 static void *
format_cb_current_command(struct format_tree * ft)804 format_cb_current_command(struct format_tree *ft)
805 {
806 	struct window_pane	*wp = ft->wp;
807 	char			*cmd, *value;
808 
809 	if (wp == NULL || wp->shell == NULL)
810 		return (NULL);
811 
812 	cmd = osdep_get_name(wp->fd, wp->tty);
813 	if (cmd == NULL || *cmd == '\0') {
814 		free(cmd);
815 		cmd = cmd_stringify_argv(wp->argc, wp->argv);
816 		if (cmd == NULL || *cmd == '\0') {
817 			free(cmd);
818 			cmd = xstrdup(wp->shell);
819 		}
820 	}
821 	value = parse_window_name(cmd);
822 	free(cmd);
823 	return (value);
824 }
825 
826 /* Callback for pane_current_path. */
827 static void *
format_cb_current_path(struct format_tree * ft)828 format_cb_current_path(struct format_tree *ft)
829 {
830 	struct window_pane	*wp = ft->wp;
831 	char			*cwd;
832 
833 	if (wp == NULL)
834 		return (NULL);
835 
836 	cwd = osdep_get_cwd(wp->fd);
837 	if (cwd == NULL)
838 		return (NULL);
839 	return (xstrdup(cwd));
840 }
841 
842 /* Callback for history_bytes. */
843 static void *
format_cb_history_bytes(struct format_tree * ft)844 format_cb_history_bytes(struct format_tree *ft)
845 {
846 	struct window_pane	*wp = ft->wp;
847 	struct grid		*gd;
848 	struct grid_line	*gl;
849 	size_t		         size = 0;
850 	u_int			 i;
851 	char			*value;
852 
853 	if (wp == NULL)
854 		return (NULL);
855 	gd = wp->base.grid;
856 
857 	for (i = 0; i < gd->hsize + gd->sy; i++) {
858 		gl = grid_get_line(gd, i);
859 		size += gl->cellsize * sizeof *gl->celldata;
860 		size += gl->extdsize * sizeof *gl->extddata;
861 	}
862 	size += (gd->hsize + gd->sy) * sizeof *gl;
863 
864 	xasprintf(&value, "%zu", size);
865 	return (value);
866 }
867 
868 /* Callback for history_all_bytes. */
869 static void *
format_cb_history_all_bytes(struct format_tree * ft)870 format_cb_history_all_bytes(struct format_tree *ft)
871 {
872 	struct window_pane	*wp = ft->wp;
873 	struct grid		*gd;
874 	struct grid_line	*gl;
875 	u_int			 i, lines, cells = 0, extended_cells = 0;
876 	char			*value;
877 
878 	if (wp == NULL)
879 		return (NULL);
880 	gd = wp->base.grid;
881 
882 	lines = gd->hsize + gd->sy;
883 	for (i = 0; i < lines; i++) {
884 		gl = grid_get_line(gd, i);
885 		cells += gl->cellsize;
886 		extended_cells += gl->extdsize;
887 	}
888 
889 	xasprintf(&value, "%u,%zu,%u,%zu,%u,%zu", lines,
890 	    lines * sizeof *gl, cells, cells * sizeof *gl->celldata,
891 	    extended_cells, extended_cells * sizeof *gl->extddata);
892 	return (value);
893 }
894 
895 /* Callback for pane_tabs. */
896 static void *
format_cb_pane_tabs(struct format_tree * ft)897 format_cb_pane_tabs(struct format_tree *ft)
898 {
899 	struct window_pane	*wp = ft->wp;
900 	struct evbuffer		*buffer;
901 	u_int			 i;
902 	int			 size;
903 	char			*value = NULL;
904 
905 	if (wp == NULL)
906 		return (NULL);
907 
908 	buffer = evbuffer_new();
909 	if (buffer == NULL)
910 		fatalx("out of memory");
911 	for (i = 0; i < wp->base.grid->sx; i++) {
912 		if (!bit_test(wp->base.tabs, i))
913 			continue;
914 
915 		if (EVBUFFER_LENGTH(buffer) > 0)
916 			evbuffer_add(buffer, ",", 1);
917 		evbuffer_add_printf(buffer, "%u", i);
918 	}
919 	if ((size = EVBUFFER_LENGTH(buffer)) != 0)
920 		xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer));
921 	evbuffer_free(buffer);
922 	return (value);
923 }
924 
925 /* Callback for pane_fg. */
926 static void *
format_cb_pane_fg(struct format_tree * ft)927 format_cb_pane_fg(struct format_tree *ft)
928 {
929 	struct window_pane	*wp = ft->wp;
930 	struct grid_cell	 gc;
931 
932 	tty_default_colours(&gc, wp);
933 	return (xstrdup(colour_tostring(gc.fg)));
934 }
935 
936 /* Callback for pane_bg. */
937 static void *
format_cb_pane_bg(struct format_tree * ft)938 format_cb_pane_bg(struct format_tree *ft)
939 {
940 	struct window_pane	*wp = ft->wp;
941 	struct grid_cell	 gc;
942 
943 	tty_default_colours(&gc, wp);
944 	return (xstrdup(colour_tostring(gc.bg)));
945 }
946 
947 /* Callback for session_group_list. */
948 static void *
format_cb_session_group_list(struct format_tree * ft)949 format_cb_session_group_list(struct format_tree *ft)
950 {
951 	struct session		*s = ft->s;
952 	struct session_group	*sg;
953 	struct session		*loop;
954 	struct evbuffer		*buffer;
955 	int			 size;
956 	char			*value = NULL;
957 
958 	if (s == NULL)
959 		return (NULL);
960 	sg = session_group_contains(s);
961 	if (sg == NULL)
962 		return (NULL);
963 
964 	buffer = evbuffer_new();
965 	if (buffer == NULL)
966 		fatalx("out of memory");
967 
968 	TAILQ_FOREACH(loop, &sg->sessions, gentry) {
969 		if (EVBUFFER_LENGTH(buffer) > 0)
970 			evbuffer_add(buffer, ",", 1);
971 		evbuffer_add_printf(buffer, "%s", loop->name);
972 	}
973 
974 	if ((size = EVBUFFER_LENGTH(buffer)) != 0)
975 		xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer));
976 	evbuffer_free(buffer);
977 	return (value);
978 }
979 
980 /* Callback for session_group_attached_list. */
981 static void *
format_cb_session_group_attached_list(struct format_tree * ft)982 format_cb_session_group_attached_list(struct format_tree *ft)
983 {
984 	struct session		*s = ft->s, *client_session, *session_loop;
985 	struct session_group	*sg;
986 	struct client		*loop;
987 	struct evbuffer		*buffer;
988 	int			 size;
989 	char			*value = NULL;
990 
991 	if (s == NULL)
992 		return (NULL);
993 	sg = session_group_contains(s);
994 	if (sg == NULL)
995 		return (NULL);
996 
997 	buffer = evbuffer_new();
998 	if (buffer == NULL)
999 		fatalx("out of memory");
1000 
1001 	TAILQ_FOREACH(loop, &clients, entry) {
1002 		client_session = loop->session;
1003 		if (client_session == NULL)
1004 			continue;
1005 		TAILQ_FOREACH(session_loop, &sg->sessions, gentry) {
1006 			if (session_loop == client_session){
1007 				if (EVBUFFER_LENGTH(buffer) > 0)
1008 					evbuffer_add(buffer, ",", 1);
1009 				evbuffer_add_printf(buffer, "%s", loop->name);
1010 			}
1011 		}
1012 	}
1013 
1014 	if ((size = EVBUFFER_LENGTH(buffer)) != 0)
1015 		xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer));
1016 	evbuffer_free(buffer);
1017 	return (value);
1018 }
1019 
1020 /* Callback for pane_in_mode. */
1021 static void *
format_cb_pane_in_mode(struct format_tree * ft)1022 format_cb_pane_in_mode(struct format_tree *ft)
1023 {
1024 	struct window_pane		*wp = ft->wp;
1025 	u_int				 n = 0;
1026 	struct window_mode_entry	*wme;
1027 	char				*value;
1028 
1029 	if (wp == NULL)
1030 		return (NULL);
1031 
1032 	TAILQ_FOREACH(wme, &wp->modes, entry)
1033 		n++;
1034 	xasprintf(&value, "%u", n);
1035 	return (value);
1036 }
1037 
1038 /* Callback for pane_at_top. */
1039 static void *
format_cb_pane_at_top(struct format_tree * ft)1040 format_cb_pane_at_top(struct format_tree *ft)
1041 {
1042 	struct window_pane	*wp = ft->wp;
1043 	struct window		*w;
1044 	int			 status, flag;
1045 	char			*value;
1046 
1047 	if (wp == NULL)
1048 		return (NULL);
1049 	w = wp->window;
1050 
1051 	status = options_get_number(w->options, "pane-border-status");
1052 	if (status == PANE_STATUS_TOP)
1053 		flag = (wp->yoff == 1);
1054 	else
1055 		flag = (wp->yoff == 0);
1056 	xasprintf(&value, "%d", flag);
1057 	return (value);
1058 }
1059 
1060 /* Callback for pane_at_bottom. */
1061 static void *
format_cb_pane_at_bottom(struct format_tree * ft)1062 format_cb_pane_at_bottom(struct format_tree *ft)
1063 {
1064 	struct window_pane	*wp = ft->wp;
1065 	struct window		*w;
1066 	int			 status, flag;
1067 	char			*value;
1068 
1069 	if (wp == NULL)
1070 		return (NULL);
1071 	w = wp->window;
1072 
1073 	status = options_get_number(w->options, "pane-border-status");
1074 	if (status == PANE_STATUS_BOTTOM)
1075 		flag = (wp->yoff + wp->sy == w->sy - 1);
1076 	else
1077 		flag = (wp->yoff + wp->sy == w->sy);
1078 	xasprintf(&value, "%d", flag);
1079 	return (value);
1080 }
1081 
1082 /* Callback for cursor_character. */
1083 static void *
format_cb_cursor_character(struct format_tree * ft)1084 format_cb_cursor_character(struct format_tree *ft)
1085 {
1086 	struct window_pane	*wp = ft->wp;
1087 	struct grid_cell	 gc;
1088 	char			*value = NULL;
1089 
1090 	if (wp == NULL)
1091 		return (NULL);
1092 
1093 	grid_view_get_cell(wp->base.grid, wp->base.cx, wp->base.cy, &gc);
1094 	if (~gc.flags & GRID_FLAG_PADDING)
1095 		xasprintf(&value, "%.*s", (int)gc.data.size, gc.data.data);
1096 	return (value);
1097 }
1098 
1099 /* Callback for mouse_word. */
1100 static void *
format_cb_mouse_word(struct format_tree * ft)1101 format_cb_mouse_word(struct format_tree *ft)
1102 {
1103 	struct window_pane	*wp;
1104 	struct grid		*gd;
1105 	u_int			 x, y;
1106 	char			*s;
1107 
1108 	if (!ft->m.valid)
1109 		return (NULL);
1110 	wp = cmd_mouse_pane(&ft->m, NULL, NULL);
1111 	if (wp == NULL)
1112 		return (NULL);
1113 	if (cmd_mouse_at(wp, &ft->m, &x, &y, 0) != 0)
1114 		return (NULL);
1115 
1116 	if (!TAILQ_EMPTY(&wp->modes)) {
1117 		if (TAILQ_FIRST(&wp->modes)->mode == &window_copy_mode ||
1118 		    TAILQ_FIRST(&wp->modes)->mode == &window_view_mode)
1119 			return (s = window_copy_get_word(wp, x, y));
1120 		return (NULL);
1121 	}
1122 	gd = wp->base.grid;
1123 	return (format_grid_word(gd, x, gd->hsize + y));
1124 }
1125 
1126 /* Callback for mouse_line. */
1127 static void *
format_cb_mouse_line(struct format_tree * ft)1128 format_cb_mouse_line(struct format_tree *ft)
1129 {
1130 	struct window_pane	*wp;
1131 	struct grid		*gd;
1132 	u_int			 x, y;
1133 
1134 	if (!ft->m.valid)
1135 		return (NULL);
1136 	wp = cmd_mouse_pane(&ft->m, NULL, NULL);
1137 	if (wp == NULL)
1138 		return (NULL);
1139 	if (cmd_mouse_at(wp, &ft->m, &x, &y, 0) != 0)
1140 		return (NULL);
1141 
1142 	if (!TAILQ_EMPTY(&wp->modes)) {
1143 		if (TAILQ_FIRST(&wp->modes)->mode == &window_copy_mode ||
1144 		    TAILQ_FIRST(&wp->modes)->mode == &window_view_mode)
1145 			return (window_copy_get_line(wp, y));
1146 		return (NULL);
1147 	}
1148 	gd = wp->base.grid;
1149 	return (format_grid_line(gd, gd->hsize + y));
1150 }
1151 
1152 /* Callback for alternate_on. */
1153 static void *
format_cb_alternate_on(struct format_tree * ft)1154 format_cb_alternate_on(struct format_tree *ft)
1155 {
1156 	if (ft->wp != NULL) {
1157 		if (ft->wp->base.saved_grid != NULL)
1158 			return (xstrdup("1"));
1159 		return (xstrdup("0"));
1160 	}
1161 	return (NULL);
1162 }
1163 
1164 /* Callback for alternate_saved_x. */
1165 static void *
format_cb_alternate_saved_x(struct format_tree * ft)1166 format_cb_alternate_saved_x(struct format_tree *ft)
1167 {
1168 	if (ft->wp != NULL)
1169 		return (format_printf("%u", ft->wp->base.saved_cx));
1170 	return (NULL);
1171 }
1172 
1173 /* Callback for alternate_saved_y. */
1174 static void *
format_cb_alternate_saved_y(struct format_tree * ft)1175 format_cb_alternate_saved_y(struct format_tree *ft)
1176 {
1177 	if (ft->wp != NULL)
1178 		return (format_printf("%u", ft->wp->base.saved_cy));
1179 	return (NULL);
1180 }
1181 
1182 /* Callback for buffer_name. */
1183 static void *
format_cb_buffer_name(struct format_tree * ft)1184 format_cb_buffer_name(struct format_tree *ft)
1185 {
1186 	if (ft->pb != NULL)
1187 		return (xstrdup(paste_buffer_name(ft->pb)));
1188 	return (NULL);
1189 }
1190 
1191 /* Callback for buffer_sample. */
1192 static void *
format_cb_buffer_sample(struct format_tree * ft)1193 format_cb_buffer_sample(struct format_tree *ft)
1194 {
1195 	if (ft->pb != NULL)
1196 		return (paste_make_sample(ft->pb));
1197 	return (NULL);
1198 }
1199 
1200 /* Callback for buffer_size. */
1201 static void *
format_cb_buffer_size(struct format_tree * ft)1202 format_cb_buffer_size(struct format_tree *ft)
1203 {
1204 	size_t	size;
1205 
1206 	if (ft->pb != NULL) {
1207 		paste_buffer_data(ft->pb, &size);
1208 		return (format_printf("%zu", size));
1209 	}
1210 	return (NULL);
1211 }
1212 
1213 /* Callback for client_cell_height. */
1214 static void *
format_cb_client_cell_height(struct format_tree * ft)1215 format_cb_client_cell_height(struct format_tree *ft)
1216 {
1217 	if (ft->c != NULL && (ft->c->tty.flags & TTY_STARTED))
1218 		return (format_printf("%u", ft->c->tty.ypixel));
1219 	return (NULL);
1220 }
1221 
1222 /* Callback for client_cell_width. */
1223 static void *
format_cb_client_cell_width(struct format_tree * ft)1224 format_cb_client_cell_width(struct format_tree *ft)
1225 {
1226 	if (ft->c != NULL && (ft->c->tty.flags & TTY_STARTED))
1227 		return (format_printf("%u", ft->c->tty.xpixel));
1228 	return (NULL);
1229 }
1230 
1231 /* Callback for client_control_mode. */
1232 static void *
format_cb_client_control_mode(struct format_tree * ft)1233 format_cb_client_control_mode(struct format_tree *ft)
1234 {
1235 	if (ft->c != NULL) {
1236 		if (ft->c->flags & CLIENT_CONTROL)
1237 			return (xstrdup("1"));
1238 		return (xstrdup("0"));
1239 	}
1240 	return (NULL);
1241 }
1242 
1243 /* Callback for client_discarded. */
1244 static void *
format_cb_client_discarded(struct format_tree * ft)1245 format_cb_client_discarded(struct format_tree *ft)
1246 {
1247 	if (ft->c != NULL)
1248 		return (format_printf("%zu", ft->c->discarded));
1249 	return (NULL);
1250 }
1251 
1252 /* Callback for client_flags. */
1253 static void *
format_cb_client_flags(struct format_tree * ft)1254 format_cb_client_flags(struct format_tree *ft)
1255 {
1256 	if (ft->c != NULL)
1257 		return (xstrdup(server_client_get_flags(ft->c)));
1258 	return (NULL);
1259 }
1260 
1261 /* Callback for client_height. */
1262 static void *
format_cb_client_height(struct format_tree * ft)1263 format_cb_client_height(struct format_tree *ft)
1264 {
1265 	if (ft->c != NULL && (ft->c->tty.flags & TTY_STARTED))
1266 		return (format_printf("%u", ft->c->tty.sy));
1267 	return (NULL);
1268 }
1269 
1270 /* Callback for client_key_table. */
1271 static void *
format_cb_client_key_table(struct format_tree * ft)1272 format_cb_client_key_table(struct format_tree *ft)
1273 {
1274 	if (ft->c != NULL)
1275 		return (xstrdup(ft->c->keytable->name));
1276 	return (NULL);
1277 }
1278 
1279 /* Callback for client_last_session. */
1280 static void *
format_cb_client_last_session(struct format_tree * ft)1281 format_cb_client_last_session(struct format_tree *ft)
1282 {
1283 	if (ft->c != NULL &&
1284 	    ft->c->last_session != NULL &&
1285 	    session_alive(ft->c->last_session))
1286 		return (xstrdup(ft->c->last_session->name));
1287 	return (NULL);
1288 }
1289 
1290 /* Callback for client_name. */
1291 static void *
format_cb_client_name(struct format_tree * ft)1292 format_cb_client_name(struct format_tree *ft)
1293 {
1294 	if (ft->c != NULL)
1295 		return (xstrdup(ft->c->name));
1296 	return (NULL);
1297 }
1298 
1299 /* Callback for client_pid. */
1300 static void *
format_cb_client_pid(struct format_tree * ft)1301 format_cb_client_pid(struct format_tree *ft)
1302 {
1303 	if (ft->c != NULL)
1304 		return (format_printf("%ld", (long)ft->c->pid));
1305 	return (NULL);
1306 }
1307 
1308 /* Callback for client_prefix. */
1309 static void *
format_cb_client_prefix(struct format_tree * ft)1310 format_cb_client_prefix(struct format_tree *ft)
1311 {
1312 	const char	*name;
1313 
1314 	if (ft->c != NULL) {
1315 		name = server_client_get_key_table(ft->c);
1316 		if (strcmp(ft->c->keytable->name, name) == 0)
1317 			return (xstrdup("0"));
1318 		return (xstrdup("1"));
1319 	}
1320 	return (NULL);
1321 }
1322 
1323 /* Callback for client_readonly. */
1324 static void *
format_cb_client_readonly(struct format_tree * ft)1325 format_cb_client_readonly(struct format_tree *ft)
1326 {
1327 	if (ft->c != NULL) {
1328 		if (ft->c->flags & CLIENT_READONLY)
1329 			return (xstrdup("1"));
1330 		return (xstrdup("0"));
1331 	}
1332 	return (NULL);
1333 }
1334 
1335 /* Callback for client_session. */
1336 static void *
format_cb_client_session(struct format_tree * ft)1337 format_cb_client_session(struct format_tree *ft)
1338 {
1339 	if (ft->c != NULL && ft->c->session != NULL)
1340 		return (xstrdup(ft->c->session->name));
1341 	return (NULL);
1342 }
1343 
1344 /* Callback for client_termfeatures. */
1345 static void *
format_cb_client_termfeatures(struct format_tree * ft)1346 format_cb_client_termfeatures(struct format_tree *ft)
1347 {
1348 	if (ft->c != NULL)
1349 		return (xstrdup(tty_get_features(ft->c->term_features)));
1350 	return (NULL);
1351 }
1352 
1353 /* Callback for client_termname. */
1354 static void *
format_cb_client_termname(struct format_tree * ft)1355 format_cb_client_termname(struct format_tree *ft)
1356 {
1357 	if (ft->c != NULL)
1358 		return (xstrdup(ft->c->term_name));
1359 	return (NULL);
1360 }
1361 
1362 /* Callback for client_termtype. */
1363 static void *
format_cb_client_termtype(struct format_tree * ft)1364 format_cb_client_termtype(struct format_tree *ft)
1365 {
1366 	if (ft->c != NULL) {
1367 		if (ft->c->term_type == NULL)
1368 			return (xstrdup(""));
1369 		return (xstrdup(ft->c->term_type));
1370 	}
1371 	return (NULL);
1372 }
1373 
1374 /* Callback for client_tty. */
1375 static void *
format_cb_client_tty(struct format_tree * ft)1376 format_cb_client_tty(struct format_tree *ft)
1377 {
1378 	if (ft->c != NULL)
1379 		return (xstrdup(ft->c->ttyname));
1380 	return (NULL);
1381 }
1382 
1383 /* Callback for client_utf8. */
1384 static void *
format_cb_client_utf8(struct format_tree * ft)1385 format_cb_client_utf8(struct format_tree *ft)
1386 {
1387 	if (ft->c != NULL) {
1388 		if (ft->c->flags & CLIENT_UTF8)
1389 			return (xstrdup("1"));
1390 		return (xstrdup("0"));
1391 	}
1392 	return (NULL);
1393 }
1394 
1395 /* Callback for client_width. */
1396 static void *
format_cb_client_width(struct format_tree * ft)1397 format_cb_client_width(struct format_tree *ft)
1398 {
1399 	if (ft->c != NULL)
1400 		return (format_printf("%u", ft->c->tty.sx));
1401 	return (NULL);
1402 }
1403 
1404 /* Callback for client_written. */
1405 static void *
format_cb_client_written(struct format_tree * ft)1406 format_cb_client_written(struct format_tree *ft)
1407 {
1408 	if (ft->c != NULL)
1409 		return (format_printf("%zu", ft->c->written));
1410 	return (NULL);
1411 }
1412 
1413 /* Callback for config_files. */
1414 static void *
format_cb_config_files(__unused struct format_tree * ft)1415 format_cb_config_files(__unused struct format_tree *ft)
1416 {
1417 	char	*s = NULL;
1418 	size_t	 slen = 0;
1419 	u_int	 i;
1420 	size_t	 n;
1421 
1422 	for (i = 0; i < cfg_nfiles; i++) {
1423 		n = strlen(cfg_files[i]) + 1;
1424 		s = xrealloc(s, slen + n + 1);
1425 		slen += xsnprintf(s + slen, n + 1, "%s,", cfg_files[i]);
1426 	}
1427 	if (s == NULL)
1428 		return (xstrdup(""));
1429 	s[slen - 1] = '\0';
1430 	return (s);
1431 }
1432 
1433 /* Callback for cursor_flag. */
1434 static void *
format_cb_cursor_flag(struct format_tree * ft)1435 format_cb_cursor_flag(struct format_tree *ft)
1436 {
1437 	if (ft->wp != NULL) {
1438 		if (ft->wp->base.mode & MODE_CURSOR)
1439 			return (xstrdup("1"));
1440 		return (xstrdup("0"));
1441 	}
1442 	return (NULL);
1443 }
1444 
1445 /* Callback for cursor_x. */
1446 static void *
format_cb_cursor_x(struct format_tree * ft)1447 format_cb_cursor_x(struct format_tree *ft)
1448 {
1449 	if (ft->wp != NULL)
1450 		return (format_printf("%u", ft->wp->base.cx));
1451 	return (NULL);
1452 }
1453 
1454 /* Callback for cursor_y. */
1455 static void *
format_cb_cursor_y(struct format_tree * ft)1456 format_cb_cursor_y(struct format_tree *ft)
1457 {
1458 	if (ft->wp != NULL)
1459 		return (format_printf("%u", ft->wp->base.cy));
1460 	return (NULL);
1461 }
1462 
1463 /* Callback for history_limit. */
1464 static void *
format_cb_history_limit(struct format_tree * ft)1465 format_cb_history_limit(struct format_tree *ft)
1466 {
1467 	if (ft->wp != NULL)
1468 		return (format_printf("%u", ft->wp->base.grid->hlimit));
1469 	return (NULL);
1470 }
1471 
1472 /* Callback for history_size. */
1473 static void *
format_cb_history_size(struct format_tree * ft)1474 format_cb_history_size(struct format_tree *ft)
1475 {
1476 	if (ft->wp != NULL)
1477 		return (format_printf("%u", ft->wp->base.grid->hsize));
1478 	return (NULL);
1479 }
1480 
1481 /* Callback for insert_flag. */
1482 static void *
format_cb_insert_flag(struct format_tree * ft)1483 format_cb_insert_flag(struct format_tree *ft)
1484 {
1485 	if (ft->wp != NULL) {
1486 		if (ft->wp->base.mode & MODE_INSERT)
1487 			return (xstrdup("1"));
1488 		return (xstrdup("0"));
1489 	}
1490 	return (NULL);
1491 }
1492 
1493 /* Callback for keypad_cursor_flag. */
1494 static void *
format_cb_keypad_cursor_flag(struct format_tree * ft)1495 format_cb_keypad_cursor_flag(struct format_tree *ft)
1496 {
1497 	if (ft->wp != NULL) {
1498 		if (ft->wp->base.mode & MODE_KCURSOR)
1499 			return (xstrdup("1"));
1500 		return (xstrdup("0"));
1501 	}
1502 	return (NULL);
1503 }
1504 
1505 /* Callback for keypad_flag. */
1506 static void *
format_cb_keypad_flag(struct format_tree * ft)1507 format_cb_keypad_flag(struct format_tree *ft)
1508 {
1509 	if (ft->wp != NULL) {
1510 		if (ft->wp->base.mode & MODE_KKEYPAD)
1511 			return (xstrdup("1"));
1512 		return (xstrdup("0"));
1513 	}
1514 	return (NULL);
1515 }
1516 
1517 /* Callback for mouse_all_flag. */
1518 static void *
format_cb_mouse_all_flag(struct format_tree * ft)1519 format_cb_mouse_all_flag(struct format_tree *ft)
1520 {
1521 	if (ft->wp != NULL) {
1522 		if (ft->wp->base.mode & MODE_MOUSE_ALL)
1523 			return (xstrdup("1"));
1524 		return (xstrdup("0"));
1525 	}
1526 	return (NULL);
1527 }
1528 
1529 /* Callback for mouse_any_flag. */
1530 static void *
format_cb_mouse_any_flag(struct format_tree * ft)1531 format_cb_mouse_any_flag(struct format_tree *ft)
1532 {
1533 	if (ft->wp != NULL) {
1534 		if (ft->wp->base.mode & ALL_MOUSE_MODES)
1535 			return (xstrdup("1"));
1536 		return (xstrdup("0"));
1537 	}
1538 	return (NULL);
1539 }
1540 
1541 /* Callback for mouse_button_flag. */
1542 static void *
format_cb_mouse_button_flag(struct format_tree * ft)1543 format_cb_mouse_button_flag(struct format_tree *ft)
1544 {
1545 	if (ft->wp != NULL) {
1546 		if (ft->wp->base.mode & MODE_MOUSE_BUTTON)
1547 			return (xstrdup("1"));
1548 		return (xstrdup("0"));
1549 	}
1550 	return (NULL);
1551 }
1552 
1553 /* Callback for mouse_pane. */
1554 static void *
format_cb_mouse_pane(struct format_tree * ft)1555 format_cb_mouse_pane(struct format_tree *ft)
1556 {
1557 	struct window_pane	*wp;
1558 
1559 	if (ft->m.valid) {
1560 		wp = cmd_mouse_pane(&ft->m, NULL, NULL);
1561 		if (wp != NULL)
1562 			return (format_printf("%%%u", wp->id));
1563 		return (NULL);
1564 	}
1565 	return (NULL);
1566 }
1567 
1568 /* Callback for mouse_sgr_flag. */
1569 static void *
format_cb_mouse_sgr_flag(struct format_tree * ft)1570 format_cb_mouse_sgr_flag(struct format_tree *ft)
1571 {
1572 	if (ft->wp != NULL) {
1573 		if (ft->wp->base.mode & MODE_MOUSE_SGR)
1574 			return (xstrdup("1"));
1575 		return (xstrdup("0"));
1576 	}
1577 	return (NULL);
1578 }
1579 
1580 /* Callback for mouse_standard_flag. */
1581 static void *
format_cb_mouse_standard_flag(struct format_tree * ft)1582 format_cb_mouse_standard_flag(struct format_tree *ft)
1583 {
1584 	if (ft->wp != NULL) {
1585 		if (ft->wp->base.mode & MODE_MOUSE_STANDARD)
1586 			return (xstrdup("1"));
1587 		return (xstrdup("0"));
1588 	}
1589 	return (NULL);
1590 }
1591 
1592 /* Callback for mouse_utf8_flag. */
1593 static void *
format_cb_mouse_utf8_flag(struct format_tree * ft)1594 format_cb_mouse_utf8_flag(struct format_tree *ft)
1595 {
1596 	if (ft->wp != NULL) {
1597 		if (ft->wp->base.mode & MODE_MOUSE_UTF8)
1598 			return (xstrdup("1"));
1599 		return (xstrdup("0"));
1600 	}
1601 	return (NULL);
1602 }
1603 
1604 /* Callback for mouse_x. */
1605 static void *
format_cb_mouse_x(struct format_tree * ft)1606 format_cb_mouse_x(struct format_tree *ft)
1607 {
1608 	struct window_pane	*wp;
1609 	u_int			 x, y;
1610 
1611 	if (ft->m.valid) {
1612 		wp = cmd_mouse_pane(&ft->m, NULL, NULL);
1613 		if (wp != NULL && cmd_mouse_at(wp, &ft->m, &x, &y, 0) == 0)
1614 			return (format_printf("%u", x));
1615 		return (NULL);
1616 	}
1617 	return (NULL);
1618 }
1619 
1620 /* Callback for mouse_y. */
1621 static void *
format_cb_mouse_y(struct format_tree * ft)1622 format_cb_mouse_y(struct format_tree *ft)
1623 {
1624 	struct window_pane	*wp;
1625 	u_int			 x, y;
1626 
1627 	if (ft->m.valid) {
1628 		wp = cmd_mouse_pane(&ft->m, NULL, NULL);
1629 		if (wp != NULL && cmd_mouse_at(wp, &ft->m, &x, &y, 0) == 0)
1630 			return (format_printf("%u", y));
1631 		return (NULL);
1632 	}
1633 	return (NULL);
1634 }
1635 
1636 /* Callback for origin_flag. */
1637 static void *
format_cb_origin_flag(struct format_tree * ft)1638 format_cb_origin_flag(struct format_tree *ft)
1639 {
1640 	if (ft->wp != NULL) {
1641 		if (ft->wp->base.mode & MODE_ORIGIN)
1642 			return (xstrdup("1"));
1643 		return (xstrdup("0"));
1644 	}
1645 	return (NULL);
1646 }
1647 
1648 /* Callback for pane_active. */
1649 static void *
format_cb_pane_active(struct format_tree * ft)1650 format_cb_pane_active(struct format_tree *ft)
1651 {
1652 	if (ft->wp != NULL) {
1653 		if (ft->wp == ft->wp->window->active)
1654 			return (xstrdup("1"));
1655 		return (xstrdup("0"));
1656 	}
1657 	return (NULL);
1658 }
1659 
1660 /* Callback for pane_at_left. */
1661 static void *
format_cb_pane_at_left(struct format_tree * ft)1662 format_cb_pane_at_left(struct format_tree *ft)
1663 {
1664 	if (ft->wp != NULL) {
1665 		if (ft->wp->xoff == 0)
1666 			return (xstrdup("1"));
1667 		return (xstrdup("0"));
1668 	}
1669 	return (NULL);
1670 }
1671 
1672 /* Callback for pane_at_right. */
1673 static void *
format_cb_pane_at_right(struct format_tree * ft)1674 format_cb_pane_at_right(struct format_tree *ft)
1675 {
1676 	if (ft->wp != NULL) {
1677 		if (ft->wp->xoff + ft->wp->sx == ft->wp->window->sx)
1678 			return (xstrdup("1"));
1679 		return (xstrdup("0"));
1680 	}
1681 	return (NULL);
1682 }
1683 
1684 /* Callback for pane_bottom. */
1685 static void *
format_cb_pane_bottom(struct format_tree * ft)1686 format_cb_pane_bottom(struct format_tree *ft)
1687 {
1688 	if (ft->wp != NULL)
1689 		return (format_printf("%u", ft->wp->yoff + ft->wp->sy - 1));
1690 	return (NULL);
1691 }
1692 
1693 /* Callback for pane_dead. */
1694 static void *
format_cb_pane_dead(struct format_tree * ft)1695 format_cb_pane_dead(struct format_tree *ft)
1696 {
1697 	if (ft->wp != NULL) {
1698 		if (ft->wp->fd == -1)
1699 			return (xstrdup("1"));
1700 		return (xstrdup("0"));
1701 	}
1702 	return (NULL);
1703 }
1704 
1705 /* Callback for pane_dead_status. */
1706 static void *
format_cb_pane_dead_status(struct format_tree * ft)1707 format_cb_pane_dead_status(struct format_tree *ft)
1708 {
1709 	struct window_pane	*wp = ft->wp;
1710 
1711 	if (wp != NULL) {
1712 		if ((wp->flags & PANE_STATUSREADY) && WIFEXITED(wp->status))
1713 			return (format_printf("%d", WEXITSTATUS(wp->status)));
1714 		return (NULL);
1715 	}
1716 	return (NULL);
1717 }
1718 
1719 /* Callback for pane_format. */
1720 static void *
format_cb_pane_format(struct format_tree * ft)1721 format_cb_pane_format(struct format_tree *ft)
1722 {
1723 	if (ft->type == FORMAT_TYPE_PANE)
1724 		return (xstrdup("1"));
1725 	return (xstrdup("0"));
1726 }
1727 
1728 /* Callback for pane_height. */
1729 static void *
format_cb_pane_height(struct format_tree * ft)1730 format_cb_pane_height(struct format_tree *ft)
1731 {
1732 	if (ft->wp != NULL)
1733 		return (format_printf("%u", ft->wp->sy));
1734 	return (NULL);
1735 }
1736 
1737 /* Callback for pane_id. */
1738 static void *
format_cb_pane_id(struct format_tree * ft)1739 format_cb_pane_id(struct format_tree *ft)
1740 {
1741 	if (ft->wp != NULL)
1742 		return (format_printf("%%%u", ft->wp->id));
1743 	return (NULL);
1744 }
1745 
1746 /* Callback for pane_index. */
1747 static void *
format_cb_pane_index(struct format_tree * ft)1748 format_cb_pane_index(struct format_tree *ft)
1749 {
1750 	u_int	idx;
1751 
1752 	if (ft->wp != NULL && window_pane_index(ft->wp, &idx) == 0)
1753 		return (format_printf("%u", idx));
1754 	return (NULL);
1755 }
1756 
1757 /* Callback for pane_input_off. */
1758 static void *
format_cb_pane_input_off(struct format_tree * ft)1759 format_cb_pane_input_off(struct format_tree *ft)
1760 {
1761 	if (ft->wp != NULL) {
1762 		if (ft->wp->flags & PANE_INPUTOFF)
1763 			return (xstrdup("1"));
1764 		return (xstrdup("0"));
1765 	}
1766 	return (NULL);
1767 }
1768 
1769 /* Callback for pane_last. */
1770 static void *
format_cb_pane_last(struct format_tree * ft)1771 format_cb_pane_last(struct format_tree *ft)
1772 {
1773 	if (ft->wp != NULL) {
1774 		if (ft->wp == ft->wp->window->last)
1775 			return (xstrdup("1"));
1776 		return (xstrdup("0"));
1777 	}
1778 	return (NULL);
1779 }
1780 
1781 /* Callback for pane_left. */
1782 static void *
format_cb_pane_left(struct format_tree * ft)1783 format_cb_pane_left(struct format_tree *ft)
1784 {
1785 	if (ft->wp != NULL)
1786 		return (format_printf("%u", ft->wp->xoff));
1787 	return (NULL);
1788 }
1789 
1790 /* Callback for pane_marked. */
1791 static void *
format_cb_pane_marked(struct format_tree * ft)1792 format_cb_pane_marked(struct format_tree *ft)
1793 {
1794 	if (ft->wp != NULL) {
1795 		if (server_check_marked() && marked_pane.wp == ft->wp)
1796 			return (xstrdup("1"));
1797 		return (xstrdup("0"));
1798 	}
1799 	return (NULL);
1800 }
1801 
1802 /* Callback for pane_marked_set. */
1803 static void *
format_cb_pane_marked_set(struct format_tree * ft)1804 format_cb_pane_marked_set(struct format_tree *ft)
1805 {
1806 	if (ft->wp != NULL) {
1807 		if (server_check_marked())
1808 			return (xstrdup("1"));
1809 		return (xstrdup("0"));
1810 	}
1811 	return (NULL);
1812 }
1813 
1814 /* Callback for pane_mode. */
1815 static void *
format_cb_pane_mode(struct format_tree * ft)1816 format_cb_pane_mode(struct format_tree *ft)
1817 {
1818 	struct window_mode_entry	*wme;
1819 
1820 	if (ft->wp != NULL) {
1821 		wme = TAILQ_FIRST(&ft->wp->modes);
1822 		if (wme != NULL)
1823 			return (xstrdup(wme->mode->name));
1824 		return (NULL);
1825 	}
1826 	return (NULL);
1827 }
1828 
1829 /* Callback for pane_path. */
1830 static void *
format_cb_pane_path(struct format_tree * ft)1831 format_cb_pane_path(struct format_tree *ft)
1832 {
1833 	if (ft->wp != NULL) {
1834 		if (ft->wp->base.path == NULL)
1835 			return (xstrdup(""));
1836 		return (xstrdup(ft->wp->base.path));
1837 	}
1838 	return (NULL);
1839 }
1840 
1841 /* Callback for pane_pid. */
1842 static void *
format_cb_pane_pid(struct format_tree * ft)1843 format_cb_pane_pid(struct format_tree *ft)
1844 {
1845 	if (ft->wp != NULL)
1846 		return (format_printf("%ld", (long)ft->wp->pid));
1847 	return (NULL);
1848 }
1849 
1850 /* Callback for pane_pipe. */
1851 static void *
format_cb_pane_pipe(struct format_tree * ft)1852 format_cb_pane_pipe(struct format_tree *ft)
1853 {
1854 	if (ft->wp != NULL) {
1855 		if (ft->wp->pipe_fd != -1)
1856 			return (xstrdup("1"));
1857 		return (xstrdup("0"));
1858 	}
1859 	return (NULL);
1860 }
1861 
1862 /* Callback for pane_right. */
1863 static void *
format_cb_pane_right(struct format_tree * ft)1864 format_cb_pane_right(struct format_tree *ft)
1865 {
1866 	if (ft->wp != NULL)
1867 		return (format_printf("%u", ft->wp->xoff + ft->wp->sx - 1));
1868 	return (NULL);
1869 }
1870 
1871 /* Callback for pane_search_string. */
1872 static void *
format_cb_pane_search_string(struct format_tree * ft)1873 format_cb_pane_search_string(struct format_tree *ft)
1874 {
1875 	if (ft->wp != NULL) {
1876 		if (ft->wp->searchstr == NULL)
1877 			return (xstrdup(""));
1878 		return (xstrdup(ft->wp->searchstr));
1879 	}
1880 	return (NULL);
1881 }
1882 
1883 /* Callback for pane_synchronized. */
1884 static void *
format_cb_pane_synchronized(struct format_tree * ft)1885 format_cb_pane_synchronized(struct format_tree *ft)
1886 {
1887 	if (ft->wp != NULL) {
1888 		if (options_get_number(ft->wp->options, "synchronize-panes"))
1889 			return (xstrdup("1"));
1890 		return (xstrdup("0"));
1891 	}
1892 	return (NULL);
1893 }
1894 
1895 /* Callback for pane_title. */
1896 static void *
format_cb_pane_title(struct format_tree * ft)1897 format_cb_pane_title(struct format_tree *ft)
1898 {
1899 	if (ft->wp != NULL)
1900 		return (xstrdup(ft->wp->base.title));
1901 	return (NULL);
1902 }
1903 
1904 /* Callback for pane_top. */
1905 static void *
format_cb_pane_top(struct format_tree * ft)1906 format_cb_pane_top(struct format_tree *ft)
1907 {
1908 	if (ft->wp != NULL)
1909 		return (format_printf("%u", ft->wp->yoff));
1910 	return (NULL);
1911 }
1912 
1913 /* Callback for pane_tty. */
1914 static void *
format_cb_pane_tty(struct format_tree * ft)1915 format_cb_pane_tty(struct format_tree *ft)
1916 {
1917 	if (ft->wp != NULL)
1918 		return (xstrdup(ft->wp->tty));
1919 	return (NULL);
1920 }
1921 
1922 /* Callback for pane_width. */
1923 static void *
format_cb_pane_width(struct format_tree * ft)1924 format_cb_pane_width(struct format_tree *ft)
1925 {
1926 	if (ft->wp != NULL)
1927 		return (format_printf("%u", ft->wp->sx));
1928 	return (NULL);
1929 }
1930 
1931 /* Callback for scroll_region_lower. */
1932 static void *
format_cb_scroll_region_lower(struct format_tree * ft)1933 format_cb_scroll_region_lower(struct format_tree *ft)
1934 {
1935 	if (ft->wp != NULL)
1936 		return (format_printf("%u", ft->wp->base.rlower));
1937 	return (NULL);
1938 }
1939 
1940 /* Callback for scroll_region_upper. */
1941 static void *
format_cb_scroll_region_upper(struct format_tree * ft)1942 format_cb_scroll_region_upper(struct format_tree *ft)
1943 {
1944 	if (ft->wp != NULL)
1945 		return (format_printf("%u", ft->wp->base.rupper));
1946 	return (NULL);
1947 }
1948 
1949 /* Callback for session_attached. */
1950 static void *
format_cb_session_attached(struct format_tree * ft)1951 format_cb_session_attached(struct format_tree *ft)
1952 {
1953 	if (ft->s != NULL)
1954 		return (format_printf("%u", ft->s->attached));
1955 	return (NULL);
1956 }
1957 
1958 /* Callback for session_format. */
1959 static void *
format_cb_session_format(struct format_tree * ft)1960 format_cb_session_format(struct format_tree *ft)
1961 {
1962 	if (ft->type == FORMAT_TYPE_SESSION)
1963 		return (xstrdup("1"));
1964 	return (xstrdup("0"));
1965 }
1966 
1967 /* Callback for session_group. */
1968 static void *
format_cb_session_group(struct format_tree * ft)1969 format_cb_session_group(struct format_tree *ft)
1970 {
1971 	struct session_group	*sg;
1972 
1973 	if (ft->s != NULL && (sg = session_group_contains(ft->s)) != NULL)
1974 		return (xstrdup(sg->name));
1975 	return (NULL);
1976 }
1977 
1978 /* Callback for session_group_attached. */
1979 static void *
format_cb_session_group_attached(struct format_tree * ft)1980 format_cb_session_group_attached(struct format_tree *ft)
1981 {
1982 	struct session_group	*sg;
1983 
1984 	if (ft->s != NULL && (sg = session_group_contains(ft->s)) != NULL)
1985 		return (format_printf("%u", session_group_attached_count (sg)));
1986 	return (NULL);
1987 }
1988 
1989 /* Callback for session_group_many_attached. */
1990 static void *
format_cb_session_group_many_attached(struct format_tree * ft)1991 format_cb_session_group_many_attached(struct format_tree *ft)
1992 {
1993 	struct session_group	*sg;
1994 
1995 	if (ft->s != NULL && (sg = session_group_contains(ft->s)) != NULL) {
1996 		if (session_group_attached_count (sg) > 1)
1997 			return (xstrdup("1"));
1998 		return (xstrdup("0"));
1999 	}
2000 	return (NULL);
2001 }
2002 
2003 /* Callback for session_group_size. */
2004 static void *
format_cb_session_group_size(struct format_tree * ft)2005 format_cb_session_group_size(struct format_tree *ft)
2006 {
2007 	struct session_group	*sg;
2008 
2009 	if (ft->s != NULL && (sg = session_group_contains(ft->s)) != NULL)
2010 		return (format_printf("%u", session_group_count (sg)));
2011 	return (NULL);
2012 }
2013 
2014 /* Callback for session_grouped. */
2015 static void *
format_cb_session_grouped(struct format_tree * ft)2016 format_cb_session_grouped(struct format_tree *ft)
2017 {
2018 	if (ft->s != NULL) {
2019 		if (session_group_contains(ft->s) != NULL)
2020 			return (xstrdup("1"));
2021 		return (xstrdup("0"));
2022 	}
2023 	return (NULL);
2024 }
2025 
2026 /* Callback for session_id. */
2027 static void *
format_cb_session_id(struct format_tree * ft)2028 format_cb_session_id(struct format_tree *ft)
2029 {
2030 	if (ft->s != NULL)
2031 		return (format_printf("$%u", ft->s->id));
2032 	return (NULL);
2033 }
2034 
2035 /* Callback for session_many_attached. */
2036 static void *
format_cb_session_many_attached(struct format_tree * ft)2037 format_cb_session_many_attached(struct format_tree *ft)
2038 {
2039 	if (ft->s != NULL) {
2040 		if (ft->s->attached > 1)
2041 			return (xstrdup("1"));
2042 		return (xstrdup("0"));
2043 	}
2044 	return (NULL);
2045 }
2046 
2047 /* Callback for session_marked. */
2048 static void *
format_cb_session_marked(struct format_tree * ft)2049 format_cb_session_marked(struct format_tree *ft)
2050 {
2051 	if (ft->s != NULL) {
2052 		if (server_check_marked() && marked_pane.s == ft->s)
2053 			return (xstrdup("1"));
2054 		return (xstrdup("0"));
2055 	}
2056 	return (NULL);
2057 }
2058 
2059 /* Callback for session_name. */
2060 static void *
format_cb_session_name(struct format_tree * ft)2061 format_cb_session_name(struct format_tree *ft)
2062 {
2063 	if (ft->s != NULL)
2064 		return (xstrdup(ft->s->name));
2065 	return (NULL);
2066 }
2067 
2068 /* Callback for session_path. */
2069 static void *
format_cb_session_path(struct format_tree * ft)2070 format_cb_session_path(struct format_tree *ft)
2071 {
2072 	if (ft->s != NULL)
2073 		return (xstrdup(ft->s->cwd));
2074 	return (NULL);
2075 }
2076 
2077 /* Callback for session_windows. */
2078 static void *
format_cb_session_windows(struct format_tree * ft)2079 format_cb_session_windows(struct format_tree *ft)
2080 {
2081 	if (ft->s != NULL)
2082 		return (format_printf ("%u", winlink_count(&ft->s->windows)));
2083 	return (NULL);
2084 }
2085 
2086 /* Callback for socket_path. */
2087 static void *
format_cb_socket_path(__unused struct format_tree * ft)2088 format_cb_socket_path(__unused struct format_tree *ft)
2089 {
2090 	return (xstrdup(socket_path));
2091 }
2092 
2093 /* Callback for version. */
2094 static void *
format_cb_version(__unused struct format_tree * ft)2095 format_cb_version(__unused struct format_tree *ft)
2096 {
2097 	return (xstrdup(getversion()));
2098 }
2099 
2100 /* Callback for active_window_index. */
2101 static void *
format_cb_active_window_index(struct format_tree * ft)2102 format_cb_active_window_index(struct format_tree *ft)
2103 {
2104 	if (ft->s != NULL)
2105 		return (format_printf("%u", ft->s->curw->idx));
2106 	return (NULL);
2107 }
2108 
2109 /* Callback for last_window_index. */
2110 static void *
format_cb_last_window_index(struct format_tree * ft)2111 format_cb_last_window_index(struct format_tree *ft)
2112 {
2113 	struct winlink	*wl;
2114 
2115 	if (ft->s != NULL) {
2116 		wl = RB_MAX(winlinks, &ft->s->windows);
2117 		return (format_printf("%u", wl->idx));
2118 	}
2119 	return (NULL);
2120 }
2121 
2122 /* Callback for window_active. */
2123 static void *
format_cb_window_active(struct format_tree * ft)2124 format_cb_window_active(struct format_tree *ft)
2125 {
2126 	if (ft->wl != NULL) {
2127 		if (ft->wl == ft->wl->session->curw)
2128 			return (xstrdup("1"));
2129 		return (xstrdup("0"));
2130 	}
2131 	return (NULL);
2132 }
2133 
2134 /* Callback for window_activity_flag. */
2135 static void *
format_cb_window_activity_flag(struct format_tree * ft)2136 format_cb_window_activity_flag(struct format_tree *ft)
2137 {
2138 	if (ft->wl != NULL) {
2139 		if (ft->wl->flags & WINLINK_ACTIVITY)
2140 			return (xstrdup("1"));
2141 		return (xstrdup("0"));
2142 	}
2143 	return (NULL);
2144 }
2145 
2146 /* Callback for window_bell_flag. */
2147 static void *
format_cb_window_bell_flag(struct format_tree * ft)2148 format_cb_window_bell_flag(struct format_tree *ft)
2149 {
2150 	if (ft->wl != NULL) {
2151 		if (ft->wl->flags & WINLINK_BELL)
2152 			return (xstrdup("1"));
2153 		return (xstrdup("0"));
2154 	}
2155 	return (NULL);
2156 }
2157 
2158 /* Callback for window_bigger. */
2159 static void *
format_cb_window_bigger(struct format_tree * ft)2160 format_cb_window_bigger(struct format_tree *ft)
2161 {
2162 	u_int	ox, oy, sx, sy;
2163 
2164 	if (ft->c != NULL) {
2165 		if (tty_window_offset(&ft->c->tty, &ox, &oy, &sx, &sy))
2166 			return (xstrdup("1"));
2167 		return (xstrdup("0"));
2168 	}
2169 	return (NULL);
2170 }
2171 
2172 /* Callback for window_cell_height. */
2173 static void *
format_cb_window_cell_height(struct format_tree * ft)2174 format_cb_window_cell_height(struct format_tree *ft)
2175 {
2176 	if (ft->w != NULL)
2177 		return (format_printf("%u", ft->w->ypixel));
2178 	return (NULL);
2179 }
2180 
2181 /* Callback for window_cell_width. */
2182 static void *
format_cb_window_cell_width(struct format_tree * ft)2183 format_cb_window_cell_width(struct format_tree *ft)
2184 {
2185 	if (ft->w != NULL)
2186 		return (format_printf("%u", ft->w->xpixel));
2187 	return (NULL);
2188 }
2189 
2190 /* Callback for window_end_flag. */
2191 static void *
format_cb_window_end_flag(struct format_tree * ft)2192 format_cb_window_end_flag(struct format_tree *ft)
2193 {
2194 	if (ft->wl != NULL) {
2195 		if (ft->wl == RB_MAX(winlinks, &ft->wl->session->windows))
2196 			return (xstrdup("1"));
2197 		return (xstrdup("0"));
2198 	}
2199 	return (NULL);
2200 }
2201 
2202 /* Callback for window_flags. */
2203 static void *
format_cb_window_flags(struct format_tree * ft)2204 format_cb_window_flags(struct format_tree *ft)
2205 {
2206 	if (ft->wl != NULL)
2207 		return (xstrdup(window_printable_flags(ft->wl, 1)));
2208 	return (NULL);
2209 }
2210 
2211 /* Callback for window_format. */
2212 static void *
format_cb_window_format(struct format_tree * ft)2213 format_cb_window_format(struct format_tree *ft)
2214 {
2215 	if (ft->type == FORMAT_TYPE_WINDOW)
2216 		return (xstrdup("1"));
2217 	return (xstrdup("0"));
2218 }
2219 
2220 /* Callback for window_height. */
2221 static void *
format_cb_window_height(struct format_tree * ft)2222 format_cb_window_height(struct format_tree *ft)
2223 {
2224 	if (ft->w != NULL)
2225 		return (format_printf("%u", ft->w->sy));
2226 	return (NULL);
2227 }
2228 
2229 /* Callback for window_id. */
2230 static void *
format_cb_window_id(struct format_tree * ft)2231 format_cb_window_id(struct format_tree *ft)
2232 {
2233 	if (ft->w != NULL)
2234 		return (format_printf("@%u", ft->w->id));
2235 	return (NULL);
2236 }
2237 
2238 /* Callback for window_index. */
2239 static void *
format_cb_window_index(struct format_tree * ft)2240 format_cb_window_index(struct format_tree *ft)
2241 {
2242 	if (ft->wl != NULL)
2243 		return (format_printf("%d", ft->wl->idx));
2244 	return (NULL);
2245 }
2246 
2247 /* Callback for window_last_flag. */
2248 static void *
format_cb_window_last_flag(struct format_tree * ft)2249 format_cb_window_last_flag(struct format_tree *ft)
2250 {
2251 	if (ft->wl != NULL) {
2252 		if (ft->wl == TAILQ_FIRST(&ft->wl->session->lastw))
2253 			return (xstrdup("1"));
2254 		return (xstrdup("0"));
2255 	}
2256 	return (NULL);
2257 }
2258 
2259 /* Callback for window_linked. */
2260 static void *
format_cb_window_linked(struct format_tree * ft)2261 format_cb_window_linked(struct format_tree *ft)
2262 {
2263 	if (ft->wl != NULL) {
2264 		if (session_is_linked(ft->wl->session, ft->wl->window))
2265 			return (xstrdup("1"));
2266 		return (xstrdup("0"));
2267 	}
2268 	return (NULL);
2269 }
2270 
2271 /* Callback for window_linked_sessions. */
2272 static void *
format_cb_window_linked_sessions(struct format_tree * ft)2273 format_cb_window_linked_sessions(struct format_tree *ft)
2274 {
2275 	if (ft->wl != NULL)
2276 		return (format_printf("%u", ft->wl->window->references));
2277 	return (NULL);
2278 }
2279 
2280 /* Callback for window_marked_flag. */
2281 static void *
format_cb_window_marked_flag(struct format_tree * ft)2282 format_cb_window_marked_flag(struct format_tree *ft)
2283 {
2284 	if (ft->wl != NULL) {
2285 		if (server_check_marked() && marked_pane.wl == ft->wl)
2286 			return (xstrdup("1"));
2287 		return (xstrdup("0"));
2288 	}
2289 	return (NULL);
2290 }
2291 
2292 /* Callback for window_name. */
2293 static void *
format_cb_window_name(struct format_tree * ft)2294 format_cb_window_name(struct format_tree *ft)
2295 {
2296 	if (ft->w != NULL)
2297 		return (format_printf("%s", ft->w->name));
2298 	return (NULL);
2299 }
2300 
2301 /* Callback for window_offset_x. */
2302 static void *
format_cb_window_offset_x(struct format_tree * ft)2303 format_cb_window_offset_x(struct format_tree *ft)
2304 {
2305 	u_int	ox, oy, sx, sy;
2306 
2307 	if (ft->c != NULL) {
2308 		if (tty_window_offset(&ft->c->tty, &ox, &oy, &sx, &sy))
2309 			return (format_printf("%u", ox));
2310 		return (NULL);
2311 	}
2312 	return (NULL);
2313 }
2314 
2315 /* Callback for window_offset_y. */
2316 static void *
format_cb_window_offset_y(struct format_tree * ft)2317 format_cb_window_offset_y(struct format_tree *ft)
2318 {
2319 	u_int	ox, oy, sx, sy;
2320 
2321 	if (ft->c != NULL) {
2322 		if (tty_window_offset(&ft->c->tty, &ox, &oy, &sx, &sy))
2323 			return (format_printf("%u", oy));
2324 		return (NULL);
2325 	}
2326 	return (NULL);
2327 }
2328 
2329 /* Callback for window_panes. */
2330 static void *
format_cb_window_panes(struct format_tree * ft)2331 format_cb_window_panes(struct format_tree *ft)
2332 {
2333 	if (ft->w != NULL)
2334 		return (format_printf("%u", window_count_panes(ft->w)));
2335 	return (NULL);
2336 }
2337 
2338 /* Callback for window_raw_flags. */
2339 static void *
format_cb_window_raw_flags(struct format_tree * ft)2340 format_cb_window_raw_flags(struct format_tree *ft)
2341 {
2342 	if (ft->wl != NULL)
2343 		return (xstrdup(window_printable_flags(ft->wl, 0)));
2344 	return (NULL);
2345 }
2346 
2347 /* Callback for window_silence_flag. */
2348 static void *
format_cb_window_silence_flag(struct format_tree * ft)2349 format_cb_window_silence_flag(struct format_tree *ft)
2350 {
2351 	if (ft->wl != NULL) {
2352 		if (ft->wl->flags & WINLINK_SILENCE)
2353 			return (xstrdup("1"));
2354 		return (xstrdup("0"));
2355 	}
2356 	return (NULL);
2357 }
2358 
2359 /* Callback for window_start_flag. */
2360 static void *
format_cb_window_start_flag(struct format_tree * ft)2361 format_cb_window_start_flag(struct format_tree *ft)
2362 {
2363 	if (ft->wl != NULL) {
2364 		if (ft->wl == RB_MIN(winlinks, &ft->wl->session->windows))
2365 			return (xstrdup("1"));
2366 		return (xstrdup("0"));
2367 	}
2368 	return (NULL);
2369 }
2370 
2371 /* Callback for window_width. */
2372 static void *
format_cb_window_width(struct format_tree * ft)2373 format_cb_window_width(struct format_tree *ft)
2374 {
2375 	if (ft->w != NULL)
2376 		return (format_printf("%u", ft->w->sx));
2377 	return (NULL);
2378 }
2379 
2380 /* Callback for window_zoomed_flag. */
2381 static void *
format_cb_window_zoomed_flag(struct format_tree * ft)2382 format_cb_window_zoomed_flag(struct format_tree *ft)
2383 {
2384 	if (ft->w != NULL) {
2385 		if (ft->w->flags & WINDOW_ZOOMED)
2386 			return (xstrdup("1"));
2387 		return (xstrdup("0"));
2388 	}
2389 	return (NULL);
2390 }
2391 
2392 /* Callback for wrap_flag. */
2393 static void *
format_cb_wrap_flag(struct format_tree * ft)2394 format_cb_wrap_flag(struct format_tree *ft)
2395 {
2396 	if (ft->wp != NULL) {
2397 		if (ft->wp->base.mode & MODE_WRAP)
2398 			return (xstrdup("1"));
2399 		return (xstrdup("0"));
2400 	}
2401 	return (NULL);
2402 }
2403 
2404 /* Callback for buffer_created. */
2405 static void *
format_cb_buffer_created(struct format_tree * ft)2406 format_cb_buffer_created(struct format_tree *ft)
2407 {
2408 	static struct timeval	 tv;
2409 
2410 	if (ft->pb != NULL) {
2411 		timerclear(&tv);
2412 		tv.tv_sec = paste_buffer_created(ft->pb);
2413 		return (&tv);
2414 	}
2415 	return (NULL);
2416 }
2417 
2418 /* Callback for client_activity. */
2419 static void *
format_cb_client_activity(struct format_tree * ft)2420 format_cb_client_activity(struct format_tree *ft)
2421 {
2422 	if (ft->c != NULL)
2423 		return (&ft->c->activity_time);
2424 	return (NULL);
2425 }
2426 
2427 /* Callback for client_created. */
2428 static void *
format_cb_client_created(struct format_tree * ft)2429 format_cb_client_created(struct format_tree *ft)
2430 {
2431 	if (ft->c != NULL)
2432 		return (&ft->c->creation_time);
2433 	return (NULL);
2434 }
2435 
2436 /* Callback for session_activity. */
2437 static void *
format_cb_session_activity(struct format_tree * ft)2438 format_cb_session_activity(struct format_tree *ft)
2439 {
2440 	if (ft->s != NULL)
2441 		return (&ft->s->activity_time);
2442 	return (NULL);
2443 }
2444 
2445 /* Callback for session_created. */
2446 static void *
format_cb_session_created(struct format_tree * ft)2447 format_cb_session_created(struct format_tree *ft)
2448 {
2449 	if (ft->s != NULL)
2450 		return (&ft->s->creation_time);
2451 	return (NULL);
2452 }
2453 
2454 /* Callback for session_last_attached. */
2455 static void *
format_cb_session_last_attached(struct format_tree * ft)2456 format_cb_session_last_attached(struct format_tree *ft)
2457 {
2458 	if (ft->s != NULL)
2459 		return (&ft->s->last_attached_time);
2460 	return (NULL);
2461 }
2462 
2463 /* Callback for start_time. */
2464 static void *
format_cb_start_time(__unused struct format_tree * ft)2465 format_cb_start_time(__unused struct format_tree *ft)
2466 {
2467 	return (&start_time);
2468 }
2469 
2470 /* Callback for window_activity. */
2471 static void *
format_cb_window_activity(struct format_tree * ft)2472 format_cb_window_activity(struct format_tree *ft)
2473 {
2474 	if (ft->w != NULL)
2475 		return (&ft->w->activity_time);
2476 	return (NULL);
2477 }
2478 
2479 /* Callback for buffer_mode_format, */
2480 static void *
format_cb_buffer_mode_format(__unused struct format_tree * ft)2481 format_cb_buffer_mode_format(__unused struct format_tree *ft)
2482 {
2483 	return (xstrdup(window_buffer_mode.default_format));
2484 }
2485 
2486 /* Callback for client_mode_format, */
2487 static void *
format_cb_client_mode_format(__unused struct format_tree * ft)2488 format_cb_client_mode_format(__unused struct format_tree *ft)
2489 {
2490 	return (xstrdup(window_client_mode.default_format));
2491 }
2492 
2493 /* Callback for tree_mode_format, */
2494 static void *
format_cb_tree_mode_format(__unused struct format_tree * ft)2495 format_cb_tree_mode_format(__unused struct format_tree *ft)
2496 {
2497 	return (xstrdup(window_tree_mode.default_format));
2498 }
2499 
2500 /* Format table type. */
2501 enum format_table_type {
2502 	FORMAT_TABLE_STRING,
2503 	FORMAT_TABLE_TIME
2504 };
2505 
2506 /* Format table entry. */
2507 struct format_table_entry {
2508 	const char		*key;
2509 	enum format_table_type	 type;
2510 	format_cb		 cb;
2511 };
2512 
2513 /*
2514  * Format table. Default format variables (that are almost always in the tree
2515  * and where the value is expanded by a callback in this file) are listed here.
2516  * Only variables which are added by the caller go into the tree.
2517  */
2518 static const struct format_table_entry format_table[] = {
2519 	{ "active_window_index", FORMAT_TABLE_STRING,
2520 	  format_cb_active_window_index
2521 	},
2522 	{ "alternate_on", FORMAT_TABLE_STRING,
2523 	  format_cb_alternate_on
2524 	},
2525 	{ "alternate_saved_x", FORMAT_TABLE_STRING,
2526 	  format_cb_alternate_saved_x
2527 	},
2528 	{ "alternate_saved_y", FORMAT_TABLE_STRING,
2529 	  format_cb_alternate_saved_y
2530 	},
2531 	{ "buffer_created", FORMAT_TABLE_TIME,
2532 	  format_cb_buffer_created
2533 	},
2534 	{ "buffer_mode_format", FORMAT_TABLE_STRING,
2535 	  format_cb_buffer_mode_format
2536 	},
2537 	{ "buffer_name", FORMAT_TABLE_STRING,
2538 	  format_cb_buffer_name
2539 	},
2540 	{ "buffer_sample", FORMAT_TABLE_STRING,
2541 	  format_cb_buffer_sample
2542 	},
2543 	{ "buffer_size", FORMAT_TABLE_STRING,
2544 	  format_cb_buffer_size
2545 	},
2546 	{ "client_activity", FORMAT_TABLE_TIME,
2547 	  format_cb_client_activity
2548 	},
2549 	{ "client_cell_height", FORMAT_TABLE_STRING,
2550 	  format_cb_client_cell_height
2551 	},
2552 	{ "client_cell_width", FORMAT_TABLE_STRING,
2553 	  format_cb_client_cell_width
2554 	},
2555 	{ "client_control_mode", FORMAT_TABLE_STRING,
2556 	  format_cb_client_control_mode
2557 	},
2558 	{ "client_created", FORMAT_TABLE_TIME,
2559 	  format_cb_client_created
2560 	},
2561 	{ "client_discarded", FORMAT_TABLE_STRING,
2562 	  format_cb_client_discarded
2563 	},
2564 	{ "client_flags", FORMAT_TABLE_STRING,
2565 	  format_cb_client_flags
2566 	},
2567 	{ "client_height", FORMAT_TABLE_STRING,
2568 	  format_cb_client_height
2569 	},
2570 	{ "client_key_table", FORMAT_TABLE_STRING,
2571 	  format_cb_client_key_table
2572 	},
2573 	{ "client_last_session", FORMAT_TABLE_STRING,
2574 	  format_cb_client_last_session
2575 	},
2576 	{ "client_mode_format", FORMAT_TABLE_STRING,
2577 	  format_cb_client_mode_format
2578 	},
2579 	{ "client_name", FORMAT_TABLE_STRING,
2580 	  format_cb_client_name
2581 	},
2582 	{ "client_pid", FORMAT_TABLE_STRING,
2583 	  format_cb_client_pid
2584 	},
2585 	{ "client_prefix", FORMAT_TABLE_STRING,
2586 	  format_cb_client_prefix
2587 	},
2588 	{ "client_readonly", FORMAT_TABLE_STRING,
2589 	  format_cb_client_readonly
2590 	},
2591 	{ "client_session", FORMAT_TABLE_STRING,
2592 	  format_cb_client_session
2593 	},
2594 	{ "client_termfeatures", FORMAT_TABLE_STRING,
2595 	  format_cb_client_termfeatures
2596 	},
2597 	{ "client_termname", FORMAT_TABLE_STRING,
2598 	  format_cb_client_termname
2599 	},
2600 	{ "client_termtype", FORMAT_TABLE_STRING,
2601 	  format_cb_client_termtype
2602 	},
2603 	{ "client_tty", FORMAT_TABLE_STRING,
2604 	  format_cb_client_tty
2605 	},
2606 	{ "client_utf8", FORMAT_TABLE_STRING,
2607 	  format_cb_client_utf8
2608 	},
2609 	{ "client_width", FORMAT_TABLE_STRING,
2610 	  format_cb_client_width
2611 	},
2612 	{ "client_written", FORMAT_TABLE_STRING,
2613 	  format_cb_client_written
2614 	},
2615 	{ "config_files", FORMAT_TABLE_STRING,
2616 	  format_cb_config_files
2617 	},
2618 	{ "cursor_character", FORMAT_TABLE_STRING,
2619 	  format_cb_cursor_character
2620 	},
2621 	{ "cursor_flag", FORMAT_TABLE_STRING,
2622 	  format_cb_cursor_flag
2623 	},
2624 	{ "cursor_x", FORMAT_TABLE_STRING,
2625 	  format_cb_cursor_x
2626 	},
2627 	{ "cursor_y", FORMAT_TABLE_STRING,
2628 	  format_cb_cursor_y
2629 	},
2630 	{ "history_all_bytes", FORMAT_TABLE_STRING,
2631 	  format_cb_history_all_bytes
2632 	},
2633 	{ "history_bytes", FORMAT_TABLE_STRING,
2634 	  format_cb_history_bytes
2635 	},
2636 	{ "history_limit", FORMAT_TABLE_STRING,
2637 	  format_cb_history_limit
2638 	},
2639 	{ "history_size", FORMAT_TABLE_STRING,
2640 	  format_cb_history_size
2641 	},
2642 	{ "host", FORMAT_TABLE_STRING,
2643 	  format_cb_host
2644 	},
2645 	{ "host_short", FORMAT_TABLE_STRING,
2646 	  format_cb_host_short
2647 	},
2648 	{ "insert_flag", FORMAT_TABLE_STRING,
2649 	  format_cb_insert_flag
2650 	},
2651 	{ "keypad_cursor_flag", FORMAT_TABLE_STRING,
2652 	  format_cb_keypad_cursor_flag
2653 	},
2654 	{ "keypad_flag", FORMAT_TABLE_STRING,
2655 	  format_cb_keypad_flag
2656 	},
2657 	{ "last_window_index", FORMAT_TABLE_STRING,
2658 	  format_cb_last_window_index
2659 	},
2660 	{ "mouse_all_flag", FORMAT_TABLE_STRING,
2661 	  format_cb_mouse_all_flag
2662 	},
2663 	{ "mouse_any_flag", FORMAT_TABLE_STRING,
2664 	  format_cb_mouse_any_flag
2665 	},
2666 	{ "mouse_button_flag", FORMAT_TABLE_STRING,
2667 	  format_cb_mouse_button_flag
2668 	},
2669 	{ "mouse_line", FORMAT_TABLE_STRING,
2670 	  format_cb_mouse_line
2671 	},
2672 	{ "mouse_pane", FORMAT_TABLE_STRING,
2673 	  format_cb_mouse_pane
2674 	},
2675 	{ "mouse_sgr_flag", FORMAT_TABLE_STRING,
2676 	  format_cb_mouse_sgr_flag
2677 	},
2678 	{ "mouse_standard_flag", FORMAT_TABLE_STRING,
2679 	  format_cb_mouse_standard_flag
2680 	},
2681 	{ "mouse_utf8_flag", FORMAT_TABLE_STRING,
2682 	  format_cb_mouse_utf8_flag
2683 	},
2684 	{ "mouse_word", FORMAT_TABLE_STRING,
2685 	  format_cb_mouse_word
2686 	},
2687 	{ "mouse_x", FORMAT_TABLE_STRING,
2688 	  format_cb_mouse_x
2689 	},
2690 	{ "mouse_y", FORMAT_TABLE_STRING,
2691 	  format_cb_mouse_y
2692 	},
2693 	{ "origin_flag", FORMAT_TABLE_STRING,
2694 	  format_cb_origin_flag
2695 	},
2696 	{ "pane_active", FORMAT_TABLE_STRING,
2697 	  format_cb_pane_active
2698 	},
2699 	{ "pane_at_bottom", FORMAT_TABLE_STRING,
2700 	  format_cb_pane_at_bottom
2701 	},
2702 	{ "pane_at_left", FORMAT_TABLE_STRING,
2703 	  format_cb_pane_at_left
2704 	},
2705 	{ "pane_at_right", FORMAT_TABLE_STRING,
2706 	  format_cb_pane_at_right
2707 	},
2708 	{ "pane_at_top", FORMAT_TABLE_STRING,
2709 	  format_cb_pane_at_top
2710 	},
2711 	{ "pane_bg", FORMAT_TABLE_STRING,
2712 	  format_cb_pane_bg
2713 	},
2714 	{ "pane_bottom", FORMAT_TABLE_STRING,
2715 	  format_cb_pane_bottom
2716 	},
2717 	{ "pane_current_command", FORMAT_TABLE_STRING,
2718 	  format_cb_current_command
2719 	},
2720 	{ "pane_current_path", FORMAT_TABLE_STRING,
2721 	  format_cb_current_path
2722 	},
2723 	{ "pane_dead", FORMAT_TABLE_STRING,
2724 	  format_cb_pane_dead
2725 	},
2726 	{ "pane_dead_status", FORMAT_TABLE_STRING,
2727 	  format_cb_pane_dead_status
2728 	},
2729 	{ "pane_fg", FORMAT_TABLE_STRING,
2730 	  format_cb_pane_fg
2731 	},
2732 	{ "pane_format", FORMAT_TABLE_STRING,
2733 	  format_cb_pane_format
2734 	},
2735 	{ "pane_height", FORMAT_TABLE_STRING,
2736 	  format_cb_pane_height
2737 	},
2738 	{ "pane_id", FORMAT_TABLE_STRING,
2739 	  format_cb_pane_id
2740 	},
2741 	{ "pane_in_mode", FORMAT_TABLE_STRING,
2742 	  format_cb_pane_in_mode
2743 	},
2744 	{ "pane_index", FORMAT_TABLE_STRING,
2745 	  format_cb_pane_index
2746 	},
2747 	{ "pane_input_off", FORMAT_TABLE_STRING,
2748 	  format_cb_pane_input_off
2749 	},
2750 	{ "pane_last", FORMAT_TABLE_STRING,
2751 	  format_cb_pane_last
2752 	},
2753 	{ "pane_left", FORMAT_TABLE_STRING,
2754 	  format_cb_pane_left
2755 	},
2756 	{ "pane_marked", FORMAT_TABLE_STRING,
2757 	  format_cb_pane_marked
2758 	},
2759 	{ "pane_marked_set", FORMAT_TABLE_STRING,
2760 	  format_cb_pane_marked_set
2761 	},
2762 	{ "pane_mode", FORMAT_TABLE_STRING,
2763 	  format_cb_pane_mode
2764 	},
2765 	{ "pane_path", FORMAT_TABLE_STRING,
2766 	  format_cb_pane_path
2767 	},
2768 	{ "pane_pid", FORMAT_TABLE_STRING,
2769 	  format_cb_pane_pid
2770 	},
2771 	{ "pane_pipe", FORMAT_TABLE_STRING,
2772 	  format_cb_pane_pipe
2773 	},
2774 	{ "pane_right", FORMAT_TABLE_STRING,
2775 	  format_cb_pane_right
2776 	},
2777 	{ "pane_search_string", FORMAT_TABLE_STRING,
2778 	  format_cb_pane_search_string
2779 	},
2780 	{ "pane_start_command", FORMAT_TABLE_STRING,
2781 	  format_cb_start_command
2782 	},
2783 	{ "pane_synchronized", FORMAT_TABLE_STRING,
2784 	  format_cb_pane_synchronized
2785 	},
2786 	{ "pane_tabs", FORMAT_TABLE_STRING,
2787 	  format_cb_pane_tabs
2788 	},
2789 	{ "pane_title", FORMAT_TABLE_STRING,
2790 	  format_cb_pane_title
2791 	},
2792 	{ "pane_top", FORMAT_TABLE_STRING,
2793 	  format_cb_pane_top
2794 	},
2795 	{ "pane_tty", FORMAT_TABLE_STRING,
2796 	  format_cb_pane_tty
2797 	},
2798 	{ "pane_width", FORMAT_TABLE_STRING,
2799 	  format_cb_pane_width
2800 	},
2801 	{ "pid", FORMAT_TABLE_STRING,
2802 	  format_cb_pid
2803 	},
2804 	{ "scroll_region_lower", FORMAT_TABLE_STRING,
2805 	  format_cb_scroll_region_lower
2806 	},
2807 	{ "scroll_region_upper", FORMAT_TABLE_STRING,
2808 	  format_cb_scroll_region_upper
2809 	},
2810 	{ "session_activity", FORMAT_TABLE_TIME,
2811 	  format_cb_session_activity
2812 	},
2813 	{ "session_alerts", FORMAT_TABLE_STRING,
2814 	  format_cb_session_alerts
2815 	},
2816 	{ "session_attached", FORMAT_TABLE_STRING,
2817 	  format_cb_session_attached
2818 	},
2819 	{ "session_attached_list", FORMAT_TABLE_STRING,
2820 	  format_cb_session_attached_list
2821 	},
2822 	{ "session_created", FORMAT_TABLE_TIME,
2823 	  format_cb_session_created
2824 	},
2825 	{ "session_format", FORMAT_TABLE_STRING,
2826 	  format_cb_session_format
2827 	},
2828 	{ "session_group", FORMAT_TABLE_STRING,
2829 	  format_cb_session_group
2830 	},
2831 	{ "session_group_attached", FORMAT_TABLE_STRING,
2832 	  format_cb_session_group_attached
2833 	},
2834 	{ "session_group_attached_list", FORMAT_TABLE_STRING,
2835 	  format_cb_session_group_attached_list
2836 	},
2837 	{ "session_group_list", FORMAT_TABLE_STRING,
2838 	  format_cb_session_group_list
2839 	},
2840 	{ "session_group_many_attached", FORMAT_TABLE_STRING,
2841 	  format_cb_session_group_many_attached
2842 	},
2843 	{ "session_group_size", FORMAT_TABLE_STRING,
2844 	  format_cb_session_group_size
2845 	},
2846 	{ "session_grouped", FORMAT_TABLE_STRING,
2847 	  format_cb_session_grouped
2848 	},
2849 	{ "session_id", FORMAT_TABLE_STRING,
2850 	  format_cb_session_id
2851 	},
2852 	{ "session_last_attached", FORMAT_TABLE_TIME,
2853 	  format_cb_session_last_attached
2854 	},
2855 	{ "session_many_attached", FORMAT_TABLE_STRING,
2856 	  format_cb_session_many_attached
2857 	},
2858 	{ "session_marked", FORMAT_TABLE_STRING,
2859 	  format_cb_session_marked,
2860 	},
2861 	{ "session_name", FORMAT_TABLE_STRING,
2862 	  format_cb_session_name
2863 	},
2864 	{ "session_path", FORMAT_TABLE_STRING,
2865 	  format_cb_session_path
2866 	},
2867 	{ "session_stack", FORMAT_TABLE_STRING,
2868 	  format_cb_session_stack
2869 	},
2870 	{ "session_windows", FORMAT_TABLE_STRING,
2871 	  format_cb_session_windows
2872 	},
2873 	{ "socket_path", FORMAT_TABLE_STRING,
2874 	  format_cb_socket_path
2875 	},
2876 	{ "start_time", FORMAT_TABLE_TIME,
2877 	  format_cb_start_time
2878 	},
2879 	{ "tree_mode_format", FORMAT_TABLE_STRING,
2880 	  format_cb_tree_mode_format
2881 	},
2882 	{ "version", FORMAT_TABLE_STRING,
2883 	  format_cb_version
2884 	},
2885 	{ "window_active", FORMAT_TABLE_STRING,
2886 	  format_cb_window_active
2887 	},
2888 	{ "window_active_clients", FORMAT_TABLE_STRING,
2889 	  format_cb_window_active_clients
2890 	},
2891 	{ "window_active_clients_list", FORMAT_TABLE_STRING,
2892 	  format_cb_window_active_clients_list
2893 	},
2894 	{ "window_active_sessions", FORMAT_TABLE_STRING,
2895 	  format_cb_window_active_sessions
2896 	},
2897 	{ "window_active_sessions_list", FORMAT_TABLE_STRING,
2898 	  format_cb_window_active_sessions_list
2899 	},
2900 	{ "window_activity", FORMAT_TABLE_TIME,
2901 	  format_cb_window_activity
2902 	},
2903 	{ "window_activity_flag", FORMAT_TABLE_STRING,
2904 	  format_cb_window_activity_flag
2905 	},
2906 	{ "window_bell_flag", FORMAT_TABLE_STRING,
2907 	  format_cb_window_bell_flag
2908 	},
2909 	{ "window_bigger", FORMAT_TABLE_STRING,
2910 	  format_cb_window_bigger
2911 	},
2912 	{ "window_cell_height", FORMAT_TABLE_STRING,
2913 	  format_cb_window_cell_height
2914 	},
2915 	{ "window_cell_width", FORMAT_TABLE_STRING,
2916 	  format_cb_window_cell_width
2917 	},
2918 	{ "window_end_flag", FORMAT_TABLE_STRING,
2919 	  format_cb_window_end_flag
2920 	},
2921 	{ "window_flags", FORMAT_TABLE_STRING,
2922 	  format_cb_window_flags
2923 	},
2924 	{ "window_format", FORMAT_TABLE_STRING,
2925 	  format_cb_window_format
2926 	},
2927 	{ "window_height", FORMAT_TABLE_STRING,
2928 	  format_cb_window_height
2929 	},
2930 	{ "window_id", FORMAT_TABLE_STRING,
2931 	  format_cb_window_id
2932 	},
2933 	{ "window_index", FORMAT_TABLE_STRING,
2934 	  format_cb_window_index
2935 	},
2936 	{ "window_last_flag", FORMAT_TABLE_STRING,
2937 	  format_cb_window_last_flag
2938 	},
2939 	{ "window_layout", FORMAT_TABLE_STRING,
2940 	  format_cb_window_layout
2941 	},
2942 	{ "window_linked", FORMAT_TABLE_STRING,
2943 	  format_cb_window_linked
2944 	},
2945 	{ "window_linked_sessions", FORMAT_TABLE_STRING,
2946 	  format_cb_window_linked_sessions
2947 	},
2948 	{ "window_linked_sessions_list", FORMAT_TABLE_STRING,
2949 	  format_cb_window_linked_sessions_list
2950 	},
2951 	{ "window_marked_flag", FORMAT_TABLE_STRING,
2952 	  format_cb_window_marked_flag
2953 	},
2954 	{ "window_name", FORMAT_TABLE_STRING,
2955 	  format_cb_window_name
2956 	},
2957 	{ "window_offset_x", FORMAT_TABLE_STRING,
2958 	  format_cb_window_offset_x
2959 	},
2960 	{ "window_offset_y", FORMAT_TABLE_STRING,
2961 	  format_cb_window_offset_y
2962 	},
2963 	{ "window_panes", FORMAT_TABLE_STRING,
2964 	  format_cb_window_panes
2965 	},
2966 	{ "window_raw_flags", FORMAT_TABLE_STRING,
2967 	  format_cb_window_raw_flags
2968 	},
2969 	{ "window_silence_flag", FORMAT_TABLE_STRING,
2970 	  format_cb_window_silence_flag
2971 	},
2972 	{ "window_stack_index", FORMAT_TABLE_STRING,
2973 	  format_cb_window_stack_index
2974 	},
2975 	{ "window_start_flag", FORMAT_TABLE_STRING,
2976 	  format_cb_window_start_flag
2977 	},
2978 	{ "window_visible_layout", FORMAT_TABLE_STRING,
2979 	  format_cb_window_visible_layout
2980 	},
2981 	{ "window_width", FORMAT_TABLE_STRING,
2982 	  format_cb_window_width
2983 	},
2984 	{ "window_zoomed_flag", FORMAT_TABLE_STRING,
2985 	  format_cb_window_zoomed_flag
2986 	},
2987 	{ "wrap_flag", FORMAT_TABLE_STRING,
2988 	  format_cb_wrap_flag
2989 	}
2990 };
2991 
2992 /* Compare format table entries. */
2993 static int
format_table_compare(const void * key0,const void * entry0)2994 format_table_compare(const void *key0, const void *entry0)
2995 {
2996 	const char			*key = key0;
2997 	const struct format_table_entry	*entry = entry0;
2998 
2999 	return (strcmp(key, entry->key));
3000 }
3001 
3002 /* Get a format callback. */
3003 static struct format_table_entry *
format_table_get(const char * key)3004 format_table_get(const char *key)
3005 {
3006 	return (bsearch(key, format_table, nitems(format_table),
3007 	    sizeof *format_table, format_table_compare));
3008 }
3009 
3010 /* Merge one format tree into another. */
3011 void
format_merge(struct format_tree * ft,struct format_tree * from)3012 format_merge(struct format_tree *ft, struct format_tree *from)
3013 {
3014 	struct format_entry	*fe;
3015 
3016 	RB_FOREACH(fe, format_entry_tree, &from->tree) {
3017 		if (fe->value != NULL)
3018 			format_add(ft, fe->key, "%s", fe->value);
3019 	}
3020 }
3021 
3022 /* Get format pane. */
3023 struct window_pane *
format_get_pane(struct format_tree * ft)3024 format_get_pane(struct format_tree *ft)
3025 {
3026 	return (ft->wp);
3027 }
3028 
3029 /* Add item bits to tree. */
3030 static void
format_create_add_item(struct format_tree * ft,struct cmdq_item * item)3031 format_create_add_item(struct format_tree *ft, struct cmdq_item *item)
3032 {
3033 	struct key_event	*event = cmdq_get_event(item);
3034 	struct mouse_event	*m = &event->m;
3035 
3036 	cmdq_merge_formats(item, ft);
3037 	memcpy(&ft->m, m, sizeof ft->m);
3038 }
3039 
3040 /* Create a new tree. */
3041 struct format_tree *
format_create(struct client * c,struct cmdq_item * item,int tag,int flags)3042 format_create(struct client *c, struct cmdq_item *item, int tag, int flags)
3043 {
3044 	struct format_tree	*ft;
3045 
3046 	ft = xcalloc(1, sizeof *ft);
3047 	RB_INIT(&ft->tree);
3048 
3049 	if (c != NULL) {
3050 		ft->client = c;
3051 		ft->client->references++;
3052 	}
3053 	ft->item = item;
3054 
3055 	ft->tag = tag;
3056 	ft->flags = flags;
3057 
3058 	if (item != NULL)
3059 		format_create_add_item(ft, item);
3060 
3061 	return (ft);
3062 }
3063 
3064 /* Free a tree. */
3065 void
format_free(struct format_tree * ft)3066 format_free(struct format_tree *ft)
3067 {
3068 	struct format_entry	*fe, *fe1;
3069 
3070 	RB_FOREACH_SAFE(fe, format_entry_tree, &ft->tree, fe1) {
3071 		RB_REMOVE(format_entry_tree, &ft->tree, fe);
3072 		free(fe->value);
3073 		free(fe->key);
3074 		free(fe);
3075 	}
3076 
3077 	if (ft->client != NULL)
3078 		server_client_unref(ft->client);
3079 	free(ft);
3080 }
3081 
3082 /* Walk each format. */
3083 void
format_each(struct format_tree * ft,void (* cb)(const char *,const char *,void *),void * arg)3084 format_each(struct format_tree *ft, void (*cb)(const char *, const char *,
3085     void *), void *arg)
3086 {
3087 	const struct format_table_entry	*fte;
3088 	struct format_entry		*fe;
3089 	u_int				 i;
3090 	char				 s[64];
3091 	void				*value;
3092 	struct timeval			*tv;
3093 
3094 	for (i = 0; i < nitems(format_table); i++) {
3095 		fte = &format_table[i];
3096 
3097 		value = fte->cb(ft);
3098 		if (value == NULL)
3099 			continue;
3100 		if (fte->type == FORMAT_TABLE_TIME) {
3101 			tv = value;
3102 			xsnprintf(s, sizeof s, "%lld", (long long)tv->tv_sec);
3103 			cb(fte->key, s, arg);
3104 		} else {
3105 			cb(fte->key, value, arg);
3106 			free(value);
3107 		}
3108 	}
3109 	RB_FOREACH(fe, format_entry_tree, &ft->tree) {
3110 		if (fe->time != 0) {
3111 			xsnprintf(s, sizeof s, "%lld", (long long)fe->time);
3112 			cb(fe->key, s, arg);
3113 		} else {
3114 			if (fe->value == NULL && fe->cb != NULL) {
3115 				fe->value = fe->cb(ft);
3116 				if (fe->value == NULL)
3117 					fe->value = xstrdup("");
3118 			}
3119 			cb(fe->key, fe->value, arg);
3120 		}
3121 	}
3122 }
3123 
3124 /* Add a key-value pair. */
3125 void
format_add(struct format_tree * ft,const char * key,const char * fmt,...)3126 format_add(struct format_tree *ft, const char *key, const char *fmt, ...)
3127 {
3128 	struct format_entry	*fe;
3129 	struct format_entry	*fe_now;
3130 	va_list			 ap;
3131 
3132 	fe = xmalloc(sizeof *fe);
3133 	fe->key = xstrdup(key);
3134 
3135 	fe_now = RB_INSERT(format_entry_tree, &ft->tree, fe);
3136 	if (fe_now != NULL) {
3137 		free(fe->key);
3138 		free(fe);
3139 		free(fe_now->value);
3140 		fe = fe_now;
3141 	}
3142 
3143 	fe->cb = NULL;
3144 	fe->time = 0;
3145 
3146 	va_start(ap, fmt);
3147 	xvasprintf(&fe->value, fmt, ap);
3148 	va_end(ap);
3149 }
3150 
3151 /* Add a key and time. */
3152 void
format_add_tv(struct format_tree * ft,const char * key,struct timeval * tv)3153 format_add_tv(struct format_tree *ft, const char *key, struct timeval *tv)
3154 {
3155 	struct format_entry	*fe, *fe_now;
3156 
3157 	fe = xmalloc(sizeof *fe);
3158 	fe->key = xstrdup(key);
3159 
3160 	fe_now = RB_INSERT(format_entry_tree, &ft->tree, fe);
3161 	if (fe_now != NULL) {
3162 		free(fe->key);
3163 		free(fe);
3164 		free(fe_now->value);
3165 		fe = fe_now;
3166 	}
3167 
3168 	fe->cb = NULL;
3169 	fe->time = tv->tv_sec;
3170 
3171 	fe->value = NULL;
3172 }
3173 
3174 /* Add a key and function. */
3175 void
format_add_cb(struct format_tree * ft,const char * key,format_cb cb)3176 format_add_cb(struct format_tree *ft, const char *key, format_cb cb)
3177 {
3178 	struct format_entry	*fe;
3179 	struct format_entry	*fe_now;
3180 
3181 	fe = xmalloc(sizeof *fe);
3182 	fe->key = xstrdup(key);
3183 
3184 	fe_now = RB_INSERT(format_entry_tree, &ft->tree, fe);
3185 	if (fe_now != NULL) {
3186 		free(fe->key);
3187 		free(fe);
3188 		free(fe_now->value);
3189 		fe = fe_now;
3190 	}
3191 
3192 	fe->cb = cb;
3193 	fe->time = 0;
3194 
3195 	fe->value = NULL;
3196 }
3197 
3198 /* Quote shell special characters in string. */
3199 static char *
format_quote_shell(const char * s)3200 format_quote_shell(const char *s)
3201 {
3202 	const char	*cp;
3203 	char		*out, *at;
3204 
3205 	at = out = xmalloc(strlen(s) * 2 + 1);
3206 	for (cp = s; *cp != '\0'; cp++) {
3207 		if (strchr("|&;<>()$`\\\"'*?[# =%", *cp) != NULL)
3208 			*at++ = '\\';
3209 		*at++ = *cp;
3210 	}
3211 	*at = '\0';
3212 	return (out);
3213 }
3214 
3215 /* Quote #s in string. */
3216 static char *
format_quote_style(const char * s)3217 format_quote_style(const char *s)
3218 {
3219 	const char	*cp;
3220 	char		*out, *at;
3221 
3222 	at = out = xmalloc(strlen(s) * 2 + 1);
3223 	for (cp = s; *cp != '\0'; cp++) {
3224 		if (*cp == '#')
3225 			*at++ = '#';
3226 		*at++ = *cp;
3227 	}
3228 	*at = '\0';
3229 	return (out);
3230 }
3231 
3232 /* Make a prettier time. */
3233 static char *
format_pretty_time(time_t t)3234 format_pretty_time(time_t t)
3235 {
3236 	struct tm       now_tm, tm;
3237 	time_t		now, age;
3238 	char		s[6];
3239 
3240 	time(&now);
3241 	if (now < t)
3242 		now = t;
3243 	age = now - t;
3244 
3245 	localtime_r(&now, &now_tm);
3246 	localtime_r(&t, &tm);
3247 
3248 	/* Last 24 hours. */
3249 	if (age < 24 * 3600) {
3250 		strftime(s, sizeof s, "%H:%M", &tm);
3251 		return (xstrdup(s));
3252 	}
3253 
3254 	/* This month or last 28 days. */
3255 	if ((tm.tm_year == now_tm.tm_year && tm.tm_mon == now_tm.tm_mon) ||
3256 	    age < 28 * 24 * 3600) {
3257 		strftime(s, sizeof s, "%a%d", &tm);
3258 		return (xstrdup(s));
3259 	}
3260 
3261 	/* Last 12 months. */
3262 	if ((tm.tm_year == now_tm.tm_year && tm.tm_mon < now_tm.tm_mon) ||
3263 	    (tm.tm_year == now_tm.tm_year - 1 && tm.tm_mon > now_tm.tm_mon)) {
3264 		strftime(s, sizeof s, "%d%b", &tm);
3265 		return (xstrdup(s));
3266 	}
3267 
3268 	/* Older than that. */
3269 	strftime(s, sizeof s, "%h%y", &tm);
3270 	return (xstrdup(s));
3271 }
3272 
3273 /* Find a format entry. */
3274 static char *
format_find(struct format_tree * ft,const char * key,int modifiers,const char * time_format)3275 format_find(struct format_tree *ft, const char *key, int modifiers,
3276     const char *time_format)
3277 {
3278 	struct format_table_entry	*fte;
3279 	void				*value;
3280 	struct format_entry		*fe, fe_find;
3281 	struct environ_entry		*envent;
3282 	struct options_entry		*o;
3283 	int				 idx;
3284 	char				*found = NULL, *saved, s[512];
3285 	const char			*errstr;
3286 	time_t				 t = 0;
3287 	struct tm			 tm;
3288 
3289 	o = options_parse_get(global_options, key, &idx, 0);
3290 	if (o == NULL && ft->wp != NULL)
3291 		o = options_parse_get(ft->wp->options, key, &idx, 0);
3292 	if (o == NULL && ft->w != NULL)
3293 		o = options_parse_get(ft->w->options, key, &idx, 0);
3294 	if (o == NULL)
3295 		o = options_parse_get(global_w_options, key, &idx, 0);
3296 	if (o == NULL && ft->s != NULL)
3297 		o = options_parse_get(ft->s->options, key, &idx, 0);
3298 	if (o == NULL)
3299 		o = options_parse_get(global_s_options, key, &idx, 0);
3300 	if (o != NULL) {
3301 		found = options_to_string(o, idx, 1);
3302 		goto found;
3303 	}
3304 
3305 	fte = format_table_get(key);
3306 	if (fte != NULL) {
3307 		value = fte->cb(ft);
3308 		if (fte->type == FORMAT_TABLE_TIME)
3309 			t = ((struct timeval *)value)->tv_sec;
3310 		else
3311 			found = value;
3312 		goto found;
3313 	}
3314 	fe_find.key = (char *)key;
3315 	fe = RB_FIND(format_entry_tree, &ft->tree, &fe_find);
3316 	if (fe != NULL) {
3317 		if (fe->time != 0) {
3318 			t = fe->time;
3319 			goto found;
3320 		}
3321 		if (fe->value == NULL && fe->cb != NULL) {
3322 			fe->value = fe->cb(ft);
3323 			if (fe->value == NULL)
3324 				fe->value = xstrdup("");
3325 		}
3326 		found = xstrdup(fe->value);
3327 		goto found;
3328 	}
3329 
3330 	if (~modifiers & FORMAT_TIMESTRING) {
3331 		envent = NULL;
3332 		if (ft->s != NULL)
3333 			envent = environ_find(ft->s->environ, key);
3334 		if (envent == NULL)
3335 			envent = environ_find(global_environ, key);
3336 		if (envent != NULL && envent->value != NULL) {
3337 			found = xstrdup(envent->value);
3338 			goto found;
3339 		}
3340 	}
3341 
3342 	return (NULL);
3343 
3344 found:
3345 	if (modifiers & FORMAT_TIMESTRING) {
3346 		if (t == 0 && found != NULL) {
3347 			t = strtonum(found, 0, INT64_MAX, &errstr);
3348 			if (errstr != NULL)
3349 				t = 0;
3350 			free(found);
3351 		}
3352 		if (t == 0)
3353 			return (NULL);
3354 		if (modifiers & FORMAT_PRETTY)
3355 			found = format_pretty_time(t);
3356 		else {
3357 			if (time_format != NULL) {
3358 				localtime_r(&t, &tm);
3359 				strftime(s, sizeof s, time_format, &tm);
3360 			} else {
3361 				ctime_r(&t, s);
3362 				s[strcspn(s, "\n")] = '\0';
3363 			}
3364 			found = xstrdup(s);
3365 		}
3366 		return (found);
3367 	}
3368 
3369 	if (t != 0)
3370 		xasprintf(&found, "%lld", (long long)t);
3371 	else if (found == NULL)
3372 		return (NULL);
3373 	if (modifiers & FORMAT_BASENAME) {
3374 		saved = found;
3375 		found = xstrdup(basename(saved));
3376 		free(saved);
3377 	}
3378 	if (modifiers & FORMAT_DIRNAME) {
3379 		saved = found;
3380 		found = xstrdup(dirname(saved));
3381 		free(saved);
3382 	}
3383 	if (modifiers & FORMAT_QUOTE_SHELL) {
3384 		saved = found;
3385 		found = xstrdup(format_quote_shell(saved));
3386 		free(saved);
3387 	}
3388 	if (modifiers & FORMAT_QUOTE_STYLE) {
3389 		saved = found;
3390 		found = xstrdup(format_quote_style(saved));
3391 		free(saved);
3392 	}
3393 	return (found);
3394 }
3395 
3396 /* Remove escaped characters from string. */
3397 static char *
format_strip(const char * s)3398 format_strip(const char *s)
3399 {
3400 	char	*out, *cp;
3401 	int	 brackets = 0;
3402 
3403 	cp = out = xmalloc(strlen(s) + 1);
3404 	for (; *s != '\0'; s++) {
3405 		if (*s == '#' && s[1] == '{')
3406 			brackets++;
3407 		if (*s == '#' && strchr(",#{}:", s[1]) != NULL) {
3408 			if (brackets != 0)
3409 				*cp++ = *s;
3410 			continue;
3411 		}
3412 		if (*s == '}')
3413 			brackets--;
3414 		*cp++ = *s;
3415 	}
3416 	*cp = '\0';
3417 	return (out);
3418 }
3419 
3420 /* Skip until end. */
3421 const char *
format_skip(const char * s,const char * end)3422 format_skip(const char *s, const char *end)
3423 {
3424 	int	brackets = 0;
3425 
3426 	for (; *s != '\0'; s++) {
3427 		if (*s == '#' && s[1] == '{')
3428 			brackets++;
3429 		if (*s == '#' && strchr(",#{}:", s[1]) != NULL) {
3430 			s++;
3431 			continue;
3432 		}
3433 		if (*s == '}')
3434 			brackets--;
3435 		if (strchr(end, *s) != NULL && brackets == 0)
3436 			break;
3437 	}
3438 	if (*s == '\0')
3439 		return (NULL);
3440 	return (s);
3441 }
3442 
3443 /* Return left and right alternatives separated by commas. */
3444 static int
format_choose(struct format_expand_state * es,const char * s,char ** left,char ** right,int expand)3445 format_choose(struct format_expand_state *es, const char *s, char **left,
3446     char **right, int expand)
3447 {
3448 	const char	*cp;
3449 	char		*left0, *right0;
3450 
3451 	cp = format_skip(s, ",");
3452 	if (cp == NULL)
3453 		return (-1);
3454 	left0 = xstrndup(s, cp - s);
3455 	right0 = xstrdup(cp + 1);
3456 
3457 	if (expand) {
3458 		*left = format_expand1(es, left0);
3459 		free(left0);
3460 		*right = format_expand1(es, right0);
3461 		free(right0);
3462 	} else {
3463 		*left = left0;
3464 		*right = right0;
3465 	}
3466 	return (0);
3467 }
3468 
3469 /* Is this true? */
3470 int
format_true(const char * s)3471 format_true(const char *s)
3472 {
3473 	if (s != NULL && *s != '\0' && (s[0] != '0' || s[1] != '\0'))
3474 		return (1);
3475 	return (0);
3476 }
3477 
3478 /* Check if modifier end. */
3479 static int
format_is_end(char c)3480 format_is_end(char c)
3481 {
3482 	return (c == ';' || c == ':');
3483 }
3484 
3485 /* Add to modifier list. */
3486 static void
format_add_modifier(struct format_modifier ** list,u_int * count,const char * c,size_t n,char ** argv,int argc)3487 format_add_modifier(struct format_modifier **list, u_int *count,
3488     const char *c, size_t n, char **argv, int argc)
3489 {
3490 	struct format_modifier *fm;
3491 
3492 	*list = xreallocarray(*list, (*count) + 1, sizeof **list);
3493 	fm = &(*list)[(*count)++];
3494 
3495 	memcpy(fm->modifier, c, n);
3496 	fm->modifier[n] = '\0';
3497 	fm->size = n;
3498 
3499 	fm->argv = argv;
3500 	fm->argc = argc;
3501 }
3502 
3503 /* Free modifier list. */
3504 static void
format_free_modifiers(struct format_modifier * list,u_int count)3505 format_free_modifiers(struct format_modifier *list, u_int count)
3506 {
3507 	u_int	i;
3508 
3509 	for (i = 0; i < count; i++)
3510 		cmd_free_argv(list[i].argc, list[i].argv);
3511 	free(list);
3512 }
3513 
3514 /* Build modifier list. */
3515 static struct format_modifier *
format_build_modifiers(struct format_expand_state * es,const char ** s,u_int * count)3516 format_build_modifiers(struct format_expand_state *es, const char **s,
3517     u_int *count)
3518 {
3519 	const char		*cp = *s, *end;
3520 	struct format_modifier	*list = NULL;
3521 	char			 c, last[] = "X;:", **argv, *value;
3522 	int			 argc;
3523 
3524 	/*
3525 	 * Modifiers are a ; separated list of the forms:
3526 	 *      l,m,C,a,b,d,n,t,w,q,E,T,S,W,P,<,>
3527 	 *	=a
3528 	 *	=/a
3529 	 *      =/a/
3530 	 *	s/a/b/
3531 	 *	s/a/b
3532 	 *	||,&&,!=,==,<=,>=
3533 	 */
3534 
3535 	*count = 0;
3536 
3537 	while (*cp != '\0' && *cp != ':') {
3538 		/* Skip any separator character. */
3539 		if (*cp == ';')
3540 			cp++;
3541 
3542 		/* Check single character modifiers with no arguments. */
3543 		if (strchr("labdnwETSWP<>", cp[0]) != NULL &&
3544 		    format_is_end(cp[1])) {
3545 			format_add_modifier(&list, count, cp, 1, NULL, 0);
3546 			cp++;
3547 			continue;
3548 		}
3549 
3550 		/* Then try double character with no arguments. */
3551 		if ((memcmp("||", cp, 2) == 0 ||
3552 		    memcmp("&&", cp, 2) == 0 ||
3553 		    memcmp("!=", cp, 2) == 0 ||
3554 		    memcmp("==", cp, 2) == 0 ||
3555 		    memcmp("<=", cp, 2) == 0 ||
3556 		    memcmp(">=", cp, 2) == 0) &&
3557 		    format_is_end(cp[2])) {
3558 			format_add_modifier(&list, count, cp, 2, NULL, 0);
3559 			cp += 2;
3560 			continue;
3561 		}
3562 
3563 		/* Now try single character with arguments. */
3564 		if (strchr("mCNst=peq", cp[0]) == NULL)
3565 			break;
3566 		c = cp[0];
3567 
3568 		/* No arguments provided. */
3569 		if (format_is_end(cp[1])) {
3570 			format_add_modifier(&list, count, cp, 1, NULL, 0);
3571 			cp++;
3572 			continue;
3573 		}
3574 		argv = NULL;
3575 		argc = 0;
3576 
3577 		/* Single argument with no wrapper character. */
3578 		if (!ispunct(cp[1]) || cp[1] == '-') {
3579 			end = format_skip(cp + 1, ":;");
3580 			if (end == NULL)
3581 				break;
3582 
3583 			argv = xcalloc(1, sizeof *argv);
3584 			value = xstrndup(cp + 1, end - (cp + 1));
3585 			argv[0] = format_expand1(es, value);
3586 			free(value);
3587 			argc = 1;
3588 
3589 			format_add_modifier(&list, count, &c, 1, argv, argc);
3590 			cp = end;
3591 			continue;
3592 		}
3593 
3594 		/* Multiple arguments with a wrapper character. */
3595 		last[0] = cp[1];
3596 		cp++;
3597 		do {
3598 			if (cp[0] == last[0] && format_is_end(cp[1])) {
3599 				cp++;
3600 				break;
3601 			}
3602 			end = format_skip(cp + 1, last);
3603 			if (end == NULL)
3604 				break;
3605 			cp++;
3606 
3607 			argv = xreallocarray (argv, argc + 1, sizeof *argv);
3608 			value = xstrndup(cp, end - cp);
3609 			argv[argc++] = format_expand1(es, value);
3610 			free(value);
3611 
3612 			cp = end;
3613 		} while (!format_is_end(cp[0]));
3614 		format_add_modifier(&list, count, &c, 1, argv, argc);
3615 	}
3616 	if (*cp != ':') {
3617 		format_free_modifiers(list, *count);
3618 		*count = 0;
3619 		return (NULL);
3620 	}
3621 	*s = cp + 1;
3622 	return (list);
3623 }
3624 
3625 /* Match against an fnmatch(3) pattern or regular expression. */
3626 static char *
format_match(struct format_modifier * fm,const char * pattern,const char * text)3627 format_match(struct format_modifier *fm, const char *pattern, const char *text)
3628 {
3629 	const char	*s = "";
3630 	regex_t		 r;
3631 	int		 flags = 0;
3632 
3633 	if (fm->argc >= 1)
3634 		s = fm->argv[0];
3635 	if (strchr(s, 'r') == NULL) {
3636 		if (strchr(s, 'i') != NULL)
3637 			flags |= FNM_CASEFOLD;
3638 		if (fnmatch(pattern, text, flags) != 0)
3639 			return (xstrdup("0"));
3640 	} else {
3641 		flags = REG_EXTENDED|REG_NOSUB;
3642 		if (strchr(s, 'i') != NULL)
3643 			flags |= REG_ICASE;
3644 		if (regcomp(&r, pattern, flags) != 0)
3645 			return (xstrdup("0"));
3646 		if (regexec(&r, text, 0, NULL, 0) != 0) {
3647 			regfree(&r);
3648 			return (xstrdup("0"));
3649 		}
3650 		regfree(&r);
3651 	}
3652 	return (xstrdup("1"));
3653 }
3654 
3655 /* Perform substitution in string. */
3656 static char *
format_sub(struct format_modifier * fm,const char * text,const char * pattern,const char * with)3657 format_sub(struct format_modifier *fm, const char *text, const char *pattern,
3658     const char *with)
3659 {
3660 	char	*value;
3661 	int	 flags = REG_EXTENDED;
3662 
3663 	if (fm->argc >= 3 && strchr(fm->argv[2], 'i') != NULL)
3664 		flags |= REG_ICASE;
3665 	value = regsub(pattern, with, text, flags);
3666 	if (value == NULL)
3667 		return (xstrdup(text));
3668 	return (value);
3669 }
3670 
3671 /* Search inside pane. */
3672 static char *
format_search(struct format_modifier * fm,struct window_pane * wp,const char * s)3673 format_search(struct format_modifier *fm, struct window_pane *wp, const char *s)
3674 {
3675 	int	 ignore = 0, regex = 0;
3676 	char	*value;
3677 
3678 	if (fm->argc >= 1) {
3679 		if (strchr(fm->argv[0], 'i') != NULL)
3680 			ignore = 1;
3681 		if (strchr(fm->argv[0], 'r') != NULL)
3682 			regex = 1;
3683 	}
3684 	xasprintf(&value, "%u", window_pane_search(wp, s, regex, ignore));
3685 	return (value);
3686 }
3687 
3688 /* Does session name exist? */
3689 static char *
format_session_name(struct format_expand_state * es,const char * fmt)3690 format_session_name(struct format_expand_state *es, const char *fmt)
3691 {
3692 	char		*name;
3693 	struct session	*s;
3694 
3695 	name = format_expand1(es, fmt);
3696 	RB_FOREACH(s, sessions, &sessions) {
3697 		if (strcmp(s->name, name) == 0) {
3698 			free(name);
3699 			return (xstrdup("1"));
3700 		}
3701 	}
3702 	free(name);
3703 	return (xstrdup("0"));
3704 }
3705 
3706 /* Loop over sessions. */
3707 static char *
format_loop_sessions(struct format_expand_state * es,const char * fmt)3708 format_loop_sessions(struct format_expand_state *es, const char *fmt)
3709 {
3710 	struct format_tree		*ft = es->ft;
3711 	struct client			*c = ft->client;
3712 	struct cmdq_item		*item = ft->item;
3713 	struct format_tree		*nft;
3714 	struct format_expand_state	 next;
3715 	char				*expanded, *value;
3716 	size_t				 valuelen;
3717 	struct session			*s;
3718 
3719 	value = xcalloc(1, 1);
3720 	valuelen = 1;
3721 
3722 	RB_FOREACH(s, sessions, &sessions) {
3723 		format_log(es, "session loop: $%u", s->id);
3724 		nft = format_create(c, item, FORMAT_NONE, ft->flags);
3725 		format_defaults(nft, ft->c, s, NULL, NULL);
3726 		format_copy_state(&next, es, 0);
3727 		next.ft = nft;
3728 		expanded = format_expand1(&next, fmt);
3729 		format_free(next.ft);
3730 
3731 		valuelen += strlen(expanded);
3732 		value = xrealloc(value, valuelen);
3733 
3734 		strlcat(value, expanded, valuelen);
3735 		free(expanded);
3736 	}
3737 
3738 	return (value);
3739 }
3740 
3741 /* Does window name exist? */
3742 static char *
format_window_name(struct format_expand_state * es,const char * fmt)3743 format_window_name(struct format_expand_state *es, const char *fmt)
3744 {
3745 	struct format_tree	*ft = es->ft;
3746 	char			*name;
3747 	struct winlink		*wl;
3748 
3749 	if (ft->s == NULL) {
3750 		format_log(es, "window name but no session");
3751 		return (NULL);
3752 	}
3753 
3754 	name = format_expand1(es, fmt);
3755 	RB_FOREACH(wl, winlinks, &ft->s->windows) {
3756 		if (strcmp(wl->window->name, name) == 0) {
3757 			free(name);
3758 			return (xstrdup("1"));
3759 		}
3760 	}
3761 	free(name);
3762 	return (xstrdup("0"));
3763 }
3764 
3765 /* Loop over windows. */
3766 static char *
format_loop_windows(struct format_expand_state * es,const char * fmt)3767 format_loop_windows(struct format_expand_state *es, const char *fmt)
3768 {
3769 	struct format_tree		*ft = es->ft;
3770 	struct client			*c = ft->client;
3771 	struct cmdq_item		*item = ft->item;
3772 	struct format_tree		*nft;
3773 	struct format_expand_state	 next;
3774 	char				*all, *active, *use, *expanded, *value;
3775 	size_t				 valuelen;
3776 	struct winlink			*wl;
3777 	struct window			*w;
3778 
3779 	if (ft->s == NULL) {
3780 		format_log(es, "window loop but no session");
3781 		return (NULL);
3782 	}
3783 
3784 	if (format_choose(es, fmt, &all, &active, 0) != 0) {
3785 		all = xstrdup(fmt);
3786 		active = NULL;
3787 	}
3788 
3789 	value = xcalloc(1, 1);
3790 	valuelen = 1;
3791 
3792 	RB_FOREACH(wl, winlinks, &ft->s->windows) {
3793 		w = wl->window;
3794 		format_log(es, "window loop: %u @%u", wl->idx, w->id);
3795 		if (active != NULL && wl == ft->s->curw)
3796 			use = active;
3797 		else
3798 			use = all;
3799 		nft = format_create(c, item, FORMAT_WINDOW|w->id, ft->flags);
3800 		format_defaults(nft, ft->c, ft->s, wl, NULL);
3801 		format_copy_state(&next, es, 0);
3802 		next.ft = nft;
3803 		expanded = format_expand1(&next, use);
3804 		format_free(nft);
3805 
3806 		valuelen += strlen(expanded);
3807 		value = xrealloc(value, valuelen);
3808 
3809 		strlcat(value, expanded, valuelen);
3810 		free(expanded);
3811 	}
3812 
3813 	free(active);
3814 	free(all);
3815 
3816 	return (value);
3817 }
3818 
3819 /* Loop over panes. */
3820 static char *
format_loop_panes(struct format_expand_state * es,const char * fmt)3821 format_loop_panes(struct format_expand_state *es, const char *fmt)
3822 {
3823 	struct format_tree		*ft = es->ft;
3824 	struct client			*c = ft->client;
3825 	struct cmdq_item		*item = ft->item;
3826 	struct format_tree		*nft;
3827 	struct format_expand_state	 next;
3828 	char				*all, *active, *use, *expanded, *value;
3829 	size_t				 valuelen;
3830 	struct window_pane		*wp;
3831 
3832 	if (ft->w == NULL) {
3833 		format_log(es, "pane loop but no window");
3834 		return (NULL);
3835 	}
3836 
3837 	if (format_choose(es, fmt, &all, &active, 0) != 0) {
3838 		all = xstrdup(fmt);
3839 		active = NULL;
3840 	}
3841 
3842 	value = xcalloc(1, 1);
3843 	valuelen = 1;
3844 
3845 	TAILQ_FOREACH(wp, &ft->w->panes, entry) {
3846 		format_log(es, "pane loop: %%%u", wp->id);
3847 		if (active != NULL && wp == ft->w->active)
3848 			use = active;
3849 		else
3850 			use = all;
3851 		nft = format_create(c, item, FORMAT_PANE|wp->id, ft->flags);
3852 		format_defaults(nft, ft->c, ft->s, ft->wl, wp);
3853 		format_copy_state(&next, es, 0);
3854 		next.ft = nft;
3855 		expanded = format_expand1(&next, use);
3856 		format_free(nft);
3857 
3858 		valuelen += strlen(expanded);
3859 		value = xrealloc(value, valuelen);
3860 
3861 		strlcat(value, expanded, valuelen);
3862 		free(expanded);
3863 	}
3864 
3865 	free(active);
3866 	free(all);
3867 
3868 	return (value);
3869 }
3870 
3871 static char *
format_replace_expression(struct format_modifier * mexp,struct format_expand_state * es,const char * copy)3872 format_replace_expression(struct format_modifier *mexp,
3873     struct format_expand_state *es, const char *copy)
3874 {
3875 	int			 argc = mexp->argc;
3876 	const char		*errstr;
3877 	char			*endch, *value, *left = NULL, *right = NULL;
3878 	int			 use_fp = 0;
3879 	u_int			 prec = 0;
3880 	double			 mleft, mright, result;
3881 	enum { ADD,
3882 	       SUBTRACT,
3883 	       MULTIPLY,
3884 	       DIVIDE,
3885 	       MODULUS,
3886 	       EQUAL,
3887 	       NOT_EQUAL,
3888 	       GREATER_THAN,
3889 	       GREATER_THAN_EQUAL,
3890 	       LESS_THAN,
3891 	       LESS_THAN_EQUAL } operator;
3892 
3893 	if (strcmp(mexp->argv[0], "+") == 0)
3894 		operator = ADD;
3895 	else if (strcmp(mexp->argv[0], "-") == 0)
3896 		operator = SUBTRACT;
3897 	else if (strcmp(mexp->argv[0], "*") == 0)
3898 		operator = MULTIPLY;
3899 	else if (strcmp(mexp->argv[0], "/") == 0)
3900 		operator = DIVIDE;
3901 	else if (strcmp(mexp->argv[0], "%") == 0 ||
3902 	    strcmp(mexp->argv[0], "m") == 0)
3903 		operator = MODULUS;
3904 	else if (strcmp(mexp->argv[0], "==") == 0)
3905 		operator = EQUAL;
3906 	else if (strcmp(mexp->argv[0], "!=") == 0)
3907 		operator = NOT_EQUAL;
3908 	else if (strcmp(mexp->argv[0], ">") == 0)
3909 		operator = GREATER_THAN;
3910 	else if (strcmp(mexp->argv[0], "<") == 0)
3911 		operator = LESS_THAN;
3912 	else if (strcmp(mexp->argv[0], ">=") == 0)
3913 		operator = GREATER_THAN_EQUAL;
3914 	else if (strcmp(mexp->argv[0], "<=") == 0)
3915 		operator = LESS_THAN_EQUAL;
3916 	else {
3917 		format_log(es, "expression has no valid operator: '%s'",
3918 		    mexp->argv[0]);
3919 		goto fail;
3920 	}
3921 
3922 	/* The second argument may be flags. */
3923 	if (argc >= 2 && strchr(mexp->argv[1], 'f') != NULL) {
3924 		use_fp = 1;
3925 		prec = 2;
3926 	}
3927 
3928 	/* The third argument may be precision. */
3929 	if (argc >= 3) {
3930 		prec = strtonum(mexp->argv[2], INT_MIN, INT_MAX, &errstr);
3931 		if (errstr != NULL) {
3932 			format_log(es, "expression precision %s: %s", errstr,
3933 			    mexp->argv[2]);
3934 			goto fail;
3935 		}
3936 	}
3937 
3938 	if (format_choose(es, copy, &left, &right, 1) != 0) {
3939 		format_log(es, "expression syntax error");
3940 		goto fail;
3941 	}
3942 
3943 	mleft = strtod(left, &endch);
3944 	if (*endch != '\0') {
3945 		format_log(es, "expression left side is invalid: %s", left);
3946 		goto fail;
3947 	}
3948 
3949 	mright = strtod(right, &endch);
3950 	if (*endch != '\0') {
3951 		format_log(es, "expression right side is invalid: %s", right);
3952 		goto fail;
3953 	}
3954 
3955 	if (!use_fp) {
3956 		mleft = (long long)mleft;
3957 		mright = (long long)mright;
3958 	}
3959 	format_log(es, "expression left side is: %.*f", prec, mleft);
3960 	format_log(es, "expression right side is: %.*f", prec, mright);
3961 
3962 	switch (operator) {
3963 	case ADD:
3964 		result = mleft + mright;
3965 		break;
3966 	case SUBTRACT:
3967 		result = mleft - mright;
3968 		break;
3969 	case MULTIPLY:
3970 		result = mleft * mright;
3971 		break;
3972 	case DIVIDE:
3973 		result = mleft / mright;
3974 		break;
3975 	case MODULUS:
3976 		result = fmod(mleft, mright);
3977 		break;
3978 	case EQUAL:
3979 		result = fabs(mleft - mright) < 1e-9;
3980 		break;
3981 	case NOT_EQUAL:
3982 		result = fabs(mleft - mright) > 1e-9;
3983 		break;
3984 	case GREATER_THAN:
3985 		result = (mleft > mright);
3986 		break;
3987 	case GREATER_THAN_EQUAL:
3988 		result = (mleft >= mright);
3989 		break;
3990 	case LESS_THAN:
3991 		result = (mleft < mright);
3992 		break;
3993 	case LESS_THAN_EQUAL:
3994 		result = (mleft <= mright);
3995 		break;
3996 	}
3997 	if (use_fp)
3998 		xasprintf(&value, "%.*f", prec, result);
3999 	else
4000 		xasprintf(&value, "%.*f", prec, (double)(long long)result);
4001 	format_log(es, "expression result is %s", value);
4002 
4003 	free(right);
4004 	free(left);
4005 	return (value);
4006 
4007 fail:
4008 	free(right);
4009 	free(left);
4010 	return (NULL);
4011 }
4012 
4013 /* Replace a key. */
4014 static int
format_replace(struct format_expand_state * es,const char * key,size_t keylen,char ** buf,size_t * len,size_t * off)4015 format_replace(struct format_expand_state *es, const char *key, size_t keylen,
4016     char **buf, size_t *len, size_t *off)
4017 {
4018 	struct format_tree		 *ft = es->ft;
4019 	struct window_pane		 *wp = ft->wp;
4020 	const char			 *errstr, *copy, *cp, *marker = NULL;
4021 	const char			 *time_format = NULL;
4022 	char				 *copy0, *condition, *found, *new;
4023 	char				 *value, *left, *right, c;
4024 	size_t				  valuelen;
4025 	int				  modifiers = 0, limit = 0, width = 0;
4026 	int				  j;
4027 	struct format_modifier		 *list, *cmp = NULL, *search = NULL;
4028 	struct format_modifier		**sub = NULL, *mexp = NULL, *fm;
4029 	u_int				  i, count, nsub = 0;
4030 	struct format_expand_state	  next;
4031 
4032 	/* Make a copy of the key. */
4033 	copy = copy0 = xstrndup(key, keylen);
4034 
4035 	/* Process modifier list. */
4036 	list = format_build_modifiers(es, &copy, &count);
4037 	for (i = 0; i < count; i++) {
4038 		fm = &list[i];
4039 		if (format_logging(ft)) {
4040 			format_log(es, "modifier %u is %s", i, fm->modifier);
4041 			for (j = 0; j < fm->argc; j++) {
4042 				format_log(es, "modifier %u argument %d: %s", i,
4043 				    j, fm->argv[j]);
4044 			}
4045 		}
4046 		if (fm->size == 1) {
4047 			switch (fm->modifier[0]) {
4048 			case 'm':
4049 			case '<':
4050 			case '>':
4051 				cmp = fm;
4052 				break;
4053 			case 'C':
4054 				search = fm;
4055 				break;
4056 			case 's':
4057 				if (fm->argc < 2)
4058 					break;
4059 				sub = xreallocarray (sub, nsub + 1,
4060 				    sizeof *sub);
4061 				sub[nsub++] = fm;
4062 				break;
4063 			case '=':
4064 				if (fm->argc < 1)
4065 					break;
4066 				limit = strtonum(fm->argv[0], INT_MIN, INT_MAX,
4067 				    &errstr);
4068 				if (errstr != NULL)
4069 					limit = 0;
4070 				if (fm->argc >= 2 && fm->argv[1] != NULL)
4071 					marker = fm->argv[1];
4072 				break;
4073 			case 'p':
4074 				if (fm->argc < 1)
4075 					break;
4076 				width = strtonum(fm->argv[0], INT_MIN, INT_MAX,
4077 				    &errstr);
4078 				if (errstr != NULL)
4079 					width = 0;
4080 				break;
4081 			case 'w':
4082 				modifiers |= FORMAT_WIDTH;
4083 				break;
4084 			case 'e':
4085 				if (fm->argc < 1 || fm->argc > 3)
4086 					break;
4087 				mexp = fm;
4088 				break;
4089 			case 'l':
4090 				modifiers |= FORMAT_LITERAL;
4091 				break;
4092 			case 'a':
4093 				modifiers |= FORMAT_CHARACTER;
4094 				break;
4095 			case 'b':
4096 				modifiers |= FORMAT_BASENAME;
4097 				break;
4098 			case 'd':
4099 				modifiers |= FORMAT_DIRNAME;
4100 				break;
4101 			case 'n':
4102 				modifiers |= FORMAT_LENGTH;
4103 				break;
4104 			case 't':
4105 				modifiers |= FORMAT_TIMESTRING;
4106 				if (fm->argc < 1)
4107 					break;
4108 				if (strchr(fm->argv[0], 'p') != NULL)
4109 					modifiers |= FORMAT_PRETTY;
4110 				else if (fm->argc >= 2 &&
4111 				    strchr(fm->argv[0], 'f') != NULL)
4112 					time_format = format_strip(fm->argv[1]);
4113 				break;
4114 			case 'q':
4115 				if (fm->argc < 1)
4116 					modifiers |= FORMAT_QUOTE_SHELL;
4117 				else if (strchr(fm->argv[0], 'e') != NULL ||
4118 				    strchr(fm->argv[0], 'h') != NULL)
4119 					modifiers |= FORMAT_QUOTE_STYLE;
4120 				break;
4121 			case 'E':
4122 				modifiers |= FORMAT_EXPAND;
4123 				break;
4124 			case 'T':
4125 				modifiers |= FORMAT_EXPANDTIME;
4126 				break;
4127 			case 'N':
4128 				if (fm->argc < 1 ||
4129 				    strchr(fm->argv[0], 'w') != NULL)
4130 					modifiers |= FORMAT_WINDOW_NAME;
4131 				else if (strchr(fm->argv[0], 's') != NULL)
4132 					modifiers |= FORMAT_SESSION_NAME;
4133 				break;
4134 			case 'S':
4135 				modifiers |= FORMAT_SESSIONS;
4136 				break;
4137 			case 'W':
4138 				modifiers |= FORMAT_WINDOWS;
4139 				break;
4140 			case 'P':
4141 				modifiers |= FORMAT_PANES;
4142 				break;
4143 			}
4144 		} else if (fm->size == 2) {
4145 			if (strcmp(fm->modifier, "||") == 0 ||
4146 			    strcmp(fm->modifier, "&&") == 0 ||
4147 			    strcmp(fm->modifier, "==") == 0 ||
4148 			    strcmp(fm->modifier, "!=") == 0 ||
4149 			    strcmp(fm->modifier, ">=") == 0 ||
4150 			    strcmp(fm->modifier, "<=") == 0)
4151 				cmp = fm;
4152 		}
4153 	}
4154 
4155 	/* Is this a literal string? */
4156 	if (modifiers & FORMAT_LITERAL) {
4157 		value = xstrdup(copy);
4158 		goto done;
4159 	}
4160 
4161 	/* Is this a character? */
4162 	if (modifiers & FORMAT_CHARACTER) {
4163 		new = format_expand1(es, copy);
4164 		c = strtonum(new, 32, 126, &errstr);
4165 		if (errstr != NULL)
4166 			value = xstrdup("");
4167 		else
4168 			xasprintf(&value, "%c", c);
4169 		free (new);
4170 		goto done;
4171 	}
4172 
4173 	/* Is this a loop, comparison or condition? */
4174 	if (modifiers & FORMAT_SESSIONS) {
4175 		value = format_loop_sessions(es, copy);
4176 		if (value == NULL)
4177 			goto fail;
4178 	} else if (modifiers & FORMAT_WINDOWS) {
4179 		value = format_loop_windows(es, copy);
4180 		if (value == NULL)
4181 			goto fail;
4182 	} else if (modifiers & FORMAT_PANES) {
4183 		value = format_loop_panes(es, copy);
4184 		if (value == NULL)
4185 			goto fail;
4186 	} else if (modifiers & FORMAT_WINDOW_NAME) {
4187 		value = format_window_name(es, copy);
4188 		if (value == NULL)
4189 			goto fail;
4190 	} else if (modifiers & FORMAT_SESSION_NAME) {
4191 		value = format_session_name(es, copy);
4192 		if (value == NULL)
4193 			goto fail;
4194 	} else if (search != NULL) {
4195 		/* Search in pane. */
4196 		new = format_expand1(es, copy);
4197 		if (wp == NULL) {
4198 			format_log(es, "search '%s' but no pane", new);
4199 			value = xstrdup("0");
4200 		} else {
4201 			format_log(es, "search '%s' pane %%%u", new, wp->id);
4202 			value = format_search(search, wp, new);
4203 		}
4204 		free(new);
4205 	} else if (cmp != NULL) {
4206 		/* Comparison of left and right. */
4207 		if (format_choose(es, copy, &left, &right, 1) != 0) {
4208 			format_log(es, "compare %s syntax error: %s",
4209 			    cmp->modifier, copy);
4210 			goto fail;
4211 		}
4212 		format_log(es, "compare %s left is: %s", cmp->modifier, left);
4213 		format_log(es, "compare %s right is: %s", cmp->modifier, right);
4214 
4215 		if (strcmp(cmp->modifier, "||") == 0) {
4216 			if (format_true(left) || format_true(right))
4217 				value = xstrdup("1");
4218 			else
4219 				value = xstrdup("0");
4220 		} else if (strcmp(cmp->modifier, "&&") == 0) {
4221 			if (format_true(left) && format_true(right))
4222 				value = xstrdup("1");
4223 			else
4224 				value = xstrdup("0");
4225 		} else if (strcmp(cmp->modifier, "==") == 0) {
4226 			if (strcmp(left, right) == 0)
4227 				value = xstrdup("1");
4228 			else
4229 				value = xstrdup("0");
4230 		} else if (strcmp(cmp->modifier, "!=") == 0) {
4231 			if (strcmp(left, right) != 0)
4232 				value = xstrdup("1");
4233 			else
4234 				value = xstrdup("0");
4235 		} else if (strcmp(cmp->modifier, "<") == 0) {
4236 			if (strcmp(left, right) < 0)
4237 				value = xstrdup("1");
4238 			else
4239 				value = xstrdup("0");
4240 		} else if (strcmp(cmp->modifier, ">") == 0) {
4241 			if (strcmp(left, right) > 0)
4242 				value = xstrdup("1");
4243 			else
4244 				value = xstrdup("0");
4245 		} else if (strcmp(cmp->modifier, "<=") == 0) {
4246 			if (strcmp(left, right) <= 0)
4247 				value = xstrdup("1");
4248 			else
4249 				value = xstrdup("0");
4250 		} else if (strcmp(cmp->modifier, ">=") == 0) {
4251 			if (strcmp(left, right) >= 0)
4252 				value = xstrdup("1");
4253 			else
4254 				value = xstrdup("0");
4255 		} else if (strcmp(cmp->modifier, "m") == 0)
4256 			value = format_match(cmp, left, right);
4257 
4258 		free(right);
4259 		free(left);
4260 	} else if (*copy == '?') {
4261 		/* Conditional: check first and choose second or third. */
4262 		cp = format_skip(copy + 1, ",");
4263 		if (cp == NULL) {
4264 			format_log(es, "condition syntax error: %s", copy + 1);
4265 			goto fail;
4266 		}
4267 		condition = xstrndup(copy + 1, cp - (copy + 1));
4268 		format_log(es, "condition is: %s", condition);
4269 
4270 		found = format_find(ft, condition, modifiers, time_format);
4271 		if (found == NULL) {
4272 			/*
4273 			 * If the condition not found, try to expand it. If
4274 			 * the expansion doesn't have any effect, then assume
4275 			 * false.
4276 			 */
4277 			found = format_expand1(es, condition);
4278 			if (strcmp(found, condition) == 0) {
4279 				free(found);
4280 				found = xstrdup("");
4281 				format_log(es, "condition '%s' found: %s",
4282 				    condition, found);
4283 			} else {
4284 				format_log(es,
4285 				    "condition '%s' not found; assuming false",
4286 				    condition);
4287 			}
4288 		} else
4289 			format_log(es, "condition '%s' found", condition);
4290 
4291 		if (format_choose(es, cp + 1, &left, &right, 0) != 0) {
4292 			format_log(es, "condition '%s' syntax error: %s",
4293 			    condition, cp + 1);
4294 			free(found);
4295 			goto fail;
4296 		}
4297 		if (format_true(found)) {
4298 			format_log(es, "condition '%s' is true", condition);
4299 			value = format_expand1(es, left);
4300 		} else {
4301 			format_log(es, "condition '%s' is false", condition);
4302 			value = format_expand1(es, right);
4303 		}
4304 		free(right);
4305 		free(left);
4306 
4307 		free(condition);
4308 		free(found);
4309 	} else if (mexp != NULL) {
4310 		value = format_replace_expression(mexp, es, copy);
4311 		if (value == NULL)
4312 			value = xstrdup("");
4313 	} else {
4314 		if (strstr(copy, "#{") != 0) {
4315 			format_log(es, "expanding inner format '%s'", copy);
4316 			value = format_expand1(es, copy);
4317 		} else {
4318 			value = format_find(ft, copy, modifiers, time_format);
4319 			if (value == NULL) {
4320 				format_log(es, "format '%s' not found", copy);
4321 				value = xstrdup("");
4322 			} else {
4323 				format_log(es, "format '%s' found: %s", copy,
4324 				    value);
4325 			}
4326 		}
4327 	}
4328 
4329 done:
4330 	/* Expand again if required. */
4331 	if (modifiers & FORMAT_EXPAND) {
4332 		new = format_expand1(es, value);
4333 		free(value);
4334 		value = new;
4335 	} else if (modifiers & FORMAT_EXPANDTIME) {
4336 		format_copy_state(&next, es, FORMAT_EXPAND_TIME);
4337 		new = format_expand1(&next, value);
4338 		free(value);
4339 		value = new;
4340 	}
4341 
4342 	/* Perform substitution if any. */
4343 	for (i = 0; i < nsub; i++) {
4344 		left = format_expand1(es, sub[i]->argv[0]);
4345 		right = format_expand1(es, sub[i]->argv[1]);
4346 		new = format_sub(sub[i], value, left, right);
4347 		format_log(es, "substitute '%s' to '%s': %s", left, right, new);
4348 		free(value);
4349 		value = new;
4350 		free(right);
4351 		free(left);
4352 	}
4353 
4354 	/* Truncate the value if needed. */
4355 	if (limit > 0) {
4356 		new = format_trim_left(value, limit);
4357 		if (marker != NULL && strcmp(new, value) != 0) {
4358 			free(value);
4359 			xasprintf(&value, "%s%s", new, marker);
4360 		} else {
4361 			free(value);
4362 			value = new;
4363 		}
4364 		format_log(es, "applied length limit %d: %s", limit, value);
4365 	} else if (limit < 0) {
4366 		new = format_trim_right(value, -limit);
4367 		if (marker != NULL && strcmp(new, value) != 0) {
4368 			free(value);
4369 			xasprintf(&value, "%s%s", marker, new);
4370 		} else {
4371 			free(value);
4372 			value = new;
4373 		}
4374 		format_log(es, "applied length limit %d: %s", limit, value);
4375 	}
4376 
4377 	/* Pad the value if needed. */
4378 	if (width > 0) {
4379 		new = utf8_padcstr(value, width);
4380 		free(value);
4381 		value = new;
4382 		format_log(es, "applied padding width %d: %s", width, value);
4383 	} else if (width < 0) {
4384 		new = utf8_rpadcstr(value, -width);
4385 		free(value);
4386 		value = new;
4387 		format_log(es, "applied padding width %d: %s", width, value);
4388 	}
4389 
4390 	/* Replace with the length or width if needed. */
4391 	if (modifiers & FORMAT_LENGTH) {
4392 		xasprintf(&new, "%zu", strlen(value));
4393 		free(value);
4394 		value = new;
4395 		format_log(es, "replacing with length: %s", new);
4396 	}
4397 	if (modifiers & FORMAT_WIDTH) {
4398 		xasprintf(&new, "%u", format_width(value));
4399 		free(value);
4400 		value = new;
4401 		format_log(es, "replacing with width: %s", new);
4402 	}
4403 
4404 	/* Expand the buffer and copy in the value. */
4405 	valuelen = strlen(value);
4406 	while (*len - *off < valuelen + 1) {
4407 		*buf = xreallocarray(*buf, 2, *len);
4408 		*len *= 2;
4409 	}
4410 	memcpy(*buf + *off, value, valuelen);
4411 	*off += valuelen;
4412 
4413 	format_log(es, "replaced '%s' with '%s'", copy0, value);
4414 	free(value);
4415 
4416 	free(sub);
4417 	format_free_modifiers(list, count);
4418 	free(copy0);
4419 	return (0);
4420 
4421 fail:
4422 	format_log(es, "failed %s", copy0);
4423 
4424 	free(sub);
4425 	format_free_modifiers(list, count);
4426 	free(copy0);
4427 	return (-1);
4428 }
4429 
4430 /* Expand keys in a template. */
4431 static char *
format_expand1(struct format_expand_state * es,const char * fmt)4432 format_expand1(struct format_expand_state *es, const char *fmt)
4433 {
4434 	struct format_tree	*ft = es->ft;
4435 	char			*buf, *out, *name;
4436 	const char		*ptr, *s;
4437 	size_t			 off, len, n, outlen;
4438 	int     		 ch, brackets;
4439 	char			 expanded[8192];
4440 
4441 	if (fmt == NULL || *fmt == '\0')
4442 		return (xstrdup(""));
4443 
4444 	if (es->loop == FORMAT_LOOP_LIMIT) {
4445 		format_log(es, "reached loop limit (%u)", FORMAT_LOOP_LIMIT);
4446 		return (xstrdup(""));
4447 	}
4448 	es->loop++;
4449 
4450 	format_log(es, "expanding format: %s", fmt);
4451 
4452 	if ((es->flags & FORMAT_EXPAND_TIME) && strchr(fmt, '%') != NULL) {
4453 		if (es->time == 0) {
4454 			es->time = time(NULL);
4455 			localtime_r(&es->time, &es->tm);
4456 		}
4457 		if (strftime(expanded, sizeof expanded, fmt, &es->tm) == 0) {
4458 			format_log(es, "format is too long");
4459 			return (xstrdup(""));
4460 		}
4461 		if (format_logging(ft) && strcmp(expanded, fmt) != 0)
4462 			format_log(es, "after time expanded: %s", expanded);
4463 		fmt = expanded;
4464 	}
4465 
4466 	len = 64;
4467 	buf = xmalloc(len);
4468 	off = 0;
4469 
4470 	while (*fmt != '\0') {
4471 		if (*fmt != '#') {
4472 			while (len - off < 2) {
4473 				buf = xreallocarray(buf, 2, len);
4474 				len *= 2;
4475 			}
4476 			buf[off++] = *fmt++;
4477 			continue;
4478 		}
4479 		fmt++;
4480 
4481 		ch = (u_char)*fmt++;
4482 		switch (ch) {
4483 		case '(':
4484 			brackets = 1;
4485 			for (ptr = fmt; *ptr != '\0'; ptr++) {
4486 				if (*ptr == '(')
4487 					brackets++;
4488 				if (*ptr == ')' && --brackets == 0)
4489 					break;
4490 			}
4491 			if (*ptr != ')' || brackets != 0)
4492 				break;
4493 			n = ptr - fmt;
4494 
4495 			name = xstrndup(fmt, n);
4496 			format_log(es, "found #(): %s", name);
4497 
4498 			if ((ft->flags & FORMAT_NOJOBS) ||
4499 			    (es->flags & FORMAT_EXPAND_NOJOBS)) {
4500 				out = xstrdup("");
4501 				format_log(es, "#() is disabled");
4502 			} else {
4503 				out = format_job_get(es, name);
4504 				format_log(es, "#() result: %s", out);
4505 			}
4506 			free(name);
4507 
4508 			outlen = strlen(out);
4509 			while (len - off < outlen + 1) {
4510 				buf = xreallocarray(buf, 2, len);
4511 				len *= 2;
4512 			}
4513 			memcpy(buf + off, out, outlen);
4514 			off += outlen;
4515 
4516 			free(out);
4517 
4518 			fmt += n + 1;
4519 			continue;
4520 		case '{':
4521 			ptr = format_skip((char *)fmt - 2, "}");
4522 			if (ptr == NULL)
4523 				break;
4524 			n = ptr - fmt;
4525 
4526 			format_log(es, "found #{}: %.*s", (int)n, fmt);
4527 			if (format_replace(es, fmt, n, &buf, &len, &off) != 0)
4528 				break;
4529 			fmt += n + 1;
4530 			continue;
4531 		case '#':
4532 			/*
4533 			 * If ##[ (with two or more #s), then it is a style and
4534 			 * can be left for format_draw to handle.
4535 			 */
4536 			ptr = fmt;
4537 			n = 2;
4538 			while (*ptr == '#') {
4539 				ptr++;
4540 				n++;
4541 			}
4542 			if (*ptr == '[') {
4543 				format_log(es, "found #*%zu[", n);
4544 				while (len - off < n + 2) {
4545 					buf = xreallocarray(buf, 2, len);
4546 					len *= 2;
4547 				}
4548 				memcpy(buf + off, fmt - 2, n + 1);
4549 				off += n + 1;
4550 				fmt = ptr + 1;
4551 				continue;
4552 			}
4553 			/* FALLTHROUGH */
4554 		case '}':
4555 		case ',':
4556 			format_log(es, "found #%c", ch);
4557 			while (len - off < 2) {
4558 				buf = xreallocarray(buf, 2, len);
4559 				len *= 2;
4560 			}
4561 			buf[off++] = ch;
4562 			continue;
4563 		default:
4564 			s = NULL;
4565 			if (ch >= 'A' && ch <= 'Z')
4566 				s = format_upper[ch - 'A'];
4567 			else if (ch >= 'a' && ch <= 'z')
4568 				s = format_lower[ch - 'a'];
4569 			if (s == NULL) {
4570 				while (len - off < 3) {
4571 					buf = xreallocarray(buf, 2, len);
4572 					len *= 2;
4573 				}
4574 				buf[off++] = '#';
4575 				buf[off++] = ch;
4576 				continue;
4577 			}
4578 			n = strlen(s);
4579 			format_log(es, "found #%c: %s", ch, s);
4580 			if (format_replace(es, s, n, &buf, &len, &off) != 0)
4581 				break;
4582 			continue;
4583 		}
4584 
4585 		break;
4586 	}
4587 	buf[off] = '\0';
4588 
4589 	format_log(es, "result is: %s", buf);
4590 	es->loop--;
4591 
4592 	return (buf);
4593 }
4594 
4595 /* Expand keys in a template, passing through strftime first. */
4596 char *
format_expand_time(struct format_tree * ft,const char * fmt)4597 format_expand_time(struct format_tree *ft, const char *fmt)
4598 {
4599 	struct format_expand_state	es;
4600 
4601 	memset(&es, 0, sizeof es);
4602 	es.ft = ft;
4603 	es.flags = FORMAT_EXPAND_TIME;
4604 	return (format_expand1(&es, fmt));
4605 }
4606 
4607 /* Expand keys in a template. */
4608 char *
format_expand(struct format_tree * ft,const char * fmt)4609 format_expand(struct format_tree *ft, const char *fmt)
4610 {
4611 	struct format_expand_state	es;
4612 
4613 	memset(&es, 0, sizeof es);
4614 	es.ft = ft;
4615 	es.flags = 0;
4616 	return (format_expand1(&es, fmt));
4617 }
4618 
4619 /* Expand a single string. */
4620 char *
format_single(struct cmdq_item * item,const char * fmt,struct client * c,struct session * s,struct winlink * wl,struct window_pane * wp)4621 format_single(struct cmdq_item *item, const char *fmt, struct client *c,
4622     struct session *s, struct winlink *wl, struct window_pane *wp)
4623 {
4624 	struct format_tree	*ft;
4625 	char			*expanded;
4626 
4627 	ft = format_create_defaults(item, c, s, wl, wp);
4628 	expanded = format_expand(ft, fmt);
4629 	format_free(ft);
4630 	return (expanded);
4631 }
4632 
4633 /* Expand a single string using state. */
4634 char *
format_single_from_state(struct cmdq_item * item,const char * fmt,struct client * c,struct cmd_find_state * fs)4635 format_single_from_state(struct cmdq_item *item, const char *fmt,
4636     struct client *c, struct cmd_find_state *fs)
4637 {
4638 	return (format_single(item, fmt, c, fs->s, fs->wl, fs->wp));
4639 }
4640 
4641 /* Expand a single string using target. */
4642 char *
format_single_from_target(struct cmdq_item * item,const char * fmt)4643 format_single_from_target(struct cmdq_item *item, const char *fmt)
4644 {
4645 	struct client	*tc = cmdq_get_target_client(item);
4646 
4647 	return (format_single_from_state(item, fmt, tc, cmdq_get_target(item)));
4648 }
4649 
4650 /* Create and add defaults. */
4651 struct format_tree *
format_create_defaults(struct cmdq_item * item,struct client * c,struct session * s,struct winlink * wl,struct window_pane * wp)4652 format_create_defaults(struct cmdq_item *item, struct client *c,
4653     struct session *s, struct winlink *wl, struct window_pane *wp)
4654 {
4655 	struct format_tree	*ft;
4656 
4657 	if (item != NULL)
4658 		ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
4659 	else
4660 		ft = format_create(NULL, item, FORMAT_NONE, 0);
4661 	format_defaults(ft, c, s, wl, wp);
4662 	return (ft);
4663 }
4664 
4665 /* Create and add defaults using state. */
4666 struct format_tree *
format_create_from_state(struct cmdq_item * item,struct client * c,struct cmd_find_state * fs)4667 format_create_from_state(struct cmdq_item *item, struct client *c,
4668     struct cmd_find_state *fs)
4669 {
4670 	return (format_create_defaults(item, c, fs->s, fs->wl, fs->wp));
4671 }
4672 
4673 /* Create and add defaults using target. */
4674 struct format_tree *
format_create_from_target(struct cmdq_item * item)4675 format_create_from_target(struct cmdq_item *item)
4676 {
4677 	struct client	*tc = cmdq_get_target_client(item);
4678 
4679 	return (format_create_from_state(item, tc, cmdq_get_target(item)));
4680 }
4681 
4682 /* Set defaults for any of arguments that are not NULL. */
4683 void
format_defaults(struct format_tree * ft,struct client * c,struct session * s,struct winlink * wl,struct window_pane * wp)4684 format_defaults(struct format_tree *ft, struct client *c, struct session *s,
4685     struct winlink *wl, struct window_pane *wp)
4686 {
4687 	struct paste_buffer	*pb;
4688 
4689 	if (c != NULL && c->name != NULL)
4690 		log_debug("%s: c=%s", __func__, c->name);
4691 	else
4692 		log_debug("%s: c=none", __func__);
4693 	if (s != NULL)
4694 		log_debug("%s: s=$%u", __func__, s->id);
4695 	else
4696 		log_debug("%s: s=none", __func__);
4697 	if (wl != NULL)
4698 		log_debug("%s: wl=%u", __func__, wl->idx);
4699 	else
4700 		log_debug("%s: wl=none", __func__);
4701 	if (wp != NULL)
4702 		log_debug("%s: wp=%%%u", __func__, wp->id);
4703 	else
4704 		log_debug("%s: wp=none", __func__);
4705 
4706 	if (c != NULL && s != NULL && c->session != s)
4707 		log_debug("%s: session does not match", __func__);
4708 
4709 	if (wp != NULL)
4710 		ft->type = FORMAT_TYPE_PANE;
4711 	else if (wl != NULL)
4712 		ft->type = FORMAT_TYPE_WINDOW;
4713 	else if (s != NULL)
4714 		ft->type = FORMAT_TYPE_SESSION;
4715 	else
4716 		ft->type = FORMAT_TYPE_UNKNOWN;
4717 
4718 	if (s == NULL && c != NULL)
4719 		s = c->session;
4720 	if (wl == NULL && s != NULL)
4721 		wl = s->curw;
4722 	if (wp == NULL && wl != NULL)
4723 		wp = wl->window->active;
4724 
4725 	if (c != NULL)
4726 		format_defaults_client(ft, c);
4727 	if (s != NULL)
4728 		format_defaults_session(ft, s);
4729 	if (wl != NULL)
4730 		format_defaults_winlink(ft, wl);
4731 	if (wp != NULL)
4732 		format_defaults_pane(ft, wp);
4733 
4734 	pb = paste_get_top (NULL);
4735 	if (pb != NULL)
4736 		format_defaults_paste_buffer(ft, pb);
4737 }
4738 
4739 /* Set default format keys for a session. */
4740 static void
format_defaults_session(struct format_tree * ft,struct session * s)4741 format_defaults_session(struct format_tree *ft, struct session *s)
4742 {
4743 	ft->s = s;
4744 }
4745 
4746 /* Set default format keys for a client. */
4747 static void
format_defaults_client(struct format_tree * ft,struct client * c)4748 format_defaults_client(struct format_tree *ft, struct client *c)
4749 {
4750 	if (ft->s == NULL)
4751 		ft->s = c->session;
4752 	ft->c = c;
4753 }
4754 
4755 /* Set default format keys for a window. */
4756 void
format_defaults_window(struct format_tree * ft,struct window * w)4757 format_defaults_window(struct format_tree *ft, struct window *w)
4758 {
4759 	ft->w = w;
4760 }
4761 
4762 /* Set default format keys for a winlink. */
4763 static void
format_defaults_winlink(struct format_tree * ft,struct winlink * wl)4764 format_defaults_winlink(struct format_tree *ft, struct winlink *wl)
4765 {
4766 	if (ft->w == NULL)
4767 		format_defaults_window(ft, wl->window);
4768 	ft->wl = wl;
4769 }
4770 
4771 /* Set default format keys for a window pane. */
4772 void
format_defaults_pane(struct format_tree * ft,struct window_pane * wp)4773 format_defaults_pane(struct format_tree *ft, struct window_pane *wp)
4774 {
4775 	struct window_mode_entry	*wme;
4776 
4777 	if (ft->w == NULL)
4778 		format_defaults_window(ft, wp->window);
4779 	ft->wp = wp;
4780 
4781 	wme = TAILQ_FIRST(&wp->modes);
4782 	if (wme != NULL && wme->mode->formats != NULL)
4783 		wme->mode->formats(wme, ft);
4784 }
4785 
4786 /* Set default format keys for paste buffer. */
4787 void
format_defaults_paste_buffer(struct format_tree * ft,struct paste_buffer * pb)4788 format_defaults_paste_buffer(struct format_tree *ft, struct paste_buffer *pb)
4789 {
4790 	ft->pb = pb;
4791 }
4792 
4793 /* Return word at given coordinates. Caller frees. */
4794 char *
format_grid_word(struct grid * gd,u_int x,u_int y)4795 format_grid_word(struct grid *gd, u_int x, u_int y)
4796 {
4797 	const struct grid_line	*gl;
4798 	struct grid_cell	 gc;
4799 	const char		*ws;
4800 	struct utf8_data	*ud = NULL;
4801 	u_int			 end;
4802 	size_t			 size = 0;
4803 	int			 found = 0;
4804 	char			*s = NULL;
4805 
4806 	ws = options_get_string(global_s_options, "word-separators");
4807 
4808 	for (;;) {
4809 		grid_get_cell(gd, x, y, &gc);
4810 		if (gc.flags & GRID_FLAG_PADDING)
4811 			break;
4812 		if (utf8_cstrhas(ws, &gc.data)) {
4813 			found = 1;
4814 			break;
4815 		}
4816 
4817 		if (x == 0) {
4818 			if (y == 0)
4819 				break;
4820 			gl = grid_peek_line(gd, y - 1);
4821 			if (~gl->flags & GRID_LINE_WRAPPED)
4822 				break;
4823 			y--;
4824 			x = grid_line_length(gd, y);
4825 			if (x == 0)
4826 				break;
4827 		}
4828 		x--;
4829 	}
4830 	for (;;) {
4831 		if (found) {
4832 			end = grid_line_length(gd, y);
4833 			if (end == 0 || x == end - 1) {
4834 				if (y == gd->hsize + gd->sy - 1)
4835 					break;
4836 				gl = grid_peek_line(gd, y);
4837 				if (~gl->flags & GRID_LINE_WRAPPED)
4838 					break;
4839 				y++;
4840 				x = 0;
4841 			} else
4842 				x++;
4843 		}
4844 		found = 1;
4845 
4846 		grid_get_cell(gd, x, y, &gc);
4847 		if (gc.flags & GRID_FLAG_PADDING)
4848 			break;
4849 		if (utf8_cstrhas(ws, &gc.data))
4850 			break;
4851 
4852 		ud = xreallocarray(ud, size + 2, sizeof *ud);
4853 		memcpy(&ud[size++], &gc.data, sizeof *ud);
4854 	}
4855 	if (size != 0) {
4856 		ud[size].size = 0;
4857 		s = utf8_tocstr(ud);
4858 		free(ud);
4859 	}
4860 	return (s);
4861 }
4862 
4863 /* Return line at given coordinates. Caller frees. */
4864 char *
format_grid_line(struct grid * gd,u_int y)4865 format_grid_line(struct grid *gd, u_int y)
4866 {
4867 	struct grid_cell	 gc;
4868 	struct utf8_data	*ud = NULL;
4869 	u_int			 x;
4870 	size_t			 size = 0;
4871 	char			*s = NULL;
4872 
4873 	for (x = 0; x < grid_line_length(gd, y); x++) {
4874 		grid_get_cell(gd, x, y, &gc);
4875 		if (gc.flags & GRID_FLAG_PADDING)
4876 			break;
4877 
4878 		ud = xreallocarray(ud, size + 2, sizeof *ud);
4879 		memcpy(&ud[size++], &gc.data, sizeof *ud);
4880 	}
4881 	if (size != 0) {
4882 		ud[size].size = 0;
4883 		s = utf8_tocstr(ud);
4884 		free(ud);
4885 	}
4886 	return (s);
4887 }
4888