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