1 /* $OpenBSD: format.c,v 1.294 2021/08/20 20:08: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, 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 wp = cmd_mouse_pane(&ft->m, NULL, NULL); 1619 if (wp != NULL && cmd_mouse_at(wp, &ft->m, &x, &y, 0) == 0) 1620 return (format_printf("%u", x)); 1621 return (NULL); 1622 } 1623 return (NULL); 1624 } 1625 1626 /* Callback for mouse_y. */ 1627 static void * 1628 format_cb_mouse_y(struct format_tree *ft) 1629 { 1630 struct window_pane *wp; 1631 u_int x, y; 1632 1633 if (ft->m.valid) { 1634 wp = cmd_mouse_pane(&ft->m, NULL, NULL); 1635 if (wp != NULL && cmd_mouse_at(wp, &ft->m, &x, &y, 0) == 0) 1636 return (format_printf("%u", y)); 1637 return (NULL); 1638 } 1639 return (NULL); 1640 } 1641 1642 /* Callback for origin_flag. */ 1643 static void * 1644 format_cb_origin_flag(struct format_tree *ft) 1645 { 1646 if (ft->wp != NULL) { 1647 if (ft->wp->base.mode & MODE_ORIGIN) 1648 return (xstrdup("1")); 1649 return (xstrdup("0")); 1650 } 1651 return (NULL); 1652 } 1653 1654 /* Callback for pane_active. */ 1655 static void * 1656 format_cb_pane_active(struct format_tree *ft) 1657 { 1658 if (ft->wp != NULL) { 1659 if (ft->wp == ft->wp->window->active) 1660 return (xstrdup("1")); 1661 return (xstrdup("0")); 1662 } 1663 return (NULL); 1664 } 1665 1666 /* Callback for pane_at_left. */ 1667 static void * 1668 format_cb_pane_at_left(struct format_tree *ft) 1669 { 1670 if (ft->wp != NULL) { 1671 if (ft->wp->xoff == 0) 1672 return (xstrdup("1")); 1673 return (xstrdup("0")); 1674 } 1675 return (NULL); 1676 } 1677 1678 /* Callback for pane_at_right. */ 1679 static void * 1680 format_cb_pane_at_right(struct format_tree *ft) 1681 { 1682 if (ft->wp != NULL) { 1683 if (ft->wp->xoff + ft->wp->sx == ft->wp->window->sx) 1684 return (xstrdup("1")); 1685 return (xstrdup("0")); 1686 } 1687 return (NULL); 1688 } 1689 1690 /* Callback for pane_bottom. */ 1691 static void * 1692 format_cb_pane_bottom(struct format_tree *ft) 1693 { 1694 if (ft->wp != NULL) 1695 return (format_printf("%u", ft->wp->yoff + ft->wp->sy - 1)); 1696 return (NULL); 1697 } 1698 1699 /* Callback for pane_dead. */ 1700 static void * 1701 format_cb_pane_dead(struct format_tree *ft) 1702 { 1703 if (ft->wp != NULL) { 1704 if (ft->wp->fd == -1) 1705 return (xstrdup("1")); 1706 return (xstrdup("0")); 1707 } 1708 return (NULL); 1709 } 1710 1711 /* Callback for pane_dead_status. */ 1712 static void * 1713 format_cb_pane_dead_status(struct format_tree *ft) 1714 { 1715 struct window_pane *wp = ft->wp; 1716 1717 if (wp != NULL) { 1718 if ((wp->flags & PANE_STATUSREADY) && WIFEXITED(wp->status)) 1719 return (format_printf("%d", WEXITSTATUS(wp->status))); 1720 return (NULL); 1721 } 1722 return (NULL); 1723 } 1724 1725 /* Callback for pane_format. */ 1726 static void * 1727 format_cb_pane_format(struct format_tree *ft) 1728 { 1729 if (ft->type == FORMAT_TYPE_PANE) 1730 return (xstrdup("1")); 1731 return (xstrdup("0")); 1732 } 1733 1734 /* Callback for pane_height. */ 1735 static void * 1736 format_cb_pane_height(struct format_tree *ft) 1737 { 1738 if (ft->wp != NULL) 1739 return (format_printf("%u", ft->wp->sy)); 1740 return (NULL); 1741 } 1742 1743 /* Callback for pane_id. */ 1744 static void * 1745 format_cb_pane_id(struct format_tree *ft) 1746 { 1747 if (ft->wp != NULL) 1748 return (format_printf("%%%u", ft->wp->id)); 1749 return (NULL); 1750 } 1751 1752 /* Callback for pane_index. */ 1753 static void * 1754 format_cb_pane_index(struct format_tree *ft) 1755 { 1756 u_int idx; 1757 1758 if (ft->wp != NULL && window_pane_index(ft->wp, &idx) == 0) 1759 return (format_printf("%u", idx)); 1760 return (NULL); 1761 } 1762 1763 /* Callback for pane_input_off. */ 1764 static void * 1765 format_cb_pane_input_off(struct format_tree *ft) 1766 { 1767 if (ft->wp != NULL) { 1768 if (ft->wp->flags & PANE_INPUTOFF) 1769 return (xstrdup("1")); 1770 return (xstrdup("0")); 1771 } 1772 return (NULL); 1773 } 1774 1775 /* Callback for pane_last. */ 1776 static void * 1777 format_cb_pane_last(struct format_tree *ft) 1778 { 1779 if (ft->wp != NULL) { 1780 if (ft->wp == ft->wp->window->last) 1781 return (xstrdup("1")); 1782 return (xstrdup("0")); 1783 } 1784 return (NULL); 1785 } 1786 1787 /* Callback for pane_left. */ 1788 static void * 1789 format_cb_pane_left(struct format_tree *ft) 1790 { 1791 if (ft->wp != NULL) 1792 return (format_printf("%u", ft->wp->xoff)); 1793 return (NULL); 1794 } 1795 1796 /* Callback for pane_marked. */ 1797 static void * 1798 format_cb_pane_marked(struct format_tree *ft) 1799 { 1800 if (ft->wp != NULL) { 1801 if (server_check_marked() && marked_pane.wp == ft->wp) 1802 return (xstrdup("1")); 1803 return (xstrdup("0")); 1804 } 1805 return (NULL); 1806 } 1807 1808 /* Callback for pane_marked_set. */ 1809 static void * 1810 format_cb_pane_marked_set(struct format_tree *ft) 1811 { 1812 if (ft->wp != NULL) { 1813 if (server_check_marked()) 1814 return (xstrdup("1")); 1815 return (xstrdup("0")); 1816 } 1817 return (NULL); 1818 } 1819 1820 /* Callback for pane_mode. */ 1821 static void * 1822 format_cb_pane_mode(struct format_tree *ft) 1823 { 1824 struct window_mode_entry *wme; 1825 1826 if (ft->wp != NULL) { 1827 wme = TAILQ_FIRST(&ft->wp->modes); 1828 if (wme != NULL) 1829 return (xstrdup(wme->mode->name)); 1830 return (NULL); 1831 } 1832 return (NULL); 1833 } 1834 1835 /* Callback for pane_path. */ 1836 static void * 1837 format_cb_pane_path(struct format_tree *ft) 1838 { 1839 if (ft->wp != NULL) { 1840 if (ft->wp->base.path == NULL) 1841 return (xstrdup("")); 1842 return (xstrdup(ft->wp->base.path)); 1843 } 1844 return (NULL); 1845 } 1846 1847 /* Callback for pane_pid. */ 1848 static void * 1849 format_cb_pane_pid(struct format_tree *ft) 1850 { 1851 if (ft->wp != NULL) 1852 return (format_printf("%ld", (long)ft->wp->pid)); 1853 return (NULL); 1854 } 1855 1856 /* Callback for pane_pipe. */ 1857 static void * 1858 format_cb_pane_pipe(struct format_tree *ft) 1859 { 1860 if (ft->wp != NULL) { 1861 if (ft->wp->pipe_fd != -1) 1862 return (xstrdup("1")); 1863 return (xstrdup("0")); 1864 } 1865 return (NULL); 1866 } 1867 1868 /* Callback for pane_right. */ 1869 static void * 1870 format_cb_pane_right(struct format_tree *ft) 1871 { 1872 if (ft->wp != NULL) 1873 return (format_printf("%u", ft->wp->xoff + ft->wp->sx - 1)); 1874 return (NULL); 1875 } 1876 1877 /* Callback for pane_search_string. */ 1878 static void * 1879 format_cb_pane_search_string(struct format_tree *ft) 1880 { 1881 if (ft->wp != NULL) { 1882 if (ft->wp->searchstr == NULL) 1883 return (xstrdup("")); 1884 return (xstrdup(ft->wp->searchstr)); 1885 } 1886 return (NULL); 1887 } 1888 1889 /* Callback for pane_synchronized. */ 1890 static void * 1891 format_cb_pane_synchronized(struct format_tree *ft) 1892 { 1893 if (ft->wp != NULL) { 1894 if (options_get_number(ft->wp->options, "synchronize-panes")) 1895 return (xstrdup("1")); 1896 return (xstrdup("0")); 1897 } 1898 return (NULL); 1899 } 1900 1901 /* Callback for pane_title. */ 1902 static void * 1903 format_cb_pane_title(struct format_tree *ft) 1904 { 1905 if (ft->wp != NULL) 1906 return (xstrdup(ft->wp->base.title)); 1907 return (NULL); 1908 } 1909 1910 /* Callback for pane_top. */ 1911 static void * 1912 format_cb_pane_top(struct format_tree *ft) 1913 { 1914 if (ft->wp != NULL) 1915 return (format_printf("%u", ft->wp->yoff)); 1916 return (NULL); 1917 } 1918 1919 /* Callback for pane_tty. */ 1920 static void * 1921 format_cb_pane_tty(struct format_tree *ft) 1922 { 1923 if (ft->wp != NULL) 1924 return (xstrdup(ft->wp->tty)); 1925 return (NULL); 1926 } 1927 1928 /* Callback for pane_width. */ 1929 static void * 1930 format_cb_pane_width(struct format_tree *ft) 1931 { 1932 if (ft->wp != NULL) 1933 return (format_printf("%u", ft->wp->sx)); 1934 return (NULL); 1935 } 1936 1937 /* Callback for scroll_region_lower. */ 1938 static void * 1939 format_cb_scroll_region_lower(struct format_tree *ft) 1940 { 1941 if (ft->wp != NULL) 1942 return (format_printf("%u", ft->wp->base.rlower)); 1943 return (NULL); 1944 } 1945 1946 /* Callback for scroll_region_upper. */ 1947 static void * 1948 format_cb_scroll_region_upper(struct format_tree *ft) 1949 { 1950 if (ft->wp != NULL) 1951 return (format_printf("%u", ft->wp->base.rupper)); 1952 return (NULL); 1953 } 1954 1955 /* Callback for session_attached. */ 1956 static void * 1957 format_cb_session_attached(struct format_tree *ft) 1958 { 1959 if (ft->s != NULL) 1960 return (format_printf("%u", ft->s->attached)); 1961 return (NULL); 1962 } 1963 1964 /* Callback for session_format. */ 1965 static void * 1966 format_cb_session_format(struct format_tree *ft) 1967 { 1968 if (ft->type == FORMAT_TYPE_SESSION) 1969 return (xstrdup("1")); 1970 return (xstrdup("0")); 1971 } 1972 1973 /* Callback for session_group. */ 1974 static void * 1975 format_cb_session_group(struct format_tree *ft) 1976 { 1977 struct session_group *sg; 1978 1979 if (ft->s != NULL && (sg = session_group_contains(ft->s)) != NULL) 1980 return (xstrdup(sg->name)); 1981 return (NULL); 1982 } 1983 1984 /* Callback for session_group_attached. */ 1985 static void * 1986 format_cb_session_group_attached(struct format_tree *ft) 1987 { 1988 struct session_group *sg; 1989 1990 if (ft->s != NULL && (sg = session_group_contains(ft->s)) != NULL) 1991 return (format_printf("%u", session_group_attached_count (sg))); 1992 return (NULL); 1993 } 1994 1995 /* Callback for session_group_many_attached. */ 1996 static void * 1997 format_cb_session_group_many_attached(struct format_tree *ft) 1998 { 1999 struct session_group *sg; 2000 2001 if (ft->s != NULL && (sg = session_group_contains(ft->s)) != NULL) { 2002 if (session_group_attached_count (sg) > 1) 2003 return (xstrdup("1")); 2004 return (xstrdup("0")); 2005 } 2006 return (NULL); 2007 } 2008 2009 /* Callback for session_group_size. */ 2010 static void * 2011 format_cb_session_group_size(struct format_tree *ft) 2012 { 2013 struct session_group *sg; 2014 2015 if (ft->s != NULL && (sg = session_group_contains(ft->s)) != NULL) 2016 return (format_printf("%u", session_group_count (sg))); 2017 return (NULL); 2018 } 2019 2020 /* Callback for session_grouped. */ 2021 static void * 2022 format_cb_session_grouped(struct format_tree *ft) 2023 { 2024 if (ft->s != NULL) { 2025 if (session_group_contains(ft->s) != NULL) 2026 return (xstrdup("1")); 2027 return (xstrdup("0")); 2028 } 2029 return (NULL); 2030 } 2031 2032 /* Callback for session_id. */ 2033 static void * 2034 format_cb_session_id(struct format_tree *ft) 2035 { 2036 if (ft->s != NULL) 2037 return (format_printf("$%u", ft->s->id)); 2038 return (NULL); 2039 } 2040 2041 /* Callback for session_many_attached. */ 2042 static void * 2043 format_cb_session_many_attached(struct format_tree *ft) 2044 { 2045 if (ft->s != NULL) { 2046 if (ft->s->attached > 1) 2047 return (xstrdup("1")); 2048 return (xstrdup("0")); 2049 } 2050 return (NULL); 2051 } 2052 2053 /* Callback for session_marked. */ 2054 static void * 2055 format_cb_session_marked(struct format_tree *ft) 2056 { 2057 if (ft->s != NULL) { 2058 if (server_check_marked() && marked_pane.s == ft->s) 2059 return (xstrdup("1")); 2060 return (xstrdup("0")); 2061 } 2062 return (NULL); 2063 } 2064 2065 /* Callback for session_name. */ 2066 static void * 2067 format_cb_session_name(struct format_tree *ft) 2068 { 2069 if (ft->s != NULL) 2070 return (xstrdup(ft->s->name)); 2071 return (NULL); 2072 } 2073 2074 /* Callback for session_path. */ 2075 static void * 2076 format_cb_session_path(struct format_tree *ft) 2077 { 2078 if (ft->s != NULL) 2079 return (xstrdup(ft->s->cwd)); 2080 return (NULL); 2081 } 2082 2083 /* Callback for session_windows. */ 2084 static void * 2085 format_cb_session_windows(struct format_tree *ft) 2086 { 2087 if (ft->s != NULL) 2088 return (format_printf("%u", winlink_count(&ft->s->windows))); 2089 return (NULL); 2090 } 2091 2092 /* Callback for socket_path. */ 2093 static void * 2094 format_cb_socket_path(__unused struct format_tree *ft) 2095 { 2096 return (xstrdup(socket_path)); 2097 } 2098 2099 /* Callback for version. */ 2100 static void * 2101 format_cb_version(__unused struct format_tree *ft) 2102 { 2103 return (xstrdup(getversion())); 2104 } 2105 2106 /* Callback for active_window_index. */ 2107 static void * 2108 format_cb_active_window_index(struct format_tree *ft) 2109 { 2110 if (ft->s != NULL) 2111 return (format_printf("%u", ft->s->curw->idx)); 2112 return (NULL); 2113 } 2114 2115 /* Callback for last_window_index. */ 2116 static void * 2117 format_cb_last_window_index(struct format_tree *ft) 2118 { 2119 struct winlink *wl; 2120 2121 if (ft->s != NULL) { 2122 wl = RB_MAX(winlinks, &ft->s->windows); 2123 return (format_printf("%u", wl->idx)); 2124 } 2125 return (NULL); 2126 } 2127 2128 /* Callback for window_active. */ 2129 static void * 2130 format_cb_window_active(struct format_tree *ft) 2131 { 2132 if (ft->wl != NULL) { 2133 if (ft->wl == ft->wl->session->curw) 2134 return (xstrdup("1")); 2135 return (xstrdup("0")); 2136 } 2137 return (NULL); 2138 } 2139 2140 /* Callback for window_activity_flag. */ 2141 static void * 2142 format_cb_window_activity_flag(struct format_tree *ft) 2143 { 2144 if (ft->wl != NULL) { 2145 if (ft->wl->flags & WINLINK_ACTIVITY) 2146 return (xstrdup("1")); 2147 return (xstrdup("0")); 2148 } 2149 return (NULL); 2150 } 2151 2152 /* Callback for window_bell_flag. */ 2153 static void * 2154 format_cb_window_bell_flag(struct format_tree *ft) 2155 { 2156 if (ft->wl != NULL) { 2157 if (ft->wl->flags & WINLINK_BELL) 2158 return (xstrdup("1")); 2159 return (xstrdup("0")); 2160 } 2161 return (NULL); 2162 } 2163 2164 /* Callback for window_bigger. */ 2165 static void * 2166 format_cb_window_bigger(struct format_tree *ft) 2167 { 2168 u_int ox, oy, sx, sy; 2169 2170 if (ft->c != NULL) { 2171 if (tty_window_offset(&ft->c->tty, &ox, &oy, &sx, &sy)) 2172 return (xstrdup("1")); 2173 return (xstrdup("0")); 2174 } 2175 return (NULL); 2176 } 2177 2178 /* Callback for window_cell_height. */ 2179 static void * 2180 format_cb_window_cell_height(struct format_tree *ft) 2181 { 2182 if (ft->w != NULL) 2183 return (format_printf("%u", ft->w->ypixel)); 2184 return (NULL); 2185 } 2186 2187 /* Callback for window_cell_width. */ 2188 static void * 2189 format_cb_window_cell_width(struct format_tree *ft) 2190 { 2191 if (ft->w != NULL) 2192 return (format_printf("%u", ft->w->xpixel)); 2193 return (NULL); 2194 } 2195 2196 /* Callback for window_end_flag. */ 2197 static void * 2198 format_cb_window_end_flag(struct format_tree *ft) 2199 { 2200 if (ft->wl != NULL) { 2201 if (ft->wl == RB_MAX(winlinks, &ft->wl->session->windows)) 2202 return (xstrdup("1")); 2203 return (xstrdup("0")); 2204 } 2205 return (NULL); 2206 } 2207 2208 /* Callback for window_flags. */ 2209 static void * 2210 format_cb_window_flags(struct format_tree *ft) 2211 { 2212 if (ft->wl != NULL) 2213 return (xstrdup(window_printable_flags(ft->wl, 1))); 2214 return (NULL); 2215 } 2216 2217 /* Callback for window_format. */ 2218 static void * 2219 format_cb_window_format(struct format_tree *ft) 2220 { 2221 if (ft->type == FORMAT_TYPE_WINDOW) 2222 return (xstrdup("1")); 2223 return (xstrdup("0")); 2224 } 2225 2226 /* Callback for window_height. */ 2227 static void * 2228 format_cb_window_height(struct format_tree *ft) 2229 { 2230 if (ft->w != NULL) 2231 return (format_printf("%u", ft->w->sy)); 2232 return (NULL); 2233 } 2234 2235 /* Callback for window_id. */ 2236 static void * 2237 format_cb_window_id(struct format_tree *ft) 2238 { 2239 if (ft->w != NULL) 2240 return (format_printf("@%u", ft->w->id)); 2241 return (NULL); 2242 } 2243 2244 /* Callback for window_index. */ 2245 static void * 2246 format_cb_window_index(struct format_tree *ft) 2247 { 2248 if (ft->wl != NULL) 2249 return (format_printf("%d", ft->wl->idx)); 2250 return (NULL); 2251 } 2252 2253 /* Callback for window_last_flag. */ 2254 static void * 2255 format_cb_window_last_flag(struct format_tree *ft) 2256 { 2257 if (ft->wl != NULL) { 2258 if (ft->wl == TAILQ_FIRST(&ft->wl->session->lastw)) 2259 return (xstrdup("1")); 2260 return (xstrdup("0")); 2261 } 2262 return (NULL); 2263 } 2264 2265 /* Callback for window_linked. */ 2266 static void * 2267 format_cb_window_linked(struct format_tree *ft) 2268 { 2269 if (ft->wl != NULL) { 2270 if (session_is_linked(ft->wl->session, ft->wl->window)) 2271 return (xstrdup("1")); 2272 return (xstrdup("0")); 2273 } 2274 return (NULL); 2275 } 2276 2277 /* Callback for window_linked_sessions. */ 2278 static void * 2279 format_cb_window_linked_sessions(struct format_tree *ft) 2280 { 2281 if (ft->wl != NULL) 2282 return (format_printf("%u", ft->wl->window->references)); 2283 return (NULL); 2284 } 2285 2286 /* Callback for window_marked_flag. */ 2287 static void * 2288 format_cb_window_marked_flag(struct format_tree *ft) 2289 { 2290 if (ft->wl != NULL) { 2291 if (server_check_marked() && marked_pane.wl == ft->wl) 2292 return (xstrdup("1")); 2293 return (xstrdup("0")); 2294 } 2295 return (NULL); 2296 } 2297 2298 /* Callback for window_name. */ 2299 static void * 2300 format_cb_window_name(struct format_tree *ft) 2301 { 2302 if (ft->w != NULL) 2303 return (format_printf("%s", ft->w->name)); 2304 return (NULL); 2305 } 2306 2307 /* Callback for window_offset_x. */ 2308 static void * 2309 format_cb_window_offset_x(struct format_tree *ft) 2310 { 2311 u_int ox, oy, sx, sy; 2312 2313 if (ft->c != NULL) { 2314 if (tty_window_offset(&ft->c->tty, &ox, &oy, &sx, &sy)) 2315 return (format_printf("%u", ox)); 2316 return (NULL); 2317 } 2318 return (NULL); 2319 } 2320 2321 /* Callback for window_offset_y. */ 2322 static void * 2323 format_cb_window_offset_y(struct format_tree *ft) 2324 { 2325 u_int ox, oy, sx, sy; 2326 2327 if (ft->c != NULL) { 2328 if (tty_window_offset(&ft->c->tty, &ox, &oy, &sx, &sy)) 2329 return (format_printf("%u", oy)); 2330 return (NULL); 2331 } 2332 return (NULL); 2333 } 2334 2335 /* Callback for window_panes. */ 2336 static void * 2337 format_cb_window_panes(struct format_tree *ft) 2338 { 2339 if (ft->w != NULL) 2340 return (format_printf("%u", window_count_panes(ft->w))); 2341 return (NULL); 2342 } 2343 2344 /* Callback for window_raw_flags. */ 2345 static void * 2346 format_cb_window_raw_flags(struct format_tree *ft) 2347 { 2348 if (ft->wl != NULL) 2349 return (xstrdup(window_printable_flags(ft->wl, 0))); 2350 return (NULL); 2351 } 2352 2353 /* Callback for window_silence_flag. */ 2354 static void * 2355 format_cb_window_silence_flag(struct format_tree *ft) 2356 { 2357 if (ft->wl != NULL) { 2358 if (ft->wl->flags & WINLINK_SILENCE) 2359 return (xstrdup("1")); 2360 return (xstrdup("0")); 2361 } 2362 return (NULL); 2363 } 2364 2365 /* Callback for window_start_flag. */ 2366 static void * 2367 format_cb_window_start_flag(struct format_tree *ft) 2368 { 2369 if (ft->wl != NULL) { 2370 if (ft->wl == RB_MIN(winlinks, &ft->wl->session->windows)) 2371 return (xstrdup("1")); 2372 return (xstrdup("0")); 2373 } 2374 return (NULL); 2375 } 2376 2377 /* Callback for window_width. */ 2378 static void * 2379 format_cb_window_width(struct format_tree *ft) 2380 { 2381 if (ft->w != NULL) 2382 return (format_printf("%u", ft->w->sx)); 2383 return (NULL); 2384 } 2385 2386 /* Callback for window_zoomed_flag. */ 2387 static void * 2388 format_cb_window_zoomed_flag(struct format_tree *ft) 2389 { 2390 if (ft->w != NULL) { 2391 if (ft->w->flags & WINDOW_ZOOMED) 2392 return (xstrdup("1")); 2393 return (xstrdup("0")); 2394 } 2395 return (NULL); 2396 } 2397 2398 /* Callback for wrap_flag. */ 2399 static void * 2400 format_cb_wrap_flag(struct format_tree *ft) 2401 { 2402 if (ft->wp != NULL) { 2403 if (ft->wp->base.mode & MODE_WRAP) 2404 return (xstrdup("1")); 2405 return (xstrdup("0")); 2406 } 2407 return (NULL); 2408 } 2409 2410 /* Callback for buffer_created. */ 2411 static void * 2412 format_cb_buffer_created(struct format_tree *ft) 2413 { 2414 static struct timeval tv; 2415 2416 if (ft->pb != NULL) { 2417 timerclear(&tv); 2418 tv.tv_sec = paste_buffer_created(ft->pb); 2419 return (&tv); 2420 } 2421 return (NULL); 2422 } 2423 2424 /* Callback for client_activity. */ 2425 static void * 2426 format_cb_client_activity(struct format_tree *ft) 2427 { 2428 if (ft->c != NULL) 2429 return (&ft->c->activity_time); 2430 return (NULL); 2431 } 2432 2433 /* Callback for client_created. */ 2434 static void * 2435 format_cb_client_created(struct format_tree *ft) 2436 { 2437 if (ft->c != NULL) 2438 return (&ft->c->creation_time); 2439 return (NULL); 2440 } 2441 2442 /* Callback for session_activity. */ 2443 static void * 2444 format_cb_session_activity(struct format_tree *ft) 2445 { 2446 if (ft->s != NULL) 2447 return (&ft->s->activity_time); 2448 return (NULL); 2449 } 2450 2451 /* Callback for session_created. */ 2452 static void * 2453 format_cb_session_created(struct format_tree *ft) 2454 { 2455 if (ft->s != NULL) 2456 return (&ft->s->creation_time); 2457 return (NULL); 2458 } 2459 2460 /* Callback for session_last_attached. */ 2461 static void * 2462 format_cb_session_last_attached(struct format_tree *ft) 2463 { 2464 if (ft->s != NULL) 2465 return (&ft->s->last_attached_time); 2466 return (NULL); 2467 } 2468 2469 /* Callback for start_time. */ 2470 static void * 2471 format_cb_start_time(__unused struct format_tree *ft) 2472 { 2473 return (&start_time); 2474 } 2475 2476 /* Callback for window_activity. */ 2477 static void * 2478 format_cb_window_activity(struct format_tree *ft) 2479 { 2480 if (ft->w != NULL) 2481 return (&ft->w->activity_time); 2482 return (NULL); 2483 } 2484 2485 /* Callback for buffer_mode_format, */ 2486 static void * 2487 format_cb_buffer_mode_format(__unused struct format_tree *ft) 2488 { 2489 return (xstrdup(window_buffer_mode.default_format)); 2490 } 2491 2492 /* Callback for client_mode_format, */ 2493 static void * 2494 format_cb_client_mode_format(__unused struct format_tree *ft) 2495 { 2496 return (xstrdup(window_client_mode.default_format)); 2497 } 2498 2499 /* Callback for tree_mode_format, */ 2500 static void * 2501 format_cb_tree_mode_format(__unused struct format_tree *ft) 2502 { 2503 return (xstrdup(window_tree_mode.default_format)); 2504 } 2505 2506 /* Format table type. */ 2507 enum format_table_type { 2508 FORMAT_TABLE_STRING, 2509 FORMAT_TABLE_TIME 2510 }; 2511 2512 /* Format table entry. */ 2513 struct format_table_entry { 2514 const char *key; 2515 enum format_table_type type; 2516 format_cb cb; 2517 }; 2518 2519 /* 2520 * Format table. Default format variables (that are almost always in the tree 2521 * and where the value is expanded by a callback in this file) are listed here. 2522 * Only variables which are added by the caller go into the tree. 2523 */ 2524 static const struct format_table_entry format_table[] = { 2525 { "active_window_index", FORMAT_TABLE_STRING, 2526 format_cb_active_window_index 2527 }, 2528 { "alternate_on", FORMAT_TABLE_STRING, 2529 format_cb_alternate_on 2530 }, 2531 { "alternate_saved_x", FORMAT_TABLE_STRING, 2532 format_cb_alternate_saved_x 2533 }, 2534 { "alternate_saved_y", FORMAT_TABLE_STRING, 2535 format_cb_alternate_saved_y 2536 }, 2537 { "buffer_created", FORMAT_TABLE_TIME, 2538 format_cb_buffer_created 2539 }, 2540 { "buffer_mode_format", FORMAT_TABLE_STRING, 2541 format_cb_buffer_mode_format 2542 }, 2543 { "buffer_name", FORMAT_TABLE_STRING, 2544 format_cb_buffer_name 2545 }, 2546 { "buffer_sample", FORMAT_TABLE_STRING, 2547 format_cb_buffer_sample 2548 }, 2549 { "buffer_size", FORMAT_TABLE_STRING, 2550 format_cb_buffer_size 2551 }, 2552 { "client_activity", FORMAT_TABLE_TIME, 2553 format_cb_client_activity 2554 }, 2555 { "client_cell_height", FORMAT_TABLE_STRING, 2556 format_cb_client_cell_height 2557 }, 2558 { "client_cell_width", FORMAT_TABLE_STRING, 2559 format_cb_client_cell_width 2560 }, 2561 { "client_control_mode", FORMAT_TABLE_STRING, 2562 format_cb_client_control_mode 2563 }, 2564 { "client_created", FORMAT_TABLE_TIME, 2565 format_cb_client_created 2566 }, 2567 { "client_discarded", FORMAT_TABLE_STRING, 2568 format_cb_client_discarded 2569 }, 2570 { "client_flags", FORMAT_TABLE_STRING, 2571 format_cb_client_flags 2572 }, 2573 { "client_height", FORMAT_TABLE_STRING, 2574 format_cb_client_height 2575 }, 2576 { "client_key_table", FORMAT_TABLE_STRING, 2577 format_cb_client_key_table 2578 }, 2579 { "client_last_session", FORMAT_TABLE_STRING, 2580 format_cb_client_last_session 2581 }, 2582 { "client_mode_format", FORMAT_TABLE_STRING, 2583 format_cb_client_mode_format 2584 }, 2585 { "client_name", FORMAT_TABLE_STRING, 2586 format_cb_client_name 2587 }, 2588 { "client_pid", FORMAT_TABLE_STRING, 2589 format_cb_client_pid 2590 }, 2591 { "client_prefix", FORMAT_TABLE_STRING, 2592 format_cb_client_prefix 2593 }, 2594 { "client_readonly", FORMAT_TABLE_STRING, 2595 format_cb_client_readonly 2596 }, 2597 { "client_session", FORMAT_TABLE_STRING, 2598 format_cb_client_session 2599 }, 2600 { "client_termfeatures", FORMAT_TABLE_STRING, 2601 format_cb_client_termfeatures 2602 }, 2603 { "client_termname", FORMAT_TABLE_STRING, 2604 format_cb_client_termname 2605 }, 2606 { "client_termtype", FORMAT_TABLE_STRING, 2607 format_cb_client_termtype 2608 }, 2609 { "client_tty", FORMAT_TABLE_STRING, 2610 format_cb_client_tty 2611 }, 2612 { "client_utf8", FORMAT_TABLE_STRING, 2613 format_cb_client_utf8 2614 }, 2615 { "client_width", FORMAT_TABLE_STRING, 2616 format_cb_client_width 2617 }, 2618 { "client_written", FORMAT_TABLE_STRING, 2619 format_cb_client_written 2620 }, 2621 { "config_files", FORMAT_TABLE_STRING, 2622 format_cb_config_files 2623 }, 2624 { "cursor_character", FORMAT_TABLE_STRING, 2625 format_cb_cursor_character 2626 }, 2627 { "cursor_flag", FORMAT_TABLE_STRING, 2628 format_cb_cursor_flag 2629 }, 2630 { "cursor_x", FORMAT_TABLE_STRING, 2631 format_cb_cursor_x 2632 }, 2633 { "cursor_y", FORMAT_TABLE_STRING, 2634 format_cb_cursor_y 2635 }, 2636 { "history_all_bytes", FORMAT_TABLE_STRING, 2637 format_cb_history_all_bytes 2638 }, 2639 { "history_bytes", FORMAT_TABLE_STRING, 2640 format_cb_history_bytes 2641 }, 2642 { "history_limit", FORMAT_TABLE_STRING, 2643 format_cb_history_limit 2644 }, 2645 { "history_size", FORMAT_TABLE_STRING, 2646 format_cb_history_size 2647 }, 2648 { "host", FORMAT_TABLE_STRING, 2649 format_cb_host 2650 }, 2651 { "host_short", FORMAT_TABLE_STRING, 2652 format_cb_host_short 2653 }, 2654 { "insert_flag", FORMAT_TABLE_STRING, 2655 format_cb_insert_flag 2656 }, 2657 { "keypad_cursor_flag", FORMAT_TABLE_STRING, 2658 format_cb_keypad_cursor_flag 2659 }, 2660 { "keypad_flag", FORMAT_TABLE_STRING, 2661 format_cb_keypad_flag 2662 }, 2663 { "last_window_index", FORMAT_TABLE_STRING, 2664 format_cb_last_window_index 2665 }, 2666 { "mouse_all_flag", FORMAT_TABLE_STRING, 2667 format_cb_mouse_all_flag 2668 }, 2669 { "mouse_any_flag", FORMAT_TABLE_STRING, 2670 format_cb_mouse_any_flag 2671 }, 2672 { "mouse_button_flag", FORMAT_TABLE_STRING, 2673 format_cb_mouse_button_flag 2674 }, 2675 { "mouse_line", FORMAT_TABLE_STRING, 2676 format_cb_mouse_line 2677 }, 2678 { "mouse_pane", FORMAT_TABLE_STRING, 2679 format_cb_mouse_pane 2680 }, 2681 { "mouse_sgr_flag", FORMAT_TABLE_STRING, 2682 format_cb_mouse_sgr_flag 2683 }, 2684 { "mouse_standard_flag", FORMAT_TABLE_STRING, 2685 format_cb_mouse_standard_flag 2686 }, 2687 { "mouse_utf8_flag", FORMAT_TABLE_STRING, 2688 format_cb_mouse_utf8_flag 2689 }, 2690 { "mouse_word", FORMAT_TABLE_STRING, 2691 format_cb_mouse_word 2692 }, 2693 { "mouse_x", FORMAT_TABLE_STRING, 2694 format_cb_mouse_x 2695 }, 2696 { "mouse_y", FORMAT_TABLE_STRING, 2697 format_cb_mouse_y 2698 }, 2699 { "origin_flag", FORMAT_TABLE_STRING, 2700 format_cb_origin_flag 2701 }, 2702 { "pane_active", FORMAT_TABLE_STRING, 2703 format_cb_pane_active 2704 }, 2705 { "pane_at_bottom", FORMAT_TABLE_STRING, 2706 format_cb_pane_at_bottom 2707 }, 2708 { "pane_at_left", FORMAT_TABLE_STRING, 2709 format_cb_pane_at_left 2710 }, 2711 { "pane_at_right", FORMAT_TABLE_STRING, 2712 format_cb_pane_at_right 2713 }, 2714 { "pane_at_top", FORMAT_TABLE_STRING, 2715 format_cb_pane_at_top 2716 }, 2717 { "pane_bg", FORMAT_TABLE_STRING, 2718 format_cb_pane_bg 2719 }, 2720 { "pane_bottom", FORMAT_TABLE_STRING, 2721 format_cb_pane_bottom 2722 }, 2723 { "pane_current_command", FORMAT_TABLE_STRING, 2724 format_cb_current_command 2725 }, 2726 { "pane_current_path", FORMAT_TABLE_STRING, 2727 format_cb_current_path 2728 }, 2729 { "pane_dead", FORMAT_TABLE_STRING, 2730 format_cb_pane_dead 2731 }, 2732 { "pane_dead_status", FORMAT_TABLE_STRING, 2733 format_cb_pane_dead_status 2734 }, 2735 { "pane_fg", FORMAT_TABLE_STRING, 2736 format_cb_pane_fg 2737 }, 2738 { "pane_format", FORMAT_TABLE_STRING, 2739 format_cb_pane_format 2740 }, 2741 { "pane_height", FORMAT_TABLE_STRING, 2742 format_cb_pane_height 2743 }, 2744 { "pane_id", FORMAT_TABLE_STRING, 2745 format_cb_pane_id 2746 }, 2747 { "pane_in_mode", FORMAT_TABLE_STRING, 2748 format_cb_pane_in_mode 2749 }, 2750 { "pane_index", FORMAT_TABLE_STRING, 2751 format_cb_pane_index 2752 }, 2753 { "pane_input_off", FORMAT_TABLE_STRING, 2754 format_cb_pane_input_off 2755 }, 2756 { "pane_last", FORMAT_TABLE_STRING, 2757 format_cb_pane_last 2758 }, 2759 { "pane_left", FORMAT_TABLE_STRING, 2760 format_cb_pane_left 2761 }, 2762 { "pane_marked", FORMAT_TABLE_STRING, 2763 format_cb_pane_marked 2764 }, 2765 { "pane_marked_set", FORMAT_TABLE_STRING, 2766 format_cb_pane_marked_set 2767 }, 2768 { "pane_mode", FORMAT_TABLE_STRING, 2769 format_cb_pane_mode 2770 }, 2771 { "pane_path", FORMAT_TABLE_STRING, 2772 format_cb_pane_path 2773 }, 2774 { "pane_pid", FORMAT_TABLE_STRING, 2775 format_cb_pane_pid 2776 }, 2777 { "pane_pipe", FORMAT_TABLE_STRING, 2778 format_cb_pane_pipe 2779 }, 2780 { "pane_right", FORMAT_TABLE_STRING, 2781 format_cb_pane_right 2782 }, 2783 { "pane_search_string", FORMAT_TABLE_STRING, 2784 format_cb_pane_search_string 2785 }, 2786 { "pane_start_command", FORMAT_TABLE_STRING, 2787 format_cb_start_command 2788 }, 2789 { "pane_synchronized", FORMAT_TABLE_STRING, 2790 format_cb_pane_synchronized 2791 }, 2792 { "pane_tabs", FORMAT_TABLE_STRING, 2793 format_cb_pane_tabs 2794 }, 2795 { "pane_title", FORMAT_TABLE_STRING, 2796 format_cb_pane_title 2797 }, 2798 { "pane_top", FORMAT_TABLE_STRING, 2799 format_cb_pane_top 2800 }, 2801 { "pane_tty", FORMAT_TABLE_STRING, 2802 format_cb_pane_tty 2803 }, 2804 { "pane_width", FORMAT_TABLE_STRING, 2805 format_cb_pane_width 2806 }, 2807 { "pid", FORMAT_TABLE_STRING, 2808 format_cb_pid 2809 }, 2810 { "scroll_region_lower", FORMAT_TABLE_STRING, 2811 format_cb_scroll_region_lower 2812 }, 2813 { "scroll_region_upper", FORMAT_TABLE_STRING, 2814 format_cb_scroll_region_upper 2815 }, 2816 { "session_activity", FORMAT_TABLE_TIME, 2817 format_cb_session_activity 2818 }, 2819 { "session_alerts", FORMAT_TABLE_STRING, 2820 format_cb_session_alerts 2821 }, 2822 { "session_attached", FORMAT_TABLE_STRING, 2823 format_cb_session_attached 2824 }, 2825 { "session_attached_list", FORMAT_TABLE_STRING, 2826 format_cb_session_attached_list 2827 }, 2828 { "session_created", FORMAT_TABLE_TIME, 2829 format_cb_session_created 2830 }, 2831 { "session_format", FORMAT_TABLE_STRING, 2832 format_cb_session_format 2833 }, 2834 { "session_group", FORMAT_TABLE_STRING, 2835 format_cb_session_group 2836 }, 2837 { "session_group_attached", FORMAT_TABLE_STRING, 2838 format_cb_session_group_attached 2839 }, 2840 { "session_group_attached_list", FORMAT_TABLE_STRING, 2841 format_cb_session_group_attached_list 2842 }, 2843 { "session_group_list", FORMAT_TABLE_STRING, 2844 format_cb_session_group_list 2845 }, 2846 { "session_group_many_attached", FORMAT_TABLE_STRING, 2847 format_cb_session_group_many_attached 2848 }, 2849 { "session_group_size", FORMAT_TABLE_STRING, 2850 format_cb_session_group_size 2851 }, 2852 { "session_grouped", FORMAT_TABLE_STRING, 2853 format_cb_session_grouped 2854 }, 2855 { "session_id", FORMAT_TABLE_STRING, 2856 format_cb_session_id 2857 }, 2858 { "session_last_attached", FORMAT_TABLE_TIME, 2859 format_cb_session_last_attached 2860 }, 2861 { "session_many_attached", FORMAT_TABLE_STRING, 2862 format_cb_session_many_attached 2863 }, 2864 { "session_marked", FORMAT_TABLE_STRING, 2865 format_cb_session_marked, 2866 }, 2867 { "session_name", FORMAT_TABLE_STRING, 2868 format_cb_session_name 2869 }, 2870 { "session_path", FORMAT_TABLE_STRING, 2871 format_cb_session_path 2872 }, 2873 { "session_stack", FORMAT_TABLE_STRING, 2874 format_cb_session_stack 2875 }, 2876 { "session_windows", FORMAT_TABLE_STRING, 2877 format_cb_session_windows 2878 }, 2879 { "socket_path", FORMAT_TABLE_STRING, 2880 format_cb_socket_path 2881 }, 2882 { "start_time", FORMAT_TABLE_TIME, 2883 format_cb_start_time 2884 }, 2885 { "tree_mode_format", FORMAT_TABLE_STRING, 2886 format_cb_tree_mode_format 2887 }, 2888 { "version", FORMAT_TABLE_STRING, 2889 format_cb_version 2890 }, 2891 { "window_active", FORMAT_TABLE_STRING, 2892 format_cb_window_active 2893 }, 2894 { "window_active_clients", FORMAT_TABLE_STRING, 2895 format_cb_window_active_clients 2896 }, 2897 { "window_active_clients_list", FORMAT_TABLE_STRING, 2898 format_cb_window_active_clients_list 2899 }, 2900 { "window_active_sessions", FORMAT_TABLE_STRING, 2901 format_cb_window_active_sessions 2902 }, 2903 { "window_active_sessions_list", FORMAT_TABLE_STRING, 2904 format_cb_window_active_sessions_list 2905 }, 2906 { "window_activity", FORMAT_TABLE_TIME, 2907 format_cb_window_activity 2908 }, 2909 { "window_activity_flag", FORMAT_TABLE_STRING, 2910 format_cb_window_activity_flag 2911 }, 2912 { "window_bell_flag", FORMAT_TABLE_STRING, 2913 format_cb_window_bell_flag 2914 }, 2915 { "window_bigger", FORMAT_TABLE_STRING, 2916 format_cb_window_bigger 2917 }, 2918 { "window_cell_height", FORMAT_TABLE_STRING, 2919 format_cb_window_cell_height 2920 }, 2921 { "window_cell_width", FORMAT_TABLE_STRING, 2922 format_cb_window_cell_width 2923 }, 2924 { "window_end_flag", FORMAT_TABLE_STRING, 2925 format_cb_window_end_flag 2926 }, 2927 { "window_flags", FORMAT_TABLE_STRING, 2928 format_cb_window_flags 2929 }, 2930 { "window_format", FORMAT_TABLE_STRING, 2931 format_cb_window_format 2932 }, 2933 { "window_height", FORMAT_TABLE_STRING, 2934 format_cb_window_height 2935 }, 2936 { "window_id", FORMAT_TABLE_STRING, 2937 format_cb_window_id 2938 }, 2939 { "window_index", FORMAT_TABLE_STRING, 2940 format_cb_window_index 2941 }, 2942 { "window_last_flag", FORMAT_TABLE_STRING, 2943 format_cb_window_last_flag 2944 }, 2945 { "window_layout", FORMAT_TABLE_STRING, 2946 format_cb_window_layout 2947 }, 2948 { "window_linked", FORMAT_TABLE_STRING, 2949 format_cb_window_linked 2950 }, 2951 { "window_linked_sessions", FORMAT_TABLE_STRING, 2952 format_cb_window_linked_sessions 2953 }, 2954 { "window_linked_sessions_list", FORMAT_TABLE_STRING, 2955 format_cb_window_linked_sessions_list 2956 }, 2957 { "window_marked_flag", FORMAT_TABLE_STRING, 2958 format_cb_window_marked_flag 2959 }, 2960 { "window_name", FORMAT_TABLE_STRING, 2961 format_cb_window_name 2962 }, 2963 { "window_offset_x", FORMAT_TABLE_STRING, 2964 format_cb_window_offset_x 2965 }, 2966 { "window_offset_y", FORMAT_TABLE_STRING, 2967 format_cb_window_offset_y 2968 }, 2969 { "window_panes", FORMAT_TABLE_STRING, 2970 format_cb_window_panes 2971 }, 2972 { "window_raw_flags", FORMAT_TABLE_STRING, 2973 format_cb_window_raw_flags 2974 }, 2975 { "window_silence_flag", FORMAT_TABLE_STRING, 2976 format_cb_window_silence_flag 2977 }, 2978 { "window_stack_index", FORMAT_TABLE_STRING, 2979 format_cb_window_stack_index 2980 }, 2981 { "window_start_flag", FORMAT_TABLE_STRING, 2982 format_cb_window_start_flag 2983 }, 2984 { "window_visible_layout", FORMAT_TABLE_STRING, 2985 format_cb_window_visible_layout 2986 }, 2987 { "window_width", FORMAT_TABLE_STRING, 2988 format_cb_window_width 2989 }, 2990 { "window_zoomed_flag", FORMAT_TABLE_STRING, 2991 format_cb_window_zoomed_flag 2992 }, 2993 { "wrap_flag", FORMAT_TABLE_STRING, 2994 format_cb_wrap_flag 2995 } 2996 }; 2997 2998 /* Compare format table entries. */ 2999 static int 3000 format_table_compare(const void *key0, const void *entry0) 3001 { 3002 const char *key = key0; 3003 const struct format_table_entry *entry = entry0; 3004 3005 return (strcmp(key, entry->key)); 3006 } 3007 3008 /* Get a format callback. */ 3009 static struct format_table_entry * 3010 format_table_get(const char *key) 3011 { 3012 return (bsearch(key, format_table, nitems(format_table), 3013 sizeof *format_table, format_table_compare)); 3014 } 3015 3016 /* Merge one format tree into another. */ 3017 void 3018 format_merge(struct format_tree *ft, struct format_tree *from) 3019 { 3020 struct format_entry *fe; 3021 3022 RB_FOREACH(fe, format_entry_tree, &from->tree) { 3023 if (fe->value != NULL) 3024 format_add(ft, fe->key, "%s", fe->value); 3025 } 3026 } 3027 3028 /* Get format pane. */ 3029 struct window_pane * 3030 format_get_pane(struct format_tree *ft) 3031 { 3032 return (ft->wp); 3033 } 3034 3035 /* Add item bits to tree. */ 3036 static void 3037 format_create_add_item(struct format_tree *ft, struct cmdq_item *item) 3038 { 3039 struct key_event *event = cmdq_get_event(item); 3040 struct mouse_event *m = &event->m; 3041 3042 cmdq_merge_formats(item, ft); 3043 memcpy(&ft->m, m, sizeof ft->m); 3044 } 3045 3046 /* Create a new tree. */ 3047 struct format_tree * 3048 format_create(struct client *c, struct cmdq_item *item, int tag, int flags) 3049 { 3050 struct format_tree *ft; 3051 3052 ft = xcalloc(1, sizeof *ft); 3053 RB_INIT(&ft->tree); 3054 3055 if (c != NULL) { 3056 ft->client = c; 3057 ft->client->references++; 3058 } 3059 ft->item = item; 3060 3061 ft->tag = tag; 3062 ft->flags = flags; 3063 3064 if (item != NULL) 3065 format_create_add_item(ft, item); 3066 3067 return (ft); 3068 } 3069 3070 /* Free a tree. */ 3071 void 3072 format_free(struct format_tree *ft) 3073 { 3074 struct format_entry *fe, *fe1; 3075 3076 RB_FOREACH_SAFE(fe, format_entry_tree, &ft->tree, fe1) { 3077 RB_REMOVE(format_entry_tree, &ft->tree, fe); 3078 free(fe->value); 3079 free(fe->key); 3080 free(fe); 3081 } 3082 3083 if (ft->client != NULL) 3084 server_client_unref(ft->client); 3085 free(ft); 3086 } 3087 3088 /* Log each format. */ 3089 static void 3090 format_log_debug_cb(const char *key, const char *value, void *arg) 3091 { 3092 const char *prefix = arg; 3093 3094 log_debug("%s: %s=%s", prefix, key, value); 3095 } 3096 3097 /* Log a format tree. */ 3098 void 3099 format_log_debug(struct format_tree *ft, const char *prefix) 3100 { 3101 format_each(ft, format_log_debug_cb, (void *)prefix); 3102 } 3103 3104 /* Walk each format. */ 3105 void 3106 format_each(struct format_tree *ft, void (*cb)(const char *, const char *, 3107 void *), void *arg) 3108 { 3109 const struct format_table_entry *fte; 3110 struct format_entry *fe; 3111 u_int i; 3112 char s[64]; 3113 void *value; 3114 struct timeval *tv; 3115 3116 for (i = 0; i < nitems(format_table); i++) { 3117 fte = &format_table[i]; 3118 3119 value = fte->cb(ft); 3120 if (value == NULL) 3121 continue; 3122 if (fte->type == FORMAT_TABLE_TIME) { 3123 tv = value; 3124 xsnprintf(s, sizeof s, "%lld", (long long)tv->tv_sec); 3125 cb(fte->key, s, arg); 3126 } else { 3127 cb(fte->key, value, arg); 3128 free(value); 3129 } 3130 } 3131 RB_FOREACH(fe, format_entry_tree, &ft->tree) { 3132 if (fe->time != 0) { 3133 xsnprintf(s, sizeof s, "%lld", (long long)fe->time); 3134 cb(fe->key, s, arg); 3135 } else { 3136 if (fe->value == NULL && fe->cb != NULL) { 3137 fe->value = fe->cb(ft); 3138 if (fe->value == NULL) 3139 fe->value = xstrdup(""); 3140 } 3141 cb(fe->key, fe->value, arg); 3142 } 3143 } 3144 } 3145 3146 /* Add a key-value pair. */ 3147 void 3148 format_add(struct format_tree *ft, const char *key, const char *fmt, ...) 3149 { 3150 struct format_entry *fe; 3151 struct format_entry *fe_now; 3152 va_list ap; 3153 3154 fe = xmalloc(sizeof *fe); 3155 fe->key = xstrdup(key); 3156 3157 fe_now = RB_INSERT(format_entry_tree, &ft->tree, fe); 3158 if (fe_now != NULL) { 3159 free(fe->key); 3160 free(fe); 3161 free(fe_now->value); 3162 fe = fe_now; 3163 } 3164 3165 fe->cb = NULL; 3166 fe->time = 0; 3167 3168 va_start(ap, fmt); 3169 xvasprintf(&fe->value, fmt, ap); 3170 va_end(ap); 3171 } 3172 3173 /* Add a key and time. */ 3174 void 3175 format_add_tv(struct format_tree *ft, const char *key, struct timeval *tv) 3176 { 3177 struct format_entry *fe, *fe_now; 3178 3179 fe = xmalloc(sizeof *fe); 3180 fe->key = xstrdup(key); 3181 3182 fe_now = RB_INSERT(format_entry_tree, &ft->tree, fe); 3183 if (fe_now != NULL) { 3184 free(fe->key); 3185 free(fe); 3186 free(fe_now->value); 3187 fe = fe_now; 3188 } 3189 3190 fe->cb = NULL; 3191 fe->time = tv->tv_sec; 3192 3193 fe->value = NULL; 3194 } 3195 3196 /* Add a key and function. */ 3197 void 3198 format_add_cb(struct format_tree *ft, const char *key, format_cb cb) 3199 { 3200 struct format_entry *fe; 3201 struct format_entry *fe_now; 3202 3203 fe = xmalloc(sizeof *fe); 3204 fe->key = xstrdup(key); 3205 3206 fe_now = RB_INSERT(format_entry_tree, &ft->tree, fe); 3207 if (fe_now != NULL) { 3208 free(fe->key); 3209 free(fe); 3210 free(fe_now->value); 3211 fe = fe_now; 3212 } 3213 3214 fe->cb = cb; 3215 fe->time = 0; 3216 3217 fe->value = NULL; 3218 } 3219 3220 /* Quote shell special characters in string. */ 3221 static char * 3222 format_quote_shell(const char *s) 3223 { 3224 const char *cp; 3225 char *out, *at; 3226 3227 at = out = xmalloc(strlen(s) * 2 + 1); 3228 for (cp = s; *cp != '\0'; cp++) { 3229 if (strchr("|&;<>()$`\\\"'*?[# =%", *cp) != NULL) 3230 *at++ = '\\'; 3231 *at++ = *cp; 3232 } 3233 *at = '\0'; 3234 return (out); 3235 } 3236 3237 /* Quote #s in string. */ 3238 static char * 3239 format_quote_style(const char *s) 3240 { 3241 const char *cp; 3242 char *out, *at; 3243 3244 at = out = xmalloc(strlen(s) * 2 + 1); 3245 for (cp = s; *cp != '\0'; cp++) { 3246 if (*cp == '#') 3247 *at++ = '#'; 3248 *at++ = *cp; 3249 } 3250 *at = '\0'; 3251 return (out); 3252 } 3253 3254 /* Make a prettier time. */ 3255 static char * 3256 format_pretty_time(time_t t) 3257 { 3258 struct tm now_tm, tm; 3259 time_t now, age; 3260 char s[6]; 3261 3262 time(&now); 3263 if (now < t) 3264 now = t; 3265 age = now - t; 3266 3267 localtime_r(&now, &now_tm); 3268 localtime_r(&t, &tm); 3269 3270 /* Last 24 hours. */ 3271 if (age < 24 * 3600) { 3272 strftime(s, sizeof s, "%H:%M", &tm); 3273 return (xstrdup(s)); 3274 } 3275 3276 /* This month or last 28 days. */ 3277 if ((tm.tm_year == now_tm.tm_year && tm.tm_mon == now_tm.tm_mon) || 3278 age < 28 * 24 * 3600) { 3279 strftime(s, sizeof s, "%a%d", &tm); 3280 return (xstrdup(s)); 3281 } 3282 3283 /* Last 12 months. */ 3284 if ((tm.tm_year == now_tm.tm_year && tm.tm_mon < now_tm.tm_mon) || 3285 (tm.tm_year == now_tm.tm_year - 1 && tm.tm_mon > now_tm.tm_mon)) { 3286 strftime(s, sizeof s, "%d%b", &tm); 3287 return (xstrdup(s)); 3288 } 3289 3290 /* Older than that. */ 3291 strftime(s, sizeof s, "%h%y", &tm); 3292 return (xstrdup(s)); 3293 } 3294 3295 /* Find a format entry. */ 3296 static char * 3297 format_find(struct format_tree *ft, const char *key, int modifiers, 3298 const char *time_format) 3299 { 3300 struct format_table_entry *fte; 3301 void *value; 3302 struct format_entry *fe, fe_find; 3303 struct environ_entry *envent; 3304 struct options_entry *o; 3305 int idx; 3306 char *found = NULL, *saved, s[512]; 3307 const char *errstr; 3308 time_t t = 0; 3309 struct tm tm; 3310 3311 o = options_parse_get(global_options, key, &idx, 0); 3312 if (o == NULL && ft->wp != NULL) 3313 o = options_parse_get(ft->wp->options, key, &idx, 0); 3314 if (o == NULL && ft->w != NULL) 3315 o = options_parse_get(ft->w->options, key, &idx, 0); 3316 if (o == NULL) 3317 o = options_parse_get(global_w_options, key, &idx, 0); 3318 if (o == NULL && ft->s != NULL) 3319 o = options_parse_get(ft->s->options, key, &idx, 0); 3320 if (o == NULL) 3321 o = options_parse_get(global_s_options, key, &idx, 0); 3322 if (o != NULL) { 3323 found = options_to_string(o, idx, 1); 3324 goto found; 3325 } 3326 3327 fte = format_table_get(key); 3328 if (fte != NULL) { 3329 value = fte->cb(ft); 3330 if (fte->type == FORMAT_TABLE_TIME) 3331 t = ((struct timeval *)value)->tv_sec; 3332 else 3333 found = value; 3334 goto found; 3335 } 3336 fe_find.key = (char *)key; 3337 fe = RB_FIND(format_entry_tree, &ft->tree, &fe_find); 3338 if (fe != NULL) { 3339 if (fe->time != 0) { 3340 t = fe->time; 3341 goto found; 3342 } 3343 if (fe->value == NULL && fe->cb != NULL) { 3344 fe->value = fe->cb(ft); 3345 if (fe->value == NULL) 3346 fe->value = xstrdup(""); 3347 } 3348 found = xstrdup(fe->value); 3349 goto found; 3350 } 3351 3352 if (~modifiers & FORMAT_TIMESTRING) { 3353 envent = NULL; 3354 if (ft->s != NULL) 3355 envent = environ_find(ft->s->environ, key); 3356 if (envent == NULL) 3357 envent = environ_find(global_environ, key); 3358 if (envent != NULL && envent->value != NULL) { 3359 found = xstrdup(envent->value); 3360 goto found; 3361 } 3362 } 3363 3364 return (NULL); 3365 3366 found: 3367 if (modifiers & FORMAT_TIMESTRING) { 3368 if (t == 0 && found != NULL) { 3369 t = strtonum(found, 0, INT64_MAX, &errstr); 3370 if (errstr != NULL) 3371 t = 0; 3372 free(found); 3373 } 3374 if (t == 0) 3375 return (NULL); 3376 if (modifiers & FORMAT_PRETTY) 3377 found = format_pretty_time(t); 3378 else { 3379 if (time_format != NULL) { 3380 localtime_r(&t, &tm); 3381 strftime(s, sizeof s, time_format, &tm); 3382 } else { 3383 ctime_r(&t, s); 3384 s[strcspn(s, "\n")] = '\0'; 3385 } 3386 found = xstrdup(s); 3387 } 3388 return (found); 3389 } 3390 3391 if (t != 0) 3392 xasprintf(&found, "%lld", (long long)t); 3393 else if (found == NULL) 3394 return (NULL); 3395 if (modifiers & FORMAT_BASENAME) { 3396 saved = found; 3397 found = xstrdup(basename(saved)); 3398 free(saved); 3399 } 3400 if (modifiers & FORMAT_DIRNAME) { 3401 saved = found; 3402 found = xstrdup(dirname(saved)); 3403 free(saved); 3404 } 3405 if (modifiers & FORMAT_QUOTE_SHELL) { 3406 saved = found; 3407 found = xstrdup(format_quote_shell(saved)); 3408 free(saved); 3409 } 3410 if (modifiers & FORMAT_QUOTE_STYLE) { 3411 saved = found; 3412 found = xstrdup(format_quote_style(saved)); 3413 free(saved); 3414 } 3415 return (found); 3416 } 3417 3418 /* Remove escaped characters from string. */ 3419 static char * 3420 format_strip(const char *s) 3421 { 3422 char *out, *cp; 3423 int brackets = 0; 3424 3425 cp = out = xmalloc(strlen(s) + 1); 3426 for (; *s != '\0'; s++) { 3427 if (*s == '#' && s[1] == '{') 3428 brackets++; 3429 if (*s == '#' && strchr(",#{}:", s[1]) != NULL) { 3430 if (brackets != 0) 3431 *cp++ = *s; 3432 continue; 3433 } 3434 if (*s == '}') 3435 brackets--; 3436 *cp++ = *s; 3437 } 3438 *cp = '\0'; 3439 return (out); 3440 } 3441 3442 /* Skip until end. */ 3443 const char * 3444 format_skip(const char *s, const char *end) 3445 { 3446 int brackets = 0; 3447 3448 for (; *s != '\0'; s++) { 3449 if (*s == '#' && s[1] == '{') 3450 brackets++; 3451 if (*s == '#' && strchr(",#{}:", s[1]) != NULL) { 3452 s++; 3453 continue; 3454 } 3455 if (*s == '}') 3456 brackets--; 3457 if (strchr(end, *s) != NULL && brackets == 0) 3458 break; 3459 } 3460 if (*s == '\0') 3461 return (NULL); 3462 return (s); 3463 } 3464 3465 /* Return left and right alternatives separated by commas. */ 3466 static int 3467 format_choose(struct format_expand_state *es, const char *s, char **left, 3468 char **right, int expand) 3469 { 3470 const char *cp; 3471 char *left0, *right0; 3472 3473 cp = format_skip(s, ","); 3474 if (cp == NULL) 3475 return (-1); 3476 left0 = xstrndup(s, cp - s); 3477 right0 = xstrdup(cp + 1); 3478 3479 if (expand) { 3480 *left = format_expand1(es, left0); 3481 free(left0); 3482 *right = format_expand1(es, right0); 3483 free(right0); 3484 } else { 3485 *left = left0; 3486 *right = right0; 3487 } 3488 return (0); 3489 } 3490 3491 /* Is this true? */ 3492 int 3493 format_true(const char *s) 3494 { 3495 if (s != NULL && *s != '\0' && (s[0] != '0' || s[1] != '\0')) 3496 return (1); 3497 return (0); 3498 } 3499 3500 /* Check if modifier end. */ 3501 static int 3502 format_is_end(char c) 3503 { 3504 return (c == ';' || c == ':'); 3505 } 3506 3507 /* Add to modifier list. */ 3508 static void 3509 format_add_modifier(struct format_modifier **list, u_int *count, 3510 const char *c, size_t n, char **argv, int argc) 3511 { 3512 struct format_modifier *fm; 3513 3514 *list = xreallocarray(*list, (*count) + 1, sizeof **list); 3515 fm = &(*list)[(*count)++]; 3516 3517 memcpy(fm->modifier, c, n); 3518 fm->modifier[n] = '\0'; 3519 fm->size = n; 3520 3521 fm->argv = argv; 3522 fm->argc = argc; 3523 } 3524 3525 /* Free modifier list. */ 3526 static void 3527 format_free_modifiers(struct format_modifier *list, u_int count) 3528 { 3529 u_int i; 3530 3531 for (i = 0; i < count; i++) 3532 cmd_free_argv(list[i].argc, list[i].argv); 3533 free(list); 3534 } 3535 3536 /* Build modifier list. */ 3537 static struct format_modifier * 3538 format_build_modifiers(struct format_expand_state *es, const char **s, 3539 u_int *count) 3540 { 3541 const char *cp = *s, *end; 3542 struct format_modifier *list = NULL; 3543 char c, last[] = "X;:", **argv, *value; 3544 int argc; 3545 3546 /* 3547 * Modifiers are a ; separated list of the forms: 3548 * l,m,C,a,b,d,n,t,w,q,E,T,S,W,P,<,> 3549 * =a 3550 * =/a 3551 * =/a/ 3552 * s/a/b/ 3553 * s/a/b 3554 * ||,&&,!=,==,<=,>= 3555 */ 3556 3557 *count = 0; 3558 3559 while (*cp != '\0' && *cp != ':') { 3560 /* Skip any separator character. */ 3561 if (*cp == ';') 3562 cp++; 3563 3564 /* Check single character modifiers with no arguments. */ 3565 if (strchr("labdnwETSWP<>", cp[0]) != NULL && 3566 format_is_end(cp[1])) { 3567 format_add_modifier(&list, count, cp, 1, NULL, 0); 3568 cp++; 3569 continue; 3570 } 3571 3572 /* Then try double character with no arguments. */ 3573 if ((memcmp("||", cp, 2) == 0 || 3574 memcmp("&&", cp, 2) == 0 || 3575 memcmp("!=", cp, 2) == 0 || 3576 memcmp("==", cp, 2) == 0 || 3577 memcmp("<=", cp, 2) == 0 || 3578 memcmp(">=", cp, 2) == 0) && 3579 format_is_end(cp[2])) { 3580 format_add_modifier(&list, count, cp, 2, NULL, 0); 3581 cp += 2; 3582 continue; 3583 } 3584 3585 /* Now try single character with arguments. */ 3586 if (strchr("mCNst=peq", cp[0]) == NULL) 3587 break; 3588 c = cp[0]; 3589 3590 /* No arguments provided. */ 3591 if (format_is_end(cp[1])) { 3592 format_add_modifier(&list, count, cp, 1, NULL, 0); 3593 cp++; 3594 continue; 3595 } 3596 argv = NULL; 3597 argc = 0; 3598 3599 /* Single argument with no wrapper character. */ 3600 if (!ispunct(cp[1]) || cp[1] == '-') { 3601 end = format_skip(cp + 1, ":;"); 3602 if (end == NULL) 3603 break; 3604 3605 argv = xcalloc(1, sizeof *argv); 3606 value = xstrndup(cp + 1, end - (cp + 1)); 3607 argv[0] = format_expand1(es, value); 3608 free(value); 3609 argc = 1; 3610 3611 format_add_modifier(&list, count, &c, 1, argv, argc); 3612 cp = end; 3613 continue; 3614 } 3615 3616 /* Multiple arguments with a wrapper character. */ 3617 last[0] = cp[1]; 3618 cp++; 3619 do { 3620 if (cp[0] == last[0] && format_is_end(cp[1])) { 3621 cp++; 3622 break; 3623 } 3624 end = format_skip(cp + 1, last); 3625 if (end == NULL) 3626 break; 3627 cp++; 3628 3629 argv = xreallocarray(argv, argc + 1, sizeof *argv); 3630 value = xstrndup(cp, end - cp); 3631 argv[argc++] = format_expand1(es, value); 3632 free(value); 3633 3634 cp = end; 3635 } while (!format_is_end(cp[0])); 3636 format_add_modifier(&list, count, &c, 1, argv, argc); 3637 } 3638 if (*cp != ':') { 3639 format_free_modifiers(list, *count); 3640 *count = 0; 3641 return (NULL); 3642 } 3643 *s = cp + 1; 3644 return (list); 3645 } 3646 3647 /* Match against an fnmatch(3) pattern or regular expression. */ 3648 static char * 3649 format_match(struct format_modifier *fm, const char *pattern, const char *text) 3650 { 3651 const char *s = ""; 3652 regex_t r; 3653 int flags = 0; 3654 3655 if (fm->argc >= 1) 3656 s = fm->argv[0]; 3657 if (strchr(s, 'r') == NULL) { 3658 if (strchr(s, 'i') != NULL) 3659 flags |= FNM_CASEFOLD; 3660 if (fnmatch(pattern, text, flags) != 0) 3661 return (xstrdup("0")); 3662 } else { 3663 flags = REG_EXTENDED|REG_NOSUB; 3664 if (strchr(s, 'i') != NULL) 3665 flags |= REG_ICASE; 3666 if (regcomp(&r, pattern, flags) != 0) 3667 return (xstrdup("0")); 3668 if (regexec(&r, text, 0, NULL, 0) != 0) { 3669 regfree(&r); 3670 return (xstrdup("0")); 3671 } 3672 regfree(&r); 3673 } 3674 return (xstrdup("1")); 3675 } 3676 3677 /* Perform substitution in string. */ 3678 static char * 3679 format_sub(struct format_modifier *fm, const char *text, const char *pattern, 3680 const char *with) 3681 { 3682 char *value; 3683 int flags = REG_EXTENDED; 3684 3685 if (fm->argc >= 3 && strchr(fm->argv[2], 'i') != NULL) 3686 flags |= REG_ICASE; 3687 value = regsub(pattern, with, text, flags); 3688 if (value == NULL) 3689 return (xstrdup(text)); 3690 return (value); 3691 } 3692 3693 /* Search inside pane. */ 3694 static char * 3695 format_search(struct format_modifier *fm, struct window_pane *wp, const char *s) 3696 { 3697 int ignore = 0, regex = 0; 3698 char *value; 3699 3700 if (fm->argc >= 1) { 3701 if (strchr(fm->argv[0], 'i') != NULL) 3702 ignore = 1; 3703 if (strchr(fm->argv[0], 'r') != NULL) 3704 regex = 1; 3705 } 3706 xasprintf(&value, "%u", window_pane_search(wp, s, regex, ignore)); 3707 return (value); 3708 } 3709 3710 /* Does session name exist? */ 3711 static char * 3712 format_session_name(struct format_expand_state *es, const char *fmt) 3713 { 3714 char *name; 3715 struct session *s; 3716 3717 name = format_expand1(es, fmt); 3718 RB_FOREACH(s, sessions, &sessions) { 3719 if (strcmp(s->name, name) == 0) { 3720 free(name); 3721 return (xstrdup("1")); 3722 } 3723 } 3724 free(name); 3725 return (xstrdup("0")); 3726 } 3727 3728 /* Loop over sessions. */ 3729 static char * 3730 format_loop_sessions(struct format_expand_state *es, const char *fmt) 3731 { 3732 struct format_tree *ft = es->ft; 3733 struct client *c = ft->client; 3734 struct cmdq_item *item = ft->item; 3735 struct format_tree *nft; 3736 struct format_expand_state next; 3737 char *expanded, *value; 3738 size_t valuelen; 3739 struct session *s; 3740 3741 value = xcalloc(1, 1); 3742 valuelen = 1; 3743 3744 RB_FOREACH(s, sessions, &sessions) { 3745 format_log(es, "session loop: $%u", s->id); 3746 nft = format_create(c, item, FORMAT_NONE, ft->flags); 3747 format_defaults(nft, ft->c, s, NULL, NULL); 3748 format_copy_state(&next, es, 0); 3749 next.ft = nft; 3750 expanded = format_expand1(&next, fmt); 3751 format_free(next.ft); 3752 3753 valuelen += strlen(expanded); 3754 value = xrealloc(value, valuelen); 3755 3756 strlcat(value, expanded, valuelen); 3757 free(expanded); 3758 } 3759 3760 return (value); 3761 } 3762 3763 /* Does window name exist? */ 3764 static char * 3765 format_window_name(struct format_expand_state *es, const char *fmt) 3766 { 3767 struct format_tree *ft = es->ft; 3768 char *name; 3769 struct winlink *wl; 3770 3771 if (ft->s == NULL) { 3772 format_log(es, "window name but no session"); 3773 return (NULL); 3774 } 3775 3776 name = format_expand1(es, fmt); 3777 RB_FOREACH(wl, winlinks, &ft->s->windows) { 3778 if (strcmp(wl->window->name, name) == 0) { 3779 free(name); 3780 return (xstrdup("1")); 3781 } 3782 } 3783 free(name); 3784 return (xstrdup("0")); 3785 } 3786 3787 /* Loop over windows. */ 3788 static char * 3789 format_loop_windows(struct format_expand_state *es, const char *fmt) 3790 { 3791 struct format_tree *ft = es->ft; 3792 struct client *c = ft->client; 3793 struct cmdq_item *item = ft->item; 3794 struct format_tree *nft; 3795 struct format_expand_state next; 3796 char *all, *active, *use, *expanded, *value; 3797 size_t valuelen; 3798 struct winlink *wl; 3799 struct window *w; 3800 3801 if (ft->s == NULL) { 3802 format_log(es, "window loop but no session"); 3803 return (NULL); 3804 } 3805 3806 if (format_choose(es, fmt, &all, &active, 0) != 0) { 3807 all = xstrdup(fmt); 3808 active = NULL; 3809 } 3810 3811 value = xcalloc(1, 1); 3812 valuelen = 1; 3813 3814 RB_FOREACH(wl, winlinks, &ft->s->windows) { 3815 w = wl->window; 3816 format_log(es, "window loop: %u @%u", wl->idx, w->id); 3817 if (active != NULL && wl == ft->s->curw) 3818 use = active; 3819 else 3820 use = all; 3821 nft = format_create(c, item, FORMAT_WINDOW|w->id, ft->flags); 3822 format_defaults(nft, ft->c, ft->s, wl, NULL); 3823 format_copy_state(&next, es, 0); 3824 next.ft = nft; 3825 expanded = format_expand1(&next, use); 3826 format_free(nft); 3827 3828 valuelen += strlen(expanded); 3829 value = xrealloc(value, valuelen); 3830 3831 strlcat(value, expanded, valuelen); 3832 free(expanded); 3833 } 3834 3835 free(active); 3836 free(all); 3837 3838 return (value); 3839 } 3840 3841 /* Loop over panes. */ 3842 static char * 3843 format_loop_panes(struct format_expand_state *es, const char *fmt) 3844 { 3845 struct format_tree *ft = es->ft; 3846 struct client *c = ft->client; 3847 struct cmdq_item *item = ft->item; 3848 struct format_tree *nft; 3849 struct format_expand_state next; 3850 char *all, *active, *use, *expanded, *value; 3851 size_t valuelen; 3852 struct window_pane *wp; 3853 3854 if (ft->w == NULL) { 3855 format_log(es, "pane loop but no window"); 3856 return (NULL); 3857 } 3858 3859 if (format_choose(es, fmt, &all, &active, 0) != 0) { 3860 all = xstrdup(fmt); 3861 active = NULL; 3862 } 3863 3864 value = xcalloc(1, 1); 3865 valuelen = 1; 3866 3867 TAILQ_FOREACH(wp, &ft->w->panes, entry) { 3868 format_log(es, "pane loop: %%%u", wp->id); 3869 if (active != NULL && wp == ft->w->active) 3870 use = active; 3871 else 3872 use = all; 3873 nft = format_create(c, item, FORMAT_PANE|wp->id, ft->flags); 3874 format_defaults(nft, ft->c, ft->s, ft->wl, wp); 3875 format_copy_state(&next, es, 0); 3876 next.ft = nft; 3877 expanded = format_expand1(&next, use); 3878 format_free(nft); 3879 3880 valuelen += strlen(expanded); 3881 value = xrealloc(value, valuelen); 3882 3883 strlcat(value, expanded, valuelen); 3884 free(expanded); 3885 } 3886 3887 free(active); 3888 free(all); 3889 3890 return (value); 3891 } 3892 3893 static char * 3894 format_replace_expression(struct format_modifier *mexp, 3895 struct format_expand_state *es, const char *copy) 3896 { 3897 int argc = mexp->argc; 3898 const char *errstr; 3899 char *endch, *value, *left = NULL, *right = NULL; 3900 int use_fp = 0; 3901 u_int prec = 0; 3902 double mleft, mright, result; 3903 enum { ADD, 3904 SUBTRACT, 3905 MULTIPLY, 3906 DIVIDE, 3907 MODULUS, 3908 EQUAL, 3909 NOT_EQUAL, 3910 GREATER_THAN, 3911 GREATER_THAN_EQUAL, 3912 LESS_THAN, 3913 LESS_THAN_EQUAL } operator; 3914 3915 if (strcmp(mexp->argv[0], "+") == 0) 3916 operator = ADD; 3917 else if (strcmp(mexp->argv[0], "-") == 0) 3918 operator = SUBTRACT; 3919 else if (strcmp(mexp->argv[0], "*") == 0) 3920 operator = MULTIPLY; 3921 else if (strcmp(mexp->argv[0], "/") == 0) 3922 operator = DIVIDE; 3923 else if (strcmp(mexp->argv[0], "%") == 0 || 3924 strcmp(mexp->argv[0], "m") == 0) 3925 operator = MODULUS; 3926 else if (strcmp(mexp->argv[0], "==") == 0) 3927 operator = EQUAL; 3928 else if (strcmp(mexp->argv[0], "!=") == 0) 3929 operator = NOT_EQUAL; 3930 else if (strcmp(mexp->argv[0], ">") == 0) 3931 operator = GREATER_THAN; 3932 else if (strcmp(mexp->argv[0], "<") == 0) 3933 operator = LESS_THAN; 3934 else if (strcmp(mexp->argv[0], ">=") == 0) 3935 operator = GREATER_THAN_EQUAL; 3936 else if (strcmp(mexp->argv[0], "<=") == 0) 3937 operator = LESS_THAN_EQUAL; 3938 else { 3939 format_log(es, "expression has no valid operator: '%s'", 3940 mexp->argv[0]); 3941 goto fail; 3942 } 3943 3944 /* The second argument may be flags. */ 3945 if (argc >= 2 && strchr(mexp->argv[1], 'f') != NULL) { 3946 use_fp = 1; 3947 prec = 2; 3948 } 3949 3950 /* The third argument may be precision. */ 3951 if (argc >= 3) { 3952 prec = strtonum(mexp->argv[2], INT_MIN, INT_MAX, &errstr); 3953 if (errstr != NULL) { 3954 format_log(es, "expression precision %s: %s", errstr, 3955 mexp->argv[2]); 3956 goto fail; 3957 } 3958 } 3959 3960 if (format_choose(es, copy, &left, &right, 1) != 0) { 3961 format_log(es, "expression syntax error"); 3962 goto fail; 3963 } 3964 3965 mleft = strtod(left, &endch); 3966 if (*endch != '\0') { 3967 format_log(es, "expression left side is invalid: %s", left); 3968 goto fail; 3969 } 3970 3971 mright = strtod(right, &endch); 3972 if (*endch != '\0') { 3973 format_log(es, "expression right side is invalid: %s", right); 3974 goto fail; 3975 } 3976 3977 if (!use_fp) { 3978 mleft = (long long)mleft; 3979 mright = (long long)mright; 3980 } 3981 format_log(es, "expression left side is: %.*f", prec, mleft); 3982 format_log(es, "expression right side is: %.*f", prec, mright); 3983 3984 switch (operator) { 3985 case ADD: 3986 result = mleft + mright; 3987 break; 3988 case SUBTRACT: 3989 result = mleft - mright; 3990 break; 3991 case MULTIPLY: 3992 result = mleft * mright; 3993 break; 3994 case DIVIDE: 3995 result = mleft / mright; 3996 break; 3997 case MODULUS: 3998 result = fmod(mleft, mright); 3999 break; 4000 case EQUAL: 4001 result = fabs(mleft - mright) < 1e-9; 4002 break; 4003 case NOT_EQUAL: 4004 result = fabs(mleft - mright) > 1e-9; 4005 break; 4006 case GREATER_THAN: 4007 result = (mleft > mright); 4008 break; 4009 case GREATER_THAN_EQUAL: 4010 result = (mleft >= mright); 4011 break; 4012 case LESS_THAN: 4013 result = (mleft < mright); 4014 break; 4015 case LESS_THAN_EQUAL: 4016 result = (mleft <= mright); 4017 break; 4018 } 4019 if (use_fp) 4020 xasprintf(&value, "%.*f", prec, result); 4021 else 4022 xasprintf(&value, "%.*f", prec, (double)(long long)result); 4023 format_log(es, "expression result is %s", value); 4024 4025 free(right); 4026 free(left); 4027 return (value); 4028 4029 fail: 4030 free(right); 4031 free(left); 4032 return (NULL); 4033 } 4034 4035 /* Replace a key. */ 4036 static int 4037 format_replace(struct format_expand_state *es, const char *key, size_t keylen, 4038 char **buf, size_t *len, size_t *off) 4039 { 4040 struct format_tree *ft = es->ft; 4041 struct window_pane *wp = ft->wp; 4042 const char *errstr, *copy, *cp, *marker = NULL; 4043 const char *time_format = NULL; 4044 char *copy0, *condition, *found, *new; 4045 char *value, *left, *right, c; 4046 size_t valuelen; 4047 int modifiers = 0, limit = 0, width = 0; 4048 int j; 4049 struct format_modifier *list, *cmp = NULL, *search = NULL; 4050 struct format_modifier **sub = NULL, *mexp = NULL, *fm; 4051 u_int i, count, nsub = 0; 4052 struct format_expand_state next; 4053 4054 /* Make a copy of the key. */ 4055 copy = copy0 = xstrndup(key, keylen); 4056 4057 /* Process modifier list. */ 4058 list = format_build_modifiers(es, ©, &count); 4059 for (i = 0; i < count; i++) { 4060 fm = &list[i]; 4061 if (format_logging(ft)) { 4062 format_log(es, "modifier %u is %s", i, fm->modifier); 4063 for (j = 0; j < fm->argc; j++) { 4064 format_log(es, "modifier %u argument %d: %s", i, 4065 j, fm->argv[j]); 4066 } 4067 } 4068 if (fm->size == 1) { 4069 switch (fm->modifier[0]) { 4070 case 'm': 4071 case '<': 4072 case '>': 4073 cmp = fm; 4074 break; 4075 case 'C': 4076 search = fm; 4077 break; 4078 case 's': 4079 if (fm->argc < 2) 4080 break; 4081 sub = xreallocarray(sub, nsub + 1, sizeof *sub); 4082 sub[nsub++] = fm; 4083 break; 4084 case '=': 4085 if (fm->argc < 1) 4086 break; 4087 limit = strtonum(fm->argv[0], INT_MIN, INT_MAX, 4088 &errstr); 4089 if (errstr != NULL) 4090 limit = 0; 4091 if (fm->argc >= 2 && fm->argv[1] != NULL) 4092 marker = fm->argv[1]; 4093 break; 4094 case 'p': 4095 if (fm->argc < 1) 4096 break; 4097 width = strtonum(fm->argv[0], INT_MIN, INT_MAX, 4098 &errstr); 4099 if (errstr != NULL) 4100 width = 0; 4101 break; 4102 case 'w': 4103 modifiers |= FORMAT_WIDTH; 4104 break; 4105 case 'e': 4106 if (fm->argc < 1 || fm->argc > 3) 4107 break; 4108 mexp = fm; 4109 break; 4110 case 'l': 4111 modifiers |= FORMAT_LITERAL; 4112 break; 4113 case 'a': 4114 modifiers |= FORMAT_CHARACTER; 4115 break; 4116 case 'b': 4117 modifiers |= FORMAT_BASENAME; 4118 break; 4119 case 'd': 4120 modifiers |= FORMAT_DIRNAME; 4121 break; 4122 case 'n': 4123 modifiers |= FORMAT_LENGTH; 4124 break; 4125 case 't': 4126 modifiers |= FORMAT_TIMESTRING; 4127 if (fm->argc < 1) 4128 break; 4129 if (strchr(fm->argv[0], 'p') != NULL) 4130 modifiers |= FORMAT_PRETTY; 4131 else if (fm->argc >= 2 && 4132 strchr(fm->argv[0], 'f') != NULL) 4133 time_format = format_strip(fm->argv[1]); 4134 break; 4135 case 'q': 4136 if (fm->argc < 1) 4137 modifiers |= FORMAT_QUOTE_SHELL; 4138 else if (strchr(fm->argv[0], 'e') != NULL || 4139 strchr(fm->argv[0], 'h') != NULL) 4140 modifiers |= FORMAT_QUOTE_STYLE; 4141 break; 4142 case 'E': 4143 modifiers |= FORMAT_EXPAND; 4144 break; 4145 case 'T': 4146 modifiers |= FORMAT_EXPANDTIME; 4147 break; 4148 case 'N': 4149 if (fm->argc < 1 || 4150 strchr(fm->argv[0], 'w') != NULL) 4151 modifiers |= FORMAT_WINDOW_NAME; 4152 else if (strchr(fm->argv[0], 's') != NULL) 4153 modifiers |= FORMAT_SESSION_NAME; 4154 break; 4155 case 'S': 4156 modifiers |= FORMAT_SESSIONS; 4157 break; 4158 case 'W': 4159 modifiers |= FORMAT_WINDOWS; 4160 break; 4161 case 'P': 4162 modifiers |= FORMAT_PANES; 4163 break; 4164 } 4165 } else if (fm->size == 2) { 4166 if (strcmp(fm->modifier, "||") == 0 || 4167 strcmp(fm->modifier, "&&") == 0 || 4168 strcmp(fm->modifier, "==") == 0 || 4169 strcmp(fm->modifier, "!=") == 0 || 4170 strcmp(fm->modifier, ">=") == 0 || 4171 strcmp(fm->modifier, "<=") == 0) 4172 cmp = fm; 4173 } 4174 } 4175 4176 /* Is this a literal string? */ 4177 if (modifiers & FORMAT_LITERAL) { 4178 value = xstrdup(copy); 4179 goto done; 4180 } 4181 4182 /* Is this a character? */ 4183 if (modifiers & FORMAT_CHARACTER) { 4184 new = format_expand1(es, copy); 4185 c = strtonum(new, 32, 126, &errstr); 4186 if (errstr != NULL) 4187 value = xstrdup(""); 4188 else 4189 xasprintf(&value, "%c", c); 4190 free(new); 4191 goto done; 4192 } 4193 4194 /* Is this a loop, comparison or condition? */ 4195 if (modifiers & FORMAT_SESSIONS) { 4196 value = format_loop_sessions(es, copy); 4197 if (value == NULL) 4198 goto fail; 4199 } else if (modifiers & FORMAT_WINDOWS) { 4200 value = format_loop_windows(es, copy); 4201 if (value == NULL) 4202 goto fail; 4203 } else if (modifiers & FORMAT_PANES) { 4204 value = format_loop_panes(es, copy); 4205 if (value == NULL) 4206 goto fail; 4207 } else if (modifiers & FORMAT_WINDOW_NAME) { 4208 value = format_window_name(es, copy); 4209 if (value == NULL) 4210 goto fail; 4211 } else if (modifiers & FORMAT_SESSION_NAME) { 4212 value = format_session_name(es, copy); 4213 if (value == NULL) 4214 goto fail; 4215 } else if (search != NULL) { 4216 /* Search in pane. */ 4217 new = format_expand1(es, copy); 4218 if (wp == NULL) { 4219 format_log(es, "search '%s' but no pane", new); 4220 value = xstrdup("0"); 4221 } else { 4222 format_log(es, "search '%s' pane %%%u", new, wp->id); 4223 value = format_search(search, wp, new); 4224 } 4225 free(new); 4226 } else if (cmp != NULL) { 4227 /* Comparison of left and right. */ 4228 if (format_choose(es, copy, &left, &right, 1) != 0) { 4229 format_log(es, "compare %s syntax error: %s", 4230 cmp->modifier, copy); 4231 goto fail; 4232 } 4233 format_log(es, "compare %s left is: %s", cmp->modifier, left); 4234 format_log(es, "compare %s right is: %s", cmp->modifier, right); 4235 4236 if (strcmp(cmp->modifier, "||") == 0) { 4237 if (format_true(left) || format_true(right)) 4238 value = xstrdup("1"); 4239 else 4240 value = xstrdup("0"); 4241 } else if (strcmp(cmp->modifier, "&&") == 0) { 4242 if (format_true(left) && format_true(right)) 4243 value = xstrdup("1"); 4244 else 4245 value = xstrdup("0"); 4246 } else if (strcmp(cmp->modifier, "==") == 0) { 4247 if (strcmp(left, right) == 0) 4248 value = xstrdup("1"); 4249 else 4250 value = xstrdup("0"); 4251 } else if (strcmp(cmp->modifier, "!=") == 0) { 4252 if (strcmp(left, right) != 0) 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, "m") == 0) 4277 value = format_match(cmp, left, right); 4278 4279 free(right); 4280 free(left); 4281 } else if (*copy == '?') { 4282 /* Conditional: check first and choose second or third. */ 4283 cp = format_skip(copy + 1, ","); 4284 if (cp == NULL) { 4285 format_log(es, "condition syntax error: %s", copy + 1); 4286 goto fail; 4287 } 4288 condition = xstrndup(copy + 1, cp - (copy + 1)); 4289 format_log(es, "condition is: %s", condition); 4290 4291 found = format_find(ft, condition, modifiers, time_format); 4292 if (found == NULL) { 4293 /* 4294 * If the condition not found, try to expand it. If 4295 * the expansion doesn't have any effect, then assume 4296 * false. 4297 */ 4298 found = format_expand1(es, condition); 4299 if (strcmp(found, condition) == 0) { 4300 free(found); 4301 found = xstrdup(""); 4302 format_log(es, 4303 "condition '%s' not found; assuming false", 4304 condition); 4305 } 4306 } else { 4307 format_log(es, "condition '%s' found: %s", condition, 4308 found); 4309 } 4310 4311 if (format_choose(es, cp + 1, &left, &right, 0) != 0) { 4312 format_log(es, "condition '%s' syntax error: %s", 4313 condition, cp + 1); 4314 free(found); 4315 goto fail; 4316 } 4317 if (format_true(found)) { 4318 format_log(es, "condition '%s' is true", condition); 4319 value = format_expand1(es, left); 4320 } else { 4321 format_log(es, "condition '%s' is false", condition); 4322 value = format_expand1(es, right); 4323 } 4324 free(right); 4325 free(left); 4326 4327 free(condition); 4328 free(found); 4329 } else if (mexp != NULL) { 4330 value = format_replace_expression(mexp, es, copy); 4331 if (value == NULL) 4332 value = xstrdup(""); 4333 } else { 4334 if (strstr(copy, "#{") != 0) { 4335 format_log(es, "expanding inner format '%s'", copy); 4336 value = format_expand1(es, copy); 4337 } else { 4338 value = format_find(ft, copy, modifiers, time_format); 4339 if (value == NULL) { 4340 format_log(es, "format '%s' not found", copy); 4341 value = xstrdup(""); 4342 } else { 4343 format_log(es, "format '%s' found: %s", copy, 4344 value); 4345 } 4346 } 4347 } 4348 4349 done: 4350 /* Expand again if required. */ 4351 if (modifiers & FORMAT_EXPAND) { 4352 new = format_expand1(es, value); 4353 free(value); 4354 value = new; 4355 } else if (modifiers & FORMAT_EXPANDTIME) { 4356 format_copy_state(&next, es, FORMAT_EXPAND_TIME); 4357 new = format_expand1(&next, value); 4358 free(value); 4359 value = new; 4360 } 4361 4362 /* Perform substitution if any. */ 4363 for (i = 0; i < nsub; i++) { 4364 left = format_expand1(es, sub[i]->argv[0]); 4365 right = format_expand1(es, sub[i]->argv[1]); 4366 new = format_sub(sub[i], value, left, right); 4367 format_log(es, "substitute '%s' to '%s': %s", left, right, new); 4368 free(value); 4369 value = new; 4370 free(right); 4371 free(left); 4372 } 4373 4374 /* Truncate the value if needed. */ 4375 if (limit > 0) { 4376 new = format_trim_left(value, limit); 4377 if (marker != NULL && strcmp(new, value) != 0) { 4378 free(value); 4379 xasprintf(&value, "%s%s", new, marker); 4380 } else { 4381 free(value); 4382 value = new; 4383 } 4384 format_log(es, "applied length limit %d: %s", limit, value); 4385 } else if (limit < 0) { 4386 new = format_trim_right(value, -limit); 4387 if (marker != NULL && strcmp(new, value) != 0) { 4388 free(value); 4389 xasprintf(&value, "%s%s", marker, new); 4390 } else { 4391 free(value); 4392 value = new; 4393 } 4394 format_log(es, "applied length limit %d: %s", limit, value); 4395 } 4396 4397 /* Pad the value if needed. */ 4398 if (width > 0) { 4399 new = utf8_padcstr(value, width); 4400 free(value); 4401 value = new; 4402 format_log(es, "applied padding width %d: %s", width, value); 4403 } else if (width < 0) { 4404 new = utf8_rpadcstr(value, -width); 4405 free(value); 4406 value = new; 4407 format_log(es, "applied padding width %d: %s", width, value); 4408 } 4409 4410 /* Replace with the length or width if needed. */ 4411 if (modifiers & FORMAT_LENGTH) { 4412 xasprintf(&new, "%zu", strlen(value)); 4413 free(value); 4414 value = new; 4415 format_log(es, "replacing with length: %s", new); 4416 } 4417 if (modifiers & FORMAT_WIDTH) { 4418 xasprintf(&new, "%u", format_width(value)); 4419 free(value); 4420 value = new; 4421 format_log(es, "replacing with width: %s", new); 4422 } 4423 4424 /* Expand the buffer and copy in the value. */ 4425 valuelen = strlen(value); 4426 while (*len - *off < valuelen + 1) { 4427 *buf = xreallocarray(*buf, 2, *len); 4428 *len *= 2; 4429 } 4430 memcpy(*buf + *off, value, valuelen); 4431 *off += valuelen; 4432 4433 format_log(es, "replaced '%s' with '%s'", copy0, value); 4434 free(value); 4435 4436 free(sub); 4437 format_free_modifiers(list, count); 4438 free(copy0); 4439 return (0); 4440 4441 fail: 4442 format_log(es, "failed %s", copy0); 4443 4444 free(sub); 4445 format_free_modifiers(list, count); 4446 free(copy0); 4447 return (-1); 4448 } 4449 4450 /* Expand keys in a template. */ 4451 static char * 4452 format_expand1(struct format_expand_state *es, const char *fmt) 4453 { 4454 struct format_tree *ft = es->ft; 4455 char *buf, *out, *name; 4456 const char *ptr, *s; 4457 size_t off, len, n, outlen; 4458 int ch, brackets; 4459 char expanded[8192]; 4460 4461 if (fmt == NULL || *fmt == '\0') 4462 return (xstrdup("")); 4463 4464 if (es->loop == FORMAT_LOOP_LIMIT) { 4465 format_log(es, "reached loop limit (%u)", FORMAT_LOOP_LIMIT); 4466 return (xstrdup("")); 4467 } 4468 es->loop++; 4469 4470 format_log(es, "expanding format: %s", fmt); 4471 4472 if ((es->flags & FORMAT_EXPAND_TIME) && strchr(fmt, '%') != NULL) { 4473 if (es->time == 0) { 4474 es->time = time(NULL); 4475 localtime_r(&es->time, &es->tm); 4476 } 4477 if (strftime(expanded, sizeof expanded, fmt, &es->tm) == 0) { 4478 format_log(es, "format is too long"); 4479 return (xstrdup("")); 4480 } 4481 if (format_logging(ft) && strcmp(expanded, fmt) != 0) 4482 format_log(es, "after time expanded: %s", expanded); 4483 fmt = expanded; 4484 } 4485 4486 len = 64; 4487 buf = xmalloc(len); 4488 off = 0; 4489 4490 while (*fmt != '\0') { 4491 if (*fmt != '#') { 4492 while (len - off < 2) { 4493 buf = xreallocarray(buf, 2, len); 4494 len *= 2; 4495 } 4496 buf[off++] = *fmt++; 4497 continue; 4498 } 4499 fmt++; 4500 4501 ch = (u_char)*fmt++; 4502 switch (ch) { 4503 case '(': 4504 brackets = 1; 4505 for (ptr = fmt; *ptr != '\0'; ptr++) { 4506 if (*ptr == '(') 4507 brackets++; 4508 if (*ptr == ')' && --brackets == 0) 4509 break; 4510 } 4511 if (*ptr != ')' || brackets != 0) 4512 break; 4513 n = ptr - fmt; 4514 4515 name = xstrndup(fmt, n); 4516 format_log(es, "found #(): %s", name); 4517 4518 if ((ft->flags & FORMAT_NOJOBS) || 4519 (es->flags & FORMAT_EXPAND_NOJOBS)) { 4520 out = xstrdup(""); 4521 format_log(es, "#() is disabled"); 4522 } else { 4523 out = format_job_get(es, name); 4524 format_log(es, "#() result: %s", out); 4525 } 4526 free(name); 4527 4528 outlen = strlen(out); 4529 while (len - off < outlen + 1) { 4530 buf = xreallocarray(buf, 2, len); 4531 len *= 2; 4532 } 4533 memcpy(buf + off, out, outlen); 4534 off += outlen; 4535 4536 free(out); 4537 4538 fmt += n + 1; 4539 continue; 4540 case '{': 4541 ptr = format_skip((char *)fmt - 2, "}"); 4542 if (ptr == NULL) 4543 break; 4544 n = ptr - fmt; 4545 4546 format_log(es, "found #{}: %.*s", (int)n, fmt); 4547 if (format_replace(es, fmt, n, &buf, &len, &off) != 0) 4548 break; 4549 fmt += n + 1; 4550 continue; 4551 case '#': 4552 /* 4553 * If ##[ (with two or more #s), then it is a style and 4554 * can be left for format_draw to handle. 4555 */ 4556 ptr = fmt; 4557 n = 2; 4558 while (*ptr == '#') { 4559 ptr++; 4560 n++; 4561 } 4562 if (*ptr == '[') { 4563 format_log(es, "found #*%zu[", n); 4564 while (len - off < n + 2) { 4565 buf = xreallocarray(buf, 2, len); 4566 len *= 2; 4567 } 4568 memcpy(buf + off, fmt - 2, n + 1); 4569 off += n + 1; 4570 fmt = ptr + 1; 4571 continue; 4572 } 4573 /* FALLTHROUGH */ 4574 case '}': 4575 case ',': 4576 format_log(es, "found #%c", ch); 4577 while (len - off < 2) { 4578 buf = xreallocarray(buf, 2, len); 4579 len *= 2; 4580 } 4581 buf[off++] = ch; 4582 continue; 4583 default: 4584 s = NULL; 4585 if (ch >= 'A' && ch <= 'Z') 4586 s = format_upper[ch - 'A']; 4587 else if (ch >= 'a' && ch <= 'z') 4588 s = format_lower[ch - 'a']; 4589 if (s == NULL) { 4590 while (len - off < 3) { 4591 buf = xreallocarray(buf, 2, len); 4592 len *= 2; 4593 } 4594 buf[off++] = '#'; 4595 buf[off++] = ch; 4596 continue; 4597 } 4598 n = strlen(s); 4599 format_log(es, "found #%c: %s", ch, s); 4600 if (format_replace(es, s, n, &buf, &len, &off) != 0) 4601 break; 4602 continue; 4603 } 4604 4605 break; 4606 } 4607 buf[off] = '\0'; 4608 4609 format_log(es, "result is: %s", buf); 4610 es->loop--; 4611 4612 return (buf); 4613 } 4614 4615 /* Expand keys in a template, passing through strftime first. */ 4616 char * 4617 format_expand_time(struct format_tree *ft, const char *fmt) 4618 { 4619 struct format_expand_state es; 4620 4621 memset(&es, 0, sizeof es); 4622 es.ft = ft; 4623 es.flags = FORMAT_EXPAND_TIME; 4624 return (format_expand1(&es, fmt)); 4625 } 4626 4627 /* Expand keys in a template. */ 4628 char * 4629 format_expand(struct format_tree *ft, const char *fmt) 4630 { 4631 struct format_expand_state es; 4632 4633 memset(&es, 0, sizeof es); 4634 es.ft = ft; 4635 es.flags = 0; 4636 return (format_expand1(&es, fmt)); 4637 } 4638 4639 /* Expand a single string. */ 4640 char * 4641 format_single(struct cmdq_item *item, const char *fmt, struct client *c, 4642 struct session *s, struct winlink *wl, struct window_pane *wp) 4643 { 4644 struct format_tree *ft; 4645 char *expanded; 4646 4647 ft = format_create_defaults(item, c, s, wl, wp); 4648 expanded = format_expand(ft, fmt); 4649 format_free(ft); 4650 return (expanded); 4651 } 4652 4653 /* Expand a single string using state. */ 4654 char * 4655 format_single_from_state(struct cmdq_item *item, const char *fmt, 4656 struct client *c, struct cmd_find_state *fs) 4657 { 4658 return (format_single(item, fmt, c, fs->s, fs->wl, fs->wp)); 4659 } 4660 4661 /* Expand a single string using target. */ 4662 char * 4663 format_single_from_target(struct cmdq_item *item, const char *fmt) 4664 { 4665 struct client *tc = cmdq_get_target_client(item); 4666 4667 return (format_single_from_state(item, fmt, tc, cmdq_get_target(item))); 4668 } 4669 4670 /* Create and add defaults. */ 4671 struct format_tree * 4672 format_create_defaults(struct cmdq_item *item, struct client *c, 4673 struct session *s, struct winlink *wl, struct window_pane *wp) 4674 { 4675 struct format_tree *ft; 4676 4677 if (item != NULL) 4678 ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0); 4679 else 4680 ft = format_create(NULL, item, FORMAT_NONE, 0); 4681 format_defaults(ft, c, s, wl, wp); 4682 return (ft); 4683 } 4684 4685 /* Create and add defaults using state. */ 4686 struct format_tree * 4687 format_create_from_state(struct cmdq_item *item, struct client *c, 4688 struct cmd_find_state *fs) 4689 { 4690 return (format_create_defaults(item, c, fs->s, fs->wl, fs->wp)); 4691 } 4692 4693 /* Create and add defaults using target. */ 4694 struct format_tree * 4695 format_create_from_target(struct cmdq_item *item) 4696 { 4697 struct client *tc = cmdq_get_target_client(item); 4698 4699 return (format_create_from_state(item, tc, cmdq_get_target(item))); 4700 } 4701 4702 /* Set defaults for any of arguments that are not NULL. */ 4703 void 4704 format_defaults(struct format_tree *ft, struct client *c, struct session *s, 4705 struct winlink *wl, struct window_pane *wp) 4706 { 4707 struct paste_buffer *pb; 4708 4709 if (c != NULL && c->name != NULL) 4710 log_debug("%s: c=%s", __func__, c->name); 4711 else 4712 log_debug("%s: c=none", __func__); 4713 if (s != NULL) 4714 log_debug("%s: s=$%u", __func__, s->id); 4715 else 4716 log_debug("%s: s=none", __func__); 4717 if (wl != NULL) 4718 log_debug("%s: wl=%u", __func__, wl->idx); 4719 else 4720 log_debug("%s: wl=none", __func__); 4721 if (wp != NULL) 4722 log_debug("%s: wp=%%%u", __func__, wp->id); 4723 else 4724 log_debug("%s: wp=none", __func__); 4725 4726 if (c != NULL && s != NULL && c->session != s) 4727 log_debug("%s: session does not match", __func__); 4728 4729 if (wp != NULL) 4730 ft->type = FORMAT_TYPE_PANE; 4731 else if (wl != NULL) 4732 ft->type = FORMAT_TYPE_WINDOW; 4733 else if (s != NULL) 4734 ft->type = FORMAT_TYPE_SESSION; 4735 else 4736 ft->type = FORMAT_TYPE_UNKNOWN; 4737 4738 if (s == NULL && c != NULL) 4739 s = c->session; 4740 if (wl == NULL && s != NULL) 4741 wl = s->curw; 4742 if (wp == NULL && wl != NULL) 4743 wp = wl->window->active; 4744 4745 if (c != NULL) 4746 format_defaults_client(ft, c); 4747 if (s != NULL) 4748 format_defaults_session(ft, s); 4749 if (wl != NULL) 4750 format_defaults_winlink(ft, wl); 4751 if (wp != NULL) 4752 format_defaults_pane(ft, wp); 4753 4754 pb = paste_get_top(NULL); 4755 if (pb != NULL) 4756 format_defaults_paste_buffer(ft, pb); 4757 } 4758 4759 /* Set default format keys for a session. */ 4760 static void 4761 format_defaults_session(struct format_tree *ft, struct session *s) 4762 { 4763 ft->s = s; 4764 } 4765 4766 /* Set default format keys for a client. */ 4767 static void 4768 format_defaults_client(struct format_tree *ft, struct client *c) 4769 { 4770 if (ft->s == NULL) 4771 ft->s = c->session; 4772 ft->c = c; 4773 } 4774 4775 /* Set default format keys for a window. */ 4776 void 4777 format_defaults_window(struct format_tree *ft, struct window *w) 4778 { 4779 ft->w = w; 4780 } 4781 4782 /* Set default format keys for a winlink. */ 4783 static void 4784 format_defaults_winlink(struct format_tree *ft, struct winlink *wl) 4785 { 4786 if (ft->w == NULL) 4787 format_defaults_window(ft, wl->window); 4788 ft->wl = wl; 4789 } 4790 4791 /* Set default format keys for a window pane. */ 4792 void 4793 format_defaults_pane(struct format_tree *ft, struct window_pane *wp) 4794 { 4795 struct window_mode_entry *wme; 4796 4797 if (ft->w == NULL) 4798 format_defaults_window(ft, wp->window); 4799 ft->wp = wp; 4800 4801 wme = TAILQ_FIRST(&wp->modes); 4802 if (wme != NULL && wme->mode->formats != NULL) 4803 wme->mode->formats(wme, ft); 4804 } 4805 4806 /* Set default format keys for paste buffer. */ 4807 void 4808 format_defaults_paste_buffer(struct format_tree *ft, struct paste_buffer *pb) 4809 { 4810 ft->pb = pb; 4811 } 4812 4813 /* Return word at given coordinates. Caller frees. */ 4814 char * 4815 format_grid_word(struct grid *gd, u_int x, u_int y) 4816 { 4817 const struct grid_line *gl; 4818 struct grid_cell gc; 4819 const char *ws; 4820 struct utf8_data *ud = NULL; 4821 u_int end; 4822 size_t size = 0; 4823 int found = 0; 4824 char *s = NULL; 4825 4826 ws = options_get_string(global_s_options, "word-separators"); 4827 4828 for (;;) { 4829 grid_get_cell(gd, x, y, &gc); 4830 if (gc.flags & GRID_FLAG_PADDING) 4831 break; 4832 if (utf8_cstrhas(ws, &gc.data) || 4833 (gc.data.size == 1 && *gc.data.data == ' ')) { 4834 found = 1; 4835 break; 4836 } 4837 4838 if (x == 0) { 4839 if (y == 0) 4840 break; 4841 gl = grid_peek_line(gd, y - 1); 4842 if (~gl->flags & GRID_LINE_WRAPPED) 4843 break; 4844 y--; 4845 x = grid_line_length(gd, y); 4846 if (x == 0) 4847 break; 4848 } 4849 x--; 4850 } 4851 for (;;) { 4852 if (found) { 4853 end = grid_line_length(gd, y); 4854 if (end == 0 || x == end - 1) { 4855 if (y == gd->hsize + gd->sy - 1) 4856 break; 4857 gl = grid_peek_line(gd, y); 4858 if (~gl->flags & GRID_LINE_WRAPPED) 4859 break; 4860 y++; 4861 x = 0; 4862 } else 4863 x++; 4864 } 4865 found = 1; 4866 4867 grid_get_cell(gd, x, y, &gc); 4868 if (gc.flags & GRID_FLAG_PADDING) 4869 break; 4870 if (utf8_cstrhas(ws, &gc.data) || 4871 (gc.data.size == 1 && *gc.data.data == ' ')) 4872 break; 4873 4874 ud = xreallocarray(ud, size + 2, sizeof *ud); 4875 memcpy(&ud[size++], &gc.data, sizeof *ud); 4876 } 4877 if (size != 0) { 4878 ud[size].size = 0; 4879 s = utf8_tocstr(ud); 4880 free(ud); 4881 } 4882 return (s); 4883 } 4884 4885 /* Return line at given coordinates. Caller frees. */ 4886 char * 4887 format_grid_line(struct grid *gd, u_int y) 4888 { 4889 struct grid_cell gc; 4890 struct utf8_data *ud = NULL; 4891 u_int x; 4892 size_t size = 0; 4893 char *s = NULL; 4894 4895 for (x = 0; x < grid_line_length(gd, y); x++) { 4896 grid_get_cell(gd, x, y, &gc); 4897 if (gc.flags & GRID_FLAG_PADDING) 4898 break; 4899 4900 ud = xreallocarray(ud, size + 2, sizeof *ud); 4901 memcpy(&ud[size++], &gc.data, sizeof *ud); 4902 } 4903 if (size != 0) { 4904 ud[size].size = 0; 4905 s = utf8_tocstr(ud); 4906 free(ud); 4907 } 4908 return (s); 4909 } 4910