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 : #include "types.h"
11 : #include "type.h"
12 :
13 : #include <ctype.h>
14 : #include <stdio.h>
15 : #include <stdlib.h>
16 : #include <string.h>
17 :
18 : #include <kdbhelper.h>
19 :
20 : #include <kdbease.h>
21 : #include <kdberrors.h>
22 :
23 : #define CHECK_TYPE(key, var, toValue) \
24 : { \
25 : if (strlen (keyString (key)) == 0 || toValue (key, &var) != 1) \
26 : { \
27 : return false; \
28 : } \
29 : }
30 :
31 : #define CHECK_TYPE_REVERSIBLE(key, var, toString) \
32 : { \
33 : char * string = toString (var); \
34 : if (strcmp (keyString (key), string) != 0) \
35 : { \
36 : elektraFree (string); \
37 : return false; \
38 : } \
39 : elektraFree (string); \
40 : }
41 :
42 0 : bool elektraTypeCheckAny (const Key * key ELEKTRA_UNUSED)
43 : {
44 0 : return true;
45 : }
46 :
47 1045 : bool elektraTypeCheckChar (const Key * key)
48 : {
49 1045 : return strlen (keyString (key)) == 1;
50 : }
51 :
52 :
53 131072 : bool elektraTypeCheckWChar (const Key * key)
54 : {
55 : wchar_t out[2];
56 131072 : return mbstowcs (out, keyString (key), 2) == 1;
57 : }
58 :
59 10 : bool elektraTypeCheckString (const Key * key)
60 : {
61 10 : return strlen (keyString (key)) != 0;
62 : }
63 :
64 10 : bool elektraTypeCheckWString (const Key * key)
65 : {
66 10 : const char * value = keyString (key);
67 10 : size_t max = strlen (value) + 1;
68 10 : wchar_t * wvalue = elektraCalloc (sizeof (wchar_t) * max);
69 10 : size_t result = mbstowcs (wvalue, value, max);
70 10 : elektraFree (wvalue);
71 10 : return result > 0 && result < max;
72 : }
73 :
74 260 : bool elektraTypeNormalizeBoolean (Plugin * handle, Key * key)
75 : {
76 260 : const char * value = keyString (key);
77 :
78 260 : TypeData * data = elektraPluginGetData (handle);
79 :
80 260 : const Key * trueOverride = keyGetMeta (key, "check/boolean/true");
81 260 : const Key * falseOverride = keyGetMeta (key, "check/boolean/false");
82 :
83 260 : if ((trueOverride == NULL) != (falseOverride == NULL))
84 : {
85 : return false;
86 : }
87 260 : else if (trueOverride != NULL)
88 : {
89 12 : if (strcasecmp (keyString (trueOverride), value) == 0 || strcmp ("1", value) == 0)
90 : {
91 12 : keySetString (key, "1");
92 12 : keySetMeta (key, "origvalue", keyString (trueOverride));
93 12 : return true;
94 : }
95 0 : else if (strcasecmp (keyString (falseOverride), value) == 0 || strcmp ("0", value) == 0)
96 : {
97 0 : keySetString (key, "0");
98 0 : keySetMeta (key, "origvalue", keyString (falseOverride));
99 0 : return true;
100 : }
101 : return false;
102 : }
103 :
104 : const char * origTrueValue;
105 : const char * origFalseValue;
106 :
107 248 : bool restore = data->booleanRestore >= 0;
108 :
109 248 : if (value[0] == '1' && value[1] == '\0')
110 : {
111 46 : if (restore)
112 : {
113 24 : keySetMeta (key, "origvalue", data->booleans[data->booleanRestore].trueValue);
114 : }
115 :
116 : return true;
117 : }
118 :
119 202 : if (value[0] == '0' && value[1] == '\0')
120 : {
121 42 : if (restore)
122 : {
123 24 : keySetMeta (key, "origvalue", data->booleans[data->booleanRestore].falseValue);
124 : }
125 :
126 : return true;
127 : }
128 :
129 160 : char * origValue = elektraStrDup (value);
130 :
131 160 : origTrueValue = restore ? data->booleans[data->booleanRestore].trueValue : origValue;
132 160 : origFalseValue = restore ? data->booleans[data->booleanRestore].falseValue : origValue;
133 :
134 386 : for (kdb_long_long_t i = 0; i < data->booleanCount; ++i)
135 : {
136 377 : if (strcasecmp (data->booleans[i].trueValue, value) == 0)
137 : {
138 73 : keySetString (key, "1");
139 73 : if (data->booleanRestore != -2)
140 : {
141 69 : keySetMeta (key, "origvalue", origTrueValue);
142 : }
143 73 : elektraFree (origValue);
144 73 : return true;
145 : }
146 304 : else if (strcasecmp (data->booleans[i].falseValue, value) == 0)
147 : {
148 78 : keySetString (key, "0");
149 78 : if (data->booleanRestore != -2)
150 : {
151 74 : keySetMeta (key, "origvalue", origFalseValue);
152 : }
153 78 : elektraFree (origValue);
154 78 : return true;
155 : }
156 : }
157 :
158 9 : elektraFree (origValue);
159 9 : return false;
160 : }
161 :
162 418 : bool elektraTypeCheckBoolean (const Key * key)
163 : {
164 418 : const char * value = keyString (key);
165 418 : return (value[0] == '1' || value[0] == '0') && value[1] == '\0';
166 : }
167 :
168 187 : bool elektraTypeRestoreBoolean (Plugin * handle ELEKTRA_UNUSED, Key * key)
169 : {
170 187 : const Key * orig = keyGetMeta (key, "origvalue");
171 187 : if (orig != NULL)
172 : {
173 164 : keySetString (key, keyString (orig));
174 : }
175 :
176 187 : return true;
177 : }
178 :
179 24 : bool elektraTypeCheckFloat (const Key * key)
180 : {
181 : kdb_float_t value;
182 24 : CHECK_TYPE (key, value, elektraKeyToFloat)
183 : return true;
184 : }
185 :
186 0 : bool elektraTypeCheckDouble (const Key * key)
187 : {
188 : kdb_double_t value;
189 0 : CHECK_TYPE (key, value, elektraKeyToDouble)
190 : return true;
191 : }
192 :
193 : #ifdef ELEKTRA_HAVE_KDB_LONG_DOUBLE
194 0 : bool elektraTypeCheckLongDouble (const Key * key)
195 : {
196 : kdb_long_double_t value;
197 0 : CHECK_TYPE (key, value, elektraKeyToLongDouble)
198 : return true;
199 : }
200 :
201 : #endif
202 :
203 27 : bool elektraTypeCheckShort (const Key * key)
204 : {
205 : kdb_short_t value;
206 27 : CHECK_TYPE (key, value, elektraKeyToShort)
207 12 : CHECK_TYPE_REVERSIBLE (key, value, elektraShortToString);
208 12 : return true;
209 : }
210 :
211 0 : bool elektraTypeCheckLong (const Key * key)
212 : {
213 : kdb_long_t value;
214 0 : CHECK_TYPE (key, value, elektraKeyToLong)
215 0 : CHECK_TYPE_REVERSIBLE (key, value, elektraLongToString);
216 0 : return true;
217 : }
218 :
219 0 : bool elektraTypeCheckLongLong (const Key * key)
220 : {
221 : kdb_long_long_t value;
222 0 : CHECK_TYPE (key, value, elektraKeyToLongLong)
223 0 : CHECK_TYPE_REVERSIBLE (key, value, elektraLongLongToString);
224 0 : return true;
225 : }
226 :
227 18 : bool elektraTypeCheckUnsignedShort (const Key * key)
228 : {
229 : kdb_unsigned_short_t value;
230 18 : CHECK_TYPE (key, value, elektraKeyToUnsignedShort)
231 6 : CHECK_TYPE_REVERSIBLE (key, value, elektraUnsignedShortToString);
232 6 : return true;
233 : }
234 :
235 0 : bool elektraTypeCheckUnsignedLong (const Key * key)
236 : {
237 : kdb_unsigned_long_t value;
238 0 : CHECK_TYPE (key, value, elektraKeyToUnsignedLong)
239 0 : CHECK_TYPE_REVERSIBLE (key, value, elektraUnsignedLongToString);
240 0 : return true;
241 : }
242 :
243 0 : bool elektraTypeCheckUnsignedLongLong (const Key * key)
244 : {
245 : kdb_unsigned_long_long_t value;
246 0 : CHECK_TYPE (key, value, elektraKeyToUnsignedLongLong)
247 0 : CHECK_TYPE_REVERSIBLE (key, value, elektraUnsignedLongLongToString);
248 0 : return true;
249 : }
250 :
251 111 : static bool enumValidValues (const Key * key, KeySet * validValues, char * delim)
252 : {
253 :
254 111 : const Key * maxKey = keyGetMeta (key, "check/enum");
255 111 : const char * max = maxKey == NULL ? NULL : keyString (maxKey);
256 :
257 111 : if (max == NULL)
258 : {
259 : return false;
260 : }
261 :
262 : char elem[sizeof ("check/enum/") + ELEKTRA_MAX_ARRAY_SIZE];
263 111 : strcpy (elem, "check/enum/");
264 111 : char * indexStart = elem + sizeof ("check/enum/") - 1;
265 :
266 111 : kdb_long_long_t index = 0;
267 111 : elektraWriteArrayNumber (indexStart, index);
268 535 : while (strcmp (indexStart, max) <= 0)
269 : {
270 313 : const Key * enumKey = keyGetMeta (key, elem);
271 313 : const char * name = enumKey != NULL ? keyString (enumKey) : "";
272 313 : if (strlen (name) > 0)
273 : {
274 303 : kdb_unsigned_long_long_t val = index;
275 303 : ksAppendKey (validValues, keyNew (name, KEY_META_NAME, KEY_BINARY, KEY_SIZE, sizeof (kdb_unsigned_long_long_t),
276 : KEY_VALUE, &val, KEY_END));
277 : }
278 :
279 313 : ++index;
280 313 : elektraWriteArrayNumber (indexStart, index);
281 : }
282 :
283 111 : const Key * multiEnum = keyGetMeta (key, "check/enum/delimiter");
284 111 : if (multiEnum != NULL)
285 : {
286 56 : const char * delimString = keyString (multiEnum);
287 :
288 56 : if (strlen (delimString) != 1)
289 : {
290 0 : ksDel (validValues);
291 0 : return false;
292 : }
293 56 : *delim = delimString[0];
294 : }
295 :
296 : return true;
297 : }
298 :
299 10 : static char * calculateStringValue (KeySet * validValues, char delimiter, kdb_unsigned_long_long_t value)
300 : {
301 10 : char * stringValue = elektraStrDup ("");
302 :
303 10 : ksRewind (validValues);
304 10 : Key * cur = NULL;
305 38 : while ((cur = ksNext (validValues)) != NULL)
306 : {
307 24 : const kdb_unsigned_long_long_t * val = keyValue (cur);
308 24 : if (delimiter == 0 && *val == value)
309 : {
310 4 : elektraFree (stringValue);
311 4 : return elektraStrDup (keyName (cur));
312 : }
313 20 : else if (delimiter != 0)
314 : {
315 18 : if (*val == 0 && value == 0 && stringValue[0] == '\0')
316 : {
317 2 : elektraFree (stringValue);
318 2 : return elektraStrDup (keyName (cur));
319 : }
320 16 : else if (*val != 0 && (*val & value) == *val)
321 : {
322 8 : char * tmp = stringValue[0] == '\0' ? elektraFormat ("%s", keyName (cur)) :
323 2 : elektraFormat ("%s%c%s", stringValue, delimiter, keyName (cur));
324 6 : elektraFree (stringValue);
325 6 : stringValue = tmp;
326 :
327 6 : value &= ~*val;
328 : }
329 : }
330 : }
331 :
332 : return stringValue;
333 : }
334 :
335 111 : bool elektraTypeNormalizeEnum (Plugin * handle ELEKTRA_UNUSED, Key * key)
336 : {
337 111 : const Key * normalize = keyGetMeta (key, "check/enum/normalize");
338 111 : if (normalize == NULL || strcmp (keyString (normalize), "1") != 0)
339 : {
340 : return true;
341 : }
342 :
343 52 : KeySet * validValues = ksNew (0, KS_END);
344 52 : char delim = 0;
345 52 : if (!enumValidValues (key, validValues, &delim))
346 : {
347 : return false;
348 : }
349 :
350 52 : char * values = elektraStrDup (keyString (key));
351 52 : char * value = values;
352 : char * next;
353 :
354 52 : if (isdigit (values[0]))
355 : {
356 10 : kdb_unsigned_long_long_t val = ELEKTRA_UNSIGNED_LONG_LONG_S (values, NULL, 10);
357 10 : char * origValue = calculateStringValue (validValues, delim, val);
358 10 : if (origValue == NULL)
359 : {
360 0 : ksDel (validValues);
361 0 : elektraFree (values);
362 0 : return false;
363 : }
364 :
365 10 : keySetMeta (key, "origvalue", origValue);
366 :
367 10 : elektraFree (origValue);
368 10 : ksDel (validValues);
369 10 : elektraFree (values);
370 10 : return true;
371 : }
372 :
373 42 : kdb_unsigned_long_long_t normalized = 0;
374 42 : if (delim != 0)
375 : {
376 48 : while ((next = strchr (value, delim)) != NULL)
377 : {
378 20 : *next = '\0';
379 20 : Key * cur = ksLookupByName (validValues, value, 0);
380 20 : if (cur == NULL)
381 : {
382 0 : ksDel (validValues);
383 0 : elektraFree (values);
384 0 : return false;
385 : }
386 :
387 20 : const kdb_unsigned_long_long_t * val = keyValue (cur);
388 20 : normalized |= *val;
389 20 : value = next + 1;
390 : }
391 : }
392 :
393 42 : Key * cur = ksLookupByName (validValues, value, 0);
394 42 : if (cur == NULL)
395 : {
396 0 : ksDel (validValues);
397 0 : elektraFree (values);
398 0 : return false;
399 : }
400 :
401 42 : const kdb_unsigned_long_long_t * val = keyValue (cur);
402 42 : normalized |= *val;
403 :
404 42 : ksDel (validValues);
405 42 : elektraFree (values);
406 :
407 42 : char * origValue = elektraStrDup (keyString (key));
408 42 : char * normValue = elektraFormat (ELEKTRA_UNSIGNED_LONG_LONG_F, normalized);
409 :
410 42 : keySetString (key, normValue);
411 42 : keySetMeta (key, "origvalue", origValue);
412 :
413 42 : elektraFree (origValue);
414 42 : elektraFree (normValue);
415 :
416 42 : return true;
417 : }
418 :
419 139 : bool elektraTypeCheckEnum (const Key * key)
420 : {
421 139 : const Key * normalize = keyGetMeta (key, "check/enum/normalize");
422 139 : if (normalize != NULL && strcmp (keyString (normalize), "1") == 0)
423 : {
424 : // was already implicitly checked during normalization
425 : return true;
426 : }
427 :
428 59 : const Key * maxKey = keyGetMeta (key, "check/enum");
429 59 : const char * max = maxKey == NULL ? NULL : keyString (maxKey);
430 :
431 59 : if (max == NULL)
432 : {
433 : return false;
434 : }
435 :
436 59 : KeySet * validValues = ksNew (0, KS_END);
437 59 : char delim = 0;
438 59 : if (!enumValidValues (key, validValues, &delim))
439 : {
440 : return false;
441 : }
442 :
443 59 : char * values = elektraStrDup (keyString (key));
444 59 : char * value = values;
445 : char * next;
446 :
447 59 : if (delim != 0)
448 : {
449 35 : while ((next = strchr (value, delim)) != NULL)
450 : {
451 14 : *next = '\0';
452 14 : if (ksLookupByName (validValues, value, 0) == NULL)
453 : {
454 1 : ksDel (validValues);
455 1 : elektraFree (values);
456 1 : return false;
457 : }
458 13 : value = next + 1;
459 : }
460 : }
461 :
462 58 : if (ksLookupByName (validValues, value, 0) == NULL)
463 : {
464 9 : ksDel (validValues);
465 9 : elektraFree (values);
466 9 : return false;
467 : }
468 :
469 :
470 49 : ksDel (validValues);
471 49 : elektraFree (values);
472 :
473 49 : return true;
474 : }
475 :
476 63 : bool elektraTypeRestoreEnum (Plugin * handle ELEKTRA_UNUSED, Key * key)
477 : {
478 63 : const Key * orig = keyGetMeta (key, "origvalue");
479 63 : if (orig != NULL)
480 : {
481 40 : keySetString (key, keyString (orig));
482 : }
483 :
484 63 : return true;
485 : }
486 :
487 10 : void elektraTypeSetErrorEnum (Plugin * handle ELEKTRA_UNUSED, Key * errorKey, const Key * key)
488 : {
489 10 : const Key * maxKey = keyGetMeta (key, "check/enum");
490 10 : const char * max = maxKey == NULL ? NULL : keyString (maxKey);
491 :
492 10 : if (max == NULL)
493 : {
494 0 : ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (
495 : errorKey,
496 : "The type 'enum' failed to match for '%s' with string: '%s'\n"
497 : "No values are allowed (check/enum is an empty array, or parent isn't set to last element)",
498 : keyName (key), keyString (key));
499 0 : return;
500 : }
501 :
502 10 : char * errorMessage = elektraFormat (
503 : "The type 'enum' failed to match for '%s' with string: '%s'\n"
504 : "Allowed values:",
505 : keyName (key), keyString (key));
506 :
507 : char elem[sizeof ("check/enum/") + ELEKTRA_MAX_ARRAY_SIZE];
508 10 : strcpy (elem, "check/enum/");
509 10 : char * indexStart = elem + sizeof ("check/enum/") - 1;
510 :
511 10 : kdb_long_long_t index = 0;
512 10 : elektraWriteArrayNumber (indexStart, index);
513 43 : while (strcmp (indexStart, max) <= 0)
514 : {
515 23 : const Key * enumKey = keyGetMeta (key, elem);
516 23 : const char * name = enumKey != NULL ? keyString (enumKey) : "";
517 23 : if (strlen (name) > 0)
518 : {
519 23 : char * newErrorMessage = elektraFormat ("%s '%s'", errorMessage, name);
520 23 : elektraFree (errorMessage);
521 23 : errorMessage = newErrorMessage;
522 : }
523 :
524 23 : ++index;
525 23 : elektraWriteArrayNumber (indexStart, index);
526 : }
527 :
528 10 : ELEKTRA_SET_VALIDATION_SEMANTIC_ERROR (errorKey, errorMessage);
529 10 : elektraFree (errorMessage);
530 : }
|