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