| [1129] | 1 | /* tolua: functions to map features | 
|---|
|  | 2 | ** Support code for Lua bindings. | 
|---|
|  | 3 | ** Written by Waldemar Celes | 
|---|
|  | 4 | ** TeCGraf/PUC-Rio | 
|---|
|  | 5 | ** Apr 2003 | 
|---|
|  | 6 | ** $Id: $ | 
|---|
|  | 7 | */ | 
|---|
|  | 8 |  | 
|---|
|  | 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. | 
|---|
|  | 13 | */ | 
|---|
|  | 14 |  | 
|---|
|  | 15 | #include "tolua++.h" | 
|---|
|  | 16 | #include "tolua_event.h" | 
|---|
| [2710] | 17 | #include "lauxlib.h" | 
|---|
| [1129] | 18 |  | 
|---|
|  | 19 | #include <string.h> | 
|---|
|  | 20 | #include <stdio.h> | 
|---|
|  | 21 | #include <stdlib.h> | 
|---|
|  | 22 | #include <math.h> | 
|---|
|  | 23 |  | 
|---|
|  | 24 |  | 
|---|
|  | 25 | /* Create metatable | 
|---|
|  | 26 | * Create and register new metatable | 
|---|
|  | 27 | */ | 
|---|
|  | 28 | static int tolua_newmetatable (lua_State* L, char* name) | 
|---|
|  | 29 | { | 
|---|
|  | 30 | int r = luaL_newmetatable(L,name); | 
|---|
|  | 31 |  | 
|---|
|  | 32 | #ifdef LUA_VERSION_NUM /* only lua 5.1 */ | 
|---|
|  | 33 | if (r) { | 
|---|
|  | 34 | lua_pushvalue(L, -1); | 
|---|
|  | 35 | lua_pushstring(L, name); | 
|---|
|  | 36 | lua_settable(L, LUA_REGISTRYINDEX); /* reg[mt] = type_name */ | 
|---|
|  | 37 | }; | 
|---|
|  | 38 | #endif | 
|---|
|  | 39 |  | 
|---|
|  | 40 | if (r) | 
|---|
|  | 41 | tolua_classevents(L); /* set meta events */ | 
|---|
|  | 42 | lua_pop(L,1); | 
|---|
|  | 43 | return r; | 
|---|
|  | 44 | } | 
|---|
|  | 45 |  | 
|---|
|  | 46 | /* Map super classes | 
|---|
|  | 47 | * It sets 'name' as being also a 'base', mapping all super classes of 'base' in 'name' | 
|---|
|  | 48 | */ | 
|---|
|  | 49 | static void mapsuper (lua_State* L, const char* name, const char* base) | 
|---|
|  | 50 | { | 
|---|
|  | 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 */ | 
|---|
|  | 56 | if (lua_isnil(L,-1)) | 
|---|
|  | 57 | { | 
|---|
|  | 58 | /* create table */ | 
|---|
|  | 59 | lua_pop(L,1); | 
|---|
|  | 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 */ | 
|---|
|  | 64 | } | 
|---|
|  | 65 |  | 
|---|
|  | 66 | /* set base as super class */ | 
|---|
|  | 67 | lua_pushstring(L,base); | 
|---|
|  | 68 | lua_pushboolean(L,1); | 
|---|
|  | 69 | lua_rawset(L,-3);                    /* stack: super table */ | 
|---|
|  | 70 |  | 
|---|
|  | 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)) | 
|---|
|  | 75 | { | 
|---|
|  | 76 | /* traverse base table */ | 
|---|
|  | 77 | lua_pushnil(L);  /* first key */ | 
|---|
|  | 78 | while (lua_next(L,-2) != 0) | 
|---|
|  | 79 | { | 
|---|
|  | 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 */ | 
|---|
|  | 84 | } | 
|---|
|  | 85 | } | 
|---|
|  | 86 | lua_pop(L,3);                       /* stack: <empty> */ | 
|---|
|  | 87 | } | 
|---|
|  | 88 |  | 
|---|
|  | 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) { | 
|---|
|  | 92 |  | 
|---|
|  | 93 | /* mt basemt */ | 
|---|
|  | 94 | if (!lua_isnil(L, -1)) { | 
|---|
|  | 95 | lua_pushstring(L, "tolua_ubox"); | 
|---|
|  | 96 | lua_rawget(L,-2); | 
|---|
|  | 97 | } else { | 
|---|
|  | 98 | lua_pushnil(L); | 
|---|
|  | 99 | }; | 
|---|
|  | 100 | /* mt basemt base_ubox */ | 
|---|
|  | 101 | if (!lua_isnil(L,-1)) { | 
|---|
|  | 102 | lua_pushstring(L, "tolua_ubox"); | 
|---|
|  | 103 | lua_insert(L, -2); | 
|---|
|  | 104 | /* mt basemt key ubox */ | 
|---|
|  | 105 | lua_rawset(L,-4); | 
|---|
|  | 106 | /* (mt with ubox) basemt */ | 
|---|
|  | 107 | } else { | 
|---|
|  | 108 | /* mt basemt nil */ | 
|---|
|  | 109 | lua_pop(L, 1); | 
|---|
|  | 110 | lua_pushstring(L,"tolua_ubox"); lua_newtable(L); | 
|---|
|  | 111 | /* make weak value metatable for ubox table to allow userdata to be | 
|---|
|  | 112 | garbage-collected */ | 
|---|
|  | 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 */ | 
|---|
|  | 115 | lua_rawset(L,-4); | 
|---|
|  | 116 | }; | 
|---|
|  | 117 |  | 
|---|
|  | 118 | }; | 
|---|
|  | 119 |  | 
|---|
|  | 120 | /* Map inheritance | 
|---|
|  | 121 | * It sets 'name' as derived from 'base' by setting 'base' as metatable of 'name' | 
|---|
|  | 122 | */ | 
|---|
|  | 123 | static void mapinheritance (lua_State* L, const char* name, const char* base) | 
|---|
|  | 124 | { | 
|---|
|  | 125 | /* set metatable inheritance */ | 
|---|
|  | 126 | luaL_getmetatable(L,name); | 
|---|
|  | 127 |  | 
|---|
|  | 128 | if (base && *base) | 
|---|
|  | 129 | luaL_getmetatable(L,base); | 
|---|
|  | 130 | else { | 
|---|
|  | 131 |  | 
|---|
|  | 132 | if (lua_getmetatable(L, -1)) { /* already has a mt, we don't overwrite it */ | 
|---|
|  | 133 | lua_pop(L, 2); | 
|---|
|  | 134 | return; | 
|---|
|  | 135 | }; | 
|---|
|  | 136 | luaL_getmetatable(L,"tolua_commonclass"); | 
|---|
|  | 137 | }; | 
|---|
|  | 138 |  | 
|---|
|  | 139 | set_ubox(L); | 
|---|
|  | 140 |  | 
|---|
|  | 141 | lua_setmetatable(L,-2); | 
|---|
|  | 142 | lua_pop(L,1); | 
|---|
|  | 143 | } | 
|---|
|  | 144 |  | 
|---|
|  | 145 | /* Object type | 
|---|
|  | 146 | */ | 
|---|
|  | 147 | static int tolua_bnd_type (lua_State* L) | 
|---|
|  | 148 | { | 
|---|
|  | 149 | tolua_typename(L,lua_gettop(L)); | 
|---|
|  | 150 | return 1; | 
|---|
|  | 151 | } | 
|---|
|  | 152 |  | 
|---|
|  | 153 | /* Take ownership | 
|---|
|  | 154 | */ | 
|---|
|  | 155 | static int tolua_bnd_takeownership (lua_State* L) | 
|---|
|  | 156 | { | 
|---|
|  | 157 | int success = 0; | 
|---|
|  | 158 | if (lua_isuserdata(L,1)) | 
|---|
|  | 159 | { | 
|---|
|  | 160 | if (lua_getmetatable(L,1))        /* if metatable? */ | 
|---|
|  | 161 | { | 
|---|
|  | 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); | 
|---|
|  | 166 | #else | 
|---|
|  | 167 | lua_setgcthreshold(L,0); | 
|---|
|  | 168 | #endif | 
|---|
|  | 169 |  | 
|---|
|  | 170 | success = tolua_register_gc(L,1); | 
|---|
|  | 171 | } | 
|---|
|  | 172 | } | 
|---|
|  | 173 | lua_pushboolean(L,success!=0); | 
|---|
|  | 174 | return 1; | 
|---|
|  | 175 | } | 
|---|
|  | 176 |  | 
|---|
|  | 177 | /* Release ownership | 
|---|
|  | 178 | */ | 
|---|
|  | 179 | static int tolua_bnd_releaseownership (lua_State* L) | 
|---|
|  | 180 | { | 
|---|
|  | 181 | int done = 0; | 
|---|
|  | 182 | if (lua_isuserdata(L,1)) | 
|---|
|  | 183 | { | 
|---|
|  | 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); | 
|---|
|  | 188 | #else | 
|---|
|  | 189 | lua_setgcthreshold(L,0); | 
|---|
|  | 190 | #endif | 
|---|
|  | 191 | lua_pushstring(L,"tolua_gc"); | 
|---|
|  | 192 | lua_rawget(L,LUA_REGISTRYINDEX); | 
|---|
|  | 193 | lua_pushlightuserdata(L,u); | 
|---|
|  | 194 | lua_rawget(L,-2); | 
|---|
|  | 195 | lua_getmetatable(L,1); | 
|---|
|  | 196 | if (lua_rawequal(L,-1,-2))  /* check that we are releasing the correct type */ | 
|---|
|  | 197 | { | 
|---|
|  | 198 | lua_pushlightuserdata(L,u); | 
|---|
|  | 199 | lua_pushnil(L); | 
|---|
|  | 200 | lua_rawset(L,-5); | 
|---|
|  | 201 | done = 1; | 
|---|
|  | 202 | } | 
|---|
|  | 203 | } | 
|---|
|  | 204 | lua_pushboolean(L,done!=0); | 
|---|
|  | 205 | return 1; | 
|---|
|  | 206 | } | 
|---|
|  | 207 |  | 
|---|
|  | 208 | /* Type casting | 
|---|
|  | 209 | */ | 
|---|
|  | 210 | static int tolua_bnd_cast (lua_State* L) | 
|---|
|  | 211 | { | 
|---|
|  | 212 |  | 
|---|
|  | 213 | /* // old code | 
|---|
|  | 214 | void* v = tolua_tousertype(L,1,NULL); | 
|---|
|  | 215 | const char* s = tolua_tostring(L,2,NULL); | 
|---|
|  | 216 | if (v && s) | 
|---|
|  | 217 | tolua_pushusertype(L,v,s); | 
|---|
|  | 218 | else | 
|---|
|  | 219 | lua_pushnil(L); | 
|---|
|  | 220 | return 1; | 
|---|
|  | 221 | */ | 
|---|
|  | 222 |  | 
|---|
|  | 223 | void* v; | 
|---|
|  | 224 | const char* s; | 
|---|
|  | 225 | if (lua_islightuserdata(L, 1)) { | 
|---|
|  | 226 | v = tolua_touserdata(L, 1, NULL); | 
|---|
|  | 227 | } else { | 
|---|
|  | 228 | v = tolua_tousertype(L, 1, 0); | 
|---|
|  | 229 | }; | 
|---|
|  | 230 |  | 
|---|
|  | 231 | s = tolua_tostring(L,2,NULL); | 
|---|
|  | 232 | if (v && s) | 
|---|
|  | 233 | tolua_pushusertype(L,v,s); | 
|---|
|  | 234 | else | 
|---|
|  | 235 | lua_pushnil(L); | 
|---|
|  | 236 | return 1; | 
|---|
|  | 237 | } | 
|---|
|  | 238 |  | 
|---|
|  | 239 | /* Inheritance | 
|---|
|  | 240 | */ | 
|---|
|  | 241 | static int tolua_bnd_inherit (lua_State* L) { | 
|---|
|  | 242 |  | 
|---|
|  | 243 | /* stack: lua object, c object */ | 
|---|
|  | 244 | lua_pushstring(L, ".c_instance"); | 
|---|
|  | 245 | lua_pushvalue(L, -2); | 
|---|
|  | 246 | lua_rawset(L, -4); | 
|---|
|  | 247 | /* l_obj[".c_instance"] = c_obj */ | 
|---|
|  | 248 |  | 
|---|
|  | 249 | return 0; | 
|---|
|  | 250 | }; | 
|---|
|  | 251 |  | 
|---|
|  | 252 | #ifdef LUA_VERSION_NUM /* lua 5.1 */ | 
|---|
|  | 253 | static int tolua_bnd_setpeer(lua_State* L) { | 
|---|
|  | 254 |  | 
|---|
|  | 255 | /* stack: userdata, table */ | 
|---|
|  | 256 | if (!lua_isuserdata(L, -2)) { | 
|---|
|  | 257 | lua_pushstring(L, "Invalid argument #1 to setpeer: userdata expected."); | 
|---|
|  | 258 | lua_error(L); | 
|---|
|  | 259 | }; | 
|---|
|  | 260 |  | 
|---|
|  | 261 | if (lua_isnil(L, -1)) { | 
|---|
|  | 262 |  | 
|---|
|  | 263 | lua_pop(L, 1); | 
|---|
|  | 264 | lua_pushvalue(L, TOLUA_NOPEER); | 
|---|
|  | 265 | }; | 
|---|
|  | 266 | lua_setfenv(L, -2); | 
|---|
|  | 267 |  | 
|---|
|  | 268 | return 0; | 
|---|
|  | 269 | }; | 
|---|
|  | 270 |  | 
|---|
|  | 271 | static int tolua_bnd_getpeer(lua_State* L) { | 
|---|
|  | 272 |  | 
|---|
|  | 273 | /* stack: userdata */ | 
|---|
|  | 274 | lua_getfenv(L, -1); | 
|---|
|  | 275 | if (lua_rawequal(L, -1, TOLUA_NOPEER)) { | 
|---|
|  | 276 | lua_pop(L, 1); | 
|---|
|  | 277 | lua_pushnil(L); | 
|---|
|  | 278 | }; | 
|---|
|  | 279 | return 1; | 
|---|
|  | 280 | }; | 
|---|
|  | 281 | #endif | 
|---|
|  | 282 |  | 
|---|
|  | 283 | /* static int class_gc_event (lua_State* L); */ | 
|---|
|  | 284 |  | 
|---|
|  | 285 | TOLUA_API void tolua_open (lua_State* L) | 
|---|
|  | 286 | { | 
|---|
|  | 287 | int top = lua_gettop(L); | 
|---|
|  | 288 | lua_pushstring(L,"tolua_opened"); | 
|---|
|  | 289 | lua_rawget(L,LUA_REGISTRYINDEX); | 
|---|
|  | 290 | if (!lua_isboolean(L,-1)) | 
|---|
|  | 291 | { | 
|---|
|  | 292 | lua_pushstring(L,"tolua_opened"); lua_pushboolean(L,1); lua_rawset(L,LUA_REGISTRYINDEX); | 
|---|
|  | 293 |  | 
|---|
|  | 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); | 
|---|
|  | 301 | #endif | 
|---|
|  | 302 |  | 
|---|
|  | 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 | 
|---|
|  | 306 | garbage-collected */ | 
|---|
|  | 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); | 
|---|
|  | 310 |  | 
|---|
|  | 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); | 
|---|
|  | 313 |  | 
|---|
|  | 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); | 
|---|
|  | 322 |  | 
|---|
|  | 323 | tolua_newmetatable(L,"tolua_commonclass"); | 
|---|
|  | 324 |  | 
|---|
|  | 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); | 
|---|
|  | 337 | #endif | 
|---|
|  | 338 |  | 
|---|
|  | 339 | tolua_endmodule(L); | 
|---|
|  | 340 | tolua_endmodule(L); | 
|---|
|  | 341 | } | 
|---|
|  | 342 | lua_settop(L,top); | 
|---|
|  | 343 | } | 
|---|
|  | 344 |  | 
|---|
|  | 345 | /* Copy a C object | 
|---|
|  | 346 | */ | 
|---|
|  | 347 | TOLUA_API void* tolua_copy (lua_State* L, void* value, unsigned int size) | 
|---|
|  | 348 | { | 
|---|
|  | 349 | void* clone = (void*)malloc(size); | 
|---|
|  | 350 | if (clone) | 
|---|
|  | 351 | memcpy(clone,value,size); | 
|---|
|  | 352 | else | 
|---|
|  | 353 | tolua_error(L,"insuficient memory",NULL); | 
|---|
|  | 354 | return clone; | 
|---|
|  | 355 | } | 
|---|
|  | 356 |  | 
|---|
|  | 357 | /* Default collect function | 
|---|
|  | 358 | */ | 
|---|
|  | 359 | TOLUA_API int tolua_default_collect (lua_State* tolua_S) | 
|---|
|  | 360 | { | 
|---|
|  | 361 | void* self = tolua_tousertype(tolua_S,1,0); | 
|---|
|  | 362 | free(self); | 
|---|
|  | 363 | return 0; | 
|---|
|  | 364 | } | 
|---|
|  | 365 |  | 
|---|
|  | 366 | /* Do clone | 
|---|
|  | 367 | */ | 
|---|
|  | 368 | TOLUA_API int tolua_register_gc (lua_State* L, int lo) | 
|---|
|  | 369 | { | 
|---|
|  | 370 | int success = 1; | 
|---|
|  | 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); | 
|---|
|  | 375 | lua_rawget(L,-2); | 
|---|
|  | 376 | if (!lua_isnil(L,-1)) /* make sure that object is not already owned */ | 
|---|
|  | 377 | success = 0; | 
|---|
|  | 378 | else | 
|---|
|  | 379 | { | 
|---|
|  | 380 | lua_pushlightuserdata(L,value); | 
|---|
|  | 381 | lua_getmetatable(L,lo); | 
|---|
|  | 382 | lua_rawset(L,-4); | 
|---|
|  | 383 | } | 
|---|
|  | 384 | lua_pop(L,2); | 
|---|
|  | 385 | return success; | 
|---|
|  | 386 | } | 
|---|
|  | 387 |  | 
|---|
|  | 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' | 
|---|
|  | 391 | */ | 
|---|
|  | 392 | TOLUA_API void tolua_usertype (lua_State* L, char* type) | 
|---|
|  | 393 | { | 
|---|
|  | 394 | char ctype[128] = "const "; | 
|---|
|  | 395 | strncat(ctype,type,120); | 
|---|
|  | 396 |  | 
|---|
|  | 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' */ | 
|---|
|  | 400 | } | 
|---|
|  | 401 |  | 
|---|
|  | 402 |  | 
|---|
|  | 403 | /* Begin module | 
|---|
|  | 404 | * It pushes the module (or class) table on the stack | 
|---|
|  | 405 | */ | 
|---|
|  | 406 | TOLUA_API void tolua_beginmodule (lua_State* L, char* name) | 
|---|
|  | 407 | { | 
|---|
|  | 408 | if (name) | 
|---|
|  | 409 | { | 
|---|
|  | 410 | lua_pushstring(L,name); | 
|---|
|  | 411 | lua_rawget(L,-2); | 
|---|
|  | 412 | } | 
|---|
|  | 413 | else | 
|---|
|  | 414 | lua_pushvalue(L,LUA_GLOBALSINDEX); | 
|---|
|  | 415 | } | 
|---|
|  | 416 |  | 
|---|
|  | 417 | /* End module | 
|---|
|  | 418 | * It pops the module (or class) from the stack | 
|---|
|  | 419 | */ | 
|---|
|  | 420 | TOLUA_API void tolua_endmodule (lua_State* L) | 
|---|
|  | 421 | { | 
|---|
|  | 422 | lua_pop(L,1); | 
|---|
|  | 423 | } | 
|---|
|  | 424 |  | 
|---|
|  | 425 | /* Map module | 
|---|
|  | 426 | * It creates a new module | 
|---|
|  | 427 | */ | 
|---|
|  | 428 | #if 1 | 
|---|
|  | 429 | TOLUA_API void tolua_module (lua_State* L, char* name, int hasvar) | 
|---|
|  | 430 | { | 
|---|
|  | 431 | if (name) | 
|---|
|  | 432 | { | 
|---|
|  | 433 | /* tolua module */ | 
|---|
|  | 434 | lua_pushstring(L,name); | 
|---|
|  | 435 | lua_rawget(L,-2); | 
|---|
|  | 436 | if (!lua_istable(L,-1))  /* check if module already exists */ | 
|---|
|  | 437 | { | 
|---|
|  | 438 | lua_pop(L,1); | 
|---|
|  | 439 | lua_newtable(L); | 
|---|
|  | 440 | lua_pushstring(L,name); | 
|---|
|  | 441 | lua_pushvalue(L,-2); | 
|---|
|  | 442 | lua_rawset(L,-4);       /* assing module into module */ | 
|---|
|  | 443 | } | 
|---|
|  | 444 | } | 
|---|
|  | 445 | else | 
|---|
|  | 446 | { | 
|---|
|  | 447 | /* global table */ | 
|---|
|  | 448 | lua_pushvalue(L,LUA_GLOBALSINDEX); | 
|---|
|  | 449 | } | 
|---|
|  | 450 | if (hasvar) | 
|---|
|  | 451 | { | 
|---|
|  | 452 | if (!tolua_ismodulemetatable(L))  /* check if it already has a module metatable */ | 
|---|
|  | 453 | { | 
|---|
|  | 454 | /* create metatable to get/set C/C++ variable */ | 
|---|
|  | 455 | lua_newtable(L); | 
|---|
|  | 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); | 
|---|
|  | 460 | } | 
|---|
|  | 461 | } | 
|---|
|  | 462 | lua_pop(L,1);               /* pop module */ | 
|---|
|  | 463 | } | 
|---|
|  | 464 | #else | 
|---|
|  | 465 | TOLUA_API void tolua_module (lua_State* L, char* name, int hasvar) | 
|---|
|  | 466 | { | 
|---|
|  | 467 | if (name) | 
|---|
|  | 468 | { | 
|---|
|  | 469 | /* tolua module */ | 
|---|
|  | 470 | lua_pushstring(L,name); | 
|---|
|  | 471 | lua_newtable(L); | 
|---|
|  | 472 | } | 
|---|
|  | 473 | else | 
|---|
|  | 474 | { | 
|---|
|  | 475 | /* global table */ | 
|---|
|  | 476 | lua_pushvalue(L,LUA_GLOBALSINDEX); | 
|---|
|  | 477 | } | 
|---|
|  | 478 | if (hasvar) | 
|---|
|  | 479 | { | 
|---|
|  | 480 | /* create metatable to get/set C/C++ variable */ | 
|---|
|  | 481 | lua_newtable(L); | 
|---|
|  | 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); | 
|---|
|  | 486 | } | 
|---|
|  | 487 | if (name) | 
|---|
|  | 488 | lua_rawset(L,-3);       /* assing module into module */ | 
|---|
|  | 489 | else | 
|---|
|  | 490 | lua_pop(L,1);           /* pop global table */ | 
|---|
|  | 491 | } | 
|---|
|  | 492 | #endif | 
|---|
|  | 493 |  | 
|---|
|  | 494 | static void push_collector(lua_State* L, const char* type, lua_CFunction col) { | 
|---|
|  | 495 |  | 
|---|
|  | 496 | /* push collector function, but only if it's not NULL, or if there's no | 
|---|
|  | 497 | collector already */ | 
|---|
|  | 498 | if (!col) return; | 
|---|
|  | 499 | luaL_getmetatable(L,type); | 
|---|
|  | 500 | lua_pushstring(L,".collector"); | 
|---|
|  | 501 | /* | 
|---|
|  | 502 | if (!col) { | 
|---|
|  | 503 | lua_pushvalue(L, -1); | 
|---|
|  | 504 | lua_rawget(L, -3); | 
|---|
|  | 505 | if (!lua_isnil(L, -1)) { | 
|---|
|  | 506 | lua_pop(L, 3); | 
|---|
|  | 507 | return; | 
|---|
|  | 508 | }; | 
|---|
|  | 509 | lua_pop(L, 1); | 
|---|
|  | 510 | }; | 
|---|
|  | 511 | //      */ | 
|---|
|  | 512 | lua_pushcfunction(L,col); | 
|---|
|  | 513 |  | 
|---|
|  | 514 | lua_rawset(L,-3); | 
|---|
|  | 515 | lua_pop(L, 1); | 
|---|
|  | 516 | }; | 
|---|
|  | 517 |  | 
|---|
|  | 518 | /* Map C class | 
|---|
|  | 519 | * It maps a C class, setting the appropriate inheritance and super classes. | 
|---|
|  | 520 | */ | 
|---|
|  | 521 | TOLUA_API void tolua_cclass (lua_State* L, char* lname, char* name, char* base, lua_CFunction col) | 
|---|
|  | 522 | { | 
|---|
|  | 523 | char cname[128] = "const "; | 
|---|
|  | 524 | char cbase[128] = "const "; | 
|---|
|  | 525 | strncat(cname,name,120); | 
|---|
|  | 526 | strncat(cbase,base,120); | 
|---|
|  | 527 |  | 
|---|
|  | 528 | mapinheritance(L,name,base); | 
|---|
|  | 529 | mapinheritance(L,cname,name); | 
|---|
|  | 530 |  | 
|---|
|  | 531 | mapsuper(L,cname,cbase); | 
|---|
|  | 532 | mapsuper(L,name,base); | 
|---|
|  | 533 |  | 
|---|
|  | 534 | lua_pushstring(L,lname); | 
|---|
|  | 535 |  | 
|---|
|  | 536 | push_collector(L, name, col); | 
|---|
|  | 537 | /* | 
|---|
|  | 538 | luaL_getmetatable(L,name); | 
|---|
|  | 539 | lua_pushstring(L,".collector"); | 
|---|
|  | 540 | lua_pushcfunction(L,col); | 
|---|
|  | 541 |  | 
|---|
|  | 542 | lua_rawset(L,-3); | 
|---|
|  | 543 | */ | 
|---|
|  | 544 |  | 
|---|
|  | 545 | luaL_getmetatable(L,name); | 
|---|
|  | 546 | lua_rawset(L,-3);              /* assign class metatable to module */ | 
|---|
|  | 547 |  | 
|---|
|  | 548 | /* now we also need to store the collector table for the const | 
|---|
|  | 549 | instances of the class */ | 
|---|
|  | 550 | push_collector(L, cname, col); | 
|---|
|  | 551 | /* | 
|---|
|  | 552 | luaL_getmetatable(L,cname); | 
|---|
|  | 553 | lua_pushstring(L,".collector"); | 
|---|
|  | 554 | lua_pushcfunction(L,col); | 
|---|
|  | 555 | lua_rawset(L,-3); | 
|---|
|  | 556 | lua_pop(L,1); | 
|---|
|  | 557 | */ | 
|---|
|  | 558 |  | 
|---|
|  | 559 |  | 
|---|
|  | 560 | } | 
|---|
|  | 561 |  | 
|---|
|  | 562 | /* Add base | 
|---|
|  | 563 | * It adds additional base classes to a class (for multiple inheritance) | 
|---|
|  | 564 | * (not for now) | 
|---|
|  | 565 | TOLUA_API void tolua_addbase(lua_State* L, char* name, char* base) { | 
|---|
|  | 566 |  | 
|---|
|  | 567 | char cname[128] = "const "; | 
|---|
|  | 568 | char cbase[128] = "const "; | 
|---|
|  | 569 | strncat(cname,name,120); | 
|---|
|  | 570 | strncat(cbase,base,120); | 
|---|
|  | 571 |  | 
|---|
|  | 572 | mapsuper(L,cname,cbase); | 
|---|
|  | 573 | mapsuper(L,name,base); | 
|---|
|  | 574 | }; | 
|---|
|  | 575 | */ | 
|---|
|  | 576 |  | 
|---|
|  | 577 | /* Map function | 
|---|
|  | 578 | * It assigns a function into the current module (or class) | 
|---|
|  | 579 | */ | 
|---|
|  | 580 | TOLUA_API void tolua_function (lua_State* L, char* name, lua_CFunction func) | 
|---|
|  | 581 | { | 
|---|
|  | 582 | lua_pushstring(L,name); | 
|---|
|  | 583 | lua_pushcfunction(L,func); | 
|---|
|  | 584 | lua_rawset(L,-3); | 
|---|
|  | 585 | } | 
|---|
|  | 586 |  | 
|---|
|  | 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) { | 
|---|
|  | 590 |  | 
|---|
|  | 591 | lua_getmetatable(L, -1); | 
|---|
|  | 592 | //luaL_getmetatable(L, type); | 
|---|
|  | 593 | lua_pushstring(L,"__call"); | 
|---|
|  | 594 | lua_pushcfunction(L,func); | 
|---|
|  | 595 | lua_rawset(L,-3); | 
|---|
|  | 596 | lua_pop(L, 1); | 
|---|
|  | 597 | }; | 
|---|
|  | 598 | */ | 
|---|
|  | 599 |  | 
|---|
|  | 600 | /* Map constant number | 
|---|
|  | 601 | * It assigns a constant number into the current module (or class) | 
|---|
|  | 602 | */ | 
|---|
|  | 603 | TOLUA_API void tolua_constant (lua_State* L, char* name, double value) | 
|---|
|  | 604 | { | 
|---|
|  | 605 | lua_pushstring(L,name); | 
|---|
|  | 606 | tolua_pushnumber(L,value); | 
|---|
|  | 607 | lua_rawset(L,-3); | 
|---|
|  | 608 | } | 
|---|
|  | 609 |  | 
|---|
|  | 610 |  | 
|---|
|  | 611 | /* Map variable | 
|---|
|  | 612 | * It assigns a variable into the current module (or class) | 
|---|
|  | 613 | */ | 
|---|
|  | 614 | TOLUA_API void tolua_variable (lua_State* L, char* name, lua_CFunction get, lua_CFunction set) | 
|---|
|  | 615 | { | 
|---|
|  | 616 | /* get func */ | 
|---|
|  | 617 | lua_pushstring(L,".get"); | 
|---|
|  | 618 | lua_rawget(L,-2); | 
|---|
|  | 619 | if (!lua_istable(L,-1)) | 
|---|
|  | 620 | { | 
|---|
|  | 621 | /* create .get table, leaving it at the top */ | 
|---|
|  | 622 | lua_pop(L,1); | 
|---|
|  | 623 | lua_newtable(L); | 
|---|
|  | 624 | lua_pushstring(L,".get"); | 
|---|
|  | 625 | lua_pushvalue(L,-2); | 
|---|
|  | 626 | lua_rawset(L,-4); | 
|---|
|  | 627 | } | 
|---|
|  | 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 */ | 
|---|
|  | 632 |  | 
|---|
|  | 633 | /* set func */ | 
|---|
|  | 634 | if (set) | 
|---|
|  | 635 | { | 
|---|
|  | 636 | lua_pushstring(L,".set"); | 
|---|
|  | 637 | lua_rawget(L,-2); | 
|---|
|  | 638 | if (!lua_istable(L,-1)) | 
|---|
|  | 639 | { | 
|---|
|  | 640 | /* create .set table, leaving it at the top */ | 
|---|
|  | 641 | lua_pop(L,1); | 
|---|
|  | 642 | lua_newtable(L); | 
|---|
|  | 643 | lua_pushstring(L,".set"); | 
|---|
|  | 644 | lua_pushvalue(L,-2); | 
|---|
|  | 645 | lua_rawset(L,-4); | 
|---|
|  | 646 | } | 
|---|
|  | 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 */ | 
|---|
|  | 651 | } | 
|---|
|  | 652 | } | 
|---|
|  | 653 |  | 
|---|
|  | 654 | /* Access const array | 
|---|
|  | 655 | * It reports an error when trying to write into a const array | 
|---|
|  | 656 | */ | 
|---|
|  | 657 | static int const_array (lua_State* L) | 
|---|
|  | 658 | { | 
|---|
|  | 659 | luaL_error(L,"value of const array cannot be changed"); | 
|---|
|  | 660 | return 0; | 
|---|
|  | 661 | } | 
|---|
|  | 662 |  | 
|---|
|  | 663 | /* Map an array | 
|---|
|  | 664 | * It assigns an array into the current module (or class) | 
|---|
|  | 665 | */ | 
|---|
|  | 666 | TOLUA_API void tolua_array (lua_State* L, char* name, lua_CFunction get, lua_CFunction set) | 
|---|
|  | 667 | { | 
|---|
|  | 668 | lua_pushstring(L,".get"); | 
|---|
|  | 669 | lua_rawget(L,-2); | 
|---|
|  | 670 | if (!lua_istable(L,-1)) | 
|---|
|  | 671 | { | 
|---|
|  | 672 | /* create .get table, leaving it at the top */ | 
|---|
|  | 673 | lua_pop(L,1); | 
|---|
|  | 674 | lua_newtable(L); | 
|---|
|  | 675 | lua_pushstring(L,".get"); | 
|---|
|  | 676 | lua_pushvalue(L,-2); | 
|---|
|  | 677 | lua_rawset(L,-4); | 
|---|
|  | 678 | } | 
|---|
|  | 679 | lua_pushstring(L,name); | 
|---|
|  | 680 |  | 
|---|
|  | 681 | lua_newtable(L);           /* create array metatable */ | 
|---|
|  | 682 | lua_pushvalue(L,-1); | 
|---|
|  | 683 | lua_setmetatable(L,-2);    /* set the own table as metatable (for modules) */ | 
|---|
|  | 684 | lua_pushstring(L,"__index"); | 
|---|
|  | 685 | lua_pushcfunction(L,get); | 
|---|
|  | 686 | lua_rawset(L,-3); | 
|---|
|  | 687 | lua_pushstring(L,"__newindex"); | 
|---|
|  | 688 | lua_pushcfunction(L,set?set:const_array); | 
|---|
|  | 689 | lua_rawset(L,-3); | 
|---|
|  | 690 |  | 
|---|
|  | 691 | lua_rawset(L,-3);                  /* store variable */ | 
|---|
|  | 692 | lua_pop(L,1);                      /* pop .get table */ | 
|---|
|  | 693 | } | 
|---|
|  | 694 |  | 
|---|
|  | 695 |  | 
|---|
|  | 696 | TOLUA_API void tolua_dobuffer(lua_State* L, char* B, unsigned int size, const char* name) { | 
|---|
|  | 697 |  | 
|---|
|  | 698 | #ifdef LUA_VERSION_NUM /* lua 5.1 */ | 
|---|
|  | 699 | luaL_loadbuffer(L, B, size, name) || lua_pcall(L, 0, 0, 0); | 
|---|
|  | 700 | #else | 
|---|
|  | 701 | lua_dobuffer(L, B, size, name); | 
|---|
|  | 702 | #endif | 
|---|
|  | 703 | }; | 
|---|
|  | 704 |  | 
|---|