diff --git a/lauxlib.c b/lauxlib.c index 46c7e4f9..c0d7fb5c 100644 --- a/lauxlib.c +++ b/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.201 2010/02/18 19:37:57 roberto Exp roberto $ +** $Id: lauxlib.c,v 1.202 2010/03/12 18:59:32 roberto Exp roberto $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -670,13 +670,13 @@ LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { static int libsize (const luaL_Reg *l) { int size = 0; - for (; l->name; l++) size++; + for (; l && l->name; l++) size++; return size; } -LUALIB_API void luaL_register (lua_State *L, const char *libname, - const luaL_Reg *l) { +LUALIB_API void luaL_openlib (lua_State *L, const char *libname, + const luaL_Reg *l, int nup) { luaL_checkversion(L); if (libname) { /* check whether lib already exists */ @@ -692,12 +692,17 @@ LUALIB_API void luaL_register (lua_State *L, const char *libname, lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */ } lua_remove(L, -2); /* remove _LOADED table */ + lua_insert(L, -(nup + 1)); /* move library table to below upvalues */ } - if (l == NULL) return; /* nothing to register? */ - for (; l->name; l++) { /* else fill the table with given functions */ - lua_pushcfunction(L, l->func); - lua_setfield(L, -2, l->name); + luaL_checkstack(L, nup, "too many upvalues"); + for (; l && l->name; l++) { /* else fill the table with given functions */ + int i; + for (i = 0; i < nup; i++) /* copy upvalues to the top */ + lua_pushvalue(L, -nup); + lua_pushcclosure(L, l->func, nup); + lua_setfield(L, -(nup + 2), l->name); } + lua_pop(L, nup); /* remove upvalues */ } diff --git a/lauxlib.h b/lauxlib.h index fa293c64..ae961835 100644 --- a/lauxlib.h +++ b/lauxlib.h @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.h,v 1.99 2010/01/11 16:00:45 roberto Exp roberto $ +** $Id: lauxlib.h,v 1.100 2010/01/21 16:49:21 roberto Exp roberto $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -29,8 +29,8 @@ typedef struct luaL_Reg { LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver); #define luaL_checkversion(L) luaL_checkversion_(L, LUA_VERSION_NUM) -LUALIB_API void (luaL_register) (lua_State *L, const char *libname, - const luaL_Reg *l); +LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname, + const luaL_Reg *l, int nup); LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len); @@ -71,7 +71,7 @@ LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); LUALIB_API lua_State *(luaL_newstate) (void); -LUALIB_API int luaL_len (lua_State *L, int idx); +LUALIB_API int (luaL_len) (lua_State *L, int idx); LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, const char *r); @@ -79,11 +79,11 @@ LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx, const char *fname, int szhint); -LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, - const char *msg, int level); +LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1, + const char *msg, int level); -LUALIB_API int luaL_cpcall (lua_State *L, lua_CFunction f, int nargs, - int nresults); +LUALIB_API int (luaL_cpcall) (lua_State *L, lua_CFunction f, int nargs, + int nresults); /* @@ -113,6 +113,9 @@ LUALIB_API int luaL_cpcall (lua_State *L, lua_CFunction f, int nargs, #define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n))) +#define luaL_register(L,n,l) (luaL_openlib(L,(n),(l),0)) + + /* ** {====================================================== ** Generic Buffer manipulation diff --git a/liolib.c b/liolib.c index 7f22bd8b..fce6b69b 100644 --- a/liolib.c +++ b/liolib.c @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 2.85 2009/12/17 16:20:01 roberto Exp roberto $ +** $Id: liolib.c,v 2.86 2010/03/03 18:48:57 roberto Exp roberto $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -103,13 +103,12 @@ static FILE *tofile (lua_State *L) { } - /* ** When creating file handles, always creates a `closed' file handle ** before opening the actual file; so, if there is a memory error, the ** file is not left opened. */ -static FILE **newfile (lua_State *L) { +static FILE **newprefile (lua_State *L) { FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *)); *pf = NULL; /* file handle is currently `closed' */ luaL_getmetatable(L, LUA_FILEHANDLE); @@ -118,6 +117,14 @@ static FILE **newfile (lua_State *L) { } +static FILE **newfile (lua_State *L) { + FILE **pf = newprefile(L); + lua_pushvalue(L, lua_upvalueindex(1)); /* set upvalue... */ + lua_setfenv(L, -2); /* ... as environment for new file */ + return pf; +} + + /* ** function to (not) close the standard files stdin, stdout, and stderr */ @@ -164,7 +171,7 @@ static int aux_close (lua_State *L) { static int io_close (lua_State *L) { if (lua_isnone(L, 1)) - lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT); + lua_rawgeti(L, lua_upvalueindex(1), IO_OUTPUT); tofile(L); /* make sure argument is a file */ return aux_close(L); } @@ -229,7 +236,7 @@ static int io_tmpfile (lua_State *L) { static FILE *getiofile (lua_State *L, int findex) { FILE *f; - lua_rawgeti(L, LUA_ENVIRONINDEX, findex); + lua_rawgeti(L, lua_upvalueindex(1), findex); f = *(FILE **)lua_touserdata(L, -1); if (f == NULL) luaL_error(L, "standard %s file is closed", fnames[findex - 1]); @@ -250,10 +257,10 @@ static int g_iofile (lua_State *L, int f, const char *mode) { tofile(L); /* check that it's a valid file handle */ lua_pushvalue(L, 1); } - lua_rawseti(L, LUA_ENVIRONINDEX, f); + lua_rawseti(L, lua_upvalueindex(1), f); } /* return current value */ - lua_rawgeti(L, LUA_ENVIRONINDEX, f); + lua_rawgeti(L, lua_upvalueindex(1), f); return 1; } @@ -295,7 +302,7 @@ static int io_lines (lua_State *L) { int toclose; if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */ if (lua_isnil(L, 1)) { /* no file name? */ - lua_rawgeti(L, LUA_ENVIRONINDEX, IO_INPUT); /* get default input */ + lua_rawgeti(L, lua_upvalueindex(1), IO_INPUT); /* get default input */ lua_replace(L, 1); /* put it at index 1 */ tofile(L); /* check that it's a valid file handle */ toclose = 0; /* do not close it after iteration */ @@ -576,23 +583,27 @@ static void createmeta (lua_State *L) { luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */ lua_pushvalue(L, -1); /* push metatable */ lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ - luaL_register(L, NULL, flib); /* file methods */ + luaL_register(L, NULL, flib); /* add file methods to new metatable */ + lua_pop(L, 1); /* pop new metatable */ } static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) { - *newfile(L) = f; + *newprefile(L) = f; if (k > 0) { - lua_pushvalue(L, -1); - lua_rawseti(L, LUA_ENVIRONINDEX, k); + lua_pushvalue(L, -1); /* copy new file */ + lua_rawseti(L, 1, k); /* add it to common upvalue */ } - lua_pushvalue(L, -2); /* copy environment */ - lua_setfenv(L, -2); /* set it */ - lua_setfield(L, -3, fname); + lua_pushvalue(L, 3); /* get environment for default files */ + lua_setfenv(L, -2); /* set it as environment for file */ + lua_setfield(L, 2, fname); /* add file to module */ } -static void newfenv (lua_State *L, lua_CFunction cls) { +/* +** pushes a new table with {__close = cls} +*/ +static void newenv (lua_State *L, lua_CFunction cls) { lua_createtable(L, 0, 1); lua_pushcfunction(L, cls); lua_setfield(L, -2, "__close"); @@ -600,21 +611,21 @@ static void newfenv (lua_State *L, lua_CFunction cls) { LUAMOD_API int luaopen_io (lua_State *L) { + lua_settop(L, 0); createmeta(L); /* create (private) environment (with fields IO_INPUT, IO_OUTPUT, __close) */ - newfenv(L, io_fclose); - lua_replace(L, LUA_ENVIRONINDEX); - /* open library */ - luaL_register(L, LUA_IOLIBNAME, iolib); + newenv(L, io_fclose); /* upvalue for all io functions at index 1 */ + lua_pushvalue(L, -1); /* copy to be consumed by 'openlib' */ + luaL_openlib(L, LUA_IOLIBNAME, iolib, 1); /* new module at index 2 */ /* create (and set) default files */ - newfenv(L, io_noclose); /* close function for default files */ + newenv(L, io_noclose); /* environment for default files at index 3 */ createstdfile(L, stdin, IO_INPUT, "stdin"); createstdfile(L, stdout, IO_OUTPUT, "stdout"); createstdfile(L, stderr, 0, "stderr"); lua_pop(L, 1); /* pop environment for default files */ - lua_getfield(L, -1, "popen"); - newfenv(L, io_pclose); /* create environment for 'popen' */ - lua_setfenv(L, -2); /* set fenv for 'popen' */ + lua_getfield(L, 2, "popen"); + newenv(L, io_pclose); /* create environment for 'popen' streams */ + lua_setupvalue(L, -2, 1); /* set it as upvalue for 'popen' */ lua_pop(L, 1); /* pop 'popen' */ return 1; } diff --git a/loadlib.c b/loadlib.c index eba25e30..44112e31 100644 --- a/loadlib.c +++ b/loadlib.c @@ -1,5 +1,5 @@ /* -** $Id: loadlib.c,v 1.79 2010/01/13 16:09:05 roberto Exp roberto $ +** $Id: loadlib.c,v 1.80 2010/01/13 16:30:27 roberto Exp roberto $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h ** @@ -353,9 +353,7 @@ static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { lua_CFunction f = ll_sym(L, *reg, sym); if (f == NULL) return ERRFUNC; /* unable to find function */ - lua_pushcfunction(L, f); /* else create new function... */ - lua_pushglobaltable(L); /* ... and set the standard global table... */ - lua_setfenv(L, -2); /* ... as its environment */ + lua_pushcfunction(L, f); /* else create new function */ return 0; /* no errors */ } } @@ -435,7 +433,7 @@ static int ll_searchpath (lua_State *L) { static const char *findfile (lua_State *L, const char *name, const char *pname) { const char *path; - lua_getfield(L, LUA_ENVIRONINDEX, pname); + lua_getfield(L, lua_upvalueindex(1), pname); path = lua_tostring(L, -1); if (path == NULL) luaL_error(L, LUA_QL("package.%s") " must be a string", pname); @@ -509,7 +507,7 @@ static int loader_Croot (lua_State *L) { static int loader_preload (lua_State *L) { const char *name = luaL_checkstring(L, 1); - lua_getfield(L, LUA_ENVIRONINDEX, "preload"); + lua_getfield(L, lua_upvalueindex(1), "preload"); if (!lua_istable(L, -1)) luaL_error(L, LUA_QL("package.preload") " must be a table"); lua_getfield(L, -1, name); @@ -535,7 +533,7 @@ static int ll_require (lua_State *L) { return 1; /* package is already loaded */ } /* else must load it; iterate over available loaders */ - lua_getfield(L, LUA_ENVIRONINDEX, "loaders"); + lua_getfield(L, lua_upvalueindex(1), "loaders"); if (!lua_istable(L, -1)) luaL_error(L, LUA_QL("package.loaders") " must be a table"); lua_pushliteral(L, ""); /* error message accumulator */ @@ -709,12 +707,12 @@ LUAMOD_API int luaopen_package (lua_State *L) { lua_setfield(L, -2, "__gc"); /* create `package' table */ luaL_register(L, LUA_LOADLIBNAME, pk_funcs); - lua_copy(L, -1, LUA_ENVIRONINDEX); /* create `loaders' table */ lua_createtable(L, sizeof(loaders)/sizeof(loaders[0]) - 1, 0); /* fill it with pre-defined loaders */ for (i=0; loaders[i] != NULL; i++) { - lua_pushcfunction(L, loaders[i]); + lua_pushvalue(L, -2); /* set 'package' as upvalue for all loaders */ + lua_pushcclosure(L, loaders[i], 1); lua_rawseti(L, -2, i+1); } lua_setfield(L, -2, "loaders"); /* put it in field `loaders' */ @@ -731,8 +729,9 @@ LUAMOD_API int luaopen_package (lua_State *L) { lua_newtable(L); lua_setfield(L, -2, "preload"); lua_pushglobaltable(L); - luaL_register(L, NULL, ll_funcs); /* open lib into global table */ - lua_pop(L, 1); + lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */ + luaL_openlib(L, NULL, ll_funcs, 1); /* open lib into global table */ + lua_pop(L, 1); /* pop global table */ return 1; /* return 'package' table */ }