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