xref: /minix/external/bsd/tmux/dist/format.c (revision 0a6a1f1d)
1*0a6a1f1dSLionel Sambuc /* Id */
2*0a6a1f1dSLionel Sambuc 
3*0a6a1f1dSLionel Sambuc /*
4*0a6a1f1dSLionel Sambuc  * Copyright (c) 2011 Nicholas Marriott <nicm@users.sourceforge.net>
5*0a6a1f1dSLionel Sambuc  *
6*0a6a1f1dSLionel Sambuc  * Permission to use, copy, modify, and distribute this software for any
7*0a6a1f1dSLionel Sambuc  * purpose with or without fee is hereby granted, provided that the above
8*0a6a1f1dSLionel Sambuc  * copyright notice and this permission notice appear in all copies.
9*0a6a1f1dSLionel Sambuc  *
10*0a6a1f1dSLionel Sambuc  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11*0a6a1f1dSLionel Sambuc  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12*0a6a1f1dSLionel Sambuc  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13*0a6a1f1dSLionel Sambuc  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14*0a6a1f1dSLionel Sambuc  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15*0a6a1f1dSLionel Sambuc  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16*0a6a1f1dSLionel Sambuc  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*0a6a1f1dSLionel Sambuc  */
18*0a6a1f1dSLionel Sambuc 
19*0a6a1f1dSLionel Sambuc #include <sys/types.h>
20*0a6a1f1dSLionel Sambuc 
21*0a6a1f1dSLionel Sambuc #include <ctype.h>
22*0a6a1f1dSLionel Sambuc #include <errno.h>
23*0a6a1f1dSLionel Sambuc #include <netdb.h>
24*0a6a1f1dSLionel Sambuc #include <stdarg.h>
25*0a6a1f1dSLionel Sambuc #include <stdlib.h>
26*0a6a1f1dSLionel Sambuc #include <string.h>
27*0a6a1f1dSLionel Sambuc #include <time.h>
28*0a6a1f1dSLionel Sambuc #include <unistd.h>
29*0a6a1f1dSLionel Sambuc 
30*0a6a1f1dSLionel Sambuc #include "tmux.h"
31*0a6a1f1dSLionel Sambuc 
32*0a6a1f1dSLionel Sambuc /*
33*0a6a1f1dSLionel Sambuc  * Build a list of key-value pairs and use them to expand #{key} entries in a
34*0a6a1f1dSLionel Sambuc  * string.
35*0a6a1f1dSLionel Sambuc  */
36*0a6a1f1dSLionel Sambuc 
37*0a6a1f1dSLionel Sambuc int	 format_replace(struct format_tree *, const char *, size_t, char **,
38*0a6a1f1dSLionel Sambuc 	     size_t *, size_t *);
39*0a6a1f1dSLionel Sambuc char	*format_get_command(struct window_pane *);
40*0a6a1f1dSLionel Sambuc void	 format_window_pane_tabs(struct format_tree *, struct window_pane *);
41*0a6a1f1dSLionel Sambuc 
42*0a6a1f1dSLionel Sambuc /* Format key-value replacement entry. */
43*0a6a1f1dSLionel Sambuc RB_GENERATE(format_tree, format_entry, entry, format_cmp);
44*0a6a1f1dSLionel Sambuc 
45*0a6a1f1dSLionel Sambuc /* Format tree comparison function. */
46*0a6a1f1dSLionel Sambuc int
format_cmp(struct format_entry * fe1,struct format_entry * fe2)47*0a6a1f1dSLionel Sambuc format_cmp(struct format_entry *fe1, struct format_entry *fe2)
48*0a6a1f1dSLionel Sambuc {
49*0a6a1f1dSLionel Sambuc 	return (strcmp(fe1->key, fe2->key));
50*0a6a1f1dSLionel Sambuc }
51*0a6a1f1dSLionel Sambuc 
52*0a6a1f1dSLionel Sambuc /* Single-character uppercase aliases. */
53*0a6a1f1dSLionel Sambuc const char *format_upper[] = {
54*0a6a1f1dSLionel Sambuc 	NULL,		/* A */
55*0a6a1f1dSLionel Sambuc 	NULL,		/* B */
56*0a6a1f1dSLionel Sambuc 	NULL,		/* C */
57*0a6a1f1dSLionel Sambuc 	"pane_id",	/* D */
58*0a6a1f1dSLionel Sambuc 	NULL,		/* E */
59*0a6a1f1dSLionel Sambuc 	"window_flags",	/* F */
60*0a6a1f1dSLionel Sambuc 	NULL,		/* G */
61*0a6a1f1dSLionel Sambuc 	"host",		/* H */
62*0a6a1f1dSLionel Sambuc 	"window_index",	/* I */
63*0a6a1f1dSLionel Sambuc 	NULL,		/* J */
64*0a6a1f1dSLionel Sambuc 	NULL,		/* K */
65*0a6a1f1dSLionel Sambuc 	NULL,		/* L */
66*0a6a1f1dSLionel Sambuc 	NULL,		/* M */
67*0a6a1f1dSLionel Sambuc 	NULL,		/* N */
68*0a6a1f1dSLionel Sambuc 	NULL,		/* O */
69*0a6a1f1dSLionel Sambuc 	"pane_index",	/* P */
70*0a6a1f1dSLionel Sambuc 	NULL,		/* Q */
71*0a6a1f1dSLionel Sambuc 	NULL,		/* R */
72*0a6a1f1dSLionel Sambuc 	"session_name",	/* S */
73*0a6a1f1dSLionel Sambuc 	"pane_title",	/* T */
74*0a6a1f1dSLionel Sambuc 	NULL,		/* U */
75*0a6a1f1dSLionel Sambuc 	NULL,		/* V */
76*0a6a1f1dSLionel Sambuc 	"window_name",	/* W */
77*0a6a1f1dSLionel Sambuc 	NULL,		/* X */
78*0a6a1f1dSLionel Sambuc 	NULL,		/* Y */
79*0a6a1f1dSLionel Sambuc 	NULL 		/* Z */
80*0a6a1f1dSLionel Sambuc };
81*0a6a1f1dSLionel Sambuc 
82*0a6a1f1dSLionel Sambuc /* Single-character lowercase aliases. */
83*0a6a1f1dSLionel Sambuc const char *format_lower[] = {
84*0a6a1f1dSLionel Sambuc 	NULL,		/* a */
85*0a6a1f1dSLionel Sambuc 	NULL,		/* b */
86*0a6a1f1dSLionel Sambuc 	NULL,		/* c */
87*0a6a1f1dSLionel Sambuc 	NULL,		/* d */
88*0a6a1f1dSLionel Sambuc 	NULL,		/* e */
89*0a6a1f1dSLionel Sambuc 	NULL,		/* f */
90*0a6a1f1dSLionel Sambuc 	NULL,		/* g */
91*0a6a1f1dSLionel Sambuc 	"host_short",	/* h */
92*0a6a1f1dSLionel Sambuc 	NULL,		/* i */
93*0a6a1f1dSLionel Sambuc 	NULL,		/* j */
94*0a6a1f1dSLionel Sambuc 	NULL,		/* k */
95*0a6a1f1dSLionel Sambuc 	NULL,		/* l */
96*0a6a1f1dSLionel Sambuc 	NULL,		/* m */
97*0a6a1f1dSLionel Sambuc 	NULL,		/* n */
98*0a6a1f1dSLionel Sambuc 	NULL,		/* o */
99*0a6a1f1dSLionel Sambuc 	NULL,		/* p */
100*0a6a1f1dSLionel Sambuc 	NULL,		/* q */
101*0a6a1f1dSLionel Sambuc 	NULL,		/* r */
102*0a6a1f1dSLionel Sambuc 	NULL,		/* s */
103*0a6a1f1dSLionel Sambuc 	NULL,		/* t */
104*0a6a1f1dSLionel Sambuc 	NULL,		/* u */
105*0a6a1f1dSLionel Sambuc 	NULL,		/* v */
106*0a6a1f1dSLionel Sambuc 	NULL,		/* w */
107*0a6a1f1dSLionel Sambuc 	NULL,		/* x */
108*0a6a1f1dSLionel Sambuc 	NULL,		/* y */
109*0a6a1f1dSLionel Sambuc 	NULL		/* z */
110*0a6a1f1dSLionel Sambuc };
111*0a6a1f1dSLionel Sambuc 
112*0a6a1f1dSLionel Sambuc /* Create a new tree. */
113*0a6a1f1dSLionel Sambuc struct format_tree *
format_create(void)114*0a6a1f1dSLionel Sambuc format_create(void)
115*0a6a1f1dSLionel Sambuc {
116*0a6a1f1dSLionel Sambuc 	struct format_tree	*ft;
117*0a6a1f1dSLionel Sambuc 	char			 host[MAXHOSTNAMELEN], *ptr;
118*0a6a1f1dSLionel Sambuc 
119*0a6a1f1dSLionel Sambuc 	ft = xmalloc(sizeof *ft);
120*0a6a1f1dSLionel Sambuc 	RB_INIT(ft);
121*0a6a1f1dSLionel Sambuc 
122*0a6a1f1dSLionel Sambuc 	if (gethostname(host, sizeof host) == 0) {
123*0a6a1f1dSLionel Sambuc 		format_add(ft, "host", "%s", host);
124*0a6a1f1dSLionel Sambuc 		if ((ptr = strchr(host, '.')) != NULL)
125*0a6a1f1dSLionel Sambuc 			*ptr = '\0';
126*0a6a1f1dSLionel Sambuc 		format_add(ft, "host_short", "%s", host);
127*0a6a1f1dSLionel Sambuc 	}
128*0a6a1f1dSLionel Sambuc 
129*0a6a1f1dSLionel Sambuc 	return (ft);
130*0a6a1f1dSLionel Sambuc }
131*0a6a1f1dSLionel Sambuc 
132*0a6a1f1dSLionel Sambuc /* Free a tree. */
133*0a6a1f1dSLionel Sambuc void
format_free(struct format_tree * ft)134*0a6a1f1dSLionel Sambuc format_free(struct format_tree *ft)
135*0a6a1f1dSLionel Sambuc {
136*0a6a1f1dSLionel Sambuc 	struct format_entry	*fe, *fe_next;
137*0a6a1f1dSLionel Sambuc 
138*0a6a1f1dSLionel Sambuc 	fe_next = RB_MIN(format_tree, ft);
139*0a6a1f1dSLionel Sambuc 	while (fe_next != NULL) {
140*0a6a1f1dSLionel Sambuc 		fe = fe_next;
141*0a6a1f1dSLionel Sambuc 		fe_next = RB_NEXT(format_tree, ft, fe);
142*0a6a1f1dSLionel Sambuc 
143*0a6a1f1dSLionel Sambuc 		RB_REMOVE(format_tree, ft, fe);
144*0a6a1f1dSLionel Sambuc 		free(fe->value);
145*0a6a1f1dSLionel Sambuc 		free(fe->key);
146*0a6a1f1dSLionel Sambuc 		free(fe);
147*0a6a1f1dSLionel Sambuc 	}
148*0a6a1f1dSLionel Sambuc 
149*0a6a1f1dSLionel Sambuc 	free(ft);
150*0a6a1f1dSLionel Sambuc }
151*0a6a1f1dSLionel Sambuc 
152*0a6a1f1dSLionel Sambuc /* Add a key-value pair. */
153*0a6a1f1dSLionel Sambuc void
format_add(struct format_tree * ft,const char * key,const char * fmt,...)154*0a6a1f1dSLionel Sambuc format_add(struct format_tree *ft, const char *key, const char *fmt, ...)
155*0a6a1f1dSLionel Sambuc {
156*0a6a1f1dSLionel Sambuc 	struct format_entry	*fe;
157*0a6a1f1dSLionel Sambuc 	struct format_entry	*fe_now;
158*0a6a1f1dSLionel Sambuc 	va_list			 ap;
159*0a6a1f1dSLionel Sambuc 
160*0a6a1f1dSLionel Sambuc 	fe = xmalloc(sizeof *fe);
161*0a6a1f1dSLionel Sambuc 	fe->key = xstrdup(key);
162*0a6a1f1dSLionel Sambuc 
163*0a6a1f1dSLionel Sambuc 	va_start(ap, fmt);
164*0a6a1f1dSLionel Sambuc 	xvasprintf(&fe->value, fmt, ap);
165*0a6a1f1dSLionel Sambuc 	va_end(ap);
166*0a6a1f1dSLionel Sambuc 
167*0a6a1f1dSLionel Sambuc 	fe_now = RB_INSERT(format_tree, ft, fe);
168*0a6a1f1dSLionel Sambuc 	if (fe_now != NULL) {
169*0a6a1f1dSLionel Sambuc 		free(fe_now->value);
170*0a6a1f1dSLionel Sambuc 		fe_now->value = fe->value;
171*0a6a1f1dSLionel Sambuc 		free(fe->key);
172*0a6a1f1dSLionel Sambuc 		free(fe);
173*0a6a1f1dSLionel Sambuc 	}
174*0a6a1f1dSLionel Sambuc }
175*0a6a1f1dSLionel Sambuc 
176*0a6a1f1dSLionel Sambuc /* Find a format entry. */
177*0a6a1f1dSLionel Sambuc const char *
format_find(struct format_tree * ft,const char * key)178*0a6a1f1dSLionel Sambuc format_find(struct format_tree *ft, const char *key)
179*0a6a1f1dSLionel Sambuc {
180*0a6a1f1dSLionel Sambuc 	struct format_entry	*fe, fe_find;
181*0a6a1f1dSLionel Sambuc 
182*0a6a1f1dSLionel Sambuc 	fe_find.key = __UNCONST(key);
183*0a6a1f1dSLionel Sambuc 	fe = RB_FIND(format_tree, ft, &fe_find);
184*0a6a1f1dSLionel Sambuc 	if (fe == NULL)
185*0a6a1f1dSLionel Sambuc 		return (NULL);
186*0a6a1f1dSLionel Sambuc 	return (fe->value);
187*0a6a1f1dSLionel Sambuc }
188*0a6a1f1dSLionel Sambuc 
189*0a6a1f1dSLionel Sambuc /*
190*0a6a1f1dSLionel Sambuc  * Replace a key/value pair in buffer. #{blah} is expanded directly,
191*0a6a1f1dSLionel Sambuc  * #{?blah,a,b} is replace with a if blah exists and is nonzero else b.
192*0a6a1f1dSLionel Sambuc  */
193*0a6a1f1dSLionel Sambuc int
format_replace(struct format_tree * ft,const char * key,size_t keylen,char ** buf,size_t * len,size_t * off)194*0a6a1f1dSLionel Sambuc format_replace(struct format_tree *ft, const char *key, size_t keylen,
195*0a6a1f1dSLionel Sambuc     char **buf, size_t *len, size_t *off)
196*0a6a1f1dSLionel Sambuc {
197*0a6a1f1dSLionel Sambuc 	char		*copy, *copy0, *endptr, *ptr, *saved;
198*0a6a1f1dSLionel Sambuc 	const char	*value;
199*0a6a1f1dSLionel Sambuc 	size_t		 valuelen;
200*0a6a1f1dSLionel Sambuc 	u_long		 limit = ULONG_MAX;
201*0a6a1f1dSLionel Sambuc 
202*0a6a1f1dSLionel Sambuc 	/* Make a copy of the key. */
203*0a6a1f1dSLionel Sambuc 	copy0 = copy = xmalloc(keylen + 1);
204*0a6a1f1dSLionel Sambuc 	memcpy(copy, key, keylen);
205*0a6a1f1dSLionel Sambuc 	copy[keylen] = '\0';
206*0a6a1f1dSLionel Sambuc 
207*0a6a1f1dSLionel Sambuc 	/* Is there a length limit or whatnot? */
208*0a6a1f1dSLionel Sambuc 	if (!islower((u_char) *copy) && *copy != '?') {
209*0a6a1f1dSLionel Sambuc 		while (*copy != ':' && *copy != '\0') {
210*0a6a1f1dSLionel Sambuc 			switch (*copy) {
211*0a6a1f1dSLionel Sambuc 			case '=':
212*0a6a1f1dSLionel Sambuc 				errno = 0;
213*0a6a1f1dSLionel Sambuc 				limit = strtoul(copy + 1, &endptr, 10);
214*0a6a1f1dSLionel Sambuc 				if (errno == ERANGE && limit == ULONG_MAX)
215*0a6a1f1dSLionel Sambuc 					goto fail;
216*0a6a1f1dSLionel Sambuc 				copy = endptr;
217*0a6a1f1dSLionel Sambuc 				break;
218*0a6a1f1dSLionel Sambuc 			default:
219*0a6a1f1dSLionel Sambuc 				copy++;
220*0a6a1f1dSLionel Sambuc 				break;
221*0a6a1f1dSLionel Sambuc 			}
222*0a6a1f1dSLionel Sambuc 		}
223*0a6a1f1dSLionel Sambuc 		if (*copy != ':')
224*0a6a1f1dSLionel Sambuc 			goto fail;
225*0a6a1f1dSLionel Sambuc 		copy++;
226*0a6a1f1dSLionel Sambuc 	}
227*0a6a1f1dSLionel Sambuc 
228*0a6a1f1dSLionel Sambuc 	/*
229*0a6a1f1dSLionel Sambuc 	 * Is this a conditional? If so, check it exists and extract either the
230*0a6a1f1dSLionel Sambuc 	 * first or second element. If not, look up the key directly.
231*0a6a1f1dSLionel Sambuc 	 */
232*0a6a1f1dSLionel Sambuc 	if (*copy == '?') {
233*0a6a1f1dSLionel Sambuc 		ptr = strchr(copy, ',');
234*0a6a1f1dSLionel Sambuc 		if (ptr == NULL)
235*0a6a1f1dSLionel Sambuc 			goto fail;
236*0a6a1f1dSLionel Sambuc 		*ptr = '\0';
237*0a6a1f1dSLionel Sambuc 
238*0a6a1f1dSLionel Sambuc 		value = format_find(ft, copy + 1);
239*0a6a1f1dSLionel Sambuc 		if (value != NULL && (value[0] != '0' || value[1] != '\0')) {
240*0a6a1f1dSLionel Sambuc 			value = ptr + 1;
241*0a6a1f1dSLionel Sambuc 			ptr = strchr(value, ',');
242*0a6a1f1dSLionel Sambuc 			if (ptr == NULL)
243*0a6a1f1dSLionel Sambuc 				goto fail;
244*0a6a1f1dSLionel Sambuc 			*ptr = '\0';
245*0a6a1f1dSLionel Sambuc 		} else {
246*0a6a1f1dSLionel Sambuc 			ptr = strchr(ptr + 1, ',');
247*0a6a1f1dSLionel Sambuc 			if (ptr == NULL)
248*0a6a1f1dSLionel Sambuc 				goto fail;
249*0a6a1f1dSLionel Sambuc 			value = ptr + 1;
250*0a6a1f1dSLionel Sambuc 		}
251*0a6a1f1dSLionel Sambuc 		saved = format_expand(ft, value);
252*0a6a1f1dSLionel Sambuc 		value = saved;
253*0a6a1f1dSLionel Sambuc 	} else {
254*0a6a1f1dSLionel Sambuc 		value = format_find(ft, copy);
255*0a6a1f1dSLionel Sambuc 		if (value == NULL)
256*0a6a1f1dSLionel Sambuc 			value = "";
257*0a6a1f1dSLionel Sambuc 		saved = NULL;
258*0a6a1f1dSLionel Sambuc 	}
259*0a6a1f1dSLionel Sambuc 	valuelen = strlen(value);
260*0a6a1f1dSLionel Sambuc 
261*0a6a1f1dSLionel Sambuc 	/* Truncate the value if needed. */
262*0a6a1f1dSLionel Sambuc 	if (valuelen > limit)
263*0a6a1f1dSLionel Sambuc 		valuelen = limit;
264*0a6a1f1dSLionel Sambuc 
265*0a6a1f1dSLionel Sambuc 	/* Expand the buffer and copy in the value. */
266*0a6a1f1dSLionel Sambuc 	while (*len - *off < valuelen + 1) {
267*0a6a1f1dSLionel Sambuc 		*buf = xrealloc(*buf, 2, *len);
268*0a6a1f1dSLionel Sambuc 		*len *= 2;
269*0a6a1f1dSLionel Sambuc 	}
270*0a6a1f1dSLionel Sambuc 	memcpy(*buf + *off, value, valuelen);
271*0a6a1f1dSLionel Sambuc 	*off += valuelen;
272*0a6a1f1dSLionel Sambuc 
273*0a6a1f1dSLionel Sambuc 	free(saved);
274*0a6a1f1dSLionel Sambuc 	free(copy0);
275*0a6a1f1dSLionel Sambuc 	return (0);
276*0a6a1f1dSLionel Sambuc 
277*0a6a1f1dSLionel Sambuc fail:
278*0a6a1f1dSLionel Sambuc 	free(copy0);
279*0a6a1f1dSLionel Sambuc 	return (-1);
280*0a6a1f1dSLionel Sambuc }
281*0a6a1f1dSLionel Sambuc 
282*0a6a1f1dSLionel Sambuc /* Expand keys in a template. */
283*0a6a1f1dSLionel Sambuc char *
format_expand(struct format_tree * ft,const char * fmt)284*0a6a1f1dSLionel Sambuc format_expand(struct format_tree *ft, const char *fmt)
285*0a6a1f1dSLionel Sambuc {
286*0a6a1f1dSLionel Sambuc 	char		*buf;
287*0a6a1f1dSLionel Sambuc 	const char	*ptr, *s;
288*0a6a1f1dSLionel Sambuc 	size_t		 off, len, n;
289*0a6a1f1dSLionel Sambuc 	int     	 ch, brackets;
290*0a6a1f1dSLionel Sambuc 
291*0a6a1f1dSLionel Sambuc 	len = 64;
292*0a6a1f1dSLionel Sambuc 	buf = xmalloc(len);
293*0a6a1f1dSLionel Sambuc 	off = 0;
294*0a6a1f1dSLionel Sambuc 
295*0a6a1f1dSLionel Sambuc 	while (*fmt != '\0') {
296*0a6a1f1dSLionel Sambuc 		if (*fmt != '#') {
297*0a6a1f1dSLionel Sambuc 			while (len - off < 2) {
298*0a6a1f1dSLionel Sambuc 				buf = xrealloc(buf, 2, len);
299*0a6a1f1dSLionel Sambuc 				len *= 2;
300*0a6a1f1dSLionel Sambuc 			}
301*0a6a1f1dSLionel Sambuc 			buf[off++] = *fmt++;
302*0a6a1f1dSLionel Sambuc 			continue;
303*0a6a1f1dSLionel Sambuc 		}
304*0a6a1f1dSLionel Sambuc 		fmt++;
305*0a6a1f1dSLionel Sambuc 
306*0a6a1f1dSLionel Sambuc 		ch = (u_char) *fmt++;
307*0a6a1f1dSLionel Sambuc 		switch (ch) {
308*0a6a1f1dSLionel Sambuc 		case '{':
309*0a6a1f1dSLionel Sambuc 			brackets = 1;
310*0a6a1f1dSLionel Sambuc 			for (ptr = fmt; *ptr != '\0'; ptr++) {
311*0a6a1f1dSLionel Sambuc 				if (*ptr == '{')
312*0a6a1f1dSLionel Sambuc 					brackets++;
313*0a6a1f1dSLionel Sambuc 				if (*ptr == '}' && --brackets == 0)
314*0a6a1f1dSLionel Sambuc 					break;
315*0a6a1f1dSLionel Sambuc 			}
316*0a6a1f1dSLionel Sambuc 			if (*ptr != '}' || brackets != 0)
317*0a6a1f1dSLionel Sambuc 				break;
318*0a6a1f1dSLionel Sambuc 			n = ptr - fmt;
319*0a6a1f1dSLionel Sambuc 
320*0a6a1f1dSLionel Sambuc 			if (format_replace(ft, fmt, n, &buf, &len, &off) != 0)
321*0a6a1f1dSLionel Sambuc 				break;
322*0a6a1f1dSLionel Sambuc 			fmt += n + 1;
323*0a6a1f1dSLionel Sambuc 			continue;
324*0a6a1f1dSLionel Sambuc 		case '#':
325*0a6a1f1dSLionel Sambuc 			while (len - off < 2) {
326*0a6a1f1dSLionel Sambuc 				buf = xrealloc(buf, 2, len);
327*0a6a1f1dSLionel Sambuc 				len *= 2;
328*0a6a1f1dSLionel Sambuc 			}
329*0a6a1f1dSLionel Sambuc 			buf[off++] = '#';
330*0a6a1f1dSLionel Sambuc 			continue;
331*0a6a1f1dSLionel Sambuc 		default:
332*0a6a1f1dSLionel Sambuc 			s = NULL;
333*0a6a1f1dSLionel Sambuc 			if (ch >= 'A' && ch <= 'Z')
334*0a6a1f1dSLionel Sambuc 				s = format_upper[ch - 'A'];
335*0a6a1f1dSLionel Sambuc 			else if (ch >= 'a' && ch <= 'z')
336*0a6a1f1dSLionel Sambuc 				s = format_lower[ch - 'a'];
337*0a6a1f1dSLionel Sambuc 			if (s == NULL) {
338*0a6a1f1dSLionel Sambuc 				while (len - off < 3) {
339*0a6a1f1dSLionel Sambuc 					buf = xrealloc(buf, 2, len);
340*0a6a1f1dSLionel Sambuc 					len *= 2;
341*0a6a1f1dSLionel Sambuc 				}
342*0a6a1f1dSLionel Sambuc 				buf[off++] = '#';
343*0a6a1f1dSLionel Sambuc 				buf[off++] = ch;
344*0a6a1f1dSLionel Sambuc 				continue;
345*0a6a1f1dSLionel Sambuc 			}
346*0a6a1f1dSLionel Sambuc 			n = strlen(s);
347*0a6a1f1dSLionel Sambuc 			if (format_replace(ft, s, n, &buf, &len, &off) != 0)
348*0a6a1f1dSLionel Sambuc 				break;
349*0a6a1f1dSLionel Sambuc 			continue;
350*0a6a1f1dSLionel Sambuc 		}
351*0a6a1f1dSLionel Sambuc 
352*0a6a1f1dSLionel Sambuc 		break;
353*0a6a1f1dSLionel Sambuc 	}
354*0a6a1f1dSLionel Sambuc 	buf[off] = '\0';
355*0a6a1f1dSLionel Sambuc 
356*0a6a1f1dSLionel Sambuc 	return (buf);
357*0a6a1f1dSLionel Sambuc }
358*0a6a1f1dSLionel Sambuc 
359*0a6a1f1dSLionel Sambuc /* Get command name for format. */
360*0a6a1f1dSLionel Sambuc char *
format_get_command(struct window_pane * wp)361*0a6a1f1dSLionel Sambuc format_get_command(struct window_pane *wp)
362*0a6a1f1dSLionel Sambuc {
363*0a6a1f1dSLionel Sambuc 	char	*cmd, *out;
364*0a6a1f1dSLionel Sambuc 
365*0a6a1f1dSLionel Sambuc 	cmd = osdep_get_name(wp->fd, wp->tty);
366*0a6a1f1dSLionel Sambuc 	if (cmd == NULL || *cmd == '\0') {
367*0a6a1f1dSLionel Sambuc 		free(cmd);
368*0a6a1f1dSLionel Sambuc 		cmd = xstrdup(wp->cmd);
369*0a6a1f1dSLionel Sambuc 		if (cmd == NULL || *cmd == '\0') {
370*0a6a1f1dSLionel Sambuc 			free(cmd);
371*0a6a1f1dSLionel Sambuc 			cmd = xstrdup(wp->shell);
372*0a6a1f1dSLionel Sambuc 		}
373*0a6a1f1dSLionel Sambuc 	}
374*0a6a1f1dSLionel Sambuc 	out = parse_window_name(cmd);
375*0a6a1f1dSLionel Sambuc 	free(cmd);
376*0a6a1f1dSLionel Sambuc 	return (out);
377*0a6a1f1dSLionel Sambuc }
378*0a6a1f1dSLionel Sambuc 
379*0a6a1f1dSLionel Sambuc /* Set default format keys for a session. */
380*0a6a1f1dSLionel Sambuc void
format_session(struct format_tree * ft,struct session * s)381*0a6a1f1dSLionel Sambuc format_session(struct format_tree *ft, struct session *s)
382*0a6a1f1dSLionel Sambuc {
383*0a6a1f1dSLionel Sambuc 	struct session_group	*sg;
384*0a6a1f1dSLionel Sambuc 	char			*tim;
385*0a6a1f1dSLionel Sambuc 	time_t			 t;
386*0a6a1f1dSLionel Sambuc 
387*0a6a1f1dSLionel Sambuc 	format_add(ft, "session_name", "%s", s->name);
388*0a6a1f1dSLionel Sambuc 	format_add(ft, "session_windows", "%u", winlink_count(&s->windows));
389*0a6a1f1dSLionel Sambuc 	format_add(ft, "session_width", "%u", s->sx);
390*0a6a1f1dSLionel Sambuc 	format_add(ft, "session_height", "%u", s->sy);
391*0a6a1f1dSLionel Sambuc 	format_add(ft, "session_id", "$%u", s->id);
392*0a6a1f1dSLionel Sambuc 
393*0a6a1f1dSLionel Sambuc 	sg = session_group_find(s);
394*0a6a1f1dSLionel Sambuc 	format_add(ft, "session_grouped", "%d", sg != NULL);
395*0a6a1f1dSLionel Sambuc 	if (sg != NULL)
396*0a6a1f1dSLionel Sambuc 		format_add(ft, "session_group", "%u", session_group_index(sg));
397*0a6a1f1dSLionel Sambuc 
398*0a6a1f1dSLionel Sambuc 	t = s->creation_time.tv_sec;
399*0a6a1f1dSLionel Sambuc 	format_add(ft, "session_created", "%lld", (long long) t);
400*0a6a1f1dSLionel Sambuc 	tim = ctime(&t);
401*0a6a1f1dSLionel Sambuc 	*strchr(tim, '\n') = '\0';
402*0a6a1f1dSLionel Sambuc 	format_add(ft, "session_created_string", "%s", tim);
403*0a6a1f1dSLionel Sambuc 
404*0a6a1f1dSLionel Sambuc 	if (s->flags & SESSION_UNATTACHED)
405*0a6a1f1dSLionel Sambuc 		format_add(ft, "session_attached", "%d", 0);
406*0a6a1f1dSLionel Sambuc 	else
407*0a6a1f1dSLionel Sambuc 		format_add(ft, "session_attached", "%d", 1);
408*0a6a1f1dSLionel Sambuc }
409*0a6a1f1dSLionel Sambuc 
410*0a6a1f1dSLionel Sambuc /* Set default format keys for a client. */
411*0a6a1f1dSLionel Sambuc void
format_client(struct format_tree * ft,struct client * c)412*0a6a1f1dSLionel Sambuc format_client(struct format_tree *ft, struct client *c)
413*0a6a1f1dSLionel Sambuc {
414*0a6a1f1dSLionel Sambuc 	char		*tim;
415*0a6a1f1dSLionel Sambuc 	time_t		 t;
416*0a6a1f1dSLionel Sambuc 	struct session	*s;
417*0a6a1f1dSLionel Sambuc 
418*0a6a1f1dSLionel Sambuc 	format_add(ft, "client_height", "%u", c->tty.sy);
419*0a6a1f1dSLionel Sambuc 	format_add(ft, "client_width", "%u", c->tty.sx);
420*0a6a1f1dSLionel Sambuc 	if (c->tty.path != NULL)
421*0a6a1f1dSLionel Sambuc 		format_add(ft, "client_tty", "%s", c->tty.path);
422*0a6a1f1dSLionel Sambuc 	if (c->tty.termname != NULL)
423*0a6a1f1dSLionel Sambuc 		format_add(ft, "client_termname", "%s", c->tty.termname);
424*0a6a1f1dSLionel Sambuc 
425*0a6a1f1dSLionel Sambuc 	t = c->creation_time.tv_sec;
426*0a6a1f1dSLionel Sambuc 	format_add(ft, "client_created", "%lld", (long long) t);
427*0a6a1f1dSLionel Sambuc 	tim = ctime(&t);
428*0a6a1f1dSLionel Sambuc 	*strchr(tim, '\n') = '\0';
429*0a6a1f1dSLionel Sambuc 	format_add(ft, "client_created_string", "%s", tim);
430*0a6a1f1dSLionel Sambuc 
431*0a6a1f1dSLionel Sambuc 	t = c->activity_time.tv_sec;
432*0a6a1f1dSLionel Sambuc 	format_add(ft, "client_activity", "%lld", (long long) t);
433*0a6a1f1dSLionel Sambuc 	tim = ctime(&t);
434*0a6a1f1dSLionel Sambuc 	*strchr(tim, '\n') = '\0';
435*0a6a1f1dSLionel Sambuc 	format_add(ft, "client_activity_string", "%s", tim);
436*0a6a1f1dSLionel Sambuc 
437*0a6a1f1dSLionel Sambuc 	format_add(ft, "client_prefix", "%d", !!(c->flags & CLIENT_PREFIX));
438*0a6a1f1dSLionel Sambuc 
439*0a6a1f1dSLionel Sambuc 	if (c->tty.flags & TTY_UTF8)
440*0a6a1f1dSLionel Sambuc 		format_add(ft, "client_utf8", "%d", 1);
441*0a6a1f1dSLionel Sambuc 	else
442*0a6a1f1dSLionel Sambuc 		format_add(ft, "client_utf8", "%d", 0);
443*0a6a1f1dSLionel Sambuc 
444*0a6a1f1dSLionel Sambuc 	if (c->flags & CLIENT_READONLY)
445*0a6a1f1dSLionel Sambuc 		format_add(ft, "client_readonly", "%d", 1);
446*0a6a1f1dSLionel Sambuc 	else
447*0a6a1f1dSLionel Sambuc 		format_add(ft, "client_readonly", "%d", 0);
448*0a6a1f1dSLionel Sambuc 
449*0a6a1f1dSLionel Sambuc 	s = c->session;
450*0a6a1f1dSLionel Sambuc 	if (s != NULL)
451*0a6a1f1dSLionel Sambuc 		format_add(ft, "client_session", "%s", s->name);
452*0a6a1f1dSLionel Sambuc 	s = c->last_session;
453*0a6a1f1dSLionel Sambuc 	if (s != NULL && session_alive(s))
454*0a6a1f1dSLionel Sambuc 		format_add(ft, "client_last_session", "%s", s->name);
455*0a6a1f1dSLionel Sambuc }
456*0a6a1f1dSLionel Sambuc 
457*0a6a1f1dSLionel Sambuc /* Set default format keys for a window. */
458*0a6a1f1dSLionel Sambuc void
format_window(struct format_tree * ft,struct window * w)459*0a6a1f1dSLionel Sambuc format_window(struct format_tree *ft, struct window *w)
460*0a6a1f1dSLionel Sambuc {
461*0a6a1f1dSLionel Sambuc 	char	*layout;
462*0a6a1f1dSLionel Sambuc 
463*0a6a1f1dSLionel Sambuc 	layout = layout_dump(w);
464*0a6a1f1dSLionel Sambuc 
465*0a6a1f1dSLionel Sambuc 	format_add(ft, "window_id", "@%u", w->id);
466*0a6a1f1dSLionel Sambuc 	format_add(ft, "window_name", "%s", w->name);
467*0a6a1f1dSLionel Sambuc 	format_add(ft, "window_width", "%u", w->sx);
468*0a6a1f1dSLionel Sambuc 	format_add(ft, "window_height", "%u", w->sy);
469*0a6a1f1dSLionel Sambuc 	format_add(ft, "window_layout", "%s", layout);
470*0a6a1f1dSLionel Sambuc 	format_add(ft, "window_panes", "%u", window_count_panes(w));
471*0a6a1f1dSLionel Sambuc 
472*0a6a1f1dSLionel Sambuc 	free(layout);
473*0a6a1f1dSLionel Sambuc }
474*0a6a1f1dSLionel Sambuc 
475*0a6a1f1dSLionel Sambuc /* Set default format keys for a winlink. */
476*0a6a1f1dSLionel Sambuc void
format_winlink(struct format_tree * ft,struct session * s,struct winlink * wl)477*0a6a1f1dSLionel Sambuc format_winlink(struct format_tree *ft, struct session *s, struct winlink *wl)
478*0a6a1f1dSLionel Sambuc {
479*0a6a1f1dSLionel Sambuc 	struct window	*w = wl->window;
480*0a6a1f1dSLionel Sambuc 	char		*flags;
481*0a6a1f1dSLionel Sambuc 
482*0a6a1f1dSLionel Sambuc 	flags = window_printable_flags(s, wl);
483*0a6a1f1dSLionel Sambuc 
484*0a6a1f1dSLionel Sambuc 	format_window(ft, w);
485*0a6a1f1dSLionel Sambuc 
486*0a6a1f1dSLionel Sambuc 	format_add(ft, "window_index", "%d", wl->idx);
487*0a6a1f1dSLionel Sambuc 	format_add(ft, "window_flags", "%s", flags);
488*0a6a1f1dSLionel Sambuc 	format_add(ft, "window_active", "%d", wl == s->curw);
489*0a6a1f1dSLionel Sambuc 
490*0a6a1f1dSLionel Sambuc 	format_add(ft, "window_bell_flag", "%u",
491*0a6a1f1dSLionel Sambuc 	    !!(wl->flags & WINLINK_BELL));
492*0a6a1f1dSLionel Sambuc 	format_add(ft, "window_content_flag", "%u",
493*0a6a1f1dSLionel Sambuc 	    !!(wl->flags & WINLINK_CONTENT));
494*0a6a1f1dSLionel Sambuc 	format_add(ft, "window_activity_flag", "%u",
495*0a6a1f1dSLionel Sambuc 	    !!(wl->flags & WINLINK_ACTIVITY));
496*0a6a1f1dSLionel Sambuc 	format_add(ft, "window_silence_flag", "%u",
497*0a6a1f1dSLionel Sambuc 	    !!(wl->flags & WINLINK_SILENCE));
498*0a6a1f1dSLionel Sambuc 
499*0a6a1f1dSLionel Sambuc 
500*0a6a1f1dSLionel Sambuc 	free(flags);
501*0a6a1f1dSLionel Sambuc }
502*0a6a1f1dSLionel Sambuc 
503*0a6a1f1dSLionel Sambuc /* Add window pane tabs. */
504*0a6a1f1dSLionel Sambuc void
format_window_pane_tabs(struct format_tree * ft,struct window_pane * wp)505*0a6a1f1dSLionel Sambuc format_window_pane_tabs(struct format_tree *ft, struct window_pane *wp)
506*0a6a1f1dSLionel Sambuc {
507*0a6a1f1dSLionel Sambuc 	struct evbuffer	*buffer;
508*0a6a1f1dSLionel Sambuc 	u_int		 i;
509*0a6a1f1dSLionel Sambuc 
510*0a6a1f1dSLionel Sambuc 	buffer = evbuffer_new();
511*0a6a1f1dSLionel Sambuc 	for (i = 0; i < wp->base.grid->sx; i++) {
512*0a6a1f1dSLionel Sambuc 		if (!bit_test(wp->base.tabs, i))
513*0a6a1f1dSLionel Sambuc 			continue;
514*0a6a1f1dSLionel Sambuc 
515*0a6a1f1dSLionel Sambuc 		if (EVBUFFER_LENGTH(buffer) > 0)
516*0a6a1f1dSLionel Sambuc 			evbuffer_add(buffer, ",", 1);
517*0a6a1f1dSLionel Sambuc 		evbuffer_add_printf(buffer, "%d", i);
518*0a6a1f1dSLionel Sambuc 	}
519*0a6a1f1dSLionel Sambuc 
520*0a6a1f1dSLionel Sambuc 	format_add(ft, "pane_tabs", "%.*s", (int) EVBUFFER_LENGTH(buffer),
521*0a6a1f1dSLionel Sambuc 	    EVBUFFER_DATA(buffer));
522*0a6a1f1dSLionel Sambuc 	evbuffer_free(buffer);
523*0a6a1f1dSLionel Sambuc }
524*0a6a1f1dSLionel Sambuc 
525*0a6a1f1dSLionel Sambuc /* Set default format keys for a window pane. */
526*0a6a1f1dSLionel Sambuc void
format_window_pane(struct format_tree * ft,struct window_pane * wp)527*0a6a1f1dSLionel Sambuc format_window_pane(struct format_tree *ft, struct window_pane *wp)
528*0a6a1f1dSLionel Sambuc {
529*0a6a1f1dSLionel Sambuc 	struct grid		*gd = wp->base.grid;
530*0a6a1f1dSLionel Sambuc 	struct grid_line	*gl;
531*0a6a1f1dSLionel Sambuc 	unsigned long long	 size;
532*0a6a1f1dSLionel Sambuc 	u_int			 i, idx;
533*0a6a1f1dSLionel Sambuc 	char			*cmd, *cwd;
534*0a6a1f1dSLionel Sambuc 
535*0a6a1f1dSLionel Sambuc 	size = 0;
536*0a6a1f1dSLionel Sambuc 	for (i = 0; i < gd->hsize; i++) {
537*0a6a1f1dSLionel Sambuc 		gl = &gd->linedata[i];
538*0a6a1f1dSLionel Sambuc 		size += gl->cellsize * sizeof *gl->celldata;
539*0a6a1f1dSLionel Sambuc 	}
540*0a6a1f1dSLionel Sambuc 	size += gd->hsize * sizeof *gd->linedata;
541*0a6a1f1dSLionel Sambuc 	format_add(ft, "history_size", "%u", gd->hsize);
542*0a6a1f1dSLionel Sambuc 	format_add(ft, "history_limit", "%u", gd->hlimit);
543*0a6a1f1dSLionel Sambuc 	format_add(ft, "history_bytes", "%llu", size);
544*0a6a1f1dSLionel Sambuc 
545*0a6a1f1dSLionel Sambuc 	if (window_pane_index(wp, &idx) != 0)
546*0a6a1f1dSLionel Sambuc 		fatalx("index not found");
547*0a6a1f1dSLionel Sambuc 	format_add(ft, "pane_index", "%u", idx);
548*0a6a1f1dSLionel Sambuc 
549*0a6a1f1dSLionel Sambuc 	format_add(ft, "pane_width", "%u", wp->sx);
550*0a6a1f1dSLionel Sambuc 	format_add(ft, "pane_height", "%u", wp->sy);
551*0a6a1f1dSLionel Sambuc 	format_add(ft, "pane_title", "%s", wp->base.title);
552*0a6a1f1dSLionel Sambuc 	format_add(ft, "pane_id", "%%%u", wp->id);
553*0a6a1f1dSLionel Sambuc 	format_add(ft, "pane_active", "%d", wp == wp->window->active);
554*0a6a1f1dSLionel Sambuc 	format_add(ft, "pane_dead", "%d", wp->fd == -1);
555*0a6a1f1dSLionel Sambuc 
556*0a6a1f1dSLionel Sambuc 	format_add(ft, "pane_in_mode", "%d", wp->screen != &wp->base);
557*0a6a1f1dSLionel Sambuc 	format_add(ft, "pane_synchronized", "%d",
558*0a6a1f1dSLionel Sambuc 	    !!options_get_number(&wp->window->options, "synchronize-panes"));
559*0a6a1f1dSLionel Sambuc 
560*0a6a1f1dSLionel Sambuc 	format_add(ft, "pane_tty", "%s", wp->tty);
561*0a6a1f1dSLionel Sambuc 	format_add(ft, "pane_pid", "%ld", (long) wp->pid);
562*0a6a1f1dSLionel Sambuc 	if (wp->cmd != NULL)
563*0a6a1f1dSLionel Sambuc 		format_add(ft, "pane_start_command", "%s", wp->cmd);
564*0a6a1f1dSLionel Sambuc 	if ((cwd = osdep_get_cwd(wp->fd)) != NULL)
565*0a6a1f1dSLionel Sambuc 		format_add(ft, "pane_current_path", "%s", cwd);
566*0a6a1f1dSLionel Sambuc 	if ((cmd = format_get_command(wp)) != NULL) {
567*0a6a1f1dSLionel Sambuc 		format_add(ft, "pane_current_command", "%s", cmd);
568*0a6a1f1dSLionel Sambuc 		free(cmd);
569*0a6a1f1dSLionel Sambuc 	}
570*0a6a1f1dSLionel Sambuc 
571*0a6a1f1dSLionel Sambuc 	format_add(ft, "cursor_x", "%d", wp->base.cx);
572*0a6a1f1dSLionel Sambuc 	format_add(ft, "cursor_y", "%d", wp->base.cy);
573*0a6a1f1dSLionel Sambuc 	format_add(ft, "scroll_region_upper", "%d", wp->base.rupper);
574*0a6a1f1dSLionel Sambuc 	format_add(ft, "scroll_region_lower", "%d", wp->base.rlower);
575*0a6a1f1dSLionel Sambuc 	format_add(ft, "saved_cursor_x", "%d", wp->ictx.old_cx);
576*0a6a1f1dSLionel Sambuc 	format_add(ft, "saved_cursor_y", "%d", wp->ictx.old_cy);
577*0a6a1f1dSLionel Sambuc 
578*0a6a1f1dSLionel Sambuc 	format_add(ft, "alternate_on", "%d", wp->saved_grid ? 1 : 0);
579*0a6a1f1dSLionel Sambuc 	format_add(ft, "alternate_saved_x", "%d", wp->saved_cx);
580*0a6a1f1dSLionel Sambuc 	format_add(ft, "alternate_saved_y", "%d", wp->saved_cy);
581*0a6a1f1dSLionel Sambuc 
582*0a6a1f1dSLionel Sambuc 	format_add(ft, "cursor_flag", "%d",
583*0a6a1f1dSLionel Sambuc 	    !!(wp->base.mode & MODE_CURSOR));
584*0a6a1f1dSLionel Sambuc 	format_add(ft, "insert_flag", "%d",
585*0a6a1f1dSLionel Sambuc 	    !!(wp->base.mode & MODE_INSERT));
586*0a6a1f1dSLionel Sambuc 	format_add(ft, "keypad_cursor_flag", "%d",
587*0a6a1f1dSLionel Sambuc 	    !!(wp->base.mode & MODE_KCURSOR));
588*0a6a1f1dSLionel Sambuc 	format_add(ft, "keypad_flag", "%d",
589*0a6a1f1dSLionel Sambuc 	    !!(wp->base.mode & MODE_KKEYPAD));
590*0a6a1f1dSLionel Sambuc 	format_add(ft, "wrap_flag", "%d",
591*0a6a1f1dSLionel Sambuc 	    !!(wp->base.mode & MODE_WRAP));
592*0a6a1f1dSLionel Sambuc 
593*0a6a1f1dSLionel Sambuc 	format_add(ft, "mouse_standard_flag", "%d",
594*0a6a1f1dSLionel Sambuc 	    !!(wp->base.mode & MODE_MOUSE_STANDARD));
595*0a6a1f1dSLionel Sambuc 	format_add(ft, "mouse_button_flag", "%d",
596*0a6a1f1dSLionel Sambuc 	    !!(wp->base.mode & MODE_MOUSE_BUTTON));
597*0a6a1f1dSLionel Sambuc 	format_add(ft, "mouse_any_flag", "%d",
598*0a6a1f1dSLionel Sambuc 	    !!(wp->base.mode & MODE_MOUSE_ANY));
599*0a6a1f1dSLionel Sambuc 	format_add(ft, "mouse_utf8_flag", "%d",
600*0a6a1f1dSLionel Sambuc 	    !!(wp->base.mode & MODE_MOUSE_UTF8));
601*0a6a1f1dSLionel Sambuc 
602*0a6a1f1dSLionel Sambuc 	format_window_pane_tabs(ft, wp);
603*0a6a1f1dSLionel Sambuc }
604*0a6a1f1dSLionel Sambuc 
605*0a6a1f1dSLionel Sambuc /* Set default format keys for paste buffer. */
606*0a6a1f1dSLionel Sambuc void
format_paste_buffer(struct format_tree * ft,struct paste_buffer * pb)607*0a6a1f1dSLionel Sambuc format_paste_buffer(struct format_tree *ft, struct paste_buffer *pb)
608*0a6a1f1dSLionel Sambuc {
609*0a6a1f1dSLionel Sambuc 	char	*pb_print = paste_print(pb, 50);
610*0a6a1f1dSLionel Sambuc 
611*0a6a1f1dSLionel Sambuc 	format_add(ft, "buffer_size", "%zu", pb->size);
612*0a6a1f1dSLionel Sambuc 	format_add(ft, "buffer_sample", "%s", pb_print);
613*0a6a1f1dSLionel Sambuc 
614*0a6a1f1dSLionel Sambuc 	free(pb_print);
615*0a6a1f1dSLionel Sambuc }
616