add prototype for lqtL_getoverload
[lqt.git] / common / lqt_common.cpp
blob01e5edb5bdcfce2dc2930e6bf401266401999954
1 /*
2 * Copyright (c) 2007-2008 Mauro Iazzi
3 *
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);
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 static 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 int lqtL_newindexfunc (lua_State *L) {
198 lua_settop(L, 3); // (=3)
199 if (!lua_isuserdata(L, 1) && lua_islightuserdata(L, 1)) return 0;
200 lua_getfenv(L, 1); // (+1)
201 if (!lua_istable(L, -1)) {
202 lua_pop(L, 1); // (+0)
203 return 0;
205 lua_remove(L, 1); // (+0)
206 lua_insert(L, 1); // (+0)
207 lua_rawset(L, 1); // (-2)
208 return 0;
211 int lqtL_getoverload (lua_State *L, int index, const char *name) {
212 if (lua_isuserdata(L, index) && !lua_islightuserdata(L, index)) {
213 lua_getfenv(L, index); // (1)
214 lua_getfield(L, -1, name); // (2)
215 lua_remove(L, -2);
216 } else {
217 lua_pushnil(L); // (1)
219 return 1;
222 static int lqtL_indexfunc (lua_State *L) {
223 int i = 1;
224 if (lua_isuserdata(L, 1) && !lua_islightuserdata(L, 1)) {
225 lua_getfenv(L, 1); // (1)
226 lua_pushvalue(L, 2); // (2)
227 lua_gettable(L, -2); // (2)
228 if (!lua_isnil(L, -1)) {
229 lua_remove(L, -2);
230 return 1;
232 lua_pop(L, 2); // (0)
234 lua_pushnil(L); // (+1)
235 while (!lua_isnone(L, lua_upvalueindex(i))) { // (+1)
236 lua_pop(L, 1); // (+0)
237 lua_pushvalue(L, 2); // (+1)
238 if (i==1) {
239 lua_rawget(L, lua_upvalueindex(i)); // (+1)
240 } else {
241 lua_gettable(L, lua_upvalueindex(i)); // (+1)
243 if (!lua_isnil(L, -1)) break;
244 i++;
246 return 1; // (+1)
249 static int lqtL_pushindexfunc (lua_State *L, const char *name, lqt_Base *bases) {
250 int upnum = 1;
251 luaL_newmetatable(L, name); // (1)
252 while (bases->basename!=NULL) {
253 luaL_newmetatable(L, bases->basename); // (upnum)
254 upnum++;
255 bases++;
257 lua_pushcclosure(L, lqtL_indexfunc, upnum); // (1)
258 return 1;
261 static int lqtL_ctor_helper(lua_State*L) {
262 lua_getfield(L, 1, "new");
263 lua_replace(L, 1);
264 lua_call(L, lua_gettop(L)-1, LUA_MULTRET);
265 return lua_gettop(L);
268 static int lqtL_local_ctor(lua_State*L) {
269 lua_pushvalue(L, lua_upvalueindex(1)); // (+1)
270 lua_getfield(L, -1, "new"); // (+2)
271 lua_insert(L, 1); // (+2)
272 lua_pop(L, 1); // (+1)
273 lua_call(L, lua_gettop(L)-1, LUA_MULTRET); // (X)
274 lua_getfield(L, 1, "delete"); // (X+1)
275 lua_setfield(L, 1, "__gc"); // (X)
276 return lua_gettop(L);
279 int lqtL_createclass (lua_State *L, const char *name, luaL_Reg *mt, lqt_Base *bases) {
280 int len = 0;
281 char *new_name = NULL;
282 lqt_Base *bi = bases;
283 luaL_newmetatable(L, name); // (1)
284 luaL_register(L, NULL, mt); // (1)
285 // setup offsets
286 lua_pushstring(L, name); // (2) FIXME: remove
287 lua_pushinteger(L, 0); // (3) FIXME: remove
288 lua_settable(L, -3); // (1) FIXME: remove
289 while (bi->basename!=NULL) {
290 lua_pushstring(L, bi->basename); // (2) FIXME: remove
291 lua_pushinteger(L, bi->offset); // (3) FIXME: remove
292 lua_settable(L, -3); // (1) FIXME: remove
293 bi++;
295 // set metafunctions
296 lqtL_pushindexfunc(L, name, bases); // (2)
297 lua_setfield(L, -2, "__index"); // (1)
298 lua_pushcfunction(L, lqtL_newindexfunc); // (2)
299 lua_setfield(L, -2, "__newindex"); // (1)
300 lua_pushcfunction(L, lqtL_gcfunc); // (2)
301 lua_setfield(L, -2, "__gc"); // (1)
303 // set it as its own metatable
304 lua_pushvalue(L, -1); // (2)
305 lua_setmetatable(L, -2); // (1)
306 lua_pop(L, 1); // (0)
307 len = strlen(name);
308 new_name = (char*)malloc(len*sizeof(char));
309 strncpy(new_name, name, len);
310 new_name[len-1] = '\0';
311 luaL_register(L, new_name, mt); // (1)
312 free(new_name);
313 new_name = NULL;
314 lua_newtable(L); // (2)
315 lua_pushcfunction(L, lqtL_ctor_helper); // (3)
316 lua_setfield(L, -2, "__call"); // (2)
317 lua_setmetatable(L, -2); // (1)
318 lua_pushvalue(L, -1); // (2)
319 lua_pushcclosure(L, lqtL_local_ctor, 1); // (2)
320 lua_setfield(L, -2, "new_local");
321 lua_pop(L, 1); // (0)
323 lua_pushlstring(L, name, strlen(name)-1); // (1)
324 lua_newtable(L); // (2)
325 luaL_newmetatable(L, name); // (3)
326 lua_setmetatable(L, -2); // (2)
327 // don't register again but use metatable
328 //luaL_register(L, NULL, mt); // (2)
329 lua_settable(L, LUA_GLOBALSINDEX); // (0)
331 return 0;
334 bool lqtL_isinteger (lua_State *L, int i) {
335 if (lua_type(L, i)==LUA_TNUMBER)
336 return lua_tointeger(L, i)==lua_tonumber(L, i);
337 else
338 return false;
340 bool lqtL_isnumber (lua_State *L, int i) {
341 return lua_type(L, i)==LUA_TNUMBER;
343 bool lqtL_isstring (lua_State *L, int i) {
344 return lua_type(L, i)==LUA_TSTRING;
346 bool lqtL_isboolean (lua_State *L, int i) {
347 return lua_type(L, i)==LUA_TBOOLEAN;
349 bool lqtL_missarg (lua_State *L, int index, int n) {
350 bool ret = true;
351 int i = 0;
352 for (i=index;i<index+n;i++) {
353 if (!lua_isnoneornil(L, i)) {
354 ret = false;
355 break;
358 return ret;
361 static void CS(lua_State *L) {
362 std::cerr << "++++++++++" << std::endl;
363 for (int i=1;i<=lua_gettop(L);i++) {
364 std::cerr << luaL_typename(L, i) << " " << lua_touserdata(L, i) << std::endl;
366 std::cerr << "----------" << std::endl;
369 static void lqtL_ensurepointer (lua_State *L, const void *p) { // (+1)
370 lqtL_getpointertable(L); // (1)
371 lua_pushlightuserdata(L, const_cast<void*>(p)); // (2)
372 lua_gettable(L, -2); // (2)
373 if (lua_isnil(L, -1)) { // (2)
374 lua_pop(L, 1); // (1)
375 const void **pp = static_cast<const void**>(lua_newuserdata(L, sizeof(void*))); // (2)
376 *pp = p; // (2)
377 lua_newtable(L); // (3)
378 lua_setfenv(L, -2); // (2)
379 lua_pushlightuserdata(L, const_cast<void*>(p)); // (3)
380 lua_pushvalue(L, -2); // (4)
381 lua_settable(L, -4); // (2)
382 } else {
383 //const void **pp = static_cast<const void**>(lua_touserdata(L, -1)); // (2)
384 //if (pp!=NULL) *pp = p; // (2)
386 // (2)
387 lua_remove(L, -2); // (1)
390 void lqtL_register (lua_State *L, const void *p) { // (+0)
391 lqtL_ensurepointer(L, p);
392 lua_pop(L, 1);
395 void lqtL_unregister (lua_State *L, const void *p) {
396 lqtL_getpointertable(L); // (1)
397 lua_pushlightuserdata(L, const_cast<void*>(p)); // (2)
398 lua_gettable(L, -2); // (2)
399 if (lua_isuserdata(L, -1)) {
400 const void **pp = static_cast<const void**>(lua_touserdata(L, -1)); // (2)
401 *pp = 0;
403 lua_pop(L, 1); // (1)
404 lua_pushlightuserdata(L, const_cast<void*>(p)); // (2)
405 lua_pushnil(L); // (3)
406 lua_settable(L, -3); // (1)
407 lua_pop(L, 1); // (0)
410 void lqtL_pushudata (lua_State *L, const void *p, const char *name) {
411 bool already = false;
412 lqtL_ensurepointer(L, p); // (1)
413 if (lua_getmetatable(L, -1)) {
414 // (2)
415 lua_pop(L, 1); // (1)
416 lua_getfield(L, -1, name); // (2)
417 already = lua_toboolean(L, -1); // (2)
418 lua_pop(L, 1); // (1)
419 } else {
420 // (1)
422 if (!already) {
423 luaL_newmetatable(L, name); // (2)
424 lua_setmetatable(L, -2); // (1)
426 return;
429 void lqtL_passudata (lua_State *L, const void *p, const char *name) {
430 lqtL_pushudata(L, p, name);
431 // FIXME: these should be added, but it is not safe for now
432 lua_getfield(L, -1, "delete");
433 lua_setfield(L, -2, "__gc");
434 return;
437 void lqtL_copyudata (lua_State *L, const void *p, const char *name) {
438 luaL_newmetatable(L, name);
439 lua_pushstring(L, "new");
440 lua_rawget(L, -2);
441 if (lua_isnil(L, -1)) {
442 std::cerr << "cannot copy " << name << std::endl;
443 lua_pop(L, 2);
444 lua_pushnil(L);
445 } else {
446 lua_remove(L, -2);
447 lqtL_pushudata(L, p, name);
448 if (lqtL_pcall(L, 1, 1, 0)) {
449 std::cerr << "error copying " << name << std::endl;
450 lua_pop(L, 1);
451 lua_pushnil(L);
453 // Enable autodeletion for copied stuff
454 lua_getfield(L, -1, "delete");
455 lua_setfield(L, -2, "__gc");
457 return;
460 void *lqtL_toudata (lua_State *L, int index, const char *name) {
461 void *ret = 0;
462 if (!lqtL_testudata(L, index, name)) return 0;
463 void **pp = static_cast<void**>(lua_touserdata(L, index));
464 ret = *pp;
465 lua_getfield(L, index, name);
466 ret = (void*)(lua_tointeger(L, -1) + (char*)ret);
467 lua_pop(L, 1);
468 return ret;
471 void lqtL_eraseudata (lua_State *L, int index, const char *name) {
472 void *ret = 0;
473 if (name!=NULL && !lqtL_testudata(L, index, name)) return;
474 void **pp = static_cast<void**>(lua_touserdata(L, index));
475 void *p = *pp;
476 *pp = 0;
477 lqtL_getpointertable(L); // (1)
478 lua_pushlightuserdata(L, p); // (2)
479 lua_pushnil(L); // (3)
480 lua_settable(L, -3); // (1)
481 lua_pop(L, 1);
482 return;
485 bool lqtL_testudata (lua_State *L, int index, const char *name) {
486 if (!lua_isuserdata(L, index) || lua_islightuserdata(L, index)) return false;
487 lua_getfield(L, index, name);
488 if (lua_isnil(L, -1)) {
489 lua_pop(L, 1);
490 return false;
492 lua_pop(L, 1);
493 return true;
496 void lqtL_pushenum (lua_State *L, int value, const char *name) {
497 lqtL_getenumtable(L);
498 lua_getfield(L, -1, name);
499 lua_remove(L, -2);
500 if (!lua_istable(L, -1)) {
501 lua_pop(L, 1);
502 lua_pushnil(L);
503 return;
505 lua_pushnumber(L, value);
506 lua_gettable(L, -2);
507 lua_remove(L, -2);
510 bool lqtL_isenum (lua_State *L, int index, const char *name) {
511 bool ret = false;
512 if (!lua_isstring(L, index)) return false;
513 lqtL_getenumtable(L);
514 lua_getfield(L, -1, name);
515 if (!lua_istable(L, -1)) {
516 lua_pop(L, 2);
517 return false;
519 lua_remove(L, -2);
520 lua_pushvalue(L, index);
521 lua_gettable(L, -2);
522 ret = !lua_isnil(L, -1);
523 lua_pop(L, 2);
524 return ret;
527 int lqtL_toenum (lua_State *L, int index, const char *name) {
528 int ret = -1;
529 // index = LQT_TOPOSITIVE(L, index);
530 lqtL_getenumtable(L); // (1)
531 lua_getfield(L, -1, name); // (2)
532 if (lua_isnil(L, -1)) {
533 lua_pop(L, 2); //(0)
534 return 0;
536 lua_pushvalue(L, index); // (3)
537 lua_gettable(L, -2); // (3)
538 if (lqtL_isinteger(L, -1)) {
539 ret = lua_tointeger(L, -1); // (3)
540 } else {
541 ret = lua_tointeger(L, index); // (3)
543 lua_pop(L, 3); // (0)
544 return ret;
547 int lqtL_getflags (lua_State *L, int index, const char *name) {
548 int ret = 0;
549 int eindex = 0;
550 int i = 1;
551 if (lqtL_isinteger(L, index)) return lua_tointeger(L, index);
552 if (!lua_istable(L, index)) return 0;
553 lqtL_getenumtable(L); // (1)
554 lua_getfield(L, -1, name); // (2)
555 if (!lua_istable(L, -1)) {
556 // (2)
557 lua_pop(L, 2);
558 return 0;
560 // (2)
561 lua_remove(L, -2); // (1)
562 eindex = lua_gettop(L);
563 for (i=1;;i++) { // (1)
564 lua_rawgeti(L, index, i); // (2)
565 if (lua_type(L, -1)!=LUA_TSTRING) {
566 lua_pop(L, 1); // (1)
567 break;
568 } else {
569 lua_gettable(L, eindex); // (2)
570 ret = ret | (int)lua_tointeger(L, -1);
571 lua_pop(L, 1); // (1)
574 // (1)
575 lua_pop(L, 1); // (0)
576 return ret;
579 void lqtL_pushflags (lua_State *L, int index, const char *name) {
580 // TODO
581 lua_pushnil(L);
582 return;
585 int lqtL_touintarray (lua_State *L) {
586 uint *p = NULL;
587 size_t i = 0;
588 size_t n, nb;
589 n = lua_objlen(L, -1);
590 nb = (n + 1) * sizeof(uint);
591 p = (uint*)lua_newuserdata(L, nb);
592 for (i=1;i<=n;i++) {
593 lua_rawgeti(L, -2, i);
594 p[i-1] = lua_tointeger(L, -1);
595 lua_pop(L, 1);
597 lua_remove(L, -2);
598 p[n] = 0;
599 return 1;
602 int lqtL_pcall_debug_default (lua_State *L, int narg, int nres, int err) {
603 int status = 0;
604 std::cerr << "entering a pcall" << std::endl;
605 status = lua_pcall(L, narg, nres, err);
606 std::cerr << "pcall finished with status " << status << std::endl;
607 return status;
610 int lqtL_pcall_debug (lua_State *L, int narg, int nres, int err) {
611 int status = 0;
612 lua_getfield(L, LUA_REGISTRYINDEX, LQT_PCALL);
613 lqt_PCallPtr pcall = (lqt_PCallPtr)lua_touserdata(L, -1);
614 lua_pop(L, 1);
615 if (pcall) {
616 status = pcall(L, narg, nres, err);
617 } else {
618 status = lqtL_pcall_debug_default(L, narg, nres, err);
620 return status;