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