diff options
Diffstat (limited to 'ltests.c')
-rw-r--r-- | ltests.c | 1145 |
1 files changed, 0 insertions, 1145 deletions
diff --git a/ltests.c b/ltests.c deleted file mode 100644 index 7ae9ba6f..00000000 --- a/ltests.c +++ /dev/null | |||
@@ -1,1145 +0,0 @@ | |||
1 | /* | ||
2 | ** $Id: ltests.c,v 2.36 2006/01/10 13:13:06 roberto Exp roberto $ | ||
3 | ** Internal Module for Debugging of the Lua Implementation | ||
4 | ** See Copyright Notice in lua.h | ||
5 | */ | ||
6 | |||
7 | |||
8 | #include <ctype.h> | ||
9 | #include <limits.h> | ||
10 | #include <stdio.h> | ||
11 | #include <stdlib.h> | ||
12 | #include <string.h> | ||
13 | |||
14 | #define ltests_c | ||
15 | #define LUA_CORE | ||
16 | |||
17 | #include "lua.h" | ||
18 | |||
19 | #include "lapi.h" | ||
20 | #include "lauxlib.h" | ||
21 | #include "lcode.h" | ||
22 | #include "ldebug.h" | ||
23 | #include "ldo.h" | ||
24 | #include "lfunc.h" | ||
25 | #include "lmem.h" | ||
26 | #include "lopcodes.h" | ||
27 | #include "lstate.h" | ||
28 | #include "lstring.h" | ||
29 | #include "ltable.h" | ||
30 | #include "lualib.h" | ||
31 | |||
32 | |||
33 | |||
34 | /* | ||
35 | ** The whole module only makes sense with LUA_DEBUG on | ||
36 | */ | ||
37 | #if defined(LUA_DEBUG) | ||
38 | |||
39 | |||
40 | int Trick = 0; | ||
41 | |||
42 | |||
43 | static lua_State *lua_state = NULL; | ||
44 | |||
45 | int islocked = 0; | ||
46 | |||
47 | |||
48 | #define obj_at(L,k) (L->ci->base+(k) - 1) | ||
49 | |||
50 | |||
51 | static void setnameval (lua_State *L, const char *name, int val) { | ||
52 | lua_pushstring(L, name); | ||
53 | lua_pushinteger(L, val); | ||
54 | lua_settable(L, -3); | ||
55 | } | ||
56 | |||
57 | |||
58 | /* | ||
59 | ** {====================================================================== | ||
60 | ** Controlled version for realloc. | ||
61 | ** ======================================================================= | ||
62 | */ | ||
63 | |||
64 | #define MARK 0x55 /* 01010101 (a nice pattern) */ | ||
65 | |||
66 | #ifndef EXTERNMEMCHECK | ||
67 | /* full memory check */ | ||
68 | #define HEADER (sizeof(L_Umaxalign)) /* ensures maximum alignment for HEADER */ | ||
69 | #define MARKSIZE 16 /* size of marks after each block */ | ||
70 | #define blockhead(b) (cast(char *, b) - HEADER) | ||
71 | #define setsize(newblock, size) (*cast(size_t *, newblock) = size) | ||
72 | #define checkblocksize(b, size) (size == (*cast(size_t *, blockhead(b)))) | ||
73 | #define fillmem(mem,size) memset(mem, -MARK, size) | ||
74 | #else | ||
75 | /* external memory check: don't do it twice */ | ||
76 | #define HEADER 0 | ||
77 | #define MARKSIZE 0 | ||
78 | #define blockhead(b) (b) | ||
79 | #define setsize(newblock, size) /* empty */ | ||
80 | #define checkblocksize(b,size) (1) | ||
81 | #define fillmem(mem,size) /* empty */ | ||
82 | #endif | ||
83 | |||
84 | |||
85 | Memcontrol memcontrol = {0L, 0L, 0L, 0L}; | ||
86 | |||
87 | |||
88 | static void *checkblock (void *block, size_t size) { | ||
89 | void *b = blockhead(block); | ||
90 | int i; | ||
91 | for (i=0;i<MARKSIZE;i++) | ||
92 | lua_assert(*(cast(char *, b)+HEADER+size+i) == MARK+i); /* corrupted block? */ | ||
93 | return b; | ||
94 | } | ||
95 | |||
96 | |||
97 | static void freeblock (Memcontrol *mc, void *block, size_t size) { | ||
98 | if (block) { | ||
99 | lua_assert(checkblocksize(block, size)); | ||
100 | block = checkblock(block, size); | ||
101 | fillmem(block, size+HEADER+MARKSIZE); /* erase block */ | ||
102 | free(block); /* free original block */ | ||
103 | mc->numblocks--; | ||
104 | mc->total -= size; | ||
105 | } | ||
106 | } | ||
107 | |||
108 | |||
109 | void *debug_realloc (void *ud, void *block, size_t oldsize, size_t size) { | ||
110 | Memcontrol *mc = cast(Memcontrol *, ud); | ||
111 | lua_assert(oldsize == 0 || checkblocksize(block, oldsize)); | ||
112 | if (mc->memlimit == 0) { /* first time? */ | ||
113 | char *limit = getenv("MEMLIMIT"); /* initialize memory limit */ | ||
114 | mc->memlimit = limit ? strtoul(limit, NULL, 10) : ULONG_MAX; | ||
115 | } | ||
116 | if (size == 0) { | ||
117 | freeblock(mc, block, oldsize); | ||
118 | return NULL; | ||
119 | } | ||
120 | else if (size > oldsize && mc->total+size-oldsize > mc->memlimit) | ||
121 | return NULL; /* to test memory allocation errors */ | ||
122 | else { | ||
123 | void *newblock; | ||
124 | int i; | ||
125 | size_t realsize = HEADER+size+MARKSIZE; | ||
126 | size_t commonsize = (oldsize < size) ? oldsize : size; | ||
127 | if (realsize < size) return NULL; /* overflow! */ | ||
128 | newblock = malloc(realsize); /* alloc a new block */ | ||
129 | if (newblock == NULL) return NULL; | ||
130 | if (block) { | ||
131 | memcpy(cast(char *, newblock)+HEADER, block, commonsize); | ||
132 | freeblock(mc, block, oldsize); /* erase (and check) old copy */ | ||
133 | } | ||
134 | /* initialize new part of the block with something `weird' */ | ||
135 | fillmem(cast(char *, newblock)+HEADER+commonsize, size-commonsize); | ||
136 | mc->total += size; | ||
137 | if (mc->total > mc->maxmem) | ||
138 | mc->maxmem = mc->total; | ||
139 | mc->numblocks++; | ||
140 | setsize(newblock, size); | ||
141 | for (i=0;i<MARKSIZE;i++) | ||
142 | *(cast(char *, newblock)+HEADER+size+i) = cast(char, MARK+i); | ||
143 | return cast(char *, newblock)+HEADER; | ||
144 | } | ||
145 | } | ||
146 | |||
147 | |||
148 | /* }====================================================================== */ | ||
149 | |||
150 | |||
151 | |||
152 | /* | ||
153 | ** {====================================================== | ||
154 | ** Functions to check memory consistency | ||
155 | ** ======================================================= | ||
156 | */ | ||
157 | |||
158 | static int testobjref1 (global_State *g, GCObject *f, GCObject *t) { | ||
159 | if (isdead(g,t)) return 0; | ||
160 | if (g->gcstate == GCSpropagate) | ||
161 | return !isblack(f) || !iswhite(t); | ||
162 | else if (g->gcstate == GCSfinalize) | ||
163 | return iswhite(f); | ||
164 | else | ||
165 | return 1; | ||
166 | } | ||
167 | |||
168 | |||
169 | static void printobj (global_State *g, GCObject *o) { | ||
170 | int i = 0; | ||
171 | GCObject *p; | ||
172 | for (p = g->rootgc; p != o && p != NULL; p = p->gch.next) i++; | ||
173 | if (p == NULL) i = -1; | ||
174 | printf("%d:%s(%p)-%c(%02X)", i, luaT_typenames[o->gch.tt], (void *)o, | ||
175 | isdead(g,o)?'d':isblack(o)?'b':iswhite(o)?'w':'g', o->gch.marked); | ||
176 | } | ||
177 | |||
178 | |||
179 | static int testobjref (global_State *g, GCObject *f, GCObject *t) { | ||
180 | int r = testobjref1(g,f,t); | ||
181 | if (!r) { | ||
182 | printf("%d(%02X) - ", g->gcstate, g->currentwhite); | ||
183 | printobj(g, f); | ||
184 | printf("\t-> "); | ||
185 | printobj(g, t); | ||
186 | printf("\n"); | ||
187 | } | ||
188 | return r; | ||
189 | } | ||
190 | |||
191 | #define checkobjref(g,f,t) lua_assert(testobjref(g,f,obj2gco(t))) | ||
192 | |||
193 | #define checkvalref(g,f,t) lua_assert(!iscollectable(t) || \ | ||
194 | ((ttype(t) == (t)->value.gc->gch.tt) && testobjref(g,f,gcvalue(t)))) | ||
195 | |||
196 | |||
197 | |||
198 | static void checktable (global_State *g, Table *h) { | ||
199 | int i; | ||
200 | int weakkey = 0; | ||
201 | int weakvalue = 0; | ||
202 | const TValue *mode; | ||
203 | GCObject *hgc = obj2gco(h); | ||
204 | if (h->metatable) | ||
205 | checkobjref(g, hgc, h->metatable); | ||
206 | mode = gfasttm(g, h->metatable, TM_MODE); | ||
207 | if (mode && ttisstring(mode)) { /* is there a weak mode? */ | ||
208 | weakkey = (strchr(svalue(mode), 'k') != NULL); | ||
209 | weakvalue = (strchr(svalue(mode), 'v') != NULL); | ||
210 | } | ||
211 | i = h->sizearray; | ||
212 | while (i--) | ||
213 | checkvalref(g, hgc, &h->array[i]); | ||
214 | i = sizenode(h); | ||
215 | while (i--) { | ||
216 | Node *n = gnode(h, i); | ||
217 | if (!ttisnil(gval(n))) { | ||
218 | lua_assert(!ttisnil(gkey(n))); | ||
219 | checkvalref(g, hgc, gkey(n)); | ||
220 | checkvalref(g, hgc, gval(n)); | ||
221 | } | ||
222 | } | ||
223 | } | ||
224 | |||
225 | |||
226 | /* | ||
227 | ** All marks are conditional because a GC may happen while the | ||
228 | ** prototype is still being created | ||
229 | */ | ||
230 | static void checkproto (global_State *g, Proto *f) { | ||
231 | int i; | ||
232 | GCObject *fgc = obj2gco(f); | ||
233 | if (f->source) checkobjref(g, fgc, f->source); | ||
234 | for (i=0; i<f->sizek; i++) { | ||
235 | if (ttisstring(f->k+i)) | ||
236 | checkobjref(g, fgc, rawtsvalue(f->k+i)); | ||
237 | } | ||
238 | for (i=0; i<f->sizeupvalues; i++) { | ||
239 | if (f->upvalues[i]) | ||
240 | checkobjref(g, fgc, f->upvalues[i]); | ||
241 | } | ||
242 | for (i=0; i<f->sizep; i++) { | ||
243 | if (f->p[i]) | ||
244 | checkobjref(g, fgc, f->p[i]); | ||
245 | } | ||
246 | for (i=0; i<f->sizelocvars; i++) { | ||
247 | if (f->locvars[i].varname) | ||
248 | checkobjref(g, fgc, f->locvars[i].varname); | ||
249 | } | ||
250 | } | ||
251 | |||
252 | |||
253 | |||
254 | static void checkclosure (global_State *g, Closure *cl) { | ||
255 | GCObject *clgc = obj2gco(cl); | ||
256 | checkobjref(g, clgc, cl->l.env); | ||
257 | if (cl->c.isC) { | ||
258 | int i; | ||
259 | for (i=0; i<cl->c.nupvalues; i++) | ||
260 | checkvalref(g, clgc, &cl->c.upvalue[i]); | ||
261 | } | ||
262 | else { | ||
263 | int i; | ||
264 | lua_assert(cl->l.nupvalues == cl->l.p->nups); | ||
265 | checkobjref(g, clgc, cl->l.p); | ||
266 | for (i=0; i<cl->l.nupvalues; i++) { | ||
267 | if (cl->l.upvals[i]) { | ||
268 | lua_assert(cl->l.upvals[i]->tt == LUA_TUPVAL); | ||
269 | checkobjref(g, clgc, cl->l.upvals[i]); | ||
270 | } | ||
271 | } | ||
272 | } | ||
273 | } | ||
274 | |||
275 | |||
276 | static void checkstack (global_State *g, lua_State *L1) { | ||
277 | StkId o; | ||
278 | CallInfo *ci; | ||
279 | GCObject *uvo; | ||
280 | lua_assert(!isdead(g, obj2gco(L1))); | ||
281 | for (uvo = L1->openupval; uvo != NULL; uvo = uvo->gch.next) { | ||
282 | UpVal *uv = gco2uv(uvo); | ||
283 | lua_assert(uv->v != &uv->u.value); /* must be open */ | ||
284 | lua_assert(!isblack(uvo)); /* open upvalues cannot be black */ | ||
285 | } | ||
286 | checkliveness(g, gt(L1)); | ||
287 | if (L1->base_ci) { | ||
288 | for (ci = L1->base_ci; ci <= L1->ci; ci++) { | ||
289 | lua_assert(ci->top <= L1->stack_last); | ||
290 | lua_assert(lua_checkpc(L1, ci)); | ||
291 | } | ||
292 | } | ||
293 | else lua_assert(L1->size_ci == 0); | ||
294 | if (L1->stack) { | ||
295 | for (o = L1->stack; o < L1->top; o++) | ||
296 | checkliveness(g, o); | ||
297 | } | ||
298 | else lua_assert(L1->stacksize == 0); | ||
299 | } | ||
300 | |||
301 | |||
302 | static void checkobject (global_State *g, GCObject *o) { | ||
303 | if (isdead(g, o)) | ||
304 | /* lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep);*/ | ||
305 | { if (!(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep)) | ||
306 | printf(">>> %d %s %02x\n", g->gcstate, luaT_typenames[o->gch.tt], o->gch.marked); | ||
307 | } | ||
308 | else { | ||
309 | if (g->gcstate == GCSfinalize) | ||
310 | lua_assert(iswhite(o)); | ||
311 | switch (o->gch.tt) { | ||
312 | case LUA_TUPVAL: { | ||
313 | UpVal *uv = gco2uv(o); | ||
314 | lua_assert(uv->v == &uv->u.value); /* must be closed */ | ||
315 | lua_assert(!isgray(o)); /* closed upvalues are never gray */ | ||
316 | checkvalref(g, o, uv->v); | ||
317 | break; | ||
318 | } | ||
319 | case LUA_TUSERDATA: { | ||
320 | Table *mt = gco2u(o)->metatable; | ||
321 | if (mt) checkobjref(g, o, mt); | ||
322 | break; | ||
323 | } | ||
324 | case LUA_TTABLE: { | ||
325 | checktable(g, gco2h(o)); | ||
326 | break; | ||
327 | } | ||
328 | case LUA_TTHREAD: { | ||
329 | checkstack(g, gco2th(o)); | ||
330 | break; | ||
331 | } | ||
332 | case LUA_TFUNCTION: { | ||
333 | checkclosure(g, gco2cl(o)); | ||
334 | break; | ||
335 | } | ||
336 | case LUA_TPROTO: { | ||
337 | checkproto(g, gco2p(o)); | ||
338 | break; | ||
339 | } | ||
340 | default: lua_assert(0); | ||
341 | } | ||
342 | } | ||
343 | } | ||
344 | |||
345 | |||
346 | int lua_checkpc (lua_State *L, pCallInfo ci) { | ||
347 | if (ci == L->base_ci || !f_isLua(ci)) return 1; | ||
348 | else { | ||
349 | Proto *p = ci_func(ci)->l.p; | ||
350 | if (ci < L->ci) | ||
351 | return p->code <= ci->savedpc && ci->savedpc <= p->code + p->sizecode; | ||
352 | else | ||
353 | return p->code <= L->savedpc && L->savedpc <= p->code + p->sizecode; | ||
354 | } | ||
355 | } | ||
356 | |||
357 | |||
358 | int lua_checkmemory (lua_State *L) { | ||
359 | global_State *g = G(L); | ||
360 | GCObject *o; | ||
361 | UpVal *uv; | ||
362 | checkstack(g, g->mainthread); | ||
363 | for (o = g->rootgc; o != obj2gco(g->mainthread); o = o->gch.next) | ||
364 | checkobject(g, o); | ||
365 | for (o = o->gch.next; o != NULL; o = o->gch.next) { | ||
366 | lua_assert(o->gch.tt == LUA_TUSERDATA); | ||
367 | checkobject(g, o); | ||
368 | } | ||
369 | for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { | ||
370 | lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); | ||
371 | lua_assert(uv->v != &uv->u.value); /* must be open */ | ||
372 | lua_assert(!isblack(obj2gco(uv))); /* open upvalues are never black */ | ||
373 | checkvalref(g, obj2gco(uv), uv->v); | ||
374 | } | ||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | /* }====================================================== */ | ||
379 | |||
380 | |||
381 | |||
382 | /* | ||
383 | ** {====================================================== | ||
384 | ** Disassembler | ||
385 | ** ======================================================= | ||
386 | */ | ||
387 | |||
388 | |||
389 | static char *buildop (Proto *p, int pc, char *buff) { | ||
390 | Instruction i = p->code[pc]; | ||
391 | OpCode o = GET_OPCODE(i); | ||
392 | const char *name = luaP_opnames[o]; | ||
393 | int line = getline(p, pc); | ||
394 | sprintf(buff, "(%4d) %4d - ", line, pc); | ||
395 | switch (getOpMode(o)) { | ||
396 | case iABC: | ||
397 | sprintf(buff+strlen(buff), "%-12s%4d %4d %4d", name, | ||
398 | GETARG_A(i), GETARG_B(i), GETARG_C(i)); | ||
399 | break; | ||
400 | case iABx: | ||
401 | sprintf(buff+strlen(buff), "%-12s%4d %4d", name, GETARG_A(i), GETARG_Bx(i)); | ||
402 | break; | ||
403 | case iAsBx: | ||
404 | sprintf(buff+strlen(buff), "%-12s%4d %4d", name, GETARG_A(i), GETARG_sBx(i)); | ||
405 | break; | ||
406 | } | ||
407 | return buff; | ||
408 | } | ||
409 | |||
410 | |||
411 | #if 0 | ||
412 | void luaI_printcode (Proto *pt, int size) { | ||
413 | int pc; | ||
414 | for (pc=0; pc<size; pc++) { | ||
415 | char buff[100]; | ||
416 | printf("%s\n", buildop(pt, pc, buff)); | ||
417 | } | ||
418 | printf("-------\n"); | ||
419 | } | ||
420 | #endif | ||
421 | |||
422 | |||
423 | static int listcode (lua_State *L) { | ||
424 | int pc; | ||
425 | Proto *p; | ||
426 | luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), | ||
427 | 1, "Lua function expected"); | ||
428 | p = clvalue(obj_at(L, 1))->l.p; | ||
429 | lua_newtable(L); | ||
430 | setnameval(L, "maxstack", p->maxstacksize); | ||
431 | setnameval(L, "numparams", p->numparams); | ||
432 | for (pc=0; pc<p->sizecode; pc++) { | ||
433 | char buff[100]; | ||
434 | lua_pushinteger(L, pc+1); | ||
435 | lua_pushstring(L, buildop(p, pc, buff)); | ||
436 | lua_settable(L, -3); | ||
437 | } | ||
438 | return 1; | ||
439 | } | ||
440 | |||
441 | |||
442 | static int listk (lua_State *L) { | ||
443 | Proto *p; | ||
444 | int i; | ||
445 | luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), | ||
446 | 1, "Lua function expected"); | ||
447 | p = clvalue(obj_at(L, 1))->l.p; | ||
448 | lua_createtable(L, p->sizek, 0); | ||
449 | for (i=0; i<p->sizek; i++) { | ||
450 | luaA_pushobject(L, p->k+i); | ||
451 | lua_rawseti(L, -2, i+1); | ||
452 | } | ||
453 | return 1; | ||
454 | } | ||
455 | |||
456 | |||
457 | static int listlocals (lua_State *L) { | ||
458 | Proto *p; | ||
459 | int pc = luaL_checkint(L, 2) - 1; | ||
460 | int i = 0; | ||
461 | const char *name; | ||
462 | luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), | ||
463 | 1, "Lua function expected"); | ||
464 | p = clvalue(obj_at(L, 1))->l.p; | ||
465 | while ((name = luaF_getlocalname(p, ++i, pc)) != NULL) | ||
466 | lua_pushstring(L, name); | ||
467 | return i-1; | ||
468 | } | ||
469 | |||
470 | /* }====================================================== */ | ||
471 | |||
472 | |||
473 | |||
474 | |||
475 | static int get_limits (lua_State *L) { | ||
476 | lua_createtable(L, 0, 5); | ||
477 | setnameval(L, "BITS_INT", LUAI_BITSINT); | ||
478 | setnameval(L, "LFPF", LFIELDS_PER_FLUSH); | ||
479 | setnameval(L, "MAXVARS", LUAI_MAXVARS); | ||
480 | setnameval(L, "MAXSTACK", MAXSTACK); | ||
481 | setnameval(L, "MAXUPVALUES", LUAI_MAXUPVALUES); | ||
482 | setnameval(L, "NUM_OPCODES", NUM_OPCODES); | ||
483 | return 1; | ||
484 | } | ||
485 | |||
486 | |||
487 | static int mem_query (lua_State *L) { | ||
488 | if (lua_isnone(L, 1)) { | ||
489 | lua_pushinteger(L, memcontrol.total); | ||
490 | lua_pushinteger(L, memcontrol.numblocks); | ||
491 | lua_pushinteger(L, memcontrol.maxmem); | ||
492 | return 3; | ||
493 | } | ||
494 | else { | ||
495 | memcontrol.memlimit = luaL_checkint(L, 1); | ||
496 | return 0; | ||
497 | } | ||
498 | } | ||
499 | |||
500 | |||
501 | static int settrick (lua_State *L) { | ||
502 | Trick = lua_tointeger(L, 1); | ||
503 | return 0; | ||
504 | } | ||
505 | |||
506 | |||
507 | /*static int set_gcstate (lua_State *L) { | ||
508 | static const char *const state[] = {"propagate", "sweep", "finalize"}; | ||
509 | return 0; | ||
510 | }*/ | ||
511 | |||
512 | |||
513 | static int get_gccolor (lua_State *L) { | ||
514 | TValue *o; | ||
515 | luaL_checkany(L, 1); | ||
516 | o = obj_at(L, 1); | ||
517 | if (!iscollectable(o)) | ||
518 | lua_pushstring(L, "no collectable"); | ||
519 | else | ||
520 | lua_pushstring(L, iswhite(gcvalue(o)) ? "white" : | ||
521 | isblack(gcvalue(o)) ? "black" : "grey"); | ||
522 | return 1; | ||
523 | } | ||
524 | |||
525 | |||
526 | static int gcstate (lua_State *L) { | ||
527 | switch(G(L)->gcstate) { | ||
528 | case GCSpropagate: lua_pushstring(L, "propagate"); break; | ||
529 | case GCSsweepstring: lua_pushstring(L, "sweep strings"); break; | ||
530 | case GCSsweep: lua_pushstring(L, "sweep"); break; | ||
531 | case GCSfinalize: lua_pushstring(L, "finalize"); break; | ||
532 | } | ||
533 | return 1; | ||
534 | } | ||
535 | |||
536 | |||
537 | static int hash_query (lua_State *L) { | ||
538 | if (lua_isnone(L, 2)) { | ||
539 | luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "string expected"); | ||
540 | lua_pushinteger(L, tsvalue(obj_at(L, 1))->hash); | ||
541 | } | ||
542 | else { | ||
543 | TValue *o = obj_at(L, 1); | ||
544 | Table *t; | ||
545 | luaL_checktype(L, 2, LUA_TTABLE); | ||
546 | t = hvalue(obj_at(L, 2)); | ||
547 | lua_pushinteger(L, luaH_mainposition(t, o) - t->node); | ||
548 | } | ||
549 | return 1; | ||
550 | } | ||
551 | |||
552 | |||
553 | static int stacklevel (lua_State *L) { | ||
554 | unsigned long a = 0; | ||
555 | lua_pushinteger(L, (L->top - L->stack)); | ||
556 | lua_pushinteger(L, (L->stack_last - L->stack)); | ||
557 | lua_pushinteger(L, (L->ci - L->base_ci)); | ||
558 | lua_pushinteger(L, (L->end_ci - L->base_ci)); | ||
559 | lua_pushinteger(L, (unsigned long)&a); | ||
560 | return 5; | ||
561 | } | ||
562 | |||
563 | |||
564 | static int table_query (lua_State *L) { | ||
565 | const Table *t; | ||
566 | int i = luaL_optint(L, 2, -1); | ||
567 | luaL_checktype(L, 1, LUA_TTABLE); | ||
568 | t = hvalue(obj_at(L, 1)); | ||
569 | if (i == -1) { | ||
570 | lua_pushinteger(L, t->sizearray); | ||
571 | lua_pushinteger(L, luaH_isdummy(t->node) ? 0 : sizenode(t)); | ||
572 | lua_pushinteger(L, t->lastfree - t->node); | ||
573 | } | ||
574 | else if (i < t->sizearray) { | ||
575 | lua_pushinteger(L, i); | ||
576 | luaA_pushobject(L, &t->array[i]); | ||
577 | lua_pushnil(L); | ||
578 | } | ||
579 | else if ((i -= t->sizearray) < sizenode(t)) { | ||
580 | if (!ttisnil(gval(gnode(t, i))) || | ||
581 | ttisnil(gkey(gnode(t, i))) || | ||
582 | ttisnumber(gkey(gnode(t, i)))) { | ||
583 | luaA_pushobject(L, key2tval(gnode(t, i))); | ||
584 | } | ||
585 | else | ||
586 | lua_pushliteral(L, "<undef>"); | ||
587 | luaA_pushobject(L, gval(gnode(t, i))); | ||
588 | if (gnext(&t->node[i])) | ||
589 | lua_pushinteger(L, gnext(&t->node[i]) - t->node); | ||
590 | else | ||
591 | lua_pushnil(L); | ||
592 | } | ||
593 | return 3; | ||
594 | } | ||
595 | |||
596 | |||
597 | static int string_query (lua_State *L) { | ||
598 | stringtable *tb = &G(L)->strt; | ||
599 | int s = luaL_optint(L, 2, 0) - 1; | ||
600 | if (s==-1) { | ||
601 | lua_pushinteger(L ,tb->nuse); | ||
602 | lua_pushinteger(L ,tb->size); | ||
603 | return 2; | ||
604 | } | ||
605 | else if (s < tb->size) { | ||
606 | GCObject *ts; | ||
607 | int n = 0; | ||
608 | for (ts = tb->hash[s]; ts; ts = ts->gch.next) { | ||
609 | setsvalue2s(L, L->top, gco2ts(ts)); | ||
610 | incr_top(L); | ||
611 | n++; | ||
612 | } | ||
613 | return n; | ||
614 | } | ||
615 | return 0; | ||
616 | } | ||
617 | |||
618 | |||
619 | static int tref (lua_State *L) { | ||
620 | int level = lua_gettop(L); | ||
621 | int lock = luaL_optint(L, 2, 1); | ||
622 | luaL_checkany(L, 1); | ||
623 | lua_pushvalue(L, 1); | ||
624 | lua_pushinteger(L, lua_ref(L, lock)); | ||
625 | lua_assert(lua_gettop(L) == level+1); /* +1 for result */ | ||
626 | return 1; | ||
627 | } | ||
628 | |||
629 | static int getref (lua_State *L) { | ||
630 | int level = lua_gettop(L); | ||
631 | lua_getref(L, luaL_checkint(L, 1)); | ||
632 | lua_assert(lua_gettop(L) == level+1); | ||
633 | return 1; | ||
634 | } | ||
635 | |||
636 | static int unref (lua_State *L) { | ||
637 | int level = lua_gettop(L); | ||
638 | lua_unref(L, luaL_checkint(L, 1)); | ||
639 | lua_assert(lua_gettop(L) == level); | ||
640 | return 0; | ||
641 | } | ||
642 | |||
643 | |||
644 | static int upvalue (lua_State *L) { | ||
645 | int n = luaL_checkint(L, 2); | ||
646 | luaL_checktype(L, 1, LUA_TFUNCTION); | ||
647 | if (lua_isnone(L, 3)) { | ||
648 | const char *name = lua_getupvalue(L, 1, n); | ||
649 | if (name == NULL) return 0; | ||
650 | lua_pushstring(L, name); | ||
651 | return 2; | ||
652 | } | ||
653 | else { | ||
654 | const char *name = lua_setupvalue(L, 1, n); | ||
655 | lua_pushstring(L, name); | ||
656 | return 1; | ||
657 | } | ||
658 | } | ||
659 | |||
660 | |||
661 | static int newuserdata (lua_State *L) { | ||
662 | size_t size = luaL_checkint(L, 1); | ||
663 | char *p = cast(char *, lua_newuserdata(L, size)); | ||
664 | while (size--) *p++ = '\0'; | ||
665 | return 1; | ||
666 | } | ||
667 | |||
668 | |||
669 | static int pushuserdata (lua_State *L) { | ||
670 | lua_pushlightuserdata(L, cast(void *, luaL_checkint(L, 1))); | ||
671 | return 1; | ||
672 | } | ||
673 | |||
674 | |||
675 | static int udataval (lua_State *L) { | ||
676 | lua_pushinteger(L, cast(long, lua_touserdata(L, 1))); | ||
677 | return 1; | ||
678 | } | ||
679 | |||
680 | |||
681 | static int doonnewstack (lua_State *L) { | ||
682 | lua_State *L1 = lua_newthread(L); | ||
683 | size_t l; | ||
684 | const char *s = luaL_checklstring(L, 1, &l); | ||
685 | int status = luaL_loadbuffer(L1, s, l, s); | ||
686 | if (status == 0) | ||
687 | status = lua_pcall(L1, 0, 0, 0); | ||
688 | lua_pushinteger(L, status); | ||
689 | return 1; | ||
690 | } | ||
691 | |||
692 | |||
693 | static int s2d (lua_State *L) { | ||
694 | lua_pushnumber(L, *cast(const double *, luaL_checkstring(L, 1))); | ||
695 | return 1; | ||
696 | } | ||
697 | |||
698 | |||
699 | static int d2s (lua_State *L) { | ||
700 | double d = luaL_checknumber(L, 1); | ||
701 | lua_pushlstring(L, cast(char *, &d), sizeof(d)); | ||
702 | return 1; | ||
703 | } | ||
704 | |||
705 | |||
706 | static int num2int (lua_State *L) { | ||
707 | lua_pushinteger(L, lua_tointeger(L, 1)); | ||
708 | return 1; | ||
709 | } | ||
710 | |||
711 | |||
712 | static int newstate (lua_State *L) { | ||
713 | void *ud; | ||
714 | lua_Alloc f = lua_getallocf(L, &ud); | ||
715 | lua_State *L1 = lua_newstate(f, ud); | ||
716 | if (L1) | ||
717 | lua_pushinteger(L, (unsigned long)L1); | ||
718 | else | ||
719 | lua_pushnil(L); | ||
720 | return 1; | ||
721 | } | ||
722 | |||
723 | |||
724 | static int loadlib (lua_State *L) { | ||
725 | static const luaL_Reg libs[] = { | ||
726 | {"baselibopen", luaopen_base}, | ||
727 | {"dblibopen", luaopen_debug}, | ||
728 | {"iolibopen", luaopen_io}, | ||
729 | {"mathlibopen", luaopen_math}, | ||
730 | {"strlibopen", luaopen_string}, | ||
731 | {"tablibopen", luaopen_table}, | ||
732 | {"packageopen", luaopen_package}, | ||
733 | {NULL, NULL} | ||
734 | }; | ||
735 | lua_State *L1 = cast(lua_State *, | ||
736 | cast(unsigned long, luaL_checknumber(L, 1))); | ||
737 | lua_pushvalue(L1, LUA_GLOBALSINDEX); | ||
738 | luaL_register(L1, NULL, libs); | ||
739 | return 0; | ||
740 | } | ||
741 | |||
742 | static int closestate (lua_State *L) { | ||
743 | lua_State *L1 = cast(lua_State *, cast(unsigned long, luaL_checknumber(L, 1))); | ||
744 | lua_close(L1); | ||
745 | return 0; | ||
746 | } | ||
747 | |||
748 | static int doremote (lua_State *L) { | ||
749 | lua_State *L1 = cast(lua_State *,cast(unsigned long,luaL_checknumber(L, 1))); | ||
750 | size_t lcode; | ||
751 | const char *code = luaL_checklstring(L, 2, &lcode); | ||
752 | int status; | ||
753 | lua_settop(L1, 0); | ||
754 | status = luaL_loadbuffer(L1, code, lcode, code); | ||
755 | if (status == 0) | ||
756 | status = lua_pcall(L1, 0, LUA_MULTRET, 0); | ||
757 | if (status != 0) { | ||
758 | lua_pushnil(L); | ||
759 | lua_pushinteger(L, status); | ||
760 | lua_pushstring(L, lua_tostring(L1, -1)); | ||
761 | return 3; | ||
762 | } | ||
763 | else { | ||
764 | int i = 0; | ||
765 | while (!lua_isnone(L1, ++i)) | ||
766 | lua_pushstring(L, lua_tostring(L1, i)); | ||
767 | lua_pop(L1, i-1); | ||
768 | return i-1; | ||
769 | } | ||
770 | } | ||
771 | |||
772 | |||
773 | static int log2_aux (lua_State *L) { | ||
774 | lua_pushinteger(L, luaO_log2(luaL_checkint(L, 1))); | ||
775 | return 1; | ||
776 | } | ||
777 | |||
778 | static int int2fb_aux (lua_State *L) { | ||
779 | int b = luaO_int2fb(luaL_checkint(L, 1)); | ||
780 | lua_pushinteger(L, b); | ||
781 | lua_pushinteger(L, luaO_fb2int(b)); | ||
782 | return 2; | ||
783 | } | ||
784 | |||
785 | |||
786 | |||
787 | /* | ||
788 | ** {====================================================== | ||
789 | ** function to test the API with C. It interprets a kind of assembler | ||
790 | ** language with calls to the API, so the test can be driven by Lua code | ||
791 | ** ======================================================= | ||
792 | */ | ||
793 | |||
794 | static const char *const delimits = " \t\n,;"; | ||
795 | |||
796 | static void skip (const char **pc) { | ||
797 | while (**pc != '\0' && strchr(delimits, **pc)) (*pc)++; | ||
798 | } | ||
799 | |||
800 | static int getnum_aux (lua_State *L, const char **pc) { | ||
801 | int res = 0; | ||
802 | int sig = 1; | ||
803 | skip(pc); | ||
804 | if (**pc == '.') { | ||
805 | res = cast_int(lua_tonumber(L, -1)); | ||
806 | lua_pop(L, 1); | ||
807 | (*pc)++; | ||
808 | return res; | ||
809 | } | ||
810 | else if (**pc == '-') { | ||
811 | sig = -1; | ||
812 | (*pc)++; | ||
813 | } | ||
814 | while (isdigit(cast_int(**pc))) res = res*10 + (*(*pc)++) - '0'; | ||
815 | return sig*res; | ||
816 | } | ||
817 | |||
818 | static const char *getname_aux (char *buff, const char **pc) { | ||
819 | int i = 0; | ||
820 | skip(pc); | ||
821 | while (**pc != '\0' && !strchr(delimits, **pc)) | ||
822 | buff[i++] = *(*pc)++; | ||
823 | buff[i] = '\0'; | ||
824 | return buff; | ||
825 | } | ||
826 | |||
827 | |||
828 | static int getindex_aux (lua_State *L, const char **pc) { | ||
829 | skip(pc); | ||
830 | switch (*(*pc)++) { | ||
831 | case 'R': return LUA_REGISTRYINDEX; | ||
832 | case 'G': return LUA_GLOBALSINDEX; | ||
833 | case 'E': return LUA_ENVIRONINDEX; | ||
834 | case 'U': return lua_upvalueindex(getnum_aux(L, pc)); | ||
835 | default: (*pc)--; return getnum_aux(L, pc); | ||
836 | } | ||
837 | } | ||
838 | |||
839 | #define EQ(s1) (strcmp(s1, inst) == 0) | ||
840 | |||
841 | #define getnum (getnum_aux(L, &pc)) | ||
842 | #define getname (getname_aux(buff, &pc)) | ||
843 | #define getindex (getindex_aux(L, &pc)) | ||
844 | |||
845 | |||
846 | static int testC (lua_State *L) { | ||
847 | char buff[30]; | ||
848 | lua_State *L1; | ||
849 | const char *pc; | ||
850 | if (lua_isnumber(L, 1)) { | ||
851 | L1 = cast(lua_State *,cast(unsigned long,luaL_checknumber(L, 1))); | ||
852 | pc = luaL_checkstring(L, 2); | ||
853 | } | ||
854 | else { | ||
855 | L1 = L; | ||
856 | pc = luaL_checkstring(L, 1); | ||
857 | } | ||
858 | for (;;) { | ||
859 | const char *inst = getname; | ||
860 | if EQ("") return 0; | ||
861 | else if EQ("isnumber") { | ||
862 | lua_pushinteger(L1, lua_isnumber(L1, getindex)); | ||
863 | } | ||
864 | else if EQ("isstring") { | ||
865 | lua_pushinteger(L1, lua_isstring(L1, getindex)); | ||
866 | } | ||
867 | else if EQ("istable") { | ||
868 | lua_pushinteger(L1, lua_istable(L1, getindex)); | ||
869 | } | ||
870 | else if EQ("iscfunction") { | ||
871 | lua_pushinteger(L1, lua_iscfunction(L1, getindex)); | ||
872 | } | ||
873 | else if EQ("isfunction") { | ||
874 | lua_pushinteger(L1, lua_isfunction(L1, getindex)); | ||
875 | } | ||
876 | else if EQ("isuserdata") { | ||
877 | lua_pushinteger(L1, lua_isuserdata(L1, getindex)); | ||
878 | } | ||
879 | else if EQ("isudataval") { | ||
880 | lua_pushinteger(L1, lua_islightuserdata(L1, getindex)); | ||
881 | } | ||
882 | else if EQ("isnil") { | ||
883 | lua_pushinteger(L1, lua_isnil(L1, getindex)); | ||
884 | } | ||
885 | else if EQ("isnull") { | ||
886 | lua_pushinteger(L1, lua_isnone(L1, getindex)); | ||
887 | } | ||
888 | else if EQ("tonumber") { | ||
889 | lua_pushnumber(L1, lua_tonumber(L1, getindex)); | ||
890 | } | ||
891 | else if EQ("tostring") { | ||
892 | const char *s = lua_tostring(L1, getindex); | ||
893 | lua_pushstring(L1, s); | ||
894 | } | ||
895 | else if EQ("objsize") { | ||
896 | lua_pushinteger(L1, lua_objlen(L1, getindex)); | ||
897 | } | ||
898 | else if EQ("tocfunction") { | ||
899 | lua_pushcfunction(L1, lua_tocfunction(L1, getindex)); | ||
900 | } | ||
901 | else if EQ("return") { | ||
902 | return getnum; | ||
903 | } | ||
904 | else if EQ("gettop") { | ||
905 | lua_pushinteger(L1, lua_gettop(L1)); | ||
906 | } | ||
907 | else if EQ("settop") { | ||
908 | lua_settop(L1, getnum); | ||
909 | } | ||
910 | else if EQ("pop") { | ||
911 | lua_pop(L1, getnum); | ||
912 | } | ||
913 | else if EQ("pushnum") { | ||
914 | lua_pushinteger(L1, getnum); | ||
915 | } | ||
916 | else if EQ("pushstring") { | ||
917 | lua_pushstring(L1, getname); | ||
918 | } | ||
919 | else if EQ("pushnil") { | ||
920 | lua_pushnil(L1); | ||
921 | } | ||
922 | else if EQ("pushbool") { | ||
923 | lua_pushboolean(L1, getnum); | ||
924 | } | ||
925 | else if EQ("newuserdata") { | ||
926 | lua_newuserdata(L1, getnum); | ||
927 | } | ||
928 | else if EQ("tobool") { | ||
929 | lua_pushinteger(L1, lua_toboolean(L1, getindex)); | ||
930 | } | ||
931 | else if EQ("pushvalue") { | ||
932 | lua_pushvalue(L1, getindex); | ||
933 | } | ||
934 | else if EQ("pushcclosure") { | ||
935 | lua_pushcclosure(L1, testC, getnum); | ||
936 | } | ||
937 | else if EQ("remove") { | ||
938 | lua_remove(L1, getnum); | ||
939 | } | ||
940 | else if EQ("insert") { | ||
941 | lua_insert(L1, getnum); | ||
942 | } | ||
943 | else if EQ("replace") { | ||
944 | lua_replace(L1, getindex); | ||
945 | } | ||
946 | else if EQ("gettable") { | ||
947 | lua_gettable(L1, getindex); | ||
948 | } | ||
949 | else if EQ("settable") { | ||
950 | lua_settable(L1, getindex); | ||
951 | } | ||
952 | else if EQ("next") { | ||
953 | lua_next(L1, -2); | ||
954 | } | ||
955 | else if EQ("concat") { | ||
956 | lua_concat(L1, getnum); | ||
957 | } | ||
958 | else if EQ("lessthan") { | ||
959 | int a = getindex; | ||
960 | lua_pushboolean(L1, lua_lessthan(L1, a, getindex)); | ||
961 | } | ||
962 | else if EQ("equal") { | ||
963 | int a = getindex; | ||
964 | lua_pushboolean(L1, lua_equal(L1, a, getindex)); | ||
965 | } | ||
966 | else if EQ("rawcall") { | ||
967 | int narg = getnum; | ||
968 | int nres = getnum; | ||
969 | lua_call(L1, narg, nres); | ||
970 | } | ||
971 | else if EQ("call") { | ||
972 | int narg = getnum; | ||
973 | int nres = getnum; | ||
974 | lua_pcall(L1, narg, nres, 0); | ||
975 | } | ||
976 | else if EQ("loadstring") { | ||
977 | size_t sl; | ||
978 | const char *s = luaL_checklstring(L1, getnum, &sl); | ||
979 | luaL_loadbuffer(L1, s, sl, s); | ||
980 | } | ||
981 | else if EQ("loadfile") { | ||
982 | luaL_loadfile(L1, luaL_checkstring(L1, getnum)); | ||
983 | } | ||
984 | else if EQ("setmetatable") { | ||
985 | lua_setmetatable(L1, getindex); | ||
986 | } | ||
987 | else if EQ("getmetatable") { | ||
988 | if (lua_getmetatable(L1, getindex) == 0) | ||
989 | lua_pushnil(L1); | ||
990 | } | ||
991 | else if EQ("type") { | ||
992 | lua_pushstring(L1, luaL_typename(L1, getnum)); | ||
993 | } | ||
994 | else if EQ("getn") { | ||
995 | int i = getindex; | ||
996 | lua_pushinteger(L1, luaL_getn(L1, i)); | ||
997 | } | ||
998 | #ifndef luaL_setn | ||
999 | else if EQ("setn") { | ||
1000 | int i = getindex; | ||
1001 | int n = cast_int(lua_tonumber(L1, -1)); | ||
1002 | luaL_setn(L1, i, n); | ||
1003 | lua_pop(L1, 1); | ||
1004 | } | ||
1005 | #endif | ||
1006 | else if EQ("throw") { | ||
1007 | #if defined(__cplusplus) | ||
1008 | static struct X { int x; } x; | ||
1009 | throw x; | ||
1010 | #else | ||
1011 | luaL_error(L1, "C++"); | ||
1012 | #endif | ||
1013 | break; | ||
1014 | } | ||
1015 | else luaL_error(L, "unknown instruction %s", buff); | ||
1016 | } | ||
1017 | return 0; | ||
1018 | } | ||
1019 | |||
1020 | /* }====================================================== */ | ||
1021 | |||
1022 | |||
1023 | /* | ||
1024 | ** {====================================================== | ||
1025 | ** tests for yield inside hooks | ||
1026 | ** ======================================================= | ||
1027 | */ | ||
1028 | |||
1029 | static void yieldf (lua_State *L, lua_Debug *ar) { | ||
1030 | lua_yield(L, 0); | ||
1031 | } | ||
1032 | |||
1033 | static int setyhook (lua_State *L) { | ||
1034 | if (lua_isnoneornil(L, 1)) | ||
1035 | lua_sethook(L, NULL, 0, 0); /* turn off hooks */ | ||
1036 | else { | ||
1037 | const char *smask = luaL_checkstring(L, 1); | ||
1038 | int count = luaL_optint(L, 2, 0); | ||
1039 | int mask = 0; | ||
1040 | if (strchr(smask, 'l')) mask |= LUA_MASKLINE; | ||
1041 | if (count > 0) mask |= LUA_MASKCOUNT; | ||
1042 | lua_sethook(L, yieldf, mask, count); | ||
1043 | } | ||
1044 | return 0; | ||
1045 | } | ||
1046 | |||
1047 | |||
1048 | static int coresume (lua_State *L) { | ||
1049 | int status; | ||
1050 | lua_State *co = lua_tothread(L, 1); | ||
1051 | luaL_argcheck(L, co, 1, "coroutine expected"); | ||
1052 | status = lua_resume(co, 0); | ||
1053 | if (status != 0) { | ||
1054 | lua_pushboolean(L, 0); | ||
1055 | lua_insert(L, -2); | ||
1056 | return 2; /* return false + error message */ | ||
1057 | } | ||
1058 | else { | ||
1059 | lua_pushboolean(L, 1); | ||
1060 | return 1; | ||
1061 | } | ||
1062 | } | ||
1063 | |||
1064 | /* }====================================================== */ | ||
1065 | |||
1066 | |||
1067 | |||
1068 | /* | ||
1069 | ** {====================================================== | ||
1070 | ** tests auxlib functions | ||
1071 | ** ======================================================= | ||
1072 | */ | ||
1073 | |||
1074 | static int auxgsub (lua_State *L) { | ||
1075 | const char *s1 = luaL_checkstring(L, 1); | ||
1076 | const char *s2 = luaL_checkstring(L, 2); | ||
1077 | const char *s3 = luaL_checkstring(L, 3); | ||
1078 | lua_settop(L, 3); | ||
1079 | luaL_gsub(L, s1, s2, s3); | ||
1080 | lua_assert(lua_gettop(L) == 4); | ||
1081 | return 1; | ||
1082 | } | ||
1083 | |||
1084 | |||
1085 | /* }====================================================== */ | ||
1086 | |||
1087 | |||
1088 | |||
1089 | static const struct luaL_Reg tests_funcs[] = { | ||
1090 | {"checkmemory", lua_checkmemory}, | ||
1091 | {"closestate", closestate}, | ||
1092 | {"d2s", d2s}, | ||
1093 | {"doonnewstack", doonnewstack}, | ||
1094 | {"doremote", doremote}, | ||
1095 | {"gccolor", get_gccolor}, | ||
1096 | {"gcstate", gcstate}, | ||
1097 | {"getref", getref}, | ||
1098 | {"gsub", auxgsub}, | ||
1099 | {"hash", hash_query}, | ||
1100 | {"int2fb", int2fb_aux}, | ||
1101 | {"limits", get_limits}, | ||
1102 | {"listcode", listcode}, | ||
1103 | {"listk", listk}, | ||
1104 | {"listlocals", listlocals}, | ||
1105 | {"loadlib", loadlib}, | ||
1106 | {"log2", log2_aux}, | ||
1107 | {"newstate", newstate}, | ||
1108 | {"newuserdata", newuserdata}, | ||
1109 | {"num2int", num2int}, | ||
1110 | {"pushuserdata", pushuserdata}, | ||
1111 | {"querystr", string_query}, | ||
1112 | {"querytab", table_query}, | ||
1113 | {"ref", tref}, | ||
1114 | {"resume", coresume}, | ||
1115 | {"s2d", s2d}, | ||
1116 | {"setyhook", setyhook}, | ||
1117 | {"stacklevel", stacklevel}, | ||
1118 | {"testC", testC}, | ||
1119 | {"totalmem", mem_query}, | ||
1120 | {"trick", settrick}, | ||
1121 | {"udataval", udataval}, | ||
1122 | {"unref", unref}, | ||
1123 | {"upvalue", upvalue}, | ||
1124 | {NULL, NULL} | ||
1125 | }; | ||
1126 | |||
1127 | |||
1128 | static void checkfinalmem (void) { | ||
1129 | lua_assert(memcontrol.numblocks == 0); | ||
1130 | lua_assert(memcontrol.total == 0); | ||
1131 | } | ||
1132 | |||
1133 | |||
1134 | int luaB_opentests (lua_State *L) { | ||
1135 | void *ud; | ||
1136 | atexit(checkfinalmem); | ||
1137 | lua_assert(lua_getallocf(L, &ud) == debug_realloc); | ||
1138 | lua_assert(ud == cast(void *, &memcontrol)); | ||
1139 | lua_setallocf(L, lua_getallocf(L, NULL), ud); | ||
1140 | lua_state = L; /* keep first state to be opened */ | ||
1141 | luaL_register(L, "T", tests_funcs); | ||
1142 | return 0; | ||
1143 | } | ||
1144 | |||
1145 | #endif | ||