aboutsummaryrefslogtreecommitdiffstats
path: root/filter.c
diff options
context:
space:
mode:
authorGravatar Jason A. Donenfeld <Jason@zx2c4.com>2014-01-13 22:18:51 (JST)
committerGravatar Jason A. Donenfeld <Jason@zx2c4.com>2014-01-14 10:00:07 (JST)
commitf43b228d0bca5791be98ff3fbb2f8743219635b6 (patch)
tree2200619d48fd24f5e809736ff94c84a57da4481f /filter.c
parente83b51b4f6bd53efea0c772e6ecdf1c5605ca611 (diff)
downloadcgit-f43b228d0bca5791be98ff3fbb2f8743219635b6.zip
cgit-f43b228d0bca5791be98ff3fbb2f8743219635b6.tar.gz
filter: add lua support
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'filter.c')
-rw-r--r--filter.c186
1 files changed, 186 insertions, 0 deletions
diff --git a/filter.c b/filter.c
index f5a5992..3702585 100644
--- a/filter.c
+++ b/filter.c
@@ -7,12 +7,19 @@
7 */ 7 */
8 8
9#include "cgit.h" 9#include "cgit.h"
10#include "html.h"
10#include <sys/types.h> 11#include <sys/types.h>
11#include <sys/wait.h> 12#include <sys/wait.h>
12#include <unistd.h> 13#include <unistd.h>
13#include <string.h> 14#include <string.h>
14#include <stdlib.h> 15#include <stdlib.h>
15#include <dlfcn.h> 16#include <dlfcn.h>
17#include <errno.h>
18#ifndef NO_LUA
19#include <lua.h>
20#include <lualib.h>
21#include <lauxlib.h>
22#endif
16 23
17static ssize_t (*libc_write)(int fd, const void *buf, size_t count); 24static ssize_t (*libc_write)(int fd, const void *buf, size_t count);
18static ssize_t (*filter_write)(struct cgit_filter *base, const void *buf, size_t count) = NULL; 25static ssize_t (*filter_write)(struct cgit_filter *base, const void *buf, size_t count) = NULL;
@@ -164,6 +171,182 @@ void cgit_exec_filter_init(struct cgit_exec_filter *filter, char *cmd, char **ar
164 filter->base.argument_count = 0; 171 filter->base.argument_count = 0;
165} 172}
166 173
174#ifndef NO_LUA
175struct lua_filter {
176 struct cgit_filter base;
177 char *script_file;
178 lua_State *lua_state;
179};
180
181static void error_lua_filter(struct lua_filter *filter)
182{
183 die("Lua error in %s: %s", filter->script_file, lua_tostring(filter->lua_state, -1));
184 lua_pop(filter->lua_state, 1);
185}
186
187static ssize_t write_lua_filter(struct cgit_filter *base, const void *buf, size_t count)
188{
189 struct lua_filter *filter = (struct lua_filter *) base;
190
191 lua_getglobal(filter->lua_state, "filter_write");
192 lua_pushlstring(filter->lua_state, buf, count);
193 if (lua_pcall(filter->lua_state, 1, 0, 0)) {
194 error_lua_filter(filter);
195 errno = EIO;
196 return -1;
197 }
198 return count;
199}
200
201static inline int hook_lua_filter(lua_State *lua_state, void (*fn)(const char *txt))
202{
203 const char *str;
204 ssize_t (*save_filter_write)(struct cgit_filter *base, const void *buf, size_t count);
205 struct cgit_filter *save_filter;
206
207 str = lua_tostring(lua_state, 1);
208 if (!str)
209 return 0;
210
211 save_filter_write = filter_write;
212 save_filter = current_write_filter;
213 unhook_write();
214 fn(str);
215 hook_write(save_filter, save_filter_write);
216
217 return 0;
218}
219
220static int html_lua_filter(lua_State *lua_state)
221{
222 return hook_lua_filter(lua_state, html);
223}
224
225static int html_txt_lua_filter(lua_State *lua_state)
226{
227 return hook_lua_filter(lua_state, html_txt);
228}
229
230static int html_attr_lua_filter(lua_State *lua_state)
231{
232 return hook_lua_filter(lua_state, html_attr);
233}
234
235static int html_url_path_lua_filter(lua_State *lua_state)
236{
237 return hook_lua_filter(lua_state, html_url_path);
238}
239
240static int html_url_arg_lua_filter(lua_State *lua_state)
241{
242 return hook_lua_filter(lua_state, html_url_arg);
243}
244
245static void cleanup_lua_filter(struct cgit_filter *base)
246{
247 struct lua_filter *filter = (struct lua_filter *) base;
248
249 if (!filter->lua_state)
250 return;
251
252 lua_close(filter->lua_state);
253 filter->lua_state = NULL;
254 if (filter->script_file) {
255 free(filter->script_file);
256 filter->script_file = NULL;
257 }
258}
259
260static int init_lua_filter(struct lua_filter *filter)
261{
262 if (filter->lua_state)
263 return 0;
264
265 if (!(filter->lua_state = luaL_newstate()))
266 return 1;
267
268 luaL_openlibs(filter->lua_state);
269
270 lua_pushcfunction(filter->lua_state, html_lua_filter);
271 lua_setglobal(filter->lua_state, "html");
272 lua_pushcfunction(filter->lua_state, html_txt_lua_filter);
273 lua_setglobal(filter->lua_state, "html_txt");
274 lua_pushcfunction(filter->lua_state, html_attr_lua_filter);
275 lua_setglobal(filter->lua_state, "html_attr");
276 lua_pushcfunction(filter->lua_state, html_url_path_lua_filter);
277 lua_setglobal(filter->lua_state, "html_url_path");
278 lua_pushcfunction(filter->lua_state, html_url_arg_lua_filter);
279 lua_setglobal(filter->lua_state, "html_url_arg");
280
281 if (luaL_dofile(filter->lua_state, filter->script_file)) {
282 error_lua_filter(filter);
283 lua_close(filter->lua_state);
284 filter->lua_state = NULL;
285 return 1;
286 }
287 return 0;
288}
289
290static int open_lua_filter(struct cgit_filter *base, va_list ap)
291{
292 struct lua_filter *filter = (struct lua_filter *) base;
293 int i;
294
295 if (init_lua_filter(filter))
296 return 1;
297
298 hook_write(base, write_lua_filter);
299
300 lua_getglobal(filter->lua_state, "filter_open");
301 for (i = 0; i < filter->base.argument_count; ++i)
302 lua_pushstring(filter->lua_state, va_arg(ap, char *));
303 if (lua_pcall(filter->lua_state, filter->base.argument_count, 0, 0)) {
304 error_lua_filter(filter);
305 return 1;
306 }
307 return 0;
308}
309
310static int close_lua_filter(struct cgit_filter *base)
311{
312 struct lua_filter *filter = (struct lua_filter *) base;
313 int ret = 0;
314
315 lua_getglobal(filter->lua_state, "filter_close");
316 if (lua_pcall(filter->lua_state, 0, 0, 0)) {
317 error_lua_filter(filter);
318 ret = 1;
319 }
320 unhook_write();
321 return ret;
322}
323
324static void fprintf_lua_filter(struct cgit_filter *base, FILE *f, const char *prefix)
325{
326 struct lua_filter *filter = (struct lua_filter *) base;
327 fprintf(f, "%slua:%s\n", prefix, filter->script_file);
328}
329
330
331static struct cgit_filter *new_lua_filter(const char *cmd, int argument_count)
332{
333 struct lua_filter *filter;
334
335 filter = xmalloc(sizeof(*filter));
336 memset(filter, 0, sizeof(*filter));
337 filter->base.open = open_lua_filter;
338 filter->base.close = close_lua_filter;
339 filter->base.fprintf = fprintf_lua_filter;
340 filter->base.cleanup = cleanup_lua_filter;
341 filter->base.argument_count = argument_count;
342 filter->script_file = xstrdup(cmd);
343
344 return &filter->base;
345}
346
347#endif
348
349
167int cgit_open_filter(struct cgit_filter *filter, ...) 350int cgit_open_filter(struct cgit_filter *filter, ...)
168{ 351{
169 int result; 352 int result;
@@ -191,6 +374,9 @@ static const struct {
191 struct cgit_filter *(*ctor)(const char *cmd, int argument_count); 374 struct cgit_filter *(*ctor)(const char *cmd, int argument_count);
192} filter_specs[] = { 375} filter_specs[] = {
193 { "exec", new_exec_filter }, 376 { "exec", new_exec_filter },
377#ifndef NO_LUA
378 { "lua", new_lua_filter },
379#endif
194}; 380};
195 381
196struct cgit_filter *cgit_new_filter(const char *cmd, filter_type filtertype) 382struct cgit_filter *cgit_new_filter(const char *cmd, filter_type filtertype)