format.c revision 1.8
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
39struct format_entry;
40typedef void (*format_cb)(struct format_tree *, struct format_entry *);
41
42static char	*format_job_get(struct format_tree *, const char *);
43static void	 format_job_timer(int, short, void *);
44
45static char	*format_find(struct format_tree *, const char *, int);
46static void	 format_add_cb(struct format_tree *, const char *, format_cb);
47static void	 format_add_tv(struct format_tree *, const char *,
48		     struct timeval *);
49static int	 format_replace(struct format_tree *, const char *, size_t,
50		     char **, size_t *, size_t *);
51
52static void	 format_defaults_session(struct format_tree *,
53		     struct session *);
54static void	 format_defaults_client(struct format_tree *, struct client *);
55static void	 format_defaults_winlink(struct format_tree *,
56		     struct winlink *);
57
58/* Entry in format job tree. */
59struct 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. */
76static struct event format_job_event;
77static int format_job_cmp(struct format_job *, struct format_job *);
78static RB_HEAD(format_job_tree, format_job) format_jobs = RB_INITIALIZER();
79RB_GENERATE_STATIC(format_job_tree, format_job, entry, format_job_cmp);
80
81/* Format job tree comparison function. */
82static int
83format_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. */
99struct 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. */
108struct 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};
120static int format_entry_cmp(struct format_entry *, struct format_entry *);
121RB_GENERATE_STATIC(format_entry_tree, format_entry, entry, format_entry_cmp);
122
123/* Format entry tree comparison function. */
124static int
125format_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. */
131static 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. */
161static 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. */
191static void
192format_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. */
221static void
222format_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. */
256static char *
257format_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. */
316static void
317format_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. */
342void
343format_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. */
351static void
352format_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. */
368static void
369format_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. */
380static void
381format_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. */
395static void
396format_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. */
402static void
403format_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. */
432static void
433format_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. */
454static void
455format_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. */
474static void
475format_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. */
489static void
490format_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. */
501static void
502format_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. */
513static void
514format_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. */
536static void
537format_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. */
551static void
552format_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. */
576static void
577format_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. */
602static void
603format_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. */
629static void
630format_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. */
641struct format_tree *
642format_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. */
680void
681format_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. */
698void
699format_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. */
725static void
726format_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. */
749static void
750format_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. */
773static char *
774format_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
840found:
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. */
858static char *
859format_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. */
881static int
882format_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? */
897int
898format_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. */
906static int
907format_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
1129done:
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
1143fail:
1144	free(copy0);
1145	return (-1);
1146}
1147
1148/* Expand keys in a template, passing through strftime first. */
1149char *
1150format_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. */
1167char *
1168format_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. */
1276char *
1277format_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. */
1295void
1296format_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. */
1324static void
1325format_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. */
1359static void
1360format_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. */
1415void
1416format_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. */
1434static void
1435format_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. */
1463void
1464format_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. */
1557void
1558format_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