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