forked from ElektraInitiative/libelektra
-
Notifications
You must be signed in to change notification settings - Fork 0
/
plugin.c
223 lines (203 loc) · 5.81 KB
/
plugin.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
/**
* @file
*
* @brief Access plugin handle.
*
* @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
*/
#ifdef HAVE_KDBCONFIG_H
#include "kdbconfig.h"
#endif
#include <kdbassert.h>
#include <kdbinternal.h>
/**
* @brief Allows one to Export Methods for a Plugin.
*
* This function must be called within ELEKTRA_PLUGIN_EXPORT.
* It define the plugin's methods that will be exported.
*
* All KDB methods implemented by the plugin basically could
* have random names (convention is elektraName*), except
* ELEKTRA_PLUGIN_EXPORT.
*
* This is the single symbol that will be looked up
* when loading the plugin, and the first method of the backend
* implementation that will be called.
*
* You need to use a macro so that both dynamic and static loading
* of the plugin works. For example for the doc plugin:
* @snippet doc.c export
*
* The first parameter is the name of the plugin.
* Then every plugin should have:
* @c ELEKTRA_PLUGIN_OPEN,
* @c ELEKTRA_PLUGIN_CLOSE,
* @c ELEKTRA_PLUGIN_GET,
* @c ELEKTRA_PLUGIN_SET and optionally
* @c ELEKTRA_PLUGIN_ERROR and
* @c ELEKTRA_PLUGIN_COMMIT.
*
* The list is terminated with
* @c ELEKTRA_PLUGIN_END.
*
* You must use static "char arrays" in a read only segment.
* Don't allocate storage, it won't be freed.
*
* @param pluginName the name of this plugin
* @return an object that contains all plugin information needed by
* libelektra.so
* @ingroup plugin
*/
Plugin * elektraPluginExport (const char * pluginName, ...)
{
va_list va;
Plugin * returned;
plugin_t method = 0;
if (pluginName == 0) return 0;
returned = elektraCalloc (sizeof (struct _Plugin));
/* Start processing parameters */
va_start (va, pluginName);
returned->name = pluginName;
while ((method = va_arg (va, plugin_t)))
{
switch (method)
{
case ELEKTRA_PLUGIN_OPEN:
returned->kdbOpen = va_arg (va, kdbOpenPtr);
break;
case ELEKTRA_PLUGIN_CLOSE:
returned->kdbClose = va_arg (va, kdbClosePtr);
break;
case ELEKTRA_PLUGIN_INIT:
returned->kdbInit = va_arg (va, kdbInitPtr);
break;
case ELEKTRA_PLUGIN_GET:
returned->kdbGet = va_arg (va, kdbGetPtr);
break;
case ELEKTRA_PLUGIN_SET:
returned->kdbSet = va_arg (va, kdbSetPtr);
break;
case ELEKTRA_PLUGIN_ERROR:
returned->kdbError = va_arg (va, kdbErrorPtr);
break;
case ELEKTRA_PLUGIN_COMMIT:
returned->kdbCommit = va_arg (va, kdbCommitPtr);
break;
default:
ELEKTRA_ASSERT (0, "plugin passed something unexpected");
// fallthrough, will end here
case ELEKTRA_PLUGIN_END:
va_end (va);
return returned;
}
}
return returned;
}
/**
* @brief Returns the configuration of that plugin.
*
* - The user:/ config holds plugin specific configuration
* - The system:/ config holds backend specific configuration
*
* So prefer cascading lookups to honor both.
*
* @param handle a pointer to the plugin
* @ingroup plugin
* @return keyset to the configuration for that plugin
*/
KeySet * elektraPluginGetConfig (Plugin * handle)
{
return handle->config;
}
/**
* @brief Store a pointer to plugin specific data.
*
* This data is private to one instance of a plugin.
*
* @see elektraPluginGetData
* @param plugin a pointer to the plugin
* @param data the pointer to the data
* @ingroup plugin
*/
void elektraPluginSetData (Plugin * plugin, void * data)
{
plugin->data = data;
}
/**
* @brief Get a pointer to the plugin specific data stored before.
*
* If elektraPluginSetData() was not called earlier, NULL will be returned.
*
* This data is private to one instance of a plugin.
*
* @see elektraPluginSetData
* @param plugin a pointer to the plugin
* @return a pointer to the data
* @ingroup plugin
*/
void * elektraPluginGetData (Plugin * plugin)
{
return plugin->data;
}
/**
* @brief Get a pointer to the global keyset.
*
* Initialized for all plugins by the KDB, except for manually
* created plugins with `elektraPluginOpen()`.
* The global keyset is tied to a KDB handle, initialized on
* `kdbOpen()` and deleted on `kdbClose()`.
*
* Plugins using this keyset are responsible for cleaning up
* their parts of the keyset which they do not need any more.
*
* @param plugin a pointer to the plugin
* @return a pointer to the global keyset
* @ingroup plugin
*/
KeySet * elektraPluginGetGlobalKeySet (Plugin * plugin)
{
return plugin->global;
}
/**
* Returns the current phase of the current KDB operation.
*
* During kdbGet() this will be one of the `ELEKTRA_KDB_GET_PHASE_*` constants
* and during kdbSet() it will be one of the `ELEKTRA_KDB_SET_PHASE_*` constants.
*
* @param plugin plugin handle
* @return current phase
* @retval 0 if @p plugin is `NULL`
*/
ElektraKdbPhase elektraPluginGetPhase (Plugin * plugin)
{
if (plugin == NULL)
{
return 0;
}
return *(ElektraKdbPhase *) keyValue (ksLookupByName (plugin->global, "system:/elektra/kdb/backend/phase", 0));
}
/**
* Retrieves the handle for another plugin in the same mountpoint based on a reference.
*
* The plugins of a mountpoint are defined via `system:/elektra/mountpoint/<mp>/pluigns/<ref>` keys
* in the declaration of the mountpoint. To use this function, you must provide the `<ref>` part as
* @p ref.
*
* @param plugin active plugin handle
* @param ref reference to another plugin
* @return the plugin referenced by @p ref
* @retval NULL if @p plugin, or @p ref are `NULL`, or no plugin was found for @p ref
*/
Plugin * elektraPluginFromMountpoint (Plugin * plugin, const char * ref)
{
if (plugin == NULL || ref == NULL)
{
return NULL;
}
KeySet * plugins = *(KeySet **) keyValue (ksLookupByName (plugin->global, "system:/elektra/kdb/backend/plugins", 0));
Key * lookupHelper = keyNew ("system:/", KEY_END);
keyAddBaseName (lookupHelper, ref);
Key * pluginKey = ksLookup (plugins, lookupHelper, 0);
keyDel (lookupHelper);
return pluginKey == NULL ? NULL : *(Plugin **) keyValue (pluginKey);
}