| Elektra 0.11.0

Macros | Enumerations | Functions
KeySet

Methods to manipulate KeySets. More...

## Macros
#define | KS_END ((Key *) 0)
| End of a list of keys.

## Enumerations
enum | elektraLookupFlags { KDB_O_NONE = 0 , KDB_O_DEL = 1 , KDB_O_POP = 1 << 1 }
| Options to change the default behavior of ksLookup() functions. More...

## Functions
KeySet * | ksNew (size_t alloc,...)
| Allocate, initialize and return a new KeySet object.
KeySet * | ksVNew (size_t alloc, va_list va)
| Allocate, initialize and return a new KeySet object.
KeySet * | ksDup (const KeySet *source)
| Return a duplicate of a KeySet.
int | ksCopy (KeySet *dest, const KeySet *source)
| Replace the content of a KeySet with another one.
int | ksDel (KeySet *ks)
| A destructor for KeySet objects.
int | ksClear (KeySet *ks)
| Empties a KeySet.
uint16_t | ksIncRef (KeySet *ks)
| Increment the reference counter of a KeySet object.
uint16_t | ksDecRef (KeySet *ks)
| Decrement the reference counter of a KeySet object.
uint16_t | ksGetRef (const KeySet *ks)
| Return the current reference counter value of a KeySet object.
ssize_t | ksGetSize (const KeySet *ks)
| Return the number of Keys that `ks` contains.
ssize_t | ksSearch (const KeySet *ks, const Key *key)
| Search in a key set, either yielding the actual index of the key, if the key has been found within the key set, or a negative value indicating the insertion index of the key, if the key would be inserted.
ssize_t | ksAppendKey (KeySet *ks, Key *toAppend)
| Appends a Key to the end of `ks`.
ssize_t | ksAppend (KeySet *ks, const KeySet *toAppend)
| Append all Keys in `toAppend` to the end of the KeySet `ks`.
ssize_t | ksRename (KeySet *ks, const Key *root, const Key *newRoot)
| Moves all keys below `root` to below `newRoot`.
elektraCursor | ksFindHierarchy (const KeySet *ks, const Key *root, elektraCursor *end)
| Searches for the start and optionally end of the key hierarchy rooted at `root` in `ks`.
KeySet * | ksBelow (const KeySet *ks, const Key *root)
| Retrieves all Keys from KeySet `ks` that are below or at `root`.
KeySet * | ksCut (KeySet *ks, const Key *cutpoint)
| Cuts out all Keys from KeySet `ks` that are below or at `cutpoint`.
Key * | ksPop (KeySet *ks)
| Remove and return the last Key of `ks`.
int | ksRewind (KeySet *ks)
| Rewinds the KeySet internal cursor.
Key * | ksNext (KeySet *ks)
| Returns the next Key in a KeySet.
Key * | ksCurrent (const KeySet *ks)
| Return the current Key.
elektraCursor | ksGetCursor (const KeySet *ks)
| Get the internal cursor of the KeySet.
Key * | ksAtCursor (const KeySet *ks, elektraCursor pos)
| Return Key at given position `pos`.
int | ksSetCursor (KeySet *ks, elektraCursor cursor)
| Set the KeySet internal cursor to `cursor`.
Key * | ksLookup (KeySet *ks, Key *key, elektraLookupFlags options)
| Look for a Key contained in `ks` that matches the name of the `key`.
Key * | ksLookupByName (KeySet *ks, const char *name, elektraLookupFlags options)
| Convenience method to look for a Key contained in `ks` with name `name`.
ssize_t | ksSubtract (KeySet *total, const KeySet *sub)
| Remove all the keys in `sub` from `total`.

## Detailed Description

Methods to manipulate KeySets.

A KeySet is a set of keys.

Most important properties of a KeySet:

- Allows us to iterate over all keys (in any depth)
- Iteration is always sorted
- Fast key lookup
- A Key may be shared among many KeySets.

The most important methods of KeySet:

- With ksNew() you can create a new KeySet.
- You can append keys with ksAppendKey() or with ksAppend() you can append a whole keyset.
- Using ksLookup() you can lookup (or pop with KDB_O_POP) a key.
- With ksGetSize() and ksAtCursor() you can iterate through the keyset. Be assured that you will get every key of the set in a stable order (parents before children).

KeySet is the most important data structure in Elektra. It makes it possible to get and store many keys at once inside the database. In addition to that, the class can be used as high level datastructure in applications and it can be used in plugins to manipulate or check configuration.

With ksLookupByName() it is possible to fetch easily specific keys out of the list of keys.

You can easily create and iterate keys:

// create a new keyset with 3 keys
// with a hint that about 20 keys will be inside
KeySet * myConfig = ksNew (20, keyNew ("user:/name1", KEY_END), keyNew ("user:/name2", KEY_END), keyNew ("user:/name3", KEY_END), KS_END);
// append a key in the keyset
ksAppendKey (myConfig, keyNew ("user:/name4", KEY_END));
Key * current;
for (elektraCursor it = 0; it < ksGetSize (myConfig); ++it)
{
current = ksAtCursor (myConfig, it);
printf ("Key name is %s.\n", keyName (current));
}
ksDel (myConfig); // delete keyset and all keys appended
keyNew
Key * keyNew(const char *name,...)
A practical way to fully create a Key object in one step.
Definition key.c:144
keyName
const char * keyName(const Key *key)
Returns a pointer to the abbreviated real internal key name.
Definition elektra/keyname.c:429
ksDel
int ksDel(KeySet *ks)
A destructor for KeySet objects.
Definition keyset.c:521
ksGetSize
ssize_t ksGetSize(const KeySet *ks)
Return the number of Keys that ks contains.
Definition keyset.c:791
KS_END
#define KS_END
End of a list of keys.
Definition kdbenum.c:156
ksAppendKey
ssize_t ksAppendKey(KeySet *ks, Key *toAppend)
Appends a Key to the end of ks.
Definition keyset.c:968
ksAtCursor
Key * ksAtCursor(const KeySet *ks, elektraCursor pos)
Return Key at given position pos.
Definition keyset.c:1978
ksNew
KeySet * ksNew(size_t alloc,...)
Allocate, initialize and return a new KeySet object.
Definition keyset.c:282

