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 <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(__UNCONST(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(__UNCONST(fj->expanded)); 392 free(__UNCONST(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 = osdep_get_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 pane_current_path. */ 594 static void 595 format_cb_current_path(struct format_tree *ft, struct format_entry *fe) 596 { 597 struct window_pane *wp = ft->wp; 598 char *cwd; 599 600 if (wp == NULL) 601 return; 602 603 cwd = osdep_get_cwd(wp->fd); 604 if (cwd != NULL) 605 fe->value = xstrdup(cwd); 606 } 607 608 /* Callback for history_bytes. */ 609 static void 610 format_cb_history_bytes(struct format_tree *ft, struct format_entry *fe) 611 { 612 struct window_pane *wp = ft->wp; 613 struct grid *gd; 614 struct grid_line *gl; 615 unsigned long long size; 616 u_int i; 617 618 if (wp == NULL) 619 return; 620 gd = wp->base.grid; 621 622 size = 0; 623 for (i = 0; i < gd->hsize; i++) { 624 gl = grid_get_line(gd, i); 625 size += gl->cellsize * sizeof *gl->celldata; 626 size += gl->extdsize * sizeof *gl->extddata; 627 } 628 size += gd->hsize * sizeof *gl; 629 630 xasprintf(&fe->value, "%llu", size); 631 } 632 633 /* Callback for pane_tabs. */ 634 static void 635 format_cb_pane_tabs(struct format_tree *ft, struct format_entry *fe) 636 { 637 struct window_pane *wp = ft->wp; 638 struct evbuffer *buffer; 639 u_int i; 640 int size; 641 642 if (wp == NULL) 643 return; 644 645 buffer = evbuffer_new(); 646 if (buffer == NULL) 647 fatalx("out of memory"); 648 for (i = 0; i < wp->base.grid->sx; i++) { 649 if (!bit_test(wp->base.tabs, i)) 650 continue; 651 652 if (EVBUFFER_LENGTH(buffer) > 0) 653 evbuffer_add(buffer, ",", 1); 654 evbuffer_add_printf(buffer, "%u", i); 655 } 656 if ((size = EVBUFFER_LENGTH(buffer)) != 0) 657 xasprintf(&fe->value, "%.*s", size, EVBUFFER_DATA(buffer)); 658 evbuffer_free(buffer); 659 } 660 661 /* Callback for session_group_list. */ 662 static void 663 format_cb_session_group_list(struct format_tree *ft, struct format_entry *fe) 664 { 665 struct session *s = ft->s; 666 struct session_group *sg; 667 struct session *loop; 668 struct evbuffer *buffer; 669 int size; 670 671 if (s == NULL) 672 return; 673 sg = session_group_contains(s); 674 if (sg == NULL) 675 return; 676 677 buffer = evbuffer_new(); 678 if (buffer == NULL) 679 fatalx("out of memory"); 680 TAILQ_FOREACH(loop, &sg->sessions, gentry) { 681 if (EVBUFFER_LENGTH(buffer) > 0) 682 evbuffer_add(buffer, ",", 1); 683 evbuffer_add_printf(buffer, "%s", loop->name); 684 } 685 if ((size = EVBUFFER_LENGTH(buffer)) != 0) 686 xasprintf(&fe->value, "%.*s", size, EVBUFFER_DATA(buffer)); 687 evbuffer_free(buffer); 688 } 689 690 /* Callback for pane_in_mode. */ 691 static void 692 format_cb_pane_in_mode(struct format_tree *ft, struct format_entry *fe) 693 { 694 struct window_pane *wp = ft->wp; 695 u_int n = 0; 696 struct window_mode_entry *wme; 697 698 if (wp == NULL) 699 return; 700 701 TAILQ_FOREACH(wme, &wp->modes, entry) 702 n++; 703 xasprintf(&fe->value, "%u", n); 704 } 705 706 /* Callback for cursor_character. */ 707 static void 708 format_cb_cursor_character(struct format_tree *ft, struct format_entry *fe) 709 { 710 struct window_pane *wp = ft->wp; 711 struct grid_cell gc; 712 713 if (wp == NULL) 714 return; 715 716 grid_view_get_cell(wp->base.grid, wp->base.cx, wp->base.cy, &gc); 717 if (~gc.flags & GRID_FLAG_PADDING) 718 xasprintf(&fe->value, "%.*s", (int)gc.data.size, gc.data.data); 719 } 720 721 /* Callback for mouse_word. */ 722 static void 723 format_cb_mouse_word(struct format_tree *ft, struct format_entry *fe) 724 { 725 struct window_pane *wp; 726 u_int x, y, end; 727 struct grid *gd; 728 struct grid_line *gl; 729 struct grid_cell gc; 730 const char *ws; 731 struct utf8_data *ud = NULL; 732 size_t size = 0; 733 int found = 0; 734 735 if (!ft->m.valid) 736 return; 737 wp = cmd_mouse_pane(&ft->m, NULL, NULL); 738 if (wp == NULL) 739 return; 740 if (!TAILQ_EMPTY (&wp->modes)) 741 return; 742 if (cmd_mouse_at(wp, &ft->m, &x, &y, 0) != 0) 743 return; 744 gd = wp->base.grid; 745 ws = options_get_string(global_s_options, "word-separators"); 746 747 y = gd->hsize + y; 748 for (;;) { 749 grid_get_cell(gd, x, y, &gc); 750 if (gc.flags & GRID_FLAG_PADDING) 751 break; 752 if (utf8_cstrhas(ws, &gc.data)) { 753 found = 1; 754 break; 755 } 756 757 if (x == 0) { 758 if (y == 0) 759 break; 760 gl = &gd->linedata[y - 1]; 761 if (~gl->flags & GRID_LINE_WRAPPED) 762 break; 763 y--; 764 x = grid_line_length(gd, y); 765 if (x == 0) 766 break; 767 } 768 x--; 769 } 770 for (;;) { 771 if (found) { 772 end = grid_line_length(gd, y); 773 if (end == 0 || x == end - 1) { 774 if (y == gd->hsize + gd->sy - 1) 775 break; 776 gl = &gd->linedata[y]; 777 if (~gl->flags & GRID_LINE_WRAPPED) 778 break; 779 y++; 780 x = 0; 781 } else 782 x++; 783 } 784 found = 1; 785 786 grid_get_cell(gd, x, y, &gc); 787 if (gc.flags & GRID_FLAG_PADDING) 788 break; 789 if (utf8_cstrhas(ws, &gc.data)) 790 break; 791 792 ud = xreallocarray(ud, size + 2, sizeof *ud); 793 memcpy(&ud[size++], &gc.data, sizeof *ud); 794 } 795 if (size != 0) { 796 ud[size].size = 0; 797 fe->value = utf8_tocstr(ud); 798 free(ud); 799 } 800 } 801 802 /* Callback for mouse_line. */ 803 static void 804 format_cb_mouse_line(struct format_tree *ft, struct format_entry *fe) 805 { 806 struct window_pane *wp; 807 u_int x, y; 808 struct grid *gd; 809 struct grid_cell gc; 810 struct utf8_data *ud = NULL; 811 size_t size = 0; 812 813 if (!ft->m.valid) 814 return; 815 wp = cmd_mouse_pane(&ft->m, NULL, NULL); 816 if (wp == NULL) 817 return; 818 if (!TAILQ_EMPTY (&wp->modes)) 819 return; 820 if (cmd_mouse_at(wp, &ft->m, &x, &y, 0) != 0) 821 return; 822 gd = wp->base.grid; 823 824 y = gd->hsize + y; 825 for (x = 0; x < grid_line_length(gd, y); x++) { 826 grid_get_cell(gd, x, y, &gc); 827 if (gc.flags & GRID_FLAG_PADDING) 828 break; 829 830 ud = xreallocarray(ud, size + 2, sizeof *ud); 831 memcpy(&ud[size++], &gc.data, sizeof *ud); 832 } 833 if (size != 0) { 834 ud[size].size = 0; 835 fe->value = utf8_tocstr(ud); 836 free(ud); 837 } 838 } 839 840 /* Merge a format tree. */ 841 static void 842 format_merge(struct format_tree *ft, struct format_tree *from) 843 { 844 struct format_entry *fe; 845 846 RB_FOREACH(fe, format_entry_tree, &from->tree) { 847 if (fe->value != NULL) 848 format_add(ft, fe->key, "%s", fe->value); 849 } 850 } 851 852 /* Add item bits to tree. */ 853 static void 854 format_create_add_item(struct format_tree *ft, struct cmdq_item *item) 855 { 856 struct mouse_event *m; 857 struct window_pane *wp; 858 u_int x, y; 859 860 if (item->cmd != NULL) 861 format_add(ft, "command", "%s", item->cmd->entry->name); 862 863 if (item->shared == NULL) 864 return; 865 if (item->shared->formats != NULL) 866 format_merge(ft, item->shared->formats); 867 868 m = &item->shared->mouse; 869 if (m->valid && ((wp = cmd_mouse_pane(m, NULL, NULL)) != NULL)) { 870 format_add(ft, "mouse_pane", "%%%u", wp->id); 871 if (cmd_mouse_at(wp, m, &x, &y, 0) == 0) { 872 format_add(ft, "mouse_x", "%u", x); 873 format_add(ft, "mouse_y", "%u", y); 874 format_add_cb(ft, "mouse_word", format_cb_mouse_word); 875 format_add_cb(ft, "mouse_line", format_cb_mouse_line); 876 } 877 } 878 memcpy(&ft->m, m, sizeof ft->m); 879 } 880 881 /* Create a new tree. */ 882 struct format_tree * 883 format_create(struct client *c, struct cmdq_item *item, int tag, int flags) 884 { 885 struct format_tree *ft; 886 const struct window_mode **wm; 887 char tmp[64]; 888 889 if (!event_initialized(&format_job_event)) { 890 evtimer_set(&format_job_event, format_job_timer, NULL); 891 format_job_timer(-1, 0, NULL); 892 } 893 894 ft = xcalloc(1, sizeof *ft); 895 RB_INIT(&ft->tree); 896 897 if (c != NULL) { 898 ft->client = c; 899 ft->client->references++; 900 } 901 ft->item = item; 902 903 ft->tag = tag; 904 ft->flags = flags; 905 ft->time = time(NULL); 906 907 format_add(ft, "version", "%s", VERSION); 908 format_add_cb(ft, "host", format_cb_host); 909 format_add_cb(ft, "host_short", format_cb_host_short); 910 format_add_cb(ft, "pid", format_cb_pid); 911 format_add(ft, "socket_path", "%s", socket_path); 912 format_add_tv(ft, "start_time", &start_time); 913 914 for (wm = all_window_modes; *wm != NULL; wm++) { 915 if ((*wm)->default_format != NULL) { 916 xsnprintf(tmp, sizeof tmp, "%s_format", (*wm)->name); 917 tmp[strcspn(tmp, "-")] = '_'; 918 format_add(ft, tmp, "%s", (*wm)->default_format); 919 } 920 } 921 922 if (item != NULL) 923 format_create_add_item(ft, item); 924 925 return (ft); 926 } 927 928 /* Free a tree. */ 929 void 930 format_free(struct format_tree *ft) 931 { 932 struct format_entry *fe, *fe1; 933 934 RB_FOREACH_SAFE(fe, format_entry_tree, &ft->tree, fe1) { 935 RB_REMOVE(format_entry_tree, &ft->tree, fe); 936 free(fe->value); 937 free(fe->key); 938 free(fe); 939 } 940 941 if (ft->client != NULL) 942 server_client_unref(ft->client); 943 free(ft); 944 } 945 946 /* Walk each format. */ 947 void 948 format_each(struct format_tree *ft, void (*cb)(const char *, const char *, 949 void *), void *arg) 950 { 951 struct format_entry *fe; 952 static char s[64]; 953 954 RB_FOREACH(fe, format_entry_tree, &ft->tree) { 955 if (fe->t != 0) { 956 xsnprintf(s, sizeof s, "%lld", (long long)fe->t); 957 cb(fe->key, fe->value, s); 958 } else { 959 if (fe->value == NULL && fe->cb != NULL) { 960 fe->cb(ft, fe); 961 if (fe->value == NULL) 962 fe->value = xstrdup(""); 963 } 964 cb(fe->key, fe->value, arg); 965 } 966 } 967 } 968 969 970 /* Add a key-value pair. */ 971 void 972 format_add(struct format_tree *ft, const char *key, const char *fmt, ...) 973 { 974 struct format_entry *fe; 975 struct format_entry *fe_now; 976 va_list ap; 977 978 fe = xmalloc(sizeof *fe); 979 fe->key = xstrdup(key); 980 981 fe_now = RB_INSERT(format_entry_tree, &ft->tree, fe); 982 if (fe_now != NULL) { 983 free(fe->key); 984 free(fe); 985 free(fe_now->value); 986 fe = fe_now; 987 } 988 989 fe->cb = NULL; 990 fe->t = 0; 991 992 va_start(ap, fmt); 993 xvasprintf(&fe->value, fmt, ap); 994 va_end(ap); 995 } 996 997 /* Add a key and time. */ 998 static void 999 format_add_tv(struct format_tree *ft, const char *key, struct timeval *tv) 1000 { 1001 struct format_entry *fe; 1002 struct format_entry *fe_now; 1003 1004 fe = xmalloc(sizeof *fe); 1005 fe->key = xstrdup(key); 1006 1007 fe_now = RB_INSERT(format_entry_tree, &ft->tree, fe); 1008 if (fe_now != NULL) { 1009 free(fe->key); 1010 free(fe); 1011 free(fe_now->value); 1012 fe = fe_now; 1013 } 1014 1015 fe->cb = NULL; 1016 fe->t = tv->tv_sec; 1017 1018 fe->value = NULL; 1019 } 1020 1021 /* Add a key and function. */ 1022 static void 1023 format_add_cb(struct format_tree *ft, const char *key, format_cb cb) 1024 { 1025 struct format_entry *fe; 1026 struct format_entry *fe_now; 1027 1028 fe = xmalloc(sizeof *fe); 1029 fe->key = xstrdup(key); 1030 1031 fe_now = RB_INSERT(format_entry_tree, &ft->tree, fe); 1032 if (fe_now != NULL) { 1033 free(fe->key); 1034 free(fe); 1035 free(fe_now->value); 1036 fe = fe_now; 1037 } 1038 1039 fe->cb = cb; 1040 fe->t = 0; 1041 1042 fe->value = NULL; 1043 } 1044 1045 /* Quote special characters in string. */ 1046 static char * 1047 format_quote(const char *s) 1048 { 1049 const char *cp; 1050 char *out, *at; 1051 1052 at = out = xmalloc(strlen(s) * 2 + 1); 1053 for (cp = s; *cp != '\0'; cp++) { 1054 if (strchr("|&;<>()$`\\\"'*?[# =%", *cp) != NULL) 1055 *at++ = '\\'; 1056 *at++ = *cp; 1057 } 1058 *at = '\0'; 1059 return (out); 1060 } 1061 1062 /* Find a format entry. */ 1063 static char * 1064 format_find(struct format_tree *ft, const char *key, int modifiers) 1065 { 1066 struct format_entry *fe, fe_find; 1067 struct environ_entry *envent; 1068 static char s[64]; 1069 struct options_entry *o; 1070 int idx; 1071 char *found, *saved; 1072 1073 if (~modifiers & FORMAT_TIMESTRING) { 1074 o = options_parse_get(global_options, key, &idx, 0); 1075 if (o == NULL && ft->wp != NULL) 1076 o = options_parse_get(ft->wp->options, key, &idx, 0); 1077 if (o == NULL && ft->w != NULL) 1078 o = options_parse_get(ft->w->options, key, &idx, 0); 1079 if (o == NULL) 1080 o = options_parse_get(global_w_options, key, &idx, 0); 1081 if (o == NULL && ft->s != NULL) 1082 o = options_parse_get(ft->s->options, key, &idx, 0); 1083 if (o == NULL) 1084 o = options_parse_get(global_s_options, key, &idx, 0); 1085 if (o != NULL) { 1086 found = options_tostring(o, idx, 1); 1087 goto found; 1088 } 1089 } 1090 found = NULL; 1091 1092 fe_find.key = __UNCONST(key); 1093 fe = RB_FIND(format_entry_tree, &ft->tree, &fe_find); 1094 if (fe != NULL) { 1095 if (modifiers & FORMAT_TIMESTRING) { 1096 if (fe->t == 0) 1097 return (NULL); 1098 ctime_r(&fe->t, s); 1099 s[strcspn(s, "\n")] = '\0'; 1100 found = xstrdup(s); 1101 goto found; 1102 } 1103 if (fe->t != 0) { 1104 xasprintf(&found, "%lld", (long long)fe->t); 1105 goto found; 1106 } 1107 if (fe->value == NULL && fe->cb != NULL) 1108 fe->cb(ft, fe); 1109 if (fe->value == NULL) 1110 fe->value = xstrdup(""); 1111 found = xstrdup(fe->value); 1112 goto found; 1113 } 1114 1115 if (~modifiers & FORMAT_TIMESTRING) { 1116 envent = NULL; 1117 if (ft->s != NULL) 1118 envent = environ_find(ft->s->environ, key); 1119 if (envent == NULL) 1120 envent = environ_find(global_environ, key); 1121 if (envent != NULL && envent->value != NULL) { 1122 found = xstrdup(envent->value); 1123 goto found; 1124 } 1125 } 1126 1127 return (NULL); 1128 1129 found: 1130 if (found == NULL) 1131 return (NULL); 1132 if (modifiers & FORMAT_BASENAME) { 1133 saved = found; 1134 found = xstrdup(basename(saved)); 1135 free(saved); 1136 } 1137 if (modifiers & FORMAT_DIRNAME) { 1138 saved = found; 1139 found = xstrdup(dirname(saved)); 1140 free(saved); 1141 } 1142 if (modifiers & FORMAT_QUOTE) { 1143 saved = found; 1144 found = xstrdup(format_quote(saved)); 1145 free(saved); 1146 } 1147 return (found); 1148 } 1149 1150 /* Skip until end. */ 1151 const char * 1152 format_skip(const char *s, const char *end) 1153 { 1154 int brackets = 0; 1155 1156 for (; *s != '\0'; s++) { 1157 if (*s == '#' && s[1] == '{') 1158 brackets++; 1159 if (*s == '#' && strchr(",#{}", s[1]) != NULL) { 1160 s++; 1161 continue; 1162 } 1163 if (*s == '}') 1164 brackets--; 1165 if (strchr(end, *s) != NULL && brackets == 0) 1166 break; 1167 } 1168 if (*s == '\0') 1169 return (NULL); 1170 return __UNCONST(s); 1171 } 1172 1173 /* Return left and right alternatives separated by commas. */ 1174 static int 1175 format_choose(struct format_tree *ft, const char *s, char **left, char **right, 1176 int expand) 1177 { 1178 const char *cp; 1179 char *left0, *right0; 1180 1181 cp = format_skip(s, ","); 1182 if (cp == NULL) 1183 return (-1); 1184 left0 = xstrndup(s, cp - s); 1185 right0 = xstrdup(cp + 1); 1186 1187 if (expand) { 1188 *left = format_expand(ft, left0); 1189 free(left0); 1190 *right = format_expand(ft, right0); 1191 free(right0); 1192 } else { 1193 *left = left0; 1194 *right = right0; 1195 } 1196 return (0); 1197 } 1198 1199 /* Is this true? */ 1200 int 1201 format_true(const char *s) 1202 { 1203 if (s != NULL && *s != '\0' && (s[0] != '0' || s[1] != '\0')) 1204 return (1); 1205 return (0); 1206 } 1207 1208 /* Check if modifier end. */ 1209 static int 1210 format_is_end(char c) 1211 { 1212 return (c == ';' || c == ':'); 1213 } 1214 1215 /* Add to modifier list. */ 1216 static void 1217 format_add_modifier(struct format_modifier **list, u_int *count, 1218 const char *c, size_t n, char **argv, int argc) 1219 { 1220 struct format_modifier *fm; 1221 1222 *list = xreallocarray(*list, (*count) + 1, sizeof **list); 1223 fm = &(*list)[(*count)++]; 1224 1225 memcpy(fm->modifier, c, n); 1226 fm->modifier[n] = '\0'; 1227 fm->size = n; 1228 1229 fm->argv = argv; 1230 fm->argc = argc; 1231 } 1232 1233 /* Free modifier list. */ 1234 static void 1235 format_free_modifiers(struct format_modifier *list, u_int count) 1236 { 1237 u_int i; 1238 1239 for (i = 0; i < count; i++) 1240 cmd_free_argv(list[i].argc, list[i].argv); 1241 free(list); 1242 } 1243 1244 /* Build modifier list. */ 1245 static struct format_modifier * 1246 format_build_modifiers(struct format_tree *ft, const char **s, u_int *count) 1247 { 1248 const char *cp = *s, *end; 1249 struct format_modifier *list = NULL; 1250 char c, last[] = "X;:", **argv, *value; 1251 int argc; 1252 1253 /* 1254 * Modifiers are a ; separated list of the forms: 1255 * l,m,C,b,d,t,q,E,T,S,W,P,<,> 1256 * =a 1257 * =/a 1258 * =/a/ 1259 * s/a/b/ 1260 * s/a/b 1261 * ||,&&,!=,==,<=,>= 1262 */ 1263 1264 *count = 0; 1265 1266 while (*cp != '\0' && *cp != ':') { 1267 /* Skip and separator character. */ 1268 if (*cp == ';') 1269 cp++; 1270 1271 /* Check single character modifiers with no arguments. */ 1272 if (strchr("lbdtqETSWP<>", cp[0]) != NULL && 1273 format_is_end(cp[1])) { 1274 format_add_modifier(&list, count, cp, 1, NULL, 0); 1275 cp++; 1276 continue; 1277 } 1278 1279 /* Then try double character with no arguments. */ 1280 if ((memcmp("||", cp, 2) == 0 || 1281 memcmp("&&", cp, 2) == 0 || 1282 memcmp("!=", cp, 2) == 0 || 1283 memcmp("==", cp, 2) == 0 || 1284 memcmp("<=", cp, 2) == 0 || 1285 memcmp(">=", cp, 2) == 0) && 1286 format_is_end(cp[2])) { 1287 format_add_modifier(&list, count, cp, 2, NULL, 0); 1288 cp += 2; 1289 continue; 1290 } 1291 1292 /* Now try single character with arguments. */ 1293 if (strchr("mCs=", cp[0]) == NULL) 1294 break; 1295 c = cp[0]; 1296 1297 /* No arguments provided. */ 1298 if (format_is_end(cp[1])) { 1299 format_add_modifier(&list, count, cp, 1, NULL, 0); 1300 cp++; 1301 continue; 1302 } 1303 argv = NULL; 1304 argc = 0; 1305 1306 /* Single argument with no wrapper character. */ 1307 if (!ispunct((unsigned char)cp[1]) || cp[1] == '-') { 1308 end = format_skip(cp + 1, ":;"); 1309 if (end == NULL) 1310 break; 1311 1312 argv = xcalloc(1, sizeof *argv); 1313 value = xstrndup(cp + 1, end - (cp + 1)); 1314 argv[0] = format_expand(ft, value); 1315 free(value); 1316 argc = 1; 1317 1318 format_add_modifier(&list, count, &c, 1, argv, argc); 1319 cp = end; 1320 continue; 1321 } 1322 1323 /* Multiple arguments with a wrapper character. */ 1324 last[0] = cp[1]; 1325 cp++; 1326 do { 1327 if (cp[0] == last[0] && format_is_end(cp[1])) { 1328 cp++; 1329 break; 1330 } 1331 end = format_skip(cp + 1, last); 1332 if (end == NULL) 1333 break; 1334 cp++; 1335 1336 argv = xreallocarray (argv, argc + 1, sizeof *argv); 1337 value = xstrndup(cp, end - cp); 1338 argv[argc++] = format_expand(ft, value); 1339 free(value); 1340 1341 cp = end; 1342 } while (!format_is_end(cp[0])); 1343 format_add_modifier(&list, count, &c, 1, argv, argc); 1344 } 1345 if (*cp != ':') { 1346 format_free_modifiers(list, *count); 1347 *count = 0; 1348 return (NULL); 1349 } 1350 *s = cp + 1; 1351 return list; 1352 } 1353 1354 /* Match against an fnmatch(3) pattern or regular expression. */ 1355 static char * 1356 format_match(struct format_modifier *fm, const char *pattern, const char *text) 1357 { 1358 const char *s = ""; 1359 regex_t r; 1360 int flags = 0; 1361 1362 if (fm->argc >= 1) 1363 s = fm->argv[0]; 1364 if (strchr(s, 'r') == NULL) { 1365 if (strchr(s, 'i') != NULL) 1366 flags |= FNM_CASEFOLD; 1367 if (fnmatch(pattern, text, flags) != 0) 1368 return (xstrdup("0")); 1369 } else { 1370 flags = REG_EXTENDED|REG_NOSUB; 1371 if (strchr(s, 'i') != NULL) 1372 flags |= REG_ICASE; 1373 if (regcomp(&r, pattern, flags) != 0) 1374 return (xstrdup("0")); 1375 if (regexec(&r, text, 0, NULL, 0) != 0) { 1376 regfree(&r); 1377 return (xstrdup("0")); 1378 } 1379 regfree(&r); 1380 } 1381 return (xstrdup("1")); 1382 } 1383 1384 /* Perform substitution in string. */ 1385 static char * 1386 format_sub(struct format_modifier *fm, const char *text, const char *pattern, 1387 const char *with) 1388 { 1389 char *value; 1390 int flags = REG_EXTENDED; 1391 1392 if (fm->argc >= 3 && strchr(fm->argv[2], 'i') != NULL) 1393 flags |= REG_ICASE; 1394 value = regsub(pattern, with, text, flags); 1395 if (value == NULL) 1396 return (xstrdup(text)); 1397 return (value); 1398 } 1399 1400 /* Search inside pane. */ 1401 static char * 1402 format_search(struct format_modifier *fm, struct window_pane *wp, const char *s) 1403 { 1404 int ignore = 0, regex = 0; 1405 char *value; 1406 1407 if (fm->argc >= 1) { 1408 if (strchr(fm->argv[0], 'i') != NULL) 1409 ignore = 1; 1410 if (strchr(fm->argv[0], 'r') != NULL) 1411 regex = 1; 1412 } 1413 xasprintf(&value, "%u", window_pane_search(wp, s, regex, ignore)); 1414 return (value); 1415 } 1416 1417 /* Loop over sessions. */ 1418 static char * 1419 format_loop_sessions(struct format_tree *ft, const char *fmt) 1420 { 1421 struct client *c = ft->client; 1422 struct cmdq_item *item = ft->item; 1423 struct format_tree *nft; 1424 char *expanded, *value; 1425 size_t valuelen; 1426 struct session *s; 1427 1428 value = xcalloc(1, 1); 1429 valuelen = 1; 1430 1431 RB_FOREACH(s, sessions, &sessions) { 1432 format_log(ft, "session loop: $%u", s->id); 1433 nft = format_create(c, item, FORMAT_NONE, ft->flags); 1434 nft->loop = ft->loop; 1435 format_defaults(nft, ft->c, s, NULL, NULL); 1436 expanded = format_expand(nft, fmt); 1437 format_free(nft); 1438 1439 valuelen += strlen(expanded); 1440 value = xrealloc(value, valuelen); 1441 1442 strlcat(value, expanded, valuelen); 1443 free(expanded); 1444 } 1445 1446 return (value); 1447 } 1448 1449 /* Loop over windows. */ 1450 static char * 1451 format_loop_windows(struct format_tree *ft, const char *fmt) 1452 { 1453 struct client *c = ft->client; 1454 struct cmdq_item *item = ft->item; 1455 struct format_tree *nft; 1456 char *all, *active, *use, *expanded, *value; 1457 size_t valuelen; 1458 struct winlink *wl; 1459 struct window *w; 1460 1461 if (ft->s == NULL) { 1462 format_log(ft, "window loop but no session"); 1463 return (NULL); 1464 } 1465 1466 if (format_choose(ft, fmt, &all, &active, 0) != 0) { 1467 all = xstrdup(fmt); 1468 active = NULL; 1469 } 1470 1471 value = xcalloc(1, 1); 1472 valuelen = 1; 1473 1474 RB_FOREACH(wl, winlinks, &ft->s->windows) { 1475 w = wl->window; 1476 format_log(ft, "window loop: %u @%u", wl->idx, w->id); 1477 if (active != NULL && wl == ft->s->curw) 1478 use = active; 1479 else 1480 use = all; 1481 nft = format_create(c, item, FORMAT_WINDOW|w->id, ft->flags); 1482 nft->loop = ft->loop; 1483 format_defaults(nft, ft->c, ft->s, wl, NULL); 1484 expanded = format_expand(nft, use); 1485 format_free(nft); 1486 1487 valuelen += strlen(expanded); 1488 value = xrealloc(value, valuelen); 1489 1490 strlcat(value, expanded, valuelen); 1491 free(expanded); 1492 } 1493 1494 free(active); 1495 free(all); 1496 1497 return (value); 1498 } 1499 1500 /* Loop over panes. */ 1501 static char * 1502 format_loop_panes(struct format_tree *ft, const char *fmt) 1503 { 1504 struct client *c = ft->client; 1505 struct cmdq_item *item = ft->item; 1506 struct format_tree *nft; 1507 char *all, *active, *use, *expanded, *value; 1508 size_t valuelen; 1509 struct window_pane *wp; 1510 1511 if (ft->w == NULL) { 1512 format_log(ft, "pane loop but no window"); 1513 return (NULL); 1514 } 1515 1516 if (format_choose(ft, fmt, &all, &active, 0) != 0) { 1517 all = xstrdup(fmt); 1518 active = NULL; 1519 } 1520 1521 value = xcalloc(1, 1); 1522 valuelen = 1; 1523 1524 TAILQ_FOREACH(wp, &ft->w->panes, entry) { 1525 format_log(ft, "pane loop: %%%u", wp->id); 1526 if (active != NULL && wp == ft->w->active) 1527 use = active; 1528 else 1529 use = all; 1530 nft = format_create(c, item, FORMAT_PANE|wp->id, ft->flags); 1531 nft->loop = ft->loop; 1532 format_defaults(nft, ft->c, ft->s, ft->wl, wp); 1533 expanded = format_expand(nft, use); 1534 format_free(nft); 1535 1536 valuelen += strlen(expanded); 1537 value = xrealloc(value, valuelen); 1538 1539 strlcat(value, expanded, valuelen); 1540 free(expanded); 1541 } 1542 1543 free(active); 1544 free(all); 1545 1546 return (value); 1547 } 1548 1549 /* Replace a key. */ 1550 static int 1551 format_replace(struct format_tree *ft, const char *key, size_t keylen, 1552 char **buf, size_t *len, size_t *off) 1553 { 1554 struct window_pane *wp = ft->wp; 1555 const char *errptr, *copy, *cp, *marker = NULL; 1556 char *copy0, *condition, *found, *new; 1557 char *value, *left, *right; 1558 size_t valuelen; 1559 int modifiers = 0, limit = 0, j; 1560 struct format_modifier *list, *fm, *cmp = NULL, *search = NULL; 1561 struct format_modifier *sub = NULL; 1562 u_int i, count; 1563 1564 /* Make a copy of the key. */ 1565 copy = copy0 = xstrndup(key, keylen); 1566 1567 /* Process modifier list. */ 1568 list = format_build_modifiers(ft, ©, &count); 1569 for (i = 0; i < count; i++) { 1570 fm = &list[i]; 1571 if (format_logging(ft)) { 1572 format_log(ft, "modifier %u is %s", i, fm->modifier); 1573 for (j = 0; j < fm->argc; j++) { 1574 format_log(ft, "modifier %u argument %d: %s", i, 1575 j, fm->argv[j]); 1576 } 1577 } 1578 if (fm->size == 1) { 1579 switch (fm->modifier[0]) { 1580 case 'm': 1581 case '<': 1582 case '>': 1583 cmp = fm; 1584 break; 1585 case 'C': 1586 search = fm; 1587 break; 1588 case 's': 1589 if (fm->argc < 2) 1590 break; 1591 sub = fm; 1592 break; 1593 case '=': 1594 if (fm->argc < 1) 1595 break; 1596 limit = strtonum(fm->argv[0], INT_MIN, INT_MAX, 1597 &errptr); 1598 if (errptr != NULL) 1599 limit = 0; 1600 if (fm->argc >= 2 && fm->argv[1] != NULL) 1601 marker = fm->argv[1]; 1602 break; 1603 case 'l': 1604 modifiers |= FORMAT_LITERAL; 1605 break; 1606 case 'b': 1607 modifiers |= FORMAT_BASENAME; 1608 break; 1609 case 'd': 1610 modifiers |= FORMAT_DIRNAME; 1611 break; 1612 case 't': 1613 modifiers |= FORMAT_TIMESTRING; 1614 break; 1615 case 'q': 1616 modifiers |= FORMAT_QUOTE; 1617 break; 1618 case 'E': 1619 modifiers |= FORMAT_EXPAND; 1620 break; 1621 case 'T': 1622 modifiers |= FORMAT_EXPANDTIME; 1623 break; 1624 case 'S': 1625 modifiers |= FORMAT_SESSIONS; 1626 break; 1627 case 'W': 1628 modifiers |= FORMAT_WINDOWS; 1629 break; 1630 case 'P': 1631 modifiers |= FORMAT_PANES; 1632 break; 1633 } 1634 } else if (fm->size == 2) { 1635 if (strcmp(fm->modifier, "||") == 0 || 1636 strcmp(fm->modifier, "&&") == 0 || 1637 strcmp(fm->modifier, "==") == 0 || 1638 strcmp(fm->modifier, "!=") == 0 || 1639 strcmp(fm->modifier, ">=") == 0 || 1640 strcmp(fm->modifier, "<=") == 0) 1641 cmp = fm; 1642 } 1643 } 1644 1645 /* Is this a literal string? */ 1646 if (modifiers & FORMAT_LITERAL) { 1647 value = xstrdup(copy); 1648 goto done; 1649 } 1650 1651 /* Is this a loop, comparison or condition? */ 1652 if (modifiers & FORMAT_SESSIONS) { 1653 value = format_loop_sessions(ft, copy); 1654 if (value == NULL) 1655 goto fail; 1656 } else if (modifiers & FORMAT_WINDOWS) { 1657 value = format_loop_windows(ft, copy); 1658 if (value == NULL) 1659 goto fail; 1660 } else if (modifiers & FORMAT_PANES) { 1661 value = format_loop_panes(ft, copy); 1662 if (value == NULL) 1663 goto fail; 1664 } else if (search != NULL) { 1665 /* Search in pane. */ 1666 new = format_expand(ft, copy); 1667 if (wp == NULL) { 1668 format_log(ft, "search '%s' but no pane", new); 1669 value = xstrdup("0"); 1670 } else { 1671 format_log(ft, "search '%s' pane %%%u", new, wp->id); 1672 value = format_search(fm, wp, new); 1673 } 1674 free(new); 1675 } else if (cmp != NULL) { 1676 /* Comparison of left and right. */ 1677 if (format_choose(ft, copy, &left, &right, 1) != 0) { 1678 format_log(ft, "compare %s syntax error: %s", 1679 cmp->modifier, copy); 1680 goto fail; 1681 } 1682 format_log(ft, "compare %s left is: %s", cmp->modifier, left); 1683 format_log(ft, "compare %s right is: %s", cmp->modifier, right); 1684 1685 if (strcmp(cmp->modifier, "||") == 0) { 1686 if (format_true(left) || format_true(right)) 1687 value = xstrdup("1"); 1688 else 1689 value = xstrdup("0"); 1690 } else if (strcmp(cmp->modifier, "&&") == 0) { 1691 if (format_true(left) && format_true(right)) 1692 value = xstrdup("1"); 1693 else 1694 value = xstrdup("0"); 1695 } else if (strcmp(cmp->modifier, "==") == 0) { 1696 if (strcmp(left, right) == 0) 1697 value = xstrdup("1"); 1698 else 1699 value = xstrdup("0"); 1700 } else if (strcmp(cmp->modifier, "!=") == 0) { 1701 if (strcmp(left, right) != 0) 1702 value = xstrdup("1"); 1703 else 1704 value = xstrdup("0"); 1705 } else if (strcmp(cmp->modifier, "<") == 0) { 1706 if (strcmp(left, right) < 0) 1707 value = xstrdup("1"); 1708 else 1709 value = xstrdup("0"); 1710 } else if (strcmp(cmp->modifier, ">") == 0) { 1711 if (strcmp(left, right) > 0) 1712 value = xstrdup("1"); 1713 else 1714 value = xstrdup("0"); 1715 } else if (strcmp(cmp->modifier, "<=") == 0) { 1716 if (strcmp(left, right) <= 0) 1717 value = xstrdup("1"); 1718 else 1719 value = xstrdup("0"); 1720 } else if (strcmp(cmp->modifier, ">=") == 0) { 1721 if (strcmp(left, right) >= 0) 1722 value = xstrdup("1"); 1723 else 1724 value = xstrdup("0"); 1725 } else if (strcmp(cmp->modifier, "m") == 0) 1726 value = format_match(cmp, left, right); 1727 1728 free(right); 1729 free(left); 1730 } else if (*copy == '?') { 1731 /* Conditional: check first and choose second or third. */ 1732 cp = format_skip(copy + 1, ","); 1733 if (cp == NULL) { 1734 format_log(ft, "condition syntax error: %s", copy + 1); 1735 goto fail; 1736 } 1737 condition = xstrndup(copy + 1, cp - (copy + 1)); 1738 format_log(ft, "condition is: %s", condition); 1739 1740 found = format_find(ft, condition, modifiers); 1741 if (found == NULL) { 1742 /* 1743 * If the condition not found, try to expand it. If 1744 * the expansion doesn't have any effect, then assume 1745 * false. 1746 */ 1747 found = format_expand(ft, condition); 1748 if (strcmp(found, condition) == 0) { 1749 free(found); 1750 found = xstrdup(""); 1751 format_log(ft, "condition '%s' found: %s", 1752 condition, found); 1753 } else { 1754 format_log(ft, 1755 "condition '%s' not found; assuming false", 1756 condition); 1757 } 1758 } else 1759 format_log(ft, "condition '%s' found", condition); 1760 1761 if (format_choose(ft, cp + 1, &left, &right, 0) != 0) { 1762 format_log(ft, "condition '%s' syntax error: %s", 1763 condition, cp + 1); 1764 free(found); 1765 goto fail; 1766 } 1767 if (format_true(found)) { 1768 format_log(ft, "condition '%s' is true", condition); 1769 value = format_expand(ft, left); 1770 } else { 1771 format_log(ft, "condition '%s' is false", condition); 1772 value = format_expand(ft, right); 1773 } 1774 free(right); 1775 free(left); 1776 1777 free(condition); 1778 free(found); 1779 } else { 1780 /* Neither: look up directly. */ 1781 value = format_find(ft, copy, modifiers); 1782 if (value == NULL) { 1783 format_log(ft, "format '%s' not found", copy); 1784 value = xstrdup(""); 1785 } else 1786 format_log(ft, "format '%s' found: %s", copy, value); 1787 } 1788 1789 done: 1790 /* Expand again if required. */ 1791 if (modifiers & FORMAT_EXPAND) { 1792 new = format_expand(ft, value); 1793 free(value); 1794 value = new; 1795 } 1796 else if (modifiers & FORMAT_EXPANDTIME) { 1797 new = format_expand_time(ft, value); 1798 free(value); 1799 value = new; 1800 } 1801 1802 /* Perform substitution if any. */ 1803 if (sub != NULL) { 1804 left = format_expand(ft, sub->argv[0]); 1805 right = format_expand(ft, sub->argv[1]); 1806 new = format_sub(sub, value, left, right); 1807 format_log(ft, "substitute '%s' to '%s': %s", left, right, new); 1808 free(value); 1809 value = new; 1810 free(right); 1811 free(left); 1812 } 1813 1814 /* Truncate the value if needed. */ 1815 if (limit > 0) { 1816 new = format_trim_left(value, limit); 1817 if (marker != NULL && strcmp(new, value) != 0) { 1818 free(value); 1819 xasprintf(&value, "%s%s", new, marker); 1820 } else { 1821 free(value); 1822 value = new; 1823 } 1824 format_log(ft, "applied length limit %d: %s", limit, value); 1825 } else if (limit < 0) { 1826 new = format_trim_right(value, -limit); 1827 if (marker != NULL && strcmp(new, value) != 0) { 1828 free(value); 1829 xasprintf(&value, "%s%s", marker, new); 1830 } else { 1831 free(value); 1832 value = new; 1833 } 1834 format_log(ft, "applied length limit %d: %s", limit, value); 1835 } 1836 1837 /* Expand the buffer and copy in the value. */ 1838 valuelen = strlen(value); 1839 while (*len - *off < valuelen + 1) { 1840 *buf = xreallocarray(*buf, 2, *len); 1841 *len *= 2; 1842 } 1843 memcpy(*buf + *off, value, valuelen); 1844 *off += valuelen; 1845 1846 format_log(ft, "replaced '%s' with '%s'", copy0, value); 1847 free(value); 1848 1849 format_free_modifiers(list, count); 1850 free(copy0); 1851 return (0); 1852 1853 fail: 1854 format_log(ft, "failed %s", copy0); 1855 format_free_modifiers(list, count); 1856 free(copy0); 1857 return (-1); 1858 } 1859 1860 /* Expand keys in a template. */ 1861 static char * 1862 format_expand1(struct format_tree *ft, const char *fmt, int time) 1863 { 1864 char *buf, *out, *name; 1865 const char *ptr, *s; 1866 size_t off, len, n, outlen; 1867 int ch, brackets; 1868 struct tm *tm; 1869 char expanded[8192]; 1870 1871 if (fmt == NULL || *fmt == '\0') 1872 return (xstrdup("")); 1873 1874 if (ft->loop == FORMAT_LOOP_LIMIT) 1875 return (xstrdup("")); 1876 ft->loop++; 1877 1878 format_log(ft, "expanding format: %s", fmt); 1879 1880 if (time) { 1881 tm = localtime(&ft->time); 1882 if (strftime(expanded, sizeof expanded, fmt, tm) == 0) { 1883 format_log(ft, "format is too long"); 1884 return (xstrdup("")); 1885 } 1886 if (format_logging(ft) && strcmp(expanded, fmt) != 0) 1887 format_log(ft, "after time expanded: %s", expanded); 1888 fmt = expanded; 1889 } 1890 1891 len = 64; 1892 buf = xmalloc(len); 1893 off = 0; 1894 1895 while (*fmt != '\0') { 1896 if (*fmt != '#') { 1897 while (len - off < 2) { 1898 buf = xreallocarray(buf, 2, len); 1899 len *= 2; 1900 } 1901 buf[off++] = *fmt++; 1902 continue; 1903 } 1904 fmt++; 1905 1906 ch = (u_char)*fmt++; 1907 switch (ch) { 1908 case '(': 1909 brackets = 1; 1910 for (ptr = fmt; *ptr != '\0'; ptr++) { 1911 if (*ptr == '(') 1912 brackets++; 1913 if (*ptr == ')' && --brackets == 0) 1914 break; 1915 } 1916 if (*ptr != ')' || brackets != 0) 1917 break; 1918 n = ptr - fmt; 1919 1920 name = xstrndup(fmt, n); 1921 format_log(ft, "found #(): %s", name); 1922 1923 if (ft->flags & FORMAT_NOJOBS) { 1924 out = xstrdup(""); 1925 format_log(ft, "#() is disabled"); 1926 } else { 1927 out = format_job_get(ft, name); 1928 format_log(ft, "#() result: %s", out); 1929 } 1930 free(name); 1931 1932 outlen = strlen(out); 1933 while (len - off < outlen + 1) { 1934 buf = xreallocarray(buf, 2, len); 1935 len *= 2; 1936 } 1937 memcpy(buf + off, out, outlen); 1938 off += outlen; 1939 1940 free(out); 1941 1942 fmt += n + 1; 1943 continue; 1944 case '{': 1945 ptr = format_skip((const char *)fmt - 2, "}"); 1946 if (ptr == NULL) 1947 break; 1948 n = ptr - fmt; 1949 1950 format_log(ft, "found #{}: %.*s", (int)n, fmt); 1951 if (format_replace(ft, fmt, n, &buf, &len, &off) != 0) 1952 break; 1953 fmt += n + 1; 1954 continue; 1955 case '}': 1956 case '#': 1957 case ',': 1958 format_log(ft, "found #%c", ch); 1959 while (len - off < 2) { 1960 buf = xreallocarray(buf, 2, len); 1961 len *= 2; 1962 } 1963 buf[off++] = ch; 1964 continue; 1965 default: 1966 s = NULL; 1967 if (ch >= 'A' && ch <= 'Z') 1968 s = format_upper[ch - 'A']; 1969 else if (ch >= 'a' && ch <= 'z') 1970 s = format_lower[ch - 'a']; 1971 if (s == NULL) { 1972 while (len - off < 3) { 1973 buf = xreallocarray(buf, 2, len); 1974 len *= 2; 1975 } 1976 buf[off++] = '#'; 1977 buf[off++] = ch; 1978 continue; 1979 } 1980 n = strlen(s); 1981 format_log(ft, "found #%c: %s", ch, s); 1982 if (format_replace(ft, s, n, &buf, &len, &off) != 0) 1983 break; 1984 continue; 1985 } 1986 1987 break; 1988 } 1989 buf[off] = '\0'; 1990 1991 format_log(ft, "result is: %s", buf); 1992 ft->loop--; 1993 1994 return (buf); 1995 } 1996 1997 /* Expand keys in a template, passing through strftime first. */ 1998 char * 1999 format_expand_time(struct format_tree *ft, const char *fmt) 2000 { 2001 return (format_expand1(ft, fmt, 1)); 2002 } 2003 2004 /* Expand keys in a template. */ 2005 char * 2006 format_expand(struct format_tree *ft, const char *fmt) 2007 { 2008 return (format_expand1(ft, fmt, 0)); 2009 } 2010 2011 /* Expand a single string. */ 2012 char * 2013 format_single(struct cmdq_item *item, const char *fmt, struct client *c, 2014 struct session *s, struct winlink *wl, struct window_pane *wp) 2015 { 2016 struct format_tree *ft; 2017 char *expanded; 2018 2019 if (item != NULL) 2020 ft = format_create(item->client, item, FORMAT_NONE, 0); 2021 else 2022 ft = format_create(NULL, item, FORMAT_NONE, 0); 2023 format_defaults(ft, c, s, wl, wp); 2024 2025 expanded = format_expand(ft, fmt); 2026 format_free(ft); 2027 return (expanded); 2028 } 2029 2030 /* Set defaults for any of arguments that are not NULL. */ 2031 void 2032 format_defaults(struct format_tree *ft, struct client *c, struct session *s, 2033 struct winlink *wl, struct window_pane *wp) 2034 { 2035 if (c != NULL && c->name != NULL) 2036 log_debug("%s: c=%s", __func__, c->name); 2037 else 2038 log_debug("%s: c=none", __func__); 2039 if (s != NULL) 2040 log_debug("%s: s=$%u", __func__, s->id); 2041 else 2042 log_debug("%s: s=none", __func__); 2043 if (wl != NULL) 2044 log_debug("%s: wl=%u w=@%u", __func__, wl->idx, wl->window->id); 2045 else 2046 log_debug("%s: wl=none", __func__); 2047 if (wp != NULL) 2048 log_debug("%s: wp=%%%u", __func__, wp->id); 2049 else 2050 log_debug("%s: wp=none", __func__); 2051 2052 if (c != NULL && s != NULL && c->session != s) 2053 log_debug("%s: session does not match", __func__); 2054 2055 format_add(ft, "session_format", "%d", s != NULL); 2056 format_add(ft, "window_format", "%d", wl != NULL); 2057 format_add(ft, "pane_format", "%d", wp != NULL); 2058 2059 if (s == NULL && c != NULL) 2060 s = c->session; 2061 if (wl == NULL && s != NULL) 2062 wl = s->curw; 2063 if (wp == NULL && wl != NULL) 2064 wp = wl->window->active; 2065 2066 if (c != NULL) 2067 format_defaults_client(ft, c); 2068 if (s != NULL) 2069 format_defaults_session(ft, s); 2070 if (wl != NULL) 2071 format_defaults_winlink(ft, wl); 2072 if (wp != NULL) 2073 format_defaults_pane(ft, wp); 2074 } 2075 2076 /* Set default format keys for a session. */ 2077 static void 2078 format_defaults_session(struct format_tree *ft, struct session *s) 2079 { 2080 struct session_group *sg; 2081 2082 ft->s = s; 2083 2084 format_add(ft, "session_name", "%s", s->name); 2085 format_add(ft, "session_windows", "%u", winlink_count(&s->windows)); 2086 format_add(ft, "session_id", "$%u", s->id); 2087 2088 sg = session_group_contains(s); 2089 format_add(ft, "session_grouped", "%d", sg != NULL); 2090 if (sg != NULL) { 2091 format_add(ft, "session_group", "%s", sg->name); 2092 format_add(ft, "session_group_size", "%u", 2093 session_group_count (sg)); 2094 format_add_cb(ft, "session_group_list", 2095 format_cb_session_group_list); 2096 } 2097 2098 format_add_tv(ft, "session_created", &s->creation_time); 2099 format_add_tv(ft, "session_last_attached", &s->last_attached_time); 2100 format_add_tv(ft, "session_activity", &s->activity_time); 2101 2102 format_add(ft, "session_attached", "%u", s->attached); 2103 format_add(ft, "session_many_attached", "%d", s->attached > 1); 2104 2105 format_add_cb(ft, "session_alerts", format_cb_session_alerts); 2106 format_add_cb(ft, "session_stack", format_cb_session_stack); 2107 } 2108 2109 /* Set default format keys for a client. */ 2110 static void 2111 format_defaults_client(struct format_tree *ft, struct client *c) 2112 { 2113 struct session *s; 2114 const char *name; 2115 struct tty *tty = &c->tty; 2116 const char *types[] = TTY_TYPES; 2117 2118 if (ft->s == NULL) 2119 ft->s = c->session; 2120 ft->c = c; 2121 2122 format_add(ft, "client_name", "%s", c->name); 2123 format_add(ft, "client_pid", "%ld", (long) c->pid); 2124 format_add(ft, "client_height", "%u", tty->sy); 2125 format_add(ft, "client_width", "%u", tty->sx); 2126 format_add(ft, "client_tty", "%s", c->ttyname); 2127 format_add(ft, "client_control_mode", "%d", 2128 !!(c->flags & CLIENT_CONTROL)); 2129 2130 if (tty->term_name != NULL) 2131 format_add(ft, "client_termname", "%s", tty->term_name); 2132 if (tty->term_name != NULL) 2133 format_add(ft, "client_termtype", "%s", types[tty->term_type]); 2134 2135 format_add_tv(ft, "client_created", &c->creation_time); 2136 format_add_tv(ft, "client_activity", &c->activity_time); 2137 2138 format_add(ft, "client_written", "%zu", c->written); 2139 format_add(ft, "client_discarded", "%zu", c->discarded); 2140 2141 name = server_client_get_key_table(c); 2142 if (strcmp(c->keytable->name, name) == 0) 2143 format_add(ft, "client_prefix", "%d", 0); 2144 else 2145 format_add(ft, "client_prefix", "%d", 1); 2146 format_add(ft, "client_key_table", "%s", c->keytable->name); 2147 2148 if (tty->flags & TTY_UTF8) 2149 format_add(ft, "client_utf8", "%d", 1); 2150 else 2151 format_add(ft, "client_utf8", "%d", 0); 2152 2153 if (c->flags & CLIENT_READONLY) 2154 format_add(ft, "client_readonly", "%d", 1); 2155 else 2156 format_add(ft, "client_readonly", "%d", 0); 2157 2158 s = c->session; 2159 if (s != NULL) 2160 format_add(ft, "client_session", "%s", s->name); 2161 s = c->last_session; 2162 if (s != NULL && session_alive(s)) 2163 format_add(ft, "client_last_session", "%s", s->name); 2164 } 2165 2166 /* Set default format keys for a window. */ 2167 void 2168 format_defaults_window(struct format_tree *ft, struct window *w) 2169 { 2170 ft->w = w; 2171 2172 format_add_tv(ft, "window_activity", &w->activity_time); 2173 format_add(ft, "window_id", "@%u", w->id); 2174 format_add(ft, "window_name", "%s", w->name); 2175 format_add(ft, "window_width", "%u", w->sx); 2176 format_add(ft, "window_height", "%u", w->sy); 2177 format_add_cb(ft, "window_layout", format_cb_window_layout); 2178 format_add_cb(ft, "window_visible_layout", 2179 format_cb_window_visible_layout); 2180 format_add(ft, "window_panes", "%u", window_count_panes(w)); 2181 format_add(ft, "window_zoomed_flag", "%d", 2182 !!(w->flags & WINDOW_ZOOMED)); 2183 } 2184 2185 /* Set default format keys for a winlink. */ 2186 static void 2187 format_defaults_winlink(struct format_tree *ft, struct winlink *wl) 2188 { 2189 struct client *c = ft->c; 2190 struct session *s = wl->session; 2191 struct window *w = wl->window; 2192 int flag; 2193 u_int ox, oy, sx, sy; 2194 2195 if (ft->w == NULL) 2196 ft->w = wl->window; 2197 ft->wl = wl; 2198 2199 format_defaults_window(ft, w); 2200 2201 if (c != NULL) { 2202 flag = tty_window_offset(&c->tty, &ox, &oy, &sx, &sy); 2203 format_add(ft, "window_bigger", "%d", flag); 2204 if (flag) { 2205 format_add(ft, "window_offset_x", "%u", ox); 2206 format_add(ft, "window_offset_y", "%u", oy); 2207 } 2208 } 2209 2210 format_add(ft, "window_index", "%d", wl->idx); 2211 format_add_cb(ft, "window_stack_index", format_cb_window_stack_index); 2212 format_add(ft, "window_flags", "%s", window_printable_flags(wl)); 2213 format_add(ft, "window_active", "%d", wl == s->curw); 2214 2215 format_add(ft, "window_start_flag", "%d", 2216 !!(wl == RB_MIN(winlinks, &s->windows))); 2217 format_add(ft, "window_end_flag", "%d", 2218 !!(wl == RB_MAX(winlinks, &s->windows))); 2219 2220 format_add(ft, "window_bell_flag", "%d", 2221 !!(wl->flags & WINLINK_BELL)); 2222 format_add(ft, "window_activity_flag", "%d", 2223 !!(wl->flags & WINLINK_ACTIVITY)); 2224 format_add(ft, "window_silence_flag", "%d", 2225 !!(wl->flags & WINLINK_SILENCE)); 2226 format_add(ft, "window_last_flag", "%d", 2227 !!(wl == TAILQ_FIRST(&s->lastw))); 2228 format_add(ft, "window_linked", "%d", session_is_linked(s, wl->window)); 2229 } 2230 2231 /* Set default format keys for a window pane. */ 2232 void 2233 format_defaults_pane(struct format_tree *ft, struct window_pane *wp) 2234 { 2235 struct window *w = wp->window; 2236 struct grid *gd = wp->base.grid; 2237 int status = wp->status; 2238 u_int idx; 2239 struct window_mode_entry *wme; 2240 2241 if (ft->w == NULL) 2242 ft->w = w; 2243 ft->wp = wp; 2244 2245 format_add(ft, "history_size", "%u", gd->hsize); 2246 format_add(ft, "history_limit", "%u", gd->hlimit); 2247 format_add_cb(ft, "history_bytes", format_cb_history_bytes); 2248 2249 if (window_pane_index(wp, &idx) != 0) 2250 fatalx("index not found"); 2251 format_add(ft, "pane_index", "%u", idx); 2252 2253 format_add(ft, "pane_width", "%u", wp->sx); 2254 format_add(ft, "pane_height", "%u", wp->sy); 2255 format_add(ft, "pane_title", "%s", wp->base.title); 2256 format_add(ft, "pane_id", "%%%u", wp->id); 2257 format_add(ft, "pane_active", "%d", wp == w->active); 2258 format_add(ft, "pane_input_off", "%d", !!(wp->flags & PANE_INPUTOFF)); 2259 format_add(ft, "pane_pipe", "%d", wp->pipe_fd != -1); 2260 2261 if ((wp->flags & PANE_STATUSREADY) && WIFEXITED(status)) 2262 format_add(ft, "pane_dead_status", "%d", WEXITSTATUS(status)); 2263 if (~wp->flags & PANE_EMPTY) 2264 format_add(ft, "pane_dead", "%d", wp->fd == -1); 2265 else 2266 format_add(ft, "pane_dead", "0"); 2267 2268 if (server_check_marked() && marked_pane.wp == wp) 2269 format_add(ft, "pane_marked", "1"); 2270 else 2271 format_add(ft, "pane_marked", "0"); 2272 format_add(ft, "pane_marked_set", "%d", server_check_marked()); 2273 2274 format_add(ft, "pane_left", "%u", wp->xoff); 2275 format_add(ft, "pane_top", "%u", wp->yoff); 2276 format_add(ft, "pane_right", "%u", wp->xoff + wp->sx - 1); 2277 format_add(ft, "pane_bottom", "%u", wp->yoff + wp->sy - 1); 2278 format_add(ft, "pane_at_left", "%d", wp->xoff == 0); 2279 format_add(ft, "pane_at_top", "%d", wp->yoff == 0); 2280 format_add(ft, "pane_at_right", "%d", wp->xoff + wp->sx == w->sx); 2281 format_add(ft, "pane_at_bottom", "%d", wp->yoff + wp->sy == w->sy); 2282 2283 wme = TAILQ_FIRST(&wp->modes); 2284 if (wme != NULL) { 2285 format_add(ft, "pane_mode", "%s", wme->mode->name); 2286 if (wme->mode->formats != NULL) 2287 wme->mode->formats(wme, ft); 2288 } 2289 format_add_cb(ft, "pane_in_mode", format_cb_pane_in_mode); 2290 2291 format_add(ft, "pane_synchronized", "%d", 2292 !!options_get_number(w->options, "synchronize-panes")); 2293 if (wp->searchstr != NULL) 2294 format_add(ft, "pane_search_string", "%s", wp->searchstr); 2295 2296 format_add(ft, "pane_tty", "%s", wp->tty); 2297 format_add(ft, "pane_pid", "%ld", (long) wp->pid); 2298 format_add_cb(ft, "pane_start_command", format_cb_start_command); 2299 format_add_cb(ft, "pane_current_command", format_cb_current_command); 2300 format_add_cb(ft, "pane_current_path", format_cb_current_path); 2301 2302 format_add(ft, "cursor_x", "%u", wp->base.cx); 2303 format_add(ft, "cursor_y", "%u", wp->base.cy); 2304 format_add_cb(ft, "cursor_character", format_cb_cursor_character); 2305 2306 format_add(ft, "scroll_region_upper", "%u", wp->base.rupper); 2307 format_add(ft, "scroll_region_lower", "%u", wp->base.rlower); 2308 2309 format_add(ft, "alternate_on", "%d", wp->saved_grid ? 1 : 0); 2310 format_add(ft, "alternate_saved_x", "%u", wp->saved_cx); 2311 format_add(ft, "alternate_saved_y", "%u", wp->saved_cy); 2312 2313 format_add(ft, "cursor_flag", "%d", 2314 !!(wp->base.mode & MODE_CURSOR)); 2315 format_add(ft, "insert_flag", "%d", 2316 !!(wp->base.mode & MODE_INSERT)); 2317 format_add(ft, "keypad_cursor_flag", "%d", 2318 !!(wp->base.mode & MODE_KCURSOR)); 2319 format_add(ft, "keypad_flag", "%d", 2320 !!(wp->base.mode & MODE_KKEYPAD)); 2321 format_add(ft, "wrap_flag", "%d", 2322 !!(wp->base.mode & MODE_WRAP)); 2323 format_add(ft, "origin_flag", "%d", 2324 !!(wp->base.mode & MODE_ORIGIN)); 2325 2326 format_add(ft, "mouse_any_flag", "%d", 2327 !!(wp->base.mode & ALL_MOUSE_MODES)); 2328 format_add(ft, "mouse_standard_flag", "%d", 2329 !!(wp->base.mode & MODE_MOUSE_STANDARD)); 2330 format_add(ft, "mouse_button_flag", "%d", 2331 !!(wp->base.mode & MODE_MOUSE_BUTTON)); 2332 format_add(ft, "mouse_all_flag", "%d", 2333 !!(wp->base.mode & MODE_MOUSE_ALL)); 2334 format_add(ft, "mouse_utf8_flag", "%d", 2335 !!(wp->base.mode & MODE_MOUSE_UTF8)); 2336 format_add(ft, "mouse_sgr_flag", "%d", 2337 !!(wp->base.mode & MODE_MOUSE_SGR)); 2338 2339 format_add_cb(ft, "pane_tabs", format_cb_pane_tabs); 2340 } 2341 2342 /* Set default format keys for paste buffer. */ 2343 void 2344 format_defaults_paste_buffer(struct format_tree *ft, struct paste_buffer *pb) 2345 { 2346 struct timeval tv; 2347 size_t size; 2348 char *s; 2349 2350 timerclear(&tv); 2351 tv.tv_sec = paste_buffer_created(pb); 2352 paste_buffer_data(pb, &size); 2353 2354 format_add(ft, "buffer_size", "%zu", size); 2355 format_add(ft, "buffer_name", "%s", paste_buffer_name(pb)); 2356 format_add_tv(ft, "buffer_created", &tv); 2357 2358 s = paste_make_sample(pb); 2359 format_add(ft, "buffer_sample", "%s", s); 2360 free(s); 2361 } 2362