Annotation of src/usr.bin/tmux/cmd-set-option.c, Revision 1.121
1.121 ! nicm 1: /* $OpenBSD: cmd-set-option.c,v 1.120 2018/10/18 08:38:01 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.115 nicm 46: .args = { "aFgoqst:uw", 1, 2 },
47: .usage = "[-aFgosquw] [-t target-window] option [value]",
1.91 nicm 48:
1.114 nicm 49: .target = { 't', CMD_FIND_WINDOW, 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.99 nicm 68: static enum cmd_retval
1.101 nicm 69: cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
1.1 nicm 70: {
1.105 nicm 71: struct args *args = self->args;
1.109 nicm 72: int append = args_has(args, 'a');
1.114 nicm 73: struct cmd_find_state *fs = &item->target;
1.115 nicm 74: struct client *c, *loop;
1.105 nicm 75: struct session *s = fs->s;
76: struct winlink *wl = fs->wl;
1.112 nicm 77: struct window *w;
1.105 nicm 78: enum options_table_scope scope;
79: struct options *oo;
1.107 nicm 80: struct options_entry *parent, *o;
1.115 nicm 81: char *name, *argument, *value = NULL, *cause;
82: const char *target;
1.105 nicm 83: int window, idx, already, error, ambiguous;
1.115 nicm 84:
85: /* Expand argument. */
86: c = cmd_find_client(item, NULL, 1);
87: argument = format_single(item, args->argv[0], c, s, wl, NULL);
1.105 nicm 88:
89: /* Parse option name and index. */
1.115 nicm 90: name = options_match(argument, &idx, &ambiguous);
1.105 nicm 91: if (name == NULL) {
1.106 nicm 92: if (args_has(args, 'q'))
1.115 nicm 93: goto out;
1.105 nicm 94: if (ambiguous)
1.115 nicm 95: cmdq_error(item, "ambiguous option: %s", argument);
1.105 nicm 96: else
1.115 nicm 97: cmdq_error(item, "invalid option: %s", argument);
98: goto fail;
1.50 nicm 99: }
100: if (args->argc < 2)
1.105 nicm 101: value = NULL;
1.115 nicm 102: else if (args_has(args, 'F'))
103: value = format_single(item, args->argv[1], c, s, wl, NULL);
1.50 nicm 104: else
1.115 nicm 105: value = xstrdup(args->argv[1]);
1.50 nicm 106:
1.105 nicm 107: /*
108: * Figure out the scope: for user options it comes from the arguments,
109: * otherwise from the option name.
110: */
111: if (*name == '@') {
112: window = (self->entry == &cmd_set_window_option_entry);
113: scope = options_scope_from_flags(args, window, fs, &oo, &cause);
114: } else {
115: if (options_get_only(global_options, name) != NULL)
116: scope = OPTIONS_TABLE_SERVER;
117: else if (options_get_only(global_s_options, name) != NULL)
118: scope = OPTIONS_TABLE_SESSION;
119: else if (options_get_only(global_w_options, name) != NULL)
120: scope = OPTIONS_TABLE_WINDOW;
121: else {
122: scope = OPTIONS_TABLE_NONE;
1.115 nicm 123: xasprintf(&cause, "unknown option: %s", argument);
1.76 nicm 124: }
1.50 nicm 125: }
1.105 nicm 126: if (scope == OPTIONS_TABLE_NONE) {
1.106 nicm 127: if (args_has(args, 'q'))
1.115 nicm 128: goto out;
1.105 nicm 129: cmdq_error(item, "%s", cause);
130: free(cause);
1.113 nicm 131: goto fail;
1.50 nicm 132: }
133:
1.105 nicm 134: /* Which table should this option go into? */
135: if (scope == OPTIONS_TABLE_SERVER)
1.84 nicm 136: oo = global_options;
1.105 nicm 137: else if (scope == OPTIONS_TABLE_SESSION) {
138: if (args_has(self->args, 'g'))
139: oo = global_s_options;
140: else if (s == NULL) {
141: target = args_get(args, 't');
142: if (target != NULL)
143: cmdq_error(item, "no such session: %s", target);
144: else
145: cmdq_error(item, "no current session");
1.113 nicm 146: goto fail;
1.105 nicm 147: } else
148: oo = s->options;
149: } else if (scope == OPTIONS_TABLE_WINDOW) {
1.44 nicm 150: if (args_has(self->args, 'g'))
1.84 nicm 151: oo = global_w_options;
1.94 nicm 152: else if (wl == NULL) {
153: target = args_get(args, 't');
1.105 nicm 154: if (target != NULL)
155: cmdq_error(item, "no such window: %s", target);
156: else
1.101 nicm 157: cmdq_error(item, "no current window");
1.113 nicm 158: goto fail;
1.94 nicm 159: } else
1.84 nicm 160: oo = wl->window->options;
1.105 nicm 161: }
162: o = options_get_only(oo, name);
163: parent = options_get(oo, name);
164:
165: /* Check that array options and indexes match up. */
166: if (idx != -1) {
167: if (*name == '@' || options_array_size(parent, NULL) == -1) {
1.115 nicm 168: cmdq_error(item, "not an array: %s", argument);
1.113 nicm 169: goto fail;
1.105 nicm 170: }
171: }
172:
173: /* With -o, check this option is not already set. */
174: if (!args_has(args, 'u') && args_has(args, 'o')) {
175: if (idx == -1)
176: already = (o != NULL);
177: else {
178: if (o == NULL)
179: already = 0;
180: else
181: already = (options_array_get(o, idx) != NULL);
182: }
183: if (already) {
184: if (args_has(args, 'q'))
1.115 nicm 185: goto out;
186: cmdq_error(item, "already set: %s", argument);
1.113 nicm 187: goto fail;
1.105 nicm 188: }
1.1 nicm 189: }
190:
1.105 nicm 191: /* Change the option. */
1.44 nicm 192: if (args_has(args, 'u')) {
1.105 nicm 193: if (o == NULL)
1.118 nicm 194: goto out;
1.105 nicm 195: if (idx == -1) {
1.119 nicm 196: if (*name == '@')
197: options_remove(o);
198: else if (oo == global_options ||
1.105 nicm 199: oo == global_s_options ||
200: oo == global_w_options)
201: options_default(oo, options_table_entry(o));
202: else
203: options_remove(o);
204: } else
1.108 nicm 205: options_array_set(o, idx, NULL, 0);
1.109 nicm 206: } else if (*name == '@') {
207: if (value == NULL) {
208: cmdq_error(item, "empty value");
1.113 nicm 209: goto fail;
1.109 nicm 210: }
211: options_set_string(oo, name, append, "%s", value);
212: } else if (idx == -1 && options_array_size(parent, NULL) == -1) {
1.105 nicm 213: error = cmd_set_option_set(self, item, oo, parent, value);
214: if (error != 0)
1.113 nicm 215: goto fail;
1.43 nicm 216: } else {
1.109 nicm 217: if (value == NULL) {
218: cmdq_error(item, "empty value");
1.113 nicm 219: goto fail;
1.109 nicm 220: }
1.105 nicm 221: if (o == NULL)
222: o = options_empty(oo, options_table_entry(parent));
1.110 nicm 223: if (idx == -1) {
224: if (!append)
225: options_array_clear(o);
1.109 nicm 226: options_array_assign(o, value);
1.110 nicm 227: } else if (options_array_set(o, idx, value, append) != 0) {
1.115 nicm 228: cmdq_error(item, "invalid index: %s", argument);
1.113 nicm 229: goto fail;
1.61 nicm 230: }
1.55 nicm 231: }
232:
1.103 nicm 233: /* Update timers and so on for various options. */
1.105 nicm 234: if (strcmp(name, "automatic-rename") == 0) {
1.72 nicm 235: RB_FOREACH(w, windows, &windows) {
1.102 nicm 236: if (w->active == NULL)
237: continue;
1.84 nicm 238: if (options_get_number(w->options, "automatic-rename"))
1.81 nicm 239: w->active->flags |= PANE_CHANGED;
1.55 nicm 240: }
1.89 nicm 241: }
1.105 nicm 242: if (strcmp(name, "key-table") == 0) {
1.115 nicm 243: TAILQ_FOREACH(loop, &clients, entry)
244: server_client_set_key_table(loop, NULL);
1.117 nicm 245: }
246: if (strcmp(name, "user-keys") == 0) {
247: TAILQ_FOREACH(loop, &clients, entry) {
248: if (loop->tty.flags & TTY_OPENED)
249: tty_keys_build(&loop->tty);
250: }
1.1 nicm 251: }
1.105 nicm 252: if (strcmp(name, "status") == 0 ||
253: strcmp(name, "status-interval") == 0)
1.77 nicm 254: status_timer_start_all();
1.105 nicm 255: if (strcmp(name, "monitor-silence") == 0)
1.82 nicm 256: alerts_reset_all();
1.105 nicm 257: if (strcmp(name, "window-style") == 0 ||
258: strcmp(name, "window-active-style") == 0) {
1.96 nicm 259: RB_FOREACH(w, windows, &windows)
260: w->flags |= WINDOW_STYLECHANGED;
261: }
1.105 nicm 262: if (strcmp(name, "pane-border-status") == 0) {
1.95 nicm 263: RB_FOREACH(w, windows, &windows)
1.120 nicm 264: layout_fix_panes(w);
1.95 nicm 265: }
1.116 nicm 266: RB_FOREACH(s, sessions, &sessions)
1.121 ! nicm 267: status_update_cache(s);
1.1 nicm 268:
1.105 nicm 269: /*
270: * Update sizes and redraw. May not always be necessary but do it
271: * anyway.
272: */
1.1 nicm 273: recalculate_sizes();
1.115 nicm 274: TAILQ_FOREACH(loop, &clients, entry) {
275: if (loop->session != NULL)
276: server_redraw_client(loop);
1.1 nicm 277: }
278:
1.115 nicm 279: out:
280: free(argument);
281: free(value);
1.113 nicm 282: free(name);
1.57 nicm 283: return (CMD_RETURN_NORMAL);
1.113 nicm 284:
285: fail:
1.115 nicm 286: free(argument);
287: free(value);
1.113 nicm 288: free(name);
289: return (CMD_RETURN_ERROR);
1.27 nicm 290: }
1.59 nicm 291:
1.99 nicm 292: static int
1.105 nicm 293: cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo,
1.107 nicm 294: struct options_entry *parent, const char *value)
1.27 nicm 295: {
1.105 nicm 296: const struct options_table_entry *oe;
297: struct args *args = self->args;
298: int append = args_has(args, 'a');
1.107 nicm 299: struct options_entry *o;
1.105 nicm 300: long long number;
1.120 nicm 301: const char *errstr, *new;
302: char *old;
1.105 nicm 303: key_code key;
304:
305: oe = options_table_entry(parent);
306: if (value == NULL &&
307: oe->type != OPTIONS_TABLE_FLAG &&
308: oe->type != OPTIONS_TABLE_CHOICE) {
309: cmdq_error(item, "empty value");
1.43 nicm 310: return (-1);
1.27 nicm 311: }
1.43 nicm 312:
313: switch (oe->type) {
314: case OPTIONS_TABLE_STRING:
1.120 nicm 315: old = xstrdup(options_get_string(oo, oe->name));
1.105 nicm 316: options_set_string(oo, oe->name, append, "%s", value);
1.120 nicm 317: new = options_get_string(oo, oe->name);
318: if (oe->pattern != NULL && fnmatch(oe->pattern, new, 0) != 0) {
319: options_set_string(oo, oe->name, 0, "%s", old);
320: free(old);
321: cmdq_error(item, "value is invalid: %s", value);
322: return (-1);
323: }
324: free(old);
1.105 nicm 325: return (0);
1.43 nicm 326: case OPTIONS_TABLE_NUMBER:
1.105 nicm 327: number = strtonum(value, oe->minimum, oe->maximum, &errstr);
328: if (errstr != NULL) {
329: cmdq_error(item, "value is %s: %s", errstr, value);
330: return (-1);
331: }
332: options_set_number(oo, oe->name, number);
333: return (0);
1.52 nicm 334: case OPTIONS_TABLE_KEY:
1.105 nicm 335: key = key_string_lookup_string(value);
336: if (key == KEYC_UNKNOWN) {
337: cmdq_error(item, "bad key: %s", value);
338: return (-1);
339: }
340: options_set_number(oo, oe->name, key);
341: return (0);
1.43 nicm 342: case OPTIONS_TABLE_COLOUR:
1.105 nicm 343: if ((number = colour_fromstring(value)) == -1) {
344: cmdq_error(item, "bad colour: %s", value);
345: return (-1);
346: }
347: o = options_set_number(oo, oe->name, number);
348: options_style_update_new(oo, o);
349: return (0);
1.43 nicm 350: case OPTIONS_TABLE_ATTRIBUTES:
1.105 nicm 351: if ((number = attributes_fromstring(value)) == -1) {
352: cmdq_error(item, "bad attributes: %s", value);
353: return (-1);
354: }
355: o = options_set_number(oo, oe->name, number);
356: options_style_update_new(oo, o);
357: return (0);
1.43 nicm 358: case OPTIONS_TABLE_FLAG:
1.105 nicm 359: return (cmd_set_option_flag(item, oe, oo, value));
1.43 nicm 360: case OPTIONS_TABLE_CHOICE:
1.105 nicm 361: return (cmd_set_option_choice(item, oe, oo, value));
1.64 nicm 362: case OPTIONS_TABLE_STYLE:
1.105 nicm 363: o = options_set_style(oo, oe->name, append, value);
364: if (o == NULL) {
365: cmdq_error(item, "bad style: %s", value);
366: return (-1);
367: }
368: options_style_update_old(oo, o);
369: return (0);
370: case OPTIONS_TABLE_ARRAY:
1.64 nicm 371: break;
1.43 nicm 372: }
1.105 nicm 373: return (-1);
1.43 nicm 374: }
375:
1.105 nicm 376: static int
377: cmd_set_option_flag(struct cmdq_item *item,
1.69 nicm 378: const struct options_table_entry *oe, struct options *oo,
379: const char *value)
1.27 nicm 380: {
1.44 nicm 381: int flag;
1.27 nicm 382:
1.44 nicm 383: if (value == NULL || *value == '\0')
1.43 nicm 384: flag = !options_get_number(oo, oe->name);
1.105 nicm 385: else if (strcmp(value, "1") == 0 ||
386: strcasecmp(value, "on") == 0 ||
387: strcasecmp(value, "yes") == 0)
388: flag = 1;
389: else if (strcmp(value, "0") == 0 ||
390: strcasecmp(value, "off") == 0 ||
391: strcasecmp(value, "no") == 0)
392: flag = 0;
1.27 nicm 393: else {
1.105 nicm 394: cmdq_error(item, "bad value: %s", value);
395: return (-1);
1.27 nicm 396: }
1.105 nicm 397: options_set_number(oo, oe->name, flag);
398: return (0);
1.27 nicm 399: }
400:
1.105 nicm 401: static int
402: cmd_set_option_choice(struct cmdq_item *item,
1.60 nicm 403: const struct options_table_entry *oe, struct options *oo,
404: const char *value)
1.27 nicm 405: {
1.105 nicm 406: const char **cp;
1.44 nicm 407: int n, choice = -1;
1.27 nicm 408:
1.73 nicm 409: if (value == NULL) {
410: choice = options_get_number(oo, oe->name);
411: if (choice < 2)
412: choice = !choice;
413: } else {
414: n = 0;
1.105 nicm 415: for (cp = oe->choices; *cp != NULL; cp++) {
416: if (strcmp(*cp, value) == 0)
417: choice = n;
1.73 nicm 418: n++;
419: }
420: if (choice == -1) {
1.101 nicm 421: cmdq_error(item, "unknown value: %s", value);
1.105 nicm 422: return (-1);
1.27 nicm 423: }
424: }
1.105 nicm 425: options_set_number(oo, oe->name, choice);
426: return (0);
1.1 nicm 427: }