Copy-on-Write

Keysets employ copy-on-write techniques to minimize memory footprint. If you create a copy or a duplication of a keyset, the resulting keyset initially references the same data as the source keyset. Only if add or remove keys from a keyset additional memory is allocated.

## Macro Definition Documentation

## ◆ KS_END

#define KS_END ((Key *) 0)

End of a list of keys.

Use this macro to define the end of a variable-length list of keys.

See also
  ksNew() and ksVNew()

## Enumeration Type Documentation

## ◆ elektraLookupFlags

enum elektraLookupFlags

Options to change the default behavior of ksLookup() functions.

These options can be ORed. That is the |-Operator in C.

See also
  kdbGet(), kdbSet()

Enumerator
KDB_O_NONE | No Option set. See also ksLookup()
KDB_O_DEL | Delete parentKey key in ksLookup(). See also ksLookup()
KDB_O_POP | Pop Parent out of keyset key in ksLookup().
       @see ksPop().

## Function Documentation

## ◆ ksAppend()

ssize_t ksAppend | ( | KeySet * | ks,
|  | const KeySet * | toAppend
| ) |  |

Append all Keys in `toAppend` to the end of the KeySet `ks`.

`toAppend` KeySet will be left unchanged.

If a Key is both in `toAppend` and `ks`, the Key in `ks` will be overwritten.

Postcondition
  Sorted KeySet ks with all Keys it had before and additionally the Keys from toAppend

Parameters

  ks | the KeySet that will receive the Keys
  toAppend | the KeySet that provides the Keys that will be transferred

Returns
  the size of the KeySet `ks` after transfer

Return values

  -1 | on NULL pointers

Since
  1.0.0

See also
  ksAppendKey()

## ◆ ksAppendKey()

ssize_t ksAppendKey | ( | KeySet * | ks,
|  | Key * | toAppend
| ) |  |

Appends a Key to the end of `ks`.

Hands the ownership of the Key `toAppend` to the KeySet `ks`. ksDel(ks) uses keyDel(k) to delete every Key unless it got its reference counter incremented by keyIncRef(), e.g. by another KeySet that contains this Key.

The reference counter of the Key will be incremented to indicate this ownership, and thus `toAppend` is not const.

See also
  keyGetRef()

If the Key's name already exists in the KeySet, it will be replaced with the new Key.

ksAppendKey() will also lock the Key's name from `toAppend`. This is necessary so that the order of the KeySet cannot be destroyed via calls to keySetName().

The KeySet internal cursor will be set to the new Key.

It is safe to directly append newly created Keys:

KeySet * ks = ksNew (1, KS_END);
ksAppendKey (ks, keyNew ("user:/my/new/key", KEY_END));
ksDel (ks);
// key deleted, too!

If you want the key to outlive the KeySet, make sure to do proper ref counting:

KeySet * ks = ksNew (1, KS_END);
Key * k = keyNew ("user:/ref/key", KEY_END);
keyIncRef (k);
ksAppendKey (ks, k);
ksDel (ks);
// now we still can work with the key k!
keyDecRef (k);
keyDel (k);
keyIncRef
uint16_t keyIncRef(Key *key)
Increment the reference counter of a Key object.
Definition key.c:581
keyDecRef
uint16_t keyDecRef(Key *key)
Decrement the reference counter of a Key object.
Definition key.c:620
keyDel
int keyDel(Key *key)
A destructor for Key objects.
Definition key.c:459

You can duplicate the Key to avoid aliasing, but then the Key in the KeySet has another identity:

KeySet * ks = ksNew (1, KS_END);
Key * k = keyNew ("user:/ref/key", KEY_END);
ksAppendKey (ks, keyDup (k, KEY_CP_ALL));
ksDel (ks);
// now we still can work with the key k!
keyDel (k);
KEY_CP_ALL
@ KEY_CP_ALL
Definition kdbenum.c:110

Parameters

  ks | KeySet where `toAppend` should be append
  toAppend | Key that will be appended to `ks` or deleted

Returns
  the size of the KeySet after appending

Return values

  -1 | on NULL pointers
  -1 | if appending failed (only on memory problems). The Key will be deleted then.

Since
  1.0.0

See also
  ksAppend() for appending a KeySet to another KeySet
  keyIncRef() for manually increasing a Key's reference counter

## ◆ ksAtCursor()

Key * ksAtCursor | ( | const KeySet * | ks,
|  | elektraCursor | pos
| ) |  |

Return Key at given position `pos`.

The position is a number starting from 0.

Parameters

  ks | the KeySet to get the Key from
  pos | the position of the Key that should be retrieved

Returns
  the Key at the cursor `pos` on success

Return values

  NULL | on NULL pointer, negative cursor position or a position that does not lie within the KeySet `ks`

Since
  1.0.0

## ◆ ksBelow()

KeySet * ksBelow | ( | const KeySet * | ks,
|  | const Key * | root
| ) |  |

Retrieves all Keys from KeySet `ks` that are below or at `root`.

This function works very much like ksCut(). It returns an identical KeySet, but the Keys also remain in `ks`

Parameters

  ks | the Keyset to copy from
  root | the point where to copy from the Keyset

