Logo Search packages:      
Sourcecode: ocropus version File versions  Download package

tolua_map.c

/* tolua: functions to map features
** Support code for Lua bindings.
** Written by Waldemar Celes
** TeCGraf/PUC-Rio
** Apr 2003
** $Id: $
*/

/* This code is free software; you can redistribute it and/or modify it.
** The software provided hereunder is on an "as is" basis, and
** the author has no obligation to provide maintenance, support, updates,
** enhancements, or modifications.
*/

#include "tolua++.h"
#include "tolua_event.h"
#include "lauxlib.h"

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>


/* Create metatable
      * Create and register new metatable
*/
static int tolua_newmetatable (lua_State* L, char* name)
{
      int r = luaL_newmetatable(L,name);

      #ifdef LUA_VERSION_NUM /* only lua 5.1 */
      if (r) {
            lua_pushvalue(L, -1);
            lua_pushstring(L, name);
            lua_settable(L, LUA_REGISTRYINDEX); /* reg[mt] = type_name */
      };
      #endif

      if (r)
            tolua_classevents(L); /* set meta events */
      lua_pop(L,1);
      return r;
}

/* Map super classes
      * It sets 'name' as being also a 'base', mapping all super classes of 'base' in 'name'
*/
static void mapsuper (lua_State* L, const char* name, const char* base)
{
      /* push registry.super */
 lua_pushstring(L,"tolua_super");
 lua_rawget(L,LUA_REGISTRYINDEX);    /* stack: super */
      luaL_getmetatable(L,name);          /* stack: super mt */
 lua_rawget(L,-2);                   /* stack: super table */
      if (lua_isnil(L,-1))
      {
       /* create table */
            lua_pop(L,1);
       lua_newtable(L);                    /* stack: super table */
       luaL_getmetatable(L,name);          /* stack: super table mt */
            lua_pushvalue(L,-2);                /* stack: super table mt table */
            lua_rawset(L,-4);                   /* stack: super table */
      }

      /* set base as super class */
      lua_pushstring(L,base);
      lua_pushboolean(L,1);
      lua_rawset(L,-3);                    /* stack: super table */

      /* set all super class of base as super class of name */
      luaL_getmetatable(L,base);          /* stack: super table base_mt */
      lua_rawget(L,-3);                   /* stack: super table base_table */
      if (lua_istable(L,-1))
      {
            /* traverse base table */
            lua_pushnil(L);  /* first key */
            while (lua_next(L,-2) != 0)
            {
                  /* stack: ... base_table key value */
                  lua_pushvalue(L,-2);    /* stack: ... base_table key value key */
                  lua_insert(L,-2);       /* stack: ... base_table key key value */
                  lua_rawset(L,-5);       /* stack: ... base_table key */
            }
      }
      lua_pop(L,3);                       /* stack: <empty> */
}

/* creates a 'tolua_ubox' table for base clases, and
// expects the metatable and base metatable on the stack */
static void set_ubox(lua_State* L) {

      /* mt basemt */
      if (!lua_isnil(L, -1)) {
            lua_pushstring(L, "tolua_ubox");
            lua_rawget(L,-2);
      } else {
            lua_pushnil(L);
      };
      /* mt basemt base_ubox */
      if (!lua_isnil(L,-1)) {
            lua_pushstring(L, "tolua_ubox");
            lua_insert(L, -2);
            /* mt basemt key ubox */
            lua_rawset(L,-4);
            /* (mt with ubox) basemt */
      } else {
            /* mt basemt nil */
            lua_pop(L, 1);
            lua_pushstring(L,"tolua_ubox"); lua_newtable(L);
            /* make weak value metatable for ubox table to allow userdata to be
            garbage-collected */
            lua_newtable(L); lua_pushliteral(L, "__mode"); lua_pushliteral(L, "v"); lua_rawset(L, -3);               /* stack: string ubox mt */
            lua_setmetatable(L, -2);  /* stack:mt basemt string ubox */
            lua_rawset(L,-4);
      };

};

/* Map inheritance
      * It sets 'name' as derived from 'base' by setting 'base' as metatable of 'name'
*/
static void mapinheritance (lua_State* L, const char* name, const char* base)
{
      /* set metatable inheritance */
      luaL_getmetatable(L,name);

      if (base && *base)
            luaL_getmetatable(L,base);
      else {

            if (lua_getmetatable(L, -1)) { /* already has a mt, we don't overwrite it */
                  lua_pop(L, 2);
                  return;
            };
            luaL_getmetatable(L,"tolua_commonclass");
      };

      set_ubox(L);

      lua_setmetatable(L,-2);
      lua_pop(L,1);
}

