Annotation of src/usr.bin/tmux/cmd-set-option.c, Revision 1.132
1.132 ! nicm 1: /* $OpenBSD: cmd-set-option.c,v 1.131 2020/04/13 10:59:58 nicm Exp $ */
1.1 nicm 2:
3: /*
1.93 nicm 4: * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
1.1 nicm 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:
1.120 nicm 21: #include <fnmatch.h>
1.1 nicm 22: #include <stdlib.h>
23: #include <string.h>
24:
25: #include "tmux.h"
26:
27: /*
28: * Set an option.
29: */
30:
1.101 nicm 31: static enum cmd_retval cmd_set_option_exec(struct cmd *, struct cmdq_item *);
1.59 nicm 32:
1.105 nicm 33: static int cmd_set_option_set(struct cmd *, struct cmdq_item *,
1.107 nicm 34: struct options *, struct options_entry *, const char *);
1.105 nicm 35: static int cmd_set_option_flag(struct cmdq_item *,
1.99 nicm 36: const struct options_table_entry *, struct options *,
37: const char *);
1.105 nicm 38: static int cmd_set_option_choice(struct cmdq_item *,
1.99 nicm 39: const struct options_table_entry *, struct options *,
40: const char *);
1.43 nicm 41:
1.1 nicm 42: const struct cmd_entry cmd_set_option_entry = {
1.91 nicm 43: .name = "set-option",
44: .alias = "set",
45:
1.127 nicm 46: .args = { "aFgopqst:uw", 1, 2 },
47: .usage = "[-aFgopqsuw] " CMD_TARGET_PANE_USAGE " option [value]",
1.91 nicm 48:
1.127 nicm 49: .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
1.92 nicm 50:
1.100 nicm 51: .flags = CMD_AFTERHOOK,
1.91 nicm 52: .exec = cmd_set_option_exec
1.1 nicm 53: };
54:
1.46 nicm 55: const struct cmd_entry cmd_set_window_option_entry = {
1.91 nicm 56: .name = "set-window-option",
57: .alias = "setw",
58:
1.115 nicm 59: .args = { "aFgoqt:u", 1, 2 },
60: .usage = "[-aFgoqu] " CMD_TARGET_WINDOW_USAGE " option [value]",
1.91 nicm 61:
1.114 nicm 62: .target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL },
1.92 nicm 63:
1.100 nicm 64: .flags = CMD_AFTERHOOK,
1.91 nicm 65: .exec = cmd_set_option_exec
1.46 nicm 66: };
67:
1.125 nicm 68: const struct cmd_entry cmd_set_hook_entry = {
69: .name = "set-hook",
70: .alias = NULL,
71:
1.129 nicm 72: .args = { "agpRt:uw", 1, 2 },
73: .usage = "[-agpRuw] " CMD_TARGET_PANE_USAGE " hook [command]",
1.125 nicm 74:
1.129 nicm 75: .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
1.125 nicm 76:
77: .flags = CMD_AFTERHOOK,
78: .exec = cmd_set_option_exec
79: };
80:
1.99 nicm 81: static enum cmd_retval
1.101 nicm 82: cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
1.1 nicm 83: {
1.130 nicm 84: struct args *args = cmd_get_args(self);
1.109 nicm 85: int append = args_has(args, 'a');
1.131 nicm 86: struct cmd_find_state *target = cmdq_get_target(item);
1.132 ! nicm 87: struct client *tc = cmdq_get_target_client(item);
! 88: struct client *loop;
1.131 nicm 89: struct session *s = target->s;
1.112 nicm 90: struct window *w;
1.127 nicm 91: struct window_pane *wp;
1.105 nicm 92: struct options *oo;
1.107 nicm 93: struct options_entry *parent, *o;
1.115 nicm 94: char *name, *argument, *value = NULL, *cause;
1.105 nicm 95: int window, idx, already, error, ambiguous;
1.127 nicm 96: int scope;
1.123 nicm 97: struct style *sy;
1.115 nicm 98:
1.130 nicm 99: window = (cmd_get_entry(self) == &cmd_set_window_option_entry);
1.126 nicm 100:
1.115 nicm 101: /* Expand argument. */
1.132 ! nicm 102: argument = format_single_from_target(item, args->argv[0]);
1.105 nicm 103:
1.126 nicm 104: /* If set-hook -R, fire the hook straight away. */
1.130 nicm 105: if (cmd_get_entry(self) == &cmd_set_hook_entry && args_has(args, 'R')) {
1.125 nicm 106: notify_hook(item, argument);
1.126 nicm 107: free(argument);
1.125 nicm 108: return (CMD_RETURN_NORMAL);
109: }
110:
1.105 nicm 111: /* Parse option name and index. */
1.115 nicm 112: name = options_match(argument, &idx, &ambiguous);
1.105 nicm 113: if (name == NULL) {
1.106 nicm 114: if (args_has(args, 'q'))
1.115 nicm 115: goto out;
1.105 nicm 116: if (ambiguous)
1.115 nicm 117: cmdq_error(item, "ambiguous option: %s", argument);
1.105 nicm 118: else
1.115 nicm 119: cmdq_error(item, "invalid option: %s", argument);
120: goto fail;
1.50 nicm 121: }
122: if (args->argc < 2)
1.105 nicm 123: value = NULL;
1.115 nicm 124: else if (args_has(args, 'F'))
1.132 ! nicm 125: value = format_single_from_target(item, args->argv[1]);
1.50 nicm 126: else
1.115 nicm 127: value = xstrdup(args->argv[1]);
1.50 nicm 128:
1.126 nicm 129: /* Get the scope and table for the option .*/
1.131 nicm 130: scope = options_scope_from_name(args, window, name, target, &oo,
131: &cause);
1.105 nicm 132: if (scope == OPTIONS_TABLE_NONE) {
1.106 nicm 133: if (args_has(args, 'q'))
1.115 nicm 134: goto out;
1.105 nicm 135: cmdq_error(item, "%s", cause);
136: free(cause);
1.113 nicm 137: goto fail;
1.105 nicm 138: }
139: o = options_get_only(oo, name);
140: parent = options_get(oo, name);
141:
142: /* Check that array options and indexes match up. */
1.122 nicm 143: if (idx != -1 && (*name == '@' || !options_isarray(parent))) {
144: cmdq_error(item, "not an array: %s", argument);
145: goto fail;
1.105 nicm 146: }
147:
148: /* With -o, check this option is not already set. */
149: if (!args_has(args, 'u') && args_has(args, 'o')) {
150: if (idx == -1)
151: already = (o != NULL);
152: else {
153: if (o == NULL)
154: already = 0;
155: else
156: already = (options_array_get(o, idx) != NULL);
157: }
158: if (already) {
159: if (args_has(args, 'q'))
1.115 nicm 160: goto out;
161: cmdq_error(item, "already set: %s", argument);
1.113 nicm 162: goto fail;
1.105 nicm 163: }
1.1 nicm 164: }
165:
1.105 nicm 166: /* Change the option. */
1.44 nicm 167: if (args_has(args, 'u')) {
1.105 nicm 168: if (o == NULL)
1.118 nicm 169: goto out;
1.105 nicm 170: if (idx == -1) {
1.119 nicm 171: if (*name == '@')
172: options_remove(o);
173: else if (oo == global_options ||
1.105 nicm 174: oo == global_s_options ||
175: oo == global_w_options)
176: options_default(oo, options_table_entry(o));
177: else
178: options_remove(o);
1.125 nicm 179: } else if (options_array_set(o, idx, NULL, 0, &cause) != 0) {
180: cmdq_error(item, "%s", cause);
181: free(cause);
182: goto fail;
183: }
1.109 nicm 184: } else if (*name == '@') {
185: if (value == NULL) {
186: cmdq_error(item, "empty value");
1.113 nicm 187: goto fail;
1.109 nicm 188: }
189: options_set_string(oo, name, append, "%s", value);
1.122 nicm 190: } else if (idx == -1 && !options_isarray(parent)) {
1.105 nicm 191: error = cmd_set_option_set(self, item, oo, parent, value);
192: if (error != 0)
1.113 nicm 193: goto fail;
1.43 nicm 194: } else {
1.109 nicm 195: if (value == NULL) {
196: cmdq_error(item, "empty value");
1.113 nicm 197: goto fail;
1.109 nicm 198: }
1.105 nicm 199: if (o == NULL)
200: o = options_empty(oo, options_table_entry(parent));
1.110 nicm 201: if (idx == -1) {
202: if (!append)
203: options_array_clear(o);
1.125 nicm 204: if (options_array_assign(o, value, &cause) != 0) {
205: cmdq_error(item, "%s", cause);
206: free(cause);
207: goto fail;
208: }
209: } else if (options_array_set(o, idx, value, append,
210: &cause) != 0) {
211: cmdq_error(item, "%s", cause);
212: free(cause);
1.113 nicm 213: goto fail;
1.61 nicm 214: }
1.55 nicm 215: }
216:
1.103 nicm 217: /* Update timers and so on for various options. */
1.105 nicm 218: if (strcmp(name, "automatic-rename") == 0) {
1.72 nicm 219: RB_FOREACH(w, windows, &windows) {
1.102 nicm 220: if (w->active == NULL)
221: continue;
1.84 nicm 222: if (options_get_number(w->options, "automatic-rename"))
1.81 nicm 223: w->active->flags |= PANE_CHANGED;
1.55 nicm 224: }
1.89 nicm 225: }
1.105 nicm 226: if (strcmp(name, "key-table") == 0) {
1.115 nicm 227: TAILQ_FOREACH(loop, &clients, entry)
228: server_client_set_key_table(loop, NULL);
1.117 nicm 229: }
230: if (strcmp(name, "user-keys") == 0) {
231: TAILQ_FOREACH(loop, &clients, entry) {
232: if (loop->tty.flags & TTY_OPENED)
233: tty_keys_build(&loop->tty);
234: }
1.1 nicm 235: }
1.123 nicm 236: if (strcmp(name, "status-fg") == 0 || strcmp(name, "status-bg") == 0) {
237: sy = options_get_style(oo, "status-style");
238: sy->gc.fg = options_get_number(oo, "status-fg");
239: sy->gc.bg = options_get_number(oo, "status-bg");
240: }
241: if (strcmp(name, "status-style") == 0) {
242: sy = options_get_style(oo, "status-style");
243: options_set_number(oo, "status-fg", sy->gc.fg);
244: options_set_number(oo, "status-bg", sy->gc.bg);
245: }
1.105 nicm 246: if (strcmp(name, "status") == 0 ||
247: strcmp(name, "status-interval") == 0)
1.77 nicm 248: status_timer_start_all();
1.105 nicm 249: if (strcmp(name, "monitor-silence") == 0)
1.82 nicm 250: alerts_reset_all();
1.105 nicm 251: if (strcmp(name, "window-style") == 0 ||
252: strcmp(name, "window-active-style") == 0) {
1.127 nicm 253: RB_FOREACH(wp, window_pane_tree, &all_window_panes)
254: wp->flags |= PANE_STYLECHANGED;
1.96 nicm 255: }
1.105 nicm 256: if (strcmp(name, "pane-border-status") == 0) {
1.95 nicm 257: RB_FOREACH(w, windows, &windows)
1.120 nicm 258: layout_fix_panes(w);
1.95 nicm 259: }
1.116 nicm 260: RB_FOREACH(s, sessions, &sessions)
1.121 nicm 261: status_update_cache(s);
1.1 nicm 262:
1.105 nicm 263: /*
264: * Update sizes and redraw. May not always be necessary but do it
265: * anyway.
266: */
1.1 nicm 267: recalculate_sizes();
1.115 nicm 268: TAILQ_FOREACH(loop, &clients, entry) {
269: if (loop->session != NULL)
270: server_redraw_client(loop);
1.1 nicm 271: }
272:
1.115 nicm 273: out:
274: free(argument);
275: free(value);
1.113 nicm 276: free(name);
1.57 nicm 277: return (CMD_RETURN_NORMAL);
1.113 nicm 278:
279: fail:
1.115 nicm 280: free(argument);
281: free(value);
1.113 nicm 282: free(name);
283: return (CMD_RETURN_ERROR);
1.27 nicm 284: }
1.59 nicm 285:
1.99 nicm 286: static int
1.105 nicm 287: cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo,
1.107 nicm 288: struct options_entry *parent, const char *value)
1.27 nicm 289: {
1.105 nicm 290: const struct options_table_entry *oe;
1.130 nicm 291: struct args *args = cmd_get_args(self);
1.105 nicm 292: int append = args_has(args, 'a');
1.107 nicm 293: struct options_entry *o;
1.105 nicm 294: long long number;
1.120 nicm 295: const char *errstr, *new;
296: char *old;
1.105 nicm 297: key_code key;
298:
299: oe = options_table_entry(parent);
300: if (value == NULL &&
301: oe->type != OPTIONS_TABLE_FLAG &&
302: oe->type != OPTIONS_TABLE_CHOICE) {
303: cmdq_error(item, "empty value");
1.43 nicm 304: return (-1);
1.27 nicm 305: }
1.43 nicm 306:
307: switch (oe->type) {
308: case OPTIONS_TABLE_STRING:
1.120 nicm 309: old = xstrdup(options_get_string(oo, oe->name));
1.105 nicm 310: options_set_string(oo, oe->name, append, "%s", value);
1.120 nicm 311: new = options_get_string(oo, oe->name);
1.128 nicm 312: if (strcmp(oe->name, "default-shell") == 0 &&
313: !checkshell(new)) {
314: options_set_string(oo, oe->name, 0, "%s", old);
315: free(old);
316: cmdq_error(item, "not a suitable shell: %s", value);
317: return (-1);
318: }
1.120 nicm 319: if (oe->pattern != NULL && fnmatch(oe->pattern, new, 0) != 0) {
320: options_set_string(oo, oe->name, 0, "%s", old);
321: free(old);
322: cmdq_error(item, "value is invalid: %s", value);
323: return (-1);
324: }
325: free(old);
1.105 nicm 326: return (0);
1.43 nicm 327: case OPTIONS_TABLE_NUMBER:
1.105 nicm 328: number = strtonum(value, oe->minimum, oe->maximum, &errstr);
329: if (errstr != NULL) {
330: cmdq_error(item, "value is %s: %s", errstr, value);
331: return (-1);
332: }
333: options_set_number(oo, oe->name, number);
334: return (0);
1.52 nicm 335: case OPTIONS_TABLE_KEY:
1.105 nicm 336: key = key_string_lookup_string(value);
337: if (key == KEYC_UNKNOWN) {
338: cmdq_error(item, "bad key: %s", value);
339: return (-1);
340: }
341: options_set_number(oo, oe->name, key);
342: return (0);
1.43 nicm 343: case OPTIONS_TABLE_COLOUR:
1.105 nicm 344: if ((number = colour_fromstring(value)) == -1) {
345: cmdq_error(item, "bad colour: %s", value);
346: return (-1);
347: }
1.123 nicm 348: options_set_number(oo, oe->name, number);
1.105 nicm 349: return (0);
1.43 nicm 350: case OPTIONS_TABLE_FLAG:
1.105 nicm 351: return (cmd_set_option_flag(item, oe, oo, value));
1.43 nicm 352: case OPTIONS_TABLE_CHOICE:
1.105 nicm 353: return (cmd_set_option_choice(item, oe, oo, value));
1.64 nicm 354: case OPTIONS_TABLE_STYLE:
1.105 nicm 355: o = options_set_style(oo, oe->name, append, value);
356: if (o == NULL) {
357: cmdq_error(item, "bad style: %s", value);
358: return (-1);
359: }
360: return (0);
1.125 nicm 361: case OPTIONS_TABLE_COMMAND:
362: break;
1.43 nicm 363: }
1.105 nicm 364: return (-1);
1.43 nicm 365: }
366:
1.105 nicm 367: static int
368: cmd_set_option_flag(struct cmdq_item *item,
1.69 nicm 369: const struct options_table_entry *oe, struct options *oo,
370: const char *value)
1.27 nicm 371: {
1.44 nicm 372: int flag;
1.27 nicm 373:
1.44 nicm 374: if (value == NULL || *value == '\0')
1.43 nicm 375: flag = !options_get_number(oo, oe->name);
1.105 nicm 376: else if (strcmp(value, "1") == 0 ||
377: strcasecmp(value, "on") == 0 ||
378: strcasecmp(value, "yes") == 0)
379: flag = 1;
380: else if (strcmp(value, "0") == 0 ||
381: strcasecmp(value, "off") == 0 ||
382: strcasecmp(value, "no") == 0)
383: flag = 0;
1.27 nicm 384: else {
1.105 nicm 385: cmdq_error(item, "bad value: %s", value);
386: return (-1);
1.27 nicm 387: }
1.105 nicm 388: options_set_number(oo, oe->name, flag);
389: return (0);
1.27 nicm 390: }
391:
1.105 nicm 392: static int
393: cmd_set_option_choice(struct cmdq_item *item,
1.60 nicm 394: const struct options_table_entry *oe, struct options *oo,
395: const char *value)
1.27 nicm 396: {
1.105 nicm 397: const char **cp;
1.44 nicm 398: int n, choice = -1;
1.27 nicm 399:
1.73 nicm 400: if (value == NULL) {
401: choice = options_get_number(oo, oe->name);
402: if (choice < 2)
403: choice = !choice;
404: } else {
405: n = 0;
1.105 nicm 406: for (cp = oe->choices; *cp != NULL; cp++) {
407: if (strcmp(*cp, value) == 0)
408: choice = n;
1.73 nicm 409: n++;
410: }
411: if (choice == -1) {
1.101 nicm 412: cmdq_error(item, "unknown value: %s", value);
1.105 nicm 413: return (-1);
1.27 nicm 414: }
415: }
1.105 nicm 416: options_set_number(oo, oe->name, choice);
417: return (0);
1.1 nicm 418: }