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