1 /* tolua: functions to map features
2 ** Support code for Lua bindings.
3 ** Written by Waldemar Celes
9 /* This code is free software; you can redistribute it and/or modify it.
10 ** The software provided hereunder is on an "as is" basis, and
11 ** the author has no obligation to provide maintenance, support, updates,
12 ** enhancements, or modifications.
16 #include "tolua_event.h"
26 * Create and register new metatable
28 static int tolua_newmetatable (lua_State* L, char* name)
30 int r = luaL_newmetatable(L,name);
32 #ifdef LUA_VERSION_NUM /* only lua 5.1 */
35 lua_pushstring(L, name);
36 lua_settable(L, LUA_REGISTRYINDEX); /* reg[mt] = type_name */
41 tolua_classevents(L); /* set meta events */
47 * It sets 'name' as being also a 'base', mapping all super classes of 'base' in 'name'
49 static void mapsuper (lua_State* L, const char* name, const char* base)
51 /* push registry.super */
52 lua_pushstring(L,"tolua_super");
53 lua_rawget(L,LUA_REGISTRYINDEX); /* stack: super */
54 luaL_getmetatable(L,name); /* stack: super mt */
55 lua_rawget(L,-2); /* stack: super table */
60 lua_newtable(L); /* stack: super table */
61 luaL_getmetatable(L,name); /* stack: super table mt */
62 lua_pushvalue(L,-2); /* stack: super table mt table */
63 lua_rawset(L,-4); /* stack: super table */
66 /* set base as super class */
67 lua_pushstring(L,base);
69 lua_rawset(L,-3); /* stack: super table */
71 /* set all super class of base as super class of name */
72 luaL_getmetatable(L,base); /* stack: super table base_mt */
73 lua_rawget(L,-3); /* stack: super table base_table */
74 if (lua_istable(L,-1))
76 /* traverse base table */
77 lua_pushnil(L); /* first key */
78 while (lua_next(L,-2) != 0)
80 /* stack: ... base_table key value */
81 lua_pushvalue(L,-2); /* stack: ... base_table key value key */
82 lua_insert(L,-2); /* stack: ... base_table key key value */
83 lua_rawset(L,-5); /* stack: ... base_table key */
86 lua_pop(L,3); /* stack: <empty> */
89 /* creates a 'tolua_ubox' table for base clases, and
90 // expects the metatable and base metatable on the stack */
91 static void set_ubox(lua_State* L) {
94 if (!lua_isnil(L, -1)) {
95 lua_pushstring(L, "tolua_ubox");
100 /* mt basemt base_ubox */
101 if (!lua_isnil(L,-1)) {
102 lua_pushstring(L, "tolua_ubox");
104 /* mt basemt key ubox */
106 /* (mt with ubox) basemt */
110 lua_pushstring(L,"tolua_ubox"); lua_newtable(L);
111 /* make weak value metatable for ubox table to allow userdata to be
113 lua_newtable(L); lua_pushliteral(L, "__mode"); lua_pushliteral(L, "v"); lua_rawset(L, -3); /* stack: string ubox mt */
114 lua_setmetatable(L, -2); /* stack:mt basemt string ubox */
121 * It sets 'name' as derived from 'base' by setting 'base' as metatable of 'name'
123 static void mapinheritance (lua_State* L, const char* name, const char* base)
125 /* set metatable inheritance */
126 luaL_getmetatable(L,name);
129 luaL_getmetatable(L,base);
132 if (lua_getmetatable(L, -1)) { /* already has a mt, we don't overwrite it */
136 luaL_getmetatable(L,"tolua_commonclass");
141 lua_setmetatable(L,-2);
147 static int tolua_bnd_type (lua_State* L)
149 tolua_typename(L,lua_gettop(L));
155 static int tolua_bnd_takeownership (lua_State* L)
158 if (lua_isuserdata(L,1))
160 if (lua_getmetatable(L,1)) /* if metatable? */
162 lua_pop(L,1); /* clear metatable off stack */
163 /* force garbage collection to avoid C to reuse a to-be-collected address */
164 #ifdef LUA_VERSION_NUM
165 lua_gc(L, LUA_GCCOLLECT, 0);
167 lua_setgcthreshold(L,0);
170 success = tolua_register_gc(L,1);
173 lua_pushboolean(L,success!=0);
179 static int tolua_bnd_releaseownership (lua_State* L)
182 if (lua_isuserdata(L,1))
184 void* u = *((void**)lua_touserdata(L,1));
185 /* force garbage collection to avoid releasing a to-be-collected address */
186 #ifdef LUA_VERSION_NUM
187 lua_gc(L, LUA_GCCOLLECT, 0);
189 lua_setgcthreshold(L,0);
191 lua_pushstring(L,"tolua_gc");
192 lua_rawget(L,LUA_REGISTRYINDEX);
193 lua_pushlightuserdata(L,u);
195 lua_getmetatable(L,1);
196 if (lua_rawequal(L,-1,-2)) /* check that we are releasing the correct type */
198 lua_pushlightuserdata(L,u);
204 lua_pushboolean(L,done!=0);
210 static int tolua_bnd_cast (lua_State* L)
214 void* v = tolua_tousertype(L,1,NULL);
215 const char* s = tolua_tostring(L,2,NULL);
217 tolua_pushusertype(L,v,s);
225 if (lua_islightuserdata(L, 1)) {
226 v = tolua_touserdata(L, 1, NULL);
228 v = tolua_tousertype(L, 1, 0);
231 s = tolua_tostring(L,2,NULL);
233 tolua_pushusertype(L,v,s);
241 static int tolua_bnd_inherit (lua_State* L) {
243 /* stack: lua object, c object */
244 lua_pushstring(L, ".c_instance");
245 lua_pushvalue(L, -2);
247 /* l_obj[".c_instance"] = c_obj */
252 #ifdef LUA_VERSION_NUM /* lua 5.1 */
253 static int tolua_bnd_setpeer(lua_State* L) {
255 /* stack: userdata, table */
256 if (!lua_isuserdata(L, -2)) {
257 lua_pushstring(L, "Invalid argument #1 to setpeer: userdata expected.");
261 if (lua_isnil(L, -1)) {
264 lua_pushvalue(L, TOLUA_NOPEER);
271 static int tolua_bnd_getpeer(lua_State* L) {
273 /* stack: userdata */
275 if (lua_rawequal(L, -1, TOLUA_NOPEER)) {
283 /* static int class_gc_event (lua_State* L); */
285 TOLUA_API void tolua_open (lua_State* L)
287 int top = lua_gettop(L);
288 lua_pushstring(L,"tolua_opened");
289 lua_rawget(L,LUA_REGISTRYINDEX);
290 if (!lua_isboolean(L,-1))
292 lua_pushstring(L,"tolua_opened"); lua_pushboolean(L,1); lua_rawset(L,LUA_REGISTRYINDEX);
294 #ifndef LUA_VERSION_NUM /* only prior to lua 5.1 */
295 /* create peer object table */
296 lua_pushstring(L, "tolua_peers"); lua_newtable(L);
297 /* make weak key metatable for peers indexed by userdata object */
298 lua_newtable(L); lua_pushliteral(L, "__mode"); lua_pushliteral(L, "k"); lua_rawset(L, -3); /* stack: string peers mt */
299 lua_setmetatable(L, -2); /* stack: string peers */
300 lua_rawset(L,LUA_REGISTRYINDEX);
303 /* create object ptr -> udata mapping table */
304 lua_pushstring(L,"tolua_ubox"); lua_newtable(L);
305 /* make weak value metatable for ubox table to allow userdata to be
307 lua_newtable(L); lua_pushliteral(L, "__mode"); lua_pushliteral(L, "v"); lua_rawset(L, -3); /* stack: string ubox mt */
308 lua_setmetatable(L, -2); /* stack: string ubox */
309 lua_rawset(L,LUA_REGISTRYINDEX);
311 lua_pushstring(L,"tolua_super"); lua_newtable(L); lua_rawset(L,LUA_REGISTRYINDEX);
312 lua_pushstring(L,"tolua_gc"); lua_newtable(L);lua_rawset(L,LUA_REGISTRYINDEX);
314 /* create gc_event closure */
315 lua_pushstring(L, "tolua_gc_event");
316 lua_pushstring(L, "tolua_gc");
317 lua_rawget(L, LUA_REGISTRYINDEX);
318 lua_pushstring(L, "tolua_super");
319 lua_rawget(L, LUA_REGISTRYINDEX);
320 lua_pushcclosure(L, class_gc_event, 2);
321 lua_rawset(L, LUA_REGISTRYINDEX);
323 tolua_newmetatable(L,"tolua_commonclass");
325 tolua_module(L,NULL,0);
326 tolua_beginmodule(L,NULL);
327 tolua_module(L,"tolua",0);
328 tolua_beginmodule(L,"tolua");
329 tolua_function(L,"type",tolua_bnd_type);
330 tolua_function(L,"takeownership",tolua_bnd_takeownership);
331 tolua_function(L,"releaseownership",tolua_bnd_releaseownership);
332 tolua_function(L,"cast",tolua_bnd_cast);
333 tolua_function(L,"inherit", tolua_bnd_inherit);
334 #ifdef LUA_VERSION_NUM /* lua 5.1 */
335 tolua_function(L, "setpeer", tolua_bnd_setpeer);
336 tolua_function(L, "getpeer", tolua_bnd_getpeer);
347 TOLUA_API void* tolua_copy (lua_State* L, void* value, unsigned int size)
349 void* clone = (void*)malloc(size);
351 memcpy(clone,value,size);
353 tolua_error(L,"insuficient memory",NULL);
357 /* Default collect function
359 TOLUA_API int tolua_default_collect (lua_State* tolua_S)
361 void* self = tolua_tousertype(tolua_S,1,0);
368 TOLUA_API int tolua_register_gc (lua_State* L, int lo)
371 void *value = *(void **)lua_touserdata(L,lo);
372 lua_pushstring(L,"tolua_gc");
373 lua_rawget(L,LUA_REGISTRYINDEX);
374 lua_pushlightuserdata(L,value);
376 if (!lua_isnil(L,-1)) /* make sure that object is not already owned */
380 lua_pushlightuserdata(L,value);
381 lua_getmetatable(L,lo);
388 /* Register a usertype
389 * It creates the correspoding metatable in the registry, for both 'type' and 'const type'.
390 * It maps 'const type' as being also a 'type'
392 TOLUA_API void tolua_usertype (lua_State* L, const char* type)
394 char ctype[128] = "const ";
395 strncat(ctype,type,120);
397 /* create both metatables */
398 if (tolua_newmetatable(L,ctype) && tolua_newmetatable(L,type))
399 mapsuper(L,type,ctype); /* 'type' is also a 'const type' */
404 * It pushes the module (or class) table on the stack
406 TOLUA_API void tolua_beginmodule (lua_State* L, const char* name)
410 lua_pushstring(L,name);
414 lua_pushvalue(L,LUA_GLOBALSINDEX);
418 * It pops the module (or class) from the stack
420 TOLUA_API void tolua_endmodule (lua_State* L)
426 * It creates a new module
429 TOLUA_API void tolua_module (lua_State* L, const char* name, int hasvar)
434 lua_pushstring(L,name);
436 if (!lua_istable(L,-1)) /* check if module already exists */
440 lua_pushstring(L,name);
442 lua_rawset(L,-4); /* assing module into module */
448 lua_pushvalue(L,LUA_GLOBALSINDEX);
452 if (!tolua_ismodulemetatable(L)) /* check if it already has a module metatable */
454 /* create metatable to get/set C/C++ variable */
456 tolua_moduleevents(L);
457 if (lua_getmetatable(L,-2))
458 lua_setmetatable(L,-2); /* set old metatable as metatable of metatable */
459 lua_setmetatable(L,-2);
462 lua_pop(L,1); /* pop module */
465 TOLUA_API void tolua_module (lua_State* L, const char* name, int hasvar)
470 lua_pushstring(L,name);
476 lua_pushvalue(L,LUA_GLOBALSINDEX);
480 /* create metatable to get/set C/C++ variable */
482 tolua_moduleevents(L);
483 if (lua_getmetatable(L,-2))
484 lua_setmetatable(L,-2); /* set old metatable as metatable of metatable */
485 lua_setmetatable(L,-2);
488 lua_rawset(L,-3); /* assing module into module */
490 lua_pop(L,1); /* pop global table */
494 static void push_collector(lua_State* L, const char* type, lua_CFunction col) {
496 /* push collector function, but only if it's not NULL, or if there's no
499 luaL_getmetatable(L,type);
500 lua_pushstring(L,".collector");
503 lua_pushvalue(L, -1);
505 if (!lua_isnil(L, -1)) {
512 lua_pushcfunction(L,col);
519 * It maps a C class, setting the appropriate inheritance and super classes.
521 TOLUA_API void tolua_cclass (lua_State* L, const char* lname, const char* name, const char* base, lua_CFunction col)
523 char cname[128] = "const ";
524 char cbase[128] = "const ";
525 strncat(cname,name,120);
526 strncat(cbase,base,120);
528 mapinheritance(L,name,base);
529 mapinheritance(L,cname,name);
531 mapsuper(L,cname,cbase);
532 mapsuper(L,name,base);
534 lua_pushstring(L,lname);
536 push_collector(L, name, col);
538 luaL_getmetatable(L,name);
539 lua_pushstring(L,".collector");
540 lua_pushcfunction(L,col);
545 luaL_getmetatable(L,name);
546 lua_rawset(L,-3); /* assign class metatable to module */
548 /* now we also need to store the collector table for the const
549 instances of the class */
550 push_collector(L, cname, col);
552 luaL_getmetatable(L,cname);
553 lua_pushstring(L,".collector");
554 lua_pushcfunction(L,col);
563 * It adds additional base classes to a class (for multiple inheritance)
565 TOLUA_API void tolua_addbase(lua_State* L, char* name, char* base) {
567 char cname[128] = "const ";
568 char cbase[128] = "const ";
569 strncat(cname,name,120);
570 strncat(cbase,base,120);
572 mapsuper(L,cname,cbase);
573 mapsuper(L,name,base);
578 * It assigns a function into the current module (or class)
580 TOLUA_API void tolua_function (lua_State* L, const char* name, lua_CFunction func)
582 lua_pushstring(L,name);
583 lua_pushcfunction(L,func);
587 /* sets the __call event for the class (expects the class' main table on top) */
588 /* never really worked :(
589 TOLUA_API void tolua_set_call_event(lua_State* L, lua_CFunction func, char* type) {
591 lua_getmetatable(L, -1);
592 //luaL_getmetatable(L, type);
593 lua_pushstring(L,"__call");
594 lua_pushcfunction(L,func);
600 /* Map constant number
601 * It assigns a constant number into the current module (or class)
603 TOLUA_API void tolua_constant (lua_State* L, const char* name, lua_Number value)
605 lua_pushstring(L,name);
606 tolua_pushnumber(L,value);
612 * It assigns a variable into the current module (or class)
614 TOLUA_API void tolua_variable (lua_State* L, const char* name, lua_CFunction get, lua_CFunction set)
617 lua_pushstring(L,".get");
619 if (!lua_istable(L,-1))
621 /* create .get table, leaving it at the top */
624 lua_pushstring(L,".get");
628 lua_pushstring(L,name);
629 lua_pushcfunction(L,get);
630 lua_rawset(L,-3); /* store variable */
631 lua_pop(L,1); /* pop .get table */
636 lua_pushstring(L,".set");
638 if (!lua_istable(L,-1))
640 /* create .set table, leaving it at the top */
643 lua_pushstring(L,".set");
647 lua_pushstring(L,name);
648 lua_pushcfunction(L,set);
649 lua_rawset(L,-3); /* store variable */
650 lua_pop(L,1); /* pop .set table */
654 /* Access const array
655 * It reports an error when trying to write into a const array
657 static int const_array (lua_State* L)
659 luaL_error(L,"value of const array cannot be changed");
664 * It assigns an array into the current module (or class)
666 TOLUA_API void tolua_array (lua_State* L, const char* name, lua_CFunction get, lua_CFunction set)
668 lua_pushstring(L,".get");
670 if (!lua_istable(L,-1))
672 /* create .get table, leaving it at the top */
675 lua_pushstring(L,".get");
679 lua_pushstring(L,name);
681 lua_newtable(L); /* create array metatable */
683 lua_setmetatable(L,-2); /* set the own table as metatable (for modules) */
684 lua_pushstring(L,"__index");
685 lua_pushcfunction(L,get);
687 lua_pushstring(L,"__newindex");
688 lua_pushcfunction(L,set?set:const_array);
691 lua_rawset(L,-3); /* store variable */
692 lua_pop(L,1); /* pop .get table */
696 TOLUA_API void tolua_dobuffer(lua_State* L, char* B, unsigned int size, const char* name) {
698 #ifdef LUA_VERSION_NUM /* lua 5.1 */
699 luaL_loadbuffer(L, B, size, name) || lua_pcall(L, 0, 0, 0);
701 lua_dobuffer(L, B, size, name);