PageRenderTime 188ms CodeModel.GetById 43ms app.highlight 73ms RepoModel.GetById 35ms app.codeStats 0ms

/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
  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"
 17#include "lauxlib.h"
 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*/
 28static int tolua_newmetatable (lua_State* L, const 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*/
 49static 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 */
 91static 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*/
123static 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*/
147static int tolua_bnd_type (lua_State* L)
148{
149	tolua_typename(L,lua_gettop(L));
150	return 1;
151}
152
153/* Take ownership
154*/
155static 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*/
179static 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*/
210static 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*/
241static 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 */
253static 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
271static 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
285TOLUA_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*/
347TOLUA_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*/
359TOLUA_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*/
368TOLUA_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*/
392TOLUA_API void tolua_usertype (lua_State* L, const 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*/
406TOLUA_API void tolua_beginmodule (lua_State* L, const 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*/
420TOLUA_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
429TOLUA_API void tolua_module (lua_State* L, const 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
465TOLUA_API void tolua_module (lua_State* L, const 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
494static 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*/
521TOLUA_API void tolua_cclass (lua_State* L, const char* lname, const char* name, const 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)
565TOLUA_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*/
580TOLUA_API void tolua_function (lua_State* L, const 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 :(
589TOLUA_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*/
603TOLUA_API void tolua_constant (lua_State* L, const char* name, lua_Number 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*/
614TOLUA_API void tolua_variable (lua_State* L, const 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*/
657static 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*/
666TOLUA_API void tolua_array (lua_State* L, const 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
696TOLUA_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 if (luaL_loadbuffer(L, B, size, name) == 0)
700 {
701	 lua_pcall(L, 0, 0, 0);
702 }
703 #else
704 lua_dobuffer(L, B, size, name);
705 #endif
706};
707