Returns
  a new allocated KeySet which needs to be deleted with ksDel(). The KeySet consists of all Keys (of the original KeySet ks) below `root`. If `root` exists, it will also be appended.

## ◆ ksClear()

int ksClear | ( | KeySet * | ks | ) |

Empties a KeySet.

This function

- does not check or modify the reference count of `ks`
- decrements the reference count of all keys contained in `ks`
- deletes all keys that where only referenced by `ks`
- resets size of `ks` to 0

Parameters

  ks | the KeySet to clear

Return values

  0 | on success
  -1 | on failure (memory) or ks == NULL

## ◆ ksCopy()

int ksCopy | ( | KeySet * | dest,
|  | const KeySet * | source
| ) |  |

Replace the content of a KeySet with another one.

Most often you may want a duplicate of a KeySet, see ksDup() or append keys, see ksAppend(). In some situations you need to copy Keys from a KeySet to another KeySet, for which this function exists.

Note
  You can also use it to clear a KeySet when you pass a NULL pointer as `source`.

Implementation:
  First all Keys in `dest` will be deleted. Afterwards the content of `source` will be added to the destination.

A flat copy is made, so Keys will not be duplicated, but their reference counter is updated, so both KeySets need to be deleted via ksDel().

int f (KeySet *ks)
{
KeySet *c = ksNew (20, ..., KS_END);
// c receives keys
ksCopy (ks, c); // pass the KeySet to the caller
ksDel (c);
} // caller needs to ksDel (ks)
ksCopy
int ksCopy(KeySet *dest, const KeySet *source)
Replace the content of a KeySet with another one.
Definition keyset.c:476

Parameters

  source | an initialized KeySet or NULL
  dest | an initialized KeySet, where the Keys from `source` get copied to

Return values

  1 | on success
  0 | if `dest` was cleared successfully (`source` is NULL)
  -1 | when `dest` is a NULL pointer

Since
  1.0.0

See also
  ksNew() for creating a new KeySet
  ksDel() for deleting an existing KeySet
  ksDup() for duplicating an existing KeySet
  keyCopy() for copying Keys

## ◆ ksCurrent()

Key * ksCurrent | ( | const KeySet * | ks | ) |

Return the current Key.

The returned pointer is NULL if you reached the end or after ksRewind().

Note
  You must not delete the Key or change the Key, use ksPop() if you want to delete it.

Parameters

  ks | the KeySet object to get the current Key from

Returns
  pointer to the Key pointed by `ks's` cursor

Return values

  0 | on NULL pointer

Since
  1.0.0

See also
  ksNext() to get the next Key in the KeySet
  ksRewind() for resetting the internal cursor of the KeySet

## ◆ ksCut()

KeySet * ksCut | ( | KeySet * | ks,
|  | const Key * | cutpoint
| ) |  |

Cuts out all Keys from KeySet `ks` that are below or at `cutpoint`.

Searches for the `cutpoint` inside the KeySet `ks`. If found, it cuts out this Key and everything which is below (see keyIsBelow()) this Key. These Keys will be missing in the keyset `ks`. Instead, they will be moved to the returned KeySet. If `cutpoint` is not found an empty KeySet is returned and `ks` is not changed.

The cursor will stay at the same Key as it was before. If the cursor was inside the region of cut (moved) Keys, the cursor will be set to the Key before the `cutpoint`.

If you use ksCut() on a KeySet you got from kdbGet() and plan to use kdbSet() later, make sure that you keep all Keys that should not be removed permanently. You have to keep the KeySet that was returned and the KeySet `ks`.

Example:

You have the keyset `ks:`

- `system:/mountpoint/interest`
- `system:/mountpoint/interest/folder`
- `system:/mountpoint/interest/folder/key1`
- `system:/mountpoint/interest/folder/key2`
- `system:/mountpoint/other/key1`

When you use

Key * parentKey = keyNew ("system:/mountpoint/interest", KEY_END);
KDB * kdb = kdbOpen (NULL, parentKey);
KeySet * ks = ksNew (0, KS_END);
kdbGet (kdb, ks, parentKey);
KeySet * returned = ksCut (ks, parentKey);
kdbSet (kdb, ks, parentKey); // all keys below cutpoint are now removed
kdbClose (kdb, parentKey);
kdbSet
int kdbSet(KDB *handle, KeySet *ks, Key *parentKey)
Set Keys to the Key database in an atomic and universal way.
Definition kdb.c:2343
kdbGet
int kdbGet(KDB *handle, KeySet *ks, Key *parentKey)
Retrieve Keys from the Key database in an atomic and universal way.
Definition kdb.c:1734
kdbOpen
KDB * kdbOpen(const KeySet *contract, Key *errorKey)
Opens the session with the Key database.
Definition kdb.c:967
kdbClose
int kdbClose(KDB *handle, Key *errorKey)
Closes the session with the Key database.
Definition kdb.c:1105
ksCut
KeySet * ksCut(KeySet *ks, const Key *cutpoint)
Cuts out all Keys from KeySet ks that are below or at cutpoint.
Definition keyset.c:1608
kdb
This is the main namespace for the C++ binding and libraries.
Definition backend.hpp:31

Then in `returned` are:

- `system:/mountpoint/interest`
- `system:/mountpoint/interest/folder`
- `system:/mountpoint/interest/folder/key1`
- `system:/mountpoint/interest/folder/key2`

And in `ks` are:

- `system:/mountpoint/other/key1`

So kdbSet() permanently removes all keys at or below `system:/mountpoint/interest`.

Parameters

  ks | the Keyset to cut. It will be modified by removing all Keys at or below the cutpoint.
  cutpoint | the point where to cut out the Keyset

