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