xref: /netbsd-src/external/bsd/tmux/dist/format.c (revision f3cfa6f6ce31685c6c4a758bc430e69eb99f50a4)
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 <stdarg.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <time.h>
30 #include <unistd.h>
31 
32 #include "tmux.h"
33 
34 /*
35  * Build a list of key-value pairs and use them to expand #{key} entries in a
36  * string.
37  */
38 
39 struct format_entry;
40 typedef void (*format_cb)(struct format_tree *, struct format_entry *);
41 
42 static char	*format_job_get(struct format_tree *, const char *);
43 static void	 format_job_timer(int, short, void *);
44 
45 static char	*format_find(struct format_tree *, const char *, int);
46 static void	 format_add_cb(struct format_tree *, const char *, format_cb);
47 static void	 format_add_tv(struct format_tree *, const char *,
48 		     struct timeval *);
49 static int	 format_replace(struct format_tree *, const char *, size_t,
50 		     char **, size_t *, size_t *);
51 
52 static void	 format_defaults_session(struct format_tree *,
53 		     struct session *);
54 static void	 format_defaults_client(struct format_tree *, struct client *);
55 static void	 format_defaults_winlink(struct format_tree *,
56 		     struct winlink *);
57 
58 /* Entry in format job tree. */
59 struct format_job {
60 	struct client		*client;
61 	u_int			 tag;
62 	const char		*cmd;
63 	const char		*expanded;
64 
65 	time_t			 last;
66 	char			*out;
67 	int			 updated;
68 
69 	struct job		*job;
70 	int			 status;
71 
72 	RB_ENTRY(format_job)	 entry;
73 };
74 
75 /* Format job tree. */
76 static struct event format_job_event;
77 static int format_job_cmp(struct format_job *, struct format_job *);
78 static RB_HEAD(format_job_tree, format_job) format_jobs = RB_INITIALIZER();
79 RB_GENERATE_STATIC(format_job_tree, format_job, entry, format_job_cmp);
80 
81 /* Format job tree comparison function. */
82 static int
83 format_job_cmp(struct format_job *fj1, struct format_job *fj2)
84 {
85 	if (fj1->tag < fj2->tag)
86 		return (-1);
87 	if (fj1->tag > fj2->tag)
88 		return (1);
89 	return (strcmp(fj1->cmd, fj2->cmd));
90 }
91 
92 /* Format modifiers. */
93 #define FORMAT_TIMESTRING 0x1
94 #define FORMAT_BASENAME 0x2
95 #define FORMAT_DIRNAME 0x4
96 #define FORMAT_SUBSTITUTE 0x8
97 
98 /* Entry in format tree. */
99 struct format_entry {
100 	char			*key;
101 	char			*value;
102 	time_t			 t;
103 	format_cb		 cb;
104 	RB_ENTRY(format_entry)	 entry;
105 };
106 
107 /* Format entry tree. */
108 struct format_tree {
109 	struct window		*w;
110 	struct winlink		*wl;
111 	struct session		*s;
112 	struct window_pane	*wp;
113 
114 	struct client		*client;
115 	u_int			 tag;
116 	int			 flags;
117 
118 	RB_HEAD(format_entry_tree, format_entry) tree;
119 };
120 static int format_entry_cmp(struct format_entry *, struct format_entry *);
121 RB_GENERATE_STATIC(format_entry_tree, format_entry, entry, format_entry_cmp);
122 
123 /* Format entry tree comparison function. */
124 static int
125 format_entry_cmp(struct format_entry *fe1, struct format_entry *fe2)
126 {
127 	return (strcmp(fe1->key, fe2->key));
128 }
129 
130 /* Single-character uppercase aliases. */
131 static const char *format_upper[] = {
132 	NULL,		/* A */
133 	NULL,		/* B */
134 	NULL,		/* C */
135 	"pane_id",	/* D */
136 	NULL,		/* E */
137 	"window_flags",	/* F */
138 	NULL,		/* G */
139 	"host",		/* H */
140 	"window_index",	/* I */
141 	NULL,		/* J */
142 	NULL,		/* K */
143 	NULL,		/* L */
144 	NULL,		/* M */
145 	NULL,		/* N */
146 	NULL,		/* O */
147 	"pane_index",	/* P */
148 	NULL,		/* Q */
149 	NULL,		/* R */
150 	"session_name",	/* S */
151 	"pane_title",	/* T */
152 	NULL,		/* U */
153 	NULL,		/* V */
154 	"window_name",	/* W */
155 	NULL,		/* X */
156 	NULL,		/* Y */
157 	NULL 		/* Z */
158 };
159 
160 /* Single-character lowercase aliases. */
161 static const char *format_lower[] = {
162 	NULL,		/* a */
163 	NULL,		/* b */
164 	NULL,		/* c */
165 	NULL,		/* d */
166 	NULL,		/* e */
167 	NULL,		/* f */
168 	NULL,		/* g */
169 	"host_short",	/* h */
170 	NULL,		/* i */
171 	NULL,		/* j */
172 	NULL,		/* k */
173 	NULL,		/* l */
174 	NULL,		/* m */
175 	NULL,		/* n */
176 	NULL,		/* o */
177 	NULL,		/* p */
178 	NULL,		/* q */
179 	NULL,		/* r */
180 	NULL,		/* s */
181 	NULL,		/* t */
182 	NULL,		/* u */
183 	NULL,		/* v */
184 	NULL,		/* w */
185 	NULL,		/* x */
186 	NULL,		/* y */
187 	NULL		/* z */
188 };
189 
190 /* Format job update callback. */
191 static void
192 format_job_update(struct job *job)
193 {
194 	struct format_job	*fj = job->data;
195 	struct evbuffer		*evb = job->event->input;
196 	char			*line = NULL, *next;
197 	time_t			 t;
198 
199 	while ((next = evbuffer_readline(evb)) != NULL) {
200 		free(line);
201 		line = next;
202 	}
203 	if (line == NULL)
204 		return;
205 	fj->updated = 1;
206 
207 	free(fj->out);
208 	fj->out = line;
209 
210 	log_debug("%s: %p %s: %s", __func__, fj, fj->cmd, fj->out);
211 
212 	t = time(NULL);
213 	if (fj->status && fj->last != t) {
214 		if (fj->client != NULL)
215 			server_status_client(fj->client);
216 		fj->last = t;
217 	}
218 }
219 
220 /* Format job complete callback. */
221 static void
222 format_job_complete(struct job *job)
223 {
224 	struct format_job	*fj = job->data;
225 	char			*line, *buf;
226 	size_t			 len;
227 
228 	fj->job = NULL;
229 
230 	buf = NULL;
231 	if ((line = evbuffer_readline(job->event->input)) == NULL) {
232 		len = EVBUFFER_LENGTH(job->event->input);
233 		buf = xmalloc(len + 1);
234 		if (len != 0)
235 			memcpy(buf, EVBUFFER_DATA(job->event->input), len);
236 		buf[len] = '\0';
237 	} else
238 		buf = line;
239 
240 	log_debug("%s: %p %s: %s", __func__, fj, fj->cmd, buf);
241 
242 	if (*buf != '\0' || !fj->updated) {
243 		free(fj->out);
244 		fj->out = buf;
245 	} else
246 		free(buf);
247 
248 	if (fj->status) {
249 		if (fj->client != NULL)
250 			server_status_client(fj->client);
251 		fj->status = 0;
252 	}
253 }
254 
255 /* Find a job. */
256 static char *
257 format_job_get(struct format_tree *ft, const char *cmd)
258 {
259 	struct format_job_tree	*jobs;
260 	struct format_job	 fj0, *fj;
261 	time_t			 t;
262 	char			*expanded;
263 	int			 force;
264 
265 	if (ft->client == NULL)
266 		jobs = &format_jobs;
267 	else if (ft->client->jobs != NULL)
268 		jobs = ft->client->jobs;
269 	else {
270 		jobs = ft->client->jobs = xmalloc(sizeof *ft->client->jobs);
271 		RB_INIT(jobs);
272 	}
273 
274 	fj0.tag = ft->tag;
275 	fj0.cmd = cmd;
276 	if ((fj = RB_FIND(format_job_tree, jobs, &fj0)) == NULL) {
277 		fj = xcalloc(1, sizeof *fj);
278 		fj->client = ft->client;
279 		fj->tag = ft->tag;
280 		fj->cmd = xstrdup(cmd);
281 		fj->expanded = NULL;
282 
283 		xasprintf(&fj->out, "<'%s' not ready>", fj->cmd);
284 
285 		RB_INSERT(format_job_tree, jobs, fj);
286 	}
287 
288 	expanded = format_expand(ft, cmd);
289 	if (fj->expanded == NULL || strcmp(expanded, fj->expanded) != 0) {
290 		free(__UNCONST(fj->expanded));
291 		fj->expanded = xstrdup(expanded);
292 		force = 1;
293 	} else
294 		force = (ft->flags & FORMAT_FORCE);
295 
296 	t = time(NULL);
297 	if (fj->job == NULL && (force || fj->last != t)) {
298 		fj->job = job_run(expanded, NULL, NULL, format_job_update,
299 		    format_job_complete, NULL, fj, JOB_NOWAIT);
300 		if (fj->job == NULL) {
301 			free(fj->out);
302 			xasprintf(&fj->out, "<'%s' didn't start>", fj->cmd);
303 		}
304 		fj->last = t;
305 		fj->updated = 0;
306 	}
307 
308 	if (ft->flags & FORMAT_STATUS)
309 		fj->status = 1;
310 
311 	free(expanded);
312 	return (format_expand(ft, fj->out));
313 }
314 
315 /* Remove old jobs. */
316 static void
317 format_job_tidy(struct format_job_tree *jobs, int force)
318 {
319 	struct format_job	*fj, *fj1;
320 	time_t			 now;
321 
322 	now = time(NULL);
323 	RB_FOREACH_SAFE(fj, format_job_tree, jobs, fj1) {
324 		if (!force && (fj->last > now || now - fj->last < 3600))
325 			continue;
326 		RB_REMOVE(format_job_tree, jobs, fj);
327 
328 		log_debug("%s: %s", __func__, fj->cmd);
329 
330 		if (fj->job != NULL)
331 			job_free(fj->job);
332 
333 		free(__UNCONST(fj->expanded));
334 		free(__UNCONST(fj->cmd));
335 		free(fj->out);
336 
337 		free(fj);
338 	}
339 }
340 
341 /* Remove old jobs for client. */
342 void
343 format_lost_client(struct client *c)
344 {
345 	if (c->jobs != NULL)
346 		format_job_tidy(c->jobs, 1);
347 	free(c->jobs);
348 }
349 
350 /* Remove old jobs periodically. */
351 static void
352 format_job_timer(__unused int fd, __unused short events, __unused void *arg)
353 {
354 	struct client	*c;
355 	struct timeval	 tv = { .tv_sec = 60 };
356 
357 	format_job_tidy(&format_jobs, 0);
358 	TAILQ_FOREACH(c, &clients, entry) {
359 		if (c->jobs != NULL)
360 			format_job_tidy(c->jobs, 0);
361 	}
362 
363 	evtimer_del(&format_job_event);
364 	evtimer_add(&format_job_event, &tv);
365 }
366 
367 /* Callback for host. */
368 static void
369 format_cb_host(__unused struct format_tree *ft, struct format_entry *fe)
370 {
371 	char host[HOST_NAME_MAX + 1];
372 
373 	if (gethostname(host, sizeof host) != 0)
374 		fe->value = xstrdup("");
375 	else
376 		fe->value = xstrdup(host);
377 }
378 
379 /* Callback for host_short. */
380 static void
381 format_cb_host_short(__unused struct format_tree *ft, struct format_entry *fe)
382 {
383 	char host[HOST_NAME_MAX + 1], *cp;
384 
385 	if (gethostname(host, sizeof host) != 0)
386 		fe->value = xstrdup("");
387 	else {
388 		if ((cp = strchr(host, '.')) != NULL)
389 			*cp = '\0';
390 		fe->value = xstrdup(host);
391 	}
392 }
393 
394 /* Callback for pid. */
395 static void
396 format_cb_pid(__unused struct format_tree *ft, struct format_entry *fe)
397 {
398 	xasprintf(&fe->value, "%ld", (long)getpid());
399 }
400 
401 /* Callback for session_alerts. */
402 static void
403 format_cb_session_alerts(struct format_tree *ft, struct format_entry *fe)
404 {
405 	struct session	*s = ft->s;
406 	struct winlink	*wl;
407 	char		 alerts[1024], tmp[16];
408 
409 	if (s == NULL)
410 		return;
411 
412 	*alerts = '\0';
413 	RB_FOREACH(wl, winlinks, &s->windows) {
414 		if ((wl->flags & WINLINK_ALERTFLAGS) == 0)
415 			continue;
416 		xsnprintf(tmp, sizeof tmp, "%u", wl->idx);
417 
418 		if (*alerts != '\0')
419 			strlcat(alerts, ",", sizeof alerts);
420 		strlcat(alerts, tmp, sizeof alerts);
421 		if (wl->flags & WINLINK_ACTIVITY)
422 			strlcat(alerts, "#", sizeof alerts);
423 		if (wl->flags & WINLINK_BELL)
424 			strlcat(alerts, "!", sizeof alerts);
425 		if (wl->flags & WINLINK_SILENCE)
426 			strlcat(alerts, "~", sizeof alerts);
427 	}
428 	fe->value = xstrdup(alerts);
429 }
430 
431 /* Callback for session_stack. */
432 static void
433 format_cb_session_stack(struct format_tree *ft, struct format_entry *fe)
434 {
435 	struct session	*s = ft->s;
436 	struct winlink	*wl;
437 	char		 result[1024], tmp[16];
438 
439 	if (s == NULL)
440 		return;
441 
442 	xsnprintf(result, sizeof result, "%u", s->curw->idx);
443 	TAILQ_FOREACH(wl, &s->lastw, sentry) {
444 		xsnprintf(tmp, sizeof tmp, "%u", wl->idx);
445 
446 		if (*result != '\0')
447 			strlcat(result, ",", sizeof result);
448 		strlcat(result, tmp, sizeof result);
449 	}
450 	fe->value = xstrdup(result);
451 }
452 
453 /* Callback for window_stack_index. */
454 static void
455 format_cb_window_stack_index(struct format_tree *ft, struct format_entry *fe)
456 {
457 	struct session	*s = ft->wl->session;
458 	struct winlink	*wl;
459 	u_int		 idx;
460 
461 	idx = 0;
462 	TAILQ_FOREACH(wl, &s->lastw, sentry) {
463 		idx++;
464 		if (wl == ft->wl)
465 			break;
466 	}
467 	if (wl != NULL)
468 		xasprintf(&fe->value, "%u", idx);
469 	else
470 		fe->value = xstrdup("0");
471 }
472 
473 /* Callback for window_layout. */
474 static void
475 format_cb_window_layout(struct format_tree *ft, struct format_entry *fe)
476 {
477 	struct window	*w = ft->w;
478 
479 	if (w == NULL)
480 		return;
481 
482 	if (w->saved_layout_root != NULL)
483 		fe->value = layout_dump(w->saved_layout_root);
484 	else
485 		fe->value = layout_dump(w->layout_root);
486 }
487 
488 /* Callback for window_visible_layout. */
489 static void
490 format_cb_window_visible_layout(struct format_tree *ft, struct format_entry *fe)
491 {
492 	struct window	*w = ft->w;
493 
494 	if (w == NULL)
495 		return;
496 
497 	fe->value = layout_dump(w->layout_root);
498 }
499 
500 /* Callback for pane_start_command. */
501 static void
502 format_cb_start_command(struct format_tree *ft, struct format_entry *fe)
503 {
504 	struct window_pane	*wp = ft->wp;
505 
506 	if (wp == NULL)
507 		return;
508 
509 	fe->value = cmd_stringify_argv(wp->argc, wp->argv);
510 }
511 
512 /* Callback for pane_current_command. */
513 static void
514 format_cb_current_command(struct format_tree *ft, struct format_entry *fe)
515 {
516 	struct window_pane	*wp = ft->wp;
517 	char			*cmd;
518 
519 	if (wp == NULL)
520 		return;
521 
522 	cmd = osdep_get_name(wp->fd, wp->tty);
523 	if (cmd == NULL || *cmd == '\0') {
524 		free(cmd);
525 		cmd = cmd_stringify_argv(wp->argc, wp->argv);
526 		if (cmd == NULL || *cmd == '\0') {
527 			free(cmd);
528 			cmd = xstrdup(wp->shell);
529 		}
530 	}
531 	fe->value = parse_window_name(cmd);
532 	free(cmd);
533 }
534 
535 /* Callback for pane_current_path. */
536 static void
537 format_cb_current_path(struct format_tree *ft, struct format_entry *fe)
538 {
539 	struct window_pane	*wp = ft->wp;
540 	char			*cwd;
541 
542 	if (wp == NULL)
543 		return;
544 
545 	cwd = osdep_get_cwd(wp->fd);
546 	if (cwd != NULL)
547 		fe->value = xstrdup(cwd);
548 }
549 
550 /* Callback for history_bytes. */
551 static void
552 format_cb_history_bytes(struct format_tree *ft, struct format_entry *fe)
553 {
554 	struct window_pane	*wp = ft->wp;
555 	struct grid		*gd;
556 	struct grid_line	*gl;
557 	unsigned long long	 size;
558 	u_int			 i;
559 
560 	if (wp == NULL)
561 		return;
562 	gd = wp->base.grid;
563 
564 	size = 0;
565 	for (i = 0; i < gd->hsize; i++) {
566 		gl = grid_get_line(gd, i);
567 		size += gl->cellsize * sizeof *gl->celldata;
568 		size += gl->extdsize * sizeof *gl->extddata;
569 	}
570 	size += gd->hsize * sizeof *gl;
571 
572 	xasprintf(&fe->value, "%llu", size);
573 }
574 
575 /* Callback for pane_tabs. */
576 static void
577 format_cb_pane_tabs(struct format_tree *ft, struct format_entry *fe)
578 {
579 	struct window_pane	*wp = ft->wp;
580 	struct evbuffer		*buffer;
581 	u_int			 i;
582 	int			 size;
583 
584 	if (wp == NULL)
585 		return;
586 
587 	buffer = evbuffer_new();
588 	for (i = 0; i < wp->base.grid->sx; i++) {
589 		if (!bit_test(wp->base.tabs, i))
590 			continue;
591 
592 		if (EVBUFFER_LENGTH(buffer) > 0)
593 			evbuffer_add(buffer, ",", 1);
594 		evbuffer_add_printf(buffer, "%u", i);
595 	}
596 	if ((size = EVBUFFER_LENGTH(buffer)) != 0)
597 		xasprintf(&fe->value, "%.*s", size, EVBUFFER_DATA(buffer));
598 	evbuffer_free(buffer);
599 }
600 
601 /* Callback for session_group_list. */
602 static void
603 format_cb_session_group_list(struct format_tree *ft, struct format_entry *fe)
604 {
605 	struct session		*s = ft->s;
606 	struct session_group	*sg;
607 	struct session		*loop;
608 	struct evbuffer		*buffer;
609 	int			 size;
610 
611 	if (s == NULL)
612 		return;
613 	sg = session_group_contains(s);
614 	if (sg == NULL)
615 		return;
616 
617 	buffer = evbuffer_new();
618 	TAILQ_FOREACH(loop, &sg->sessions, gentry) {
619 		if (EVBUFFER_LENGTH(buffer) > 0)
620 			evbuffer_add(buffer, ",", 1);
621 		evbuffer_add_printf(buffer, "%s", loop->name);
622 	}
623 	if ((size = EVBUFFER_LENGTH(buffer)) != 0)
624 		xasprintf(&fe->value, "%.*s", size, EVBUFFER_DATA(buffer));
625 	evbuffer_free(buffer);
626 }
627 
628 /* Merge a format tree. */
629 static void
630 format_merge(struct format_tree *ft, struct format_tree *from)
631 {
632 	struct format_entry	*fe;
633 
634 	RB_FOREACH(fe, format_entry_tree, &from->tree) {
635 		if (fe->value != NULL)
636 			format_add(ft, fe->key, "%s", fe->value);
637 	}
638 }
639 
640 /* Create a new tree. */
641 struct format_tree *
642 format_create(struct client *c, struct cmdq_item *item, int tag, int flags)
643 {
644 	struct format_tree	*ft;
645 
646 	if (!event_initialized(&format_job_event)) {
647 		evtimer_set(&format_job_event, format_job_timer, NULL);
648 		format_job_timer(-1, 0, NULL);
649 	}
650 
651 	ft = xcalloc(1, sizeof *ft);
652 	RB_INIT(&ft->tree);
653 
654 	if (c != NULL) {
655 		ft->client = c;
656 		ft->client->references++;
657 	}
658 
659 	ft->tag = tag;
660 	ft->flags = flags;
661 
662 	format_add(ft, "version", "%s", VERSION);
663 	format_add_cb(ft, "host", format_cb_host);
664 	format_add_cb(ft, "host_short", format_cb_host_short);
665 	format_add_cb(ft, "pid", format_cb_pid);
666 	format_add(ft, "socket_path", "%s", socket_path);
667 	format_add_tv(ft, "start_time", &start_time);
668 
669 	if (item != NULL) {
670 		if (item->cmd != NULL)
671 			format_add(ft, "command", "%s", item->cmd->entry->name);
672 		if (item->shared != NULL && item->shared->formats != NULL)
673 			format_merge(ft, item->shared->formats);
674 	}
675 
676 	return (ft);
677 }
678 
679 /* Free a tree. */
680 void
681 format_free(struct format_tree *ft)
682 {
683 	struct format_entry	*fe, *fe1;
684 
685 	RB_FOREACH_SAFE(fe, format_entry_tree, &ft->tree, fe1) {
686 		RB_REMOVE(format_entry_tree, &ft->tree, fe);
687 		free(fe->value);
688 		free(fe->key);
689 		free(fe);
690 	}
691 
692 	if (ft->client != NULL)
693 		server_client_unref(ft->client);
694 	free(ft);
695 }
696 
697 /* Add a key-value pair. */
698 void
699 format_add(struct format_tree *ft, const char *key, const char *fmt, ...)
700 {
701 	struct format_entry	*fe;
702 	struct format_entry	*fe_now;
703 	va_list			 ap;
704 
705 	fe = xmalloc(sizeof *fe);
706 	fe->key = xstrdup(key);
707 
708 	fe_now = RB_INSERT(format_entry_tree, &ft->tree, fe);
709 	if (fe_now != NULL) {
710 		free(fe->key);
711 		free(fe);
712 		free(fe_now->value);
713 		fe = fe_now;
714 	}
715 
716 	fe->cb = NULL;
717 	fe->t = 0;
718 
719 	va_start(ap, fmt);
720 	xvasprintf(&fe->value, fmt, ap);
721 	va_end(ap);
722 }
723 
724 /* Add a key and time. */
725 static void
726 format_add_tv(struct format_tree *ft, const char *key, struct timeval *tv)
727 {
728 	struct format_entry	*fe;
729 	struct format_entry	*fe_now;
730 
731 	fe = xmalloc(sizeof *fe);
732 	fe->key = xstrdup(key);
733 
734 	fe_now = RB_INSERT(format_entry_tree, &ft->tree, fe);
735 	if (fe_now != NULL) {
736 		free(fe->key);
737 		free(fe);
738 		free(fe_now->value);
739 		fe = fe_now;
740 	}
741 
742 	fe->cb = NULL;
743 	fe->t = tv->tv_sec;
744 
745 	fe->value = NULL;
746 }
747 
748 /* Add a key and function. */
749 static void
750 format_add_cb(struct format_tree *ft, const char *key, format_cb cb)
751 {
752 	struct format_entry	*fe;
753 	struct format_entry	*fe_now;
754 
755 	fe = xmalloc(sizeof *fe);
756 	fe->key = xstrdup(key);
757 
758 	fe_now = RB_INSERT(format_entry_tree, &ft->tree, fe);
759 	if (fe_now != NULL) {
760 		free(fe->key);
761 		free(fe);
762 		free(fe_now->value);
763 		fe = fe_now;
764 	}
765 
766 	fe->cb = cb;
767 	fe->t = 0;
768 
769 	fe->value = NULL;
770 }
771 
772 /* Find a format entry. */
773 static char *
774 format_find(struct format_tree *ft, const char *key, int modifiers)
775 {
776 	struct format_entry	*fe, fe_find;
777 	struct environ_entry	*envent;
778 	static char		 s[64];
779 	struct options_entry	*o;
780 	const char		*found;
781 	int			 idx;
782 	char			*copy, *saved;
783 
784 	if (~modifiers & FORMAT_TIMESTRING) {
785 		o = options_parse_get(global_options, key, &idx, 0);
786 		if (o == NULL && ft->w != NULL)
787 			o = options_parse_get(ft->w->options, key, &idx, 0);
788 		if (o == NULL)
789 			o = options_parse_get(global_w_options, key, &idx, 0);
790 		if (o == NULL && ft->s != NULL)
791 			o = options_parse_get(ft->s->options, key, &idx, 0);
792 		if (o == NULL)
793 			o = options_parse_get(global_s_options, key, &idx, 0);
794 		if (o != NULL) {
795 			found = options_tostring(o, idx, 1);
796 			goto found;
797 		}
798 	}
799 	found = NULL;
800 
801 	fe_find.key = __UNCONST(key);
802 	fe = RB_FIND(format_entry_tree, &ft->tree, &fe_find);
803 	if (fe != NULL) {
804 		if (modifiers & FORMAT_TIMESTRING) {
805 			if (fe->t == 0)
806 				return (NULL);
807 			ctime_r(&fe->t, s);
808 			s[strcspn(s, "\n")] = '\0';
809 			found = s;
810 			goto found;
811 		}
812 		if (fe->t != 0) {
813 			xsnprintf(s, sizeof s, "%lld", (long long)fe->t);
814 			found = s;
815 			goto found;
816 		}
817 		if (fe->value == NULL && fe->cb != NULL) {
818 			fe->cb(ft, fe);
819 			if (fe->value == NULL)
820 				fe->value = xstrdup("");
821 		}
822 		found = fe->value;
823 		goto found;
824 	}
825 
826 	if (~modifiers & FORMAT_TIMESTRING) {
827 		envent = NULL;
828 		if (ft->s != NULL)
829 			envent = environ_find(ft->s->environ, key);
830 		if (envent == NULL)
831 			envent = environ_find(global_environ, key);
832 		if (envent != NULL) {
833 			found = envent->value;
834 			goto found;
835 		}
836 	}
837 
838 	return (NULL);
839 
840 found:
841 	if (found == NULL)
842 		return (NULL);
843 	copy = xstrdup(found);
844 	if (modifiers & FORMAT_BASENAME) {
845 		saved = copy;
846 		copy = xstrdup(basename(saved));
847 		free(saved);
848 	}
849 	if (modifiers & FORMAT_DIRNAME) {
850 		saved = copy;
851 		copy = xstrdup(dirname(saved));
852 		free(saved);
853 	}
854 	return (copy);
855 }
856 
857 /* Skip until end. */
858 static char *
859 format_skip(const char *s, char end)
860 {
861 	int	brackets = 0;
862 
863 	for (; *s != '\0'; s++) {
864 		if (*s == '#' && s[1] == '{')
865 			brackets++;
866 		if (*s == '#' && strchr(",#{}", s[1]) != NULL) {
867 			s++;
868 			continue;
869 		}
870 		if (*s == '}')
871 			brackets--;
872 		if (*s == end && brackets == 0)
873 			break;
874 	}
875 	if (*s == '\0')
876 		return (NULL);
877 	return __UNCONST(s);
878 }
879 
880 /* Return left and right alternatives separated by commas. */
881 static int
882 format_choose(char *s, char **left, char **right)
883 {
884 	char	*cp;
885 
886 	cp = format_skip(s, ',');
887 	if (cp == NULL)
888 		return (-1);
889 	*cp = '\0';
890 
891 	*left = s;
892 	*right = cp + 1;
893 	return (0);
894 }
895 
896 /* Is this true? */
897 int
898 format_true(const char *s)
899 {
900 	if (s != NULL && *s != '\0' && (s[0] != '0' || s[1] != '\0'))
901 		return (1);
902 	return (0);
903 }
904 
905 /* Replace a key. */
906 static int
907 format_replace(struct format_tree *ft, const char *key, size_t keylen,
908     char **buf, size_t *len, size_t *off)
909 {
910 	struct window_pane	*wp = ft->wp;
911 	char			*copy, *copy0, *endptr, *ptr, *found, *new, sep;
912 	char			*value, *from = NULL, *to = NULL, *left, *right;
913 	size_t			 valuelen, newlen, fromlen, tolen, used;
914 	long			 limit = 0;
915 	int			 modifiers = 0, compare = 0, search = 0;
916 	int			 literal = 0;
917 
918 	/* Make a copy of the key. */
919 	copy0 = copy = xmalloc(keylen + 1);
920 	memcpy(copy, key, keylen);
921 	copy[keylen] = '\0';
922 
923 	/* Is there a length limit or whatnot? */
924 	switch (copy[0]) {
925 	case 'l':
926 		if (copy[1] != ':')
927 			break;
928 		literal = 1;
929 		copy += 2;
930 		break;
931 	case 'm':
932 		if (copy[1] != ':')
933 			break;
934 		compare = -2;
935 		copy += 2;
936 		break;
937 	case 'C':
938 		if (copy[1] != ':')
939 			break;
940 		search = 1;
941 		copy += 2;
942 		break;
943 	case '|':
944 		if (copy[1] != '|' || copy[2] != ':')
945 			break;
946 		compare = -3;
947 		copy += 3;
948 		break;
949 	case '&':
950 		if (copy[1] != '&' || copy[2] != ':')
951 			break;
952 		compare = -4;
953 		copy += 3;
954 		break;
955 	case '!':
956 		if (copy[1] == '=' && copy[2] == ':') {
957 			compare = -1;
958 			copy += 3;
959 			break;
960 		}
961 		break;
962 	case '=':
963 		if (copy[1] == '=' && copy[2] == ':') {
964 			compare = 1;
965 			copy += 3;
966 			break;
967 		}
968 		errno = 0;
969 		limit = strtol(copy + 1, &endptr, 10);
970 		if (errno == ERANGE && (limit == LONG_MIN || limit == LONG_MAX))
971 			break;
972 		if (*endptr != ':')
973 			break;
974 		copy = endptr + 1;
975 		break;
976 	case 'b':
977 		if (copy[1] != ':')
978 			break;
979 		modifiers |= FORMAT_BASENAME;
980 		copy += 2;
981 		break;
982 	case 'd':
983 		if (copy[1] != ':')
984 			break;
985 		modifiers |= FORMAT_DIRNAME;
986 		copy += 2;
987 		break;
988 	case 't':
989 		if (copy[1] != ':')
990 			break;
991 		modifiers |= FORMAT_TIMESTRING;
992 		copy += 2;
993 		break;
994 	case 's':
995 		sep = copy[1];
996 		if (sep == ':' || !ispunct((u_char)sep))
997 			break;
998 		from = copy + 2;
999 		for (copy = from; *copy != '\0' && *copy != sep; copy++)
1000 			/* nothing */;
1001 		if (copy[0] != sep || copy == from) {
1002 			copy = copy0;
1003 			break;
1004 		}
1005 		copy[0] = '\0';
1006 		to = copy + 1;
1007 		for (copy = to; *copy != '\0' && *copy != sep; copy++)
1008 			/* nothing */;
1009 		if (copy[0] != sep || copy[1] != ':') {
1010 			copy = copy0;
1011 			break;
1012 		}
1013 		copy[0] = '\0';
1014 
1015 		modifiers |= FORMAT_SUBSTITUTE;
1016 		copy += 2;
1017 		break;
1018 	}
1019 
1020 	/* Is this a literal string? */
1021 	if (literal) {
1022 		value = xstrdup(copy);
1023 		goto done;
1024 	}
1025 
1026 	/* Is this a comparison or a conditional? */
1027 	if (search) {
1028 		/* Search in pane. */
1029 		if (wp == NULL)
1030 			value = xstrdup("0");
1031 		else
1032 			xasprintf(&value, "%u", window_pane_search(wp, copy));
1033 	} else if (compare != 0) {
1034 		/* Comparison: compare comma-separated left and right. */
1035 		if (format_choose(copy, &left, &right) != 0)
1036 			goto fail;
1037 		left = format_expand(ft, left);
1038 		right = format_expand(ft, right);
1039 		if (compare == -3 &&
1040 		    (format_true(left) || format_true(right)))
1041 			value = xstrdup("1");
1042 		else if (compare == -4 &&
1043 		    (format_true(left) && format_true(right)))
1044 			value = xstrdup("1");
1045 		else if (compare == 1 && strcmp(left, right) == 0)
1046 			value = xstrdup("1");
1047 		else if (compare == -1 && strcmp(left, right) != 0)
1048 			value = xstrdup("1");
1049 		else if (compare == -2 && fnmatch(left, right, 0) == 0)
1050 			value = xstrdup("1");
1051 		else
1052 			value = xstrdup("0");
1053 		free(right);
1054 		free(left);
1055 	} else if (*copy == '?') {
1056 		/* Conditional: check first and choose second or third. */
1057 		ptr = format_skip(copy, ',');
1058 		if (ptr == NULL)
1059 			goto fail;
1060 		*ptr = '\0';
1061 
1062 		found = format_find(ft, copy + 1, modifiers);
1063 		if (found == NULL) {
1064 			/*
1065 			 * If the conditional not found, try to expand it. If
1066 			 * the expansion doesn't have any effect, then assume
1067 			 * false.
1068 			 */
1069 			found = format_expand(ft, copy + 1);
1070 			if (strcmp(found, copy + 1) == 0) {
1071 				free(found);
1072 				found = xstrdup("");
1073 			}
1074 		}
1075 		if (format_choose(ptr + 1, &left, &right) != 0)
1076 			goto fail;
1077 
1078 		if (format_true(found))
1079 			value = format_expand(ft, left);
1080 		else
1081 			value = format_expand(ft, right);
1082 		free(found);
1083 	} else {
1084 		/* Neither: look up directly. */
1085 		value = format_find(ft, copy, modifiers);
1086 		if (value == NULL)
1087 			value = xstrdup("");
1088 	}
1089 
1090 	/* Perform substitution if any. */
1091 	if (modifiers & FORMAT_SUBSTITUTE) {
1092 		fromlen = strlen(from);
1093 		tolen = strlen(to);
1094 
1095 		newlen = strlen(value) + 1;
1096 		copy = new = xmalloc(newlen);
1097 		for (ptr = value; *ptr != '\0'; /* nothing */) {
1098 			if (strncmp(ptr, from, fromlen) != 0) {
1099 				*new++ = *ptr++;
1100 				continue;
1101 			}
1102 			used = new - copy;
1103 
1104 			newlen += tolen;
1105 			copy = xrealloc(copy, newlen);
1106 
1107 			new = copy + used;
1108 			memcpy(new, to, tolen);
1109 
1110 			new += tolen;
1111 			ptr += fromlen;
1112 		}
1113 		*new = '\0';
1114 		free(value);
1115 		value = copy;
1116 	}
1117 
1118 	/* Truncate the value if needed. */
1119 	if (limit > 0) {
1120 		new = utf8_trimcstr(value, limit);
1121 		free(value);
1122 		value = new;
1123 	} else if (limit < 0) {
1124 		new = utf8_rtrimcstr(value, -limit);
1125 		free(value);
1126 		value = new;
1127 	}
1128 
1129 done:
1130 	/* Expand the buffer and copy in the value. */
1131 	valuelen = strlen(value);
1132 	while (*len - *off < valuelen + 1) {
1133 		*buf = xreallocarray(*buf, 2, *len);
1134 		*len *= 2;
1135 	}
1136 	memcpy(*buf + *off, value, valuelen);
1137 	*off += valuelen;
1138 
1139 	free(value);
1140 	free(copy0);
1141 	return (0);
1142 
1143 fail:
1144 	free(copy0);
1145 	return (-1);
1146 }
1147 
1148 /* Expand keys in a template, passing through strftime first. */
1149 char *
1150 format_expand_time(struct format_tree *ft, const char *fmt, time_t t)
1151 {
1152 	struct tm	*tm;
1153 	char		 s[2048];
1154 
1155 	if (fmt == NULL || *fmt == '\0')
1156 		return (xstrdup(""));
1157 
1158 	tm = localtime(&t);
1159 
1160 	if (strftime(s, sizeof s, fmt, tm) == 0)
1161 		return (xstrdup(""));
1162 
1163 	return (format_expand(ft, s));
1164 }
1165 
1166 /* Expand keys in a template. */
1167 char *
1168 format_expand(struct format_tree *ft, const char *fmt)
1169 {
1170 	char		*buf, *out, *name;
1171 	const char	*ptr, *s, *saved = fmt;
1172 	size_t		 off, len, n, outlen;
1173 	int     	 ch, brackets;
1174 
1175 	if (fmt == NULL)
1176 		return (xstrdup(""));
1177 
1178 	len = 64;
1179 	buf = xmalloc(len);
1180 	off = 0;
1181 
1182 	while (*fmt != '\0') {
1183 		if (*fmt != '#') {
1184 			while (len - off < 2) {
1185 				buf = xreallocarray(buf, 2, len);
1186 				len *= 2;
1187 			}
1188 			buf[off++] = *fmt++;
1189 			continue;
1190 		}
1191 		fmt++;
1192 
1193 		ch = (u_char) *fmt++;
1194 		switch (ch) {
1195 		case '(':
1196 			brackets = 1;
1197 			for (ptr = fmt; *ptr != '\0'; ptr++) {
1198 				if (*ptr == '(')
1199 					brackets++;
1200 				if (*ptr == ')' && --brackets == 0)
1201 					break;
1202 			}
1203 			if (*ptr != ')' || brackets != 0)
1204 				break;
1205 			n = ptr - fmt;
1206 
1207 			if (ft->flags & FORMAT_NOJOBS)
1208 				out = xstrdup("");
1209 			else {
1210 				name = xstrndup(fmt, n);
1211 				out = format_job_get(ft, name);
1212 				free(name);
1213 			}
1214 			outlen = strlen(out);
1215 
1216 			while (len - off < outlen + 1) {
1217 				buf = xreallocarray(buf, 2, len);
1218 				len *= 2;
1219 			}
1220 			memcpy(buf + off, out, outlen);
1221 			off += outlen;
1222 
1223 			free(out);
1224 
1225 			fmt += n + 1;
1226 			continue;
1227 		case '{':
1228 			ptr = format_skip(fmt - 2, '}');
1229 			if (ptr == NULL)
1230 				break;
1231 			n = ptr - fmt;
1232 
1233 			if (format_replace(ft, fmt, n, &buf, &len, &off) != 0)
1234 				break;
1235 			fmt += n + 1;
1236 			continue;
1237 		case '}':
1238 		case '#':
1239 		case ',':
1240 			while (len - off < 2) {
1241 				buf = xreallocarray(buf, 2, len);
1242 				len *= 2;
1243 			}
1244 			buf[off++] = ch;
1245 			continue;
1246 		default:
1247 			s = NULL;
1248 			if (ch >= 'A' && ch <= 'Z')
1249 				s = format_upper[ch - 'A'];
1250 			else if (ch >= 'a' && ch <= 'z')
1251 				s = format_lower[ch - 'a'];
1252 			if (s == NULL) {
1253 				while (len - off < 3) {
1254 					buf = xreallocarray(buf, 2, len);
1255 					len *= 2;
1256 				}
1257 				buf[off++] = '#';
1258 				buf[off++] = ch;
1259 				continue;
1260 			}
1261 			n = strlen(s);
1262 			if (format_replace(ft, s, n, &buf, &len, &off) != 0)
1263 				break;
1264 			continue;
1265 		}
1266 
1267 		break;
1268 	}
1269 	buf[off] = '\0';
1270 
1271 	log_debug("format '%s' -> '%s'", saved, buf);
1272 	return (buf);
1273 }
1274 
1275 /* Expand a single string. */
1276 char *
1277 format_single(struct cmdq_item *item, const char *fmt, struct client *c,
1278     struct session *s, struct winlink *wl, struct window_pane *wp)
1279 {
1280 	struct format_tree	*ft;
1281 	char			*expanded;
1282 
1283 	if (item != NULL)
1284 		ft = format_create(item->client, item, FORMAT_NONE, 0);
1285 	else
1286 		ft = format_create(NULL, item, FORMAT_NONE, 0);
1287 	format_defaults(ft, c, s, wl, wp);
1288 
1289 	expanded = format_expand(ft, fmt);
1290 	format_free(ft);
1291 	return (expanded);
1292 }
1293 
1294 /* Set defaults for any of arguments that are not NULL. */
1295 void
1296 format_defaults(struct format_tree *ft, struct client *c, struct session *s,
1297     struct winlink *wl, struct window_pane *wp)
1298 {
1299 	if (c != NULL && s != NULL && c->session != s)
1300 		log_debug("%s: session does not match", __func__);
1301 
1302 	format_add(ft, "session_format", "%d", s != NULL);
1303 	format_add(ft, "window_format", "%d", wl != NULL);
1304 	format_add(ft, "pane_format", "%d", wp != NULL);
1305 
1306 	if (s == NULL && c != NULL)
1307 		s = c->session;
1308 	if (wl == NULL && s != NULL)
1309 		wl = s->curw;
1310 	if (wp == NULL && wl != NULL)
1311 		wp = wl->window->active;
1312 
1313 	if (c != NULL)
1314 		format_defaults_client(ft, c);
1315 	if (s != NULL)
1316 		format_defaults_session(ft, s);
1317 	if (wl != NULL)
1318 		format_defaults_winlink(ft, wl);
1319 	if (wp != NULL)
1320 		format_defaults_pane(ft, wp);
1321 }
1322 
1323 /* Set default format keys for a session. */
1324 static void
1325 format_defaults_session(struct format_tree *ft, struct session *s)
1326 {
1327 	struct session_group	*sg;
1328 
1329 	ft->s = s;
1330 
1331 	format_add(ft, "session_name", "%s", s->name);
1332 	format_add(ft, "session_windows", "%u", winlink_count(&s->windows));
1333 	format_add(ft, "session_width", "%u", s->sx);
1334 	format_add(ft, "session_height", "%u", s->sy);
1335 	format_add(ft, "session_id", "$%u", s->id);
1336 
1337 	sg = session_group_contains(s);
1338 	format_add(ft, "session_grouped", "%d", sg != NULL);
1339 	if (sg != NULL) {
1340 		format_add(ft, "session_group", "%s", sg->name);
1341 		format_add(ft, "session_group_size", "%u",
1342 		    session_group_count (sg));
1343 		format_add_cb(ft, "session_group_list",
1344 		    format_cb_session_group_list);
1345 	}
1346 
1347 	format_add_tv(ft, "session_created", &s->creation_time);
1348 	format_add_tv(ft, "session_last_attached", &s->last_attached_time);
1349 	format_add_tv(ft, "session_activity", &s->activity_time);
1350 
1351 	format_add(ft, "session_attached", "%u", s->attached);
1352 	format_add(ft, "session_many_attached", "%d", s->attached > 1);
1353 
1354 	format_add_cb(ft, "session_alerts", format_cb_session_alerts);
1355 	format_add_cb(ft, "session_stack", format_cb_session_stack);
1356 }
1357 
1358 /* Set default format keys for a client. */
1359 static void
1360 format_defaults_client(struct format_tree *ft, struct client *c)
1361 {
1362 	struct session	*s;
1363 	const char	*name;
1364 	struct tty	*tty = &c->tty;
1365 	const char	*types[] = TTY_TYPES;
1366 
1367 	if (ft->s == NULL)
1368 		ft->s = c->session;
1369 
1370 	format_add(ft, "client_name", "%s", c->name);
1371 	format_add(ft, "client_pid", "%ld", (long) c->pid);
1372 	format_add(ft, "client_height", "%u", tty->sy);
1373 	format_add(ft, "client_width", "%u", tty->sx);
1374 	format_add(ft, "client_tty", "%s", c->ttyname);
1375 	format_add(ft, "client_control_mode", "%d",
1376 		!!(c->flags & CLIENT_CONTROL));
1377 
1378 	if (tty->term_name != NULL)
1379 		format_add(ft, "client_termname", "%s", tty->term_name);
1380 	if (tty->term_name != NULL)
1381 		format_add(ft, "client_termtype", "%s", types[tty->term_type]);
1382 
1383 	format_add_tv(ft, "client_created", &c->creation_time);
1384 	format_add_tv(ft, "client_activity", &c->activity_time);
1385 
1386 	format_add(ft, "client_written", "%zu", c->written);
1387 	format_add(ft, "client_discarded", "%zu", c->discarded);
1388 
1389 	name = server_client_get_key_table(c);
1390 	if (strcmp(c->keytable->name, name) == 0)
1391 		format_add(ft, "client_prefix", "%d", 0);
1392 	else
1393 		format_add(ft, "client_prefix", "%d", 1);
1394 	format_add(ft, "client_key_table", "%s", c->keytable->name);
1395 
1396 	if (tty->flags & TTY_UTF8)
1397 		format_add(ft, "client_utf8", "%d", 1);
1398 	else
1399 		format_add(ft, "client_utf8", "%d", 0);
1400 
1401 	if (c->flags & CLIENT_READONLY)
1402 		format_add(ft, "client_readonly", "%d", 1);
1403 	else
1404 		format_add(ft, "client_readonly", "%d", 0);
1405 
1406 	s = c->session;
1407 	if (s != NULL)
1408 		format_add(ft, "client_session", "%s", s->name);
1409 	s = c->last_session;
1410 	if (s != NULL && session_alive(s))
1411 		format_add(ft, "client_last_session", "%s", s->name);
1412 }
1413 
1414 /* Set default format keys for a window. */
1415 void
1416 format_defaults_window(struct format_tree *ft, struct window *w)
1417 {
1418 	ft->w = w;
1419 
1420 	format_add_tv(ft, "window_activity", &w->activity_time);
1421 	format_add(ft, "window_id", "@%u", w->id);
1422 	format_add(ft, "window_name", "%s", w->name);
1423 	format_add(ft, "window_width", "%u", w->sx);
1424 	format_add(ft, "window_height", "%u", w->sy);
1425 	format_add_cb(ft, "window_layout", format_cb_window_layout);
1426 	format_add_cb(ft, "window_visible_layout",
1427 	    format_cb_window_visible_layout);
1428 	format_add(ft, "window_panes", "%u", window_count_panes(w));
1429 	format_add(ft, "window_zoomed_flag", "%d",
1430 	    !!(w->flags & WINDOW_ZOOMED));
1431 }
1432 
1433 /* Set default format keys for a winlink. */
1434 static void
1435 format_defaults_winlink(struct format_tree *ft, struct winlink *wl)
1436 {
1437 	struct session	*s = wl->session;
1438 	struct window	*w = wl->window;
1439 
1440 	if (ft->w == NULL)
1441 		ft->w = wl->window;
1442 	ft->wl = wl;
1443 
1444 	format_defaults_window(ft, w);
1445 
1446 	format_add(ft, "window_index", "%d", wl->idx);
1447 	format_add_cb(ft, "window_stack_index", format_cb_window_stack_index);
1448 	format_add(ft, "window_flags", "%s", window_printable_flags(wl));
1449 	format_add(ft, "window_active", "%d", wl == s->curw);
1450 
1451 	format_add(ft, "window_bell_flag", "%d",
1452 	    !!(wl->flags & WINLINK_BELL));
1453 	format_add(ft, "window_activity_flag", "%d",
1454 	    !!(wl->flags & WINLINK_ACTIVITY));
1455 	format_add(ft, "window_silence_flag", "%d",
1456 	    !!(wl->flags & WINLINK_SILENCE));
1457 	format_add(ft, "window_last_flag", "%d",
1458 	    !!(wl == TAILQ_FIRST(&s->lastw)));
1459 	format_add(ft, "window_linked", "%d", session_is_linked(s, wl->window));
1460 }
1461 
1462 /* Set default format keys for a window pane. */
1463 void
1464 format_defaults_pane(struct format_tree *ft, struct window_pane *wp)
1465 {
1466 	struct grid	*gd = wp->base.grid;
1467 	int  		 status = wp->status;
1468 	u_int		 idx;
1469 
1470 	if (ft->w == NULL)
1471 		ft->w = wp->window;
1472 	ft->wp = wp;
1473 
1474 	format_add(ft, "history_size", "%u", gd->hsize);
1475 	format_add(ft, "history_limit", "%u", gd->hlimit);
1476 	format_add_cb(ft, "history_bytes", format_cb_history_bytes);
1477 
1478 	if (window_pane_index(wp, &idx) != 0)
1479 		fatalx("index not found");
1480 	format_add(ft, "pane_index", "%u", idx);
1481 
1482 	format_add(ft, "pane_width", "%u", wp->sx);
1483 	format_add(ft, "pane_height", "%u", wp->sy);
1484 	format_add(ft, "pane_title", "%s", wp->base.title);
1485 	format_add(ft, "pane_id", "%%%u", wp->id);
1486 	format_add(ft, "pane_active", "%d", wp == wp->window->active);
1487 	format_add(ft, "pane_input_off", "%d", !!(wp->flags & PANE_INPUTOFF));
1488 	format_add(ft, "pane_pipe", "%d", wp->pipe_fd != -1);
1489 
1490 	if ((wp->flags & PANE_STATUSREADY) && WIFEXITED(status))
1491 		format_add(ft, "pane_dead_status", "%d", WEXITSTATUS(status));
1492 	format_add(ft, "pane_dead", "%d", wp->fd == -1);
1493 
1494 	if (window_pane_visible(wp)) {
1495 		format_add(ft, "pane_left", "%u", wp->xoff);
1496 		format_add(ft, "pane_top", "%u", wp->yoff);
1497 		format_add(ft, "pane_right", "%u", wp->xoff + wp->sx - 1);
1498 		format_add(ft, "pane_bottom", "%u", wp->yoff + wp->sy - 1);
1499 		format_add(ft, "pane_at_left", "%d", wp->xoff == 0);
1500 		format_add(ft, "pane_at_top", "%d", wp->yoff == 0);
1501 		format_add(ft, "pane_at_right", "%d",
1502 		    wp->xoff + wp->sx == wp->window->sx);
1503 		format_add(ft, "pane_at_bottom", "%d",
1504 		    wp->yoff + wp->sy == wp->window->sy);
1505 	}
1506 
1507 	format_add(ft, "pane_in_mode", "%d", wp->screen != &wp->base);
1508 	if (wp->mode != NULL)
1509 		format_add(ft, "pane_mode", "%s", wp->mode->name);
1510 
1511 	format_add(ft, "pane_synchronized", "%d",
1512 	    !!options_get_number(wp->window->options, "synchronize-panes"));
1513 	if (wp->searchstr != NULL)
1514 		format_add(ft, "pane_search_string", "%s", wp->searchstr);
1515 
1516 	format_add(ft, "pane_tty", "%s", wp->tty);
1517 	format_add(ft, "pane_pid", "%ld", (long) wp->pid);
1518 	format_add_cb(ft, "pane_start_command", format_cb_start_command);
1519 	format_add_cb(ft, "pane_current_command", format_cb_current_command);
1520 	format_add_cb(ft, "pane_current_path", format_cb_current_path);
1521 
1522 	format_add(ft, "cursor_x", "%u", wp->base.cx);
1523 	format_add(ft, "cursor_y", "%u", wp->base.cy);
1524 	format_add(ft, "scroll_region_upper", "%u", wp->base.rupper);
1525 	format_add(ft, "scroll_region_lower", "%u", wp->base.rlower);
1526 
1527 	window_copy_add_formats(wp, ft);
1528 
1529 	format_add(ft, "alternate_on", "%d", wp->saved_grid ? 1 : 0);
1530 	format_add(ft, "alternate_saved_x", "%u", wp->saved_cx);
1531 	format_add(ft, "alternate_saved_y", "%u", wp->saved_cy);
1532 
1533 	format_add(ft, "cursor_flag", "%d",
1534 	    !!(wp->base.mode & MODE_CURSOR));
1535 	format_add(ft, "insert_flag", "%d",
1536 	    !!(wp->base.mode & MODE_INSERT));
1537 	format_add(ft, "keypad_cursor_flag", "%d",
1538 	    !!(wp->base.mode & MODE_KCURSOR));
1539 	format_add(ft, "keypad_flag", "%d",
1540 	    !!(wp->base.mode & MODE_KKEYPAD));
1541 	format_add(ft, "wrap_flag", "%d",
1542 	    !!(wp->base.mode & MODE_WRAP));
1543 
1544 	format_add(ft, "mouse_any_flag", "%d",
1545 	    !!(wp->base.mode & ALL_MOUSE_MODES));
1546 	format_add(ft, "mouse_standard_flag", "%d",
1547 	    !!(wp->base.mode & MODE_MOUSE_STANDARD));
1548 	format_add(ft, "mouse_button_flag", "%d",
1549 	    !!(wp->base.mode & MODE_MOUSE_BUTTON));
1550 	format_add(ft, "mouse_all_flag", "%d",
1551 	    !!(wp->base.mode & MODE_MOUSE_ALL));
1552 
1553 	format_add_cb(ft, "pane_tabs", format_cb_pane_tabs);
1554 }
1555 
1556 /* Set default format keys for paste buffer. */
1557 void
1558 format_defaults_paste_buffer(struct format_tree *ft, struct paste_buffer *pb)
1559 {
1560 	struct timeval	 tv;
1561 	size_t		 size;
1562 	char		*s;
1563 
1564 	timerclear(&tv);
1565 	tv.tv_sec = paste_buffer_created(pb);
1566 	paste_buffer_data(pb, &size);
1567 
1568 	format_add(ft, "buffer_size", "%zu", size);
1569 	format_add(ft, "buffer_name", "%s", paste_buffer_name(pb));
1570 	format_add_tv(ft, "buffer_created", &tv);
1571 
1572 	s = paste_make_sample(pb);
1573 	format_add(ft, "buffer_sample", "%s", s);
1574 	free(s);
1575 }
1576