Provided by: elektra-doc_0.8.14-5.1ubuntu2_all bug

NAME

       kdb::KDB - Constructs a class KDB.

SYNOPSIS

       #include <kdb.hpp>

   Public Member Functions
       KDB ()
           Constructs a class KDB.
       KDB (Key &errorKey)
           Constructs a class KDB.
       ~KDB ()  throw ()
           The destructor closes the database.
       void open (Key &errorKey)
           Open the database.
       void close (Key &errorKey)  throw ()
           Open the database.
       int get (KeySet &returned, std::string const &keyname)
           Get all keys below keyname inside returned.
       int get (KeySet &returned, Key &parentKey)
           Get all keys below parentKey inside returned.
       int set (KeySet &returned, std::string const &keyname)
           Set all keys below keyname.
       int set (KeySet &returned, Key &parentKey)
           Set all keys below parentKey.

Detailed Description

       Constructs a class KDB.

       Exceptions:
           KDBException if database could not be opened

       Opens the session with the Key database.

       Precondition:
           errorKey must be a valid key, e.g. created with keyNew()

       The method will bootstrap itself the following way. The first step is to open the default
       backend. With it system/elektra/mountpoints will be loaded and all needed libraries and
       mountpoints will be determined. These libraries for backends will be loaded and with it
       the KDB datastructure will be initialized.

       You must always call this method before retrieving or committing any keys to the database.
       In the end of the program, after using the key database, you must not forget to
       kdbClose().

       The pointer to the KDB structure returned will be initialized like described above, and it
       must be passed along on any kdb*() method your application calls.

       Get a KDB handle for every thread using elektra. Don't share the handle across threads,
       and also not the pointer accessing it:

       void thread1()
       {
               Key *parent = keyNew("/app/part1", KEY_CASCADING_NAME, KEY_END);
               KDB * h = kdbOpen(parent);
               // fetch keys and work with them
               kdbClose(h, parent);
       }
       void thread2()
       {
               Key *parent = keyNew("/app/part2", KEY_CASCADING_NAME, KEY_END);
               KDB * h = kdbOpen(parent);
               // fetch keys and work with them
               kdbClose(h, parent);
       }

        You don't need kdbOpen() if you only want to manipulate plain in-memory Key or KeySet
       objects.

       Precondition:
           errorKey must be a valid key, e.g. created with keyNew()

       Parameters:
           errorKey the key which holds errors and warnings which were issued

       See also:
           kdbGet(), kdbClose() to end all affairs to the Key database.

       Return values:
           handle on success
           NULL on failure

       Access to the key database.

       Invariant:
           the object holds an valid connection to the key database or is empty