Returns
  a new allocated KeySet which needs to be deleted with ksDel(). The KeySet consists of all Keys (of the original KeySet ks) below the cutpoint. If the Key cutpoint exists, it will also be appended.

Return values

  0 | on NULL pointers, no Key name or allocation problems

Since
  1.0.0

See also
  kdbGet() for an explanation on why you might get more Keys than you requested.

## ◆ ksDecRef()

uint16_t ksDecRef | ( | KeySet * | ks | ) |

Decrement the reference counter of a KeySet object.

As long as the reference counter is non-zero, `ksDel()` operations on `key` will be a no-op and return an error code.

Parameters

  key | the KeySet object whose reference counter should get decreased

Returns
  the updated value of the reference counter

Return values

  UINT16_MAX | on NULL pointer
  0 | when the reference counter already was the minimum value 0, the reference counter will not be modified in this case

Since
  1.0.0

See also
  ksGetRef() to retrieve the current reference count
  ksIncRef() for increasing the reference counter and for a more complete explanation of the reference counting system
  ksDel() for deleting a Key

## ◆ ksDel()

int ksDel | ( | KeySet * | ks | ) |

A destructor for KeySet objects.

Every KeySet created by ksNew() must be deleted with ksDel().

When the reference counter of `ks` is non-zero, this function will do nothing and simply return the current value of the reference counter.

It is therefore safe to call `ksDel (ks)` on any `KeySet * ks`.

Parameters

  ks | the KeySet object to delete

Return values

  0 | when the KeySet was freed
  -1 | on NULL pointers

Returns
  the value of the reference counter, if it was non-zero

Since
  1.0.0

See also
  ksNew() for creating a new KeySet
  ksIncRef() for more information about the reference counter

## ◆ ksDup()

KeySet * ksDup | ( | const KeySet * | source | ) |

Return a duplicate of a KeySet.

Objects created with ksDup() must be destroyed with ksDel().

Memory will be allocated as needed for dynamic properties, so you need to ksDel() the returned pointer.

A flat copy is made, so the Keys will not be duplicated, but their reference counter is updated, so both KeySets need to be deleted via ksDel().

Parameters

  source | has to be an initialized KeySet

Returns
  a flat copy of source on success

Return values

  0 | on NULL pointer

Since
  1.0.0

See also
  ksNew() for creating a new KeySet
  ksDel() for deleting a KeySet
  keyDup() for Key duplication

## ◆ ksFindHierarchy()

elektraCursor ksFindHierarchy | ( | const KeySet * | ks,
|  | const Key * | root,
|  | elektraCursor * | end
| ) |  |

Searches for the start and optionally end of the key hierarchy rooted at `root` in `ks`.

The hierarchy will only contain keys in the same namespace as `root`. If `root` is a cascading key, only cascading keys will be part of the hierarchy.

The main use-case for this function is this kind of loop:

elektraCursor end;
for (elektraCursor it = ksFindHierarchy (ks, root, &end); it < end; ++it)
{
Key * cur = ksAtCursor (ks, it);
}
ksFindHierarchy
elektraCursor ksFindHierarchy(const KeySet *ks, const Key *root, elektraCursor *end)
Searches for the start and optionally end of the key hierarchy rooted at root in ks.
Definition keyset.c:1315

Parameters

  ks | The keyset to search in
  root | The root of the hierachy to find
  end | If this is not NULL, it will be set to position of the first key after `root` that is not below `root`. This is useful for loops like the one above. If not keys below `root` exist in `ks`, `end` will always be set to the size of `ks`. This way a loop like the one above will still work correctly.

Return values

  -1 | if `ks` or `root` are NULL

Returns
  the position of either `root` itself or the first key below `root` that is part of `ks`. If no keys below `root` exist in `ks`, the size of `ks` is returned. The snippet above shows why this is useful.

## ◆ ksGetCursor()

elektraCursor ksGetCursor | ( | const KeySet * | ks | ) |

Get the internal cursor of the KeySet.

Warning
  Cursors are getting invalid when the Key was ksPop()ed or ksLookup() with KDB_O_POP was used.

# Read ahead

With the cursors it is possible to read ahead in a KeySet:

elektraCursor jump;
ksRewind (ks);
while ((key = keyNextMeta (ks))!=0)
{
// now mark this key
jump = ksGetCursor(ks);
//code..
keyNextMeta (ks); // now browse on
// use ksCurrent(ks) to check the keys
//code..
// jump back to the position marked before
ksSetCursor(ks, jump);
}
keyNextMeta
const Key * keyNextMeta(Key *key)
Get the next metadata entry of a Key.
Definition keymeta.c:154
ksSetCursor
int ksSetCursor(KeySet *ks, elektraCursor cursor)
Set the KeySet internal cursor to cursor.
Definition keyset.c:2024
ksRewind
int ksRewind(KeySet *ks)
Rewinds the KeySet internal cursor.
Definition keyset.c:1790
ksGetCursor
elektraCursor ksGetCursor(const KeySet *ks)
Get the internal cursor of the KeySet.
Definition keyset.c:1954

# Restoring state

It can also be used to restore the state of a KeySet in a function

int f (KeySet *ks)
{
elektraCursor state = ksGetCursor(ks);
// work with keyset
// now bring the keyset to the state before
ksSetCursor (ks, state);
}

It is of course possible to make the KeySet const and cast its const away to set the cursor. Another way to achieve the same is to ksDup() the KeySet, but it is not as efficient.

An invalid cursor will be returned directly after ksRewind(). When you set an invalid cursor ksCurrent() is 0.

# Using Cursor directly

You can also use the cursor directly by initializing it to some index in the KeySet and then incrementing or decrementing it, to iterate over the KeySet.

Key * cur;
for (elektraCursor cursor = 0; (cur = ksAtCursor (ks, cursor)) != NULL; ++cursor)
{
printf ("%s\n", keyName (cur));
}

