options.c revision 1.63
1/* $OpenBSD: options.c,v 1.63 2021/08/11 20:49:55 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_EMPTY: 447 if (cause != NULL) 448 *cause = xstrdup("empty command"); 449 return (-1); 450 case CMD_PARSE_ERROR: 451 if (cause != NULL) 452 *cause = pr->error; 453 else 454 free(pr->error); 455 return (-1); 456 case CMD_PARSE_SUCCESS: 457 break; 458 } 459 460 a = options_array_item(o, idx); 461 if (a == NULL) 462 a = options_array_new(o, idx); 463 else 464 options_value_free(o, &a->value); 465 a->value.cmdlist = pr->cmdlist; 466 return (0); 467 } 468 469 if (OPTIONS_IS_STRING(o)) { 470 a = options_array_item(o, idx); 471 if (a != NULL && append) 472 xasprintf(&new, "%s%s", a->value.string, value); 473 else 474 new = xstrdup(value); 475 if (a == NULL) 476 a = options_array_new(o, idx); 477 else 478 options_value_free(o, &a->value); 479 a->value.string = new; 480 return (0); 481 } 482 483 if (o->tableentry->type == OPTIONS_TABLE_COLOUR) { 484 if ((number = colour_fromstring(value)) == -1) { 485 xasprintf(cause, "bad colour: %s", value); 486 return (-1); 487 } 488 a = options_array_item(o, idx); 489 if (a == NULL) 490 a = options_array_new(o, idx); 491 else 492 options_value_free(o, &a->value); 493 a->value.number = number; 494 return (0); 495 } 496 497 if (cause != NULL) 498 *cause = xstrdup("wrong array type"); 499 return (-1); 500} 501 502int 503options_array_assign(struct options_entry *o, const char *s, char **cause) 504{ 505 const char *separator; 506 char *copy, *next, *string; 507 u_int i; 508 509 separator = o->tableentry->separator; 510 if (separator == NULL) 511 separator = " ,"; 512 if (*separator == '\0') { 513 if (*s == '\0') 514 return (0); 515 for (i = 0; i < UINT_MAX; i++) { 516 if (options_array_item(o, i) == NULL) 517 break; 518 } 519 return (options_array_set(o, i, s, 0, cause)); 520 } 521 522 if (*s == '\0') 523 return (0); 524 copy = string = xstrdup(s); 525 while ((next = strsep(&string, separator)) != NULL) { 526 if (*next == '\0') 527 continue; 528 for (i = 0; i < UINT_MAX; i++) { 529 if (options_array_item(o, i) == NULL) 530 break; 531 } 532 if (i == UINT_MAX) 533 break; 534 if (options_array_set(o, i, next, 0, cause) != 0) { 535 free(copy); 536 return (-1); 537 } 538 } 539 free(copy); 540 return (0); 541} 542 543struct options_array_item * 544options_array_first(struct options_entry *o) 545{ 546 if (!OPTIONS_IS_ARRAY(o)) 547 return (NULL); 548 return (RB_MIN(options_array, &o->value.array)); 549} 550 551struct options_array_item * 552options_array_next(struct options_array_item *a) 553{ 554 return (RB_NEXT(options_array, &o->value.array, a)); 555} 556 557u_int 558options_array_item_index(struct options_array_item *a) 559{ 560 return (a->index); 561} 562 563union options_value * 564options_array_item_value(struct options_array_item *a) 565{ 566 return (&a->value); 567} 568 569int 570options_is_array(struct options_entry *o) 571{ 572 return (OPTIONS_IS_ARRAY(o)); 573} 574 575int 576options_is_string(struct options_entry *o) 577{ 578 return (OPTIONS_IS_STRING(o)); 579} 580 581char * 582options_to_string(struct options_entry *o, int idx, int numeric) 583{ 584 struct options_array_item *a; 585 586 if (OPTIONS_IS_ARRAY(o)) { 587 if (idx == -1) 588 return (xstrdup("")); 589 a = options_array_item(o, idx); 590 if (a == NULL) 591 return (xstrdup("")); 592 return (options_value_to_string(o, &a->value, numeric)); 593 } 594 return (options_value_to_string(o, &o->value, numeric)); 595} 596 597char * 598options_parse(const char *name, int *idx) 599{ 600 char *copy, *cp, *end; 601 602 if (*name == '\0') 603 return (NULL); 604 copy = xstrdup(name); 605 if ((cp = strchr(copy, '[')) == NULL) { 606 *idx = -1; 607 return (copy); 608 } 609 end = strchr(cp + 1, ']'); 610 if (end == NULL || end[1] != '\0' || !isdigit((u_char)end[-1])) { 611 free(copy); 612 return (NULL); 613 } 614 if (sscanf(cp, "[%d]", idx) != 1 || *idx < 0) { 615 free(copy); 616 return (NULL); 617 } 618 *cp = '\0'; 619 return (copy); 620} 621 622struct options_entry * 623options_parse_get(struct options *oo, const char *s, int *idx, int only) 624{ 625 struct options_entry *o; 626 char *name; 627 628 name = options_parse(s, idx); 629 if (name == NULL) 630 return (NULL); 631 if (only) 632 o = options_get_only(oo, name); 633 else 634 o = options_get(oo, name); 635 free(name); 636 return (o); 637} 638 639char * 640options_match(const char *s, int *idx, int *ambiguous) 641{ 642 const struct options_table_entry *oe, *found; 643 char *parsed; 644 const char *name; 645 size_t namelen; 646 647 parsed = options_parse(s, idx); 648 if (parsed == NULL) 649 return (NULL); 650 if (*parsed == '@') { 651 *ambiguous = 0; 652 return (parsed); 653 } 654 655 name = options_map_name(parsed); 656 namelen = strlen(name); 657 658 found = NULL; 659 for (oe = options_table; oe->name != NULL; oe++) { 660 if (strcmp(oe->name, name) == 0) { 661 found = oe; 662 break; 663 } 664 if (strncmp(oe->name, name, namelen) == 0) { 665 if (found != NULL) { 666 *ambiguous = 1; 667 free(parsed); 668 return (NULL); 669 } 670 found = oe; 671 } 672 } 673 free(parsed); 674 if (found == NULL) { 675 *ambiguous = 0; 676 return (NULL); 677 } 678 return (xstrdup(found->name)); 679} 680 681struct options_entry * 682options_match_get(struct options *oo, const char *s, int *idx, int only, 683 int *ambiguous) 684{ 685 char *name; 686 struct options_entry *o; 687 688 name = options_match(s, idx, ambiguous); 689 if (name == NULL) 690 return (NULL); 691 *ambiguous = 0; 692 if (only) 693 o = options_get_only(oo, name); 694 else 695 o = options_get(oo, name); 696 free(name); 697 return (o); 698} 699 700const char * 701options_get_string(struct options *oo, const char *name) 702{ 703 struct options_entry *o; 704 705 o = options_get(oo, name); 706 if (o == NULL) 707 fatalx("missing option %s", name); 708 if (!OPTIONS_IS_STRING(o)) 709 fatalx("option %s is not a string", name); 710 return (o->value.string); 711} 712 713long long 714options_get_number(struct options *oo, const char *name) 715{ 716 struct options_entry *o; 717 718 o = options_get(oo, name); 719 if (o == NULL) 720 fatalx("missing option %s", name); 721 if (!OPTIONS_IS_NUMBER(o)) 722 fatalx("option %s is not a number", name); 723 return (o->value.number); 724} 725 726struct options_entry * 727options_set_string(struct options *oo, const char *name, int append, 728 const char *fmt, ...) 729{ 730 struct options_entry *o; 731 va_list ap; 732 const char *separator = ""; 733 char *s, *value; 734 735 va_start(ap, fmt); 736 xvasprintf(&s, fmt, ap); 737 va_end(ap); 738 739 o = options_get_only(oo, name); 740 if (o != NULL && append && OPTIONS_IS_STRING(o)) { 741 if (*name != '@') { 742 separator = o->tableentry->separator; 743 if (separator == NULL) 744 separator = ""; 745 } 746 xasprintf(&value, "%s%s%s", o->value.string, separator, s); 747 free(s); 748 } else 749 value = s; 750 if (o == NULL && *name == '@') 751 o = options_add(oo, name); 752 else if (o == NULL) { 753 o = options_default(oo, options_parent_table_entry(oo, name)); 754 if (o == NULL) 755 return (NULL); 756 } 757 758 if (!OPTIONS_IS_STRING(o)) 759 fatalx("option %s is not a string", name); 760 free(o->value.string); 761 o->value.string = value; 762 o->cached = 0; 763 return (o); 764} 765 766struct options_entry * 767options_set_number(struct options *oo, const char *name, long long value) 768{ 769 struct options_entry *o; 770 771 if (*name == '@') 772 fatalx("user option %s must be a string", name); 773 774 o = options_get_only(oo, name); 775 if (o == NULL) { 776 o = options_default(oo, options_parent_table_entry(oo, name)); 777 if (o == NULL) 778 return (NULL); 779 } 780 781 if (!OPTIONS_IS_NUMBER(o)) 782 fatalx("option %s is not a number", name); 783 o->value.number = value; 784 return (o); 785} 786 787int 788options_scope_from_name(struct args *args, int window, 789 const char *name, struct cmd_find_state *fs, struct options **oo, 790 char **cause) 791{ 792 struct session *s = fs->s; 793 struct winlink *wl = fs->wl; 794 struct window_pane *wp = fs->wp; 795 const char *target = args_get(args, 't'); 796 const struct options_table_entry *oe; 797 int scope = OPTIONS_TABLE_NONE; 798 799 if (*name == '@') 800 return (options_scope_from_flags(args, window, fs, oo, cause)); 801 802 for (oe = options_table; oe->name != NULL; oe++) { 803 if (strcmp(oe->name, name) == 0) 804 break; 805 } 806 if (oe->name == NULL) { 807 xasprintf(cause, "unknown option: %s", name); 808 return (OPTIONS_TABLE_NONE); 809 } 810 switch (oe->scope) { 811 case OPTIONS_TABLE_SERVER: 812 *oo = global_options; 813 scope = OPTIONS_TABLE_SERVER; 814 break; 815 case OPTIONS_TABLE_SESSION: 816 if (args_has(args, 'g')) { 817 *oo = global_s_options; 818 scope = OPTIONS_TABLE_SESSION; 819 } else if (s == NULL && target != NULL) 820 xasprintf(cause, "no such session: %s", target); 821 else if (s == NULL) 822 xasprintf(cause, "no current session"); 823 else { 824 *oo = s->options; 825 scope = OPTIONS_TABLE_SESSION; 826 } 827 break; 828 case OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE: 829 if (args_has(args, 'p')) { 830 if (wp == NULL && target != NULL) 831 xasprintf(cause, "no such pane: %s", target); 832 else if (wp == NULL) 833 xasprintf(cause, "no current pane"); 834 else { 835 *oo = wp->options; 836 scope = OPTIONS_TABLE_PANE; 837 } 838 break; 839 } 840 /* FALLTHROUGH */ 841 case OPTIONS_TABLE_WINDOW: 842 if (args_has(args, 'g')) { 843 *oo = global_w_options; 844 scope = OPTIONS_TABLE_WINDOW; 845 } else if (wl == NULL && target != NULL) 846 xasprintf(cause, "no such window: %s", target); 847 else if (wl == NULL) 848 xasprintf(cause, "no current window"); 849 else { 850 *oo = wl->window->options; 851 scope = OPTIONS_TABLE_WINDOW; 852 } 853 break; 854 } 855 return (scope); 856} 857 858int 859options_scope_from_flags(struct args *args, int window, 860 struct cmd_find_state *fs, struct options **oo, char **cause) 861{ 862 struct session *s = fs->s; 863 struct winlink *wl = fs->wl; 864 struct window_pane *wp = fs->wp; 865 const char *target = args_get(args, 't'); 866 867 if (args_has(args, 's')) { 868 *oo = global_options; 869 return (OPTIONS_TABLE_SERVER); 870 } 871 872 if (args_has(args, 'p')) { 873 if (wp == NULL) { 874 if (target != NULL) 875 xasprintf(cause, "no such pane: %s", target); 876 else 877 xasprintf(cause, "no current pane"); 878 return (OPTIONS_TABLE_NONE); 879 } 880 *oo = wp->options; 881 return (OPTIONS_TABLE_PANE); 882 } else if (window || args_has(args, 'w')) { 883 if (args_has(args, 'g')) { 884 *oo = global_w_options; 885 return (OPTIONS_TABLE_WINDOW); 886 } 887 if (wl == NULL) { 888 if (target != NULL) 889 xasprintf(cause, "no such window: %s", target); 890 else 891 xasprintf(cause, "no current window"); 892 return (OPTIONS_TABLE_NONE); 893 } 894 *oo = wl->window->options; 895 return (OPTIONS_TABLE_WINDOW); 896 } else { 897 if (args_has(args, 'g')) { 898 *oo = global_s_options; 899 return (OPTIONS_TABLE_SESSION); 900 } 901 if (s == NULL) { 902 if (target != NULL) 903 xasprintf(cause, "no such session: %s", target); 904 else 905 xasprintf(cause, "no current session"); 906 return (OPTIONS_TABLE_NONE); 907 } 908 *oo = s->options; 909 return (OPTIONS_TABLE_SESSION); 910 } 911} 912 913struct style * 914options_string_to_style(struct options *oo, const char *name, 915 struct format_tree *ft) 916{ 917 struct options_entry *o; 918 const char *s; 919 char *expanded; 920 921 o = options_get(oo, name); 922 if (o == NULL || !OPTIONS_IS_STRING(o)) 923 return (NULL); 924 925 if (o->cached) 926 return (&o->style); 927 s = o->value.string; 928 log_debug("%s: %s is '%s'", __func__, name, s); 929 930 style_set(&o->style, &grid_default_cell); 931 o->cached = (strstr(s, "#{") == NULL); 932 933 if (ft != NULL && !o->cached) { 934 expanded = format_expand(ft, s); 935 if (style_parse(&o->style, &grid_default_cell, expanded) != 0) { 936 free(expanded); 937 return (NULL); 938 } 939 free(expanded); 940 } else { 941 if (style_parse(&o->style, &grid_default_cell, s) != 0) 942 return (NULL); 943 } 944 return (&o->style); 945} 946 947static int 948options_from_string_check(const struct options_table_entry *oe, 949 const char *value, char **cause) 950{ 951 struct style sy; 952 953 if (oe == NULL) 954 return (0); 955 if (strcmp(oe->name, "default-shell") == 0 && !checkshell(value)) { 956 xasprintf(cause, "not a suitable shell: %s", value); 957 return (-1); 958 } 959 if (oe->pattern != NULL && fnmatch(oe->pattern, value, 0) != 0) { 960 xasprintf(cause, "value is invalid: %s", value); 961 return (-1); 962 } 963 if ((oe->flags & OPTIONS_TABLE_IS_STYLE) && 964 strstr(value, "#{") == NULL && 965 style_parse(&sy, &grid_default_cell, value) != 0) { 966 xasprintf(cause, "invalid style: %s", value); 967 return (-1); 968 } 969 return (0); 970} 971 972static int 973options_from_string_flag(struct options *oo, const char *name, 974 const char *value, char **cause) 975{ 976 int flag; 977 978 if (value == NULL || *value == '\0') 979 flag = !options_get_number(oo, name); 980 else if (strcmp(value, "1") == 0 || 981 strcasecmp(value, "on") == 0 || 982 strcasecmp(value, "yes") == 0) 983 flag = 1; 984 else if (strcmp(value, "0") == 0 || 985 strcasecmp(value, "off") == 0 || 986 strcasecmp(value, "no") == 0) 987 flag = 0; 988 else { 989 xasprintf(cause, "bad value: %s", value); 990 return (-1); 991 } 992 options_set_number(oo, name, flag); 993 return (0); 994} 995 996static int 997options_from_string_choice(const struct options_table_entry *oe, 998 struct options *oo, const char *name, const char *value, char **cause) 999{ 1000 const char **cp; 1001 int n, choice = -1; 1002 1003 if (value == NULL) { 1004 choice = options_get_number(oo, name); 1005 if (choice < 2) 1006 choice = !choice; 1007 } else { 1008 n = 0; 1009 for (cp = oe->choices; *cp != NULL; cp++) { 1010 if (strcmp(*cp, value) == 0) 1011 choice = n; 1012 n++; 1013 } 1014 if (choice == -1) { 1015 xasprintf(cause, "unknown value: %s", value); 1016 return (-1); 1017 } 1018 } 1019 options_set_number(oo, name, choice); 1020 return (0); 1021} 1022 1023int 1024options_from_string(struct options *oo, const struct options_table_entry *oe, 1025 const char *name, const char *value, int append, char **cause) 1026{ 1027 enum options_table_type type; 1028 long long number; 1029 const char *errstr, *new; 1030 char *old; 1031 key_code key; 1032 1033 if (oe != NULL) { 1034 if (value == NULL && 1035 oe->type != OPTIONS_TABLE_FLAG && 1036 oe->type != OPTIONS_TABLE_CHOICE) { 1037 xasprintf(cause, "empty value"); 1038 return (-1); 1039 } 1040 type = oe->type; 1041 } else { 1042 if (*name != '@') { 1043 xasprintf(cause, "bad option name"); 1044 return (-1); 1045 } 1046 type = OPTIONS_TABLE_STRING; 1047 } 1048 1049 switch (type) { 1050 case OPTIONS_TABLE_STRING: 1051 old = xstrdup(options_get_string(oo, name)); 1052 options_set_string(oo, name, append, "%s", value); 1053 1054 new = options_get_string(oo, name); 1055 if (options_from_string_check(oe, new, cause) != 0) { 1056 options_set_string(oo, name, 0, "%s", old); 1057 free(old); 1058 return (-1); 1059 } 1060 free(old); 1061 return (0); 1062 case OPTIONS_TABLE_NUMBER: 1063 number = strtonum(value, oe->minimum, oe->maximum, &errstr); 1064 if (errstr != NULL) { 1065 xasprintf(cause, "value is %s: %s", errstr, value); 1066 return (-1); 1067 } 1068 options_set_number(oo, name, number); 1069 return (0); 1070 case OPTIONS_TABLE_KEY: 1071 key = key_string_lookup_string(value); 1072 if (key == KEYC_UNKNOWN) { 1073 xasprintf(cause, "bad key: %s", value); 1074 return (-1); 1075 } 1076 options_set_number(oo, name, key); 1077 return (0); 1078 case OPTIONS_TABLE_COLOUR: 1079 if ((number = colour_fromstring(value)) == -1) { 1080 xasprintf(cause, "bad colour: %s", value); 1081 return (-1); 1082 } 1083 options_set_number(oo, name, number); 1084 return (0); 1085 case OPTIONS_TABLE_FLAG: 1086 return (options_from_string_flag(oo, name, value, cause)); 1087 case OPTIONS_TABLE_CHOICE: 1088 return (options_from_string_choice(oe, oo, name, value, cause)); 1089 case OPTIONS_TABLE_COMMAND: 1090 break; 1091 } 1092 return (-1); 1093} 1094 1095void 1096options_push_changes(const char *name) 1097{ 1098 struct client *loop; 1099 struct session *s; 1100 struct window *w; 1101 struct window_pane *wp; 1102 1103 if (strcmp(name, "automatic-rename") == 0) { 1104 RB_FOREACH(w, windows, &windows) { 1105 if (w->active == NULL) 1106 continue; 1107 if (options_get_number(w->options, "automatic-rename")) 1108 w->active->flags |= PANE_CHANGED; 1109 } 1110 } 1111 if (strcmp(name, "key-table") == 0) { 1112 TAILQ_FOREACH(loop, &clients, entry) 1113 server_client_set_key_table(loop, NULL); 1114 } 1115 if (strcmp(name, "user-keys") == 0) { 1116 TAILQ_FOREACH(loop, &clients, entry) { 1117 if (loop->tty.flags & TTY_OPENED) 1118 tty_keys_build(&loop->tty); 1119 } 1120 } 1121 if (strcmp(name, "status") == 0 || 1122 strcmp(name, "status-interval") == 0) 1123 status_timer_start_all(); 1124 if (strcmp(name, "monitor-silence") == 0) 1125 alerts_reset_all(); 1126 if (strcmp(name, "window-style") == 0 || 1127 strcmp(name, "window-active-style") == 0) { 1128 RB_FOREACH(wp, window_pane_tree, &all_window_panes) 1129 wp->flags |= PANE_STYLECHANGED; 1130 } 1131 if (strcmp(name, "pane-colours") == 0) { 1132 RB_FOREACH(wp, window_pane_tree, &all_window_panes) 1133 colour_palette_from_option(&wp->palette, wp->options); 1134 } 1135 if (strcmp(name, "pane-border-status") == 0) { 1136 RB_FOREACH(w, windows, &windows) 1137 layout_fix_panes(w, NULL); 1138 } 1139 RB_FOREACH(s, sessions, &sessions) 1140 status_update_cache(s); 1141 1142 recalculate_sizes(); 1143 TAILQ_FOREACH(loop, &clients, entry) { 1144 if (loop->session != NULL) 1145 server_redraw_client(loop); 1146 } 1147} 1148 1149int 1150options_remove_or_default(struct options_entry *o, int idx, char **cause) 1151{ 1152 struct options *oo = o->owner; 1153 1154 if (idx == -1) { 1155 if (o->tableentry != NULL && 1156 (oo == global_options || 1157 oo == global_s_options || 1158 oo == global_w_options)) 1159 options_default(oo, o->tableentry); 1160 else 1161 options_remove(o); 1162 } else if (options_array_set(o, idx, NULL, 0, cause) != 0) 1163 return (-1); 1164 return (0); 1165} 1166