lua c читать вложенные таблицы

ниже приведена таблица lua, которую мне нужно прочитать с C:

listen = {
    { port = 1234, address = "192.168.1.1", userdata = "liunx" },
    { port = 1235, address = "192.168.1.2", userdata = "liunx1" },
    { port = 1236, address = "192.168.1.3", userdata = "liunx2" }
}

ниже приведен код c:

#include <lua.h>                                /* Always include this when calling Lua */
#include <lauxlib.h>                            /* Always include this when calling Lua */
#include <lualib.h>                             /* Prototype for luaL_openlibs(), */
/*   always include this when calling Lua */

#include <stdlib.h>                             /* For function exit() */
#include <stdio.h>                              /* For input/output */

void bail(lua_State *L, char *msg){
    fprintf(stderr, "\nFATAL ERROR:\n  %s: %s\n\n",
            msg, lua_tostring(L, -1));
    exit(1);
}

int main(void)
{
    lua_State *L;
    L = luaL_newstate();                        /* Create Lua state variable */
    luaL_openlibs(L);                           /* Load Lua libraries */
    if (luaL_loadfile(L, "cfg.lua")) 
        bail(L, "luaL_loadfile() failed");
    if (lua_pcall(L, 0, 0, 0))           
        bail(L, "lua_pcall() failed");
    // how to read???
    lua_getglobal(L, "listen");
    lua_close(L);
    return 0;
}

Я хочу путешествовать по этой таблице, которая может содержать несколько данных в цикле while, но на самом деле не знаю, как это сделать, так что какие-нибудь советы?

Большое спасибо за ваши советы! Ниже приведен рабочий код:

#include <lua.h>                                /* Always include this when calling Lua */
#include <lauxlib.h>                            /* Always include this when calling Lua */
#include <lualib.h>                             /* Prototype for luaL_openlibs(), */
/*   always include this when calling Lua */

#include <stdlib.h>                             /* For function exit() */
#include <stdio.h>                              /* For input/output */

void bail(lua_State *L, char *msg)
{
    fprintf(stderr, "\nFATAL ERROR:\n  %s: %s\n\n",
            msg, lua_tostring(L, -1));
    exit(1);
}

int main(void)
{
    lua_State *L;

    static struct {
        const char * name;
        int type;
    } fields[] = {
        {"port", LUA_TNUMBER},
        {"address", LUA_TSTRING},
        {"userdata", LUA_TSTRING},
        {NULL, 0}
    };

    L = luaL_newstate();                        /* Create Lua state variable */
    luaL_openlibs(L);                           /* Load Lua libraries */

    if (luaL_loadfile(L, "cfg.lua")) 
        bail(L, "luaL_loadfile() failed");

    if (lua_pcall(L, 0, 0, 0))           
        bail(L, "lua_pcall() failed");

    lua_getglobal(L, "listen");
    luaL_checktype(L, -1, LUA_TTABLE);

    int i;
    for (i = 1; ; i++) {
        lua_rawgeti(L, -1, i);
        if (lua_isnil(L, -1)) {
            lua_pop(L, 1);
            break;
        }
        // an element of the 'listen' table should now be at the top of the stack
        luaL_checktype(L, -1, LUA_TTABLE);
        // read the content of that element
        int field_index;
        for (field_index = 0; (fields[field_index].name != NULL 
                    && fields[field_index].name != NULL); field_index++) {

            lua_getfield(L, -1, fields[field_index].name);
            luaL_checktype(L, -1, fields[field_index].type);
            // you should probably use a function pointer in the fields table.
            // I am using a simple switch/case here
            switch(field_index) {
                case 0:
                    printf("port: %d\n", (int)lua_tonumber(L, -1));
                    // do what you want with port
                    break;
                case 1:
                    printf("address: %s\n", lua_tostring(L, -1));
                    break;
                case 2:
                    // handle userdata
                    printf("userdata: %s\n", lua_tostring(L, -1));
                    break;
            }
            // remove the field value from the top of the stack
            lua_pop(L, 1); 
        }
        // remove the element of the 'listen' table from the top of the stack.
        lua_pop(L, 1);
    }

    lua_close(L);

    return 0;
}

person liunx    schedule 20.11.2014    source источник


Ответы (1)


Вы не слишком далеко. Ключевым моментом здесь является понимание того, как API Lua использует стек для всего.

Вот непроверенный пример кода, который должен помочь вам:

// this will be used to validate our table
static struct {
    const char * name;
    int type;
} fields[] = {
    {"port", LUA_TNUMBER},
    {"address", LUA_TSTRING},
    {"userdata", LUA_TSTRING},
    NULL
};

lua_getglobal(L, "listen");

// the 'listen' table should be at the top of the stack
luaL_checktype(L, -1, LUA_TTABLE);

// iterate the listen table
int i;
for (i = 1; ; i++) {
    lua_rawgeti(L, -1, i);
    // when you get nil, you're done
    if (lua_isnil(L, -1)) {
        lua_pop(L,1);
        break;
    }
    // an element of the 'listen' table should now be at the top of the stack
    luaL_checktype(L, -1, LUA_TTABLE);
    // read the content of that element
    int field_index;
    for (field_index = 0; fields[field_index] != NULL; field_index++) {
        lua_getfield(L, -1, fields[field_index].name);
        luaL_checktype(L, -1, fields[field_index].type);
        // you should probably use a function pointer in the fields table.
        // I am using a simple switch/case here
        switch(field_index) {
        case 0:
            port = lua_tonumber(L, -1);
            // do what you want with port
            break;
        case 1:
            address = lua_tostring(L, -1);
            break;
        case 2:
            // handle userdata
            break;
        }
        // remove the field value from the top of the stack
        lua_pop(L, 1); 
    }
    // remove the element of the 'listen' table from the top of the stack.
    lua_pop(L, 1);
}

Я предлагаю вам использовать эти документы: таблица Lua API ссылка на Lua API

person Gilles Gregoire    schedule 20.11.2014