1 /*
2 ** $Id$
3 ** Basic library
4 ** See Copyright Notice in lua.h
5 */
6
7
8 #define FORBIDDEN_SYMBOL_EXCEPTION_fputs
9 #define FORBIDDEN_SYMBOL_EXCEPTION_stdout
10
11 #include "common/util.h"
12
13 #define lbaselib_c
14 #define LUA_LIB
15
16 #include "lua.h"
17
18 #include "lauxlib.h"
19 #include "lualib.h"
20
21
22
23 /*
24 ** If your system does not support `stdout', you can just remove this function.
25 ** If you need, you can define your own `print' function, following this
26 ** model but changing `fputs' to put the strings at a proper place
27 ** (a console window or a log file, for instance).
28 */
luaB_print(lua_State * L)29 static int luaB_print (lua_State *L) {
30 int n = lua_gettop(L); /* number of arguments */
31 int i;
32 lua_getglobal(L, "tostring");
33 for (i=1; i<=n; i++) {
34 const char *s;
35 lua_pushvalue(L, -1); /* function to be called */
36 lua_pushvalue(L, i); /* value to print */
37 lua_call(L, 1, 1);
38 s = lua_tostring(L, -1); /* get result */
39 if (s == NULL)
40 return luaL_error(L, LUA_QL("tostring") " must return a string to "
41 LUA_QL("print"));
42 if (i>1) fputs("\t", stdout);
43 fputs(s, stdout);
44 lua_pop(L, 1); /* pop result */
45 }
46 fputs("\n", stdout);
47 return 0;
48 }
49
50
luaB_tonumber(lua_State * L)51 static int luaB_tonumber (lua_State *L) {
52 int base = luaL_optint(L, 2, 10);
53 if (base == 10) { /* standard conversion */
54 luaL_checkany(L, 1);
55 if (lua_isnumber(L, 1)) {
56 lua_pushnumber(L, lua_tonumber(L, 1));
57 return 1;
58 }
59 }
60 else {
61 const char *s1 = luaL_checkstring(L, 1);
62 char *s2;
63 unsigned long n;
64 luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
65 n = strtoul(s1, &s2, base);
66 if (s1 != s2) { /* at least one valid digit? */
67 while (Common::isSpace(*s2)) s2++; /* skip trailing spaces */
68 if (*s2 == '\0') { /* no invalid trailing characters? */
69 lua_pushnumber(L, (lua_Number)n);
70 return 1;
71 }
72 }
73 }
74 lua_pushnil(L); /* else not a number */
75 return 1;
76 }
77
78
luaB_error(lua_State * L)79 static int luaB_error (lua_State *L) {
80 int level = luaL_optint(L, 2, 1);
81 lua_settop(L, 1);
82 if (lua_isstring(L, 1) && level > 0) { /* add extra information? */
83 luaL_where(L, level);
84 lua_pushvalue(L, 1);
85 lua_concat(L, 2);
86 }
87 return lua_error(L);
88 }
89
90
luaB_getmetatable(lua_State * L)91 static int luaB_getmetatable (lua_State *L) {
92 luaL_checkany(L, 1);
93 if (!lua_getmetatable(L, 1)) {
94 lua_pushnil(L);
95 return 1; /* no metatable */
96 }
97 luaL_getmetafield(L, 1, "__metatable");
98 return 1; /* returns either __metatable field (if present) or metatable */
99 }
100
101
luaB_setmetatable(lua_State * L)102 static int luaB_setmetatable (lua_State *L) {
103 int t = lua_type(L, 2);
104 luaL_checktype(L, 1, LUA_TTABLE);
105 luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
106 "nil or table expected");
107 if (luaL_getmetafield(L, 1, "__metatable"))
108 luaL_error(L, "cannot change a protected metatable");
109 lua_settop(L, 2);
110 lua_setmetatable(L, 1);
111 return 1;
112 }
113
114
getfunc(lua_State * L,int opt)115 static void getfunc (lua_State *L, int opt) {
116 if (lua_isfunction(L, 1)) lua_pushvalue(L, 1);
117 else {
118 lua_Debug ar;
119 int level = opt ? luaL_optint(L, 1, 1) : luaL_checkint(L, 1);
120 luaL_argcheck(L, level >= 0, 1, "level must be non-negative");
121 if (lua_getstack(L, level, &ar) == 0)
122 luaL_argerror(L, 1, "invalid level");
123 lua_getinfo(L, "f", &ar);
124 if (lua_isnil(L, -1))
125 luaL_error(L, "no function environment for tail call at level %d",
126 level);
127 }
128 }
129
130
luaB_getfenv(lua_State * L)131 static int luaB_getfenv (lua_State *L) {
132 getfunc(L, 1);
133 if (lua_iscfunction(L, -1)) /* is a C function? */
134 lua_pushvalue(L, LUA_GLOBALSINDEX); /* return the thread's global env. */
135 else
136 lua_getfenv(L, -1);
137 return 1;
138 }
139
140
luaB_setfenv(lua_State * L)141 static int luaB_setfenv (lua_State *L) {
142 luaL_checktype(L, 2, LUA_TTABLE);
143 getfunc(L, 0);
144 lua_pushvalue(L, 2);
145 if (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0) {
146 /* change environment of current thread */
147 lua_pushthread(L);
148 lua_insert(L, -2);
149 lua_setfenv(L, -2);
150 return 0;
151 }
152 else if (lua_iscfunction(L, -2) || lua_setfenv(L, -2) == 0)
153 luaL_error(L,
154 LUA_QL("setfenv") " cannot change environment of given object");
155 return 1;
156 }
157
158
luaB_rawequal(lua_State * L)159 static int luaB_rawequal (lua_State *L) {
160 luaL_checkany(L, 1);
161 luaL_checkany(L, 2);
162 lua_pushboolean(L, lua_rawequal(L, 1, 2));
163 return 1;
164 }
165
166
luaB_rawget(lua_State * L)167 static int luaB_rawget (lua_State *L) {
168 luaL_checktype(L, 1, LUA_TTABLE);
169 luaL_checkany(L, 2);
170 lua_settop(L, 2);
171 lua_rawget(L, 1);
172 return 1;
173 }
174
luaB_rawset(lua_State * L)175 static int luaB_rawset (lua_State *L) {
176 luaL_checktype(L, 1, LUA_TTABLE);
177 luaL_checkany(L, 2);
178 luaL_checkany(L, 3);
179 lua_settop(L, 3);
180 lua_rawset(L, 1);
181 return 1;
182 }
183
184
luaB_gcinfo(lua_State * L)185 static int luaB_gcinfo (lua_State *L) {
186 lua_pushinteger(L, lua_getgccount(L));
187 return 1;
188 }
189
190
luaB_collectgarbage(lua_State * L)191 static int luaB_collectgarbage (lua_State *L) {
192 static const char *const opts[] = {"stop", "restart", "collect",
193 "count", "step", "setpause", "setstepmul", NULL};
194 static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT,
195 LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL};
196 int o = luaL_checkoption(L, 1, "collect", opts);
197 int ex = luaL_optint(L, 2, 0);
198 int res = lua_gc(L, optsnum[o], ex);
199 switch (optsnum[o]) {
200 case LUA_GCCOUNT: {
201 int b = lua_gc(L, LUA_GCCOUNTB, 0);
202 lua_pushnumber(L, res + ((lua_Number)b/1024));
203 return 1;
204 }
205 case LUA_GCSTEP: {
206 lua_pushboolean(L, res);
207 return 1;
208 }
209 default: {
210 lua_pushnumber(L, res);
211 return 1;
212 }
213 }
214 }
215
216
luaB_type(lua_State * L)217 static int luaB_type (lua_State *L) {
218 luaL_checkany(L, 1);
219 lua_pushstring(L, luaL_typename(L, 1));
220 return 1;
221 }
222
223
luaB_next(lua_State * L)224 static int luaB_next (lua_State *L) {
225 luaL_checktype(L, 1, LUA_TTABLE);
226 lua_settop(L, 2); /* create a 2nd argument if there isn't one */
227 if (lua_next(L, 1))
228 return 2;
229 else {
230 lua_pushnil(L);
231 return 1;
232 }
233 }
234
235
luaB_pairs(lua_State * L)236 static int luaB_pairs (lua_State *L) {
237 luaL_checktype(L, 1, LUA_TTABLE);
238 lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */
239 lua_pushvalue(L, 1); /* state, */
240 lua_pushnil(L); /* and initial value */
241 return 3;
242 }
243
244
ipairsaux(lua_State * L)245 static int ipairsaux (lua_State *L) {
246 int i = luaL_checkint(L, 2);
247 luaL_checktype(L, 1, LUA_TTABLE);
248 i++; /* next value */
249 lua_pushinteger(L, i);
250 lua_rawgeti(L, 1, i);
251 return (lua_isnil(L, -1)) ? 0 : 2;
252 }
253
254
luaB_ipairs(lua_State * L)255 static int luaB_ipairs (lua_State *L) {
256 luaL_checktype(L, 1, LUA_TTABLE);
257 lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */
258 lua_pushvalue(L, 1); /* state, */
259 lua_pushinteger(L, 0); /* and initial value */
260 return 3;
261 }
262
263
load_aux(lua_State * L,int status)264 static int load_aux (lua_State *L, int status) {
265 if (status == 0) /* OK? */
266 return 1;
267 else {
268 lua_pushnil(L);
269 lua_insert(L, -2); /* put before error message */
270 return 2; /* return nil plus error message */
271 }
272 }
273
274
luaB_loadstring(lua_State * L)275 static int luaB_loadstring (lua_State *L) {
276 size_t l;
277 const char *s = luaL_checklstring(L, 1, &l);
278 const char *chunkname = luaL_optstring(L, 2, s);
279 return load_aux(L, luaL_loadbuffer(L, s, l, chunkname));
280 }
281
282
luaB_loadfile(lua_State * L)283 static int luaB_loadfile (lua_State *L) {
284 const char *fname = luaL_optstring(L, 1, NULL);
285 return load_aux(L, luaL_loadfile(L, fname));
286 }
287
288
289 /*
290 ** Reader for generic `load' function: `lua_load' uses the
291 ** stack for internal stuff, so the reader cannot change the
292 ** stack top. Instead, it keeps its resulting string in a
293 ** reserved slot inside the stack.
294 */
generic_reader(lua_State * L,void * ud,size_t * size)295 static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
296 (void)ud; /* to avoid warnings */
297 luaL_checkstack(L, 2, "too many nested functions");
298 lua_pushvalue(L, 1); /* get function */
299 lua_call(L, 0, 1); /* call it */
300 if (lua_isnil(L, -1)) {
301 *size = 0;
302 return NULL;
303 }
304 else if (lua_isstring(L, -1)) {
305 lua_replace(L, 3); /* save string in a reserved stack slot */
306 return lua_tolstring(L, 3, size);
307 }
308 else luaL_error(L, "reader function must return a string");
309 return NULL; /* to avoid warnings */
310 }
311
312
luaB_load(lua_State * L)313 static int luaB_load (lua_State *L) {
314 int status;
315 const char *cname = luaL_optstring(L, 2, "=(load)");
316 luaL_checktype(L, 1, LUA_TFUNCTION);
317 lua_settop(L, 3); /* function, eventual name, plus one reserved slot */
318 status = lua_load(L, generic_reader, NULL, cname);
319 return load_aux(L, status);
320 }
321
322
luaB_dofile(lua_State * L)323 static int luaB_dofile (lua_State *L) {
324 const char *fname = luaL_optstring(L, 1, NULL);
325 int n = lua_gettop(L);
326 if (luaL_loadfile(L, fname) != 0) lua_error(L);
327 lua_call(L, 0, LUA_MULTRET);
328 return lua_gettop(L) - n;
329 }
330
331
luaB_assert(lua_State * L)332 static int luaB_assert (lua_State *L) {
333 luaL_checkany(L, 1);
334 if (!lua_toboolean(L, 1))
335 return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!"));
336 return lua_gettop(L);
337 }
338
339
luaB_unpack(lua_State * L)340 static int luaB_unpack (lua_State *L) {
341 int i, e, n;
342 luaL_checktype(L, 1, LUA_TTABLE);
343 i = luaL_optint(L, 2, 1);
344 e = luaL_opt(L, luaL_checkint, 3, luaL_getn(L, 1));
345 n = e - i + 1; /* number of elements */
346 if (n <= 0) return 0; /* empty range */
347 luaL_checkstack(L, n, "table too big to unpack");
348 for (; i<=e; i++) /* push arg[i...e] */
349 lua_rawgeti(L, 1, i);
350 return n;
351 }
352
353
luaB_select(lua_State * L)354 static int luaB_select (lua_State *L) {
355 int n = lua_gettop(L);
356 if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') {
357 lua_pushinteger(L, n-1);
358 return 1;
359 }
360 else {
361 int i = luaL_checkint(L, 1);
362 if (i < 0) i = n + i;
363 else if (i > n) i = n;
364 luaL_argcheck(L, 1 <= i, 1, "index out of range");
365 return n - i;
366 }
367 }
368
369
luaB_pcall(lua_State * L)370 static int luaB_pcall (lua_State *L) {
371 int status;
372 luaL_checkany(L, 1);
373 status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0);
374 lua_pushboolean(L, (status == 0));
375 lua_insert(L, 1);
376 return lua_gettop(L); /* return status + all results */
377 }
378
379
luaB_xpcall(lua_State * L)380 static int luaB_xpcall (lua_State *L) {
381 int status;
382 luaL_checkany(L, 2);
383 lua_settop(L, 2);
384 lua_insert(L, 1); /* put error function under function to be called */
385 status = lua_pcall(L, 0, LUA_MULTRET, 1);
386 lua_pushboolean(L, (status == 0));
387 lua_replace(L, 1);
388 return lua_gettop(L); /* return status + all results */
389 }
390
391
luaB_tostring(lua_State * L)392 static int luaB_tostring (lua_State *L) {
393 luaL_checkany(L, 1);
394 if (luaL_callmeta(L, 1, "__tostring")) /* is there a metafield? */
395 return 1; /* use its value */
396 switch (lua_type(L, 1)) {
397 case LUA_TNUMBER:
398 lua_pushstring(L, lua_tostring(L, 1));
399 break;
400 case LUA_TSTRING:
401 lua_pushvalue(L, 1);
402 break;
403 case LUA_TBOOLEAN:
404 lua_pushstring(L, (lua_toboolean(L, 1) ? "true" : "false"));
405 break;
406 case LUA_TNIL:
407 lua_pushliteral(L, "nil");
408 break;
409 default:
410 lua_pushfstring(L, "%s: %p", luaL_typename(L, 1), lua_topointer(L, 1));
411 break;
412 }
413 return 1;
414 }
415
416
luaB_newproxy(lua_State * L)417 static int luaB_newproxy (lua_State *L) {
418 lua_settop(L, 1);
419 lua_newuserdata(L, 0); /* create proxy */
420 if (lua_toboolean(L, 1) == 0)
421 return 1; /* no metatable */
422 else if (lua_isboolean(L, 1)) {
423 lua_newtable(L); /* create a new metatable `m' ... */
424 lua_pushvalue(L, -1); /* ... and mark `m' as a valid metatable */
425 lua_pushboolean(L, 1);
426 lua_rawset(L, lua_upvalueindex(1)); /* weaktable[m] = true */
427 }
428 else {
429 int validproxy = 0; /* to check if weaktable[metatable(u)] == true */
430 if (lua_getmetatable(L, 1)) {
431 lua_rawget(L, lua_upvalueindex(1));
432 validproxy = lua_toboolean(L, -1);
433 lua_pop(L, 1); /* remove value */
434 }
435 luaL_argcheck(L, validproxy, 1, "boolean or proxy expected");
436 lua_getmetatable(L, 1); /* metatable is valid; get it */
437 }
438 lua_setmetatable(L, 2);
439 return 1;
440 }
441
442
443 static const luaL_Reg base_funcs[] = {
444 {"assert", luaB_assert},
445 {"collectgarbage", luaB_collectgarbage},
446 {"dofile", luaB_dofile},
447 {"error", luaB_error},
448 {"gcinfo", luaB_gcinfo},
449 {"getfenv", luaB_getfenv},
450 {"getmetatable", luaB_getmetatable},
451 {"loadfile", luaB_loadfile},
452 {"load", luaB_load},
453 {"loadstring", luaB_loadstring},
454 {"next", luaB_next},
455 {"pcall", luaB_pcall},
456 {"print", luaB_print},
457 {"rawequal", luaB_rawequal},
458 {"rawget", luaB_rawget},
459 {"rawset", luaB_rawset},
460 {"select", luaB_select},
461 {"setfenv", luaB_setfenv},
462 {"setmetatable", luaB_setmetatable},
463 {"tonumber", luaB_tonumber},
464 {"tostring", luaB_tostring},
465 {"type", luaB_type},
466 {"unpack", luaB_unpack},
467 {"xpcall", luaB_xpcall},
468 {NULL, NULL}
469 };
470
471
472 /*
473 ** {======================================================
474 ** Coroutine library
475 ** =======================================================
476 */
477
478 #define CO_RUN 0 /* running */
479 #define CO_SUS 1 /* suspended */
480 #define CO_NOR 2 /* 'normal' (it resumed another coroutine) */
481 #define CO_DEAD 3
482
483 static const char *const statnames[] =
484 {"running", "suspended", "normal", "dead"};
485
costatus(lua_State * L,lua_State * co)486 static int costatus (lua_State *L, lua_State *co) {
487 if (L == co) return CO_RUN;
488 switch (lua_status(co)) {
489 case LUA_YIELD:
490 return CO_SUS;
491 case 0: {
492 lua_Debug ar;
493 if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */
494 return CO_NOR; /* it is running */
495 else if (lua_gettop(co) == 0)
496 return CO_DEAD;
497 else
498 return CO_SUS; /* initial state */
499 }
500 default: /* some error occurred */
501 return CO_DEAD;
502 }
503 }
504
505
luaB_costatus(lua_State * L)506 static int luaB_costatus (lua_State *L) {
507 lua_State *co = lua_tothread(L, 1);
508 luaL_argcheck(L, co, 1, "coroutine expected");
509 lua_pushstring(L, statnames[costatus(L, co)]);
510 return 1;
511 }
512
513
auxresume(lua_State * L,lua_State * co,int narg)514 static int auxresume (lua_State *L, lua_State *co, int narg) {
515 int status = costatus(L, co);
516 if (!lua_checkstack(co, narg))
517 luaL_error(L, "too many arguments to resume");
518 if (status != CO_SUS) {
519 lua_pushfstring(L, "cannot resume %s coroutine", statnames[status]);
520 return -1; /* error flag */
521 }
522 lua_xmove(L, co, narg);
523 lua_setlevel(L, co);
524 status = lua_resume(co, narg);
525 if (status == 0 || status == LUA_YIELD) {
526 int nres = lua_gettop(co);
527 if (!lua_checkstack(L, nres))
528 luaL_error(L, "too many results to resume");
529 lua_xmove(co, L, nres); /* move yielded values */
530 return nres;
531 }
532 else {
533 lua_xmove(co, L, 1); /* move error message */
534 return -1; /* error flag */
535 }
536 }
537
538
luaB_coresume(lua_State * L)539 static int luaB_coresume (lua_State *L) {
540 lua_State *co = lua_tothread(L, 1);
541 int r;
542 luaL_argcheck(L, co, 1, "coroutine expected");
543 r = auxresume(L, co, lua_gettop(L) - 1);
544 if (r < 0) {
545 lua_pushboolean(L, 0);
546 lua_insert(L, -2);
547 return 2; /* return false + error message */
548 }
549 else {
550 lua_pushboolean(L, 1);
551 lua_insert(L, -(r + 1));
552 return r + 1; /* return true + `resume' returns */
553 }
554 }
555
556
luaB_auxwrap(lua_State * L)557 static int luaB_auxwrap (lua_State *L) {
558 lua_State *co = lua_tothread(L, lua_upvalueindex(1));
559 int r = auxresume(L, co, lua_gettop(L));
560 if (r < 0) {
561 if (lua_isstring(L, -1)) { /* error object is a string? */
562 luaL_where(L, 1); /* add extra info */
563 lua_insert(L, -2);
564 lua_concat(L, 2);
565 }
566 lua_error(L); /* propagate error */
567 }
568 return r;
569 }
570
571
luaB_cocreate(lua_State * L)572 static int luaB_cocreate (lua_State *L) {
573 lua_State *NL = lua_newthread(L);
574 luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1,
575 "Lua function expected");
576 lua_pushvalue(L, 1); /* move function to top */
577 lua_xmove(L, NL, 1); /* move function from L to NL */
578 return 1;
579 }
580
581
luaB_cowrap(lua_State * L)582 static int luaB_cowrap (lua_State *L) {
583 luaB_cocreate(L);
584 lua_pushcclosure(L, luaB_auxwrap, 1);
585 return 1;
586 }
587
588
luaB_yield(lua_State * L)589 static int luaB_yield (lua_State *L) {
590 return lua_yield(L, lua_gettop(L));
591 }
592
593
luaB_corunning(lua_State * L)594 static int luaB_corunning (lua_State *L) {
595 if (lua_pushthread(L))
596 lua_pushnil(L); /* main thread is not a coroutine */
597 return 1;
598 }
599
600
601 static const luaL_Reg co_funcs[] = {
602 {"create", luaB_cocreate},
603 {"resume", luaB_coresume},
604 {"running", luaB_corunning},
605 {"status", luaB_costatus},
606 {"wrap", luaB_cowrap},
607 {"yield", luaB_yield},
608 {NULL, NULL}
609 };
610
611 /* }====================================================== */
612
613
auxopen(lua_State * L,const char * name,lua_CFunction f,lua_CFunction u)614 static void auxopen (lua_State *L, const char *name,
615 lua_CFunction f, lua_CFunction u) {
616 lua_pushcfunction(L, u);
617 /* BS25 ==== */
618 lua_pushstring(L, name);
619 lua_pushstring(L, "_next");
620 lua_concat(L, 2);
621 lua_pushvalue(L, -2);
622 lua_settable(L, LUA_GLOBALSINDEX);
623 /* ==== BS25 */
624 lua_pushcclosure(L, f, 1);
625 lua_setfield(L, -2, name);
626 }
627
628
base_open(lua_State * L)629 static void base_open (lua_State *L) {
630 /* set global _G */
631 lua_pushvalue(L, LUA_GLOBALSINDEX);
632 lua_setglobal(L, "_G");
633 /* open lib into global table */
634 luaL_register(L, "_G", base_funcs);
635 lua_pushliteral(L, LUA_VERSION);
636 lua_setglobal(L, "_VERSION"); /* set global _VERSION */
637 /* `ipairs' and `pairs' need auxliliary functions as upvalues */
638 auxopen(L, "ipairs", luaB_ipairs, ipairsaux);
639 auxopen(L, "pairs", luaB_pairs, luaB_next);
640 /* `newproxy' needs a weaktable as upvalue */
641 lua_createtable(L, 0, 1); /* new table `w' */
642 lua_pushvalue(L, -1); /* `w' will be its own metatable */
643 lua_setmetatable(L, -2);
644 lua_pushliteral(L, "kv");
645 lua_setfield(L, -2, "__mode"); /* metatable(w).__mode = "kv" */
646 lua_pushcclosure(L, luaB_newproxy, 1);
647 lua_setglobal(L, "newproxy"); /* set global `newproxy' */
648 }
649
650
luaopen_base(lua_State * L)651 LUALIB_API int luaopen_base (lua_State *L) {
652 base_open(L);
653 luaL_register(L, LUA_COLIBNAME, co_funcs);
654 return 2;
655 }
656