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