diff options
Diffstat (limited to 'src/lib/lbaselib.c')
-rw-r--r-- | src/lib/lbaselib.c | 296 |
1 files changed, 120 insertions, 176 deletions
diff --git a/src/lib/lbaselib.c b/src/lib/lbaselib.c index 42b0355a..f734f358 100644 --- a/src/lib/lbaselib.c +++ b/src/lib/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.140 2004/03/09 17:34:35 roberto Exp $ +** $Id: lbaselib.c,v 1.156 2004/08/30 18:35:14 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -12,6 +12,7 @@ #include <string.h> #define lbaselib_c +#define LUA_LIB #include "lua.h" @@ -128,18 +129,9 @@ static void getfunc (lua_State *L) { } -static int aux_getfenv (lua_State *L) { - lua_getfenv(L, -1); - lua_pushliteral(L, "__fenv"); - lua_rawget(L, -2); - return !lua_isnil(L, -1); -} - - static int luaB_getfenv (lua_State *L) { getfunc(L); - if (!aux_getfenv(L)) /* __fenv not defined? */ - lua_pop(L, 1); /* remove it, to return real environment */ + lua_getfenv(L, -1); return 1; } @@ -147,16 +139,14 @@ static int luaB_getfenv (lua_State *L) { static int luaB_setfenv (lua_State *L) { luaL_checktype(L, 2, LUA_TTABLE); getfunc(L); - if (aux_getfenv(L)) /* __fenv defined? */ - luaL_error(L, "`setfenv' cannot change a protected environment"); - else - lua_pop(L, 2); /* remove __fenv and real environment table */ lua_pushvalue(L, 2); - if (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0) + if (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0) { lua_replace(L, LUA_GLOBALSINDEX); + return 0; + } else if (lua_setfenv(L, -2) == 0) luaL_error(L, "`setfenv' cannot change environment of given function"); - return 0; + return 1; } @@ -192,22 +182,11 @@ static int luaB_gcinfo (lua_State *L) { static int luaB_collectgarbage (lua_State *L) { static const char *const opts[] = {"stop", "restart", "collect", "count", - NULL}; + "step", NULL}; static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, - LUA_GCCOLLECT, LUA_GCCOUNT}; - int o; - int ex; -#if 1 - if (lua_isnumber(L, 1)) { - int v = lua_tointeger(L, 1); - lua_settop(L, 0); - if (v == 0) lua_pushstring(L, "collect"); - else if (v >= 10000) lua_pushstring(L, "stop"); - else lua_pushstring(L, "restart"); - } -#endif - o = luaL_findstring(luaL_optstring(L, 1, "collect"), opts); - ex = luaL_optint(L, 2, 0); + LUA_GCCOLLECT, LUA_GCCOUNT, LUA_GCSTEP}; + int o = luaL_findstring(luaL_optstring(L, 1, "collect"), opts); + int ex = luaL_optint(L, 2, 0); luaL_argcheck(L, o >= 0, 1, "invalid option"); lua_pushinteger(L, lua_gc(L, optsnum[o], ex)); return 1; @@ -216,7 +195,7 @@ static int luaB_collectgarbage (lua_State *L) { static int luaB_type (lua_State *L) { luaL_checkany(L, 1); - lua_pushstring(L, lua_typename(L, lua_type(L, 1))); + lua_pushstring(L, luaL_typename(L, 1)); return 1; } @@ -235,28 +214,29 @@ static int luaB_next (lua_State *L) { static int luaB_pairs (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); - lua_getglobal(L, "next"); /* return generator, */ + lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */ lua_pushvalue(L, 1); /* state, */ lua_pushnil(L); /* and initial value */ return 3; } +static int ipairsaux (lua_State *L) { + int i = luaL_checkint(L, 2); + luaL_checktype(L, 1, LUA_TTABLE); + i++; /* next value */ + lua_pushinteger(L, i); + lua_rawgeti(L, 1, i); + return (lua_isnil(L, -1)) ? 0 : 2; +} + + static int luaB_ipairs (lua_State *L) { - int i = (int)lua_tointeger(L, 2); luaL_checktype(L, 1, LUA_TTABLE); - if (i == 0 && lua_isnone(L, 2)) { /* `for' start? */ - lua_getglobal(L, "ipairs"); /* return generator, */ - lua_pushvalue(L, 1); /* state, */ - lua_pushinteger(L, 0); /* and initial value */ - return 3; - } - else { /* `for' step */ - i++; /* next value */ - lua_pushinteger(L, i); - lua_rawgeti(L, 1, i); - return (lua_isnil(L, -1)) ? 0 : 2; - } + lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */ + lua_pushvalue(L, 1); /* state, */ + lua_pushinteger(L, LUA_FIRSTINDEX - 1); /* and initial value */ + return 3; } @@ -281,7 +261,15 @@ static int luaB_loadstring (lua_State *L) { static int luaB_loadfile (lua_State *L) { const char *fname = luaL_optstring(L, 1, NULL); - return load_aux(L, luaL_loadfile(L, fname)); + const char *path = luaL_optstring(L, 2, NULL); + int status; + if (path == NULL) + status = luaL_loadfile(L, fname); + else { + fname = luaL_searchpath(L, fname, path); + status = (fname) ? luaL_loadfile(L, fname) : 1; + } + return load_aux(L, status); } @@ -339,22 +327,41 @@ static int luaB_assert (lua_State *L) { luaL_checkany(L, 1); if (!lua_toboolean(L, 1)) return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!")); - lua_settop(L, 1); - return 1; + return lua_gettop(L); } static int luaB_unpack (lua_State *L) { - int n, i; + int i = luaL_optint(L, 2, LUA_FIRSTINDEX); + int e = luaL_optint(L, 3, -1); + int n; luaL_checktype(L, 1, LUA_TTABLE); - n = luaL_getn(L, 1); + if (e == -1) + e = luaL_getn(L, 1) + LUA_FIRSTINDEX - 1; + n = e - i + 1; /* number of elements */ + if (n <= 0) return 0; /* empty range */ luaL_checkstack(L, n, "table too big to unpack"); - for (i=1; i<=n; i++) /* push arg[1...n] */ + for (; i<=e; i++) /* push arg[i...e] */ lua_rawgeti(L, 1, i); return n; } +static int luaB_select (lua_State *L) { + int n = lua_gettop(L); + if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') { + lua_pushinteger(L, n-1); + return 1; + } + else { + int i = luaL_checkint(L, 1); + if (i <= 0) i = 1; + else if (i >= n) i = n; + return n - i; + } +} + + static int luaB_pcall (lua_State *L) { int status; luaL_checkany(L, 1); @@ -378,45 +385,36 @@ static int luaB_xpcall (lua_State *L) { static int luaB_tostring (lua_State *L) { - char buff[4*sizeof(void *) + 2]; /* enough space for a `%p' */ - const char *tn = ""; - const void *p = NULL; luaL_checkany(L, 1); if (luaL_callmeta(L, 1, "__tostring")) /* is there a metafield? */ return 1; /* use its value */ switch (lua_type(L, 1)) { case LUA_TNUMBER: lua_pushstring(L, lua_tostring(L, 1)); - return 1; + break; case LUA_TSTRING: lua_pushvalue(L, 1); - return 1; + break; case LUA_TBOOLEAN: lua_pushstring(L, (lua_toboolean(L, 1) ? "true" : "false")); - return 1; + break; case LUA_TNIL: lua_pushliteral(L, "nil"); - return 1; + break; case LUA_TTABLE: - p = lua_topointer(L, 1); - tn = "table"; + lua_pushfstring(L, "table: %p", lua_topointer(L, 1)); break; case LUA_TFUNCTION: - p = lua_topointer(L, 1); - tn = "function"; + lua_pushfstring(L, "function: %p", lua_topointer(L, 1)); break; case LUA_TUSERDATA: case LUA_TLIGHTUSERDATA: - p = lua_touserdata(L, 1); - tn = "userdata"; + lua_pushfstring(L, "userdata: %p", lua_topointer(L, 1)); break; case LUA_TTHREAD: - p = lua_tothread(L, 1); - tn = "thread"; + lua_pushfstring(L, "thread: %p", lua_topointer(L, 1)); break; } - sprintf(buff, "%p", p); - lua_pushfstring(L, "%s: %s", tn, buff); return 1; } @@ -454,112 +452,38 @@ static int luaB_newproxy (lua_State *L) { */ -/* name of global that holds table with loaded packages */ -#define REQTAB "_LOADED" - -/* name of global that holds the search path for packages */ -#define LUA_PATH "LUA_PATH" - -#ifndef LUA_PATH_SEP -#define LUA_PATH_SEP ';' -#endif - -#ifndef LUA_PATH_MARK -#define LUA_PATH_MARK '?' -#endif - -#ifndef LUA_PATH_DEFAULT -#define LUA_PATH_DEFAULT "?;?.lua" -#endif - - static const char *getpath (lua_State *L) { - const char *path; - lua_getglobal(L, LUA_PATH); /* try global variable */ - path = lua_tostring(L, -1); - lua_pop(L, 1); - if (path) return path; - path = getenv(LUA_PATH); /* else try environment variable */ - if (path) return path; - return LUA_PATH_DEFAULT; /* else use default */ -} - - -static const char *pushnextpath (lua_State *L, const char *path) { - const char *l; - if (*path == '\0') return NULL; /* no more paths */ - if (*path == LUA_PATH_SEP) path++; /* skip separator */ - l = strchr(path, LUA_PATH_SEP); /* find next separator */ - if (l == NULL) l = path+strlen(path); - lua_pushlstring(L, path, l - path); /* directory name */ - return l; -} - - -static void pushcomposename (lua_State *L) { - const char *path = lua_tostring(L, -1); - const char *wild; - int n = 1; - while ((wild = strchr(path, LUA_PATH_MARK)) != NULL) { - /* is there stack space for prefix, name, and eventual last suffix? */ - luaL_checkstack(L, 3, "too many marks in a path component"); - lua_pushlstring(L, path, wild - path); /* push prefix */ - lua_pushvalue(L, 1); /* push package name (in place of MARK) */ - path = wild + 1; /* continue after MARK */ - n += 2; + /* try first `LUA_PATH' for compatibility */ + lua_getfield(L, LUA_GLOBALSINDEX, "LUA_PATH"); + if (!lua_isstring(L, -1)) { + lua_pop(L, 1); + lua_getfield(L, LUA_GLOBALSINDEX, "_PATH"); } - lua_pushstring(L, path); /* push last suffix (`n' already includes this) */ - lua_concat(L, n); + if (!lua_isstring(L, -1)) + luaL_error(L, "global _PATH must be a string"); + return lua_tostring(L, -1); } static int luaB_require (lua_State *L) { - const char *path; - int status = LUA_ERRFILE; /* not found (yet) */ - luaL_checkstring(L, 1); - lua_settop(L, 1); - lua_getglobal(L, REQTAB); - if (!lua_istable(L, 2)) return luaL_error(L, "`" REQTAB "' is not a table"); - path = getpath(L); - lua_pushvalue(L, 1); /* check package's name in book-keeping table */ - lua_rawget(L, 2); + const char *name = luaL_checkstring(L, 1); + const char *fname; + lua_getfield(L, lua_upvalueindex(1), name); if (lua_toboolean(L, -1)) /* is it there? */ return 1; /* package is already loaded; return its result */ - else { /* must load it */ - while (status == LUA_ERRFILE) { - lua_settop(L, 3); /* reset stack position */ - if ((path = pushnextpath(L, path)) == NULL) break; - pushcomposename(L); - status = luaL_loadfile(L, lua_tostring(L, -1)); /* try to load it */ - } - } - switch (status) { - case 0: { - lua_getglobal(L, "_REQUIREDNAME"); /* save previous name */ - lua_insert(L, -2); /* put it below function */ - lua_pushvalue(L, 1); - lua_setglobal(L, "_REQUIREDNAME"); /* set new name */ - lua_call(L, 0, 1); /* run loaded module */ - lua_insert(L, -2); /* put result below previous name */ - lua_setglobal(L, "_REQUIREDNAME"); /* reset to previous name */ - if (lua_isnil(L, -1)) { /* no/nil return? */ - lua_pushboolean(L, 1); - lua_replace(L, -2); /* replace to true */ - } - lua_pushvalue(L, 1); - lua_pushvalue(L, -2); - lua_rawset(L, 2); /* mark it as loaded */ - return 1; /* return value */ - } - case LUA_ERRFILE: { /* file not found */ - return luaL_error(L, "could not load package `%s' from path `%s'", - lua_tostring(L, 1), getpath(L)); - } - default: { - return luaL_error(L, "error loading package `%s' (%s)", - lua_tostring(L, 1), lua_tostring(L, -1)); - } - } + /* else must load it; first mark it as loaded */ + lua_pushboolean(L, 1); + lua_setfield(L, lua_upvalueindex(1), name); /* _LOADED[name] = true */ + fname = luaL_searchpath(L, name, getpath(L)); + if (fname == NULL || luaL_loadfile(L, fname) != 0) + return luaL_error(L, "error loading package `%s' (%s)", name, + lua_tostring(L, -1)); + lua_pushvalue(L, 1); /* pass name as argument to module */ + lua_call(L, 1, 1); /* run loaded module */ + if (!lua_isnil(L, -1)) /* nil return? */ + lua_setfield(L, lua_upvalueindex(1), name); + lua_getfield(L, lua_upvalueindex(1), name); /* return _LOADED[name] */ + return 1; } /* }====================================================== */ @@ -572,14 +496,13 @@ static const luaL_reg base_funcs[] = { {"getfenv", luaB_getfenv}, {"setfenv", luaB_setfenv}, {"next", luaB_next}, - {"ipairs", luaB_ipairs}, - {"pairs", luaB_pairs}, {"print", luaB_print}, {"tonumber", luaB_tonumber}, {"tostring", luaB_tostring}, {"type", luaB_type}, {"assert", luaB_assert}, {"unpack", luaB_unpack}, + {"select", luaB_select}, {"rawequal", luaB_rawequal}, {"rawget", luaB_rawget}, {"rawset", luaB_rawset}, @@ -591,7 +514,6 @@ static const luaL_reg base_funcs[] = { {"dofile", luaB_dofile}, {"loadstring", luaB_loadstring}, {"load", luaB_load}, - {"require", luaB_require}, {NULL, NULL} }; @@ -704,12 +626,23 @@ static const luaL_reg co_funcs[] = { /* }====================================================== */ +static void auxopen (lua_State *L, const char *name, + lua_CFunction f, lua_CFunction u) { + lua_pushcfunction(L, u); + lua_pushcclosure(L, f, 1); + lua_setfield(L, -2, name); +} + static void base_open (lua_State *L) { + const char *path; lua_pushvalue(L, LUA_GLOBALSINDEX); luaL_openlib(L, NULL, base_funcs, 0); /* open lib into global table */ lua_pushliteral(L, LUA_VERSION); - lua_setfield(L, -2, "_VERSION"); /* set global _VERSION */ + lua_setfield(L, LUA_GLOBALSINDEX, "_VERSION"); /* set global _VERSION */ + /* `ipairs' and `pairs' need auxliliary functions as upvalues */ + auxopen(L, "ipairs", luaB_ipairs, ipairsaux); + auxopen(L, "pairs", luaB_pairs, luaB_next); /* `newproxy' needs a weaktable as upvalue */ lua_newtable(L); /* new table `w' */ lua_pushvalue(L, -1); /* `w' will be its own metatable */ @@ -717,16 +650,27 @@ static void base_open (lua_State *L) { lua_pushliteral(L, "kv"); lua_setfield(L, -2, "__mode"); /* metatable(w).__mode = "kv" */ lua_pushcclosure(L, luaB_newproxy, 1); - lua_setfield(L, -2, "newproxy"); /* set global `newproxy' */ - lua_setfield(L, -1, "_G"); /* set global _G */ + lua_setfield(L, LUA_GLOBALSINDEX, "newproxy"); /* set global `newproxy' */ + /* `require' needs a table to keep loaded chunks */ + lua_newtable(L); + lua_pushvalue(L, -1); + lua_setglobal(L, "_LOADED"); + lua_pushcclosure(L, luaB_require, 1); + lua_setfield(L, LUA_GLOBALSINDEX, "require"); + /* set global _G */ + lua_pushvalue(L, LUA_GLOBALSINDEX); + lua_setfield(L, LUA_GLOBALSINDEX, "_G"); + /* set global _PATH */ + path = getenv(LUA_PATH); + if (path == NULL) path = LUA_PATH_DEFAULT; + lua_pushstring(L, path); + lua_setfield(L, LUA_GLOBALSINDEX, "_PATH"); } LUALIB_API int luaopen_base (lua_State *L) { base_open(L); luaL_openlib(L, LUA_COLIBNAME, co_funcs, 0); - lua_newtable(L); - lua_setglobal(L, REQTAB); return 2; } |