You can also use a while loop if you need access to the last cursor position.

elektraCursor cursor = 0;
Key * cur;
while ((cur = ksAtCursor (ks, cursor)) != 0)
{
printf ("%s\n", keyName (cur));
++cursor;
}

Note
  Only use a cursor for the same KeySet which it was made for.

Parameters

  ks | the KeySet object to get the cursor from

Returns
  a valid cursor on success

Return values

  -1 | on NULL pointer
  -1 | on an invalid internal cursor or after ksRewind

Since
  1.0.0

See also
  ksNext() for moving the internal cursor forward
  ksSetCursor() for setting the cursor to a specific position
  ksAtCursor() for getting the Key at a specific position

## ◆ ksGetRef()

uint16_t ksGetRef | ( | const KeySet * | ks | ) |

Return the current reference counter value of a KeySet object.

Parameters

  ks | the KeySet whose reference counter to retrieve

Returns
  the value of the `key's` reference counter

Return values

  -1 | on NULL pointer

Since
  1.0.0

See also
  ksIncRef() for increasing the reference counter and for a more complete explanation of the reference counting system
  ksDecRef() for decreasing the reference counter

## ◆ ksGetSize()

ssize_t ksGetSize | ( | const KeySet * | ks | ) |

Return the number of Keys that `ks` contains.

Parameters

  ks | the KeySet object to get the size from

Returns
  the number of Keys that `ks` contains.

Return values

  -1 | on NULL pointer

Since
  1.0.0

## ◆ ksIncRef()

uint16_t ksIncRef | ( | KeySet * | ks | ) |

Increment the reference counter of a KeySet object.

As long as the reference counter is non-zero, `ksDel()` operations on `key` will be a no-op and return an error code.

Elektra's system for reference counting is not based on a concept of shared ownership. It is more similar to a shared lock, where the counter is used to keep track of how many clients hold the lock.

Initially, the reference counter will be 0. This can be interpreted as the lock being unlocked. When you increment the reference counter, the lock becomes locked and `ksDel()` is blocked and fails. Only when the reference counter is fully decremented back down to 0 again, will `ksDel()` work again.

Note
  The reference counter can never exceed `UINT16_MAX - 1`. `UINT16_MAX` is reserved as an error code.

Postcondition
  `ks's` reference counter is > 0
  `ks's` reference counter is <= UINT16_MAX - 1

Parameters

  ks | the KeySet object whose reference counter should be increased

Returns
  the updated value of the reference counter

Return values

  UINT16_MAX | on NULL pointer
  UINT16_MAX | when the reference counter already was the maximum value `UINT16_MAX - 1`, the reference counter will not be modified in this case

Since
  1.0.0

See also
  ksGetRef() to retrieve the current reference count
  ksDecRef() for decreasing the reference counter
  ksDel() for deleting a Key

## ◆ ksLookup()

Key * ksLookup | ( | KeySet * | ks,
|  | Key * | key,
|  | elektraLookupFlags | options
| ) |  |

Look for a Key contained in `ks` that matches the name of the `key`.

Note
  Applications should only use ksLookup() with cascading Keys (Key name starting with `/`). Furthermore, a lookup should be done for every Key (also when iterating over Keys) so that the specifications are honored correctly. Keys of all namespaces need to be present so that ksLookup() can work correctly, so make sure to also use kdbGet() with a cascading Key.

ksLookup() is designed to let you work with a KeySet containing all Keys of the application. The idea is to fully kdbGet() the whole configuration of your application and process it all at once with many `ksLookup()`.

This function is efficient (at least using binary search). Together with kdbGet(), which you can use to load the whole configuration, you can write very effective and short code for configuration:

Key * key = keyNew ("/sw/tests/myapp/#0/current/", KEY_END);
KDB * handle = kdbOpen (NULL, key);
kdbGet (handle, myConfig, key);
Key * result = ksLookupByName (myConfig, "/sw/tests/myapp/#0/current/testkey1", 0);
ksLookupByName
Key * ksLookupByName(KeySet *ks, const char *name, elektraLookupFlags options)
Convenience method to look for a Key contained in ks with name name.
Definition keyset.c:2778

This is the way programs should get their configuration and search for the values. It is guaranteed, that more namespaces can be added easily and that all values can be set by admin and user. Furthermore, using the kdb-tool, it is possible to introspect which values an application will get (by doing the same cascading lookup).

If found, a pointer to the Key is returned. If not found a NULL pointer is returned.

Cascading lookups will by default search in all namespaces (proc:/, dir:/, user:/ and system:/), but will also correctly consider the specification (=metadata) in spec:/:

- `override/#` will make sure that another Key is considered before
- `namespace/#` will change the number and/or order in which the namespaces are searched
- `fallback/#` will search for other Keys when the other possibilities up to now were not successful
- `default` to return the given value when not even `fallback` Keys were found.

Note
  override and fallback work recursively, while default does not.

This process is very flexible, but it would be boring to manually follow all this links to find out which Key will be taken in the end. Use `kdb get -v` to trace the Keys.

KDB_O_POP
  When KDB_O_POP is set the Key which was found will be ksPop()ed.

Note
  Like in ksPop() the popped Key always needs to be keyDel() afterwards, even if it is appended to another KeySet.

