Elektra  0.8.19
Enumerations | Functions
KeySet

Methods to manipulate KeySets. More...

Enumerations

enum  option_t {
  KDB_O_NONE =0, KDB_O_DEL =1, KDB_O_POP =1<<1, KDB_O_NODIR =1<<2,
  KDB_O_DIRONLY =1<<3, KDB_O_NOREMOVE =1<<6, KDB_O_REMOVEONLY =1<<7, KDB_O_INACTIVE =1<<8,
  KDB_O_SYNC =1<<9, KDB_O_SORT =1<<10, KDB_O_NORECURSIVE =1<<11, KDB_O_NOCASE =1<<12,
  KDB_O_WITHOWNER =1<<13, KDB_O_NOALL =1<<14
}
 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 toAppend contained keys to the end of the ks. More...
 
KeySet * ksCut (KeySet *ks, const Key *cutpoint)
 Cuts out a keyset at the 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...
 
cursor_t ksGetCursor (const KeySet *ks)
 Get the KeySet internal cursor. More...
 
Key * ksAtCursor (KeySet *ks, cursor_t pos)
 return key at given cursor position More...
 
int ksSetCursor (KeySet *ks, cursor_t cursor)
 Set the KeySet internal cursor. More...
 
Key * ksLookup (KeySet *ks, Key *key, option_t options)
 Look for a Key contained in ks that matches the name of the key. More...
 
Key * ksLookupByName (KeySet *ks, const char *name, option_t options)
 Convenience method to look for a Key contained in ks that matches 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", 0), keyNew ("user/name2", 0), keyNew ("user/name3", 0), KS_END);
// append a key in the keyset
ksAppendKey (myConfig, keyNew ("user/name4", 0));
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

Enumeration Type Documentation

enum option_t

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 also
ksPop().
KDB_O_NODIR 

Feature not available.

TODO: remove for 1.0

KDB_O_DIRONLY 

Feature not available.

TODO: remove for 1.0

KDB_O_NOREMOVE 

Feature not available.

TODO: remove for 1.0

KDB_O_REMOVEONLY 

Feature not available.

TODO: remove for 1.0

KDB_O_INACTIVE 

Feature not available.

TODO: remove for 1.0

KDB_O_SYNC 

Feature not available.

TODO: remove for 1.0

KDB_O_SORT 

Feature not available.

TODO: remove for 1.0

KDB_O_NORECURSIVE 

Feature not available.

TODO: remove for 1.0

KDB_O_NOCASE 

Ignore case.

do not use without KDB_O_NOALL

TODO: remove for 1.0

See also
ksLookup()
KDB_O_WITHOWNER 

Search with owner.

The owner concept is deprecated, do not use.

TODO: remove for 1.0

See also
ksLookup()
KDB_O_NOALL 

Linear search from start -> cursor to cursor -> end.

TODO: remove for 1.0

See also
ksLookup()

Function Documentation

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

Append all toAppend contained keys to the end of the ks.

toAppend KeySet will be left unchanged.

If a key is both in toAppend and ks, the Key in ks will be overridden.

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
Returns
the size of the KeySet after transfer
Return values
-1on NULL pointers
Parameters
ksthe KeySet that will receive the keys
toAppendthe KeySet that provides the keys that will be transferred
See also
ksAppendKey()
ssize_t ksAppendKey ( KeySet *  ks,
Key *  toAppend 
)

Appends a Key to the end of ks.

Will take ownership of the key toAppend. That means ksDel(ks) will remove the key unless the key:

  • was duplicated before inserting
  • got its refcount incremented by keyIncRef() before inserting
  • was also inserted into another keyset with ksAppendKey()

The reference counter of the key will be incremented to show 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 keyname already existed in the keyset, it will be replaced with the new key.

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

It is save 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);

Or if you want to avoid aliasing at all, you can duplicate the key. But then 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));
ksDel (ks);
// now we still can work with the key k!
keyDel (k);
Returns
the size of the KeySet after insertion
Return values
-1on NULL pointers
-1if insertion failed, the key will be deleted then.
Parameters
ksKeySet that will receive the key
toAppendKey that will be appended to ks or deleted
See also
ksAppend(), keyNew(), ksDel()
keyIncRef()
Key* ksAtCursor ( KeySet *  ks,
cursor_t  pos 
)

return key at given cursor position