/* Object type
*/
static int tolua_bnd_type (lua_State* L)
{
      tolua_typename(L,lua_gettop(L));
      return 1;
}

/* Take ownership
*/
static int tolua_bnd_takeownership (lua_State* L)
{
      int success = 0;
      if (lua_isuserdata(L,1))
      {
            if (lua_getmetatable(L,1))        /* if metatable? */
            {
                  lua_pop(L,1);             /* clear metatable off stack */
                  /* force garbage collection to avoid C to reuse a to-be-collected address */
                  #ifdef LUA_VERSION_NUM
                  lua_gc(L, LUA_GCCOLLECT, 0);
                  #else
                  lua_setgcthreshold(L,0);
                  #endif

                  success = tolua_register_gc(L,1);
            }
      }
      lua_pushboolean(L,success!=0);
      return 1;
}

/* Release ownership
*/
static int tolua_bnd_releaseownership (lua_State* L)
{
      int done = 0;
      if (lua_isuserdata(L,1))
      {
            void* u = *((void**)lua_touserdata(L,1));
            /* force garbage collection to avoid releasing a to-be-collected address */
            #ifdef LUA_VERSION_NUM
            lua_gc(L, LUA_GCCOLLECT, 0);
            #else
            lua_setgcthreshold(L,0);
            #endif
            lua_pushstring(L,"tolua_gc");
            lua_rawget(L,LUA_REGISTRYINDEX);
            lua_pushlightuserdata(L,u);
            lua_rawget(L,-2);
            lua_getmetatable(L,1);
            if (lua_rawequal(L,-1,-2))  /* check that we are releasing the correct type */
            {
                  lua_pushlightuserdata(L,u);
                  lua_pushnil(L);
                  lua_rawset(L,-5);
                  done = 1;
            }
      }
      lua_pushboolean(L,done!=0);
      return 1;
}

/* Type casting
*/
static int tolua_bnd_cast (lua_State* L)
{

/* // old code
        void* v = tolua_tousertype(L,1,NULL);
        const char* s = tolua_tostring(L,2,NULL);
        if (v && s)
         tolua_pushusertype(L,v,s);
        else
         lua_pushnil(L);
        return 1;
*/

      void* v;
      const char* s;
      if (lua_islightuserdata(L, 1)) {
            v = tolua_touserdata(L, 1, NULL);
      } else {
            v = tolua_tousertype(L, 1, 0);
      };

      s = tolua_tostring(L,2,NULL);
      if (v && s)
       tolua_pushusertype(L,v,s);
      else
       lua_pushnil(L);
      return 1;
}

/* Inheritance
*/
static int tolua_bnd_inherit (lua_State* L) {

      /* stack: lua object, c object */
      lua_pushstring(L, ".c_instance");
      lua_pushvalue(L, -2);
      lua_rawset(L, -4);
      /* l_obj[".c_instance"] = c_obj */

      return 0;
};

#ifdef LUA_VERSION_NUM /* lua 5.1 */
static int tolua_bnd_setpeer(lua_State* L) {

      /* stack: userdata, table */
      if (!lua_isuserdata(L, -2)) {
            lua_pushstring(L, "Invalid argument #1 to setpeer: userdata expected.");
            lua_error(L);
      };
      
      if (lua_isnil(L, -1)) {

            lua_pop(L, 1);
            lua_pushvalue(L, TOLUA_NOPEER);
      };
      lua_setfenv(L, -2);

      return 0;
};

static int tolua_bnd_getpeer(lua_State* L) {

      /* stack: userdata */
      lua_getfenv(L, -1);
      if (lua_rawequal(L, -1, TOLUA_NOPEER)) {
            lua_pop(L, 1);
            lua_pushnil(L);
      };
      return 1;
};
#endif

/* static int class_gc_event (lua_State* L); */

