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