This document describes the design of the C-\/\+A\+P\+I and provides hints for binding writers. It is not aimed at plugin writers, since it does not talk about the implementation details of Elektra.

Elektra follows two design principles\+:


\begin{DoxyEnumerate}
\item Make it hard to use the A\+P\+I the wrong way, and
\item aim towards an easy to use A\+P\+I for programmers reading and writing configuration.
\end{DoxyEnumerate}

Elektra's data structures are optimized to get, set and lookup values easily and fast.

The idea is, that the K\+D\+B A\+P\+I is not only implemented by Elektra. Elektra provides a full blown architecture to really support modern Linux Systems, but comes with some overhead. This document describes the {\ttfamily K\+D\+B} A\+P\+I. It also contains some hints about Elektra-\/specific conventions.

\subsection*{Data Structures}

The {\ttfamily Key}, {\ttfamily Key\+Set} and {\ttfamily K\+D\+B} data structures are defined in {\ttfamily \hyperlink{kdbprivate_8h}{kdbprivate.\+h}} to remain A\+B\+I compatible when one of them is changed. This means, it is not possible to put one of Elektra's data structures on the stack. You must use the memory management facilities mentioned in the next section.

\subsection*{Memory Management}

Elektra manages memory itself. This means, a programmer is not allowed to use free on data, which was not allocated by himself. This avoids situation where the programmer forgets to free data, and makes the A\+P\+I more beginner-\/friendly. In addition to that, {\ttfamily elektra\+Malloc} and free must use the same libc version. {\ttfamily elektra\+Malloc} in a library linked against another libc, but freed by the application could lead to hard to find bugs.

Some calls that create data, have an opposite call that frees this data. For example after you call\+: \begin{DoxyVerb}    KDB * kdbOpen();
\end{DoxyVerb}


you need to use\+: \begin{DoxyVerb}    int kdbClose(KDB *handle);
\end{DoxyVerb}


to get rid of the resources again. The second function may also shut down connections. Therefore it really must be called at the end of a program. \begin{DoxyVerb}    Key *keyNew(const char *keyName, ...);
    int keyDel(Key *key);

    KeySet *ksNew(int alloc, ...);
    int ksDel(KeySet *ks);
\end{DoxyVerb}


In the above pairs, the first function uses {\ttfamily elektra\+Malloc} to reserve the necessary amount of memory. The second function frees the allocated data segment. There are more occurrences of {\ttfamily elektra\+Malloc}, but they are invisible to the user of the A\+P\+I and happen implicitly within any of these 3 classes\+: {\ttfamily K\+D\+B}, {\ttfamily Key} and {\ttfamily Key\+Set}.

Names, values, and comments cannot be handled as easy, because Elektra does not provide a string library. There are 2 ways to access the mentioned attributes. We show these methods here, using the comment attribute as an example. The function \begin{DoxyVerb}    char *keyString(const Key *key);
\end{DoxyVerb}


just returns a string. Your are not allowed to change the returned string. The function \begin{DoxyVerb}    ssize_t keyGetValueSize(const Key *key);
\end{DoxyVerb}


shows how long the string is for the specified key. The returned value also specifies the minimum buffer size that {\ttfamily key\+Get\+String} will reserve for the copy of the key. The return value can be directly passed to {\ttfamily elektra\+Malloc}. \begin{DoxyVerb}    ssize_t keyGetString(const Key *key, char *returnedValue, size_t maxSize);
\end{DoxyVerb}


writes the comment in a buffer maintained by you.

\subsection*{Variable Arguments}

The constructors for {\ttfamily Key} and {\ttfamily Key\+Set} take a variable sized list of arguments. They can be used as an alternatives to the various {\ttfamily key\+Set$\ast$} methods and {\ttfamily ks\+Append\+Key}. With them you are able to generate any {\ttfamily Key} or {\ttfamily Key\+Set} with a single C-\/statement. This can be done programmatically by the plugin {\ttfamily c}.

To just retrieve a key, use \begin{DoxyVerb}    Key *k = keyNew(0);
\end{DoxyVerb}


