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