lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


2011/10/28 Bryan McGinty <bmcginty@silverspringnet.com>:
> I am writing Lua library code in C.  I am attempting to
> determine if a global object exists, and if it does has
> a particular key.
>
> I first determine if the global object exists using:
> lua_getglobal(ls, module);
> if (lua_isnil(ls, -1) == 0) {
>
> If the object exists and a key has been specified I then
>
> attempt to determine if the key exists using:
> lua_getfield(ls, -1, key);
>
> With this call the object's __index metamethod is called.
> If the __index metamethod returns an argument error my
> code terminates.
>
> Is there a better way to be doing this operation?  If not,
> how can I catch the exception?

You have to wrap the code that can generate the exception in a
protected call. In C it's done with lua_pcall or lua_cpcall. In your
case you would replace code like this:

const char* get_foo_bar(lua_State* L)
{
    const char* name;

    // Lua part, may throw
    lua_getglobal(L, "foo");
    if (!lua_isnil(L, -1))
    {
        lua_getfield(L, -1, "bar");
        if (lua_isstring(L, -1))
            name = strdup(lua_tostring(L, -1));
        lua_pop(L, 1); // pop foo.bar or nil
    }
    lua_pop(L, 1); // pop foo or nil

    // C part, safe
    name = adjust_name(name);

    return name;
}

with code like this:

struct context_t
{
    const char* name;
};

const char* get_foo_bar2(lua_State* L)
{
    context_t context;
    const char* name;

    // protect the Lua part
    lua_cpcall(L, get_foo_bar2_helper, &context);
    name = context.name;

    // C part stays the same
    name = adjust_name(name);

    return name;
}


int get_foo_bar2_helper(lua_State* L)
{
    context_t* context;
    const char* name;

    context = lua_touserdata(L, 1);

    lua_getglobal(L, "foo");
    if (!lua_isnil(L, -1))
    {
        lua_getfield(L, -1, "bar");
        if (lua_isstring(L, -1))
            name = strdup(lua_tostring(L, -1));
        lua_pop(L, 1); // pop foo.bar or nil
    }
    lua_pop(L, 1); // pop foo or nil

    context.name = name;

    return 0;
}