Annotation of embedaddon/tmux/cmd-set-option.c, revision 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>