1 |
|
|
/* $OpenBSD: options.c,v 1.36 2017/08/09 13:44:36 nicm Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 2008 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 <ctype.h> |
22 |
|
|
#include <stdarg.h> |
23 |
|
|
#include <stdlib.h> |
24 |
|
|
#include <string.h> |
25 |
|
|
|
26 |
|
|
#include "tmux.h" |
27 |
|
|
|
28 |
|
|
/* |
29 |
|
|
* Option handling; each option has a name, type and value and is stored in |
30 |
|
|
* a red-black tree. |
31 |
|
|
*/ |
32 |
|
|
|
33 |
|
|
struct options_entry { |
34 |
|
|
struct options *owner; |
35 |
|
|
|
36 |
|
|
const char *name; |
37 |
|
|
const struct options_table_entry *tableentry; |
38 |
|
|
|
39 |
|
|
union { |
40 |
|
|
char *string; |
41 |
|
|
long long number; |
42 |
|
|
struct grid_cell style; |
43 |
|
|
struct { |
44 |
|
|
const char **array; |
45 |
|
|
u_int arraysize; |
46 |
|
|
}; |
47 |
|
|
}; |
48 |
|
|
|
49 |
|
|
RB_ENTRY(options_entry) entry; |
50 |
|
|
}; |
51 |
|
|
|
52 |
|
|
struct options { |
53 |
|
|
RB_HEAD(options_tree, options_entry) tree; |
54 |
|
|
struct options *parent; |
55 |
|
|
}; |
56 |
|
|
|
57 |
|
|
static struct options_entry *options_add(struct options *, const char *); |
58 |
|
|
|
59 |
|
|
#define OPTIONS_ARRAY_LIMIT 1000 |
60 |
|
|
|
61 |
|
|
#define OPTIONS_IS_STRING(o) \ |
62 |
|
|
((o)->tableentry == NULL || \ |
63 |
|
|
(o)->tableentry->type == OPTIONS_TABLE_STRING) |
64 |
|
|
#define OPTIONS_IS_NUMBER(o) \ |
65 |
|
|
((o)->tableentry != NULL && \ |
66 |
|
|
((o)->tableentry->type == OPTIONS_TABLE_NUMBER || \ |
67 |
|
|
(o)->tableentry->type == OPTIONS_TABLE_KEY || \ |
68 |
|
|
(o)->tableentry->type == OPTIONS_TABLE_COLOUR || \ |
69 |
|
|
(o)->tableentry->type == OPTIONS_TABLE_ATTRIBUTES || \ |
70 |
|
|
(o)->tableentry->type == OPTIONS_TABLE_FLAG || \ |
71 |
|
|
(o)->tableentry->type == OPTIONS_TABLE_CHOICE)) |
72 |
|
|
#define OPTIONS_IS_STYLE(o) \ |
73 |
|
|
((o)->tableentry != NULL && \ |
74 |
|
|
(o)->tableentry->type == OPTIONS_TABLE_STYLE) |
75 |
|
|
#define OPTIONS_IS_ARRAY(o) \ |
76 |
|
|
((o)->tableentry != NULL && \ |
77 |
|
|
(o)->tableentry->type == OPTIONS_TABLE_ARRAY) |
78 |
|
|
|
79 |
|
|
static int options_cmp(struct options_entry *, struct options_entry *); |
80 |
|
|
RB_GENERATE_STATIC(options_tree, options_entry, entry, options_cmp); |
81 |
|
|
|
82 |
|
|
static int |
83 |
|
|
options_cmp(struct options_entry *lhs, struct options_entry *rhs) |
84 |
|
|
{ |
85 |
|
|
return (strcmp(lhs->name, rhs->name)); |
86 |
|
|
} |
87 |
|
|
|
88 |
|
|
static const struct options_table_entry * |
89 |
|
|
options_parent_table_entry(struct options *oo, const char *s) |
90 |
|
|
{ |
91 |
|
|
struct options_entry *o; |
92 |
|
|
|
93 |
|
|
if (oo->parent == NULL) |
94 |
|
|
fatalx("no parent options for %s", s); |
95 |
|
|
o = options_get_only(oo->parent, s); |
96 |
|
|
if (o == NULL) |
97 |
|
|
fatalx("%s not in parent options", s); |
98 |
|
|
return (o->tableentry); |
99 |
|
|
} |
100 |
|
|
|
101 |
|
|
struct options * |
102 |
|
|
options_create(struct options *parent) |
103 |
|
|
{ |
104 |
|
|
struct options *oo; |
105 |
|
|
|
106 |
|
|
oo = xcalloc(1, sizeof *oo); |
107 |
|
|
RB_INIT(&oo->tree); |
108 |
|
|
oo->parent = parent; |
109 |
|
|
return (oo); |
110 |
|
|
} |
111 |
|
|
|
112 |
|
|
void |
113 |
|
|
options_free(struct options *oo) |
114 |
|
|
{ |
115 |
|
|
struct options_entry *o, *tmp; |
116 |
|
|
|
117 |
|
|
RB_FOREACH_SAFE(o, options_tree, &oo->tree, tmp) |
118 |
|
|
options_remove(o); |
119 |
|
|
free(oo); |
120 |
|
|
} |
121 |
|
|
|
122 |
|
|
struct options_entry * |
123 |
|
|
options_first(struct options *oo) |
124 |
|
|
{ |
125 |
|
|
return (RB_MIN(options_tree, &oo->tree)); |
126 |
|
|
} |
127 |
|
|
|
128 |
|
|
struct options_entry * |
129 |
|
|
options_next(struct options_entry *o) |
130 |
|
|
{ |
131 |
|
|
return (RB_NEXT(options_tree, &oo->tree, o)); |
132 |
|
|
} |
133 |
|
|
|
134 |
|
|
struct options_entry * |
135 |
|
|
options_get_only(struct options *oo, const char *name) |
136 |
|
|
{ |
137 |
|
|
struct options_entry o; |
138 |
|
|
|
139 |
|
|
o.name = name; |
140 |
|
|
return (RB_FIND(options_tree, &oo->tree, &o)); |
141 |
|
|
} |
142 |
|
|
|
143 |
|
|
struct options_entry * |
144 |
|
|
options_get(struct options *oo, const char *name) |
145 |
|
|
{ |
146 |
|
|
struct options_entry *o; |
147 |
|
|
|
148 |
|
|
o = options_get_only(oo, name); |
149 |
|
|
while (o == NULL) { |
150 |
|
|
oo = oo->parent; |
151 |
|
|
if (oo == NULL) |
152 |
|
|
break; |
153 |
|
|
o = options_get_only(oo, name); |
154 |
|
|
} |
155 |
|
|
return (o); |
156 |
|
|
} |
157 |
|
|
|
158 |
|
|
struct options_entry * |
159 |
|
|
options_empty(struct options *oo, const struct options_table_entry *oe) |
160 |
|
|
{ |
161 |
|
|
struct options_entry *o; |
162 |
|
|
|
163 |
|
|
o = options_add(oo, oe->name); |
164 |
|
|
o->tableentry = oe; |
165 |
|
|
|
166 |
|
|
return (o); |
167 |
|
|
} |
168 |
|
|
|
169 |
|
|
struct options_entry * |
170 |
|
|
options_default(struct options *oo, const struct options_table_entry *oe) |
171 |
|
|
{ |
172 |
|
|
struct options_entry *o; |
173 |
|
|
|
174 |
|
|
o = options_empty(oo, oe); |
175 |
|
|
if (oe->type == OPTIONS_TABLE_ARRAY) |
176 |
|
|
options_array_assign(o, oe->default_str); |
177 |
|
|
else if (oe->type == OPTIONS_TABLE_STRING) |
178 |
|
|
o->string = xstrdup(oe->default_str); |
179 |
|
|
else if (oe->type == OPTIONS_TABLE_STYLE) { |
180 |
|
|
memcpy(&o->style, &grid_default_cell, sizeof o->style); |
181 |
|
|
style_parse(&grid_default_cell, &o->style, oe->default_str); |
182 |
|
|
} else |
183 |
|
|
o->number = oe->default_num; |
184 |
|
|
return (o); |
185 |
|
|
} |
186 |
|
|
|
187 |
|
|
static struct options_entry * |
188 |
|
|
options_add(struct options *oo, const char *name) |
189 |
|
|
{ |
190 |
|
|
struct options_entry *o; |
191 |
|
|
|
192 |
|
|
o = options_get_only(oo, name); |
193 |
|
|
if (o != NULL) |
194 |
|
|
options_remove(o); |
195 |
|
|
|
196 |
|
|
o = xcalloc(1, sizeof *o); |
197 |
|
|
o->owner = oo; |
198 |
|
|
o->name = xstrdup(name); |
199 |
|
|
|
200 |
|
|
RB_INSERT(options_tree, &oo->tree, o); |
201 |
|
|
return (o); |
202 |
|
|
} |
203 |
|
|
|
204 |
|
|
void |
205 |
|
|
options_remove(struct options_entry *o) |
206 |
|
|
{ |
207 |
|
|
struct options *oo = o->owner; |
208 |
|
|
u_int i; |
209 |
|
|
|
210 |
|
|
if (OPTIONS_IS_STRING(o)) |
211 |
|
|
free((void *)o->string); |
212 |
|
|
else if (OPTIONS_IS_ARRAY(o)) { |
213 |
|
|
for (i = 0; i < o->arraysize; i++) |
214 |
|
|
free((void *)o->array[i]); |
215 |
|
|
free(o->array); |
216 |
|
|
} |
217 |
|
|
|
218 |
|
|
RB_REMOVE(options_tree, &oo->tree, o); |
219 |
|
|
free(o); |
220 |
|
|
} |
221 |
|
|
|
222 |
|
|
const char * |
223 |
|
|
options_name(struct options_entry *o) |
224 |
|
|
{ |
225 |
|
|
return (o->name); |
226 |
|
|
} |
227 |
|
|
|
228 |
|
|
const struct options_table_entry * |
229 |
|
|
options_table_entry(struct options_entry *o) |
230 |
|
|
{ |
231 |
|
|
return (o->tableentry); |
232 |
|
|
} |
233 |
|
|
|
234 |
|
|
void |
235 |
|
|
options_array_clear(struct options_entry *o) |
236 |
|
|
{ |
237 |
|
|
if (OPTIONS_IS_ARRAY(o)) |
238 |
|
|
o->arraysize = 0; |
239 |
|
|
} |
240 |
|
|
|
241 |
|
|
const char * |
242 |
|
|
options_array_get(struct options_entry *o, u_int idx) |
243 |
|
|
{ |
244 |
|
|
if (!OPTIONS_IS_ARRAY(o)) |
245 |
|
|
return (NULL); |
246 |
|
|
if (idx >= o->arraysize) |
247 |
|
|
return (NULL); |
248 |
|
|
return (o->array[idx]); |
249 |
|
|
} |
250 |
|
|
|
251 |
|
|
int |
252 |
|
|
options_array_set(struct options_entry *o, u_int idx, const char *value, |
253 |
|
|
int append) |
254 |
|
|
{ |
255 |
|
|
char *new; |
256 |
|
|
u_int i; |
257 |
|
|
|
258 |
|
|
if (!OPTIONS_IS_ARRAY(o)) |
259 |
|
|
return (-1); |
260 |
|
|
|
261 |
|
|
if (idx >= OPTIONS_ARRAY_LIMIT) |
262 |
|
|
return (-1); |
263 |
|
|
if (idx >= o->arraysize) { |
264 |
|
|
o->array = xreallocarray(o->array, idx + 1, sizeof *o->array); |
265 |
|
|
for (i = o->arraysize; i < idx + 1; i++) |
266 |
|
|
o->array[i] = NULL; |
267 |
|
|
o->arraysize = idx + 1; |
268 |
|
|
} |
269 |
|
|
|
270 |
|
|
new = NULL; |
271 |
|
|
if (value != NULL) { |
272 |
|
|
if (o->array[idx] != NULL && append) |
273 |
|
|
xasprintf(&new, "%s%s", o->array[idx], value); |
274 |
|
|
else |
275 |
|
|
new = xstrdup(value); |
276 |
|
|
} |
277 |
|
|
|
278 |
|
|
free((void *)o->array[idx]); |
279 |
|
|
o->array[idx] = new; |
280 |
|
|
return (0); |
281 |
|
|
} |
282 |
|
|
|
283 |
|
|
int |
284 |
|
|
options_array_size(struct options_entry *o, u_int *size) |
285 |
|
|
{ |
286 |
|
|
if (!OPTIONS_IS_ARRAY(o)) |
287 |
|
|
return (-1); |
288 |
|
|
if (size != NULL) |
289 |
|
|
*size = o->arraysize; |
290 |
|
|
return (0); |
291 |
|
|
} |
292 |
|
|
|
293 |
|
|
void |
294 |
|
|
options_array_assign(struct options_entry *o, const char *s) |
295 |
|
|
{ |
296 |
|
|
const char *separator; |
297 |
|
|
char *copy, *next, *string; |
298 |
|
|
u_int i; |
299 |
|
|
|
300 |
|
|
separator = o->tableentry->separator; |
301 |
|
|
if (separator == NULL) |
302 |
|
|
separator = " ,"; |
303 |
|
|
|
304 |
|
|
copy = string = xstrdup(s); |
305 |
|
|
while ((next = strsep(&string, separator)) != NULL) { |
306 |
|
|
if (*next == '\0') |
307 |
|
|
continue; |
308 |
|
|
for (i = 0; i < OPTIONS_ARRAY_LIMIT; i++) { |
309 |
|
|
if (i >= o->arraysize || o->array[i] == NULL) |
310 |
|
|
break; |
311 |
|
|
} |
312 |
|
|
if (i == OPTIONS_ARRAY_LIMIT) |
313 |
|
|
break; |
314 |
|
|
options_array_set(o, i, next, 0); |
315 |
|
|
} |
316 |
|
|
free(copy); |
317 |
|
|
} |
318 |
|
|
|
319 |
|
|
int |
320 |
|
|
options_isstring(struct options_entry *o) |
321 |
|
|
{ |
322 |
|
|
if (o->tableentry == NULL) |
323 |
|
|
return (1); |
324 |
|
|
return (OPTIONS_IS_STRING(o) || OPTIONS_IS_ARRAY(o)); |
325 |
|
|
} |
326 |
|
|
|
327 |
|
|
const char * |
328 |
|
|
options_tostring(struct options_entry *o, int idx, int numeric) |
329 |
|
|
{ |
330 |
|
|
static char s[1024]; |
331 |
|
|
const char *tmp; |
332 |
|
|
|
333 |
|
|
if (OPTIONS_IS_ARRAY(o)) { |
334 |
|
|
if (idx == -1) |
335 |
|
|
return (NULL); |
336 |
|
|
if ((u_int)idx >= o->arraysize || o->array[idx] == NULL) |
337 |
|
|
return (""); |
338 |
|
|
return (o->array[idx]); |
339 |
|
|
} |
340 |
|
|
if (OPTIONS_IS_STYLE(o)) |
341 |
|
|
return (style_tostring(&o->style)); |
342 |
|
|
if (OPTIONS_IS_NUMBER(o)) { |
343 |
|
|
tmp = NULL; |
344 |
|
|
switch (o->tableentry->type) { |
345 |
|
|
case OPTIONS_TABLE_NUMBER: |
346 |
|
|
xsnprintf(s, sizeof s, "%lld", o->number); |
347 |
|
|
break; |
348 |
|
|
case OPTIONS_TABLE_KEY: |
349 |
|
|
tmp = key_string_lookup_key(o->number); |
350 |
|
|
break; |
351 |
|
|
case OPTIONS_TABLE_COLOUR: |
352 |
|
|
tmp = colour_tostring(o->number); |
353 |
|
|
break; |
354 |
|
|
case OPTIONS_TABLE_ATTRIBUTES: |
355 |
|
|
tmp = attributes_tostring(o->number); |
356 |
|
|
break; |
357 |
|
|
case OPTIONS_TABLE_FLAG: |
358 |
|
|
if (numeric) |
359 |
|
|
xsnprintf(s, sizeof s, "%lld", o->number); |
360 |
|
|
else |
361 |
|
|
tmp = (o->number ? "on" : "off"); |
362 |
|
|
break; |
363 |
|
|
case OPTIONS_TABLE_CHOICE: |
364 |
|
|
tmp = o->tableentry->choices[o->number]; |
365 |
|
|
break; |
366 |
|
|
case OPTIONS_TABLE_STRING: |
367 |
|
|
case OPTIONS_TABLE_STYLE: |
368 |
|
|
case OPTIONS_TABLE_ARRAY: |
369 |
|
|
break; |
370 |
|
|
} |
371 |
|
|
if (tmp != NULL) |
372 |
|
|
xsnprintf(s, sizeof s, "%s", tmp); |
373 |
|
|
return (s); |
374 |
|
|
} |
375 |
|
|
if (OPTIONS_IS_STRING(o)) |
376 |
|
|
return (o->string); |
377 |
|
|
return (NULL); |
378 |
|
|
} |
379 |
|
|
|
380 |
|
|
char * |
381 |
|
|
options_parse(const char *name, int *idx) |
382 |
|
|
{ |
383 |
|
|
char *copy, *cp, *end; |
384 |
|
|
|
385 |
|
|
if (*name == '\0') |
386 |
|
|
return (NULL); |
387 |
|
|
copy = xstrdup(name); |
388 |
|
|
if ((cp = strchr(copy, '[')) == NULL) { |
389 |
|
|
*idx = -1; |
390 |
|
|
return (copy); |
391 |
|
|
} |
392 |
|
|
end = strchr(cp + 1, ']'); |
393 |
|
|
if (end == NULL || end[1] != '\0' || !isdigit((u_char)end[-1])) { |
394 |
|
|
free(copy); |
395 |
|
|
return (NULL); |
396 |
|
|
} |
397 |
|
|
if (sscanf(cp, "[%d]", idx) != 1 || *idx < 0) { |
398 |
|
|
free(copy); |
399 |
|
|
return (NULL); |
400 |
|
|
} |
401 |
|
|
*cp = '\0'; |
402 |
|
|
return (copy); |
403 |
|
|
} |
404 |
|
|
|
405 |
|
|
struct options_entry * |
406 |
|
|
options_parse_get(struct options *oo, const char *s, int *idx, int only) |
407 |
|
|
{ |
408 |
|
|
struct options_entry *o; |
409 |
|
|
char *name; |
410 |
|
|
|
411 |
|
|
name = options_parse(s, idx); |
412 |
|
|
if (name == NULL) |
413 |
|
|
return (NULL); |
414 |
|
|
if (only) |
415 |
|
|
o = options_get_only(oo, name); |
416 |
|
|
else |
417 |
|
|
o = options_get(oo, name); |
418 |
|
|
free(name); |
419 |
|
|
return (o); |
420 |
|
|
} |
421 |
|
|
|
422 |
|
|
char * |
423 |
|
|
options_match(const char *s, int *idx, int* ambiguous) |
424 |
|
|
{ |
425 |
|
|
const struct options_table_entry *oe, *found; |
426 |
|
|
char *name; |
427 |
|
|
size_t namelen; |
428 |
|
|
|
429 |
|
|
name = options_parse(s, idx); |
430 |
|
|
if (name == NULL) |
431 |
|
|
return (NULL); |
432 |
|
|
namelen = strlen(name); |
433 |
|
|
|
434 |
|
|
if (*name == '@') { |
435 |
|
|
*ambiguous = 0; |
436 |
|
|
return (name); |
437 |
|
|
} |
438 |
|
|
|
439 |
|
|
found = NULL; |
440 |
|
|
for (oe = options_table; oe->name != NULL; oe++) { |
441 |
|
|
if (strcmp(oe->name, name) == 0) { |
442 |
|
|
found = oe; |
443 |
|
|
break; |
444 |
|
|
} |
445 |
|
|
if (strncmp(oe->name, name, namelen) == 0) { |
446 |
|
|
if (found != NULL) { |
447 |
|
|
*ambiguous = 1; |
448 |
|
|
free(name); |
449 |
|
|
return (NULL); |
450 |
|
|
} |
451 |
|
|
found = oe; |
452 |
|
|
} |
453 |
|
|
} |
454 |
|
|
free(name); |
455 |
|
|
if (found == NULL) { |
456 |
|
|
*ambiguous = 0; |
457 |
|
|
return (NULL); |
458 |
|
|
} |
459 |
|
|
return (xstrdup(found->name)); |
460 |
|
|
} |
461 |
|
|
|
462 |
|
|
struct options_entry * |
463 |
|
|
options_match_get(struct options *oo, const char *s, int *idx, int only, |
464 |
|
|
int* ambiguous) |
465 |
|
|
{ |
466 |
|
|
char *name; |
467 |
|
|
struct options_entry *o; |
468 |
|
|
|
469 |
|
|
name = options_match(s, idx, ambiguous); |
470 |
|
|
if (name == NULL) |
471 |
|
|
return (NULL); |
472 |
|
|
*ambiguous = 0; |
473 |
|
|
if (only) |
474 |
|
|
o = options_get_only(oo, name); |
475 |
|
|
else |
476 |
|
|
o = options_get(oo, name); |
477 |
|
|
free(name); |
478 |
|
|
return (o); |
479 |
|
|
} |
480 |
|
|
|
481 |
|
|
const char * |
482 |
|
|
options_get_string(struct options *oo, const char *name) |
483 |
|
|
{ |
484 |
|
|
struct options_entry *o; |
485 |
|
|
|
486 |
|
|
o = options_get(oo, name); |
487 |
|
|
if (o == NULL) |
488 |
|
|
fatalx("missing option %s", name); |
489 |
|
|
if (!OPTIONS_IS_STRING(o)) |
490 |
|
|
fatalx("option %s is not a string", name); |
491 |
|
|
return (o->string); |
492 |
|
|
} |
493 |
|
|
|
494 |
|
|
long long |
495 |
|
|
options_get_number(struct options *oo, const char *name) |
496 |
|
|
{ |
497 |
|
|
struct options_entry *o; |
498 |
|
|
|
499 |
|
|
o = options_get(oo, name); |
500 |
|
|
if (o == NULL) |
501 |
|
|
fatalx("missing option %s", name); |
502 |
|
|
if (!OPTIONS_IS_NUMBER(o)) |
503 |
|
|
fatalx("option %s is not a number", name); |
504 |
|
|
return (o->number); |
505 |
|
|
} |
506 |
|
|
|
507 |
|
|
const struct grid_cell * |
508 |
|
|
options_get_style(struct options *oo, const char *name) |
509 |
|
|
{ |
510 |
|
|
struct options_entry *o; |
511 |
|
|
|
512 |
|
|
o = options_get(oo, name); |
513 |
|
|
if (o == NULL) |
514 |
|
|
fatalx("missing option %s", name); |
515 |
|
|
if (!OPTIONS_IS_STYLE(o)) |
516 |
|
|
fatalx("option %s is not a style", name); |
517 |
|
|
return (&o->style); |
518 |
|
|
} |
519 |
|
|
|
520 |
|
|
struct options_entry * |
521 |
|
|
options_set_string(struct options *oo, const char *name, int append, |
522 |
|
|
const char *fmt, ...) |
523 |
|
|
{ |
524 |
|
|
struct options_entry *o; |
525 |
|
|
va_list ap; |
526 |
|
|
char *s, *value; |
527 |
|
|
|
528 |
|
|
va_start(ap, fmt); |
529 |
|
|
xvasprintf(&s, fmt, ap); |
530 |
|
|
va_end(ap); |
531 |
|
|
|
532 |
|
|
o = options_get_only(oo, name); |
533 |
|
|
if (o != NULL && append && OPTIONS_IS_STRING(o)) { |
534 |
|
|
xasprintf(&value, "%s%s", o->string, s); |
535 |
|
|
free(s); |
536 |
|
|
} else |
537 |
|
|
value = s; |
538 |
|
|
if (o == NULL && *name == '@') |
539 |
|
|
o = options_add(oo, name); |
540 |
|
|
else if (o == NULL) { |
541 |
|
|
o = options_default(oo, options_parent_table_entry(oo, name)); |
542 |
|
|
if (o == NULL) |
543 |
|
|
return (NULL); |
544 |
|
|
} |
545 |
|
|
|
546 |
|
|
if (!OPTIONS_IS_STRING(o)) |
547 |
|
|
fatalx("option %s is not a string", name); |
548 |
|
|
free(o->string); |
549 |
|
|
o->string = value; |
550 |
|
|
return (o); |
551 |
|
|
} |
552 |
|
|
|
553 |
|
|
struct options_entry * |
554 |
|
|
options_set_number(struct options *oo, const char *name, long long value) |
555 |
|
|
{ |
556 |
|
|
struct options_entry *o; |
557 |
|
|
|
558 |
|
|
if (*name == '@') |
559 |
|
|
fatalx("user option %s must be a string", name); |
560 |
|
|
|
561 |
|
|
o = options_get_only(oo, name); |
562 |
|
|
if (o == NULL) { |
563 |
|
|
o = options_default(oo, options_parent_table_entry(oo, name)); |
564 |
|
|
if (o == NULL) |
565 |
|
|
return (NULL); |
566 |
|
|
} |
567 |
|
|
|
568 |
|
|
if (!OPTIONS_IS_NUMBER(o)) |
569 |
|
|
fatalx("option %s is not a number", name); |
570 |
|
|
o->number = value; |
571 |
|
|
return (o); |
572 |
|
|
} |
573 |
|
|
|
574 |
|
|
struct options_entry * |
575 |
|
|
options_set_style(struct options *oo, const char *name, int append, |
576 |
|
|
const char *value) |
577 |
|
|
{ |
578 |
|
|
struct options_entry *o; |
579 |
|
|
struct grid_cell gc; |
580 |
|
|
|
581 |
|
|
if (*name == '@') |
582 |
|
|
fatalx("user option %s must be a string", name); |
583 |
|
|
|
584 |
|
|
o = options_get_only(oo, name); |
585 |
|
|
if (o != NULL && append && OPTIONS_IS_STYLE(o)) |
586 |
|
|
memcpy(&gc, &o->style, sizeof gc); |
587 |
|
|
else |
588 |
|
|
memcpy(&gc, &grid_default_cell, sizeof gc); |
589 |
|
|
if (style_parse(&grid_default_cell, &gc, value) == -1) |
590 |
|
|
return (NULL); |
591 |
|
|
if (o == NULL) { |
592 |
|
|
o = options_default(oo, options_parent_table_entry(oo, name)); |
593 |
|
|
if (o == NULL) |
594 |
|
|
return (NULL); |
595 |
|
|
} |
596 |
|
|
|
597 |
|
|
if (!OPTIONS_IS_STYLE(o)) |
598 |
|
|
fatalx("option %s is not a style", name); |
599 |
|
|
memcpy(&o->style, &gc, sizeof o->style); |
600 |
|
|
return (o); |
601 |
|
|
} |
602 |
|
|
|
603 |
|
|
enum options_table_scope |
604 |
|
|
options_scope_from_flags(struct args *args, int window, |
605 |
|
|
struct cmd_find_state *fs, struct options **oo, char **cause) |
606 |
|
|
{ |
607 |
|
|
struct session *s = fs->s; |
608 |
|
|
struct winlink *wl = fs->wl; |
609 |
|
|
const char *target= args_get(args, 't'); |
610 |
|
|
|
611 |
|
|
if (args_has(args, 's')) { |
612 |
|
|
*oo = global_options; |
613 |
|
|
return (OPTIONS_TABLE_SERVER); |
614 |
|
|
} |
615 |
|
|
|
616 |
|
|
if (window || args_has(args, 'w')) { |
617 |
|
|
if (args_has(args, 'g')) { |
618 |
|
|
*oo = global_w_options; |
619 |
|
|
return (OPTIONS_TABLE_WINDOW); |
620 |
|
|
} |
621 |
|
|
if (wl == NULL) { |
622 |
|
|
if (target != NULL) |
623 |
|
|
xasprintf(cause, "no such window: %s", target); |
624 |
|
|
else |
625 |
|
|
xasprintf(cause, "no current window"); |
626 |
|
|
return (OPTIONS_TABLE_NONE); |
627 |
|
|
} |
628 |
|
|
*oo = wl->window->options; |
629 |
|
|
return (OPTIONS_TABLE_WINDOW); |
630 |
|
|
} else { |
631 |
|
|
if (args_has(args, 'g')) { |
632 |
|
|
*oo = global_s_options; |
633 |
|
|
return (OPTIONS_TABLE_SESSION); |
634 |
|
|
} |
635 |
|
|
if (s == NULL) { |
636 |
|
|
if (target != NULL) |
637 |
|
|
xasprintf(cause, "no such session: %s", target); |
638 |
|
|
else |
639 |
|
|
xasprintf(cause, "no current session"); |
640 |
|
|
return (OPTIONS_TABLE_NONE); |
641 |
|
|
} |
642 |
|
|
*oo = s->options; |
643 |
|
|
return (OPTIONS_TABLE_SESSION); |
644 |
|
|
} |
645 |
|
|
} |
646 |
|
|
|
647 |
|
|
void |
648 |
|
|
options_style_update_new(struct options *oo, struct options_entry *o) |
649 |
|
|
{ |
650 |
|
|
const char *newname = o->tableentry->style; |
651 |
|
|
struct options_entry *new; |
652 |
|
|
|
653 |
|
|
if (newname == NULL) |
654 |
|
|
return; |
655 |
|
|
new = options_get_only(oo, newname); |
656 |
|
|
if (new == NULL) |
657 |
|
|
new = options_set_style(oo, newname, 0, "default"); |
658 |
|
|
|
659 |
|
|
if (strstr(o->name, "-bg") != NULL) |
660 |
|
|
new->style.bg = o->number; |
661 |
|
|
else if (strstr(o->name, "-fg") != NULL) |
662 |
|
|
new->style.fg = o->number; |
663 |
|
|
else if (strstr(o->name, "-attr") != NULL) |
664 |
|
|
new->style.attr = o->number; |
665 |
|
|
} |
666 |
|
|
|
667 |
|
|
void |
668 |
|
|
options_style_update_old(struct options *oo, struct options_entry *o) |
669 |
|
|
{ |
670 |
|
|
char newname[128]; |
671 |
|
|
int size; |
672 |
|
|
|
673 |
|
|
size = strrchr(o->name, '-') - o->name; |
674 |
|
|
|
675 |
|
|
xsnprintf(newname, sizeof newname, "%.*s-bg", size, o->name); |
676 |
|
|
if (options_get(oo, newname) != NULL) |
677 |
|
|
options_set_number(oo, newname, o->style.bg); |
678 |
|
|
|
679 |
|
|
xsnprintf(newname, sizeof newname, "%.*s-fg", size, o->name); |
680 |
|
|
if (options_get(oo, newname) != NULL) |
681 |
|
|
options_set_number(oo, newname, o->style.fg); |
682 |
|
|
|
683 |
|
|
xsnprintf(newname, sizeof newname, "%.*s-attr", size, o->name); |
684 |
|
|
if (options_get(oo, newname) != NULL) |
685 |
|
|
options_set_number(oo, newname, o->style.attr); |
686 |
|
|
} |