/script_binding/lua/tolua_map.c

http://ftk.googlecode.com/ · C · 707 lines · 453 code · 81 blank · 173 comment · 47 complexity · 511940810662de566068b675f794f2d1 MD5 · raw file

  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. /* This code is free software; you can redistribute it and/or modify it.
  9. ** The software provided hereunder is on an "as is" basis, and
  10. ** the author has no obligation to provide maintenance, support, updates,
  11. ** enhancements, or modifications.
  12. */
  13. #include "tolua++.h"
  14. #include "tolua_event.h"
  15. #include "lauxlib.h"
  16. #include <string.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <math.h>
  20. /* Create metatable
  21. * Create and register new metatable
  22. */
  23. static int tolua_newmetatable (lua_State* L, const char* name)
  24. {
  25. int r = luaL_newmetatable(L,name);
  26. #ifdef LUA_VERSION_NUM /* only lua 5.1 */
  27. if (r) {
  28. lua_pushvalue(L, -1);
  29. lua_pushstring(L, name);
  30. lua_settable(L, LUA_REGISTRYINDEX); /* reg[mt] = type_name */
  31. };
  32. #endif
  33. if (r)
  34. tolua_classevents(L); /* set meta events */
  35. lua_pop(L,1);
  36. return r;
  37. }
  38. /* Map super classes
  39. * It sets 'name' as being also a 'base', mapping all super classes of 'base' in 'name'
  40. */
  41. static void mapsuper (lua_State* L, const char* name, const char* base)
  42. {
  43. /* push registry.super */
  44. lua_pushstring(L,"tolua_super");
  45. lua_rawget(L,LUA_REGISTRYINDEX); /* stack: super */
  46. luaL_getmetatable(L,name); /* stack: super mt */
  47. lua_rawget(L,-2); /* stack: super table */
  48. if (lua_isnil(L,-1))
  49. {
  50. /* create table */
  51. lua_pop(L,1);
  52. lua_newtable(L); /* stack: super table */
  53. luaL_getmetatable(L,name); /* stack: super table mt */
  54. lua_pushvalue(L,-2); /* stack: super table mt table */
  55. lua_rawset(L,-4); /* stack: super table */
  56. }
  57. /* set base as super class */
  58. lua_pushstring(L,base);
  59. lua_pushboolean(L,1);
  60. lua_rawset(L,-3); /* stack: super table */
  61. /* set all super class of base as super class of name */
  62. luaL_getmetatable(L,base); /* stack: super table base_mt */
  63. lua_rawget(L,-3); /* stack: super table base_table */
  64. if (lua_istable(L,-1))
  65. {
  66. /* traverse base table */
  67. lua_pushnil(L); /* first key */
  68. while (lua_next(L,-2) != 0)
  69. {
  70. /* stack: ... base_table key value */
  71. lua_pushvalue(L,-2); /* stack: ... base_table key value key */
  72. lua_insert(L,-2); /* stack: ... base_table key key value */
  73. lua_rawset(L,-5); /* stack: ... base_table key */
  74. }
  75. }
  76. lua_pop(L,3); /* stack: <empty> */
  77. }
  78. /* creates a 'tolua_ubox' table for base clases, and
  79. // expects the metatable and base metatable on the stack */
  80. static void set_ubox(lua_State* L) {
  81. /* mt basemt */
  82. if (!lua_isnil(L, -1)) {
  83. lua_pushstring(L, "tolua_ubox");
  84. lua_rawget(L,-2);
  85. } else {
  86. lua_pushnil(L);
  87. };
  88. /* mt basemt base_ubox */
  89. if (!lua_isnil(L,-1)) {
  90. lua_pushstring(L, "tolua_ubox");
  91. lua_insert(L, -2);
  92. /* mt basemt key ubox */
  93. lua_rawset(L,-4);
  94. /* (mt with ubox) basemt */
  95. } else {
  96. /* mt basemt nil */
  97. lua_pop(L, 1);
  98. lua_pushstring(L,"tolua_ubox"); lua_newtable(L);
  99. /* make weak value metatable for ubox table to allow userdata to be
  100. garbage-collected */
  101. lua_newtable(L); lua_pushliteral(L, "__mode"); lua_pushliteral(L, "v"); lua_rawset(L, -3); /* stack: string ubox mt */
  102. lua_setmetatable(L, -2); /* stack:mt basemt string ubox */
  103. lua_rawset(L,-4);
  104. };
  105. };
  106. /* Map inheritance
  107. * It sets 'name' as derived from 'base' by setting 'base' as metatable of 'name'
  108. */
  109. static void mapinheritance (lua_State* L, const char* name, const char* base)
  110. {
  111. /* set metatable inheritance */
  112. luaL_getmetatable(L,name);
  113. if (base && *base)
  114. luaL_getmetatable(L,base);
  115. else {
  116. if (lua_getmetatable(L, -1)) { /* already has a mt, we don't overwrite it */
  117. lua_pop(L, 2);
  118. return;
  119. };
  120. luaL_getmetatable(L,"tolua_commonclass");
  121. };
  122. set_ubox(L);
  123. lua_setmetatable(L,-2);
  124. lua_pop(L,1);
  125. }
  126. /* Object type
  127. */
  128. static int tolua_bnd_type (lua_State* L)
  129. {
  130. tolua_typename(L,lua_gettop(L));
  131. return 1;
  132. }
  133. /* Take ownership
  134. */
  135. static int tolua_bnd_takeownership (lua_State* L)
  136. {
  137. int success = 0;
  138. if (lua_isuserdata(L,1))
  139. {
  140. if (lua_getmetatable(L,1)) /* if metatable? */
  141. {
  142. lua_pop(L,1); /* clear metatable off stack */
  143. /* force garbage collection to avoid C to reuse a to-be-collected address */
  144. #ifdef LUA_VERSION_NUM
  145. lua_gc(L, LUA_GCCOLLECT, 0);
  146. #else
  147. lua_setgcthreshold(L,0);
  148. #endif
  149. success = tolua_register_gc(L,1);
  150. }
  151. }
  152. lua_pushboolean(L,success!=0);
  153. return 1;
  154. }
  155. /* Release ownership
  156. */
  157. static int tolua_bnd_releaseownership (lua_State* L)
  158. {
  159. int done = 0;
  160. if (lua_isuserdata(L,1))
  161. {
  162. void* u = *((void**)lua_touserdata(L,1));
  163. /* force garbage collection to avoid releasing 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. lua_pushstring(L,"tolua_gc");
  170. lua_rawget(L,LUA_REGISTRYINDEX);
  171. lua_pushlightuserdata(L,u);
  172. lua_rawget(L,-2);
  173. lua_getmetatable(L,1);
  174. if (lua_rawequal(L,-1,-2)) /* check that we are releasing the correct type */
  175. {
  176. lua_pushlightuserdata(L,u);
  177. lua_pushnil(L);
  178. lua_rawset(L,-5);
  179. done = 1;
  180. }
  181. }
  182. lua_pushboolean(L,done!=0);
  183. return 1;
  184. }
  185. /* Type casting
  186. */
  187. static int tolua_bnd_cast (lua_State* L)
  188. {
  189. /* // old code
  190. void* v = tolua_tousertype(L,1,NULL);
  191. const char* s = tolua_tostring(L,2,NULL);
  192. if (v && s)
  193. tolua_pushusertype(L,v,s);
  194. else
  195. lua_pushnil(L);
  196. return 1;
  197. */
  198. void* v;
  199. const char* s;
  200. if (lua_islightuserdata(L, 1)) {
  201. v = tolua_touserdata(L, 1, NULL);
  202. } else {
  203. v = tolua_tousertype(L, 1, 0);
  204. };
  205. s = tolua_tostring(L,2,NULL);
  206. if (v && s)
  207. tolua_pushusertype(L,v,s);
  208. else
  209. lua_pushnil(L);
  210. return 1;
  211. }
  212. /* Inheritance
  213. */
  214. static int tolua_bnd_inherit (lua_State* L) {
  215. /* stack: lua object, c object */
  216. lua_pushstring(L, ".c_instance");
  217. lua_pushvalue(L, -2);
  218. lua_rawset(L, -4);
  219. /* l_obj[".c_instance"] = c_obj */
  220. return 0;
  221. };
  222. #ifdef LUA_VERSION_NUM /* lua 5.1 */
  223. static int tolua_bnd_setpeer(lua_State* L) {
  224. /* stack: userdata, table */
  225. if (!lua_isuserdata(L, -2)) {
  226. lua_pushstring(L, "Invalid argument #1 to setpeer: userdata expected.");
  227. lua_error(L);
  228. };
  229. if (lua_isnil(L, -1)) {
  230. lua_pop(L, 1);
  231. lua_pushvalue(L, TOLUA_NOPEER);
  232. };
  233. lua_setfenv(L, -2);
  234. return 0;
  235. };
  236. static int tolua_bnd_getpeer(lua_State* L) {
  237. /* stack: userdata */
  238. lua_getfenv(L, -1);
  239. if (lua_rawequal(L, -1, TOLUA_NOPEER)) {
  240. lua_pop(L, 1);
  241. lua_pushnil(L);
  242. };
  243. return 1;
  244. };
  245. #endif
  246. /* static int class_gc_event (lua_State* L); */
  247. TOLUA_API void tolua_open (lua_State* L)
  248. {
  249. int top = lua_gettop(L);
  250. lua_pushstring(L,"tolua_opened");
  251. lua_rawget(L,LUA_REGISTRYINDEX);
  252. if (!lua_isboolean(L,-1))
  253. {
  254. lua_pushstring(L,"tolua_opened"); lua_pushboolean(L,1); lua_rawset(L,LUA_REGISTRYINDEX);
  255. #ifndef LUA_VERSION_NUM /* only prior to lua 5.1 */
  256. /* create peer object table */
  257. lua_pushstring(L, "tolua_peers"); lua_newtable(L);
  258. /* make weak key metatable for peers indexed by userdata object */
  259. lua_newtable(L); lua_pushliteral(L, "__mode"); lua_pushliteral(L, "k"); lua_rawset(L, -3); /* stack: string peers mt */
  260. lua_setmetatable(L, -2); /* stack: string peers */
  261. lua_rawset(L,LUA_REGISTRYINDEX);
  262. #endif
  263. /* create object ptr -> udata mapping table */
  264. lua_pushstring(L,"tolua_ubox"); lua_newtable(L);
  265. /* make weak value metatable for ubox table to allow userdata to be
  266. garbage-collected */
  267. lua_newtable(L); lua_pushliteral(L, "__mode"); lua_pushliteral(L, "v"); lua_rawset(L, -3); /* stack: string ubox mt */
  268. lua_setmetatable(L, -2); /* stack: string ubox */
  269. lua_rawset(L,LUA_REGISTRYINDEX);
  270. lua_pushstring(L,"tolua_super"); lua_newtable(L); lua_rawset(L,LUA_REGISTRYINDEX);
  271. lua_pushstring(L,"tolua_gc"); lua_newtable(L);lua_rawset(L,LUA_REGISTRYINDEX);
  272. /* create gc_event closure */
  273. lua_pushstring(L, "tolua_gc_event");
  274. lua_pushstring(L, "tolua_gc");
  275. lua_rawget(L, LUA_REGISTRYINDEX);
  276. lua_pushstring(L, "tolua_super");
  277. lua_rawget(L, LUA_REGISTRYINDEX);
  278. lua_pushcclosure(L, class_gc_event, 2);
  279. lua_rawset(L, LUA_REGISTRYINDEX);
  280. tolua_newmetatable(L,"tolua_commonclass");
  281. tolua_module(L,NULL,0);
  282. tolua_beginmodule(L,NULL);
  283. tolua_module(L,"tolua",0);
  284. tolua_beginmodule(L,"tolua");
  285. tolua_function(L,"type",tolua_bnd_type);
  286. tolua_function(L,"takeownership",tolua_bnd_takeownership);
  287. tolua_function(L,"releaseownership",tolua_bnd_releaseownership);
  288. tolua_function(L,"cast",tolua_bnd_cast);
  289. tolua_function(L,"inherit", tolua_bnd_inherit);
  290. #ifdef LUA_VERSION_NUM /* lua 5.1 */
  291. tolua_function(L, "setpeer", tolua_bnd_setpeer);
  292. tolua_function(L, "getpeer", tolua_bnd_getpeer);
  293. #endif
  294. tolua_endmodule(L);
  295. tolua_endmodule(L);
  296. }
  297. lua_settop(L,top);
  298. }
  299. /* Copy a C object
  300. */
  301. TOLUA_API void* tolua_copy (lua_State* L, void* value, unsigned int size)
  302. {
  303. void* clone = (void*)malloc(size);
  304. if (clone)
  305. memcpy(clone,value,size);
  306. else
  307. tolua_error(L,"insuficient memory",NULL);
  308. return clone;
  309. }
  310. /* Default collect function
  311. */
  312. TOLUA_API int tolua_default_collect (lua_State* tolua_S)
  313. {
  314. void* self = tolua_tousertype(tolua_S,1,0);
  315. free(self);
  316. return 0;
  317. }
  318. /* Do clone
  319. */
  320. TOLUA_API int tolua_register_gc (lua_State* L, int lo)
  321. {
  322. int success = 1;
  323. void *value = *(void **)lua_touserdata(L,lo);
  324. lua_pushstring(L,"tolua_gc");
  325. lua_rawget(L,LUA_REGISTRYINDEX);
  326. lua_pushlightuserdata(L,value);
  327. lua_rawget(L,-2);
  328. if (!lua_isnil(L,-1)) /* make sure that object is not already owned */
  329. success = 0;
  330. else
  331. {
  332. lua_pushlightuserdata(L,value);
  333. lua_getmetatable(L,lo);
  334. lua_rawset(L,-4);
  335. }
  336. lua_pop(L,2);
  337. return success;
  338. }
  339. /* Register a usertype
  340. * It creates the correspoding metatable in the registry, for both 'type' and 'const type'.
  341. * It maps 'const type' as being also a 'type'
  342. */
  343. TOLUA_API void tolua_usertype (lua_State* L, const char* type)
  344. {
  345. char ctype[128] = "const ";
  346. strncat(ctype,type,120);
  347. /* create both metatables */
  348. if (tolua_newmetatable(L,ctype) && tolua_newmetatable(L,type))
  349. mapsuper(L,type,ctype); /* 'type' is also a 'const type' */
  350. }
  351. /* Begin module
  352. * It pushes the module (or class) table on the stack
  353. */
  354. TOLUA_API void tolua_beginmodule (lua_State* L, const char* name)
  355. {
  356. if (name)
  357. {
  358. lua_pushstring(L,name);
  359. lua_rawget(L,-2);
  360. }
  361. else
  362. lua_pushvalue(L,LUA_GLOBALSINDEX);
  363. }
  364. /* End module
  365. * It pops the module (or class) from the stack
  366. */
  367. TOLUA_API void tolua_endmodule (lua_State* L)
  368. {
  369. lua_pop(L,1);
  370. }
  371. /* Map module
  372. * It creates a new module
  373. */
  374. #if 1
  375. TOLUA_API void tolua_module (lua_State* L, const char* name, int hasvar)
  376. {
  377. if (name)
  378. {
  379. /* tolua module */
  380. lua_pushstring(L,name);
  381. lua_rawget(L,-2);
  382. if (!lua_istable(L,-1)) /* check if module already exists */
  383. {
  384. lua_pop(L,1);
  385. lua_newtable(L);
  386. lua_pushstring(L,name);
  387. lua_pushvalue(L,-2);
  388. lua_rawset(L,-4); /* assing module into module */
  389. }
  390. }
  391. else
  392. {
  393. /* global table */
  394. lua_pushvalue(L,LUA_GLOBALSINDEX);
  395. }
  396. if (hasvar)
  397. {
  398. if (!tolua_ismodulemetatable(L)) /* check if it already has a module metatable */
  399. {
  400. /* create metatable to get/set C/C++ variable */
  401. lua_newtable(L);
  402. tolua_moduleevents(L);
  403. if (lua_getmetatable(L,-2))
  404. lua_setmetatable(L,-2); /* set old metatable as metatable of metatable */
  405. lua_setmetatable(L,-2);
  406. }
  407. }
  408. lua_pop(L,1); /* pop module */
  409. }
  410. #else
  411. TOLUA_API void tolua_module (lua_State* L, const char* name, int hasvar)
  412. {
  413. if (name)
  414. {
  415. /* tolua module */
  416. lua_pushstring(L,name);
  417. lua_newtable(L);
  418. }
  419. else
  420. {
  421. /* global table */
  422. lua_pushvalue(L,LUA_GLOBALSINDEX);
  423. }
  424. if (hasvar)
  425. {
  426. /* create metatable to get/set C/C++ variable */
  427. lua_newtable(L);
  428. tolua_moduleevents(L);
  429. if (lua_getmetatable(L,-2))
  430. lua_setmetatable(L,-2); /* set old metatable as metatable of metatable */
  431. lua_setmetatable(L,-2);
  432. }
  433. if (name)
  434. lua_rawset(L,-3); /* assing module into module */
  435. else
  436. lua_pop(L,1); /* pop global table */
  437. }
  438. #endif
  439. static void push_collector(lua_State* L, const char* type, lua_CFunction col) {
  440. /* push collector function, but only if it's not NULL, or if there's no
  441. collector already */
  442. if (!col) return;
  443. luaL_getmetatable(L,type);
  444. lua_pushstring(L,".collector");
  445. /*
  446. if (!col) {
  447. lua_pushvalue(L, -1);
  448. lua_rawget(L, -3);
  449. if (!lua_isnil(L, -1)) {
  450. lua_pop(L, 3);
  451. return;
  452. };
  453. lua_pop(L, 1);
  454. };
  455. // */
  456. lua_pushcfunction(L,col);
  457. lua_rawset(L,-3);
  458. lua_pop(L, 1);
  459. };
  460. /* Map C class
  461. * It maps a C class, setting the appropriate inheritance and super classes.
  462. */
  463. TOLUA_API void tolua_cclass (lua_State* L, const char* lname, const char* name, const char* base, lua_CFunction col)
  464. {
  465. char cname[128] = "const ";
  466. char cbase[128] = "const ";
  467. strncat(cname,name,120);
  468. strncat(cbase,base,120);
  469. mapinheritance(L,name,base);
  470. mapinheritance(L,cname,name);
  471. mapsuper(L,cname,cbase);
  472. mapsuper(L,name,base);
  473. lua_pushstring(L,lname);
  474. push_collector(L, name, col);
  475. /*
  476. luaL_getmetatable(L,name);
  477. lua_pushstring(L,".collector");
  478. lua_pushcfunction(L,col);
  479. lua_rawset(L,-3);
  480. */
  481. luaL_getmetatable(L,name);
  482. lua_rawset(L,-3); /* assign class metatable to module */
  483. /* now we also need to store the collector table for the const
  484. instances of the class */
  485. push_collector(L, cname, col);
  486. /*
  487. luaL_getmetatable(L,cname);
  488. lua_pushstring(L,".collector");
  489. lua_pushcfunction(L,col);
  490. lua_rawset(L,-3);
  491. lua_pop(L,1);
  492. */
  493. }
  494. /* Add base
  495. * It adds additional base classes to a class (for multiple inheritance)
  496. * (not for now)
  497. TOLUA_API void tolua_addbase(lua_State* L, char* name, char* base) {
  498. char cname[128] = "const ";
  499. char cbase[128] = "const ";
  500. strncat(cname,name,120);
  501. strncat(cbase,base,120);
  502. mapsuper(L,cname,cbase);
  503. mapsuper(L,name,base);
  504. };
  505. */
  506. /* Map function
  507. * It assigns a function into the current module (or class)
  508. */
  509. TOLUA_API void tolua_function (lua_State* L, const char* name, lua_CFunction func)
  510. {
  511. lua_pushstring(L,name);
  512. lua_pushcfunction(L,func);
  513. lua_rawset(L,-3);
  514. }
  515. /* sets the __call event for the class (expects the class' main table on top) */
  516. /* never really worked :(
  517. TOLUA_API void tolua_set_call_event(lua_State* L, lua_CFunction func, char* type) {
  518. lua_getmetatable(L, -1);
  519. //luaL_getmetatable(L, type);
  520. lua_pushstring(L,"__call");
  521. lua_pushcfunction(L,func);
  522. lua_rawset(L,-3);
  523. lua_pop(L, 1);
  524. };
  525. */
  526. /* Map constant number
  527. * It assigns a constant number into the current module (or class)
  528. */
  529. TOLUA_API void tolua_constant (lua_State* L, const char* name, lua_Number value)
  530. {
  531. lua_pushstring(L,name);
  532. tolua_pushnumber(L,value);
  533. lua_rawset(L,-3);
  534. }
  535. /* Map variable
  536. * It assigns a variable into the current module (or class)
  537. */
  538. TOLUA_API void tolua_variable (lua_State* L, const char* name, lua_CFunction get, lua_CFunction set)
  539. {
  540. /* get func */
  541. lua_pushstring(L,".get");
  542. lua_rawget(L,-2);
  543. if (!lua_istable(L,-1))
  544. {
  545. /* create .get table, leaving it at the top */
  546. lua_pop(L,1);
  547. lua_newtable(L);
  548. lua_pushstring(L,".get");
  549. lua_pushvalue(L,-2);
  550. lua_rawset(L,-4);
  551. }
  552. lua_pushstring(L,name);
  553. lua_pushcfunction(L,get);
  554. lua_rawset(L,-3); /* store variable */
  555. lua_pop(L,1); /* pop .get table */
  556. /* set func */
  557. if (set)
  558. {
  559. lua_pushstring(L,".set");
  560. lua_rawget(L,-2);
  561. if (!lua_istable(L,-1))
  562. {
  563. /* create .set table, leaving it at the top */
  564. lua_pop(L,1);
  565. lua_newtable(L);
  566. lua_pushstring(L,".set");
  567. lua_pushvalue(L,-2);
  568. lua_rawset(L,-4);
  569. }
  570. lua_pushstring(L,name);
  571. lua_pushcfunction(L,set);
  572. lua_rawset(L,-3); /* store variable */
  573. lua_pop(L,1); /* pop .set table */
  574. }
  575. }
  576. /* Access const array
  577. * It reports an error when trying to write into a const array
  578. */
  579. static int const_array (lua_State* L)
  580. {
  581. luaL_error(L,"value of const array cannot be changed");
  582. return 0;
  583. }
  584. /* Map an array
  585. * It assigns an array into the current module (or class)
  586. */
  587. TOLUA_API void tolua_array (lua_State* L, const char* name, lua_CFunction get, lua_CFunction set)
  588. {
  589. lua_pushstring(L,".get");
  590. lua_rawget(L,-2);
  591. if (!lua_istable(L,-1))
  592. {
  593. /* create .get table, leaving it at the top */
  594. lua_pop(L,1);
  595. lua_newtable(L);
  596. lua_pushstring(L,".get");
  597. lua_pushvalue(L,-2);
  598. lua_rawset(L,-4);
  599. }
  600. lua_pushstring(L,name);
  601. lua_newtable(L); /* create array metatable */
  602. lua_pushvalue(L,-1);
  603. lua_setmetatable(L,-2); /* set the own table as metatable (for modules) */
  604. lua_pushstring(L,"__index");
  605. lua_pushcfunction(L,get);
  606. lua_rawset(L,-3);
  607. lua_pushstring(L,"__newindex");
  608. lua_pushcfunction(L,set?set:const_array);
  609. lua_rawset(L,-3);
  610. lua_rawset(L,-3); /* store variable */
  611. lua_pop(L,1); /* pop .get table */
  612. }
  613. TOLUA_API void tolua_dobuffer(lua_State* L, char* B, unsigned int size, const char* name) {
  614. #ifdef LUA_VERSION_NUM /* lua 5.1 */
  615. if (luaL_loadbuffer(L, B, size, name) == 0)
  616. {
  617. lua_pcall(L, 0, 0, 0);
  618. }
  619. #else
  620. lua_dobuffer(L, B, size, name);
  621. #endif
  622. };