correct typo in error message
[monky] / src / llua.c
1 /* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*-
2  *
3  * Conky, a system monitor, based on torsmo
4  *
5  * Copyright (c) 2009 Toni Spets
6  * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al.
7  *      (see AUTHORS)
8  * All rights reserved.
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  * vim: ts=4 sw=4 noet ai cindent syntax=c
23  *
24  */
25
26 #include "conky.h"
27 #include "logging.h"
28 #include "build.h"
29
30 #ifdef LUA_EXTRAS
31 #include <tolua++.h>
32 #endif /* LUA_EXTRAS */
33
34 #ifdef HAVE_SYS_INOTIFY_H
35 #include <sys/inotify.h>
36
37 void llua_append_notify(const char *name);
38 void llua_rm_notifies(void);
39 static int llua_block_notify = 0;
40 #endif /* HAVE_SYS_INOTIFY_H */
41
42 static char *draw_pre = 0;
43 static char *draw_post = 0;
44
45 lua_State *lua_L = NULL;
46
47 static int llua_conky_parse(lua_State *L)
48 {
49         int n = lua_gettop(L);    /* number of arguments */
50         char *str;
51         char *buf = calloc(1, max_user_text);
52         if (n != 1) {
53                 lua_pushstring(L, "incorrect arguments, conky_parse(string) takes exactly 1 argument");
54                 lua_error(L);
55         }
56         if (!lua_isstring(L, 1)) {
57                 lua_pushstring(L, "incorrect argument (expecting a string)");
58                 lua_error(L);
59         }
60         str = strdup(lua_tostring(L, 1));
61         evaluate(str, buf);
62         lua_pushstring(L, buf);
63         free(str);
64         free(buf);
65         return 1;                 /* number of results */
66 }
67
68 static int llua_conky_set_update_interval(lua_State *L)
69 {
70         int n = lua_gettop(L);    /* number of arguments */
71         double value;
72         if (n != 1) {
73                 lua_pushstring(L, "incorrect arguments, conky_set_update_interval(number) takes exactly 1 argument");
74                 lua_error(L);
75         }
76         if (!lua_isnumber(L, 1)) {
77                 lua_pushstring(L, "incorrect argument (expecting a number)");
78                 lua_error(L);
79         }
80         value = lua_tonumber(L, 1);
81         set_update_interval(value);
82         return 0;                 /* number of results */
83 }
84
85 void llua_init(void)
86 {
87         const char *libs = PACKAGE_LIBDIR"/lib?.so;";
88         char *old_path, *new_path;
89         if (lua_L) return;
90         lua_L = lua_open();
91
92         /* add our library path to the lua package.cpath global var */
93         luaL_openlibs(lua_L);
94         lua_getglobal(lua_L, "package");
95         lua_getfield(lua_L, -1, "cpath");
96         old_path = strdup(lua_tostring(lua_L, -1));
97         new_path = malloc(strlen(old_path) + strlen(libs) + 1);
98         strcpy(new_path, libs);
99         strcat(new_path, old_path);
100         lua_pushstring(lua_L, new_path);
101         lua_setfield(lua_L, -3, "cpath");
102         lua_pop(lua_L, 2);
103         free(old_path);
104         free(new_path);
105
106         lua_pushstring(lua_L, PACKAGE_NAME" "VERSION" compiled "BUILD_DATE" for "BUILD_ARCH);
107         lua_setglobal(lua_L, "conky_build_info");
108
109         lua_pushstring(lua_L, VERSION);
110         lua_setglobal(lua_L, "conky_version");
111
112         lua_pushstring(lua_L, BUILD_DATE);
113         lua_setglobal(lua_L, "conky_build_date");
114
115         lua_pushstring(lua_L, BUILD_ARCH);
116         lua_setglobal(lua_L, "conky_build_arch");
117
118         lua_pushstring(lua_L, current_config);
119         lua_setglobal(lua_L, "conky_config");
120
121         lua_pushcfunction(lua_L, &llua_conky_parse);
122         lua_setglobal(lua_L, "conky_parse");
123
124         lua_pushcfunction(lua_L, &llua_conky_set_update_interval);
125         lua_setglobal(lua_L, "conky_set_update_interval");
126
127 #if defined(X11) && defined(LUA_EXTRAS)
128         /* register tolua++ user types */
129         tolua_open(lua_L);
130         tolua_usertype(lua_L, "Drawable");
131         tolua_usertype(lua_L, "Visual");
132         tolua_usertype(lua_L, "Display");
133 #endif /* X11 */
134 }
135
136 void llua_load(const char *script)
137 {
138         int error;
139         char path[DEFAULT_TEXT_BUFFER_SIZE];
140
141         llua_init();
142
143         to_real_path(path, script);
144         error = luaL_dofile(lua_L, path);
145         if (error) {
146                 ERR("llua_load: %s", lua_tostring(lua_L, -1));
147                 lua_pop(lua_L, 1);
148 #ifdef HAVE_SYS_INOTIFY_H
149         } else if (!llua_block_notify && inotify_fd != -1) {
150                 llua_append_notify(path);
151 #endif /* HAVE_SYS_INOTIFY_H */
152         }
153 }
154
155 /*
156    llua_do_call does a flexible call to any Lua function
157 string: <function> [par1] [par2...]
158 retc: the number of return values expected
159  */
160 char *llua_do_call(const char *string, int retc)
161 {
162         static char func[64];
163         int argc = 0;
164
165         char *tmp = strdup(string);
166         char *ptr = strtok(tmp, " ");
167
168         /* proceed only if the function name is present */
169         if (!ptr) {
170                 free(tmp);
171                 return NULL;
172         }
173
174         /* call only conky_ prefixed functions */
175         if(strncmp(ptr, LUAPREFIX, strlen(LUAPREFIX)) == 0) {
176                 snprintf(func, 64, "%s", ptr);
177         }else{
178                 snprintf(func, 64, "%s%s", LUAPREFIX, ptr);
179         }
180
181         /* push the function name to stack */
182         lua_getglobal(lua_L, func);
183
184         /* parse all function parameters from args and push them to the stack */
185         ptr = strtok(NULL, " ");
186         while (ptr) {
187                 lua_pushstring(lua_L, ptr);
188                 ptr = strtok(NULL, " ");
189                 argc++;
190         }
191
192         free(tmp);
193
194         if(lua_pcall(lua_L, argc, retc, 0) != 0) {
195                 ERR("llua_do_call: function %s execution failed: %s", func, lua_tostring(lua_L, -1));
196                 lua_pop(lua_L, -1);
197                 return NULL;
198         }
199
200         return func;
201 }
202
203 /*
204  * same as llua_do_call() except passes everything after func as one arg.
205  */
206 char *llua_do_read_call(const char *function, const char *arg, int retc)
207 {
208         static char func[64];
209         snprintf(func, 64, "conky_%s", function);
210
211         /* push the function name to stack */
212         lua_getglobal(lua_L, func);
213
214         /* push function parameter to the stack */
215         lua_pushstring(lua_L, arg);
216
217         if (lua_pcall(lua_L, 1, retc, 0) != 0) {
218                 ERR("llua_do_call: function %s execution failed: %s", func, lua_tostring(lua_L, -1));
219                 lua_pop(lua_L, -1);
220                 return NULL;
221         }
222
223         return func;
224 }
225
226 char *llua_getstring(const char *args)
227 {
228         char *func;
229         char *ret = NULL;
230
231         if(!lua_L) return NULL;
232
233         func = llua_do_call(args, 1);
234         if (func) {
235                 if (!lua_isstring(lua_L, -1)) {
236                         ERR("llua_getstring: function %s didn't return a string, result discarded", func);
237                 } else {
238                         ret = strdup(lua_tostring(lua_L, -1));
239                         lua_pop(lua_L, 1);
240                 }
241         }
242
243         return ret;
244 }
245
246 char *llua_getstring_read(const char *function, const char *arg)
247 {
248         char *func;
249         char *ret = NULL;
250
251         if(!lua_L) return NULL;
252
253         func = llua_do_read_call(function, arg, 1);
254         if (func) {
255                 if(!lua_isstring(lua_L, -1)) {
256                         ERR("llua_getstring_read: function %s didn't return a string, result discarded", func);
257                 } else {
258                         ret = strdup(lua_tostring(lua_L, -1));
259                         lua_pop(lua_L, 1);
260                 }
261         }
262
263         return ret;
264 }
265
266 int llua_getnumber(const char *args, double *ret)
267 {
268         char *func;
269
270         if(!lua_L) return 0;
271
272         func = llua_do_call(args, 1);
273         if(func) {
274                 if(!lua_isnumber(lua_L, -1)) {
275                         ERR("llua_getnumber: function %s didn't return a number, result discarded", func);
276                 } else {
277                         *ret = lua_tonumber(lua_L, -1);
278                         lua_pop(lua_L, 1);
279                         return 1;
280                 }
281         }
282         return 0;
283 }
284
285 void llua_close(void)
286 {
287 #ifdef HAVE_SYS_INOTIFY_H
288         llua_rm_notifies();
289 #endif /* HAVE_SYS_INOTIFY_H */
290         if (draw_pre) {
291                 free(draw_pre);
292                 draw_pre = 0;
293         }
294         if (draw_post) {
295                 free(draw_post);
296                 draw_post = 0;
297         }
298         if(!lua_L) return;
299         lua_close(lua_L);
300         lua_L = NULL;
301 }
302
303 #ifdef HAVE_SYS_INOTIFY_H
304 struct _lua_notify_s {
305         int wd;
306         char name[DEFAULT_TEXT_BUFFER_SIZE];
307         struct _lua_notify_s *next;
308 };
309 static struct _lua_notify_s *lua_notifies = 0;
310
311 static struct _lua_notify_s *llua_notify_list_do_alloc(const char *name)
312 {
313         struct _lua_notify_s *ret = malloc(sizeof(struct _lua_notify_s));
314         memset(ret, 0, sizeof(struct _lua_notify_s));
315         strncpy(ret->name, name, DEFAULT_TEXT_BUFFER_SIZE);
316         return ret;
317 }
318
319 void llua_append_notify(const char *name)
320 {
321         /* do it */
322         struct _lua_notify_s *new_tail = 0;
323         if (!lua_notifies) {
324                 /* empty, fresh new digs */
325                 new_tail = lua_notifies = llua_notify_list_do_alloc(name);
326         } else {
327                 struct _lua_notify_s *tail = lua_notifies;
328                 while (tail->next) {
329                         tail = tail->next;
330                 }
331                 // should be @ the end now
332                 new_tail = llua_notify_list_do_alloc(name);
333                 tail->next = new_tail;
334         }
335         new_tail->wd = inotify_add_watch(inotify_fd,
336                         new_tail->name,
337                         IN_MODIFY);
338 }
339
340 void llua_rm_notifies(void)
341 {
342         /* git 'er done */
343         struct _lua_notify_s *head = lua_notifies;
344         struct _lua_notify_s *next = 0;
345         if (!lua_notifies) return;
346         inotify_rm_watch(inotify_fd, head->wd);
347         if (head->next) next = head->next;
348         free(head);
349         while (next) {
350                 head = next;
351                 next = head->next;
352                 inotify_rm_watch(inotify_fd, head->wd);
353                 free(head);
354         }
355         lua_notifies = 0;
356 }
357
358 void llua_inotify_query(int wd, int mask)
359 {
360         struct _lua_notify_s *head = lua_notifies;
361         if (mask & IN_MODIFY || mask & IN_IGNORED) {
362                 /* for whatever reason, i keep getting IN_IGNORED when the file is
363                  * modified */
364                 while (head) {
365                         if (head->wd == wd) {
366                                 llua_block_notify = 1;
367                                 llua_load(head->name);
368                                 llua_block_notify = 0;
369                                 ERR("Lua script '%s' reloaded", head->name);
370                                 if (mask & IN_IGNORED) {
371                                         /* for some reason we get IN_IGNORED here
372                                          * sometimes, so we need to re-add the watch */
373                                         head->wd = inotify_add_watch(inotify_fd,
374                                                         head->name,
375                                                         IN_MODIFY);
376                                 }
377                                 return;
378                         }
379                         head = head->next;
380                 }
381         }
382 }
383 #endif /* HAVE_SYS_INOTIFY_H */
384
385 void llua_set_number(const char *key, double value)
386 {
387         lua_pushnumber(lua_L, value);
388         lua_setfield(lua_L, -2, key);
389 }
390
391 #ifdef X11
392 void llua_draw_pre_hook(void)
393 {
394         if (!lua_L || !draw_pre) return;
395         llua_do_call(draw_pre, 0);
396 }
397
398 void llua_draw_post_hook(void)
399 {
400         if (!lua_L || !draw_post) return;
401         llua_do_call(draw_post, 0);
402 }
403
404 void llua_set_draw_pre_hook(const char *args)
405 {
406         draw_pre = strdup(args);
407 }
408
409 void llua_set_draw_post_hook(const char *args)
410 {
411         draw_post = strdup(args);
412 }
413
414 #ifdef LUA_EXTRAS
415 void llua_set_userdata(const char *key, const char *type, void *value)
416 {
417         tolua_pushusertype(lua_L, value, type);
418         lua_setfield(lua_L, -2, key);
419 }
420 #endif /* LUA_EXTRAS */
421
422 void llua_setup_window_table(int text_start_x, int text_start_y, int text_width, int text_height)
423 {
424         if (!lua_L) return;
425         lua_newtable(lua_L);
426
427         if (output_methods & TO_X) {
428 #ifdef LUA_EXTRAS
429                 llua_set_userdata("drawable", "Drawable", (void*)&window.drawable);
430                 llua_set_userdata("visual", "Visual", window.visual);
431                 llua_set_userdata("display", "Display", display);
432 #endif /* LUA_EXTRAS */
433
434
435                 llua_set_number("width", window.width);
436                 llua_set_number("height", window.height);
437                 llua_set_number("border_inner_margin", window.border_inner_margin);
438                 llua_set_number("border_outer_margin", window.border_outer_margin);
439                 llua_set_number("border_width", window.border_width);
440
441                 llua_set_number("text_start_x", text_start_x);
442                 llua_set_number("text_start_y", text_start_y);
443                 llua_set_number("text_width", text_width);
444                 llua_set_number("text_height", text_height);
445
446                 lua_setglobal(lua_L, "conky_window");
447         }
448 }
449
450 void llua_update_window_table(int text_start_x, int text_start_y, int text_width, int text_height)
451 {
452         if (!lua_L) return;
453
454         lua_getglobal(lua_L, "conky_window");
455         if (lua_isnil(lua_L, -1)) {
456                 /* window table isn't populated yet */
457                 lua_pop(lua_L, 1);
458                 return;
459         }
460
461         llua_set_number("width", window.width);
462         llua_set_number("height", window.height);
463
464         llua_set_number("text_start_x", text_start_x);
465         llua_set_number("text_start_y", text_start_y);
466         llua_set_number("text_width", text_width);
467         llua_set_number("text_height", text_height);
468
469         lua_setglobal(lua_L, "conky_window");
470 }
471 #endif /* X11 */
472
473 void llua_setup_info(struct information *i, double u_interval)
474 {
475         if (!lua_L) return;
476         lua_newtable(lua_L);
477
478         llua_set_number("update_interval", u_interval);
479         llua_set_number("uptime", i->uptime);
480
481         lua_setglobal(lua_L, "conky_info");
482 }
483
484 void llua_update_info(struct information *i, double u_interval)
485 {
486         if (!lua_L) return;
487
488         lua_getglobal(lua_L, "conky_info");
489         if (lua_isnil(lua_L, -1)) {
490                 /* window table isn't populated yet */
491                 lua_pop(lua_L, 1);
492                 return;
493         }
494
495         llua_set_number("update_interval", u_interval);
496         llua_set_number("uptime", i->uptime);
497
498         lua_setglobal(lua_L, "conky_info");
499 }
500