File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / tmux / cmd-set-option.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 14 12:22:44 2017 UTC (6 years, 11 months ago) by misho
Branches: tmux, MAIN
CVS tags: v2_4p0, v2_4, HEAD
tmux 2.4

    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>