NeoMutt  2023-11-03-107-g582dc1
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
subset.c
Go to the documentation of this file.
1
29#include "config.h"
30#include <limits.h>
31#include <stdint.h>
32#include <stdio.h>
33#include "mutt/lib.h"
34#include "subset.h"
35#include "set.h"
36
37struct Notify;
38
42static const struct Mapping ConfigEventNames[] = {
43 // clang-format off
44 { "NT_CONFIG_SET", NT_CONFIG_SET },
45 { "NT_CONFIG_RESET", NT_CONFIG_RESET },
46 { "NT_CONFIG_DELETED", NT_CONFIG_DELETED },
47 { NULL, 0 },
48 // clang-format on
49};
50
54int elem_list_sort(const void *a, const void *b, void *sdata)
55{
56 if (!a || !b)
57 return 0;
58
59 const struct HashElem *hea = *(struct HashElem const *const *) a;
60 const struct HashElem *heb = *(struct HashElem const *const *) b;
61
62 return mutt_istr_cmp(hea->key.strkey, heb->key.strkey);
63}
64
70struct HashElem **get_elem_list(struct ConfigSet *cs)
71{
72 if (!cs)
73 return NULL;
74
75 struct HashElem **he_list = mutt_mem_calloc(1024, sizeof(struct HashElem *));
76 size_t index = 0;
77
78 struct HashWalkState walk = { 0 };
79 struct HashElem *he = NULL;
80
81 while ((he = mutt_hash_walk(cs->hash, &walk)))
82 {
83 he_list[index++] = he;
84 if (index == 1022)
85 break; /* LCOV_EXCL_LINE */
86 }
87
88 mutt_qsort_r(he_list, index, sizeof(struct HashElem *), elem_list_sort, NULL);
89
90 return he_list;
91}
92
99void cs_subset_free(struct ConfigSubset **ptr)
100{
101 if (!ptr || !*ptr)
102 return;
103
104 struct ConfigSubset *sub = *ptr;
105
106 struct EventConfig ev_c = { sub, NULL, NULL };
107 mutt_debug(LL_NOTIFY, "NT_CONFIG_DELETED: ALL\n");
109
110 if (sub->cs && sub->name)
111 {
112 char scope[256] = { 0 };
113 snprintf(scope, sizeof(scope), "%s:", sub->name);
114
115 // We don't know if any config items have been set,
116 // so search for anything with a matching scope.
117 struct HashElem **he_list = get_elem_list(sub->cs);
118 for (size_t i = 0; he_list[i]; i++)
119 {
120 const char *item = he_list[i]->key.strkey;
121 if (mutt_str_startswith(item, scope) != 0)
122 {
123 cs_uninherit_variable(sub->cs, item);
124 }
125 }
126 FREE(&he_list);
127 }
128
129 notify_free(&sub->notify);
130 FREE(&sub->name);
131 FREE(ptr);
132}
133
143struct ConfigSubset *cs_subset_new(const char *name, struct ConfigSubset *sub_parent,
144 struct Notify *not_parent)
145{
146 struct ConfigSubset *sub = mutt_mem_calloc(1, sizeof(*sub));
147
148 if (sub_parent)
149 {
150 sub->parent = sub_parent;
151 sub->cs = sub_parent->cs;
152 }
153
154 if (name)
155 {
156 char scope[256] = { 0 };
157
158 if (sub_parent && sub_parent->name)
159 snprintf(scope, sizeof(scope), "%s:%s", sub_parent->name, name);
160 else
161 mutt_str_copy(scope, name, sizeof(scope));
162
163 sub->name = mutt_str_dup(scope);
164 }
165
166 sub->notify = notify_new();
167 notify_set_parent(sub->notify, not_parent);
168
169 return sub;
170}
171
178struct HashElem *cs_subset_lookup(const struct ConfigSubset *sub, const char *name)
179{
180 if (!sub || !name)
181 return NULL;
182
183 char scope[256] = { 0 };
184 if (sub->name)
185 snprintf(scope, sizeof(scope), "%s:%s", sub->name, name);
186 else
187 mutt_str_copy(scope, name, sizeof(scope));
188
189 return cs_get_elem(sub->cs, scope);
190}
191
199struct HashElem *cs_subset_create_inheritance(const struct ConfigSubset *sub, const char *name)
200{
201 if (!sub)
202 return NULL;
203
204 struct HashElem *he = cs_subset_lookup(sub, name);
205 if (he)
206 return he;
207
208 if (sub->parent)
209 {
210 // Create parent before creating name
211 he = cs_subset_create_inheritance(sub->parent, name);
212 }
213
214 if (!he)
215 return NULL;
216
217 char scope[256] = { 0 };
218 snprintf(scope, sizeof(scope), "%s:%s", sub->name, name);
219 return cs_inherit_variable(sub->cs, he, scope);
220}
221
229 struct HashElem *he, enum NotifyConfig ev)
230{
231 if (!sub || !he)
232 return;
233
234 struct HashElem *he_base = cs_get_base(he);
235 struct EventConfig ev_c = { sub, he_base->key.strkey, he };
236 mutt_debug(LL_NOTIFY, "%s: %s\n",
238 notify_send(sub->notify, NT_CONFIG, ev, &ev_c);
239}
240
250 struct HashElem *he, struct Buffer *err)
251{
252 if (!sub)
253 return INT_MIN;
254
255 return cs_he_native_get(sub->cs, he, err);
256}
257
267 const char *name, struct Buffer *err)
268{
269 struct HashElem *he = cs_subset_create_inheritance(sub, name);
270
271 return cs_subset_he_native_get(sub, he, err);
272}
273
282int cs_subset_he_native_set(const struct ConfigSubset *sub, struct HashElem *he,
283 intptr_t value, struct Buffer *err)
284{
285 if (!sub)
286 return CSR_ERR_CODE;
287
288 int rc = cs_he_native_set(sub->cs, he, value, err);
289
290 if ((CSR_RESULT(rc) == CSR_SUCCESS) && !(rc & CSR_SUC_NO_CHANGE))
292
293 return rc;
294}
295
304int cs_subset_str_native_set(const struct ConfigSubset *sub, const char *name,
305 intptr_t value, struct Buffer *err)
306{
307 struct HashElem *he = cs_subset_create_inheritance(sub, name);
308
309 return cs_subset_he_native_set(sub, he, value, err);
310}
311
319int cs_subset_he_reset(const struct ConfigSubset *sub, struct HashElem *he, struct Buffer *err)
320{
321 if (!sub)
322 return CSR_ERR_CODE;
323
324 int rc = cs_he_reset(sub->cs, he, err);
325
326 if ((CSR_RESULT(rc) == CSR_SUCCESS) && !(rc & CSR_SUC_NO_CHANGE))
328
329 return rc;
330}
331
339int cs_subset_str_reset(const struct ConfigSubset *sub, const char *name, struct Buffer *err)
340{
341 struct HashElem *he = cs_subset_create_inheritance(sub, name);
342
343 return cs_subset_he_reset(sub, he, err);
344}
345
353int cs_subset_he_string_get(const struct ConfigSubset *sub, struct HashElem *he,
354 struct Buffer *result)
355{
356 if (!sub)
357 return CSR_ERR_CODE;
358
359 return cs_he_string_get(sub->cs, he, result);
360}
361
369int cs_subset_str_string_get(const struct ConfigSubset *sub, const char *name,
370 struct Buffer *result)
371{
372 struct HashElem *he = cs_subset_create_inheritance(sub, name);
373
374 return cs_subset_he_string_get(sub, he, result);
375}
376
385int cs_subset_he_string_set(const struct ConfigSubset *sub, struct HashElem *he,
386 const char *value, struct Buffer *err)
387{
388 if (!sub)
389 return CSR_ERR_CODE;
390
391 int rc = cs_he_string_set(sub->cs, he, value, err);
392
393 if ((CSR_RESULT(rc) == CSR_SUCCESS) && !(rc & CSR_SUC_NO_CHANGE))
395
396 return rc;
397}
398
407int cs_subset_str_string_set(const struct ConfigSubset *sub, const char *name,
408 const char *value, struct Buffer *err)
409{
410 struct HashElem *he = cs_subset_create_inheritance(sub, name);
411
412 return cs_subset_he_string_set(sub, he, value, err);
413}
414
423int cs_subset_he_string_plus_equals(const struct ConfigSubset *sub, struct HashElem *he,
424 const char *value, struct Buffer *err)
425{
426 if (!sub)
427 return CSR_ERR_CODE;
428
429 int rc = cs_he_string_plus_equals(sub->cs, he, value, err);
430
431 if ((CSR_RESULT(rc) == CSR_SUCCESS) && !(rc & CSR_SUC_NO_CHANGE))
433
434 return rc;
435}
436
445int cs_subset_str_string_plus_equals(const struct ConfigSubset *sub, const char *name,
446 const char *value, struct Buffer *err)
447{
448 struct HashElem *he = cs_subset_create_inheritance(sub, name);
449
450 return cs_subset_he_string_plus_equals(sub, he, value, err);
451}
452
462 const char *value, struct Buffer *err)
463{
464 if (!sub)
465 return CSR_ERR_CODE;
466
467 int rc = cs_he_string_minus_equals(sub->cs, he, value, err);
468
469 if ((CSR_RESULT(rc) == CSR_SUCCESS) && !(rc & CSR_SUC_NO_CHANGE))
471
472 return rc;
473}
474
483int cs_subset_str_string_minus_equals(const struct ConfigSubset *sub, const char *name,
484 const char *value, struct Buffer *err)
485{
486 struct HashElem *he = cs_subset_create_inheritance(sub, name);
487
488 return cs_subset_he_string_minus_equals(sub, he, value, err);
489}
490
498int cs_subset_he_delete(const struct ConfigSubset *sub, struct HashElem *he, struct Buffer *err)
499{
500 if (!sub)
501 return CSR_ERR_CODE;
502
503 const char *name = mutt_str_dup(he->key.strkey);
504 int rc = cs_he_delete(sub->cs, he, err);
505
506 if (CSR_RESULT(rc) == CSR_SUCCESS)
507 {
508 struct EventConfig ev_c = { sub, name, NULL };
509 mutt_debug(LL_NOTIFY, "NT_CONFIG_DELETED: %s\n", name);
511 }
512
513 FREE(&name);
514 return rc;
515}
516
524int cs_subset_str_delete(const struct ConfigSubset *sub, const char *name, struct Buffer *err)
525{
526 struct HashElem *he = cs_subset_create_inheritance(sub, name);
527
528 return cs_subset_he_delete(sub, he, err);
529}
struct HashElem * cs_get_elem(const struct ConfigSet *cs, const char *name)
Get the HashElem representing a config item.
Definition: set.c:172
int cs_he_string_plus_equals(const struct ConfigSet *cs, struct HashElem *he, const char *value, struct Buffer *err)
Add to a config item by string.
Definition: set.c:902
int cs_he_reset(const struct ConfigSet *cs, struct HashElem *he, struct Buffer *err)
Reset a config item to its initial value.
Definition: set.c:390
int cs_he_delete(const struct ConfigSet *cs, struct HashElem *he, struct Buffer *err)
Delete config item from a config set.
Definition: set.c:1067
int cs_he_string_set(const struct ConfigSet *cs, struct HashElem *he, const char *value, struct Buffer *err)
Set a config item by string.
Definition: set.c:587
struct HashElem * cs_get_base(struct HashElem *he)
Find the root Config Item.
Definition: set.c:157
int cs_he_native_set(const struct ConfigSet *cs, struct HashElem *he, intptr_t value, struct Buffer *err)
Natively set the value of a HashElem config item.
Definition: set.c:729
intptr_t cs_he_native_get(const struct ConfigSet *cs, struct HashElem *he, struct Buffer *err)
Natively get the value of a HashElem config item.
Definition: set.c:834
struct HashElem * cs_inherit_variable(const struct ConfigSet *cs, struct HashElem *he_parent, const char *name)
Create in inherited config item.
Definition: set.c:346
int cs_he_string_get(const struct ConfigSet *cs, struct HashElem *he, struct Buffer *result)
Get a config item as a string.
Definition: set.c:662
int cs_he_string_minus_equals(const struct ConfigSet *cs, struct HashElem *he, const char *value, struct Buffer *err)
Remove from a config item by string.
Definition: set.c:985
void cs_uninherit_variable(const struct ConfigSet *cs, const char *name)
Remove an inherited config item.
Definition: set.c:375
#define CSR_SUC_NO_CHANGE
The value hasn't changed.
Definition: set.h:44
#define CSR_ERR_CODE
Problem with the code.
Definition: set.h:36
#define CSR_RESULT(x)
Definition: set.h:52
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:35
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
int elem_list_sort(const void *a, const void *b, void *sdata)
Compare two HashElem pointers to config - Implements sort_t -.
Definition: subset.c:54
struct HashElem * mutt_hash_walk(const struct HashTable *table, struct HashWalkState *state)
Iterate through all the HashElem's in a Hash Table.
Definition: hash.c:489
@ LL_NOTIFY
Log of notifications.
Definition: logging2.h:48
const char * mutt_map_get_name(int val, const struct Mapping *map)
Lookup a string for a constant.
Definition: mapping.c:42
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
#define FREE(x)
Definition: memory.h:45
Convenience wrapper for the library headers.
struct Notify * notify_new(void)
Create a new notifications handler.
Definition: notify.c:62
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition: notify.c:173
void notify_set_parent(struct Notify *notify, struct Notify *parent)
Set the parent notification handler.
Definition: notify.c:95
void notify_free(struct Notify **ptr)
Free a notification handler.
Definition: notify.c:75
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:251
int mutt_istr_cmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:484
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:228
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:653
@ NT_CONFIG
Config has changed, NotifyConfig, EventConfig.
Definition: notify_type.h:43
Parse the 'set' command.
void mutt_qsort_r(void *base, size_t nmemb, size_t size, sort_t compar, void *sdata)
Sort an array, where the comparator has access to opaque data rather than requiring global variables.
Definition: qsort_r.c:66
#define NONULL(x)
Definition: string2.h:37
String manipulation buffer.
Definition: buffer.h:34
Container for lots of config items.
Definition: set.h:252
struct HashTable * hash
Hash Table: "$name" -> ConfigDef.
Definition: set.h:253
A set of inherited config items.
Definition: subset.h:47
struct Notify * notify
Notifications: NotifyConfig, EventConfig.
Definition: subset.h:52
const char * name
Scope name of Subset.
Definition: subset.h:48
struct ConfigSet * cs
Parent ConfigSet.
Definition: subset.h:51
struct ConfigSubset * parent
Parent Subset.
Definition: subset.h:50
enum ConfigScope scope
Scope of Subset, e.g. SET_SCOPE_ACCOUNT.
Definition: subset.h:49
A config-change event.
Definition: subset.h:71
const struct ConfigSubset * sub
Config Subset.
Definition: subset.h:72
const char * name
Name of config item that changed.
Definition: subset.h:73
struct HashElem * he
Config item that changed.
Definition: subset.h:74
The item stored in a Hash Table.
Definition: hash.h:44
union HashKey key
Key representing the data.
Definition: hash.h:46
Cursor to iterate through a Hash Table.
Definition: hash.h:133
Mapping between user-readable string and a constant.
Definition: mapping.h:32
Notification API.
Definition: notify.c:53
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:461
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:353
int cs_subset_str_string_plus_equals(const struct ConfigSubset *sub, const char *name, const char *value, struct Buffer *err)
Add to a config item by string.
Definition: subset.c:445
int cs_subset_str_reset(const struct ConfigSubset *sub, const char *name, struct Buffer *err)
Reset a config item to its initial value.
Definition: subset.c:339
int cs_subset_str_string_minus_equals(const struct ConfigSubset *sub, const char *name, const char *value, struct Buffer *err)
Remove from a config item by string.
Definition: subset.c:483
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:282
int cs_subset_str_native_set(const struct ConfigSubset *sub, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: subset.c:304
intptr_t cs_subset_he_native_get(const struct ConfigSubset *sub, struct HashElem *he, struct Buffer *err)
Natively get the value of a HashElem config item.
Definition: subset.c:249
int cs_subset_he_delete(const struct ConfigSubset *sub, struct HashElem *he, struct Buffer *err)
Delete config item from a config.
Definition: subset.c:498
struct HashElem ** get_elem_list(struct ConfigSet *cs)
Create a sorted list of all config items.
Definition: subset.c:70
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:319
int cs_subset_str_string_get(const struct ConfigSubset *sub, const char *name, struct Buffer *result)
Get a config item as a string.
Definition: subset.c:369
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:385
int cs_subset_str_string_set(const struct ConfigSubset *sub, const char *name, const char *value, struct Buffer *err)
Set a config item by string.
Definition: subset.c:407
struct HashElem * cs_subset_create_inheritance(const struct ConfigSubset *sub, const char *name)
Create a Subset config item (inherited)
Definition: subset.c:199
struct ConfigSubset * cs_subset_new(const char *name, struct ConfigSubset *sub_parent, struct Notify *not_parent)
Create a new Config Subset.
Definition: subset.c:143
void cs_subset_free(struct ConfigSubset **ptr)
Free a Config Subset.
Definition: subset.c:99
static const struct Mapping ConfigEventNames[]
Names for logging.
Definition: subset.c:42
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:423
struct HashElem * cs_subset_lookup(const struct ConfigSubset *sub, const char *name)
Find an inherited config item.
Definition: subset.c:178
intptr_t cs_subset_str_native_get(const struct ConfigSubset *sub, const char *name, struct Buffer *err)
Natively get the value of a string config item.
Definition: subset.c:266
int cs_subset_str_delete(const struct ConfigSubset *sub, const char *name, struct Buffer *err)
Delete config item from a config by string.
Definition: subset.c:524
void cs_subset_notify_observers(const struct ConfigSubset *sub, struct HashElem *he, enum NotifyConfig ev)
Notify all observers of an event.
Definition: subset.c:228
Subset of Config Items.
NotifyConfig
Config notification types.
Definition: subset.h:61
@ NT_CONFIG_DELETED
Config item has been deleted.
Definition: subset.h:64
@ NT_CONFIG_RESET
Config item has been reset to initial, or parent, value.
Definition: subset.h:63
@ NT_CONFIG_SET
Config item has been set.
Definition: subset.h:62
const char * strkey
String key.
Definition: hash.h:36