First attempt at safe virtual overrides
[lqt/mk.git] / common / lqt_common.cpp
blobc28e114dcd156fb0169be8e8185f58ec1f82bf80
1 /*
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
11 * conditions:
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"
28 #include <iostream>
29 #include <cstdlib>
30 #include <cstring>
32 static void lqtL_getenumtable (lua_State *L) {
33 lua_getfield(L, LUA_REGISTRYINDEX, LQT_ENUMS);
34 if (lua_isnil(L, -1)) {
35 lua_pop(L, 1);
36 lua_newtable(L);
37 lua_pushvalue(L, -1);
38 lua_setfield(L, LUA_REGISTRYINDEX, LQT_ENUMS);
42 static void lqtL_getpointertable (lua_State *L) {
43 lua_getfield(L, LUA_REGISTRYINDEX, LQT_POINTERS); // (1) get storage for pointers
44 if (lua_isnil(L, -1)) { // (1) if there is not
45 lua_pop(L, 1); // (0) pop the nil value
46 lua_newtable(L); // (1) create a new one
47 lua_newtable(L); // (2) create an empty metatable
48 lua_pushstring(L, "v"); // (3) push the mode value: weak values are enough
49 lua_setfield(L, -2, "__mode"); // (2) set the __mode field
50 lua_setmetatable(L, -2); // (1) set it as the metatable
51 lua_pushvalue(L, -1); // (2) duplicate the new pointer table
52 lua_setfield(L, LUA_REGISTRYINDEX, LQT_POINTERS); // (1) put one copy as storage
56 static void lqtL_getreftable (lua_State *L) {
57 lua_getfield(L, LUA_REGISTRYINDEX, LQT_REFS); // (1) get storage for pointers
58 if (lua_isnil(L, -1)) { // (1) if there is not
59 lua_pop(L, 1); // (0) pop the nil value
60 lua_newtable(L); // (1) create a new one
61 lua_newtable(L); // (2) create an empty metatable
62 lua_pushstring(L, "v"); // (3) push the mode value: weak values are enough
63 lua_setfield(L, -2, "__mode"); // (2) set the __mode field
64 lua_setmetatable(L, -2); // (1) set it as the metatable
65 lua_pushvalue(L, -1); // (2) duplicate the new pointer table
66 lua_setfield(L, LUA_REGISTRYINDEX, LQT_REFS); // (1) put one copy as storage
70 void * lqtL_getref (lua_State *L, size_t sz, bool weak) {
71 void *ret = NULL;
72 lqtL_getreftable(L); // (1)
73 ret = lua_newuserdata(L, sz); // (2)
75 lua_newtable(L); // (3)
76 lua_getglobal(L, "DEBUG"); // (4)
77 lua_setfield(L, -2, "__gc"); // (3)
78 lua_setmetatable(L, -2); // (2)
80 if (weak) {
81 lua_rawseti(L, -2, 1+lua_objlen(L, -2)); // (1)
82 } else {
83 lua_pushinteger(L, 1+lua_objlen(L, -2)); // (3)
84 lua_settable(L, -3); // (1)
86 lua_pop(L, 1);
87 return ret;
90 bool * lqtL_toboolref (lua_State *L, int index) {
91 bool tmp = lua_toboolean(L, index) == 1;
92 bool *ret = (bool*)lqtL_getref(L, sizeof(bool), true);
93 *ret = tmp;
94 return ret;
97 int * lqtL_tointref (lua_State *L, int index) {
98 int tmp = lua_tointeger(L, index);
99 int *ret = (int*)lqtL_getref(L, sizeof(int), false);
100 *ret = tmp;
101 return ret;
104 void lqtL_pusharguments (lua_State *L, char **argv) {
105 int i = 0;
106 lua_newtable(L);
107 for (i=0;*argv /* fix the maximum number? */;argv++,i++) {
108 lua_pushstring(L, *argv);
109 lua_rawseti(L, -2, i+1);
111 return;
114 char ** lqtL_toarguments (lua_State *L, int index) {
115 char ** ret = (char**)lqtL_getref(L, sizeof(char*)*(lua_objlen(L, index)+1), false);
116 const char *str = NULL;
117 size_t strlen = 0;
118 int i = 0;
119 for (i=0;;i++) {
120 lua_rawgeti(L, index, i+1);
121 if (!lua_isstring(L, -1)) {
122 str = NULL; strlen = 0;
123 ret[i] = NULL;
124 lua_pop(L, 1);
125 break;
126 } else {
127 str = lua_tolstring(L, -1, &strlen);
128 ret[i] = (char*)lqtL_getref(L, sizeof(char)*(strlen+1), false);
129 strncpy(ret[i], str, strlen+1);
130 lua_pop(L, 1);
133 return ret;
136 int lqtL_createenum (lua_State *L, lqt_Enum e[], const char *n) {
137 luaL_Reg empty[] = { { 0, 0 } };
138 lqt_Enum *l = e;
139 lqtL_getenumtable(L); // (1)
140 lua_newtable(L); // (2)
141 lua_pushvalue(L, -1); // (3)
142 lua_setfield(L, -3, n); // (2)
143 while ( (l->name!=0) ) { // (2)
144 lua_pushstring(L, l->name); // (3)
145 lua_pushinteger(L, l->value); // (4)
146 lua_settable(L, -3); // (2)
147 lua_pushinteger(L, l->value); // (3)
148 lua_pushstring(L, l->name); // (4)
149 lua_settable(L, -3); // (2)
150 l++; // (2)
152 lua_pop(L, 2); // (0)
153 l = e;
154 luaL_register(L, n, empty); // (1)
155 while ( (l->name!=0) ) { // (1)
156 lua_pushstring(L, l->name); // (2)
157 lua_pushinteger(L, l->value); // (3)
158 lua_settable(L, -3); // (1)
159 lua_pushinteger(L, l->value); // (2)
160 lua_pushstring(L, l->name); // (3)
161 lua_settable(L, -3); // (1)
162 l++; // (1)
164 lua_pop(L, 1); // (0)
165 return 0;
168 int lqtL_createenumlist (lua_State *L, lqt_Enumlist list[]) {
169 while (list->enums!=0 && list->name!=0) {
170 lqtL_createenum(L, list->enums, list->name); // (0)
171 list++;
173 return 0;
176 static int lqtL_gcfunc (lua_State *L) {
177 if (!lua_isuserdata(L, 1) || lua_islightuserdata(L, 1)) return 0;
178 lua_getfenv(L, 1); // (1)
179 if (!lua_istable(L, -1)) {
180 lua_pop(L, 1); // (0)
181 return 0;
183 lua_getfield(L, -1, "__gc"); // (2)
184 lua_remove(L, -2); // (1)
185 if (!lua_isfunction(L, -1)) {
186 lua_pop(L, 1); // (0)
187 return 0;
189 lua_pushvalue(L, 1); // (2)
190 if (lqtL_pcall(L, 1, 0, 0)) { // (-2;+1/+0)
191 // (1)
192 return lua_error(L);
194 return 0; // (+0)
197 static void dumpStack(const char *msg, lua_State* l) {
198 int i;
199 int top = lua_gettop(l);
201 printf("=== %s: %d {\n", msg, top);
203 for (i = 1; i <= top; i++)
204 { /* repeat for each level */
205 int t = lua_type(l, i);
206 switch (t) {
207 case LUA_TSTRING: /* strings */
208 printf("string: '%s'\n", lua_tostring(l, i));
209 break;
210 case LUA_TBOOLEAN: /* booleans */
211 printf("boolean %s\n",lua_toboolean(l, i) ? "true" : "false");
212 break;
213 case LUA_TNUMBER: /* numbers */
214 printf("number: %g\n", lua_tonumber(l, i));
215 break;
216 default: /* other values */
217 printf("%s: %p\n", lua_typename(l, t), lua_topointer(l, i));
218 break;
221 printf("} ===\n"); /* end the listing */
224 static int lqtL_newindexfunc (lua_State *L) {
225 if (!lua_isuserdata(L, 1) && lua_islightuserdata(L, 1)) return 0;
227 // first try a setter
228 lua_getmetatable(L, 1);
229 lua_pushliteral(L, "__set");
230 lua_rawget(L, -2);
231 if (lua_istable(L, -1)) {
232 lua_pushvalue(L, 2);
233 lua_gettable(L, -2);
234 if (lua_isfunction(L, -1)) {
235 lua_CFunction setter = lua_tocfunction(L, -1);
236 if (!setter) return luaL_error(L, "Invalid setter %s", lua_tostring(L, 2));
237 return setter(L);
241 // then try marking a method override
242 lua_settop(L, 4);
243 lua_pushliteral(L, "__override");
244 lua_rawget(L, -2);
245 if (lua_iscfunction(L, -1) && lua_isfunction(L, 3)) {
246 lua_CFunction addOverride = lua_tocfunction(L, -1);
247 addOverride(L);
250 // anyway, use the environment table for the userdata as per-object storage
251 lua_settop(L, 3); // (=3)
252 lua_getfenv(L, 1); // (+1)
253 if (!lua_istable(L, -1)) {
254 lua_pop(L, 1); // (+0)
255 return 0;
257 lua_remove(L, 1); // (+0)
258 lua_insert(L, 1); // (+0)
259 lua_rawset(L, 1); // (-2)
260 return 0;
263 int lqtL_getoverload (lua_State *L, int index, const char *name) {
264 luaL_checkstack(L, 2, "no space to grow");
265 if (lua_isuserdata(L, index) && !lua_islightuserdata(L, index)) {
266 lua_getfenv(L, index); // (1)
267 lua_getfield(L, -1, name); // (2)
268 lua_remove(L, -2); // (1)
269 } else {
270 lua_pushnil(L); // (1)
272 return 1;
275 static int lqtL_indexfunc (lua_State *L) {
276 int i = 1;
277 if (lua_isuserdata(L, 1) && !lua_islightuserdata(L, 1)) {
278 lua_getmetatable(L, 1);
279 lua_pushliteral(L, "__get");
280 lua_rawget(L, -2);
281 if (lua_istable(L, -1)) {
282 lua_pushvalue(L, 2);
283 lua_gettable(L, -2);
284 if (lua_isfunction(L, -1)) {
285 lua_CFunction getter = lua_tocfunction(L, -1);
286 if (!getter) return luaL_error(L, "Invalid getter %s", lua_tostring(L, 2));
287 return getter(L);
290 lua_settop(L, 2);
291 lua_getfenv(L, 1); // (1)
292 lua_pushvalue(L, 2); // (2)
293 lua_gettable(L, -2); // (2)
294 if (!lua_isnil(L, -1)) {
295 lua_remove(L, -2);
296 return 1;
298 lua_pop(L, 2); // (0)
300 lua_pushnil(L); // (+1)
301 while (!lua_isnone(L, lua_upvalueindex(i))) { // (+1)
302 lua_pop(L, 1); // (+0)
303 lua_pushvalue(L, 2); // (+1)
304 if (i==1) {
305 lua_rawget(L, lua_upvalueindex(i)); // (+1)
306 } else {
307 lua_gettable(L, lua_upvalueindex(i)); // (+1)
309 if (!lua_isnil(L, -1)) break;
310 i++;
312 return 1; // (+1)
315 static int lqtL_pushindexfunc (lua_State *L, const char *name, lqt_Base *bases) {
316 int upnum = 1;
317 luaL_newmetatable(L, name); // (1)
318 while (bases->basename!=NULL) {
319 luaL_newmetatable(L, bases->basename); // (upnum)
320 upnum++;
321 bases++;
323 lua_pushcclosure(L, lqtL_indexfunc, upnum); // (1)
324 return 1;
327 static int lqtL_local_ctor(lua_State*L) {
328 lua_getfield(L, 1, "new"); // (+2)
329 lua_replace(L, 1); // (+2)
330 lua_call(L, lua_gettop(L)-1, LUA_MULTRET);// (X)
331 lua_getfield(L, 1, "delete"); // (X+1)
332 lua_setfield(L, 1, "__gc"); // (X)
333 return lua_gettop(L);
336 int lqtL_createclass (lua_State *L, const char *name, luaL_Reg *mt,
337 luaL_Reg *getters, luaL_Reg *setters, lua_CFunction override,
338 lqt_Base *bases)
340 int len = 0;
341 char *new_name = NULL;
342 lqt_Base *bi = bases;
343 luaL_newmetatable(L, name); // (1)
344 luaL_register(L, NULL, mt); // (1)
345 // setup offsets
346 lua_pushstring(L, name); // (2) FIXME: remove
347 lua_pushinteger(L, 0); // (3) FIXME: remove
348 lua_settable(L, -3); // (1) FIXME: remove
349 while (bi->basename!=NULL) {
350 lua_pushstring(L, bi->basename); // (2) FIXME: remove
351 lua_pushinteger(L, bi->offset); // (3) FIXME: remove
352 lua_settable(L, -3); // (1) FIXME: remove
353 bi++;
356 if (getters) {
357 lua_newtable(L);
358 luaL_register(L, NULL, getters);
359 lua_setfield(L, -2, "__get");
361 if (setters) {
362 lua_newtable(L);
363 luaL_register(L, NULL, setters);
364 lua_setfield(L, -2, "__set");
366 if (override) {
367 lua_pushcfunction(L, override);
368 lua_setfield(L, -2, "__override");
371 // set metafunctions
372 lqtL_pushindexfunc(L, name, bases); // (2)
373 lua_setfield(L, -2, "__index"); // (1)
374 lua_pushcfunction(L, lqtL_newindexfunc); // (2)
375 lua_setfield(L, -2, "__newindex"); // (1)
376 lua_pushcfunction(L, lqtL_gcfunc); // (2)
377 lua_setfield(L, -2, "__gc"); // (1)
378 lua_pushstring(L, name);
379 lua_setfield(L, -2, "__type");
381 // set it as its own metatable
382 lua_pushvalue(L, -1); // (2)
383 lua_setmetatable(L, -2); // (1)
384 lua_pop(L, 1); // (0)
385 len = strlen(name);
386 new_name = (char*)malloc(len*sizeof(char));
387 strncpy(new_name, name, len);
388 new_name[len-1] = '\0';
389 luaL_register(L, new_name, mt); // (1)
390 free(new_name);
391 new_name = NULL;
392 lua_newtable(L); // (2)
393 lua_pushcfunction(L, lqtL_local_ctor);
394 lua_setfield(L, -2, "__call"); // (2)
395 lua_setmetatable(L, -2); // (1)
396 lua_pop(L, 1); // (0)
398 lua_pushlstring(L, name, strlen(name)-1); // (1)
399 lua_newtable(L); // (2)
400 luaL_newmetatable(L, name); // (3)
401 lua_setmetatable(L, -2); // (2)
402 // don't register again but use metatable
403 //luaL_register(L, NULL, mt); // (2)
404 lua_settable(L, LUA_GLOBALSINDEX); // (0)
406 return 0;
409 bool lqtL_isinteger (lua_State *L, int i) {
410 if (lua_type(L, i)==LUA_TNUMBER) {
411 return lua_tointeger(L, i)==lua_tonumber(L, i);
412 } else {
413 return false;
416 bool lqtL_isnumber (lua_State *L, int i) {
417 return lua_type(L, i)==LUA_TNUMBER;
419 bool lqtL_isstring (lua_State *L, int i) {
420 return lua_type(L, i)==LUA_TSTRING;
422 bool lqtL_isboolean (lua_State *L, int i) {
423 return lua_type(L, i)==LUA_TBOOLEAN;
425 bool lqtL_missarg (lua_State *L, int index, int n) {
426 bool ret = true;
427 int i = 0;
428 for (i=index;i<index+n;i++) {
429 if (!lua_isnoneornil(L, i)) {
430 ret = false;
431 break;
434 return ret;
437 static void CS(lua_State *L) {
438 std::cerr << "++++++++++" << std::endl;
439 for (int i=1;i<=lua_gettop(L);i++) {
440 std::cerr << luaL_typename(L, i) << " " << lua_touserdata(L, i) << std::endl;
442 std::cerr << "----------" << std::endl;
445 static void lqtL_ensurepointer (lua_State *L, const void *p) { // (+1)
446 lqtL_getpointertable(L); // (1)
447 lua_pushlightuserdata(L, const_cast<void*>(p)); // (2)
448 lua_gettable(L, -2); // (2)
449 if (lua_isnil(L, -1)) { // (2)
450 lua_pop(L, 1); // (1)
451 const void **pp = static_cast<const void**>(lua_newuserdata(L, sizeof(void*))); // (2)
452 *pp = p; // (2)
453 lua_newtable(L); // (3)
454 lua_setfenv(L, -2); // (2)
455 lua_pushlightuserdata(L, const_cast<void*>(p)); // (3)
456 lua_pushvalue(L, -2); // (4)
457 lua_settable(L, -4); // (2)
458 } else {
459 //const void **pp = static_cast<const void**>(lua_touserdata(L, -1)); // (2)
460 //if (pp!=NULL) *pp = p; // (2)
462 // (2)
463 lua_remove(L, -2); // (1)
466 void lqtL_register (lua_State *L, const void *p) { // (+0)
467 lqtL_ensurepointer(L, p);
468 lua_pop(L, 1);
471 void lqtL_unregister (lua_State *L, const void *p) {
472 lqtL_getpointertable(L); // (1)
473 lua_pushlightuserdata(L, const_cast<void*>(p)); // (2)
474 lua_gettable(L, -2); // (2)
475 if (lua_isuserdata(L, -1)) {
476 const void **pp = static_cast<const void**>(lua_touserdata(L, -1)); // (2)
477 *pp = 0;
479 lua_pop(L, 1); // (1)
480 lua_pushlightuserdata(L, const_cast<void*>(p)); // (2)
481 lua_pushnil(L); // (3)
482 lua_settable(L, -3); // (1)
483 lua_pop(L, 1); // (0)
486 void lqtL_pushudata (lua_State *L, const void *p, const char *name) {
487 bool already = false;
489 if (p == NULL) {
490 lua_pushnil(L); // (1)
491 return;
494 lqtL_ensurepointer(L, p); // (1)
495 if (lua_getmetatable(L, -1)) {
496 // (2)
497 lua_pop(L, 1); // (1)
498 lua_getfield(L, -1, name); // (2)
499 already = lua_toboolean(L, -1) == 1; // (2)
500 lua_pop(L, 1); // (1)
501 } else {
502 // (1)
504 if (!already) {
505 luaL_newmetatable(L, name); // (2)
506 lua_setmetatable(L, -2); // (1)
508 return;
511 void lqtL_passudata (lua_State *L, const void *p, const char *name) {
512 lqtL_pushudata(L, p, name);
513 // used only when passing temporaries - should be deleted afterwards
514 lua_getfield(L, -1, "delete");
515 lua_setfield(L, -2, "__gc");
516 return;
519 void lqtL_copyudata (lua_State *L, const void *p, const char *name) {
520 luaL_newmetatable(L, name);
521 lua_pushstring(L, "new");
522 lua_rawget(L, -2);
523 if (lua_isnil(L, -1)) {
524 std::cerr << "cannot copy " << name << std::endl;
525 lua_pop(L, 2);
526 lua_pushnil(L);
527 } else {
528 lua_remove(L, -2);
529 lqtL_pushudata(L, p, name);
530 if (lqtL_pcall(L, 1, 1, 0)) {
531 std::cerr << "error copying " << name << std::endl;
532 lua_pop(L, 1);
533 lua_pushnil(L);
535 // Enable autodeletion for copied stuff
536 lua_getfield(L, -1, "delete");
537 lua_setfield(L, -2, "__gc");
539 return;
542 void *lqtL_toudata (lua_State *L, int index, const char *name) {
543 void *ret = 0;
544 if (!lqtL_testudata(L, index, name)) return 0;
545 void **pp = static_cast<void**>(lua_touserdata(L, index));
546 ret = *pp;
547 lua_getfield(L, index, name);
548 ret = (void*)(lua_tointeger(L, -1) + (char*)ret);
549 lua_pop(L, 1);
550 return ret;
553 void lqtL_eraseudata (lua_State *L, int index, const char *name) {
554 void *ret = 0;
555 if (name!=NULL && !lqtL_testudata(L, index, name)) return;
556 void **pp = static_cast<void**>(lua_touserdata(L, index));
557 void *p = *pp;
558 *pp = 0;
559 lqtL_getpointertable(L); // (1)
560 lua_pushlightuserdata(L, p); // (2)
561 lua_pushnil(L); // (3)
562 lua_settable(L, -3); // (1)
563 lua_pop(L, 1);
564 return;
567 bool lqtL_testudata (lua_State *L, int index, const char *name) {
568 if (!lua_isuserdata(L, index) || lua_islightuserdata(L, index)) return false;
569 lua_getfield(L, index, name);
570 if (lua_isnil(L, -1)) {
571 lua_pop(L, 1);
572 return false;
574 lua_pop(L, 1);
575 return true;
578 const char * lqtL_pushtrace(lua_State *L) {
579 lua_getglobal(L, "debug");
580 lua_getfield(L, -1, "traceback");
581 lua_remove(L, -2);
582 lua_call(L, 0, 1);
583 return lua_tostring(L, -1);
586 void lqtL_pushenum (lua_State *L, int value, const char *name) {
587 lqtL_getenumtable(L);
588 lua_getfield(L, -1, name);
589 lua_remove(L, -2);
590 if (!lua_istable(L, -1)) {
591 lua_pop(L, 1);
592 lua_pushnil(L);
593 return;
595 lua_pushnumber(L, value);
596 lua_gettable(L, -2);
597 lua_remove(L, -2);
600 bool lqtL_isenum (lua_State *L, int index, const char *name) {
601 bool ret = false;
602 if (!lua_isstring(L, index)) return false;
603 lqtL_getenumtable(L);
604 lua_getfield(L, -1, name);
605 if (!lua_istable(L, -1)) {
606 lua_pop(L, 2);
607 return false;
609 lua_remove(L, -2);
610 lua_pushvalue(L, index);
611 lua_gettable(L, -2);
612 ret = !lua_isnil(L, -1);
613 lua_pop(L, 2);
614 return ret;
617 int lqtL_toenum (lua_State *L, int index, const char *name) {
618 int ret = -1;
619 // index = LQT_TOPOSITIVE(L, index);
620 lqtL_getenumtable(L); // (1)
621 lua_getfield(L, -1, name); // (2)
622 if (lua_isnil(L, -1)) {
623 lua_pop(L, 2); //(0)
624 return 0;
626 lua_pushvalue(L, index); // (3)
627 lua_gettable(L, -2); // (3)
628 if (lqtL_isinteger(L, -1)) {
629 ret = lua_tointeger(L, -1); // (3)
630 } else {
631 ret = lua_tointeger(L, index); // (3)
633 lua_pop(L, 3); // (0)
634 return ret;
637 int lqtL_getflags (lua_State *L, int index, const char *name) {
638 int ret = 0;
639 int eindex = 0;
640 int i = 1;
641 if (lqtL_isinteger(L, index)) return lua_tointeger(L, index);
642 if (!lua_istable(L, index)) return 0;
643 lqtL_getenumtable(L); // (1)
644 lua_getfield(L, -1, name); // (2)
645 if (!lua_istable(L, -1)) {
646 // (2)
647 lua_pop(L, 2);
648 return 0;
650 // (2)
651 lua_remove(L, -2); // (1)
652 eindex = lua_gettop(L);
653 for (i=1;;i++) { // (1)
654 lua_rawgeti(L, index, i); // (2)
655 if (lua_type(L, -1)!=LUA_TSTRING) {
656 lua_pop(L, 1); // (1)
657 break;
658 } else {
659 lua_gettable(L, eindex); // (2)
660 ret = ret | (int)lua_tointeger(L, -1);
661 lua_pop(L, 1); // (1)
664 // (1)
665 lua_pop(L, 1); // (0)
666 return ret;
669 //#include <QDebug>
671 void lqtL_pushflags (lua_State *L, int value, const char *name) {
672 int index = 1;
673 lua_newtable(L); // (1) return value
674 lqtL_getenumtable(L); // (2)
675 lua_getfield(L, -1, name); // (3)
676 lua_remove(L, -2); // (2) stack: ret, enumtable
677 lua_pushnil(L); // (3) first index
678 while (lua_next(L, -2) != 0) { // (4) stack: ret, enumtable, index, value
679 //if (lua_isnumber(L, -2)) {
680 //qDebug() << ((void*)lua_tointeger(L, -2))
681 //<< ((void*)value) << (void*)(lua_tointeger(L, -2)&value)
682 //<< ((lua_tointeger(L, -2)&value)==lua_tointeger(L, -2)) << lua_tostring(L, -1);
684 if (lua_isnumber(L, -2) &&
685 ((lua_tointeger(L, -2)&value)==lua_tointeger(L, -2))) {
686 // (4) if index is the value
687 lua_rawseti(L, -4, index); // (3) the string is put into the ret table
688 index = index + 1; // (3) the size of the ret table has increased
689 } else {
690 lua_pop(L, 1); // (3) pop the value
693 // (2) lua_next pops the vale and pushes nothing at the end of the iteration
694 // (2) stack: ret, enumtable
695 lua_pop(L, 1); // (1) stack: ret
696 return;
699 int lqtL_touintarray (lua_State *L) {
700 unsigned int *p = NULL;
701 size_t i = 0;
702 size_t n, nb;
703 n = lua_objlen(L, -1);
704 nb = (n + 1) * sizeof(unsigned int);
705 p = (unsigned int *)lua_newuserdata(L, nb);
706 for (i=1;i<=n;i++) {
707 lua_rawgeti(L, -2, i);
708 p[i-1] = lua_tointeger(L, -1);
709 lua_pop(L, 1);
711 lua_remove(L, -2);
712 p[n] = 0;
713 return 1;
716 int lqtL_pcall_debug_default (lua_State *L, int narg, int nres, int err) {
717 int status = 0;
718 std::cerr << "entering a pcall" << std::endl;
719 status = lua_pcall(L, narg, nres, err);
720 std::cerr << "pcall finished with status " << status << std::endl;
721 return status;
724 int lqtL_pcall_debug (lua_State *L, int narg, int nres, int err) {
725 int status = 0;
726 lua_getfield(L, LUA_REGISTRYINDEX, LQT_PCALL);
727 lqt_PCallPtr pcall = (lqt_PCallPtr)lua_touserdata(L, -1);
728 lua_pop(L, 1);
729 if (pcall) {
730 status = pcall(L, narg, nres, err);
731 } else {
732 status = lqtL_pcall_debug_default(L, narg, nres, err);
734 return status;
737 void lqtL_pushudatatype (lua_State *L, int index) {
738 if (!lua_isuserdata(L, index) || lua_islightuserdata(L, index)) {
739 lua_pushstring(L, luaL_typename(L, index));
740 } else {
741 lua_getfield(L, index, "__type");
742 if (lua_isnil(L, -1)) {
743 lua_pop(L, 1);
744 lua_pushstring(L, luaL_typename(L, index));
749 const char * lqtL_getarglist (lua_State *L) {
750 int args = lua_gettop(L);
751 lua_checkstack(L, args * 2);
752 lua_pushliteral(L, "");
753 for(int i = 1; i <= args; i++) {
754 lqtL_pushudatatype(L, i);
755 if (i<args)
756 lua_pushliteral(L, ", ");
758 lua_concat(L, 2*args - 1);
759 return lua_tostring(L, -1);
762 const char * lqtL_source(lua_State *L, int idx) {
763 static char buf[1024]; // TODO: try something better
764 lua_Debug ar = {0};
765 lua_pushvalue(L, idx);
766 lua_getinfo(L, ">S", &ar);
767 if (ar.source[0] != '@') {
768 sprintf(buf, "%s", ar.source);
769 } else {
770 sprintf(buf, "%s %s:%d", ar.name, ar.source, ar.linedefined);
772 return buf;
775 bool lqtL_is_super(lua_State *L, int idx) {
776 lua_getfield(L, LUA_GLOBALSINDEX, LQT_SUPER);
777 void *super = lua_touserdata(L, -1);
778 void *comp = lua_touserdata(L, idx);
779 bool ret = lua_equal(L, -1, idx);
780 lua_pop(L, 1);
781 return ret;
784 void lqtL_register_super(lua_State *L) {
785 lua_getfield(L, LUA_GLOBALSINDEX, LQT_SUPER);
786 if (lua_isnil(L, -1)) {
787 void *ud = lua_newuserdata(L, sizeof(int));
788 lua_setfield(L, LUA_GLOBALSINDEX, LQT_SUPER);
789 } else {
790 lua_pop(L, -1);
794 // returns true if the value at index `n` can be converted to `to_type`
795 bool lqtL_canconvert(lua_State *L, int n, const char *to_type) {
796 if (lqtL_testudata(L, n, to_type))
797 return true;
798 int oldtop = lua_gettop(L);
799 luaL_getmetatable(L, to_type);
800 if (lua_isnil(L, -1)) {
801 lua_settop(L, oldtop);
802 return false;
804 lua_getfield(L, -1, "__test");
805 if (lua_isnil(L, -1)) {
806 lua_settop(L, oldtop);
807 return false;
809 lqt_testfunc func = (lqt_testfunc) lua_touserdata(L, -1);
810 lua_settop(L, oldtop);
811 return func(L, n);
814 // converts the value at index `n` to `to_type` and returns a pointer to it
815 void *lqtL_convert(lua_State *L, int n, const char *to_type) {
816 if (lqtL_testudata(L, n, to_type))
817 return lqtL_toudata(L, n, to_type);
818 int oldtop = lua_gettop(L);
819 luaL_getmetatable(L, to_type);
820 if (lua_isnil(L, -1)) {
821 lua_settop(L, oldtop);
822 return NULL;
824 lua_getfield(L, -1, "__convert");
825 if (lua_isnil(L, -1)) {
826 lua_settop(L, oldtop);
827 return NULL;
829 lqt_convertfunc func = (lqt_convertfunc) lua_touserdata(L, -1);
830 lua_settop(L, oldtop);
831 return func(L, n);
834 void lqtL_selfcheck(lua_State *L, void *self, const char *name) {
835 if (NULL==self) {
836 lua_pushfstring(L, "Instance of %s has already been deleted in:\n", name);
837 lqtL_pushtrace(L);
838 lua_concat(L, 2);
839 lua_error(L);