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