options.c revision 1.69
1/* $OpenBSD: options.c,v 1.69 2022/06/17 07:28:05 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 34struct options_array_item { 35 u_int index; 36 union options_value value; 37 RB_ENTRY(options_array_item) entry; 38}; 39static int 40options_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} 48RB_GENERATE_STATIC(options_array, options_array_item, entry, options_array_cmp); 49 50struct 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 63struct options { 64 RB_HEAD(options_tree, options_entry) tree; 65 struct options *parent; 66}; 67 68static struct options_entry *options_add(struct options *, const char *); 69static 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 89static int options_cmp(struct options_entry *, struct options_entry *); 90RB_GENERATE_STATIC(options_tree, options_entry, entry, options_cmp); 91 92static int 93options_cmp(struct options_entry *lhs, struct options_entry *rhs) 94{ 95 return (strcmp(lhs->name, rhs->name)); 96} 97 98static const char * 99options_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 110static const struct options_table_entry * 111options_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 123static void 124options_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 132static char * 133options_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 170struct options * 171options_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 181void 182options_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 191struct options * 192options_get_parent(struct options *oo) 193{ 194 return (oo->parent); 195} 196 197void 198options_set_parent(struct options *oo, struct options *parent) 199{ 200 oo->parent = parent; 201} 202 203struct options_entry * 204options_first(struct options *oo) 205{ 206 return (RB_MIN(options_tree, &oo->tree)); 207} 208 209struct options_entry * 210options_next(struct options_entry *o) 211{ 212 return (RB_NEXT(options_tree, &oo->tree, o)); 213} 214 215struct options_entry * 216options_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 228struct options_entry * 229options_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 243struct options_entry * 244options_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 257struct options_entry * 258options_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 288char * 289options_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 319static struct options_entry * 320options_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 336static void 337options_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 350const char * 351options_name(struct options_entry *o) 352{ 353 return (o->name); 354} 355 356struct options * 357options_owner(struct options_entry *o) 358{ 359 return (o->owner); 360} 361 362const struct options_table_entry * 363options_table_entry(struct options_entry *o) 364{ 365 return (o->tableentry); 366} 367 368static struct options_array_item * 369options_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 377static struct options_array_item * 378options_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 388static void 389options_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 396void 397options_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 408union options_value * 409options_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 421int 422options_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 498int 499options_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 539struct options_array_item * 540options_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 547struct options_array_item * 548options_array_next(struct options_array_item *a) 549{ 550 return (RB_NEXT(options_array, &o->value.array, a)); 551} 552 553u_int 554options_array_item_index(struct options_array_item *a) 555{ 556 return (a->index); 557} 558 559union options_value * 560options_array_item_value(struct options_array_item *a) 561{ 562 return (&a->value); 563} 564 565int 566options_is_array(struct options_entry *o) 567{ 568 return (OPTIONS_IS_ARRAY(o)); 569} 570 571int 572options_is_string(struct options_entry *o) 573{ 574 return (OPTIONS_IS_STRING(o)); 575} 576 577char * 578options_to_string(struct options_entry *o, int idx, int numeric) 579{ 580 struct options_array_item *a; 581 582 if (OPTIONS_IS_ARRAY(o)) { 583 if (idx == -1) 584 return (xstrdup("")); 585 a = options_array_item(o, idx); 586 if (a == NULL) 587 return (xstrdup("")); 588 return (options_value_to_string(o, &a->value, numeric)); 589 } 590 return (options_value_to_string(o, &o->value, numeric)); 591} 592 593char * 594options_parse(const char *name, int *idx) 595{ 596 char *copy, *cp, *end; 597 598 if (*name == '\0') 599 return (NULL); 600 copy = xstrdup(name); 601 if ((cp = strchr(copy, '[')) == NULL) { 602 *idx = -1; 603 return (copy); 604 } 605 end = strchr(cp + 1, ']'); 606 if (end == NULL || end[1] != '\0' || !isdigit((u_char)end[-1])) { 607 free(copy); 608 return (NULL); 609 } 610 if (sscanf(cp, "[%d]", idx) != 1 || *idx < 0) { 611 free(copy); 612 return (NULL); 613 } 614 *cp = '\0'; 615 return (copy); 616} 617 618struct options_entry * 619options_parse_get(struct options *oo, const char *s, int *idx, int only) 620{ 621 struct options_entry *o; 622 char *name; 623 624 name = options_parse(s, idx); 625 if (name == NULL) 626 return (NULL); 627 if (only) 628 o = options_get_only(oo, name); 629 else 630 o = options_get(oo, name); 631 free(name); 632 return (o); 633} 634 635char * 636options_match(const char *s, int *idx, int *ambiguous) 637{ 638 const struct options_table_entry *oe, *found; 639 char *parsed; 640 const char *name; 641 size_t namelen; 642 643 parsed = options_parse(s, idx); 644 if (parsed == NULL) 645 return (NULL); 646 if (*parsed == '@') { 647 *ambiguous = 0; 648 return (parsed); 649 } 650 651 name = options_map_name(parsed); 652 namelen = strlen(name); 653 654 found = NULL; 655 for (oe = options_table; oe->name != NULL; oe++) { 656 if (strcmp(oe->name, name) == 0) { 657 found = oe; 658 break; 659 } 660 if (strncmp(oe->name, name, namelen) == 0) { 661 if (found != NULL) { 662 *ambiguous = 1; 663 free(parsed); 664 return (NULL); 665 } 666 found = oe; 667 } 668 } 669 free(parsed); 670 if (found == NULL) { 671 *ambiguous = 0; 672 return (NULL); 673 } 674 return (xstrdup(found->name)); 675} 676 677struct options_entry * 678options_match_get(struct options *oo, const char *s, int *idx, int only, 679 int *ambiguous) 680{ 681 char *name; 682 struct options_entry *o; 683 684 name = options_match(s, idx, ambiguous); 685 if (name == NULL) 686 return (NULL); 687 *ambiguous = 0; 688 if (only) 689 o = options_get_only(oo, name); 690 else 691 o = options_get(oo, name); 692 free(name); 693 return (o); 694} 695 696const char * 697options_get_string(struct options *oo, const char *name) 698{ 699 struct options_entry *o; 700 701 o = options_get(oo, name); 702 if (o == NULL) 703 fatalx("missing option %s", name); 704 if (!OPTIONS_IS_STRING(o)) 705 fatalx("option %s is not a string", name); 706 return (o->value.string); 707} 708 709long long 710options_get_number(struct options *oo, const char *name) 711{ 712 struct options_entry *o; 713 714 o = options_get(oo, name); 715 if (o == NULL) 716 fatalx("missing option %s", name); 717 if (!OPTIONS_IS_NUMBER(o)) 718 fatalx("option %s is not a number", name); 719 return (o->value.number); 720} 721 722struct options_entry * 723options_set_string(struct options *oo, const char *name, int append, 724 const char *fmt, ...) 725{ 726 struct options_entry *o; 727 va_list ap; 728 const char *separator = ""; 729 char *s, *value; 730 731 va_start(ap, fmt); 732 xvasprintf(&s, fmt, ap); 733 va_end(ap); 734 735 o = options_get_only(oo, name); 736 if (o != NULL && append && OPTIONS_IS_STRING(o)) { 737 if (*name != '@') { 738 separator = o->tableentry->separator; 739 if (separator == NULL) 740 separator = ""; 741 } 742 xasprintf(&value, "%s%s%s", o->value.string, separator, s); 743 free(s); 744 } else 745 value = s; 746 if (o == NULL && *name == '@') 747 o = options_add(oo, name); 748 else if (o == NULL) { 749 o = options_default(oo, options_parent_table_entry(oo, name)); 750 if (o == NULL) 751 return (NULL); 752 } 753 754 if (!OPTIONS_IS_STRING(o)) 755 fatalx("option %s is not a string", name); 756 free(o->value.string); 757 o->value.string = value; 758 o->cached = 0; 759 return (o); 760} 761 762struct options_entry * 763options_set_number(struct options *oo, const char *name, long long value) 764{ 765 struct options_entry *o; 766 767 if (*name == '@') 768 fatalx("user option %s must be a string", name); 769 770 o = options_get_only(oo, name); 771 if (o == NULL) { 772 o = options_default(oo, options_parent_table_entry(oo, name)); 773 if (o == NULL) 774 return (NULL); 775 } 776 777 if (!OPTIONS_IS_NUMBER(o)) 778 fatalx("option %s is not a number", name); 779 o->value.number = value; 780 return (o); 781} 782 783int 784options_scope_from_name(struct args *args, int window, 785 const char *name, struct cmd_find_state *fs, struct options **oo, 786 char **cause) 787{ 788 struct session *s = fs->s; 789 struct winlink *wl = fs->wl; 790 struct window_pane *wp = fs->wp; 791 const char *target = args_get(args, 't'); 792 const struct options_table_entry *oe; 793 int scope = OPTIONS_TABLE_NONE; 794 795 if (*name == '@') 796 return (options_scope_from_flags(args, window, fs, oo, cause)); 797 798 for (oe = options_table; oe->name != NULL; oe++) { 799 if (strcmp(oe->name, name) == 0) 800 break; 801 } 802 if (oe->name == NULL) { 803 xasprintf(cause, "unknown option: %s", name); 804 return (OPTIONS_TABLE_NONE); 805 } 806 switch (oe->scope) { 807 case OPTIONS_TABLE_SERVER: 808 *oo = global_options; 809 scope = OPTIONS_TABLE_SERVER; 810 break; 811 case OPTIONS_TABLE_SESSION: 812 if (args_has(args, 'g')) { 813 *oo = global_s_options; 814 scope = OPTIONS_TABLE_SESSION; 815 } else if (s == NULL && target != NULL) 816 xasprintf(cause, "no such session: %s", target); 817 else if (s == NULL) 818 xasprintf(cause, "no current session"); 819 else { 820 *oo = s->options; 821 scope = OPTIONS_TABLE_SESSION; 822 } 823 break; 824 case OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE: 825 if (args_has(args, 'p')) { 826 if (wp == NULL && target != NULL) 827 xasprintf(cause, "no such pane: %s", target); 828 else if (wp == NULL) 829 xasprintf(cause, "no current pane"); 830 else { 831 *oo = wp->options; 832 scope = OPTIONS_TABLE_PANE; 833 } 834 break; 835 } 836 /* FALLTHROUGH */ 837 case OPTIONS_TABLE_WINDOW: 838 if (args_has(args, 'g')) { 839 *oo = global_w_options; 840 scope = OPTIONS_TABLE_WINDOW; 841 } else if (wl == NULL && target != NULL) 842 xasprintf(cause, "no such window: %s", target); 843 else if (wl == NULL) 844 xasprintf(cause, "no current window"); 845 else { 846 *oo = wl->window->options; 847 scope = OPTIONS_TABLE_WINDOW; 848 } 849 break; 850 } 851 return (scope); 852} 853 854int 855options_scope_from_flags(struct args *args, int window, 856 struct cmd_find_state *fs, struct options **oo, char **cause) 857{ 858 struct session *s = fs->s; 859 struct winlink *wl = fs->wl; 860 struct window_pane *wp = fs->wp; 861 const char *target = args_get(args, 't'); 862 863 if (args_has(args, 's')) { 864 *oo = global_options; 865 return (OPTIONS_TABLE_SERVER); 866 } 867 868 if (args_has(args, 'p')) { 869 if (wp == NULL) { 870 if (target != NULL) 871 xasprintf(cause, "no such pane: %s", target); 872 else 873 xasprintf(cause, "no current pane"); 874 return (OPTIONS_TABLE_NONE); 875 } 876 *oo = wp->options; 877 return (OPTIONS_TABLE_PANE); 878 } else if (window || args_has(args, 'w')) { 879 if (args_has(args, 'g')) { 880 *oo = global_w_options; 881 return (OPTIONS_TABLE_WINDOW); 882 } 883 if (wl == NULL) { 884 if (target != NULL) 885 xasprintf(cause, "no such window: %s", target); 886 else 887 xasprintf(cause, "no current window"); 888 return (OPTIONS_TABLE_NONE); 889 } 890 *oo = wl->window->options; 891 return (OPTIONS_TABLE_WINDOW); 892 } else { 893 if (args_has(args, 'g')) { 894 *oo = global_s_options; 895 return (OPTIONS_TABLE_SESSION); 896 } 897 if (s == NULL) { 898 if (target != NULL) 899 xasprintf(cause, "no such session: %s", target); 900 else 901 xasprintf(cause, "no current session"); 902 return (OPTIONS_TABLE_NONE); 903 } 904 *oo = s->options; 905 return (OPTIONS_TABLE_SESSION); 906 } 907} 908 909struct style * 910options_string_to_style(struct options *oo, const char *name, 911 struct format_tree *ft) 912{ 913 struct options_entry *o; 914 const char *s; 915 char *expanded; 916 917 o = options_get(oo, name); 918 if (o == NULL || !OPTIONS_IS_STRING(o)) 919 return (NULL); 920 921 if (o->cached) 922 return (&o->style); 923 s = o->value.string; 924 log_debug("%s: %s is '%s'", __func__, name, s); 925 926 style_set(&o->style, &grid_default_cell); 927 o->cached = (strstr(s, "#{") == NULL); 928 929 if (ft != NULL && !o->cached) { 930 expanded = format_expand(ft, s); 931 if (style_parse(&o->style, &grid_default_cell, expanded) != 0) { 932 free(expanded); 933 return (NULL); 934 } 935 free(expanded); 936 } else { 937 if (style_parse(&o->style, &grid_default_cell, s) != 0) 938 return (NULL); 939 } 940 return (&o->style); 941} 942 943static int 944options_from_string_check(const struct options_table_entry *oe, 945 const char *value, char **cause) 946{ 947 struct style sy; 948 949 if (oe == NULL) 950 return (0); 951 if (strcmp(oe->name, "default-shell") == 0 && !checkshell(value)) { 952 xasprintf(cause, "not a suitable shell: %s", value); 953 return (-1); 954 } 955 if (oe->pattern != NULL && fnmatch(oe->pattern, value, 0) != 0) { 956 xasprintf(cause, "value is invalid: %s", value); 957 return (-1); 958 } 959 if ((oe->flags & OPTIONS_TABLE_IS_STYLE) && 960 strstr(value, "#{") == NULL && 961 style_parse(&sy, &grid_default_cell, value) != 0) { 962 xasprintf(cause, "invalid style: %s", value); 963 return (-1); 964 } 965 return (0); 966} 967 968static int 969options_from_string_flag(struct options *oo, const char *name, 970 const char *value, char **cause) 971{ 972 int flag; 973 974 if (value == NULL || *value == '\0') 975 flag = !options_get_number(oo, name); 976 else if (strcmp(value, "1") == 0 || 977 strcasecmp(value, "on") == 0 || 978 strcasecmp(value, "yes") == 0) 979 flag = 1; 980 else if (strcmp(value, "0") == 0 || 981 strcasecmp(value, "off") == 0 || 982 strcasecmp(value, "no") == 0) 983 flag = 0; 984 else { 985 xasprintf(cause, "bad value: %s", value); 986 return (-1); 987 } 988 options_set_number(oo, name, flag); 989 return (0); 990} 991 992int 993options_find_choice(const struct options_table_entry *oe, const char *value, 994 char **cause) 995{ 996 const char **cp; 997 int n = 0, choice = -1; 998 999 for (cp = oe->choices; *cp != NULL; cp++) { 1000 if (strcmp(*cp, value) == 0) 1001 choice = n; 1002 n++; 1003 } 1004 if (choice == -1) { 1005 xasprintf(cause, "unknown value: %s", value); 1006 return (-1); 1007 } 1008 return (choice); 1009} 1010 1011static int 1012options_from_string_choice(const struct options_table_entry *oe, 1013 struct options *oo, const char *name, const char *value, char **cause) 1014{ 1015 int choice = -1; 1016 1017 if (value == NULL) { 1018 choice = options_get_number(oo, name); 1019 if (choice < 2) 1020 choice = !choice; 1021 } else { 1022 choice = options_find_choice(oe, value, cause); 1023 if (choice < 0) 1024 return (-1); 1025 } 1026 options_set_number(oo, name, choice); 1027 return (0); 1028} 1029 1030int 1031options_from_string(struct options *oo, const struct options_table_entry *oe, 1032 const char *name, const char *value, int append, char **cause) 1033{ 1034 enum options_table_type type; 1035 long long number; 1036 const char *errstr, *new; 1037 char *old; 1038 key_code key; 1039 1040 if (oe != NULL) { 1041 if (value == NULL && 1042 oe->type != OPTIONS_TABLE_FLAG && 1043 oe->type != OPTIONS_TABLE_CHOICE) { 1044 xasprintf(cause, "empty value"); 1045 return (-1); 1046 } 1047 type = oe->type; 1048 } else { 1049 if (*name != '@') { 1050 xasprintf(cause, "bad option name"); 1051 return (-1); 1052 } 1053 type = OPTIONS_TABLE_STRING; 1054 } 1055 1056 switch (type) { 1057 case OPTIONS_TABLE_STRING: 1058 old = xstrdup(options_get_string(oo, name)); 1059 options_set_string(oo, name, append, "%s", value); 1060 1061 new = options_get_string(oo, name); 1062 if (options_from_string_check(oe, new, cause) != 0) { 1063 options_set_string(oo, name, 0, "%s", old); 1064 free(old); 1065 return (-1); 1066 } 1067 free(old); 1068 return (0); 1069 case OPTIONS_TABLE_NUMBER: 1070 number = strtonum(value, oe->minimum, oe->maximum, &errstr); 1071 if (errstr != NULL) { 1072 xasprintf(cause, "value is %s: %s", errstr, value); 1073 return (-1); 1074 } 1075 options_set_number(oo, name, number); 1076 return (0); 1077 case OPTIONS_TABLE_KEY: 1078 key = key_string_lookup_string(value); 1079 if (key == KEYC_UNKNOWN) { 1080 xasprintf(cause, "bad key: %s", value); 1081 return (-1); 1082 } 1083 options_set_number(oo, name, key); 1084 return (0); 1085 case OPTIONS_TABLE_COLOUR: 1086 if ((number = colour_fromstring(value)) == -1) { 1087 xasprintf(cause, "bad colour: %s", value); 1088 return (-1); 1089 } 1090 options_set_number(oo, name, number); 1091 return (0); 1092 case OPTIONS_TABLE_FLAG: 1093 return (options_from_string_flag(oo, name, value, cause)); 1094 case OPTIONS_TABLE_CHOICE: 1095 return (options_from_string_choice(oe, oo, name, value, cause)); 1096 case OPTIONS_TABLE_COMMAND: 1097 break; 1098 } 1099 return (-1); 1100} 1101 1102void 1103options_push_changes(const char *name) 1104{ 1105 struct client *loop; 1106 struct session *s; 1107 struct window *w; 1108 struct window_pane *wp; 1109 1110 log_debug("%s: %s", __func__, name); 1111 1112 if (strcmp(name, "automatic-rename") == 0) { 1113 RB_FOREACH(w, windows, &windows) { 1114 if (w->active == NULL) 1115 continue; 1116 if (options_get_number(w->options, name)) 1117 w->active->flags |= PANE_CHANGED; 1118 } 1119 } 1120 if (strcmp(name, "cursor-colour") == 0) { 1121 RB_FOREACH(wp, window_pane_tree, &all_window_panes) 1122 window_pane_default_cursor(wp); 1123 } 1124 if (strcmp(name, "cursor-style") == 0) { 1125 RB_FOREACH(wp, window_pane_tree, &all_window_panes) 1126 window_pane_default_cursor(wp); 1127 } 1128 if (strcmp(name, "fill-character") == 0) { 1129 RB_FOREACH(w, windows, &windows) 1130 window_set_fill_character(w); 1131 } 1132 if (strcmp(name, "key-table") == 0) { 1133 TAILQ_FOREACH(loop, &clients, entry) 1134 server_client_set_key_table(loop, NULL); 1135 } 1136 if (strcmp(name, "user-keys") == 0) { 1137 TAILQ_FOREACH(loop, &clients, entry) { 1138 if (loop->tty.flags & TTY_OPENED) 1139 tty_keys_build(&loop->tty); 1140 } 1141 } 1142 if (strcmp(name, "status") == 0 || 1143 strcmp(name, "status-interval") == 0) 1144 status_timer_start_all(); 1145 if (strcmp(name, "monitor-silence") == 0) 1146 alerts_reset_all(); 1147 if (strcmp(name, "window-style") == 0 || 1148 strcmp(name, "window-active-style") == 0) { 1149 RB_FOREACH(wp, window_pane_tree, &all_window_panes) 1150 wp->flags |= PANE_STYLECHANGED; 1151 } 1152 if (strcmp(name, "pane-colours") == 0) { 1153 RB_FOREACH(wp, window_pane_tree, &all_window_panes) 1154 colour_palette_from_option(&wp->palette, wp->options); 1155 } 1156 if (strcmp(name, "pane-border-status") == 0) { 1157 RB_FOREACH(w, windows, &windows) 1158 layout_fix_panes(w, NULL); 1159 } 1160 RB_FOREACH(s, sessions, &sessions) 1161 status_update_cache(s); 1162 1163 recalculate_sizes(); 1164 TAILQ_FOREACH(loop, &clients, entry) { 1165 if (loop->session != NULL) 1166 server_redraw_client(loop); 1167 } 1168} 1169 1170int 1171options_remove_or_default(struct options_entry *o, int idx, char **cause) 1172{ 1173 struct options *oo = o->owner; 1174 1175 if (idx == -1) { 1176 if (o->tableentry != NULL && 1177 (oo == global_options || 1178 oo == global_s_options || 1179 oo == global_w_options)) 1180 options_default(oo, o->tableentry); 1181 else 1182 options_remove(o); 1183 } else if (options_array_set(o, idx, NULL, 0, cause) != 0) 1184 return (-1); 1185 return (0); 1186} 1187