Initial commit
[Leditor.git] / src / lqt_common.cpp
blob555432852f2db846aebc1ff14669cea84e604a6b
1 #include "lqt_common.hpp"
2 #include <cstring>
4 #define LQT_FIXEDINDEX(i) (i<0?(1+lua_gettop(L)+i):i)
5 #define LQT_MAX_ARGS 50
7 #include <QDebug>
8 #ifndef SEE_STACK
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); }
10 #endif
12 // TODO
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
21 //#include <iostream>
22 //using namespace std;
24 int check_gc(lua_State*L){
25 lua_newtable(L);
26 lua_getglobal(L, "print");
27 lua_setfield(L, -2, "__gc");
28 lua_setmetatable(L, -2);
29 return 0;
32 void *get_buffer(lua_State *L, size_t sz) {
33 #if 1
34 void *ret = lua_newuserdata(L, sz);
35 //check_gc(L);
36 lua_pushlightuserdata(L, ret);
37 lua_insert(L, -2);
38 lua_settable(L, LUA_REGISTRYINDEX);
39 #else
40 void *ret = malloc(sz);
41 cout << ret << endl;
42 #endif
43 return ret;
46 int& lqtL_tointref (lua_State *L, int i) {
47 i = LQT_FIXEDINDEX(i);
48 int *ret = NULL;
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;
52 return *ret;
54 void lqtL_pusharguments (lua_State *L, const char **argv) {
55 int i = 0;
56 lua_newtable(L);
57 for (i=0;*argv && i<LQT_MAX_ARGS;argv++,i++) {
58 lua_pushstring(L, *argv);
59 lua_rawseti(L, -2, i+1);
61 return;
63 char** lqtL_toarguments (lua_State *L, int index) {
64 index = LQT_FIXEDINDEX(index);
65 char **ret;
66 const char *str;
67 int retlen = 0;
68 size_t strlen = 0;
69 int i = 0;
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;
80 } else {
81 strlen = 0;
82 str = "\0";
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;
87 lua_pop(L, 1);
89 ret[retlen] = NULL;
90 //cout << "arg[] " << ret << endl;
91 return ret;
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*")) {
100 lua_newtable(L);
101 lua_setfield(L, -2, "__index");
102 lua_pushstring(L, "void*");
103 lua_setfield(L, -2, "__qtype");
105 lua_setmetatable(L, i);
106 if (t!=0) {
107 lua_newtable(L);
108 lua_pushstring(L, t);
109 lua_setfield(L, -2, "__unknown_type");
110 lua_setfenv(L, i);
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;
118 lua_pop(L, 1);
119 lua_newtable(L);
120 lua_newtable(L);
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);
127 return;
130 int lqtL_reusepointer (lua_State *L, const void *p, const char *t) {
131 lqtL_getpointers(L);
132 lua_pushlightuserdata(L, const_cast<void*>(p));
133 lua_gettable(L, -2);
134 if (lqtL_testudata(L, -1, t) && (p==*(const void**)lua_touserdata(L, -1))) {
135 lua_remove(L, -2);
136 //qDebug();
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);
140 //lua_pop(L, 2);
141 return 1;
143 lua_pop(L, 2);
144 return 0;
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 *));
149 *objp = 0;
150 lua_getfield(L, LUA_REGISTRYINDEX, t);
151 if (lua_istable(L, -1)) {
152 lua_setmetatable(L, -2);
153 lua_newtable(L);
154 lua_setfenv(L, -2);
155 } else {
156 //cout << "NO metatable given" << endl;
157 // TODO: add a fallback?
158 lua_pop(L, 1);
159 lqtL_setvoidmetatable(L, -1, t);
161 *objp = obj;
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;
168 lqtL_getpointers(L);
169 lua_pushlightuserdata(L, const_cast<void *>(obj));
170 lua_pushvalue(L, index);
171 lua_settable(L, -3);
172 lua_pop(L, 1);
173 return;
175 void lqtL_unsetpointer (lua_State *L, const void *obj) {
176 lqtL_getpointers(L);
177 lua_pushlightuserdata(L, const_cast<void *>(obj));
178 lua_pushnil(L);
179 lua_settable(L, -3);
180 lua_pop(L, 1);
181 return;
184 // TODO: don't need, it's debug
185 void * lqtL_topointer (lua_State *L, int i) {
186 void * ret = NULL;
187 ret = lua_touserdata(L, i);
188 ret = (ret==0)?0:*static_cast<void**>(ret);
189 return ret;
192 void lqtL_unmanageudata (lua_State *L, int i) {
193 if (!lua_isuserdata(L, i)) return;
194 lua_getfenv(L, i);
195 if (lua_istable(L, -1)) {
196 lua_pushnil(L);
197 lua_setfield(L, -2, "__gc");
199 lua_pop(L, 1);
200 return;
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)) {
208 lua_pop(L, 1);
209 return;
211 lua_getfenv(L, index);
212 if (!lua_istable(L, -1)) {
213 lua_pop(L, 1);
214 //if (1) {
215 lua_newtable(L);
216 lua_pushvalue(L, -1);
217 lua_setfenv(L, index);
219 lua_insert(L, -2);
220 lua_setfield(L, -2, "__gc");
221 lua_pop(L, 1);
222 return;
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);
229 if (1) {
230 if (lqtL_reusepointer(L, obj, t)) {
231 //cout << obj << " reused " << t << endl;
232 return;
234 //cout << obj << " NOT reused " << t << endl;
235 } else {
236 lqtL_getpointers(L);
237 lua_pushlightuserdata(L, const_cast<void *>(obj));
238 lua_gettable(L, -2);
239 if (0) {
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;
244 lua_call(L, 1, 0);
245 } else {
246 //cout << "no metatable" << endl;
247 lua_pop(L, 1);
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);
253 lua_call(L, 1, 0);
254 } else if (0) {
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");
260 lua_insert(L, -3);
261 lua_call(L, 2, 0);
262 } else {
263 //cout << "no metatable" << endl;
264 lua_pop(L, 1);
267 if (lqtL_testudata(L, -1, t)) {
268 //cout << obj << " reused" << endl;
269 lua_remove(L, -2);
270 return;
271 } else {
272 //cout << luaL_typename(L, -1) << " testudata failed " << lua_touserdata(L, -1) << ' ' << lqtL_topointer(L, -1) << endl;
274 lua_pop(L, 2);
277 if (1) {
278 lqtL_pushpointer(L, obj, t);
279 } else {
280 const void **objp = (const void**)lua_newuserdata(L, sizeof(const void *));
281 *objp = 0;
282 lua_getfield(L, LUA_REGISTRYINDEX, t);
283 if (lua_istable(L, -1)) {
284 lua_setmetatable(L, -2);
285 } else {
286 //cout << "NO metatable given" << endl;
287 lua_pop(L, 1);
288 // TODO: add a fallback?
290 *objp = obj;
291 //cout << "pushed " << objp << ' ' << obj << endl;
293 //cout << lua_gettop(L) << endl;
294 if (1) {
295 lqtL_setpointer(L, -1, obj);
296 } else {
297 lua_getfield(L, LUA_REGISTRYINDEX, LQT_POINTERS);
298 lua_pushlightuserdata(L, const_cast<void *>(obj));
299 lua_pushvalue(L, -3);
300 lua_settable(L, -3);
301 lua_pop(L, 1);
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) {
313 int ret = 0;
314 int oldtop = lua_gettop(L);
315 i = LQT_FIXEDINDEX(i);
317 if (!lua_istable(L, i)) {
318 return 0;
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);
332 return ret;
333 // */
335 if (!ret) {
336 lua_pop(L, 1);
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)) {
341 lua_pop(L, 1);
342 ret = 0;
343 } else {
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)) {
350 lua_pop(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);
356 lua_settable(L, -5);
359 if (lua_istable(L, -1)) {
360 ret = lqtL_derivesfrom(L, -1, t);
362 lua_pop(L, 1);
367 lua_settop(L, oldtop);
369 return ret;
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);
376 bool ret = false;
377 if (lua_getmetatable(L, i)) {
378 //SEE_STACK(L, pippo);
379 //SEE_STACK(L, pippo);
380 if (0) {
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);
385 lua_pop(L, 1);
387 lua_pop(L, 2);
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");
396 lua_getfenv(L, i);
397 lua_getfield(L, -1, "__unknown_type");
398 //TODO: assign dynamically?
399 lua_pushstring(L, t);
400 ret = (bool)lua_equal(L, -1, -2);
401 lua_pop(L, 3);
402 // */
403 // FIXME: deleting makes QMetaObjects not work
404 //ret = true;
406 lua_pop(L, 1);
407 } else {
409 //cout << t << (ret?"":" NOT") <<" found" << endl;
410 return ret;
412 bool ret = false;
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);
417 if (!ret) {
418 lua_remove(L, -2);
419 ret = lqTL_derivesfrom(L, -1, t);
422 lua_settop(L, oldtop);
423 return ret;
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));
432 } else {
433 lua_getfield(L, i, "__qtype");
434 if (!lua_isstring(L, -1)) {
435 lua_pop(L, 1);
436 lua_pushstring(L, "<unknown>");
439 return 1;
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);
445 } else {
446 lua_pushstring(L, "Fatal error: userdata type mismatch. requested ");
447 lua_pushstring(L, t);
448 lua_pushstring(L, " found ");
449 lqtL_pushtype(L, i);
450 lua_concat(L, 4);
451 lua_error(L);
453 return 0;
455 //*/
456 void * lqtL_toudata (lua_State *L, int i, const char *t) {
457 void * ret = NULL;
458 if (lqtL_testudata(L, i, t)) {
459 ret = *static_cast<void**>(lua_touserdata(L, i));
461 return ret;
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);
469 lua_remove(L, -2);
470 } else {
471 //qDebug() << "LQT_ENUMS is NOT a table";
473 lua_pushinteger(L, v);
474 if (lua_istable(L, -2)) {
475 //qDebug() << "getting translation";
476 lua_gettable(L, -2);
477 } else {
478 //qDebug() << "no translation table for" << e;
480 lua_remove(L, -2);
482 bool lqtL_isenum (lua_State *L, int i, const char *e) {
483 bool ret = false;
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);
490 lua_remove(L, -2);
492 lua_pushvalue(L, i);
493 if (lua_istable(L, -2)) {
494 lua_gettable(L, -2);
496 if (lua_type(L, -1)==LUA_TNUMBER) {
497 ret = (lua_tointeger(L, -1)==lua_tonumber(L, -1));
499 lua_pop(L, 2);
501 return ret;
503 int lqtL_toenum (lua_State *L, int i, const char *e) {
504 int ret = -1;
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);
511 lua_remove(L, -2);
513 lua_pushvalue(L, i);
514 if (lua_istable(L, -2)) {
515 lua_gettable(L, -2);
517 if (lua_type(L, -1)==LUA_TNUMBER) {
518 ret = lua_tointeger(L, -1);
520 lua_pop(L, 2);
522 return ret;
525 int lqtL_baseindex (lua_State *L, int index, int key) {
526 int ret = 0;
527 int oldtop = lua_gettop(L);
528 index = LQT_FIXEDINDEX(index);
529 key = LQT_FIXEDINDEX(key);
531 if (!lua_istable(L, index)) {
532 return 0;
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)) {
541 ret = 1;
542 } else {
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)) {
547 lua_pop(L, 2);
548 ret = 0;
549 } else {
550 lua_insert(L, -2);
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)) {
554 lua_pop(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);
560 lua_settable(L, -5);
563 if (lua_istable(L, -1)) {
564 ret = lqtL_baseindex(L, -1, key);
566 if (ret == 0) {
567 lua_pop(L, 1);
573 if (ret != 0) {
574 lua_insert(L, oldtop+1);
576 lua_settop(L, oldtop+ret);
578 return ret;
581 int lqtL_index (lua_State *L) {
582 lua_settop(L, 2);
583 luaL_checkstack(L, 1, "cannot grow stack for retrieving member");
584 if (!lua_getmetatable(L, 1)) {
585 return 0;
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)) {
593 lua_pushvalue(L, 2);
594 lua_gettable(L, -2);
595 } else {
596 lua_pushnil(L);
598 lua_remove(L, -2);
599 return 1;
603 int lqtL_newindex (lua_State *L) {
604 if (!lua_getmetatable(L, 1)) {
605 return 0;
607 if (lua_istable(L, -1)) {
608 lua_pushvalue(L, 2);
609 lua_pushvalue(L, 3);
610 lua_settable(L, -3);
611 lua_pop(L, 1);
613 return 0;
616 int lqtL_gc (lua_State *L) {
617 if (!lua_isuserdata(L, 1)) return 0;
619 lua_getfenv(L, 1);
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;
624 lua_pushvalue(L, 1);
625 lua_call(L, 1, 0);
626 } else {
627 //cout << "NOT found fenv gc" << endl;
628 lua_pop(L, 1);
631 lua_pop(L, 1);
633 // FIXME: this is useless, isn't it?
634 void **p = static_cast<void**>(lua_touserdata(L, 1));
635 *p = 0;
637 return 0;