1

So, I have a C++ program which recursively goes through a directory tree and calls a certain lua function on all of the files in that directory.

Managing stack with Lua and C++

you can read my previous question for some insight on exactly how this works, but essentially it's pretty simple. The lua function returns 0 to many strings. However, the results of one lua return can effect the results of a later lua return. (specifically, I'm trying to remove duplicate strings, and some other things)

I'm wondering if there is a way to set up so that I can still make these lua calls, but have the lua state remain open for the duration of the recursive operations. In this way, I should retain variables, and other important information during this recursive process, which would allow me to extend the functionality of my program easily.

My C++ application uses my open source interface called FileDigger which allows me to fill in logic to perform beforeDig() and afterDig() and fileFound()

currently this is my code:

#include "LanguageShovel.h"
#include <FileDigger/src/FileDigger.h>
#include <fstream>
#include <iostream>

extern "C" {
#include <lua/src/lua.h>
#include <lua/src/lauxlib.h>
#include <lua/src/lualib.h>
}

void LanguageShovel::BeforeDig(string path) {
    cout << "Searching Files..." << endl;
}

void LanguageShovel::AfterDig(string path) {

    for (int i = 0 ; i < list_strings.size(); i++) 
    {
        cout << list_strings[i] << endl;
    }

    cout << list_strings.size() << endl;
    cout << "Finished..." << endl;
}

void LanguageShovel::FileFound(string path) {

    list_strings.push_back(path);

    int error = 0;
    lua_State *L = lua_open();
    luaL_openlibs(L);

    // Push function to stack
    if ((error = luaL_loadfile(L, "src/language.lua")) == 0)
    {
        // Push path to stack
        lua_pushstring(L, path.c_str());

        // Pop stack and call lua script, to return a single table
        if ((error = lua_pcall(L, 1, 1, 0)) == 0)
        {
            // If single value on stack, and is table
            if (lua_gettop(L) == 1 && lua_istable(L,-1))
            {
                int len = lua_objlen(L,-1);
                // list_strings.reserve(len);
                for (int i=0; i < len; i++)
                {
                    // Push index on stack for gettable
                    lua_pushinteger(L,i + 1);
                    lua_gettable(L,-2);

                    size_t strLen = 0;
                    const char *s = lua_tolstring(L,-1, &strLen);
                    if (s)
                    {
                        // Lua strings may not be null terminated
                        // Assign will ensure null terminated end
                        list_strings.push_back(s);
                        list_strings.back().assign(s,strLen);
                    }

                    // Pop the string when finished with it
                    lua_pop(L,1);
                }
            }   
        }
    }

    lua_close(L);
}

void LanguageShovel::DirectoryFound(string path) {
}

int main(int argc, char *argv[]) {

    if( argc < 2 ) {
        cout << "Not enough arguments:\n\n Ex: a C:\\cpp\\a .cpp .h";

        int any_number;
        std::cout << "\n\n";
        std::cout << "Please enter a number to end the program:";
        std::cout << "\n\n";
        std::cin >> any_number;
        return 1;
    }

    FileDigger f;
    LanguageShovel s;
    string directory = argv[1];

    // Get filters from arguments
    for (int i = 2; i < argc; i++) {
        s.AddFilter(argv[i]);
    }

    f.Dig(directory, s);

    int any_number;
    std::cout << "\n\n";
    std::cout << "Please enter a number to end the program:";
    std::cout << "\n\n";
    //std::cin >> any_number;
    return 0;
}

So as you can see, it creates a FileDigger class, and a Shovel. The shovel is the interface where you place your logic. After those are created it starts the recursive process by calling dig()

This calls beforeDig() then starts the recursive process. when a file is found, it calls fileFound() which then gets the strings and puts them into a vector. After the dig is finished I simply print the strings.

As you'll see, I create and remove a state in the fileFound function. I'm thinking of instead of doing this, I should start a Lua state in beforeDig() and end it in afterDig().

Also, right now my lua source is being called directly in the .lua file instead of caling a specific function which contains that code. I think I'll probably need to change that... So... If you have any more questions I'll answer them, but let's start the discussion! :D

Community
  • 1
  • 1
Colton Phillips
  • 237
  • 1
  • 4
  • 13

1 Answers1

1

You're going to need to redesign how you're using Lua. You'll have a setup or init function called before your scripts that sets up the Lua state like always:

init_lua() {
  lua_State *L = lua_open();
  luaL_openlibs(L);
  luaL_loadfile(L, "src/language.lua");
  return L;
}

In Lua, you need to define your function and local variables to use between function calls:

local data_store -- this is where you cache data between function calls
function my_func (path)
  -- do something with path and your data_store
end

And back in your program, you retrieve and call your function instead of reloading/compiling the script:

lua_getglobal(L, "my_func");
lua_pushstring(L, path.c_str());
lua_pcall(L, 1, 1, 0);
/* etc */

Note, error handling, and using a module instead of a global, are left as exercises for the reader.

Stuart P. Bentley
  • 10,195
  • 10
  • 55
  • 84
BMitch
  • 231,797
  • 42
  • 475
  • 450
  • So, I initialized Lua just as you did but opening a lua state and the libraries than loading the file. My lua function is called function trans(path) and is called identically to yours, getglobal, then push the path, then do your call. However this lua call returns an error of return code 2, which is a runtime error. The only real difference in my lua script is that I used to use "path = ..." to get that pushed string, but now I just assume it's passed in via a parameter. What's the deal yo? – Colton Phillips Jul 18 '11 at 21:21
  • Because of all the changes, it may be easier to help if you post your code in a new question. Make sure you run the function using `lua_pcall` and extract any error message from the stack if pcall doesn't succeed (it will be a string at the top of the stack). – BMitch Jul 18 '11 at 23:02
  • That means your function lookup failed, typo or it wasn't defined for some reason. – BMitch Jul 19 '11 at 00:58
  • Forehead slap, I didn't include the `lua_pcall` after the `LuaL_loadfile` in my example, but I see you've got a resolution in your other question. http://stackoverflow.com/questions/6741050/lua-getting-global-function-failing-after-loading-file – BMitch Jul 19 '11 at 01:01