Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 1505 was 1505, checked in by rgrieder, 12 years ago

f* svn: It doesn't even inform you if you attempt to set a non existing property. It is svn:eol-style and not eol-style when using the command by the way…

  • 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.