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