4 * Copyright (c) The Notion Team 2011
5 * Copyright (c) Tuomo Valkonen 1999-2005.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
26 #include <libtu/obj.h>
27 #include <libtu/objp.h>
28 #include <libtu/dlist.h>
29 #include <libtu/util.h>
31 #include "readconfig.h"
35 #define MAGIC 0xf00ba7
37 /* Maximum number of parameters and return values for calls from Lua
38 * and (if va_copy is not available) return value from Lua functions.
42 static lua_State
*l_st
=NULL
;
43 ExtlHook current_hook
=NULL
;
45 static bool extl_stack_get(lua_State
*st
, int pos
, char type
,
46 bool copystring
, bool *wasdeadobject
,
49 static int extl_protected(lua_State
*st
);
51 #ifdef EXTL_LOG_ERRORS
52 static void flushtrace();
57 /*{{{ Safer rawget/set/getn */
60 #define CHECK_TABLE(ST, INDEX) luaL_checktype(ST, INDEX, LUA_TTABLE)
62 static int lua_objlen_check(lua_State
*st
, int index
)
64 CHECK_TABLE(st
, index
);
65 #if LUA_VERSION_NUM>=502
66 return lua_rawlen(st
, index
);
68 return lua_objlen(st
, index
);
73 static void lua_rawset_check(lua_State
*st
, int index
)
75 CHECK_TABLE(st
, index
);
76 lua_rawset(st
, index
);
80 static void lua_rawseti_check(lua_State
*st
, int index
, int n
)
82 CHECK_TABLE(st
, index
);
83 lua_rawseti(st
, index
, n
);
87 static void lua_rawget_check(lua_State
*st
, int index
)
89 CHECK_TABLE(st
, index
);
90 lua_rawget(st
, index
);
94 static void lua_rawgeti_check(lua_State
*st
, int index
, int n
)
96 CHECK_TABLE(st
, index
);
97 lua_rawgeti(st
, index
, n
);
104 /*{{{ A cpcall wrapper */
107 typedef bool ExtlCPCallFn(lua_State
*st
, void *ptr
);
117 static int extl_docpcall(lua_State
*st
)
119 ExtlCPCallParam
*param
=(ExtlCPCallParam
*)lua_touserdata(st
, -1);
121 /* Should be enough for most things */
122 if(!lua_checkstack(st
, 8)){
123 extl_warn(TR("Lua stack full."));
127 param
->retval
=param
->fn(st
, param
->udata
);
132 static bool extl_cpcall(lua_State
*st
, ExtlCPCallFn
*fn
, void *ptr
)
134 ExtlCPCallParam param
;
135 int oldtop
=lua_gettop(st
);
143 #if LUA_VERSION_NUM>=502
144 /* TODO: Call appropriate lua_checkstack!?
145 lua_checkstack(st, 2); */
146 lua_pushcfunction(st
, extl_docpcall
);
147 lua_pushlightuserdata(st
, ¶m
);
148 err
=lua_pcall(st
, 1, 0, 0);
150 err
=lua_cpcall(st
, extl_docpcall
, ¶m
);
153 extl_warn("%s", lua_tostring(st
, -1));
154 }else if(err
==LUA_ERRMEM
){
155 extl_warn("%s", strerror(ENOMEM
));
157 extl_warn(TR("Unknown Lua error."));
160 lua_settop(st
, oldtop
);
169 /*{{{ Obj userdata handling -- unsafe */
172 static int owned_cache_ref
=LUA_NOREF
;
175 static Obj
*extl_get_obj(lua_State
*st
, int pos
,
176 bool *invalid
, bool *dead
)
183 if(!lua_isuserdata(st
, pos
)){
184 *invalid
=!lua_isnil(st
, pos
);
188 if(!lua_getmetatable(st
, pos
))
191 /* If the userdata object is a proper Obj, metatable[MAGIC] must
192 * have been set to MAGIC.
194 lua_pushnumber(st
, MAGIC
);
195 lua_gettable(st
, -2);
196 val
=lua_tonumber(st
, -1);
200 ExtlProxy
*proxy
=(ExtlProxy
*)lua_touserdata(st
, pos
);
205 Obj
*obj
=EXTL_PROXY_OBJ(proxy
);
218 static void extl_uncache_(lua_State
*st
, Obj
*obj
)
220 if(EXTL_OBJ_OWNED(obj
)){
221 lua_rawgeti(st
, LUA_REGISTRYINDEX
, owned_cache_ref
);
222 lua_pushlightuserdata(st
, obj
);
226 lua_pushlightuserdata(st
, obj
);
228 lua_rawset(st
, LUA_REGISTRYINDEX
);
233 void extl_uncache(Obj
*obj
)
235 extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_uncache_
, obj
);
239 static void extl_push_obj(lua_State
*st
, Obj
*obj
)
248 if(EXTL_OBJ_CACHED(obj
)){
249 if(EXTL_OBJ_OWNED(obj
)){
250 lua_rawgeti(st
, LUA_REGISTRYINDEX
, owned_cache_ref
);
251 lua_pushlightuserdata(st
, obj
);
253 lua_remove(st
, -2); /* owned_cache */
255 lua_pushlightuserdata(st
, obj
);
256 lua_rawget(st
, LUA_REGISTRYINDEX
);
258 if(lua_isuserdata(st
, -1)){
259 D(fprintf(stderr
, "found %p cached\n", obj
));
265 D(fprintf(stderr
, "Creating %p\n", obj
));
267 proxy
=(ExtlProxy
*)lua_newuserdata(st
, sizeof(ExtlProxy
));
269 /* Lua shouldn't return if the allocation fails */
271 lua_pushfstring(st
, "luaextl_%s_metatable", OBJ_TYPESTR(obj
));
272 lua_gettable(st
, LUA_REGISTRYINDEX
);
273 if(lua_isnil(st
, -1)){
277 lua_setmetatable(st
, -2);
280 if(EXTL_OBJ_OWNED(obj
)){
281 lua_rawgeti(st
, LUA_REGISTRYINDEX
, owned_cache_ref
);
282 lua_pushlightuserdata(st
, obj
);
283 lua_pushvalue(st
, -3); /* the WWatch */
284 lua_rawset_check(st
, -3);
285 lua_pop(st
, 1); /* owned_cache */
287 lua_pushlightuserdata(st
, obj
);
288 lua_pushvalue(st
, -2); /* the WWatch */
289 lua_rawset_check(st
, LUA_REGISTRYINDEX
);
291 EXTL_BEGIN_PROXY_OBJ(proxy
, obj
);
296 /*{{{ Functions available to Lua code */
299 static int extl_obj_gc_handler(lua_State
*st
)
302 bool dead
=FALSE
, invalid
=FALSE
;
305 obj
=extl_get_obj(st
, 1, &invalid
, &dead
);
308 /* This should not happen, actually. Our object cache should
309 * hold references to all objects seen on the Lua side until
310 * they are destroyed.
315 proxy
=(ExtlProxy
*)lua_touserdata(st
, 1);
318 EXTL_END_PROXY_OBJ(proxy
, obj
);
320 if(EXTL_OBJ_OWNED(obj
))
321 EXTL_DESTROY_OWNED_OBJ(obj
);
327 static int extl_obj_typename(lua_State
*st
)
331 if(!extl_stack_get(st
, 1, 'o', FALSE
, NULL
, &obj
) || obj
==NULL
)
334 lua_pushstring(st
, EXTL_OBJ_TYPENAME(obj
));
338 /* Dummy code for documentation generation. */
341 * Return type name of \var{obj}.
343 EXTL_EXPORT_AS(global
, obj_typename
)
344 const char *__obj_typename(Obj
*obj
);
347 static int extl_obj_exists(lua_State
*st
)
351 extl_stack_get(st
, 1, 'o', FALSE
, NULL
, &obj
);
353 lua_pushboolean(st
, obj
!=NULL
);
358 /* Dummy code for documentation generation. */
361 * Does \var{obj} still exist on the C side of the application?
363 EXTL_EXPORT_AS(global
, obj_exists
)
364 bool __obj_exists(Obj
*obj
);
367 static int extl_obj_is(lua_State
*st
)
372 extl_stack_get(st
, 1, 'o', FALSE
, NULL
, &obj
);
375 lua_pushboolean(st
, 0);
377 tn
=lua_tostring(st
, 2);
378 lua_pushboolean(st
, EXTL_OBJ_IS(obj
, tn
));
384 /* Dummy code for documentation generation. */
387 * Is \var{obj} of type \var{typename}.
389 EXTL_EXPORT_AS(global
, obj_is
)
390 bool __obj_is(Obj
*obj
, const char *typename
);
393 static int extl_current_file_or_dir(lua_State
*st
, bool dir
)
398 if(lua_getstack(st
, 1, &ar
)!=1)
400 if(lua_getinfo(st
, "S", &ar
)==0)
403 if(ar
.source
==NULL
|| ar
.source
[0]!='@')
404 return 0; /* not a file */
409 lua_pushstring(st
, s
);
413 lua_pushstring(st
, ".");
415 lua_pushlstring(st
, s
, p
-s
);
421 extl_warn("Unable to get caller file from stack.");
426 static int extl_dopath(lua_State
*st
)
428 const char *toincl
, *cfdir
;
431 toincl
=luaL_checkstring(st
, 1);
432 complain
=!lua_toboolean(st
, 2);
434 if(extl_current_file_or_dir(st
, TRUE
)!=1){
435 res
=extl_read_config(toincl
, NULL
, complain
);
437 cfdir
=lua_tostring(st
, -1);
438 res
=extl_read_config(toincl
, cfdir
, complain
);
441 lua_pushboolean(st
, res
);
445 /* Dummy code for documentation generation. */
448 * Look up and execute another file with Lua code.
450 EXTL_EXPORT_AS(global
, dopath
)
451 bool dopath(const char *what
);
457 static bool extl_init_obj_info(lua_State
*st
)
459 static ExtlExportedFnSpec dummy
[]={
460 {NULL
, NULL
, NULL
, NULL
, NULL
, FALSE
, FALSE
, FALSE
}
463 extl_register_class("Obj", dummy
, NULL
);
465 /* Create cache for proxies to objects owned by Lua-side.
466 * These need to be in a weak table to ever be collected.
470 lua_pushstring(st
, "__mode");
471 lua_pushstring(st
, "v");
472 lua_rawset_check(st
, -3);
473 lua_setmetatable(st
, -2);
474 owned_cache_ref
=luaL_ref(st
, LUA_REGISTRYINDEX
);
476 lua_pushcfunction(st
, extl_obj_typename
);
477 lua_setglobal(st
, "obj_typename");
478 lua_pushcfunction(st
, extl_obj_is
);
479 lua_setglobal(st
, "obj_is");
480 lua_pushcfunction(st
, extl_obj_exists
);
481 lua_setglobal(st
, "obj_exists");
482 lua_pushcfunction(st
, extl_dopath
);
483 lua_setglobal(st
, "dopath");
484 lua_pushcfunction(st
, extl_protected
);
485 lua_setglobal(st
, "protected");
494 /*{{{ Error handling and reporting -- unsafe */
497 static int extl_stack_trace(lua_State
*st
)
503 lua_pushstring(st
, TR("Stack trace:"));
505 for( ; lua_getstack(st
, lvl
, &ar
); lvl
++){
508 if(lua_getinfo(st
, "Sln", &ar
)==0){
510 TR("\n(Unable to get debug info for level %d)"),
516 is_c
=(ar
.what
!=NULL
&& strcmp(ar
.what
, "C")==0);
518 if(!is_c
|| ar
.name
!=NULL
){
519 lua_pushfstring(st
, "\n%d %s", lvl
, ar
.short_src
);
520 if(ar
.currentline
!=-1)
521 lua_pushfstring(st
, ":%d", ar
.currentline
);
523 lua_pushfstring(st
, ": in '%s'", ar
.name
);
524 lua_concat(st
, 2+(ar
.currentline
!=-1)+(ar
.name
!=NULL
));
528 lua_pushstring(st
, TR("\n [Skipping unnamed C functions.]"));
529 /*lua_pushstring(st, "\n...skipping...");*/
539 #ifdef EXTL_LOG_ERRORS
541 static int extl_do_collect_errors(lua_State
*st
)
544 ErrorLog
*el
=(ErrorLog
*)lua_touserdata(st
, -1);
549 err
=lua_pcall(st
, n
, 0, 0);
552 extl_warn("%s", lua_tostring(st
, -1));
556 lua_pushstring(st
, el
->msgs
);
561 int extl_collect_errors(lua_State
*st
)
564 int n
=lua_gettop(st
);
567 lua_pushcfunction(st
, extl_do_collect_errors
);
569 lua_pushlightuserdata(st
, &el
);
573 err
=lua_pcall(st
, n
+1, 1, 0);
576 errorlog_deinit(&el
);
579 extl_warn(TR("Internal error."));
590 /*{{{ Init -- unsafe, but it doesn't matter at this point */
595 l_st
=luaL_newstate();
598 extl_warn(TR("Unable to initialize Lua."));
604 if(!extl_init_obj_info(l_st
)){
609 #ifdef EXTL_LOG_ERRORS
610 lua_pushcfunction(l_st
, extl_collect_errors
);
611 lua_setglobal(l_st
, "collect_errors");
628 /*{{{ Stack get/push -- all unsafe */
631 static bool extl_stack_get(lua_State
*st
, int pos
, char type
,
632 bool copystring
, bool *wasdeadobject
,
638 if(wasdeadobject
!=NULL
)
639 *wasdeadobject
=FALSE
;
643 *((bool*)valret
)=lua_toboolean(st
, pos
);
647 switch(lua_type(st
, pos
)){
649 if(type
!='i' && type
!='d' && type
!='a')
652 d
=lua_tonumber(st
, pos
);
661 ((ExtlAny
*)valret
)->type
='d';
662 ((ExtlAny
*)valret
)->value
.d
=d
;
666 *((double*)valret
)=d
;
674 ((ExtlAny
*)valret
)->type
='v';
675 }else if(type
=='t' || type
=='f'){
677 *((int*)valret
)=LUA_NOREF
;
678 }else if(type
=='s' || type
=='S'){
680 *((char**)valret
)=NULL
;
683 *((Obj
**)valret
)=NULL
;
690 if(type
!='s' && type
!='S' && type
!='a')
693 str
=lua_tostring(st
, pos
);
694 if(str
!=NULL
&& copystring
){
700 ((ExtlAny
*)valret
)->type
=(copystring
? 's' : 'S');
701 ((ExtlAny
*)valret
)->value
.s
=str
;
703 *((const char**)valret
)=str
;
709 if(type
!='f' && type
!='a')
712 lua_pushvalue(st
, pos
);
714 ((ExtlAny
*)valret
)->type
='f';
715 ((ExtlAny
*)valret
)->value
.f
=luaL_ref(st
, LUA_REGISTRYINDEX
);
717 *((int*)valret
)=luaL_ref(st
, LUA_REGISTRYINDEX
);
723 if(type
!='t' && type
!='a')
726 lua_pushvalue(st
, pos
);
728 ((ExtlAny
*)valret
)->type
='t';
729 ((ExtlAny
*)valret
)->value
.f
=luaL_ref(st
, LUA_REGISTRYINDEX
);
731 *((int*)valret
)=luaL_ref(st
, LUA_REGISTRYINDEX
);
737 if(type
=='o'|| type
=='a'){
738 bool invalid
=FALSE
, dead
=FALSE
;
739 Obj
*obj
=extl_get_obj(st
, pos
, &invalid
, &dead
);
740 if(wasdeadobject
!=NULL
)
744 ((ExtlAny
*)valret
)->type
='o';
745 ((ExtlAny
*)valret
)->value
.o
=obj
;
747 *((Obj
**)valret
)=obj
;
758 static void extl_to_any(ExtlAny
*a
, char type
, void *ptr
)
768 case 'i': a
->value
.i
=*(int*)ptr
; break;
769 case 'd': a
->value
.d
=*(double*)ptr
; break;
770 case 'b': a
->value
.b
=*(bool*)ptr
; break;
771 case 'o': a
->value
.o
=*(Obj
**)ptr
; break;
773 case 'S': a
->value
.s
=*(char**)ptr
; break;
774 case 't': a
->value
.t
=*(ExtlTab
*)ptr
; break;
775 case 'f': a
->value
.f
=*(ExtlFn
*)ptr
; break;
780 static void extl_to_any_vararg(ExtlAny
*a
, char type
, va_list *argsp
)
783 *a
=va_arg(*argsp
, ExtlAny
);
790 case 'i': a
->value
.i
=va_arg(*argsp
, int); break;
791 case 'd': a
->value
.d
=va_arg(*argsp
, double); break;
792 case 'b': a
->value
.b
=va_arg(*argsp
, bool); break;
793 case 'o': a
->value
.o
=va_arg(*argsp
, Obj
*); break;
795 case 'S': a
->value
.s
=va_arg(*argsp
, char*); break;
796 case 't': a
->value
.t
=va_arg(*argsp
, ExtlTab
); break;
797 case 'f': a
->value
.f
=va_arg(*argsp
, ExtlFn
); break;
802 static void extl_stack_pusha(lua_State
*st
, ExtlAny
*a
)
805 case 'i': lua_pushnumber(st
, a
->value
.i
); break;
806 case 'd': lua_pushnumber(st
, a
->value
.d
); break;
807 case 'b': lua_pushboolean(st
, a
->value
.b
); break;
808 case 'o': extl_push_obj(st
, a
->value
.o
); break;
810 case 'S': lua_pushstring(st
, a
->value
.s
); break;
811 case 't': lua_rawgeti(st
, LUA_REGISTRYINDEX
, a
->value
.t
); break;
812 case 'f': lua_rawgeti(st
, LUA_REGISTRYINDEX
, a
->value
.f
); break;
813 default: lua_pushnil(st
);
818 static void extl_stack_push(lua_State
*st
, char spec
, void *ptr
)
822 extl_to_any(&a
, spec
, ptr
);
823 extl_stack_pusha(st
, &a
);
827 static bool extl_stack_push_vararg(lua_State
*st
, char spec
, va_list *argsp
)
831 extl_to_any_vararg(&a
, spec
, argsp
);
832 extl_stack_pusha(st
, &a
);
844 enum{STRINGS_NONE
, STRINGS_NONCONST
, STRINGS_ALL
};
847 static void extl_any_free(ExtlAny
*a
, int strings
)
849 if((a
->type
=='s' && strings
!=STRINGS_NONE
) ||
850 (a
->type
=='S' && strings
==STRINGS_ALL
)){
852 free((char*)a
->value
.s
);
853 }else if(a
->type
=='t'){
854 extl_unref_table(a
->value
.t
);
855 }else if(a
->type
=='f'){
856 extl_unref_fn(a
->value
.f
);
861 static void extl_free(void *ptr
, char spec
, int strings
)
865 extl_to_any(&a
, spec
, ptr
);
866 extl_any_free(&a
, strings
);
873 /*{{{ Table and function references. */
876 static bool extl_getref(lua_State
*st
, int ref
)
878 lua_rawgeti(st
, LUA_REGISTRYINDEX
, ref
);
879 if(lua_isnil(st
, -1)){
888 static bool extl_do_unref(lua_State
*st
, int *refp
)
890 luaL_unref(st
, LUA_REGISTRYINDEX
, *refp
);
895 ExtlFn
extl_unref_fn(ExtlFn ref
)
897 extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_unref
, &ref
);
902 ExtlFn
extl_unref_table(ExtlTab ref
)
904 extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_unref
, &ref
);
911 ExtlFn
extl_fn_none()
917 ExtlTab
extl_table_none()
925 static bool extl_do_ref(lua_State
*st
, int *refp
)
927 if(!extl_getref(st
, *refp
))
929 *refp
=luaL_ref(st
, LUA_REGISTRYINDEX
);
934 ExtlTab
extl_ref_table(ExtlTab ref
)
936 if(extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_ref
, &ref
))
942 ExtlFn
extl_ref_fn(ExtlFn ref
)
944 if(extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_ref
, &ref
))
952 static bool extl_do_create_table(lua_State
*st
, int *refp
)
955 *refp
=luaL_ref(st
, LUA_REGISTRYINDEX
);
960 ExtlTab
extl_create_table()
963 if(extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_create_table
, &ref
))
977 static bool extl_do_eq(lua_State
*st
, EqParams
*ep
)
979 if(!extl_getref(st
, ep
->o1
))
981 if(!extl_getref(st
, ep
->o2
))
983 #if LUA_VERSION_NUM>=502
984 ep
->ret
=lua_compare(st
, -1, -2,LUA_OPEQ
);
986 ep
->ret
=lua_equal(st
, -1, -2);
992 bool extl_fn_eq(ExtlFn fn1
, ExtlFn fn2
)
998 extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_eq
, &ep
);
1003 bool extl_table_eq(ExtlTab t1
, ExtlTab t2
)
1009 extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_eq
, &ep
);
1028 static bool extl_table_dodo_get2(lua_State
*st
, TableParams2
*params
)
1033 lua_rawgeti(st
, LUA_REGISTRYINDEX
, params
->ref
);
1034 extl_stack_push_vararg(st
, params
->itype
, params
->argsp
);
1035 lua_gettable(st
, -2);
1036 if(lua_isnil(st
, -1))
1039 return extl_stack_get(st
, -1, params
->type
, TRUE
, NULL
,
1040 va_arg(*(params
->argsp
), void*));
1044 bool extl_table_get_vararg(ExtlTab ref
, char itype
, char type
, va_list *args
)
1046 TableParams2 params
;
1053 return extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_table_dodo_get2
, ¶ms
);
1057 bool extl_table_get(ExtlTab ref
, char itype
, char type
, ...)
1062 va_start(args
, type
);
1063 retval
=extl_table_get_vararg(ref
, itype
, type
, &args
);
1070 static bool extl_table_do_gets(ExtlTab ref
, const char *entry
,
1071 char type
, void *valret
)
1073 return extl_table_get(ref
, 's', type
, entry
, valret
);
1076 bool extl_table_gets_a(ExtlTab ref
, const char *entry
, ExtlAny
*ret
)
1078 return extl_table_do_gets(ref
, entry
, 'a', (void*)ret
);
1081 bool extl_table_gets_o(ExtlTab ref
, const char *entry
, Obj
**ret
)
1083 return extl_table_do_gets(ref
, entry
, 'o', (void*)ret
);
1086 bool extl_table_gets_i(ExtlTab ref
, const char *entry
, int *ret
)
1088 return extl_table_do_gets(ref
, entry
, 'i', (void*)ret
);
1091 bool extl_table_gets_d(ExtlTab ref
, const char *entry
, double *ret
)
1093 return extl_table_do_gets(ref
, entry
, 'd', (void*)ret
);
1096 bool extl_table_gets_b(ExtlTab ref
, const char *entry
, bool *ret
)
1098 return extl_table_do_gets(ref
, entry
, 'b', (void*)ret
);
1101 bool extl_table_gets_s(ExtlTab ref
, const char *entry
, char **ret
)
1103 return extl_table_do_gets(ref
, entry
, 's', (void*)ret
);
1106 bool extl_table_gets_f(ExtlTab ref
, const char *entry
, ExtlFn
*ret
)
1108 return extl_table_do_gets(ref
, entry
, 'f', (void*)ret
);
1111 bool extl_table_gets_t(ExtlTab ref
, const char *entry
, ExtlTab
*ret
)
1113 return extl_table_do_gets(ref
, entry
, 't', (void*)ret
);
1117 static bool extl_table_do_geti(ExtlTab ref
, int entry
, char type
, void *valret
)
1119 return extl_table_get(ref
, 'i', type
, entry
, valret
);
1122 bool extl_table_geti_a(ExtlTab ref
, int entry
, ExtlAny
*ret
)
1124 return extl_table_do_geti(ref
, entry
, 'a', (void*)ret
);
1127 bool extl_table_geti_o(ExtlTab ref
, int entry
, Obj
**ret
)
1129 return extl_table_do_geti(ref
, entry
, 'o', (void*)ret
);
1132 bool extl_table_geti_i(ExtlTab ref
, int entry
, int *ret
)
1134 return extl_table_do_geti(ref
, entry
, 'i', (void*)ret
);
1137 bool extl_table_geti_d(ExtlTab ref
, int entry
, double *ret
)
1139 return extl_table_do_geti(ref
, entry
, 'd', (void*)ret
);
1142 bool extl_table_geti_b(ExtlTab ref
, int entry
, bool *ret
)
1144 return extl_table_do_geti(ref
, entry
, 'b', (void*)ret
);
1147 bool extl_table_geti_s(ExtlTab ref
, int entry
, char **ret
)
1149 return extl_table_do_geti(ref
, entry
, 's', (void*)ret
);
1152 bool extl_table_geti_f(ExtlTab ref
, int entry
, ExtlFn
*ret
)
1154 return extl_table_do_geti(ref
, entry
, 'f', (void*)ret
);
1157 bool extl_table_geti_t(ExtlTab ref
, int entry
, ExtlTab
*ret
)
1159 return extl_table_do_geti(ref
, entry
, 't', (void*)ret
);
1169 static bool extl_table_do_get_n(lua_State
*st
, GetNParams
*params
)
1171 lua_rawgeti(st
, LUA_REGISTRYINDEX
, params
->ref
);
1172 params
->n
=lua_objlen_check(st
, -1);
1177 int extl_table_get_n(ExtlTab ref
)
1184 extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_table_do_get_n
, ¶ms
);
1196 static bool extl_table_dodo_set2(lua_State
*st
, TableParams2
*params
)
1198 lua_rawgeti(st
, LUA_REGISTRYINDEX
, params
->ref
);
1199 extl_stack_push_vararg(st
, params
->itype
, params
->argsp
);
1200 extl_stack_push_vararg(st
, params
->type
, params
->argsp
);
1201 lua_rawset_check(st
, -3);
1206 bool extl_table_set_vararg(ExtlTab ref
, char itype
, char type
, va_list *args
)
1208 TableParams2 params
;
1215 return extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_table_dodo_set2
, ¶ms
);
1219 bool extl_table_set(ExtlTab ref
, char itype
, char type
, ...)
1224 va_start(args
, type
);
1225 retval
=extl_table_set_vararg(ref
, itype
, type
, &args
);
1231 bool extl_table_sets_a(ExtlTab ref
, const char *entry
, const ExtlAny
*val
)
1233 return extl_table_set(ref
, 's', 'a', entry
, val
);
1236 bool extl_table_sets_o(ExtlTab ref
, const char *entry
, Obj
*val
)
1238 return extl_table_set(ref
, 's', 'o', entry
, val
);
1241 bool extl_table_sets_i(ExtlTab ref
, const char *entry
, int val
)
1243 return extl_table_set(ref
, 's', 'i', entry
, val
);
1246 bool extl_table_sets_d(ExtlTab ref
, const char *entry
, double val
)
1248 return extl_table_set(ref
, 's', 'd', entry
, val
);
1251 bool extl_table_sets_b(ExtlTab ref
, const char *entry
, bool val
)
1253 return extl_table_set(ref
, 's', 'b', entry
, val
);
1256 bool extl_table_sets_s(ExtlTab ref
, const char *entry
, const char *val
)
1258 return extl_table_set(ref
, 's', 'S', entry
, val
);
1261 bool extl_table_sets_f(ExtlTab ref
, const char *entry
, ExtlFn val
)
1263 return extl_table_set(ref
, 's', 'f', entry
, val
);
1266 bool extl_table_sets_t(ExtlTab ref
, const char *entry
, ExtlTab val
)
1268 return extl_table_set(ref
, 's', 't', entry
, val
);
1272 bool extl_table_seti_a(ExtlTab ref
, int entry
, const ExtlAny
*val
)
1274 return extl_table_set(ref
, 'i', 'a', entry
, val
);
1277 bool extl_table_seti_o(ExtlTab ref
, int entry
, Obj
*val
)
1279 return extl_table_set(ref
, 'i', 'o', entry
, val
);
1282 bool extl_table_seti_i(ExtlTab ref
, int entry
, int val
)
1284 return extl_table_set(ref
, 'i', 'i', entry
, val
);
1287 bool extl_table_seti_d(ExtlTab ref
, int entry
, double val
)
1289 return extl_table_set(ref
, 'i', 'd', entry
, val
);
1292 bool extl_table_seti_b(ExtlTab ref
, int entry
, bool val
)
1294 return extl_table_set(ref
, 'i', 'b', entry
, val
);
1297 bool extl_table_seti_s(ExtlTab ref
, int entry
, const char *val
)
1299 return extl_table_set(ref
, 'i', 'S', entry
, val
);
1302 bool extl_table_seti_f(ExtlTab ref
, int entry
, ExtlFn val
)
1304 return extl_table_set(ref
, 'i', 'f', entry
, val
);
1307 bool extl_table_seti_t(ExtlTab ref
, int entry
, ExtlTab val
)
1309 return extl_table_set(ref
, 'i', 't', entry
, val
);
1316 /*{{{Â Table/clear entry */
1319 static bool extl_table_dodo_clear2(lua_State
*st
, TableParams2
*params
)
1321 lua_rawgeti(st
, LUA_REGISTRYINDEX
, params
->ref
);
1322 extl_stack_push_vararg(st
, params
->itype
, params
->argsp
);
1324 lua_rawset_check(st
, -3);
1328 bool extl_table_clear_vararg(ExtlTab ref
, char itype
, va_list *args
)
1330 TableParams2 params
;
1334 /*params.type='?';*/
1337 return extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_table_dodo_clear2
, ¶ms
);
1340 bool extl_table_clear(ExtlTab ref
, char itype
, ...)
1345 va_start(args
, itype
);
1346 retval
=extl_table_clear_vararg(ref
, itype
, &args
);
1353 bool extl_table_clears(ExtlTab ref
, const char *entry
)
1355 return extl_table_clear(ref
, 's', entry
);
1358 bool extl_table_cleari(ExtlTab ref
, int entry
)
1360 return extl_table_clear(ref
, 'i', entry
);
1368 /*{{{ Table iteration */
1378 int extl_table_iter_do(lua_State
*st
, IterP
*par
)
1380 lua_rawgeti(st
, LUA_REGISTRYINDEX
, par
->ref
);
1384 while(lua_next(st
, -2)!=0){
1387 if(extl_stack_get(st
, -2, 'a', FALSE
, NULL
, &k
)){
1389 if(extl_stack_get(st
, -1, 'a', FALSE
, NULL
, &v
)){
1390 ret
=par
->fn(k
, v
, par
->d
);
1391 extl_any_free(&v
, STRINGS_NONE
);
1393 extl_any_free(&k
, STRINGS_NONE
);
1405 void extl_table_iter(ExtlTab ref
, ExtlIterFn
*fn
, void *d
)
1413 extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_table_iter_do
, &par
);
1420 /*{{{ Function calls to Lua */
1423 static bool extl_push_args(lua_State
*st
, const char *spec
, va_list *argsp
)
1428 if(!extl_stack_push_vararg(st
, *spec
, argsp
))
1444 #ifndef CF_HAS_VA_COPY
1445 void *ret_ptrs
[MAX_PARAMS
];
1450 static bool extl_get_retvals(lua_State
*st
, int m
, ExtlDoCallParam
*param
)
1453 const char *spec
=param
->rspec
;
1455 #ifdef CF_HAS_VA_COPY
1457 va_copy(args
, *(param
->args
));
1460 extl_warn(TR("Too many return values. Use a C compiler that has "
1461 "va_copy to support more."));
1468 #ifdef CF_HAS_VA_COPY
1469 ptr
=va_arg(args
, void*);
1471 ptr
=va_arg(*(param
->args
), void*);
1472 param
->ret_ptrs
[param
->nret
]=ptr
;
1474 if(!extl_stack_get(st
, -m
, *spec
, TRUE
, &dead
, ptr
)){
1475 /* This is the only place where we allow nil-objects */
1476 /*if(*spec=='o' && lua_isnil(st, -m)){
1480 extl_warn(TR("Returned dead object."));
1483 extl_warn(TR("Invalid return value (expected '%c', "
1484 "got lua type \"%s\")."),
1485 *spec
, lua_typename(st
, lua_type(st
, -m
)));
1495 #ifdef CF_HAS_VA_COPY
1503 /* The function to be called is expected on the top of stack st.
1504 * This function should be cpcalled through extl_cpcall_call (below), which
1505 * will take care that we don't leak anything in case of error.
1507 static bool extl_dodo_call_vararg(lua_State
*st
, ExtlDoCallParam
*param
)
1511 if(lua_isnil(st
, -1))
1514 if(param
->spec
!=NULL
)
1515 n
=strlen(param
->spec
);
1517 if(!lua_checkstack(st
, n
+8)){
1518 extl_warn(TR("Stack full."));
1523 if(!extl_push_args(st
, param
->spec
, param
->args
))
1527 if(param
->rspec
!=NULL
)
1528 m
=strlen(param
->rspec
);
1532 if(lua_pcall(st
, n
, m
, 0)!=0){
1533 extl_warn("%s", lua_tostring(st
, -1));
1538 return extl_get_retvals(st
, m
, param
);
1544 static bool extl_cpcall_call(lua_State
*st
, ExtlCPCallFn
*fn
,
1545 ExtlDoCallParam
*param
)
1552 if(extl_cpcall(st
, fn
, param
))
1555 /* If param.nret>0, there was an error getting some return value and
1556 * we must free what we got.
1559 for(i
=0; i
<param
->nret
; i
++){
1560 #ifdef CF_HAS_VA_COPY
1561 ptr
=va_arg(*(param
->args
), void*);
1563 ptr
=param
->ret_ptrs
[i
];
1565 extl_free(ptr
, *(param
->rspec
+i
), STRINGS_ALL
);
1572 static bool extl_do_call_vararg(lua_State
*st
, ExtlDoCallParam
*param
)
1574 if(!extl_getref(st
, *(ExtlFn
*)(param
->misc
)))
1576 return extl_dodo_call_vararg(st
, param
);
1580 bool extl_call_vararg(ExtlFn fnref
, const char *spec
,
1581 const char *rspec
, va_list *args
)
1583 ExtlDoCallParam param
;
1585 if(fnref
==LUA_NOREF
|| fnref
==LUA_REFNIL
)
1591 param
.misc
=(void*)&fnref
;
1593 return extl_cpcall_call(l_st
, (ExtlCPCallFn
*)extl_do_call_vararg
, ¶m
);
1597 bool extl_call(ExtlFn fnref
, const char *spec
, const char *rspec
, ...)
1602 va_start(args
, rspec
);
1603 retval
=extl_call_vararg(fnref
, spec
, rspec
, &args
);
1613 /*{{{ extl_loadfile/string */
1618 * - a stack with only the parameters to be passed to the function
1619 * - the function to call as an upvalue
1621 * - execute the function
1623 * - the number of return values
1625 static int call_loaded(lua_State
*st
)
1627 int nargs
=lua_gettop(st
);
1629 /* Get the loaded file/string as function */
1630 lua_pushvalue(st
, lua_upvalueindex(1));
1633 lua_call(st
, nargs
, LUA_MULTRET
);
1634 return lua_gettop(st
);
1646 * Stores a c closure in param->resptr containing a call to call_loaded with
1647 * as (fixed) parameter the function loaded from the file/buffer in param->src
1649 static bool extl_do_load(lua_State
*st
, ExtlLoadParam
*param
)
1654 res
=luaL_loadfile(st
, param
->src
);
1656 res
=luaL_loadbuffer(st
, param
->src
, strlen(param
->src
), param
->src
);
1660 extl_warn("%s", lua_tostring(st
, -1));
1664 lua_pushcclosure(st
, call_loaded
, 1);
1665 *(param
->resptr
)=luaL_ref(st
, LUA_REGISTRYINDEX
);
1671 bool extl_loadfile(const char *file
, ExtlFn
*ret
)
1673 ExtlLoadParam param
;
1678 return extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_load
, ¶m
);
1682 bool extl_loadstring(const char *str
, ExtlFn
*ret
)
1684 ExtlLoadParam param
;
1689 return extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_load
, ¶m
);
1696 /*{{{ L1 CH error logging */
1698 #ifdef EXTL_LOG_ERRORS
1700 INTRSTRUCT(WarnChain
);
1701 DECLSTRUCT(WarnChain
){
1704 WarnHandler
*old_handler
;
1709 static WarnChain
*warnchain
=NULL
;
1710 static int notrace
=0;
1713 static void l1_warn_handler(const char *message
)
1715 WarnChain
*ch
=warnchain
;
1716 static int called
=0;
1718 assert(warnchain
!=NULL
);
1720 if(called
==0 && notrace
==0)
1721 ch
->need_trace
=TRUE
;
1725 ch
->old_handler(message
);
1731 static void do_trace(WarnChain
*ch
)
1738 extl_stack_trace(ch
->st
);
1739 p
=lua_tostring(ch
->st
, -1);
1743 ch
->need_trace
=FALSE
;
1747 static void flushtrace()
1749 if(warnchain
&& warnchain
->need_trace
)
1750 do_trace(warnchain
);
1758 /*{{{ L1-CH safe functions */
1761 static int protect_count
=0;
1762 static ExtlSafelist
*safelists
=NULL
;
1765 void extl_protect(ExtlSafelist
*l
)
1770 LINK_ITEM(safelists
, l
, next
, prev
);
1777 void extl_unprotect(ExtlSafelist
*l
)
1779 assert(protect_count
>0);
1786 UNLINK_ITEM(safelists
, l
, next
, prev
);
1792 static bool extl_check_protected(ExtlExportedFnSpec
*spec
)
1798 if(protect_count
>0 && !spec
->safe
){
1799 for(l
=safelists
; l
!=NULL
; l
=l
->next
){
1801 for(j
=0; l
->list
[j
]!=NULL
; j
++){
1802 if(l
->list
[j
]==spec
->fn
)
1805 if(l
->list
[j
]==NULL
){
1821 /*{{{ L1 call handler */
1823 /* To get around potential memory leaks and corruption that could be caused
1824 * by Lua's longjmp-on-error lameness, The L1 call handler is divided into
1825 * two steps. In the first step we first setup a call to the second step.
1826 * At this point it is still fine if Lua raises an error. Then we set up
1827 * our warning handlers and stuff--at which point Lua's raising an error
1828 * would corrupt our data--and finally call the second step with lua_pcall.
1829 * Now the second step can safely call Lua's functions and do what is needed.
1830 * When the second step returns, we deallocate our data in the L1Param
1831 * structure that was passed to the second step and reset warning handlers.
1832 * After that it is again safe to call Lua's functions.
1836 ExtlL2Param ip
[MAX_PARAMS
];
1837 ExtlL2Param op
[MAX_PARAMS
];
1838 ExtlExportedFnSpec
*spec
;
1842 static L1Param
*current_param
=NULL
;
1845 static int extl_l1_call_handler2(lua_State
*st
)
1847 L1Param
*param
=current_param
;
1848 ExtlExportedFnSpec
*spec
=param
->spec
;
1851 D(fprintf(stderr
, "%s called\n", spec
->name
));
1853 if(!lua_checkstack(st
, MAX_PARAMS
+1)){
1854 extl_warn(TR("Stack full."));
1858 param
->ni
=(spec
->ispec
==NULL
? 0 : strlen(spec
->ispec
));
1860 for(i
=0; i
<param
->ni
; i
++){
1862 if(!extl_stack_get(st
, i
+1, spec
->ispec
[i
], FALSE
, &dead
,
1863 (void*)&(param
->ip
[i
]))){
1865 extl_warn(TR("Argument %d to %s is a dead object."),
1868 extl_warn(TR("Argument %d to %s is of invalid type. "
1869 "(Argument template is '%s', got lua type %s)."),
1870 i
+1, spec
->name
, spec
->ispec
,
1871 lua_typename(st
, lua_type(st
, i
+1)));
1882 if(!spec
->l2handler(spec
->fn
, param
->ip
, param
->op
))
1888 param
->no
=(spec
->ospec
==NULL
? 0 : strlen(spec
->ospec
));
1890 for(i
=0; i
<param
->no
; i
++)
1891 extl_stack_push(st
, spec
->ospec
[i
], (void*)&(param
->op
[i
]));
1897 static void extl_l1_finalize(L1Param
*param
)
1899 ExtlExportedFnSpec
*spec
=param
->spec
;
1902 for(i
=0; i
<param
->ii
; i
++)
1903 extl_free((void*)&(param
->ip
[i
]), spec
->ispec
[i
], STRINGS_NONE
);
1905 for(i
=0; i
<param
->no
; i
++)
1906 extl_free((void*)&(param
->op
[i
]), spec
->ospec
[i
], STRINGS_NONCONST
);
1911 static bool extl_l1_just_check_protected
=FALSE
;
1914 static int extl_l1_call_handler(lua_State
*st
)
1916 #ifdef EXTL_LOG_ERRORS
1919 L1Param param
={{NULL
, }, {NULL
, }, NULL
, 0, 0, 0};
1922 int n
=lua_gettop(st
);
1925 /* Get the info we need on the function, check it's ok, and then set
1926 * up a safe environment for extl_l1_call_handler2.
1928 param
.spec
=(ExtlExportedFnSpec
*)lua_touserdata(st
, lua_upvalueindex(1));
1930 if(param
.spec
==NULL
){
1931 extl_warn(TR("L1 call handler upvalues corrupt."));
1935 if(!param
.spec
->registered
){
1936 extl_warn(TR("Called function has been unregistered."));
1940 if(extl_l1_just_check_protected
){
1941 /* Just checking whether the function may be called. */
1942 lua_pushboolean(st
, !extl_check_protected(param
.spec
));
1946 if(!extl_check_protected(param
.spec
)){
1947 extl_warn(TR("Ignoring call to unsafe function \"%s\" in "
1948 "restricted mode."), param
.spec
->name
);
1953 lua_pushcfunction(st
, extl_l1_call_handler2
);
1956 old_param
=current_param
;
1957 current_param
=¶m
;
1959 #ifdef EXTL_LOG_ERRORS
1960 ch
.old_handler
=set_warn_handler(l1_warn_handler
);
1961 ch
.need_trace
=FALSE
;
1967 /* Ok, Lua may now freely fail in extl_l1_call_handler2, we can handle
1970 ret
=lua_pcall(st
, n
, LUA_MULTRET
, 0);
1972 /* Now that the actual call handler has returned, we need to free
1973 * any of our data before calling Lua again.
1975 current_param
=old_param
;
1976 extl_l1_finalize(¶m
);
1978 #ifdef EXTL_LOG_ERRORS
1980 set_warn_handler(ch
.old_handler
);
1982 /* Ok, we can now safely use Lua functions again without fear of
1988 p
=lua_tostring(st
, -1);
1994 if(ret
!=0 || ch
.need_trace
)
2006 * Is calling the function \var{fn} not allowed now? If \var{fn} is nil,
2007 * tells if some functions are not allowed to be called now due to
2010 EXTL_EXPORT_AS(global
, protected)
2011 bool __protected(ExtlFn fn
);
2013 static int extl_protected(lua_State
*st
)
2017 if(lua_isnil(st
, 1)){
2018 lua_pushboolean(st
, protect_count
>0);
2022 if(!lua_isfunction(st
, 1)){
2023 lua_pushboolean(st
, TRUE
);
2027 if(lua_tocfunction(st
, 1)!=(lua_CFunction
)extl_l1_call_handler
){
2028 lua_pushboolean(st
, FALSE
);
2032 extl_l1_just_check_protected
=TRUE
;
2033 ret
=lua_pcall(st
, 0, 1, 0);
2034 extl_l1_just_check_protected
=FALSE
;
2036 lua_pushboolean(st
, TRUE
);
2043 /*{{{ Function registration */
2047 ExtlExportedFnSpec
*spec
;
2053 static bool extl_do_register_function(lua_State
*st
, RegData
*data
)
2055 ExtlExportedFnSpec
*spec
=data
->spec
;
2056 #if LUA_VERSION_NUM>=502
2059 int ind
=LUA_GLOBALSINDEX
;
2062 if((spec
->ispec
!=NULL
&& strlen(spec
->ispec
)>MAX_PARAMS
) ||
2063 (spec
->ospec
!=NULL
&& strlen(spec
->ospec
)>MAX_PARAMS
)){
2064 extl_warn(TR("Function '%s' has more parameters than the level 1 "
2065 "call handler can handle"), spec
->name
);
2069 if(data
->table
!=LUA_NOREF
){
2070 lua_rawgeti(st
, LUA_REGISTRYINDEX
, data
->table
);
2073 #if LUA_VERSION_NUM>=502
2075 lua_pushglobaltable(st
);
2080 lua_pushstring(st
, spec
->name
);
2082 lua_pushlightuserdata(st
, spec
);
2083 lua_pushcclosure(st
, extl_l1_call_handler
, 1);
2085 lua_rawset_check(st
, ind
);
2091 static bool extl_do_register_functions(ExtlExportedFnSpec
*spec
, int max
,
2092 const char *cls
, int table
)
2099 regdata
.table
=table
;
2101 for(i
=0; spec
[i
].name
&& i
<max
; i
++){
2102 regdata
.spec
=&(spec
[i
]);
2103 if(!extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_register_function
,
2107 spec
[i
].registered
=TRUE
;
2114 bool extl_register_function(ExtlExportedFnSpec
*spec
)
2116 return extl_do_register_functions(spec
, 1, "", LUA_NOREF
);
2120 bool extl_register_functions(ExtlExportedFnSpec
*spec
)
2122 return extl_do_register_functions(spec
, INT_MAX
, "", LUA_NOREF
);
2126 static bool extl_do_unregister_function(lua_State
*st
, RegData
*data
)
2128 ExtlExportedFnSpec
*spec
=data
->spec
;
2129 #if LUA_VERSION_NUM>=502
2132 int ind
=LUA_GLOBALSINDEX
;
2135 if(data
->table
!=LUA_NOREF
){
2136 lua_rawgeti(st
, LUA_REGISTRYINDEX
, data
->table
);
2139 #if LUA_VERSION_NUM>=502
2141 lua_pushglobaltable(st
);
2146 /* Clear table.fn */
2147 lua_pushstring(st
, spec
->name
);
2149 lua_rawset_check(st
, ind
);
2155 static void extl_do_unregister_functions(ExtlExportedFnSpec
*spec
, int max
,
2156 const char *cls
, int table
)
2163 regdata
.table
=table
;
2165 for(i
=0; spec
[i
].name
&& i
<max
; i
++){
2166 regdata
.spec
=&(spec
[i
]);
2167 extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_unregister_function
,
2169 spec
[i
].registered
=FALSE
;
2173 void extl_unregister_function(ExtlExportedFnSpec
*spec
)
2175 extl_do_unregister_functions(spec
, 1, "", LUA_NOREF
);
2179 void extl_unregister_functions(ExtlExportedFnSpec
*spec
)
2181 extl_do_unregister_functions(spec
, INT_MAX
, "", LUA_NOREF
);
2188 /*{{{ Class registration */
2192 const char *cls
, *parent
;
2198 static bool extl_do_register_class(lua_State
*st
, ClassData
*data
)
2200 /* Create the globally visible WFoobar table in which the function
2201 * references reside.
2205 /* Set type information.
2207 lua_pushstring(st
, "__typename");
2208 lua_pushstring(st
, data
->cls
);
2209 lua_settable(st
, -3);
2211 /* If we have a parent class (i.e. class!=Obj), we want also the parent's
2212 * functions visible in this table so set up a metatable to do so.
2214 if(data
->parent
!=NULL
){
2215 /* Get luaextl_ParentClass_metatable */
2216 lua_pushfstring(st
, "luaextl_%s_metatable", data
->parent
);
2217 lua_gettable(st
, LUA_REGISTRYINDEX
);
2218 if(!lua_istable(st
, -1)){
2219 extl_warn("Could not find metatable for parent class %s of %s.\n",
2220 data
->parent
, data
->cls
);
2223 /* Create our metatable */
2225 /* Get parent_metatable.__index */
2226 lua_pushstring(st
, "__index");
2227 lua_pushvalue(st
, -1);
2228 /* Stack: cls, parent_meta, meta, "__index", "__index" */
2229 lua_gettable(st
, -4);
2230 /* Stack: cls, parent_meta, meta, "__index", parent_meta.__index */
2231 lua_pushvalue(st
, -1);
2233 /* Stack: cls, parent_meta, meta, parent_meta.__index, "__index", parent_meta.__index */
2234 lua_rawset_check(st
, -4);
2235 /* Stack: cls, parent_meta, meta, parent_meta.__index */
2236 lua_pushstring(st
, "__parentclass");
2238 /* Stack: cls, parent_meta, meta, "__parentclass", parent_meta.__index */
2239 lua_settable(st
, -5);
2240 /* Stack: cls, parent_meta, meta, */
2241 lua_setmetatable(st
, -3);
2246 /* Set the global WFoobar */
2247 lua_pushvalue(st
, -1);
2248 data
->refret
=luaL_ref(st
, LUA_REGISTRYINDEX
); /* TODO: free on failure */
2250 #if LUA_VERSION_NUM>=502
2251 lua_pushglobaltable(st
);
2252 lua_pushstring(st
, data
->cls
);
2253 lua_pushvalue(st
, -3);
2257 lua_pushstring(st
, data
->cls
);
2258 lua_pushvalue(st
, -2);
2259 lua_rawset(st
, LUA_GLOBALSINDEX
);
2263 /* New we create a metatable for the actual objects with __gc metamethod
2264 * and __index pointing to the table created above. The MAGIC entry is
2265 * used to check that userdatas passed to us really are Watches with a
2270 lua_pushnumber(st
, MAGIC
);
2271 lua_pushnumber(st
, MAGIC
);
2272 lua_rawset_check(st
, -3);
2274 lua_pushstring(st
, "__index");
2275 lua_pushvalue(st
, -3);
2276 lua_rawset_check(st
, -3); /* set metatable.__index=WFoobar created above */
2277 lua_pushstring(st
, "__gc");
2278 lua_pushcfunction(st
, extl_obj_gc_handler
);
2279 lua_rawset_check(st
, -3); /* set metatable.__gc=extl_obj_gc_handler */
2280 lua_pushfstring(st
, "luaextl_%s_metatable", data
->cls
);
2282 lua_rawset(st
, LUA_REGISTRYINDEX
);
2288 bool extl_register_class(const char *cls
, ExtlExportedFnSpec
*fns
,
2293 clsdata
.parent
=parent
;
2294 clsdata
.refret
=LUA_NOREF
;
2295 clsdata
.hide
=(strcmp(cls
, "Obj")==0);/*(fns==NULL);*/
2297 D(assert(strcmp(cls
, "Obj")==0 || parent
!=NULL
));
2299 if(!extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_register_class
, &clsdata
))
2305 return extl_do_register_functions(fns
, INT_MAX
, cls
, clsdata
.refret
);
2309 static void extl_do_unregister_class(lua_State
*st
, ClassData
*data
)
2311 /* Get reference from registry to the metatable. */
2312 lua_pushfstring(st
, "luaextl_%s_metatable", data
->cls
);
2313 lua_pushvalue(st
, -1);
2314 lua_gettable(st
, LUA_REGISTRYINDEX
);
2315 /* Get __index and return it for resetting the functions. */
2316 lua_pushstring(st
, "__index");
2317 lua_gettable(st
, -2);
2318 data
->refret
=luaL_ref(st
, LUA_REGISTRYINDEX
);
2320 /* Set the entry from registry to nil. */
2322 lua_rawset(st
, LUA_REGISTRYINDEX
);
2324 /* Reset the global reference to the class to nil. */
2325 #if LUA_VERSION_NUM>=502
2326 lua_pushglobaltable(st
);
2327 lua_pushstring(st
, data
->cls
);
2332 lua_pushstring(st
, data
->cls
);
2334 lua_rawset(st
, LUA_GLOBALSINDEX
);
2339 void extl_unregister_class(const char *cls
, ExtlExportedFnSpec
*fns
)
2343 clsdata
.parent
=NULL
;
2344 clsdata
.refret
=LUA_NOREF
;
2345 clsdata
.hide
=FALSE
; /* unused, but initialise */
2347 if(!extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_unregister_class
,
2351 /* We still need to reset function upvalues. */
2353 extl_do_unregister_functions(fns
, INT_MAX
, cls
, clsdata
.refret
);
2360 /*{{{ Module registration */
2363 static bool extl_do_register_module(lua_State
*st
, ClassData
*clsdata
)
2365 lua_getglobal(st
, clsdata
->cls
);
2367 if(!lua_istable(st
, -1)){
2369 lua_pushvalue(st
, -1);
2370 lua_setglobal(st
, clsdata
->cls
);
2372 lua_pushfstring(st
, "luaextl_module_%s", clsdata
->cls
);
2373 lua_pushvalue(st
, -2);
2374 lua_rawset(st
, LUA_REGISTRYINDEX
);
2376 clsdata
->refret
=luaL_ref(st
, LUA_REGISTRYINDEX
);
2382 bool extl_register_module(const char *mdl
, ExtlExportedFnSpec
*fns
)
2387 clsdata
.parent
=NULL
;
2388 clsdata
.refret
=LUA_NOREF
;
2389 clsdata
.hide
=FALSE
; /* unused, but initialise */
2391 if(!extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_register_module
, &clsdata
))
2397 return extl_do_register_functions(fns
, INT_MAX
, mdl
, clsdata
.refret
);
2401 static bool extl_do_unregister_module(lua_State
*st
, ClassData
*clsdata
)
2403 lua_pushfstring(st
, "luaextl_module_%s", clsdata
->cls
);
2404 lua_pushvalue(st
, -1);
2406 lua_rawset(st
, LUA_REGISTRYINDEX
);
2407 clsdata
->refret
=luaL_ref(st
, LUA_REGISTRYINDEX
);
2413 void extl_unregister_module(const char *mdl
, ExtlExportedFnSpec
*fns
)
2418 clsdata
.parent
=NULL
;
2419 clsdata
.refret
=LUA_NOREF
;
2420 clsdata
.hide
=FALSE
; /* unused, but initialise */
2422 if(!extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_unregister_module
, &clsdata
))
2426 extl_do_unregister_functions(fns
, INT_MAX
, mdl
, clsdata
.refret
);
2441 static void write_escaped_string(FILE *f
, const char *str
)
2446 if(((*str
)&0x7f)<32 || *str
=='"' || *str
=='\\'){
2447 /* Lua uses decimal in escapes */
2448 fprintf(f
, "\\%03d", (int)(uchar
)(*str
));
2459 static void indent(FILE *f
, int lvl
)
2462 for(i
=0; i
<lvl
; i
++)
2467 static bool ser(lua_State
*st
, FILE *f
, int lvl
)
2470 lua_checkstack(st
, 5);
2472 switch(lua_type(st
, -1)){
2474 fprintf(f
, "%s", lua_toboolean(st
, -1) ? "true" : "false");
2477 fprintf(f
, "%s", lua_tostring(st
, -1));
2483 write_escaped_string(f
, lua_tostring(st
, -1));
2486 if(lvl
+1>=EXTL_MAX_SERIALISE_DEPTH
){
2487 extl_warn(TR("Maximal serialisation depth reached."));
2495 while(lua_next(st
, -2)!=0){
2496 lua_pushvalue(st
, -2);
2508 extl_warn(TR("Unable to serialise type %s."),
2509 lua_typename(st
, lua_type(st
, -1)));
2516 static bool extl_do_serialise(lua_State
*st
, SerData
*d
)
2518 if(!extl_getref(st
, d
->tab
))
2521 return ser(st
, d
->f
, 0);
2525 /* Tab must not contain recursive references! */
2526 extern bool extl_serialise(const char *file
, ExtlTab tab
)
2532 d
.f
=fopen(file
, "w");
2535 extl_warn_err_obj(file
);
2539 fprintf(d
.f
, TR("-- This file has been generated by %s. Do not edit.\n"), libtu_progname());
2540 fprintf(d
.f
, "return ");
2542 ret
=extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_serialise
, &d
);
2544 fprintf(d
.f
, "\n\n");
2551 void extl_dohook(lua_State
*L
, lua_Debug
*ar
)
2553 enum ExtlHookEvent event
;
2555 lua_getinfo(L
, "Sn", ar
);
2556 if (ar
->event
== LUA_HOOKCALL
)
2557 event
= EXTL_HOOK_ENTER
;
2558 else if (ar
->event
== LUA_HOOKRET
)
2559 event
= EXTL_HOOK_EXIT
;
2561 event
= EXTL_HOOK_UNKNOWN
;
2563 if (ar
->source
[0] == '@' && strcmp(ar
->what
, "Lua") == 0)
2564 (*current_hook
) (event
, ar
->name
, ar
->source
+ 1, ar
->linedefined
);
2567 int extl_sethook(ExtlHook hook
)
2569 current_hook
= hook
;
2570 return lua_sethook(l_st
, extl_dohook
, LUA_MASKCALL
| LUA_MASKRET
, -1);
2573 int extl_resethook()
2575 return lua_sethook(l_st
, NULL
, 0, -1);