Suge
Suge

Reputation: 2897

How to get the complicated arguments of a Lua function in C language?

My Lua functions will call the C functions, one of which is very complicated as below, how can I get all the arguments in C? The argument colors is an array of {color, x, y} struct type elements, and it has uncertain number count.the argument region is a {x, y, width, height} struct type.

/* the function in Lua:
    findColors {
        colors={{#FFFFFF,0.0,0.0}, 
                {#EEEEEE,30.0,30.0}, 
                {#DDDDDD,20.0,40.0}},
        count=1, 
        region={10, 20, 100, 200}
     }
*/


typedef struct {
    int color;
    int x;
    int y;
} pixel_t;

static int findColorsProxy(lua_State *L)
{
    lua_settop(L, 1);
    luaL_checktype(L, 1, LUA_TTABLE);

    lua_getfield(L, 1, "colors");
    lua_getfield(L, 1, "count");
    lua_getfield(L, 1, "region");

    int colors_count = (int)lua_rawlen(L, -3);
    if (colors_count == 0) return 0;

    pixel_t *ps = NULL;
    for (int i = 0; i < colors_count; lua_pop(L, 1))
    {
        pixel_t *p_new = (pixel_t *)realloc(ret, sizeof(pixel_t));
        if (p_new == NULL) {
            if (ps != NULL) free(ps);
            return 0;
        }


        lua_rawgeti(L, 4, ++i);

        ... // I don't know what should I do next to get the pixels.
    }


    int count = (int)luaL_optinteger(L, -2, 0);

    int region_args_count  = (int)lua_rawlen(L, -1);
    if (region_args_count != 0 && region_args_count != 4) return 0;

    region_t rg;
    memset(&rg, 0, sizeof(region_t));
    for (int i = 0; i < region_args_count; lua_pop(L, 1))
    {
        lua_rawgeti(L, 4, ++i);
        int c = (int)luaL_checkinteger(L, -1);

        switch (i-1) {
            case 0:
                rg.x = c;
            case 1:
                rg.y = c;
            case 2:
                rg.width = c;
            case 3:
                rg.height = c;
        }
    }

    lua_pop(L, 3);

    ......
}

Upvotes: 2

Views: 536

Answers (1)

greatwolf
greatwolf

Reputation: 20838

What I would do is break off the processing logic for pixel_t from lua table into a separate function. This will make the code more palatable and easier to reason about. Something like lua_topixel_t following lua's C api signature convention:

bool lua_topixel_t(lua_State *L, int t, pixel *p)
{
  if (lua_type(L, t) != LUA_TTABLE) return false;
  if (!p) return false;

  int i = 0;
  lua_rawgeti(L, t, ++i);
  p->color = lua_tointeger(L, -1);
  lua_rawgeti(L, t, ++i);
  p->x = lua_tointeger(L, -1);
  lua_rawgeti(L, t, ++i);
  p->y = lua_tointeger(L, -1);

  lua_pop(L, i);
  return true;
}

Now it's just a matter of using it in your findColorsProxy:

pixel_t *ps = (pixel_t *) malloc(sizeof(pixel_t) * colors_count);
for (int i = 0; i < colors_count; lua_pop(L, 1))
{
  // ..., -3 = colors, count, region
  lua_rawgeti(L, -3, ++i);
  // ..., colors, count, region, -1 = color[i]
  if (!lua_topixel_t(L, -1, &ps[i - 1]))
  {
    free(ps); return 0;
  }
}
// ...

Note, I'm not sure how you're representing the rgb color from the lua side so here I just assumed it's a whole number. If the representation is different, like a lua string for example, modify lua_topixel_t as appropriate.

Upvotes: 2

Related Questions