Parameters
ksthe keyset to pop key from
poswhere to get
Returns
the key at the cursor position on success
Return values
NULLon NULL pointer, negative cursor position or a position that does not lie within the keyset
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(). But in some situations you need to copy a keyset to a existing keyset, for that 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 the source will be added to the destination and the ksCurrent() is set properly in dest.

A flat copy is made, so the keys will not be duplicated, but there reference counter is updated, so both keysets need to be ksDel().

Note
Because the key is not copied, also the pointer to the current metadata keyNextMeta() will be shared.
1 int f (KeySet *ks)
2 {
3  KeySet *c = ksNew (20, ..., KS_END);
4  // c receives keys
5  ksCopy (ks, c); // pass the keyset to the caller
6 
7  ksDel (c);
8 } // caller needs to ksDel (ks)
Parameters
sourcehas to be an initialized source KeySet or NULL
desthas to be an initialized KeySet where to write the keys
Return values
1on success
0if dest was cleared successfully (source is NULL)
-1on NULL pointer
See also
ksNew(), ksDel(), ksDup()
keyCopy() for copying keys
Key* ksCurrent ( const KeySet *  ks)

Return the current Key.

The 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 work with
Returns
pointer to the Key pointed by ks's cursor
Return values
0on NULL pointer
See also
ksNext(), ksRewind()
KeySet* ksCut ( KeySet *  ks,
const Key *  cutpoint 
)

Cuts out a keyset at the cutpoint.

Searches for the cutpoint inside the KeySet ks. If found it cuts out 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 make a 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 (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);

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 below system/mountpoint/interest.

See also
kdbGet() for explanation why you might get more keys than you requested.
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
Parameters
ksthe keyset to cut. It will be modified by removing all keys below the cutpoint. The cutpoint itself will also be removed.
cutpointthe point where to cut out the keyset
int ksDel ( KeySet *  ks)

A destructor for KeySet objects.

Cleans all internal dynamic attributes, decrement all reference pointers to all keys and then keyDel() all contained Keys, and elektraFree ()s the release the KeySet object memory (that was previously allocated by ksNew()).

Parameters
ksthe keyset object to work with
Return values
0when the keyset was freed
-1on null pointer
See also
ksNew()
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 there reference counter is updated, so both keysets need ksDel().

Parameters
sourcehas to be an initialized source KeySet
Returns
a flat copy of source on success
Return values
0on NULL pointer
See also
ksNew(), ksDel()
keyDup() for Key duplication
cursor_t ksGetCursor ( const KeySet *  ks)

Get the KeySet internal cursor.

Use it to get the cursor of the actual position.

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:

1 cursor_t jump;
2 ksRewind (ks);
3 while ((key = keyNextMeta (ks))!=0)
4 {
5  // now mark this key
6  jump = ksGetCursor(ks);
7 
8  //code..
9  keyNextMeta (ks); // now browse on
10  // use ksCurrent(ks) to check the keys
11  //code..
12 
13  // jump back to the position marked before
14  ksSetCursor(ks, jump);
15 }

Restoring state

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

1 int f (KeySet *ks)
2 {
3  cursor_t state = ksGetCursor(ks);
4 
5  // work with keyset
6 
7  // now bring the keyset to the state before
8  ksSetCursor (ks, state);
9 }

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

Note
Only use a cursor for the same keyset which it was made for.
Parameters
ksthe keyset object to work with
Returns
a valid cursor on success
an invalid cursor on NULL pointer or after ksRewind()
See also
ksNext(), ksSetCursor()
ssize_t ksGetSize ( const KeySet *  ks)

Return the number of keys that ks contains.

Parameters
ksthe keyset object to work with
Returns
the number of keys that ks contains.
Return values
-1on NULL pointer
See also
ksNew(0, KS_END), ksDel()
Key* ksHead ( const KeySet *  ks)

Return the first key in the KeySet.

The KeySets cursor will not be affected.

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

Parameters
ksthe keyset object to work with
Returns
the first Key of a keyset
Return values
0on NULL pointer or empty keyset
See also
ksTail() for the last Key
ksRewind(), ksCurrent() and ksNext() for iterating over the KeySet
Key* ksLookup ( KeySet *  ks,
Key *  key,
option_t  options 
)

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

ksLookup() is designed to let you work with entirely pre-loaded KeySets. The idea is to fully kdbGet() for your application root key and process it all at once with ksLookup().

