Skip to content

Instantly share code, notes, and snippets.

@st235
Created January 4, 2025 15:08
Show Gist options
  • Save st235/b8bbf94e730362aefb288fa715dea1f2 to your computer and use it in GitHub Desktop.
Save st235/b8bbf94e730362aefb288fa715dea1f2 to your computer and use it in GitHub Desktop.
Programming in Lua. Exercise 30.1
// Exercise 30.1:
// Modify the dir_iter function in the directory example
// so that it closes the DIR structure when it reaches
// the end of the traversal.
// With this change,
// the program does not need to wait for a garbage collection
// to release a resource that it knows it will not need anymore.
// (When you close the directory,
// you should set the address stored in the userdatum to NULL,
// to signal to the finalizer that the directory is already closed.
// Also, function dir_iter will have to check whether the directory
// is not closed before using it.)
#define LUA_COMPAT_APIINTCASTS
#include <cmath>
#include <cstdint>
#include <dirent.h>
#include <exception>
#include <iomanip>
#include <iostream>
#include <limits>
#include <string>
#include <vector>
#include <stack>
#include <unordered_set>
#include "lua.hpp"
namespace {
bool AbortWithMessage(const char* message) {
std::cout << message << std::endl;
std::abort();
}
bool LoadFile(lua_State* state, const std::string& filename) {
return !(luaL_loadfile(state, filename.c_str()) || lua_pcall(state, 0, 0, 0));
}
int dir_iter(lua_State *L) {
DIR** dir_ptr = (DIR**) lua_touserdata(L, lua_upvalueindex(1));
struct dirent* entry;
if (*dir_ptr && (entry = readdir(*dir_ptr)) != NULL) {
lua_pushstring(L, entry->d_name);
return 1;
}
// Directory is empty.
if (*dir_ptr) {
closedir(*dir_ptr);
*dir_ptr = nullptr;
}
return 0;
}
int l_dir(lua_State *L) {
const char *path = luaL_checkstring(L, 1);
DIR** d = (DIR**) lua_newuserdata(L, sizeof(DIR*));
luaL_getmetatable(L, "LuaBook.dir");
lua_setmetatable(L, -2);
*d = opendir(path);
if (*d == NULL) {
luaL_error(L, "cannot open %s: %s", path, strerror(errno));
}
lua_pushcclosure(L, dir_iter, 1);
return 1;
}
int dir_gc(lua_State *L) {
DIR* d = *(DIR**) lua_touserdata(L, 1);
if (d) {
closedir(d);
}
return 0;
}
const struct luaL_Reg dirlib[] = {
{"open", l_dir},
{NULL, NULL}
};
int luaopen_dir(lua_State *L) {
luaL_newmetatable(L, "LuaBook.dir");
lua_pushcfunction(L, dir_gc);
lua_setfield(L, -2, "__gc");
luaL_newlib(L, dirlib);
lua_setglobal(L, "dir");
return 0;
}
} // namespace
int main(int argc, char* argv[]) {
if (argc < 2) {
std::cout << "Please, specify lua script file to run." << std::endl;
return 0;
}
lua_State* L = luaL_newstate();
luaL_openlibs(L);
luaopen_dir(L);
if (!LoadFile(L, std::string(argv[1]))) {
AbortWithMessage(lua_tostring(L, -1));
return -1;
}
return 0;
}
for fname in dir.open(".") do
print(fname)
end
.
..
CMakeFiles
Makefile
cmake_install.cmake
deps
CMakeCache.txt
lua-test
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment