0d60e42db8bfc87147ffd6ab51b9c23027ae0448
[monky] / src / llua.c
1 /* Conky, a system monitor, based on torsmo
2  *
3  * Copyright (c) 2009 Toni Spets
4  * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al.
5  *      (see AUTHORS)
6  * All rights reserved.
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21
22 #include "conky.h"
23 #include "logging.h"
24
25 #ifdef HAVE_SYS_INOTIFY_H
26 #include <sys/inotify.h>
27
28 void llua_append_notify(const char *name);
29 void llua_rm_notifies(void);
30 static int llua_block_notify = 0;
31 #endif /* HAVE_SYS_INOTIFY_H */
32
33 lua_State *lua_L = NULL;
34
35 void llua_init(void)
36 {
37         if(lua_L) return;
38         lua_L = lua_open();
39         luaL_openlibs(lua_L);
40 }
41
42 void llua_load(const char *script)
43 {
44         int error;
45         char path[DEFAULT_TEXT_BUFFER_SIZE];
46
47         if(!lua_L) return;
48
49         to_real_path(path, script);
50         error = luaL_dofile(lua_L, path);
51         if (error) {
52                 ERR("llua_load: %s", lua_tostring(lua_L, -1));
53                 lua_pop(lua_L, 1);
54 #ifdef HAVE_SYS_INOTIFY_H
55         } else if (!llua_block_notify && inotify_fd != -1) {
56                 llua_append_notify(path);
57 #endif /* HAVE_SYS_INOTIFY_H */
58         }
59 }
60
61 /*
62         llua_do_call does a flexible call to any Lua function
63         string: <function> [par1] [par2...]
64         retc: the number of return values expected
65 */
66 char *llua_do_call(const char *string, int retc)
67 {
68         static char func[64];
69         int argc = 0;
70
71         char *tmp = strdup(string);
72         char *ptr = strtok(tmp, " ");
73
74         /* proceed only if the function name is present */
75         if(!ptr) {
76                 free(tmp);
77                 return NULL;
78         }
79
80         /* call only conky_ prefixed functions */
81         snprintf(func, 64, "conky_%s", ptr);
82
83         /* push the function name to stack */
84         lua_getglobal(lua_L, func);
85
86         /* parse all function parameters from args and push them to the stack */
87         ptr = strtok(NULL, " ");
88         while(ptr) {
89                 lua_pushstring(lua_L, ptr);
90                 ptr = strtok(NULL, " ");
91                 argc++;
92         }
93
94         free(tmp);
95
96         if(lua_pcall(lua_L, argc, retc, 0) != 0) {
97                 ERR("llua_do_call: function %s execution failed: %s", func, lua_tostring(lua_L, -1));
98                 lua_pop(lua_L, -1);
99                 return NULL;
100         }
101
102         return func;
103 }
104
105 /*
106  * same as llua_do_call() except passes everything after func as one arg.
107  */
108 char *llua_do_read_call(const char *function, const char *arg, int retc)
109 {
110         static char func[64];
111         snprintf(func, 64, "conky_%s", function);
112         
113         /* push the function name to stack */
114         lua_getglobal(lua_L, func);
115
116         /* push function parameter to the stack */
117         lua_pushstring(lua_L, arg);
118
119         if (lua_pcall(lua_L, 1, retc, 0) != 0) {
120                 ERR("llua_do_call: function %s execution failed: %s", func, lua_tostring(lua_L, -1));
121                 lua_pop(lua_L, -1);
122                 return NULL;
123         }
124
125         return func;
126 }
127
128 char *llua_getstring(const char *args)
129 {
130         char *func;
131         char *ret = NULL;
132
133         if(!lua_L) return NULL;
134
135         func = llua_do_call(args, 1);
136         if(func) {
137                 if(!lua_isstring(lua_L, -1)) {
138                         ERR("llua_getstring: function %s didn't return a string, result discarded", func);
139                 } else {
140                         ret = strdup(lua_tostring(lua_L, -1));
141                         lua_pop(lua_L, 1);
142                 }
143         }
144
145         return ret;
146 }
147
148 char *llua_getstring_read(const char *function, const char *arg)
149 {
150         char *func;
151         char *ret = NULL;
152
153         if(!lua_L) return NULL;
154
155         func = llua_do_read_call(function, arg, 1);
156         if (func) {
157                 if(!lua_isstring(lua_L, -1)) {
158                         ERR("llua_getstring_read: function %s didn't return a string, result discarded", func);
159                 } else {
160                         ret = strdup(lua_tostring(lua_L, -1));
161                         lua_pop(lua_L, 1);
162                 }
163         }
164
165         return ret;
166 }
167
168 int llua_getnumber(const char *args, double *ret)
169 {
170         char *func;
171
172         if(!lua_L) return 0;
173
174         func = llua_do_call(args, 1);
175         if(func) {
176                 if(!lua_isnumber(lua_L, -1)) {
177                         ERR("llua_getnumber: function %s didn't return a number, result discarded", func);
178                 } else {
179                         *ret = lua_tonumber(lua_L, -1);
180                         lua_pop(lua_L, 1);
181                         return 1;
182                 }
183         }
184         return 0;
185 }
186
187 void llua_close(void)
188 {
189 #ifdef HAVE_SYS_INOTIFY_H
190         llua_rm_notifies();
191 #endif /* HAVE_SYS_INOTIFY_H */
192         if(!lua_L) return;
193         lua_close(lua_L);
194         lua_L = NULL;
195 }
196
197 #ifdef HAVE_SYS_INOTIFY_H
198 struct _lua_notify_s {
199         int wd;
200         char name[DEFAULT_TEXT_BUFFER_SIZE];
201         struct _lua_notify_s *next;
202 };
203 static struct _lua_notify_s *lua_notifies = 0;
204
205 static struct _lua_notify_s *llua_notify_list_do_alloc(const char *name)
206 {
207         struct _lua_notify_s *ret = malloc(sizeof(struct _lua_notify_s));
208         memset(ret, 0, sizeof(struct _lua_notify_s));
209         strncpy(ret->name, name, DEFAULT_TEXT_BUFFER_SIZE);
210         return ret;
211 }
212
213 void llua_append_notify(const char *name)
214 {
215         /* do it */
216         struct _lua_notify_s *new_tail = 0;
217         if (!lua_notifies) {
218                 /* empty, fresh new digs */
219                 new_tail = lua_notifies = llua_notify_list_do_alloc(name);
220         } else {
221                 struct _lua_notify_s *tail = lua_notifies;
222                 while (tail->next) {
223                         tail = tail->next;
224                 }
225                 // should be @ the end now
226                 new_tail = llua_notify_list_do_alloc(name);
227                 tail->next = new_tail;
228         }
229         new_tail->wd = inotify_add_watch(inotify_fd,
230                         new_tail->name,
231                         IN_MODIFY);
232 }
233
234 void llua_rm_notifies(void)
235 {
236         /* git 'er done */
237         struct _lua_notify_s *head = lua_notifies;
238         struct _lua_notify_s *next = 0;
239         if (!lua_notifies) return;
240         inotify_rm_watch(inotify_fd, head->wd);
241         if (head->next) next = head->next;
242         free(head);
243         while (next) {
244                 head = next;
245                 next = head->next;
246                 inotify_rm_watch(inotify_fd, head->wd);
247                 free(head);
248         }
249         lua_notifies = 0;
250 }
251
252 void llua_inotify_query(int wd, int mask)
253 {
254         struct _lua_notify_s *head = lua_notifies;
255         if (mask & IN_MODIFY || mask & IN_IGNORED) {
256                 /* for whatever reason, i keep getting IN_IGNORED when the file is
257                  * modified */
258                 while (head) {
259                         if (head->wd == wd) {
260                                 llua_block_notify = 1;
261                                 llua_load(head->name);
262                                 llua_block_notify = 0;
263                                 ERR("Lua script '%s' reloaded", head->name);
264                                 if (mask & IN_IGNORED) {
265                                         /* for some reason we get IN_IGNORED here
266                                          * sometimes, so we need to re-add the watch */
267                                         head->wd = inotify_add_watch(inotify_fd,
268                                                         head->name,
269                                                         IN_MODIFY);
270                                 }
271                                 return;
272                         }
273                         head = head->next;
274                 }
275         }
276 }
277 #endif /* HAVE_SYS_INOTIFY_H */
278