lua-users home
lua-l archive

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


It was thus said that the Great Jeff Smith once stated:

> Thanks for the suggestion, but I am already using SWIG in the embedded
> project I am working on. I chose Swig as it had the advantage of not having
> any Windows dependencies, so it was pretty easy to use in an embedded
> environment. I have found it has some limitations, for example as far as I
> can see it cannot really handle arrays of data, hence my question here.
> 
> Besides, I wanted to gain an understanding of the Lua C API, so I was happy
> to go with a hybrid approach, SWIG for some bindings and manuallly written
> binding code for some of the things that SWIG didnt handle. So far its
> working out well, and its easy to mix and match SWIG bound code and manual
> code.
> 
> I just need to figure out this userdata stuff as it is obviously pretty
> important in getting a good handle on understanding the Lua/C API. Pity I
> dont think I can use the light userdata as I now understand that
> sufficiently.  I wonder if anyone has got time to post a full user data
> example to contrast with the light userdata example earlier in this thread ?
> I am sure it would help other folks in the future apart from just me !

  I just whipped this up.  There are two different userdata objects created,
one that uses strings for indicies, and another one that uses numeric
indicies.  They don't have to be separate objects, I just did it that way to
keep things easy.  So first, the code:


#include <string.h>

#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

#define MAX_BAR 	10
#define FOO_TYPE	"FOO"
#define BAR_TYPE	"BAR"

/******************************************************************/

struct bar
{
  int data[MAX_BAR];
};

struct foo
{
  int   x;
  int   y;
  int   z;
  int   xyzzy;
  char *blah;
};

/******************************************************************/

static int foolua___index(lua_State *L)
{
  struct foo *pfoo;
  const char *idx;
  
  pfoo = luaL_checkudata(L,1,FOO_TYPE);
  if (lua_isstring(L,2))
  {
    idx = lua_tostring(L,2);
    if (strcmp(idx,"x") == 0)
      lua_pushinteger(L,pfoo->x);
    else if (strcmp(idx,"y") == 0)
      lua_pushinteger(L,pfoo->y);
    else if (strcmp(idx,"z") == 0)
      lua_pushinteger(L,pfoo->z);
    else if (strcmp(idx,"xyzzy") == 0)
      lua_pushinteger(L,pfoo->xyzzy);
    else if (strcmp(idx,"confuse a cat") == 0)
      lua_pushstring(L,pfoo->blah);
    else
      lua_pushnil(L);
  }
  else
    lua_pushnil(L);
  
  return 1;
}

/******************************************************************/

static int foolua___newindex(lua_State *L)
{
  struct foo *pfoo;
  const char *idx;
  
  pfoo = luaL_checkudata(L,1,FOO_TYPE);
  
  if (lua_isstring(L,2))
  {
    idx = lua_tostring(L,2);
    if (strcmp(idx,"x") == 0)
      pfoo->x = luaL_checkint(L,3);
    else if (strcmp(idx,"y") == 0)
      pfoo->y = luaL_checkint(L,3);
    else if (strcmp(idx,"z") == 0)
      pfoo->z = luaL_checkint(L,3);
    else if (strcmp(idx,"xyzzy") == 0)
      pfoo->xyzzy = luaL_checkint(L,3);
    else if (strcmp(idx,"confuse a cat") == 0)
    {
      const char *val;
      size_t      vsize;
      
      free(pfoo->blah);	/* free(NULL) valid in C89 */
      val = luaL_checklstring(L,3,&vsize);
      vsize += 1;	/* include trailing NUL byte */
      pfoo->blah = malloc(vsize);
      if (pfoo->blah)
        memcpy(pfoo->blah,val,vsize);
    }
  }
  return 0;
}

/******************************************************************/

static int foolua___gc(lua_State *L)
{
  struct foo *pfoo;
  
  pfoo = luaL_checkudata(L,1,FOO_TYPE);
  free(pfoo->blah);
  pfoo->blah = NULL;
  return 0;
}

/******************************************************************/

static int foolua_new(lua_State *L)
{
  struct foo *pfoo;
  
  pfoo = lua_newuserdata(L,sizeof(struct foo));
  memset(pfoo,0,sizeof(struct foo));
  pfoo->blah = NULL;	/* required---too long to describe why */
  luaL_getmetatable(L,FOO_TYPE);
  lua_setmetatable(L,-2);
  return 1;
}

/******************************************************************/

static int barlua___index(lua_State *L)
{
  struct bar *pbar;
  int         idx;
  
  pbar = luaL_checkudata(L,1,BAR_TYPE);
  if (lua_isnumber(L,2))
  {
    idx = lua_tointeger(L,2) - 1;
    if (idx > MAX_BAR)
      lua_pushnil(L);
    else
      lua_pushinteger(L,pbar->data[idx]);
  }
  else
    lua_pushnil(L);
    
  return 1;
}

/******************************************************************/

static int barlua___newindex(lua_State *L)
{
  struct bar *pbar;
  int         idx;
  int         val;
  
  pbar = luaL_checkudata(L,1,BAR_TYPE);
  val  = luaL_checkint(L,3);
  
  if (lua_isnumber(L,2))
  {
    idx = lua_tointeger(L,2) - 1;
    if (idx < MAX_BAR)
      pbar->data[idx] = val;
  }
  
  return 0;
}

/******************************************************************/

static int barlua___len(lua_State *L)
{
  struct bar *pbar;
  
  pbar = luaL_checkudata(L,1,BAR_TYPE);
  lua_pushinteger(L,MAX_BAR);
  return 1;
}

/******************************************************************/

static int barlua_new(lua_State *L)
{
  struct bar *pbar;
  
  pbar = lua_newuserdata(L,sizeof(struct bar));
  memset(pbar,0,sizeof(struct bar));
  luaL_getmetatable(L,BAR_TYPE);
  lua_setmetatable(L,-2);
  return 1;
}

/******************************************************************/

static const luaL_Reg m_foobarreg[] =
{
  { "new_foo"		, foolua_new		} ,
  { "new_bar"		, barlua_new		} ,
  { NULL		, NULL			}
};

static const luaL_Reg m_foometareg[] =
{
  { "__index"		, foolua___index	} ,
  { "__newindex"	, foolua___newindex	} ,
  { "__gc"		, foolua___gc		} ,
  { NULL		, NULL			}
};

static const luaL_Reg m_barmetareg[] =
{
  { "__index"		, barlua___index	} ,
  { "__newindex"	, barlua___newindex	} ,
  { "__len"		, barlua___len		} ,
  { NULL		, NULL			}
};

int luaopen_foobar(lua_State *L)
{
  luaL_newmetatable(L,FOO_TYPE);
  luaL_register(L,NULL,m_foometareg);
  luaL_newmetatable(L,BAR_TYPE);
  luaL_register(L,NULL,m_barmetareg);
  luaL_register(L,"foobar",m_foobarreg);
  return 1;
}

/********************************************************************/

  The Lua code here manages the memory for the objects---it doesn't have to
and the changes are rather minimal (basically, have Lua manage pointers to
the pre-defined structures).  Both objects support the Lua __index() and
__newindex() methods, and I have an example of both __gc() and __len()
metamethods.  Here's a sample run:

[spc]lucy:~/source/lua/C>lua
Lua 5.1.4  Copyright (C) 1994-2008 Lua.org, PUC-Rio
> require "foobar"
> x = foobar.new_foo()
> x.x = 4
> x.xyzzy = 5
> x['confuse a cat'] = "hello"
> print(x.x,x.xyzzy,x['confuse a cat'])
4       5       hello
> 

  -spc (Hope this clears up some issues)