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