To obtain a {\ttfamily keyset}, use \begin{DoxyVerb}    KeySet *k = ksNew(0, KS_END);
\end{DoxyVerb}


The macros {\ttfamily va\+\_\+start} and {\ttfamily va\+\_\+end} will not be used then. Alternatively pass a list as described in the documentation.

\subsection*{Off-\/by-\/one}

We avoid Off-\/by-\/one errors by starting all indizes with 0, as usual in C. The size returned by the {\ttfamily $\ast$\+Get\+Size} functions ({\ttfamily key\+Get\+Value\+Size}, {\ttfamily key\+Get\+Comment\+Size} and {\ttfamily key\+Get\+Owner\+Size}) is exactly the size you need to allocate. So if you add 1 to it, too much space is allocated, but no error will occur.

The same is true for {\ttfamily elektra\+Str\+Len} which also already has the null byte included.

\subsection*{Minimal Set}

{\ttfamily kdb.\+h} contains a minimal set of functions to fully work with a key database. The functions are implemented in {\ttfamily src/libs/elektra} in A\+N\+S\+I C.

\subsection*{Value, String or Binary}

Sometimes people confuse the terms “value”, “string” and “binary”\+:


\begin{DoxyItemize}
\item Value is just a name which does not specify if data is stored as string or in binary form.
\item A string is a char array, with a terminating `'\textbackslash{}0'`.
\item Binary data is stored in a array of type void, and not terminated by `'\textbackslash{}0'`.
\end{DoxyItemize}

See also \hyperlink{md_doc_help_elektra-glossary_doc_help_elektra-glossary_md}{the glossary} for further terminology.

In Elektra {\ttfamily char$\ast$} are used as null-\/terminated strings, while {\ttfamily void$\ast$} might contain {\ttfamily 0}-\/bytes\+: \begin{DoxyVerb}    const void *keyValue(const Key *key);
\end{DoxyVerb}