void f (KeySet * iterator, KeySet * lookup)
{
KeySet * append = ksNew (ksGetSize (lookup), KS_END);
ssize_t ksSize = ksGetSize (iterator);
for (elektraCursor it = 0; it < ksSize; ++it)
{
Key * current = ksAtCursor (iterator, it);
Key * key = ksLookup (lookup, current, KDB_O_POP);
// do something...
ksAppendKey (append, key); // now append it to append, not lookup!
keyDel (key); // make sure to ALWAYS delete poped keys.
}
ksAppend (lookup, append);
// now lookup needs to be sorted only once, append never
ksDel (append);
}
ksLookup
Key * ksLookup(KeySet *ks, Key *key, elektraLookupFlags options)
Look for a Key contained in ks that matches the name of the key.
Definition keyset.c:2714
ksAppend
ssize_t ksAppend(KeySet *ks, const KeySet *toAppend)
Append all Keys in toAppend to the end of the KeySet ks.
Definition keyset.c:1081
KDB_O_POP
@ KDB_O_POP
Pop Parent out of keyset key in ksLookup().
Definition kdbenum.c:186

This is also a nice example how a complete application with ksLookup() can look like.

KDB_O_DEL
  Passing KDB_O_DEL will cause the deletion of the parameter `key` using keyDel().

Hybrid search
  When Elektra is compiled with `ENABLE_OPTIMIZATIONS=ON` a hybrid search decides dynamically between the binary search and the OPMPHM. The hybrid search can be overruled by passing KDB_O_OPMPHM or KDB_O_BINSEARCH in the options to ksLookup().

Parameters

  ks | the KeySet that should be searched
  key | the Key object you are looking for
  options | of type elektraLookupFlags with some `KDB_O_*` option bits - as explained above

Returns
  pointer to the Key found

Return values

  0 | if no Key has been found
  0 | on NULL pointers

Since
  1.0.0

See also
  ksLookupByName() to search by a name given by a string
  ksGetSize(), ksAtCursor() for iterating over a KeySet

## ◆ ksLookupByName()

Key * ksLookupByName | ( | KeySet * | ks,
|  | const char * | name,
|  | elektraLookupFlags | options
| ) |  |

Convenience method to look for a Key contained in `ks` with name `name`.

There are several options that can be used in conjunction with this function. All possible option flags can be found in elektraLookupFlags

Parameters

  ks | the KeySet that should be searched
  name | name of the Key you are looking for
  options | some `KDB_O_*` option bits (KDB_O_POP, KDB_O_DEL): See ksLookup() or elektraLookupFlags for possible options

Returns
  pointer to the Key found

Return values

  0 | if no Key has been found
  0 | on NULL pointers

Since
  1.0.0

See also
  ksLookup() for explanation of the functionality and examples.
  ksGetSize(), ksAtCursor() for iterating over a KeySet

## ◆ ksNew()

KeySet * ksNew | ( | size_t | alloc,
|  |  | ...
| ) |  |

Allocate, initialize and return a new KeySet object.

Objects created with ksNew() must be destroyed with ksDel().

You can use an arbitrary long list of parameters to preload the KeySet with a list of Keys. Either your first and only parameter is 0 or your last parameter must be KS_END.

So, terminate with ksNew(0, KS_END) or ksNew(20, ..., KS_END)

Warning
  Never use ksNew(0, keyNew(...), KS_END). If the first parameter is 0, other arguments are ignored.

The first parameter `alloc` defines how many Keys can be added without reallocation. If you pass any alloc size greater than 0, but less than 16, it will default to 16.

For most uses

KeySet * keys = ksNew (1, KS_END);
// enough memory for up to 16 keys, without needing reallocation
ksDel (keys);

will be fine. The alloc size will be 16 and will double whenever size reaches alloc size, so it also performs well with large KeySets.

You can defer the allocation of the internal array that holds the Keys, by passing 0 as the alloc size. This is useful if it is unclear whether your KeySet will actually hold any Keys and you want to avoid a malloc call.

// Create KeySet without allocating memory for keys
KeySet * keys = ksNew (0, KS_END);
// The first allocation will happen in ksAppendKey
ksAppendKey(keys, keyNew ("user:/sw/org/app/#0/current/fixedConfiguration/key02", KEY_VALUE, "value02", KEY_END));
// work with the KeySet
ksDel (keys);

If the size of the KeySet is known in advance, use the `alloc` parameter to hint the size of the KeySet.

If your application only needs up to 15 Keys you can request a KeySet of size 15:

KeySet * keys = ksNew (15, keyNew ("user:/sw/org/app/#0/current/fixedConfiguration/key01", KEY_VALUE, "value01", KEY_END),
keyNew ("user:/sw/org/app/#0/current/fixedConfiguration/key02", KEY_VALUE, "value02", KEY_END),
keyNew ("user:/sw/org/app/#0/current/fixedConfiguration/key03", KEY_VALUE, "value03", KEY_END),
// ...
keyNew ("user:/sw/org/app/#0/current/fixedConfiguration/key15", KEY_VALUE, "value15", KEY_END), KS_END);
// work with it
ksDel (keys);

If you start having 3 Keys, and your application needs approximately 200 up to 500 Keys, you can use:

KeySet * config = ksNew (500, keyNew ("user:/sw/org/app/#0/current/fixedConfiguration/key1", KEY_VALUE, "value1", KEY_END),
keyNew ("user:/sw/org/app/#0/current/fixedConfiguration/key2", KEY_VALUE, "value2", KEY_END),
keyNew ("user:/sw/org/app/#0/current/fixedConfiguration/key3", KEY_VALUE, "value3", KEY_END),
KS_END); // don't forget the KS_END at the end!
// work with it
ksDel (config);

Alloc size is 500, the size of the KeySet will be 3 after ksNew. This means the KeySet will reallocate when appending more than 497 keys.

The main benefit of taking a list of variant length parameters is to be able to have one C-Statement for any possible KeySet. If you prefer, you can always create an empty KeySet and use ksAppendKey().

Postcondition
  the KeySet is rewinded properly

Parameters

  alloc | gives a hint for how many Keys may be stored initially

