remove pointer from poiter table when it is erased
[lqt.git] / common / lqt_common.cpp
blob4201e50d234b2acfb31b39a3cf7049f1688672b1
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 <cstring>
30 #include <QDebug>
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, "kv"); // (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) {
71 void *ret = NULL;
72 lqtL_getreftable(L); // (1)
73 ret = lua_newuserdata(L, sz); // (2)
74 lua_rawseti(L, -2, 1+lua_objlen(L, -2));
75 return ret;
78 int * lqtL_tointref (lua_State *L, int index) {
79 int *ret = (int*)lqtL_getref(L, sizeof(int));
80 *ret = lua_tointeger(L, index);
81 return ret;
84 void lqtL_pusharguments (lua_State *L, char **argv) {
85 int i = 0;
86 lua_newtable(L);
87 for (i=0;*argv /* fix the maximum number? */;argv++,i++) {
88 lua_pushstring(L, *argv);
89 lua_rawseti(L, -2, i+1);
91 return;
94 char ** lqtL_toarguments (lua_State *L, int index) {
95 char ** ret = (char**)lqtL_getref(L, sizeof(char*)*(lua_objlen(L, index)+1));
96 const char *str = NULL;
97 size_t strlen = 0;
98 int i = 0;
99 for (i=0;;i++) {
100 lua_rawgeti(L, index, i+1);
101 if (!lua_isstring(L, -1)) {
102 str = NULL; strlen = 0;
103 ret[i] = NULL;
104 lua_pop(L, 1);
105 break;
106 } else {
107 str = lua_tolstring(L, -1, &strlen);
108 ret[i] = (char*)lqtL_getref(L, sizeof(char)*(strlen+1));
109 strncpy(ret[i], str, strlen+1);
110 lua_pop(L, 1);
113 return ret;
116 static int lqtL_createenum (lua_State *L, lqt_Enum e[], const char *n) {
117 lqtL_getenumtable(L); // (1)
118 lua_newtable(L); // (2)
119 lua_pushvalue(L, -1); // (3)
120 lua_setfield(L, -3, n); // (2)
121 while ( (e->name!=0) ) { // (2)
122 lua_pushstring(L, e->name); // (3)
123 lua_pushinteger(L, e->value); // (4)
124 lua_settable(L, -3); // (2)
125 lua_pushinteger(L, e->value); // (3)
126 lua_pushstring(L, e->name); // (4)
127 lua_settable(L, -3); // (2)
128 e++; // (2)
130 lua_pop(L, 2); // (0)
131 return 0;
134 int lqtL_createenumlist (lua_State *L, lqt_Enumlist list[]) {
135 while (list->enums!=0 && list->name!=0) {
136 lqtL_createenum(L, list->enums, list->name); // (0)
137 list++;
139 return 0;
142 static int lqtL_gcfunc (lua_State *L) {
143 if (!lua_isuserdata(L, 1) && lua_islightuserdata(L, 1)) return 0;
144 lua_getfenv(L, 1); // (1)
145 if (!lua_istable(L, -1)) {
146 lua_pop(L, 1); // (0)
147 return 0;
149 lua_getfield(L, -1, "__gc"); // (2)
150 lua_remove(L, -2); // (1)
151 if (!lua_isfunction(L, -1)) {
152 lua_pop(L, 1); // (0)
153 return 0;
155 lua_pushvalue(L, 1); // (2)
156 if (lua_pcall(L, 1, 0, 0)) { // (-2;+1/+0)
157 // (1)
158 return lua_error(L);
160 return 0; // (+0)
163 static int lqtL_newindexfunc (lua_State *L) {
164 lua_settop(L, 3); // (=3)
165 if (!lua_isuserdata(L, 1) && lua_islightuserdata(L, 1)) return 0;
166 lua_getfenv(L, 1); // (+1)
167 if (!lua_istable(L, -1)) {
168 lua_pop(L, 1); // (+0)
169 return 0;
171 lua_remove(L, 1); // (+0)
172 lua_insert(L, 1); // (+0)
173 lua_rawset(L, 1); // (-2)
174 return 0;
176 static int lqtL_indexfunc (lua_State *L) {
177 int i = 1;
178 if (lua_isuserdata(L, 1) && !lua_islightuserdata(L, 1)) {
179 lua_getfenv(L, 1); // (1)
180 lua_pushvalue(L, 2); // (2)
181 lua_gettable(L, -2); // (2)
182 if (!lua_isnil(L, -1)) {
183 lua_remove(L, -2);
184 return 1;
186 lua_pop(L, 2); // (0)
188 lua_pushnil(L); // (+1)
189 while (!lua_isnone(L, lua_upvalueindex(i))) { // (+1)
190 lua_pop(L, 1); // (+0)
191 lua_pushvalue(L, 2); // (+1)
192 if (i==1) {
193 lua_rawget(L, lua_upvalueindex(i)); // (+1)
194 } else {
195 lua_gettable(L, lua_upvalueindex(i)); // (+1)
197 if (!lua_isnil(L, -1)) break;
198 i++;
200 return 1; // (+1)
203 static int lqtL_pushindexfunc (lua_State *L, const char *name, lqt_Base *bases) {
204 int upnum = 1;
205 luaL_newmetatable(L, name); // (1)
206 while (bases->basename!=NULL) {
207 luaL_newmetatable(L, bases->basename); // (upnum)
208 upnum++;
209 bases++;
211 lua_pushcclosure(L, lqtL_indexfunc, upnum); // (1)
212 return 1;
215 static int lqtL_ctor_helper(lua_State*L) {
216 lua_getfield(L, 1, "new");
217 lua_replace(L, 1);
218 lua_call(L, lua_gettop(L)-1, LUA_MULTRET);
219 return lua_gettop(L);
222 static int lqtL_local_ctor(lua_State*L) {
223 lua_pushvalue(L, lua_upvalueindex(1)); // (+1)
224 lua_getfield(L, -1, "new"); // (+2)
225 lua_insert(L, 1); // (+2)
226 lua_pop(L, 1); // (+1)
227 lua_call(L, lua_gettop(L)-1, LUA_MULTRET); // (X)
228 lua_getfield(L, 1, "delete"); // (X+1)
229 lua_setfield(L, 1, "__gc"); // (X)
230 return lua_gettop(L);
233 int lqtL_createclass (lua_State *L, const char *name, luaL_Reg *mt, lqt_Base *bases) {
234 int len = 0;
235 char *new_name = NULL;
236 lqt_Base *bi = bases;
237 luaL_newmetatable(L, name); // (1)
238 luaL_register(L, NULL, mt); // (1)
239 // setup offsets
240 lua_pushstring(L, name); // (2) FIXME: remove
241 lua_pushinteger(L, 0); // (3) FIXME: remove
242 lua_settable(L, -3); // (1) FIXME: remove
243 while (bi->basename!=NULL) {
244 lua_pushstring(L, bi->basename); // (2) FIXME: remove
245 lua_pushinteger(L, bi->offset); // (3) FIXME: remove
246 lua_settable(L, -3); // (1) FIXME: remove
247 bi++;
249 // set metafunctions
250 lqtL_pushindexfunc(L, name, bases); // (2)
251 lua_setfield(L, -2, "__index"); // (1)
252 lua_pushcfunction(L, lqtL_newindexfunc); // (2)
253 lua_setfield(L, -2, "__newindex"); // (1)
254 lua_pushcfunction(L, lqtL_gcfunc); // (2)
255 lua_setfield(L, -2, "__gc"); // (1)
257 // set it as its own metatable
258 lua_pushvalue(L, -1); // (2)
259 lua_setmetatable(L, -2); // (1)
260 lua_pop(L, 1); // (0)
261 len = strlen(name);
262 new_name = (char*)malloc(len*sizeof(char));
263 strncpy(new_name, name, len);
264 new_name[len-1] = '\0';
265 luaL_register(L, new_name, mt); // (1)
266 free(new_name);
267 new_name = NULL;
268 lua_newtable(L); // (2)
269 lua_pushcfunction(L, lqtL_ctor_helper); // (3)
270 lua_setfield(L, -2, "__call"); // (2)
271 lua_setmetatable(L, -2); // (1)
272 lua_pushvalue(L, -1); // (2)
273 lua_pushcclosure(L, lqtL_local_ctor, 1); // (2)
274 lua_setfield(L, -2, "new_local");
275 lua_pop(L, 1); // (0)
277 lua_pushlstring(L, name, strlen(name)-1); // (1)
278 lua_newtable(L); // (2)
279 luaL_newmetatable(L, name); // (3)
280 lua_setmetatable(L, -2); // (2)
281 // don't register again but use metatable
282 //luaL_register(L, NULL, mt); // (2)
283 lua_settable(L, LUA_GLOBALSINDEX); // (0)
285 return 0;
288 int lqtL_createclasses (lua_State *L, lqt_Class *list) {
289 while (list->name!=0) { // (0)
290 luaL_newmetatable(L, list->name); // (1)
291 luaL_register(L, NULL, list->mt); // (1)
292 lua_pushstring(L, list->name); // (2)
293 lua_pushboolean(L, 1); // (3)
294 lua_settable(L, -3); // (1)
295 lqtL_pushindexfunc(L, list->name, list->bases); // (2)
296 lua_setfield(L, -2, "__index"); // (1)
297 lua_pushcfunction(L, lqtL_newindexfunc); // (2)
298 lua_setfield(L, -2, "__newindex"); // (1)
299 lua_pushcfunction(L, lqtL_gcfunc); // (2)
300 lua_setfield(L, -2, "__gc"); // (1)
301 lua_pushvalue(L, -1); // (2)
302 lua_setmetatable(L, -2); // (1)
303 lua_pop(L, 1); // (0)
304 lua_pushlstring(L, list->name, strlen(list->name)-1); // (1)
305 lua_newtable(L); // (2)
306 luaL_register(L, NULL, list->mt); // (2)
307 lua_settable(L, LUA_GLOBALSINDEX); // (0)
308 list++;
310 return 0;
313 bool lqtL_isinteger (lua_State *L, int i) {
314 if (lua_type(L, i)==LUA_TNUMBER)
315 return lua_tointeger(L, i)==lua_tonumber(L, i);
316 else
317 return false;
319 bool lqtL_isnumber (lua_State *L, int i) {
320 return lua_type(L, i)==LUA_TNUMBER;
322 bool lqtL_isstring (lua_State *L, int i) {
323 return lua_type(L, i)==LUA_TSTRING;
325 bool lqtL_isboolean (lua_State *L, int i) {
326 return lua_type(L, i)==LUA_TBOOLEAN;
328 bool lqtL_missarg (lua_State *L, int index, int n) {
329 bool ret = true;
330 int i = 0;
331 for (i=index;i<index+n;i++) {
332 if (!lua_isnoneornil(L, i)) {
333 ret = false;
334 break;
337 return ret;
340 static void CS(lua_State *L) {
341 qDebug() << "++++++++++";
342 for (int i=1;i<=lua_gettop(L);i++) {
343 qDebug() << luaL_typename(L, i) << lua_touserdata(L, i);
345 qDebug() << "----------";
348 static void lqtL_ensurepointer (lua_State *L, const void *p) { // (+1)
349 lqtL_getpointertable(L); // (1)
350 lua_pushlightuserdata(L, const_cast<void*>(p)); // (2)
351 lua_gettable(L, -2); // (2)
352 if (lua_isnil(L, -1)) { // (2)
353 lua_pop(L, 1); // (1)
354 const void **pp = static_cast<const void**>(lua_newuserdata(L, sizeof(void*))); // (2)
355 *pp = p; // (2)
356 lua_newtable(L); // (3)
357 lua_setfenv(L, -2); // (2)
358 lua_pushlightuserdata(L, const_cast<void*>(p)); // (3)
359 lua_pushvalue(L, -2); // (4)
360 lua_settable(L, -4); // (2)
361 } else {
362 //const void **pp = static_cast<const void**>(lua_touserdata(L, -1)); // (2)
363 //if (pp!=NULL) *pp = p; // (2)
365 // (2)
366 lua_remove(L, -2); // (1)
369 void lqtL_register (lua_State *L, const void *p) { // (+0)
370 lqtL_ensurepointer(L, p);
371 lua_pop(L, 1);
374 void lqtL_unregister (lua_State *L, const void *p) {
375 lqtL_getpointertable(L); // (1)
376 lua_pushlightuserdata(L, const_cast<void*>(p)); // (2)
377 lua_gettable(L, -2); // (2)
378 if (lua_isuserdata(L, -1)) {
379 const void **pp = static_cast<const void**>(lua_touserdata(L, -1)); // (2)
380 *pp = 0;
382 lua_pop(L, 1); // (1)
383 lua_pushlightuserdata(L, const_cast<void*>(p)); // (2)
384 lua_pushnil(L); // (3)
385 lua_settable(L, -3); // (1)
386 lua_pop(L, 1); // (0)
389 void lqtL_pushudata (lua_State *L, const void *p, const char *name) {
390 bool already = false;
391 lqtL_ensurepointer(L, p); // (1)
392 if (lua_getmetatable(L, -1)) {
393 // (2)
394 lua_pop(L, 1); // (1)
395 lua_getfield(L, -1, name); // (2)
396 already = lua_toboolean(L, -1); // (2)
397 lua_pop(L, 1); // (1)
398 } else {
399 // (1)
401 if (!already) {
402 luaL_newmetatable(L, name); // (2)
403 lua_setmetatable(L, -2); // (1)
405 return;
408 void lqtL_passudata (lua_State *L, const void *p, const char *name) {
409 lqtL_pushudata(L, p, name);
410 // FIXME: these should be added, but it is not safe for now
411 //lua_getfield(L, -1, "delete");
412 //lua_setfield(L, -2, "__gc");
413 return;
416 void lqtL_copyudata (lua_State *L, const void *p, const char *name) {
417 luaL_newmetatable(L, name);
418 lua_pushstring(L, "__copy");
419 lua_rawget(L, -2);
420 if (lua_isnil(L, -1)) {
421 qDebug() << "cannot copy" << name;
422 lua_pop(L, 2);
423 lua_pushnil(L);
424 } else {
425 lua_remove(L, -2);
426 lqtL_pushudata(L, p, name);
427 if (lua_pcall(L, 1, 1, 0)) {
428 qDebug() << "error copying" << name;
429 lua_pop(L, 1);
430 lua_pushnil(L);
433 return;
436 void *lqtL_toudata (lua_State *L, int index, const char *name) {
437 void *ret = 0;
438 if (!lqtL_testudata(L, index, name)) return 0;
439 void **pp = static_cast<void**>(lua_touserdata(L, index));
440 ret = *pp;
441 lua_getfield(L, index, name);
442 ret = (void*)(lua_tointeger(L, -1) + (char*)ret);
443 lua_pop(L, 1);
444 return ret;
447 void lqtL_eraseudata (lua_State *L, int index, const char *name) {
448 void *ret = 0;
449 if (name!=NULL && !lqtL_testudata(L, index, name)) return;
450 void **pp = static_cast<void**>(lua_touserdata(L, index));
451 void *p = *pp;
452 *pp = 0;
453 lqtL_getpointertable(L); // (1)
454 lua_pushlightuserdata(L, p); // (2)
455 lua_pushnil(L); // (3)
456 lua_settable(L, -3); // (1)
457 lua_pop(L, 1);
458 return;
461 bool lqtL_testudata (lua_State *L, int index, const char *name) {
462 if (!lua_isuserdata(L, index) || lua_islightuserdata(L, index)) return false;
463 lua_getfield(L, index, name);
464 if (lua_isnil(L, -1)) {
465 lua_pop(L, 1);
466 return false;
468 lua_pop(L, 1);
469 return true;
472 void lqtL_pushenum (lua_State *L, int value, const char *name) {
473 lqtL_getenumtable(L);
474 lua_getfield(L, -1, name);
475 lua_remove(L, -2);
476 if (!lua_istable(L, -1)) {
477 lua_pop(L, 1);
478 lua_pushnil(L);
479 return;
481 lua_pushnumber(L, value);
482 lua_gettable(L, -2);
483 lua_remove(L, -2);
486 bool lqtL_isenum (lua_State *L, int index, const char *name) {
487 bool ret = false;
488 if (!lua_isstring(L, index)) return false;
489 lqtL_getenumtable(L);
490 lua_getfield(L, -1, name);
491 if (!lua_istable(L, -1)) {
492 lua_pop(L, 2);
493 return false;
495 lua_remove(L, -2);
496 lua_pushvalue(L, index);
497 lua_gettable(L, -2);
498 ret = lua_isnumber(L, -1);
499 lua_pop(L, 2);
500 return ret;
503 int lqtL_toenum (lua_State *L, int index, const char *name) {
504 int ret = -1;
505 lqtL_getenumtable(L); // (1)
506 lua_getfield(L, -1, name); // (2)
507 if (lua_isnil(L, -1)) {
508 lua_pop(L, 2); //(0)
509 return 0;
511 lua_pushvalue(L, index); // (3)
512 lua_gettable(L, -2); // (3)
513 ret = lua_tointeger(L, -1); // (3)
514 lua_pop(L, 3); // (0)
515 return ret;
518 int lqtL_getflags (lua_State *L, int index, const char *name) {
519 int ret = 0;
520 int eindex = 0;
521 int i = 1;
522 if (!lua_istable(L, index)) return 0;
523 lqtL_getenumtable(L); // (1)
524 lua_getfield(L, -1, name); // (2)
525 if (!lua_istable(L, -1)) {
526 // (2)
527 lua_pop(L, 2);
528 return 0;
530 // (2)
531 lua_remove(L, -2); // (1)
532 eindex = lua_gettop(L);
533 for (i=1;;i++) { // (1)
534 lua_rawgeti(L, index, i); // (2)
535 if (lua_type(L, -1)!=LUA_TSTRING) {
536 lua_pop(L, 1); // (1)
537 break;
538 } else {
539 lua_gettable(L, eindex); // (2)
540 ret = ret | (int)lua_tointeger(L, -1);
541 lua_pop(L, 1); // (1)
544 // (1)
545 lua_pop(L, 1); // (0)
546 return ret;
549 void lqtL_pushflags (lua_State *L, int index, const char *name) {
550 // TODO
551 lua_pushnil(L);
552 return;
555 int lqtL_touintarray (lua_State *L) {
556 uint *p = NULL;
557 size_t i = 0;
558 size_t n, nb;
559 n = lua_objlen(L, -1);
560 nb = (n + 1) * sizeof(uint);
561 p = (uint*)lua_newuserdata(L, nb);
562 for (i=1;i<=n;i++) {
563 lua_rawgeti(L, -2, i);
564 p[i-1] = lua_tointeger(L, -1);
565 lua_pop(L, 1);
567 lua_remove(L, -2);
568 p[n] = 0;
569 return 1;