LCOV - code coverage report
Current view: top level - src/libs/elektra - keyset.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 714 778 91.8 %
Date: 2019-09-12 12:28:41 Functions: 50 52 96.2 %

          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, &current)) break;
    1972             :                 }
    1973         176 :                 else if (options & KDB_O_WITHOWNER)
    1974             :                 {
    1975           0 :                         if (!keyCompareByNameOwner (&key, &current)) break;
    1976             :                 }
    1977         176 :                 else if (options & KDB_O_NOCASE)
    1978             :                 {
    1979          84 :                         if (!keyCompareByNameCase (&key, &current)) break;
    1980             :                 }
    1981          92 :                 else if (!keyCompareByName (&key, &current))
    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             :  */

Generated by: LCOV version 1.13