2 * Copyright (c) 2007-2008 Mauro Iazzi
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use,
8 * copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
27 #include "lqt_common.hpp"
30 #define LQT_FIXEDINDEX(i) (i<0?(1+lua_gettop(L)+i):i)
31 #define LQT_MAX_ARGS 50
35 # define SEE_STACK(L, j) for (int j=1;j<=lua_gettop(L);j++) { qDebug() << j << '=' << luaL_typename(L, j) << '@' << lua_topointer (L, j); }
40 // - add a metatable for void* which always results in nil and possibly
41 // accounts for reassigning the userdata to the right metatable.
42 // - proper descending down the dependency tree for indexing, and proper
43 // handling of missing binds
48 //using namespace std;
50 int check_gc(lua_State
*L
){
52 lua_getglobal(L
, "print");
53 lua_setfield(L
, -2, "__gc");
54 lua_setmetatable(L
, -2);
58 void *get_buffer(lua_State
*L
, size_t sz
) {
60 void *ret
= lua_newuserdata(L
, sz
);
62 lua_pushlightuserdata(L
, ret
);
64 lua_settable(L
, LUA_REGISTRYINDEX
);
66 void *ret
= malloc(sz
);
72 int& lqtL_tointref (lua_State
*L
, int i
) {
73 i
= LQT_FIXEDINDEX(i
);
75 ret
= (int*)get_buffer(L
, sizeof(int));
76 *ret
= lua_type(L
, i
)==LUA_TNUMBER
?lua_tointeger(L
, i
):0;
77 //cout << "interef " << ret << endl;
80 void lqtL_pusharguments (lua_State
*L
, char **argv
) {
83 for (i
=0;*argv
&& i
<LQT_MAX_ARGS
;argv
++,i
++) {
84 lua_pushstring(L
, *argv
);
85 lua_rawseti(L
, -2, i
+1);
89 char** lqtL_toarguments (lua_State
*L
, int index
) {
90 index
= LQT_FIXEDINDEX(index
);
96 retlen
= lua_objlen(L
, index
);
97 ret
= (char**)get_buffer(L
, sizeof(char*)*(retlen
+1));
98 //cout << retlen << endl;
99 for (i
=0;i
<retlen
;i
++) {
100 lua_rawgeti(L
, index
, i
+1);
101 if (lua_isstring(L
, -1)) {
102 str
= lua_tolstring(L
, -1, &strlen
);
103 ret
[i
] = (char*)get_buffer(L
, sizeof(char)*(strlen
+1));
104 strncpy(ret
[i
], str
, strlen
+1);
105 //cout << "arg " << (void*)ret[i] << ' ' << ret[i] << endl;
109 ret
[i
] = (char*)get_buffer(L
, sizeof(char)*(strlen
+1));
110 strncpy(ret
[i
], str
, strlen
+1);
111 //cout << "Zarg " << (void*)ret[i] << ' ' << ret[i] << endl;
116 //cout << "arg[] " << ret << endl;
119 bool lqtL_testarguments (lua_State
*L
, int index
) {
120 return (bool)lua_istable(L
, index
);
123 void lqtL_setvoidmetatable (lua_State
*L
, int i
, const char *t
= 0) {
124 i
= LQT_FIXEDINDEX(i
);
125 if (luaL_newmetatable(L
, "void*")) {
127 lua_setfield(L
, -2, "__index");
128 lua_pushstring(L
, "void*");
129 lua_setfield(L
, -2, "__qtype");
131 lua_setmetatable(L
, i
);
134 lua_pushstring(L
, t
);
135 lua_setfield(L
, -2, "__unknown_type");
140 void lqtL_getpointers (lua_State
*L
) {
141 lua_getfield(L
, LUA_REGISTRYINDEX
, LQT_POINTERS
);
142 if (!lua_istable(L
, -1)) {
143 //cout << "Registry Pointers created" << endl;
147 lua_pushstring(L
, "kv");
148 lua_setfield(L
, -2, "__mode");
149 lua_setmetatable(L
, -2);
150 lua_pushvalue(L
, -1);
151 lua_setfield(L
, LUA_REGISTRYINDEX
, LQT_POINTERS
);
156 int lqtL_reusepointer (lua_State
*L
, const void *p
, const char *t
) {
158 lua_pushlightuserdata(L
, const_cast<void*>(p
));
160 if (lqtL_testudata(L
, -1, t
) && (p
==*(const void**)lua_touserdata(L
, -1))) {
163 //qDebug() << "reused" << p << "in" << lua_touserdata(L, -1) << t;
164 //lua_getmetatable(L, -1);luaL_getmetatable(L, t);
165 //qDebug() << "meta" << lua_topointer(L, -2) << "type" << lua_topointer(L, -1);
173 void lqtL_pushpointer (lua_State
*L
, const void *obj
, const char *t
) {
174 const void **objp
= (const void**)lua_newuserdata(L
, sizeof(const void *));
176 lua_getfield(L
, LUA_REGISTRYINDEX
, t
);
177 if (lua_istable(L
, -1)) {
178 lua_setmetatable(L
, -2);
182 //cout << "NO metatable given" << endl;
183 // TODO: add a fallback?
185 lqtL_setvoidmetatable(L
, -1, t
);
188 //cout << "pushed " << objp << ' ' << obj << endl;
191 void lqtL_setpointer (lua_State
*L
, int i
, const void *obj
) {
192 int index
= i
<0?(1+lua_gettop(L
)+i
):i
;
193 //cout << lua_gettop(L) << ' ' << i << ' ' << index << endl;
195 lua_pushlightuserdata(L
, const_cast<void *>(obj
));
196 lua_pushvalue(L
, index
);
201 void lqtL_unsetpointer (lua_State
*L
, const void *obj
) {
203 lua_pushlightuserdata(L
, const_cast<void *>(obj
));
210 // TODO: don't need, it's debug
211 void * lqtL_topointer (lua_State
*L
, int i
) {
213 ret
= lua_touserdata(L
, i
);
214 ret
= (ret
==0)?0:*static_cast<void**>(ret
);
218 void lqtL_unmanageudata (lua_State
*L
, int i
) {
219 if (!lua_isuserdata(L
, i
)) return;
221 if (lua_istable(L
, -1)) {
223 lua_setfield(L
, -2, "__gc");
228 void lqtL_manageudata (lua_State
*L
, int index
) {
229 //luaL_checkstack(L, 20, "");
230 index
= LQT_FIXEDINDEX(index
);
231 if (!lua_isuserdata(L
, index
)) return;
232 lua_getfield(L
, index
, "delete");
233 if (!lua_isfunction(L
, -1)) {
237 lua_getfenv(L
, index
);
238 if (!lua_istable(L
, -1)) {
242 lua_pushvalue(L
, -1);
243 lua_setfenv(L
, index
);
246 lua_setfield(L
, -2, "__gc");
250 void lqtL_pushudata (lua_State
*L
, const void *obj
, const char *t
) {
251 // TODO: make the udata unique
252 //cout << endl << "pushing udata " << obj << " with type " << t << endl;
254 lua_checkstack(L
, 5);
256 if (lqtL_reusepointer(L
, obj
, t
)) {
257 //cout << obj << " reused " << t << endl;
260 //cout << obj << " NOT reused " << t << endl;
263 lua_pushlightuserdata(L
, const_cast<void *>(obj
));
266 //cout << lua_gettop(L) << endl;
267 lua_getglobal(L
, "print");
268 if (lua_getmetatable(L
, -2)) {
269 //cout << "metatable "; // << lua_tostring(L, -1) << endl << endl;
272 //cout << "no metatable" << endl;
275 //cout << lua_gettop(L) << endl;
276 lua_getglobal(L
, "print");
277 lua_getfield(L
, LUA_REGISTRYINDEX
, t
);
278 //cout << "registry "; // << lua_tostring(L, -1) << endl; lua_pop(L, 1);
281 //cout << lua_gettop(L) << endl;
282 if (lua_getmetatable(L
, -1)) {
283 lua_getfield(L
, LUA_REGISTRYINDEX
, t
);
284 //cout << (bool)lua_equal(L, -1, -2) << endl;
285 lua_getglobal(L
, "print");
289 //cout << "no metatable" << endl;
293 if (lqtL_testudata(L
, -1, t
)) {
294 //cout << obj << " reused" << endl;
298 //cout << luaL_typename(L, -1) << " testudata failed " << lua_touserdata(L, -1) << ' ' << lqtL_topointer(L, -1) << endl;
304 lqtL_pushpointer(L
, obj
, t
);
306 const void **objp
= (const void**)lua_newuserdata(L
, sizeof(const void *));
308 lua_getfield(L
, LUA_REGISTRYINDEX
, t
);
309 if (lua_istable(L
, -1)) {
310 lua_setmetatable(L
, -2);
312 //cout << "NO metatable given" << endl;
314 // TODO: add a fallback?
317 //cout << "pushed " << objp << ' ' << obj << endl;
319 //cout << lua_gettop(L) << endl;
321 lqtL_setpointer(L
, -1, obj
);
323 lua_getfield(L
, LUA_REGISTRYINDEX
, LQT_POINTERS
);
324 lua_pushlightuserdata(L
, const_cast<void *>(obj
));
325 lua_pushvalue(L
, -3);
329 //cout << lua_gettop(L) << endl;
331 void lqtL_passudata (lua_State
*L
, const void *obj
, const char *t
) {
332 //cout << "passing: " << obj << " " << t << endl;
333 lqtL_pushudata(L
, obj
, t
);
334 lqtL_manageudata(L
, -1);
338 int lqtL_derivesfrom (lua_State
*L
, int i
, const char *t
) {
340 int oldtop
= lua_gettop(L
);
341 i
= LQT_FIXEDINDEX(i
);
343 if (!lua_istable(L
, i
)) {
347 luaL_checkstack(L
, 1, "cannot grow stack for checking object type");
349 //qDebug() << "given a table" << lua_topointer(L, i);
350 lua_getfield(L
, LUA_REGISTRYINDEX
, t
);
351 //qDebug() << "table" << t << lua_topointer(L, -1);
352 ret
= lua_equal(L
, i
, -1);
353 //qDebug() << "same as" << t << "?" << (bool)ret;
356 lua_settop(L, oldtop);
363 luaL_checkstack(L
, 13, "cannot grow stack for checking object type"); // FIXME: is it enough?
364 lua_getfield(L
, i
, "__base");
366 if (!lua_istable(L
, -1)) {
370 lua_getfield(L
, -1, t
);
371 ret
= lua_isnil(L
, -1)?0:1;
372 //if (ret) qDebug() << (lua_toboolean(L, -1)?"directly":"INDIRECTLY") << "derives from" << t;
373 // DANGER: order of control expression is important
374 while ((ret
== 0) && (lua_next(L
, -2) != 0)) {
375 if (!lua_istable(L
, -1)) {
377 lua_pushvalue(L
, -1);
378 lua_gettable(L
, LUA_REGISTRYINDEX
);
379 if (lua_istable(L
, -1)) {
380 lua_pushvalue(L
, -2);
381 lua_pushvalue(L
, -2);
385 if (lua_istable(L
, -1)) {
386 ret
= lqtL_derivesfrom(L
, -1, t
);
393 lua_settop(L
, oldtop
);
398 bool lqtL_testudata (lua_State
*L
, int i
, const char *t
) {
399 //qDebug() << "================ testudata" << t;
400 //luaL_checkstack(L, 99, "");
401 i
= LQT_FIXEDINDEX(i
);
403 if (lua_getmetatable(L
, i
)) {
404 //SEE_STACK(L, pippo);
405 //SEE_STACK(L, pippo);
407 lua_getfield(L
, LUA_REGISTRYINDEX
, "QEvent*");
408 if (0 && lua_istable(L
, -1)) {
409 lua_getfield(L
, -1, "__qtype");
410 //SEE_STACK(L, pippo);
415 ret
= (bool) lqtL_derivesfrom(L
, -1, t
);
417 //qDebug() << "derives?" << ret;
418 if (!ret
&& lqtL_derivesfrom(L
, -1, "void*")) {
419 //cout << "checking for a generic void* pointer" << endl;
421 luaL_checkstack(L
, 3, "cannot check void* real type");
423 lua_getfield(L
, -1, "__unknown_type");
424 //TODO: assign dynamically?
425 lua_pushstring(L
, t
);
426 ret
= (bool)lua_equal(L
, -1, -2);
429 // FIXME: deleting makes QMetaObjects not work
435 //cout << t << (ret?"":" NOT") <<" found" << endl;
439 int oldtop = lua_gettop(L);
440 lua_getfield(L, LUA_REGISTRYINDEX, t);
441 if (lua_getmetatable(L, i)) {
442 ret = (bool)lua_equal(L, -1, -2);
445 ret = lqTL_derivesfrom(L, -1, t);
448 lua_settop(L, oldtop);
454 int lqtL_pushtype (lua_State
*L
, int i
) {
455 int type
= lua_type(L
, i
);
456 if (type
!= LUA_TUSERDATA
) {
457 lua_pushstring(L
, lua_typename(L
, type
));
459 lua_getfield(L
, i
, "__qtype");
460 if (!lua_isstring(L
, -1)) {
462 lua_pushstring(L
, "<unknown>");
468 void * lqtL_checkudata (lua_State
*L
, int i
, const char *t
) {
469 if (lqtL_testudata(L
, i
, t
)) {
470 return lua_touserdata(L
, i
);
472 lua_pushstring(L
, "Fatal error: userdata type mismatch. requested ");
473 lua_pushstring(L
, t
);
474 lua_pushstring(L
, " found ");
482 void * lqtL_toudata (lua_State
*L
, int i
, const char *t
) {
484 if (lqtL_testudata(L
, i
, t
)) {
485 ret
= *static_cast<void**>(lua_touserdata(L
, i
));
490 void lqtL_pushenum (lua_State
*L
, int v
, const char *e
) {
491 lua_getfield(L
, LUA_REGISTRYINDEX
, LQT_ENUMS
);
492 if (lua_istable(L
, -1)) {
493 //qDebug() << "LQT_ENUMS is a table";
494 lua_getfield(L
, -1, e
);
497 //qDebug() << "LQT_ENUMS is NOT a table";
499 lua_pushinteger(L
, v
);
500 if (lua_istable(L
, -2)) {
501 //qDebug() << "getting translation";
504 //qDebug() << "no translation table for" << e;
508 bool lqtL_isenum (lua_State
*L
, int i
, const char *e
) {
510 if (lua_type(L
, i
)==LUA_TNUMBER
) {
511 ret
= (lua_tointeger(L
, i
)==lua_tonumber(L
, i
));
512 } else if (lua_type(L
, i
)==LUA_TSTRING
) {
513 lua_getfield(L
, LUA_REGISTRYINDEX
, LQT_ENUMS
);
514 if (lua_istable(L
, -1)) {
515 lua_getfield(L
, -1, e
);
519 if (lua_istable(L
, -2)) {
522 if (lua_type(L
, -1)==LUA_TNUMBER
) {
523 ret
= (lua_tointeger(L
, -1)==lua_tonumber(L
, -1));
529 int lqtL_toenum (lua_State
*L
, int i
, const char *e
) {
531 if (lua_type(L
, i
)==LUA_TNUMBER
) {
532 ret
= lua_tointeger(L
, i
);
533 } else if (lua_type(L
, i
)==LUA_TSTRING
) {
534 lua_getfield(L
, LUA_REGISTRYINDEX
, LQT_ENUMS
);
535 if (lua_istable(L
, -1)) {
536 lua_getfield(L
, -1, e
);
540 if (lua_istable(L
, -2)) {
543 if (lua_type(L
, -1)==LUA_TNUMBER
) {
544 ret
= lua_tointeger(L
, -1);
551 int lqtL_baseindex (lua_State
*L
, int index
, int key
) {
553 int oldtop
= lua_gettop(L
);
554 index
= LQT_FIXEDINDEX(index
);
555 key
= LQT_FIXEDINDEX(key
);
557 if (!lua_istable(L
, index
)) {
561 luaL_checkstack(L
, 1, "cannot grow stack for retrieving member");
563 lua_pushvalue(L
, key
);
564 lua_gettable(L
, index
);
566 if (!lua_isnil(L
, -1)) {
569 luaL_checkstack(L
, 7, "cannot grow stack for retrieving member"); // FIXME: is it enough?
570 lua_getfield(L
, index
, "__base");
572 if (!lua_istable(L
, -1)) {
577 // DANGER: order of control expression is important
578 while ((ret
== 0) && (lua_next(L
, -2) != 0)) {
579 if (!lua_istable(L
, -1) && lua_isboolean(L
, -1) && lua_toboolean(L
, -1)) {
581 lua_pushvalue(L
, -1);
582 lua_gettable(L
, LUA_REGISTRYINDEX
);
583 if (lua_istable(L
, -1)) {
584 lua_pushvalue(L
, -2);
585 lua_pushvalue(L
, -2);
589 if (lua_istable(L
, -1)) {
590 ret
= lqtL_baseindex(L
, -1, key
);
600 lua_insert(L
, oldtop
+1);
602 lua_settop(L
, oldtop
+ret
);
607 int lqtL_index (lua_State
*L
) {
609 luaL_checkstack(L
, 1, "cannot grow stack for retrieving member");
610 if (!lua_getmetatable(L
, 1)) {
614 return lqtL_baseindex(L
, 3, 2);
616 luaL_checkstack(L, 2, "cannot grow stack for retrieving member");
617 lua_getmetatable(L, 1);
618 if (lua_istable(L, -1)) {
629 int lqtL_newindex (lua_State
*L
) {
630 if (!lua_getmetatable(L
, 1)) {
633 if (lua_istable(L
, -1)) {
642 int lqtL_gc (lua_State
*L
) {
643 if (!lua_isuserdata(L
, 1)) return 0;
646 if (lua_istable(L
, -1)) {
647 lua_getfield(L
, -1, "__gc");
648 if (lua_isfunction(L
, -1)) {
649 //cout << "found fenv gc " << lua_topointer(L, -1) << endl;
653 //cout << "NOT found fenv gc" << endl;
659 // FIXME: this is useless, isn't it?
660 void **p
= static_cast<void**>(lua_touserdata(L
, 1));