TOLUA_API void tolua_open (lua_State* L)
{
 int top = lua_gettop(L);
 lua_pushstring(L,"tolua_opened");
 lua_rawget(L,LUA_REGISTRYINDEX);
 if (!lua_isboolean(L,-1))
 {
  lua_pushstring(L,"tolua_opened"); lua_pushboolean(L,1); lua_rawset(L,LUA_REGISTRYINDEX);

  #ifndef LUA_VERSION_NUM /* only prior to lua 5.1 */
  /* create peer object table */
  lua_pushstring(L, "tolua_peers"); lua_newtable(L);
  /* make weak key metatable for peers indexed by userdata object */
  lua_newtable(L); lua_pushliteral(L, "__mode"); lua_pushliteral(L, "k"); lua_rawset(L, -3);                /* stack: string peers mt */
  lua_setmetatable(L, -2);   /* stack: string peers */
  lua_rawset(L,LUA_REGISTRYINDEX);
  #endif

  /* create object ptr -> udata mapping table */
  lua_pushstring(L,"tolua_ubox"); lua_newtable(L);
  /* make weak value metatable for ubox table to allow userdata to be
     garbage-collected */
  lua_newtable(L); lua_pushliteral(L, "__mode"); lua_pushliteral(L, "v"); lua_rawset(L, -3);               /* stack: string ubox mt */
  lua_setmetatable(L, -2);  /* stack: string ubox */
  lua_rawset(L,LUA_REGISTRYINDEX);

  lua_pushstring(L,"tolua_super"); lua_newtable(L); lua_rawset(L,LUA_REGISTRYINDEX);
  lua_pushstring(L,"tolua_gc"); lua_newtable(L);lua_rawset(L,LUA_REGISTRYINDEX);

  /* create gc_event closure */
  lua_pushstring(L, "tolua_gc_event");
  lua_pushstring(L, "tolua_gc");
  lua_rawget(L, LUA_REGISTRYINDEX);
  lua_pushstring(L, "tolua_super");
  lua_rawget(L, LUA_REGISTRYINDEX);
  lua_pushcclosure(L, class_gc_event, 2);
  lua_rawset(L, LUA_REGISTRYINDEX);

  tolua_newmetatable(L,"tolua_commonclass");

  tolua_module(L,NULL,0);
  tolua_beginmodule(L,NULL);
  tolua_module(L,"tolua",0);
  tolua_beginmodule(L,"tolua");
  tolua_function(L,"type",tolua_bnd_type);
  tolua_function(L,"takeownership",tolua_bnd_takeownership);
  tolua_function(L,"releaseownership",tolua_bnd_releaseownership);
  tolua_function(L,"cast",tolua_bnd_cast);
  tolua_function(L,"inherit", tolua_bnd_inherit);
  #ifdef LUA_VERSION_NUM /* lua 5.1 */
  tolua_function(L, "setpeer", tolua_bnd_setpeer);
  tolua_function(L, "getpeer", tolua_bnd_getpeer);
  #endif

  tolua_endmodule(L);
  tolua_endmodule(L);
 }
 lua_settop(L,top);
}

/* Copy a C object
*/
TOLUA_API void* tolua_copy (lua_State* L, void* value, unsigned int size)
{
      void* clone = (void*)malloc(size);
      if (clone)
       memcpy(clone,value,size);
      else
            tolua_error(L,"insuficient memory",NULL);
      return clone;
}

/* Default collect function
*/
TOLUA_API int tolua_default_collect (lua_State* tolua_S)
{
 void* self = tolua_tousertype(tolua_S,1,0);
 free(self);
 return 0;
}

/* Do clone
*/
TOLUA_API int tolua_register_gc (lua_State* L, int lo)
{
 int success = 1;
 void *value = *(void **)lua_touserdata(L,lo);
 lua_pushstring(L,"tolua_gc");
 lua_rawget(L,LUA_REGISTRYINDEX);
      lua_pushlightuserdata(L,value);
      lua_rawget(L,-2);
      if (!lua_isnil(L,-1)) /* make sure that object is not already owned */
            success = 0;
      else
      {
            lua_pushlightuserdata(L,value);
            lua_getmetatable(L,lo);
            lua_rawset(L,-4);
      }
      lua_pop(L,2);
      return success;
}

/* Register a usertype
      * It creates the correspoding metatable in the registry, for both 'type' and 'const type'.
      * It maps 'const type' as being also a 'type'
*/
TOLUA_API void tolua_usertype (lua_State* L, char* type)
{
 char ctype[128] = "const ";
 strncat(ctype,type,120);

      /* create both metatables */
 if (tolua_newmetatable(L,ctype) && tolua_newmetatable(L,type))
       mapsuper(L,type,ctype);             /* 'type' is also a 'const type' */
}


/* Begin module
      * It pushes the module (or class) table on the stack
*/
TOLUA_API void tolua_beginmodule (lua_State* L, char* name)
{
      if (name)
      {
       lua_pushstring(L,name);
            lua_rawget(L,-2);
      }
      else
       lua_pushvalue(L,LUA_GLOBALSINDEX);
}

/* End module
      * It pops the module (or class) from the stack
*/
TOLUA_API void tolua_endmodule (lua_State* L)
{
      lua_pop(L,1);
}

/* Map module
      * It creates a new module
*/
#if 1
TOLUA_API void tolua_module (lua_State* L, char* name, int hasvar)
{
      if (name)
      {
            /* tolua module */
            lua_pushstring(L,name);
            lua_rawget(L,-2);
            if (!lua_istable(L,-1))  /* check if module already exists */
            {
                  lua_pop(L,1);
             lua_newtable(L);
             lua_pushstring(L,name);
                  lua_pushvalue(L,-2);
             lua_rawset(L,-4);       /* assing module into module */
            }
      }
      else
      {
            /* global table */
            lua_pushvalue(L,LUA_GLOBALSINDEX);
      }
      if (hasvar)
      {
            if (!tolua_ismodulemetatable(L))  /* check if it already has a module metatable */
            {
                  /* create metatable to get/set C/C++ variable */
                  lua_newtable(L);
                  tolua_moduleevents(L);
                  if (lua_getmetatable(L,-2))
                        lua_setmetatable(L,-2);  /* set old metatable as metatable of metatable */
                  lua_setmetatable(L,-2);
            }
      }
      lua_pop(L,1);               /* pop module */
}
#else
TOLUA_API void tolua_module (lua_State* L, char* name, int hasvar)
{
      if (name)
      {
            /* tolua module */
            lua_pushstring(L,name);
            lua_newtable(L);
      }
      else
      {
            /* global table */
            lua_pushvalue(L,LUA_GLOBALSINDEX);
      }
      if (hasvar)
      {
            /* create metatable to get/set C/C++ variable */
            lua_newtable(L);
            tolua_moduleevents(L);
            if (lua_getmetatable(L,-2))
                  lua_setmetatable(L,-2);  /* set old metatable as metatable of metatable */
            lua_setmetatable(L,-2);
      }
      if (name)
            lua_rawset(L,-3);       /* assing module into module */
      else
            lua_pop(L,1);           /* pop global table */
}
#endif

static void push_collector(lua_State* L, const char* type, lua_CFunction col) {

      /* push collector function, but only if it's not NULL, or if there's no
         collector already */
      if (!col) return;
      luaL_getmetatable(L,type);
      lua_pushstring(L,".collector");
      /*
      if (!col) {
            lua_pushvalue(L, -1);
            lua_rawget(L, -3);
            if (!lua_isnil(L, -1)) {
                  lua_pop(L, 3);
                  return;
            };
            lua_pop(L, 1);
      };
      //    */
      lua_pushcfunction(L,col);

      lua_rawset(L,-3);
      lua_pop(L, 1);
};

/* Map C class
      * It maps a C class, setting the appropriate inheritance and super classes.
*/
TOLUA_API void tolua_cclass (lua_State* L, char* lname, char* name, char* base, lua_CFunction col)
{
      char cname[128] = "const ";
      char cbase[128] = "const ";
      strncat(cname,name,120);
      strncat(cbase,base,120);

      mapinheritance(L,name,base);
      mapinheritance(L,cname,name);

      mapsuper(L,cname,cbase);
      mapsuper(L,name,base);

      lua_pushstring(L,lname);
      
      push_collector(L, name, col);
      /*
      luaL_getmetatable(L,name);
      lua_pushstring(L,".collector");
      lua_pushcfunction(L,col);

      lua_rawset(L,-3);
      */
      
      luaL_getmetatable(L,name);
      lua_rawset(L,-3);              /* assign class metatable to module */

      /* now we also need to store the collector table for the const
         instances of the class */
      push_collector(L, cname, col);
      /*
      luaL_getmetatable(L,cname);
      lua_pushstring(L,".collector");
      lua_pushcfunction(L,col);
      lua_rawset(L,-3);
      lua_pop(L,1);
      */
      

}

