New function 'luaL_openselectedlibs'

Makes it easier to start Lua with only some standard libraries.
This commit is contained in:
Roberto Ierusalimschy 2022-12-07 15:12:52 -03:00
parent 0270c204c2
commit d738c8d18b
7 changed files with 85 additions and 83 deletions

51
linit.c
View File

@ -8,21 +8,6 @@
#define linit_c
#define LUA_LIB
/*
** If you embed Lua in your program and need to open the standard
** libraries, call luaL_openlibs in your program. If you need a
** different set of libraries, copy this file to your project and edit
** it to suit your needs.
**
** You can also *preload* libraries, so that a later 'require' can
** open the library, which is already linked to the application.
** For that, do the following code:
**
** luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
** lua_pushcfunction(L, luaopen_modname);
** lua_setfield(L, -2, modname);
** lua_pop(L, 1); // remove PRELOAD table
*/
#include "lprefix.h"
@ -36,30 +21,44 @@
/*
** these libs are loaded by lua.c and are readily available to any Lua
** program
** Standard Libraries
*/
static const luaL_Reg loadedlibs[] = {
static const luaL_Reg stdlibs[] = {
{LUA_GNAME, luaopen_base},
{LUA_LOADLIBNAME, luaopen_package},
{LUA_COLIBNAME, luaopen_coroutine},
{LUA_TABLIBNAME, luaopen_table},
{LUA_DBLIBNAME, luaopen_debug},
{LUA_IOLIBNAME, luaopen_io},
{LUA_MATHLIBNAME, luaopen_math},
{LUA_OSLIBNAME, luaopen_os},
{LUA_STRLIBNAME, luaopen_string},
{LUA_MATHLIBNAME, luaopen_math},
{LUA_TABLIBNAME, luaopen_table},
{LUA_UTF8LIBNAME, luaopen_utf8},
{LUA_DBLIBNAME, luaopen_debug},
{NULL, NULL}
};
LUALIB_API void luaL_openlibs (lua_State *L) {
/*
** require selected standard libraries and add the others to the
** preload table.
*/
LUALIB_API void luaL_openselectedlibs (lua_State *L, int what) {
int mask = 1;
const luaL_Reg *lib;
/* "require" functions from 'loadedlibs' and set results to global table */
for (lib = loadedlibs; lib->func; lib++) {
luaL_requiref(L, lib->name, lib->func, 1);
lua_pop(L, 1); /* remove lib */
luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
for (lib = stdlibs; lib->func; (lib++, mask <<= 1)) {
if (what & mask) { /* selected? */
luaL_requiref(L, lib->name, lib->func, 1); /* require library */
lua_pop(L, 1); /* remove result from the stack */
}
else { /* add library to PRELOAD table */
lua_pushcfunction(L, lib->func);
lua_setfield(L, -2, lib->name);
}
}
lua_assert((mask >> 1) == LUA_UTF8LIBK);
lua_pop(L, 1); // remove PRELOAD table
}

View File

@ -1178,31 +1178,15 @@ static lua_State *getstate (lua_State *L) {
static int loadlib (lua_State *L) {
static const luaL_Reg libs[] = {
{LUA_GNAME, luaopen_base},
{"coroutine", luaopen_coroutine},
{"debug", luaopen_debug},
{"io", luaopen_io},
{"os", luaopen_os},
{"math", luaopen_math},
{"string", luaopen_string},
{"table", luaopen_table},
{"T", luaB_opentests},
{NULL, NULL}
};
lua_State *L1 = getstate(L);
int i;
luaL_requiref(L1, "package", luaopen_package, 0);
int what = luaL_checkinteger(L, 2);
luaL_openselectedlibs(L1, what);
luaL_requiref(L1, "T", luaB_opentests, 0);
lua_assert(lua_type(L1, -1) == LUA_TTABLE);
/* 'requiref' should not reload module already loaded... */
luaL_requiref(L1, "package", NULL, 1); /* seg. fault if it reloads */
luaL_requiref(L1, "T", NULL, 1); /* seg. fault if it reloads */
/* ...but should return the same module */
lua_assert(lua_compare(L1, -1, -2, LUA_OPEQ));
luaL_getsubtable(L1, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
for (i = 0; libs[i].name; i++) {
lua_pushcfunction(L1, libs[i].func);
lua_setfield(L1, -2, libs[i].name);
}
return 0;
}

View File

@ -103,8 +103,8 @@ LUA_API void *debug_realloc (void *ud, void *block,
#if defined(lua_c)
#define luaL_newstate() lua_newstate(debug_realloc, &l_memcontrol)
#define luaL_openlibs(L) \
{ (luaL_openlibs)(L); \
#define luai_openlibs(L) \
{ luaL_openlibs(L); \
luaL_requiref(L, "T", luaB_opentests, 1); \
lua_pop(L, 1); }
#endif

6
lua.c
View File

@ -609,6 +609,10 @@ static void doREPL (lua_State *L) {
/* }================================================================== */
#if !defined(luai_openlibs)
#define luai_openlibs(L) luaL_openlibs(L)
#endif
/*
** Main body of stand-alone interpreter (to be called in protected mode).
@ -631,7 +635,7 @@ static int pmain (lua_State *L) {
lua_pushboolean(L, 1); /* signal for libraries to ignore env. vars. */
lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
}
luaL_openlibs(L); /* open standard libraries */
luai_openlibs(L); /* open standard libraries */
createargtable(L, argv, argc, script); /* create table 'arg' */
lua_gc(L, LUA_GCRESTART); /* start GC... */
lua_gc(L, LUA_GCGEN, 0, 0); /* ...in generational mode */

View File

@ -14,39 +14,52 @@
/* version suffix for environment variable names */
#define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
#define LUA_GK 1
LUAMOD_API int (luaopen_base) (lua_State *L);
#define LUA_COLIBNAME "coroutine"
LUAMOD_API int (luaopen_coroutine) (lua_State *L);
#define LUA_TABLIBNAME "table"
LUAMOD_API int (luaopen_table) (lua_State *L);
#define LUA_IOLIBNAME "io"
LUAMOD_API int (luaopen_io) (lua_State *L);
#define LUA_OSLIBNAME "os"
LUAMOD_API int (luaopen_os) (lua_State *L);
#define LUA_STRLIBNAME "string"
LUAMOD_API int (luaopen_string) (lua_State *L);
#define LUA_UTF8LIBNAME "utf8"
LUAMOD_API int (luaopen_utf8) (lua_State *L);
#define LUA_MATHLIBNAME "math"
LUAMOD_API int (luaopen_math) (lua_State *L);
#define LUA_DBLIBNAME "debug"
LUAMOD_API int (luaopen_debug) (lua_State *L);
#define LUA_LOADLIBNAME "package"
#define LUA_LOADLIBK (LUA_GK << 1)
LUAMOD_API int (luaopen_package) (lua_State *L);
/* open all previous libraries */
LUALIB_API void (luaL_openlibs) (lua_State *L);
#define LUA_COLIBNAME "coroutine"
#define LUA_COLIBK (LUA_LOADLIBK << 1)
LUAMOD_API int (luaopen_coroutine) (lua_State *L);
#define LUA_DBLIBNAME "debug"
#define LUA_DBLIBK (LUA_COLIBK << 1)
LUAMOD_API int (luaopen_debug) (lua_State *L);
#define LUA_IOLIBNAME "io"
#define LUA_IOLIBK (LUA_DBLIBK << 1)
LUAMOD_API int (luaopen_io) (lua_State *L);
#define LUA_MATHLIBNAME "math"
#define LUA_MATHLIBK (LUA_IOLIBK << 1)
LUAMOD_API int (luaopen_math) (lua_State *L);
#define LUA_OSLIBNAME "os"
#define LUA_OSLIBK (LUA_MATHLIBK << 1)
LUAMOD_API int (luaopen_os) (lua_State *L);
#define LUA_STRLIBNAME "string"
#define LUA_STRLIBK (LUA_OSLIBK << 1)
LUAMOD_API int (luaopen_string) (lua_State *L);
#define LUA_TABLIBNAME "table"
#define LUA_TABLIBK (LUA_STRLIBK << 1)
LUAMOD_API int (luaopen_table) (lua_State *L);
#define LUA_UTF8LIBNAME "utf8"
#define LUA_UTF8LIBK (LUA_TABLIBK << 1)
LUAMOD_API int (luaopen_utf8) (lua_State *L);
/* open selected libraries */
LUALIB_API void (luaL_openselectedlibs) (lua_State *L, int what);
/* open all libraries */
#define luaL_openlibs(L) luaL_openselectedlibs(L, ~0)
#endif

View File

@ -1039,10 +1039,12 @@ assert(a == nil and b == 2) -- 2 == run-time error
a, b, c = T.doremote(L1, "return a+")
assert(a == nil and c == 3 and type(b) == "string") -- 3 == syntax error
T.loadlib(L1)
T.loadlib(L1, 2) -- load only 'package'
a, b, c = T.doremote(L1, [[
string = require'string'
a = require'_G'; assert(a == _G and require("_G") == a)
local initialG = _G -- not loaded yet
local a = require'_G'; assert(a == _G and require("_G") == a)
assert(initialG == nil and io == nil) -- now we have 'assert'
io = require'io'; assert(type(io.read) == "function")
assert(require("io") == io)
a = require'table'; assert(type(a.insert) == "function")
@ -1056,7 +1058,7 @@ T.closestate(L1);
L1 = T.newstate()
T.loadlib(L1)
T.loadlib(L1, 0)
T.doremote(L1, "a = {}")
T.testC(L1, [[getglobal "a"; pushstring "x"; pushint 1;
settable -3]])
@ -1436,10 +1438,10 @@ end
do -- garbage collection with no extra memory
local L = T.newstate()
T.loadlib(L)
T.loadlib(L, 1 | 2) -- load _G and 'package'
local res = (T.doremote(L, [[
_ENV = require"_G"
local T = require"T"
_ENV = _G
assert(string == nil)
local a = {}
for i = 1, 1000 do a[i] = 'i' .. i end -- grow string table
local stsize, stuse = T.querystr()

View File

@ -694,7 +694,7 @@ else
T.testC(state, "settop 0")
T.loadlib(state)
T.loadlib(state, 1 | 2) -- load _G and 'package'
assert(T.doremote(state, [[
coroutine = require'coroutine';