1 /* 2 ** $Id: lbaselib.c $ 3 ** Basic library 4 ** See Copyright Notice in lua.h 5 */ 6 7 #define lbaselib_c 8 #define LUA_LIB 9 10 #include "lprefix.h" 11 12 13 #include <ctype.h> 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <string.h> 17 18 #include "lua.h" 19 20 #include "lauxlib.h" 21 #include "lualib.h" 22 23 24 static int luaB_print (lua_State *L) { 25 int n = lua_gettop(L); /* number of arguments */ 26 int i; 27 for (i = 1; i <= n; i++) { /* for each argument */ 28 size_t l; 29 const char *s = luaL_tolstring(L, i, &l); /* convert it to string */ 30 if (i > 1) /* not the first element? */ 31 lua_writestring("\t", 1); /* add a tab before it */ 32 lua_writestring(s, l); /* print it */ 33 lua_pop(L, 1); /* pop result */ 34 } 35 lua_writeline(); 36 return 0; 37 } 38 39 40 /* 41 ** Creates a warning with all given arguments. 42 ** Check first for errors; otherwise an error may interrupt 43 ** the composition of a warning, leaving it unfinished. 44 */ 45 static int luaB_warn (lua_State *L) { 46 int n = lua_gettop(L); /* number of arguments */ 47 int i; 48 luaL_checkstring(L, 1); /* at least one argument */ 49 for (i = 2; i <= n; i++) 50 luaL_checkstring(L, i); /* make sure all arguments are strings */ 51 for (i = 1; i < n; i++) /* compose warning */ 52 lua_warning(L, lua_tostring(L, i), 1); 53 lua_warning(L, lua_tostring(L, n), 0); /* close warning */ 54 return 0; 55 } 56 57 58 #define SPACECHARS " \f\n\r\t\v" 59 60 static const char *b_str2int (const char *s, int base, lua_Integer *pn) { 61 lua_Unsigned n = 0; 62 int neg = 0; 63 s += strspn(s, SPACECHARS); /* skip initial spaces */ 64 if (*s == '-') { s++; neg = 1; } /* handle sign */ 65 else if (*s == '+') s++; 66 if (!isalnum((unsigned char)*s)) /* no digit? */ 67 return NULL; 68 do { 69 int digit = (isdigit((unsigned char)*s)) ? *s - '0' 70 : (toupper((unsigned char)*s) - 'A') + 10; 71 if (digit >= base) return NULL; /* invalid numeral */ 72 n = n * base + digit; 73 s++; 74 } while (isalnum((unsigned char)*s)); 75 s += strspn(s, SPACECHARS); /* skip trailing spaces */ 76 *pn = (lua_Integer)((neg) ? (0u - n) : n); 77 return s; 78 } 79 80 81 static int luaB_tonumber (lua_State *L) { 82 if (lua_isnoneornil(L, 2)) { /* standard conversion? */ 83 if (lua_type(L, 1) == LUA_TNUMBER) { /* already a number? */ 84 lua_settop(L, 1); /* yes; return it */ 85 return 1; 86 } 87 else { 88 size_t l; 89 const char *s = lua_tolstring(L, 1, &l); 90 if (s != NULL && lua_stringtonumber(L, s) == l + 1) 91 return 1; /* successful conversion to number */ 92 /* else not a number */ 93 luaL_checkany(L, 1); /* (but there must be some parameter) */ 94 } 95 } 96 else { 97 size_t l; 98 const char *s; 99 lua_Integer n = 0; /* to avoid warnings */ 100 lua_Integer base = luaL_checkinteger(L, 2); 101 luaL_checktype(L, 1, LUA_TSTRING); /* no numbers as strings */ 102 s = lua_tolstring(L, 1, &l); 103 luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); 104 if (b_str2int(s, (int)base, &n) == s + l) { 105 lua_pushinteger(L, n); 106 return 1; 107 } /* else not a number */ 108 } /* else not a number */ 109 luaL_pushfail(L); /* not a number */ 110 return 1; 111 } 112 113 114 static int luaB_error (lua_State *L) { 115 int level = (int)luaL_optinteger(L, 2, 1); 116 lua_settop(L, 1); 117 if (lua_type(L, 1) == LUA_TSTRING && level > 0) { 118 luaL_where(L, level); /* add extra information */ 119 lua_pushvalue(L, 1); 120 lua_concat(L, 2); 121 } 122 return lua_error(L); 123 } 124 125 126 static int luaB_getmetatable (lua_State *L) { 127 luaL_checkany(L, 1); 128 if (!lua_getmetatable(L, 1)) { 129 lua_pushnil(L); 130 return 1; /* no metatable */ 131 } 132 luaL_getmetafield(L, 1, "__metatable"); 133 return 1; /* returns either __metatable field (if present) or metatable */ 134 } 135 136 137 static int luaB_setmetatable (lua_State *L) { 138 int t = lua_type(L, 2); 139 luaL_checktype(L, 1, LUA_TTABLE); 140 luaL_argexpected(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table"); 141 if (l_unlikely(luaL_getmetafield(L, 1, "__metatable") != LUA_TNIL)) 142 return luaL_error(L, "cannot change a protected metatable"); 143 lua_settop(L, 2); 144 lua_setmetatable(L, 1); 145 return 1; 146 } 147 148 149 static int luaB_rawequal (lua_State *L) { 150 luaL_checkany(L, 1); 151 luaL_checkany(L, 2); 152 lua_pushboolean(L, lua_rawequal(L, 1, 2)); 153 return 1; 154 } 155 156 157 static int luaB_rawlen (lua_State *L) { 158 int t = lua_type(L, 1); 159 luaL_argexpected(L, t == LUA_TTABLE || t == LUA_TSTRING, 1, 160 "table or string"); 161 lua_pushinteger(L, lua_rawlen(L, 1)); 162 return 1; 163 } 164 165 166 static int luaB_rawget (lua_State *L) { 167 luaL_checktype(L, 1, LUA_TTABLE); 168 luaL_checkany(L, 2); 169 lua_settop(L, 2); 170 lua_rawget(L, 1); 171 return 1; 172 } 173 174 static int luaB_rawset (lua_State *L) { 175 luaL_checktype(L, 1, LUA_TTABLE); 176 luaL_checkany(L, 2); 177 luaL_checkany(L, 3); 178 lua_settop(L, 3); 179 lua_rawset(L, 1); 180 return 1; 181 } 182 183 184 static int pushmode (lua_State *L, int oldmode) { 185 if (oldmode == -1) 186 luaL_pushfail(L); /* invalid call to 'lua_gc' */ 187 else 188 lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental" 189 : "generational"); 190 return 1; 191 } 192 193 194 /* 195 ** check whether call to 'lua_gc' was valid (not inside a finalizer) 196 */ 197 #define checkvalres(res) { if (res == -1) break; } 198 199 static int luaB_collectgarbage (lua_State *L) { 200 static const char *const opts[] = {"stop", "restart", "collect", 201 "count", "step", "setpause", "setstepmul", 202 "isrunning", "generational", "incremental", NULL}; 203 static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, 204 LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, 205 LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC}; 206 int o = optsnum[luaL_checkoption(L, 1, "collect", opts)]; 207 switch (o) { 208 case LUA_GCCOUNT: { 209 int k = lua_gc(L, o); 210 int b = lua_gc(L, LUA_GCCOUNTB); 211 checkvalres(k); 212 lua_pushnumber(L, (lua_Number)k + ((lua_Number)b/1024)); 213 return 1; 214 } 215 case LUA_GCSTEP: { 216 int step = (int)luaL_optinteger(L, 2, 0); 217 int res = lua_gc(L, o, step); 218 checkvalres(res); 219 lua_pushboolean(L, res); 220 return 1; 221 } 222 case LUA_GCSETPAUSE: 223 case LUA_GCSETSTEPMUL: { 224 int p = (int)luaL_optinteger(L, 2, 0); 225 int previous = lua_gc(L, o, p); 226 checkvalres(previous); 227 lua_pushinteger(L, previous); 228 return 1; 229 } 230 case LUA_GCISRUNNING: { 231 int res = lua_gc(L, o); 232 checkvalres(res); 233 lua_pushboolean(L, res); 234 return 1; 235 } 236 case LUA_GCGEN: { 237 int minormul = (int)luaL_optinteger(L, 2, 0); 238 int majormul = (int)luaL_optinteger(L, 3, 0); 239 return pushmode(L, lua_gc(L, o, minormul, majormul)); 240 } 241 case LUA_GCINC: { 242 int pause = (int)luaL_optinteger(L, 2, 0); 243 int stepmul = (int)luaL_optinteger(L, 3, 0); 244 int stepsize = (int)luaL_optinteger(L, 4, 0); 245 return pushmode(L, lua_gc(L, o, pause, stepmul, stepsize)); 246 } 247 default: { 248 int res = lua_gc(L, o); 249 checkvalres(res); 250 lua_pushinteger(L, res); 251 return 1; 252 } 253 } 254 luaL_pushfail(L); /* invalid call (inside a finalizer) */ 255 return 1; 256 } 257 258 259 static int luaB_type (lua_State *L) { 260 int t = lua_type(L, 1); 261 luaL_argcheck(L, t != LUA_TNONE, 1, "value expected"); 262 lua_pushstring(L, lua_typename(L, t)); 263 return 1; 264 } 265 266 267 static int luaB_next (lua_State *L) { 268 luaL_checktype(L, 1, LUA_TTABLE); 269 lua_settop(L, 2); /* create a 2nd argument if there isn't one */ 270 if (lua_next(L, 1)) 271 return 2; 272 else { 273 lua_pushnil(L); 274 return 1; 275 } 276 } 277 278 279 static int pairscont (lua_State *L, int status, lua_KContext k) { 280 (void)L; (void)status; (void)k; /* unused */ 281 return 3; 282 } 283 284 static int luaB_pairs (lua_State *L) { 285 luaL_checkany(L, 1); 286 if (luaL_getmetafield(L, 1, "__pairs") == LUA_TNIL) { /* no metamethod? */ 287 lua_pushcfunction(L, luaB_next); /* will return generator, */ 288 lua_pushvalue(L, 1); /* state, */ 289 lua_pushnil(L); /* and initial value */ 290 } 291 else { 292 lua_pushvalue(L, 1); /* argument 'self' to metamethod */ 293 lua_callk(L, 1, 3, 0, pairscont); /* get 3 values from metamethod */ 294 } 295 return 3; 296 } 297 298 299 /* 300 ** Traversal function for 'ipairs' 301 */ 302 static int ipairsaux (lua_State *L) { 303 lua_Integer i = luaL_checkinteger(L, 2); 304 i = luaL_intop(+, i, 1); 305 lua_pushinteger(L, i); 306 return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2; 307 } 308 309 310 /* 311 ** 'ipairs' function. Returns 'ipairsaux', given "table", 0. 312 ** (The given "table" may not be a table.) 313 */ 314 static int luaB_ipairs (lua_State *L) { 315 luaL_checkany(L, 1); 316 lua_pushcfunction(L, ipairsaux); /* iteration function */ 317 lua_pushvalue(L, 1); /* state */ 318 lua_pushinteger(L, 0); /* initial value */ 319 return 3; 320 } 321 322 323 static int load_aux (lua_State *L, int status, int envidx) { 324 if (l_likely(status == LUA_OK)) { 325 if (envidx != 0) { /* 'env' parameter? */ 326 lua_pushvalue(L, envidx); /* environment for loaded function */ 327 if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */ 328 lua_pop(L, 1); /* remove 'env' if not used by previous call */ 329 } 330 return 1; 331 } 332 else { /* error (message is on top of the stack) */ 333 luaL_pushfail(L); 334 lua_insert(L, -2); /* put before error message */ 335 return 2; /* return fail plus error message */ 336 } 337 } 338 339 340 static int luaB_loadfile (lua_State *L) { 341 const char *fname = luaL_optstring(L, 1, NULL); 342 const char *mode = luaL_optstring(L, 2, NULL); 343 int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */ 344 int status = luaL_loadfilex(L, fname, mode); 345 return load_aux(L, status, env); 346 } 347 348 349 /* 350 ** {====================================================== 351 ** Generic Read function 352 ** ======================================================= 353 */ 354 355 356 /* 357 ** reserved slot, above all arguments, to hold a copy of the returned 358 ** string to avoid it being collected while parsed. 'load' has four 359 ** optional arguments (chunk, source name, mode, and environment). 360 */ 361 #define RESERVEDSLOT 5 362 363 364 /* 365 ** Reader for generic 'load' function: 'lua_load' uses the 366 ** stack for internal stuff, so the reader cannot change the 367 ** stack top. Instead, it keeps its resulting string in a 368 ** reserved slot inside the stack. 369 */ 370 static const char *generic_reader (lua_State *L, void *ud, size_t *size) { 371 (void)(ud); /* not used */ 372 luaL_checkstack(L, 2, "too many nested functions"); 373 lua_pushvalue(L, 1); /* get function */ 374 lua_call(L, 0, 1); /* call it */ 375 if (lua_isnil(L, -1)) { 376 lua_pop(L, 1); /* pop result */ 377 *size = 0; 378 return NULL; 379 } 380 else if (l_unlikely(!lua_isstring(L, -1))) 381 luaL_error(L, "reader function must return a string"); 382 lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */ 383 return lua_tolstring(L, RESERVEDSLOT, size); 384 } 385 386 387 static int luaB_load (lua_State *L) { 388 int status; 389 size_t l; 390 const char *s = lua_tolstring(L, 1, &l); 391 const char *mode = luaL_optstring(L, 3, "bt"); 392 int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */ 393 if (s != NULL) { /* loading a string? */ 394 const char *chunkname = luaL_optstring(L, 2, s); 395 status = luaL_loadbufferx(L, s, l, chunkname, mode); 396 } 397 else { /* loading from a reader function */ 398 const char *chunkname = luaL_optstring(L, 2, "=(load)"); 399 luaL_checktype(L, 1, LUA_TFUNCTION); 400 lua_settop(L, RESERVEDSLOT); /* create reserved slot */ 401 status = lua_load(L, generic_reader, NULL, chunkname, mode); 402 } 403 return load_aux(L, status, env); 404 } 405 406 /* }====================================================== */ 407 408 409 static int dofilecont (lua_State *L, int d1, lua_KContext d2) { 410 (void)d1; (void)d2; /* only to match 'lua_Kfunction' prototype */ 411 return lua_gettop(L) - 1; 412 } 413 414 415 static int luaB_dofile (lua_State *L) { 416 const char *fname = luaL_optstring(L, 1, NULL); 417 lua_settop(L, 1); 418 if (l_unlikely(luaL_loadfile(L, fname) != LUA_OK)) 419 return lua_error(L); 420 lua_callk(L, 0, LUA_MULTRET, 0, dofilecont); 421 return dofilecont(L, 0, 0); 422 } 423 424 425 static int luaB_assert (lua_State *L) { 426 if (l_likely(lua_toboolean(L, 1))) /* condition is true? */ 427 return lua_gettop(L); /* return all arguments */ 428 else { /* error */ 429 luaL_checkany(L, 1); /* there must be a condition */ 430 lua_remove(L, 1); /* remove it */ 431 lua_pushliteral(L, "assertion failed!"); /* default message */ 432 lua_settop(L, 1); /* leave only message (default if no other one) */ 433 return luaB_error(L); /* call 'error' */ 434 } 435 } 436 437 438 static int luaB_select (lua_State *L) { 439 int n = lua_gettop(L); 440 if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') { 441 lua_pushinteger(L, n-1); 442 return 1; 443 } 444 else { 445 lua_Integer i = luaL_checkinteger(L, 1); 446 if (i < 0) i = n + i; 447 else if (i > n) i = n; 448 luaL_argcheck(L, 1 <= i, 1, "index out of range"); 449 return n - (int)i; 450 } 451 } 452 453 454 /* 455 ** Continuation function for 'pcall' and 'xpcall'. Both functions 456 ** already pushed a 'true' before doing the call, so in case of success 457 ** 'finishpcall' only has to return everything in the stack minus 458 ** 'extra' values (where 'extra' is exactly the number of items to be 459 ** ignored). 460 */ 461 static int finishpcall (lua_State *L, int status, lua_KContext extra) { 462 if (l_unlikely(status != LUA_OK && status != LUA_YIELD)) { /* error? */ 463 lua_pushboolean(L, 0); /* first result (false) */ 464 lua_pushvalue(L, -2); /* error message */ 465 return 2; /* return false, msg */ 466 } 467 else 468 return lua_gettop(L) - (int)extra; /* return all results */ 469 } 470 471 472 static int luaB_pcall (lua_State *L) { 473 int status; 474 luaL_checkany(L, 1); 475 lua_pushboolean(L, 1); /* first result if no errors */ 476 lua_insert(L, 1); /* put it in place */ 477 status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, finishpcall); 478 return finishpcall(L, status, 0); 479 } 480 481 482 /* 483 ** Do a protected call with error handling. After 'lua_rotate', the 484 ** stack will have <f, err, true, f, [args...]>; so, the function passes 485 ** 2 to 'finishpcall' to skip the 2 first values when returning results. 486 */ 487 static int luaB_xpcall (lua_State *L) { 488 int status; 489 int n = lua_gettop(L); 490 luaL_checktype(L, 2, LUA_TFUNCTION); /* check error function */ 491 lua_pushboolean(L, 1); /* first result */ 492 lua_pushvalue(L, 1); /* function */ 493 lua_rotate(L, 3, 2); /* move them below function's arguments */ 494 status = lua_pcallk(L, n - 2, LUA_MULTRET, 2, 2, finishpcall); 495 return finishpcall(L, status, 2); 496 } 497 498 499 static int luaB_tostring (lua_State *L) { 500 luaL_checkany(L, 1); 501 luaL_tolstring(L, 1, NULL); 502 return 1; 503 } 504 505 506 static const luaL_Reg base_funcs[] = { 507 {"assert", luaB_assert}, 508 {"collectgarbage", luaB_collectgarbage}, 509 {"dofile", luaB_dofile}, 510 {"error", luaB_error}, 511 {"getmetatable", luaB_getmetatable}, 512 {"ipairs", luaB_ipairs}, 513 {"loadfile", luaB_loadfile}, 514 {"load", luaB_load}, 515 {"next", luaB_next}, 516 {"pairs", luaB_pairs}, 517 {"pcall", luaB_pcall}, 518 {"print", luaB_print}, 519 {"warn", luaB_warn}, 520 {"rawequal", luaB_rawequal}, 521 {"rawlen", luaB_rawlen}, 522 {"rawget", luaB_rawget}, 523 {"rawset", luaB_rawset}, 524 {"select", luaB_select}, 525 {"setmetatable", luaB_setmetatable}, 526 {"tonumber", luaB_tonumber}, 527 {"tostring", luaB_tostring}, 528 {"type", luaB_type}, 529 {"xpcall", luaB_xpcall}, 530 /* placeholders */ 531 {LUA_GNAME, NULL}, 532 {"_VERSION", NULL}, 533 {NULL, NULL} 534 }; 535 536 537 LUAMOD_API int luaopen_base (lua_State *L) { 538 /* open lib into global table */ 539 lua_pushglobaltable(L); 540 luaL_setfuncs(L, base_funcs, 0); 541 /* set global _G */ 542 lua_pushvalue(L, -1); 543 lua_setfield(L, -2, LUA_GNAME); 544 /* set global _VERSION */ 545 lua_pushliteral(L, LUA_VERSION); 546 lua_setfield(L, -2, "_VERSION"); 547 return 1; 548 } 549 550