1 /*
2 * glspi_kfile.c - This file is part of the Lua scripting plugin for the Geany IDE
3 * See the file "geanylua.c" for copyright information.
4 */
5
6 /* Minimal interface to a GKeyFile object */
7
8 #include <glib.h>
9 #include <glib/gi18n.h>
10
11 #include <lua.h>
12 #include <lualib.h>
13 #include <lauxlib.h>
14
15 #define LUA_MODULE_NAME "keyfile"
16 #define MetaName "_g_key_file_metatable"
17
18
19 #define SetTableValue(name,value,pusher) \
20 lua_pushstring(L, name); \
21 pusher(L, value); \
22 lua_rawset(L,-3);
23
24 #define SetTableStr(name,value) SetTableValue(name,value,lua_pushstring)
25
26 #define FAIL_STRING_ARG(argnum) \
27 (fail_arg_type(L,__FUNCTION__,argnum,"string"))
28
29 #define FAIL_BOOL_ARG(argnum) \
30 (fail_arg_type(L,__FUNCTION__,argnum,"boolean"))
31
32 #define FAIL_TABLE_ARG(argnum) \
33 (fail_arg_type(L,__FUNCTION__,argnum,"table"))
34
35 #define FAIL_KEYFILE_ARG(argnum) \
36 (fail_arg_type(L,__FUNCTION__,argnum,LuaKeyFileType))
37
38
39 #define push_number(L,n) lua_pushnumber(L,(lua_Number)n)
40
41 /* Subtract one from error argnum if we have implicit "self" */
adjust_argnum(lua_State * L,gint argnum)42 static gint adjust_argnum(lua_State *L, gint argnum) {
43 lua_Debug ar;
44 if (lua_getstack(L, 0, &ar)){
45 lua_getinfo(L, "n", &ar);
46 if (g_str_equal(ar.namewhat, "method")) { return argnum-1; }
47 }
48 return argnum;
49 }
50
51 /* Pushes an error message onto Lua stack if script passes a wrong arg type */
fail_arg_type(lua_State * L,const gchar * func,gint argnum,const gchar * type)52 static gint fail_arg_type(lua_State *L, const gchar *func, gint argnum, const gchar *type)
53 {
54 lua_pushfstring(L, _("Error in module \"%s\" at function %s():\n"
55 " expected type \"%s\" for argument #%d\n"),
56 LUA_MODULE_NAME, func+6, type, adjust_argnum(L,argnum));
57 lua_error(L);
58 return 0;
59 }
60
61
62 #define KF_FLAGS G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS
63
64 static const gchar*LuaKeyFileType="GKeyFile";
65
66 typedef struct _LuaKeyFile
67 {
68 const gchar*id;
69 GKeyFile*kf;
70 gboolean managed;
71 } LuaKeyFile;
72
73
74 typedef gint (*KeyfileAssignFunc) (lua_State *L, GKeyFile*kf);
75
glspi_kfile_assign(lua_State * L,GKeyFile * kf)76 static gint glspi_kfile_assign(lua_State *L, GKeyFile*kf)
77 {
78 LuaKeyFile*k=(LuaKeyFile*)lua_newuserdata(L,sizeof(LuaKeyFile));
79 k->id=LuaKeyFileType;
80 k->kf=kf;
81 luaL_getmetatable(L, MetaName);
82 lua_setmetatable(L, -2);
83 k->managed=FALSE;
84 return 1;
85 }
86
87
88
kfile_new(lua_State * L)89 static gint kfile_new(lua_State *L)
90 {
91 LuaKeyFile*k=(LuaKeyFile*)lua_newuserdata(L,sizeof(LuaKeyFile));
92 k->id=LuaKeyFileType;
93 k->kf=g_key_file_new();
94 luaL_getmetatable(L, MetaName);
95 lua_setmetatable(L, -2);
96 k->managed=TRUE;
97 return 1;
98 }
99
100
101
kfile_done(lua_State * L)102 static gint kfile_done(lua_State *L)
103 {
104 LuaKeyFile*k;
105 if (lua_isnil(L, 1)) { return 0; }
106 k=(LuaKeyFile*)lua_touserdata(L,1);
107 if ( (k->id!=LuaKeyFileType) || (!k->managed) ) { return 1; }
108 g_key_file_free(k->kf);
109 return 1;
110 }
111
112
113
tokeyfile(lua_State * L,gint argnum)114 static LuaKeyFile* tokeyfile(lua_State *L, gint argnum)
115 {
116 LuaKeyFile* rv;
117 if ( (lua_gettop(L)<argnum) || (!lua_isuserdata(L,argnum))) return NULL;
118 rv=lua_touserdata(L,argnum);
119 return (rv && (rv->id==LuaKeyFileType))?rv:NULL;
120 }
121
122
123
kfile_data(lua_State * L)124 static gint kfile_data(lua_State *L)
125 {
126 LuaKeyFile*k;
127
128 gsize len=0;
129 GError *err=NULL;
130
131 if (lua_gettop(L)>1) {
132 const gchar *data=NULL;
133 if ((lua_gettop(L)<2)||(!lua_isstring(L,2))) {return FAIL_STRING_ARG(2); }
134 data=lua_tolstring(L,2,&len);
135 k=tokeyfile(L,1);
136 if (!k) {return FAIL_KEYFILE_ARG(1); }
137 g_key_file_load_from_data(k->kf, data, len, KF_FLAGS, &err);
138 if (err) {
139 lua_pushstring(L,err->message);
140 g_error_free(err);
141 } else {lua_pushnil(L);}
142 return 1;
143 } else {
144 gchar *data=NULL;
145 k=tokeyfile(L,1);
146 if (!k) {return FAIL_KEYFILE_ARG(1); }
147 data=g_key_file_to_data(k->kf,&len,&err);
148 if (!err) {
149 lua_pushlstring(L,data,len);
150 g_free(data);
151 return 1;
152 } else {
153 lua_pushnil(L);
154 lua_pushstring(L,err->message);
155 g_error_free(err);
156 if (data) {g_free(data);}
157 return 2;
158 }
159 }
160 }
161
162
163
164 /*
165 Lua "closure" function to iterate through each string in an array of strings
166 */
strings_closure(lua_State * L)167 static gint strings_closure(lua_State *L)
168 {
169 gchar **strings;
170 gchar *string;
171 gint i=lua_tonumber(L, lua_upvalueindex(2));
172 strings=lua_touserdata(L,lua_upvalueindex(1));
173 if (!strings) {return 0;}
174 string=strings[i];
175 if ( string ) {
176 lua_pushstring(L,string);
177 push_number(L, i+1);
178 lua_pushvalue(L, -1);
179 lua_replace(L, lua_upvalueindex(2));
180 return 2;
181 } else {
182 g_strfreev(strings);
183 return 0;
184 }
185 }
186
187
188
189 /* Iterate through the group names of a keyfile */
kfile_groups(lua_State * L)190 static gint kfile_groups(lua_State* L)
191 {
192 LuaKeyFile*k=NULL;
193 gchar**groups=NULL;
194 gsize len=0;
195 k=tokeyfile(L,1);
196 if (!k) {return FAIL_KEYFILE_ARG(1); }
197 groups=g_key_file_get_groups(k->kf, &len);
198 lua_pushlightuserdata(L,groups);
199 push_number(L,0);
200 lua_pushcclosure(L, &strings_closure, 2);
201 return 1;
202 }
203
204
205
206 /* Iterate through the key names of a group*/
kfile_keys(lua_State * L)207 static gint kfile_keys(lua_State* L)
208 {
209 LuaKeyFile*k=NULL;
210 gchar**keylist=NULL;
211 gsize len=0;
212 const gchar*group=NULL;
213 GError *err=NULL;
214 if ((lua_gettop(L)<2)||(!lua_isstring(L,2))) {return FAIL_STRING_ARG(2); }
215 group=lua_tostring(L,2);
216 k=tokeyfile(L,1);
217 if (!k) {return FAIL_KEYFILE_ARG(1); }
218 keylist=g_key_file_get_keys(k->kf, group, &len, &err);
219 if (err) {
220 g_error_free(err);
221 }
222 lua_pushlightuserdata(L,keylist);
223 push_number(L,0);
224 lua_pushcclosure(L, &strings_closure, 2);
225 return 1;
226 }
227
228
229
kfile_value(lua_State * L)230 static gint kfile_value(lua_State* L)
231 {
232 const gchar *group=NULL;
233 const gchar *key=NULL;
234 const gchar *value=NULL;
235 LuaKeyFile*k=NULL;
236 GError *err=NULL;
237 if (lua_gettop(L)>=4) {
238 if (!lua_isstring(L,4)) {return FAIL_STRING_ARG(4);}
239 value=lua_tostring(L,4);
240 }
241 if ((lua_gettop(L)<3)||(!lua_isstring(L,3))) {return FAIL_STRING_ARG(3); }
242 key=lua_tostring(L,3);
243 if (!lua_isstring(L,2)) {return FAIL_STRING_ARG(2); }
244 group=lua_tostring(L,2);
245 k=tokeyfile(L,1);
246 if (!k) {return FAIL_KEYFILE_ARG(1); }
247
248 if (value) {
249 g_key_file_set_value(k->kf,group,key,value);
250 return 0;
251 } else {
252 gchar *kfv=g_key_file_get_value(k->kf,group,key,&err);
253 if (err) {
254 g_error_free(err);
255 }
256 if (kfv) {
257 lua_pushstring(L, kfv);
258 g_free(kfv);
259 return 1;
260 } else {
261 return 0;
262 }
263 }
264 }
265
266
267
268 #define str_or_nil(L,argnum) (lua_isstring(L,argnum)||lua_isnil(L,argnum))
269
270
kfile_comment(lua_State * L)271 static gint kfile_comment(lua_State* L)
272 {
273 const gchar *group=NULL;
274 const gchar *key=NULL;
275 const gchar *comment=NULL;
276 LuaKeyFile*k=NULL;
277 GError *err=NULL;
278 if (lua_gettop(L)>=4) {
279 if (!lua_isstring(L,4)) {return FAIL_STRING_ARG(4);}
280 comment=lua_tostring(L,4);
281 }
282 if ((lua_gettop(L)<3)||(!str_or_nil(L,3))) {return FAIL_STRING_ARG(3); }
283 key=lua_tostring(L,3);
284 if (!str_or_nil(L,2)) {return FAIL_STRING_ARG(2); }
285 group=lua_tostring(L,2);
286 k=tokeyfile(L,1);
287 if (!k) {return FAIL_KEYFILE_ARG(1); }
288
289 if (comment) {
290 g_key_file_set_comment(k->kf,group,key,comment,&err);
291 return 0;
292 } else {
293 gchar*kfc=g_key_file_get_comment(k->kf,group,key,&err);
294 if (err) {
295 g_error_free(err);
296 }
297 if (kfc) {
298 lua_pushstring(L, kfc);
299 g_free(kfc);
300 return 1;
301 } else {
302 return 0;
303 }
304 }
305 }
306
307
308
kfile_has(lua_State * L)309 static gint kfile_has(lua_State* L)
310 {
311 const gchar *group=NULL;
312 const gchar *key=NULL;
313 gint argc=lua_gettop(L);
314 gboolean hasit=FALSE;
315 LuaKeyFile*k=NULL;
316 GError*err=NULL;
317 if (argc>=3) {
318 if (lua_isstring(L,3)) {
319 key=lua_tostring(L,3);
320 } else {
321 if (!lua_isnil(L,3)) { return FAIL_STRING_ARG(3); }
322 }
323 }
324 if ((lua_gettop(L)<2)||(!lua_isstring(L,2))) { return FAIL_STRING_ARG(2); }
325 group=lua_tostring(L,2);
326 k=tokeyfile(L,1);
327 if (!k) { return FAIL_KEYFILE_ARG(1); }
328 if (key) {
329 hasit=g_key_file_has_key(k->kf, group, key, &err);
330 } else {
331 hasit=g_key_file_has_group(k->kf, group);
332 }
333 lua_pushboolean(L,hasit);
334 if (err) {
335 g_error_free(err);
336 }
337 return 1;
338 }
339
340
341
kfile_remove(lua_State * L)342 static gint kfile_remove(lua_State* L)
343 {
344 const gchar *group=NULL;
345 const gchar *key=NULL;
346 gint argc=lua_gettop(L);
347 LuaKeyFile*k=NULL;
348 GError*err=NULL;
349 if (argc>=3) {
350 if (lua_isstring(L,3)) {
351 key=lua_tostring(L,3);
352 } else {
353 if (!lua_isnil(L,3)) { return FAIL_STRING_ARG(3); }
354 }
355 }
356 if ((lua_gettop(L)<2)||(!lua_isstring(L,2))) { return FAIL_STRING_ARG(2); }
357 group=lua_tostring(L,3);
358 k=tokeyfile(L,1);
359 if (!k) { return FAIL_KEYFILE_ARG(1); }
360 if (key) {
361 g_key_file_remove_key(k->kf, group, key, &err);
362 } else {
363 g_key_file_remove_group(k->kf, group, &err);
364 }
365 if (err) {
366 g_error_free(err);
367 }
368 return 0;
369 }
370
371
372
373 static const struct luaL_reg kfile_funcs[] = {
374 {"new", kfile_new},
375 {"data", kfile_data},
376 {"groups", kfile_groups},
377 {"keys", kfile_keys},
378 {"value", kfile_value},
379 {"comment", kfile_comment},
380 {"has", kfile_has},
381 {"remove", kfile_remove},
382 {NULL,NULL}
383 };
384
385
386
387
luaopen_keyfile(lua_State * L)388 static gint luaopen_keyfile(lua_State *L)
389 {
390 luaL_newmetatable(L, MetaName);
391 lua_pushstring(L, "__index");
392 lua_pushvalue(L, -2);
393 lua_settable(L, -3);
394 luaL_getmetatable(L, MetaName);
395 lua_pushstring(L,"__gc");
396 lua_pushcfunction(L,kfile_done);
397 lua_rawset(L,-3);
398 luaL_openlib(L, NULL, &kfile_funcs[1], 0);
399 luaL_openlib(L, LUA_MODULE_NAME, kfile_funcs, 0);
400 return 0;
401 }
402
403
404
405
406
glspi_init_kfile_module(lua_State * L,KeyfileAssignFunc * func)407 void glspi_init_kfile_module(lua_State *L, KeyfileAssignFunc *func)
408 {
409
410 *func=glspi_kfile_assign;
411 luaopen_keyfile(L);
412 }
413
414
415
416