Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/tolua/tolua_map.c @ 2906

Last change on this file since 2906 was 2710, checked in by rgrieder, 16 years ago

Merged buildsystem3 containing buildsystem2 containing Adi's buildsystem branch back to the trunk.
Please update the media directory if you were not using buildsystem3 before.

  • Property svn:eol-style set to native
File size: 16.6 KB
Line 
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, 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, 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, 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, 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, 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, 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)
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, 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, 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*/
614TOLUA_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*/
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, 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 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
Note: See TracBrowser for help on using the repository browser.