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