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