diff options
Diffstat (limited to 'lib/ldirlib.c')
-rw-r--r-- | lib/ldirlib.c | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/lib/ldirlib.c b/lib/ldirlib.c new file mode 100644 index 0000000..8e68f0b --- /dev/null +++ b/lib/ldirlib.c @@ -0,0 +1,113 @@ +#include <stdlib.h> +#include <string.h> +#include <dirent.h> +#include <errno.h> +#include <sys/stat.h> + +#define ldirlib_c + +#define LUA_DIRLIBNAME "dir" + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + +/* forward declaration for the iterator function */ +static int dir_iter (lua_State *L); + +static int l_dir (lua_State *L) { + const char *path = luaL_checkstring(L, 1); + char * d_path, * p; + DIR **d; + + /* create a userdatum to store a DIR address */ + p = (char *) lua_newuserdata(L, sizeof(DIR *) + strlen(path) + 1); + d = (DIR **) p; + d_path = p + sizeof(DIR *); + + strcpy(d_path, path); + + /* set its metatable */ + luaL_getmetatable(L, "LuaBook.dir"); + lua_setmetatable(L, -2); + + /* try to open the given directory */ + *d = opendir(path); + if (*d == NULL) /* error opening the directory? */ + luaL_error(L, "cannot open %s: %s", path, + strerror(errno)); + + /* creates and returns the iterator function + (its sole upvalue, the directory userdatum, + is already on the stack top */ + lua_pushcclosure(L, dir_iter, 1); + return 1; +} + +static int dir_iter (lua_State *L) { + char * p = (char *) lua_touserdata(L, lua_upvalueindex(1)); + DIR * d = *(DIR **) p; + char * path = p + sizeof(DIR *); + char * fullpath; + struct dirent *entry; +#ifdef _WIN32 + struct _stat file_stat; +#else + struct stat file_stat; +#endif + if ((entry = readdir(d)) != NULL) { + lua_newtable(L); + lua_pushstring(L, "name"); + lua_pushstring(L, entry->d_name); + lua_settable(L, -3); + fullpath = (char *) malloc(strlen(path) + strlen(entry->d_name) + 2); + sprintf(fullpath, "%s/%s", path, entry->d_name); +#ifdef _WIN32 + _stat(fullpath, &file_stat); +#else + stat(fullpath, &file_stat); +#endif + free(fullpath); + lua_pushstring(L, "type"); + lua_pushnumber(L, (S_IFREG & file_stat.st_mode) ? 2 : ((S_IFDIR & file_stat.st_mode) ? 1 : 0)); + lua_settable(L, -3); + + return 1; + } + else return 0; /* no more values to return */ +} + +static int dir_gc (lua_State *L) { + DIR *d = *(DIR **)lua_touserdata(L, 1); + if (d) closedir(d); + return 0; +} + +static const luaL_reg dirlib[] = { + {NULL, NULL} +}; + +int luaopen_dir (lua_State *L) { + luaL_openlib(L, LUA_DIRLIBNAME, dirlib, 0); + luaL_newmetatable(L, "LuaBook.dir"); + + /* set its __gc field */ + lua_pushstring(L, "__gc"); + lua_pushcfunction(L, dir_gc); + lua_settable(L, -3); + + /* register the `dir' function */ + lua_pushcfunction(L, l_dir); + lua_setglobal(L, "dir"); + + lua_pushnumber(L, 1); + lua_setglobal(L, "FLAG_DIR"); + + lua_pushnumber(L, 2); + lua_setglobal(L, "FLAG_FILE"); + + lua_pop(L, 1); + + return 0; +} |