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