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.

Revisions

  1. st235 created this gist Jan 4, 2025.
    119 changes: 119 additions & 0 deletions Lua.Exercise30.1.cpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,119 @@
    // 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;
    }
    3 changes: 3 additions & 0 deletions main.lua
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,3 @@
    for fname in dir.open(".") do
    print(fname)
    end
    8 changes: 8 additions & 0 deletions output.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,8 @@
    .
    ..
    CMakeFiles
    Makefile
    cmake_install.cmake
    deps
    CMakeCache.txt
    lua-test