rlm@1: /* rlm@1: ** $Id: lbaselib.c,v 1.191.1.6 2008/02/14 16:46:22 roberto Exp $ rlm@1: ** Basic library rlm@1: ** See Copyright Notice in lua.h rlm@1: */ rlm@1: rlm@1: rlm@1: rlm@1: #include rlm@1: #include rlm@1: #include rlm@1: #include rlm@1: rlm@1: #define lbaselib_c rlm@1: #define LUA_LIB rlm@1: rlm@1: #include "lua.h" rlm@1: rlm@1: #include "lauxlib.h" rlm@1: #include "lualib.h" rlm@1: rlm@1: rlm@1: rlm@1: rlm@1: /* rlm@1: ** If your system does not support `stdout', you can just remove this function. rlm@1: ** If you need, you can define your own `print' function, following this rlm@1: ** model but changing `fputs' to put the strings at a proper place rlm@1: ** (a console window or a log file, for instance). rlm@1: */ rlm@1: static int luaB_print (lua_State *L) { rlm@1: int n = lua_gettop(L); /* number of arguments */ rlm@1: int i; rlm@1: lua_getglobal(L, "tostring"); rlm@1: for (i=1; i<=n; i++) { rlm@1: const char *s; rlm@1: lua_pushvalue(L, -1); /* function to be called */ rlm@1: lua_pushvalue(L, i); /* value to print */ rlm@1: lua_call(L, 1, 1); rlm@1: s = lua_tostring(L, -1); /* get result */ rlm@1: if (s == NULL) rlm@1: return luaL_error(L, LUA_QL("tostring") " must return a string to " rlm@1: LUA_QL("print")); rlm@1: if (i>1) fputs("\t", stdout); rlm@1: fputs(s, stdout); rlm@1: lua_pop(L, 1); /* pop result */ rlm@1: } rlm@1: fputs("\n", stdout); rlm@1: return 0; rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_tonumber (lua_State *L) { rlm@1: int base = luaL_optint(L, 2, 10); rlm@1: if (base == 10) { /* standard conversion */ rlm@1: luaL_checkany(L, 1); rlm@1: if (lua_isnumber(L, 1)) { rlm@1: lua_pushnumber(L, lua_tonumber(L, 1)); rlm@1: return 1; rlm@1: } rlm@1: } rlm@1: else { rlm@1: const char *s1 = luaL_checkstring(L, 1); rlm@1: char *s2; rlm@1: unsigned long n; rlm@1: luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); rlm@1: n = strtoul(s1, &s2, base); rlm@1: if (s1 != s2) { /* at least one valid digit? */ rlm@1: while (isspace((unsigned char)(*s2))) s2++; /* skip trailing spaces */ rlm@1: if (*s2 == '\0') { /* no invalid trailing characters? */ rlm@1: lua_pushnumber(L, (lua_Number)n); rlm@1: return 1; rlm@1: } rlm@1: } rlm@1: } rlm@1: lua_pushnil(L); /* else not a number */ rlm@1: return 1; rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_error (lua_State *L) { rlm@1: int level = luaL_optint(L, 2, 1); rlm@1: lua_settop(L, 1); rlm@1: if (lua_isstring(L, 1) && level > 0) { /* add extra information? */ rlm@1: luaL_where(L, level); rlm@1: lua_pushvalue(L, 1); rlm@1: lua_concat(L, 2); rlm@1: } rlm@1: return lua_error(L); rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_getmetatable (lua_State *L) { rlm@1: luaL_checkany(L, 1); rlm@1: if (!lua_getmetatable(L, 1)) { rlm@1: lua_pushnil(L); rlm@1: return 1; /* no metatable */ rlm@1: } rlm@1: luaL_getmetafield(L, 1, "__metatable"); rlm@1: return 1; /* returns either __metatable field (if present) or metatable */ rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_setmetatable (lua_State *L) { rlm@1: int t = lua_type(L, 2); rlm@1: luaL_checktype(L, 1, LUA_TTABLE); rlm@1: luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, rlm@1: "nil or table expected"); rlm@1: if (luaL_getmetafield(L, 1, "__metatable")) rlm@1: luaL_error(L, "cannot change a protected metatable"); rlm@1: lua_settop(L, 2); rlm@1: lua_setmetatable(L, 1); rlm@1: return 1; rlm@1: } rlm@1: rlm@1: rlm@1: static void getfunc (lua_State *L, int opt) { rlm@1: if (lua_isfunction(L, 1)) lua_pushvalue(L, 1); rlm@1: else { rlm@1: lua_Debug ar; rlm@1: int level = opt ? luaL_optint(L, 1, 1) : luaL_checkint(L, 1); rlm@1: luaL_argcheck(L, level >= 0, 1, "level must be non-negative"); rlm@1: if (lua_getstack(L, level, &ar) == 0) rlm@1: luaL_argerror(L, 1, "invalid level"); rlm@1: lua_getinfo(L, "f", &ar); rlm@1: if (lua_isnil(L, -1)) rlm@1: luaL_error(L, "no function environment for tail call at level %d", rlm@1: level); rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_getfenv (lua_State *L) { rlm@1: getfunc(L, 1); rlm@1: if (lua_iscfunction(L, -1)) /* is a C function? */ rlm@1: lua_pushvalue(L, LUA_GLOBALSINDEX); /* return the thread's global env. */ rlm@1: else rlm@1: lua_getfenv(L, -1); rlm@1: return 1; rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_setfenv (lua_State *L) { rlm@1: luaL_checktype(L, 2, LUA_TTABLE); rlm@1: getfunc(L, 0); rlm@1: lua_pushvalue(L, 2); rlm@1: if (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0) { rlm@1: /* change environment of current thread */ rlm@1: lua_pushthread(L); rlm@1: lua_insert(L, -2); rlm@1: lua_setfenv(L, -2); rlm@1: return 0; rlm@1: } rlm@1: else if (lua_iscfunction(L, -2) || lua_setfenv(L, -2) == 0) rlm@1: luaL_error(L, rlm@1: LUA_QL("setfenv") " cannot change environment of given object"); rlm@1: return 1; rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_rawequal (lua_State *L) { rlm@1: luaL_checkany(L, 1); rlm@1: luaL_checkany(L, 2); rlm@1: lua_pushboolean(L, lua_rawequal(L, 1, 2)); rlm@1: return 1; rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_rawget (lua_State *L) { rlm@1: luaL_checktype(L, 1, LUA_TTABLE); rlm@1: luaL_checkany(L, 2); rlm@1: lua_settop(L, 2); rlm@1: lua_rawget(L, 1); rlm@1: return 1; rlm@1: } rlm@1: rlm@1: static int luaB_rawset (lua_State *L) { rlm@1: luaL_checktype(L, 1, LUA_TTABLE); rlm@1: luaL_checkany(L, 2); rlm@1: luaL_checkany(L, 3); rlm@1: lua_settop(L, 3); rlm@1: lua_rawset(L, 1); rlm@1: return 1; rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_gcinfo (lua_State *L) { rlm@1: lua_pushinteger(L, lua_getgccount(L)); rlm@1: return 1; rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_collectgarbage (lua_State *L) { rlm@1: static const char *const opts[] = {"stop", "restart", "collect", rlm@1: "count", "step", "setpause", "setstepmul", NULL}; rlm@1: static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, rlm@1: LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL}; rlm@1: int o = luaL_checkoption(L, 1, "collect", opts); rlm@1: int ex = luaL_optint(L, 2, 0); rlm@1: int res = lua_gc(L, optsnum[o], ex); rlm@1: switch (optsnum[o]) { rlm@1: case LUA_GCCOUNT: { rlm@1: int b = lua_gc(L, LUA_GCCOUNTB, 0); rlm@1: lua_pushnumber(L, res + ((lua_Number)b/1024)); rlm@1: return 1; rlm@1: } rlm@1: case LUA_GCSTEP: { rlm@1: lua_pushboolean(L, res); rlm@1: return 1; rlm@1: } rlm@1: default: { rlm@1: lua_pushnumber(L, res); rlm@1: return 1; rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_type (lua_State *L) { rlm@1: luaL_checkany(L, 1); rlm@1: lua_pushstring(L, luaL_typename(L, 1)); rlm@1: return 1; rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_next (lua_State *L) { rlm@1: luaL_checktype(L, 1, LUA_TTABLE); rlm@1: lua_settop(L, 2); /* create a 2nd argument if there isn't one */ rlm@1: if (lua_next(L, 1)) rlm@1: return 2; rlm@1: else { rlm@1: lua_pushnil(L); rlm@1: return 1; rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_pairs (lua_State *L) { rlm@1: luaL_checktype(L, 1, LUA_TTABLE); rlm@1: lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */ rlm@1: lua_pushvalue(L, 1); /* state, */ rlm@1: lua_pushnil(L); /* and initial value */ rlm@1: return 3; rlm@1: } rlm@1: rlm@1: rlm@1: static int ipairsaux (lua_State *L) { rlm@1: int i = luaL_checkint(L, 2); rlm@1: luaL_checktype(L, 1, LUA_TTABLE); rlm@1: i++; /* next value */ rlm@1: lua_pushinteger(L, i); rlm@1: lua_rawgeti(L, 1, i); rlm@1: return (lua_isnil(L, -1)) ? 0 : 2; rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_ipairs (lua_State *L) { rlm@1: luaL_checktype(L, 1, LUA_TTABLE); rlm@1: lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */ rlm@1: lua_pushvalue(L, 1); /* state, */ rlm@1: lua_pushinteger(L, 0); /* and initial value */ rlm@1: return 3; rlm@1: } rlm@1: rlm@1: rlm@1: static int load_aux (lua_State *L, int status) { rlm@1: if (status == 0) /* OK? */ rlm@1: return 1; rlm@1: else { rlm@1: lua_pushnil(L); rlm@1: lua_insert(L, -2); /* put before error message */ rlm@1: return 2; /* return nil plus error message */ rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_loadstring (lua_State *L) { rlm@1: size_t l; rlm@1: const char *s = luaL_checklstring(L, 1, &l); rlm@1: const char *chunkname = luaL_optstring(L, 2, s); rlm@1: return load_aux(L, luaL_loadbuffer(L, s, l, chunkname)); rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_loadfile (lua_State *L) { rlm@1: const char *fname = luaL_optstring(L, 1, NULL); rlm@1: return load_aux(L, luaL_loadfile(L, fname)); rlm@1: } rlm@1: rlm@1: rlm@1: /* rlm@1: ** Reader for generic `load' function: `lua_load' uses the rlm@1: ** stack for internal stuff, so the reader cannot change the rlm@1: ** stack top. Instead, it keeps its resulting string in a rlm@1: ** reserved slot inside the stack. rlm@1: */ rlm@1: static const char *generic_reader (lua_State *L, void *ud, size_t *size) { rlm@1: (void)ud; /* to avoid warnings */ rlm@1: luaL_checkstack(L, 2, "too many nested functions"); rlm@1: lua_pushvalue(L, 1); /* get function */ rlm@1: lua_call(L, 0, 1); /* call it */ rlm@1: if (lua_isnil(L, -1)) { rlm@1: *size = 0; rlm@1: return NULL; rlm@1: } rlm@1: else if (lua_isstring(L, -1)) { rlm@1: lua_replace(L, 3); /* save string in a reserved stack slot */ rlm@1: return lua_tolstring(L, 3, size); rlm@1: } rlm@1: else luaL_error(L, "reader function must return a string"); rlm@1: return NULL; /* to avoid warnings */ rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_load (lua_State *L) { rlm@1: int status; rlm@1: const char *cname = luaL_optstring(L, 2, "=(load)"); rlm@1: luaL_checktype(L, 1, LUA_TFUNCTION); rlm@1: lua_settop(L, 3); /* function, eventual name, plus one reserved slot */ rlm@1: status = lua_load(L, generic_reader, NULL, cname); rlm@1: return load_aux(L, status); rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_dofile (lua_State *L) { rlm@1: const char *fname = luaL_optstring(L, 1, NULL); rlm@1: int n = lua_gettop(L); rlm@1: if (luaL_loadfile(L, fname) != 0) lua_error(L); rlm@1: lua_call(L, 0, LUA_MULTRET); rlm@1: return lua_gettop(L) - n; rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_assert (lua_State *L) { rlm@1: luaL_checkany(L, 1); rlm@1: if (!lua_toboolean(L, 1)) rlm@1: return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!")); rlm@1: return lua_gettop(L); rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_unpack (lua_State *L) { rlm@1: int i, e, n; rlm@1: luaL_checktype(L, 1, LUA_TTABLE); rlm@1: i = luaL_optint(L, 2, 1); rlm@1: e = luaL_opt(L, luaL_checkint, 3, luaL_getn(L, 1)); rlm@1: if (i > e) return 0; /* empty range */ rlm@1: n = e - i + 1; /* number of elements */ rlm@1: if (n <= 0 || !lua_checkstack(L, n)) /* n <= 0 means arith. overflow */ rlm@1: return luaL_error(L, "too many results to unpack"); rlm@1: lua_rawgeti(L, 1, i); /* push arg[i] (avoiding overflow problems) */ rlm@1: while (i++ < e) /* push arg[i + 1...e] */ rlm@1: lua_rawgeti(L, 1, i); rlm@1: return n; rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_select (lua_State *L) { rlm@1: int n = lua_gettop(L); rlm@1: if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') { rlm@1: lua_pushinteger(L, n-1); rlm@1: return 1; rlm@1: } rlm@1: else { rlm@1: int i = luaL_checkint(L, 1); rlm@1: if (i < 0) i = n + i; rlm@1: else if (i > n) i = n; rlm@1: luaL_argcheck(L, 1 <= i, 1, "index out of range"); rlm@1: return n - i; rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_pcall (lua_State *L) { rlm@1: int status; rlm@1: luaL_checkany(L, 1); rlm@1: status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0); rlm@1: lua_pushboolean(L, (status == 0)); rlm@1: lua_insert(L, 1); rlm@1: return lua_gettop(L); /* return status + all results */ rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_xpcall (lua_State *L) { rlm@1: int status; rlm@1: luaL_checkany(L, 2); rlm@1: lua_settop(L, 2); rlm@1: lua_insert(L, 1); /* put error function under function to be called */ rlm@1: status = lua_pcall(L, 0, LUA_MULTRET, 1); rlm@1: lua_pushboolean(L, (status == 0)); rlm@1: lua_replace(L, 1); rlm@1: return lua_gettop(L); /* return status + all results */ rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_tostring (lua_State *L) { rlm@1: luaL_checkany(L, 1); rlm@1: if (luaL_callmeta(L, 1, "__tostring")) /* is there a metafield? */ rlm@1: return 1; /* use its value */ rlm@1: switch (lua_type(L, 1)) { rlm@1: case LUA_TNUMBER: rlm@1: lua_pushstring(L, lua_tostring(L, 1)); rlm@1: break; rlm@1: case LUA_TSTRING: rlm@1: lua_pushvalue(L, 1); rlm@1: break; rlm@1: case LUA_TBOOLEAN: rlm@1: lua_pushstring(L, (lua_toboolean(L, 1) ? "true" : "false")); rlm@1: break; rlm@1: case LUA_TNIL: rlm@1: lua_pushliteral(L, "nil"); rlm@1: break; rlm@1: default: rlm@1: lua_pushfstring(L, "%s: %p", luaL_typename(L, 1), lua_topointer(L, 1)); rlm@1: break; rlm@1: } rlm@1: return 1; rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_newproxy (lua_State *L) { rlm@1: lua_settop(L, 1); rlm@1: lua_newuserdata(L, 0); /* create proxy */ rlm@1: if (lua_toboolean(L, 1) == 0) rlm@1: return 1; /* no metatable */ rlm@1: else if (lua_isboolean(L, 1)) { rlm@1: lua_newtable(L); /* create a new metatable `m' ... */ rlm@1: lua_pushvalue(L, -1); /* ... and mark `m' as a valid metatable */ rlm@1: lua_pushboolean(L, 1); rlm@1: lua_rawset(L, lua_upvalueindex(1)); /* weaktable[m] = true */ rlm@1: } rlm@1: else { rlm@1: int validproxy = 0; /* to check if weaktable[metatable(u)] == true */ rlm@1: if (lua_getmetatable(L, 1)) { rlm@1: lua_rawget(L, lua_upvalueindex(1)); rlm@1: validproxy = lua_toboolean(L, -1); rlm@1: lua_pop(L, 1); /* remove value */ rlm@1: } rlm@1: luaL_argcheck(L, validproxy, 1, "boolean or proxy expected"); rlm@1: lua_getmetatable(L, 1); /* metatable is valid; get it */ rlm@1: } rlm@1: lua_setmetatable(L, 2); rlm@1: return 1; rlm@1: } rlm@1: rlm@1: rlm@1: static const luaL_Reg base_funcs[] = { rlm@1: {"assert", luaB_assert}, rlm@1: {"collectgarbage", luaB_collectgarbage}, rlm@1: {"dofile", luaB_dofile}, rlm@1: {"error", luaB_error}, rlm@1: {"gcinfo", luaB_gcinfo}, rlm@1: {"getfenv", luaB_getfenv}, rlm@1: {"getmetatable", luaB_getmetatable}, rlm@1: {"loadfile", luaB_loadfile}, rlm@1: {"load", luaB_load}, rlm@1: {"loadstring", luaB_loadstring}, rlm@1: {"next", luaB_next}, rlm@1: {"pcall", luaB_pcall}, rlm@1: {"print", luaB_print}, rlm@1: {"rawequal", luaB_rawequal}, rlm@1: {"rawget", luaB_rawget}, rlm@1: {"rawset", luaB_rawset}, rlm@1: {"select", luaB_select}, rlm@1: {"setfenv", luaB_setfenv}, rlm@1: {"setmetatable", luaB_setmetatable}, rlm@1: {"tonumber", luaB_tonumber}, rlm@1: {"tostring", luaB_tostring}, rlm@1: {"type", luaB_type}, rlm@1: {"unpack", luaB_unpack}, rlm@1: {"xpcall", luaB_xpcall}, rlm@1: {NULL, NULL} rlm@1: }; rlm@1: rlm@1: rlm@1: /* rlm@1: ** {====================================================== rlm@1: ** Coroutine library rlm@1: ** ======================================================= rlm@1: */ rlm@1: rlm@1: #define CO_RUN 0 /* running */ rlm@1: #define CO_SUS 1 /* suspended */ rlm@1: #define CO_NOR 2 /* 'normal' (it resumed another coroutine) */ rlm@1: #define CO_DEAD 3 rlm@1: rlm@1: static const char *const statnames[] = rlm@1: {"running", "suspended", "normal", "dead"}; rlm@1: rlm@1: static int costatus (lua_State *L, lua_State *co) { rlm@1: if (L == co) return CO_RUN; rlm@1: switch (lua_status(co)) { rlm@1: case LUA_YIELD: rlm@1: return CO_SUS; rlm@1: case 0: { rlm@1: lua_Debug ar; rlm@1: if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */ rlm@1: return CO_NOR; /* it is running */ rlm@1: else if (lua_gettop(co) == 0) rlm@1: return CO_DEAD; rlm@1: else rlm@1: return CO_SUS; /* initial state */ rlm@1: } rlm@1: default: /* some error occured */ rlm@1: return CO_DEAD; rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_costatus (lua_State *L) { rlm@1: lua_State *co = lua_tothread(L, 1); rlm@1: luaL_argcheck(L, co, 1, "coroutine expected"); rlm@1: lua_pushstring(L, statnames[costatus(L, co)]); rlm@1: return 1; rlm@1: } rlm@1: rlm@1: rlm@1: static int auxresume (lua_State *L, lua_State *co, int narg) { rlm@1: int status = costatus(L, co); rlm@1: if (!lua_checkstack(co, narg)) rlm@1: luaL_error(L, "too many arguments to resume"); rlm@1: if (status != CO_SUS) { rlm@1: lua_pushfstring(L, "cannot resume %s coroutine", statnames[status]); rlm@1: return -1; /* error flag */ rlm@1: } rlm@1: lua_xmove(L, co, narg); rlm@1: lua_setlevel(L, co); rlm@1: status = lua_resume(co, narg); rlm@1: if (status == 0 || status == LUA_YIELD) { rlm@1: int nres = lua_gettop(co); rlm@1: if (!lua_checkstack(L, nres + 1)) rlm@1: luaL_error(L, "too many results to resume"); rlm@1: lua_xmove(co, L, nres); /* move yielded values */ rlm@1: return nres; rlm@1: } rlm@1: else { rlm@1: lua_xmove(co, L, 1); /* move error message */ rlm@1: return -1; /* error flag */ rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_coresume (lua_State *L) { rlm@1: lua_State *co = lua_tothread(L, 1); rlm@1: int r; rlm@1: luaL_argcheck(L, co, 1, "coroutine expected"); rlm@1: r = auxresume(L, co, lua_gettop(L) - 1); rlm@1: if (r < 0) { rlm@1: lua_pushboolean(L, 0); rlm@1: lua_insert(L, -2); rlm@1: return 2; /* return false + error message */ rlm@1: } rlm@1: else { rlm@1: lua_pushboolean(L, 1); rlm@1: lua_insert(L, -(r + 1)); rlm@1: return r + 1; /* return true + `resume' returns */ rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_auxwrap (lua_State *L) { rlm@1: lua_State *co = lua_tothread(L, lua_upvalueindex(1)); rlm@1: int r = auxresume(L, co, lua_gettop(L)); rlm@1: if (r < 0) { rlm@1: if (lua_isstring(L, -1)) { /* error object is a string? */ rlm@1: luaL_where(L, 1); /* add extra info */ rlm@1: lua_insert(L, -2); rlm@1: lua_concat(L, 2); rlm@1: } rlm@1: lua_error(L); /* propagate error */ rlm@1: } rlm@1: return r; rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_cocreate (lua_State *L) { rlm@1: lua_State *NL = lua_newthread(L); rlm@1: luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, rlm@1: "Lua function expected"); rlm@1: lua_pushvalue(L, 1); /* move function to top */ rlm@1: lua_xmove(L, NL, 1); /* move function from L to NL */ rlm@1: return 1; rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_cowrap (lua_State *L) { rlm@1: luaB_cocreate(L); rlm@1: lua_pushcclosure(L, luaB_auxwrap, 1); rlm@1: return 1; rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_yield (lua_State *L) { rlm@1: return lua_yield(L, lua_gettop(L)); rlm@1: } rlm@1: rlm@1: rlm@1: static int luaB_corunning (lua_State *L) { rlm@1: if (lua_pushthread(L)) rlm@1: lua_pushnil(L); /* main thread is not a coroutine */ rlm@1: return 1; rlm@1: } rlm@1: rlm@1: rlm@1: static const luaL_Reg co_funcs[] = { rlm@1: {"create", luaB_cocreate}, rlm@1: {"resume", luaB_coresume}, rlm@1: {"running", luaB_corunning}, rlm@1: {"status", luaB_costatus}, rlm@1: {"wrap", luaB_cowrap}, rlm@1: {"yield", luaB_yield}, rlm@1: {NULL, NULL} rlm@1: }; rlm@1: rlm@1: /* }====================================================== */ rlm@1: rlm@1: rlm@1: static void auxopen (lua_State *L, const char *name, rlm@1: lua_CFunction f, lua_CFunction u) { rlm@1: lua_pushcfunction(L, u); rlm@1: lua_pushcclosure(L, f, 1); rlm@1: lua_setfield(L, -2, name); rlm@1: } rlm@1: rlm@1: rlm@1: static void base_open (lua_State *L) { rlm@1: /* set global _G */ rlm@1: lua_pushvalue(L, LUA_GLOBALSINDEX); rlm@1: lua_setglobal(L, "_G"); rlm@1: /* open lib into global table */ rlm@1: luaL_register(L, "_G", base_funcs); rlm@1: lua_pushliteral(L, LUA_VERSION); rlm@1: lua_setglobal(L, "_VERSION"); /* set global _VERSION */ rlm@1: /* `ipairs' and `pairs' need auxliliary functions as upvalues */ rlm@1: auxopen(L, "ipairs", luaB_ipairs, ipairsaux); rlm@1: auxopen(L, "pairs", luaB_pairs, luaB_next); rlm@1: /* `newproxy' needs a weaktable as upvalue */ rlm@1: lua_createtable(L, 0, 1); /* new table `w' */ rlm@1: lua_pushvalue(L, -1); /* `w' will be its own metatable */ rlm@1: lua_setmetatable(L, -2); rlm@1: lua_pushliteral(L, "kv"); rlm@1: lua_setfield(L, -2, "__mode"); /* metatable(w).__mode = "kv" */ rlm@1: lua_pushcclosure(L, luaB_newproxy, 1); rlm@1: lua_setglobal(L, "newproxy"); /* set global `newproxy' */ rlm@1: } rlm@1: rlm@1: rlm@1: LUALIB_API int luaopen_base (lua_State *L) { rlm@1: base_open(L); rlm@1: luaL_register(L, LUA_COLIBNAME, co_funcs); rlm@1: return 2; rlm@1: } rlm@1: