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