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