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