소스 검색

New function 'luaL_openselectedlibs'

Makes it easier to start Lua with only some standard libraries.
Roberto Ierusalimschy 2 년 전
부모
커밋
d738c8d18b
7개의 변경된 파일71개의 추가작업 그리고 69개의 파일을 삭제
  1. 25 26
      linit.c
  2. 4 20
      ltests.c
  3. 2 2
      ltests.h
  4. 5 1
      lua.c
  5. 26 13
      lualib.h
  6. 8 6
      testes/api.lua
  7. 1 1
      testes/coroutine.lua

+ 25 - 26
linit.c

@@ -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
 }
 

+ 4 - 20
ltests.c

@@ -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;
 }
 

+ 2 - 2
ltests.h

@@ -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

+ 5 - 1
lua.c

@@ -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 */

+ 26 - 13
lualib.h

@@ -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_LOADLIBNAME	"package"
+#define LUA_LOADLIBK	(LUA_GK << 1)
+LUAMOD_API int (luaopen_package) (lua_State *L);
+
+
 #define LUA_COLIBNAME	"coroutine"
+#define LUA_COLIBK	(LUA_LOADLIBK << 1)
 LUAMOD_API int (luaopen_coroutine) (lua_State *L);
 
-#define LUA_TABLIBNAME	"table"
-LUAMOD_API int (luaopen_table) (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);
 
-#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"
-LUAMOD_API int (luaopen_package) (lua_State *L);
 
+/* open selected libraries */
+LUALIB_API void (luaL_openselectedlibs) (lua_State *L, int what);
 
-/* open all previous libraries */
-LUALIB_API void (luaL_openlibs) (lua_State *L);
+/* open all libraries */
+#define luaL_openlibs(L)	luaL_openselectedlibs(L, ~0)
 
 
 #endif

+ 8 - 6
testes/api.lua

@@ -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()

+ 1 - 1
testes/coroutine.lua

@@ -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';