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