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