Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief Plugin which acts as proxy and calls other plugins written in lua
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : *
8 : */
9 :
10 : #ifndef SWIG_TYPE_TABLE
11 : #error Build system error, SWIG_TYPE_TABLE is not defined
12 : #endif
13 :
14 : #include "lua.hpp"
15 : #include <kdbhelper.h>
16 : #include <kdbmacros.h>
17 :
18 : #include <key.hpp>
19 : #include <keyset.hpp>
20 : #include <libgen.h>
21 :
22 : #include <lua.hpp>
23 : extern "C" {
24 : #include <lualib.h>
25 : }
26 : #include "runtime.h"
27 :
28 : using namespace ckdb;
29 : #include <kdberrors.h>
30 :
31 : #ifndef LUA_OK
32 : #define LUA_OK 0
33 : #endif
34 :
35 13 : static void Lua_fromSWIG (lua_State * L, ckdb::Key * key)
36 : {
37 13 : swig_type_info * ti = SWIG_TypeQuery (L, "kdb::Key *");
38 13 : if (key == NULL || ti == NULL)
39 4 : lua_pushnil (L);
40 : else
41 18 : SWIG_NewPointerObj (L, new kdb::Key (key), ti, 0);
42 13 : }
43 :
44 9 : static void Lua_fromSWIG (lua_State * L, ckdb::KeySet * keyset)
45 : {
46 9 : swig_type_info * ti = SWIG_TypeQuery (L, "kdb::KeySet *");
47 9 : if (keyset == NULL || ti == NULL)
48 0 : lua_pushnil (L);
49 : else
50 18 : SWIG_NewPointerObj (L, new kdb::KeySet (keyset), ti, 0);
51 9 : }
52 :
53 : typedef struct
54 : {
55 : lua_State * L;
56 : int printError;
57 : int shutdown;
58 : } moduleData;
59 :
60 : static void Lua_Shutdown (lua_State * L)
61 : {
62 5 : if (L) lua_close (L);
63 : }
64 :
65 5 : static int Lua_Require (lua_State * L, const char * name)
66 : {
67 5 : lua_getglobal (L, "require");
68 5 : lua_pushstring (L, name);
69 5 : int status = lua_pcall (L, 1, 1, 0);
70 5 : if (status == LUA_OK) lua_setglobal (L, name);
71 5 : return status;
72 : }
73 :
74 13 : static int Lua_CallFunction_Int (lua_State * L, int nargs, ckdb::Key * errorKey)
75 : {
76 13 : int ret = -1;
77 13 : if (lua_pcall (L, nargs, 1, 0) != LUA_OK)
78 1 : ELEKTRA_SET_VALIDATION_SEMANTIC_ERROR (errorKey, lua_tostring (L, -1));
79 : else
80 : {
81 12 : if (!lua_isnumber (L, -1))
82 0 : ELEKTRA_SET_VALIDATION_SEMANTIC_ERROR (errorKey, "Return value is no integer");
83 : else
84 12 : ret = lua_tonumber (L, -1);
85 : }
86 13 : return ret;
87 : }
88 :
89 5 : static int Lua_CallFunction_Helper1 (lua_State * L, const char * funcName, ckdb::Key * errorKey)
90 : {
91 5 : int ret = 0;
92 5 : int top = lua_gettop (L);
93 5 : lua_getglobal (L, funcName);
94 5 : if (lua_isfunction (L, -1))
95 : {
96 4 : Lua_fromSWIG (L, errorKey);
97 4 : ret = Lua_CallFunction_Int (L, 1, errorKey);
98 : }
99 5 : lua_settop (L, top);
100 5 : return ret;
101 : }
102 :
103 9 : static int Lua_CallFunction_Helper2 (lua_State * L, const char * funcName, ckdb::KeySet * returned, ckdb::Key * parentKey)
104 : {
105 9 : int ret = 0;
106 9 : int top = lua_gettop (L);
107 9 : lua_getglobal (L, funcName);
108 9 : if (lua_isfunction (L, -1))
109 : {
110 9 : Lua_fromSWIG (L, returned);
111 9 : Lua_fromSWIG (L, parentKey);
112 9 : ret = Lua_CallFunction_Int (L, 2, parentKey);
113 : }
114 9 : lua_settop (L, top);
115 9 : return ret;
116 : }
117 :
118 : extern "C" {
119 9352 : static void * Lua_alloc (void * ud ELEKTRA_UNUSED, void * ptr, size_t osize ELEKTRA_UNUSED, size_t nsize)
120 : {
121 9352 : if (nsize == 0)
122 : {
123 4545 : elektraFree (ptr);
124 4545 : return NULL;
125 : }
126 4807 : return (elektraRealloc (&ptr, nsize) < 0) ? NULL : ptr;
127 : }
128 :
129 25 : int elektraLuaOpen (ckdb::Plugin * handle, ckdb::Key * errorKey)
130 : {
131 25 : KeySet * config = elektraPluginGetConfig (handle);
132 :
133 25 : Key * script = ksLookupByName (config, "/script", 0);
134 25 : if (script == NULL || !strlen (keyString (script)))
135 : {
136 20 : if (ksLookupByName (config, "/module", 0) != NULL)
137 : {
138 : return 0; // by convention: success if /module exists
139 : }
140 2 : ELEKTRA_SET_INSTALLATION_ERROR (errorKey, "No lua script set");
141 2 : return -1;
142 : }
143 :
144 : /* create module data */
145 5 : moduleData * data = new moduleData;
146 :
147 : /* init new lua state */
148 5 : if ((data->L = lua_newstate (Lua_alloc, NULL)) == NULL)
149 : {
150 0 : ELEKTRA_SET_OUT_OF_MEMORY_ERROR (errorKey, "Unable to create new lua state");
151 0 : goto error;
152 : }
153 :
154 : /* load std. libs */
155 5 : luaL_openlibs (data->L);
156 :
157 : /* require kdb */
158 5 : if (Lua_Require (data->L, "kdb") != LUA_OK) goto error_print;
159 :
160 : /* load lua script */
161 5 : if (luaL_dofile (data->L, keyString (script))) goto error_print;
162 :
163 : /* store module data after everything is set up */
164 5 : elektraPluginSetData (handle, data);
165 :
166 : /* call lua function */
167 5 : return Lua_CallFunction_Helper2 (data->L, "elektraOpen", config, errorKey);
168 :
169 : error_print:
170 0 : if (!lua_isnil (data->L, -1)) ELEKTRA_SET_INSTALLATION_ERROR (errorKey, lua_tostring (data->L, -1));
171 : error:
172 : /* destroy lua */
173 0 : Lua_Shutdown (data->L);
174 0 : delete data;
175 0 : return -1;
176 : }
177 :
178 25 : int elektraLuaClose (ckdb::Plugin * handle, ckdb::Key * errorKey)
179 : {
180 25 : moduleData * data = static_cast<moduleData *> (elektraPluginGetData (handle));
181 25 : if (data == NULL) return 0;
182 :
183 5 : int ret = Lua_CallFunction_Helper1 (data->L, "elektraClose", errorKey);
184 :
185 : /* destroy lua */
186 10 : Lua_Shutdown (data->L);
187 5 : delete data;
188 5 : return ret;
189 : }
190 :
191 20 : int elektraLuaGet (ckdb::Plugin * handle, ckdb::KeySet * returned, ckdb::Key * parentKey)
192 : {
193 : #define _MODULE_CONFIG_PATH "system/elektra/modules/lua"
194 20 : if (!strcmp (keyName (parentKey), _MODULE_CONFIG_PATH))
195 : {
196 : KeySet * n;
197 : ksAppend (returned,
198 18 : n = ksNew (30, keyNew (_MODULE_CONFIG_PATH, KEY_VALUE, "lua interpreter waits for your orders", KEY_END),
199 : keyNew (_MODULE_CONFIG_PATH "/exports", KEY_END),
200 : keyNew (_MODULE_CONFIG_PATH "/exports/get", KEY_FUNC, elektraLuaGet, KEY_END),
201 : keyNew (_MODULE_CONFIG_PATH "/exports/set", KEY_FUNC, elektraLuaSet, KEY_END),
202 : keyNew (_MODULE_CONFIG_PATH "/exports/error", KEY_FUNC, elektraLuaError, KEY_END),
203 : keyNew (_MODULE_CONFIG_PATH "/exports/open", KEY_FUNC, elektraLuaOpen, KEY_END),
204 : keyNew (_MODULE_CONFIG_PATH "/exports/close", KEY_FUNC, elektraLuaClose, KEY_END),
205 : #include ELEKTRA_README
206 18 : keyNew (_MODULE_CONFIG_PATH "/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END));
207 18 : ksDel (n);
208 : }
209 :
210 20 : moduleData * data = static_cast<moduleData *> (elektraPluginGetData (handle));
211 20 : if (data != NULL) return Lua_CallFunction_Helper2 (data->L, "elektraGet", returned, parentKey);
212 : return 0;
213 : }
214 :
215 1 : int elektraLuaSet (ckdb::Plugin * handle, ckdb::KeySet * returned, ckdb::Key * parentKey)
216 : {
217 1 : moduleData * data = static_cast<moduleData *> (elektraPluginGetData (handle));
218 1 : if (data != NULL) return Lua_CallFunction_Helper2 (data->L, "elektraSet", returned, parentKey);
219 : return 0;
220 : }
221 :
222 1 : int elektraLuaError (ckdb::Plugin * handle, ckdb::KeySet * returned, ckdb::Key * parentKey)
223 : {
224 1 : moduleData * data = static_cast<moduleData *> (elektraPluginGetData (handle));
225 1 : if (data != NULL) return Lua_CallFunction_Helper2 (data->L, "elektraError", returned, parentKey);
226 : return 0;
227 : }
228 :
229 25 : ckdb::Plugin * ELEKTRA_PLUGIN_EXPORT
230 : {
231 : // clang-format off
232 : return elektraPluginExport("lua",
233 : ELEKTRA_PLUGIN_OPEN, &elektraLuaOpen,
234 : ELEKTRA_PLUGIN_CLOSE, &elektraLuaClose,
235 : ELEKTRA_PLUGIN_GET, &elektraLuaGet,
236 : ELEKTRA_PLUGIN_SET, &elektraLuaSet,
237 : ELEKTRA_PLUGIN_ERROR, &elektraLuaError,
238 25 : ELEKTRA_PLUGIN_END);
239 : }
240 : }
241 :
|