1 /* $OpenBSD: format.c,v 1.206 2019/06/20 11:59:59 nicm Exp $ */ 2 3 /* 4 * Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/wait.h> 21 22 #include <ctype.h> 23 #include <errno.h> 24 #include <fnmatch.h> 25 #include <libgen.h> 26 #include <regex.h> 27 #include <stdarg.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <time.h> 31 #include <unistd.h> 32 33 #include "tmux.h" 34 35 /* 36 * Build a list of key-value pairs and use them to expand #{key} entries in a 37 * string. 38 */ 39 40 struct format_entry; 41 typedef void (*format_cb)(struct format_tree *, struct format_entry *); 42 43 static char *format_job_get(struct format_tree *, const char *); 44 static void format_job_timer(int, short, void *); 45 46 static char *format_find(struct format_tree *, const char *, int); 47 static void format_add_cb(struct format_tree *, const char *, format_cb); 48 static void format_add_tv(struct format_tree *, const char *, 49 struct timeval *); 50 static int format_replace(struct format_tree *, const char *, size_t, 51 char **, size_t *, size_t *); 52 53 static void format_defaults_session(struct format_tree *, 54 struct session *); 55 static void format_defaults_client(struct format_tree *, struct client *); 56 static void format_defaults_winlink(struct format_tree *, struct winlink *); 57 58 /* Entry in format job tree. */ 59 struct format_job { 60 struct client *client; 61 u_int tag; 62 const char *cmd; 63 const char *expanded; 64 65 time_t last; 66 char *out; 67 int updated; 68 69 struct job *job; 70 int status; 71 72 RB_ENTRY(format_job) entry; 73 }; 74 75 /* Format job tree. */ 76 static struct event format_job_event; 77 static int format_job_cmp(struct format_job *, struct format_job *); 78 static RB_HEAD(format_job_tree, format_job) format_jobs = RB_INITIALIZER(); 79 RB_GENERATE_STATIC(format_job_tree, format_job, entry, format_job_cmp); 80 81 /* Format job tree comparison function. */ 82 static int 83 format_job_cmp(struct format_job *fj1, struct format_job *fj2) 84 { 85 if (fj1->tag < fj2->tag) 86 return (-1); 87 if (fj1->tag > fj2->tag) 88 return (1); 89 return (strcmp(fj1->cmd, fj2->cmd)); 90 } 91 92 /* Format modifiers. */ 93 #define FORMAT_TIMESTRING 0x1 94 #define FORMAT_BASENAME 0x2 95 #define FORMAT_DIRNAME 0x4 96 #define FORMAT_QUOTE 0x8 97 #define FORMAT_LITERAL 0x10 98 #define FORMAT_EXPAND 0x20 99 #define FORMAT_EXPANDTIME 0x40 100 #define FORMAT_SESSIONS 0x80 101 #define FORMAT_WINDOWS 0x100 102 #define FORMAT_PANES 0x200 103 104 /* Limit on recursion. */ 105 #define FORMAT_LOOP_LIMIT 10 106 107 /* Entry in format tree. */ 108 struct format_entry { 109 char *key; 110 char *value; 111 time_t t; 112 format_cb cb; 113 RB_ENTRY(format_entry) entry; 114 }; 115 116 /* Format entry tree. */ 117 struct format_tree { 118 struct client *c; 119 struct session *s; 120 struct winlink *wl; 121 struct window *w; 122 struct window_pane *wp; 123 124 struct cmdq_item *item; 125 struct client *client; 126 u_int tag; 127 int flags; 128 time_t time; 129 u_int loop; 130 131 struct mouse_event m; 132 133 RB_HEAD(format_entry_tree, format_entry) tree; 134 }; 135 static int format_entry_cmp(struct format_entry *, struct format_entry *); 136 RB_GENERATE_STATIC(format_entry_tree, format_entry, entry, format_entry_cmp); 137 138 /* Format modifier. */ 139 struct format_modifier { 140 char modifier[3]; 141 u_int size; 142 143 char **argv; 144 int argc; 145 }; 146 147 /* Format entry tree comparison function. */ 148 static int 149 format_entry_cmp(struct format_entry *fe1, struct format_entry *fe2) 150 { 151 return (strcmp(fe1->key, fe2->key)); 152 } 153 154 /* Single-character uppercase aliases. */ 155 static const char *format_upper[] = { 156 NULL, /* A */ 157 NULL, /* B */ 158 NULL, /* C */ 159 "pane_id", /* D */ 160 NULL, /* E */ 161 "window_flags", /* F */ 162 NULL, /* G */ 163 "host", /* H */ 164 "window_index", /* I */ 165 NULL, /* J */ 166 NULL, /* K */ 167 NULL, /* L */ 168 NULL, /* M */ 169 NULL, /* N */ 170 NULL, /* O */ 171 "pane_index", /* P */ 172 NULL, /* Q */ 173 NULL, /* R */ 174 "session_name", /* S */ 175 "pane_title", /* T */ 176 NULL, /* U */ 177 NULL, /* V */ 178 "window_name", /* W */ 179 NULL, /* X */ 180 NULL, /* Y */ 181 NULL /* Z */ 182 }; 183 184 /* Single-character lowercase aliases. */ 185 static const char *format_lower[] = { 186 NULL, /* a */ 187 NULL, /* b */ 188 NULL, /* c */ 189 NULL, /* d */ 190 NULL, /* e */ 191 NULL, /* f */ 192 NULL, /* g */ 193 "host_short", /* h */ 194 NULL, /* i */ 195 NULL, /* j */ 196 NULL, /* k */ 197 NULL, /* l */ 198 NULL, /* m */ 199 NULL, /* n */ 200 NULL, /* o */ 201 NULL, /* p */ 202 NULL, /* q */ 203 NULL, /* r */ 204 NULL, /* s */ 205 NULL, /* t */ 206 NULL, /* u */ 207 NULL, /* v */ 208 NULL, /* w */ 209 NULL, /* x */ 210 NULL, /* y */ 211 NULL /* z */ 212 }; 213 214 /* Is logging enabled? */ 215 static inline int 216 format_logging(struct format_tree *ft) 217 { 218 return (log_get_level() != 0 || (ft->flags & FORMAT_VERBOSE)); 219 } 220 221 /* Log a message if verbose. */ 222 static void printflike(3, 4) 223 format_log1(struct format_tree *ft, const char *from, const char *fmt, ...) 224 { 225 va_list ap; 226 char *s; 227 static const char spaces[] = " "; 228 229 if (!format_logging(ft)) 230 return; 231 232 va_start(ap, fmt); 233 vasprintf(&s, fmt, ap); 234 va_end(ap); 235 236 log_debug("%s: %s", from, s); 237 if (ft->item != NULL && (ft->flags & FORMAT_VERBOSE)) 238 cmdq_print(ft->item, "#%.*s%s", ft->loop, spaces, s); 239 240 free(s); 241 } 242 #define format_log(ft, fmt, ...) format_log1(ft, __func__, fmt, ##__VA_ARGS__) 243 244 /* Format job update callback. */ 245 static void 246 format_job_update(struct job *job) 247 { 248 struct format_job *fj = job_get_data(job); 249 struct evbuffer *evb = job_get_event(job)->input; 250 char *line = NULL, *next; 251 time_t t; 252 253 while ((next = evbuffer_readline(evb)) != NULL) { 254 free(line); 255 line = next; 256 } 257 if (line == NULL) 258 return; 259 fj->updated = 1; 260 261 free(fj->out); 262 fj->out = line; 263 264 log_debug("%s: %p %s: %s", __func__, fj, fj->cmd, fj->out); 265 266 t = time(NULL); 267 if (fj->status && fj->last != t) { 268 if (fj->client != NULL) 269 server_status_client(fj->client); 270 fj->last = t; 271 } 272 } 273 274 /* Format job complete callback. */ 275 static void 276 format_job_complete(struct job *job) 277 { 278 struct format_job *fj = job_get_data(job); 279 struct evbuffer *evb = job_get_event(job)->input; 280 char *line, *buf; 281 size_t len; 282 283 fj->job = NULL; 284 285 buf = NULL; 286 if ((line = evbuffer_readline(evb)) == NULL) { 287 len = EVBUFFER_LENGTH(evb); 288 buf = xmalloc(len + 1); 289 if (len != 0) 290 memcpy(buf, EVBUFFER_DATA(evb), len); 291 buf[len] = '\0'; 292 } else 293 buf = line; 294 295 log_debug("%s: %p %s: %s", __func__, fj, fj->cmd, buf); 296 297 if (*buf != '\0' || !fj->updated) { 298 free(fj->out); 299 fj->out = buf; 300 } else 301 free(buf); 302 303 if (fj->status) { 304 if (fj->client != NULL) 305 server_status_client(fj->client); 306 fj->status = 0; 307 } 308 } 309 310 /* Find a job. */ 311 static char * 312 format_job_get(struct format_tree *ft, const char *cmd) 313 { 314 struct format_job_tree *jobs; 315 struct format_job fj0, *fj; 316 time_t t; 317 char *expanded; 318 int force; 319 320 if (ft->client == NULL) 321 jobs = &format_jobs; 322 else if (ft->client->jobs != NULL) 323 jobs = ft->client->jobs; 324 else { 325 jobs = ft->client->jobs = xmalloc(sizeof *ft->client->jobs); 326 RB_INIT(jobs); 327 } 328 329 fj0.tag = ft->tag; 330 fj0.cmd = cmd; 331 if ((fj = RB_FIND(format_job_tree, jobs, &fj0)) == NULL) { 332 fj = xcalloc(1, sizeof *fj); 333 fj->client = ft->client; 334 fj->tag = ft->tag; 335 fj->cmd = xstrdup(cmd); 336 fj->expanded = NULL; 337 338 xasprintf(&fj->out, "<'%s' not ready>", fj->cmd); 339 340 RB_INSERT(format_job_tree, jobs, fj); 341 } 342 343 expanded = format_expand(ft, cmd); 344 if (fj->expanded == NULL || strcmp(expanded, fj->expanded) != 0) { 345 free((void *)fj->expanded); 346 fj->expanded = xstrdup(expanded); 347 force = 1; 348 } else 349 force = (ft->flags & FORMAT_FORCE); 350 351 t = time(NULL); 352 if (force && fj->job != NULL) 353 job_free(fj->job); 354 if (force || (fj->job == NULL && fj->last != t)) { 355 fj->job = job_run(expanded, NULL, 356 server_client_get_cwd(ft->client, NULL), format_job_update, 357 format_job_complete, NULL, fj, JOB_NOWAIT); 358 if (fj->job == NULL) { 359 free(fj->out); 360 xasprintf(&fj->out, "<'%s' didn't start>", fj->cmd); 361 } 362 fj->last = t; 363 fj->updated = 0; 364 } 365 366 if (ft->flags & FORMAT_STATUS) 367 fj->status = 1; 368 369 free(expanded); 370 return (format_expand(ft, fj->out)); 371 } 372 373 /* Remove old jobs. */ 374 static void 375 format_job_tidy(struct format_job_tree *jobs, int force) 376 { 377 struct format_job *fj, *fj1; 378 time_t now; 379 380 now = time(NULL); 381 RB_FOREACH_SAFE(fj, format_job_tree, jobs, fj1) { 382 if (!force && (fj->last > now || now - fj->last < 3600)) 383 continue; 384 RB_REMOVE(format_job_tree, jobs, fj); 385 386 log_debug("%s: %s", __func__, fj->cmd); 387 388 if (fj->job != NULL) 389 job_free(fj->job); 390 391 free((void *)fj->expanded); 392 free((void *)fj->cmd); 393 free(fj->out); 394 395 free(fj); 396 } 397 } 398 399 /* Remove old jobs for client. */ 400 void 401 format_lost_client(struct client *c) 402 { 403 if (c->jobs != NULL) 404 format_job_tidy(c->jobs, 1); 405 free(c->jobs); 406 } 407 408 /* Remove old jobs periodically. */ 409 static void 410 format_job_timer(__unused int fd, __unused short events, __unused void *arg) 411 { 412 struct client *c; 413 struct timeval tv = { .tv_sec = 60 }; 414 415 format_job_tidy(&format_jobs, 0); 416 TAILQ_FOREACH(c, &clients, entry) { 417 if (c->jobs != NULL) 418 format_job_tidy(c->jobs, 0); 419 } 420 421 evtimer_del(&format_job_event); 422 evtimer_add(&format_job_event, &tv); 423 } 424 425 /* Callback for host. */ 426 static void 427 format_cb_host(__unused struct format_tree *ft, struct format_entry *fe) 428 { 429 char host[HOST_NAME_MAX + 1]; 430 431 if (gethostname(host, sizeof host) != 0) 432 fe->value = xstrdup(""); 433 else 434 fe->value = xstrdup(host); 435 } 436 437 /* Callback for host_short. */ 438 static void 439 format_cb_host_short(__unused struct format_tree *ft, struct format_entry *fe) 440 { 441 char host[HOST_NAME_MAX + 1], *cp; 442 443 if (gethostname(host, sizeof host) != 0) 444 fe->value = xstrdup(""); 445 else { 446 if ((cp = strchr(host, '.')) != NULL) 447 *cp = '\0'; 448 fe->value = xstrdup(host); 449 } 450 } 451 452 /* Callback for pid. */ 453 static void 454 format_cb_pid(__unused struct format_tree *ft, struct format_entry *fe) 455 { 456 xasprintf(&fe->value, "%ld", (long)getpid()); 457 } 458 459 /* Callback for session_alerts. */ 460 static void 461 format_cb_session_alerts(struct format_tree *ft, struct format_entry *fe) 462 { 463 struct session *s = ft->s; 464 struct winlink *wl; 465 char alerts[1024], tmp[16]; 466 467 if (s == NULL) 468 return; 469 470 *alerts = '\0'; 471 RB_FOREACH(wl, winlinks, &s->windows) { 472 if ((wl->flags & WINLINK_ALERTFLAGS) == 0) 473 continue; 474 xsnprintf(tmp, sizeof tmp, "%u", wl->idx); 475 476 if (*alerts != '\0') 477 strlcat(alerts, ",", sizeof alerts); 478 strlcat(alerts, tmp, sizeof alerts); 479 if (wl->flags & WINLINK_ACTIVITY) 480 strlcat(alerts, "#", sizeof alerts); 481 if (wl->flags & WINLINK_BELL) 482 strlcat(alerts, "!", sizeof alerts); 483 if (wl->flags & WINLINK_SILENCE) 484 strlcat(alerts, "~", sizeof alerts); 485 } 486 fe->value = xstrdup(alerts); 487 } 488 489 /* Callback for session_stack. */ 490 static void 491 format_cb_session_stack(struct format_tree *ft, struct format_entry *fe) 492 { 493 struct session *s = ft->s; 494 struct winlink *wl; 495 char result[1024], tmp[16]; 496 497 if (s == NULL) 498 return; 499 500 xsnprintf(result, sizeof result, "%u", s->curw->idx); 501 TAILQ_FOREACH(wl, &s->lastw, sentry) { 502 xsnprintf(tmp, sizeof tmp, "%u", wl->idx); 503 504 if (*result != '\0') 505 strlcat(result, ",", sizeof result); 506 strlcat(result, tmp, sizeof result); 507 } 508 fe->value = xstrdup(result); 509 } 510 511 /* Callback for window_stack_index. */ 512 static void 513 format_cb_window_stack_index(struct format_tree *ft, struct format_entry *fe) 514 { 515 struct session *s = ft->wl->session; 516 struct winlink *wl; 517 u_int idx; 518 519 idx = 0; 520 TAILQ_FOREACH(wl, &s->lastw, sentry) { 521 idx++; 522 if (wl == ft->wl) 523 break; 524 } 525 if (wl != NULL) 526 xasprintf(&fe->value, "%u", idx); 527 else 528 fe->value = xstrdup("0"); 529 } 530 531 /* Callback for window_layout. */ 532 static void 533 format_cb_window_layout(struct format_tree *ft, struct format_entry *fe) 534 { 535 struct window *w = ft->w; 536 537 if (w == NULL) 538 return; 539 540 if (w->saved_layout_root != NULL) 541 fe->value = layout_dump(w->saved_layout_root); 542 else 543 fe->value = layout_dump(w->layout_root); 544 } 545 546 /* Callback for window_visible_layout. */ 547 static void 548 format_cb_window_visible_layout(struct format_tree *ft, struct format_entry *fe) 549 { 550 struct window *w = ft->w; 551 552 if (w == NULL) 553 return; 554 555 fe->value = layout_dump(w->layout_root); 556 } 557 558 /* Callback for pane_start_command. */ 559 static void 560 format_cb_start_command(struct format_tree *ft, struct format_entry *fe) 561 { 562 struct window_pane *wp = ft->wp; 563 564 if (wp == NULL) 565 return; 566 567 fe->value = cmd_stringify_argv(wp->argc, wp->argv); 568 } 569 570 /* Callback for pane_current_command. */ 571 static void 572 format_cb_current_command(struct format_tree *ft, struct format_entry *fe) 573 { 574 struct window_pane *wp = ft->wp; 575 char *cmd; 576 577 if (wp == NULL) 578 return; 579 580 cmd = get_proc_name(wp->fd, wp->tty); 581 if (cmd == NULL || *cmd == '\0') { 582 free(cmd); 583 cmd = cmd_stringify_argv(wp->argc, wp->argv); 584 if (cmd == NULL || *cmd == '\0') { 585 free(cmd); 586 cmd = xstrdup(wp->shell); 587 } 588 } 589 fe->value = parse_window_name(cmd); 590 free(cmd); 591 } 592 593 /* Callback for history_bytes. */ 594 static void 595 format_cb_history_bytes(struct format_tree *ft, struct format_entry *fe) 596 { 597 struct window_pane *wp = ft->wp; 598 struct grid *gd; 599 struct grid_line *gl; 600 unsigned long long size; 601 u_int i; 602 603 if (wp == NULL) 604 return; 605 gd = wp->base.grid; 606 607 size = 0; 608 for (i = 0; i < gd->hsize; i++) { 609 gl = grid_get_line(gd, i); 610 size += gl->cellsize * sizeof *gl->celldata; 611 size += gl->extdsize * sizeof *gl->extddata; 612 } 613 size += gd->hsize * sizeof *gl; 614 615 xasprintf(&fe->value, "%llu", size); 616 } 617 618 /* Callback for pane_tabs. */ 619 static void 620 format_cb_pane_tabs(struct format_tree *ft, struct format_entry *fe) 621 { 622 struct window_pane *wp = ft->wp; 623 struct evbuffer *buffer; 624 u_int i; 625 int size; 626 627 if (wp == NULL) 628 return; 629 630 buffer = evbuffer_new(); 631 if (buffer == NULL) 632 fatalx("out of memory"); 633 for (i = 0; i < wp->base.grid->sx; i++) { 634 if (!bit_test(wp->base.tabs, i)) 635 continue; 636 637 if (EVBUFFER_LENGTH(buffer) > 0) 638 evbuffer_add(buffer, ",", 1); 639 evbuffer_add_printf(buffer, "%u", i); 640 } 641 if ((size = EVBUFFER_LENGTH(buffer)) != 0) 642 xasprintf(&fe->value, "%.*s", size, EVBUFFER_DATA(buffer)); 643 evbuffer_free(buffer); 644 } 645 646 /* Callback for session_group_list. */ 647 static void 648 format_cb_session_group_list(struct format_tree *ft, struct format_entry *fe) 649 { 650 struct session *s = ft->s; 651 struct session_group *sg; 652 struct session *loop; 653 struct evbuffer *buffer; 654 int size; 655 656 if (s == NULL) 657 return; 658 sg = session_group_contains(s); 659 if (sg == NULL) 660 return; 661 662 buffer = evbuffer_new(); 663 if (buffer == NULL) 664 fatalx("out of memory"); 665 TAILQ_FOREACH(loop, &sg->sessions, gentry) { 666 if (EVBUFFER_LENGTH(buffer) > 0) 667 evbuffer_add(buffer, ",", 1); 668 evbuffer_add_printf(buffer, "%s", loop->name); 669 } 670 if ((size = EVBUFFER_LENGTH(buffer)) != 0) 671 xasprintf(&fe->value, "%.*s", size, EVBUFFER_DATA(buffer)); 672 evbuffer_free(buffer); 673 } 674 675 /* Callback for pane_in_mode. */ 676 static void 677 format_cb_pane_in_mode(struct format_tree *ft, struct format_entry *fe) 678 { 679 struct window_pane *wp = ft->wp; 680 u_int n = 0; 681 struct window_mode_entry *wme; 682 683 if (wp == NULL) 684 return; 685 686 TAILQ_FOREACH(wme, &wp->modes, entry) 687 n++; 688 xasprintf(&fe->value, "%u", n); 689 } 690 691 /* Callback for cursor_character. */ 692 static void 693 format_cb_cursor_character(struct format_tree *ft, struct format_entry *fe) 694 { 695 struct window_pane *wp = ft->wp; 696 struct grid_cell gc; 697 698 if (wp == NULL) 699 return; 700 701 grid_view_get_cell(wp->base.grid, wp->base.cx, wp->base.cy, &gc); 702 if (~gc.flags & GRID_FLAG_PADDING) 703 xasprintf(&fe->value, "%.*s", (int)gc.data.size, gc.data.data); 704 } 705 706 /* Callback for mouse_word. */ 707 static void 708 format_cb_mouse_word(struct format_tree *ft, struct format_entry *fe) 709 { 710 struct window_pane *wp; 711 u_int x, y, end; 712 struct grid *gd; 713 struct grid_line *gl; 714 struct grid_cell gc; 715 const char *ws; 716 struct utf8_data *ud = NULL; 717 size_t size = 0; 718 int found = 0; 719 720 if (!ft->m.valid) 721 return; 722 wp = cmd_mouse_pane(&ft->m, NULL, NULL); 723 if (wp == NULL) 724 return; 725 if (cmd_mouse_at(wp, &ft->m, &x, &y, 0) != 0) 726 return; 727 gd = wp->base.grid; 728 ws = options_get_string(global_s_options, "word-separators"); 729 730 y = gd->hsize + y; 731 for (;;) { 732 grid_get_cell(gd, x, y, &gc); 733 if (gc.flags & GRID_FLAG_PADDING) 734 break; 735 if (utf8_cstrhas(ws, &gc.data)) { 736 found = 1; 737 break; 738 } 739 740 if (x == 0) { 741 if (y == 0) 742 break; 743 gl = &gd->linedata[y - 1]; 744 if (~gl->flags & GRID_LINE_WRAPPED) 745 break; 746 y--; 747 x = grid_line_length(gd, y); 748 if (x == 0) 749 break; 750 } 751 x--; 752 } 753 for (;;) { 754 if (found) { 755 end = grid_line_length(gd, y); 756 if (end == 0 || x == end - 1) { 757 if (y == gd->hsize + gd->sy - 1) 758 break; 759 gl = &gd->linedata[y]; 760 if (~gl->flags & GRID_LINE_WRAPPED) 761 break; 762 y++; 763 x = 0; 764 } else 765 x++; 766 } 767 found = 1; 768 769 grid_get_cell(gd, x, y, &gc); 770 if (gc.flags & GRID_FLAG_PADDING) 771 break; 772 if (utf8_cstrhas(ws, &gc.data)) 773 break; 774 775 ud = xreallocarray(ud, size + 2, sizeof *ud); 776 memcpy(&ud[size++], &gc.data, sizeof *ud); 777 } 778 if (size != 0) { 779 ud[size].size = 0; 780 fe->value = utf8_tocstr(ud); 781 free(ud); 782 } 783 } 784 785 /* Callback for mouse_line. */ 786 static void 787 format_cb_mouse_line(struct format_tree *ft, struct format_entry *fe) 788 { 789 struct window_pane *wp; 790 u_int x, y; 791 struct grid *gd; 792 struct grid_cell gc; 793 struct utf8_data *ud = NULL; 794 size_t size = 0; 795 796 if (!ft->m.valid) 797 return; 798 wp = cmd_mouse_pane(&ft->m, NULL, NULL); 799 if (wp == NULL) 800 return; 801 if (cmd_mouse_at(wp, &ft->m, &x, &y, 0) != 0) 802 return; 803 gd = wp->base.grid; 804 805 y = gd->hsize + y; 806 for (x = 0; x < grid_line_length(gd, y); x++) { 807 grid_get_cell(gd, x, y, &gc); 808 if (gc.flags & GRID_FLAG_PADDING) 809 break; 810 811 ud = xreallocarray(ud, size + 2, sizeof *ud); 812 memcpy(&ud[size++], &gc.data, sizeof *ud); 813 } 814 if (size != 0) { 815 ud[size].size = 0; 816 fe->value = utf8_tocstr(ud); 817 free(ud); 818 } 819 } 820 821 /* Merge a format tree. */ 822 static void 823 format_merge(struct format_tree *ft, struct format_tree *from) 824 { 825 struct format_entry *fe; 826 827 RB_FOREACH(fe, format_entry_tree, &from->tree) { 828 if (fe->value != NULL) 829 format_add(ft, fe->key, "%s", fe->value); 830 } 831 } 832 833 /* Add item bits to tree. */ 834 static void 835 format_create_add_item(struct format_tree *ft, struct cmdq_item *item) 836 { 837 struct mouse_event *m; 838 struct window_pane *wp; 839 u_int x, y; 840 841 if (item->cmd != NULL) 842 format_add(ft, "command", "%s", item->cmd->entry->name); 843 844 if (item->shared == NULL) 845 return; 846 if (item->shared->formats != NULL) 847 format_merge(ft, item->shared->formats); 848 849 m = &item->shared->mouse; 850 if (m->valid && ((wp = cmd_mouse_pane(m, NULL, NULL)) != NULL)) { 851 format_add(ft, "mouse_pane", "%%%u", wp->id); 852 if (cmd_mouse_at(wp, m, &x, &y, 0) == 0) { 853 format_add(ft, "mouse_x", "%u", x); 854 format_add(ft, "mouse_y", "%u", y); 855 format_add_cb(ft, "mouse_word", format_cb_mouse_word); 856 format_add_cb(ft, "mouse_line", format_cb_mouse_line); 857 } 858 } 859 memcpy(&ft->m, m, sizeof ft->m); 860 } 861 862 /* Create a new tree. */ 863 struct format_tree * 864 format_create(struct client *c, struct cmdq_item *item, int tag, int flags) 865 { 866 struct format_tree *ft; 867 const struct window_mode **wm; 868 char tmp[64]; 869 870 if (!event_initialized(&format_job_event)) { 871 evtimer_set(&format_job_event, format_job_timer, NULL); 872 format_job_timer(-1, 0, NULL); 873 } 874 875 ft = xcalloc(1, sizeof *ft); 876 RB_INIT(&ft->tree); 877 878 if (c != NULL) { 879 ft->client = c; 880 ft->client->references++; 881 } 882 ft->item = item; 883 884 ft->tag = tag; 885 ft->flags = flags; 886 ft->time = time(NULL); 887 888 format_add_cb(ft, "host", format_cb_host); 889 format_add_cb(ft, "host_short", format_cb_host_short); 890 format_add_cb(ft, "pid", format_cb_pid); 891 format_add(ft, "socket_path", "%s", socket_path); 892 format_add_tv(ft, "start_time", &start_time); 893 894 for (wm = all_window_modes; *wm != NULL; wm++) { 895 if ((*wm)->default_format != NULL) { 896 xsnprintf(tmp, sizeof tmp, "%s_format", (*wm)->name); 897 tmp[strcspn(tmp, "-")] = '_'; 898 format_add(ft, tmp, "%s", (*wm)->default_format); 899 } 900 } 901 902 if (item != NULL) 903 format_create_add_item(ft, item); 904 905 return (ft); 906 } 907 908 /* Free a tree. */ 909 void 910 format_free(struct format_tree *ft) 911 { 912 struct format_entry *fe, *fe1; 913 914 RB_FOREACH_SAFE(fe, format_entry_tree, &ft->tree, fe1) { 915 RB_REMOVE(format_entry_tree, &ft->tree, fe); 916 free(fe->value); 917 free(fe->key); 918 free(fe); 919 } 920 921 if (ft->client != NULL) 922 server_client_unref(ft->client); 923 free(ft); 924 } 925 926 /* Walk each format. */ 927 void 928 format_each(struct format_tree *ft, void (*cb)(const char *, const char *, 929 void *), void *arg) 930 { 931 struct format_entry *fe; 932 static char s[64]; 933 934 RB_FOREACH(fe, format_entry_tree, &ft->tree) { 935 if (fe->t != 0) { 936 xsnprintf(s, sizeof s, "%lld", (long long)fe->t); 937 cb(fe->key, fe->value, s); 938 } else { 939 if (fe->value == NULL && fe->cb != NULL) { 940 fe->cb(ft, fe); 941 if (fe->value == NULL) 942 fe->value = xstrdup(""); 943 } 944 cb(fe->key, fe->value, arg); 945 } 946 } 947 } 948 949 950 /* Add a key-value pair. */ 951 void 952 format_add(struct format_tree *ft, const char *key, const char *fmt, ...) 953 { 954 struct format_entry *fe; 955 struct format_entry *fe_now; 956 va_list ap; 957 958 fe = xmalloc(sizeof *fe); 959 fe->key = xstrdup(key); 960 961 fe_now = RB_INSERT(format_entry_tree, &ft->tree, fe); 962 if (fe_now != NULL) { 963 free(fe->key); 964 free(fe); 965 free(fe_now->value); 966 fe = fe_now; 967 } 968 969 fe->cb = NULL; 970 fe->t = 0; 971 972 va_start(ap, fmt); 973 xvasprintf(&fe->value, fmt, ap); 974 va_end(ap); 975 } 976 977 /* Add a key and time. */ 978 static void 979 format_add_tv(struct format_tree *ft, const char *key, struct timeval *tv) 980 { 981 struct format_entry *fe; 982 struct format_entry *fe_now; 983 984 fe = xmalloc(sizeof *fe); 985 fe->key = xstrdup(key); 986 987 fe_now = RB_INSERT(format_entry_tree, &ft->tree, fe); 988 if (fe_now != NULL) { 989 free(fe->key); 990 free(fe); 991 free(fe_now->value); 992 fe = fe_now; 993 } 994 995 fe->cb = NULL; 996 fe->t = tv->tv_sec; 997 998 fe->value = NULL; 999 } 1000 1001 /* Add a key and function. */ 1002 static void 1003 format_add_cb(struct format_tree *ft, const char *key, format_cb cb) 1004 { 1005 struct format_entry *fe; 1006 struct format_entry *fe_now; 1007 1008 fe = xmalloc(sizeof *fe); 1009 fe->key = xstrdup(key); 1010 1011 fe_now = RB_INSERT(format_entry_tree, &ft->tree, fe); 1012 if (fe_now != NULL) { 1013 free(fe->key); 1014 free(fe); 1015 free(fe_now->value); 1016 fe = fe_now; 1017 } 1018 1019 fe->cb = cb; 1020 fe->t = 0; 1021 1022 fe->value = NULL; 1023 } 1024 1025 /* Quote special characters in string. */ 1026 static char * 1027 format_quote(const char *s) 1028 { 1029 const char *cp; 1030 char *out, *at; 1031 1032 at = out = xmalloc(strlen(s) * 2 + 1); 1033 for (cp = s; *cp != '\0'; cp++) { 1034 if (strchr("|&;<>()$`\\\"'*?[# =%", *cp) != NULL) 1035 *at++ = '\\'; 1036 *at++ = *cp; 1037 } 1038 *at = '\0'; 1039 return (out); 1040 } 1041 1042 /* Find a format entry. */ 1043 static char * 1044 format_find(struct format_tree *ft, const char *key, int modifiers) 1045 { 1046 struct format_entry *fe, fe_find; 1047 struct environ_entry *envent; 1048 static char s[64]; 1049 struct options_entry *o; 1050 int idx; 1051 char *found, *saved; 1052 1053 if (~modifiers & FORMAT_TIMESTRING) { 1054 o = options_parse_get(global_options, key, &idx, 0); 1055 if (o == NULL && ft->wp != NULL) 1056 o = options_parse_get(ft->wp->options, key, &idx, 0); 1057 if (o == NULL && ft->w != NULL) 1058 o = options_parse_get(ft->w->options, key, &idx, 0); 1059 if (o == NULL) 1060 o = options_parse_get(global_w_options, key, &idx, 0); 1061 if (o == NULL && ft->s != NULL) 1062 o = options_parse_get(ft->s->options, key, &idx, 0); 1063 if (o == NULL) 1064 o = options_parse_get(global_s_options, key, &idx, 0); 1065 if (o != NULL) { 1066 found = options_tostring(o, idx, 1); 1067 goto found; 1068 } 1069 } 1070 found = NULL; 1071 1072 fe_find.key = (char *) key; 1073 fe = RB_FIND(format_entry_tree, &ft->tree, &fe_find); 1074 if (fe != NULL) { 1075 if (modifiers & FORMAT_TIMESTRING) { 1076 if (fe->t == 0) 1077 return (NULL); 1078 ctime_r(&fe->t, s); 1079 s[strcspn(s, "\n")] = '\0'; 1080 found = xstrdup(s); 1081 goto found; 1082 } 1083 if (fe->t != 0) { 1084 xasprintf(&found, "%lld", (long long)fe->t); 1085 goto found; 1086 } 1087 if (fe->value == NULL && fe->cb != NULL) { 1088 fe->cb(ft, fe); 1089 if (fe->value == NULL) 1090 fe->value = xstrdup(""); 1091 } 1092 found = xstrdup(fe->value); 1093 goto found; 1094 } 1095 1096 if (~modifiers & FORMAT_TIMESTRING) { 1097 envent = NULL; 1098 if (ft->s != NULL) 1099 envent = environ_find(ft->s->environ, key); 1100 if (envent == NULL) 1101 envent = environ_find(global_environ, key); 1102 if (envent != NULL && envent->value != NULL) { 1103 found = xstrdup(envent->value); 1104 goto found; 1105 } 1106 } 1107 1108 return (NULL); 1109 1110 found: 1111 if (found == NULL) 1112 return (NULL); 1113 if (modifiers & FORMAT_BASENAME) { 1114 saved = found; 1115 found = xstrdup(basename(saved)); 1116 free(saved); 1117 } 1118 if (modifiers & FORMAT_DIRNAME) { 1119 saved = found; 1120 found = xstrdup(dirname(saved)); 1121 free(saved); 1122 } 1123 if (modifiers & FORMAT_QUOTE) { 1124 saved = found; 1125 found = xstrdup(format_quote(saved)); 1126 free(saved); 1127 } 1128 return (found); 1129 } 1130 1131 /* Skip until end. */ 1132 const char * 1133 format_skip(const char *s, const char *end) 1134 { 1135 int brackets = 0; 1136 1137 for (; *s != '\0'; s++) { 1138 if (*s == '#' && s[1] == '{') 1139 brackets++; 1140 if (*s == '#' && strchr(",#{}", s[1]) != NULL) { 1141 s++; 1142 continue; 1143 } 1144 if (*s == '}') 1145 brackets--; 1146 if (strchr(end, *s) != NULL && brackets == 0) 1147 break; 1148 } 1149 if (*s == '\0') 1150 return (NULL); 1151 return (s); 1152 } 1153 1154 /* Return left and right alternatives separated by commas. */ 1155 static int 1156 format_choose(struct format_tree *ft, const char *s, char **left, char **right, 1157 int expand) 1158 { 1159 const char *cp; 1160 char *left0, *right0; 1161 1162 cp = format_skip(s, ","); 1163 if (cp == NULL) 1164 return (-1); 1165 left0 = xstrndup(s, cp - s); 1166 right0 = xstrdup(cp + 1); 1167 1168 if (expand) { 1169 *left = format_expand(ft, left0); 1170 free(left0); 1171 *right = format_expand(ft, right0); 1172 free(right0); 1173 } else { 1174 *left = left0; 1175 *right = right0; 1176 } 1177 return (0); 1178 } 1179 1180 /* Is this true? */ 1181 int 1182 format_true(const char *s) 1183 { 1184 if (s != NULL && *s != '\0' && (s[0] != '0' || s[1] != '\0')) 1185 return (1); 1186 return (0); 1187 } 1188 1189 /* Check if modifier end. */ 1190 static int 1191 format_is_end(char c) 1192 { 1193 return (c == ';' || c == ':'); 1194 } 1195 1196 /* Add to modifier list. */ 1197 static void 1198 format_add_modifier(struct format_modifier **list, u_int *count, 1199 const char *c, size_t n, char **argv, int argc) 1200 { 1201 struct format_modifier *fm; 1202 1203 *list = xreallocarray(*list, (*count) + 1, sizeof **list); 1204 fm = &(*list)[(*count)++]; 1205 1206 memcpy(fm->modifier, c, n); 1207 fm->modifier[n] = '\0'; 1208 fm->size = n; 1209 1210 fm->argv = argv; 1211 fm->argc = argc; 1212 } 1213 1214 /* Free modifier list. */ 1215 static void 1216 format_free_modifiers(struct format_modifier *list, u_int count) 1217 { 1218 u_int i; 1219 1220 for (i = 0; i < count; i++) 1221 cmd_free_argv(list[i].argc, list[i].argv); 1222 free(list); 1223 } 1224 1225 /* Build modifier list. */ 1226 static struct format_modifier * 1227 format_build_modifiers(struct format_tree *ft, const char **s, u_int *count) 1228 { 1229 const char *cp = *s, *end; 1230 struct format_modifier *list = NULL; 1231 char c, last[] = "X;:", **argv, *value; 1232 int argc; 1233 1234 /* 1235 * Modifiers are a ; separated list of the forms: 1236 * l,m,C,b,d,t,q,E,T,S,W,P,<,> 1237 * =a 1238 * =/a 1239 * =/a/ 1240 * s/a/b/ 1241 * s/a/b 1242 * ||,&&,!=,==,<=,>= 1243 */ 1244 1245 *count = 0; 1246 1247 while (*cp != '\0' && *cp != ':') { 1248 /* Skip and separator character. */ 1249 if (*cp == ';') 1250 cp++; 1251 1252 /* Check single character modifiers with no arguments. */ 1253 if (strchr("lbdtqETSWP<>", cp[0]) != NULL && 1254 format_is_end(cp[1])) { 1255 format_add_modifier(&list, count, cp, 1, NULL, 0); 1256 cp++; 1257 continue; 1258 } 1259 1260 /* Then try double character with no arguments. */ 1261 if ((memcmp("||", cp, 2) == 0 || 1262 memcmp("&&", cp, 2) == 0 || 1263 memcmp("!=", cp, 2) == 0 || 1264 memcmp("==", cp, 2) == 0 || 1265 memcmp("<=", cp, 2) == 0 || 1266 memcmp(">=", cp, 2) == 0) && 1267 format_is_end(cp[2])) { 1268 format_add_modifier(&list, count, cp, 2, NULL, 0); 1269 cp += 2; 1270 continue; 1271 } 1272 1273 /* Now try single character with arguments. */ 1274 if (strchr("mCs=", cp[0]) == NULL) 1275 break; 1276 c = cp[0]; 1277 1278 /* No arguments provided. */ 1279 if (format_is_end(cp[1])) { 1280 format_add_modifier(&list, count, cp, 1, NULL, 0); 1281 cp++; 1282 continue; 1283 } 1284 argv = NULL; 1285 argc = 0; 1286 1287 /* Single argument with no wrapper character. */ 1288 if (!ispunct(cp[1]) || cp[1] == '-') { 1289 end = format_skip(cp + 1, ":;"); 1290 if (end == NULL) 1291 break; 1292 1293 argv = xcalloc(1, sizeof *argv); 1294 value = xstrndup(cp + 1, end - (cp + 1)); 1295 argv[0] = format_expand(ft, value); 1296 free(value); 1297 argc = 1; 1298 1299 format_add_modifier(&list, count, &c, 1, argv, argc); 1300 cp = end; 1301 continue; 1302 } 1303 1304 /* Multiple arguments with a wrapper character. */ 1305 last[0] = cp[1]; 1306 cp++; 1307 do { 1308 if (cp[0] == last[0] && format_is_end(cp[1])) { 1309 cp++; 1310 break; 1311 } 1312 end = format_skip(cp + 1, last); 1313 if (end == NULL) 1314 break; 1315 cp++; 1316 1317 argv = xreallocarray (argv, argc + 1, sizeof *argv); 1318 value = xstrndup(cp, end - cp); 1319 argv[argc++] = format_expand(ft, value); 1320 free(value); 1321 1322 cp = end; 1323 } while (!format_is_end(cp[0])); 1324 format_add_modifier(&list, count, &c, 1, argv, argc); 1325 } 1326 if (*cp != ':') { 1327 format_free_modifiers(list, *count); 1328 *count = 0; 1329 return (NULL); 1330 } 1331 *s = cp + 1; 1332 return list; 1333 } 1334 1335 /* Match against an fnmatch(3) pattern or regular expression. */ 1336 static char * 1337 format_match(struct format_modifier *fm, const char *pattern, const char *text) 1338 { 1339 const char *s = ""; 1340 regex_t r; 1341 int flags = 0; 1342 1343 if (fm->argc >= 1) 1344 s = fm->argv[0]; 1345 if (strchr(s, 'r') == NULL) { 1346 if (strchr(s, 'i') != NULL) 1347 flags |= FNM_CASEFOLD; 1348 if (fnmatch(pattern, text, flags) != 0) 1349 return (xstrdup("0")); 1350 } else { 1351 flags = REG_EXTENDED|REG_NOSUB; 1352 if (strchr(s, 'i') != NULL) 1353 flags |= REG_ICASE; 1354 if (regcomp(&r, pattern, flags) != 0) 1355 return (xstrdup("0")); 1356 if (regexec(&r, text, 0, NULL, 0) != 0) { 1357 regfree(&r); 1358 return (xstrdup("0")); 1359 } 1360 regfree(&r); 1361 } 1362 return (xstrdup("1")); 1363 } 1364 1365 /* Perform substitution in string. */ 1366 static char * 1367 format_sub(struct format_modifier *fm, const char *text, const char *pattern, 1368 const char *with) 1369 { 1370 char *value; 1371 int flags = REG_EXTENDED; 1372 1373 if (fm->argc >= 3 && strchr(fm->argv[2], 'i') != NULL) 1374 flags |= REG_ICASE; 1375 value = regsub(pattern, with, text, flags); 1376 if (value == NULL) 1377 return (xstrdup(text)); 1378 return (value); 1379 } 1380 1381 /* Search inside pane. */ 1382 static char * 1383 format_search(struct format_modifier *fm, struct window_pane *wp, const char *s) 1384 { 1385 int ignore = 0, regex = 0; 1386 char *value; 1387 1388 if (fm->argc >= 1) { 1389 if (strchr(fm->argv[0], 'i') != NULL) 1390 ignore = 1; 1391 if (strchr(fm->argv[0], 'r') != NULL) 1392 regex = 1; 1393 } 1394 xasprintf(&value, "%u", window_pane_search(wp, s, regex, ignore)); 1395 return (value); 1396 } 1397 1398 /* Loop over sessions. */ 1399 static char * 1400 format_loop_sessions(struct format_tree *ft, const char *fmt) 1401 { 1402 struct client *c = ft->client; 1403 struct cmdq_item *item = ft->item; 1404 struct format_tree *nft; 1405 char *expanded, *value; 1406 size_t valuelen; 1407 struct session *s; 1408 1409 value = xcalloc(1, 1); 1410 valuelen = 1; 1411 1412 RB_FOREACH(s, sessions, &sessions) { 1413 format_log(ft, "session loop: $%u", s->id); 1414 nft = format_create(c, item, FORMAT_NONE, ft->flags); 1415 nft->loop = ft->loop; 1416 format_defaults(nft, ft->c, s, NULL, NULL); 1417 expanded = format_expand(nft, fmt); 1418 format_free(nft); 1419 1420 valuelen += strlen(expanded); 1421 value = xrealloc(value, valuelen); 1422 1423 strlcat(value, expanded, valuelen); 1424 free(expanded); 1425 } 1426 1427 return (value); 1428 } 1429 1430 /* Loop over windows. */ 1431 static char * 1432 format_loop_windows(struct format_tree *ft, const char *fmt) 1433 { 1434 struct client *c = ft->client; 1435 struct cmdq_item *item = ft->item; 1436 struct format_tree *nft; 1437 char *all, *active, *use, *expanded, *value; 1438 size_t valuelen; 1439 struct winlink *wl; 1440 struct window *w; 1441 1442 if (ft->s == NULL) { 1443 format_log(ft, "window loop but no session"); 1444 return (NULL); 1445 } 1446 1447 if (format_choose(ft, fmt, &all, &active, 0) != 0) { 1448 all = xstrdup(fmt); 1449 active = NULL; 1450 } 1451 1452 value = xcalloc(1, 1); 1453 valuelen = 1; 1454 1455 RB_FOREACH(wl, winlinks, &ft->s->windows) { 1456 w = wl->window; 1457 format_log(ft, "window loop: %u @%u", wl->idx, w->id); 1458 if (active != NULL && wl == ft->s->curw) 1459 use = active; 1460 else 1461 use = all; 1462 nft = format_create(c, item, FORMAT_WINDOW|w->id, ft->flags); 1463 nft->loop = ft->loop; 1464 format_defaults(nft, ft->c, ft->s, wl, NULL); 1465 expanded = format_expand(nft, use); 1466 format_free(nft); 1467 1468 valuelen += strlen(expanded); 1469 value = xrealloc(value, valuelen); 1470 1471 strlcat(value, expanded, valuelen); 1472 free(expanded); 1473 } 1474 1475 free(active); 1476 free(all); 1477 1478 return (value); 1479 } 1480 1481 /* Loop over panes. */ 1482 static char * 1483 format_loop_panes(struct format_tree *ft, const char *fmt) 1484 { 1485 struct client *c = ft->client; 1486 struct cmdq_item *item = ft->item; 1487 struct format_tree *nft; 1488 char *all, *active, *use, *expanded, *value; 1489 size_t valuelen; 1490 struct window_pane *wp; 1491 1492 if (ft->w == NULL) { 1493 format_log(ft, "pane loop but no window"); 1494 return (NULL); 1495 } 1496 1497 if (format_choose(ft, fmt, &all, &active, 0) != 0) { 1498 all = xstrdup(fmt); 1499 active = NULL; 1500 } 1501 1502 value = xcalloc(1, 1); 1503 valuelen = 1; 1504 1505 TAILQ_FOREACH(wp, &ft->w->panes, entry) { 1506 format_log(ft, "pane loop: %%%u", wp->id); 1507 if (active != NULL && wp == ft->w->active) 1508 use = active; 1509 else 1510 use = all; 1511 nft = format_create(c, item, FORMAT_PANE|wp->id, ft->flags); 1512 nft->loop = ft->loop; 1513 format_defaults(nft, ft->c, ft->s, ft->wl, wp); 1514 expanded = format_expand(nft, use); 1515 format_free(nft); 1516 1517 valuelen += strlen(expanded); 1518 value = xrealloc(value, valuelen); 1519 1520 strlcat(value, expanded, valuelen); 1521 free(expanded); 1522 } 1523 1524 free(active); 1525 free(all); 1526 1527 return (value); 1528 } 1529 1530 /* Replace a key. */ 1531 static int 1532 format_replace(struct format_tree *ft, const char *key, size_t keylen, 1533 char **buf, size_t *len, size_t *off) 1534 { 1535 struct window_pane *wp = ft->wp; 1536 const char *errptr, *copy, *cp, *marker = NULL; 1537 char *copy0, *condition, *found, *new; 1538 char *value, *left, *right; 1539 size_t valuelen; 1540 int modifiers = 0, limit = 0, j; 1541 struct format_modifier *list, *fm, *cmp = NULL, *search = NULL; 1542 struct format_modifier *sub = NULL; 1543 u_int i, count; 1544 1545 /* Make a copy of the key. */ 1546 copy = copy0 = xstrndup(key, keylen); 1547 1548 /* Process modifier list. */ 1549 list = format_build_modifiers(ft, ©, &count); 1550 for (i = 0; i < count; i++) { 1551 fm = &list[i]; 1552 if (format_logging(ft)) { 1553 format_log(ft, "modifier %u is %s", i, fm->modifier); 1554 for (j = 0; j < fm->argc; j++) { 1555 format_log(ft, "modifier %u argument %d: %s", i, 1556 j, fm->argv[j]); 1557 } 1558 } 1559 if (fm->size == 1) { 1560 switch (fm->modifier[0]) { 1561 case 'm': 1562 case '<': 1563 case '>': 1564 cmp = fm; 1565 break; 1566 case 'C': 1567 search = fm; 1568 break; 1569 case 's': 1570 if (fm->argc < 2) 1571 break; 1572 sub = fm; 1573 break; 1574 case '=': 1575 if (fm->argc < 1) 1576 break; 1577 limit = strtonum(fm->argv[0], INT_MIN, INT_MAX, 1578 &errptr); 1579 if (errptr != NULL) 1580 limit = 0; 1581 if (fm->argc >= 2 && fm->argv[1] != NULL) 1582 marker = fm->argv[1]; 1583 break; 1584 case 'l': 1585 modifiers |= FORMAT_LITERAL; 1586 break; 1587 case 'b': 1588 modifiers |= FORMAT_BASENAME; 1589 break; 1590 case 'd': 1591 modifiers |= FORMAT_DIRNAME; 1592 break; 1593 case 't': 1594 modifiers |= FORMAT_TIMESTRING; 1595 break; 1596 case 'q': 1597 modifiers |= FORMAT_QUOTE; 1598 break; 1599 case 'E': 1600 modifiers |= FORMAT_EXPAND; 1601 break; 1602 case 'T': 1603 modifiers |= FORMAT_EXPANDTIME; 1604 break; 1605 case 'S': 1606 modifiers |= FORMAT_SESSIONS; 1607 break; 1608 case 'W': 1609 modifiers |= FORMAT_WINDOWS; 1610 break; 1611 case 'P': 1612 modifiers |= FORMAT_PANES; 1613 break; 1614 } 1615 } else if (fm->size == 2) { 1616 if (strcmp(fm->modifier, "||") == 0 || 1617 strcmp(fm->modifier, "&&") == 0 || 1618 strcmp(fm->modifier, "==") == 0 || 1619 strcmp(fm->modifier, "!=") == 0 || 1620 strcmp(fm->modifier, ">=") == 0 || 1621 strcmp(fm->modifier, "<=") == 0) 1622 cmp = fm; 1623 } 1624 } 1625 1626 /* Is this a literal string? */ 1627 if (modifiers & FORMAT_LITERAL) { 1628 value = xstrdup(copy); 1629 goto done; 1630 } 1631 1632 /* Is this a loop, comparison or condition? */ 1633 if (modifiers & FORMAT_SESSIONS) { 1634 value = format_loop_sessions(ft, copy); 1635 if (value == NULL) 1636 goto fail; 1637 } else if (modifiers & FORMAT_WINDOWS) { 1638 value = format_loop_windows(ft, copy); 1639 if (value == NULL) 1640 goto fail; 1641 } else if (modifiers & FORMAT_PANES) { 1642 value = format_loop_panes(ft, copy); 1643 if (value == NULL) 1644 goto fail; 1645 } else if (search != NULL) { 1646 /* Search in pane. */ 1647 if (wp == NULL) { 1648 format_log(ft, "search '%s' but no pane", copy); 1649 value = xstrdup("0"); 1650 } else { 1651 format_log(ft, "search '%s' pane %%%u", copy, wp->id); 1652 value = format_search(fm, wp, copy); 1653 } 1654 } else if (cmp != NULL) { 1655 /* Comparison of left and right. */ 1656 if (format_choose(ft, copy, &left, &right, 1) != 0) { 1657 format_log(ft, "compare %s syntax error: %s", 1658 cmp->modifier, copy); 1659 goto fail; 1660 } 1661 format_log(ft, "compare %s left is: %s", cmp->modifier, left); 1662 format_log(ft, "compare %s right is: %s", cmp->modifier, right); 1663 1664 if (strcmp(cmp->modifier, "||") == 0) { 1665 if (format_true(left) || format_true(right)) 1666 value = xstrdup("1"); 1667 else 1668 value = xstrdup("0"); 1669 } else if (strcmp(cmp->modifier, "&&") == 0) { 1670 if (format_true(left) && format_true(right)) 1671 value = xstrdup("1"); 1672 else 1673 value = xstrdup("0"); 1674 } else if (strcmp(cmp->modifier, "==") == 0) { 1675 if (strcmp(left, right) == 0) 1676 value = xstrdup("1"); 1677 else 1678 value = xstrdup("0"); 1679 } else if (strcmp(cmp->modifier, "!=") == 0) { 1680 if (strcmp(left, right) != 0) 1681 value = xstrdup("1"); 1682 else 1683 value = xstrdup("0"); 1684 } else if (strcmp(cmp->modifier, "<") == 0) { 1685 if (strcmp(left, right) < 0) 1686 value = xstrdup("1"); 1687 else 1688 value = xstrdup("0"); 1689 } else if (strcmp(cmp->modifier, ">") == 0) { 1690 if (strcmp(left, right) > 0) 1691 value = xstrdup("1"); 1692 else 1693 value = xstrdup("0"); 1694 } else if (strcmp(cmp->modifier, "<=") == 0) { 1695 if (strcmp(left, right) <= 0) 1696 value = xstrdup("1"); 1697 else 1698 value = xstrdup("0"); 1699 } else if (strcmp(cmp->modifier, ">=") == 0) { 1700 if (strcmp(left, right) >= 0) 1701 value = xstrdup("1"); 1702 else 1703 value = xstrdup("0"); 1704 } else if (strcmp(cmp->modifier, "m") == 0) 1705 value = format_match(cmp, left, right); 1706 1707 free(right); 1708 free(left); 1709 } else if (*copy == '?') { 1710 /* Conditional: check first and choose second or third. */ 1711 cp = format_skip(copy + 1, ","); 1712 if (cp == NULL) { 1713 format_log(ft, "condition syntax error: %s", copy + 1); 1714 goto fail; 1715 } 1716 condition = xstrndup(copy + 1, cp - (copy + 1)); 1717 format_log(ft, "condition is: %s", condition); 1718 1719 found = format_find(ft, condition, modifiers); 1720 if (found == NULL) { 1721 /* 1722 * If the condition not found, try to expand it. If 1723 * the expansion doesn't have any effect, then assume 1724 * false. 1725 */ 1726 found = format_expand(ft, condition); 1727 if (strcmp(found, condition) == 0) { 1728 free(found); 1729 found = xstrdup(""); 1730 format_log(ft, "condition '%s' found: %s", 1731 condition, found); 1732 } else { 1733 format_log(ft, 1734 "condition '%s' not found; assuming false", 1735 condition); 1736 } 1737 } else 1738 format_log(ft, "condition '%s' found", condition); 1739 1740 if (format_choose(ft, cp + 1, &left, &right, 0) != 0) { 1741 format_log(ft, "condition '%s' syntax error: %s", 1742 condition, cp + 1); 1743 free(found); 1744 goto fail; 1745 } 1746 if (format_true(found)) { 1747 format_log(ft, "condition '%s' is true", condition); 1748 value = format_expand(ft, left); 1749 } else { 1750 format_log(ft, "condition '%s' is false", condition); 1751 value = format_expand(ft, right); 1752 } 1753 free(right); 1754 free(left); 1755 1756 free(condition); 1757 free(found); 1758 } else { 1759 /* Neither: look up directly. */ 1760 value = format_find(ft, copy, modifiers); 1761 if (value == NULL) { 1762 format_log(ft, "format '%s' not found", copy); 1763 value = xstrdup(""); 1764 } else 1765 format_log(ft, "format '%s' found: %s", copy, value); 1766 } 1767 1768 done: 1769 /* Expand again if required. */ 1770 if (modifiers & FORMAT_EXPAND) { 1771 new = format_expand(ft, value); 1772 free(value); 1773 value = new; 1774 } 1775 else if (modifiers & FORMAT_EXPANDTIME) { 1776 new = format_expand_time(ft, value); 1777 free(value); 1778 value = new; 1779 } 1780 1781 /* Perform substitution if any. */ 1782 if (sub != NULL) { 1783 new = format_sub(sub, value, sub->argv[0], sub->argv[1]); 1784 format_log(ft, "substituted '%s' to '%s': %s", sub->argv[0], 1785 sub->argv[1], new); 1786 free(value); 1787 value = new; 1788 } 1789 1790 /* Truncate the value if needed. */ 1791 if (limit > 0) { 1792 new = format_trim_left(value, limit); 1793 if (marker != NULL && strcmp(new, value) != 0) { 1794 free(value); 1795 xasprintf(&value, "%s%s", new, marker); 1796 } else { 1797 free(value); 1798 value = new; 1799 } 1800 format_log(ft, "applied length limit %d: %s", limit, value); 1801 } else if (limit < 0) { 1802 new = format_trim_right(value, -limit); 1803 if (marker != NULL && strcmp(new, value) != 0) { 1804 free(value); 1805 xasprintf(&value, "%s%s", marker, new); 1806 } else { 1807 free(value); 1808 value = new; 1809 } 1810 format_log(ft, "applied length limit %d: %s", limit, value); 1811 } 1812 1813 /* Expand the buffer and copy in the value. */ 1814 valuelen = strlen(value); 1815 while (*len - *off < valuelen + 1) { 1816 *buf = xreallocarray(*buf, 2, *len); 1817 *len *= 2; 1818 } 1819 memcpy(*buf + *off, value, valuelen); 1820 *off += valuelen; 1821 1822 format_log(ft, "replaced '%s' with '%s'", copy0, value); 1823 free(value); 1824 1825 format_free_modifiers(list, count); 1826 free(copy0); 1827 return (0); 1828 1829 fail: 1830 format_log(ft, "failed %s", copy0); 1831 format_free_modifiers(list, count); 1832 free(copy0); 1833 return (-1); 1834 } 1835 1836 /* Expand keys in a template. */ 1837 static char * 1838 format_expand1(struct format_tree *ft, const char *fmt, int time) 1839 { 1840 char *buf, *out, *name; 1841 const char *ptr, *s; 1842 size_t off, len, n, outlen; 1843 int ch, brackets; 1844 struct tm *tm; 1845 char expanded[8192]; 1846 1847 if (fmt == NULL || *fmt == '\0') 1848 return (xstrdup("")); 1849 1850 if (ft->loop == FORMAT_LOOP_LIMIT) 1851 return (xstrdup("")); 1852 ft->loop++; 1853 1854 format_log(ft, "expanding format: %s", fmt); 1855 1856 if (time) { 1857 tm = localtime(&ft->time); 1858 if (strftime(expanded, sizeof expanded, fmt, tm) == 0) { 1859 format_log(ft, "format is too long"); 1860 return (xstrdup("")); 1861 } 1862 if (format_logging(ft) && strcmp(expanded, fmt) != 0) 1863 format_log(ft, "after time expanded: %s", expanded); 1864 fmt = expanded; 1865 } 1866 1867 len = 64; 1868 buf = xmalloc(len); 1869 off = 0; 1870 1871 while (*fmt != '\0') { 1872 if (*fmt != '#') { 1873 while (len - off < 2) { 1874 buf = xreallocarray(buf, 2, len); 1875 len *= 2; 1876 } 1877 buf[off++] = *fmt++; 1878 continue; 1879 } 1880 fmt++; 1881 1882 ch = (u_char)*fmt++; 1883 switch (ch) { 1884 case '(': 1885 brackets = 1; 1886 for (ptr = fmt; *ptr != '\0'; ptr++) { 1887 if (*ptr == '(') 1888 brackets++; 1889 if (*ptr == ')' && --brackets == 0) 1890 break; 1891 } 1892 if (*ptr != ')' || brackets != 0) 1893 break; 1894 n = ptr - fmt; 1895 1896 name = xstrndup(fmt, n); 1897 format_log(ft, "found #(): %s", name); 1898 1899 if (ft->flags & FORMAT_NOJOBS) { 1900 out = xstrdup(""); 1901 format_log(ft, "#() is disabled"); 1902 } else { 1903 out = format_job_get(ft, name); 1904 format_log(ft, "#() result: %s", out); 1905 } 1906 free(name); 1907 1908 outlen = strlen(out); 1909 while (len - off < outlen + 1) { 1910 buf = xreallocarray(buf, 2, len); 1911 len *= 2; 1912 } 1913 memcpy(buf + off, out, outlen); 1914 off += outlen; 1915 1916 free(out); 1917 1918 fmt += n + 1; 1919 continue; 1920 case '{': 1921 ptr = format_skip((char *)fmt - 2, "}"); 1922 if (ptr == NULL) 1923 break; 1924 n = ptr - fmt; 1925 1926 format_log(ft, "found #{}: %.*s", (int)n, fmt); 1927 if (format_replace(ft, fmt, n, &buf, &len, &off) != 0) 1928 break; 1929 fmt += n + 1; 1930 continue; 1931 case '}': 1932 case '#': 1933 case ',': 1934 format_log(ft, "found #%c", ch); 1935 while (len - off < 2) { 1936 buf = xreallocarray(buf, 2, len); 1937 len *= 2; 1938 } 1939 buf[off++] = ch; 1940 continue; 1941 default: 1942 s = NULL; 1943 if (ch >= 'A' && ch <= 'Z') 1944 s = format_upper[ch - 'A']; 1945 else if (ch >= 'a' && ch <= 'z') 1946 s = format_lower[ch - 'a']; 1947 if (s == NULL) { 1948 while (len - off < 3) { 1949 buf = xreallocarray(buf, 2, len); 1950 len *= 2; 1951 } 1952 buf[off++] = '#'; 1953 buf[off++] = ch; 1954 continue; 1955 } 1956 n = strlen(s); 1957 format_log(ft, "found #%c: %s", ch, s); 1958 if (format_replace(ft, s, n, &buf, &len, &off) != 0) 1959 break; 1960 continue; 1961 } 1962 1963 break; 1964 } 1965 buf[off] = '\0'; 1966 1967 format_log(ft, "result is: %s", buf); 1968 ft->loop--; 1969 1970 return (buf); 1971 } 1972 1973 /* Expand keys in a template, passing through strftime first. */ 1974 char * 1975 format_expand_time(struct format_tree *ft, const char *fmt) 1976 { 1977 return (format_expand1(ft, fmt, 1)); 1978 } 1979 1980 /* Expand keys in a template. */ 1981 char * 1982 format_expand(struct format_tree *ft, const char *fmt) 1983 { 1984 return (format_expand1(ft, fmt, 0)); 1985 } 1986 1987 /* Expand a single string. */ 1988 char * 1989 format_single(struct cmdq_item *item, const char *fmt, struct client *c, 1990 struct session *s, struct winlink *wl, struct window_pane *wp) 1991 { 1992 struct format_tree *ft; 1993 char *expanded; 1994 1995 if (item != NULL) 1996 ft = format_create(item->client, item, FORMAT_NONE, 0); 1997 else 1998 ft = format_create(NULL, item, FORMAT_NONE, 0); 1999 format_defaults(ft, c, s, wl, wp); 2000 2001 expanded = format_expand(ft, fmt); 2002 format_free(ft); 2003 return (expanded); 2004 } 2005 2006 /* Set defaults for any of arguments that are not NULL. */ 2007 void 2008 format_defaults(struct format_tree *ft, struct client *c, struct session *s, 2009 struct winlink *wl, struct window_pane *wp) 2010 { 2011 if (c != NULL && c->name != NULL) 2012 log_debug("%s: c=%s", __func__, c->name); 2013 else 2014 log_debug("%s: c=none", __func__); 2015 if (s != NULL) 2016 log_debug("%s: s=$%u", __func__, s->id); 2017 else 2018 log_debug("%s: s=none", __func__); 2019 if (wl != NULL) 2020 log_debug("%s: wl=%u w=@%u", __func__, wl->idx, wl->window->id); 2021 else 2022 log_debug("%s: wl=none", __func__); 2023 if (wp != NULL) 2024 log_debug("%s: wp=%%%u", __func__, wp->id); 2025 else 2026 log_debug("%s: wp=none", __func__); 2027 2028 if (c != NULL && s != NULL && c->session != s) 2029 log_debug("%s: session does not match", __func__); 2030 2031 format_add(ft, "session_format", "%d", s != NULL); 2032 format_add(ft, "window_format", "%d", wl != NULL); 2033 format_add(ft, "pane_format", "%d", wp != NULL); 2034 2035 if (s == NULL && c != NULL) 2036 s = c->session; 2037 if (wl == NULL && s != NULL) 2038 wl = s->curw; 2039 if (wp == NULL && wl != NULL) 2040 wp = wl->window->active; 2041 2042 if (c != NULL) 2043 format_defaults_client(ft, c); 2044 if (s != NULL) 2045 format_defaults_session(ft, s); 2046 if (wl != NULL) 2047 format_defaults_winlink(ft, wl); 2048 if (wp != NULL) 2049 format_defaults_pane(ft, wp); 2050 } 2051 2052 /* Set default format keys for a session. */ 2053 static void 2054 format_defaults_session(struct format_tree *ft, struct session *s) 2055 { 2056 struct session_group *sg; 2057 2058 ft->s = s; 2059 2060 format_add(ft, "session_name", "%s", s->name); 2061 format_add(ft, "session_windows", "%u", winlink_count(&s->windows)); 2062 format_add(ft, "session_id", "$%u", s->id); 2063 2064 sg = session_group_contains(s); 2065 format_add(ft, "session_grouped", "%d", sg != NULL); 2066 if (sg != NULL) { 2067 format_add(ft, "session_group", "%s", sg->name); 2068 format_add(ft, "session_group_size", "%u", 2069 session_group_count (sg)); 2070 format_add_cb(ft, "session_group_list", 2071 format_cb_session_group_list); 2072 } 2073 2074 format_add_tv(ft, "session_created", &s->creation_time); 2075 format_add_tv(ft, "session_last_attached", &s->last_attached_time); 2076 format_add_tv(ft, "session_activity", &s->activity_time); 2077 2078 format_add(ft, "session_attached", "%u", s->attached); 2079 format_add(ft, "session_many_attached", "%d", s->attached > 1); 2080 2081 format_add_cb(ft, "session_alerts", format_cb_session_alerts); 2082 format_add_cb(ft, "session_stack", format_cb_session_stack); 2083 } 2084 2085 /* Set default format keys for a client. */ 2086 static void 2087 format_defaults_client(struct format_tree *ft, struct client *c) 2088 { 2089 struct session *s; 2090 const char *name; 2091 struct tty *tty = &c->tty; 2092 const char *types[] = TTY_TYPES; 2093 2094 if (ft->s == NULL) 2095 ft->s = c->session; 2096 ft->c = c; 2097 2098 format_add(ft, "client_name", "%s", c->name); 2099 format_add(ft, "client_pid", "%ld", (long) c->pid); 2100 format_add(ft, "client_height", "%u", tty->sy); 2101 format_add(ft, "client_width", "%u", tty->sx); 2102 format_add(ft, "client_tty", "%s", c->ttyname); 2103 format_add(ft, "client_control_mode", "%d", 2104 !!(c->flags & CLIENT_CONTROL)); 2105 2106 if (tty->term_name != NULL) 2107 format_add(ft, "client_termname", "%s", tty->term_name); 2108 if (tty->term_name != NULL) 2109 format_add(ft, "client_termtype", "%s", types[tty->term_type]); 2110 2111 format_add_tv(ft, "client_created", &c->creation_time); 2112 format_add_tv(ft, "client_activity", &c->activity_time); 2113 2114 format_add(ft, "client_written", "%zu", c->written); 2115 format_add(ft, "client_discarded", "%zu", c->discarded); 2116 2117 name = server_client_get_key_table(c); 2118 if (strcmp(c->keytable->name, name) == 0) 2119 format_add(ft, "client_prefix", "%d", 0); 2120 else 2121 format_add(ft, "client_prefix", "%d", 1); 2122 format_add(ft, "client_key_table", "%s", c->keytable->name); 2123 2124 if (tty->flags & TTY_UTF8) 2125 format_add(ft, "client_utf8", "%d", 1); 2126 else 2127 format_add(ft, "client_utf8", "%d", 0); 2128 2129 if (c->flags & CLIENT_READONLY) 2130 format_add(ft, "client_readonly", "%d", 1); 2131 else 2132 format_add(ft, "client_readonly", "%d", 0); 2133 2134 s = c->session; 2135 if (s != NULL) 2136 format_add(ft, "client_session", "%s", s->name); 2137 s = c->last_session; 2138 if (s != NULL && session_alive(s)) 2139 format_add(ft, "client_last_session", "%s", s->name); 2140 } 2141 2142 /* Set default format keys for a window. */ 2143 void 2144 format_defaults_window(struct format_tree *ft, struct window *w) 2145 { 2146 ft->w = w; 2147 2148 format_add_tv(ft, "window_activity", &w->activity_time); 2149 format_add(ft, "window_id", "@%u", w->id); 2150 format_add(ft, "window_name", "%s", w->name); 2151 format_add(ft, "window_width", "%u", w->sx); 2152 format_add(ft, "window_height", "%u", w->sy); 2153 format_add_cb(ft, "window_layout", format_cb_window_layout); 2154 format_add_cb(ft, "window_visible_layout", 2155 format_cb_window_visible_layout); 2156 format_add(ft, "window_panes", "%u", window_count_panes(w)); 2157 format_add(ft, "window_zoomed_flag", "%d", 2158 !!(w->flags & WINDOW_ZOOMED)); 2159 } 2160 2161 /* Set default format keys for a winlink. */ 2162 static void 2163 format_defaults_winlink(struct format_tree *ft, struct winlink *wl) 2164 { 2165 struct client *c = ft->c; 2166 struct session *s = wl->session; 2167 struct window *w = wl->window; 2168 int flag; 2169 u_int ox, oy, sx, sy; 2170 2171 if (ft->w == NULL) 2172 ft->w = wl->window; 2173 ft->wl = wl; 2174 2175 format_defaults_window(ft, w); 2176 2177 if (c != NULL) { 2178 flag = tty_window_offset(&c->tty, &ox, &oy, &sx, &sy); 2179 format_add(ft, "window_bigger", "%d", flag); 2180 if (flag) { 2181 format_add(ft, "window_offset_x", "%u", ox); 2182 format_add(ft, "window_offset_y", "%u", oy); 2183 } 2184 } 2185 2186 format_add(ft, "window_index", "%d", wl->idx); 2187 format_add_cb(ft, "window_stack_index", format_cb_window_stack_index); 2188 format_add(ft, "window_flags", "%s", window_printable_flags(wl)); 2189 format_add(ft, "window_active", "%d", wl == s->curw); 2190 2191 format_add(ft, "window_start_flag", "%d", 2192 !!(wl == RB_MIN(winlinks, &s->windows))); 2193 format_add(ft, "window_end_flag", "%d", 2194 !!(wl == RB_MAX(winlinks, &s->windows))); 2195 2196 format_add(ft, "window_bell_flag", "%d", 2197 !!(wl->flags & WINLINK_BELL)); 2198 format_add(ft, "window_activity_flag", "%d", 2199 !!(wl->flags & WINLINK_ACTIVITY)); 2200 format_add(ft, "window_silence_flag", "%d", 2201 !!(wl->flags & WINLINK_SILENCE)); 2202 format_add(ft, "window_last_flag", "%d", 2203 !!(wl == TAILQ_FIRST(&s->lastw))); 2204 format_add(ft, "window_linked", "%d", session_is_linked(s, wl->window)); 2205 } 2206 2207 /* Set default format keys for a window pane. */ 2208 void 2209 format_defaults_pane(struct format_tree *ft, struct window_pane *wp) 2210 { 2211 struct window *w = wp->window; 2212 struct grid *gd = wp->base.grid; 2213 int status = wp->status; 2214 u_int idx; 2215 struct window_mode_entry *wme; 2216 2217 if (ft->w == NULL) 2218 ft->w = w; 2219 ft->wp = wp; 2220 2221 format_add(ft, "history_size", "%u", gd->hsize); 2222 format_add(ft, "history_limit", "%u", gd->hlimit); 2223 format_add_cb(ft, "history_bytes", format_cb_history_bytes); 2224 2225 if (window_pane_index(wp, &idx) != 0) 2226 fatalx("index not found"); 2227 format_add(ft, "pane_index", "%u", idx); 2228 2229 format_add(ft, "pane_width", "%u", wp->sx); 2230 format_add(ft, "pane_height", "%u", wp->sy); 2231 format_add(ft, "pane_title", "%s", wp->base.title); 2232 format_add(ft, "pane_id", "%%%u", wp->id); 2233 format_add(ft, "pane_active", "%d", wp == w->active); 2234 format_add(ft, "pane_input_off", "%d", !!(wp->flags & PANE_INPUTOFF)); 2235 format_add(ft, "pane_pipe", "%d", wp->pipe_fd != -1); 2236 2237 if ((wp->flags & PANE_STATUSREADY) && WIFEXITED(status)) 2238 format_add(ft, "pane_dead_status", "%d", WEXITSTATUS(status)); 2239 if (~wp->flags & PANE_EMPTY) 2240 format_add(ft, "pane_dead", "%d", wp->fd == -1); 2241 else 2242 format_add(ft, "pane_dead", "0"); 2243 2244 if (server_check_marked() && marked_pane.wp == wp) 2245 format_add(ft, "pane_marked", "1"); 2246 else 2247 format_add(ft, "pane_marked", "0"); 2248 format_add(ft, "pane_marked_set", "%d", server_check_marked()); 2249 2250 format_add(ft, "pane_left", "%u", wp->xoff); 2251 format_add(ft, "pane_top", "%u", wp->yoff); 2252 format_add(ft, "pane_right", "%u", wp->xoff + wp->sx - 1); 2253 format_add(ft, "pane_bottom", "%u", wp->yoff + wp->sy - 1); 2254 format_add(ft, "pane_at_left", "%d", wp->xoff == 0); 2255 format_add(ft, "pane_at_top", "%d", wp->yoff == 0); 2256 format_add(ft, "pane_at_right", "%d", wp->xoff + wp->sx == w->sx); 2257 format_add(ft, "pane_at_bottom", "%d", wp->yoff + wp->sy == w->sy); 2258 2259 wme = TAILQ_FIRST(&wp->modes); 2260 if (wme != NULL) { 2261 format_add(ft, "pane_mode", "%s", wme->mode->name); 2262 if (wme->mode->formats != NULL) 2263 wme->mode->formats(wme, ft); 2264 } 2265 format_add_cb(ft, "pane_in_mode", format_cb_pane_in_mode); 2266 2267 format_add(ft, "pane_synchronized", "%d", 2268 !!options_get_number(w->options, "synchronize-panes")); 2269 if (wp->searchstr != NULL) 2270 format_add(ft, "pane_search_string", "%s", wp->searchstr); 2271 2272 format_add(ft, "pane_tty", "%s", wp->tty); 2273 format_add(ft, "pane_pid", "%ld", (long) wp->pid); 2274 format_add_cb(ft, "pane_start_command", format_cb_start_command); 2275 format_add_cb(ft, "pane_current_command", format_cb_current_command); 2276 2277 format_add(ft, "cursor_x", "%u", wp->base.cx); 2278 format_add(ft, "cursor_y", "%u", wp->base.cy); 2279 format_add_cb(ft, "cursor_character", format_cb_cursor_character); 2280 2281 format_add(ft, "scroll_region_upper", "%u", wp->base.rupper); 2282 format_add(ft, "scroll_region_lower", "%u", wp->base.rlower); 2283 2284 format_add(ft, "alternate_on", "%d", wp->saved_grid ? 1 : 0); 2285 format_add(ft, "alternate_saved_x", "%u", wp->saved_cx); 2286 format_add(ft, "alternate_saved_y", "%u", wp->saved_cy); 2287 2288 format_add(ft, "cursor_flag", "%d", 2289 !!(wp->base.mode & MODE_CURSOR)); 2290 format_add(ft, "insert_flag", "%d", 2291 !!(wp->base.mode & MODE_INSERT)); 2292 format_add(ft, "keypad_cursor_flag", "%d", 2293 !!(wp->base.mode & MODE_KCURSOR)); 2294 format_add(ft, "keypad_flag", "%d", 2295 !!(wp->base.mode & MODE_KKEYPAD)); 2296 format_add(ft, "wrap_flag", "%d", 2297 !!(wp->base.mode & MODE_WRAP)); 2298 2299 format_add(ft, "mouse_any_flag", "%d", 2300 !!(wp->base.mode & ALL_MOUSE_MODES)); 2301 format_add(ft, "mouse_standard_flag", "%d", 2302 !!(wp->base.mode & MODE_MOUSE_STANDARD)); 2303 format_add(ft, "mouse_button_flag", "%d", 2304 !!(wp->base.mode & MODE_MOUSE_BUTTON)); 2305 format_add(ft, "mouse_all_flag", "%d", 2306 !!(wp->base.mode & MODE_MOUSE_ALL)); 2307 2308 format_add_cb(ft, "pane_tabs", format_cb_pane_tabs); 2309 } 2310 2311 /* Set default format keys for paste buffer. */ 2312 void 2313 format_defaults_paste_buffer(struct format_tree *ft, struct paste_buffer *pb) 2314 { 2315 struct timeval tv; 2316 size_t size; 2317 char *s; 2318 2319 timerclear(&tv); 2320 tv.tv_sec = paste_buffer_created(pb); 2321 paste_buffer_data(pb, &size); 2322 2323 format_add(ft, "buffer_size", "%zu", size); 2324 format_add(ft, "buffer_name", "%s", paste_buffer_name(pb)); 2325 format_add_tv(ft, "buffer_created", &tv); 2326 2327 s = paste_make_sample(pb); 2328 format_add(ft, "buffer_sample", "%s", s); 2329 free(s); 2330 } 2331