Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief Methods for key sets.
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : */
8 :
9 : #ifdef HAVE_KDBCONFIG_H
10 : #include "kdbconfig.h"
11 : #endif
12 :
13 : #if defined(HAVE_STDIO_H)
14 : #include <stdio.h>
15 : #endif
16 :
17 : #ifdef HAVE_STDLIB_H
18 : #include <stdlib.h>
19 : #endif
20 :
21 : #ifdef HAVE_STDARG_H
22 : #include <stdarg.h>
23 : #endif
24 :
25 : #ifdef HAVE_STRING_H
26 : #include <string.h>
27 : #endif
28 :
29 : #include <kdbtypes.h>
30 :
31 : #include "kdbinternal.h"
32 : #include <kdbassert.h>
33 : #include <kdbrand.h>
34 :
35 :
36 : #define ELEKTRA_MAX_PREFIX_SIZE sizeof ("namespace/")
37 : #define ELEKTRA_MAX_NAMESPACE_SIZE sizeof ("system")
38 :
39 : /**
40 : * @internal
41 : *
42 : * @brief KeySets OPMPHM cleaner.
43 : *
44 : * Must be invoked by every function that changes a Key name in a KeySet, adds a Key or
45 : * removes a Key.
46 : * Set also the KS_FLAG_NAME_CHANGE KeySet flag.
47 : *
48 : * @param ks the KeySet
49 : */
50 : static void elektraOpmphmInvalidate (KeySet * ks ELEKTRA_UNUSED)
51 : {
52 : #ifdef ELEKTRA_ENABLE_OPTIMIZATIONS
53 20926372 : set_bit (ks->flags, KS_FLAG_NAME_CHANGE);
54 18118988 : if (ks && ks->opmphm) opmphmClear (ks->opmphm);
55 : #endif
56 : }
57 :
58 : /**
59 : * @internal
60 : *
61 : * @brief KeySets OPMPHM and OPMPHM predictor copy.
62 : *
63 : * Should be invoked by every function making a copy of a KeySet.
64 : *
65 : * @param dest the destination KeySet
66 : * @param source the source KeySet
67 : */
68 992745 : static void elektraOpmphmCopy (KeySet * dest ELEKTRA_UNUSED, const KeySet * source ELEKTRA_UNUSED)
69 : {
70 : #ifdef ELEKTRA_ENABLE_OPTIMIZATIONS
71 992745 : if (!source || !dest)
72 : {
73 : return;
74 : }
75 : // nothing to copy
76 : // OPMPHM predictor
77 992745 : if (source->opmphmPredictor)
78 : {
79 6 : if (!dest->opmphmPredictor)
80 : {
81 6 : dest->opmphmPredictor = opmphmPredictorNew ();
82 : }
83 6 : if (dest->opmphmPredictor)
84 : {
85 6 : opmphmPredictorCopy (dest->opmphmPredictor, source->opmphmPredictor);
86 : }
87 : }
88 992745 : if (!opmphmIsBuild (source->opmphm))
89 : {
90 : return;
91 : }
92 : // OPMPHM
93 12 : if (!dest->opmphm)
94 : {
95 12 : dest->opmphm = opmphmNew ();
96 : }
97 12 : if (dest->opmphm)
98 : {
99 12 : opmphmCopy (dest->opmphm, source->opmphm);
100 : }
101 : #endif
102 : }
103 :
104 : /** @class doxygenFlatCopy
105 : *
106 : * @brief .
107 : *
108 : * @note Because the key is not copied,
109 : * also the pointer to the current metadata keyNextMeta()
110 : * will be shared.
111 : */
112 :
113 : /**
114 : * @defgroup keyset KeySet
115 : * @brief Methods to manipulate KeySets.
116 : *
117 : * A KeySet is a set of keys.
118 : *
119 : * Most important properties of a KeySet:
120 : *
121 : * - Allows us to iterate over all keys (in any depth)
122 : * - Iteration is always sorted
123 : * - Fast key lookup
124 : * - A Key may be shared among many KeySets.
125 : *
126 : * The most important methods of KeySet:
127 : *
128 : * - With ksNew() you can create a new KeySet.
129 : * - You can append keys with ksAppendKey() or
130 : * with ksAppend() you can append a whole keyset.
131 : * - Using ksLookup() you can lookup (or pop with #KDB_O_POP) a key.
132 : * - With ksRewind() and ksNext() you can iterate through the keyset.
133 : * Be assured that you will get every key of the set in a stable
134 : * order (parents before children).
135 : *
136 : * @copydetails doxygenFlatCopy
137 : *
138 : * KeySets have an @link ksCurrent() internal cursor @endlink.
139 : * Methods should avoid to change this cursor, unless they want
140 : * to communicate something with it.
141 : * The internal cursor is used:
142 : *
143 : * - in ksLookup(): points to the found key
144 : * - in kdbSet(): points to the key which caused an error
145 : *
146 : * KeySet is the most important data structure in Elektra. It makes it possible
147 : * to get and store many keys at once inside the database. In addition to
148 : * that, the class can be used as high level datastructure in applications
149 : * and it can be used in plugins to manipulate or check configuration.
150 : *
151 : * With ksLookupByName() it is possible to fetch easily specific keys
152 : * out of the list of keys.
153 : *
154 : * You can easily create and iterate keys:
155 : *
156 : * @snippet ksNewExample.c Full Example
157 : *
158 : * @{
159 : */
160 :
161 :
162 : /**
163 : * Allocate, initialize and return a new KeySet object.
164 : *
165 : * Objects created with ksNew() must be destroyed with ksDel().
166 : *
167 : * You can use an arbitrary long list of parameters to preload the keyset
168 : * with a list of keys. Either your first and only parameter is 0 or
169 : * your last parameter must be KEY_END.
170 : *
171 : * So, terminate with ksNew(0, KS_END) or ksNew(20, ..., KS_END)
172 : *
173 : * @warning Never use ksNew(0, keyNew(...), KS_END).
174 : * If the first parameter is 0, other arguments are ignored.
175 : *
176 : * For most uses
177 : *
178 : * @snippet ksNew.c Simple
179 : *
180 : * will be fine, the alloc size will be 16, defined in kdbprivate.h.
181 : * The alloc size will be doubled whenever size reaches alloc size,
182 : * so it also performs well with large keysets.
183 : *
184 : * But if you have any clue how large your keyset may be you should
185 : * read the next statements.
186 : *
187 : * If you want a keyset with length 15 (because you know of your
188 : * application that you only need up to 15 keys), use:
189 : *
190 : * @snippet ksNew.c Length 15
191 : *
192 : * If you start having 3 keys, and your application needs approximately
193 : * 200 up to 500 keys, you can use:
194 : *
195 : * @snippet ksNew.c Hint 500
196 : *
197 : * Alloc size is 500, the size of the keyset will be 3 after ksNew.
198 : * This means the keyset will reallocate when appending more than
199 : * 497 keys.
200 : *
201 : * The main benefit of taking a list of variant length parameters is to be able
202 : * to have one C-Statement for any possible KeySet.
203 : * If you prefer, you can always create an empty KeySet and use ksAppendKey().
204 : *
205 : * @post the keyset is rewinded properly
206 : *
207 : * @see ksDel() to free the keyset afterwards
208 : * @see ksDup() to duplicate an existing keyset
209 : * @see ksAppendKey() to append individual keys
210 : * @param alloc gives a hint for the size how many Keys may be stored initially
211 : * @return a ready to use KeySet object
212 : * @retval 0 on memory error
213 : */
214 2802940 : KeySet * ksNew (size_t alloc, ...)
215 : {
216 : KeySet * ks;
217 : va_list va;
218 :
219 2802940 : va_start (va, alloc);
220 2802940 : ks = ksVNew (alloc, va);
221 2802940 : va_end (va);
222 :
223 2802940 : return ks;
224 : }
225 :
226 : /**
227 : * @copydoc ksNew
228 : *
229 : * @pre caller must call va_start and va_end
230 : * @par va the list of arguments
231 : * @param alloc the allocation size
232 : * @param va the list of variable arguments
233 : **/
234 2807384 : KeySet * ksVNew (size_t alloc, va_list va)
235 : {
236 2807384 : KeySet * keyset = 0;
237 :
238 2807384 : keyset = (KeySet *) elektraMalloc (sizeof (KeySet));
239 2807384 : if (!keyset)
240 : {
241 : /*errno = KDB_ERR_NOMEM;*/
242 : return 0;
243 : }
244 2807384 : ksInit (keyset);
245 :
246 2807384 : alloc++; /* for ending null byte */
247 2807384 : if (alloc < KEYSET_SIZE)
248 1758313 : keyset->alloc = KEYSET_SIZE;
249 : else
250 1049071 : keyset->alloc = alloc;
251 :
252 2807384 : keyset->array = elektraMalloc (sizeof (struct _Key *) * keyset->alloc);
253 2807384 : if (!keyset->array)
254 : {
255 : /*errno = KDB_ERR_NOMEM;*/
256 : return 0;
257 : }
258 2807384 : keyset->array[0] = 0;
259 :
260 2807384 : if (alloc != 1) // is >0 because of increment earlier
261 : {
262 1412989 : Key * key = (struct _Key *) va_arg (va, struct _Key *);
263 3611224 : while (key)
264 : {
265 785246 : ksAppendKey (keyset, key);
266 785246 : key = (struct _Key *) va_arg (va, struct _Key *);
267 : }
268 : }
269 :
270 2807384 : ksRewind (keyset); // ksAppendKey changed the internal cursor
271 :
272 2807384 : return keyset;
273 : }
274 :
275 : /**
276 : * Return a duplicate of a keyset.
277 : *
278 : * Objects created with ksDup() must be destroyed with ksDel().
279 : *
280 : * Memory will be allocated as needed for dynamic properties,
281 : * so you need to ksDel() the returned pointer.
282 : *
283 : * A flat copy is made, so the keys will not be duplicated,
284 : * but there reference counter is updated, so both keysets
285 : * need ksDel().
286 : *
287 : * @param source has to be an initialized source KeySet
288 : * @return a flat copy of source on success
289 : * @retval 0 on NULL pointer
290 : * @see ksNew(), ksDel()
291 : * @see keyDup() for key duplication
292 : */
293 989455 : KeySet * ksDup (const KeySet * source)
294 : {
295 989455 : if (!source) return 0;
296 :
297 989355 : size_t size = source->alloc;
298 989355 : if (size < KEYSET_SIZE)
299 : {
300 0 : size = KEYSET_SIZE;
301 : }
302 :
303 989355 : KeySet * keyset = ksNew (size, KS_END);
304 989355 : ksAppend (keyset, source);
305 989355 : elektraOpmphmCopy (keyset, source);
306 989355 : return keyset;
307 : }
308 :
309 : /**
310 : * @internal
311 : * @brief Deeply copies from source to dest.
312 : *
313 : * The keyset as well as its containing keys are duplicated.
314 : * This means that you have to keyDel() the contained keys and
315 : * ksDel() the returned keyset..
316 : *
317 : * the sync status will be as in the original KeySet
318 : *
319 : * @param source has to be an initialized source KeySet
320 : * @return a deep copy of source on success
321 : * @retval 0 on NULL pointer or a memory error happened
322 : * @see ksNew(), ksDel()
323 : * @see keyDup() for key duplication
324 : * @see ksDup() for flat copy
325 : */
326 2710 : KeySet * ksDeepDup (const KeySet * source)
327 : {
328 2710 : if (!source) return 0;
329 :
330 2710 : size_t s = source->size;
331 2710 : size_t i = 0;
332 2710 : KeySet * keyset = 0;
333 :
334 2710 : keyset = ksNew (source->alloc, KS_END);
335 163679 : for (i = 0; i < s; ++i)
336 : {
337 160969 : Key * k = source->array[i];
338 160969 : Key * d = keyDup (k);
339 160969 : if (!test_bit (k->flags, KEY_FLAG_SYNC))
340 : {
341 148821 : keyClearSync (d);
342 : }
343 160969 : if (ksAppendKey (keyset, d) == -1)
344 : {
345 0 : ksDel (keyset);
346 0 : return 0;
347 : }
348 : }
349 :
350 2710 : elektraOpmphmCopy (keyset, source);
351 2710 : return keyset;
352 : }
353 :
354 :
355 : /**
356 : * Replace the content of a keyset with another one.
357 : *
358 : * Most often you may want a duplicate of a keyset, see
359 : * ksDup() or append keys, see ksAppend().
360 : * But in some situations you need to copy a
361 : * keyset to an existing keyset, for that this function
362 : * exists.
363 : *
364 : * @note You can also use it to clear a keyset when you pass
365 : * a NULL pointer as @p source.
366 : *
367 : * @par Implementation:
368 : * First all keys in @p dest will be deleted. Afterwards
369 : * the content of the source will be added to the destination
370 : * and the ksCurrent() is set properly in @p dest.
371 : *
372 : * A flat copy is made, so the keys will not be duplicated,
373 : * but there reference counter is updated, so both keysets
374 : * need to be ksDel().
375 : *
376 : * @copydetails doxygenFlatCopy
377 : *
378 : * @code
379 : int f (KeySet *ks)
380 : {
381 : KeySet *c = ksNew (20, ..., KS_END);
382 : // c receives keys
383 : ksCopy (ks, c); // pass the keyset to the caller
384 :
385 : ksDel (c);
386 : } // caller needs to ksDel (ks)
387 : * @endcode
388 : *
389 : * @param source has to be an initialized source KeySet or NULL
390 : * @param dest has to be an initialized KeySet where to write the keys
391 : * @retval 1 on success
392 : * @retval 0 if dest was cleared successfully (source is NULL)
393 : * @retval -1 on NULL pointer
394 : * @see ksNew(), ksDel(), ksDup()
395 : * @see keyCopy() for copying keys
396 : */
397 10469 : int ksCopy (KeySet * dest, const KeySet * source)
398 : {
399 10469 : if (!dest) return -1;
400 10469 : ksClear (dest);
401 10469 : if (!source) return 0;
402 :
403 680 : ksAppend (dest, source);
404 680 : ksSetCursor (dest, ksGetCursor (source));
405 :
406 680 : elektraOpmphmCopy (dest, source);
407 680 : return 1;
408 : }
409 :
410 :
411 : /**
412 : * A destructor for KeySet objects.
413 : *
414 : * Cleans all internal dynamic attributes, decrement all reference pointers
415 : * to all keys and then keyDel() all contained Keys,
416 : * and elektraFree ()s the release the KeySet object memory (that was previously
417 : * allocated by ksNew()).
418 : *
419 : * @param ks the keyset object to work with
420 : * @retval 0 when the keyset was freed
421 : * @retval -1 on null pointer
422 : * @see ksNew()
423 : */
424 4513579 : int ksDel (KeySet * ks)
425 : {
426 : int rc;
427 :
428 4513579 : if (!ks) return -1;
429 :
430 2807636 : rc = ksClose (ks);
431 :
432 : #ifdef ELEKTRA_ENABLE_OPTIMIZATIONS
433 2807636 : if (ks->opmphm)
434 : {
435 40 : opmphmDel (ks->opmphm);
436 : }
437 2807636 : if (ks->opmphmPredictor)
438 : {
439 10 : opmphmPredictorDel (ks->opmphmPredictor);
440 : }
441 :
442 : #endif
443 :
444 2807636 : if (!test_bit (ks->flags, KS_FLAG_MMAP_STRUCT))
445 : {
446 2807308 : elektraFree (ks);
447 : }
448 :
449 : return rc;
450 : }
451 :
452 : /**
453 : * @internal
454 : *
455 : * KeySet object cleaner.
456 : *
457 : * Will keyDel() all contained keys, reset internal pointers and counters.
458 : *
459 : * After this call you can use the empty keyset again.
460 : *
461 : * @param ks the keyset object to work with
462 : * @see ksAppendKey() for details on how keys are inserted in KeySets
463 : * @retval 0 on success
464 : * @retval -1 on failure (memory)
465 : */
466 64663 : int ksClear (KeySet * ks)
467 : {
468 64663 : ksClose (ks);
469 : // ks->array empty now
470 :
471 64663 : if ((ks->array = elektraMalloc (sizeof (struct _Key *) * KEYSET_SIZE)) == 0)
472 : {
473 : /*errno = KDB_ERR_NOMEM;*/
474 0 : ks->size = 0;
475 0 : return -1;
476 : }
477 64663 : ks->alloc = KEYSET_SIZE;
478 :
479 : elektraOpmphmInvalidate (ks);
480 : return 0;
481 : }
482 :
483 :
484 : /**
485 : * @brief Compare by unescaped name only (not by owner, they are equal)
486 : *
487 : * @internal
488 : *
489 : * Other non-case Cmp* are based on this one.
490 : *
491 : * Is suitable for binary search (but may return wrong owner)
492 : *
493 : */
494 38556115 : static int keyCompareByName (const void * p1, const void * p2)
495 : {
496 38556115 : Key * key1 = *(Key **) p1;
497 38556115 : Key * key2 = *(Key **) p2;
498 38556115 : const void * name1 = key1->key + key1->keySize;
499 38556115 : const void * name2 = key2->key + key2->keySize;
500 38556115 : size_t const nameSize1 = key1->keyUSize;
501 38556115 : size_t const nameSize2 = key2->keyUSize;
502 38556115 : int ret = 0;
503 38556115 : if (nameSize1 == nameSize2)
504 : {
505 8288830 : ret = memcmp (name1, name2, nameSize2);
506 : }
507 : else
508 : {
509 30267285 : if (nameSize1 < nameSize2)
510 : {
511 14570744 : ret = memcmp (name1, name2, nameSize1);
512 14570744 : if (ret == 0)
513 : {
514 3241161 : ret = -1;
515 : }
516 : }
517 : else
518 : {
519 15696541 : ret = memcmp (name1, name2, nameSize2);
520 15696541 : if (ret == 0)
521 : {
522 4928119 : ret = 1;
523 : }
524 : }
525 : }
526 38556115 : return ret;
527 : }
528 :
529 : /**
530 : * @brief Compare by unescaped name only, ignoring case
531 : *
532 : * @internal
533 : *
534 : * @param p1
535 : * @param p2
536 : *
537 : * @return
538 : */
539 8238 : static int keyCompareByNameCase (const void * p1, const void * p2)
540 : {
541 8238 : Key * key1 = *(Key **) p1;
542 8238 : Key * key2 = *(Key **) p2;
543 8238 : const void * name1 = key1->key + key1->keySize;
544 8238 : const void * name2 = key2->key + key2->keySize;
545 8238 : size_t const nameSize1 = key1->keyUSize;
546 8238 : size_t const nameSize2 = key2->keyUSize;
547 8238 : int ret = 0;
548 8238 : if (nameSize1 == nameSize2)
549 : {
550 5276 : ret = elektraMemCaseCmp (name1, name2, nameSize2);
551 : }
552 : else
553 : {
554 2962 : if (nameSize1 < nameSize2)
555 : {
556 2912 : ret = elektraMemCaseCmp (name1, name2, nameSize1);
557 2912 : if (ret == 0)
558 : {
559 1200 : ret = -1;
560 : }
561 : }
562 : else
563 : {
564 50 : ret = elektraMemCaseCmp (name1, name2, nameSize2);
565 50 : if (ret == 0)
566 : {
567 0 : ret = 1;
568 : }
569 : }
570 : }
571 8238 : return ret;
572 : }
573 :
574 : /**
575 : * @brief Compare only the owner of two keys (not the name)
576 : *
577 : * @return comparison result
578 : */
579 716578 : static int keyCompareByOwner (const void * p1, const void * p2)
580 : {
581 716578 : Key * key1 = *(Key **) p1;
582 716578 : Key * key2 = *(Key **) p2;
583 716578 : const char * owner1 = keyValue (keyGetMeta (key1, "owner"));
584 716578 : const char * owner2 = keyValue (keyGetMeta (key2, "owner"));
585 716578 : if (!owner1 && !owner2) return 0;
586 26377 : if (!owner1) return -1;
587 21621 : if (!owner2) return 1;
588 18485 : return elektraStrCmp (owner1, owner2);
589 : }
590 :
591 : /**
592 : * @internal
593 : *
594 : * Defines how keys are sorted in the keyset
595 : *
596 : * Compares by unescaped name, and if equal by owner
597 : *
598 : * Is suitable for binary search
599 : *
600 : * @see keyCmp, keyCompareByName
601 : */
602 18652045 : static int keyCompareByNameOwner (const void * p1, const void * p2)
603 : {
604 18652045 : int ret = keyCompareByName (p1, p2);
605 :
606 18652045 : if (ret == 0)
607 : {
608 716168 : return keyCompareByOwner (p1, p2);
609 : }
610 : return ret;
611 : }
612 :
613 :
614 2040 : static int keyCompareByNameOwnerCase (const void * p1, const void * p2)
615 : {
616 2040 : int result = keyCompareByNameCase (p1, p2);
617 :
618 2040 : if (result == 0)
619 : {
620 410 : return keyCompareByOwner (p1, p2);
621 : }
622 : return result;
623 : }
624 :
625 :
626 : /**
627 : * Compare the name of two keys.
628 : *
629 : * @return a number less than, equal to or greater than zero if
630 : * k1 is found, respectively, to be less than, to match, or
631 : * be greater than k2.
632 : *
633 : * The comparison is based on a strcmp of the keynames, and iff
634 : * they match a strcmp of the owner will be used to distuingish.
635 : * If even this matches the keys are found to be exactly the
636 : * same and 0 is returned. These two keys can't be used in the same
637 : * KeySet.
638 : *
639 : * keyCmp() defines the sorting order for a KeySet.
640 : *
641 : * The following 3 points are the rules for null values:
642 : *
643 : * - A null pointer will be found to be smaller than every other
644 : * key. If both are null pointers, 0 is returned.
645 : *
646 : * - A null name will be found to be smaller than every other
647 : * name. If both are null names, 0 is returned.
648 : *
649 : * If the name is equal then:
650 : *
651 : * - No owner will be found to be smaller then every other owner.
652 : * If both don't have an owner, 0 is returned.
653 : *
654 : * @note the owner will only be used if the names are equal.
655 : *
656 : * Often is enough to know if the other key is
657 : * less then or greater than the other one.
658 : * But Sometimes you need more precise information,
659 : * see keyRel().
660 : *
661 : * Given any Keys k1 and k2 constructed with keyNew(), following
662 : * equation hold true:
663 : *
664 : * @snippet testabi_rel.c cmp null
665 : *
666 : * Here are some more examples:
667 : * @code
668 : Key *k1 = keyNew("user/a", KEY_END);
669 : Key *k2 = keyNew("user/b", KEY_END);
670 :
671 : // keyCmp(k1,k2) < 0
672 : // keyCmp(k2,k1) > 0
673 : * @endcode
674 : *
675 : * And even more:
676 : * @code
677 : Key *k1 = keyNew("user/a", KEY_OWNER, "markus", KEY_END);
678 : Key *k2 = keyNew("user/a", KEY_OWNER, "max", KEY_END);
679 :
680 : // keyCmp(k1,k2) < 0
681 : // keyCmp(k2,k1) > 0
682 : * @endcode
683 : *
684 : * Do not strcmp the keyName() yourself because
685 : * the result differs from simple ascii comparison.
686 : *
687 : * @param k1 the first key object to compare with
688 : * @param k2 the second key object to compare with
689 : *
690 : * @see ksAppendKey(), ksAppend() will compare keys when appending
691 : * @see ksLookup() will compare keys during searching
692 : * @ingroup keytest
693 : */
694 1366612 : int keyCmp (const Key * k1, const Key * k2)
695 : {
696 1366612 : if (!k1 && !k2) return 0;
697 1366116 : if (!k1) return -1;
698 1366110 : if (!k2) return 1;
699 :
700 1366026 : if (!k1->key && !k2->key) return 0;
701 1366013 : if (!k1->key) return -1;
702 1365993 : if (!k2->key) return 1;
703 :
704 1365989 : return keyCompareByNameOwner (&k1, &k2);
705 : }
706 :
707 : /**
708 : * Checks if KeySet needs sync.
709 : *
710 : * When keys are changed this is reflected into keyNeedSync().
711 : *
712 : * But when keys are popped from a keyset this can't be seen
713 : * by looking at the individual keys.
714 : *
715 : * ksNeedSync() allows the backends to know if a key was
716 : * popped from the keyset to know that this keyset needs
717 : * to be written out.
718 : *
719 : * @deprecated Backends now work differently and do not rely on this
720 : * information.
721 : *
722 : * @param ks the keyset to work with
723 : * @retval -1 on null keyset
724 : * @retval 0 if it does not need sync
725 : * @retval 1 if it needs sync
726 : */
727 18 : int ksNeedSync (const KeySet * ks)
728 : {
729 18 : if (!ks) return -1;
730 :
731 18 : return (ks->flags & KS_FLAG_SYNC) == KS_FLAG_SYNC;
732 : }
733 :
734 :
735 : /**
736 : * Return the number of keys that @p ks contains.
737 : *
738 : * @param ks the keyset object to work with
739 : * @return the number of keys that @p ks contains.
740 : * @retval -1 on NULL pointer
741 : * @see ksNew(0, KS_END), ksDel()
742 : */
743 487890 : ssize_t ksGetSize (const KeySet * ks)
744 : {
745 487890 : if (!ks) return -1;
746 :
747 474174 : return ks->size;
748 : }
749 :
750 :
751 : /*******************************************
752 : * Filling up KeySets *
753 : *******************************************/
754 :
755 :
756 : /**
757 : * @internal
758 : *
759 : * Binary search in a KeySet that informs where a key should be inserted.
760 : *
761 : * @code
762 :
763 : ssize_t result = ksSearchInternal(ks, toAppend);
764 :
765 : if (result >= 0)
766 : {
767 : ssize_t position = result;
768 : // Seems like the key already exist.
769 : } else {
770 : ssize_t insertpos = -result-1;
771 : // Seems like the key does not exist.
772 : }
773 : * @endcode
774 : *
775 : * @param ks the keyset to work with
776 : * @param toAppend the key to check
777 : * @return position where the key is (>=0) if the key was found
778 : * @return -insertpos -1 (< 0) if the key was not found
779 : * so to get the insertpos simple do: -insertpos -1
780 : */
781 14431835 : ssize_t ksSearchInternal (const KeySet * ks, const Key * toAppend)
782 : {
783 14431835 : ssize_t left = 0;
784 14431835 : ssize_t right = ks->size;
785 14431835 : --right;
786 : register int cmpresult;
787 14431835 : ssize_t middle = -1;
788 14431835 : ssize_t insertpos = 0;
789 :
790 14431835 : if (ks->size == 0)
791 : {
792 : return -1;
793 : }
794 :
795 12525650 : cmpresult = keyCompareByNameOwner (&toAppend, &ks->array[right]);
796 12525650 : if (cmpresult > 0)
797 : {
798 10890827 : return -((ssize_t) ks->size) - 1;
799 : }
800 : cmpresult = 1;
801 :
802 : while (1)
803 : {
804 6012465 : if (right < left)
805 : {
806 : /* Nothing was found */
807 : break;
808 : }
809 4757168 : middle = left + ((right - left) / 2);
810 4757168 : cmpresult = keyCompareByNameOwner (&toAppend, &ks->array[middle]);
811 4757168 : if (cmpresult > 0)
812 : {
813 2027684 : insertpos = left = middle + 1;
814 : }
815 2729484 : else if (cmpresult == 0)
816 : {
817 : /* We have found it */
818 : break;
819 : }
820 : else
821 : {
822 2349958 : insertpos = middle;
823 2349958 : right = middle - 1;
824 : }
825 : }
826 :
827 1634823 : if (!cmpresult)
828 : {
829 : return middle;
830 : }
831 : else
832 : {
833 1255297 : return -insertpos - 1;
834 : }
835 : }
836 :
837 : /**
838 : * Appends a Key to the end of @p ks.
839 : *
840 : * Will take ownership of the key @p toAppend.
841 : * That means ksDel(ks) will remove the key unless
842 : * the key:
843 : * - was duplicated before inserting
844 : * - got its refcount incremented by keyIncRef() before inserting
845 : * - was also inserted into another keyset with ksAppendKey()
846 : *
847 : * The reference counter of the key will be incremented
848 : * to show this ownership, and thus @p toAppend is not const.
849 : *
850 : * @copydetails doxygenFlatCopy
851 : *
852 : * @see keyGetRef().
853 : *
854 : * If the keyname already existed in the keyset, it will be replaced with
855 : * the new key.
856 : *
857 : * ksAppendKey() will also lock the key's name from `toAppend`.
858 : * This is necessary so that the order of the KeySet cannot
859 : * be destroyed via calls to keySetName().
860 : *
861 : * The KeySet internal cursor will be set to the new key.
862 : *
863 : * It is save to directly append newly created keys:
864 : * @snippet keyset.c simple append
865 : *
866 : * If you want the key to outlive the keyset, make sure to
867 : * do proper ref counting:
868 : * @snippet keyset.c ref append
869 : *
870 : * Or if you want to avoid aliasing at all, you can duplicate the key.
871 : * But then key in the keyset has another identity:
872 : * @snippet keyset.c dup append
873 : *
874 : *
875 : * @return the size of the KeySet after insertion
876 : * @retval -1 on NULL pointers
877 : * @retval -1 if insertion failed, the key will be deleted then.
878 : * @param ks KeySet that will receive the key
879 : * @param toAppend Key that will be appended to ks or deleted
880 : * @see ksAppend(), keyNew(), ksDel()
881 : * @see keyIncRef()
882 : *
883 : */
884 14062110 : ssize_t ksAppendKey (KeySet * ks, Key * toAppend)
885 : {
886 14062110 : ssize_t result = -1;
887 :
888 14062110 : if (!ks) return -1;
889 14062110 : if (!toAppend) return -1;
890 14062042 : if (!toAppend->key)
891 : {
892 : // needed for ksAppendKey(ks, keyNew(0))
893 12 : keyDel (toAppend);
894 12 : return -1;
895 : }
896 :
897 14062030 : elektraKeyLock (toAppend, KEY_LOCK_NAME);
898 :
899 14062030 : result = ksSearchInternal (ks, toAppend);
900 :
901 14062030 : if (result >= 0)
902 : {
903 : /* Seems like the key already exist. */
904 180297 : if (toAppend == ks->array[result])
905 : {
906 : /* user tried to insert the key with same identity */
907 151839 : return ks->size;
908 : }
909 :
910 : /* Pop the key in the result */
911 28458 : keyDecRef (ks->array[result]);
912 28458 : keyDel (ks->array[result]);
913 :
914 : /* And use the other one instead */
915 28458 : keyIncRef (toAppend);
916 28458 : ks->array[result] = toAppend;
917 28458 : ksSetCursor (ks, result);
918 : }
919 : else
920 : {
921 13881733 : ssize_t insertpos = -result - 1;
922 :
923 : /* We want to append a new key
924 : in position insertpos */
925 13881733 : ++ks->size;
926 13881733 : if (ks->size >= ks->alloc)
927 : {
928 19311 : if (ksResize (ks, ks->alloc * 2 - 1) == -1)
929 : {
930 0 : --ks->size;
931 0 : return -1;
932 : }
933 : }
934 13881733 : keyIncRef (toAppend);
935 :
936 13881733 : if (insertpos == (ssize_t) ks->size - 1)
937 : {
938 : /* Append it to the very end */
939 12762133 : ks->array[ks->size - 1] = toAppend;
940 12762133 : ks->array[ks->size] = 0;
941 12762133 : ksSetCursor (ks, ks->size - 1);
942 : }
943 : else
944 : {
945 1119600 : size_t n = ks->size - insertpos;
946 1119600 : memmove (ks->array + (insertpos + 1), ks->array + insertpos, n * sizeof (struct Key *));
947 : /*
948 : printf ("memmove -- ks->size: %zd insertpos: %zd n: %zd\n",
949 : ks->size, insertpos, n);
950 : */
951 1119600 : ks->array[insertpos] = toAppend;
952 1119600 : ksSetCursor (ks, insertpos);
953 : }
954 : elektraOpmphmInvalidate (ks);
955 : }
956 :
957 13910191 : return ks->size;
958 : }
959 :
960 :
961 : /**
962 : * Append all @p toAppend contained keys to the end of the @p ks.
963 : *
964 : * @p toAppend KeySet will be left unchanged.
965 : *
966 : * If a key is both in toAppend and ks, the Key in ks will be
967 : * overridden.
968 : *
969 : * @copydetails doxygenFlatCopy
970 : *
971 : * @post Sorted KeySet ks with all keys it had before and additionally
972 : * the keys from toAppend
973 : * @return the size of the KeySet after transfer
974 : * @retval -1 on NULL pointers
975 : * @param ks the KeySet that will receive the keys
976 : * @param toAppend the KeySet that provides the keys that will be transferred
977 : * @see ksAppendKey()
978 : *
979 : */
980 1377849 : ssize_t ksAppend (KeySet * ks, const KeySet * toAppend)
981 : {
982 1377849 : size_t toAlloc = 0;
983 :
984 1377849 : if (!ks) return -1;
985 1377849 : if (!toAppend) return -1;
986 :
987 1377849 : if (toAppend->size == 0) return ks->size;
988 :
989 : /* Do only one resize in advance */
990 1084947 : for (toAlloc = ks->alloc; ks->size + toAppend->size >= toAlloc; toAlloc *= 2)
991 : ;
992 1084947 : ksResize (ks, toAlloc - 1);
993 :
994 : /* TODO: here is lots of room for optimizations */
995 11277536 : for (size_t i = 0; i < toAppend->size; ++i)
996 : {
997 10192589 : ksAppendKey (ks, toAppend->array[i]);
998 : }
999 1084947 : return ks->size;
1000 : }
1001 :
1002 :
1003 : /**
1004 : * @internal
1005 : *
1006 : * Copies all Keys until the end of the array from a position
1007 : * in the array to an position in the array.
1008 : *
1009 : * @param ks the keyset where this should be done
1010 : * @param to the position where it should be copied to
1011 : * @param from the position where it should be copied from
1012 : * @return the number of moved elements
1013 : */
1014 334892 : ssize_t ksCopyInternal (KeySet * ks, size_t to, size_t from)
1015 : {
1016 334892 : ssize_t ssize = ks->size;
1017 334892 : ssize_t sto = to;
1018 334892 : ssize_t sfrom = from;
1019 :
1020 334892 : ssize_t sizediff = sto - sfrom;
1021 334892 : ssize_t length = ssize - sfrom;
1022 334892 : size_t ret = 0;
1023 :
1024 334892 : ELEKTRA_ASSERT (length >= 0, "length %zu too small", length);
1025 334892 : ELEKTRA_ASSERT (ks->size >= to, "ks->size %zu smaller than %zu", ks->size, to);
1026 :
1027 334892 : ks->size = ssize + sizediff;
1028 :
1029 334892 : if (length != 0)
1030 : {
1031 249300 : ret = elektraMemmove (ks->array + to, ks->array + from, length);
1032 : }
1033 :
1034 334892 : ks->array[ks->size] = 0;
1035 :
1036 334892 : if (ret) elektraOpmphmInvalidate (ks);
1037 :
1038 334892 : return ret;
1039 : }
1040 :
1041 : /**
1042 : * Searches for the start and end indicies corresponding to the given cutpoint.
1043 : *
1044 : * @see ksCut() for explanation of cutpoints
1045 : *
1046 : * @param ks the keyset to cut
1047 : * @param cutpoint the cutpoint
1048 : * @param from we will store the start index here
1049 : * @param to we will store the end index here
1050 : *
1051 : * @retval -1 if the cutpoint wasn't found
1052 : * @retval 1 if the cursor has to updated to match ks->current
1053 : * @retval 0 otherwise
1054 : */
1055 369769 : static int elektraKsFindCutpoint (KeySet * ks, const Key * cutpoint, size_t * from, size_t * to)
1056 : {
1057 369769 : int set_cursor = 0;
1058 :
1059 : // search the cutpoint
1060 369769 : ssize_t search = ksSearchInternal (ks, cutpoint);
1061 369769 : size_t it = search < 0 ? -search - 1 : search;
1062 :
1063 : // we found nothing
1064 369769 : if (it == ks->size) return -1;
1065 :
1066 : // we found the cutpoint
1067 : size_t found = it;
1068 :
1069 : // search the end of the keyset to cut
1070 1470899 : while (it < ks->size && keyIsBelowOrSame (cutpoint, ks->array[it]) == 1)
1071 : {
1072 1136009 : ++it;
1073 : }
1074 :
1075 : // correct cursor if cursor is in cut keyset
1076 334890 : if (ks->current >= found && ks->current < it)
1077 : {
1078 201250 : if (found == 0)
1079 : {
1080 39397 : ksRewind (ks);
1081 : }
1082 : else
1083 : {
1084 161853 : ks->current = found - 1;
1085 161853 : set_cursor = 1;
1086 : }
1087 : }
1088 :
1089 : // correct the cursor for the keys after the cut keyset
1090 334890 : if (ks->current >= it)
1091 : {
1092 54772 : if (it >= ks->size)
1093 : {
1094 4057 : ksRewind (ks);
1095 : }
1096 : else
1097 : {
1098 50715 : ks->current = found + ks->current - it;
1099 50715 : set_cursor = 1;
1100 : }
1101 : }
1102 :
1103 334890 : *from = it;
1104 334890 : *to = found;
1105 :
1106 334890 : return set_cursor;
1107 : }
1108 :
1109 : /**
1110 : * Cuts out a keyset at the cutpoint.
1111 : *
1112 : * Searches for the cutpoint inside the KeySet ks.
1113 : * If found it cuts out everything which is below (see keyIsBelow()) this key.
1114 : * These keys will be missing in the keyset @p ks.
1115 : * Instead, they will be moved to the returned keyset.
1116 : * If @p cutpoint is not found an empty keyset is returned and @p ks
1117 : * is not changed.
1118 : *
1119 : * The cursor will stay at the same key as it was before.
1120 : * If the cursor was inside the region of cut (moved)
1121 : * keys, the cursor will be set to the key before
1122 : * the cutpoint.
1123 : *
1124 : * If you use ksCut() on a keyset you got from kdbGet() and plan to make
1125 : * a kdbSet() later, make sure that you keep all keys that should not
1126 : * be removed permanently. You have to keep the KeySet that was returned
1127 : * and the KeySet @p ks.
1128 : *
1129 : * @par Example:
1130 : *
1131 : * You have the keyset @p ks:
1132 : * - @p system/mountpoint/interest
1133 : * - @p system/mountpoint/interest/folder
1134 : * - @p system/mountpoint/interest/folder/key1
1135 : * - @p system/mountpoint/interest/folder/key2
1136 : * - @p system/mountpoint/other/key1
1137 : *
1138 : * When you use
1139 : * @snippet ksCut.c cut
1140 : *
1141 : * Then in @p returned are:
1142 : * - @p system/mountpoint/interest
1143 : * - @p system/mountpoint/interest/folder
1144 : * - @p system/mountpoint/interest/folder/key1
1145 : * - @p system/mountpoint/interest/folder/key2
1146 : *
1147 : * And in @p ks are:
1148 : * - @p system/mountpoint/other/key1
1149 : *
1150 : * So kdbSet() permanently removes all keys below
1151 : * @p system/mountpoint/interest.
1152 : *
1153 : * @see kdbGet() for explanation why you might get more keys than you
1154 : * requested.
1155 : *
1156 : * @return a new allocated KeySet which needs to deleted with ksDel().
1157 : * The keyset consists of all keys (of the original keyset ks)
1158 : * below the cutpoint. If the key cutpoint exists, it will
1159 : * also be appended.
1160 : * @retval 0 on null pointers, no key name or allocation problems
1161 : * @param ks the keyset to cut. It will be modified by removing
1162 : * all keys below the cutpoint.
1163 : * The cutpoint itself will also be removed.
1164 : * @param cutpoint the point where to cut out the keyset
1165 : */
1166 380308 : KeySet * ksCut (KeySet * ks, const Key * cutpoint)
1167 : {
1168 380308 : KeySet * returned = 0;
1169 380308 : KeySet * ret = 0; // for cascading version
1170 380308 : size_t found = 0;
1171 380308 : size_t it = 0;
1172 380308 : size_t newsize = 0;
1173 380308 : int set_cursor = 0;
1174 :
1175 380308 : if (!ks) return 0;
1176 380308 : if (!cutpoint) return 0;
1177 :
1178 369769 : char * name = cutpoint->key;
1179 369769 : if (!name) return 0;
1180 : // if (strcmp(name, "")) return 0;
1181 :
1182 369769 : elektraOpmphmInvalidate (ks);
1183 :
1184 369769 : if (name[0] == '/')
1185 9846 : {
1186 9846 : Key * key = (Key *) cutpoint;
1187 9846 : size_t size = key->keySize;
1188 9846 : size_t usize = key->keyUSize;
1189 9846 : size_t length = strlen (name) + ELEKTRA_MAX_NAMESPACE_SIZE;
1190 9846 : char newname[length * 2];
1191 :
1192 9846 : ret = ksNew (0, KS_END);
1193 :
1194 59076 : for (elektraNamespace ns = KEY_NS_FIRST; ns <= KEY_NS_LAST; ++ns)
1195 : {
1196 49230 : int validNS = 1;
1197 49230 : switch (ns)
1198 : {
1199 : case KEY_NS_SPEC:
1200 9846 : strncpy (newname + 2, "spec", 5);
1201 9846 : strcpy (newname + 6, name);
1202 9846 : key->key = newname + 2;
1203 9846 : key->keySize = length - 2;
1204 9846 : if (!strcmp (name, "/")) key->keySize = 5;
1205 9846 : elektraFinalizeName (key);
1206 9846 : break;
1207 : case KEY_NS_PROC:
1208 9846 : strncpy (newname + 2, "proc", 5);
1209 9846 : strcpy (newname + 6, name);
1210 9846 : key->key = newname + 2;
1211 9846 : key->keySize = length - 2;
1212 9846 : if (!strcmp (name, "/")) key->keySize = 5;
1213 9846 : elektraFinalizeName (key);
1214 9846 : break;
1215 : case KEY_NS_DIR:
1216 9846 : strncpy (newname + 3, "dir", 4);
1217 9846 : strcpy (newname + 6, name);
1218 9846 : key->key = newname + 3;
1219 9846 : key->keySize = length - 3;
1220 9846 : if (!strcmp (name, "/")) key->keySize = 4;
1221 9846 : elektraFinalizeName (key);
1222 9846 : break;
1223 : case KEY_NS_USER:
1224 9846 : strncpy (newname + 2, "user", 5);
1225 9846 : strcpy (newname + 6, name);
1226 9846 : key->key = newname + 2;
1227 9846 : key->keySize = length - 2;
1228 9846 : if (!strcmp (name, "/")) key->keySize = 5;
1229 9846 : elektraFinalizeName (key);
1230 9846 : break;
1231 : case KEY_NS_SYSTEM:
1232 9846 : strncpy (newname, "system", 7);
1233 9846 : strcpy (newname + 6, name);
1234 9846 : key->key = newname;
1235 9846 : key->keySize = length;
1236 9846 : if (!strcmp (name, "/")) key->keySize = 7;
1237 9846 : elektraFinalizeName (key);
1238 9846 : break;
1239 : case KEY_NS_EMPTY:
1240 : case KEY_NS_NONE:
1241 : case KEY_NS_META:
1242 : case KEY_NS_CASCADING:
1243 0 : validNS = 0;
1244 : }
1245 49230 : if (validNS)
1246 : {
1247 49230 : KeySet * n = ksCut (ks, key);
1248 49230 : ksAppend (ret, n);
1249 49230 : ksDel (n);
1250 : }
1251 : }
1252 :
1253 : // restore old cascading name
1254 9846 : key->key = name;
1255 9846 : key->keySize = size;
1256 9846 : key->keyUSize = usize;
1257 :
1258 : // now look for cascading keys
1259 : }
1260 :
1261 369769 : set_cursor = elektraKsFindCutpoint (ks, cutpoint, &it, &found);
1262 369769 : if (set_cursor < 0) return ret ? ret : ksNew (0, KS_END);
1263 :
1264 334890 : newsize = it - found;
1265 :
1266 334890 : returned = ksNew (newsize, KS_END);
1267 334890 : elektraMemcpy (returned->array, ks->array + found, newsize);
1268 334890 : returned->size = newsize;
1269 334890 : returned->array[returned->size] = 0;
1270 :
1271 334890 : ksCopyInternal (ks, found, it);
1272 :
1273 334890 : if (set_cursor) ks->cursor = ks->array[ks->current];
1274 :
1275 334890 : if (ret)
1276 : {
1277 6523 : ksAppend (returned, ret);
1278 6523 : ksDel (ret);
1279 : }
1280 :
1281 : return returned;
1282 : }
1283 :
1284 :
1285 : /**
1286 : * Remove and return the last key of @p ks.
1287 : *
1288 : * The reference counter will be decremented by one.
1289 : *
1290 : * The KeySets cursor will not be affected if it did not
1291 : * point to the popped key.
1292 : *
1293 : * @note You need to keyDel() the key afterwards, if
1294 : * you don't append it to another keyset. It has the
1295 : * same semantics like a key allocated with keyNew()
1296 : * or keyDup().
1297 : *
1298 : *@code
1299 : ks1=ksNew(0, KS_END);
1300 : ks2=ksNew(0, KS_END);
1301 :
1302 : k1=keyNew("user/name", KEY_END); // ref counter 0
1303 : ksAppendKey(ks1, k1); // ref counter 1
1304 : ksAppendKey(ks2, k1); // ref counter 2
1305 :
1306 : k1=ksPop (ks1); // ref counter 1
1307 : k1=ksPop (ks2); // ref counter 0, like after keyNew()
1308 :
1309 : ksAppendKey(ks1, k1); // ref counter 1
1310 :
1311 : ksDel (ks1); // key is deleted too
1312 : ksDel (ks2);
1313 : *@endcode
1314 : *
1315 : * @return the last key of @p ks
1316 : * @retval NULL if @p ks is empty or on NULL pointer
1317 : * @param ks KeySet to work with
1318 : * @see ksLookup() to pop keys by name
1319 : * @see ksCopy() to pop all keys
1320 : * @see commandList() for an example
1321 : *
1322 : */
1323 761109 : Key * ksPop (KeySet * ks)
1324 : {
1325 761109 : Key * ret = 0;
1326 :
1327 761109 : if (!ks) return 0;
1328 :
1329 761109 : ks->flags |= KS_FLAG_SYNC;
1330 :
1331 761109 : if (ks->size == 0) return 0;
1332 :
1333 680958 : elektraOpmphmInvalidate (ks);
1334 :
1335 680958 : --ks->size;
1336 680958 : if (ks->size + 1 < ks->alloc / 2) ksResize (ks, ks->alloc / 2 - 1);
1337 680958 : ret = ks->array[ks->size];
1338 680958 : ks->array[ks->size] = 0;
1339 680958 : keyDecRef (ret);
1340 :
1341 680958 : return ret;
1342 : }
1343 :
1344 :
1345 : /*******************************************
1346 : * KeySet browsing methods *
1347 : *******************************************/
1348 :
1349 :
1350 : /**
1351 : * Rewinds the KeySet internal cursor.
1352 : *
1353 : * Use it to set the cursor to the beginning of the KeySet.
1354 : * ksCurrent() will then always return NULL afterwards. So
1355 : * you want to ksNext() first.
1356 : *
1357 : * @code
1358 : ksRewind (ks);
1359 : while ((key = ksNext (ks))!=0) {}
1360 : * @endcode
1361 : *
1362 : * @param ks the keyset object to work with
1363 : * @retval 0 on success
1364 : * @retval -1 on NULL pointer
1365 : * @see ksNext(), ksCurrent()
1366 : */
1367 11756802 : int ksRewind (KeySet * ks)
1368 : {
1369 11756802 : if (!ks) return -1;
1370 :
1371 11746222 : ks->cursor = 0;
1372 11746222 : ks->current = 0;
1373 11746222 : return 0;
1374 : }
1375 :
1376 :
1377 : /**
1378 : * Returns the next Key in a KeySet.
1379 : *
1380 : * KeySets have an internal cursor that can be reset with ksRewind(). Every
1381 : * time ksNext() is called the cursor is incremented and the new current Key
1382 : * is returned.
1383 : *
1384 : * You'll get a NULL pointer if the key after the end of the KeySet was reached.
1385 : * On subsequent calls of ksNext() it will still return the NULL pointer.
1386 : *
1387 : * The @p ks internal cursor will be changed, so it is not const.
1388 : *
1389 : * @note You must not delete or change the key, use ksPop() if you want to delete it.
1390 : *
1391 : * @note That applications must do ksLookup() with an cascading key for every single
1392 : * key before using it, because specifications allow to hide or override keys.
1393 : *
1394 : * @param ks the keyset object to work with
1395 : * @return the new current Key
1396 : * @retval 0 when the end is reached
1397 : * @retval 0 on NULL pointer
1398 : * @see ksRewind(), ksCurrent()
1399 : * @see ksLookup() to honor specifications
1400 : */
1401 19292982 : Key * ksNext (KeySet * ks)
1402 : {
1403 19292982 : if (!ks) return 0;
1404 :
1405 19291834 : if (ks->size == 0) return 0;
1406 18131476 : if (ks->current >= ks->size)
1407 : {
1408 : return 0;
1409 : }
1410 :
1411 18131276 : if (ks->cursor) ks->current++;
1412 18131276 : return ks->cursor = ks->array[ks->current];
1413 : }
1414 :
1415 :
1416 : /**
1417 : * Return the current Key.
1418 : *
1419 : * The pointer is NULL if you reached the end or after
1420 : * ksRewind().
1421 : *
1422 : * @note You must not delete the key or change the key,
1423 : * use ksPop() if you want to delete it.
1424 : *
1425 : * @param ks the keyset object to work with
1426 : * @return pointer to the Key pointed by @p ks's cursor
1427 : * @retval 0 on NULL pointer
1428 : * @see ksNext(), ksRewind()
1429 : */
1430 136140 : Key * ksCurrent (const KeySet * ks)
1431 : {
1432 136140 : if (!ks) return 0;
1433 :
1434 136140 : return ks->cursor;
1435 : }
1436 :
1437 :
1438 : /**
1439 : * Return the first key in the KeySet.
1440 : *
1441 : * The KeySets cursor will not be affected.
1442 : *
1443 : * If ksCurrent()==ksHead() you know you are
1444 : * on the first key.
1445 : *
1446 : * @param ks the keyset object to work with
1447 : * @return the first Key of a keyset
1448 : * @retval 0 on NULL pointer or empty keyset
1449 : * @see ksTail() for the last key
1450 : * @see ksRewind(), ksCurrent() and ksNext() for iterating over the keyset
1451 : */
1452 12102 : Key * ksHead (const KeySet * ks)
1453 : {
1454 12102 : if (!ks) return 0;
1455 :
1456 12102 : if (ks->size > 0)
1457 12099 : return ks->array[0];
1458 : else
1459 : return 0;
1460 : }
1461 :
1462 :
1463 : /**
1464 : * Return the last key in the KeySet.
1465 : *
1466 : * The KeySets cursor will not be affected.
1467 : *
1468 : * If ksCurrent()==ksTail() you know you
1469 : * are on the last key. ksNext() will return
1470 : * a NULL pointer afterwards.
1471 : *
1472 : * @param ks the keyset object to work with
1473 : * @return the last Key of a keyset
1474 : * @retval 0 on NULL pointer or empty keyset
1475 : * @see ksHead() for the first key
1476 : * @see ksRewind(), ksCurrent() and ksNext() for iterating over the keyset
1477 : */
1478 171 : Key * ksTail (const KeySet * ks)
1479 : {
1480 171 : if (!ks) return 0;
1481 :
1482 171 : if (ks->size > 0)
1483 169 : return ks->array[ks->size - 1];
1484 : else
1485 : return 0;
1486 : }
1487 :
1488 :
1489 : /**
1490 : * Get the KeySet internal cursor.
1491 : *
1492 : * Use it to get the cursor of the actual position.
1493 : *
1494 : * @warning Cursors are getting invalid when the key
1495 : * was ksPop()ed or ksLookup() with KDB_O_POP was
1496 : * used.
1497 : *
1498 : * @section readahead Read ahead
1499 : *
1500 : * With the cursors it is possible to read ahead
1501 : * in a keyset:
1502 : *
1503 : * @code
1504 : cursor_t jump;
1505 : ksRewind (ks);
1506 : while ((key = keyNextMeta (ks))!=0)
1507 : {
1508 : // now mark this key
1509 : jump = ksGetCursor(ks);
1510 :
1511 : //code..
1512 : keyNextMeta (ks); // now browse on
1513 : // use ksCurrent(ks) to check the keys
1514 : //code..
1515 :
1516 : // jump back to the position marked before
1517 : ksSetCursor(ks, jump);
1518 : }
1519 : * @endcode
1520 : *
1521 : * @section restore Restoring state
1522 : *
1523 : * It can also be used to restore the state of a
1524 : * keyset in a function
1525 : *
1526 : * @code
1527 : int f (KeySet *ks)
1528 : {
1529 : cursor_t state = ksGetCursor(ks);
1530 :
1531 : // work with keyset
1532 :
1533 : // now bring the keyset to the state before
1534 : ksSetCursor (ks, state);
1535 : }
1536 : * @endcode
1537 : *
1538 : * It is of course possible to make the KeySet const
1539 : * and cast its const away to set the cursor.
1540 : * Another way to achieve
1541 : * the same is to ksDup() the keyset, but it is
1542 : * not as efficient.
1543 : *
1544 : * An invalid cursor will be returned directly after
1545 : * ksRewind(). When you set an invalid cursor ksCurrent()
1546 : * is 0 and ksNext() == ksHead().
1547 : *
1548 : * @note Only use a cursor for the same keyset which it was
1549 : * made for.
1550 : *
1551 : * @param ks the keyset object to work with
1552 : * @return a valid cursor on success
1553 : * @return an invalid cursor on NULL pointer or after ksRewind()
1554 : * @see ksNext(), ksSetCursor()
1555 : */
1556 10336295 : cursor_t ksGetCursor (const KeySet * ks)
1557 : {
1558 10336295 : if (!ks) return (cursor_t) -1;
1559 :
1560 10336295 : if (ks->cursor == 0)
1561 : return (cursor_t) -1;
1562 : else
1563 8133247 : return (cursor_t) ks->current;
1564 : }
1565 :
1566 : /**
1567 : * @brief return key at given cursor position
1568 : *
1569 : * @param ks the keyset to pop key from
1570 : * @param pos where to get
1571 : * @return the key at the cursor position on success
1572 : * @retval NULL on NULL pointer, negative cursor position
1573 : * or a position that does not lie within the keyset
1574 : */
1575 28500 : Key * ksAtCursor (KeySet * ks, cursor_t pos)
1576 : {
1577 28500 : if (!ks) return 0;
1578 28498 : if (pos < 0) return 0;
1579 27555 : if (ks->size < (size_t) pos) return 0;
1580 27549 : return ks->array[pos];
1581 : }
1582 :
1583 :
1584 : /**
1585 : * Set the KeySet internal cursor.
1586 : *
1587 : * Use it to set the cursor to a stored position.
1588 : * ksCurrent() will then be the position which you got with.
1589 : *
1590 : * @warning Cursors may get invalid when the key
1591 : * was ksPop()ed or ksLookup() was used together
1592 : * with KDB_O_POP.
1593 : *
1594 : * @code
1595 : cursor_t cursor;
1596 : ..
1597 : // key now in any position here
1598 : cursor = ksGetCursor (ks);
1599 : while ((key = keyNextMeta (ks))!=0) {}
1600 : ksSetCursor (ks, cursor); // reset state
1601 : ksCurrent(ks); // in same position as before
1602 : * @endcode
1603 : *
1604 : * An invalid cursor will set the keyset to its beginning like
1605 : * ksRewind(). When you set an invalid cursor ksCurrent()
1606 : * is 0 and ksNext() == ksHead().
1607 : *
1608 : * @param cursor the cursor to use
1609 : * @param ks the keyset object to work with
1610 : * @retval 0 when the keyset is ksRewind()ed
1611 : * @retval 1 otherwise
1612 : * @retval -1 on NULL pointer
1613 : * @see ksNext(), ksGetCursor()
1614 : */
1615 23883242 : int ksSetCursor (KeySet * ks, cursor_t cursor)
1616 : {
1617 23883242 : if (!ks) return -1;
1618 :
1619 23883242 : if ((cursor_t) -1 == cursor)
1620 : {
1621 1911816 : ksRewind (ks);
1622 1911816 : return 0;
1623 : }
1624 21971426 : ks->current = (size_t) cursor;
1625 21971426 : ks->cursor = ks->array[ks->current];
1626 21971426 : return 1;
1627 : }
1628 :
1629 :
1630 : /*******************************************
1631 : * Looking up Keys inside KeySets *
1632 : *******************************************/
1633 :
1634 1866 : static void elektraCopyCallbackMeta (Key * dest, Key * source)
1635 : {
1636 : // possible optimization: only copy when callback is present (keyIsBinary && keyGetValueSize == sizeof(void(int))
1637 1866 : const Key * m = 0;
1638 :
1639 1866 : keyRewindMeta (dest);
1640 5560 : while ((m = keyNextMeta (dest)))
1641 : {
1642 1828 : const char * metaname = keyName (m);
1643 1828 : if (!strncmp (metaname, "callback/", sizeof ("callback")))
1644 : {
1645 2 : keySetMeta (dest, metaname, 0);
1646 : }
1647 : }
1648 :
1649 1866 : keyRewindMeta (source);
1650 5558 : while ((m = keyNextMeta (source)))
1651 : {
1652 1826 : const char * metaname = keyName (m);
1653 1826 : if (!strncmp (metaname, "callback/", sizeof ("callback")))
1654 : {
1655 4 : keyCopyMeta (dest, source, metaname);
1656 : }
1657 : }
1658 1866 : }
1659 :
1660 : /**
1661 : * @internal
1662 : * @brief Writes a elektra array name
1663 : *
1664 : * @param newName the buffer to write to (size must be
1665 : * #ELEKTRA_MAX_ARRAY_SIZE or more)
1666 : * @param newIndex the index of the array to write
1667 : *
1668 : * @retval 0 on success
1669 : * @retval -1 on error
1670 : */
1671 191937 : int elektraWriteArrayNumber (char * newName, kdb_long_long_t newIndex)
1672 : {
1673 : // now we fill out newName
1674 191937 : size_t index = 0; // index of newName
1675 191937 : newName[index++] = '#';
1676 191937 : kdb_long_long_t i = newIndex / 10;
1677 :
1678 468298 : while (i > 0)
1679 : {
1680 84424 : newName[index++] = '_'; // index n-1 of decimals
1681 84424 : i /= 10;
1682 : }
1683 191937 : if (snprintf (&newName[index], ELEKTRA_MAX_ARRAY_SIZE - index, ELEKTRA_UNSIGNED_LONG_LONG_F, newIndex) < 0)
1684 : {
1685 : return -1;
1686 : }
1687 :
1688 191937 : return 0;
1689 : }
1690 :
1691 : /**
1692 : * @internal
1693 : * @brief Helper for elektraLookupBySpec
1694 : *
1695 : * Lookup using links (fallback or override passed as buffer)
1696 : *
1697 : * @param ks the keyset to search in
1698 : * @param specKey contains metadata as specified in buffer+#<number>
1699 : * @param buffer the buffer used for incrementing numbers
1700 : *
1701 : * @return
1702 : */
1703 1524 : static Key * elektraLookupBySpecLinks (KeySet * ks, Key * specKey, char * buffer)
1704 : {
1705 1524 : Key * ret = 0;
1706 1524 : Key * k = 0;
1707 1524 : const int prefixSize = ELEKTRA_MAX_PREFIX_SIZE - 2;
1708 1524 : kdb_long_long_t i = 0;
1709 1524 : const Key * m = 0;
1710 :
1711 : do
1712 : {
1713 1778 : elektraWriteArrayNumber (&buffer[prefixSize], i);
1714 1778 : m = keyGetMeta (specKey, buffer);
1715 1778 : if (!m) break;
1716 : // optimization: lazy instanziation of k
1717 328 : if (!k)
1718 : {
1719 126 : k = keyNew (keyString (m), KEY_CASCADING_NAME, KEY_END);
1720 126 : keySetBinary (k, keyValue (specKey), keyGetValueSize (specKey));
1721 126 : elektraCopyCallbackMeta (k, specKey);
1722 : }
1723 : else
1724 202 : elektraKeySetName (k, keyString (m), KEY_CASCADING_NAME);
1725 328 : ret = ksLookup (ks, k, KDB_O_NODEFAULT);
1726 328 : if (ret) break;
1727 254 : ++i;
1728 : } while (m);
1729 :
1730 1524 : if (k)
1731 : {
1732 126 : elektraCopyCallbackMeta (specKey, k);
1733 126 : keyDel (k);
1734 : }
1735 1524 : return ret;
1736 : }
1737 :
1738 : /**
1739 : * @internal
1740 : *
1741 : * @param specKey must have a cascading key name
1742 : *
1743 : * @brief Helper for elektraLookupBySpec
1744 : */
1745 574 : static Key * elektraLookupBySpecDefault (KeySet * ks, Key * specKey)
1746 : {
1747 574 : Key * ret = 0;
1748 574 : const Key * m = 0;
1749 :
1750 574 : ret = ksLookup (ks, specKey, KDB_O_NOCASCADING);
1751 574 : if (ret) return ret; // return previous added default key
1752 :
1753 354 : m = keyGetMeta (specKey, "default");
1754 354 : if (!m) return ret;
1755 302 : ret = keyNew (keyName (specKey), KEY_CASCADING_NAME, KEY_VALUE, keyString (m), KEY_END);
1756 302 : ksAppendKey (ks, ret);
1757 :
1758 302 : return ret;
1759 : }
1760 :
1761 : static Key * elektraLookupByCascading (KeySet * ks, Key * key, option_t options);
1762 :
1763 : /**
1764 : * @internal
1765 : * @brief Helper for elektraLookupBySpec
1766 : *
1767 : * Lookup using namespaces
1768 : *
1769 : * @param ks the keyset to search in
1770 : * @param specKey contains metadata as specified in buffer+#<number>
1771 : * @param buffer the buffer used for incrementing numbers
1772 : */
1773 872 : static Key * elektraLookupBySpecNamespaces (KeySet * ks, Key * specKey, char * buffer)
1774 872 : {
1775 872 : Key * ret = 0;
1776 872 : const int prefixSize = ELEKTRA_MAX_PREFIX_SIZE - 1;
1777 872 : kdb_long_long_t i = 0;
1778 872 : const Key * m = 0;
1779 :
1780 872 : m = keyGetMeta (specKey, buffer);
1781 : // no namespaces specified, so do a default cascading lookup
1782 : // (obviously w/o spec)
1783 872 : if (!m) return elektraLookupByCascading (ks, specKey, KDB_O_NOSPEC | KDB_O_NODEFAULT);
1784 :
1785 : // store old name of specKey
1786 46 : char * name = specKey->key;
1787 46 : size_t size = specKey->keySize;
1788 46 : size_t usize = specKey->keyUSize;
1789 46 : size_t nameLength = strlen (name);
1790 46 : size_t maxSize = nameLength + ELEKTRA_MAX_NAMESPACE_SIZE;
1791 46 : char newname[maxSize * 2]; // buffer for all new names (namespace + cascading key name)
1792 :
1793 : do
1794 : {
1795 : // lookup with given namespace
1796 46 : size_t namespaceSize = keyGetValueSize (m);
1797 46 : char * startOfName = newname + ELEKTRA_MAX_NAMESPACE_SIZE - namespaceSize;
1798 46 : strncpy (startOfName, keyString (m), namespaceSize);
1799 46 : strcpy (newname + ELEKTRA_MAX_NAMESPACE_SIZE - 1, name); // name starts with /
1800 46 : specKey->key = startOfName;
1801 46 : specKey->keySize = nameLength + namespaceSize;
1802 46 : elektraFinalizeName (specKey);
1803 46 : ret = ksLookup (ks, specKey, 0);
1804 46 : if (ret) break;
1805 20 : ++i; // start with 1 (#0 was already in buffer)
1806 :
1807 20 : elektraWriteArrayNumber (&buffer[prefixSize], i);
1808 20 : m = keyGetMeta (specKey, buffer);
1809 20 : } while (m);
1810 :
1811 : // restore old cascading name
1812 46 : specKey->key = name;
1813 46 : specKey->keySize = size;
1814 46 : specKey->keyUSize = usize;
1815 46 : return ret;
1816 : }
1817 :
1818 :
1819 : /**
1820 : * @internal
1821 : * @brief Helper for ksLookup
1822 : */
1823 940 : static Key * elektraLookupBySpec (KeySet * ks, Key * specKey, option_t options)
1824 : {
1825 940 : Key * ret = 0;
1826 : // strip away beginning of specKey
1827 940 : char * name = specKey->key;
1828 : // stays same if already cascading and
1829 : // root must not be cascaded, so the usage of strchr is safe.
1830 940 : specKey->key = strchr (name, '/');
1831 940 : size_t size = specKey->keySize;
1832 940 : specKey->keySize = size - (specKey->key - name);
1833 940 : elektraFinalizeName (specKey);
1834 :
1835 : // lookup by override
1836 940 : char buffer[ELEKTRA_MAX_PREFIX_SIZE + ELEKTRA_MAX_ARRAY_SIZE] = "override/";
1837 940 : ret = elektraLookupBySpecLinks (ks, specKey, buffer);
1838 940 : if (ret) goto finished;
1839 :
1840 : // lookup by namespaces
1841 872 : strcpy (buffer, "namespace/#0");
1842 872 : ret = elektraLookupBySpecNamespaces (ks, specKey, buffer);
1843 872 : if (ret) goto finished;
1844 :
1845 : // lookup by fallback
1846 584 : strcpy (buffer, "fallback/");
1847 584 : ret = elektraLookupBySpecLinks (ks, specKey, buffer);
1848 584 : if (ret) goto finished;
1849 :
1850 578 : if (!(options & KDB_O_NODEFAULT))
1851 : {
1852 574 : ret = elektraLookupBySpecDefault (ks, specKey);
1853 : }
1854 :
1855 : finished:
1856 940 : specKey->key = name;
1857 940 : specKey->keySize = size;
1858 940 : elektraFinalizeName (specKey);
1859 :
1860 940 : return ret;
1861 : }
1862 :
1863 : /**
1864 : * @internal
1865 : * @brief Helper for ksLookup
1866 : */
1867 466930 : static Key * elektraLookupByCascading (KeySet * ks, Key * key, option_t options)
1868 466930 : {
1869 466930 : char * name = key->key;
1870 466930 : size_t size = key->keySize;
1871 466930 : size_t usize = key->keyUSize;
1872 466930 : size_t length = strlen (name) + ELEKTRA_MAX_NAMESPACE_SIZE;
1873 466930 : char newname[length * 2];
1874 466930 : Key * found = 0;
1875 466930 : Key * specKey = 0;
1876 :
1877 466930 : if (!(options & KDB_O_NOSPEC))
1878 : {
1879 466104 : strncpy (newname + 2, "spec", 5);
1880 466104 : strcpy (newname + 6, name);
1881 466104 : key->key = newname + 2;
1882 466104 : key->keySize = length - 2;
1883 466104 : elektraFinalizeName (key);
1884 466104 : specKey = ksLookup (ks, key, (options & ~KDB_O_DEL) | KDB_O_CALLBACK);
1885 : }
1886 :
1887 466930 : if (specKey)
1888 : {
1889 : // restore old name
1890 330 : key->key = name;
1891 330 : key->keySize = size;
1892 330 : key->keyUSize = usize;
1893 :
1894 330 : if (strncmp (keyName (specKey), "spec/", 5))
1895 : { // the search was modified in a way that not a spec Key was returned
1896 : return specKey;
1897 : }
1898 :
1899 : // we found a spec key, so we know what to do
1900 310 : specKey = keyDup (specKey);
1901 310 : keySetBinary (specKey, keyValue (key), keyGetValueSize (key));
1902 310 : elektraCopyCallbackMeta (specKey, key);
1903 310 : found = elektraLookupBySpec (ks, specKey, options);
1904 310 : elektraCopyCallbackMeta (key, specKey);
1905 310 : keyDel (specKey);
1906 310 : return found;
1907 : }
1908 :
1909 : // default cascading:
1910 466600 : strncpy (newname + 2, "proc", 5);
1911 466600 : strcpy (newname + 6, name);
1912 466600 : key->key = newname + 2;
1913 466600 : key->keySize = length - 2;
1914 466600 : elektraFinalizeName (key);
1915 466600 : found = ksLookup (ks, key, options & ~KDB_O_DEL);
1916 :
1917 466600 : if (!found)
1918 : {
1919 466528 : strncpy (newname + 3, "dir", 4);
1920 466528 : strcpy (newname + 6, name);
1921 466528 : key->key = newname + 3;
1922 466528 : key->keySize = length - 3;
1923 466528 : elektraFinalizeName (key);
1924 466528 : found = ksLookup (ks, key, options & ~KDB_O_DEL);
1925 : }
1926 :
1927 466600 : if (!found)
1928 : {
1929 466516 : strncpy (newname + 2, "user", 5);
1930 466516 : strcpy (newname + 6, name);
1931 466516 : key->key = newname + 2;
1932 466516 : key->keySize = length - 2;
1933 466516 : elektraFinalizeName (key);
1934 466516 : found = ksLookup (ks, key, options & ~KDB_O_DEL);
1935 : }
1936 :
1937 466600 : if (!found)
1938 : {
1939 404510 : strncpy (newname, "system", 7);
1940 404510 : strcpy (newname + 6, name);
1941 404510 : key->key = newname;
1942 404510 : key->keySize = length;
1943 404510 : elektraFinalizeName (key);
1944 404510 : found = ksLookup (ks, key, options & ~KDB_O_DEL);
1945 : }
1946 :
1947 : // restore old cascading name
1948 466600 : key->key = name;
1949 466600 : key->keySize = size;
1950 466600 : key->keyUSize = usize;
1951 :
1952 466600 : if (!found && !(options & KDB_O_NODEFAULT))
1953 : {
1954 : // search / key itself
1955 363867 : found = ksLookup (ks, key, (options & ~KDB_O_DEL) | KDB_O_NOCASCADING);
1956 : }
1957 :
1958 : return found;
1959 : }
1960 :
1961 44 : static Key * elektraLookupLinearSearch (KeySet * ks, Key * key, option_t options)
1962 : {
1963 44 : cursor_t cursor = 0;
1964 44 : cursor = ksGetCursor (ks);
1965 : Key * current;
1966 44 : if (!(options & KDB_O_NOALL)) ksRewind (ks);
1967 224 : while ((current = ksNext (ks)) != 0)
1968 : {
1969 216 : if ((options & KDB_O_WITHOWNER) && (options & KDB_O_NOCASE))
1970 : {
1971 40 : if (!keyCompareByNameOwnerCase (&key, ¤t)) break;
1972 : }
1973 176 : else if (options & KDB_O_WITHOWNER)
1974 : {
1975 0 : if (!keyCompareByNameOwner (&key, ¤t)) break;
1976 : }
1977 176 : else if (options & KDB_O_NOCASE)
1978 : {
1979 84 : if (!keyCompareByNameCase (&key, ¤t)) break;
1980 : }
1981 92 : else if (!keyCompareByName (&key, ¤t))
1982 : break;
1983 : }
1984 44 : if (current == 0)
1985 : {
1986 : /*Reset Cursor to old position*/
1987 8 : ksSetCursor (ks, cursor);
1988 : }
1989 44 : return current;
1990 : }
1991 :
1992 10260936 : static Key * elektraLookupBinarySearch (KeySet * ks, Key const * key, option_t options)
1993 : {
1994 10260936 : cursor_t cursor = 0;
1995 10260936 : cursor = ksGetCursor (ks);
1996 : Key ** found;
1997 10260936 : size_t jump = 0;
1998 : /*If there is a known offset in the beginning jump could be set*/
1999 10260936 : if ((options & KDB_O_WITHOWNER) && (options & KDB_O_NOCASE))
2000 400 : found = (Key **) bsearch (&key, ks->array + jump, ks->size - jump, sizeof (Key *), keyCompareByNameOwnerCase);
2001 10260536 : else if (options & KDB_O_WITHOWNER)
2002 830 : found = (Key **) bsearch (&key, ks->array + jump, ks->size - jump, sizeof (Key *), keyCompareByNameOwner);
2003 10259706 : else if (options & KDB_O_NOCASE)
2004 1244 : found = (Key **) bsearch (&key, ks->array + jump, ks->size - jump, sizeof (Key *), keyCompareByNameCase);
2005 : else
2006 10258462 : found = (Key **) bsearch (&key, ks->array + jump, ks->size - jump, sizeof (Key *), keyCompareByName);
2007 10260936 : if (found)
2008 : {
2009 3012665 : cursor = found - ks->array;
2010 3012665 : if (options & KDB_O_POP)
2011 : {
2012 359899 : return elektraKsPopAtCursor (ks, cursor);
2013 : }
2014 : else
2015 : {
2016 2652766 : ksSetCursor (ks, cursor);
2017 2652766 : return (*found);
2018 : }
2019 : }
2020 : else
2021 : {
2022 7248271 : ksSetCursor (ks, cursor);
2023 : }
2024 7248271 : return 0;
2025 : }
2026 :
2027 : #ifdef ELEKTRA_ENABLE_OPTIMIZATIONS
2028 :
2029 : /**
2030 : * @internal
2031 : *
2032 : * @brief Extracts the Key name of Keys
2033 : *
2034 : * @param data the Key
2035 : *
2036 : * @return the Key name
2037 : */
2038 1660 : static const char * elektraOpmphmGetString (void * data)
2039 : {
2040 1660 : return keyName ((Key *) data);
2041 : }
2042 :
2043 : /**
2044 : * @internal
2045 : *
2046 : * @brief Builds the OPMPHM
2047 : *
2048 : * Creates the OPMPHM when not here.
2049 : * The passed KeySet must have a not build OPMPHM.
2050 : *
2051 : * @param ks the KeySet which OPMPHM is to build
2052 : *
2053 : * @retval 0 on success
2054 : * @retval -1 on memory error or to many mapping invocations
2055 : */
2056 28 : static int elektraLookupBuildOpmphm (KeySet * ks)
2057 : {
2058 28 : if (ks->size > KDB_OPMPHM_MAX_N)
2059 : {
2060 : return -1;
2061 : }
2062 28 : if (!ks->opmphm)
2063 : {
2064 28 : ks->opmphm = opmphmNew ();
2065 28 : if (!ks->opmphm)
2066 : {
2067 : return -1;
2068 : }
2069 : }
2070 28 : ELEKTRA_ASSERT (!opmphmIsBuild (ks->opmphm), "OPMPHM already build");
2071 : // make graph
2072 28 : uint8_t r = opmphmOptR (ks->size);
2073 28 : double c = opmphmMinC (r);
2074 28 : c += opmphmOptC (ks->size);
2075 28 : OpmphmGraph * graph = opmphmGraphNew (ks->opmphm, r, ks->size, c);
2076 28 : if (!graph)
2077 : {
2078 : return -1;
2079 : }
2080 : // make init
2081 : OpmphmInit init;
2082 28 : init.getName = elektraOpmphmGetString;
2083 28 : init.data = (void **) ks->array;
2084 28 : init.initSeed = elektraRandGetInitSeed ();
2085 :
2086 : // mapping
2087 28 : size_t mappings = 0; // counts mapping invocations
2088 : int ret;
2089 : do
2090 : {
2091 28 : ret = opmphmMapping (ks->opmphm, graph, &init, ks->size);
2092 28 : ++mappings;
2093 28 : } while (ret && mappings < 10);
2094 28 : if (ret && mappings == 10)
2095 : {
2096 0 : opmphmGraphDel (graph);
2097 0 : return -1;
2098 : }
2099 :
2100 : // assign
2101 28 : if (opmphmAssignment (ks->opmphm, graph, ks->size, 1))
2102 : {
2103 0 : opmphmGraphDel (graph);
2104 0 : return -1;
2105 : }
2106 :
2107 28 : opmphmGraphDel (graph);
2108 28 : return 0;
2109 : }
2110 :
2111 : /**
2112 : * @internal
2113 : *
2114 : * @brief Searches for a Key in an already build OPMPHM.
2115 : *
2116 : * The OPMPHM must be build.
2117 : *
2118 : * @param ks the KeySet
2119 : * @param key the Key to search for
2120 : * @param options lookup options
2121 : *
2122 : * @return Key * when key found
2123 : * @return NULL when key not found
2124 : *
2125 : */
2126 520 : static Key * elektraLookupOpmphmSearch (KeySet * ks, Key const * key, option_t options)
2127 : {
2128 520 : ELEKTRA_ASSERT (opmphmIsBuild (ks->opmphm), "OPMPHM not build");
2129 520 : cursor_t cursor = 0;
2130 520 : cursor = ksGetCursor (ks);
2131 520 : size_t index = opmphmLookup (ks->opmphm, ks->size, keyName (key));
2132 520 : if (index >= ks->size)
2133 : {
2134 : return 0;
2135 : }
2136 :
2137 520 : Key * found = ks->array[index];
2138 :
2139 520 : if (!strcmp (keyName (found), keyName (key)))
2140 : {
2141 88 : cursor = index;
2142 88 : if (options & KDB_O_POP)
2143 : {
2144 0 : return elektraKsPopAtCursor (ks, cursor);
2145 : }
2146 : else
2147 : {
2148 88 : ksSetCursor (ks, cursor);
2149 88 : return found;
2150 : }
2151 : }
2152 : else
2153 : {
2154 432 : ksSetCursor (ks, cursor);
2155 432 : return 0;
2156 : }
2157 : }
2158 :
2159 : #endif
2160 :
2161 : /**
2162 : * @brief Process Callback + maps to correct binary/hashmap search
2163 : *
2164 : * @return the found key
2165 : */
2166 10407460 : static Key * elektraLookupSearch (KeySet * ks, Key * key, option_t options)
2167 : {
2168 10407460 : if (!ks->size) return 0;
2169 : typedef Key * (*callback_t) (KeySet * ks, Key * key, Key * found, option_t options);
2170 : union
2171 : {
2172 : callback_t f;
2173 : void * v;
2174 : } conversation;
2175 :
2176 10261456 : Key * found = 0;
2177 :
2178 : #ifdef ELEKTRA_ENABLE_OPTIMIZATIONS
2179 : // flags incompatible with OPMPHM
2180 10261456 : if (test_bit (options, (KDB_O_WITHOWNER | KDB_O_NOCASE)))
2181 : {
2182 : // remove KDB_O_OPMPHM and set KDB_O_BINSEARCH
2183 2474 : clear_bit (options, KDB_O_OPMPHM);
2184 2474 : set_bit (options, KDB_O_BINSEARCH);
2185 : }
2186 :
2187 10261456 : if (!ks->opmphmPredictor && ks->size > opmphmPredictorActionLimit)
2188 : {
2189 : // lazy loading of predictor when over action limit
2190 4 : ks->opmphmPredictor = opmphmPredictorNew ();
2191 : }
2192 :
2193 : // predictor
2194 10261456 : if (!test_bit (options, (KDB_O_BINSEARCH | KDB_O_OPMPHM)))
2195 : {
2196 : // predictor not overruled
2197 10258462 : if (ks->opmphmPredictor)
2198 : {
2199 94 : if (test_bit (ks->flags, KS_FLAG_NAME_CHANGE))
2200 : {
2201 : // KeySet changed ask predictor
2202 80 : if (opmphmPredictor (ks->opmphmPredictor, ks->size))
2203 : {
2204 0 : set_bit (options, KDB_O_OPMPHM);
2205 : }
2206 : else
2207 : {
2208 80 : set_bit (options, KDB_O_BINSEARCH);
2209 : }
2210 : // resolve flag
2211 80 : clear_bit (ks->flags, (keyflag_t) KS_FLAG_NAME_CHANGE);
2212 : }
2213 : else
2214 : {
2215 14 : if (opmphmIsBuild (ks->opmphm))
2216 : {
2217 2 : opmphmPredictorIncCountOpmphm (ks->opmphmPredictor);
2218 2 : set_bit (options, KDB_O_OPMPHM);
2219 : }
2220 12 : else if (opmphmPredictorIncCountBinarySearch (ks->opmphmPredictor, ks->size))
2221 : {
2222 : // endless binary search protection
2223 0 : set_bit (options, KDB_O_OPMPHM);
2224 : }
2225 : else
2226 : {
2227 12 : set_bit (options, KDB_O_BINSEARCH);
2228 : }
2229 : }
2230 : }
2231 : else
2232 : {
2233 : // when predictor is not here use binary search as backup
2234 10258368 : set_bit (options, KDB_O_BINSEARCH);
2235 : }
2236 : }
2237 :
2238 : // the actual lookup
2239 10261456 : if ((options & (KDB_O_BINSEARCH | KDB_O_OPMPHM)) == KDB_O_OPMPHM)
2240 : {
2241 520 : if (opmphmIsBuild (ks->opmphm) || !elektraLookupBuildOpmphm (ks))
2242 : {
2243 520 : found = elektraLookupOpmphmSearch (ks, key, options);
2244 : }
2245 : else
2246 : {
2247 : // when OPMPHM build fails use binary search as backup
2248 0 : found = elektraLookupBinarySearch (ks, key, options);
2249 : }
2250 : }
2251 10260936 : else if ((options & (KDB_O_BINSEARCH | KDB_O_OPMPHM)) == KDB_O_BINSEARCH)
2252 : {
2253 10260936 : found = elektraLookupBinarySearch (ks, key, options);
2254 : }
2255 : else
2256 : {
2257 : // both flags set, make the best out of it
2258 0 : if (opmphmIsBuild (ks->opmphm))
2259 : {
2260 0 : found = elektraLookupOpmphmSearch (ks, key, options);
2261 : }
2262 : else
2263 : {
2264 0 : found = elektraLookupBinarySearch (ks, key, options);
2265 : }
2266 : }
2267 :
2268 : // remove flags to not interfere with callback
2269 10261456 : clear_bit (options, (KDB_O_OPMPHM | KDB_O_BINSEARCH));
2270 : #else
2271 : found = elektraLookupBinarySearch (ks, key, options);
2272 : #endif
2273 10261456 : Key * ret = found;
2274 :
2275 10261456 : if (keyGetMeta (key, "callback"))
2276 : {
2277 11773 : if (keyGetBinary (key, &conversation.v, sizeof (conversation)) == sizeof (conversation))
2278 : {
2279 11773 : if (conversation.v != 0)
2280 : {
2281 11773 : ret = (*conversation.f) (ks, key, found, options);
2282 : }
2283 : }
2284 : }
2285 :
2286 : return ret;
2287 : }
2288 :
2289 : static Key * elektraLookupCreateKey (KeySet * ks, Key * key, ELEKTRA_UNUSED option_t options)
2290 : {
2291 5879 : Key * ret = keyDup (key);
2292 5879 : ksAppendKey (ks, ret);
2293 : return ret;
2294 : }
2295 :
2296 :
2297 : /**
2298 : * Look for a Key contained in @p ks that matches the name of the @p key.
2299 : *
2300 : * @note Applications should only use ksLookup() with cascading
2301 : * keys (key name starting with `/`).
2302 : * Furthermore, a lookup should be done for every key (also when iterating
2303 : * over keys) so that the specifications are honored correctly.
2304 : * Keys of all namespaces need to be present so that ksLookup()
2305 : * can work correctly, so make sure to also use kdbGet() with a cascading
2306 : * key.
2307 : *
2308 : * @p ksLookup() is designed to let you work with a
2309 : * KeySet containing all keys of the application. The
2310 : * idea is to fully kdbGet() the whole configuration of your application and
2311 : * process it all at once with many @p ksLookup().
2312 : *
2313 : * This function is efficient (at least using binary search). Together with
2314 : * kdbGet() which can you load the whole configuration
2315 : * you can write very effective but short code for configuration:
2316 : *
2317 : * @snippet kdbget.c basic usage
2318 : *
2319 : * This is the way programs should get their configuration and
2320 : * search after the values. It is guaranteed that more namespaces can be
2321 : * added easily and that all values can be set by admin and user.
2322 : * Furthermore, using the kdb-tool, it is possible to introspect which values
2323 : * an application will get (by doing the same cascading lookup).
2324 : *
2325 : * If found, @p ks internal cursor will be positioned in the matched key
2326 : * (also accessible by ksCurrent()), and a pointer to the Key is returned.
2327 : * If not found, @p ks internal cursor will not move, and a NULL pointer is
2328 : * returned.
2329 : *
2330 : * Cascading lookups will by default search in
2331 : * all namespaces (proc/, dir/, user/ and system/), but will also correctly consider
2332 : * the specification (=metadata) in spec/:
2333 : *
2334 : * - @p override/# will make sure that another key is considered before
2335 : * - @p namespace/# will change the number and/or order in which the
2336 : * namespaces are searched
2337 : * - @p fallback/# will search for other keys when the other possibilities
2338 : * up to now were not successful
2339 : * - @p default to return the given value when not even @p fallback keys were
2340 : * found.
2341 : *
2342 : *
2343 : * @note override and fallback work recursively, while default does not.
2344 : *
2345 : * This process is very flexible, but it would be boring to manually follow all this links
2346 : * to find out which key will be taken in the end. Use `kdb get -v` to trace the keys.
2347 : *
2348 : *
2349 : * @par KDB_O_POP
2350 : * When ::KDB_O_POP is set the key which was found will be ksPop()ed. ksCurrent()
2351 : * will not be changed, only iff ksCurrent() is the searched key, then the keyset
2352 : * will be ksRewind()ed.
2353 : *
2354 : * @note Like in ksPop() the popped key always needs to be keyDel() afterwards, even
2355 : * if it is appended to another keyset.
2356 : *
2357 : * @warning All cursors on the keyset will be invalid
2358 : * iff you use ::KDB_O_POP, so don't use this if you rely on a cursor, see ksGetCursor().
2359 : *
2360 : * The invalidation of cursors does not matter if you use multiple keysets, e.g.
2361 : * by using ksDup(). E.g., to separate ksLookup() with ::KDB_O_POP and ksAppendKey():
2362 :
2363 : * @snippet ksLookupPop.c f
2364 : *
2365 : * This is also a nice example how a complete application with ksLookup() can look like.
2366 : *
2367 : * @par KDB_O_DEL
2368 : * Passing ::KDB_O_DEL will cause the deletion of the parameter @p key using keyDel().
2369 : *
2370 : * @par KDB_O_NOALL (deprecated)
2371 : * When ::KDB_O_NOALL is set the keyset will be only searched from ksCurrent()
2372 : * to ksTail(). You need to ksRewind() the keyset yourself. ksCurrent() is
2373 : * always set properly after searching a key, so you can go on searching
2374 : * another key after the found key.
2375 : * \n
2376 : * When ::KDB_O_NOALL is not set the cursor will stay untouched and all keys
2377 : * are considered. A much more efficient binary search will be used then.
2378 : *
2379 : * @par KDB_O_WITHOWNER (deprecated)
2380 : * Also consider correct owner (needs ::KDB_O_NOALL).
2381 : *
2382 : * @par KDB_O_NOCASE (deprecated)
2383 : * Lookup ignoring case (needs ::KDB_O_NOALL).
2384 : *
2385 : *
2386 : * @par Hybrid search
2387 : * When Elektra is compiled with `ENABLE_OPTIMIZATIONS=ON` a hybrid search decides
2388 : * dynamically between the binary search and the [OPMPHM](https://master.libelektra.org/doc/dev/data-structures.md#order-preserving-minimal-perfect-hash-map-aka-opmphm).
2389 : * The hybrid search can be overruled by passing ::KDB_O_OPMPHM or ::KDB_O_BINSEARCH in the options to ksLookup().
2390 : *
2391 : *
2392 : *
2393 : * @param ks where to look for
2394 : * @param key the key object you are looking for
2395 : * @param options of type ::option_t with some @p KDB_O_* option bits as explained above
2396 : * @return pointer to the Key found, 0 otherwise
2397 : * @retval 0 on NULL pointers
2398 : * @see ksLookupByName() to search by a name given by a string
2399 : * @see ksCurrent(), ksRewind(), ksNext() for iterating over a keyset
2400 : */
2401 10961121 : Key * ksLookup (KeySet * ks, Key * key, option_t options)
2402 : {
2403 10961121 : if (!ks) return 0;
2404 10961119 : if (!key) return 0;
2405 :
2406 10874238 : const char * name = key->key;
2407 10874238 : if (!name) return 0;
2408 :
2409 10874238 : Key * ret = 0;
2410 10874238 : const int mask = ~KDB_O_DEL & ~KDB_O_CREATE;
2411 :
2412 10874238 : if (options & KDB_O_SPEC)
2413 : {
2414 630 : Key * lookupKey = key;
2415 630 : if (test_bit (key->flags, KEY_FLAG_RO_NAME)) lookupKey = keyDup (key);
2416 630 : ret = elektraLookupBySpec (ks, lookupKey, options & mask);
2417 630 : if (test_bit (key->flags, KEY_FLAG_RO_NAME))
2418 : {
2419 4 : elektraCopyCallbackMeta (key, lookupKey);
2420 4 : keyDel (lookupKey);
2421 : }
2422 : }
2423 10873608 : else if (!(options & KDB_O_NOCASCADING) && strcmp (name, "") && name[0] == '/')
2424 : {
2425 466104 : Key * lookupKey = key;
2426 466104 : if (test_bit (key->flags, KEY_FLAG_RO_NAME)) lookupKey = keyDup (key);
2427 466104 : ret = elektraLookupByCascading (ks, lookupKey, options & mask);
2428 466104 : if (test_bit (key->flags, KEY_FLAG_RO_NAME))
2429 : {
2430 990 : elektraCopyCallbackMeta (key, lookupKey);
2431 990 : keyDel (lookupKey);
2432 : }
2433 : }
2434 10407504 : else if ((options & KDB_O_NOALL)
2435 : // || (options & KDB_O_NOCASE)
2436 : // || (options & KDB_O_WITHOWNER)
2437 : ) // TODO binary search with nocase won't work
2438 : {
2439 44 : ret = elektraLookupLinearSearch (ks, key, options & mask);
2440 : }
2441 : else
2442 : {
2443 10407460 : ret = elektraLookupSearch (ks, key, options & mask);
2444 : }
2445 :
2446 10880117 : if (!ret && options & KDB_O_CREATE) ret = elektraLookupCreateKey (ks, key, options & mask);
2447 :
2448 10874238 : if (options & KDB_O_DEL) keyDel (key);
2449 :
2450 : return ret;
2451 : }
2452 :
2453 : /**
2454 : * Convenience method to look for a Key contained in @p ks that matches @p name.
2455 : *
2456 : * @see ksLookup() for explanation of the functionality and example.
2457 : *
2458 : * @param ks where to look for
2459 : * @param name key name you are looking for
2460 : * @param options some @p KDB_O_* option bits:
2461 : * - @p KDB_O_POP @n
2462 : * Pop the key which was found.
2463 : * - See ksLookup() for others
2464 : *
2465 : * @return pointer to the Key found, 0 otherwise
2466 : * @retval 0 on NULL pointers
2467 : * @see ksLookup() to search with a given key
2468 : * @see ksCurrent(), ksRewind(), ksNext()
2469 : */
2470 993683 : Key * ksLookupByName (KeySet * ks, const char * name, option_t options)
2471 : {
2472 993683 : Key * found = 0;
2473 :
2474 993683 : if (!ks) return 0;
2475 990962 : if (!name) return 0;
2476 :
2477 990962 : if (!ks->size) return 0;
2478 :
2479 : struct _Key key;
2480 :
2481 539566 : keyInit (&key);
2482 539566 : elektraKeySetName (&key, name, KEY_META_NAME | KEY_CASCADING_NAME);
2483 :
2484 539566 : found = ksLookup (ks, &key, options);
2485 539566 : elektraFree (key.key);
2486 539566 : ksDel (key.meta); // sometimes owner is set
2487 539566 : return found;
2488 : }
2489 :
2490 :
2491 : /*
2492 : * Lookup for a Key contained in @p ks KeySet that matches @p value,
2493 : * starting from ks' ksNext() position.
2494 : *
2495 : * If found, @p ks internal cursor will be positioned in the matched key
2496 : * (also accessible by ksCurrent()), and a pointer to the Key is returned.
2497 : * If not found, @p ks internal cursor won't move, and a NULL pointer is
2498 : * returned.
2499 : *
2500 : * This method skips binary keys.
2501 : *
2502 : * @par Example:
2503 : * @code
2504 : ksRewind(ks);
2505 : while (key=ksLookupByString(ks,"my value",0))
2506 : {
2507 : // show all keys which value="my value"
2508 : keyToStream(key,stdout,0);
2509 : }
2510 : * @endcode
2511 : *
2512 : * @param ks where to look for
2513 : * @param value the value which owner key you want to find
2514 : * @param options some @p KDB_O_* option bits. Currently supported:
2515 : * - @p KDB_O_NOALL @n
2516 : * Only search from ksCurrent() to end of keyset, see ksLookup().
2517 : * - @p KDB_O_NOCASE @n
2518 : * Lookup ignoring case.
2519 : * @return the Key found, 0 otherwise
2520 : * @see ksLookupByBinary()
2521 : * @see keyCompare() for very powerful Key lookups in KeySets
2522 : * @see ksCurrent(), ksRewind(), ksNext()
2523 : */
2524 0 : Key * ksLookupByString (KeySet * ks, const char * value, option_t options)
2525 : {
2526 0 : cursor_t init = 0;
2527 0 : Key * current = 0;
2528 :
2529 0 : if (!ks) return 0;
2530 :
2531 0 : if (!(options & KDB_O_NOALL))
2532 : {
2533 0 : ksRewind (ks);
2534 0 : init = ksGetCursor (ks);
2535 : }
2536 :
2537 0 : if (!value) return 0;
2538 :
2539 0 : while ((current = ksNext (ks)) != 0)
2540 : {
2541 0 : if (!keyIsString (current)) continue;
2542 :
2543 : /*fprintf (stderr, "Compare %s with %s\n", keyValue(current), value);*/
2544 :
2545 0 : if ((options & KDB_O_NOCASE) && !elektraStrCaseCmp (keyValue (current), value))
2546 : break;
2547 0 : else if (!strcmp (keyValue (current), value))
2548 : break;
2549 : }
2550 :
2551 : /* reached end of KeySet */
2552 0 : if (!(options & KDB_O_NOALL))
2553 : {
2554 0 : ksSetCursor (ks, init);
2555 : }
2556 :
2557 : return current;
2558 : }
2559 :
2560 :
2561 : /*
2562 : * Lookup for a Key contained in @p ks KeySet that matches the binary @p value,
2563 : * starting from ks' ksNext() position.
2564 : *
2565 : * If found, @p ks internal cursor will be positioned in the matched key.
2566 : * That means it is also accessible by ksCurrent(). A pointer to the Key
2567 : * is returned. If not found, @p ks internal cursor won't move, and a
2568 : * NULL pointer is returned.
2569 : *
2570 : * This method skips string keys.
2571 : *
2572 : * @param ks where to look for
2573 : * @param value the value which owner key you want to find
2574 : * @param size the size of @p value
2575 : * @param options some @p KDB_O_* option bits:
2576 : * - @p KDB_O_NOALL @n
2577 : * Only search from ksCurrent() to end of keyset, see above text.
2578 : * @return the Key found, NULL otherwise
2579 : * @retval 0 on NULL pointer
2580 : * @see ksLookupByString()
2581 : * @see keyCompare() for very powerful Key lookups in KeySets
2582 : * @see ksCurrent(), ksRewind(), ksNext()
2583 : */
2584 0 : Key * ksLookupByBinary (KeySet * ks, const void * value, size_t size, option_t options)
2585 : {
2586 0 : cursor_t init = 0;
2587 0 : Key * current = 0;
2588 :
2589 0 : if (!ks) return 0;
2590 :
2591 0 : if (!(options & KDB_O_NOALL))
2592 : {
2593 0 : ksRewind (ks);
2594 0 : init = ksGetCursor (ks);
2595 : }
2596 :
2597 0 : while ((current = ksNext (ks)))
2598 : {
2599 0 : if (!keyIsBinary (current)) continue;
2600 :
2601 0 : if (size != current->dataSize) continue;
2602 :
2603 0 : if (!value)
2604 : {
2605 0 : if (!current->data.v)
2606 : break;
2607 : else
2608 0 : continue;
2609 : }
2610 :
2611 0 : if (current->data.v && !memcmp (current->data.v, value, size)) break;
2612 : }
2613 :
2614 : /* reached end of KeySet */
2615 0 : if (!(options & KDB_O_NOALL))
2616 : {
2617 0 : ksSetCursor (ks, init);
2618 : }
2619 :
2620 : return 0;
2621 : }
2622 :
2623 :
2624 : /*********************************************************************
2625 : * Data constructors (protected) *
2626 : *********************************************************************/
2627 :
2628 :
2629 : /**
2630 : * @internal
2631 : *
2632 : * Resize keyset.
2633 : *
2634 : * For internal usage only.
2635 : *
2636 : * Don't use that function to be portable. You can give an hint
2637 : * how large the keyset should be in ksNew().
2638 : *
2639 : * Subsequent is the description of the implementation with array.
2640 : * ksResize() enlarge or shrink the internal array to wished
2641 : * size alloc.
2642 : *
2643 : * If you resize it to n, you can be sure to fill in n-1 elements,
2644 : * the n-th element will do an automatic resize to n*2. So give
2645 : * some spare to avoid wasteful duplication.
2646 : *
2647 : * @param ks the keyset which should be resized
2648 : * @param alloc the size to which the array will be resized
2649 : * @retval 1 on success
2650 : * @retval 0 on nothing done because keyset would be too small.
2651 : * @retval -1 if alloc is smaller then current size of keyset.
2652 : * @retval -1 on memory error or null ptr
2653 : */
2654 1675043 : int ksResize (KeySet * ks, size_t alloc)
2655 : {
2656 1675043 : if (!ks) return -1;
2657 :
2658 1675043 : alloc++; /* for ending null byte */
2659 1675043 : if (alloc == ks->alloc) return 1;
2660 624739 : if (alloc < ks->size) return 0;
2661 624739 : if (alloc < KEYSET_SIZE)
2662 : {
2663 565936 : if (ks->alloc != KEYSET_SIZE)
2664 : alloc = KEYSET_SIZE;
2665 : else
2666 : return 0;
2667 : }
2668 :
2669 81882 : if (ks->array == NULL)
2670 : { /* Not allocated up to now */
2671 0 : ks->alloc = alloc;
2672 0 : ks->size = 0;
2673 0 : ks->array = elektraMalloc (sizeof (struct _Key *) * ks->alloc);
2674 0 : clear_bit (ks->flags, (keyflag_t) KS_FLAG_MMAP_ARRAY);
2675 0 : if (!ks->array)
2676 : {
2677 : /*errno = KDB_ERR_NOMEM;*/
2678 : return -1;
2679 : }
2680 : }
2681 81882 : ks->alloc = alloc;
2682 :
2683 81882 : if (test_bit (ks->flags, KS_FLAG_MMAP_ARRAY))
2684 : {
2685 : // need to move the ks->array out of mmap
2686 0 : Key ** new = elektraMalloc (sizeof (struct _Key *) * ks->alloc);
2687 0 : if (!new)
2688 : {
2689 : /*errno = KDB_ERR_NOMEM;*/
2690 : return -1;
2691 : }
2692 0 : elektraMemcpy (new, ks->array, ks->size + 1); // copy including ending NULL
2693 0 : ks->array = new;
2694 0 : clear_bit (ks->flags, (keyflag_t) KS_FLAG_MMAP_ARRAY);
2695 : }
2696 :
2697 81882 : if (elektraRealloc ((void **) &ks->array, sizeof (struct _Key *) * ks->alloc) == -1)
2698 : {
2699 0 : elektraFree (ks->array);
2700 0 : ks->array = 0;
2701 : /*errno = KDB_ERR_NOMEM;*/
2702 0 : return -1;
2703 : }
2704 :
2705 : return 1;
2706 : }
2707 :
2708 : /**
2709 : * @internal
2710 : *
2711 : * Returns current allocation size.
2712 : *
2713 : * This is the maximum size before a reallocation
2714 : * happens.
2715 : *
2716 : * @param ks the keyset object to work with
2717 : * @return allocated size*/
2718 630 : size_t ksGetAlloc (const KeySet * ks)
2719 : {
2720 630 : return ks->alloc - 1;
2721 : }
2722 :
2723 :
2724 : /**
2725 : * @internal
2726 : *
2727 : * KeySet object initializer.
2728 : *
2729 : * You should always use ksNew() instead of ksInit().
2730 : *
2731 : * Every KeySet object that will be used must be initialized first, to setup
2732 : * pointers, counters, etc. After use, all ksInit()ialized KeySets must be
2733 : * cleaned with ksClear().
2734 : *
2735 : * @see ksNew(), ksClose(), keyInit()
2736 : * @retval 0 on success
2737 : */
2738 2807384 : int ksInit (KeySet * ks)
2739 : {
2740 2807384 : ks->array = 0;
2741 :
2742 2807384 : ks->size = 0;
2743 2807384 : ks->alloc = 0;
2744 2807384 : ks->flags = 0;
2745 :
2746 2807384 : ksRewind (ks);
2747 :
2748 : #ifdef ELEKTRA_ENABLE_OPTIMIZATIONS
2749 2807384 : ks->opmphm = NULL;
2750 : // first lookup should predict so invalidate it
2751 2807384 : elektraOpmphmInvalidate (ks);
2752 2807384 : ks->opmphmPredictor = NULL;
2753 : #endif
2754 :
2755 2807384 : return 0;
2756 : }
2757 :
2758 :
2759 : /**
2760 : * @internal
2761 : *
2762 : * KeySet object initializer.
2763 : *
2764 : * @see ksDel(), ksNew(), keyInit()
2765 : * @retval 0 on success
2766 : */
2767 2872565 : int ksClose (KeySet * ks)
2768 : {
2769 : Key * k;
2770 :
2771 2872565 : ksRewind (ks);
2772 18947071 : while ((k = ksNext (ks)) != 0)
2773 : {
2774 13201941 : keyDecRef (k);
2775 13201941 : keyDel (k);
2776 : }
2777 :
2778 2872565 : if (ks->array && !test_bit (ks->flags, KS_FLAG_MMAP_ARRAY))
2779 : {
2780 2871971 : elektraFree (ks->array);
2781 : }
2782 2872565 : clear_bit (ks->flags, (keyflag_t) KS_FLAG_MMAP_ARRAY);
2783 :
2784 2872565 : ks->array = 0;
2785 2872565 : ks->alloc = 0;
2786 :
2787 2872565 : ks->size = 0;
2788 :
2789 2872565 : elektraOpmphmInvalidate (ks);
2790 :
2791 2872565 : return 0;
2792 : }
2793 :
2794 :
2795 : /**
2796 : * @}
2797 : */
|