This function is efficient by using binary search. Together with kdbGet() which can you load the whole configuration you can write very effective but short code for configuration:

kdbGet (handle, myConfig, key);
Key * result = ksLookupByName (myConfig, "/sw/tests/myapp/#0/current/testkey1", 0);

This is the way programs should get their configuration and search after 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 find out which value an application will find.

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 is done if the first character is a /. This leads to search in all namespaces proc/, dir/, user/ and system/, but also correctly considers 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 follow all this links in the head to find out which key will be taken. So 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 * key;
Key * current;
ksRewind (iterator);
while ((current = ksNext (iterator)))
{
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);
}

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().
KDB_O_NOALL (deprecated)
When KDB_O_NOALL is set the keyset will be only searched from ksCurrent() to ksTail(). You need to ksRewind() the keyset yourself. ksCurrent() is always set properly after searching a key, so you can go on searching another key after the found key.
When KDB_O_NOALL is not set the cursor will stay untouched and all keys are considered. A much more efficient binary search will be used then.
KDB_O_WITHOWNER (deprecated)
Also consider correct owner (needs KDB_O_NOALL).
KDB_O_NOCASE (deprecated)
Lookup ignoring case (needs KDB_O_NOALL).
Parameters
kswhere to look for
keythe key object you are looking for
optionsof type option_t with some KDB_O_* option bits as explained above
Returns
pointer to the Key found, 0 otherwise
Return values
0on NULL pointers
See also
ksLookupByName() to search by a name given by a string
ksCurrent(), ksRewind(), ksNext() for iterating over a KeySet
Key* ksLookupByName ( KeySet *  ks,
const char *  name,
option_t  options 
)

Convenience method to look for a Key contained in ks that matches name.

ksLookupByName() is designed to let you work with entirely pre-loaded KeySets, so instead of kdbGetKey(), key by key, the idea is to fully kdbGetByName() for your application root key and process it all at once with ksLookupByName().

This function is very efficient by using binary search. Together with kdbGetByName() which can you load the whole configuration with only some communication to backends you can write very effective but short code for configuration.

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. If requested to pop the key, the cursor will be rewinded.

Cascading

Cascading is done if the first character is a /. This leads to ignoring the prefix like system/ and user/.

1 if (kdbGet(handle, "/sw/tests/myapp/#0/current", myConfig, parentKey ) == -1)
2  errorHandler ("Could not get Keys", parentKey);
3 
4 if ((myKey = ksLookupByName (myConfig, "/sw/tests/myapp/#0/current/key", 0)) == NULL)
5  errorHandler ("Could not Lookup Key");

This is the way multi user programs should get their configuration and search after the values. It is guaranteed that more namespaces can be added easily and that all values can be set by admin and user. Also profile-features are available via plugins. Applications should not implement cascading algorithms, but only do a single lookup and put cascading functionality into plugins.

Full Search

When KDB_O_NOALL is set the keyset will be only searched from ksCurrent() to ksTail(). You need to ksRewind() the keyset yourself. ksCurrent() is always set properly after searching a key, so you can go on searching another key after the found key.

When KDB_O_NOALL is not set the cursor will stay untouched and all keys are considered. A much more efficient binary search will be used then.

Parameters
kswhere to look for
namekey name you are looking for
optionssome KDB_O_* option bits:
  • KDB_O_POP
    Pop the key which was found.
  • See ksLookup() for others
Returns
pointer to the Key found, 0 otherwise
Return values
0on NULL pointers
See also
keyCompare() for very powerful Key lookups in KeySets
ksCurrent(), ksRewind(), ksNext()
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 the 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 it does not need sync
1if it needs sync
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 a various 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 KEY_END.

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

For most uses

KeySet * keys = ksNew (0, KS_END);
// work with it
ksDel (keys);

will be fine, the alloc size will be 16, defined in kdbprivate.h. The alloc size will be doubled whenever size reaches alloc size, so it also performs well with large keysets.

But if you have any clue how large your keyset may be you should read the next statements.

If you want a keyset with length 15 (because you know of your application that you normally need about 12 up to 15 keys), use:

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

If you start having 3 keys, and your application needs approximately 200-500 keys, you can use:

