Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : *
8 : */
9 :
10 :
11 : #include "type.h"
12 : #include "types.h"
13 :
14 : #include <kdbease.h>
15 : #include <kdberrors.h>
16 :
17 : struct _Type
18 : {
19 : const char * name;
20 : bool (*normalize) (Plugin * handle, Key * key);
21 : bool (*check) (const Key * key);
22 : bool (*restore) (Plugin * handle, Key * key);
23 : void (*setError) (Plugin * handle, Key * errorKey, const Key * key);
24 : };
25 :
26 : static void elektraTypeSetDefaultError (Plugin * handle, Key * errorKey, const Key * key);
27 :
28 : static const Type elektraTypesList[] = {
29 : { "any", NULL, &elektraTypeCheckAny, NULL, &elektraTypeSetDefaultError },
30 : { "string", NULL, &elektraTypeCheckString, NULL, &elektraTypeSetDefaultError },
31 : { "wstring", NULL, &elektraTypeCheckWString, NULL, &elektraTypeSetDefaultError },
32 : { "char", NULL, &elektraTypeCheckChar, NULL, &elektraTypeSetDefaultError },
33 : { "wchar", NULL, &elektraTypeCheckWChar, NULL, &elektraTypeSetDefaultError },
34 : { "octet", NULL, &elektraTypeCheckChar, NULL, &elektraTypeSetDefaultError },
35 : { "short", NULL, &elektraTypeCheckShort, NULL, &elektraTypeSetDefaultError },
36 : { "long", NULL, &elektraTypeCheckLong, NULL, &elektraTypeSetDefaultError },
37 : { "long_long", NULL, &elektraTypeCheckLongLong, NULL, &elektraTypeSetDefaultError },
38 : { "unsigned_short", NULL, &elektraTypeCheckUnsignedShort, NULL, &elektraTypeSetDefaultError },
39 : { "unsigned_long", NULL, &elektraTypeCheckUnsignedLong, NULL, &elektraTypeSetDefaultError },
40 : { "unsigned_long_long", NULL, &elektraTypeCheckUnsignedLongLong, NULL, &elektraTypeSetDefaultError },
41 : { "float", NULL, &elektraTypeCheckFloat, NULL, &elektraTypeSetDefaultError },
42 : { "double", NULL, &elektraTypeCheckDouble, NULL, &elektraTypeSetDefaultError },
43 : #ifdef ELEKTRA_HAVE_KDB_LONG_DOUBLE
44 : { "long_double", NULL, &elektraTypeCheckLongDouble, NULL, &elektraTypeSetDefaultError },
45 : #endif
46 : { "boolean", &elektraTypeNormalizeBoolean, &elektraTypeCheckBoolean, &elektraTypeRestoreBoolean, &elektraTypeSetDefaultError },
47 : { "enum", &elektraTypeNormalizeEnum, &elektraTypeCheckEnum, &elektraTypeRestoreEnum, &elektraTypeSetErrorEnum },
48 : { NULL, NULL, NULL, NULL, NULL }
49 : };
50 :
51 : static const Type * findType (const char * name)
52 : {
53 : const Type * cur = &elektraTypesList[0];
54 670502 : while (cur->name != NULL)
55 : {
56 670502 : if (strcmp (cur->name, name) == 0)
57 : {
58 : return cur;
59 : }
60 537730 : ++cur;
61 : }
62 : return NULL;
63 : }
64 :
65 132884 : static const char * getTypeName (const Key * key)
66 : {
67 132884 : const Key * meta = keyGetMeta (key, "check/type");
68 132884 : if (meta == NULL)
69 : {
70 368 : meta = keyGetMeta (key, "type");
71 : }
72 :
73 132884 : if (meta == NULL)
74 : {
75 : return NULL;
76 : }
77 :
78 132776 : const char * type = keyString (meta);
79 132776 : return strlen (type) == 0 ? NULL : type;
80 : }
81 :
82 132208 : bool elektraTypeCheckType (const Key * key)
83 : {
84 132208 : const char * typeName = getTypeName (key);
85 132208 : if (typeName == NULL)
86 : {
87 : return true;
88 : }
89 :
90 132198 : const Type * type = findType (typeName);
91 132198 : return type != NULL && type->check (key);
92 : }
93 :
94 4 : static void elektraTypeSetDefaultError (Plugin * handle ELEKTRA_UNUSED, Key * errorKey, const Key * key)
95 : {
96 4 : ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (errorKey, "The type '%s' failed to match for '%s' with string '%s'", getTypeName (key),
97 : keyName (key), keyString (key));
98 4 : }
99 :
100 4 : bool elektraTypeValidateKey (Plugin * handle, Key * key, Key * errorKey)
101 : {
102 4 : const char * typeName = getTypeName (key);
103 4 : if (typeName == NULL)
104 : {
105 : return true;
106 : }
107 :
108 4 : const Type * type = findType (typeName);
109 4 : if (type == NULL)
110 : {
111 0 : ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (errorKey, "Unknown type '%s' for key '%s'", typeName, keyName (key));
112 0 : return false;
113 : }
114 :
115 4 : if (type->normalize != NULL && !type->normalize (handle, key))
116 : {
117 0 : ELEKTRA_SET_VALIDATION_SYNTACTIC_ERRORF (errorKey, "The value '%s' of key '%s' could not be normalized (type is '%s')",
118 : keyString (key), keyName (key), typeName);
119 0 : return false;
120 : }
121 :
122 4 : if (!type->check (key))
123 : {
124 2 : type->setError (handle, errorKey, key);
125 2 : return false;
126 : }
127 :
128 2 : if (type->restore != NULL && !type->restore (handle, key))
129 : {
130 0 : ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (errorKey,
131 : "The normalized value '%s' of key '%s' could not be restored (type is '%s')",
132 : keyString (key), keyName (key), typeName);
133 0 : return false;
134 : }
135 :
136 : return true;
137 : }
138 :
139 701 : static kdb_long_long_t readBooleans (KeySet * config, struct boolean_pair ** result, Key * errorKey)
140 : {
141 701 : Key * parent = ksLookupByName (config, "/booleans", 0);
142 701 : const char * max = keyString (parent);
143 701 : if (parent == NULL || strlen (max) == 0)
144 : {
145 687 : *result = NULL;
146 687 : return -1;
147 : }
148 :
149 14 : kdb_long_long_t index = 0;
150 : char buffer[10 + ELEKTRA_MAX_ARRAY_SIZE + 6];
151 14 : strcpy (buffer, "/booleans/");
152 14 : char * indexPos = &buffer[10];
153 14 : elektraWriteArrayNumber (indexPos, index);
154 :
155 14 : if (strcmp (indexPos, max) > 0)
156 : {
157 0 : *result = NULL;
158 0 : return 0;
159 : }
160 :
161 14 : kdb_long_long_t size = 0;
162 14 : *result = elektraMalloc (sizeof (struct boolean_pair));
163 56 : while (strcmp (indexPos, max) <= 0)
164 : {
165 30 : char * subPos = &buffer[strlen (buffer)];
166 30 : strcpy (subPos, "/true");
167 30 : Key * trueKey = ksLookupByName (config, buffer, 0);
168 30 : strcpy (subPos, "/false");
169 30 : Key * falseKey = ksLookupByName (config, buffer, 0);
170 :
171 30 : *subPos = '\0';
172 30 : if ((trueKey == NULL) != (falseKey == NULL))
173 : {
174 2 : ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (
175 : errorKey, "You must set both true and false for a boolean pair (config key: '%s')", buffer);
176 2 : elektraFree (*result);
177 2 : *result = NULL;
178 2 : return -2;
179 : }
180 :
181 :
182 28 : elektraRealloc ((void **) result, (size + 1) * sizeof (struct boolean_pair));
183 :
184 28 : (*result)[size].trueValue = keyString (trueKey);
185 28 : (*result)[size].falseValue = keyString (falseKey);
186 28 : ++size;
187 :
188 28 : ++index;
189 28 : elektraWriteArrayNumber (indexPos, index);
190 : }
191 :
192 : return size;
193 : }
194 :
195 : /**
196 : * Reads the value of the config key /boolean/restoreas.
197 : *
198 : * @p config The config KeySet obtained from elektraPluginGetConfig().
199 : *
200 : * @retval -3 on error
201 : * @retval -2 if /boolean/restoreas = none
202 : * @retval -1 if /boolean/restoreas is unset
203 : * @retval >= 0 index of chosen boolean pair
204 : */
205 686 : static kdb_long_long_t readBooleanRestore (KeySet * config)
206 : {
207 686 : Key * restore = ksLookupByName (config, "/boolean/restoreas", 0);
208 686 : if (restore == NULL)
209 : {
210 : return -1;
211 : }
212 :
213 32 : const char * restoreString = keyString (restore);
214 :
215 32 : if (strcmp (restoreString, "none") == 0)
216 : {
217 : return -2;
218 : }
219 :
220 28 : int digitStart = elektraArrayValidateBaseNameString (restoreString);
221 28 : if (digitStart <= 0)
222 : {
223 : return -3;
224 : }
225 :
226 28 : Key * restoreKey = keyNew ("", KEY_VALUE, &restoreString[digitStart], KEY_END);
227 :
228 : kdb_long_long_t size;
229 28 : if (!elektraKeyToLongLong (restoreKey, &size))
230 : {
231 0 : keyDel (restoreKey);
232 0 : return -3;
233 : }
234 :
235 28 : keyDel (restoreKey);
236 :
237 28 : return size;
238 : }
239 :
240 688 : int elektraTypeOpen (Plugin * handle, Key * errorKey)
241 : {
242 688 : KeySet * conf = elektraPluginGetConfig (handle);
243 688 : TypeData * data = elektraMalloc (sizeof (TypeData));
244 :
245 688 : kdb_long_long_t result = readBooleans (conf, &data->booleans, errorKey);
246 688 : if (result < -1)
247 : {
248 2 : elektraFree (data);
249 2 : return ELEKTRA_PLUGIN_STATUS_ERROR;
250 : }
251 :
252 686 : if (result == -1)
253 : {
254 674 : data->booleans = elektraMalloc (sizeof (struct boolean_pair) * 5);
255 674 : data->booleans[0] = (struct boolean_pair){ "yes", "no" };
256 674 : data->booleans[1] = (struct boolean_pair){ "true", "false" };
257 674 : data->booleans[2] = (struct boolean_pair){ "on", "off" };
258 674 : data->booleans[3] = (struct boolean_pair){ "enabled", "disabled" };
259 674 : data->booleans[4] = (struct boolean_pair){ "enable", "disable" };
260 674 : data->booleanCount = 5;
261 : }
262 : else
263 : {
264 12 : data->booleanCount = result;
265 : }
266 :
267 686 : data->booleanRestore = readBooleanRestore (conf);
268 686 : if (data->booleanRestore < -2 || data->booleanRestore >= data->booleanCount)
269 : {
270 0 : ELEKTRA_SET_VALIDATION_SEMANTIC_ERROR (errorKey, "The value of the config key /boolean/restoreas was invalid");
271 0 : elektraFree (data);
272 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
273 : }
274 :
275 686 : elektraPluginSetData (handle, data);
276 :
277 686 : return ELEKTRA_PLUGIN_STATUS_SUCCESS;
278 : }
279 :
280 474 : int elektraTypeGet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned, Key * parentKey)
281 : {
282 474 : if (!elektraStrCmp (keyName (parentKey), "system/elektra/modules/type"))
283 : {
284 162 : KeySet * contract =
285 162 : ksNew (30, keyNew ("system/elektra/modules/type", KEY_VALUE, "type plugin waits for your orders", KEY_END),
286 : keyNew ("system/elektra/modules/type/exports", KEY_END),
287 : keyNew ("system/elektra/modules/type/exports/open", KEY_FUNC, elektraTypeOpen, KEY_END),
288 : keyNew ("system/elektra/modules/type/exports/get", KEY_FUNC, elektraTypeGet, KEY_END),
289 : keyNew ("system/elektra/modules/type/exports/set", KEY_FUNC, elektraTypeSet, KEY_END),
290 : keyNew ("system/elektra/modules/type/exports/close", KEY_FUNC, elektraTypeClose, KEY_END),
291 : keyNew ("system/elektra/modules/type/exports/checkconf", KEY_FUNC, elektraTypeCheckConf, KEY_END),
292 : keyNew ("system/elektra/modules/type/exports/validateKey", KEY_FUNC, elektraTypeValidateKey, KEY_END),
293 : #include ELEKTRA_README
294 : keyNew ("system/elektra/modules/type/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END);
295 162 : ksAppend (returned, contract);
296 162 : ksDel (contract);
297 :
298 162 : return ELEKTRA_PLUGIN_STATUS_SUCCESS;
299 : }
300 :
301 312 : cursor_t cursor = ksGetCursor (returned);
302 :
303 312 : ksRewind (returned);
304 :
305 312 : Key * cur = NULL;
306 996 : while ((cur = ksNext (returned)))
307 : {
308 380 : const char * typeName = getTypeName (cur);
309 380 : if (typeName == NULL)
310 : {
311 76 : continue;
312 : }
313 :
314 304 : const Type * type = findType (typeName);
315 304 : if (type == NULL)
316 : {
317 0 : ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (parentKey, "Unknown type '%s' for key '%s'", typeName, keyName (cur));
318 0 : ksSetCursor (returned, cursor);
319 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
320 : }
321 :
322 304 : if (type->normalize != NULL)
323 : {
324 295 : const Key * orig = keyGetMeta (cur, "origvalue");
325 295 : if (orig != NULL)
326 : {
327 0 : ELEKTRA_SET_INSTALLATION_ERRORF (
328 : parentKey,
329 : "The key '%s' was already normalized by a different plugin. Please ensure that there is "
330 : "only one plugin active that will normalize this key",
331 : keyName (cur));
332 0 : ksSetCursor (returned, cursor);
333 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
334 : }
335 :
336 295 : if (!type->normalize (handle, cur))
337 : {
338 4 : ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (parentKey,
339 : "The value '%s' of key '%s' could not be normalized (type is '%s')",
340 : keyString (cur), keyName (cur), typeName);
341 4 : ksSetCursor (returned, cursor);
342 4 : return ELEKTRA_PLUGIN_STATUS_ERROR;
343 : }
344 : }
345 :
346 300 : if (!type->check (cur))
347 : {
348 4 : type->setError (handle, parentKey, cur);
349 4 : ksSetCursor (returned, cursor);
350 4 : return ELEKTRA_PLUGIN_STATUS_ERROR;
351 : }
352 : }
353 :
354 304 : ksSetCursor (returned, cursor);
355 :
356 304 : return ELEKTRA_PLUGIN_STATUS_SUCCESS;
357 : }
358 :
359 200 : int elektraTypeSet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned, Key * parentKey)
360 : {
361 200 : cursor_t cursor = ksGetCursor (returned);
362 :
363 200 : ksRewind (returned);
364 :
365 200 : Key * cur = NULL;
366 675 : while ((cur = ksNext (returned)))
367 : {
368 288 : const char * typeName = getTypeName (cur);
369 288 : if (typeName == NULL)
370 : {
371 22 : continue;
372 : }
373 :
374 266 : const Type * type = findType (typeName);
375 266 : if (type == NULL)
376 : {
377 0 : ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (parentKey, "Unknown type '%s' for key '%s'", typeName, keyName (cur));
378 0 : ksSetCursor (returned, cursor);
379 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
380 : }
381 :
382 266 : if (type->normalize != NULL)
383 : {
384 261 : const Key * orig = keyGetMeta (cur, "origvalue");
385 : // skip normalization origvalue already set
386 261 : if (orig == NULL && !type->normalize (handle, cur))
387 : {
388 5 : ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (parentKey,
389 : "The value '%s' of key '%s' could not be normalized (type is '%s')",
390 : keyString (cur), keyName (cur), typeName);
391 5 : ksSetCursor (returned, cursor);
392 5 : return ELEKTRA_PLUGIN_STATUS_ERROR;
393 : }
394 : }
395 :
396 261 : if (!type->check (cur))
397 : {
398 8 : type->setError (handle, parentKey, cur);
399 8 : ksSetCursor (returned, cursor);
400 8 : return ELEKTRA_PLUGIN_STATUS_ERROR;
401 : }
402 :
403 253 : if (type->restore != NULL && !type->restore (handle, cur))
404 : {
405 0 : ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (
406 : parentKey, "The normalized value '%s' of key '%s' could not be restored (type is '%s')", keyString (cur),
407 : keyName (cur), typeName);
408 0 : ksSetCursor (returned, cursor);
409 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
410 : }
411 : }
412 :
413 187 : ksSetCursor (returned, cursor);
414 :
415 187 : return ELEKTRA_PLUGIN_STATUS_SUCCESS;
416 : }
417 :
418 :
419 688 : int elektraTypeClose (Plugin * handle, Key * errorKey ELEKTRA_UNUSED)
420 : {
421 688 : TypeData * data = elektraPluginGetData (handle);
422 688 : if (data != NULL)
423 : {
424 686 : if (data->booleans != NULL)
425 : {
426 686 : elektraFree (data->booleans);
427 : }
428 686 : elektraFree (data);
429 : }
430 688 : elektraPluginSetData (handle, NULL);
431 688 : return ELEKTRA_PLUGIN_STATUS_SUCCESS;
432 : }
433 :
434 13 : int elektraTypeCheckConf (Key * errorKey, KeySet * conf)
435 : {
436 : struct boolean_pair * pairs;
437 13 : if (readBooleans (conf, &pairs, errorKey) < -1)
438 : {
439 : return ELEKTRA_PLUGIN_STATUS_ERROR;
440 : }
441 13 : elektraFree (pairs);
442 13 : return ELEKTRA_PLUGIN_STATUS_SUCCESS;
443 : }
444 :
445 688 : Plugin * ELEKTRA_PLUGIN_EXPORT
446 : {
447 : // clang-format off
448 688 : return elektraPluginExport("type",
449 : ELEKTRA_PLUGIN_OPEN, &elektraTypeOpen,
450 : ELEKTRA_PLUGIN_GET, &elektraTypeGet,
451 : ELEKTRA_PLUGIN_SET, &elektraTypeSet,
452 : ELEKTRA_PLUGIN_CLOSE, &elektraTypeClose,
453 : ELEKTRA_PLUGIN_END);
454 : // clang-format on
455 : }
|