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