Returns
  a ready to use KeySet object

Return values

  0 | on memory error

Since
  1.0.0

See also
  ksDel() to free the KeySet afterwards
  ksDup() to duplicate an existing KeySet
  ksAppendKey() to append individual Keys to a KeySet

## ◆ ksNext()

Key * ksNext | ( | KeySet * | ks | ) |

Returns the next Key in a KeySet.

KeySets have an internal cursor that can be reset with ksRewind(). Every time ksNext() is called, the cursor is incremented and the new current Key is returned.

You'll get a NULL pointer if the Key at the end of the KeySet has been reached. On subsequent calls of ksNext() it will still return the NULL pointer.

The `ks` internal cursor will be changed, so it is not const.

Note
  You must not delete or change the Key, use ksPop() if you want to delete it.
  That applications must do ksLookup() with an cascading Key for every single Key before using it, because specifications allow to hide or override Keys.

Parameters

  ks | the KeySet object to work with

Returns
  the new current Key

Return values

  0 | when the end of the KeySet has been reached
  0 | on NULL pointer

Since
  1.0.0

See also
  ksRewind() for resetting the internal cursor of the KeySet
  ksCurrent() for getting the Key the cursor currently points at
  ksLookup() to honor specifications

## ◆ ksPop()

Key * ksPop | ( | KeySet * | ks | ) |

Remove and return the last Key of `ks`.

The reference counter of the Key will be decremented by one.

The KeySet's cursor will not be affected if it did not point to the popped Key.

Note
  You need to keyDel() the Key afterwards, if you don't append it to another KeySet. It has the same semantics like a Key allocated with keyNew() or keyDup().

ks1=ksNew(0, KS_END);
ks2=ksNew(0, KS_END);
k1=keyNew("user:/name", KEY_END); // ref counter 0
ksAppendKey(ks1, k1); // ref counter 1
ksAppendKey(ks2, k1); // ref counter 2
k1=ksPop (ks1); // ref counter 1
k1=ksPop (ks2); // ref counter 0, like after keyNew()
ksAppendKey(ks1, k1); // ref counter 1
ksDel (ks1); // key is deleted too
ksDel (ks2);
ksPop
Key * ksPop(KeySet *ks)
Remove and return the last Key of ks.
Definition keyset.c:1740

Parameters

  ks | KeySet to pop a Key from

Returns
  the last Key of `ks`

Return values

  NULL | if `ks` is empty or a NULL pointer

Since
  1.0.0

See also
  ksLookup() to pop Keys by name
  ksCopy() to pop all Keys

## ◆ ksRename()

ssize_t ksRename | ( | KeySet * | ks,
|  | const Key * | root,
|  | const Key * | newRoot
| ) |  |

Moves all keys below `root` to below `newRoot`.

Only keys below `root` will be modified. The rest of `ks` remains untouched.

This functions is similar to the following snippet, but there are some differences.

KeySet * toRename = ksCut (ks, root);
for (elektraCursor cursor = 0; cursor < ksGetSize (toRename); cursor++)
{
Key * cur = keyDup (ksAtCursor (ks, cursor));
keyReplacePrefix (cur, root, newRoot);
ksAppendKey (ks, cur);
}
ksDel (toRename);
keyReplacePrefix
int keyReplacePrefix(Key *key, const Key *oldPrefix, const Key *newPrefix)
Replaces a prefix of the key name of key.
Definition elektra/keyname.c:837

Firstly, the optimizations only work, if `ks` doesn't contain any keys below `newRoot` that aren't below `root`. If such keys exist, ksRename() will still work, but it will fall back to code similar to the for-loop above.

The second difference is that ksRename() will modify the keys in `ks` directly, if they aren't referenced from anywhere else (if their reference count is 1 (see keyGetRef())). Normally, this shouldn't cause problems, but if you have a direct `Key *` pointer to a key in `ks` or hold a reference to some data within a key of `ks`, you may need to call keyIncRef() to ensure the key isn't modified.

Parameters

  ks | the keyset to manipulate
  root | the old prefix that will be removed, must not be a cascading key
  newRoot | the new prefix the will replace the old one, must not be a cascading key

Return values

  -1 | if any of `ks`, `root`, `newRoot` is NULL, or if `root` or `newRoot` are cascading keys
  -2 | if `ks` already contains keys below `newRoot`
  0 | if `ks` contains no keys below `root` (and also not `root` itself)

Returns
  otherwise, the number of keys that have been renamed

## ◆ ksRewind()

int ksRewind | ( | KeySet * | ks | ) |

Rewinds the KeySet internal cursor.

Use it to set the cursor to the beginning of the KeySet. ksCurrent() will always return NULL afterwards. So you want to use ksNext() first.

ksRewind (ks);
while ((key = ksNext (ks))!=0) {}
ksNext
Key * ksNext(KeySet *ks)
Returns the next Key in a KeySet.
Definition keyset.c:1830

Parameters

  ks | the KeySet that should be rewound

Return values

  0 | on success
  -1 | on NULL pointer

Since
  1.0.0

See also
  ksNext() for moving the cursor to the next entry in the KeySet
  ksCurrent() for getting the current element in the KeySet

## ◆ ksSearch()

ssize_t ksSearch | ( | const KeySet * | ks,
|  | const Key * | key
| ) |  |

Search in a key set, either yielding the actual index of the key, if the key has been found within the key set, or a negative value indicating the insertion index of the key, if the key would be inserted.

ssize_t result = ksSearch(ks, key);
if (result >= 0)
{
ssize_t position = result;
// The key already exist in key set.
} else {
ssize_t insertpos = -result-1;
// The key was not found in key set.
}
ksSearch
ssize_t ksSearch(const KeySet *ks, const Key *key)
Search in a key set, either yielding the actual index of the key, if the key has been found within th...
Definition keyset.c:916

