Oops, null pointer.
[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         if(!lua_L) return;
46         error = luaL_dofile(lua_L, script);
47         if (error) {
48                 ERR("llua_load: %s", lua_tostring(lua_L, -1));
49                 lua_pop(lua_L, 1);
50 #ifdef HAVE_SYS_INOTIFY_H
51         } else if (!llua_block_notify) {
52                 llua_append_notify(script);
53 #endif /* HAVE_SYS_INOTIFY_H */
54         }
55 }
56
57 /*
58         llua_do_call does a flexible call to any Lua function
59         string: <function> [par1] [par2...]
60         retc: the number of return values expected
61 */
62 char *llua_do_call(const char *string, int retc)
63 {
64         static char func[64];
65         int argc = 0;
66
67         char *tmp = strdup(string);
68         char *ptr = strtok(tmp, " ");
69
70         /* proceed only if the function name is present */
71         if(!ptr) {
72                 free(tmp);
73                 return NULL;
74         }
75
76         /* call only conky_ prefixed functions */
77         snprintf(func, 64, "conky_%s", ptr);
78
79         /* push the function name to stack */
80         lua_getglobal(lua_L, func);
81
82         /* parse all function parameters from args and push them to the stack */
83         ptr = strtok(NULL, " ");
84         while(ptr) {
85                 lua_pushstring(lua_L, ptr);
86                 ptr = strtok(NULL, " ");
87                 argc++;
88         }
89
90         free(tmp);
91
92         if(lua_pcall(lua_L, argc, retc, 0) != 0) {
93                 ERR("llua_do_call: function %s execution failed: %s", func, lua_tostring(lua_L, -1));
94                 lua_pop(lua_L, -1);
95                 return NULL;
96         }
97
98         return func;
99 }
100
101 /*
102  * same as llua_do_call() except passes everything after func as one arg.
103  */
104 char *llua_do_read_call(const char *function, const char *arg, int retc)
105 {
106         static char func[64];
107         snprintf(func, 64, "conky_%s", function);
108         
109         /* push the function name to stack */
110         lua_getglobal(lua_L, func);
111
112         /* push function parameter to the stack */
113         lua_pushstring(lua_L, arg);
114
115         if (lua_pcall(lua_L, 1, retc, 0) != 0) {
116                 ERR("llua_do_call: function %s execution failed: %s", func, lua_tostring(lua_L, -1));
117                 lua_pop(lua_L, -1);
118                 return NULL;
119         }
120
121         return func;
122 }
123
124 char *llua_getstring(const char *args)
125 {
126         char *func;
127         char *ret = NULL;
128
129         if(!lua_L) return NULL;
130
131         func = llua_do_call(args, 1);
132         if(func) {
133                 if(!lua_isstring(lua_L, -1)) {
134                         ERR("llua_getstring: function %s didn't return a string, result discarded", func);
135                 } else {
136                         ret = strdup(lua_tostring(lua_L, -1));
137                         lua_pop(lua_L, 1);
138                 }
139         }
140
141         return ret;
142 }
143
144 char *llua_getstring_read(const char *function, const char *arg)
145 {
146         char *func;
147         char *ret = NULL;
148
149         if(!lua_L) return NULL;
150
151         func = llua_do_read_call(function, arg, 1);
152         if (func) {
153                 if(!lua_isstring(lua_L, -1)) {
154                         ERR("llua_getstring_read: function %s didn't return a string, result discarded", func);
155                 } else {
156                         ret = strdup(lua_tostring(lua_L, -1));
157                         lua_pop(lua_L, 1);
158                 }
159         }
160
161         return ret;
162 }
163
164 int llua_getinteger(const char *args, int *per)
165 {
166         char *func;
167
168         if(!lua_L) return 0;
169
170         func = llua_do_call(args, 1);
171         if(func) {
172                 if(!lua_isnumber(lua_L, -1)) {
173                         ERR("llua_getinteger: function %s didn't return an integer, result discarded", func);
174                 } else {
175                         *per = lua_tointeger(lua_L, -1);
176                         lua_pop(lua_L, 1);
177                         return 1;
178                 }
179         }
180         return 0;
181 }
182
183 void llua_close(void)
184 {
185 #ifdef HAVE_SYS_INOTIFY_H
186         llua_rm_notifies();
187 #endif /* HAVE_SYS_INOTIFY_H */
188         if(!lua_L) return;
189         lua_close(lua_L);
190         lua_L = NULL;
191 }
192
193 #ifdef HAVE_SYS_INOTIFY_H
194 struct _lua_notify_s {
195         int wd;
196         char name[DEFAULT_TEXT_BUFFER_SIZE];
197         struct _lua_notify_s *next;
198 };
199 static struct _lua_notify_s *lua_notifies = 0;
200
201 static struct _lua_notify_s *llua_notify_list_do_alloc(const char *name)
202 {
203         struct _lua_notify_s *ret = malloc(sizeof(struct _lua_notify_s));
204         memset(ret, 0, sizeof(struct _lua_notify_s));
205         strncpy(ret->name, name, DEFAULT_TEXT_BUFFER_SIZE);
206         return ret;
207 }
208
209 void llua_append_notify(const char *name)
210 {
211         /* do it */
212         struct _lua_notify_s *new_tail = 0;
213         if (!lua_notifies) {
214                 /* empty, fresh new digs */
215                 new_tail = lua_notifies = llua_notify_list_do_alloc(name);
216         } else {
217                 struct _lua_notify_s *tail = lua_notifies;
218                 while (tail->next) {
219                         tail = tail->next;
220                 }
221                 // should be @ the end now
222                 new_tail = llua_notify_list_do_alloc(name);
223                 tail->next = new_tail;
224         }
225         new_tail->wd = inotify_add_watch(inotify_fd,
226                         new_tail->name,
227                         IN_MODIFY);
228 }
229
230 void llua_rm_notifies(void)
231 {
232         /* git 'er done */
233         struct _lua_notify_s *head = lua_notifies;
234         struct _lua_notify_s *next = 0;
235         if (!lua_notifies) return;
236         inotify_rm_watch(inotify_fd, head->wd);
237         if (head->next) next = head->next;
238         free(head);
239         while (next) {
240                 head = next;
241                 next = head->next;
242                 inotify_rm_watch(inotify_fd, head->wd);
243                 free(head);
244         }
245         lua_notifies = 0;
246 }
247
248 void llua_inotify_query(int wd, int mask)
249 {
250         struct _lua_notify_s *head = lua_notifies;
251         if (mask & IN_MODIFY || mask & IN_IGNORED) {
252                 /* for whatever reason, i keep getting IN_IGNORED when the file is
253                  * modified */
254                 while (head) {
255                         if (head->wd == wd) {
256                                 llua_block_notify = 1;
257                                 llua_load(head->name);
258                                 llua_block_notify = 0;
259                                 ERR("Lua script '%s' reloaded", head->name);
260                                 if (mask & IN_IGNORED) {
261                                         /* for some reason we get IN_IGNORED here
262                                          * sometimes, so we need to re-add the watch */
263                                         head->wd = inotify_add_watch(inotify_fd,
264                                                         head->name,
265                                                         IN_MODIFY);
266                                 }
267                                 return;
268                         }
269                         head = head->next;
270                 }
271         }
272 }
273 #endif /* HAVE_SYS_INOTIFY_H */
274