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.
27 #include <libtu/obj.h>
28 #include <libtu/objp.h>
29 #include <libtu/dlist.h>
30 #include <libtu/util.h>
32 #include "readconfig.h"
36 #define MAGIC 0xf00ba7
38 /* Maximum number of parameters and return values for calls from Lua
39 * and (if va_copy is not available) return value from Lua functions.
43 static lua_State
*l_st
=NULL
;
44 ExtlHook current_hook
=NULL
;
46 static bool extl_stack_get(lua_State
*st
, int pos
, char type
,
47 bool copystring
, bool *wasdeadobject
,
50 static int extl_protected(lua_State
*st
);
52 #ifdef EXTL_LOG_ERRORS
53 static void flushtrace();
58 /*{{{ Safer rawget/set/getn */
61 #define CHECK_TABLE(ST, INDEX) luaL_checktype(ST, INDEX, LUA_TTABLE)
63 static int lua_objlen_check(lua_State
*st
, int index
)
65 CHECK_TABLE(st
, index
);
66 #if LUA_VERSION_NUM>=502
67 return lua_rawlen(st
, index
);
69 return lua_objlen(st
, index
);
74 static void lua_rawset_check(lua_State
*st
, int index
)
76 CHECK_TABLE(st
, index
);
77 lua_rawset(st
, index
);
81 static void lua_rawseti_check(lua_State
*st
, int index
, int n
)
83 CHECK_TABLE(st
, index
);
84 lua_rawseti(st
, index
, n
);
88 static void lua_rawget_check(lua_State
*st
, int index
)
90 CHECK_TABLE(st
, index
);
91 lua_rawget(st
, index
);
95 static void lua_rawgeti_check(lua_State
*st
, int index
, int n
)
97 CHECK_TABLE(st
, index
);
98 lua_rawgeti(st
, index
, n
);
105 /*{{{ A cpcall wrapper */
108 typedef bool ExtlCPCallFn(lua_State
*st
, void *ptr
);
118 static int extl_docpcall(lua_State
*st
)
120 ExtlCPCallParam
*param
=(ExtlCPCallParam
*)lua_touserdata(st
, -1);
122 /* Should be enough for most things */
123 if(!lua_checkstack(st
, 8)){
124 extl_warn(TR("Lua stack full."));
128 param
->retval
=param
->fn(st
, param
->udata
);
133 static bool extl_cpcall(lua_State
*st
, ExtlCPCallFn
*fn
, void *ptr
)
135 ExtlCPCallParam param
;
136 int oldtop
=lua_gettop(st
);
144 #if LUA_VERSION_NUM>=502
145 /* TODO: Call appropriate lua_checkstack!?
146 lua_checkstack(st, 2); */
147 lua_pushcfunction(st
, extl_docpcall
);
148 lua_pushlightuserdata(st
, ¶m
);
149 err
=lua_pcall(st
, 1, 0, 0);
151 err
=lua_cpcall(st
, extl_docpcall
, ¶m
);
154 extl_warn("%s", lua_tostring(st
, -1));
155 }else if(err
==LUA_ERRMEM
){
156 extl_warn("%s", strerror(ENOMEM
));
158 extl_warn(TR("Unknown Lua error."));
161 lua_settop(st
, oldtop
);
170 /*{{{ Obj userdata handling -- unsafe */
173 static int owned_cache_ref
=LUA_NOREF
;
176 static Obj
*extl_get_obj(lua_State
*st
, int pos
,
177 bool *invalid
, bool *dead
)
184 if(!lua_isuserdata(st
, pos
)){
185 *invalid
=!lua_isnil(st
, pos
);
189 if(!lua_getmetatable(st
, pos
))
192 /* If the userdata object is a proper Obj, metatable[MAGIC] must
193 * have been set to MAGIC.
195 lua_pushnumber(st
, MAGIC
);
196 lua_gettable(st
, -2);
197 val
=lua_tonumber(st
, -1);
201 ExtlProxy
*proxy
=(ExtlProxy
*)lua_touserdata(st
, pos
);
206 Obj
*obj
=EXTL_PROXY_OBJ(proxy
);
219 static void extl_uncache_(lua_State
*st
, Obj
*obj
)
221 if(EXTL_OBJ_OWNED(obj
)){
222 lua_rawgeti(st
, LUA_REGISTRYINDEX
, owned_cache_ref
);
223 lua_pushlightuserdata(st
, obj
);
227 lua_pushlightuserdata(st
, obj
);
229 lua_rawset(st
, LUA_REGISTRYINDEX
);
234 void extl_uncache(Obj
*obj
)
236 extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_uncache_
, obj
);
240 static void extl_push_obj(lua_State
*st
, Obj
*obj
)
249 if(EXTL_OBJ_CACHED(obj
)){
250 if(EXTL_OBJ_OWNED(obj
)){
251 lua_rawgeti(st
, LUA_REGISTRYINDEX
, owned_cache_ref
);
252 lua_pushlightuserdata(st
, obj
);
254 lua_remove(st
, -2); /* owned_cache */
256 lua_pushlightuserdata(st
, obj
);
257 lua_rawget(st
, LUA_REGISTRYINDEX
);
259 if(lua_isuserdata(st
, -1)){
260 D(fprintf(stderr
, "found %p cached\n", obj
));
266 D(fprintf(stderr
, "Creating %p\n", obj
));
268 proxy
=(ExtlProxy
*)lua_newuserdata(st
, sizeof(ExtlProxy
));
270 /* Lua shouldn't return if the allocation fails */
272 lua_pushfstring(st
, "luaextl_%s_metatable", OBJ_TYPESTR(obj
));
273 lua_gettable(st
, LUA_REGISTRYINDEX
);
274 if(lua_isnil(st
, -1)){
278 lua_setmetatable(st
, -2);
281 if(EXTL_OBJ_OWNED(obj
)){
282 lua_rawgeti(st
, LUA_REGISTRYINDEX
, owned_cache_ref
);
283 lua_pushlightuserdata(st
, obj
);
284 lua_pushvalue(st
, -3); /* the WWatch */
285 lua_rawset_check(st
, -3);
286 lua_pop(st
, 1); /* owned_cache */
288 lua_pushlightuserdata(st
, obj
);
289 lua_pushvalue(st
, -2); /* the WWatch */
290 lua_rawset_check(st
, LUA_REGISTRYINDEX
);
292 EXTL_BEGIN_PROXY_OBJ(proxy
, obj
);
297 /*{{{ Functions available to Lua code */
300 static int extl_obj_gc_handler(lua_State
*st
)
303 bool dead
=FALSE
, invalid
=FALSE
;
306 obj
=extl_get_obj(st
, 1, &invalid
, &dead
);
309 /* This should not happen, actually. Our object cache should
310 * hold references to all objects seen on the Lua side until
311 * they are destroyed.
316 proxy
=(ExtlProxy
*)lua_touserdata(st
, 1);
319 EXTL_END_PROXY_OBJ(proxy
, obj
);
321 if(EXTL_OBJ_OWNED(obj
))
322 EXTL_DESTROY_OWNED_OBJ(obj
);
328 static int extl_obj_typename(lua_State
*st
)
332 if(!extl_stack_get(st
, 1, 'o', FALSE
, NULL
, &obj
) || obj
==NULL
)
335 lua_pushstring(st
, EXTL_OBJ_TYPENAME(obj
));
339 /* Dummy code for documentation generation. */
342 * Return type name of \var{obj}.
344 EXTL_EXPORT_AS(global
, obj_typename
)
345 const char *__obj_typename(Obj
*obj
);
348 static int extl_obj_exists(lua_State
*st
)
352 extl_stack_get(st
, 1, 'o', FALSE
, NULL
, &obj
);
354 lua_pushboolean(st
, obj
!=NULL
);
359 /* Dummy code for documentation generation. */
362 * Does \var{obj} still exist on the C side of the application?
364 EXTL_EXPORT_AS(global
, obj_exists
)
365 bool __obj_exists(Obj
*obj
);
368 static int extl_obj_is(lua_State
*st
)
373 extl_stack_get(st
, 1, 'o', FALSE
, NULL
, &obj
);
376 lua_pushboolean(st
, 0);
378 tn
=lua_tostring(st
, 2);
379 lua_pushboolean(st
, EXTL_OBJ_IS(obj
, tn
));
385 /* Dummy code for documentation generation. */
388 * Is \var{obj} of type \var{typename}.
390 EXTL_EXPORT_AS(global
, obj_is
)
391 bool __obj_is(Obj
*obj
, const char *typename
);
394 static int extl_current_file_or_dir(lua_State
*st
, bool dir
)
399 if(lua_getstack(st
, 1, &ar
)!=1)
401 if(lua_getinfo(st
, "S", &ar
)==0)
404 if(ar
.source
==NULL
|| ar
.source
[0]!='@')
405 return 0; /* not a file */
410 lua_pushstring(st
, s
);
414 lua_pushstring(st
, ".");
416 lua_pushlstring(st
, s
, p
-s
);
422 extl_warn("Unable to get caller file from stack.");
427 static int extl_dopath(lua_State
*st
)
429 const char *toincl
, *cfdir
;
432 toincl
=luaL_checkstring(st
, 1);
433 complain
=!lua_toboolean(st
, 2);
435 if(extl_current_file_or_dir(st
, TRUE
)!=1){
436 res
=extl_read_config(toincl
, NULL
, complain
);
438 cfdir
=lua_tostring(st
, -1);
439 res
=extl_read_config(toincl
, cfdir
, complain
);
442 lua_pushboolean(st
, res
);
446 /* Dummy code for documentation generation. */
449 * Look up and execute another file with Lua code.
451 EXTL_EXPORT_AS(global
, dopath
)
452 bool dopath(const char *what
);
458 static bool extl_init_obj_info(lua_State
*st
)
460 static ExtlExportedFnSpec dummy
[]={
461 {NULL
, NULL
, NULL
, NULL
, NULL
, FALSE
, FALSE
, FALSE
}
464 extl_register_class("Obj", dummy
, NULL
);
466 /* Create cache for proxies to objects owned by Lua-side.
467 * These need to be in a weak table to ever be collected.
471 lua_pushstring(st
, "__mode");
472 lua_pushstring(st
, "v");
473 lua_rawset_check(st
, -3);
474 lua_setmetatable(st
, -2);
475 owned_cache_ref
=luaL_ref(st
, LUA_REGISTRYINDEX
);
477 lua_pushcfunction(st
, extl_obj_typename
);
478 lua_setglobal(st
, "obj_typename");
479 lua_pushcfunction(st
, extl_obj_is
);
480 lua_setglobal(st
, "obj_is");
481 lua_pushcfunction(st
, extl_obj_exists
);
482 lua_setglobal(st
, "obj_exists");
483 lua_pushcfunction(st
, extl_dopath
);
484 lua_setglobal(st
, "dopath");
485 lua_pushcfunction(st
, extl_protected
);
486 lua_setglobal(st
, "protected");
495 /*{{{ Error handling and reporting -- unsafe */
498 static int extl_stack_trace(lua_State
*st
)
504 lua_pushstring(st
, TR("Stack trace:"));
506 for( ; lua_getstack(st
, lvl
, &ar
); lvl
++){
509 if(lua_getinfo(st
, "Sln", &ar
)==0){
511 TR("\n(Unable to get debug info for level %d)"),
517 is_c
=(ar
.what
!=NULL
&& strcmp(ar
.what
, "C")==0);
519 if(!is_c
|| ar
.name
!=NULL
){
520 lua_pushfstring(st
, "\n%d %s", lvl
, ar
.short_src
);
521 if(ar
.currentline
!=-1)
522 lua_pushfstring(st
, ":%d", ar
.currentline
);
524 lua_pushfstring(st
, ": in '%s'", ar
.name
);
525 lua_concat(st
, 2+(ar
.currentline
!=-1)+(ar
.name
!=NULL
));
529 lua_pushstring(st
, TR("\n [Skipping unnamed C functions.]"));
530 /*lua_pushstring(st, "\n...skipping...");*/
540 #ifdef EXTL_LOG_ERRORS
542 static int extl_do_collect_errors(lua_State
*st
)
545 ErrorLog
*el
=(ErrorLog
*)lua_touserdata(st
, -1);
550 err
=lua_pcall(st
, n
, 0, 0);
553 extl_warn("%s", lua_tostring(st
, -1));
557 lua_pushstring(st
, el
->msgs
);
562 int extl_collect_errors(lua_State
*st
)
565 int n
=lua_gettop(st
);
568 lua_pushcfunction(st
, extl_do_collect_errors
);
570 lua_pushlightuserdata(st
, &el
);
574 err
=lua_pcall(st
, n
+1, 1, 0);
577 errorlog_deinit(&el
);
580 extl_warn(TR("Internal error."));
591 /*{{{ Init -- unsafe, but it doesn't matter at this point */
596 l_st
=luaL_newstate();
599 extl_warn(TR("Unable to initialize Lua."));
605 if(!extl_init_obj_info(l_st
)){
610 #ifdef EXTL_LOG_ERRORS
611 lua_pushcfunction(l_st
, extl_collect_errors
);
612 lua_setglobal(l_st
, "collect_errors");
629 /*{{{ Stack get/push -- all unsafe */
632 static bool extl_stack_get(lua_State
*st
, int pos
, char type
,
633 bool copystring
, bool *wasdeadobject
,
639 if(wasdeadobject
!=NULL
)
640 *wasdeadobject
=FALSE
;
644 *((bool*)valret
)=lua_toboolean(st
, pos
);
648 switch(lua_type(st
, pos
)){
650 if(type
!='i' && type
!='d' && type
!='a')
653 d
=lua_tonumber(st
, pos
);
662 ((ExtlAny
*)valret
)->type
='d';
663 ((ExtlAny
*)valret
)->value
.d
=d
;
667 *((double*)valret
)=d
;
675 ((ExtlAny
*)valret
)->type
='v';
676 }else if(type
=='t' || type
=='f'){
678 *((int*)valret
)=LUA_NOREF
;
679 }else if(type
=='s' || type
=='S'){
681 *((char**)valret
)=NULL
;
684 *((Obj
**)valret
)=NULL
;
691 if(type
!='s' && type
!='S' && type
!='a')
694 str
=lua_tostring(st
, pos
);
695 if(str
!=NULL
&& copystring
){
701 ((ExtlAny
*)valret
)->type
=(copystring
? 's' : 'S');
702 ((ExtlAny
*)valret
)->value
.s
=str
;
704 *((const char**)valret
)=str
;
710 if(type
!='f' && type
!='a')
713 lua_pushvalue(st
, pos
);
715 ((ExtlAny
*)valret
)->type
='f';
716 ((ExtlAny
*)valret
)->value
.f
=luaL_ref(st
, LUA_REGISTRYINDEX
);
718 *((int*)valret
)=luaL_ref(st
, LUA_REGISTRYINDEX
);
724 if(type
!='t' && type
!='a')
727 lua_pushvalue(st
, pos
);
729 ((ExtlAny
*)valret
)->type
='t';
730 ((ExtlAny
*)valret
)->value
.f
=luaL_ref(st
, LUA_REGISTRYINDEX
);
732 *((int*)valret
)=luaL_ref(st
, LUA_REGISTRYINDEX
);
738 if(type
=='o'|| type
=='a'){
739 bool invalid
=FALSE
, dead
=FALSE
;
740 Obj
*obj
=extl_get_obj(st
, pos
, &invalid
, &dead
);
741 if(wasdeadobject
!=NULL
)
745 ((ExtlAny
*)valret
)->type
='o';
746 ((ExtlAny
*)valret
)->value
.o
=obj
;
748 *((Obj
**)valret
)=obj
;
759 static void extl_to_any(ExtlAny
*a
, char type
, void *ptr
)
769 case 'i': a
->value
.i
=*(int*)ptr
; break;
770 case 'd': a
->value
.d
=*(double*)ptr
; break;
771 case 'b': a
->value
.b
=*(bool*)ptr
; break;
772 case 'o': a
->value
.o
=*(Obj
**)ptr
; break;
774 case 'S': a
->value
.s
=*(char**)ptr
; break;
775 case 't': a
->value
.t
=*(ExtlTab
*)ptr
; break;
776 case 'f': a
->value
.f
=*(ExtlFn
*)ptr
; break;
781 static void extl_to_any_vararg(ExtlAny
*a
, char type
, va_list *argsp
)
784 *a
=va_arg(*argsp
, ExtlAny
);
791 case 'i': a
->value
.i
=va_arg(*argsp
, int); break;
792 case 'd': a
->value
.d
=va_arg(*argsp
, double); break;
793 case 'b': a
->value
.b
=va_arg(*argsp
, bool); break;
794 case 'o': a
->value
.o
=va_arg(*argsp
, Obj
*); break;
796 case 'S': a
->value
.s
=va_arg(*argsp
, char*); break;
797 case 't': a
->value
.t
=va_arg(*argsp
, ExtlTab
); break;
798 case 'f': a
->value
.f
=va_arg(*argsp
, ExtlFn
); break;
803 static void extl_stack_pusha(lua_State
*st
, ExtlAny
*a
)
806 case 'i': lua_pushnumber(st
, a
->value
.i
); break;
807 case 'd': lua_pushnumber(st
, a
->value
.d
); break;
808 case 'b': lua_pushboolean(st
, a
->value
.b
); break;
809 case 'o': extl_push_obj(st
, a
->value
.o
); break;
811 case 'S': lua_pushstring(st
, a
->value
.s
); break;
812 case 't': lua_rawgeti(st
, LUA_REGISTRYINDEX
, a
->value
.t
); break;
813 case 'f': lua_rawgeti(st
, LUA_REGISTRYINDEX
, a
->value
.f
); break;
814 default: lua_pushnil(st
);
819 static void extl_stack_push(lua_State
*st
, char spec
, void *ptr
)
823 extl_to_any(&a
, spec
, ptr
);
824 extl_stack_pusha(st
, &a
);
828 static bool extl_stack_push_vararg(lua_State
*st
, char spec
, va_list *argsp
)
832 extl_to_any_vararg(&a
, spec
, argsp
);
833 extl_stack_pusha(st
, &a
);
845 enum{STRINGS_NONE
, STRINGS_NONCONST
, STRINGS_ALL
};
848 static void extl_any_free(ExtlAny
*a
, int strings
)
850 if((a
->type
=='s' && strings
!=STRINGS_NONE
) ||
851 (a
->type
=='S' && strings
==STRINGS_ALL
)){
853 free((char*)a
->value
.s
);
854 }else if(a
->type
=='t'){
855 extl_unref_table(a
->value
.t
);
856 }else if(a
->type
=='f'){
857 extl_unref_fn(a
->value
.f
);
862 static void extl_free(void *ptr
, char spec
, int strings
)
866 extl_to_any(&a
, spec
, ptr
);
867 extl_any_free(&a
, strings
);
874 /*{{{ Table and function references. */
877 static bool extl_getref(lua_State
*st
, int ref
)
879 lua_rawgeti(st
, LUA_REGISTRYINDEX
, ref
);
880 if(lua_isnil(st
, -1)){
889 static bool extl_do_unref(lua_State
*st
, int *refp
)
891 luaL_unref(st
, LUA_REGISTRYINDEX
, *refp
);
896 ExtlFn
extl_unref_fn(ExtlFn ref
)
898 extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_unref
, &ref
);
903 ExtlFn
extl_unref_table(ExtlTab ref
)
905 extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_unref
, &ref
);
912 ExtlFn
extl_fn_none()
918 ExtlTab
extl_table_none()
926 static bool extl_do_ref(lua_State
*st
, int *refp
)
928 if(!extl_getref(st
, *refp
))
930 *refp
=luaL_ref(st
, LUA_REGISTRYINDEX
);
935 ExtlTab
extl_ref_table(ExtlTab ref
)
937 if(extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_ref
, &ref
))
943 ExtlFn
extl_ref_fn(ExtlFn ref
)
945 if(extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_ref
, &ref
))
953 static bool extl_do_create_table(lua_State
*st
, int *refp
)
956 *refp
=luaL_ref(st
, LUA_REGISTRYINDEX
);
961 ExtlTab
extl_create_table()
964 if(extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_create_table
, &ref
))
978 static bool extl_do_eq(lua_State
*st
, EqParams
*ep
)
980 if(!extl_getref(st
, ep
->o1
))
982 if(!extl_getref(st
, ep
->o2
))
984 #if LUA_VERSION_NUM>=502
985 ep
->ret
=lua_compare(st
, -1, -2,LUA_OPEQ
);
987 ep
->ret
=lua_equal(st
, -1, -2);
993 bool extl_fn_eq(ExtlFn fn1
, ExtlFn fn2
)
999 extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_eq
, &ep
);
1004 bool extl_table_eq(ExtlTab t1
, ExtlTab t2
)
1010 extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_eq
, &ep
);
1029 static bool extl_table_dodo_get2(lua_State
*st
, TableParams2
*params
)
1034 lua_rawgeti(st
, LUA_REGISTRYINDEX
, params
->ref
);
1035 extl_stack_push_vararg(st
, params
->itype
, params
->argsp
);
1036 lua_gettable(st
, -2);
1037 if(lua_isnil(st
, -1))
1040 return extl_stack_get(st
, -1, params
->type
, TRUE
, NULL
,
1041 va_arg(*(params
->argsp
), void*));
1045 bool extl_table_get_vararg(ExtlTab ref
, char itype
, char type
, va_list *args
)
1047 TableParams2 params
;
1054 return extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_table_dodo_get2
, ¶ms
);
1058 bool extl_table_get(ExtlTab ref
, char itype
, char type
, ...)
1063 va_start(args
, type
);
1064 retval
=extl_table_get_vararg(ref
, itype
, type
, &args
);
1071 static bool extl_table_do_gets(ExtlTab ref
, const char *entry
,
1072 char type
, void *valret
)
1074 return extl_table_get(ref
, 's', type
, entry
, valret
);
1077 bool extl_table_gets_a(ExtlTab ref
, const char *entry
, ExtlAny
*ret
)
1079 return extl_table_do_gets(ref
, entry
, 'a', (void*)ret
);
1082 bool extl_table_gets_o(ExtlTab ref
, const char *entry
, Obj
**ret
)
1084 return extl_table_do_gets(ref
, entry
, 'o', (void*)ret
);
1087 bool extl_table_gets_i(ExtlTab ref
, const char *entry
, int *ret
)
1089 return extl_table_do_gets(ref
, entry
, 'i', (void*)ret
);
1092 bool extl_table_gets_d(ExtlTab ref
, const char *entry
, double *ret
)
1094 return extl_table_do_gets(ref
, entry
, 'd', (void*)ret
);
1097 bool extl_table_gets_b(ExtlTab ref
, const char *entry
, bool *ret
)
1099 return extl_table_do_gets(ref
, entry
, 'b', (void*)ret
);
1102 bool extl_table_gets_s(ExtlTab ref
, const char *entry
, char **ret
)
1104 return extl_table_do_gets(ref
, entry
, 's', (void*)ret
);
1107 bool extl_table_gets_f(ExtlTab ref
, const char *entry
, ExtlFn
*ret
)
1109 return extl_table_do_gets(ref
, entry
, 'f', (void*)ret
);
1112 bool extl_table_gets_t(ExtlTab ref
, const char *entry
, ExtlTab
*ret
)
1114 return extl_table_do_gets(ref
, entry
, 't', (void*)ret
);
1118 static bool extl_table_do_geti(ExtlTab ref
, int entry
, char type
, void *valret
)
1120 return extl_table_get(ref
, 'i', type
, entry
, valret
);
1123 bool extl_table_geti_a(ExtlTab ref
, int entry
, ExtlAny
*ret
)
1125 return extl_table_do_geti(ref
, entry
, 'a', (void*)ret
);
1128 bool extl_table_geti_o(ExtlTab ref
, int entry
, Obj
**ret
)
1130 return extl_table_do_geti(ref
, entry
, 'o', (void*)ret
);
1133 bool extl_table_geti_i(ExtlTab ref
, int entry
, int *ret
)
1135 return extl_table_do_geti(ref
, entry
, 'i', (void*)ret
);
1138 bool extl_table_geti_d(ExtlTab ref
, int entry
, double *ret
)
1140 return extl_table_do_geti(ref
, entry
, 'd', (void*)ret
);
1143 bool extl_table_geti_b(ExtlTab ref
, int entry
, bool *ret
)
1145 return extl_table_do_geti(ref
, entry
, 'b', (void*)ret
);
1148 bool extl_table_geti_s(ExtlTab ref
, int entry
, char **ret
)
1150 return extl_table_do_geti(ref
, entry
, 's', (void*)ret
);
1153 bool extl_table_geti_f(ExtlTab ref
, int entry
, ExtlFn
*ret
)
1155 return extl_table_do_geti(ref
, entry
, 'f', (void*)ret
);
1158 bool extl_table_geti_t(ExtlTab ref
, int entry
, ExtlTab
*ret
)
1160 return extl_table_do_geti(ref
, entry
, 't', (void*)ret
);
1170 static bool extl_table_do_get_n(lua_State
*st
, GetNParams
*params
)
1172 lua_rawgeti(st
, LUA_REGISTRYINDEX
, params
->ref
);
1173 params
->n
=lua_objlen_check(st
, -1);
1178 int extl_table_get_n(ExtlTab ref
)
1185 extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_table_do_get_n
, ¶ms
);
1197 static bool extl_table_dodo_set2(lua_State
*st
, TableParams2
*params
)
1199 lua_rawgeti(st
, LUA_REGISTRYINDEX
, params
->ref
);
1200 extl_stack_push_vararg(st
, params
->itype
, params
->argsp
);
1201 extl_stack_push_vararg(st
, params
->type
, params
->argsp
);
1202 lua_rawset_check(st
, -3);
1207 bool extl_table_set_vararg(ExtlTab ref
, char itype
, char type
, va_list *args
)
1209 TableParams2 params
;
1216 return extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_table_dodo_set2
, ¶ms
);
1220 bool extl_table_set(ExtlTab ref
, char itype
, char type
, ...)
1225 va_start(args
, type
);
1226 retval
=extl_table_set_vararg(ref
, itype
, type
, &args
);
1232 bool extl_table_sets_a(ExtlTab ref
, const char *entry
, const ExtlAny
*val
)
1234 return extl_table_set(ref
, 's', 'a', entry
, val
);
1237 bool extl_table_sets_o(ExtlTab ref
, const char *entry
, Obj
*val
)
1239 return extl_table_set(ref
, 's', 'o', entry
, val
);
1242 bool extl_table_sets_i(ExtlTab ref
, const char *entry
, int val
)
1244 return extl_table_set(ref
, 's', 'i', entry
, val
);
1247 bool extl_table_sets_d(ExtlTab ref
, const char *entry
, double val
)
1249 return extl_table_set(ref
, 's', 'd', entry
, val
);
1252 bool extl_table_sets_b(ExtlTab ref
, const char *entry
, bool val
)
1254 return extl_table_set(ref
, 's', 'b', entry
, val
);
1257 bool extl_table_sets_s(ExtlTab ref
, const char *entry
, const char *val
)
1259 return extl_table_set(ref
, 's', 'S', entry
, val
);
1262 bool extl_table_sets_f(ExtlTab ref
, const char *entry
, ExtlFn val
)
1264 return extl_table_set(ref
, 's', 'f', entry
, val
);
1267 bool extl_table_sets_t(ExtlTab ref
, const char *entry
, ExtlTab val
)
1269 return extl_table_set(ref
, 's', 't', entry
, val
);
1273 bool extl_table_seti_a(ExtlTab ref
, int entry
, const ExtlAny
*val
)
1275 return extl_table_set(ref
, 'i', 'a', entry
, val
);
1278 bool extl_table_seti_o(ExtlTab ref
, int entry
, Obj
*val
)
1280 return extl_table_set(ref
, 'i', 'o', entry
, val
);
1283 bool extl_table_seti_i(ExtlTab ref
, int entry
, int val
)
1285 return extl_table_set(ref
, 'i', 'i', entry
, val
);
1288 bool extl_table_seti_d(ExtlTab ref
, int entry
, double val
)
1290 return extl_table_set(ref
, 'i', 'd', entry
, val
);
1293 bool extl_table_seti_b(ExtlTab ref
, int entry
, bool val
)
1295 return extl_table_set(ref
, 'i', 'b', entry
, val
);
1298 bool extl_table_seti_s(ExtlTab ref
, int entry
, const char *val
)
1300 return extl_table_set(ref
, 'i', 'S', entry
, val
);
1303 bool extl_table_seti_f(ExtlTab ref
, int entry
, ExtlFn val
)
1305 return extl_table_set(ref
, 'i', 'f', entry
, val
);
1308 bool extl_table_seti_t(ExtlTab ref
, int entry
, ExtlTab val
)
1310 return extl_table_set(ref
, 'i', 't', entry
, val
);
1317 /*{{{Â Table/clear entry */
1320 static bool extl_table_dodo_clear2(lua_State
*st
, TableParams2
*params
)
1322 lua_rawgeti(st
, LUA_REGISTRYINDEX
, params
->ref
);
1323 extl_stack_push_vararg(st
, params
->itype
, params
->argsp
);
1325 lua_rawset_check(st
, -3);
1329 bool extl_table_clear_vararg(ExtlTab ref
, char itype
, va_list *args
)
1331 TableParams2 params
;
1335 /*params.type='?';*/
1338 return extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_table_dodo_clear2
, ¶ms
);
1341 bool extl_table_clear(ExtlTab ref
, char itype
, ...)
1346 va_start(args
, itype
);
1347 retval
=extl_table_clear_vararg(ref
, itype
, &args
);
1354 bool extl_table_clears(ExtlTab ref
, const char *entry
)
1356 return extl_table_clear(ref
, 's', entry
);
1359 bool extl_table_cleari(ExtlTab ref
, int entry
)
1361 return extl_table_clear(ref
, 'i', entry
);
1369 /*{{{ Table iteration */
1379 int extl_table_iter_do(lua_State
*st
, IterP
*par
)
1381 lua_rawgeti(st
, LUA_REGISTRYINDEX
, par
->ref
);
1385 while(lua_next(st
, -2)!=0){
1388 if(extl_stack_get(st
, -2, 'a', FALSE
, NULL
, &k
)){
1390 if(extl_stack_get(st
, -1, 'a', FALSE
, NULL
, &v
)){
1391 ret
=par
->fn(k
, v
, par
->d
);
1392 extl_any_free(&v
, STRINGS_NONE
);
1394 extl_any_free(&k
, STRINGS_NONE
);
1406 void extl_table_iter(ExtlTab ref
, ExtlIterFn
*fn
, void *d
)
1414 extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_table_iter_do
, &par
);
1421 /*{{{ Function calls to Lua */
1424 static bool extl_push_args(lua_State
*st
, const char *spec
, va_list *argsp
)
1429 if(!extl_stack_push_vararg(st
, *spec
, argsp
))
1445 #ifndef CF_HAS_VA_COPY
1446 void *ret_ptrs
[MAX_PARAMS
];
1451 static bool extl_get_retvals(lua_State
*st
, int m
, ExtlDoCallParam
*param
)
1454 const char *spec
=param
->rspec
;
1456 #ifdef CF_HAS_VA_COPY
1458 va_copy(args
, *(param
->args
));
1461 extl_warn(TR("Too many return values. Use a C compiler that has "
1462 "va_copy to support more."));
1469 #ifdef CF_HAS_VA_COPY
1470 ptr
=va_arg(args
, void*);
1472 ptr
=va_arg(*(param
->args
), void*);
1473 param
->ret_ptrs
[param
->nret
]=ptr
;
1475 if(!extl_stack_get(st
, -m
, *spec
, TRUE
, &dead
, ptr
)){
1476 /* This is the only place where we allow nil-objects */
1477 /*if(*spec=='o' && lua_isnil(st, -m)){
1481 extl_warn(TR("Returned dead object."));
1484 extl_warn(TR("Invalid return value (expected '%c', "
1485 "got lua type \"%s\")."),
1486 *spec
, lua_typename(st
, lua_type(st
, -m
)));
1496 #ifdef CF_HAS_VA_COPY
1504 /* The function to be called is expected on the top of stack st.
1505 * This function should be cpcalled through extl_cpcall_call (below), which
1506 * will take care that we don't leak anything in case of error.
1508 static bool extl_dodo_call_vararg(lua_State
*st
, ExtlDoCallParam
*param
)
1512 if(lua_isnil(st
, -1))
1515 if(param
->spec
!=NULL
)
1516 n
=strlen(param
->spec
);
1518 if(!lua_checkstack(st
, n
+8)){
1519 extl_warn(TR("Stack full."));
1524 if(!extl_push_args(st
, param
->spec
, param
->args
))
1528 if(param
->rspec
!=NULL
)
1529 m
=strlen(param
->rspec
);
1533 if(lua_pcall(st
, n
, m
, 0)!=0){
1534 extl_warn("%s", lua_tostring(st
, -1));
1539 return extl_get_retvals(st
, m
, param
);
1545 static bool extl_cpcall_call(lua_State
*st
, ExtlCPCallFn
*fn
,
1546 ExtlDoCallParam
*param
)
1553 if(extl_cpcall(st
, fn
, param
))
1556 /* If param.nret>0, there was an error getting some return value and
1557 * we must free what we got.
1560 for(i
=0; i
<param
->nret
; i
++){
1561 #ifdef CF_HAS_VA_COPY
1562 ptr
=va_arg(*(param
->args
), void*);
1564 ptr
=param
->ret_ptrs
[i
];
1566 extl_free(ptr
, *(param
->rspec
+i
), STRINGS_ALL
);
1573 static bool extl_do_call_vararg(lua_State
*st
, ExtlDoCallParam
*param
)
1575 if(!extl_getref(st
, *(ExtlFn
*)(param
->misc
)))
1577 return extl_dodo_call_vararg(st
, param
);
1581 bool extl_call_vararg(ExtlFn fnref
, const char *spec
,
1582 const char *rspec
, va_list *args
)
1584 ExtlDoCallParam param
;
1586 if(fnref
==LUA_NOREF
|| fnref
==LUA_REFNIL
)
1592 param
.misc
=(void*)&fnref
;
1594 return extl_cpcall_call(l_st
, (ExtlCPCallFn
*)extl_do_call_vararg
, ¶m
);
1598 bool extl_call(ExtlFn fnref
, const char *spec
, const char *rspec
, ...)
1603 va_start(args
, rspec
);
1604 retval
=extl_call_vararg(fnref
, spec
, rspec
, &args
);
1614 /*{{{ extl_loadfile/string */
1619 * - a stack with only the parameters to be passed to the function
1620 * - the function to call as an upvalue
1622 * - execute the function
1624 * - the number of return values
1626 static int call_loaded(lua_State
*st
)
1628 int nargs
=lua_gettop(st
);
1630 /* Get the loaded file/string as function */
1631 lua_pushvalue(st
, lua_upvalueindex(1));
1634 lua_call(st
, nargs
, LUA_MULTRET
);
1635 return lua_gettop(st
);
1647 * Stores a c closure in param->resptr containing a call to call_loaded with
1648 * as (fixed) parameter the function loaded from the file/buffer in param->src
1650 static bool extl_do_load(lua_State
*st
, ExtlLoadParam
*param
)
1655 res
=luaL_loadfile(st
, param
->src
);
1657 res
=luaL_loadbuffer(st
, param
->src
, strlen(param
->src
), param
->src
);
1661 extl_warn("%s", lua_tostring(st
, -1));
1665 lua_pushcclosure(st
, call_loaded
, 1);
1666 *(param
->resptr
)=luaL_ref(st
, LUA_REGISTRYINDEX
);
1672 bool extl_loadfile(const char *file
, ExtlFn
*ret
)
1674 ExtlLoadParam param
;
1679 return extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_load
, ¶m
);
1683 bool extl_loadstring(const char *str
, ExtlFn
*ret
)
1685 ExtlLoadParam param
;
1690 return extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_load
, ¶m
);
1697 /*{{{ L1 CH error logging */
1699 #ifdef EXTL_LOG_ERRORS
1701 INTRSTRUCT(WarnChain
);
1702 DECLSTRUCT(WarnChain
){
1705 WarnHandler
*old_handler
;
1710 static WarnChain
*warnchain
=NULL
;
1711 static int notrace
=0;
1714 static void l1_warn_handler(const char *message
)
1716 WarnChain
*ch
=warnchain
;
1717 static int called
=0;
1719 assert(warnchain
!=NULL
);
1721 if(called
==0 && notrace
==0)
1722 ch
->need_trace
=TRUE
;
1726 ch
->old_handler(message
);
1732 static void do_trace(WarnChain
*ch
)
1739 extl_stack_trace(ch
->st
);
1740 p
=lua_tostring(ch
->st
, -1);
1744 ch
->need_trace
=FALSE
;
1748 static void flushtrace()
1750 if(warnchain
&& warnchain
->need_trace
)
1751 do_trace(warnchain
);
1759 /*{{{ L1-CH safe functions */
1762 static int protect_count
=0;
1763 static ExtlSafelist
*safelists
=NULL
;
1766 void extl_protect(ExtlSafelist
*l
)
1771 LINK_ITEM(safelists
, l
, next
, prev
);
1778 void extl_unprotect(ExtlSafelist
*l
)
1780 assert(protect_count
>0);
1787 UNLINK_ITEM(safelists
, l
, next
, prev
);
1793 static bool extl_check_protected(ExtlExportedFnSpec
*spec
)
1799 if(protect_count
>0 && !spec
->safe
){
1800 for(l
=safelists
; l
!=NULL
; l
=l
->next
){
1802 for(j
=0; l
->list
[j
]!=NULL
; j
++){
1803 if(l
->list
[j
]==spec
->fn
)
1806 if(l
->list
[j
]==NULL
){
1822 /*{{{ L1 call handler */
1824 /* To get around potential memory leaks and corruption that could be caused
1825 * by Lua's longjmp-on-error lameness, The L1 call handler is divided into
1826 * two steps. In the first step we first setup a call to the second step.
1827 * At this point it is still fine if Lua raises an error. Then we set up
1828 * our warning handlers and stuff--at which point Lua's raising an error
1829 * would corrupt our data--and finally call the second step with lua_pcall.
1830 * Now the second step can safely call Lua's functions and do what is needed.
1831 * When the second step returns, we deallocate our data in the L1Param
1832 * structure that was passed to the second step and reset warning handlers.
1833 * After that it is again safe to call Lua's functions.
1837 ExtlL2Param ip
[MAX_PARAMS
];
1838 ExtlL2Param op
[MAX_PARAMS
];
1839 ExtlExportedFnSpec
*spec
;
1843 static L1Param
*current_param
=NULL
;
1846 static int extl_l1_call_handler2(lua_State
*st
)
1848 L1Param
*param
=current_param
;
1849 ExtlExportedFnSpec
*spec
=param
->spec
;
1852 D(fprintf(stderr
, "%s called\n", spec
->name
));
1854 if(!lua_checkstack(st
, MAX_PARAMS
+1)){
1855 extl_warn(TR("Stack full."));
1859 param
->ni
=(spec
->ispec
==NULL
? 0 : strlen(spec
->ispec
));
1861 for(i
=0; i
<param
->ni
; i
++){
1863 if(!extl_stack_get(st
, i
+1, spec
->ispec
[i
], FALSE
, &dead
,
1864 (void*)&(param
->ip
[i
]))){
1866 extl_warn(TR("Argument %d to %s is a dead object."),
1869 extl_warn(TR("Argument %d to %s is of invalid type. "
1870 "(Argument template is '%s', got lua type %s)."),
1871 i
+1, spec
->name
, spec
->ispec
,
1872 lua_typename(st
, lua_type(st
, i
+1)));
1883 if(!spec
->l2handler(spec
->fn
, param
->ip
, param
->op
))
1889 param
->no
=(spec
->ospec
==NULL
? 0 : strlen(spec
->ospec
));
1891 for(i
=0; i
<param
->no
; i
++)
1892 extl_stack_push(st
, spec
->ospec
[i
], (void*)&(param
->op
[i
]));
1898 static void extl_l1_finalize(L1Param
*param
)
1900 ExtlExportedFnSpec
*spec
=param
->spec
;
1903 for(i
=0; i
<param
->ii
; i
++)
1904 extl_free((void*)&(param
->ip
[i
]), spec
->ispec
[i
], STRINGS_NONE
);
1906 for(i
=0; i
<param
->no
; i
++)
1907 extl_free((void*)&(param
->op
[i
]), spec
->ospec
[i
], STRINGS_NONCONST
);
1912 static bool extl_l1_just_check_protected
=FALSE
;
1915 static int extl_l1_call_handler(lua_State
*st
)
1917 #ifdef EXTL_LOG_ERRORS
1920 L1Param param
={{NULL
, }, {NULL
, }, NULL
, 0, 0, 0};
1923 int n
=lua_gettop(st
);
1926 /* Get the info we need on the function, check it's ok, and then set
1927 * up a safe environment for extl_l1_call_handler2.
1929 param
.spec
=(ExtlExportedFnSpec
*)lua_touserdata(st
, lua_upvalueindex(1));
1931 if(param
.spec
==NULL
){
1932 extl_warn(TR("L1 call handler upvalues corrupt."));
1936 if(!param
.spec
->registered
){
1937 extl_warn(TR("Called function has been unregistered."));
1941 if(extl_l1_just_check_protected
){
1942 /* Just checking whether the function may be called. */
1943 lua_pushboolean(st
, !extl_check_protected(param
.spec
));
1947 if(!extl_check_protected(param
.spec
)){
1948 extl_warn(TR("Ignoring call to unsafe function \"%s\" in "
1949 "restricted mode."), param
.spec
->name
);
1954 lua_pushcfunction(st
, extl_l1_call_handler2
);
1957 old_param
=current_param
;
1958 current_param
=¶m
;
1960 #ifdef EXTL_LOG_ERRORS
1961 ch
.old_handler
=set_warn_handler(l1_warn_handler
);
1962 ch
.need_trace
=FALSE
;
1968 /* Ok, Lua may now freely fail in extl_l1_call_handler2, we can handle
1971 ret
=lua_pcall(st
, n
, LUA_MULTRET
, 0);
1973 /* Now that the actual call handler has returned, we need to free
1974 * any of our data before calling Lua again.
1976 current_param
=old_param
;
1977 extl_l1_finalize(¶m
);
1979 #ifdef EXTL_LOG_ERRORS
1981 set_warn_handler(ch
.old_handler
);
1983 /* Ok, we can now safely use Lua functions again without fear of
1989 p
=lua_tostring(st
, -1);
1995 if(ret
!=0 || ch
.need_trace
)
2007 * Is calling the function \var{fn} not allowed now? If \var{fn} is nil,
2008 * tells if some functions are not allowed to be called now due to
2011 EXTL_EXPORT_AS(global
, protected)
2012 bool __protected(ExtlFn fn
);
2014 static int extl_protected(lua_State
*st
)
2018 if(lua_isnil(st
, 1)){
2019 lua_pushboolean(st
, protect_count
>0);
2023 if(!lua_isfunction(st
, 1)){
2024 lua_pushboolean(st
, TRUE
);
2028 if(lua_tocfunction(st
, 1)!=(lua_CFunction
)extl_l1_call_handler
){
2029 lua_pushboolean(st
, FALSE
);
2033 extl_l1_just_check_protected
=TRUE
;
2034 ret
=lua_pcall(st
, 0, 1, 0);
2035 extl_l1_just_check_protected
=FALSE
;
2037 lua_pushboolean(st
, TRUE
);
2044 /*{{{ Function registration */
2048 ExtlExportedFnSpec
*spec
;
2054 static bool extl_do_register_function(lua_State
*st
, RegData
*data
)
2056 ExtlExportedFnSpec
*spec
=data
->spec
;
2057 #if LUA_VERSION_NUM>=502
2060 int ind
=LUA_GLOBALSINDEX
;
2063 if((spec
->ispec
!=NULL
&& strlen(spec
->ispec
)>MAX_PARAMS
) ||
2064 (spec
->ospec
!=NULL
&& strlen(spec
->ospec
)>MAX_PARAMS
)){
2065 extl_warn(TR("Function '%s' has more parameters than the level 1 "
2066 "call handler can handle"), spec
->name
);
2070 if(data
->table
!=LUA_NOREF
){
2071 lua_rawgeti(st
, LUA_REGISTRYINDEX
, data
->table
);
2074 #if LUA_VERSION_NUM>=502
2076 lua_pushglobaltable(st
);
2081 lua_pushstring(st
, spec
->name
);
2083 lua_pushlightuserdata(st
, spec
);
2084 lua_pushcclosure(st
, extl_l1_call_handler
, 1);
2086 lua_rawset_check(st
, ind
);
2092 static bool extl_do_register_functions(ExtlExportedFnSpec
*spec
, int max
,
2093 const char *cls
, int table
)
2100 regdata
.table
=table
;
2102 for(i
=0; spec
[i
].name
&& i
<max
; i
++){
2103 regdata
.spec
=&(spec
[i
]);
2104 if(!extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_register_function
,
2108 spec
[i
].registered
=TRUE
;
2115 bool extl_register_function(ExtlExportedFnSpec
*spec
)
2117 return extl_do_register_functions(spec
, 1, "", LUA_NOREF
);
2121 bool extl_register_functions(ExtlExportedFnSpec
*spec
)
2123 return extl_do_register_functions(spec
, INT_MAX
, "", LUA_NOREF
);
2127 static bool extl_do_unregister_function(lua_State
*st
, RegData
*data
)
2129 ExtlExportedFnSpec
*spec
=data
->spec
;
2130 #if LUA_VERSION_NUM>=502
2133 int ind
=LUA_GLOBALSINDEX
;
2136 if(data
->table
!=LUA_NOREF
){
2137 lua_rawgeti(st
, LUA_REGISTRYINDEX
, data
->table
);
2140 #if LUA_VERSION_NUM>=502
2142 lua_pushglobaltable(st
);
2147 /* Clear table.fn */
2148 lua_pushstring(st
, spec
->name
);
2150 lua_rawset_check(st
, ind
);
2156 static void extl_do_unregister_functions(ExtlExportedFnSpec
*spec
, int max
,
2157 const char *cls
, int table
)
2164 regdata
.table
=table
;
2166 for(i
=0; spec
[i
].name
&& i
<max
; i
++){
2167 regdata
.spec
=&(spec
[i
]);
2168 extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_unregister_function
,
2170 spec
[i
].registered
=FALSE
;
2174 void extl_unregister_function(ExtlExportedFnSpec
*spec
)
2176 extl_do_unregister_functions(spec
, 1, "", LUA_NOREF
);
2180 void extl_unregister_functions(ExtlExportedFnSpec
*spec
)
2182 extl_do_unregister_functions(spec
, INT_MAX
, "", LUA_NOREF
);
2189 /*{{{ Class registration */
2193 const char *cls
, *parent
;
2199 static bool extl_do_register_class(lua_State
*st
, ClassData
*data
)
2201 /* Create the globally visible WFoobar table in which the function
2202 * references reside.
2206 /* Set type information.
2208 lua_pushstring(st
, "__typename");
2209 lua_pushstring(st
, data
->cls
);
2210 lua_settable(st
, -3);
2212 /* If we have a parent class (i.e. class!=Obj), we want also the parent's
2213 * functions visible in this table so set up a metatable to do so.
2215 if(data
->parent
!=NULL
){
2216 /* Get luaextl_ParentClass_metatable */
2217 lua_pushfstring(st
, "luaextl_%s_metatable", data
->parent
);
2218 lua_gettable(st
, LUA_REGISTRYINDEX
);
2219 if(!lua_istable(st
, -1)){
2220 extl_warn("Could not find metatable for parent class %s of %s.\n",
2221 data
->parent
, data
->cls
);
2224 /* Create our metatable */
2226 /* Get parent_metatable.__index */
2227 lua_pushstring(st
, "__index");
2228 lua_pushvalue(st
, -1);
2229 /* Stack: cls, parent_meta, meta, "__index", "__index" */
2230 lua_gettable(st
, -4);
2231 /* Stack: cls, parent_meta, meta, "__index", parent_meta.__index */
2232 lua_pushvalue(st
, -1);
2234 /* Stack: cls, parent_meta, meta, parent_meta.__index, "__index", parent_meta.__index */
2235 lua_rawset_check(st
, -4);
2236 /* Stack: cls, parent_meta, meta, parent_meta.__index */
2237 lua_pushstring(st
, "__parentclass");
2239 /* Stack: cls, parent_meta, meta, "__parentclass", parent_meta.__index */
2240 lua_settable(st
, -5);
2241 /* Stack: cls, parent_meta, meta, */
2242 lua_setmetatable(st
, -3);
2247 /* Set the global WFoobar */
2248 lua_pushvalue(st
, -1);
2249 data
->refret
=luaL_ref(st
, LUA_REGISTRYINDEX
); /* TODO: free on failure */
2251 #if LUA_VERSION_NUM>=502
2252 lua_pushglobaltable(st
);
2253 lua_pushstring(st
, data
->cls
);
2254 lua_pushvalue(st
, -3);
2258 lua_pushstring(st
, data
->cls
);
2259 lua_pushvalue(st
, -2);
2260 lua_rawset(st
, LUA_GLOBALSINDEX
);
2264 /* New we create a metatable for the actual objects with __gc metamethod
2265 * and __index pointing to the table created above. The MAGIC entry is
2266 * used to check that userdatas passed to us really are Watches with a
2271 lua_pushnumber(st
, MAGIC
);
2272 lua_pushnumber(st
, MAGIC
);
2273 lua_rawset_check(st
, -3);
2275 lua_pushstring(st
, "__index");
2276 lua_pushvalue(st
, -3);
2277 lua_rawset_check(st
, -3); /* set metatable.__index=WFoobar created above */
2278 lua_pushstring(st
, "__gc");
2279 lua_pushcfunction(st
, extl_obj_gc_handler
);
2280 lua_rawset_check(st
, -3); /* set metatable.__gc=extl_obj_gc_handler */
2281 lua_pushfstring(st
, "luaextl_%s_metatable", data
->cls
);
2283 lua_rawset(st
, LUA_REGISTRYINDEX
);
2289 bool extl_register_class(const char *cls
, ExtlExportedFnSpec
*fns
,
2294 clsdata
.parent
=parent
;
2295 clsdata
.refret
=LUA_NOREF
;
2296 clsdata
.hide
=(strcmp(cls
, "Obj")==0);/*(fns==NULL);*/
2298 D(assert(strcmp(cls
, "Obj")==0 || parent
!=NULL
));
2300 if(!extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_register_class
, &clsdata
))
2306 return extl_do_register_functions(fns
, INT_MAX
, cls
, clsdata
.refret
);
2310 static void extl_do_unregister_class(lua_State
*st
, ClassData
*data
)
2312 /* Get reference from registry to the metatable. */
2313 lua_pushfstring(st
, "luaextl_%s_metatable", data
->cls
);
2314 lua_pushvalue(st
, -1);
2315 lua_gettable(st
, LUA_REGISTRYINDEX
);
2316 /* Get __index and return it for resetting the functions. */
2317 lua_pushstring(st
, "__index");
2318 lua_gettable(st
, -2);
2319 data
->refret
=luaL_ref(st
, LUA_REGISTRYINDEX
);
2321 /* Set the entry from registry to nil. */
2323 lua_rawset(st
, LUA_REGISTRYINDEX
);
2325 /* Reset the global reference to the class to nil. */
2326 #if LUA_VERSION_NUM>=502
2327 lua_pushglobaltable(st
);
2328 lua_pushstring(st
, data
->cls
);
2333 lua_pushstring(st
, data
->cls
);
2335 lua_rawset(st
, LUA_GLOBALSINDEX
);
2340 void extl_unregister_class(const char *cls
, ExtlExportedFnSpec
*fns
)
2344 clsdata
.parent
=NULL
;
2345 clsdata
.refret
=LUA_NOREF
;
2346 clsdata
.hide
=FALSE
; /* unused, but initialise */
2348 if(!extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_unregister_class
,
2352 /* We still need to reset function upvalues. */
2354 extl_do_unregister_functions(fns
, INT_MAX
, cls
, clsdata
.refret
);
2361 /*{{{ Module registration */
2364 static bool extl_do_register_module(lua_State
*st
, ClassData
*clsdata
)
2366 lua_getglobal(st
, clsdata
->cls
);
2368 if(!lua_istable(st
, -1)){
2370 lua_pushvalue(st
, -1);
2371 lua_setglobal(st
, clsdata
->cls
);
2373 lua_pushfstring(st
, "luaextl_module_%s", clsdata
->cls
);
2374 lua_pushvalue(st
, -2);
2375 lua_rawset(st
, LUA_REGISTRYINDEX
);
2377 clsdata
->refret
=luaL_ref(st
, LUA_REGISTRYINDEX
);
2383 bool extl_register_module(const char *mdl
, ExtlExportedFnSpec
*fns
)
2388 clsdata
.parent
=NULL
;
2389 clsdata
.refret
=LUA_NOREF
;
2390 clsdata
.hide
=FALSE
; /* unused, but initialise */
2392 if(!extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_register_module
, &clsdata
))
2398 return extl_do_register_functions(fns
, INT_MAX
, mdl
, clsdata
.refret
);
2402 static bool extl_do_unregister_module(lua_State
*st
, ClassData
*clsdata
)
2404 lua_pushfstring(st
, "luaextl_module_%s", clsdata
->cls
);
2405 lua_pushvalue(st
, -1);
2407 lua_rawset(st
, LUA_REGISTRYINDEX
);
2408 clsdata
->refret
=luaL_ref(st
, LUA_REGISTRYINDEX
);
2414 void extl_unregister_module(const char *mdl
, ExtlExportedFnSpec
*fns
)
2419 clsdata
.parent
=NULL
;
2420 clsdata
.refret
=LUA_NOREF
;
2421 clsdata
.hide
=FALSE
; /* unused, but initialise */
2423 if(!extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_unregister_module
, &clsdata
))
2427 extl_do_unregister_functions(fns
, INT_MAX
, mdl
, clsdata
.refret
);
2442 static void write_escaped_string(FILE *f
, const char *str
)
2447 if(((*str
)&0x7f)<32 || *str
=='"' || *str
=='\\'){
2448 /* Lua uses decimal in escapes */
2449 fprintf(f
, "\\%03d", (int)(uchar
)(*str
));
2460 static void indent(FILE *f
, int lvl
)
2463 for(i
=0; i
<lvl
; i
++)
2468 static bool ser(lua_State
*st
, FILE *f
, int lvl
)
2471 lua_checkstack(st
, 5);
2473 switch(lua_type(st
, -1)){
2475 fprintf(f
, "%s", lua_toboolean(st
, -1) ? "true" : "false");
2478 fprintf(f
, "%s", lua_tostring(st
, -1));
2484 write_escaped_string(f
, lua_tostring(st
, -1));
2487 if(lvl
+1>=EXTL_MAX_SERIALISE_DEPTH
){
2488 extl_warn(TR("Maximal serialisation depth reached."));
2496 while(lua_next(st
, -2)!=0){
2497 lua_pushvalue(st
, -2);
2509 extl_warn(TR("Unable to serialize type %s."),
2510 lua_typename(st
, lua_type(st
, -1)));
2517 static bool extl_do_serialize(lua_State
*st
, SerData
*d
)
2519 if(!extl_getref(st
, d
->tab
))
2522 return ser(st
, d
->f
, 0);
2526 /* Tab must not contain recursive references! */
2527 extern bool extl_serialize(const char *file
, ExtlTab tab
)
2532 char tmp_file
[strlen(file
) + 8];
2535 strcat(tmp_file
, file
);
2536 strcat(tmp_file
, ".XXXXXX");
2537 fd
= mkstemp(tmp_file
);
2539 extl_warn_err_obj(tmp_file
);
2544 d
.f
=fdopen(fd
, "w");
2547 extl_warn_err_obj(tmp_file
);
2552 fprintf(d
.f
, TR("-- This file has been generated by %s. Do not edit.\n"), libtu_progname());
2553 fprintf(d
.f
, "return ");
2555 ret
=extl_cpcall(l_st
, (ExtlCPCallFn
*)extl_do_serialize
, &d
);
2557 fprintf(d
.f
, "\n\n");
2561 if(ret
&& rename(tmp_file
, file
) != 0) {
2562 extl_warn_err_obj(file
);
2573 void extl_dohook(lua_State
*L
, lua_Debug
*ar
)
2575 enum ExtlHookEvent event
;
2577 lua_getinfo(L
, "Sn", ar
);
2578 if (ar
->event
== LUA_HOOKCALL
)
2579 event
= EXTL_HOOK_ENTER
;
2580 else if (ar
->event
== LUA_HOOKRET
)
2581 event
= EXTL_HOOK_EXIT
;
2583 event
= EXTL_HOOK_UNKNOWN
;
2585 if (ar
->source
[0] == '@' && strcmp(ar
->what
, "Lua") == 0)
2586 (*current_hook
) (event
, ar
->name
, ar
->source
+ 1, ar
->linedefined
);
2589 int extl_sethook(ExtlHook hook
)
2591 current_hook
= hook
;
2592 return lua_sethook(l_st
, extl_dohook
, LUA_MASKCALL
| LUA_MASKRET
, -1);
2595 int extl_resethook()
2597 return lua_sethook(l_st
, NULL
, 0, -1);