2 * fastindex - fast lua module indexing plugin
3 * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2
7 * as published by the Free Software Foundation
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
15 #include <sys/types.h>
17 #include <sys/cdefs.h>
19 #ifndef _POSIX_C_SOURCE
20 #define _POSIX_C_SOURCE /* XXX: portability hack for timestamp */
35 #define MODNAME "luci.fastindex"
36 #define DEFAULT_BUFLEN 1024
41 #define DPRINTF(...) fprintf(stderr, __VA_ARGS__)
43 #define DPRINTF(...) do {} while (0)
47 * list_for_each_offset - iterate over a list, start with the provided pointer
48 * @pos: the &struct list_head to use as a loop cursor.
49 * @head: the head for your list.
51 #define list_for_each_offset(pos, head, offset) \
52 for (pos = (offset)->next; pos != (offset); \
53 pos = ((pos->next == (head)) && ((offset) != (head)) ? (head)->next : pos->next))
55 static char *namespace = NULL;
57 struct fastindex_entry {
58 struct list_head list;
64 struct fastindex_pattern {
65 struct list_head list;
73 struct list_head patterns;
74 struct list_head *last;
75 struct list_head entries;
81 static inline struct fastindex *
82 to_fastindex(struct lua_State *L)
85 lua_getfield(L, lua_upvalueindex(1), "__data");
86 f = lua_touserdata(L, -1);
92 fastindex_module(lua_State *L)
95 s = luaL_checkstring(L, 1);
100 namespace = strdup(s);
106 static struct fastindex_entry *
107 find_entry(struct fastindex *f, char *name)
112 f->last = &f->entries;
114 list_for_each_offset(p, &f->entries, f->last) {
115 struct fastindex_entry *e;
116 e = container_of(p, struct fastindex_entry, list);
117 if (!strcmp(e->name, name))
123 static struct fastindex_entry *
124 new_entry(struct fastindex *f, char *name)
126 struct fastindex_entry *e;
128 e = malloc(sizeof(struct fastindex_entry));
132 memset(e, 0, sizeof(struct fastindex_entry));
133 e->name = strdup(name);
138 INIT_LIST_HEAD(&e->list);
146 static void free_entry(struct fastindex_entry *e)
153 int bufferwriter(lua_State *L, const void *p, size_t sz, void *ud)
155 struct fastindex *f = ud;
157 while (f->ofs + sz > f->buflen) {
160 f->buf = realloc(f->buf, f->buflen);
166 memcpy(f->buf + f->ofs, p, sz);
172 load_index(struct fastindex *f, struct fastindex_entry *e)
176 DPRINTF("Loading module: %s\n", e->name);
179 f->buf = malloc(f->buflen);
182 luaL_error(f->L, "Out of memory!\n");
191 lua_pushcfunction(L, fastindex_module);
192 lua_setfield(L, LUA_GLOBALSINDEX, "module");
195 if (luaL_dofile(L, e->name)) {
196 DPRINTF("Warning: unable to open module '%s'\n", e->name);
200 lua_getglobal(L, f->func);
201 lua_dump(L, bufferwriter, f);
202 DPRINTF("Got %d bytes\n", f->ofs);
205 lua_createtable(f->L, (namespace ? 2 : 1), 0);
206 luaL_loadbuffer(f->L, f->buf, f->ofs, "tmp");
207 lua_rawseti(f->L, -2, 1);
209 DPRINTF("Module has namespace '%s'\n", namespace);
210 lua_pushstring(f->L, namespace);
211 lua_rawseti(f->L, -2, 2);
215 lua_setfield(f->L, -2, e->name);
223 fastindex_scan(lua_State *L)
225 struct list_head *tmp, *p;
229 int gl_flags = GLOB_NOESCAPE | GLOB_NOSORT | GLOB_MARK;
235 if (list_empty(&f->patterns))
238 lua_getfield(L, lua_upvalueindex(1), "indexes");
239 list_for_each(p, &f->patterns) {
240 struct fastindex_pattern *pt = container_of(p, struct fastindex_pattern, list);
241 glob(pt->pattern, gl_flags, NULL, &gl);
242 gl_flags |= GLOB_APPEND;
244 for (i = 0; i < gl.gl_pathc; i++) {
245 struct fastindex_entry *e;
248 if (stat(gl.gl_pathv[i], &st))
251 if ((st.st_mode & S_IFMT) != S_IFREG)
254 e = find_entry(f, gl.gl_pathv[i]);
256 e = new_entry(f, gl.gl_pathv[i]);
257 list_add_tail(&e->list, &f->entries);
260 e->checked = f->checked;
261 if ((e->timestamp < st.st_mtime)) {
263 e->timestamp = st.st_mtime;
267 list_for_each_safe(p, tmp, &f->entries) {
268 struct fastindex_entry *e = container_of(p, struct fastindex_entry, list);
269 if (e->checked < f->checked) {
271 lua_setfield(f->L, -2, e->name);
281 fastindex_free(lua_State *L)
284 struct list_head *p, *tmp;
286 f = lua_touserdata(L, -1);
287 list_for_each_safe(p, tmp, &f->patterns) {
288 struct fastindex_pattern *pt;
289 pt = container_of(p, struct fastindex_pattern, list);
293 list_for_each_safe(p, tmp, &f->entries) {
294 struct fastindex_entry *e;
295 e = container_of(p, struct fastindex_entry, list);
302 fastindex_add(lua_State *L)
304 struct fastindex_pattern *pt;
309 str = luaL_checkstring(L, 1);
311 luaL_error(L, "Invalid argument");
313 pt = malloc(sizeof(struct fastindex_pattern) + strlen(str) + 1);
315 luaL_error(L, "Out of memory");
317 INIT_LIST_HEAD(&pt->list);
318 strcpy(pt->pattern, str);
319 list_add(&pt->list, &f->patterns);
324 static const luaL_Reg fastindex_m[] = {
325 { "add", fastindex_add },
326 { "scan", fastindex_scan },
331 fastindex_new(lua_State *L)
336 func = luaL_checkstring(L, 1);
338 f = lua_newuserdata(L, sizeof(struct fastindex));
339 lua_createtable(L, 0, 2);
340 lua_pushvalue(L, -1);
341 lua_setfield(L, -2, "__index");
342 lua_pushcfunction(L, fastindex_free);
343 lua_setfield(L, -2, "__gc");
344 lua_pushvalue(L, -1);
345 lua_setmetatable(L, -3);
346 lua_pushvalue(L, -2);
347 lua_setfield(L, -2, "__data");
348 lua_createtable(L, 0, 1);
349 lua_setfield(L, -2, "indexes");
350 lua_pushvalue(L, -2);
351 luaI_openlib(L, NULL, fastindex_m, 1);
353 memset(f, 0, sizeof(struct fastindex));
355 f->buflen = DEFAULT_BUFLEN;
356 INIT_LIST_HEAD(&f->entries);
357 INIT_LIST_HEAD(&f->patterns);
359 f->func = strdup(func);
363 luaL_error(L, "Out of memory\n");
369 static const luaL_Reg fastindex[] = {
370 { "new", fastindex_new },
375 luaopen_luci_fastindex(lua_State *L)
377 luaL_register(L, MODNAME, fastindex);