Git init
[pkgs/e/elektra.git] / doc / elektra-api / latex / group__backend.tex
1 \section{KDB Backends :: Elektra framework for pluggable backends}
2 \label{group__backend}\index{KDB Backends :: Elektra framework for pluggable backends@{KDB Backends :: Elektra framework for pluggable backends}}
3 The tactics to create pluggable backends to libelektra.so.  
4 \subsection*{Enumerations}
5 \begin{CompactItemize}
6 \item 
7 enum {\bf backend\_\-t} \{ \par
8 {\bf KDB\_\-BE\_\-OPEN} = 1, 
9 {\bf KDB\_\-BE\_\-CLOSE} = 1$<$$<$1, 
10 {\bf KDB\_\-BE\_\-GET} = 1$<$$<$2, 
11 {\bf KDB\_\-BE\_\-SET} = 1$<$$<$3, 
12 \par
13 {\bf KDB\_\-BE\_\-VERSION} = 1$<$$<$4, 
14 {\bf KDB\_\-BE\_\-DESCRIPTION} = 1$<$$<$5, 
15 {\bf KDB\_\-BE\_\-AUTHOR} = 1$<$$<$6, 
16 {\bf KDB\_\-BE\_\-LICENCE} = 1$<$$<$7, 
17 \par
18 {\bf KDB\_\-BE\_\-END} = 0
19  \}
20 \end{CompactItemize}
21 \subsection*{Functions}
22 \begin{CompactItemize}
23 \item 
24 KDB $\ast$ {\bf kdbBackendExport} (const char $\ast$backendName,...)
25 \item 
26 int {\bf kdbOpen\_\-backend} (KDB $\ast$handle)
27 \item 
28 int {\bf kdbClose\_\-backend} (KDB $\ast$handle)
29 \item 
30 ssize\_\-t {\bf kdbGet\_\-backend} (KDB $\ast$handle, KeySet $\ast$returned, const Key $\ast$parentKey)
31 \item 
32 ssize\_\-t {\bf kdbSet\_\-backend} (KDB $\ast$handle, KeySet $\ast$returned, const Key $\ast$parentKey)
33 \item 
34 {\bf KDBEXPORT} (backend)
35 \end{CompactItemize}
36
37
38 \subsection{Detailed Description}
39 The tactics to create pluggable backends to libelektra.so. 
40
41 \subsection{Introduction}\label{group__backend_intro}
42 \begin{Desc}
43 \item[Since:]Since version 0.4.9, Elektra can dynamically load different key storage backends.
44
45 Since version 0.7.0 Elektra can have multiple storage backends, called just backends henceforth, at once for different purposes.\end{Desc}
46 \begin{Desc}
47 \item[Definition: You refers to the implementation of the function in this specification.]If you read the documentation about \doxyref{kdbGet\_\-backend()}{p.}{group__backend_gf3c9c38b7710c435e3caed9e8df2184d}, then the caller is \doxyref{kdbGet()}{p.}{group__kdb_g37b44bda1b83bc0144916bf21a86c1b5} which is the only function which can and will call (invoke) you. The Preconditions will always be met by the caller, you can count on them. But you (as said before we speak about the function) need to take care that all Postconditions are met.\end{Desc}
48 \subsubsection{Overview}\label{group__backend_overview}
49 The methods of class KDB that are backend dependent are only \doxyref{kdbOpen\_\-backend()}{p.}{group__backend_g8ce84f1f6defc40a9239058991e257da}, \doxyref{kdbClose\_\-backend()}{p.}{group__backend_g6dd468490ad54c3a52f7e5083b8c721b}, \doxyref{kdbGet\_\-backend()}{p.}{group__backend_gf3c9c38b7710c435e3caed9e8df2184d}, \doxyref{kdbSet\_\-backend()}{p.}{group__backend_g2d86ff43b693d59d4b82b597756e9e23} and \doxyref{KDBEXPORT()}{p.}{group__backend_g40bb01174ff716b57525c4dd7730aac8} to export these methods. A backend must implement each of them. A detailed specification of these methods and methods needed in that context follows in this Documentation Module.
50
51 The other KDB methods are higher level. They use the above methods to do their job, and generally don't have to be reimplemented for a different backend, but there might be a solution to do so for higher performance in future. kdbh$\ast$ methods are for access to the internals of KDB, which will be passed to all functions.\subsubsection{Include Files}\label{group__backend_incl}
52 The backend implementation must include: 
53
54 \begin{Code}\begin{verbatim}#include <kdbbackend.h>
55 \end{verbatim}
56 \end{Code}
57
58  to have direct access to the structs, which is currently needed to access the capability structure.
59
60 Don't include kdb.h, it will be automatically included and some macros will avoid redefining structs where you have more insight from a backend than you would normally have. Additionally you get the declaration of all functions described here, except the one you have to implement.\subsubsection{Dynamic Mounting}\label{group__backend_dyn}
61 An elektrified program will use elektra/libelektra-default.so as its default backend. This backend provides the system/ hierarchy and some base configuration in system/elektra for elektra itself. Everything below system/ and the other hierarchies can be stored in any different backend. This is allowed through the technique mounting. A backend can be mounted to any path except system/ and system/elektra.
62
63 A backends is guaranteed to be loaded whenever calling \doxyref{kdbGet()}{p.}{group__kdb_g37b44bda1b83bc0144916bf21a86c1b5} or \doxyref{kdbSet()}{p.}{group__kdb_g953cf29721e6000c2516cd6b5d36f571} requires the backend, but may already be loaded at \doxyref{kdbOpen()}{p.}{group__kdb_gb7be60c387892d2235907836c5060e1f}. It might be loaded explizit by \doxyref{kdbMount()}{p.}{group__kdb_g40e35f26cc69bd43ef1b2207f4fa121b} at any time after \doxyref{kdbOpen()}{p.}{group__kdb_gb7be60c387892d2235907836c5060e1f}. Backends get a chance to initialize by calling \doxyref{kdbOpen\_\-backend()}{p.}{group__backend_g8ce84f1f6defc40a9239058991e257da} whenever they are loaded.
64
65 Using \doxyref{kdbUnmount()}{p.}{group__kdb_g400ca66a9bdc04ecadb66d84dc06bd55} a backend may closed during runtime. All backends will be closed when \doxyref{kdbClose()}{p.}{group__kdb_gd9bb8bd3f1296bfa77cc9a1b41b7a859} is called. Backends might be unloaded after some time of inactivity or other reasons. After loading backends get a chance to cleanup by calling \doxyref{kdbClose\_\-backend()}{p.}{group__backend_g6dd468490ad54c3a52f7e5083b8c721b}.
66
67 That means it is not guaranteed that the backend live the whole time nor it will be loaded only one time. A tactic to handle this well is to build stateless backends referring to \doxyref{kdbGet\_\-backend()}{p.}{group__backend_gf3c9c38b7710c435e3caed9e8df2184d} and \doxyref{kdbSet\_\-backend()}{p.}{group__backend_g2d86ff43b693d59d4b82b597756e9e23}. That means that there is no more information present than in the storage itself. Be aware that you must not have any global variables in your backend. Read more about that in \doxyref{kdbOpen\_\-backend()}{p.}{group__backend_g8ce84f1f6defc40a9239058991e257da}. But to be stateless you also have to consider not to store any other than caching information into \doxyref{kdbhGetBackendData()}{p.}{group__backendhandle_ge463be8651422015fd12811ed66d20f3}. I repeat: it must be possible to restore everything dynamically stored without exception.\subsubsection{Library Names}\label{group__backend_lib}
68 Elektra source code or development package provides a skeleton and Makefile to implement a backend. Copy src/backends/template to have a good starting point. See the CODING document to know how to integrate the backend in the build system or how to compile it external.
69
70 A backend is defined by a single name, for example {\tt BACKENDNAME}, that causes libelektra.so look for its library as {\tt libelektra-BACKENDNAME.so}.
71
72 \begin{Desc}
73 \item[Example of a complete backend:]
74
75 \begin{Code}\begin{verbatim}//
76 // This is my implementation for an Elektra backend storage.
77 //
78 // To compile it:
79 // $ cc -fpic `pkg-config --cflags elektra` -o myback.o -c myback.c
80 // $ cc -shared -fpic `pkg-config --libs elektra` -o libelektra-myback.so myback.o
81 //
82 // To use it:
83 // $ preload mount myback system/myback myback /tmp/nofile
84 // $ kdb ls system/myback
85 // $ kdb set system/myback/key "value"
86 // $ kdb get system/myback/key
87 //
88
89 #include <kdbbackend.h>
90
91 #define BACKENDNAME "backend"
92
93
94 int kdbOpen_backend(KDB *handle) {...}
95 int kdbClose_backend(KDB *handle) {...}
96 int kdbGet_backend(KDB handle, KeySet *returned, Key *key) {...}
97 int kdbSet_backend(KDB handle, KeySet *returned, Key *key) {...}
98
99 KDBEXPORT(backend) {
100         return kdbBackendExport(BACKENDNAME,
101                 KDB_BE_OPEN,  &kdbOpen_backend,
102                 KDB_BE_CLOSE, &kdbClose_backend,
103                 KDB_BE_GET,   &kdbGet_backend,
104                 KDB_BE_SET,   &kdbSet_backend,
105                 KDB_BE_END);
106 }
107 \end{verbatim}
108 \end{Code}
109
110 \end{Desc}
111 In the example, the $\ast$\_\-backend() methods can have other random names, since you'll correctly pass them later to \doxyref{kdbBackendExport()}{p.}{group__backend_g2b02d413c4bb3c11e0f2560937b82db3}. It is recommended to use names according to your backendname to avoid name clashes. Be aware that every symbol name in the linked application must be unique.
112
113 Don't copy above example out, use src/backends/template, it does compile as-is and does some initialization and cleanup already.
114
115 Elektra source code tree includes several backend implementations {\tt https://svn.libelektra.org/svn/elektra/trunk/src/backends/} that can also be used as a reference.\subsection{Details}\label{group__backend_backenddetail}
116 \subsubsection{Introduction}\label{group__backend_intro}
117 Capabilities may make your live much easier. If it is impossible, very hard or would impact performance badly you may leave out some parts described here, but need to declare that you have done so with capabilites.
118
119 It is allowed to provide additional information, even if you declared you don't have it. If you declare that you are capable of doing something, you must provide it without exceptions.\subsubsection{Owner}\label{group__backend_owner}
120 You need to set the owner of keys by \doxyref{keySetOwner()}{p.}{group__keyname_ga899d9f0251cb98a89761ef112910eca}. Owner is the name to whom a specific key of the user/ hierarchy belongs. If you declare kdbcGetnoOwner() you need not to set the owner of the keys. It also means that even if you want to get keys from another user hierarchy you get yours.\subsubsection{Values}\label{group__backend_value}
121 Values are the central information of keys next to the name describing what informations it holds. Parse them out of your backend and put them into the key with \doxyref{keySetString()}{p.}{group__keyvalue_g622bde1eb0e0c4994728331326340ef2}. The information will be duplicated, so you might need to free() your string. Don't try to directly access key-$>$data, things may change there and your backend might be compiled with a different libc than elektra. If you support types, you might want to use keySetRaw() to not change the key type. If you don't support values for all keys declare kdbcGetnoValue().\subsubsection{IDs}\label{group__backend_id}
122 You need to set uid respective gid for any key not having the uid and gid of the current process. This will be set by default in every key. You can do it with \doxyref{keySetUID()}{p.}{group__keymeta_gb5f284f5ecd261e0a290095f50ba1af7} and \doxyref{keySetGID()}{p.}{group__keymeta_g9e3d0fb3f7ba906e067727b9155d22e3}. Declaring kdbcGetnoUID() and kdbcGetnoGID() you need not set uid and gid.\subsubsection{Mode}\label{group__backend_mode}
123 Mode shows what can be done with the key having or not having the above uid and gid. Use \doxyref{keySetMode()}{p.}{group__keymeta_g8803037e35b9da1ce492323a88ff6bc3} to set the correct mode description, read the description in \doxyref{keySetMode()}{p.}{group__keymeta_g8803037e35b9da1ce492323a88ff6bc3} for the semantics of the 3 octal representation. Declaring kdbcGetnoMode() means mode will remain default.
124
125 The very related method \doxyref{keySetDir()}{p.}{group__keymeta_gae575bd86a628a15ee45baa860522e75} sets the executable bits of mode. Even if your backend does not support mode, it might support directories, meaning that keys have the mode 0664 or 0775 for directories. Declaring kdbcGetnoDir() means that the backend is flat, no key will be true for \doxyref{keyIsDir()}{p.}{group__keytest_gc0a10c602d52a35f81347e8a32312017} and so can't have any subkeys.\subsubsection{Timing}\label{group__backend_timing}
126 Keys should have exact timing information of their modification and access times. Use \doxyref{keySetATime()}{p.}{group__keymeta_g995d8b84731673c88c7c01f3fed538b9}, \doxyref{keySetMTime()}{p.}{group__keymeta_g481d8997187992fe4bbf288bc8ef4db7} and \doxyref{keySetCTime()}{p.}{group__keymeta_g9f502ecab8ab43f0b17220fcc95f3fa5} to store appropriate information. ATime need to be stored in database, if you stat a key the backend need to return the time \doxyref{kdbGet()}{p.}{group__kdb_g37b44bda1b83bc0144916bf21a86c1b5} was last used for the keys. If you don't support this, declare kdbcGetnoATime() and simple store time(0) in the atime. This must be the same for every key for a single \doxyref{kdbGet\_\-backend()}{p.}{group__backend_gf3c9c38b7710c435e3caed9e8df2184d}. If you only stat keys with \doxyref{kdbGet()}{p.}{group__kdb_g37b44bda1b83bc0144916bf21a86c1b5}, see below, then the access time should not be updated. MTime is the last modification time of value or comment. If you don't support this, declare kdbcGetnoMTime() and simple store time(0) in the mtime. This must be the same for every key for a single \doxyref{kdbGet\_\-backend()}{p.}{group__backend_gf3c9c38b7710c435e3caed9e8df2184d}. CTime is the last change time of any metadata or add/remove of subkeys. If you don't support this, declare kdbcGetnoCTime() and simple store time(0) in the ctime. This must be the same for every key for a single \doxyref{kdbGet\_\-backend()}{p.}{group__backend_gf3c9c38b7710c435e3caed9e8df2184d}.\subsubsection{Types}\label{group__backend_type}
127 Keys having value and comment can be one of two fundamental types, string or binary, both called value. While string is a null terminated utf8 character sequence, binary is any data of a specific length. Be sure to use \doxyref{keySetString()}{p.}{group__keyvalue_g622bde1eb0e0c4994728331326340ef2} for string and \doxyref{keySetBinary()}{p.}{group__keyvalue_ga50a5358fd328d373a45f395fa1b99e7} if you want to store binary data. If you do not support one of these, be sure to declare kdbcGetnoBinary() or kdbcGetnoString(), if you don't support both make sure to also declare kdbcGetnoValue().
128
129 Using keySetRaw() does not set the type, be sure to use \doxyref{keySetType()}{p.}{group__keymeta_gb92003db4b938594df48807c16766bf7} afterwards. This can be KEY\_\-TYPE\_\-STRING and KEY\_\-TYPE\_\-BINARY or any other type in type\_\-t, leading to same results as explained above, but also any other number in the range of type\_\-t. Declare kdbcGetnoTypes() when your backend does not support arbitrary types. 
130
131 \subsection{Enumeration Type Documentation}
132 \index{backend@{backend}!backend\_\-t@{backend\_\-t}}
133 \index{backend\_\-t@{backend\_\-t}!backend@{backend}}
134 \subsubsection[backend\_\-t]{\setlength{\rightskip}{0pt plus 5cm}enum {\bf backend\_\-t}}\label{group__backend_ge857eadce7085ecd3a24671a1826940a}
135
136
137 Switches to denote the backend methods. Used in calls to \doxyref{kdbBackendExport()}{p.}{group__backend_g2b02d413c4bb3c11e0f2560937b82db3}. \begin{Desc}
138 \item[Enumerator: ]\par
139 \begin{description}
140 \index{KDB\_\-BE\_\-OPEN@{KDB\_\-BE\_\-OPEN}!backend@{backend}}\index{backend@{backend}!KDB\_\-BE\_\-OPEN@{KDB\_\-BE\_\-OPEN}}\item[{\em 
141 KDB\_\-BE\_\-OPEN\label{group__backend_gge857eadce7085ecd3a24671a1826940a4293cef5efac0aa0ad61c18e41c0848c}
142 }]Next arg is backend for \doxyref{kdbOpen()}{p.}{group__kdb_gb7be60c387892d2235907836c5060e1f} \index{KDB\_\-BE\_\-CLOSE@{KDB\_\-BE\_\-CLOSE}!backend@{backend}}\index{backend@{backend}!KDB\_\-BE\_\-CLOSE@{KDB\_\-BE\_\-CLOSE}}\item[{\em 
143 KDB\_\-BE\_\-CLOSE\label{group__backend_gge857eadce7085ecd3a24671a1826940a28f303117ceb95838f92780007407955}
144 }]Next arg is backend for \doxyref{kdbClose()}{p.}{group__kdb_gd9bb8bd3f1296bfa77cc9a1b41b7a859} \index{KDB\_\-BE\_\-GET@{KDB\_\-BE\_\-GET}!backend@{backend}}\index{backend@{backend}!KDB\_\-BE\_\-GET@{KDB\_\-BE\_\-GET}}\item[{\em 
145 KDB\_\-BE\_\-GET\label{group__backend_gge857eadce7085ecd3a24671a1826940ae1e894d0fe6e3f05f444f03de2bc7885}
146 }]Next arg is backend for \doxyref{kdbGet()}{p.}{group__kdb_g37b44bda1b83bc0144916bf21a86c1b5} \index{KDB\_\-BE\_\-SET@{KDB\_\-BE\_\-SET}!backend@{backend}}\index{backend@{backend}!KDB\_\-BE\_\-SET@{KDB\_\-BE\_\-SET}}\item[{\em 
147 KDB\_\-BE\_\-SET\label{group__backend_gge857eadce7085ecd3a24671a1826940ab2fe708111d49ea21669db6bd7276007}
148 }]Next arg is backend for \doxyref{kdbSet()}{p.}{group__kdb_g953cf29721e6000c2516cd6b5d36f571} \index{KDB\_\-BE\_\-VERSION@{KDB\_\-BE\_\-VERSION}!backend@{backend}}\index{backend@{backend}!KDB\_\-BE\_\-VERSION@{KDB\_\-BE\_\-VERSION}}\item[{\em 
149 KDB\_\-BE\_\-VERSION\label{group__backend_gge857eadce7085ecd3a24671a1826940aeca3339f3b62cd2136646cb59678603e}
150 }]Next arg is char $\ast$ for Version \index{KDB\_\-BE\_\-DESCRIPTION@{KDB\_\-BE\_\-DESCRIPTION}!backend@{backend}}\index{backend@{backend}!KDB\_\-BE\_\-DESCRIPTION@{KDB\_\-BE\_\-DESCRIPTION}}\item[{\em 
151 KDB\_\-BE\_\-DESCRIPTION\label{group__backend_gge857eadce7085ecd3a24671a1826940ac60eb75a1391a6a4d30420f4079e4244}
152 }]Next arg is char $\ast$ for Description \index{KDB\_\-BE\_\-AUTHOR@{KDB\_\-BE\_\-AUTHOR}!backend@{backend}}\index{backend@{backend}!KDB\_\-BE\_\-AUTHOR@{KDB\_\-BE\_\-AUTHOR}}\item[{\em 
153 KDB\_\-BE\_\-AUTHOR\label{group__backend_gge857eadce7085ecd3a24671a1826940adc638374d367d0a52d9201f782eb9f5c}
154 }]Next arg is char $\ast$ for Author \index{KDB\_\-BE\_\-LICENCE@{KDB\_\-BE\_\-LICENCE}!backend@{backend}}\index{backend@{backend}!KDB\_\-BE\_\-LICENCE@{KDB\_\-BE\_\-LICENCE}}\item[{\em 
155 KDB\_\-BE\_\-LICENCE\label{group__backend_gge857eadce7085ecd3a24671a1826940ad3348e5ab9428da29ba7b51886b87bbe}
156 }]Next arg is char $\ast$ for Licence \index{KDB\_\-BE\_\-END@{KDB\_\-BE\_\-END}!backend@{backend}}\index{backend@{backend}!KDB\_\-BE\_\-END@{KDB\_\-BE\_\-END}}\item[{\em 
157 KDB\_\-BE\_\-END\label{group__backend_gge857eadce7085ecd3a24671a1826940adab7f08d13e598d0fafa2db1aa707b2f}
158 }]End of arguments \end{description}
159 \end{Desc}
160
161
162
163 \subsection{Function Documentation}
164 \index{backend@{backend}!kdbBackendExport@{kdbBackendExport}}
165 \index{kdbBackendExport@{kdbBackendExport}!backend@{backend}}
166 \subsubsection[kdbBackendExport]{\setlength{\rightskip}{0pt plus 5cm}KDB$\ast$ kdbBackendExport (const char $\ast$ {\em backendName}, \/   {\em ...})}\label{group__backend_g2b02d413c4bb3c11e0f2560937b82db3}
167
168
169 This function must be called by a backend's kdbBackendFactory() to define the backend's methods that will be exported.
170
171 See \doxyref{KDBEXPORT()}{p.}{group__backend_g40bb01174ff716b57525c4dd7730aac8} how to use it for backends.
172
173 The order and number of arguments are flexible (as in \doxyref{keyNew()}{p.}{group__key_gf6893c038b3ebee90c73a9ea8356bebf} and \doxyref{ksNew()}{p.}{group__keyset_g671e1aaee3ae9dc13b4834a4ddbd2c3c}) to let libelektra.so evolve without breaking its ABI compatibility with backends. So for each method a backend must export, there is a flag defined by \doxyref{backend\_\-t}{p.}{group__backend_ge857eadce7085ecd3a24671a1826940a}. Each flag tells \doxyref{kdbBackendExport()}{p.}{group__backend_g2b02d413c4bb3c11e0f2560937b82db3} which method comes next. A backend can have no implementation for a few methods that have default inefficient high-level implementations and to use these defaults, simply don't pass anything to \doxyref{kdbBackendExport()}{p.}{group__backend_g2b02d413c4bb3c11e0f2560937b82db3} about them.
174
175 \begin{Desc}
176 \item[Parameters:]
177 \begin{description}
178 \item[{\em backendName}]a simple name for this backend \end{description}
179 \end{Desc}
180 \begin{Desc}
181 \item[Returns:]an object that contains all backend informations needed by libelektra.so \end{Desc}
182 \index{backend@{backend}!kdbClose\_\-backend@{kdbClose\_\-backend}}
183 \index{kdbClose\_\-backend@{kdbClose\_\-backend}!backend@{backend}}
184 \subsubsection[kdbClose\_\-backend]{\setlength{\rightskip}{0pt plus 5cm}int kdbClose\_\-backend (KDB $\ast$ {\em handle})}\label{group__backend_g6dd468490ad54c3a52f7e5083b8c721b}
185
186
187 Finalize the backend. Called prior to unloading the backend dynamic module. Should ensure that no functions or static/global variables from the module will ever be accessed again.
188
189 Make sure to free all memory that your backend requested at runtime.
190
191 Specifically make sure to capDel() all capabilites and free your backendData in \doxyref{kdbhGetBackendData()}{p.}{group__backendhandle_ge463be8651422015fd12811ed66d20f3}.
192
193 After this call, libelektra.so will unload the backend library, so this is the point to shutdown any affairs with the storage.
194
195 \begin{Desc}
196 \item[Parameters:]
197 \begin{description}
198 \item[{\em handle}]contains internal information of \doxyref{opened }{p.}{group__kdb_gb7be60c387892d2235907836c5060e1f} key database \end{description}
199 \end{Desc}
200 \begin{Desc}
201 \item[Returns:]0 on success, anything else otherwise. \end{Desc}
202 \begin{Desc}
203 \item[See also:]\doxyref{kdbClose()}{p.}{group__kdb_gd9bb8bd3f1296bfa77cc9a1b41b7a859} \end{Desc}
204 \index{backend@{backend}!KDBEXPORT@{KDBEXPORT}}
205 \index{KDBEXPORT@{KDBEXPORT}!backend@{backend}}
206 \subsubsection[KDBEXPORT]{\setlength{\rightskip}{0pt plus 5cm}KDBEXPORT (backend)}\label{group__backend_g40bb01174ff716b57525c4dd7730aac8}
207
208
209 All KDB methods implemented by the backend can have random names, except kdbBackendFactory(). This is the single symbol that will be looked up when loading the backend, and the first method of the backend implementation that will be called.
210
211 Its purpose is to publish the exported methods for libelektra.so. The implementation inside the provided skeleton is usually enough: simply call \doxyref{kdbBackendExport()}{p.}{group__backend_g2b02d413c4bb3c11e0f2560937b82db3} with all methods that must be exported.
212
213 The first paramter is the name of the backend. Then every backend must have: {\tt KDB\_\-BE\_\-OPEN}, {\tt KDB\_\-BE\_\-CLOSE}, {\tt KDB\_\-BE\_\-GET} and {\tt KDB\_\-BE\_\-SET} 
214
215 You might also give following information by char $\ast$: {\tt KDB\_\-BE\_\-VERSION}, {\tt KDB\_\-BE\_\-AUTHOR}, {\tt KDB\_\-BE\_\-LICENCE} and {\tt KDB\_\-BE\_\-DESCRIPTION} 
216
217 You must use static \char`\"{}char arrays\char`\"{} in a read only segment. Don't allocate storage, it won't be freed.
218
219 With capability you can get that information on runtime from any backend with kdbGetCapability().
220
221 The last parameter must be {\tt KDB\_\-BE\_\-END}.
222
223 \begin{Desc}
224 \item[Returns:]\doxyref{kdbBackendExport()}{p.}{group__backend_g2b02d413c4bb3c11e0f2560937b82db3} with the above described parameters. \end{Desc}
225 \begin{Desc}
226 \item[See also:]\doxyref{kdbBackendExport()}{p.}{group__backend_g2b02d413c4bb3c11e0f2560937b82db3} for an example 
227
228 kdbOpenBackend() \end{Desc}
229 \index{backend@{backend}!kdbGet\_\-backend@{kdbGet\_\-backend}}
230 \index{kdbGet\_\-backend@{kdbGet\_\-backend}!backend@{backend}}
231 \subsubsection[kdbGet\_\-backend]{\setlength{\rightskip}{0pt plus 5cm}ssize\_\-t kdbGet\_\-backend (KDB $\ast$ {\em handle}, \/  KeySet $\ast$ {\em returned}, \/  const Key $\ast$ {\em parentKey})}\label{group__backend_gf3c9c38b7710c435e3caed9e8df2184d}
232
233
234 Retrieve information from a permanent storage to construct a keyset.\subsection{Introduction}\label{group__backend_intro}
235 This function does everything related to get keys out from a backend. There is only one function for that purpose to make implementation and locking much easier.
236
237 The keyset {\tt returned} needs to be filled with information so that the application using elektra can access it. See the live cycle of a comment to understand: 
238
239 \begin{Code}\begin{verbatim}kdbGet_backend(KDB *handle, KeySet *returned, Key *parentKey)
240 {
241         // the task of kdbGet_backend is to retrieve the comment out of the permanent storage
242         Key *key = keyDup (parentKey); // generate a new key to hold the information
243         char *comment;
244         loadfromdisc (comment);
245         keySetComment (key, comment, size); // set the information
246         ksAppendKey(returned, key);
247 }
248
249 // Now return to kdbGet
250 int kdbGet(KDB *handle, KeySet *keyset, Key *parentKey, options)
251 {
252         kdbGet_backend (handle, keyset, 0);
253         // postprocess the keyset and return it
254 }
255
256 // Now return to usercode, waiting for the comment
257 void usercode (Key *key)
258 {
259         kdbGet (handle, keyset, parentKey, 0);
260         key = ksCurrent (keyset, key); // lookup the key from the keyset
261         keyGetComment (key); // now the usercode retrieves the comment
262 }
263 \end{verbatim}
264 \end{Code}
265
266  Of course not only the comment, but all information of every key in the keyset {\tt returned} need to be fetched from permanent storage and stored in the key. So this specification needs to give an exhaustive list of information present in a key.\subsection{Conditions}\label{group__backend_conditions}
267 \begin{Desc}
268 \item[Precondition:]The caller \doxyref{kdbGet()}{p.}{group__kdb_g37b44bda1b83bc0144916bf21a86c1b5} will make sure before you are called that the parentKey:\begin{itemize}
269 \item is a valid key (means that it is a system or user key).\item is below (see \doxyref{keyIsBelow()}{p.}{group__keytest_g03332b5d97c76a4fd2640aca4762b8df}) your mountpoint and that your backend is responsible for it.\item has \doxyref{keyNeedStat()}{p.}{group__keytest_g3908b6511648a950f37cd0005bfea5d5} set when you should only stat keys (see later). and that the returned:\item is a valid keyset.\item has {\tt all} keys with the flag KEY\_\-FLAG\_\-SYNC set.\item {\tt may} has keys with the flag KEY\_\-FLAG\_\-STAT set.\item contains only valid keys direct below (see \doxyref{keyIsDirectBelow()}{p.}{group__keytest_g4f175aafd98948ce6c774f3bd92b72ca}) your parentKey. That also means, that the parentKey will not be in that keyset.\item have keyIsStat() set when the value/comment information is not necessary.\item is in a sorted order, see \doxyref{ksSort()}{p.}{group__keyset_g023554d395ccf2319a3807b8b5d2530c}. and that the handle:\begin{itemize}
270 \item is a valid KDB for your backend.\item that kdbhGetBackendHandle() contains the same handle for lifetime \doxyref{kdbOpen\_\-backend()}{p.}{group__backend_g8ce84f1f6defc40a9239058991e257da} until \doxyref{kdbClose\_\-backend()}{p.}{group__backend_g6dd468490ad54c3a52f7e5083b8c721b} was called.\end{itemize}
271 \end{itemize}
272
273
274 The caller \doxyref{kdbGet()}{p.}{group__kdb_g37b44bda1b83bc0144916bf21a86c1b5} will make sure that afterwards you were called, whenever the user requested it with the options, that:\begin{itemize}
275 \item hidden keys they will be thrown away.\item dirs or only dirs \doxyref{kdbGet()}{p.}{group__kdb_g37b44bda1b83bc0144916bf21a86c1b5} will remove the other.\item you will be called again recursively with all subdirectories.\item the keyset will be sorted when needed.\item the keys in returned having KEY\_\-FLAG\_\-SYNC will be sorted out.\end{itemize}
276 \end{Desc}
277 \begin{Desc}
278 \item[Invariant:]There are no global variables and \doxyref{kdbhGetBackendData()}{p.}{group__backendhandle_ge463be8651422015fd12811ed66d20f3} only stores information which can be regenerated any time. The handle is the same when it is the same backend.\end{Desc}
279 \begin{Desc}
280 \item[Postcondition:]The keyset {\tt returned} has the {\tt parentKey} and all keys direct below (\doxyref{keyIsDirectBelow()}{p.}{group__keytest_g4f175aafd98948ce6c774f3bd92b72ca}) with all information from the storage. Make sure to return all keys, all directories and also all hidden keys. If some of them are not wished, the caller \doxyref{kdbGet()}{p.}{group__kdb_g37b44bda1b83bc0144916bf21a86c1b5} will drop these keys, see above.\end{Desc}
281 \subsection{Details}\label{group__backend_detail}
282 Now lets look at an example how the typical \doxyref{kdbGet\_\-backend()}{p.}{group__backend_gf3c9c38b7710c435e3caed9e8df2184d} might be implemented. To explain we introduce some pseudo functions which do all the work with the storage (which is of course 90\% of the work for a real backend):\begin{itemize}
283 \item find\_\-key() gets an key out from the storage and memorize the position.\item next\_\-key() will find the next key and return it (with the name).\item fetch\_\-key() gets out all information of a key from storage (details see below example). It removes the \doxyref{keyNeedStat()}{p.}{group__keytest_g3908b6511648a950f37cd0005bfea5d5} and \doxyref{keyNeedSync()}{p.}{group__keytest_gf247df0de7aca04b32ef80e39ef12950} flag afterwards.\item stat\_\-key() gets all meta information (everything but value and comment). It removes the key \doxyref{keyNeedSync()}{p.}{group__keytest_gf247df0de7aca04b32ef80e39ef12950} flag afterwards. returns the next key out from the storage. The typical loop now will be like: 
284
285 \begin{Code}\begin{verbatim}ssize_t kdbGet_backend(KDB *handle, KeySet *update, const Key *parentKey) {
286         Key * current;
287         KeySet *returned = ksNew(ksGetSize(update)*2, KS_END);
288
289         find_key (parentKey);
290         current = keyDup (parentKey);
291         if (keyNeedStat(parentKey))
292         {
293                 current = stat_key(current);
294         } else {
295                 current = fetch_key(current);
296         }
297         clear_bit (KEY_FLAG_SYNC, current->flags);
298         ksAppendKey(returned, current);
299
300         while ((current = next_key()) != 0)
301         {
302                 // search if key was passed in update by caller
303                 Key * tmp = ksLookup (update, current, KDB_O_WITHOWNER|KDB_O_POP);
304                 if (tmp) current = tmp; // key was passed, so use it
305                 if (keyNeedStat(parentKey) || keyNeedStat(current))
306                 {
307                         current = stat_key (current);
308                         set_bit (KEY_FLAG_STAT, current->flags);
309                 } else {
310                         current = fetch_key(current);
311                 }
312                 clear_bit (KEY_FLAG_SYNC, current->flags);
313                 ksAppendKey(returned, current);
314                 // TODO: delete lookup key
315         }
316
317         if (error_happened())
318         {
319                 errno = restore_errno();
320                 return -1;
321         }
322
323         ksClear (update); // the rest of update keys is not in storage anymore
324         ksAppend(update, returned); // append the keys
325         ksDel (returned);
326
327         return nr_keys();
328 }
329 \end{verbatim}
330 \end{Code}
331
332 \end{itemize}
333
334
335 \begin{Desc}
336 \item[Note:]- returned and update are separated, for details why see \doxyref{ksLookup()}{p.}{group__keyset_ga34fc43a081e6b01e4120daa6c112004}\begin{itemize}
337 \item the bit KEY\_\-FLAG\_\-SYNC is always cleared, see postconditions\end{itemize}
338 \end{Desc}
339 So your mission is simple: Search the {\tt parentKey} and add it and then search all keys below and add them too, of course with all requested information (which is only depended on \doxyref{keyNeedStat()}{p.}{group__keytest_g3908b6511648a950f37cd0005bfea5d5}).\subsection{Stat}\label{group__backend_stat}
340 Sometimes value and comment are not of interest, but metadata. To avoid a potential time-consuming \doxyref{kdbGet()}{p.}{group__kdb_g37b44bda1b83bc0144916bf21a86c1b5} you can \doxyref{keyNeedStat()}{p.}{group__keytest_g3908b6511648a950f37cd0005bfea5d5} the {\tt parentKey}. If the backend supports a less time-consuming method to just get names and metadata, implement it, otherwise declare kdbcGetnoStat().
341
342 The implementation works as follows: When the {\tt parentKey} has \doxyref{keyNeedStat()}{p.}{group__keytest_g3908b6511648a950f37cd0005bfea5d5} set, all keys need to be stated instead of getting them. So the keys you \doxyref{ksAppendKey()}{p.}{group__keyset_ga5a1d467a4d71041edce68ea7748ce45} don't have a value nor a comment and make sure that KEY\_\-FLAG\_\-SYNC is not set, but \doxyref{keyNeedStat()}{p.}{group__keytest_g3908b6511648a950f37cd0005bfea5d5} must be set for all keys which are only stated.
343
344 The keys in {\tt returned} may already have \doxyref{keyNeedStat()}{p.}{group__keytest_g3908b6511648a950f37cd0005bfea5d5} set. These keys must keep the status \doxyref{keyNeedStat()}{p.}{group__keytest_g3908b6511648a950f37cd0005bfea5d5} and you don't need to get the value and comment. See the example above for code.\subsection{Updating}\label{group__backend_updating}
345 To get all keys out of the storage over and over again can be very inefficient. You might know a more efficient method to know if the key needs update or not, e.g. by stating it or by an external time stamp info. In that case you can make use of {\tt returned} KeySet. There are following possibilities:\begin{itemize}
346 \item The key is in returned and up to date. You just need to remove the KEY\_\-FLAG\_\-SYNC flag.\item The key is in returned but \doxyref{keyNeedStat()}{p.}{group__keytest_g3908b6511648a950f37cd0005bfea5d5} is true. You just need to stat the key and remove the KEY\_\-FLAG\_\-SYNC flag and set the KEY\_\-FLAG\_\-STAT flag.\item The key is in returned, \doxyref{keyNeedStat()}{p.}{group__keytest_g3908b6511648a950f37cd0005bfea5d5} is false (for the key and the {\tt parentKey}) and you know that the key has changed. You need to fully retrieve the key and remove the KEY\_\-FLAG\_\-SYNC flag.\item The key is not in returned, the {\tt parentKey} has \doxyref{keyNeedStat()}{p.}{group__keytest_g3908b6511648a950f37cd0005bfea5d5}. You just need to stat the key. Make sure that KEY\_\-FLAG\_\-SYNC is not set, but KEY\_\-FLAG\_\-STAT needs to be set. Append the key to {\tt returned}.\item The key is not in returned and the {\tt parentKey} \doxyref{keyNeedStat()}{p.}{group__keytest_g3908b6511648a950f37cd0005bfea5d5} is false. You need to fully retrieve the key out of storage, clear KEY\_\-FLAG\_\-STAT and KEY\_\-FLAG\_\-SYNC and \doxyref{ksAppendKey()}{p.}{group__keyset_ga5a1d467a4d71041edce68ea7748ce45} it to the {\tt returned} keyset.\end{itemize}
347
348
349 \begin{Desc}
350 \item[Note:]You must clear the flag KEY\_\-FLAG\_\-SYNC at the very last point where no more modification on the key will take place, because any modification on the key will set the KEY\_\-FLAG\_\-SYNC flag again. With that \doxyref{keyNeedSync()}{p.}{group__keytest_gf247df0de7aca04b32ef80e39ef12950} will return true and the caller will sort this key out.\end{Desc}
351 \subsection{only Full Get}\label{group__backend_fullget}
352 In some backends it is not useful to get only a part of the configuration, because getting all keys would take as long as getting some. For this situation, you can declare onlyFullGet, see kdbcGetonlyFullGet().
353
354 The only valid call for your backend is then that {\tt parentKey} equals the {\tt mountpoint}. For all other {\tt parentKey} you must, add nothing and just return 0.
355
356
357
358 \begin{Code}\begin{verbatim}if (strcmp (keyName(kdbhGetMountpoint(handle)), keyName(parentKey))) return 0;
359 \end{verbatim}
360 \end{Code}
361
362
363
364 If the {\tt parentKey} is your mountpoint you will of course fetch all keys, and not only the keys direct below the {\tt parentKey}. So {\tt returned} is valid iff:\begin{itemize}
365 \item every key is below ( \doxyref{keyIsBelow()}{p.}{group__keytest_g03332b5d97c76a4fd2640aca4762b8df}) the parentKey\item every key has a direct parent (\doxyref{keyIsDirectBelow()}{p.}{group__keytest_g4f175aafd98948ce6c774f3bd92b72ca}) in the keyset\end{itemize}
366
367
368 \begin{Desc}
369 \item[Note:]This statement is only valid for backends with kdbcGetonlyFullGet() set.
370
371 If any calls you use change errno, make sure to restore the old errno.\end{Desc}
372 \begin{Desc}
373 \item[See also:]\doxyref{kdbGet()}{p.}{group__kdb_g37b44bda1b83bc0144916bf21a86c1b5} for caller.\end{Desc}
374 \begin{Desc}
375 \item[Parameters:]
376 \begin{description}
377 \item[{\em handle}]contains internal information of \doxyref{opened }{p.}{group__kdb_gb7be60c387892d2235907836c5060e1f} key database \item[{\em returned}]contains a keyset where the function need to append the keys got from the storage. There might be also some keys inside it, see conditions. You may use them to support efficient updating of keys, see \doxyref{Updating}{p.}{group__backend_updating}. \item[{\em parentKey}]contains the information below which key the keys should be gotten.\end{description}
378 \end{Desc}
379 \begin{Desc}
380 \item[Returns:]Return how many keys you added.
381
382 -1 on failure, the current key in returned shows the position. In normal execution cases a positive value will be returned. But in some cases you are not able to get keys and have to return -1. If you declare kdbcGetnoError() you are done, but otherwise you have to set the cause of the error. (Will be added in 0.7.1) \end{Desc}
383 \index{backend@{backend}!kdbOpen\_\-backend@{kdbOpen\_\-backend}}
384 \index{kdbOpen\_\-backend@{kdbOpen\_\-backend}!backend@{backend}}
385 \subsubsection[kdbOpen\_\-backend]{\setlength{\rightskip}{0pt plus 5cm}int kdbOpen\_\-backend (KDB $\ast$ {\em handle})}\label{group__backend_g8ce84f1f6defc40a9239058991e257da}
386
387
388 Initialize the backend. This is the first method kdbOpenBackend() calls after dynamically loading the backend library.
389
390 This method is responsible of:\begin{itemize}
391 \item backend's specific configuration gathering\item all backend's internal structs initialization\item initial setup of all I/O details such as opening a file, connecting to a database, etc\end{itemize}
392
393
394 If your backend does not support all aspects described in \doxyref{kdbGet\_\-backend()}{p.}{group__backend_gf3c9c38b7710c435e3caed9e8df2184d} and \doxyref{kdbSet\_\-backend()}{p.}{group__backend_g2d86ff43b693d59d4b82b597756e9e23} you need capabilities to export this information. Per default you declare to be fully compliant to the specification given here, to change it get a pointer to KDBCap structure by using \doxyref{kdbhGetCapability()}{p.}{group__backendhandle_g090cfa7483afbb159b75c975eb1d513c}.
395
396 You may also read the configuration you can get with \doxyref{kdbhGetConfig()}{p.}{group__backendhandle_gb14dc8708c2ae4ffcba6cfb130019115} and transform it into other structures used by your backend.
397
398 But be aware that you don't have any global variables. If you do your backend will not be threadsafe. You can use \doxyref{kdbhSetBackendData()}{p.}{group__backendhandle_g97fab712e488c7ec3e198492106724ab} and \doxyref{kdbhGetBackendData()}{p.}{group__backendhandle_ge463be8651422015fd12811ed66d20f3} to store and get any information related to your backend.
399
400 The correct substitute for global variables will be: 
401
402 \begin{Code}\begin{verbatim}struct _GlobalData{ int global; };
403 typedef struct _GlobalData GlobalData;
404 int kdbOpen_backend(KDB *handle) {
405         PasswdData *data;
406         data=malloc(sizeof(PasswdData));
407         data.global = 20;
408         kdbhSetBackendData(handle,data);
409 }
410 \end{verbatim}
411 \end{Code}
412
413
414
415 Make sure to free everything in \doxyref{kdbClose\_\-backend()}{p.}{group__backend_g6dd468490ad54c3a52f7e5083b8c721b}.
416
417 \begin{Desc}
418 \item[Returns:]0 on success \end{Desc}
419 \begin{Desc}
420 \item[Parameters:]
421 \begin{description}
422 \item[{\em handle}]contains internal information of \doxyref{opened }{p.}{group__kdb_gb7be60c387892d2235907836c5060e1f} key database \end{description}
423 \end{Desc}
424 \begin{Desc}
425 \item[See also:]\doxyref{kdbOpen()}{p.}{group__kdb_gb7be60c387892d2235907836c5060e1f} \end{Desc}
426 \index{backend@{backend}!kdbSet\_\-backend@{kdbSet\_\-backend}}
427 \index{kdbSet\_\-backend@{kdbSet\_\-backend}!backend@{backend}}
428 \subsubsection[kdbSet\_\-backend]{\setlength{\rightskip}{0pt plus 5cm}ssize\_\-t kdbSet\_\-backend (KDB $\ast$ {\em handle}, \/  KeySet $\ast$ {\em returned}, \/  const Key $\ast$ {\em parentKey})}\label{group__backend_g2d86ff43b693d59d4b82b597756e9e23}
429
430
431 Store a keyset permanently.
432
433 This function does everything related to set and remove keys in a backend. There is only one function for that purpose to make implementation and locking much easier.
434
435 The keyset {\tt returned} was filled in with information from the application using elektra and the task of this function is to store it in a permanent way so that a subsequent call of \doxyref{kdbGet\_\-backend()}{p.}{group__backend_gf3c9c38b7710c435e3caed9e8df2184d} can rebuild the keyset as it was before. See the live cycle of a comment to understand: 
436
437 \begin{Code}\begin{verbatim}void usercode (Key *key)
438 {
439         keySetComment (key, "mycomment"); // the usercode stores a comment for the key
440         ksAppendKey(keyset, key); // append the key to the keyset
441         kdbSet (handle, keyset, 0, 0);
442 }
443
444 // so now kdbSet is called
445 int kdbSet(KDB *handle, KeySet *keyset, Key *parentKey, options)
446 {
447         // find appropriate backend
448         kdbSet_backend (handle, keyset, 0); // the keyset with the key will be passed to this function
449 }
450
451 // so now kdbSet_backend(), which is the function described here, is called
452 kdbSet_backend(KDB *handle, KeySet *keyset, Key *parentKey)
453 {
454         // the task of kdbSet_backend is now to store the comment
455         Key *key = ksCurrent (keyset); // get out the key where the user set the comment before
456         char *comment = allocate(size);
457         keyGetComment (key, comment, size);
458         savetodisc (comment);
459 }
460 \end{verbatim}
461 \end{Code}
462
463  Of course not only the comment, but all information of every key in the keyset {\tt returned} need to be stored permanetly. So this specification needs to give an exhaustive list of information present in a key.
464
465 \begin{Desc}
466 \item[Precondition:]The keyset {\tt returned} holds all keys which must be saved permanently for this keyset. The keyset is sorted and rewinded. All keys having children must be true for \doxyref{keyIsDir()}{p.}{group__keytest_gc0a10c602d52a35f81347e8a32312017}.
467
468 The {\tt parentKey} is the key which is the ancestor for all other keys in the keyset. The first key of the keyset {\tt returned} has the same keyname. The parentKey is below the mountpoint, see \doxyref{kdbhGetMountpoint()}{p.}{group__backendhandle_g8b5612940fc9bc56e99c15ecc427cbb2}.
469
470 The caller kdbSet will fulfill following parts:\begin{itemize}
471 \item If the user does not want hidden keys they will be thrown away. All keys in {\tt returned} need to be stored permanently.\item If the user does not want dirs or only dirs \doxyref{kdbGet()}{p.}{group__kdb_g37b44bda1b83bc0144916bf21a86c1b5} will remove the other.\item Sorting of the keyset. It is not important in which order the keys are appended. So make sure to set all keys, all directories and also all hidden keys. If some of them are not wished, the caller \doxyref{kdbSet()}{p.}{group__kdb_g953cf29721e6000c2516cd6b5d36f571} will sort them out.\end{itemize}
472 \end{Desc}
473 \begin{Desc}
474 \item[Invariant:]There are no global variables and \doxyref{kdbhGetBackendData()}{p.}{group__backendhandle_ge463be8651422015fd12811ed66d20f3} only stores information which can be regenerated any time. The handle is the same when it is the same backend.\end{Desc}
475 \begin{Desc}
476 \item[Postcondition:]The information of the keyset {\tt returned} is stored permanently.\end{Desc}
477 When some keys have KEY\_\-FLAG\_\-REMOVE set, that means return true for \doxyref{keyNeedRemove()}{p.}{group__keytest_gae91159815480fbb3b3d9d7fa85e77b9}, remove the keys instead of getting them. In this case the sorting order will be the reverse way, first will be the children, then the parentKey when iterating over the KeySet returned.
478
479 Lock your permanent storage in an exclusive way, no access of a concurrent \doxyref{kdbSet\_\-backend()}{p.}{group__backend_g2d86ff43b693d59d4b82b597756e9e23} or \doxyref{kdbGet\_\-backend()}{p.}{group__backend_gf3c9c38b7710c435e3caed9e8df2184d} is possible and these methods block until the function has finished. Otherwise declare kdbcGetnoLock().
480
481 \begin{Desc}
482 \item[See also:]\doxyref{kdbSet()}{p.}{group__kdb_g953cf29721e6000c2516cd6b5d36f571} for caller.\end{Desc}
483 \begin{Desc}
484 \item[Parameters:]
485 \begin{description}
486 \item[{\em handle}]contains internal information of \doxyref{opened }{p.}{group__kdb_gb7be60c387892d2235907836c5060e1f} key database \item[{\em returned}]contains a keyset with relevant keys \item[{\em parentKey}]contains the information where to set the keys\end{description}
487 \end{Desc}
488 \begin{Desc}
489 \item[Returns:]When everything works gracefully return the number of keys you set. The cursor position and the keys remaining in the keyset are not important.
490
491 Return 0 on success with no changed key in database
492
493 Return -1 on failure.\end{Desc}
494 \begin{Desc}
495 \item[Note:]If any calls you use change errno, make sure to restore the old errno.\end{Desc}
496 \begin{Desc}
497 \item[{\bf Error}]In normal execution cases a positive value will be returned. But in some cases you are not able to set keys and have to return -1. If you declare kdbcGetnoError() you are done, but otherwise you have to set the cause of the error. (Will be added with 0.7.1)\end{Desc}
498 You also have to make sure that \doxyref{ksGetCursor()}{p.}{group__keyset_gffe507ab9281c322eb16c3e992075d29} shows to the position where the error appeared.