Parameters

  ks | the keyset to work with
  key | the key to check

Returns
  position where the key is (>=0) if the key was found
  -insertpos -1 (< 0) if the key was not found so to get the insertpos simple do: -insertpos -1

See also
  ksLookup() for retrieving the found Key

## ◆ ksSetCursor()

int ksSetCursor | ( | KeySet * | ks,
|  | elektraCursor | cursor
| ) |  |

Set the KeySet internal cursor to `cursor`.

Use it to set the cursor to a stored position. ksCurrent() will then return the Key at the position of the supplied cursor.

Warning
  Cursors may get invalid when the Key was ksPop()ed or ksLookup() was used together with KDB_O_POP.

elektraCursor cursor;
..
// key now in any position here
cursor = ksGetCursor (ks);
while ((key = keyNextMeta (ks))!=0) {}
ksSetCursor (ks, cursor); // reset state
ksCurrent(ks); // in same position as before
ksCurrent
Key * ksCurrent(const KeySet *ks)
Return the current Key.
Definition keyset.c:1863

An invalid cursor will set the KeySet to its beginning like ksRewind(). When you set an invalid cursor ksCurrent() is 0.

Parameters

  ks | the KeySet object where the cursor should be set
  cursor | the cursor to set for `ks`

Return values

  0 | when the KeySet has been ksRewind()ed
  1 | otherwise
  -1 | on NULL pointer

Since
  1.0.0

See also
  ksGetCursor() for getting the cursor at the current position
  ksNext() for moving the internal cursor forward
  ksCurrent() for getting the Key at the current position

## ◆ ksSubtract()

ssize_t ksSubtract | ( | KeySet * | total,
|  | const KeySet * | sub
| ) |  |

Remove all the keys in `sub` from `total`.

Parameters

  total | the keyset where the keys should be removed from
  sub | the keys to remove

Return values

  -1 | on `NULL` pointers
  the | number of keys removed from `total`

## ◆ ksVNew()

KeySet * ksVNew | ( | size_t | alloc,
|  | va_list | va
| ) |  |

Allocate, initialize and return a new KeySet object.

Objects created with ksNew() must be destroyed with ksDel().

You can use an arbitrary long list of parameters to preload the KeySet with a list of Keys. Either your first and only parameter is 0 or your last parameter must be KS_END.

So, terminate with ksNew(0, KS_END) or ksNew(20, ..., KS_END)

Warning
  Never use ksNew(0, keyNew(...), KS_END). If the first parameter is 0, other arguments are ignored.

The first parameter `alloc` defines how many Keys can be added without reallocation. If you pass any alloc size greater than 0, but less than 16, it will default to 16.

For most uses

KeySet * keys = ksNew (1, KS_END);
// enough memory for up to 16 keys, without needing reallocation
ksDel (keys);

will be fine. The alloc size will be 16 and will double whenever size reaches alloc size, so it also performs well with large KeySets.

You can defer the allocation of the internal array that holds the Keys, by passing 0 as the alloc size. This is useful if it is unclear whether your KeySet will actually hold any Keys and you want to avoid a malloc call.

// Create KeySet without allocating memory for keys
KeySet * keys = ksNew (0, KS_END);
// The first allocation will happen in ksAppendKey
ksAppendKey(keys, keyNew ("user:/sw/org/app/#0/current/fixedConfiguration/key02", KEY_VALUE, "value02", KEY_END));
// work with the KeySet
ksDel (keys);

If the size of the KeySet is known in advance, use the `alloc` parameter to hint the size of the KeySet.

If your application only needs up to 15 Keys you can request a KeySet of size 15:

KeySet * keys = ksNew (15, keyNew ("user:/sw/org/app/#0/current/fixedConfiguration/key01", KEY_VALUE, "value01", KEY_END),
keyNew ("user:/sw/org/app/#0/current/fixedConfiguration/key02", KEY_VALUE, "value02", KEY_END),
keyNew ("user:/sw/org/app/#0/current/fixedConfiguration/key03", KEY_VALUE, "value03", KEY_END),
// ...
keyNew ("user:/sw/org/app/#0/current/fixedConfiguration/key15", KEY_VALUE, "value15", KEY_END), KS_END);
// work with it
ksDel (keys);

If you start having 3 Keys, and your application needs approximately 200 up to 500 Keys, you can use:

KeySet * config = ksNew (500, keyNew ("user:/sw/org/app/#0/current/fixedConfiguration/key1", KEY_VALUE, "value1", KEY_END),
keyNew ("user:/sw/org/app/#0/current/fixedConfiguration/key2", KEY_VALUE, "value2", KEY_END),
keyNew ("user:/sw/org/app/#0/current/fixedConfiguration/key3", KEY_VALUE, "value3", KEY_END),
KS_END); // don't forget the KS_END at the end!
// work with it
ksDel (config);

Alloc size is 500, the size of the KeySet will be 3 after ksNew. This means the KeySet will reallocate when appending more than 497 keys.

The main benefit of taking a list of variant length parameters is to be able to have one C-Statement for any possible KeySet. If you prefer, you can always create an empty KeySet and use ksAppendKey().

Postcondition
  the KeySet is rewinded properly

Parameters

  alloc | gives a hint for how many Keys may be stored initially

Returns
  a ready to use KeySet object

Return values

  0 | on memory error

Since
  1.0.0

See also
  ksDel() to free the KeySet afterwards
  ksDup() to duplicate an existing KeySet
  ksAppendKey() to append individual Keys to a KeySet

Precondition
  caller must call va_start and va_end

va the list of arguments

Parameters

  alloc | the allocation size
  va | the list of variable arguments