NeoMutt  2024-04-25-92-gf10c0f
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
set.c
Go to the documentation of this file.
1
31#include "config.h"
32#include <stdbool.h>
33#include <stdio.h>
34#include "mutt/lib.h"
35#include "config/lib.h"
36#include "core/lib.h"
37#include "mutt.h"
38#include "set.h"
39#include "commands.h"
40#include "extract.h"
41#include "globals.h"
42#include "muttlib.h"
43
59static void command_set_expand_value(uint32_t type, struct Buffer *value)
60{
61 ASSERT(value);
62 if (DTYPE(type) == DT_PATH)
63 {
64 if (type & (D_PATH_DIR | D_PATH_FILE))
65 buf_expand_path(value);
66 else
68 }
69 else if (IS_MAILBOX(type))
70 {
71 buf_expand_path(value);
72 }
73 else if (IS_COMMAND(type))
74 {
75 struct Buffer *scratch = buf_pool_get();
76 buf_copy(scratch, value);
77
78 if (!mutt_str_equal(value->data, "builtin"))
79 {
80 buf_expand_path(scratch);
81 }
82 buf_reset(value);
83 buf_addstr(value, buf_string(scratch));
84 buf_pool_release(&scratch);
85 }
86}
87
100static enum CommandResult command_set_set(struct Buffer *name,
101 struct Buffer *value, struct Buffer *err)
102{
103 ASSERT(name);
104 ASSERT(value);
105 struct HashElem *he = cs_subset_lookup(NeoMutt->sub, name->data);
106 if (!he)
107 {
108 // In case it is a my_var, we have to create it
109 if (mutt_str_startswith(name->data, "my_"))
110 {
111 struct ConfigDef my_cdef = { 0 };
112 my_cdef.name = name->data;
113 my_cdef.type = DT_MYVAR;
114 he = cs_create_variable(NeoMutt->sub->cs, &my_cdef, err);
115 if (!he)
116 return MUTT_CMD_ERROR;
117 }
118 else
119 {
120 buf_printf(err, _("Unknown option %s"), name->data);
121 return MUTT_CMD_ERROR;
122 }
123 }
124
125 int rc = CSR_ERR_CODE;
126
127 if (DTYPE(he->type) == DT_MYVAR)
128 {
129 // my variables do not expand their value
130 rc = cs_subset_he_string_set(NeoMutt->sub, he, value->data, err);
131 }
132 else
133 {
134 command_set_expand_value(he->type, value);
135 rc = cs_subset_he_string_set(NeoMutt->sub, he, value->data, err);
136 }
137 if (CSR_RESULT(rc) != CSR_SUCCESS)
138 return MUTT_CMD_ERROR;
139
140 return MUTT_CMD_SUCCESS;
141}
142
156 struct Buffer *value, struct Buffer *err)
157{
158 ASSERT(name);
159 ASSERT(value);
160 struct HashElem *he = cs_subset_lookup(NeoMutt->sub, name->data);
161 if (!he)
162 {
163 // In case it is a my_var, we have to create it
164 if (mutt_str_startswith(name->data, "my_"))
165 {
166 struct ConfigDef my_cdef = { 0 };
167 my_cdef.name = name->data;
168 my_cdef.type = DT_MYVAR;
169 he = cs_create_variable(NeoMutt->sub->cs, &my_cdef, err);
170 if (!he)
171 return MUTT_CMD_ERROR;
172 }
173 else
174 {
175 buf_printf(err, _("Unknown option %s"), name->data);
176 return MUTT_CMD_ERROR;
177 }
178 }
179
180 int rc = CSR_ERR_CODE;
181
182 if (DTYPE(he->type) == DT_MYVAR)
183 {
184 // my variables do not expand their value
185 rc = cs_subset_he_string_plus_equals(NeoMutt->sub, he, value->data, err);
186 }
187 else
188 {
189 command_set_expand_value(he->type, value);
190 rc = cs_subset_he_string_plus_equals(NeoMutt->sub, he, value->data, err);
191 }
192 if (CSR_RESULT(rc) != CSR_SUCCESS)
193 return MUTT_CMD_ERROR;
194
195 return MUTT_CMD_SUCCESS;
196}
197
211 struct Buffer *value, struct Buffer *err)
212{
213 ASSERT(name);
214 ASSERT(value);
215 struct HashElem *he = cs_subset_lookup(NeoMutt->sub, name->data);
216 if (!he)
217 {
218 buf_printf(err, _("Unknown option %s"), name->data);
219 return MUTT_CMD_ERROR;
220 }
221
222 command_set_expand_value(he->type, value);
223 int rc = cs_subset_he_string_minus_equals(NeoMutt->sub, he, value->data, err);
224 if (CSR_RESULT(rc) != CSR_SUCCESS)
225 return MUTT_CMD_ERROR;
226
227 return MUTT_CMD_SUCCESS;
228}
229
240static enum CommandResult command_set_unset(struct Buffer *name, struct Buffer *err)
241{
242 ASSERT(name);
243 struct HashElem *he = cs_subset_lookup(NeoMutt->sub, name->data);
244 if (!he)
245 {
246 buf_printf(err, _("Unknown option %s"), name->data);
247 return MUTT_CMD_ERROR;
248 }
249
250 int rc = CSR_ERR_CODE;
251 if (DTYPE(he->type) == DT_MYVAR)
252 {
253 rc = cs_subset_he_delete(NeoMutt->sub, he, err);
254 }
255 else if ((DTYPE(he->type) == DT_BOOL) || (DTYPE(he->type) == DT_QUAD))
256 {
257 rc = cs_subset_he_native_set(NeoMutt->sub, he, false, err);
258 }
259 else
260 {
261 rc = cs_subset_he_string_set(NeoMutt->sub, he, NULL, err);
262 }
263 if (CSR_RESULT(rc) != CSR_SUCCESS)
264 return MUTT_CMD_ERROR;
265
266 return MUTT_CMD_SUCCESS;
267}
268
279static enum CommandResult command_set_reset(struct Buffer *name, struct Buffer *err)
280{
281 ASSERT(name);
282 // Handle special "reset all" syntax
283 if (mutt_str_equal(name->data, "all"))
284 {
285 struct HashElem **he_list = get_elem_list(NeoMutt->sub->cs);
286 if (!he_list)
287 return MUTT_CMD_ERROR;
288
289 for (size_t i = 0; he_list[i]; i++)
290 {
291 if (DTYPE(he_list[i]->type) == DT_MYVAR)
292 cs_subset_he_delete(NeoMutt->sub, he_list[i], err);
293 else
294 cs_subset_he_reset(NeoMutt->sub, he_list[i], NULL);
295 }
296
297 FREE(&he_list);
298 return MUTT_CMD_SUCCESS;
299 }
300
301 struct HashElem *he = cs_subset_lookup(NeoMutt->sub, name->data);
302 if (!he)
303 {
304 buf_printf(err, _("Unknown option %s"), name->data);
305 return MUTT_CMD_ERROR;
306 }
307
308 int rc = CSR_ERR_CODE;
309 if (DTYPE(he->type) == DT_MYVAR)
310 {
311 rc = cs_subset_he_delete(NeoMutt->sub, he, err);
312 }
313 else
314 {
315 rc = cs_subset_he_reset(NeoMutt->sub, he, err);
316 }
317 if (CSR_RESULT(rc) != CSR_SUCCESS)
318 return MUTT_CMD_ERROR;
319
320 return MUTT_CMD_SUCCESS;
321}
322
333static enum CommandResult command_set_toggle(struct Buffer *name, struct Buffer *err)
334{
335 ASSERT(name);
336 struct HashElem *he = cs_subset_lookup(NeoMutt->sub, name->data);
337 if (!he)
338 {
339 buf_printf(err, _("Unknown option %s"), name->data);
340 return MUTT_CMD_ERROR;
341 }
342
343 if (DTYPE(he->type) == DT_BOOL)
344 {
345 bool_he_toggle(NeoMutt->sub, he, err);
346 }
347 else if (DTYPE(he->type) == DT_QUAD)
348 {
349 quad_he_toggle(NeoMutt->sub, he, err);
350 }
351 else
352 {
353 buf_printf(err, _("Command '%s' can only be used with bool/quad variables"), "toggle");
354 return MUTT_CMD_ERROR;
355 }
356 return MUTT_CMD_SUCCESS;
357}
358
369static enum CommandResult command_set_query(struct Buffer *name, struct Buffer *err)
370{
371 ASSERT(name);
372 // In the interactive case (outside of the initial parsing of neomuttrc) we
373 // support additional syntax: "set" (no arguments) and "set all".
374 // If not in interactive mode, we recognise them but do nothing.
375
376 // Handle "set" (no arguments), i.e. show list of changed variables.
377 if (buf_is_empty(name))
378 {
379 if (StartupComplete)
380 return set_dump(CS_DUMP_ONLY_CHANGED, err);
381 else
382 return MUTT_CMD_SUCCESS;
383 }
384 // Handle special "set all" syntax
385 if (mutt_str_equal(name->data, "all"))
386 {
387 if (StartupComplete)
388 return set_dump(CS_DUMP_NO_FLAGS, err);
389 else
390 return MUTT_CMD_SUCCESS;
391 }
392
393 struct HashElem *he = cs_subset_lookup(NeoMutt->sub, name->data);
394 if (!he)
395 {
396 buf_printf(err, _("Unknown option %s"), name->data);
397 return MUTT_CMD_ERROR;
398 }
399
400 buf_addstr(err, name->data);
401 buf_addch(err, '=');
402 struct Buffer *value = buf_pool_get();
403 int rc = cs_subset_he_string_get(NeoMutt->sub, he, value);
404 if (CSR_RESULT(rc) != CSR_SUCCESS)
405 {
406 buf_reset(err);
407 buf_addstr(err, value->data);
408 buf_pool_release(&value);
409 return MUTT_CMD_ERROR;
410 }
411 if (DTYPE(he->type) == DT_PATH)
412 mutt_pretty_mailbox(value->data, value->dsize);
413 pretty_var(value->data, err);
414 buf_pool_release(&value);
415
416 return MUTT_CMD_SUCCESS;
417}
418
424enum CommandResult parse_set(struct Buffer *buf, struct Buffer *s,
425 intptr_t data, struct Buffer *err)
426{
427 /* The order must match `enum MuttSetCommand` */
428 static const char *set_commands[] = { "set", "toggle", "unset", "reset" };
429
430 if (!buf || !s)
431 return MUTT_CMD_ERROR;
432
433 do
434 {
435 bool prefix = false;
436 bool query = false;
437 bool inv = (data == MUTT_SET_INV);
438 bool reset = (data == MUTT_SET_RESET);
439 bool unset = (data == MUTT_SET_UNSET);
440
441 if (*s->dptr == '?')
442 {
443 prefix = true;
444 query = true;
445 s->dptr++;
446 }
447 else if (mutt_str_startswith(s->dptr, "no"))
448 {
449 prefix = true;
450 unset = !unset;
451 s->dptr += 2;
452 }
453 else if (mutt_str_startswith(s->dptr, "inv"))
454 {
455 prefix = true;
456 inv = !inv;
457 s->dptr += 3;
458 }
459 else if (*s->dptr == '&')
460 {
461 prefix = true;
462 reset = true;
463 s->dptr++;
464 }
465
466 if (prefix && (data != MUTT_SET_SET))
467 {
468 buf_printf(err, _("Can't use 'inv', 'no', '&' or '?' with the '%s' command"),
469 set_commands[data]);
470 return MUTT_CMD_WARNING;
471 }
472
473 // get the variable name. Note that buf might be empty if no additional
474 // argument was given.
476 if (ret == -1)
477 return MUTT_CMD_ERROR;
478
479 bool bool_or_quad = false;
480 bool equals = false;
481 bool increment = false;
482 bool decrement = false;
483
484 struct HashElem *he = cs_subset_lookup(NeoMutt->sub, buf->data);
485 if (he)
486 {
487 // Use the correct name if a synonym is used
488 buf_strcpy(buf, he->key.strkey);
489 bool_or_quad = ((DTYPE(he->type) == DT_BOOL) || (DTYPE(he->type) == DT_QUAD));
490 }
491
492 if (*s->dptr == '?')
493 {
494 if (prefix)
495 {
496 buf_printf(err, _("Can't use a prefix when querying a variable"));
497 return MUTT_CMD_WARNING;
498 }
499
500 if (reset || unset || inv)
501 {
502 buf_printf(err, _("Can't query option with the '%s' command"), set_commands[data]);
503 return MUTT_CMD_WARNING;
504 }
505
506 query = true;
507 s->dptr++;
508 }
509 else if ((*s->dptr == '+') || (*s->dptr == '-'))
510 {
511 if (prefix)
512 {
513 buf_printf(err, _("Can't use prefix when incrementing or decrementing a variable"));
514 return MUTT_CMD_WARNING;
515 }
516
517 if (reset || unset || inv)
518 {
519 buf_printf(err, _("Can't set option with the '%s' command"), set_commands[data]);
520 return MUTT_CMD_WARNING;
521 }
522 if (*s->dptr == '+')
523 increment = true;
524 else
525 decrement = true;
526
527 s->dptr++;
528 if (*s->dptr == '=')
529 {
530 equals = true;
531 s->dptr++;
532 }
533 else
534 {
535 buf_printf(err, _("'+' and '-' must be followed by '='"));
536 return MUTT_CMD_WARNING;
537 }
538 }
539 else if (*s->dptr == '=')
540 {
541 if (prefix)
542 {
543 buf_printf(err, _("Can't use prefix when setting a variable"));
544 return MUTT_CMD_WARNING;
545 }
546
547 if (reset || unset || inv)
548 {
549 buf_printf(err, _("Can't set option with the '%s' command"), set_commands[data]);
550 return MUTT_CMD_WARNING;
551 }
552
553 equals = true;
554 s->dptr++;
555 }
556
557 if (!bool_or_quad && (inv || (unset && prefix)))
558 {
559 if (data == MUTT_SET_SET)
560 {
561 buf_printf(err, _("Prefixes 'no' and 'inv' may only be used with bool/quad variables"));
562 }
563 else
564 {
565 buf_printf(err, _("Command '%s' can only be used with bool/quad variables"),
566 set_commands[data]);
567 }
568 return MUTT_CMD_WARNING;
569 }
570
571 // sanity checks for the above
572 // Each of inv, unset reset, query, equals implies that the others are not set.
573 // If none of them are set, then we are dealing with a "set foo" command.
574 // clang-format off
575 ASSERT(!inv || !( unset || reset || query || equals ));
576 ASSERT(!unset || !(inv || reset || query || equals ));
577 ASSERT(!reset || !(inv || unset || query || equals ));
578 ASSERT(!query || !(inv || unset || reset || equals ));
579 ASSERT(!equals || !(inv || unset || reset || query || prefix));
580 // clang-format on
581 ASSERT(!(increment && decrement)); // only one of increment or decrement is set
582 ASSERT(!(increment || decrement) || equals); // increment/decrement implies equals
583 ASSERT(!inv || bool_or_quad); // inv (aka toggle) implies bool or quad
584
586 if (query)
587 {
588 rc = command_set_query(buf, err);
589 return rc; // We can only do one query even if multiple config names are given
590 }
591 else if (reset)
592 {
593 rc = command_set_reset(buf, err);
594 }
595 else if (unset)
596 {
597 rc = command_set_unset(buf, err);
598 }
599 else if (inv)
600 {
601 rc = command_set_toggle(buf, err);
602 }
603 else if (equals)
604 {
605 // These three cases all need a value, since 'increment'/'decrement'
606 // implies 'equals', we can group them in this single case guarded by
607 // 'equals'.
608 struct Buffer *value = buf_pool_get();
610 if (increment)
611 rc = command_set_increment(buf, value, err);
612 else if (decrement)
613 rc = command_set_decrement(buf, value, err);
614 else
615 rc = command_set_set(buf, value, err);
616 buf_pool_release(&value);
617 }
618 else
619 {
620 // This is the "set foo" case which has different meanings depending on
621 // the type of the config variable
622 if (bool_or_quad)
623 {
624 struct Buffer *yes = buf_pool_get();
625 buf_addstr(yes, "yes");
626 rc = command_set_set(buf, yes, err);
627 buf_pool_release(&yes);
628 }
629 else
630 {
631 rc = command_set_query(buf, err);
632 return rc; // We can only do one query even if multiple config names are given
633 }
634 }
635 // Short circuit (i.e. skipping further config variable names) if the action on
636 // the current variable failed.
637 if (rc != MUTT_CMD_SUCCESS)
638 return rc;
639 } while (MoreArgs(s));
640
641 return MUTT_CMD_SUCCESS;
642}
int bool_he_toggle(struct ConfigSubset *sub, struct HashElem *he, struct Buffer *err)
Toggle the value of a bool.
Definition: bool.c:196
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:161
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:76
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:291
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:241
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:226
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:395
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:601
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
CommandResult
Error codes for command_t parse functions.
Definition: command.h:36
@ MUTT_CMD_SUCCESS
Success: Command worked.
Definition: command.h:39
@ MUTT_CMD_ERROR
Error: Can't help the user.
Definition: command.h:37
@ MUTT_CMD_WARNING
Warning: Help given to the user.
Definition: command.h:38
enum CommandResult set_dump(ConfigDumpFlags flags, struct Buffer *err)
Dump list of config variables into a file/pager.
Definition: commands.c:874
Functions to parse commands in a config file.
size_t pretty_var(const char *str, struct Buffer *buf)
Escape and stringify a config item value.
Definition: dump.c:85
void mutt_pretty_mailbox(char *buf, size_t buflen)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:440
#define CS_DUMP_ONLY_CHANGED
Only show config that the user has changed.
Definition: dump.h:36
#define CS_DUMP_NO_FLAGS
No flags are set.
Definition: dump.h:35
Convenience wrapper for the config headers.
char * HomeDir
User's home directory.
Definition: globals.c:38
struct HashElem * cs_create_variable(const struct ConfigSet *cs, struct ConfigDef *cdef, struct Buffer *err)
Create and register one config item.
Definition: set.c:318
#define CSR_ERR_CODE
Problem with the code.
Definition: set.h:36
#define CSR_RESULT(x)
Definition: set.h:52
bool StartupComplete
When the config has been read.
Definition: main.c:192
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:35
Convenience wrapper for the core headers.
int parse_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: extract.c:50
Text parser.
#define TOKEN_BACKTICK_VARS
Expand variables within backticks.
Definition: extract.h:54
#define TOKEN_EQUAL
Treat '=' as a special.
Definition: extract.h:47
#define TOKEN_PLUS
Treat '+' as a special.
Definition: extract.h:57
#define MoreArgs(buf)
Definition: extract.h:32
#define TOKEN_MINUS
Treat '-' as a special.
Definition: extract.h:58
#define TOKEN_QUESTION
Treat '?' as a special.
Definition: extract.h:56
enum CommandResult parse_set(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'set' family of commands - Implements Command::parse() -.
Definition: set.c:424
#define FREE(x)
Definition: memory.h:45
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
bool mutt_path_tilde(struct Buffer *path, const char *homedir)
Expand '~' in a path.
Definition: path.c:194
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:660
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:230
Many unsorted constants and some structs.
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:315
Some miscellaneous functions.
static enum CommandResult command_set_toggle(struct Buffer *name, struct Buffer *err)
Toggle a boolean or quad variable.
Definition: set.c:333
static enum CommandResult command_set_set(struct Buffer *name, struct Buffer *value, struct Buffer *err)
Set a variable to the given value.
Definition: set.c:100
static enum CommandResult command_set_reset(struct Buffer *name, struct Buffer *err)
Reset a variable.
Definition: set.c:279
static enum CommandResult command_set_unset(struct Buffer *name, struct Buffer *err)
Unset a variable.
Definition: set.c:240
static enum CommandResult command_set_query(struct Buffer *name, struct Buffer *err)
Query a variable.
Definition: set.c:369
static enum CommandResult command_set_increment(struct Buffer *name, struct Buffer *value, struct Buffer *err)
Increment a variable by a value.
Definition: set.c:155
static void command_set_expand_value(uint32_t type, struct Buffer *value)
Expand special characters.
Definition: set.c:59
static enum CommandResult command_set_decrement(struct Buffer *name, struct Buffer *value, struct Buffer *err)
Decrement a variable by a value.
Definition: set.c:210
Parse the 'set' command.
@ MUTT_SET_INV
default is to invert all vars
Definition: set.h:37
@ MUTT_SET_SET
default is to set all vars
Definition: set.h:36
@ MUTT_SET_RESET
default is to reset all vars to default
Definition: set.h:39
@ MUTT_SET_UNSET
default is to unset all vars
Definition: set.h:38
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
int quad_he_toggle(struct ConfigSubset *sub, struct HashElem *he, struct Buffer *err)
Toggle the value of a quad.
Definition: quad.c:217
#define ASSERT(COND)
Definition: signal2.h:58
String manipulation buffer.
Definition: buffer.h:36
char * dptr
Current read/write position.
Definition: buffer.h:38
size_t dsize
Length of data.
Definition: buffer.h:39
char * data
Pointer to data.
Definition: buffer.h:37
Definition: set.h:64
const char * name
User-visible name.
Definition: set.h:65
uint32_t type
Variable type, e.g. DT_STRING.
Definition: set.h:66
struct ConfigSet * cs
Parent ConfigSet.
Definition: subset.h:51
The item stored in a Hash Table.
Definition: hash.h:43
union HashKey key
Key representing the data.
Definition: hash.h:45
int type
Type of data stored in Hash Table, e.g. DT_STRING.
Definition: hash.h:44
void * data
User-supplied data.
Definition: hash.h:46
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
int cs_subset_he_string_minus_equals(const struct ConfigSubset *sub, struct HashElem *he, const char *value, struct Buffer *err)
Remove from a config item by string.
Definition: subset.c:424
int cs_subset_he_string_get(const struct ConfigSubset *sub, struct HashElem *he, struct Buffer *result)
Get a config item as a string.
Definition: subset.c:332
int cs_subset_he_native_set(const struct ConfigSubset *sub, struct HashElem *he, intptr_t value, struct Buffer *err)
Natively set the value of a HashElem config item.
Definition: subset.c:275
int cs_subset_he_delete(const struct ConfigSubset *sub, struct HashElem *he, struct Buffer *err)
Delete config item from a config.
Definition: subset.c:445
struct HashElem ** get_elem_list(struct ConfigSet *cs)
Create a sorted list of all config items.
Definition: subset.c:79
int cs_subset_he_reset(const struct ConfigSubset *sub, struct HashElem *he, struct Buffer *err)
Reset a config item to its initial value.
Definition: subset.c:312
int cs_subset_he_string_set(const struct ConfigSubset *sub, struct HashElem *he, const char *value, struct Buffer *err)
Set a config item by string.
Definition: subset.c:364
int cs_subset_he_string_plus_equals(const struct ConfigSubset *sub, struct HashElem *he, const char *value, struct Buffer *err)
Add to a config item by string.
Definition: subset.c:402
struct HashElem * cs_subset_lookup(const struct ConfigSubset *sub, const char *name)
Find an inherited config item.
Definition: subset.c:187
#define IS_MAILBOX(flags)
Definition: types.h:122
#define DTYPE(t)
Definition: types.h:50
#define D_PATH_DIR
Path is a directory.
Definition: types.h:103
#define D_PATH_FILE
Path is a file.
Definition: types.h:104
@ DT_BOOL
boolean option
Definition: types.h:32
@ DT_QUAD
quad-option (no/yes/ask-no/ask-yes)
Definition: types.h:41
@ DT_MYVAR
a user-defined variable (my_foo)
Definition: types.h:38
@ DT_PATH
a path to a file/directory
Definition: types.h:40
#define IS_COMMAND(flags)
Definition: types.h:123
const char * strkey
String key.
Definition: hash.h:35