1 #include "lqt_common.hpp"
4 #define LQT_FIXEDINDEX(i) (i<0?(1+lua_gettop(L)+i):i)
5 #define LQT_MAX_ARGS 50
9 # define SEE_STACK(L, j) for (int j=1;j<=lua_gettop(L);j++) { qDebug() << j << '=' << luaL_typename(L, j) << '@' << lua_topointer (L, j); }
14 // - add a metatable for void* which always results in nil and possibly
15 // accounts for reassigning the userdata to the right metatable.
16 // - proper descending down the dependency tree for indexing, and proper
17 // handling of missing binds
22 //using namespace std;
24 int check_gc(lua_State
*L
){
26 lua_getglobal(L
, "print");
27 lua_setfield(L
, -2, "__gc");
28 lua_setmetatable(L
, -2);
32 void *get_buffer(lua_State
*L
, size_t sz
) {
34 void *ret
= lua_newuserdata(L
, sz
);
36 lua_pushlightuserdata(L
, ret
);
38 lua_settable(L
, LUA_REGISTRYINDEX
);
40 void *ret
= malloc(sz
);
46 int& lqtL_tointref (lua_State
*L
, int i
) {
47 i
= LQT_FIXEDINDEX(i
);
49 ret
= (int*)get_buffer(L
, sizeof(int));
50 *ret
= lua_type(L
, i
)==LUA_TNUMBER
?lua_tointeger(L
, i
):0;
51 //cout << "interef " << ret << endl;
54 void lqtL_pusharguments (lua_State
*L
, const char **argv
) {
57 for (i
=0;*argv
&& i
<LQT_MAX_ARGS
;argv
++,i
++) {
58 lua_pushstring(L
, *argv
);
59 lua_rawseti(L
, -2, i
+1);
63 char** lqtL_toarguments (lua_State
*L
, int index
) {
64 index
= LQT_FIXEDINDEX(index
);
70 retlen
= lua_objlen(L
, index
);
71 ret
= (char**)get_buffer(L
, sizeof(char*)*(retlen
+1));
72 //cout << retlen << endl;
73 for (i
=0;i
<retlen
;i
++) {
74 lua_rawgeti(L
, index
, i
+1);
75 if (lua_isstring(L
, -1)) {
76 str
= lua_tolstring(L
, -1, &strlen
);
77 ret
[i
] = (char*)get_buffer(L
, sizeof(char)*(strlen
+1));
78 strncpy(ret
[i
], str
, strlen
+1);
79 //cout << "arg " << (void*)ret[i] << ' ' << ret[i] << endl;
83 ret
[i
] = (char*)get_buffer(L
, sizeof(char)*(strlen
+1));
84 strncpy(ret
[i
], str
, strlen
+1);
85 //cout << "Zarg " << (void*)ret[i] << ' ' << ret[i] << endl;
90 //cout << "arg[] " << ret << endl;
93 bool lqtL_testarguments (lua_State
*L
, int index
) {
94 return (bool)lua_istable(L
, index
);
97 void lqtL_setvoidmetatable (lua_State
*L
, int i
, const char *t
= 0) {
98 i
= LQT_FIXEDINDEX(i
);
99 if (luaL_newmetatable(L
, "void*")) {
101 lua_setfield(L
, -2, "__index");
102 lua_pushstring(L
, "void*");
103 lua_setfield(L
, -2, "__qtype");
105 lua_setmetatable(L
, i
);
108 lua_pushstring(L
, t
);
109 lua_setfield(L
, -2, "__unknown_type");
114 void lqtL_getpointers (lua_State
*L
) {
115 lua_getfield(L
, LUA_REGISTRYINDEX
, LQT_POINTERS
);
116 if (!lua_istable(L
, -1)) {
117 //cout << "Registry Pointers created" << endl;
121 lua_pushstring(L
, "kv");
122 lua_setfield(L
, -2, "__mode");
123 lua_setmetatable(L
, -2);
124 lua_pushvalue(L
, -1);
125 lua_setfield(L
, LUA_REGISTRYINDEX
, LQT_POINTERS
);
130 int lqtL_reusepointer (lua_State
*L
, const void *p
, const char *t
) {
132 lua_pushlightuserdata(L
, const_cast<void*>(p
));
134 if (lqtL_testudata(L
, -1, t
) && (p
==*(const void**)lua_touserdata(L
, -1))) {
137 //qDebug() << "reused" << p << "in" << lua_touserdata(L, -1) << t;
138 //lua_getmetatable(L, -1);luaL_getmetatable(L, t);
139 //qDebug() << "meta" << lua_topointer(L, -2) << "type" << lua_topointer(L, -1);
147 void lqtL_pushpointer (lua_State
*L
, const void *obj
, const char *t
) {
148 const void **objp
= (const void**)lua_newuserdata(L
, sizeof(const void *));
150 lua_getfield(L
, LUA_REGISTRYINDEX
, t
);
151 if (lua_istable(L
, -1)) {
152 lua_setmetatable(L
, -2);
156 //cout << "NO metatable given" << endl;
157 // TODO: add a fallback?
159 lqtL_setvoidmetatable(L
, -1, t
);
162 //cout << "pushed " << objp << ' ' << obj << endl;
165 void lqtL_setpointer (lua_State
*L
, int i
, const void *obj
) {
166 int index
= i
<0?(1+lua_gettop(L
)+i
):i
;
167 //cout << lua_gettop(L) << ' ' << i << ' ' << index << endl;
169 lua_pushlightuserdata(L
, const_cast<void *>(obj
));
170 lua_pushvalue(L
, index
);
175 void lqtL_unsetpointer (lua_State
*L
, const void *obj
) {
177 lua_pushlightuserdata(L
, const_cast<void *>(obj
));
184 // TODO: don't need, it's debug
185 void * lqtL_topointer (lua_State
*L
, int i
) {
187 ret
= lua_touserdata(L
, i
);
188 ret
= (ret
==0)?0:*static_cast<void**>(ret
);
192 void lqtL_unmanageudata (lua_State
*L
, int i
) {
193 if (!lua_isuserdata(L
, i
)) return;
195 if (lua_istable(L
, -1)) {
197 lua_setfield(L
, -2, "__gc");
202 void lqtL_manageudata (lua_State
*L
, int index
) {
203 //luaL_checkstack(L, 20, "");
204 index
= LQT_FIXEDINDEX(index
);
205 if (!lua_isuserdata(L
, index
)) return;
206 lua_getfield(L
, index
, "delete");
207 if (!lua_isfunction(L
, -1)) {
211 lua_getfenv(L
, index
);
212 if (!lua_istable(L
, -1)) {
216 lua_pushvalue(L
, -1);
217 lua_setfenv(L
, index
);
220 lua_setfield(L
, -2, "__gc");
224 void lqtL_pushudata (lua_State
*L
, const void *obj
, const char *t
) {
225 // TODO: make the udata unique
226 //cout << endl << "pushing udata " << obj << " with type " << t << endl;
228 lua_checkstack(L
, 5);
230 if (lqtL_reusepointer(L
, obj
, t
)) {
231 //cout << obj << " reused " << t << endl;
234 //cout << obj << " NOT reused " << t << endl;
237 lua_pushlightuserdata(L
, const_cast<void *>(obj
));
240 //cout << lua_gettop(L) << endl;
241 lua_getglobal(L
, "print");
242 if (lua_getmetatable(L
, -2)) {
243 //cout << "metatable "; // << lua_tostring(L, -1) << endl << endl;
246 //cout << "no metatable" << endl;
249 //cout << lua_gettop(L) << endl;
250 lua_getglobal(L
, "print");
251 lua_getfield(L
, LUA_REGISTRYINDEX
, t
);
252 //cout << "registry "; // << lua_tostring(L, -1) << endl; lua_pop(L, 1);
255 //cout << lua_gettop(L) << endl;
256 if (lua_getmetatable(L
, -1)) {
257 lua_getfield(L
, LUA_REGISTRYINDEX
, t
);
258 //cout << (bool)lua_equal(L, -1, -2) << endl;
259 lua_getglobal(L
, "print");
263 //cout << "no metatable" << endl;
267 if (lqtL_testudata(L
, -1, t
)) {
268 //cout << obj << " reused" << endl;
272 //cout << luaL_typename(L, -1) << " testudata failed " << lua_touserdata(L, -1) << ' ' << lqtL_topointer(L, -1) << endl;
278 lqtL_pushpointer(L
, obj
, t
);
280 const void **objp
= (const void**)lua_newuserdata(L
, sizeof(const void *));
282 lua_getfield(L
, LUA_REGISTRYINDEX
, t
);
283 if (lua_istable(L
, -1)) {
284 lua_setmetatable(L
, -2);
286 //cout << "NO metatable given" << endl;
288 // TODO: add a fallback?
291 //cout << "pushed " << objp << ' ' << obj << endl;
293 //cout << lua_gettop(L) << endl;
295 lqtL_setpointer(L
, -1, obj
);
297 lua_getfield(L
, LUA_REGISTRYINDEX
, LQT_POINTERS
);
298 lua_pushlightuserdata(L
, const_cast<void *>(obj
));
299 lua_pushvalue(L
, -3);
303 //cout << lua_gettop(L) << endl;
305 void lqtL_passudata (lua_State
*L
, const void *obj
, const char *t
) {
306 //cout << "passing: " << obj << " " << t << endl;
307 lqtL_pushudata(L
, obj
, t
);
308 lqtL_manageudata(L
, -1);
312 int lqtL_derivesfrom (lua_State
*L
, int i
, const char *t
) {
314 int oldtop
= lua_gettop(L
);
315 i
= LQT_FIXEDINDEX(i
);
317 if (!lua_istable(L
, i
)) {
321 luaL_checkstack(L
, 1, "cannot grow stack for checking object type");
323 //qDebug() << "given a table" << lua_topointer(L, i);
324 lua_getfield(L
, LUA_REGISTRYINDEX
, t
);
325 //qDebug() << "table" << t << lua_topointer(L, -1);
326 ret
= lua_equal(L
, i
, -1);
327 //qDebug() << "same as" << t << "?" << (bool)ret;
330 lua_settop(L, oldtop);
337 luaL_checkstack(L
, 13, "cannot grow stack for checking object type"); // FIXME: is it enough?
338 lua_getfield(L
, i
, "__base");
340 if (!lua_istable(L
, -1)) {
344 lua_getfield(L
, -1, t
);
345 ret
= lua_isnil(L
, -1)?0:1;
346 //if (ret) qDebug() << (lua_toboolean(L, -1)?"directly":"INDIRECTLY") << "derives from" << t;
347 // DANGER: order of control expression is important
348 while ((ret
== 0) && (lua_next(L
, -2) != 0)) {
349 if (!lua_istable(L
, -1)) {
351 lua_pushvalue(L
, -1);
352 lua_gettable(L
, LUA_REGISTRYINDEX
);
353 if (lua_istable(L
, -1)) {
354 lua_pushvalue(L
, -2);
355 lua_pushvalue(L
, -2);
359 if (lua_istable(L
, -1)) {
360 ret
= lqtL_derivesfrom(L
, -1, t
);
367 lua_settop(L
, oldtop
);
372 bool lqtL_testudata (lua_State
*L
, int i
, const char *t
) {
373 //qDebug() << "================ testudata" << t;
374 //luaL_checkstack(L, 99, "");
375 i
= LQT_FIXEDINDEX(i
);
377 if (lua_getmetatable(L
, i
)) {
378 //SEE_STACK(L, pippo);
379 //SEE_STACK(L, pippo);
381 lua_getfield(L
, LUA_REGISTRYINDEX
, "QEvent*");
382 if (0 && lua_istable(L
, -1)) {
383 lua_getfield(L
, -1, "__qtype");
384 //SEE_STACK(L, pippo);
389 ret
= (bool) lqtL_derivesfrom(L
, -1, t
);
391 //qDebug() << "derives?" << ret;
392 if (!ret
&& lqtL_derivesfrom(L
, -1, "void*")) {
393 //cout << "checking for a generic void* pointer" << endl;
395 luaL_checkstack(L
, 3, "cannot check void* real type");
397 lua_getfield(L
, -1, "__unknown_type");
398 //TODO: assign dynamically?
399 lua_pushstring(L
, t
);
400 ret
= (bool)lua_equal(L
, -1, -2);
403 // FIXME: deleting makes QMetaObjects not work
409 //cout << t << (ret?"":" NOT") <<" found" << endl;
413 int oldtop = lua_gettop(L);
414 lua_getfield(L, LUA_REGISTRYINDEX, t);
415 if (lua_getmetatable(L, i)) {
416 ret = (bool)lua_equal(L, -1, -2);
419 ret = lqTL_derivesfrom(L, -1, t);
422 lua_settop(L, oldtop);
428 int lqtL_pushtype (lua_State
*L
, int i
) {
429 int type
= lua_type(L
, i
);
430 if (type
!= LUA_TUSERDATA
) {
431 lua_pushstring(L
, lua_typename(L
, type
));
433 lua_getfield(L
, i
, "__qtype");
434 if (!lua_isstring(L
, -1)) {
436 lua_pushstring(L
, "<unknown>");
442 void * lqtL_checkudata (lua_State
*L
, int i
, const char *t
) {
443 if (lqtL_testudata(L
, i
, t
)) {
444 return lua_touserdata(L
, i
);
446 lua_pushstring(L
, "Fatal error: userdata type mismatch. requested ");
447 lua_pushstring(L
, t
);
448 lua_pushstring(L
, " found ");
456 void * lqtL_toudata (lua_State
*L
, int i
, const char *t
) {
458 if (lqtL_testudata(L
, i
, t
)) {
459 ret
= *static_cast<void**>(lua_touserdata(L
, i
));
464 void lqtL_pushenum (lua_State
*L
, int v
, const char *e
) {
465 lua_getfield(L
, LUA_REGISTRYINDEX
, LQT_ENUMS
);
466 if (lua_istable(L
, -1)) {
467 //qDebug() << "LQT_ENUMS is a table";
468 lua_getfield(L
, -1, e
);
471 //qDebug() << "LQT_ENUMS is NOT a table";
473 lua_pushinteger(L
, v
);
474 if (lua_istable(L
, -2)) {
475 //qDebug() << "getting translation";
478 //qDebug() << "no translation table for" << e;
482 bool lqtL_isenum (lua_State
*L
, int i
, const char *e
) {
484 if (lua_type(L
, i
)==LUA_TNUMBER
) {
485 ret
= (lua_tointeger(L
, i
)==lua_tonumber(L
, i
));
486 } else if (lua_type(L
, i
)==LUA_TSTRING
) {
487 lua_getfield(L
, LUA_REGISTRYINDEX
, LQT_ENUMS
);
488 if (lua_istable(L
, -1)) {
489 lua_getfield(L
, -1, e
);
493 if (lua_istable(L
, -2)) {
496 if (lua_type(L
, -1)==LUA_TNUMBER
) {
497 ret
= (lua_tointeger(L
, -1)==lua_tonumber(L
, -1));
503 int lqtL_toenum (lua_State
*L
, int i
, const char *e
) {
505 if (lua_type(L
, i
)==LUA_TNUMBER
) {
506 ret
= lua_tointeger(L
, i
);
507 } else if (lua_type(L
, i
)==LUA_TSTRING
) {
508 lua_getfield(L
, LUA_REGISTRYINDEX
, LQT_ENUMS
);
509 if (lua_istable(L
, -1)) {
510 lua_getfield(L
, -1, e
);
514 if (lua_istable(L
, -2)) {
517 if (lua_type(L
, -1)==LUA_TNUMBER
) {
518 ret
= lua_tointeger(L
, -1);
525 int lqtL_baseindex (lua_State
*L
, int index
, int key
) {
527 int oldtop
= lua_gettop(L
);
528 index
= LQT_FIXEDINDEX(index
);
529 key
= LQT_FIXEDINDEX(key
);
531 if (!lua_istable(L
, index
)) {
535 luaL_checkstack(L
, 1, "cannot grow stack for retrieving member");
537 lua_pushvalue(L
, key
);
538 lua_gettable(L
, index
);
540 if (!lua_isnil(L
, -1)) {
543 luaL_checkstack(L
, 7, "cannot grow stack for retrieving member"); // FIXME: is it enough?
544 lua_getfield(L
, index
, "__base");
546 if (!lua_istable(L
, -1)) {
551 // DANGER: order of control expression is important
552 while ((ret
== 0) && (lua_next(L
, -2) != 0)) {
553 if (!lua_istable(L
, -1) && lua_isboolean(L
, -1) && lua_toboolean(L
, -1)) {
555 lua_pushvalue(L
, -1);
556 lua_gettable(L
, LUA_REGISTRYINDEX
);
557 if (lua_istable(L
, -1)) {
558 lua_pushvalue(L
, -2);
559 lua_pushvalue(L
, -2);
563 if (lua_istable(L
, -1)) {
564 ret
= lqtL_baseindex(L
, -1, key
);
574 lua_insert(L
, oldtop
+1);
576 lua_settop(L
, oldtop
+ret
);
581 int lqtL_index (lua_State
*L
) {
583 luaL_checkstack(L
, 1, "cannot grow stack for retrieving member");
584 if (!lua_getmetatable(L
, 1)) {
588 return lqtL_baseindex(L
, 3, 2);
590 luaL_checkstack(L, 2, "cannot grow stack for retrieving member");
591 lua_getmetatable(L, 1);
592 if (lua_istable(L, -1)) {
603 int lqtL_newindex (lua_State
*L
) {
604 if (!lua_getmetatable(L
, 1)) {
607 if (lua_istable(L
, -1)) {
616 int lqtL_gc (lua_State
*L
) {
617 if (!lua_isuserdata(L
, 1)) return 0;
620 if (lua_istable(L
, -1)) {
621 lua_getfield(L
, -1, "__gc");
622 if (lua_isfunction(L
, -1)) {
623 //cout << "found fenv gc " << lua_topointer(L, -1) << endl;
627 //cout << "NOT found fenv gc" << endl;
633 // FIXME: this is useless, isn't it?
634 void **p
= static_cast<void**>(lua_touserdata(L
, 1));