Elektra  0.9.7
Macros | Enumerations | Functions
KeySet

Methods to manipulate KeySets. More...

Macros

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

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. More...
 
KeySet * ksVNew (size_t alloc, va_list va)
 Allocate, initialize and return a new KeySet object. More...
 
KeySet * ksDup (const KeySet *source)
 Return a duplicate of a KeySet. More...
 
int ksCopy (KeySet *dest, const KeySet *source)
 Replace the content of a KeySet with another one. More...
 
int ksDel (KeySet *ks)
 A destructor for KeySet objects. More...
 
int ksNeedSync (const KeySet *ks)
 Checks if KeySet needs sync. More...
 
ssize_t ksGetSize (const KeySet *ks)
 Return the number of Keys that ks contains. More...
 
ssize_t ksAppendKey (KeySet *ks, Key *toAppend)
 Appends a Key to the end of ks. More...
 
ssize_t ksAppend (KeySet *ks, const KeySet *toAppend)
 Append all Keys in toAppend to the end of the KeySet ks. More...
 
ssize_t ksRename (KeySet *ks, const Key *root, const Key *newRoot)
 Moves all keys below root to below newRoot. More...
 
elektraCursor ksFindHierarchy (const KeySet *ks, const Key *root, elektraCursor *end)
 Searches for the start and optionally end of the key hierachy rooted at root in ks. More...
 
KeySet * ksCut (KeySet *ks, const Key *cutpoint)
 Cuts out all Keys from KeySet ks that are below or at cutpoint. More...
 
Key * ksPop (KeySet *ks)
 Remove and return the last Key of ks. More...
 
int ksRewind (KeySet *ks)
 Rewinds the KeySet internal cursor. More...
 
Key * ksNext (KeySet *ks)
 Returns the next Key in a KeySet. More...
 
Key * ksCurrent (const KeySet *ks)
 Return the current Key. More...
 
Key * ksHead (const KeySet *ks)
 Return the first Key in the KeySet. More...
 
Key * ksTail (const KeySet *ks)
 Return the last Key in the KeySet. More...
 
elektraCursor ksGetCursor (const KeySet *ks)
 Get the internal cursor of the KeySet. More...
 
Key * ksAtCursor (KeySet *ks, elektraCursor pos)
 Return Key at given position pos. More...
 
int ksSetCursor (KeySet *ks, elektraCursor cursor)
 Set the KeySet internal cursor to cursor. More...
 
Key * ksLookup (KeySet *ks, Key *key, elektraLookupFlags options)
 Look for a Key contained in ks that matches the name of the key. More...
 
Key * ksLookupByName (KeySet *ks, const char *name, elektraLookupFlags options)
 Convenience method to look for a Key contained in ks with name name. More...
 

Detailed Description

Methods to manipulate KeySets.

A KeySet is a set of keys.

Most important properties of a KeySet:

The most important methods of KeySet:

Note
Because the key is not copied, also the pointer to the current metadata keyNextMeta() will be shared.

KeySets have an internal cursor . Methods should avoid to change this cursor, unless they want to communicate something with it. The internal cursor is used:

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;
ksRewind (myConfig);
while ((current = ksNext (myConfig)) != 0)
{
printf ("Key name is %s.\n", keyName (current));
}
ksDel (myConfig); // delete keyset and all keys appended
Key * keyNew(const char *name,...)
A practical way to fully create a Key object in one step.
Definition: key.c:141
@ KEY_END
Definition: kdbenum.c:97
const char * keyName(const Key *key)
Returns a pointer to the abbreviated real internal key name.
Definition: elektra/keyname.c:254
int ksDel(KeySet *ks)
A destructor for KeySet objects.
Definition: keyset.c:451
Key * ksNext(KeySet *ks)
Returns the next Key in a KeySet.
Definition: keyset.c:1489
KeySet * ksNew(size_t alloc,...)
Allocate, initialize and return a new KeySet object.
Definition: keyset.c:229
#define KS_END
End of a list of keys.
Definition: kdbenum.c:158
ssize_t ksAppendKey(KeySet *ks, Key *toAppend)
Appends a Key to the end of ks.
Definition: keyset.c:786
int ksRewind(KeySet *ks)
Rewinds the KeySet internal cursor.
Definition: keyset.c:1451

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

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.

Note
Because the key is not copied, also the pointer to the current metadata keyNextMeta() will be shared.
Postcondition
Sorted KeySet ks with all Keys it had before and additionally the Keys from toAppend
Parameters
ksthe KeySet that will receive the Keys
toAppendthe KeySet that provides the Keys that will be transferred
Returns
the size of the KeySet ks after transfer
Return values
-1on 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.

Note
Because the key is not copied, also the pointer to the current metadata keyNextMeta() will be shared.
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);
ksAppendKey (ks, k);
ksDel (ks);
// now we still can work with the key k!
keyDel (k);
ssize_t keyDecRef(Key *key)
Decrement the reference counter of a Key object.
Definition: key.c:648
int keyDel(Key *key)
A destructor for Key objects.
Definition: key.c:500
ssize_t keyIncRef(Key *key)
Increment the reference counter of a Key object.
Definition: key.c:610

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
Definition: kdbenum.c:112
Parameters
ksKeySet where toAppend should be append
toAppendKey that will be appended to ks or deleted
Returns
the size of the KeySet after appending
Return values
-1on NULL pointers
-1if 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 ( KeySet *  ks,
elektraCursor  pos 
)

Return Key at given position pos.

The position is a number starting from 0.

Parameters
ksthe KeySet to get the Key from
posthe position of the Key that should be retrieved
Returns
the Key at the cursor pos on success
Return values
NULLon NULL pointer, negative cursor position or a position that does not lie within the KeySet ks
Since
1.0.0
See also
ksGetCursor() for getting the cursor at the current position
ksSetCursor() for setting the cursor to a specific position

◆ 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 and ksCurrent() will be set properly in dest.

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().

Note
Because the key is not copied, also the pointer to the current metadata keyNextMeta() will be shared.
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)
int ksCopy(KeySet *dest, const KeySet *source)
Replace the content of a KeySet with another one.
Definition: keyset.c:421
Parameters
sourcean initialized KeySet or NULL
destan initialized KeySet, where the Keys from source get copied to
Return values
1on success
0if dest was cleared successfully (source is NULL)
-1when 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
ksthe KeySet object to get the current Key from
Returns
pointer to the Key pointed by ks's cursor
Return values
0on 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);
int kdbSet(KDB *handle, KeySet *ks, Key *parentKey)
Set Keys to a Key database in an atomic and universal way.
Definition: kdb.c:1743
int kdbGet(KDB *handle, KeySet *ks, Key *parentKey)
Retrieve Keys from a Key database in an atomic and universal way.
Definition: kdb.c:1191
KDB * kdbOpen(const KeySet *contract, Key *errorKey)
Opens the session with the Key database.
Definition: kdb.c:417
int kdbClose(KDB *handle, Key *errorKey)
Closes the session with the Key database.
Definition: kdb.c:590
KeySet * ksCut(KeySet *ks, const Key *cutpoint)
Cuts out all Keys from KeySet ks that are below or at cutpoint.
Definition: keyset.c:1281
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
ksthe Keyset to cut. It will be modified by removing all Keys at or below the cutpoint.
cutpointthe point where to cut out the Keyset
Returns
a new allocated KeySet which needs to 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
0on 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.

◆ ksDel()

int ksDel ( KeySet *  ks)

A destructor for KeySet objects.

Cleans all internal dynamic attributes, decrements all reference pointers to all Keys and then calls keyDel() on all contained Keys. Afterwards elektraFree() is used to release the KeySet's object memory (that was previously allocated by ksNew()).

Parameters
ksthe KeySet that should be deleted
Return values
0when the KeySet was successfully freed
-1on NULL pointer
Since
1.0.0
See also
ksNew() for creating a new KeySet

◆ 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
sourcehas to be an initialized KeySet
Returns
a flat copy of source on success
Return values
0on 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 hierachy rooted at root in ks.

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);
}
Key * ksAtCursor(KeySet *ks, elektraCursor pos)
Return Key at given position pos.
Definition: keyset.c:1697
elektraCursor ksFindHierarchy(const KeySet *ks, const Key *root, elektraCursor *end)
Searches for the start and optionally end of the key hierachy rooted at root in ks.
Definition: keyset.c:1111
Parameters
ksThe keyset to search in
rootThe root of the hierachy to find
endIf 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
-1if 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);
}
const Key * keyNextMeta(Key *key)
Get the next metadata entry of a Key.
Definition: keymeta.c:197
int ksSetCursor(KeySet *ks, elektraCursor cursor)
Set the KeySet internal cursor to cursor.
Definition: keyset.c:1742
elektraCursor ksGetCursor(const KeySet *ks)
Get the internal cursor of the KeySet.
Definition: keyset.c:1671

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 and ksNext() == ksHead().

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
ksthe KeySet object to get the cursor from
Returns
a valid cursor on success
Return values
-1on NULL pointer
-1on 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

◆ ksGetSize()

ssize_t ksGetSize ( const KeySet *  ks)

Return the number of Keys that ks contains.

Parameters
ksthe KeySet object to get the size from
Returns
the number of Keys that ks contains.
Return values
-1on NULL pointer
Since
1.0.0

◆ ksHead()

Key* ksHead ( const KeySet *  ks)

Return the first Key in the KeySet.

The KeySet's cursor will not be affected.

If ksCurrent()==ksHead() you know you are on the first Key.

Parameters
ksthe KeySet object to get the first Key from
Returns
the first Key of a KeySet
Return values
0on NULL pointer or empty KeySet
Since
1.0.0
See also
ksTail() for getting the last Key of the KeySet
ksRewind(), ksCurrent() and ksNext() for iterating over the KeySet

