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