Constructor & Destructor Documentation

   kdb::KDB::KDB () [inline]
       Constructs a class KDB.

       Exceptions:
           KDBException if database could not be opened

       Opens the session with the Key database.

       Precondition:
           errorKey must be a valid key, e.g. created with keyNew()

       The method will bootstrap itself the following way. The first step is to open the default
       backend. With it system/elektra/mountpoints will be loaded and all needed libraries and
       mountpoints will be determined. These libraries for backends will be loaded and with it
       the KDB datastructure will be initialized.

       You must always call this method before retrieving or committing any keys to the database.
       In the end of the program, after using the key database, you must not forget to
       kdbClose().

       The pointer to the KDB structure returned will be initialized like described above, and it
       must be passed along on any kdb*() method your application calls.

       Get a KDB handle for every thread using elektra. Don't share the handle across threads,
       and also not the pointer accessing it:

       void thread1()
       {
               Key *parent = keyNew("/app/part1", KEY_CASCADING_NAME, KEY_END);
               KDB * h = kdbOpen(parent);
               // fetch keys and work with them
               kdbClose(h, parent);
       }
       void thread2()
       {
               Key *parent = keyNew("/app/part2", KEY_CASCADING_NAME, KEY_END);
               KDB * h = kdbOpen(parent);
               // fetch keys and work with them
               kdbClose(h, parent);
       }

        You don't need kdbOpen() if you only want to manipulate plain in-memory Key or KeySet
       objects.

       Precondition:
           errorKey must be a valid key, e.g. created with keyNew()

       Parameters:
           errorKey the key which holds errors and warnings which were issued

       See also:
           kdbGet(), kdbClose() to end all affairs to the Key database.

       Return values:
           handle on success
           NULL on failure

   kdb::KDB::KDB (Key & errorKey) [inline]
       Constructs a class KDB.

       Parameters:
           errorKey is useful if you want to get the warnings in the successful case, when no
           exception is thrown.

       Exceptions:
           KDBException if database could not be opened

       Opens the session with the Key database.

       Precondition:
           errorKey must be a valid key, e.g. created with keyNew()

       The method will bootstrap itself the following way. The first step is to open the default
       backend. With it system/elektra/mountpoints will be loaded and all needed libraries and
       mountpoints will be determined. These libraries for backends will be loaded and with it
       the KDB datastructure will be initialized.

       You must always call this method before retrieving or committing any keys to the database.
       In the end of the program, after using the key database, you must not forget to
       kdbClose().

       The pointer to the KDB structure returned will be initialized like described above, and it
       must be passed along on any kdb*() method your application calls.

       Get a KDB handle for every thread using elektra. Don't share the handle across threads,
       and also not the pointer accessing it:

       void thread1()
       {
               Key *parent = keyNew("/app/part1", KEY_CASCADING_NAME, KEY_END);
               KDB * h = kdbOpen(parent);
               // fetch keys and work with them
               kdbClose(h, parent);
       }
       void thread2()
       {
               Key *parent = keyNew("/app/part2", KEY_CASCADING_NAME, KEY_END);
               KDB * h = kdbOpen(parent);
               // fetch keys and work with them
               kdbClose(h, parent);
       }

        You don't need kdbOpen() if you only want to manipulate plain in-memory Key or KeySet
       objects.

       Precondition:
           errorKey must be a valid key, e.g. created with keyNew()

       Parameters:
           errorKey the key which holds errors and warnings which were issued

       See also:
           kdbGet(), kdbClose() to end all affairs to the Key database.

       Return values:
           handle on success
           NULL on failure

   kdb::KDB::~KDB () [inline]
       The destructor closes the database. Closes the session with the Key database.

       Precondition:
           The handle must be a valid handle as returned from kdbOpen()

           errorKey must be a valid key, e.g. created with keyNew()

       This is the counterpart of kdbOpen().

       You must call this method when you finished your affairs with the key database. You can
       manipulate Key and KeySet objects also after kdbClose(), but you must not use any kdb*()
       call afterwards.

       The handle parameter will be finalized and all resources associated to it will be freed.
       After a kdbClose(), the handle cannot be used anymore.

       Parameters:
           handle contains internal information of opened  key database
           errorKey the key which holds error/warning information

       Return values:
           0 on success
           -1 on NULL pointer

