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