does not specify whether the returned value is binary or a string. The function just returns the pointer to the value. When {\ttfamily key} is a string (check with {\ttfamily key\+Is\+String}) at least {\ttfamily \char`\"{}\char`\"{}} will be returned. See section “\+Return Values” to learn more about common values returned by Elektra's functions. For binary data a {\ttfamily N\+U\+L\+L} pointer is also possible to distinguish between no data and `'\textbackslash{}0'`. \begin{DoxyVerb}    ssize_t keyGetValueSize(const Key *key);
\end{DoxyVerb}


does not specify whether the key type is binary or string. The function just returns the size which can be passed to {\ttfamily elektra\+Malloc} to hold the entire value. \begin{DoxyVerb}    ssize_t keyGetString(const Key *key, char *returnedString, size_t maxSize);
\end{DoxyVerb}


stores the string into a buffer maintained by you. \begin{DoxyVerb}    ssize_t keySetString(Key *key, const char *newString);
\end{DoxyVerb}


sets the null terminated string value for a certain key. \begin{DoxyVerb}    ssize_t keyGetBinary(const Key *key, void *returnedBinary, size_t maxSize);
\end{DoxyVerb}


retrieves binary data which might contain `'\textbackslash{}0'`. \begin{DoxyVerb}    ssize_t keySetBinary(Key *key, const void *newBinary, size_t dataSize);
\end{DoxyVerb}


sets the binary data which might contain `'\textbackslash{}0'{\ttfamily . The length is given by}data\+Size`.

\subsection*{Return Value}

Elektra's function share common error codes. Every function must return {\ttfamily -\/1} on error, if its return type is integer (like {\ttfamily int}, {\ttfamily ssize\+\_\+t}). If the function returns a pointer, {\ttfamily 0} ({\ttfamily N\+U\+L\+L}) will indicate an error. This behaviour can't be used for functions that return integers, since {\ttfamily 0} is a valid size and can also be used to represent the boolean value {\ttfamily false}.

Elektra uses integers for the length of C strings, reference counting, {\ttfamily Key\+Set} length and internal {\ttfamily Key\+Set} allocations.

The interface always accepts {\ttfamily size\+\_\+t} and internally uses {\ttfamily size\+\_\+t}, which is able to store larger numbers than {\ttfamily ssize\+\_\+t}.

The real size of C strings and buffers is limited to {\ttfamily S\+S\+I\+Z\+E\+\_\+\+M\+A\+X} which must be checked in every function. When a string exceeds that limit {\ttfamily -\/1} or a {\ttfamily N\+U\+L\+L} pointer (see above) must be returned.

The following functions return an internal string\+: \begin{DoxyVerb}    const char *keyName(const Key *key);
    const char *keyBaseName(const Key *key);
    const char *keyOwner(const Key *key);
    const char *keyComment(const Key *key);
\end{DoxyVerb}


and in the case that {\ttfamily key\+Is\+Binary(key)==0}\+: \begin{DoxyVerb}    const void *keyValue(const Key *key);
\end{DoxyVerb}


does so too. If in any of the functions above {\ttfamily key} is a {\ttfamily N\+U\+L\+L} pointer, then they also return {\ttfamily N\+U\+L\+L}.

If there is no string you will get back {\ttfamily \char`\"{}\char`\"{}}, that is a pointer to the value `'\textbackslash{}0'{\ttfamily . The function to determine the size will return}1` in that case. That means that an empty string – nothing except the N\+U\+L\+L terminator – has size {\ttfamily 1}.

This is not true for {\ttfamily key\+Value} in the case of binary data, because the value `'\textbackslash{}0'{\ttfamily in the first byte is perfectly legal binary data. }key\+Get\+Value\+Size{\ttfamily may also return}0` for that reason.

\subsection*{Error Handling}

Elektra does not set {\ttfamily errno}. If a function you call sets {\ttfamily errno}, make sure to set it back to the old value again.

Additional information about error handling is available \hyperlink{md_doc_help_elektra-error-handling_doc_help_elektra-error-handling_md}{here}.

\subsection*{Naming}

All function names begin with their class name, e.\+g. {\ttfamily kdb}, {\ttfamily ks} or {\ttfamily key}. We use capital letters to separate single words (Camel\+Case). This leads to short names, but might be not as readable as separating names by other means.

{\itshape Get} and {\itshape Set} are used for getters/and setters. We use {\itshape Is} to ask about a flag or state and {\itshape Needs} to ask about state related to databases. For allocation/deallocation we use C++ styled names (e.\+g {\ttfamily $\ast$\+New}, {\ttfamily $\ast$\+Del}).

Macros and Enums are written in capital letters. Options start with {\ttfamily K\+D\+B\+\_\+\+O}, errors with {\ttfamily K\+D\+B\+\_\+\+E\+R\+R}, namespaces with {\ttfamily K\+E\+Y\+\_\+\+N\+S} and key types with {\ttfamily K\+E\+Y\+\_\+\+T\+Y\+P\+E}.

Data structures start with a capital letter for every part of the word\+: \begin{DoxyVerb}    KDB ... Key Data Base Handle
    KeySet ... Key Set
    Key ... Key
\end{DoxyVerb}


We use singular for all names.

Function names not belonging to one of the three classes are Elektra specific. They use the prefix {\ttfamily elektra$\ast$}. They will always be Elektra specific and won't be implemented by other K\+D\+B implementations.

\subsection*{const}

Wherever possible functions should use the keyword {\ttfamily const} for parameters. The A\+P\+I uses this keyword for parameters, to show that a function does not modify a {\ttfamily Key} or a {\ttfamily Key\+Set}. We do not use {\ttfamily const} for return values, except for the following functions\+: \begin{DoxyVerb}    const char *keyName(const Key *key);
    const char *keyBaseName(const Key *key);
    const char *keyComment(const Key *key);
    const void *keyValue(const Key *key);
    const char *keyString(const Key *key);
    const Key  *keyGetMeta(const Key *key, const char* metaName)
\end{DoxyVerb}


The reason behind this is, that the above functions – as their name suggest – only retrieve values. The returned value must not be modified directly. 