Annotation of src/usr.bin/tmux/cmd-set-option.c, Revision 1.43
1.43 ! nicm 1: /* $OpenBSD: cmd-set-option.c,v 1.42 2010/12/30 23:16:18 nicm Exp $ */
1.1 nicm 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: int cmd_set_option_exec(struct cmd *, struct cmd_ctx *);
31:
1.43 ! nicm 32: int cmd_set_option_unset(struct cmd *, struct cmd_ctx *,
! 33: const struct options_table_entry *, struct options *);
! 34: int cmd_set_option_set(struct cmd *, struct cmd_ctx *,
! 35: const struct options_table_entry *, struct options *);
! 36:
! 37: struct options_entry *cmd_set_option_string(struct cmd *, struct cmd_ctx *,
! 38: const struct options_table_entry *, struct options *);
! 39: struct options_entry *cmd_set_option_number(struct cmd *, struct cmd_ctx *,
! 40: const struct options_table_entry *, struct options *);
! 41: struct options_entry *cmd_set_option_keys(struct cmd *, struct cmd_ctx *,
! 42: const struct options_table_entry *, struct options *);
! 43: struct options_entry *cmd_set_option_colour(struct cmd *, struct cmd_ctx *,
! 44: const struct options_table_entry *, struct options *);
! 45: struct options_entry *cmd_set_option_attributes(struct cmd *, struct cmd_ctx *,
! 46: const struct options_table_entry *, struct options *);
! 47: struct options_entry *cmd_set_option_flag(struct cmd *, struct cmd_ctx *,
! 48: const struct options_table_entry *, struct options *);
! 49: struct options_entry *cmd_set_option_choice(struct cmd *, struct cmd_ctx *,
! 50: const struct options_table_entry *, struct options *);
1.27 nicm 51:
1.1 nicm 52: const struct cmd_entry cmd_set_option_entry = {
53: "set-option", "set",
1.29 nicm 54: "[-agsuw] [-t target-session|target-window] option [value]",
55: CMD_ARG12, "agsuw",
1.1 nicm 56: NULL,
1.14 nicm 57: cmd_target_parse,
1.1 nicm 58: cmd_set_option_exec,
1.14 nicm 59: cmd_target_free,
60: cmd_target_print
1.1 nicm 61: };
62:
63: int
64: cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx)
65: {
1.43 ! nicm 66: struct cmd_target_data *data = self->data;
! 67: const struct options_table_entry *table, *oe, *oe_loop;
! 68: struct session *s;
! 69: struct winlink *wl;
! 70: struct client *c;
! 71: struct options *oo;
! 72: struct jobs *jobs;
! 73: struct job *job, *nextjob;
! 74: u_int i;
! 75: int try_again;
1.1 nicm 76:
1.43 ! nicm 77: /* Work out the options tree and table to use. */
1.29 nicm 78: if (cmd_check_flag(data->chflags, 's')) {
79: oo = &global_options;
1.43 ! nicm 80: table = server_options_table;
1.29 nicm 81: } else if (cmd_check_flag(data->chflags, 'w')) {
1.43 ! nicm 82: table = window_options_table;
1.27 nicm 83: if (cmd_check_flag(data->chflags, 'g'))
84: oo = &global_w_options;
85: else {
86: wl = cmd_find_window(ctx, data->target, NULL);
87: if (wl == NULL)
88: return (-1);
89: oo = &wl->window->options;
90: }
91: } else {
1.43 ! nicm 92: table = session_options_table;
1.27 nicm 93: if (cmd_check_flag(data->chflags, 'g'))
94: oo = &global_s_options;
95: else {
96: s = cmd_find_session(ctx, data->target);
97: if (s == NULL)
98: return (-1);
99: oo = &s->options;
100: }
1.1 nicm 101: }
102:
1.43 ! nicm 103: /* Find the option table entry. */
! 104: oe = NULL;
! 105: for (oe_loop = table; oe_loop->name != NULL; oe_loop++) {
! 106: if (strncmp(oe_loop->name, data->arg, strlen(data->arg)) != 0)
1.1 nicm 107: continue;
1.43 ! nicm 108: if (oe != NULL) {
1.14 nicm 109: ctx->error(ctx, "ambiguous option: %s", data->arg);
1.1 nicm 110: return (-1);
111: }
1.43 ! nicm 112: oe = oe_loop;
1.1 nicm 113:
114: /* Bail now if an exact match. */
1.43 ! nicm 115: if (strcmp(oe->name, data->arg) == 0)
1.1 nicm 116: break;
117: }
1.43 ! nicm 118: if (oe == NULL) {
1.14 nicm 119: ctx->error(ctx, "unknown option: %s", data->arg);
1.1 nicm 120: return (-1);
121: }
122:
1.43 ! nicm 123: /* Unset or set the option. */
1.25 nicm 124: if (cmd_check_flag(data->chflags, 'u')) {
1.43 ! nicm 125: if (cmd_set_option_unset(self, ctx, oe, oo) != 0)
1.1 nicm 126: return (-1);
1.43 ! nicm 127: } else {
! 128: if (cmd_set_option_set(self, ctx, oe, oo) != 0)
1.1 nicm 129: return (-1);
130: }
131:
1.43 ! nicm 132: /* Update sizes and redraw. May not need it but meh. */
1.1 nicm 133: recalculate_sizes();
1.27 nicm 134: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
135: c = ARRAY_ITEM(&clients, i);
136: if (c != NULL && c->session != NULL)
137: server_redraw_client(c);
138: }
1.24 nicm 139:
1.28 nicm 140: /*
1.24 nicm 141: * Special-case: kill all persistent jobs if status-left, status-right
142: * or set-titles-string have changed. Persistent jobs are only used by
143: * the status line at the moment so this works XXX.
144: */
1.43 ! nicm 145: if (strcmp(oe->name, "status-left") == 0 ||
! 146: strcmp(oe->name, "status-right") == 0 ||
! 147: strcmp(oe->name, "status") == 0 ||
! 148: strcmp(oe->name, "set-titles-string") == 0 ||
! 149: strcmp(oe->name, "window-status-format") == 0) {
1.24 nicm 150: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
151: c = ARRAY_ITEM(&clients, i);
152: if (c == NULL || c->session == NULL)
153: continue;
154:
155: jobs = &c->status_jobs;
156: do {
1.28 nicm 157: try_again = 0;
1.24 nicm 158: job = RB_ROOT(jobs);
159: while (job != NULL) {
160: nextjob = RB_NEXT(jobs, jobs, job);
161: if (job->flags & JOB_PERSIST) {
162: job_remove(jobs, job);
163: try_again = 1;
164: break;
165: }
166: job = nextjob;
167: }
168: } while (try_again);
1.1 nicm 169: server_redraw_client(c);
1.23 nicm 170: }
1.1 nicm 171: }
172:
173: return (0);
1.27 nicm 174: }
175:
1.43 ! nicm 176: /* Unset an option. */
! 177: int
! 178: cmd_set_option_unset(struct cmd *self, struct cmd_ctx *ctx,
! 179: const struct options_table_entry *oe, struct options *oo)
1.27 nicm 180: {
1.43 ! nicm 181: struct cmd_target_data *data = self->data;
! 182:
! 183: if (cmd_check_flag(data->chflags, 'g')) {
! 184: ctx->error(ctx, "can't unset global option: %s", oe->name);
! 185: return (-1);
! 186: }
! 187: if (data->arg2 != NULL) {
! 188: ctx->error(ctx, "value passed to unset option: %s", oe->name);
! 189: return (-1);
1.27 nicm 190: }
1.43 ! nicm 191:
! 192: options_remove(oo, oe->name);
! 193: ctx->info(ctx, "unset option: %s", oe->name);
! 194: return (0);
1.27 nicm 195: }
196:
1.43 ! nicm 197: /* Set an option. */
! 198: int
! 199: cmd_set_option_set(struct cmd *self, struct cmd_ctx *ctx,
! 200: const struct options_table_entry *oe, struct options *oo)
1.27 nicm 201: {
1.43 ! nicm 202: struct cmd_target_data *data = self->data;
1.27 nicm 203: struct options_entry *o;
1.43 ! nicm 204: const char *s;
1.27 nicm 205:
1.43 ! nicm 206: if (oe->type != OPTIONS_TABLE_FLAG && data->arg2 == NULL) {
! 207: ctx->error(ctx, "empty data->arg2");
! 208: return (-1);
1.27 nicm 209: }
210:
1.43 ! nicm 211: o = NULL;
! 212: switch (oe->type) {
! 213: case OPTIONS_TABLE_STRING:
! 214: o = cmd_set_option_string(self, ctx, oe, oo);
! 215: break;
! 216: case OPTIONS_TABLE_NUMBER:
! 217: o = cmd_set_option_number(self, ctx, oe, oo);
! 218: break;
! 219: case OPTIONS_TABLE_KEYS:
! 220: o = cmd_set_option_keys(self, ctx, oe, oo);
! 221: break;
! 222: case OPTIONS_TABLE_COLOUR:
! 223: o = cmd_set_option_colour(self, ctx, oe, oo);
! 224: break;
! 225: case OPTIONS_TABLE_ATTRIBUTES:
! 226: o = cmd_set_option_attributes(self, ctx, oe, oo);
! 227: break;
! 228: case OPTIONS_TABLE_FLAG:
! 229: o = cmd_set_option_flag(self, ctx, oe, oo);
! 230: break;
! 231: case OPTIONS_TABLE_CHOICE:
! 232: o = cmd_set_option_choice(self, ctx, oe, oo);
! 233: break;
! 234: }
! 235: if (o == NULL)
! 236: return (-1);
! 237:
! 238: s = options_table_print_entry(oe, o);
! 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)
! 247: {
! 248: struct cmd_target_data *data = self->data;
! 249: struct options_entry *o;
! 250: char *oldval, *newval;
! 251:
! 252: if (cmd_check_flag(data->chflags, 'a')) {
! 253: oldval = options_get_string(oo, oe->name);
! 254: xasprintf(&newval, "%s%s", oldval, data->arg2);
1.27 nicm 255: } else
1.43 ! nicm 256: newval = data->arg2;
1.28 nicm 257:
1.43 ! nicm 258: o = options_set_string(oo, oe->name, "%s", newval);
1.27 nicm 259:
1.43 ! nicm 260: if (newval != data->arg2)
! 261: xfree(newval);
! 262: return (o);
1.27 nicm 263: }
264:
1.43 ! nicm 265: /* Set a number option. */
! 266: struct options_entry *
! 267: cmd_set_option_number(struct cmd *self, struct cmd_ctx *ctx,
! 268: const struct options_table_entry *oe, struct options *oo)
1.27 nicm 269: {
1.43 ! nicm 270: struct cmd_target_data *data = self->data;
! 271: long long ll;
1.27 nicm 272: const char *errstr;
273:
1.43 ! nicm 274: ll = strtonum(data->arg2, oe->minimum, oe->maximum, &errstr);
1.27 nicm 275: if (errstr != NULL) {
1.43 ! nicm 276: ctx->error(ctx, "value is %s: %s", errstr, data->arg2);
! 277: return (NULL);
1.27 nicm 278: }
279:
1.43 ! nicm 280: return (options_set_number(oo, oe->name, ll));
1.27 nicm 281: }
282:
1.43 ! nicm 283: /* Set a keys option. */
! 284: struct options_entry *
! 285: cmd_set_option_keys(struct cmd *self, struct cmd_ctx *ctx,
! 286: const struct options_table_entry *oe, struct options *oo)
1.27 nicm 287: {
1.43 ! nicm 288: struct cmd_target_data *data = self->data;
1.27 nicm 289: struct keylist *keylist;
1.43 ! nicm 290: char *copy, *ptr, *s;
1.27 nicm 291: int key;
292:
293: keylist = xmalloc(sizeof *keylist);
294: ARRAY_INIT(keylist);
295:
1.43 ! nicm 296: ptr = copy = xstrdup(data->arg2);
! 297: while ((s = strsep(&ptr, ",")) != NULL) {
! 298: if ((key = key_string_lookup_string(s)) == KEYC_NONE) {
! 299: ctx->error(ctx, "unknown key: %s", s);
! 300: xfree(copy);
1.27 nicm 301: xfree(keylist);
1.43 ! nicm 302: return (NULL);
1.27 nicm 303: }
304: ARRAY_ADD(keylist, key);
305: }
1.43 ! nicm 306: xfree(copy);
1.27 nicm 307:
1.43 ! nicm 308: return (options_set_data(oo, oe->name, keylist, xfree));
1.27 nicm 309: }
310:
1.43 ! nicm 311: /* Set a colour option. */
! 312: struct options_entry *
! 313: cmd_set_option_colour(struct cmd *self, struct cmd_ctx *ctx,
! 314: const struct options_table_entry *oe, struct options *oo)
1.27 nicm 315: {
1.43 ! nicm 316: struct cmd_target_data *data = self->data;
1.27 nicm 317: int colour;
318:
1.43 ! nicm 319: if ((colour = colour_fromstring(data->arg2)) == -1) {
! 320: ctx->error(ctx, "bad colour: %s", data->arg2);
! 321: return (NULL);
1.27 nicm 322: }
323:
1.43 ! nicm 324: return (options_set_number(oo, oe->name, colour));
1.27 nicm 325: }
326:
1.43 ! nicm 327: /* Set an attributes option. */
! 328: struct options_entry *
! 329: cmd_set_option_attributes(struct cmd *self, struct cmd_ctx *ctx,
! 330: const struct options_table_entry *oe, struct options *oo)
1.27 nicm 331: {
1.43 ! nicm 332: struct cmd_target_data *data = self->data;
1.27 nicm 333: int attr;
334:
1.43 ! nicm 335: if ((attr = attributes_fromstring(data->arg2)) == -1) {
! 336: ctx->error(ctx, "bad attributes: %s", data->arg2);
! 337: return (NULL);
1.27 nicm 338: }
339:
1.43 ! nicm 340: return (options_set_number(oo, oe->name, attr));
1.27 nicm 341: }
342:
1.43 ! nicm 343: /* Set a flag option. */
! 344: struct options_entry *
! 345: cmd_set_option_flag(struct cmd *self, struct cmd_ctx *ctx,
! 346: const struct options_table_entry *oe, struct options *oo)
1.27 nicm 347: {
1.43 ! nicm 348: struct cmd_target_data *data = self->data;
1.27 nicm 349: int flag;
350:
1.43 ! nicm 351: if (data->arg2 == NULL || *data->arg2 == '\0')
! 352: flag = !options_get_number(oo, oe->name);
1.27 nicm 353: else {
1.43 ! nicm 354: if ((data->arg2[0] == '1' && data->arg2[1] == '\0') ||
! 355: strcasecmp(data->arg2, "on") == 0 ||
! 356: strcasecmp(data->arg2, "yes") == 0)
1.27 nicm 357: flag = 1;
1.43 ! nicm 358: else if ((data->arg2[0] == '0' && data->arg2[1] == '\0') ||
! 359: strcasecmp(data->arg2, "off") == 0 ||
! 360: strcasecmp(data->arg2, "no") == 0)
1.27 nicm 361: flag = 0;
362: else {
1.43 ! nicm 363: ctx->error(ctx, "bad value: %s", data->arg2);
! 364: return (NULL);
1.27 nicm 365: }
366: }
367:
1.43 ! nicm 368: return (options_set_number(oo, oe->name, flag));
1.27 nicm 369: }
370:
1.43 ! nicm 371: /* Set a choice option. */
! 372: struct options_entry *
! 373: cmd_set_option_choice(struct cmd *self, struct cmd_ctx *ctx,
! 374: const struct options_table_entry *oe, struct options *oo)
1.27 nicm 375: {
1.43 ! nicm 376: struct cmd_target_data *data = self->data;
1.27 nicm 377: const char **choicep;
378: int n, choice = -1;
379:
380: n = 0;
1.43 ! nicm 381: for (choicep = oe->choices; *choicep != NULL; choicep++) {
1.27 nicm 382: n++;
1.43 ! nicm 383: if (strncmp(*choicep, data->arg2, strlen(data->arg2)) != 0)
1.27 nicm 384: continue;
385:
386: if (choice != -1) {
1.43 ! nicm 387: ctx->error(ctx, "ambiguous value: %s", data->arg2);
! 388: return (NULL);
1.27 nicm 389: }
390: choice = n - 1;
391: }
392: if (choice == -1) {
1.43 ! nicm 393: ctx->error(ctx, "unknown value: %s", data->arg2);
! 394: return (NULL);
1.27 nicm 395: }
396:
1.43 ! nicm 397: return (options_set_number(oo, oe->name, choice));
1.1 nicm 398: }