Member Function Documentation

   void kdb::KDB::close (Key & errorKey) [inline]
       Open the database. The return value does not matter because its only a null pointer check.

       Parameters:
           errorKey is useful if you want to get the warnings

       Closes the session with the Key database.

       Precondition:
           The handle must be a valid handle as returned from kdbOpen()

           errorKey must be a valid key, e.g. created with keyNew()

       This is the counterpart of kdbOpen().

       You must call this method when you finished your affairs with the key database. You can
       manipulate Key and KeySet objects also after kdbClose(), but you must not use any kdb*()
       call afterwards.

       The handle parameter will be finalized and all resources associated to it will be freed.
       After a kdbClose(), the handle cannot be used anymore.

       Parameters:
           handle contains internal information of opened  key database
           errorKey the key which holds error/warning information

       Return values:
           0 on success
           -1 on NULL pointer

   int kdb::KDB::get (KeySet & returned, std::string const & keyname) [inline]
       Get all keys below keyname inside returned. Retrieve keys in an atomic and universal way.

       Precondition:
           The handle must be passed as returned from kdbOpen()

           The returned KeySet must be a valid KeySet, e.g. constructed with ksNew().

           The parentKey Key must be a valid Key, e.g. constructed with keyNew().

       If you pass NULL, which violates the preconditions, on any parameter kdbGet() will fail
       immediately without doing anything.

       The returned KeySet may already contain some keys, e.g. from previous kdbGet() calls. The
       new retrieved keys will be appended using ksAppendKey().

       It will fully retrieve, at least, all keys under the parentKey folder, with all subfolders
       and their children.

       Note:
           kdbGet() might retrieve more keys then requested (that are not below parentKey). These
           keys must be passed to calls of kdbSet(), otherwise they will be lost. This stems from
           the fact that the user has the only copy of the whole configuration and backends only
           write configuration that was passed to them. For example, if you kdbGet()
           'system/mountpoint/interest' you will not only get all keys below
           system/mountpoint/interest, but also all keys below system/mountpoint (if
           system/mountpoint is a mountpoint as the name suggests, but system/mountpoint/interest
           is not a mountpoint). Make sure to not touch or remove keys outside the keys of
           interest, because others may need them!

       Example:
           This example demonstrates the typical usecase within an application (without error
           handling).

       #include <kdb.h>
       #include <stdio.h>

       int main()
       {
               KeySet *myConfig = ksNew(0, KS_END);
               Key *key = keyNew("/sw/MyApp", KEY_CASCADING_NAME, KEY_END);
               KDB *handle = kdbOpen(key);

               kdbGet(handle, myConfig, key);
               // to get an intention of proper error handling see kdbget_error.c

               keyDel (key);

               Key * result = ksLookupByName (myConfig,"/sw/MyApp/Tests/TestKey1", 0);

               const char * key_name = keyName(result);
               const char * key_value = keyString(result);
               const char * key_comment = keyString(keyGetMeta(result, "comment"));
               printf("key: %s value: %s comment: %s0, key_name, key_value, key_comment);

               ksDel (myConfig); // delete the in-memory configuration

               // maybe you want kdbSet() myConfig here

               kdbClose(handle, 0); // no more affairs with the key database.
       }

       When a backend fails kdbGet() will return -1 with all error and warning information in the
       parentKey. The parameter returned will not be changed.

       Updates:
           In the first run of kdbGet all requested (or more) keys are retrieved. On subsequent
           calls only the keys are retrieved where something was changed inside the key database.
           The other keys stay unchanged in the keyset, even if they were manipulated.

       It is your responsibility to save the original keyset if you need it afterwards.

       If you want to get the same keyset again, you need to open a second handle to the key
       database using kdbOpen().

       Parameters:
           handle contains internal information of opened  key database
           parentKey is used to add warnings and set an error information. Additionally, its name
           is an hint which keys should be retrieved (it is possible that more are retrieved).

           • cascading keys (starting with /) will retrieve the same path in all namespaces

           • / will retrieve all keys

           ks the (pre-initialized) KeySet returned with all keys found will not be changed on
           error or if no update is required

       See also:
           ksLookup(), ksLookupByName() for powerful lookups after the KeySet was retrieved

           kdbOpen() which needs to be called before

           kdbSet() to save the configuration afterwards and kdbClose() to finish affairs with
           the Key database.

       Return values:
           1 if the keys were retrieved successfully
           0 if there was no update - no changes are made to the keyset then
           -1 on failure - no changes are made to the keyset then

       #include <kdb.hpp>

       #include <keyio.hpp>

       using namespace kdb;

       int main()
       {
               KeySet config;
               KDB kdb;
               kdb.get(config, "/sw/MyApp");

               Key k = config.lookup("/sw/MyApp/mykey");
               if (k)
               {
                       std::cout << k << " is " << k.get<int>() << std::endl;
               }
               else
               {
                       std::cerr << "No key found" << std::endl;
                       return 1;
               }
       }

       Parameters:
           returned the keyset where the keys will be in
           keyname the root keyname which should be used to get keys below it

       Return values:
           0 if no key was updated
           1 if user or system keys were updated
           2 if user and system keys were updated

       Exceptions:
           KDBException if there were problems with the database

       See also:
           KDB::get (KeySet & returned, Key & parentKey)

   int kdb::KDB::get (KeySet & returned, Key & parentKey) [inline]
       Get all keys below parentKey inside returned. Retrieve keys in an atomic and universal
       way.

       Precondition:
           The handle must be passed as returned from kdbOpen()

           The returned KeySet must be a valid KeySet, e.g. constructed with ksNew().

           The parentKey Key must be a valid Key, e.g. constructed with keyNew().

       If you pass NULL, which violates the preconditions, on any parameter kdbGet() will fail
       immediately without doing anything.

       The returned KeySet may already contain some keys, e.g. from previous kdbGet() calls. The
       new retrieved keys will be appended using ksAppendKey().

       It will fully retrieve, at least, all keys under the parentKey folder, with all subfolders
       and their children.

       Note:
           kdbGet() might retrieve more keys then requested (that are not below parentKey). These
           keys must be passed to calls of kdbSet(), otherwise they will be lost. This stems from
           the fact that the user has the only copy of the whole configuration and backends only
           write configuration that was passed to them. For example, if you kdbGet()
           'system/mountpoint/interest' you will not only get all keys below
           system/mountpoint/interest, but also all keys below system/mountpoint (if
           system/mountpoint is a mountpoint as the name suggests, but system/mountpoint/interest
           is not a mountpoint). Make sure to not touch or remove keys outside the keys of
           interest, because others may need them!

       Example:
           This example demonstrates the typical usecase within an application (without error
           handling).

       #include <kdb.h>
       #include <stdio.h>

       int main()
       {
               KeySet *myConfig = ksNew(0, KS_END);
               Key *key = keyNew("/sw/MyApp", KEY_CASCADING_NAME, KEY_END);
               KDB *handle = kdbOpen(key);

               kdbGet(handle, myConfig, key);
               // to get an intention of proper error handling see kdbget_error.c

               keyDel (key);

               Key * result = ksLookupByName (myConfig,"/sw/MyApp/Tests/TestKey1", 0);

               const char * key_name = keyName(result);
               const char * key_value = keyString(result);
               const char * key_comment = keyString(keyGetMeta(result, "comment"));
               printf("key: %s value: %s comment: %s0, key_name, key_value, key_comment);

               ksDel (myConfig); // delete the in-memory configuration

               // maybe you want kdbSet() myConfig here

               kdbClose(handle, 0); // no more affairs with the key database.
       }

       When a backend fails kdbGet() will return -1 with all error and warning information in the
       parentKey. The parameter returned will not be changed.

       Updates:
           In the first run of kdbGet all requested (or more) keys are retrieved. On subsequent
           calls only the keys are retrieved where something was changed inside the key database.
           The other keys stay unchanged in the keyset, even if they were manipulated.

       It is your responsibility to save the original keyset if you need it afterwards.

       If you want to get the same keyset again, you need to open a second handle to the key
       database using kdbOpen().

       Parameters:
           handle contains internal information of opened  key database
           parentKey is used to add warnings and set an error information. Additionally, its name
           is an hint which keys should be retrieved (it is possible that more are retrieved).

           • cascading keys (starting with /) will retrieve the same path in all namespaces

           • / will retrieve all keys

           ks the (pre-initialized) KeySet returned with all keys found will not be changed on
           error or if no update is required

       See also:
           ksLookup(), ksLookupByName() for powerful lookups after the KeySet was retrieved

           kdbOpen() which needs to be called before

           kdbSet() to save the configuration afterwards and kdbClose() to finish affairs with
           the Key database.

       Return values:
           1 if the keys were retrieved successfully
           0 if there was no update - no changes are made to the keyset then
           -1 on failure - no changes are made to the keyset then

       Parameters:
           returned the keyset where the keys will be in
           parentKey the parentKey of returned

       Return values:
           0 if no key was updated
           1 if user or system keys were updated
           2 if user and system keys were updated

       Exceptions:
           KDBException if there were problems with the database

   void kdb::KDB::open (Key & errorKey) [inline]
       Open the database.

       Parameters:
           errorKey is useful if you want to get the warnings in the successful case, when no
           exception is thrown.

       Opens the session with the Key database.

       Precondition:
           errorKey must be a valid key, e.g. created with keyNew()

       The method will bootstrap itself the following way. The first step is to open the default
       backend. With it system/elektra/mountpoints will be loaded and all needed libraries and
       mountpoints will be determined. These libraries for backends will be loaded and with it
       the KDB datastructure will be initialized.

       You must always call this method before retrieving or committing any keys to the database.
       In the end of the program, after using the key database, you must not forget to
       kdbClose().

       The pointer to the KDB structure returned will be initialized like described above, and it
       must be passed along on any kdb*() method your application calls.

       Get a KDB handle for every thread using elektra. Don't share the handle across threads,
       and also not the pointer accessing it:

       void thread1()
       {
               Key *parent = keyNew("/app/part1", KEY_CASCADING_NAME, KEY_END);
               KDB * h = kdbOpen(parent);
               // fetch keys and work with them
               kdbClose(h, parent);
       }
       void thread2()
       {
               Key *parent = keyNew("/app/part2", KEY_CASCADING_NAME, KEY_END);
               KDB * h = kdbOpen(parent);
               // fetch keys and work with them
               kdbClose(h, parent);
       }

        You don't need kdbOpen() if you only want to manipulate plain in-memory Key or KeySet
       objects.

       Precondition:
           errorKey must be a valid key, e.g. created with keyNew()

       Parameters:
           errorKey the key which holds errors and warnings which were issued

       See also:
           kdbGet(), kdbClose() to end all affairs to the Key database.

       Return values:
           handle on success
           NULL on failure

   int kdb::KDB::set (KeySet & returned, std::string const & keyname) [inline]
       Set all keys below keyname. If the keyname of the parentKey is invalid (e.g. empty) all
       keys will be set.

       Set keys in an atomic and universal way.

       Precondition:
           kdbGet() must be called before kdbSet():

           • initially (after kdbOpen())

           • after conflict errors in kdbSet().

           The returned KeySet must be a valid KeySet, e.g. constructed with ksNew().

           The parentKey Key must be a valid Key, e.g. constructed with

       With parentKey you can give an hint which part of the given keyset is of interest for you.
       Then you promise, you only modified or removed keys below this key.

       Errors
           If some error occurs, kdbSet() will stop. In this situation the KeySet internal cursor
           will be set on the key that generated the error. None of the keys are actually
           committed in this situation (no configuration file will be modified).

       In case of errors you should present the error message to the user and let the user decide
       what to do. Possible solutions are:

       • remove the problematic key and use kdbSet() again (for validation or type errors)

       • change the value of the problematic key and use kdbSet() again (for validation errors)

       • do a kdbGet() (for conflicts, i.e. error 30) and then

         • set the same keyset again (in favour of what was set by this user)

         • drop the old keyset (in favour of what was set from another application)

         • merge the original, your own and the other keyset

       • export the configuration into a file (for unresolvable errors)

       • repeat the same kdbSet might be of limited use if the operator does not explicitly
         request it, because temporary errors are rare and its unlikely that they fix themselves
         (e.g. disc full, permission problems)

       Optimization
           Each key is checked with keyNeedSync() before being actually committed. So only
           changed keys are updated. If no key of a backend needs to be synced any affairs to
           backends are omitted and 0 is returned.

       KeySet *myConfig = ksNew(0, KS_END);
       Key *parentKey = keyNew("system/sw/MyApp",KEY_END);
       KDB *handle = kdbOpen(parentKey);

       kdbGet(handle, myConfig, parentKey); // kdbGet needs to be called first!
       KeySet *base = ksDup(myConfig); // save a copy of original keyset

       // change the keys within myConfig

       KeySet *ours = ksDup(myConfig); // save a copy of our keyset
       KeySet *theirs; // needed for 3-way merging
       int ret=kdbSet(handle, myConfig, parentKey);
       while (ret == -1) // as long as we have an error
       {
               // We got an error. Warn user.
               Key *problemKey = ksCurrent(myConfig);
               // parentKey has the errorInformation
               // problemKey is the faulty key (may be null)
               int userInput = showElektraErrorDialog (parentKey, problemKey);
               switch (userInput)
               {
               case INPUT_USE_OURS:
                       kdbGet(handle, myConfig, parentKey); // refresh key database
                       ksDel(myConfig);
                       myConfig = ours;
                       break;
               case INPUT_DO_MERGE:
                       theirs = ksDup(ours);
                       kdbGet(handle, theirs, parentKey); // refresh key database
                       KeySet * res=doElektraMerge(ours, theirs, base);
                       ksDel(theirs);
                       myConfig = res;
                       break;
               case INPUT_USE_THEIRS:
                       // should always work, we just write what we got
                       // but to be sure always give the user another way
                       // to exit the loop
                       kdbGet(handle, myConfig, parentKey); // refresh key database
                       break;
               // other cases ...
               }
               ret=kdbSet(handle, myConfig, parentKey);
       }

       ksDel (ours);
       ksDel (base);
       ksDel (myConfig); // delete the in-memory configuration

       kdbClose(handle, parentKey); // no more affairs with the key database.
       keyDel(parentKey);

        showElektraErrorDialog() and doElektraMerge() need to be implemented by the user of
       Elektra. For doElektraMerge a 3-way merge algorithm exists in libelektra-tools.

       Parameters:
           handle contains internal information of opened  key database
           ks a KeySet which should contain changed keys, otherwise nothing is done
           parentKey is used to add warnings and set an error information. Additionally, its name
           is an hint which keys should be committed (it is possible that more are changed).

           • cascading keys (starting with /) will set the path in all namespaces

           • / will commit all keys

           • meta-names will be rejected (error 104)

           • empty/invalid (error 105)

       Return values:
           1 on success
           0 if nothing had to be done, no changes in KDB
           -1 on failure, no changes in KDB

       See also:
           keyNeedSync()

           ksCurrent() contains the error Key

           kdbOpen() and kdbGet() that must be called first

           kdbClose() that must be called afterwards

       Return values:
           0 if no key was updated
           1 if user or system keys were updated
           2 if user and system keys were updated

       Parameters:
           returned the keyset where the keys will be in
           keyname the keyname below the names should be set

       Exceptions:
           KDBException if there were problems with the database

   int kdb::KDB::set (KeySet & returned, Key & parentKey) [inline]
       Set all keys below parentKey. If the keyname of the parentKey is invalid (e.g. empty) all
       keys will be set.

       Set keys in an atomic and universal way.

       Precondition:
           kdbGet() must be called before kdbSet():

           • initially (after kdbOpen())

           • after conflict errors in kdbSet().

           The returned KeySet must be a valid KeySet, e.g. constructed with ksNew().

           The parentKey Key must be a valid Key, e.g. constructed with

       With parentKey you can give an hint which part of the given keyset is of interest for you.
       Then you promise, you only modified or removed keys below this key.

       Errors
           If some error occurs, kdbSet() will stop. In this situation the KeySet internal cursor
           will be set on the key that generated the error. None of the keys are actually
           committed in this situation (no configuration file will be modified).

       In case of errors you should present the error message to the user and let the user decide
       what to do. Possible solutions are:

       • remove the problematic key and use kdbSet() again (for validation or type errors)

       • change the value of the problematic key and use kdbSet() again (for validation errors)

       • do a kdbGet() (for conflicts, i.e. error 30) and then

         • set the same keyset again (in favour of what was set by this user)

         • drop the old keyset (in favour of what was set from another application)

         • merge the original, your own and the other keyset

       • export the configuration into a file (for unresolvable errors)

       • repeat the same kdbSet might be of limited use if the operator does not explicitly
         request it, because temporary errors are rare and its unlikely that they fix themselves
         (e.g. disc full, permission problems)

       Optimization
           Each key is checked with keyNeedSync() before being actually committed. So only
           changed keys are updated. If no key of a backend needs to be synced any affairs to
           backends are omitted and 0 is returned.

       KeySet *myConfig = ksNew(0, KS_END);
       Key *parentKey = keyNew("system/sw/MyApp",KEY_END);
       KDB *handle = kdbOpen(parentKey);

       kdbGet(handle, myConfig, parentKey); // kdbGet needs to be called first!
       KeySet *base = ksDup(myConfig); // save a copy of original keyset

       // change the keys within myConfig

       KeySet *ours = ksDup(myConfig); // save a copy of our keyset
       KeySet *theirs; // needed for 3-way merging
       int ret=kdbSet(handle, myConfig, parentKey);
       while (ret == -1) // as long as we have an error
       {
               // We got an error. Warn user.
               Key *problemKey = ksCurrent(myConfig);
               // parentKey has the errorInformation
               // problemKey is the faulty key (may be null)
               int userInput = showElektraErrorDialog (parentKey, problemKey);
               switch (userInput)
               {
               case INPUT_USE_OURS:
                       kdbGet(handle, myConfig, parentKey); // refresh key database
                       ksDel(myConfig);
                       myConfig = ours;
                       break;
               case INPUT_DO_MERGE:
                       theirs = ksDup(ours);
                       kdbGet(handle, theirs, parentKey); // refresh key database
                       KeySet * res=doElektraMerge(ours, theirs, base);
                       ksDel(theirs);
                       myConfig = res;
                       break;
               case INPUT_USE_THEIRS:
                       // should always work, we just write what we got
                       // but to be sure always give the user another way
                       // to exit the loop
                       kdbGet(handle, myConfig, parentKey); // refresh key database
                       break;
               // other cases ...
               }
               ret=kdbSet(handle, myConfig, parentKey);
       }

       ksDel (ours);
       ksDel (base);
       ksDel (myConfig); // delete the in-memory configuration

       kdbClose(handle, parentKey); // no more affairs with the key database.
       keyDel(parentKey);

        showElektraErrorDialog() and doElektraMerge() need to be implemented by the user of
       Elektra. For doElektraMerge a 3-way merge algorithm exists in libelektra-tools.

       Parameters:
           handle contains internal information of opened  key database
           ks a KeySet which should contain changed keys, otherwise nothing is done
           parentKey is used to add warnings and set an error information. Additionally, its name
           is an hint which keys should be committed (it is possible that more are changed).

           • cascading keys (starting with /) will set the path in all namespaces

           • / will commit all keys

           • meta-names will be rejected (error 104)

           • empty/invalid (error 105)

       Return values:
           1 on success
           0 if nothing had to be done, no changes in KDB
           -1 on failure, no changes in KDB

       See also:
           keyNeedSync()

           ksCurrent() contains the error Key

           kdbOpen() and kdbGet() that must be called first

           kdbClose() that must be called afterwards

       Return values:
           0 if no key was updated
           1 if user or system keys were updated
           2 if user and system keys were updated

       Parameters:
           returned the keyset where the keys are passed to the user
           parentKey the parentKey of returned

       Exceptions:
           KDBException if there were problems with the database

Author

       Generated automatically by Doxygen for Elektra from the source code.