/* Add base
      * It adds additional base classes to a class (for multiple inheritance)
      * (not for now)
TOLUA_API void tolua_addbase(lua_State* L, char* name, char* base) {

      char cname[128] = "const ";
      char cbase[128] = "const ";
      strncat(cname,name,120);
      strncat(cbase,base,120);

      mapsuper(L,cname,cbase);
      mapsuper(L,name,base);
};
*/

/* Map function
      * It assigns a function into the current module (or class)
*/
TOLUA_API void tolua_function (lua_State* L, char* name, lua_CFunction func)
{
 lua_pushstring(L,name);
 lua_pushcfunction(L,func);
      lua_rawset(L,-3);
}

/* sets the __call event for the class (expects the class' main table on top) */
/*    never really worked :(
TOLUA_API void tolua_set_call_event(lua_State* L, lua_CFunction func, char* type) {

      lua_getmetatable(L, -1);
      //luaL_getmetatable(L, type);
      lua_pushstring(L,"__call");
      lua_pushcfunction(L,func);
      lua_rawset(L,-3);
      lua_pop(L, 1);
};
*/

/* Map constant number
      * It assigns a constant number into the current module (or class)
*/
TOLUA_API void tolua_constant (lua_State* L, char* name, double value)
{
      lua_pushstring(L,name);
      tolua_pushnumber(L,value);
      lua_rawset(L,-3);
}


/* Map variable
      * It assigns a variable into the current module (or class)
*/
TOLUA_API void tolua_variable (lua_State* L, char* name, lua_CFunction get, lua_CFunction set)
{
      /* get func */
      lua_pushstring(L,".get");
      lua_rawget(L,-2);
      if (!lua_istable(L,-1))
      {
            /* create .get table, leaving it at the top */
            lua_pop(L,1);
            lua_newtable(L);
       lua_pushstring(L,".get");
            lua_pushvalue(L,-2);
            lua_rawset(L,-4);
      }
      lua_pushstring(L,name);
      lua_pushcfunction(L,get);
 lua_rawset(L,-3);                  /* store variable */
      lua_pop(L,1);                      /* pop .get table */

      /* set func */
      if (set)
      {
            lua_pushstring(L,".set");
            lua_rawget(L,-2);
            if (!lua_istable(L,-1))
            {
                  /* create .set table, leaving it at the top */
                  lua_pop(L,1);
                  lua_newtable(L);
                  lua_pushstring(L,".set");
                  lua_pushvalue(L,-2);
                  lua_rawset(L,-4);
            }
            lua_pushstring(L,name);
            lua_pushcfunction(L,set);
            lua_rawset(L,-3);                  /* store variable */
            lua_pop(L,1);                      /* pop .set table */
      }
}

/* Access const array
      * It reports an error when trying to write into a const array
*/
static int const_array (lua_State* L)
{
 luaL_error(L,"value of const array cannot be changed");
 return 0;
}

/* Map an array
      * It assigns an array into the current module (or class)
*/
TOLUA_API void tolua_array (lua_State* L, char* name, lua_CFunction get, lua_CFunction set)
{
      lua_pushstring(L,".get");
      lua_rawget(L,-2);
      if (!lua_istable(L,-1))
      {
            /* create .get table, leaving it at the top */
            lua_pop(L,1);
            lua_newtable(L);
       lua_pushstring(L,".get");
            lua_pushvalue(L,-2);
            lua_rawset(L,-4);
      }
      lua_pushstring(L,name);

 lua_newtable(L);           /* create array metatable */
 lua_pushvalue(L,-1);
      lua_setmetatable(L,-2);    /* set the own table as metatable (for modules) */
 lua_pushstring(L,"__index");
 lua_pushcfunction(L,get);
      lua_rawset(L,-3);
 lua_pushstring(L,"__newindex");
 lua_pushcfunction(L,set?set:const_array);
      lua_rawset(L,-3);

 lua_rawset(L,-3);                  /* store variable */
      lua_pop(L,1);                      /* pop .get table */
}


TOLUA_API void tolua_dobuffer(lua_State* L, char* B, unsigned int size, const char* name) {

 #ifdef LUA_VERSION_NUM /* lua 5.1 */
 luaL_loadbuffer(L, B, size, name) || lua_pcall(L, 0, 0, 0);
 #else
 lua_dobuffer(L, B, size, name);
 #endif
};


Generated by  Doxygen 1.6.0   Back to index