4 * Copyright (c) Tuomo Valkonen 1999-2005.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
25 #include <libtu/obj.h>
26 #include <libtu/objp.h>
27 #include <libtu/dlist.h>
29 #include "readconfig.h"
33 #define MAGIC 0xf00ba7
35 /* Maximum number of parameters and return values for calls from Lua
36 * and (if va_copy is not available) return value from Lua functions.
40 static lua_State *l_st=NULL;
42 static bool extl_stack_get(lua_State *st, int pos, char type,
43 bool copystring, bool *wasdeadobject,
46 static int extl_protected(lua_State *st);
48 #ifdef EXTL_LOG_ERRORS
49 static void flushtrace();
55 /*{{{ Safer rawget/set/getn */
58 #define CHECK_TABLE(ST, INDEX) luaL_checktype(ST, INDEX, LUA_TTABLE)
60 static int luaL_getn_check(lua_State *st, int index)
62 CHECK_TABLE(st, index);
63 return luaL_getn(st, index);
67 static void lua_rawset_check(lua_State *st, int index)
69 CHECK_TABLE(st, index);
70 lua_rawset(st, index);
74 static void lua_rawseti_check(lua_State *st, int index, int n)
76 CHECK_TABLE(st, index);
77 lua_rawseti(st, index, n);
81 static void lua_rawget_check(lua_State *st, int index)
83 CHECK_TABLE(st, index);
84 lua_rawget(st, index);
88 static void lua_rawgeti_check(lua_State *st, int index, int n)
90 CHECK_TABLE(st, index);
91 lua_rawgeti(st, index, n);
98 /*{{{ A cpcall wrapper */
101 typedef bool ExtlCPCallFn(lua_State *st, void *ptr);
111 static int extl_docpcall(lua_State *st)
113 ExtlCPCallParam *param=(ExtlCPCallParam*)lua_touserdata(st, -1);
115 /* Should be enough for most things */
116 if(!lua_checkstack(st, 8)){
117 extl_warn(TR("Lua stack full."));
121 param->retval=param->fn(st, param->udata);
126 static bool extl_cpcall(lua_State *st, ExtlCPCallFn *fn, void *ptr)
128 ExtlCPCallParam param;
129 int oldtop=lua_gettop(st);
137 err=lua_cpcall(st, extl_docpcall, ¶m);
139 extl_warn("%s", lua_tostring(st, -1));
140 }else if(err==LUA_ERRMEM){
141 extl_warn("%s", strerror(ENOMEM));
143 extl_warn(TR("Unknown Lua error."));
146 lua_settop(st, oldtop);
155 /*{{{ Obj userdata handling -- unsafe */
158 static int owned_cache_ref=LUA_NOREF;
161 static Obj *extl_get_obj(lua_State *st, int pos,
162 bool *invalid, bool *dead)
169 if(!lua_isuserdata(st, pos)){
170 *invalid=!lua_isnil(st, pos);
174 if(!lua_getmetatable(st, pos))
177 /* If the userdata object is a proper Obj, metatable[MAGIC] must
178 * have been set to MAGIC.
180 lua_pushnumber(st, MAGIC);
181 lua_gettable(st, -2);
182 val=lua_tonumber(st, -1);
186 ExtlProxy *proxy=(ExtlProxy*)lua_touserdata(st, pos);
191 Obj *obj=EXTL_PROXY_OBJ(proxy);
204 static void extl_uncache_(lua_State *st, Obj *obj)
206 if(EXTL_OBJ_OWNED(obj)){
207 lua_rawgeti(st, LUA_REGISTRYINDEX, owned_cache_ref);
208 lua_pushlightuserdata(st, obj);
212 lua_pushlightuserdata(st, obj);
214 lua_rawset(st, LUA_REGISTRYINDEX);
219 void extl_uncache(Obj *obj)
221 extl_cpcall(l_st, (ExtlCPCallFn*)extl_uncache_, obj);
225 static void extl_push_obj(lua_State *st, Obj *obj)
234 if(EXTL_OBJ_CACHED(obj)){
235 if(EXTL_OBJ_OWNED(obj)){
236 lua_rawgeti(st, LUA_REGISTRYINDEX, owned_cache_ref);
237 lua_pushlightuserdata(st, obj);
239 lua_remove(st, -2); /* owned_cache */
241 lua_pushlightuserdata(st, obj);
242 lua_rawget(st, LUA_REGISTRYINDEX);
244 if(lua_isuserdata(st, -1)){
245 D(fprintf(stderr, "found %p cached\n", obj));
251 D(fprintf(stderr, "Creating %p\n", obj));
253 proxy=(ExtlProxy*)lua_newuserdata(st, sizeof(ExtlProxy));
255 /* Lua shouldn't return if the allocation fails */
257 lua_pushfstring(st, "luaextl_%s_metatable", OBJ_TYPESTR(obj));
258 lua_gettable(st, LUA_REGISTRYINDEX);
259 if(lua_isnil(st, -1)){
263 lua_setmetatable(st, -2);
266 if(EXTL_OBJ_OWNED(obj)){
267 lua_rawgeti(st, LUA_REGISTRYINDEX, owned_cache_ref);
268 lua_pushlightuserdata(st, obj);
269 lua_pushvalue(st, -3); /* the WWatch */
270 lua_rawset_check(st, -3);
271 lua_pop(st, 1); /* owned_cache */
273 lua_pushlightuserdata(st, obj);
274 lua_pushvalue(st, -2); /* the WWatch */
275 lua_rawset_check(st, LUA_REGISTRYINDEX);
277 EXTL_BEGIN_PROXY_OBJ(proxy, obj);
282 /*{{{ Functions available to Lua code */
285 static int extl_obj_gc_handler(lua_State *st)
288 bool dead=FALSE, invalid=FALSE;
291 obj=extl_get_obj(st, 1, &invalid, &dead);
294 /* This should not happen, actually. Our object cache should
295 * hold references to all objects seen on the Lua side until
296 * they are destroyed.
301 proxy=(ExtlProxy*)lua_touserdata(st, 1);
304 EXTL_END_PROXY_OBJ(proxy, obj);
306 if(EXTL_OBJ_OWNED(obj))
307 EXTL_DESTROY_OWNED_OBJ(obj);
313 static int extl_obj_typename(lua_State *st)
317 if(!extl_stack_get(st, 1, 'o', FALSE, NULL, &obj) || obj==NULL)
320 lua_pushstring(st, EXTL_OBJ_TYPENAME(obj));
324 /* Dummy code for documentation generation. */
327 * Return type name of \var{obj}.
329 EXTL_EXPORT_AS(global, obj_typename)
330 const char *__obj_typename(Obj *obj);
333 static int extl_obj_exists(lua_State *st)
337 extl_stack_get(st, 1, 'o', FALSE, NULL, &obj);
339 lua_pushboolean(st, obj!=NULL);
344 /* Dummy code for documentation generation. */
347 * Does \var{obj} still exist on the C side of Ion?
349 EXTL_EXPORT_AS(global, obj_exists)
350 bool __obj_exists(Obj *obj);
353 static int extl_obj_is(lua_State *st)
358 extl_stack_get(st, 1, 'o', FALSE, NULL, &obj);
361 lua_pushboolean(st, 0);
363 tn=lua_tostring(st, 2);
364 lua_pushboolean(st, EXTL_OBJ_IS(obj, tn));
370 /* Dummy code for documentation generation. */
373 * Is \var{obj} of type \var{typename}.
375 EXTL_EXPORT_AS(global, obj_is)
376 bool __obj_is(Obj *obj, const char *typename);
379 static int extl_current_file_or_dir(lua_State *st, bool dir)
385 if(lua_getstack(st, 1, &ar)!=1)
387 if(lua_getinfo(st, "S", &ar)==0)
390 if(ar.source==NULL || ar.source[0]!='@')
391 return 0; /* not a file */
396 lua_pushstring(st, s);
400 lua_pushstring(st, ".");
402 lua_pushlstring(st, s, p-s);
408 extl_warn("Unable to get caller file from stack.");
413 static int extl_dopath(lua_State *st)
415 const char *toincl, *cfdir;
418 toincl=luaL_checkstring(st, 1);
419 complain=!lua_toboolean(st, 2);
421 if(extl_current_file_or_dir(st, TRUE)!=1){
422 res=extl_read_config(toincl, NULL, complain);
424 cfdir=lua_tostring(st, -1);
425 res=extl_read_config(toincl, cfdir, complain);
428 lua_pushboolean(st, res);
432 /* Dummy code for documentation generation. */
435 * Look up and execute another file with Lua code.
437 EXTL_EXPORT_AS(global, dopath)
438 bool dopath(const char *what);
444 static bool extl_init_obj_info(lua_State *st)
446 static ExtlExportedFnSpec dummy[]={
447 {NULL, NULL, NULL, NULL, NULL, FALSE, FALSE, FALSE}
450 extl_register_class("Obj", dummy, NULL);
452 /* Create cache for proxies to objects owned by Lua-side.
453 * These need to be in a weak table to ever be collected.
457 lua_pushstring(st, "__mode");
458 lua_pushstring(st, "v");
459 lua_rawset_check(st, -3);
460 lua_setmetatable(st, -2);
461 owned_cache_ref=lua_ref(st, -1);
463 lua_pushcfunction(st, extl_obj_typename);
464 lua_setglobal(st, "obj_typename");
465 lua_pushcfunction(st, extl_obj_is);
466 lua_setglobal(st, "obj_is");
467 lua_pushcfunction(st, extl_obj_exists);
468 lua_setglobal(st, "obj_exists");
469 lua_pushcfunction(st, extl_dopath);
470 lua_setglobal(st, "dopath");
471 lua_pushcfunction(st, extl_protected);
472 lua_setglobal(st, "protected");
481 /*{{{ Error handling and reporting -- unsafe */
484 static int extl_stack_trace(lua_State *st)
490 lua_pushstring(st, TR("Stack trace:"));
492 for( ; lua_getstack(st, lvl, &ar); lvl++){
495 if(lua_getinfo(st, "Sln", &ar)==0){
497 TR("\n(Unable to get debug info for level %d)"),
503 is_c=(ar.what!=NULL && strcmp(ar.what, "C")==0);
505 if(!is_c || ar.name!=NULL){
506 lua_pushfstring(st, "\n%d %s", lvl, ar.short_src);
507 if(ar.currentline!=-1)
508 lua_pushfstring(st, ":%d", ar.currentline);
510 lua_pushfstring(st, ": in '%s'", ar.name);
511 lua_concat(st, 2+(ar.currentline!=-1)+(ar.name!=NULL));
515 lua_pushstring(st, TR("\n [Skipping unnamed C functions.]"));
516 /*lua_pushstring(st, "\n...skipping...");*/
526 #ifdef EXTL_LOG_ERRORS
528 static int extl_do_collect_errors(lua_State *st)
531 ErrorLog *el=(ErrorLog*)lua_touserdata(st, -1);
536 err=lua_pcall(st, n, 0, 0);
539 extl_warn("%s", lua_tostring(st, -1));
543 lua_pushstring(st, el->msgs);
548 int extl_collect_errors(lua_State *st)
551 int n=lua_gettop(st);
554 lua_pushcfunction(st, extl_do_collect_errors);
556 lua_pushlightuserdata(st, &el);
560 err=lua_pcall(st, n+1, 1, 0);
563 errorlog_deinit(&el);
566 extl_warn(TR("Internal error."));
577 /*{{{ Init -- unsafe, but it doesn't matter at this point */
582 l_st=luaL_newstate();
585 extl_warn(TR("Unable to initialize Lua."));
589 /* This is equivalent to calling all the ones below but it also includes
590 * the debug library, so I went with those in case there was a reason not
591 * to include the debug library.
595 lua_pushcfunction(l_st, luaopen_base);
596 lua_call(l_st, 0, 0);
598 lua_pushcfunction(l_st, luaopen_table);
599 lua_call(l_st, 0, 0);
601 lua_pushcfunction(l_st, luaopen_io);
602 lua_call(l_st, 0, 0);
604 lua_pushcfunction(l_st, luaopen_os);
605 lua_call(l_st, 0, 0);
607 lua_pushcfunction(l_st, luaopen_string);
608 lua_call(l_st, 0, 0);
610 lua_pushcfunction(l_st, luaopen_math);
611 lua_call(l_st, 0, 0);
613 lua_pushcfunction(l_st, luaopen_package);
614 lua_call(l_st, 0, 0);
616 if(!extl_init_obj_info(l_st)){
621 #ifdef EXTL_LOG_ERRORS
622 lua_pushcfunction(l_st, extl_collect_errors);
623 lua_setglobal(l_st, "collect_errors");
640 /*{{{ Stack get/push -- all unsafe */
643 static bool extl_stack_get(lua_State *st, int pos, char type,
644 bool copystring, bool *wasdeadobject,
650 if(wasdeadobject!=NULL)
651 *wasdeadobject=FALSE;
655 *((bool*)valret)=lua_toboolean(st, pos);
659 switch(lua_type(st, pos)){
661 if(type!='i' && type!='d' && type!='a')
664 d=lua_tonumber(st, pos);
673 ((ExtlAny*)valret)->type='d';
674 ((ExtlAny*)valret)->value.d=d;
678 *((double*)valret)=d;
686 ((ExtlAny*)valret)->type='v';
687 }else if(type=='t' || type=='f'){
689 *((int*)valret)=LUA_NOREF;
690 }else if(type=='s' || type=='S'){
692 *((char**)valret)=NULL;
695 *((Obj**)valret)=NULL;
702 if(type!='s' && type!='S' && type!='a')
705 str=lua_tostring(st, pos);
706 if(str!=NULL && copystring){
712 ((ExtlAny*)valret)->type=(copystring ? 's' : 'S');
713 ((ExtlAny*)valret)->value.s=str;
715 *((const char**)valret)=str;
721 if(type!='f' && type!='a')
724 lua_pushvalue(st, pos);
726 ((ExtlAny*)valret)->type='f';
727 ((ExtlAny*)valret)->value.f=lua_ref(st, 1);
729 *((int*)valret)=lua_ref(st, 1);
735 if(type!='t' && type!='a')
738 lua_pushvalue(st, pos);
740 ((ExtlAny*)valret)->type='t';
741 ((ExtlAny*)valret)->value.f=lua_ref(st, 1);
743 *((int*)valret)=lua_ref(st, 1);
749 if(type=='o'|| type=='a'){
750 bool invalid=FALSE, dead=FALSE;
751 Obj *obj=extl_get_obj(st, pos, &invalid, &dead);
752 if(wasdeadobject!=NULL)
756 ((ExtlAny*)valret)->type='o';
757 ((ExtlAny*)valret)->value.o=obj;
759 *((Obj**)valret)=obj;
770 static void extl_to_any(ExtlAny *a, char type, void *ptr)
780 case 'i': a->value.i=*(int*)ptr; break;
781 case 'd': a->value.d=*(double*)ptr; break;
782 case 'b': a->value.b=*(bool*)ptr; break;
783 case 'o': a->value.o=*(Obj**)ptr; break;
785 case 'S': a->value.s=*(char**)ptr; break;
786 case 't': a->value.t=*(ExtlTab*)ptr; break;
787 case 'f': a->value.f=*(ExtlFn*)ptr; break;
792 static void extl_to_any_vararg(ExtlAny *a, char type, va_list *argsp)
795 *a=va_arg(*argsp, ExtlAny);
802 case 'i': a->value.i=va_arg(*argsp, int); break;
803 case 'd': a->value.d=va_arg(*argsp, double); break;
804 case 'b': a->value.b=va_arg(*argsp, bool); break;
805 case 'o': a->value.o=va_arg(*argsp, Obj*); break;
807 case 'S': a->value.s=va_arg(*argsp, char*); break;
808 case 't': a->value.t=va_arg(*argsp, ExtlTab); break;
809 case 'f': a->value.f=va_arg(*argsp, ExtlFn); break;
814 static void extl_stack_pusha(lua_State *st, ExtlAny *a)
817 case 'i': lua_pushnumber(st, a->value.i); break;
818 case 'd': lua_pushnumber(st, a->value.d); break;
819 case 'b': lua_pushboolean(st, a->value.b); break;
820 case 'o': extl_push_obj(st, a->value.o); break;
822 case 'S': lua_pushstring(st, a->value.s); break;
823 case 't': lua_rawgeti(st, LUA_REGISTRYINDEX, a->value.t); break;
824 case 'f': lua_rawgeti(st, LUA_REGISTRYINDEX, a->value.f); break;
825 default: lua_pushnil(st);
830 static void extl_stack_push(lua_State *st, char spec, void *ptr)
834 extl_to_any(&a, spec, ptr);
835 extl_stack_pusha(st, &a);
839 static bool extl_stack_push_vararg(lua_State *st, char spec, va_list *argsp)
843 extl_to_any_vararg(&a, spec, argsp);
844 extl_stack_pusha(st, &a);
856 enum{STRINGS_NONE, STRINGS_NONCONST, STRINGS_ALL};
859 static void extl_any_free(ExtlAny *a, int strings)
861 if((a->type=='s' && strings!=STRINGS_NONE) ||
862 (a->type=='S' && strings==STRINGS_ALL)){
864 free((char*)a->value.s);
865 }else if(a->type=='t'){
866 extl_unref_table(a->value.t);
867 }else if(a->type=='f'){
868 extl_unref_fn(a->value.f);
873 static void extl_free(void *ptr, char spec, int strings)
877 extl_to_any(&a, spec, ptr);
878 extl_any_free(&a, strings);
885 /*{{{ Table and function references. */
888 static bool extl_getref(lua_State *st, int ref)
890 lua_rawgeti(st, LUA_REGISTRYINDEX, ref);
891 if(lua_isnil(st, -1)){
900 static bool extl_do_unref(lua_State *st, int *refp)
902 lua_unref(st, *refp);
907 ExtlFn extl_unref_fn(ExtlFn ref)
909 extl_cpcall(l_st, (ExtlCPCallFn*)extl_do_unref, &ref);
914 ExtlFn extl_unref_table(ExtlTab ref)
916 extl_cpcall(l_st, (ExtlCPCallFn*)extl_do_unref, &ref);
923 ExtlFn extl_fn_none()
929 ExtlTab extl_table_none()
937 static bool extl_do_ref(lua_State *st, int *refp)
939 if(!extl_getref(st, *refp))
941 *refp=lua_ref(st, 1);
946 ExtlTab extl_ref_table(ExtlTab ref)
948 if(extl_cpcall(l_st, (ExtlCPCallFn*)extl_do_ref, &ref))
954 ExtlFn extl_ref_fn(ExtlFn ref)
956 if(extl_cpcall(l_st, (ExtlCPCallFn*)extl_do_ref, &ref))
964 static bool extl_do_create_table(lua_State *st, int *refp)
967 *refp=lua_ref(st, 1);
972 ExtlTab extl_create_table()
975 if(extl_cpcall(l_st, (ExtlCPCallFn*)extl_do_create_table, &ref))
989 static bool extl_do_eq(lua_State *st, EqParams *ep)
991 if(!extl_getref(st, ep->o1))
993 if(!extl_getref(st, ep->o2))
995 ep->ret=lua_equal(st, -1, -2);
1000 bool extl_fn_eq(ExtlFn fn1, ExtlFn fn2)
1006 extl_cpcall(l_st, (ExtlCPCallFn*)extl_do_eq, &ep);
1011 bool extl_table_eq(ExtlTab t1, ExtlTab t2)
1017 extl_cpcall(l_st, (ExtlCPCallFn*)extl_do_eq, &ep);
1036 static bool extl_table_dodo_get2(lua_State *st, TableParams2 *params)
1041 lua_rawgeti(st, LUA_REGISTRYINDEX, params->ref);
1042 extl_stack_push_vararg(st, params->itype, params->argsp);
1043 lua_gettable(st, -2);
1044 if(lua_isnil(st, -1))
1047 return extl_stack_get(st, -1, params->type, TRUE, NULL,
1048 va_arg(*(params->argsp), void*));
1052 bool extl_table_get_vararg(ExtlTab ref, char itype, char type, va_list *args)
1054 TableParams2 params;
1061 return extl_cpcall(l_st, (ExtlCPCallFn*)extl_table_dodo_get2, ¶ms);
1065 bool extl_table_get(ExtlTab ref, char itype, char type, ...)
1070 va_start(args, type);
1071 retval=extl_table_get_vararg(ref, itype, type, &args);
1078 static bool extl_table_do_gets(ExtlTab ref, const char *entry,
1079 char type, void *valret)
1081 return extl_table_get(ref, 's', type, entry, valret);
1084 bool extl_table_gets_a(ExtlTab ref, const char *entry, ExtlAny *ret)
1086 return extl_table_do_gets(ref, entry, 'a', (void*)ret);
1089 bool extl_table_gets_o(ExtlTab ref, const char *entry, Obj **ret)
1091 return extl_table_do_gets(ref, entry, 'o', (void*)ret);
1094 bool extl_table_gets_i(ExtlTab ref, const char *entry, int *ret)
1096 return extl_table_do_gets(ref, entry, 'i', (void*)ret);
1099 bool extl_table_gets_d(ExtlTab ref, const char *entry, double *ret)
1101 return extl_table_do_gets(ref, entry, 'd', (void*)ret);
1104 bool extl_table_gets_b(ExtlTab ref, const char *entry, bool *ret)
1106 return extl_table_do_gets(ref, entry, 'b', (void*)ret);
1109 bool extl_table_gets_s(ExtlTab ref, const char *entry, char **ret)
1111 return extl_table_do_gets(ref, entry, 's', (void*)ret);
1114 bool extl_table_gets_f(ExtlTab ref, const char *entry, ExtlFn *ret)
1116 return extl_table_do_gets(ref, entry, 'f', (void*)ret);
1119 bool extl_table_gets_t(ExtlTab ref, const char *entry, ExtlTab *ret)
1121 return extl_table_do_gets(ref, entry, 't', (void*)ret);
1125 static bool extl_table_do_geti(ExtlTab ref, int entry, char type, void *valret)
1127 return extl_table_get(ref, 'i', type, entry, valret);
1130 bool extl_table_geti_a(ExtlTab ref, int entry, ExtlAny *ret)
1132 return extl_table_do_geti(ref, entry, 'a', (void*)ret);
1135 bool extl_table_geti_o(ExtlTab ref, int entry, Obj **ret)
1137 return extl_table_do_geti(ref, entry, 'o', (void*)ret);
1140 bool extl_table_geti_i(ExtlTab ref, int entry, int *ret)
1142 return extl_table_do_geti(ref, entry, 'i', (void*)ret);
1145 bool extl_table_geti_d(ExtlTab ref, int entry, double *ret)
1147 return extl_table_do_geti(ref, entry, 'd', (void*)ret);
1150 bool extl_table_geti_b(ExtlTab ref, int entry, bool *ret)
1152 return extl_table_do_geti(ref, entry, 'b', (void*)ret);
1155 bool extl_table_geti_s(ExtlTab ref, int entry, char **ret)
1157 return extl_table_do_geti(ref, entry, 's', (void*)ret);
1160 bool extl_table_geti_f(ExtlTab ref, int entry, ExtlFn *ret)
1162 return extl_table_do_geti(ref, entry, 'f', (void*)ret);
1165 bool extl_table_geti_t(ExtlTab ref, int entry, ExtlTab *ret)
1167 return extl_table_do_geti(ref, entry, 't', (void*)ret);
1177 static bool extl_table_do_get_n(lua_State *st, GetNParams *params)
1179 lua_rawgeti(st, LUA_REGISTRYINDEX, params->ref);
1180 params->n=luaL_getn_check(st, -1);
1185 int extl_table_get_n(ExtlTab ref)
1193 extl_cpcall(l_st, (ExtlCPCallFn*)extl_table_do_get_n, ¶ms);
1205 static bool extl_table_dodo_set2(lua_State *st, TableParams2 *params)
1207 lua_rawgeti(st, LUA_REGISTRYINDEX, params->ref);
1208 extl_stack_push_vararg(st, params->itype, params->argsp);
1209 extl_stack_push_vararg(st, params->type, params->argsp);
1210 lua_rawset_check(st, -3);
1215 bool extl_table_set_vararg(ExtlTab ref, char itype, char type, va_list *args)
1217 TableParams2 params;
1224 return extl_cpcall(l_st, (ExtlCPCallFn*)extl_table_dodo_set2, ¶ms);
1228 bool extl_table_set(ExtlTab ref, char itype, char type, ...)
1233 va_start(args, type);
1234 retval=extl_table_set_vararg(ref, itype, type, &args);
1240 bool extl_table_sets_a(ExtlTab ref, const char *entry, const ExtlAny *val)
1242 return extl_table_set(ref, 's', 'a', entry, val);
1245 bool extl_table_sets_o(ExtlTab ref, const char *entry, Obj *val)
1247 return extl_table_set(ref, 's', 'o', entry, val);
1250 bool extl_table_sets_i(ExtlTab ref, const char *entry, int val)
1252 return extl_table_set(ref, 's', 'i', entry, val);
1255 bool extl_table_sets_d(ExtlTab ref, const char *entry, double val)
1257 return extl_table_set(ref, 's', 'd', entry, val);
1260 bool extl_table_sets_b(ExtlTab ref, const char *entry, bool val)
1262 return extl_table_set(ref, 's', 'b', entry, val);
1265 bool extl_table_sets_s(ExtlTab ref, const char *entry, const char *val)
1267 return extl_table_set(ref, 's', 'S', entry, val);
1270 bool extl_table_sets_f(ExtlTab ref, const char *entry, ExtlFn val)
1272 return extl_table_set(ref, 's', 'f', entry, val);
1275 bool extl_table_sets_t(ExtlTab ref, const char *entry, ExtlTab val)
1277 return extl_table_set(ref, 's', 't', entry, val);
1281 bool extl_table_seti_a(ExtlTab ref, int entry, const ExtlAny *val)
1283 return extl_table_set(ref, 'i', 'a', entry, val);
1286 bool extl_table_seti_o(ExtlTab ref, int entry, Obj *val)
1288 return extl_table_set(ref, 'i', 'o', entry, val);
1291 bool extl_table_seti_i(ExtlTab ref, int entry, int val)
1293 return extl_table_set(ref, 'i', 'i', entry, val);
1296 bool extl_table_seti_d(ExtlTab ref, int entry, double val)
1298 return extl_table_set(ref, 'i', 'd', entry, val);
1301 bool extl_table_seti_b(ExtlTab ref, int entry, bool val)
1303 return extl_table_set(ref, 'i', 'b', entry, val);
1306 bool extl_table_seti_s(ExtlTab ref, int entry, const char *val)
1308 return extl_table_set(ref, 'i', 'S', entry, val);
1311 bool extl_table_seti_f(ExtlTab ref, int entry, ExtlFn val)
1313 return extl_table_set(ref, 'i', 'f', entry, val);
1316 bool extl_table_seti_t(ExtlTab ref, int entry, ExtlTab val)
1318 return extl_table_set(ref, 'i', 't', entry, val);
1325 /*{{{Â Table/clear entry */
1328 static bool extl_table_dodo_clear2(lua_State *st, TableParams2 *params)
1330 lua_rawgeti(st, LUA_REGISTRYINDEX, params->ref);
1331 extl_stack_push_vararg(st, params->itype, params->argsp);
1333 lua_rawset_check(st, -3);
1337 bool extl_table_clear_vararg(ExtlTab ref, char itype, va_list *args)
1339 TableParams2 params;
1343 /*params.type='?';*/
1346 return extl_cpcall(l_st, (ExtlCPCallFn*)extl_table_dodo_clear2, ¶ms);
1349 bool extl_table_clear(ExtlTab ref, char itype, ...)
1354 va_start(args, itype);
1355 retval=extl_table_clear_vararg(ref, itype, &args);
1362 bool extl_table_clears(ExtlTab ref, const char *entry)
1364 return extl_table_clear(ref, 's', entry);
1367 bool extl_table_cleari(ExtlTab ref, int entry)
1369 return extl_table_clear(ref, 'i', entry);
1377 /*{{{ Table iteration */
1387 int extl_table_iter_do(lua_State *st, IterP *par)
1389 lua_rawgeti(st, LUA_REGISTRYINDEX, par->ref);
1393 while(lua_next(st, -2)!=0){
1396 if(extl_stack_get(st, -2, 'a', FALSE, NULL, &k)){
1398 if(extl_stack_get(st, -1, 'a', FALSE, NULL, &v)){
1399 ret=par->fn(k, v, par->d);
1400 extl_any_free(&v, STRINGS_NONE);
1402 extl_any_free(&k, STRINGS_NONE);
1414 void extl_table_iter(ExtlTab ref, ExtlIterFn *fn, void *d)
1422 extl_cpcall(l_st, (ExtlCPCallFn*)extl_table_iter_do, &par);
1429 /*{{{ Function calls to Lua */
1432 static bool extl_push_args(lua_State *st, const char *spec, va_list *argsp)
1437 if(!extl_stack_push_vararg(st, *spec, argsp))
1453 #ifndef CF_HAS_VA_COPY
1454 void *ret_ptrs[MAX_PARAMS];
1459 static bool extl_get_retvals(lua_State *st, int m, ExtlDoCallParam *param)
1462 const char *spec=param->rspec;
1464 #ifdef CF_HAS_VA_COPY
1466 va_copy(args, *(param->args));
1469 extl_warn(TR("Too many return values. Use a C compiler that has "
1470 "va_copy to support more."));
1477 #ifdef CF_HAS_VA_COPY
1478 ptr=va_arg(args, void*);
1480 ptr=va_arg(*(param->args), void*);
1481 param->ret_ptrs[param->nret]=ptr;
1483 if(!extl_stack_get(st, -m, *spec, TRUE, &dead, ptr)){
1484 /* This is the only place where we allow nil-objects */
1485 /*if(*spec=='o' && lua_isnil(st, -m)){
1489 extl_warn(TR("Returned dead object."));
1492 extl_warn(TR("Invalid return value (expected '%c', "
1493 "got lua type \"%s\")."),
1494 *spec, lua_typename(st, lua_type(st, -m)));
1504 #ifdef CF_HAS_VA_COPY
1512 /* The function to be called is expected on the top of stack st.
1513 * This function should be cpcalled through extl_cpcall_call (below), which
1514 * will take care that we don't leak anything in case of error.
1516 static bool extl_dodo_call_vararg(lua_State *st, ExtlDoCallParam *param)
1521 if(lua_isnil(st, -1))
1524 if(param->spec!=NULL)
1525 n=strlen(param->spec);
1527 if(!lua_checkstack(st, n+8)){
1528 extl_warn(TR("Stack full."));
1533 if(!extl_push_args(st, param->spec, param->args))
1537 if(param->rspec!=NULL)
1538 m=strlen(param->rspec);
1542 if(lua_pcall(st, n, m, 0)!=0){
1543 extl_warn("%s", lua_tostring(st, -1));
1548 return extl_get_retvals(st, m, param);
1554 static bool extl_cpcall_call(lua_State *st, ExtlCPCallFn *fn,
1555 ExtlDoCallParam *param)
1562 if(extl_cpcall(st, fn, param))
1565 /* If param.nret>0, there was an error getting some return value and
1566 * we must free what we got.
1569 for(i=0; i<param->nret; i++){
1570 #ifdef CF_HAS_VA_COPY
1571 ptr=va_arg(*(param->args), void*);
1573 ptr=param->ret_ptrs[i];
1575 extl_free(ptr, *(param->rspec+i), STRINGS_ALL);
1582 static bool extl_do_call_vararg(lua_State *st, ExtlDoCallParam *param)
1584 if(!extl_getref(st, *(ExtlFn*)(param->misc)))
1586 return extl_dodo_call_vararg(st, param);
1590 bool extl_call_vararg(ExtlFn fnref, const char *spec,
1591 const char *rspec, va_list *args)
1593 ExtlDoCallParam param;
1595 if(fnref==LUA_NOREF || fnref==LUA_REFNIL)
1601 param.misc=(void*)&fnref;
1603 return extl_cpcall_call(l_st, (ExtlCPCallFn*)extl_do_call_vararg, ¶m);
1607 bool extl_call(ExtlFn fnref, const char *spec, const char *rspec, ...)
1612 va_start(args, rspec);
1613 retval=extl_call_vararg(fnref, spec, rspec, &args);
1623 /*{{{ extl_loadfile/string */
1626 static int call_loaded(lua_State *st)
1628 int i, nargs=lua_gettop(st);
1630 /* Get the loaded file/string as function */
1631 lua_pushvalue(st, lua_upvalueindex(1));
1634 lua_getfenv(st, -1);
1635 lua_pushstring(st, "arg");
1639 for(i=1; i<=nargs; i++){
1640 lua_pushvalue(st, i);
1641 lua_rawseti_check(st, -2, i);
1647 lua_rawset_check(st, -3);
1649 lua_call(st, 0, LUA_MULTRET);
1650 return (lua_gettop(st)-nargs);
1661 static bool extl_do_load(lua_State *st, ExtlLoadParam *param)
1666 res=luaL_loadfile(st, param->src);
1668 res=luaL_loadbuffer(st, param->src, strlen(param->src), param->src);
1672 extl_warn("%s", lua_tostring(st, -1));
1676 lua_newtable(st); /* Create new environment */
1677 /* Now there's fn, newenv in stack */
1678 lua_newtable(st); /* Create metatable */
1679 lua_pushstring(st, "__index");
1680 lua_getfenv(st, -4); /* Get old environment */
1681 lua_rawset_check(st, -3); /* Set metatable.__index */
1682 lua_pushstring(st, "__newindex");
1683 lua_getfenv(st, -4); /* Get old environment */
1684 lua_rawset_check(st, -3); /* Set metatable.__newindex */
1685 /* Now there's fn, newenv, meta in stack */
1686 lua_setmetatable(st, -2); /* Set metatable for new environment */
1687 lua_setfenv(st, -2);
1688 /* Now there should be just fn in stack */
1690 /* Callloaded will put any parameters it gets in the table 'arg' in
1691 * the newly created environment.
1693 lua_pushcclosure(st, call_loaded, 1);
1694 *(param->resptr)=lua_ref(st, -1);
1700 bool extl_loadfile(const char *file, ExtlFn *ret)
1702 ExtlLoadParam param;
1707 return extl_cpcall(l_st, (ExtlCPCallFn*)extl_do_load, ¶m);
1711 bool extl_loadstring(const char *str, ExtlFn *ret)
1713 ExtlLoadParam param;
1718 return extl_cpcall(l_st, (ExtlCPCallFn*)extl_do_load, ¶m);
1725 /*{{{ L1 CH error logging */
1727 #ifdef EXTL_LOG_ERRORS
1729 INTRSTRUCT(WarnChain);
1730 DECLSTRUCT(WarnChain){
1733 WarnHandler *old_handler;
1738 static WarnChain *warnchain=NULL;
1739 static int notrace=0;
1742 static void l1_warn_handler(const char *message)
1744 WarnChain *ch=warnchain;
1745 static int called=0;
1747 assert(warnchain!=NULL);
1749 if(called==0 && notrace==0)
1750 ch->need_trace=TRUE;
1754 ch->old_handler(message);
1760 static void do_trace(WarnChain *ch)
1767 extl_stack_trace(ch->st);
1768 p=lua_tostring(ch->st, -1);
1772 ch->need_trace=FALSE;
1776 static void flushtrace()
1778 if(warnchain && warnchain->need_trace)
1779 do_trace(warnchain);
1787 /*{{{ L1-CH safe functions */
1790 static int protect_count=0;
1791 static ExtlSafelist *safelists=NULL;
1794 void extl_protect(ExtlSafelist *l)
1799 LINK_ITEM(safelists, l, next, prev);
1806 void extl_unprotect(ExtlSafelist *l)
1808 assert(protect_count>0);
1815 UNLINK_ITEM(safelists, l, next, prev);
1821 static bool extl_check_protected(ExtlExportedFnSpec *spec)
1827 if(protect_count>0 && !spec->safe){
1828 for(l=safelists; l!=NULL; l=l->next){
1830 for(j=0; l->list[j]!=NULL; j++){
1831 if(l->list[j]==spec->fn)
1834 if(l->list[j]==NULL){
1850 /*{{{ L1 call handler */
1852 /* To get around potential memory leaks and corruption that could be caused
1853 * by Lua's longjmp-on-error lameness, The L1 call handler is divided into
1854 * two steps. In the first step we first setup a call to the second step.
1855 * At this point it is still fine if Lua raises an error. Then we set up
1856 * our warning handlers and stuff--at which point Lua's raising an error
1857 * would corrupt our data--and finally call the second step with lua_pcall.
1858 * Now the second step can safely call Lua's functions and do what is needed.
1859 * When the second step returns, we deallocate our data in the L1Param
1860 * structure that was passed to the second step and reset warning handlers.
1861 * After that it is again safe to call Lua's functions.
1865 ExtlL2Param ip[MAX_PARAMS];
1866 ExtlL2Param op[MAX_PARAMS];
1867 ExtlExportedFnSpec *spec;
1871 static L1Param *current_param=NULL;
1874 static int extl_l1_call_handler2(lua_State *st)
1876 L1Param *param=current_param;
1877 ExtlExportedFnSpec *spec=param->spec;
1880 D(fprintf(stderr, "%s called\n", spec->name));
1882 if(!lua_checkstack(st, MAX_PARAMS+1)){
1883 extl_warn(TR("Stack full."));
1887 param->ni=(spec->ispec==NULL ? 0 : strlen(spec->ispec));
1889 for(i=0; i<param->ni; i++){
1891 if(!extl_stack_get(st, i+1, spec->ispec[i], FALSE, &dead,
1892 (void*)&(param->ip[i]))){
1894 extl_warn(TR("Argument %d to %s is a dead object."),
1897 extl_warn(TR("Argument %d to %s is of invalid type. "
1898 "(Argument template is '%s', got lua type %s)."),
1899 i+1, spec->name, spec->ispec,
1900 lua_typename(st, lua_type(st, i+1)));
1911 if(!spec->l2handler(spec->fn, param->ip, param->op))
1917 param->no=(spec->ospec==NULL ? 0 : strlen(spec->ospec));
1919 for(i=0; i<param->no; i++)
1920 extl_stack_push(st, spec->ospec[i], (void*)&(param->op[i]));
1926 static void extl_l1_finalize(L1Param *param)
1928 ExtlExportedFnSpec *spec=param->spec;
1931 for(i=0; i<param->ii; i++)
1932 extl_free((void*)&(param->ip[i]), spec->ispec[i], STRINGS_NONE);
1934 for(i=0; i<param->no; i++)
1935 extl_free((void*)&(param->op[i]), spec->ospec[i], STRINGS_NONCONST);
1940 static bool extl_l1_just_check_protected=FALSE;
1943 static int extl_l1_call_handler(lua_State *st)
1945 #ifdef EXTL_LOG_ERRORS
1948 L1Param param={{NULL, }, {NULL, }, NULL, 0, 0, 0};
1951 int n=lua_gettop(st);
1954 /* Get the info we need on the function, check it's ok, and then set
1955 * up a safe environment for extl_l1_call_handler2.
1957 param.spec=(ExtlExportedFnSpec*)lua_touserdata(st, lua_upvalueindex(1));
1959 if(param.spec==NULL){
1960 extl_warn(TR("L1 call handler upvalues corrupt."));
1964 if(!param.spec->registered){
1965 extl_warn(TR("Called function has been unregistered."));
1969 if(extl_l1_just_check_protected){
1970 /* Just checking whether the function may be called. */
1971 lua_pushboolean(st, !extl_check_protected(param.spec));
1975 if(!extl_check_protected(param.spec)){
1976 extl_warn(TR("Attempt to call an unsafe function \"%s\" in "
1977 "restricted mode."), param.spec->name);
1982 lua_pushcfunction(st, extl_l1_call_handler2);
1985 old_param=current_param;
1986 current_param=¶m;
1988 #ifdef EXTL_LOG_ERRORS
1989 ch.old_handler=set_warn_handler(l1_warn_handler);
1990 ch.need_trace=FALSE;
1996 /* Ok, Lua may now freely fail in extl_l1_call_handler2, we can handle
1999 ret=lua_pcall(st, n, LUA_MULTRET, 0);
2001 /* Now that the actual call handler has returned, we need to free
2002 * any of our data before calling Lua again.
2004 current_param=old_param;
2005 extl_l1_finalize(¶m);
2007 #ifdef EXTL_LOG_ERRORS
2009 set_warn_handler(ch.old_handler);
2011 /* Ok, we can now safely use Lua functions again without fear of
2017 p=lua_tostring(st, -1);
2023 if(ret!=0 || ch.need_trace)
2035 * Is calling the function \var{fn} not allowed now? If \var{fn} is nil,
2036 * tells if some functions are not allowed to be called now due to
2039 EXTL_EXPORT_AS(global, protected)
2040 bool __protected(ExtlFn fn);
2042 static int extl_protected(lua_State *st)
2046 if(lua_isnil(st, 1)){
2047 lua_pushboolean(st, protect_count>0);
2051 if(!lua_isfunction(st, 1)){
2052 lua_pushboolean(st, TRUE);
2056 if(lua_tocfunction(st, 1)!=(lua_CFunction)extl_l1_call_handler){
2057 lua_pushboolean(st, FALSE);
2061 extl_l1_just_check_protected=TRUE;
2062 ret=lua_pcall(st, 0, 1, 0);
2063 extl_l1_just_check_protected=FALSE;
2065 lua_pushboolean(st, TRUE);
2072 /*{{{ Function registration */
2076 ExtlExportedFnSpec *spec;
2082 static bool extl_do_register_function(lua_State *st, RegData *data)
2084 ExtlExportedFnSpec *spec=data->spec, *spec2;
2085 int ind=LUA_GLOBALSINDEX;
2087 if((spec->ispec!=NULL && strlen(spec->ispec)>MAX_PARAMS) ||
2088 (spec->ospec!=NULL && strlen(spec->ospec)>MAX_PARAMS)){
2089 extl_warn(TR("Function '%s' has more parameters than the level 1 "
2090 "call handler can handle"), spec->name);
2094 if(data->table!=LUA_NOREF){
2095 lua_rawgeti(st, LUA_REGISTRYINDEX, data->table);
2099 lua_pushstring(st, spec->name);
2101 lua_pushlightuserdata(st, spec);
2102 lua_pushcclosure(st, extl_l1_call_handler, 1);
2104 lua_rawset_check(st, ind);
2110 static bool extl_do_register_functions(ExtlExportedFnSpec *spec, int max,
2111 const char *cls, int table)
2118 regdata.table=table;
2120 for(i=0; spec[i].name && i<max; i++){
2121 regdata.spec=&(spec[i]);
2122 if(!extl_cpcall(l_st, (ExtlCPCallFn*)extl_do_register_function,
2126 spec[i].registered=TRUE;
2133 bool extl_register_function(ExtlExportedFnSpec *spec)
2135 return extl_do_register_functions(spec, 1, "", LUA_NOREF);
2139 bool extl_register_functions(ExtlExportedFnSpec *spec)
2141 return extl_do_register_functions(spec, INT_MAX, "", LUA_NOREF);
2145 static bool extl_do_unregister_function(lua_State *st, RegData *data)
2147 ExtlExportedFnSpec *spec=data->spec;
2148 int ind=LUA_GLOBALSINDEX;
2150 if(data->table!=LUA_NOREF){
2151 lua_rawgeti(st, LUA_REGISTRYINDEX, data->table);
2155 /* Clear table.fn */
2156 lua_pushstring(st, spec->name);
2158 lua_rawset_check(st, ind);
2164 static void extl_do_unregister_functions(ExtlExportedFnSpec *spec, int max,
2165 const char *cls, int table)
2172 regdata.table=table;
2174 for(i=0; spec[i].name && i<max; i++){
2175 regdata.spec=&(spec[i]);
2176 extl_cpcall(l_st, (ExtlCPCallFn*)extl_do_unregister_function,
2178 spec[i].registered=FALSE;
2182 void extl_unregister_function(ExtlExportedFnSpec *spec)
2184 extl_do_unregister_functions(spec, 1, "", LUA_NOREF);
2188 void extl_unregister_functions(ExtlExportedFnSpec *spec)
2190 extl_do_unregister_functions(spec, INT_MAX, "", LUA_NOREF);
2197 /*{{{ Class registration */
2201 const char *cls, *parent;
2207 static bool extl_do_register_class(lua_State *st, ClassData *data)
2209 /* Create the globally visible WFoobar table in which the function
2210 * references reside.
2214 /* Set type information.
2216 lua_pushstring(st, "__typename");
2217 lua_pushstring(st, data->cls);
2218 lua_settable(st, -3);
2220 /* If we have a parent class (i.e. class!=Obj), we want also the parent's
2221 * functions visible in this table so set up a metatable to do so.
2223 if(data->parent!=NULL){
2224 /* Get luaextl_ParentClass_metatable */
2225 lua_pushfstring(st, "luaextl_%s_metatable", data->parent);
2226 lua_gettable(st, LUA_REGISTRYINDEX);
2227 if(!lua_istable(st, -1)){
2228 extl_warn("Could not find metatable for parent class %s of %s.\n",
2229 data->parent, data->cls);
2232 /* Create our metatable */
2234 /* Get parent_metatable.__index */
2235 lua_pushstring(st, "__index");
2236 lua_pushvalue(st, -1);
2237 /* Stack: cls, parent_meta, meta, "__index", "__index" */
2238 lua_gettable(st, -4);
2239 /* Stack: cls, parent_meta, meta, "__index", parent_meta.__index */
2240 lua_pushvalue(st, -1);
2242 /* Stack: cls, parent_meta, meta, parent_meta.__index, "__index", parent_meta.__index */
2243 lua_rawset_check(st, -4);
2244 /* Stack: cls, parent_meta, meta, parent_meta.__index */
2245 lua_pushstring(st, "__parentclass");
2247 /* Stack: cls, parent_meta, meta, "__parentclass", parent_meta.__index */
2248 lua_settable(st, -5);
2249 /* Stack: cls, parent_meta, meta, */
2250 lua_setmetatable(st, -3);
2255 /* Set the global WFoobar */
2256 lua_pushvalue(st, -1);
2257 data->refret=lua_ref(st, 1); /* TODO: free on failure */
2259 lua_pushstring(st, data->cls);
2260 lua_pushvalue(st, -2);
2261 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=lua_ref(st, -1);
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 lua_pushstring(st, data->cls);
2328 lua_rawset(st, LUA_GLOBALSINDEX);
2332 void extl_unregister_class(const char *cls, ExtlExportedFnSpec *fns)
2336 clsdata.parent=NULL;
2337 clsdata.refret=LUA_NOREF;
2338 clsdata.hide=FALSE; /* unused, but initialise */
2340 if(!extl_cpcall(l_st, (ExtlCPCallFn*)extl_do_unregister_class,
2344 /* We still need to reset function upvalues. */
2346 extl_do_unregister_functions(fns, INT_MAX, cls, clsdata.refret);
2353 /*{{{ Module registration */
2356 static bool extl_do_register_module(lua_State *st, ClassData *clsdata)
2358 lua_getglobal(st, clsdata->cls);
2360 if(!lua_istable(st, -1)){
2362 lua_pushvalue(st, -1);
2363 lua_setglobal(st, clsdata->cls);
2365 lua_pushfstring(st, "luaextl_module_%s", clsdata->cls);
2366 lua_pushvalue(st, -2);
2367 lua_rawset(st, LUA_REGISTRYINDEX);
2369 clsdata->refret=lua_ref(st, -1);
2375 bool extl_register_module(const char *mdl, ExtlExportedFnSpec *fns)
2380 clsdata.parent=NULL;
2381 clsdata.refret=LUA_NOREF;
2382 clsdata.hide=FALSE; /* unused, but initialise */
2384 if(!extl_cpcall(l_st, (ExtlCPCallFn*)extl_do_register_module, &clsdata))
2390 return extl_do_register_functions(fns, INT_MAX, mdl, clsdata.refret);
2394 static bool extl_do_unregister_module(lua_State *st, ClassData *clsdata)
2396 lua_pushfstring(st, "luaextl_module_%s", clsdata->cls);
2397 lua_pushvalue(st, -1);
2399 lua_rawset(st, LUA_REGISTRYINDEX);
2400 clsdata->refret=lua_ref(st, -1);
2406 void extl_unregister_module(const char *mdl, ExtlExportedFnSpec *fns)
2411 clsdata.parent=NULL;
2412 clsdata.refret=LUA_NOREF;
2413 clsdata.hide=FALSE; /* unused, but initialise */
2415 if(!extl_cpcall(l_st, (ExtlCPCallFn*)extl_do_unregister_module, &clsdata))
2419 extl_do_unregister_functions(fns, INT_MAX, mdl, clsdata.refret);
2434 static void write_escaped_string(FILE *f, const char *str)
2439 if(((*str)&0x7f)<32 || *str=='"' || *str=='\\'){
2440 /* Lua uses decimal in escapes */
2441 fprintf(f, "\\%03d", (int)(uchar)(*str));
2452 static void indent(FILE *f, int lvl)
2455 for(i=0; i<lvl; i++)
2460 static bool ser(lua_State *st, FILE *f, int lvl)
2463 lua_checkstack(st, 5);
2465 switch(lua_type(st, -1)){
2467 fprintf(f, "%s", lua_toboolean(st, -1) ? "true" : "false");
2470 fprintf(f, "%s", lua_tostring(st, -1));
2476 write_escaped_string(f, lua_tostring(st, -1));
2479 if(lvl+1>=EXTL_MAX_SERIALISE_DEPTH){
2480 extl_warn(TR("Maximal serialisation depth reached."));
2488 while(lua_next(st, -2)!=0){
2489 lua_pushvalue(st, -2);
2501 extl_warn(TR("Unable to serialise type %s."),
2502 lua_typename(st, lua_type(st, -1)));
2509 static bool extl_do_serialise(lua_State *st, SerData *d)
2511 if(!extl_getref(st, d->tab))
2514 return ser(st, d->f, 0);
2518 /* Tab must not contain recursive references! */
2519 extern bool extl_serialise(const char *file, ExtlTab tab)
2525 d.f=fopen(file, "w");
2528 extl_warn_err_obj(file);
2532 fprintf(d.f, TR("-- This file has been generated by Ion. Do not edit.\n"));
2533 fprintf(d.f, "return ");
2535 ret=extl_cpcall(l_st, (ExtlCPCallFn*)extl_do_serialise, &d);
2537 fprintf(d.f, "\n\n");