master
c 185 lines 6.48 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "inicfg_internals.h"
4
5 // ----------------------------------------------------------------------------
6 // config options index
7
8 int inicfg_option_compare(void *a, void *b) {
9 if(((struct config_option *)a)->name < ((struct config_option *)b)->name) return -1;
10 else if(((struct config_option *)a)->name > ((struct config_option *)b)->name) return 1;
11 else return string_cmp(((struct config_option *)a)->name, ((struct config_option *)b)->name);
12 }
13
14 struct config_option *inicfg_option_find(struct config_section *sect, const char *name) {
15 struct config_option opt_tmp = {
16 .name = string_strdupz(name),
17 };
18
19 struct config_option *rc = (struct config_option *)avl_search_lock(&(sect->values_index), (avl_t *) &opt_tmp);
20
21 inicfg_option_cleanup(&opt_tmp);
22 return rc;
23 }
24
25 // ----------------------------------------------------------------------------
26 // config options methods
27
28 void inicfg_option_cleanup(struct config_option *opt) {
29 string_freez(opt->value);
30 string_freez(opt->name);
31 string_freez(opt->migrated.section);
32 string_freez(opt->migrated.name);
33 string_freez(opt->value_original);
34 string_freez(opt->value_default);
35
36 opt->value = NULL;
37 opt->name = NULL;
38 opt->migrated.section = NULL;
39 opt->migrated.name = NULL;
40 opt->value_original = NULL;
41 opt->value_default = NULL;
42 }
43
44 void inicfg_option_free(struct config_option *opt) {
45 inicfg_option_cleanup(opt);
46 freez(opt);
47 }
48
49 NEVERNULL
50 struct config_option *inicfg_option_create(struct config_section *sect, const char *name, const char *value) {
51 struct config_option *opt = callocz(1, sizeof(struct config_option));
52 opt->name = string_strdupz(name);
53 opt->value = string_strdupz(value);
54 opt->value_original = string_dup(opt->value);
55
56 struct config_option *opt_found = inicfg_option_add(sect, opt);
57 if(opt_found != opt) {
58 nd_log(NDLS_DAEMON, NDLP_INFO,
59 "CONFIG: config '%s' in section '%s': already exists - using the existing one.",
60 string2str(opt->name), string2str(sect->name));
61 inicfg_option_free(opt);
62 return opt_found;
63 }
64
65 SECTION_LOCK(sect);
66 DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(sect->values, opt, prev, next);
67 SECTION_UNLOCK(sect);
68
69 return opt;
70 }
71
72 void inicfg_option_remove_and_delete(struct config_section *sect, struct config_option *opt, bool have_sect_lock) {
73 struct config_option *opt_found = inicfg_option_del(sect, opt);
74 if(opt_found != opt) {
75 nd_log(NDLS_DAEMON, NDLP_ERR,
76 "INTERNAL ERROR: Cannot remove '%s' from section '%s', it was not inserted before.",
77 string2str(opt->name), string2str(sect->name));
78 return;
79 }
80
81 if(!have_sect_lock)
82 SECTION_LOCK(sect);
83
84 DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(sect->values, opt, prev, next);
85
86 if(!have_sect_lock)
87 SECTION_UNLOCK(sect);
88
89 inicfg_option_free(opt);
90 }
91
92 void inicfg_option_remove_and_delete_all(struct config_section *sect, bool have_sect_lock) {
93 if(!have_sect_lock)
94 SECTION_LOCK(sect);
95
96 while(sect->values)
97 inicfg_option_remove_and_delete(sect, sect->values, true);
98
99 if(!have_sect_lock)
100 SECTION_UNLOCK(sect);
101 }
102
103 void inicfg_get_raw_value_of_option(struct config_option *opt, const char *default_value, CONFIG_VALUE_TYPES type, reformat_t cb) {
104 opt->flags |= CONFIG_VALUE_USED;
105
106 if(type != CONFIG_VALUE_TYPE_UNKNOWN)
107 opt->type = type;
108
109 if((opt->flags & CONFIG_VALUE_LOADED) || (opt->flags & CONFIG_VALUE_CHANGED)) {
110 // this is a loaded value from the config file
111 // if it is different from the default, mark it
112 if(!(opt->flags & CONFIG_VALUE_CHECKED)) {
113 if(!(opt->flags & CONFIG_VALUE_REFORMATTED) && cb) {
114 STRING *value_old = opt->value;
115 opt->value = cb(opt->value);
116 if(opt->value != value_old)
117 opt->flags |= CONFIG_VALUE_REFORMATTED;
118 }
119
120 if(default_value && string_strcmp(opt->value, default_value) != 0)
121 opt->flags |= CONFIG_VALUE_CHANGED;
122
123 opt->flags |= CONFIG_VALUE_CHECKED;
124 }
125 }
126
127 if(!(opt->flags & CONFIG_VALUE_DEFAULT_SET)) {
128 opt->flags |= CONFIG_VALUE_DEFAULT_SET;
129 opt->value_default = string_strdupz(default_value);
130 }
131 }
132
133 struct config_option *inicfg_get_raw_value_of_option_in_section(struct config_section *sect, const char *option, const char *default_value, CONFIG_VALUE_TYPES type, reformat_t cb) {
134 // Only calls internal to this file check for a NULL result, and they do not supply a NULL arg.
135 // External caller should treat NULL as an error case.
136 struct config_option *opt = inicfg_option_find(sect, option);
137 if (!opt) {
138 if (!default_value) return NULL;
139 opt = inicfg_option_create(sect, option, default_value);
140 }
141
142 inicfg_get_raw_value_of_option(opt, default_value, type, cb);
143 return opt;
144 }
145
146 struct config_option *inicfg_get_raw_value(struct config *root, const char *section, const char *option, const char *default_value, CONFIG_VALUE_TYPES type, reformat_t cb) {
147 struct config_section *sect = inicfg_section_find(root, section);
148 if(!sect) {
149 if(!default_value) return NULL;
150 sect = inicfg_section_create(root, section);
151 }
152
153 return inicfg_get_raw_value_of_option_in_section(sect, option, default_value, type, cb);
154 }
155
156 void inicfg_set_raw_value_of_option(struct config_option *opt, const char *value, CONFIG_VALUE_TYPES type) {
157 opt->flags |= CONFIG_VALUE_USED;
158
159 if(opt->type == CONFIG_VALUE_TYPE_UNKNOWN)
160 opt->type = type;
161
162 if(string_strcmp(opt->value, value) != 0) {
163 opt->flags |= CONFIG_VALUE_CHANGED;
164
165 string_freez(opt->value);
166 opt->value = string_strdupz(value);
167 }
168 }
169
170 struct config_option *inicfg_set_raw_value_of_option_in_section(struct config_section *sect, const char *option, const char *value, CONFIG_VALUE_TYPES type) {
171 struct config_option *opt = inicfg_option_find(sect, option);
172 if(!opt)
173 opt = inicfg_option_create(sect, option, value);
174
175 inicfg_set_raw_value_of_option(opt, value, type);
176 return opt;
177 }
178
179 struct config_option *inicfg_set_raw_value(struct config *root, const char *section, const char *option, const char *value, CONFIG_VALUE_TYPES type) {
180 struct config_section *sect = inicfg_section_find(root, section);
181 if(!sect)
182 sect = inicfg_section_create(root, section);
183
184 return inicfg_set_raw_value_of_option_in_section(sect, option, value, type);
185 }