xref: /openbsd-src/usr.bin/tmux/cmd-set-option.c (revision a224d0d3ac3348ad8dc1a5ad50b3236b714355cb)
1 /* $OpenBSD: cmd-set-option.c,v 1.57 2012/07/11 07:10:15 nicm Exp $ */
2 
3 /*
4  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
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 enum cmd_retval	 cmd_set_option_exec(struct cmd *, struct cmd_ctx *);
31 
32 int	cmd_set_option_unset(struct cmd *, struct cmd_ctx *,
33 	    const struct options_table_entry *, struct options *,
34 	    const char *);
35 int	cmd_set_option_set(struct cmd *, struct cmd_ctx *,
36 	    const struct options_table_entry *, struct options *,
37 	    const char *);
38 
39 struct options_entry *cmd_set_option_string(struct cmd *, struct cmd_ctx *,
40 	    const struct options_table_entry *, struct options *,
41 	    const char *);
42 struct options_entry *cmd_set_option_number(struct cmd *, struct cmd_ctx *,
43 	    const struct options_table_entry *, struct options *,
44 	    const char *);
45 struct options_entry *cmd_set_option_key(struct cmd *, struct cmd_ctx *,
46 	    const struct options_table_entry *, struct options *,
47 	    const char *);
48 struct options_entry *cmd_set_option_colour(struct cmd *, struct cmd_ctx *,
49 	    const struct options_table_entry *, struct options *,
50 	    const char *);
51 struct options_entry *cmd_set_option_attributes(struct cmd *, struct cmd_ctx *,
52 	    const struct options_table_entry *, struct options *,
53 	    const char *);
54 struct options_entry *cmd_set_option_flag(struct cmd *, struct cmd_ctx *,
55 	    const struct options_table_entry *, struct options *,
56 	    const char *);
57 struct options_entry *cmd_set_option_choice(struct cmd *, struct cmd_ctx *,
58 	    const struct options_table_entry *, struct options *,
59 	    const char *);
60 
61 const struct cmd_entry cmd_set_option_entry = {
62 	"set-option", "set",
63 	"agqst:uw", 1, 2,
64 	"[-agsquw] [-t target-session|target-window] option [value]",
65 	0,
66 	NULL,
67 	NULL,
68 	cmd_set_option_exec
69 };
70 
71 const struct cmd_entry cmd_set_window_option_entry = {
72 	"set-window-option", "setw",
73 	"agqt:u", 1, 2,
74 	"[-agqu] " CMD_TARGET_WINDOW_USAGE " option [value]",
75 	0,
76 	NULL,
77 	NULL,
78 	cmd_set_option_exec
79 };
80 
81 enum cmd_retval
82 cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx)
83 {
84 	struct args				*args = self->args;
85 	const struct options_table_entry	*table, *oe;
86 	struct session				*s;
87 	struct winlink				*wl;
88 	struct client				*c;
89 	struct options				*oo;
90 	struct window				*w;
91 	const char				*optstr, *valstr;
92 	u_int					 i;
93 
94 	/* Get the option name and value. */
95 	optstr = args->argv[0];
96 	if (*optstr == '\0') {
97 		ctx->error(ctx, "invalid option");
98 		return (CMD_RETURN_ERROR);
99 	}
100 	if (args->argc < 2)
101 		valstr = NULL;
102 	else
103 		valstr = args->argv[1];
104 
105 	/* Find the option entry, try each table. */
106 	table = oe = NULL;
107 	if (options_table_find(optstr, &table, &oe) != 0) {
108 		ctx->error(ctx, "ambiguous option: %s", optstr);
109 		return (CMD_RETURN_ERROR);
110 	}
111 	if (oe == NULL) {
112 		ctx->error(ctx, "unknown option: %s", optstr);
113 		return (CMD_RETURN_ERROR);
114 	}
115 
116 	/* Work out the tree from the table. */
117 	if (table == server_options_table)
118 		oo = &global_options;
119 	else if (table == window_options_table) {
120 		if (args_has(self->args, 'g'))
121 			oo = &global_w_options;
122 		else {
123 			wl = cmd_find_window(ctx, args_get(args, 't'), NULL);
124 			if (wl == NULL)
125 				return (CMD_RETURN_ERROR);
126 			oo = &wl->window->options;
127 		}
128 	} else if (table == session_options_table) {
129 		if (args_has(self->args, 'g'))
130 			oo = &global_s_options;
131 		else {
132 			s = cmd_find_session(ctx, args_get(args, 't'), 0);
133 			if (s == NULL)
134 				return (CMD_RETURN_ERROR);
135 			oo = &s->options;
136 		}
137 	} else {
138 		ctx->error(ctx, "unknown table");
139 		return (CMD_RETURN_ERROR);
140 	}
141 
142 	/* Unset or set the option. */
143 	if (args_has(args, 'u')) {
144 		if (cmd_set_option_unset(self, ctx, oe, oo, valstr) != 0)
145 			return (CMD_RETURN_ERROR);
146 	} else {
147 		if (cmd_set_option_set(self, ctx, oe, oo, valstr) != 0)
148 			return (CMD_RETURN_ERROR);
149 	}
150 
151 	/* Start or stop timers when automatic-rename changed. */
152 	if (strcmp (oe->name, "automatic-rename") == 0) {
153 		for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
154 			if ((w = ARRAY_ITEM(&windows, i)) == NULL)
155 				continue;
156 			if (options_get_number(&w->options, "automatic-rename"))
157 				queue_window_name(w);
158 			else if (event_initialized(&w->name_timer))
159 				evtimer_del(&w->name_timer);
160 		}
161 	}
162 
163 	/* Update sizes and redraw. May not need it but meh. */
164 	recalculate_sizes();
165 	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
166 		c = ARRAY_ITEM(&clients, i);
167 		if (c != NULL && c->session != NULL)
168 			server_redraw_client(c);
169 	}
170 
171 	return (CMD_RETURN_NORMAL);
172 }
173 
174 /* Unset an option. */
175 int
176 cmd_set_option_unset(struct cmd *self, struct cmd_ctx *ctx,
177     const struct options_table_entry *oe, struct options *oo, const char *value)
178 {
179 	struct args	*args = self->args;
180 
181 	if (args_has(args, 'g')) {
182 		ctx->error(ctx, "can't unset global option: %s", oe->name);
183 		return (-1);
184 	}
185 	if (value != NULL) {
186 		ctx->error(ctx, "value passed to unset option: %s", oe->name);
187 		return (-1);
188 	}
189 
190 	options_remove(oo, oe->name);
191 	if (!args_has(args, 'q'))
192 		ctx->info(ctx, "unset option: %s", oe->name);
193 	return (0);
194 }
195 
196 /* Set an option. */
197 int
198 cmd_set_option_set(struct cmd *self, struct cmd_ctx *ctx,
199     const struct options_table_entry *oe, struct options *oo, const char *value)
200 {
201 	struct args		*args = self->args;
202 	struct options_entry	*o;
203 	const char		*s;
204 
205 	if (oe->type != OPTIONS_TABLE_FLAG && value == NULL) {
206 		ctx->error(ctx, "empty value");
207 		return (-1);
208 	}
209 
210 	o = NULL;
211 	switch (oe->type) {
212 	case OPTIONS_TABLE_STRING:
213 		o = cmd_set_option_string(self, ctx, oe, oo, value);
214 		break;
215 	case OPTIONS_TABLE_NUMBER:
216 		o = cmd_set_option_number(self, ctx, oe, oo, value);
217 		break;
218 	case OPTIONS_TABLE_KEY:
219 		o = cmd_set_option_key(self, ctx, oe, oo, value);
220 		break;
221 	case OPTIONS_TABLE_COLOUR:
222 		o = cmd_set_option_colour(self, ctx, oe, oo, value);
223 		break;
224 	case OPTIONS_TABLE_ATTRIBUTES:
225 		o = cmd_set_option_attributes(self, ctx, oe, oo, value);
226 		break;
227 	case OPTIONS_TABLE_FLAG:
228 		o = cmd_set_option_flag(self, ctx, oe, oo, value);
229 		break;
230 	case OPTIONS_TABLE_CHOICE:
231 		o = cmd_set_option_choice(self, ctx, oe, oo, value);
232 		break;
233 	}
234 	if (o == NULL)
235 		return (-1);
236 
237 	s = options_table_print_entry(oe, o);
238 	if (!args_has(args, 'q'))
239 		ctx->info(ctx, "set option: %s -> %s", oe->name, s);
240 	return (0);
241 }
242 
243 /* Set a string option. */
244 struct options_entry *
245 cmd_set_option_string(struct cmd *self, unused struct cmd_ctx *ctx,
246     const struct options_table_entry *oe, struct options *oo, const char *value)
247 {
248 	struct args		*args = self->args;
249 	struct options_entry	*o;
250 	char			*oldval, *newval;
251 
252 	if (args_has(args, 'a')) {
253 		oldval = options_get_string(oo, oe->name);
254 		xasprintf(&newval, "%s%s", oldval, value);
255 	} else
256 		newval = xstrdup(value);
257 
258 	o = options_set_string(oo, oe->name, "%s", newval);
259 
260 	free(newval);
261 	return (o);
262 }
263 
264 /* Set a number option. */
265 struct options_entry *
266 cmd_set_option_number(unused struct cmd *self, struct cmd_ctx *ctx,
267     const struct options_table_entry *oe, struct options *oo, const char *value)
268 {
269 	long long	 ll;
270 	const char     	*errstr;
271 
272 	ll = strtonum(value, oe->minimum, oe->maximum, &errstr);
273 	if (errstr != NULL) {
274 		ctx->error(ctx, "value is %s: %s", errstr, value);
275 		return (NULL);
276 	}
277 
278 	return (options_set_number(oo, oe->name, ll));
279 }
280 
281 /* Set a key option. */
282 struct options_entry *
283 cmd_set_option_key(unused struct cmd *self, struct cmd_ctx *ctx,
284     const struct options_table_entry *oe, struct options *oo, const char *value)
285 {
286 	int	key;
287 
288 	if ((key = key_string_lookup_string(value)) == KEYC_NONE) {
289 		ctx->error(ctx, "bad key: %s", value);
290 		return (NULL);
291 	}
292 
293 	return (options_set_number(oo, oe->name, key));
294 }
295 
296 /* Set a colour option. */
297 struct options_entry *
298 cmd_set_option_colour(unused struct cmd *self, struct cmd_ctx *ctx,
299     const struct options_table_entry *oe, struct options *oo, const char *value)
300 {
301 	int	colour;
302 
303 	if ((colour = colour_fromstring(value)) == -1) {
304 		ctx->error(ctx, "bad colour: %s", value);
305 		return (NULL);
306 	}
307 
308 	return (options_set_number(oo, oe->name, colour));
309 }
310 
311 /* Set an attributes option. */
312 struct options_entry *
313 cmd_set_option_attributes(unused struct cmd *self, struct cmd_ctx *ctx,
314     const struct options_table_entry *oe, struct options *oo, const char *value)
315 {
316 	int	attr;
317 
318 	if ((attr = attributes_fromstring(value)) == -1) {
319 		ctx->error(ctx, "bad attributes: %s", value);
320 		return (NULL);
321 	}
322 
323 	return (options_set_number(oo, oe->name, attr));
324 }
325 
326 /* Set a flag option. */
327 struct options_entry *
328 cmd_set_option_flag(unused struct cmd *self, struct cmd_ctx *ctx,
329     const struct options_table_entry *oe, struct options *oo, const char *value)
330 {
331 	int	flag;
332 
333 	if (value == NULL || *value == '\0')
334 		flag = !options_get_number(oo, oe->name);
335 	else {
336 		if ((value[0] == '1' && value[1] == '\0') ||
337 		    strcasecmp(value, "on") == 0 ||
338 		    strcasecmp(value, "yes") == 0)
339 			flag = 1;
340 		else if ((value[0] == '0' && value[1] == '\0') ||
341 		    strcasecmp(value, "off") == 0 ||
342 		    strcasecmp(value, "no") == 0)
343 			flag = 0;
344 		else {
345 			ctx->error(ctx, "bad value: %s", value);
346 			return (NULL);
347 		}
348 	}
349 
350 	return (options_set_number(oo, oe->name, flag));
351 }
352 
353 /* Set a choice option. */
354 struct options_entry *
355 cmd_set_option_choice(unused struct cmd *self, struct cmd_ctx *ctx,
356     const struct options_table_entry *oe, struct options *oo, const char *value)
357 {
358 	const char	**choicep;
359 	int		  n, choice = -1;
360 
361 	n = 0;
362 	for (choicep = oe->choices; *choicep != NULL; choicep++) {
363 		n++;
364 		if (strncmp(*choicep, value, strlen(value)) != 0)
365 			continue;
366 
367 		if (choice != -1) {
368 			ctx->error(ctx, "ambiguous value: %s", value);
369 			return (NULL);
370 		}
371 		choice = n - 1;
372 	}
373 	if (choice == -1) {
374 		ctx->error(ctx, "unknown value: %s", value);
375 		return (NULL);
376 	}
377 
378 	return (options_set_number(oo, oe->name, choice));
379 }
380