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