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