#include #include #include #include #include #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; }