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