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