◆ 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);
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:2496

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, ks internal cursor will be positioned in the matched Key (also accessible by ksCurrent()), and a pointer to the Key is returned. If not found, ks internal cursor will not move, and 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. ksCurrent() will not be changed, only iff ksCurrent() is the searched Key, then the KeySet will be ksRewind()ed.
Note
Like in ksPop() the popped Key always needs to be keyDel() afterwards, even if it is appended to another KeySet.
Warning
All cursors on the KeySet will be invalid iff you use KDB_O_POP, so don't use this if you rely on a cursor, see ksGetCursor().

The invalidation of cursors does not matter if you use multiple KeySets, e.g. by using ksDup(). E.g., to separate ksLookup() with KDB_O_POP and ksAppendKey():

void f (KeySet * iterator, KeySet * lookup)
{
KeySet * append = ksNew (ksGetSize (lookup), KS_END);
Key * current;
ksRewind (iterator);
while ((current = ksNext (iterator)))
{
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);
}
ssize_t ksAppend(KeySet *ks, const KeySet *toAppend)
Append all Keys in toAppend to the end of the KeySet ks.
Definition: keyset.c:898
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:2432
ssize_t ksGetSize(const KeySet *ks)
Return the number of Keys that ks contains.
Definition: keyset.c:646
@ KDB_O_POP
Pop Parent out of keyset key in ksLookup().
Definition: kdbenum.c:188

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
ksthe KeySet that should be searched
keythe Key object you are looking for
optionsof type elektraLookupFlags with some KDB_O_* option bits - as explained above
Returns
pointer to the Key found
Return values
0if no Key has been found
0on NULL pointers
Since
1.0.0
See also
ksLookupByName() to search by a name given by a string
ksCurrent(), ksRewind(), ksNext() 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
ksthe KeySet that should be searched
namename of the Key you are looking for
optionssome KDB_O_* option bits (KDB_O_POP, KDB_O_DEL):
Returns
pointer to the Key found
Return values
0if no Key has been found
0on NULL pointers
Since
1.0.0
See also
ksLookup() for explanation of the functionality and examples.
ksCurrent(), ksRewind(), ksNext() for iterating over a KeySet

◆ ksNeedSync()

int ksNeedSync ( const KeySet *  ks)

Checks if KeySet needs sync.

When Keys are changed, this is reflected into keyNeedSync().

But when Keys are popped from a KeySet this can't be seen by looking at individual Keys.

ksNeedSync() allows the backends to know if a Key was popped from the KeySet, to know that this KeySet needs to be written out.

Deprecated:
Backends now work differently and do not rely on this information.
Parameters
ksthe KeySet to work with
Return values
-1on NULL KeySet
0if ks does not need sync
1if ks needs sync
Since
1.0.0
See also
keyNeedSync() for checking whether a single Key needs to be synced

◆ 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);
@ KEY_VALUE
Definition: kdbenum.c:89

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
allocgives a hint for how many Keys may be stored initially
Returns
a ready to use KeySet object
Return values
0on 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
ksthe KeySet object to work with
Returns
the new current Key
Return values
0when the end of the KeySet has been reached
0on 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);
Key * ksPop(KeySet *ks)
Remove and return the last Key of ks.
Definition: keyset.c:1403
Parameters
ksKeySet to pop a Key from
Returns
the last Key of ks
Return values
NULLif ks is empty or a NULL pointer
Since
1.0.0
See also
ksLookup() to pop Keys by name
ksCopy() to pop all Keys
ksTail() for getting the last Key of a KeySet without removing it

◆ 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);
int keyReplacePrefix(Key *key, const Key *oldPrefix, const Key *newPrefix)
Replaces a prefix of the key name of key.
Definition: elektra/keyname.c:677

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
ksthe keyset to manipulate
rootthe old prefix that will be removed, must not be a cascading key
newRootthe new prefix the will replace the old one, must not be a cascading key
Return values
-1if any of ks, root, newRoot is NULL, or if root or newRoot are cascading keys
-2if ks already contains keys below newRoot
0if 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) {}
Parameters
ksthe KeySet that should be rewound
Return values
0on success
-1on 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

◆ 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
Key * ksCurrent(const KeySet *ks)
Return the current Key.
Definition: keyset.c:1522

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

Parameters
ksthe KeySet object where the cursor should be set
cursorthe cursor to set for ks
Return values
0when the KeySet has been ksRewind()ed
1otherwise
-1on 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

◆ ksTail()

Key* ksTail ( const KeySet *  ks)

Return the last Key in the KeySet.

The KeySet's cursor will not be affected.

If ksCurrent()==ksTail() you know you are on the last key. ksNext() will return a NULL pointer afterwards.

Parameters
ksthe KeySet object to get the last Key from
Returns
the last Key of a KeySet
Return values
0on NULL pointer or empty KeySet
Since
1.0.0
See also
ksHead() for getting the first Key of a KeySet
ksRewind(), ksCurrent() and ksNext() for iterating over the KeySet

◆ 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
allocgives a hint for how many Keys may be stored initially
Returns
a ready to use KeySet object
Return values
0on 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
allocthe allocation size
vathe list of variable arguments