Use new UNUSED macro in dock.c
[notion.git] / libextl / luaextl.c
blob178a72609e5263c4f404a0a1d11419cf7ae031a7
1 /*
2 * libextl/luaextl.c
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.
13 #include <time.h>
14 #include <errno.h>
15 #include <stdlib.h>
16 #include <stdarg.h>
17 #include <math.h>
18 #include <string.h>
19 #include <limits.h>
20 #include <assert.h>
22 #include <lua.h>
23 #include <lualib.h>
24 #include <lauxlib.h>
26 #include <libtu/obj.h>
27 #include <libtu/objp.h>
28 #include <libtu/dlist.h>
29 #include <libtu/util.h>
31 #include "readconfig.h"
32 #include "luaextl.h"
33 #include "private.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.
40 #define MAX_PARAMS 16
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,
47 void *valret);
49 static int extl_protected(lua_State *st);
51 #ifdef EXTL_LOG_ERRORS
52 static void flushtrace();
53 #else
54 #define flushtrace()
55 #endif
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);
67 #else
68 return lua_objlen(st, index);
69 #endif
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);
101 /*}}}*/
104 /*{{{ A cpcall wrapper */
107 typedef bool ExtlCPCallFn(lua_State *st, void *ptr);
110 typedef struct{
111 ExtlCPCallFn *fn;
112 void *udata;
113 bool retval;
114 } ExtlCPCallParam;
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."));
124 return 0;
127 param->retval=param->fn(st, param->udata);
128 return 0;
132 static bool extl_cpcall(lua_State *st, ExtlCPCallFn *fn, void *ptr)
134 ExtlCPCallParam param;
135 int oldtop=lua_gettop(st);
136 int err;
138 param.fn=fn;
139 param.udata=ptr;
140 param.retval=FALSE;
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, &param);
148 err=lua_pcall(st, 1, 0, 0);
149 #else
150 err=lua_cpcall(st, extl_docpcall, &param);
151 #endif
152 if(err==LUA_ERRRUN){
153 extl_warn("%s", lua_tostring(st, -1));
154 }else if(err==LUA_ERRMEM){
155 extl_warn("%s", strerror(ENOMEM));
156 }else if(err!=0){
157 extl_warn(TR("Unknown Lua error."));
160 lua_settop(st, oldtop);
162 return param.retval;
166 /*}}}*/
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)
178 int val;
180 *dead=FALSE;
181 *invalid=TRUE;
183 if(!lua_isuserdata(st, pos)){
184 *invalid=!lua_isnil(st, pos);
185 return NULL;
188 if(!lua_getmetatable(st, pos))
189 return NULL;
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);
197 lua_pop(st, 2);
199 if(val==MAGIC){
200 ExtlProxy *proxy=(ExtlProxy*)lua_touserdata(st, pos);
202 *invalid=FALSE;
204 if(proxy!=NULL){
205 Obj *obj=EXTL_PROXY_OBJ(proxy);
206 if(obj==NULL){
207 *dead=TRUE;
208 *invalid=TRUE;
210 return obj;
214 return NULL;
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);
223 lua_pushnil(st);
224 lua_rawset(st, -3);
225 }else{
226 lua_pushlightuserdata(st, obj);
227 lua_pushnil(st);
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)
241 ExtlProxy *proxy;
243 if(obj==NULL){
244 lua_pushnil(st);
245 return;
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);
252 lua_rawget(st, -2);
253 lua_remove(st, -2); /* owned_cache */
254 }else{
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));
260 return;
262 lua_pop(st, 1);
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)){
274 lua_pop(st, 2);
275 lua_pushnil(st);
276 }else{
277 lua_setmetatable(st, -2);
279 /* Store in cache */
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 */
286 }else{
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)
301 ExtlProxy *proxy;
302 bool dead=FALSE, invalid=FALSE;
303 Obj *obj;
305 obj=extl_get_obj(st, 1, &invalid, &dead);
307 if(obj==NULL){
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.
312 return 0;
315 proxy=(ExtlProxy*)lua_touserdata(st, 1);
317 if(proxy!=NULL)
318 EXTL_END_PROXY_OBJ(proxy, obj);
320 if(EXTL_OBJ_OWNED(obj))
321 EXTL_DESTROY_OWNED_OBJ(obj);
323 return 0;
327 static int extl_obj_typename(lua_State *st)
329 Obj *obj=NULL;
331 if(!extl_stack_get(st, 1, 'o', FALSE, NULL, &obj) || obj==NULL)
332 return 0;
334 lua_pushstring(st, EXTL_OBJ_TYPENAME(obj));
335 return 1;
338 /* Dummy code for documentation generation. */
340 /*EXTL_DOC
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)
349 Obj *obj=NULL;
351 extl_stack_get(st, 1, 'o', FALSE, NULL, &obj);
353 lua_pushboolean(st, obj!=NULL);
355 return 1;
358 /* Dummy code for documentation generation. */
360 /*EXTL_DOC
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)
369 Obj *obj=NULL;
370 const char *tn;
372 extl_stack_get(st, 1, 'o', FALSE, NULL, &obj);
374 if(obj==NULL){
375 lua_pushboolean(st, 0);
376 }else{
377 tn=lua_tostring(st, 2);
378 lua_pushboolean(st, EXTL_OBJ_IS(obj, tn));
381 return 1;
384 /* Dummy code for documentation generation. */
386 /*EXTL_DOC
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)
395 lua_Debug ar;
396 const char *s, *p;
398 if(lua_getstack(st, 1, &ar)!=1)
399 goto err;
400 if(lua_getinfo(st, "S", &ar)==0)
401 goto err;
403 if(ar.source==NULL || ar.source[0]!='@')
404 return 0; /* not a file */
406 s=ar.source+1;
408 if(!dir){
409 lua_pushstring(st, s);
410 }else{
411 p=strrchr(s, '/');
412 if(p==NULL){
413 lua_pushstring(st, ".");
414 }else{
415 lua_pushlstring(st, s, p-s);
418 return 1;
420 err:
421 extl_warn("Unable to get caller file from stack.");
422 return 0;
426 static int extl_dopath(lua_State *st)
428 const char *toincl, *cfdir;
429 bool res, complain;
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);
436 }else{
437 cfdir=lua_tostring(st, -1);
438 res=extl_read_config(toincl, cfdir, complain);
439 lua_pop(st, 1);
441 lua_pushboolean(st, res);
442 return 1;
445 /* Dummy code for documentation generation. */
447 /*EXTL_DOC
448 * Look up and execute another file with Lua code.
450 EXTL_EXPORT_AS(global, dopath)
451 bool dopath(const char *what);
454 /*}}}*/
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.
468 lua_newtable(st);
469 lua_newtable(st);
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");
487 return TRUE;
491 /*}}}*/
494 /*{{{ Error handling and reporting -- unsafe */
497 static int extl_stack_trace(lua_State *st)
499 lua_Debug ar;
500 int lvl=0;
501 int n_skip=0;
503 lua_pushstring(st, TR("Stack trace:"));
505 for( ; lua_getstack(st, lvl, &ar); lvl++){
506 bool is_c=FALSE;
508 if(lua_getinfo(st, "Sln", &ar)==0){
509 lua_pushfstring(st,
510 TR("\n(Unable to get debug info for level %d)"),
511 lvl);
512 lua_concat(st, 2);
513 continue;
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);
522 if(ar.name!=NULL)
523 lua_pushfstring(st, ": in '%s'", ar.name);
524 lua_concat(st, 2+(ar.currentline!=-1)+(ar.name!=NULL));
525 n_skip=0;
526 }else{
527 if(n_skip==0){
528 lua_pushstring(st, TR("\n [Skipping unnamed C functions.]"));
529 /*lua_pushstring(st, "\n...skipping...");*/
530 lua_concat(st, 2);
532 n_skip++;
535 return 1;
539 #ifdef EXTL_LOG_ERRORS
541 static int extl_do_collect_errors(lua_State *st)
543 int n, err;
544 ErrorLog *el=(ErrorLog*)lua_touserdata(st, -1);
546 lua_pop(st, 1);
548 n=lua_gettop(st)-1;
549 err=lua_pcall(st, n, 0, 0);
551 if(err!=0)
552 extl_warn("%s", lua_tostring(st, -1));
554 if(el->msgs_len==0)
555 return 0;
556 lua_pushstring(st, el->msgs);
557 return 1;
561 int extl_collect_errors(lua_State *st)
563 ErrorLog el;
564 int n=lua_gettop(st);
565 int err;
567 lua_pushcfunction(st, extl_do_collect_errors);
568 lua_insert(st, 1);
569 lua_pushlightuserdata(st, &el);
571 errorlog_begin(&el);
573 err=lua_pcall(st, n+1, 1, 0);
575 errorlog_end(&el);
576 errorlog_deinit(&el);
578 if(err!=0)
579 extl_warn(TR("Internal error."));
581 return 1;
584 #endif
587 /*}}}*/
590 /*{{{ Init -- unsafe, but it doesn't matter at this point */
593 bool extl_init()
595 l_st=luaL_newstate();
597 if(l_st==NULL){
598 extl_warn(TR("Unable to initialize Lua."));
599 return FALSE;
602 luaL_openlibs(l_st);
604 if(!extl_init_obj_info(l_st)){
605 lua_close(l_st);
606 return FALSE;
609 #ifdef EXTL_LOG_ERRORS
610 lua_pushcfunction(l_st, extl_collect_errors);
611 lua_setglobal(l_st, "collect_errors");
612 #endif
614 return TRUE;
618 void extl_deinit()
620 lua_close(l_st);
621 l_st=NULL;
625 /*}}}*/
628 /*{{{ Stack get/push -- all unsafe */
631 static bool extl_stack_get(lua_State *st, int pos, char type,
632 bool copystring, bool *wasdeadobject,
633 void *valret)
635 double d=0;
636 const char *str;
638 if(wasdeadobject!=NULL)
639 *wasdeadobject=FALSE;
641 if(type=='b'){
642 if(valret)
643 *((bool*)valret)=lua_toboolean(st, pos);
644 return TRUE;
647 switch(lua_type(st, pos)){
648 case LUA_TNUMBER:
649 if(type!='i' && type!='d' && type!='a')
650 return FALSE;
652 d=lua_tonumber(st, pos);
654 if(type=='i'){
655 if(d-floor(d)!=0)
656 return FALSE;
657 if(valret)
658 *((int*)valret)=d;
659 }else if(type=='a'){
660 if(valret){
661 ((ExtlAny*)valret)->type='d';
662 ((ExtlAny*)valret)->value.d=d;
664 }else{
665 if(valret)
666 *((double*)valret)=d;
668 return TRUE;
670 case LUA_TNIL:
671 case LUA_TNONE:
672 if(type=='a'){
673 if(valret)
674 ((ExtlAny*)valret)->type='v';
675 }else if(type=='t' || type=='f'){
676 if(valret)
677 *((int*)valret)=LUA_NOREF;
678 }else if(type=='s' || type=='S'){
679 if(valret)
680 *((char**)valret)=NULL;
681 }else if(type=='o'){
682 if(valret)
683 *((Obj**)valret)=NULL;
684 }else{
685 return FALSE;
687 return TRUE;
689 case LUA_TSTRING:
690 if(type!='s' && type!='S' && type!='a')
691 return FALSE;
692 if(valret){
693 str=lua_tostring(st, pos);
694 if(str!=NULL && copystring){
695 str=extl_scopy(str);
696 if(str==NULL)
697 return FALSE;
699 if(type=='a'){
700 ((ExtlAny*)valret)->type=(copystring ? 's' : 'S');
701 ((ExtlAny*)valret)->value.s=str;
702 }else{
703 *((const char**)valret)=str;
706 return TRUE;
708 case LUA_TFUNCTION:
709 if(type!='f' && type!='a')
710 return FALSE;
711 if(valret){
712 lua_pushvalue(st, pos);
713 if(type=='a'){
714 ((ExtlAny*)valret)->type='f';
715 ((ExtlAny*)valret)->value.f=luaL_ref(st, LUA_REGISTRYINDEX);
716 }else{
717 *((int*)valret)=luaL_ref(st, LUA_REGISTRYINDEX);
720 return TRUE;
722 case LUA_TTABLE:
723 if(type!='t' && type!='a')
724 return FALSE;
725 if(valret){
726 lua_pushvalue(st, pos);
727 if(type=='a'){
728 ((ExtlAny*)valret)->type='t';
729 ((ExtlAny*)valret)->value.f=luaL_ref(st, LUA_REGISTRYINDEX);
730 }else{
731 *((int*)valret)=luaL_ref(st, LUA_REGISTRYINDEX);
734 return TRUE;
736 case LUA_TUSERDATA:
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)
741 *wasdeadobject=dead;
742 if(valret){
743 if(type=='a'){
744 ((ExtlAny*)valret)->type='o';
745 ((ExtlAny*)valret)->value.o=obj;
746 }else{
747 *((Obj**)valret)=obj;
750 return !invalid;
754 return FALSE;
758 static void extl_to_any(ExtlAny *a, char type, void *ptr)
760 if(type=='a'){
761 *a=*(ExtlAny*)ptr;
762 return;
765 a->type=type;
767 switch(type){
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;
772 case 's':
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)
782 if(type=='a'){
783 *a=va_arg(*argsp, ExtlAny);
784 return;
787 a->type=type;
789 switch(type){
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;
794 case 's':
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)
804 switch(a->type){
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;
809 case 's':
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)
820 ExtlAny a;
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)
829 ExtlAny a;
831 extl_to_any_vararg(&a, spec, argsp);
832 extl_stack_pusha(st, &a);
834 return TRUE;
838 /*}}}*/
841 /*{{{ Free */
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)){
851 if(a->value.s!=NULL)
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)
863 ExtlAny a;
865 extl_to_any(&a, spec, ptr);
866 extl_any_free(&a, strings);
870 /*}}}*/
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)){
880 lua_pop(st, 1);
881 return FALSE;
883 return TRUE;
886 /* Unref */
888 static bool extl_do_unref(lua_State *st, int *refp)
890 luaL_unref(st, LUA_REGISTRYINDEX, *refp);
891 return TRUE;
895 ExtlFn extl_unref_fn(ExtlFn ref)
897 extl_cpcall(l_st, (ExtlCPCallFn*)extl_do_unref, &ref);
898 return LUA_NOREF;
902 ExtlFn extl_unref_table(ExtlTab ref)
904 extl_cpcall(l_st, (ExtlCPCallFn*)extl_do_unref, &ref);
905 return LUA_NOREF;
909 /* noref */
911 ExtlFn extl_fn_none()
913 return LUA_NOREF;
917 ExtlTab extl_table_none()
919 return LUA_NOREF;
923 /* ref */
925 static bool extl_do_ref(lua_State *st, int *refp)
927 if(!extl_getref(st, *refp))
928 return FALSE;
929 *refp=luaL_ref(st, LUA_REGISTRYINDEX);
930 return TRUE;
934 ExtlTab extl_ref_table(ExtlTab ref)
936 if(extl_cpcall(l_st, (ExtlCPCallFn*)extl_do_ref, &ref))
937 return ref;
938 return LUA_NOREF;
942 ExtlFn extl_ref_fn(ExtlFn ref)
944 if(extl_cpcall(l_st, (ExtlCPCallFn*)extl_do_ref, &ref))
945 return ref;
946 return LUA_NOREF;
950 /* create_table */
952 static bool extl_do_create_table(lua_State *st, int *refp)
954 lua_newtable(st);
955 *refp=luaL_ref(st, LUA_REGISTRYINDEX);
956 return TRUE;
960 ExtlTab extl_create_table()
962 ExtlTab ref;
963 if(extl_cpcall(l_st, (ExtlCPCallFn*)extl_do_create_table, &ref))
964 return ref;
965 return LUA_NOREF;
969 /* eq */
971 typedef struct{
972 int o1, o2;
973 bool ret;
974 } EqParams;
977 static bool extl_do_eq(lua_State *st, EqParams *ep)
979 if(!extl_getref(st, ep->o1))
980 return FALSE;
981 if(!extl_getref(st, ep->o2))
982 return FALSE;
983 #if LUA_VERSION_NUM>=502
984 ep->ret=lua_compare(st, -1, -2,LUA_OPEQ);
985 #else
986 ep->ret=lua_equal(st, -1, -2);
987 #endif
988 return TRUE;
992 bool extl_fn_eq(ExtlFn fn1, ExtlFn fn2)
994 EqParams ep;
995 ep.o1=fn1;
996 ep.o2=fn2;
997 ep.ret=FALSE;
998 extl_cpcall(l_st, (ExtlCPCallFn*)extl_do_eq, &ep);
999 return ep.ret;
1003 bool extl_table_eq(ExtlTab t1, ExtlTab t2)
1005 EqParams ep;
1006 ep.o1=t1;
1007 ep.o2=t2;
1008 ep.ret=FALSE;
1009 extl_cpcall(l_st, (ExtlCPCallFn*)extl_do_eq, &ep);
1010 return ep.ret;
1014 /*}}}*/
1017 /*{{{ Table/get */
1020 typedef struct{
1021 ExtlTab ref;
1022 char type;
1023 char itype;
1024 va_list *argsp;
1025 } TableParams2;
1028 static bool extl_table_dodo_get2(lua_State *st, TableParams2 *params)
1030 if(params->ref<0)
1031 return FALSE;
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))
1037 return FALSE;
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;
1048 params.ref=ref;
1049 params.itype=itype;
1050 params.type=type;
1051 params.argsp=args;
1053 return extl_cpcall(l_st, (ExtlCPCallFn*)extl_table_dodo_get2, &params);
1057 bool extl_table_get(ExtlTab ref, char itype, char type, ...)
1059 va_list args;
1060 bool retval;
1062 va_start(args, type);
1063 retval=extl_table_get_vararg(ref, itype, type, &args);
1064 va_end(args);
1066 return retval;
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);
1163 typedef struct{
1164 int ref;
1165 int n;
1166 } GetNParams;
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);
1173 return TRUE;
1177 int extl_table_get_n(ExtlTab ref)
1179 GetNParams params;
1181 params.ref=ref;
1182 params.n=0;
1184 extl_cpcall(l_st, (ExtlCPCallFn*)extl_table_do_get_n, &params);
1186 return params.n;
1190 /*}}}*/
1193 /*{{{ Table/set */
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);
1202 return TRUE;
1206 bool extl_table_set_vararg(ExtlTab ref, char itype, char type, va_list *args)
1208 TableParams2 params;
1210 params.ref=ref;
1211 params.itype=itype;
1212 params.type=type;
1213 params.argsp=args;
1215 return extl_cpcall(l_st, (ExtlCPCallFn*)extl_table_dodo_set2, &params);
1219 bool extl_table_set(ExtlTab ref, char itype, char type, ...)
1221 va_list args;
1222 bool retval;
1224 va_start(args, type);
1225 retval=extl_table_set_vararg(ref, itype, type, &args);
1226 va_end(args);
1228 return retval;
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);
1313 /*}}}*/
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);
1323 lua_pushnil(st);
1324 lua_rawset_check(st, -3);
1325 return TRUE;
1328 bool extl_table_clear_vararg(ExtlTab ref, char itype, va_list *args)
1330 TableParams2 params;
1332 params.ref=ref;
1333 params.itype=itype;
1334 /*params.type='?';*/
1335 params.argsp=args;
1337 return extl_cpcall(l_st, (ExtlCPCallFn*)extl_table_dodo_clear2, &params);
1340 bool extl_table_clear(ExtlTab ref, char itype, ...)
1342 va_list args;
1343 bool retval;
1345 va_start(args, itype);
1346 retval=extl_table_clear_vararg(ref, itype, &args);
1347 va_end(args);
1349 return retval;
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);
1365 /*}}}*/
1368 /*{{{ Table iteration */
1371 typedef struct{
1372 ExtlTab ref;
1373 ExtlIterFn *fn;
1374 void *d;
1375 } IterP;
1378 int extl_table_iter_do(lua_State *st, IterP *par)
1380 lua_rawgeti(st, LUA_REGISTRYINDEX, par->ref);
1382 lua_pushnil(st);
1384 while(lua_next(st, -2)!=0){
1385 ExtlAny k, v;
1387 if(extl_stack_get(st, -2, 'a', FALSE, NULL, &k)){
1388 bool ret=TRUE;
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);
1394 if(!ret)
1395 return 0;
1398 lua_pop(st, 1);
1401 return 0;
1405 void extl_table_iter(ExtlTab ref, ExtlIterFn *fn, void *d)
1407 IterP par;
1409 par.ref=ref;
1410 par.fn=fn;
1411 par.d=d;
1413 extl_cpcall(l_st, (ExtlCPCallFn*)extl_table_iter_do, &par);
1417 /*}}}*/
1420 /*{{{ Function calls to Lua */
1423 static bool extl_push_args(lua_State *st, const char *spec, va_list *argsp)
1425 int i=1;
1427 while(*spec!='\0'){
1428 if(!extl_stack_push_vararg(st, *spec, argsp))
1429 return FALSE;
1430 i++;
1431 spec++;
1434 return TRUE;
1438 typedef struct{
1439 const char *spec;
1440 const char *rspec;
1441 va_list *args;
1442 void *misc;
1443 int nret;
1444 #ifndef CF_HAS_VA_COPY
1445 void *ret_ptrs[MAX_PARAMS];
1446 #endif
1447 } ExtlDoCallParam;
1450 static bool extl_get_retvals(lua_State *st, int m, ExtlDoCallParam *param)
1452 void *ptr;
1453 const char *spec=param->rspec;
1455 #ifdef CF_HAS_VA_COPY
1456 va_list args;
1457 va_copy(args, *(param->args));
1458 #else
1459 if(m>MAX_PARAMS){
1460 extl_warn(TR("Too many return values. Use a C compiler that has "
1461 "va_copy to support more."));
1462 return FALSE;
1464 #endif
1466 while(m>0){
1467 bool dead=FALSE;
1468 #ifdef CF_HAS_VA_COPY
1469 ptr=va_arg(args, void*);
1470 #else
1471 ptr=va_arg(*(param->args), void*);
1472 param->ret_ptrs[param->nret]=ptr;
1473 #endif
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)){
1477 *(Obj**)ptr=NULL;
1478 }else*/
1479 if(dead){
1480 extl_warn(TR("Returned dead object."));
1481 return FALSE;
1482 }else{
1483 extl_warn(TR("Invalid return value (expected '%c', "
1484 "got lua type \"%s\")."),
1485 *spec, lua_typename(st, lua_type(st, -m)));
1486 return FALSE;
1490 (param->nret)++;
1491 spec++;
1492 m--;
1495 #ifdef CF_HAS_VA_COPY
1496 va_end(args);
1497 #endif
1499 return TRUE;
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)
1509 int n=0, m=0;
1511 if(lua_isnil(st, -1))
1512 return FALSE;
1514 if(param->spec!=NULL)
1515 n=strlen(param->spec);
1517 if(!lua_checkstack(st, n+8)){
1518 extl_warn(TR("Stack full."));
1519 return FALSE;
1522 if(n>0){
1523 if(!extl_push_args(st, param->spec, param->args))
1524 return FALSE;
1527 if(param->rspec!=NULL)
1528 m=strlen(param->rspec);
1530 flushtrace();
1532 if(lua_pcall(st, n, m, 0)!=0){
1533 extl_warn("%s", lua_tostring(st, -1));
1534 return FALSE;
1537 if(m>0)
1538 return extl_get_retvals(st, m, param);
1540 return TRUE;
1544 static bool extl_cpcall_call(lua_State *st, ExtlCPCallFn *fn,
1545 ExtlDoCallParam *param)
1547 void *ptr;
1548 int i;
1550 param->nret=0;
1552 if(extl_cpcall(st, fn, param))
1553 return TRUE;
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*);
1562 #else
1563 ptr=param->ret_ptrs[i];
1564 #endif
1565 extl_free(ptr, *(param->rspec+i), STRINGS_ALL);
1568 return FALSE;
1572 static bool extl_do_call_vararg(lua_State *st, ExtlDoCallParam *param)
1574 if(!extl_getref(st, *(ExtlFn*)(param->misc)))
1575 return FALSE;
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)
1586 return FALSE;
1588 param.spec=spec;
1589 param.rspec=rspec;
1590 param.args=args;
1591 param.misc=(void*)&fnref;
1593 return extl_cpcall_call(l_st, (ExtlCPCallFn*)extl_do_call_vararg, &param);
1597 bool extl_call(ExtlFn fnref, const char *spec, const char *rspec, ...)
1599 bool retval;
1600 va_list args;
1602 va_start(args, rspec);
1603 retval=extl_call_vararg(fnref, spec, rspec, &args);
1604 va_end(args);
1606 return retval;
1610 /*}}}*/
1613 /*{{{ extl_loadfile/string */
1617 * Expects
1618 * - a stack with only the parameters to be passed to the function
1619 * - the function to call as an upvalue
1620 * Performs
1621 * - execute the function
1622 * Returns
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));
1631 lua_insert(st, 1);
1633 lua_call(st, nargs, LUA_MULTRET);
1634 return lua_gettop(st);
1638 typedef struct{
1639 const char *src;
1640 bool isfile;
1641 ExtlFn *resptr;
1642 } ExtlLoadParam;
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)
1651 int res=0;
1653 if(param->isfile){
1654 res=luaL_loadfile(st, param->src);
1655 }else{
1656 res=luaL_loadbuffer(st, param->src, strlen(param->src), param->src);
1659 if(res!=0){
1660 extl_warn("%s", lua_tostring(st, -1));
1661 return FALSE;
1664 lua_pushcclosure(st, call_loaded, 1);
1665 *(param->resptr)=luaL_ref(st, LUA_REGISTRYINDEX);
1667 return TRUE;
1671 bool extl_loadfile(const char *file, ExtlFn *ret)
1673 ExtlLoadParam param;
1674 param.src=file;
1675 param.isfile=TRUE;
1676 param.resptr=ret;
1678 return extl_cpcall(l_st, (ExtlCPCallFn*)extl_do_load, &param);
1682 bool extl_loadstring(const char *str, ExtlFn *ret)
1684 ExtlLoadParam param;
1685 param.src=str;
1686 param.isfile=FALSE;
1687 param.resptr=ret;
1689 return extl_cpcall(l_st, (ExtlCPCallFn*)extl_do_load, &param);
1693 /*}}}*/
1696 /*{{{ L1 CH error logging */
1698 #ifdef EXTL_LOG_ERRORS
1700 INTRSTRUCT(WarnChain);
1701 DECLSTRUCT(WarnChain){
1702 bool need_trace;
1703 lua_State *st;
1704 WarnHandler *old_handler;
1705 WarnChain *prev;
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;
1723 called++;
1724 warnchain=ch->prev;
1725 ch->old_handler(message);
1726 warnchain=ch;
1727 called--;
1731 static void do_trace(WarnChain *ch)
1733 const char *p;
1735 if(notrace!=0)
1736 return;
1738 extl_stack_trace(ch->st);
1739 p=lua_tostring(ch->st, -1);
1740 notrace++;
1741 extl_warn(p);
1742 notrace--;
1743 ch->need_trace=FALSE;
1744 lua_pop(ch->st, 1);
1747 static void flushtrace()
1749 if(warnchain && warnchain->need_trace)
1750 do_trace(warnchain);
1753 #endif
1755 /*}}}*/
1758 /*{{{ L1-CH safe functions */
1761 static int protect_count=0;
1762 static ExtlSafelist *safelists=NULL;
1765 void extl_protect(ExtlSafelist *l)
1767 protect_count++;
1768 if(l!=NULL){
1769 if(l->count==0){
1770 LINK_ITEM(safelists, l, next, prev);
1772 l->count++;
1777 void extl_unprotect(ExtlSafelist *l)
1779 assert(protect_count>0);
1780 protect_count--;
1782 if(l!=NULL){
1783 assert(l->count>0);
1784 l->count--;
1785 if(l->count==0){
1786 UNLINK_ITEM(safelists, l, next, prev);
1792 static bool extl_check_protected(ExtlExportedFnSpec *spec)
1794 ExtlSafelist *l;
1795 bool ok=FALSE;
1796 int j;
1798 if(protect_count>0 && !spec->safe){
1799 for(l=safelists; l!=NULL; l=l->next){
1800 ok=TRUE;
1801 for(j=0; l->list[j]!=NULL; j++){
1802 if(l->list[j]==spec->fn)
1803 break;
1805 if(l->list[j]==NULL){
1806 ok=FALSE;
1807 break;
1810 }else{
1811 ok=TRUE;
1814 return ok;
1818 /*}}}*/
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.
1835 typedef struct{
1836 ExtlL2Param ip[MAX_PARAMS];
1837 ExtlL2Param op[MAX_PARAMS];
1838 ExtlExportedFnSpec *spec;
1839 int ii, ni, no;
1840 } L1Param;
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;
1849 int i;
1851 D(fprintf(stderr, "%s called\n", spec->name));
1853 if(!lua_checkstack(st, MAX_PARAMS+1)){
1854 extl_warn(TR("Stack full."));
1855 return 0;
1858 param->ni=(spec->ispec==NULL ? 0 : strlen(spec->ispec));
1860 for(i=0; i<param->ni; i++){
1861 bool dead=FALSE;
1862 if(!extl_stack_get(st, i+1, spec->ispec[i], FALSE, &dead,
1863 (void*)&(param->ip[i]))){
1864 if(dead){
1865 extl_warn(TR("Argument %d to %s is a dead object."),
1866 i+1, spec->name);
1867 }else{
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)));
1873 return 0;
1876 param->ii=i+1;
1879 if(spec->untraced)
1880 notrace++;
1882 if(!spec->l2handler(spec->fn, param->ip, param->op))
1883 return 0;
1885 if(spec->untraced)
1886 notrace--;
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]));
1893 return param->no;
1897 static void extl_l1_finalize(L1Param *param)
1899 ExtlExportedFnSpec *spec=param->spec;
1900 int i;
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
1917 WarnChain ch;
1918 #endif
1919 L1Param param={{NULL, }, {NULL, }, NULL, 0, 0, 0};
1920 L1Param *old_param;
1921 int ret;
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."));
1932 return 0;
1935 if(!param.spec->registered){
1936 extl_warn(TR("Called function has been unregistered."));
1937 return 0;
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));
1943 return 1;
1946 if(!extl_check_protected(param.spec)){
1947 extl_warn(TR("Ignoring call to unsafe function \"%s\" in "
1948 "restricted mode."), param.spec->name);
1949 return 0;
1953 lua_pushcfunction(st, extl_l1_call_handler2);
1954 lua_insert(st, 1);
1956 old_param=current_param;
1957 current_param=&param;
1959 #ifdef EXTL_LOG_ERRORS
1960 ch.old_handler=set_warn_handler(l1_warn_handler);
1961 ch.need_trace=FALSE;
1962 ch.st=st;
1963 ch.prev=warnchain;
1964 warnchain=&ch;
1965 #endif
1967 /* Ok, Lua may now freely fail in extl_l1_call_handler2, we can handle
1968 * that.
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(&param);
1978 #ifdef EXTL_LOG_ERRORS
1979 warnchain=ch.prev;
1980 set_warn_handler(ch.old_handler);
1982 /* Ok, we can now safely use Lua functions again without fear of
1983 * leaking.
1985 if(ret!=0){
1986 const char *p;
1987 param.no=0;
1988 p=lua_tostring(st, -1);
1989 notrace++;
1990 extl_warn("%s", p);
1991 notrace--;
1994 if(ret!=0 || ch.need_trace)
1995 do_trace(&ch);
1996 #else
1997 if(ret!=0)
1998 lua_error(st);
1999 #endif
2001 return param.no;
2005 /*EXTL_DOC
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
2008 * protected mode.
2010 EXTL_EXPORT_AS(global, protected)
2011 bool __protected(ExtlFn fn);
2013 static int extl_protected(lua_State *st)
2015 int ret;
2017 if(lua_isnil(st, 1)){
2018 lua_pushboolean(st, protect_count>0);
2019 return 1;
2022 if(!lua_isfunction(st, 1)){
2023 lua_pushboolean(st, TRUE);
2024 return 1;
2027 if(lua_tocfunction(st, 1)!=(lua_CFunction)extl_l1_call_handler){
2028 lua_pushboolean(st, FALSE);
2029 return 1;
2032 extl_l1_just_check_protected=TRUE;
2033 ret=lua_pcall(st, 0, 1, 0);
2034 extl_l1_just_check_protected=FALSE;
2035 if(ret!=0)
2036 lua_pushboolean(st, TRUE);
2037 return 1;
2040 /*}}}*/
2043 /*{{{ Function registration */
2046 typedef struct{
2047 ExtlExportedFnSpec *spec;
2048 const char *cls;
2049 ExtlTab table;
2050 } RegData;
2053 static bool extl_do_register_function(lua_State *st, RegData *data)
2055 ExtlExportedFnSpec *spec=data->spec;
2056 #if LUA_VERSION_NUM>=502
2057 int ind;
2058 #else
2059 int ind=LUA_GLOBALSINDEX;
2060 #endif
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);
2066 return FALSE;
2069 if(data->table!=LUA_NOREF){
2070 lua_rawgeti(st, LUA_REGISTRYINDEX, data->table);
2071 ind=-3;
2073 #if LUA_VERSION_NUM>=502
2074 else{
2075 lua_pushglobaltable(st);
2076 ind=-3;
2078 #endif
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);
2087 return TRUE;
2091 static bool extl_do_register_functions(ExtlExportedFnSpec *spec, int max,
2092 const char *cls, int table)
2094 int i;
2096 RegData regdata;
2097 regdata.spec=spec;
2098 regdata.cls=cls;
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,
2104 &regdata)){
2105 return FALSE;
2107 spec[i].registered=TRUE;
2110 return 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
2130 int ind;
2131 #else
2132 int ind=LUA_GLOBALSINDEX;
2133 #endif
2135 if(data->table!=LUA_NOREF){
2136 lua_rawgeti(st, LUA_REGISTRYINDEX, data->table);
2137 ind=-3;
2139 #if LUA_VERSION_NUM>=502
2140 else{
2141 lua_pushglobaltable(st);
2142 ind=-3;
2144 #endif
2146 /* Clear table.fn */
2147 lua_pushstring(st, spec->name);
2148 lua_pushnil(st);
2149 lua_rawset_check(st, ind);
2151 return TRUE;
2155 static void extl_do_unregister_functions(ExtlExportedFnSpec *spec, int max,
2156 const char *cls, int table)
2158 int i;
2160 RegData regdata;
2161 regdata.spec=spec;
2162 regdata.cls=cls;
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,
2168 &regdata);
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);
2185 /*}}}*/
2188 /*{{{ Class registration */
2191 typedef struct{
2192 const char *cls, *parent;
2193 int refret;
2194 bool hide;
2195 } ClassData;
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.
2203 lua_newtable(st);
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);
2221 return FALSE;
2223 /* Create our metatable */
2224 lua_newtable(st);
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);
2232 lua_insert(st, -3);
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");
2237 lua_insert(st, -2);
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);
2242 lua_pop(st, 1);
2243 /* Stack: cls */
2246 /* Set the global WFoobar */
2247 lua_pushvalue(st, -1);
2248 data->refret=luaL_ref(st, LUA_REGISTRYINDEX); /* TODO: free on failure */
2249 if(!data->hide){
2250 #if LUA_VERSION_NUM>=502
2251 lua_pushglobaltable(st);
2252 lua_pushstring(st, data->cls);
2253 lua_pushvalue(st, -3);
2254 lua_rawset(st, -3);
2255 lua_remove(st, -1);
2256 #else
2257 lua_pushstring(st, data->cls);
2258 lua_pushvalue(st, -2);
2259 lua_rawset(st, LUA_GLOBALSINDEX);
2260 #endif
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
2266 * high likelihood.
2268 lua_newtable(st);
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);
2281 lua_insert(st, -2);
2282 lua_rawset(st, LUA_REGISTRYINDEX);
2284 return TRUE;
2288 bool extl_register_class(const char *cls, ExtlExportedFnSpec *fns,
2289 const char *parent)
2291 ClassData clsdata;
2292 clsdata.cls=cls;
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))
2300 return FALSE;
2302 if(fns==NULL)
2303 return TRUE;
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);
2319 lua_pop(st, 1);
2320 /* Set the entry from registry to nil. */
2321 lua_pushnil(st);
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);
2328 lua_pushnil(st);
2329 lua_rawset(st, -3);
2330 lua_remove(st, -1);
2331 #else
2332 lua_pushstring(st, data->cls);
2333 lua_pushnil(st);
2334 lua_rawset(st, LUA_GLOBALSINDEX);
2335 #endif
2339 void extl_unregister_class(const char *cls, ExtlExportedFnSpec *fns)
2341 ClassData clsdata;
2342 clsdata.cls=cls;
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,
2348 &clsdata))
2349 return;
2351 /* We still need to reset function upvalues. */
2352 if(fns!=NULL)
2353 extl_do_unregister_functions(fns, INT_MAX, cls, clsdata.refret);
2357 /*}}}*/
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)){
2368 lua_newtable(st);
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);
2378 return TRUE;
2382 bool extl_register_module(const char *mdl, ExtlExportedFnSpec *fns)
2384 ClassData clsdata;
2386 clsdata.cls=mdl;
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))
2392 return FALSE;
2394 if(fns==NULL)
2395 return TRUE;
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);
2405 lua_pushnil(st);
2406 lua_rawset(st, LUA_REGISTRYINDEX);
2407 clsdata->refret=luaL_ref(st, LUA_REGISTRYINDEX);
2409 return TRUE;
2413 void extl_unregister_module(const char *mdl, ExtlExportedFnSpec *fns)
2415 ClassData clsdata;
2417 clsdata.cls=mdl;
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))
2423 return;
2425 if(fns!=NULL)
2426 extl_do_unregister_functions(fns, INT_MAX, mdl, clsdata.refret);
2430 /*}}}*/
2433 /*{{{ Serialise */
2435 typedef struct{
2436 FILE *f;
2437 ExtlTab tab;
2438 } SerData;
2441 static void write_escaped_string(FILE *f, const char *str)
2443 fputc('"', f);
2445 while(str && *str){
2446 if(((*str)&0x7f)<32 || *str=='"' || *str=='\\'){
2447 /* Lua uses decimal in escapes */
2448 fprintf(f, "\\%03d", (int)(uchar)(*str));
2449 }else{
2450 fputc(*str, f);
2452 str++;
2455 fputc('"', f);
2459 static void indent(FILE *f, int lvl)
2461 int i;
2462 for(i=0; i<lvl; i++)
2463 fprintf(f, " ");
2467 static bool ser(lua_State *st, FILE *f, int lvl)
2470 lua_checkstack(st, 5);
2472 switch(lua_type(st, -1)){
2473 case LUA_TBOOLEAN:
2474 fprintf(f, "%s", lua_toboolean(st, -1) ? "true" : "false");
2475 break;
2476 case LUA_TNUMBER:
2477 fprintf(f, "%s", lua_tostring(st, -1));
2478 break;
2479 case LUA_TNIL:
2480 fprintf(f, "nil");
2481 break;
2482 case LUA_TSTRING:
2483 write_escaped_string(f, lua_tostring(st, -1));
2484 break;
2485 case LUA_TTABLE:
2486 if(lvl+1>=EXTL_MAX_SERIALISE_DEPTH){
2487 extl_warn(TR("Maximal serialisation depth reached."));
2488 fprintf(f, "nil");
2489 lua_pop(st, 1);
2490 return FALSE;
2493 fprintf(f, "{\n");
2494 lua_pushnil(st);
2495 while(lua_next(st, -2)!=0){
2496 lua_pushvalue(st, -2);
2497 indent(f, lvl+1);
2498 fprintf(f, "[");
2499 ser(st, f, lvl+1);
2500 fprintf(f, "] = ");
2501 ser(st, f, lvl+1);
2502 fprintf(f, ",\n");
2504 indent(f, lvl);
2505 fprintf(f, "}");
2506 break;
2507 default:
2508 extl_warn(TR("Unable to serialise type %s."),
2509 lua_typename(st, lua_type(st, -1)));
2511 lua_pop(st, 1);
2512 return TRUE;
2516 static bool extl_do_serialise(lua_State *st, SerData *d)
2518 if(!extl_getref(st, d->tab))
2519 return FALSE;
2521 return ser(st, d->f, 0);
2525 /* Tab must not contain recursive references! */
2526 extern bool extl_serialise(const char *file, ExtlTab tab)
2528 SerData d;
2529 bool ret;
2531 d.tab=tab;
2532 d.f=fopen(file, "w");
2534 if(d.f==NULL){
2535 extl_warn_err_obj(file);
2536 return FALSE;
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");
2546 fclose(d.f);
2548 return ret;
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;
2560 else
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);
2578 /*}}}*/