1 /* $OpenBSD: options.c,v 1.59 2020/06/16 08:18:34 nicm Exp $ */ 2 3 /* 4 * Copyright (c) 2008 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 21 #include <ctype.h> 22 #include <fnmatch.h> 23 #include <stdarg.h> 24 #include <stdlib.h> 25 #include <string.h> 26 27 #include "tmux.h" 28 29 /* 30 * Option handling; each option has a name, type and value and is stored in 31 * a red-black tree. 32 */ 33 34 struct options_array_item { 35 u_int index; 36 union options_value value; 37 RB_ENTRY(options_array_item) entry; 38 }; 39 static int 40 options_array_cmp(struct options_array_item *a1, struct options_array_item *a2) 41 { 42 if (a1->index < a2->index) 43 return (-1); 44 if (a1->index > a2->index) 45 return (1); 46 return (0); 47 } 48 RB_GENERATE_STATIC(options_array, options_array_item, entry, options_array_cmp); 49 50 struct options_entry { 51 struct options *owner; 52 53 const char *name; 54 const struct options_table_entry *tableentry; 55 union options_value value; 56 57 int cached; 58 struct style style; 59 60 RB_ENTRY(options_entry) entry; 61 }; 62 63 struct options { 64 RB_HEAD(options_tree, options_entry) tree; 65 struct options *parent; 66 }; 67 68 static struct options_entry *options_add(struct options *, const char *); 69 static void options_remove(struct options_entry *); 70 71 #define OPTIONS_IS_STRING(o) \ 72 ((o)->tableentry == NULL || \ 73 (o)->tableentry->type == OPTIONS_TABLE_STRING) 74 #define OPTIONS_IS_NUMBER(o) \ 75 ((o)->tableentry != NULL && \ 76 ((o)->tableentry->type == OPTIONS_TABLE_NUMBER || \ 77 (o)->tableentry->type == OPTIONS_TABLE_KEY || \ 78 (o)->tableentry->type == OPTIONS_TABLE_COLOUR || \ 79 (o)->tableentry->type == OPTIONS_TABLE_FLAG || \ 80 (o)->tableentry->type == OPTIONS_TABLE_CHOICE)) 81 #define OPTIONS_IS_COMMAND(o) \ 82 ((o)->tableentry != NULL && \ 83 (o)->tableentry->type == OPTIONS_TABLE_COMMAND) 84 85 #define OPTIONS_IS_ARRAY(o) \ 86 ((o)->tableentry != NULL && \ 87 ((o)->tableentry->flags & OPTIONS_TABLE_IS_ARRAY)) 88 89 static int options_cmp(struct options_entry *, struct options_entry *); 90 RB_GENERATE_STATIC(options_tree, options_entry, entry, options_cmp); 91 92 static int 93 options_cmp(struct options_entry *lhs, struct options_entry *rhs) 94 { 95 return (strcmp(lhs->name, rhs->name)); 96 } 97 98 static const struct options_table_entry * 99 options_parent_table_entry(struct options *oo, const char *s) 100 { 101 struct options_entry *o; 102 103 if (oo->parent == NULL) 104 fatalx("no parent options for %s", s); 105 o = options_get(oo->parent, s); 106 if (o == NULL) 107 fatalx("%s not in parent options", s); 108 return (o->tableentry); 109 } 110 111 static void 112 options_value_free(struct options_entry *o, union options_value *ov) 113 { 114 if (OPTIONS_IS_STRING(o)) 115 free(ov->string); 116 if (OPTIONS_IS_COMMAND(o) && ov->cmdlist != NULL) 117 cmd_list_free(ov->cmdlist); 118 } 119 120 static char * 121 options_value_to_string(struct options_entry *o, union options_value *ov, 122 int numeric) 123 { 124 char *s; 125 126 if (OPTIONS_IS_COMMAND(o)) 127 return (cmd_list_print(ov->cmdlist, 0)); 128 if (OPTIONS_IS_NUMBER(o)) { 129 switch (o->tableentry->type) { 130 case OPTIONS_TABLE_NUMBER: 131 xasprintf(&s, "%lld", ov->number); 132 break; 133 case OPTIONS_TABLE_KEY: 134 s = xstrdup(key_string_lookup_key(ov->number, 0)); 135 break; 136 case OPTIONS_TABLE_COLOUR: 137 s = xstrdup(colour_tostring(ov->number)); 138 break; 139 case OPTIONS_TABLE_FLAG: 140 if (numeric) 141 xasprintf(&s, "%lld", ov->number); 142 else 143 s = xstrdup(ov->number ? "on" : "off"); 144 break; 145 case OPTIONS_TABLE_CHOICE: 146 s = xstrdup(o->tableentry->choices[ov->number]); 147 break; 148 case OPTIONS_TABLE_STRING: 149 case OPTIONS_TABLE_COMMAND: 150 fatalx("not a number option type"); 151 } 152 return (s); 153 } 154 if (OPTIONS_IS_STRING(o)) 155 return (xstrdup(ov->string)); 156 return (xstrdup("")); 157 } 158 159 struct options * 160 options_create(struct options *parent) 161 { 162 struct options *oo; 163 164 oo = xcalloc(1, sizeof *oo); 165 RB_INIT(&oo->tree); 166 oo->parent = parent; 167 return (oo); 168 } 169 170 void 171 options_free(struct options *oo) 172 { 173 struct options_entry *o, *tmp; 174 175 RB_FOREACH_SAFE(o, options_tree, &oo->tree, tmp) 176 options_remove(o); 177 free(oo); 178 } 179 180 struct options * 181 options_get_parent(struct options *oo) 182 { 183 return (oo->parent); 184 } 185 186 void 187 options_set_parent(struct options *oo, struct options *parent) 188 { 189 oo->parent = parent; 190 } 191 192 struct options_entry * 193 options_first(struct options *oo) 194 { 195 return (RB_MIN(options_tree, &oo->tree)); 196 } 197 198 struct options_entry * 199 options_next(struct options_entry *o) 200 { 201 return (RB_NEXT(options_tree, &oo->tree, o)); 202 } 203 204 struct options_entry * 205 options_get_only(struct options *oo, const char *name) 206 { 207 struct options_entry o; 208 209 o.name = name; 210 return (RB_FIND(options_tree, &oo->tree, &o)); 211 } 212 213 struct options_entry * 214 options_get(struct options *oo, const char *name) 215 { 216 struct options_entry *o; 217 218 o = options_get_only(oo, name); 219 while (o == NULL) { 220 oo = oo->parent; 221 if (oo == NULL) 222 break; 223 o = options_get_only(oo, name); 224 } 225 return (o); 226 } 227 228 struct options_entry * 229 options_empty(struct options *oo, const struct options_table_entry *oe) 230 { 231 struct options_entry *o; 232 233 o = options_add(oo, oe->name); 234 o->tableentry = oe; 235 236 if (oe->flags & OPTIONS_TABLE_IS_ARRAY) 237 RB_INIT(&o->value.array); 238 239 return (o); 240 } 241 242 struct options_entry * 243 options_default(struct options *oo, const struct options_table_entry *oe) 244 { 245 struct options_entry *o; 246 union options_value *ov; 247 u_int i; 248 249 o = options_empty(oo, oe); 250 ov = &o->value; 251 252 if (oe->flags & OPTIONS_TABLE_IS_ARRAY) { 253 if (oe->default_arr == NULL) { 254 options_array_assign(o, oe->default_str, NULL); 255 return (o); 256 } 257 for (i = 0; oe->default_arr[i] != NULL; i++) 258 options_array_set(o, i, oe->default_arr[i], 0, NULL); 259 return (o); 260 } 261 262 switch (oe->type) { 263 case OPTIONS_TABLE_STRING: 264 ov->string = xstrdup(oe->default_str); 265 break; 266 default: 267 ov->number = oe->default_num; 268 break; 269 } 270 return (o); 271 } 272 273 char * 274 options_default_to_string(const struct options_table_entry *oe) 275 { 276 char *s; 277 278 switch (oe->type) { 279 case OPTIONS_TABLE_STRING: 280 case OPTIONS_TABLE_COMMAND: 281 s = xstrdup(oe->default_str); 282 break; 283 case OPTIONS_TABLE_NUMBER: 284 xasprintf(&s, "%lld", oe->default_num); 285 break; 286 case OPTIONS_TABLE_KEY: 287 s = xstrdup(key_string_lookup_key(oe->default_num, 0)); 288 break; 289 case OPTIONS_TABLE_COLOUR: 290 s = xstrdup(colour_tostring(oe->default_num)); 291 break; 292 case OPTIONS_TABLE_FLAG: 293 s = xstrdup(oe->default_num ? "on" : "off"); 294 break; 295 case OPTIONS_TABLE_CHOICE: 296 s = xstrdup(oe->choices[oe->default_num]); 297 break; 298 } 299 return (s); 300 } 301 302 static struct options_entry * 303 options_add(struct options *oo, const char *name) 304 { 305 struct options_entry *o; 306 307 o = options_get_only(oo, name); 308 if (o != NULL) 309 options_remove(o); 310 311 o = xcalloc(1, sizeof *o); 312 o->owner = oo; 313 o->name = xstrdup(name); 314 315 RB_INSERT(options_tree, &oo->tree, o); 316 return (o); 317 } 318 319 static void 320 options_remove(struct options_entry *o) 321 { 322 struct options *oo = o->owner; 323 324 if (OPTIONS_IS_ARRAY(o)) 325 options_array_clear(o); 326 else 327 options_value_free(o, &o->value); 328 RB_REMOVE(options_tree, &oo->tree, o); 329 free((void *)o->name); 330 free(o); 331 } 332 333 const char * 334 options_name(struct options_entry *o) 335 { 336 return (o->name); 337 } 338 339 struct options * 340 options_owner(struct options_entry *o) 341 { 342 return (o->owner); 343 } 344 345 const struct options_table_entry * 346 options_table_entry(struct options_entry *o) 347 { 348 return (o->tableentry); 349 } 350 351 static struct options_array_item * 352 options_array_item(struct options_entry *o, u_int idx) 353 { 354 struct options_array_item a; 355 356 a.index = idx; 357 return (RB_FIND(options_array, &o->value.array, &a)); 358 } 359 360 static struct options_array_item * 361 options_array_new(struct options_entry *o, u_int idx) 362 { 363 struct options_array_item *a; 364 365 a = xcalloc(1, sizeof *a); 366 a->index = idx; 367 RB_INSERT(options_array, &o->value.array, a); 368 return (a); 369 } 370 371 static void 372 options_array_free(struct options_entry *o, struct options_array_item *a) 373 { 374 options_value_free(o, &a->value); 375 RB_REMOVE(options_array, &o->value.array, a); 376 free(a); 377 } 378 379 void 380 options_array_clear(struct options_entry *o) 381 { 382 struct options_array_item *a, *a1; 383 384 if (!OPTIONS_IS_ARRAY(o)) 385 return; 386 387 RB_FOREACH_SAFE(a, options_array, &o->value.array, a1) 388 options_array_free(o, a); 389 } 390 391 union options_value * 392 options_array_get(struct options_entry *o, u_int idx) 393 { 394 struct options_array_item *a; 395 396 if (!OPTIONS_IS_ARRAY(o)) 397 return (NULL); 398 a = options_array_item(o, idx); 399 if (a == NULL) 400 return (NULL); 401 return (&a->value); 402 } 403 404 int 405 options_array_set(struct options_entry *o, u_int idx, const char *value, 406 int append, char **cause) 407 { 408 struct options_array_item *a; 409 char *new; 410 struct cmd_parse_result *pr; 411 412 if (!OPTIONS_IS_ARRAY(o)) { 413 if (cause != NULL) 414 *cause = xstrdup("not an array"); 415 return (-1); 416 } 417 418 if (value == NULL) { 419 a = options_array_item(o, idx); 420 if (a != NULL) 421 options_array_free(o, a); 422 return (0); 423 } 424 425 if (OPTIONS_IS_COMMAND(o)) { 426 pr = cmd_parse_from_string(value, NULL); 427 switch (pr->status) { 428 case CMD_PARSE_EMPTY: 429 if (cause != NULL) 430 *cause = xstrdup("empty command"); 431 return (-1); 432 case CMD_PARSE_ERROR: 433 if (cause != NULL) 434 *cause = pr->error; 435 else 436 free(pr->error); 437 return (-1); 438 case CMD_PARSE_SUCCESS: 439 break; 440 } 441 442 a = options_array_item(o, idx); 443 if (a == NULL) 444 a = options_array_new(o, idx); 445 else 446 options_value_free(o, &a->value); 447 a->value.cmdlist = pr->cmdlist; 448 return (0); 449 } 450 451 if (OPTIONS_IS_STRING(o)) { 452 a = options_array_item(o, idx); 453 if (a != NULL && append) 454 xasprintf(&new, "%s%s", a->value.string, value); 455 else 456 new = xstrdup(value); 457 if (a == NULL) 458 a = options_array_new(o, idx); 459 else 460 options_value_free(o, &a->value); 461 a->value.string = new; 462 return (0); 463 } 464 465 if (cause != NULL) 466 *cause = xstrdup("wrong array type"); 467 return (-1); 468 } 469 470 int 471 options_array_assign(struct options_entry *o, const char *s, char **cause) 472 { 473 const char *separator; 474 char *copy, *next, *string; 475 u_int i; 476 477 separator = o->tableentry->separator; 478 if (separator == NULL) 479 separator = " ,"; 480 if (*separator == '\0') { 481 if (*s == '\0') 482 return (0); 483 for (i = 0; i < UINT_MAX; i++) { 484 if (options_array_item(o, i) == NULL) 485 break; 486 } 487 return (options_array_set(o, i, s, 0, cause)); 488 } 489 490 if (*s == '\0') 491 return (0); 492 copy = string = xstrdup(s); 493 while ((next = strsep(&string, separator)) != NULL) { 494 if (*next == '\0') 495 continue; 496 for (i = 0; i < UINT_MAX; i++) { 497 if (options_array_item(o, i) == NULL) 498 break; 499 } 500 if (i == UINT_MAX) 501 break; 502 if (options_array_set(o, i, next, 0, cause) != 0) { 503 free(copy); 504 return (-1); 505 } 506 } 507 free(copy); 508 return (0); 509 } 510 511 struct options_array_item * 512 options_array_first(struct options_entry *o) 513 { 514 if (!OPTIONS_IS_ARRAY(o)) 515 return (NULL); 516 return (RB_MIN(options_array, &o->value.array)); 517 } 518 519 struct options_array_item * 520 options_array_next(struct options_array_item *a) 521 { 522 return (RB_NEXT(options_array, &o->value.array, a)); 523 } 524 525 u_int 526 options_array_item_index(struct options_array_item *a) 527 { 528 return (a->index); 529 } 530 531 union options_value * 532 options_array_item_value(struct options_array_item *a) 533 { 534 return (&a->value); 535 } 536 537 int 538 options_is_array(struct options_entry *o) 539 { 540 return (OPTIONS_IS_ARRAY(o)); 541 } 542 543 int 544 options_is_string(struct options_entry *o) 545 { 546 return (OPTIONS_IS_STRING(o)); 547 } 548 549 char * 550 options_to_string(struct options_entry *o, int idx, int numeric) 551 { 552 struct options_array_item *a; 553 554 if (OPTIONS_IS_ARRAY(o)) { 555 if (idx == -1) 556 return (xstrdup("")); 557 a = options_array_item(o, idx); 558 if (a == NULL) 559 return (xstrdup("")); 560 return (options_value_to_string(o, &a->value, numeric)); 561 } 562 return (options_value_to_string(o, &o->value, numeric)); 563 } 564 565 char * 566 options_parse(const char *name, int *idx) 567 { 568 char *copy, *cp, *end; 569 570 if (*name == '\0') 571 return (NULL); 572 copy = xstrdup(name); 573 if ((cp = strchr(copy, '[')) == NULL) { 574 *idx = -1; 575 return (copy); 576 } 577 end = strchr(cp + 1, ']'); 578 if (end == NULL || end[1] != '\0' || !isdigit((u_char)end[-1])) { 579 free(copy); 580 return (NULL); 581 } 582 if (sscanf(cp, "[%d]", idx) != 1 || *idx < 0) { 583 free(copy); 584 return (NULL); 585 } 586 *cp = '\0'; 587 return (copy); 588 } 589 590 struct options_entry * 591 options_parse_get(struct options *oo, const char *s, int *idx, int only) 592 { 593 struct options_entry *o; 594 char *name; 595 596 name = options_parse(s, idx); 597 if (name == NULL) 598 return (NULL); 599 if (only) 600 o = options_get_only(oo, name); 601 else 602 o = options_get(oo, name); 603 free(name); 604 return (o); 605 } 606 607 char * 608 options_match(const char *s, int *idx, int *ambiguous) 609 { 610 const struct options_table_entry *oe, *found; 611 char *name; 612 size_t namelen; 613 614 name = options_parse(s, idx); 615 if (name == NULL) 616 return (NULL); 617 namelen = strlen(name); 618 619 if (*name == '@') { 620 *ambiguous = 0; 621 return (name); 622 } 623 624 found = NULL; 625 for (oe = options_table; oe->name != NULL; oe++) { 626 if (strcmp(oe->name, name) == 0) { 627 found = oe; 628 break; 629 } 630 if (strncmp(oe->name, name, namelen) == 0) { 631 if (found != NULL) { 632 *ambiguous = 1; 633 free(name); 634 return (NULL); 635 } 636 found = oe; 637 } 638 } 639 free(name); 640 if (found == NULL) { 641 *ambiguous = 0; 642 return (NULL); 643 } 644 return (xstrdup(found->name)); 645 } 646 647 struct options_entry * 648 options_match_get(struct options *oo, const char *s, int *idx, int only, 649 int *ambiguous) 650 { 651 char *name; 652 struct options_entry *o; 653 654 name = options_match(s, idx, ambiguous); 655 if (name == NULL) 656 return (NULL); 657 *ambiguous = 0; 658 if (only) 659 o = options_get_only(oo, name); 660 else 661 o = options_get(oo, name); 662 free(name); 663 return (o); 664 } 665 666 const char * 667 options_get_string(struct options *oo, const char *name) 668 { 669 struct options_entry *o; 670 671 o = options_get(oo, name); 672 if (o == NULL) 673 fatalx("missing option %s", name); 674 if (!OPTIONS_IS_STRING(o)) 675 fatalx("option %s is not a string", name); 676 return (o->value.string); 677 } 678 679 long long 680 options_get_number(struct options *oo, const char *name) 681 { 682 struct options_entry *o; 683 684 o = options_get(oo, name); 685 if (o == NULL) 686 fatalx("missing option %s", name); 687 if (!OPTIONS_IS_NUMBER(o)) 688 fatalx("option %s is not a number", name); 689 return (o->value.number); 690 } 691 692 struct options_entry * 693 options_set_string(struct options *oo, const char *name, int append, 694 const char *fmt, ...) 695 { 696 struct options_entry *o; 697 va_list ap; 698 const char *separator = ""; 699 char *s, *value; 700 701 va_start(ap, fmt); 702 xvasprintf(&s, fmt, ap); 703 va_end(ap); 704 705 o = options_get_only(oo, name); 706 if (o != NULL && append && OPTIONS_IS_STRING(o)) { 707 if (*name != '@') { 708 separator = o->tableentry->separator; 709 if (separator == NULL) 710 separator = ""; 711 } 712 xasprintf(&value, "%s%s%s", o->value.string, separator, s); 713 free(s); 714 } else 715 value = s; 716 if (o == NULL && *name == '@') 717 o = options_add(oo, name); 718 else if (o == NULL) { 719 o = options_default(oo, options_parent_table_entry(oo, name)); 720 if (o == NULL) 721 return (NULL); 722 } 723 724 if (!OPTIONS_IS_STRING(o)) 725 fatalx("option %s is not a string", name); 726 free(o->value.string); 727 o->value.string = value; 728 o->cached = 0; 729 return (o); 730 } 731 732 struct options_entry * 733 options_set_number(struct options *oo, const char *name, long long value) 734 { 735 struct options_entry *o; 736 737 if (*name == '@') 738 fatalx("user option %s must be a string", name); 739 740 o = options_get_only(oo, name); 741 if (o == NULL) { 742 o = options_default(oo, options_parent_table_entry(oo, name)); 743 if (o == NULL) 744 return (NULL); 745 } 746 747 if (!OPTIONS_IS_NUMBER(o)) 748 fatalx("option %s is not a number", name); 749 o->value.number = value; 750 return (o); 751 } 752 753 int 754 options_scope_from_name(struct args *args, int window, 755 const char *name, struct cmd_find_state *fs, struct options **oo, 756 char **cause) 757 { 758 struct session *s = fs->s; 759 struct winlink *wl = fs->wl; 760 struct window_pane *wp = fs->wp; 761 const char *target = args_get(args, 't'); 762 const struct options_table_entry *oe; 763 int scope = OPTIONS_TABLE_NONE; 764 765 if (*name == '@') 766 return (options_scope_from_flags(args, window, fs, oo, cause)); 767 768 for (oe = options_table; oe->name != NULL; oe++) { 769 if (strcmp(oe->name, name) == 0) 770 break; 771 } 772 if (oe->name == NULL) { 773 xasprintf(cause, "unknown option: %s", name); 774 return (OPTIONS_TABLE_NONE); 775 } 776 switch (oe->scope) { 777 case OPTIONS_TABLE_SERVER: 778 *oo = global_options; 779 scope = OPTIONS_TABLE_SERVER; 780 break; 781 case OPTIONS_TABLE_SESSION: 782 if (args_has(args, 'g')) { 783 *oo = global_s_options; 784 scope = OPTIONS_TABLE_SESSION; 785 } else if (s == NULL && target != NULL) 786 xasprintf(cause, "no such session: %s", target); 787 else if (s == NULL) 788 xasprintf(cause, "no current session"); 789 else { 790 *oo = s->options; 791 scope = OPTIONS_TABLE_SESSION; 792 } 793 break; 794 case OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE: 795 if (args_has(args, 'p')) { 796 if (wp == NULL && target != NULL) 797 xasprintf(cause, "no such pane: %s", target); 798 else if (wp == NULL) 799 xasprintf(cause, "no current pane"); 800 else { 801 *oo = wp->options; 802 scope = OPTIONS_TABLE_PANE; 803 } 804 break; 805 } 806 /* FALLTHROUGH */ 807 case OPTIONS_TABLE_WINDOW: 808 if (args_has(args, 'g')) { 809 *oo = global_w_options; 810 scope = OPTIONS_TABLE_WINDOW; 811 } else if (wl == NULL && target != NULL) 812 xasprintf(cause, "no such window: %s", target); 813 else if (wl == NULL) 814 xasprintf(cause, "no current window"); 815 else { 816 *oo = wl->window->options; 817 scope = OPTIONS_TABLE_WINDOW; 818 } 819 break; 820 } 821 return (scope); 822 } 823 824 int 825 options_scope_from_flags(struct args *args, int window, 826 struct cmd_find_state *fs, struct options **oo, char **cause) 827 { 828 struct session *s = fs->s; 829 struct winlink *wl = fs->wl; 830 struct window_pane *wp = fs->wp; 831 const char *target = args_get(args, 't'); 832 833 if (args_has(args, 's')) { 834 *oo = global_options; 835 return (OPTIONS_TABLE_SERVER); 836 } 837 838 if (args_has(args, 'p')) { 839 if (wp == NULL) { 840 if (target != NULL) 841 xasprintf(cause, "no such pane: %s", target); 842 else 843 xasprintf(cause, "no current pane"); 844 return (OPTIONS_TABLE_NONE); 845 } 846 *oo = wp->options; 847 return (OPTIONS_TABLE_PANE); 848 } else if (window || args_has(args, 'w')) { 849 if (args_has(args, 'g')) { 850 *oo = global_w_options; 851 return (OPTIONS_TABLE_WINDOW); 852 } 853 if (wl == NULL) { 854 if (target != NULL) 855 xasprintf(cause, "no such window: %s", target); 856 else 857 xasprintf(cause, "no current window"); 858 return (OPTIONS_TABLE_NONE); 859 } 860 *oo = wl->window->options; 861 return (OPTIONS_TABLE_WINDOW); 862 } else { 863 if (args_has(args, 'g')) { 864 *oo = global_s_options; 865 return (OPTIONS_TABLE_SESSION); 866 } 867 if (s == NULL) { 868 if (target != NULL) 869 xasprintf(cause, "no such session: %s", target); 870 else 871 xasprintf(cause, "no current session"); 872 return (OPTIONS_TABLE_NONE); 873 } 874 *oo = s->options; 875 return (OPTIONS_TABLE_SESSION); 876 } 877 } 878 879 struct style * 880 options_string_to_style(struct options *oo, const char *name, 881 struct format_tree *ft) 882 { 883 struct options_entry *o; 884 const char *s; 885 char *expanded; 886 887 o = options_get(oo, name); 888 if (o == NULL || !OPTIONS_IS_STRING(o)) 889 return (NULL); 890 891 if (o->cached) 892 return (&o->style); 893 s = o->value.string; 894 log_debug("%s: %s is '%s'", __func__, name, s); 895 896 style_set(&o->style, &grid_default_cell); 897 o->cached = (strstr(s, "#{") == NULL); 898 899 if (ft != NULL && !o->cached) { 900 expanded = format_expand(ft, s); 901 if (style_parse(&o->style, &grid_default_cell, expanded) != 0) { 902 free(expanded); 903 return (NULL); 904 } 905 free(expanded); 906 } else { 907 if (style_parse(&o->style, &grid_default_cell, s) != 0) 908 return (NULL); 909 } 910 return (&o->style); 911 } 912 913 static int 914 options_from_string_check(const struct options_table_entry *oe, 915 const char *value, char **cause) 916 { 917 struct style sy; 918 919 if (oe == NULL) 920 return (0); 921 if (strcmp(oe->name, "default-shell") == 0 && !checkshell(value)) { 922 xasprintf(cause, "not a suitable shell: %s", value); 923 return (-1); 924 } 925 if (oe->pattern != NULL && fnmatch(oe->pattern, value, 0) != 0) { 926 xasprintf(cause, "value is invalid: %s", value); 927 return (-1); 928 } 929 if ((oe->flags & OPTIONS_TABLE_IS_STYLE) && 930 strstr(value, "#{") == NULL && 931 style_parse(&sy, &grid_default_cell, value) != 0) { 932 xasprintf(cause, "invalid style: %s", value); 933 return (-1); 934 } 935 return (0); 936 } 937 938 static int 939 options_from_string_flag(struct options *oo, const char *name, 940 const char *value, char **cause) 941 { 942 int flag; 943 944 if (value == NULL || *value == '\0') 945 flag = !options_get_number(oo, name); 946 else if (strcmp(value, "1") == 0 || 947 strcasecmp(value, "on") == 0 || 948 strcasecmp(value, "yes") == 0) 949 flag = 1; 950 else if (strcmp(value, "0") == 0 || 951 strcasecmp(value, "off") == 0 || 952 strcasecmp(value, "no") == 0) 953 flag = 0; 954 else { 955 xasprintf(cause, "bad value: %s", value); 956 return (-1); 957 } 958 options_set_number(oo, name, flag); 959 return (0); 960 } 961 962 static int 963 options_from_string_choice(const struct options_table_entry *oe, 964 struct options *oo, const char *name, const char *value, char **cause) 965 { 966 const char **cp; 967 int n, choice = -1; 968 969 if (value == NULL) { 970 choice = options_get_number(oo, name); 971 if (choice < 2) 972 choice = !choice; 973 } else { 974 n = 0; 975 for (cp = oe->choices; *cp != NULL; cp++) { 976 if (strcmp(*cp, value) == 0) 977 choice = n; 978 n++; 979 } 980 if (choice == -1) { 981 xasprintf(cause, "unknown value: %s", value); 982 return (-1); 983 } 984 } 985 options_set_number(oo, name, choice); 986 return (0); 987 } 988 989 int 990 options_from_string(struct options *oo, const struct options_table_entry *oe, 991 const char *name, const char *value, int append, char **cause) 992 { 993 enum options_table_type type; 994 long long number; 995 const char *errstr, *new; 996 char *old; 997 key_code key; 998 999 if (oe != NULL) { 1000 if (value == NULL && 1001 oe->type != OPTIONS_TABLE_FLAG && 1002 oe->type != OPTIONS_TABLE_CHOICE) { 1003 xasprintf(cause, "empty value"); 1004 return (-1); 1005 } 1006 type = oe->type; 1007 } else { 1008 if (*name != '@') { 1009 xasprintf(cause, "bad option name"); 1010 return (-1); 1011 } 1012 type = OPTIONS_TABLE_STRING; 1013 } 1014 1015 switch (type) { 1016 case OPTIONS_TABLE_STRING: 1017 old = xstrdup(options_get_string(oo, name)); 1018 options_set_string(oo, name, append, "%s", value); 1019 1020 new = options_get_string(oo, name); 1021 if (options_from_string_check(oe, new, cause) != 0) { 1022 options_set_string(oo, name, 0, "%s", old); 1023 free(old); 1024 return (-1); 1025 } 1026 free(old); 1027 return (0); 1028 case OPTIONS_TABLE_NUMBER: 1029 number = strtonum(value, oe->minimum, oe->maximum, &errstr); 1030 if (errstr != NULL) { 1031 xasprintf(cause, "value is %s: %s", errstr, value); 1032 return (-1); 1033 } 1034 options_set_number(oo, name, number); 1035 return (0); 1036 case OPTIONS_TABLE_KEY: 1037 key = key_string_lookup_string(value); 1038 if (key == KEYC_UNKNOWN) { 1039 xasprintf(cause, "bad key: %s", value); 1040 return (-1); 1041 } 1042 options_set_number(oo, name, key); 1043 return (0); 1044 case OPTIONS_TABLE_COLOUR: 1045 if ((number = colour_fromstring(value)) == -1) { 1046 xasprintf(cause, "bad colour: %s", value); 1047 return (-1); 1048 } 1049 options_set_number(oo, name, number); 1050 return (0); 1051 case OPTIONS_TABLE_FLAG: 1052 return (options_from_string_flag(oo, name, value, cause)); 1053 case OPTIONS_TABLE_CHOICE: 1054 return (options_from_string_choice(oe, oo, name, value, cause)); 1055 case OPTIONS_TABLE_COMMAND: 1056 break; 1057 } 1058 return (-1); 1059 } 1060 1061 void 1062 options_push_changes(const char *name) 1063 { 1064 struct client *loop; 1065 struct session *s; 1066 struct window *w; 1067 struct window_pane *wp; 1068 1069 if (strcmp(name, "automatic-rename") == 0) { 1070 RB_FOREACH(w, windows, &windows) { 1071 if (w->active == NULL) 1072 continue; 1073 if (options_get_number(w->options, "automatic-rename")) 1074 w->active->flags |= PANE_CHANGED; 1075 } 1076 } 1077 if (strcmp(name, "key-table") == 0) { 1078 TAILQ_FOREACH(loop, &clients, entry) 1079 server_client_set_key_table(loop, NULL); 1080 } 1081 if (strcmp(name, "user-keys") == 0) { 1082 TAILQ_FOREACH(loop, &clients, entry) { 1083 if (loop->tty.flags & TTY_OPENED) 1084 tty_keys_build(&loop->tty); 1085 } 1086 } 1087 if (strcmp(name, "status") == 0 || 1088 strcmp(name, "status-interval") == 0) 1089 status_timer_start_all(); 1090 if (strcmp(name, "monitor-silence") == 0) 1091 alerts_reset_all(); 1092 if (strcmp(name, "window-style") == 0 || 1093 strcmp(name, "window-active-style") == 0) { 1094 RB_FOREACH(wp, window_pane_tree, &all_window_panes) 1095 wp->flags |= PANE_STYLECHANGED; 1096 } 1097 if (strcmp(name, "pane-border-status") == 0) { 1098 RB_FOREACH(w, windows, &windows) 1099 layout_fix_panes(w); 1100 } 1101 RB_FOREACH(s, sessions, &sessions) 1102 status_update_cache(s); 1103 1104 recalculate_sizes(); 1105 TAILQ_FOREACH(loop, &clients, entry) { 1106 if (loop->session != NULL) 1107 server_redraw_client(loop); 1108 } 1109 } 1110 1111 int 1112 options_remove_or_default(struct options_entry *o, int idx, char **cause) 1113 { 1114 struct options *oo = o->owner; 1115 1116 if (idx == -1) { 1117 if (o->tableentry != NULL && 1118 (oo == global_options || 1119 oo == global_s_options || 1120 oo == global_w_options)) 1121 options_default(oo, o->tableentry); 1122 else 1123 options_remove(o); 1124 } else if (options_array_set(o, idx, NULL, 0, cause) != 0) 1125 return (-1); 1126 return (0); 1127 } 1128