1c2d61de76f933699993b3808f4ff934efd40514
[strongswan.git] / src / libstrongswan / settings / settings_types.c
1 /*
2 * Copyright (C) 2010-2014 Tobias Brunner
3 * HSR Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "settings_types.h"
17
18 /*
19 * Described in header
20 */
21 kv_t *settings_kv_create(char *key, char *value)
22 {
23 kv_t *this;
24
25 INIT(this,
26 .key = key,
27 .value = value,
28 );
29 return this;
30 }
31
32 /*
33 * Described in header
34 */
35 void settings_kv_destroy(kv_t *this, array_t *contents)
36 {
37 free(this->key);
38 if (contents && this->value)
39 {
40 array_insert(contents, ARRAY_TAIL, this->value);
41 }
42 else
43 {
44 free(this->value);
45 }
46 free(this);
47 }
48
49 /*
50 * Described in header
51 */
52 section_t *settings_section_create(char *name)
53 {
54 section_t *this;
55
56 INIT(this,
57 .name = name,
58 );
59 return this;
60 }
61
62 static void section_destroy(section_t *section, int idx, array_t *contents)
63 {
64 settings_section_destroy(section, contents);
65 }
66
67 static void kv_destroy(kv_t *kv, int idx, array_t *contents)
68 {
69 settings_kv_destroy(kv, contents);
70 }
71
72 /*
73 * Described in header
74 */
75 void settings_section_destroy(section_t *this, array_t *contents)
76 {
77 array_destroy_function(this->sections, (void*)section_destroy, contents);
78 array_destroy(this->sections_order);
79 array_destroy_function(this->kv, (void*)kv_destroy, contents);
80 array_destroy(this->kv_order);
81 array_destroy(this->fallbacks);
82 free(this->name);
83 free(this);
84 }
85
86 /*
87 * Described in header
88 */
89 void settings_kv_set(kv_t *kv, char *value, array_t *contents)
90 {
91 if (value && kv->value && streq(value, kv->value))
92 { /* no update required */
93 free(value);
94 return;
95 }
96
97 /* if the new value was shorter we could overwrite the existing one but that
98 * could lead to reads of partially updated values from other threads that
99 * have a pointer to the existing value, so we replace it anyway */
100 if (kv->value && contents)
101 {
102 array_insert(contents, ARRAY_TAIL, kv->value);
103 }
104 else
105 {
106 free(kv->value);
107 }
108 kv->value = value;
109 }
110
111 /*
112 * Described in header
113 */
114 void settings_kv_add(section_t *section, kv_t *kv, array_t *contents)
115 {
116 kv_t *found;
117
118 if (array_bsearch(section->kv, kv->key, settings_kv_find, &found) == -1)
119 {
120 array_insert_create(&section->kv, ARRAY_TAIL, kv);
121 array_sort(section->kv, settings_kv_sort, NULL);
122 array_insert_create(&section->kv_order, ARRAY_TAIL, kv);
123 }
124 else
125 {
126 settings_kv_set(found, kv->value, contents);
127 kv->value = NULL;
128 settings_kv_destroy(kv, NULL);
129 }
130 }
131
132 /*
133 * Add a section to the given parent, optionally remove settings/subsections
134 * not found when extending an existing section
135 */
136 static void add_section(section_t *parent, section_t *section,
137 array_t *contents, bool purge)
138 {
139 section_t *found;
140
141 if (array_bsearch(parent->sections, section->name, settings_section_find,
142 &found) == -1)
143 {
144 array_insert_create(&parent->sections, ARRAY_TAIL, section);
145 array_sort(parent->sections, settings_section_sort, NULL);
146 array_insert_create(&parent->sections_order, ARRAY_TAIL, section);
147 }
148 else
149 {
150 settings_section_extend(found, section, contents, purge);
151 settings_section_destroy(section, contents);
152 }
153 }
154
155 /*
156 * Described in header
157 */
158 void settings_section_add(section_t *parent, section_t *section,
159 array_t *contents)
160 {
161 add_section(parent, section, contents, FALSE);
162 }
163
164 /**
165 * Purge contents of a section, returns TRUE if section can be safely removed.
166 */
167 static bool section_purge(section_t *this, array_t *contents)
168 {
169 section_t *current;
170 int i, idx;
171
172 array_destroy_function(this->kv, (void*)kv_destroy, contents);
173 this->kv = NULL;
174 array_destroy(this->kv_order);
175 this->kv_order = NULL;
176 /* we ensure sections used as fallback, or configured with fallbacks (or
177 * having any such subsections) are not removed */
178 for (i = array_count(this->sections_order) - 1; i >= 0; i--)
179 {
180 array_get(this->sections_order, i, &current);
181 if (section_purge(current, contents))
182 {
183 array_remove(this->sections_order, i, NULL);
184 idx = array_bsearch(this->sections, current->name,
185 settings_section_find, NULL);
186 array_remove(this->sections, idx, NULL);
187 settings_section_destroy(current, contents);
188 }
189 }
190 return !this->fallbacks && !array_count(this->sections);
191 }
192
193 /*
194 * Described in header
195 */
196 void settings_section_extend(section_t *base, section_t *extension,
197 array_t *contents, bool purge)
198 {
199 enumerator_t *enumerator;
200 section_t *section;
201 kv_t *kv;
202 array_t *sections = NULL, *kvs = NULL;
203 int idx;
204
205 if (purge)
206 { /* remove sections and settings in base not found in extension, the
207 * others are removed too (from the _order list) so they can be inserted
208 * in the order found in extension */
209 enumerator = array_create_enumerator(base->sections_order);
210 while (enumerator->enumerate(enumerator, (void**)&section))
211 {
212 if (array_bsearch(extension->sections, section->name,
213 settings_section_find, NULL) == -1)
214 {
215 idx = array_bsearch(base->sections, section->name,
216 settings_section_find, NULL);
217 if (section_purge(section, contents))
218 { /* only remove them if we can purge them */
219 array_remove(base->sections, idx, NULL);
220 array_remove_at(base->sections_order, enumerator);
221 settings_section_destroy(section, contents);
222 }
223 }
224 else
225 {
226 array_remove_at(base->sections_order, enumerator);
227 array_insert_create(&sections, ARRAY_TAIL, section);
228 array_sort(sections, settings_section_sort, NULL);
229 }
230 }
231 enumerator->destroy(enumerator);
232
233 while (array_remove(base->kv_order, 0, &kv))
234 {
235 if (array_bsearch(extension->kv, kv->key, settings_kv_find,
236 NULL) == -1)
237 {
238 idx = array_bsearch(base->kv, kv->key, settings_kv_find, NULL);
239 array_remove(base->kv, idx, NULL);
240 settings_kv_destroy(kv, contents);
241 }
242 else
243 {
244 array_insert_create(&kvs, ARRAY_TAIL, kv);
245 array_sort(kvs, settings_kv_sort, NULL);
246 }
247 }
248 }
249
250 while (array_remove(extension->sections_order, 0, &section))
251 {
252 idx = array_bsearch(sections, section->name,
253 settings_section_find, NULL);
254 if (idx != -1)
255 {
256 section_t *existing;
257
258 array_remove(sections, idx, &existing);
259 array_insert(base->sections_order, ARRAY_TAIL, existing);
260 }
261 idx = array_bsearch(extension->sections, section->name,
262 settings_section_find, NULL);
263 array_remove(extension->sections, idx, NULL);
264 add_section(base, section, contents, purge);
265 }
266
267 while (array_remove(extension->kv_order, 0, &kv))
268 {
269 idx = array_bsearch(kvs, kv->key, settings_kv_find, NULL);
270 if (idx != -1)
271 {
272 kv_t *existing;
273
274 array_remove(kvs, idx, &existing);
275 array_insert(base->kv_order, ARRAY_TAIL, existing);
276 }
277 idx = array_bsearch(extension->kv, kv->key, settings_kv_find, NULL);
278 array_remove(extension->kv, idx, NULL);
279 settings_kv_add(base, kv, contents);
280 }
281 array_destroy(sections);
282 array_destroy(kvs);
283 }
284
285 /*
286 * Described in header
287 */
288 int settings_section_find(const void *a, const void *b)
289 {
290 const char *key = a;
291 const section_t *item = b;
292 return strcmp(key, item->name);
293 }
294
295 /*
296 * Described in header
297 */
298 int settings_section_sort(const void *a, const void *b, void *user)
299 {
300 const section_t *sa = a, *sb = b;
301 return strcmp(sa->name, sb->name);
302 }
303
304 /*
305 * Described in header
306 */
307 int settings_kv_find(const void *a, const void *b)
308 {
309 const char *key = a;
310 const kv_t *item = b;
311 return strcmp(key, item->key);
312 }
313
314 /*
315 * Described in header
316 */
317 int settings_kv_sort(const void *a, const void *b, void *user)
318 {
319 const kv_t *kva = a, *kvb = b;
320 return strcmp(kva->key, kvb->key);
321 }