KeySet * config = ksNew (500, keyNew ("user/sw/org/app/#0/current/fixedConfiguration/key1", KEY_VALUE, "value1", 0),
keyNew ("user/sw/org/app/#0/current/fixedConfiguration/key2", KEY_VALUE, "value2", 0),
keyNew ("user/sw/org/app/#0/current/fixedConfiguration/key3", KEY_VALUE, "value3", 0),
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
See also
ksDel() to free the KeySet afterwards
ksDup() to duplicate an existing KeySet
ksAppendKey() to append individual keys
Parameters
allocgives a hint for the size how many Keys may be stored initially
Returns
a ready to use KeySet object
Return values
0on memory error
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 after the end of the KeySet was 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.
Parameters
ksthe keyset object to work with
Returns
the new current Key
Return values
0when the end is reached
0on NULL pointer
See also
ksRewind(), ksCurrent()
Key* ksPop ( KeySet *  ks)

Remove and return the last key of ks.

The reference counter will be decremented by one.

The KeySets 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().
1 ks1=ksNew(0, KS_END);
2 ks2=ksNew(0, KS_END);
3 
4 k1=keyNew("user/name", KEY_END); // ref counter 0
5 ksAppendKey(ks1, k1); // ref counter 1
6 ksAppendKey(ks2, k1); // ref counter 2
7 
8 k1=ksPop (ks1); // ref counter 1
9 k1=ksPop (ks2); // ref counter 0, like after keyNew()
10 
11 ksAppendKey(ks1, k1); // ref counter 1
12 
13 ksDel (ks1); // key is deleted too
14 ksDel (ks2);
Returns
the last key of ks
Return values
NULLif ks is empty or on NULL pointer
Parameters
ksKeySet to work with
See also
ksLookup() to pop keys by name
ksCopy() to pop all keys
commandList() for an example
int ksRewind ( KeySet *  ks)

Rewinds the KeySet internal cursor.

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

1 ksRewind (ks);
2 while ((key = ksNext (ks))!=0) {}
Parameters
ksthe keyset object to work with
Return values
0on success
-1on NULL pointer
See also
ksNext(), ksCurrent()
int ksSetCursor ( KeySet *  ks,
cursor_t  cursor 
)

Set the KeySet internal cursor.

Use it to set the cursor to a stored position. ksCurrent() will then be the position which you got with.

Warning
Cursors may get invalid when the key was ksPop()ed or ksLookup() was used together with KDB_O_POP.
1 cursor_t cursor;
2 ..
3 // key now in any position here
4 cursor = ksGetCursor (ks);
5 while ((key = keyNextMeta (ks))!=0) {}
6 ksSetCursor (ks, cursor); // reset state
7 ksCurrent(ks); // in same position as before

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
cursorthe cursor to use
ksthe keyset object to work with
Return values
0when the keyset is ksRewind()ed
1otherwise
-1on NULL pointer
See also
ksNext(), ksGetCursor()
Key* ksTail ( const KeySet *  ks)

Return the last key in the KeySet.

The KeySets 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 work with
Returns
the last Key of a keyset
Return values
0on NULL pointer or empty keyset
See also
ksHead() for the first Key
ksRewind(), ksCurrent() and ksNext() for iterating over the KeySet
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 a various 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 KEY_END.

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

For most uses

KeySet * keys = ksNew (0, KS_END);
// work with it
ksDel (keys);

will be fine, the alloc size will be 16, defined in kdbprivate.h. The alloc size will be doubled whenever size reaches alloc size, so it also performs well with large keysets.

But if you have any clue how large your keyset may be you should read the next statements.

If you want a keyset with length 15 (because you know of your application that you normally need about 12 up to 15 keys), use:

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

If you start having 3 keys, and your application needs approximately 200-500 keys, you can use:

KeySet * config = ksNew (500, keyNew ("user/sw/org/app/#0/current/fixedConfiguration/key1", KEY_VALUE, "value1", 0),
keyNew ("user/sw/org/app/#0/current/fixedConfiguration/key2", KEY_VALUE, "value2", 0),
keyNew ("user/sw/org/app/#0/current/fixedConfiguration/key3", KEY_VALUE, "value3", 0),
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
See also
ksDel() to free the KeySet afterwards
ksDup() to duplicate an existing KeySet
ksAppendKey() to append individual keys
Parameters
allocgives a hint for the size how many Keys may be stored initially
Returns
a ready to use KeySet object
Return values
0on memory error
Precondition
caller must call va_start and va_end
va the list of arguments
Parameters
allocthe allocation size
vathe list of variable arguments