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