Browse Source

New interface to function 'luaL_openselectedlibs'

Instead of preloading all non-loaded libraries, there is another
mask to select which libraries to preload.
Roberto Ierusalimschy 1 year ago
parent
commit
165389b27b
8 changed files with 80 additions and 56 deletions
  1. 10 12
      linit.c
  2. 3 2
      ltests.c
  3. 1 1
      lua.c
  4. 4 4
      lualib.h
  5. 1 1
      manual/2html
  6. 55 30
      manual/manual.of
  7. 5 5
      testes/api.lua
  8. 1 1
      testes/coroutine.lua

+ 10 - 12
linit.c

@@ -21,12 +21,12 @@
 
 
 /*
-** Standard Libraries
+** Standard Libraries. (Must be listed in the same ORDER of their
+** respective constants LUA_<libname>K.)
 */
 static const luaL_Reg stdlibs[] = {
   {LUA_GNAME, luaopen_base},
   {LUA_LOADLIBNAME, luaopen_package},
-
   {LUA_COLIBNAME, luaopen_coroutine},
   {LUA_DBLIBNAME, luaopen_debug},
   {LUA_IOLIBNAME, luaopen_io},
@@ -35,30 +35,28 @@ static const luaL_Reg stdlibs[] = {
   {LUA_STRLIBNAME, luaopen_string},
   {LUA_TABLIBNAME, luaopen_table},
   {LUA_UTF8LIBNAME, luaopen_utf8},
-
   {NULL, NULL}
 };
 
 
 /*
-** require selected standard libraries and add the others to the
-** preload table.
+** require and preload selected standard libraries
 */
-LUALIB_API void luaL_openselectedlibs (lua_State *L, int what) {
-  int mask = 1;
+LUALIB_API void luaL_openselectedlibs (lua_State *L, int load, int preload) {
+  int mask;
   const luaL_Reg *lib;
   luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
-  for (lib = stdlibs; lib->func; (lib++, mask <<= 1)) {
-    if (what & mask) {  /* selected? */
+  for (lib = stdlibs, mask = 1; lib->name != NULL; lib++, mask <<= 1) {
+    if (load & 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 */
+    else if (preload & mask) {  /* selected? */
       lua_pushcfunction(L, lib->func);
-      lua_setfield(L, -2, lib->name);
+      lua_setfield(L, -2, lib->name);  /* add library to PRELOAD table */
     }
   }
   lua_assert((mask >> 1) == LUA_UTF8LIBK);
-  lua_pop(L, 1);  // remove PRELOAD table
+  lua_pop(L, 1);  /* remove PRELOAD table */
 }
 

+ 3 - 2
ltests.c

@@ -1223,8 +1223,9 @@ static lua_State *getstate (lua_State *L) {
 
 static int loadlib (lua_State *L) {
   lua_State *L1 = getstate(L);
-  int what = luaL_checkinteger(L, 2);
-  luaL_openselectedlibs(L1, what);
+  int load = luaL_checkinteger(L, 2);
+  int preload = luaL_checkinteger(L, 3);
+  luaL_openselectedlibs(L1, load, preload);
   luaL_requiref(L1, "T", luaB_opentests, 0);
   lua_assert(lua_type(L1, -1) == LUA_TTABLE);
   /* 'requiref' should not reload module already loaded... */

+ 1 - 1
lua.c

@@ -618,7 +618,7 @@ static void doREPL (lua_State *L) {
 /* }================================================================== */
 
 #if !defined(luai_openlibs)
-#define luai_openlibs(L)	luaL_openlibs(L)
+#define luai_openlibs(L)	luaL_openselectedlibs(L, ~0, 0)
 #endif
 
 

+ 4 - 4
lualib.h

@@ -14,11 +14,11 @@
 /* version suffix for environment variable names */
 #define LUA_VERSUFFIX          "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
 
-#define LUA_GK		1
+#define LUA_GLIBK		1
 LUAMOD_API int (luaopen_base) (lua_State *L);
 
 #define LUA_LOADLIBNAME	"package"
-#define LUA_LOADLIBK	(LUA_GK << 1)
+#define LUA_LOADLIBK	(LUA_GLIBK << 1)
 LUAMOD_API int (luaopen_package) (lua_State *L);
 
 
@@ -56,10 +56,10 @@ LUAMOD_API int (luaopen_utf8) (lua_State *L);
 
 
 /* open selected libraries */
-LUALIB_API void (luaL_openselectedlibs) (lua_State *L, int what);
+LUALIB_API void (luaL_openselectedlibs) (lua_State *L, int load, int preload);
 
 /* open all libraries */
-#define luaL_openlibs(L)	luaL_openselectedlibs(L, ~0)
+#define luaL_openlibs(L)	luaL_openselectedlibs(L, ~0, 0)
 
 
 #endif

+ 1 - 1
manual/2html

@@ -358,7 +358,7 @@ item = function (s)
          local t, p = string.match(s, "^([^\n|]+)|()")
          if t then
            s = string.sub(s, p)
-           s = Tag.b(t..": ") .. s
+           s = Tag.b(t) ..": " .. s
          end
          return Tag.li(fixpara(s))
        end,

+ 55 - 30
manual/manual.of

@@ -664,7 +664,6 @@ Values equal to or less than 100 mean the collector will not wait to
 start a new cycle.
 A value of 200 means that the collector waits for
 the total number of objects to double before starting a new cycle.
-The default value is 200.
 
 The garbage-collector step size controls the
 size of each incremental step,
@@ -672,7 +671,6 @@ specifically how many objects the interpreter creates
 before performing a step:
 A value of @M{n} means the interpreter will create
 approximately @M{n} objects between steps.
-The default value is 250.
 
 The garbage-collector step multiplier
 controls the size of each GC step.
@@ -681,7 +679,6 @@ in each step, @M{n%} objects for each created object.
 Larger values make the collector more aggressive.
 Beware that values too small can
 make the collector too slow to ever finish a cycle.
-The default value is 200.
 As a special case, a zero value means unlimited work,
 effectively producing a non-incremental, stop-the-world collector.
 
@@ -711,7 +708,6 @@ after the last major collection.
 For instance, for a multiplier of 20,
 the collector will do a minor collection when the number of objects
 gets 20% larger than the total after the last major collection.
-The default value is 25.
 
 The minor-major multiplier controls the shift to major collections.
 For a multiplier @M{x},
@@ -721,7 +717,6 @@ than the total after the previous major collection.
 For instance, for a multiplier of 100,
 the collector will do a major collection when the number of old objects
 gets larger than twice the total after the previous major collection.
-The default value is 100.
 
 The major-minor multiplier controls the shift back to minor collections.
 For a multiplier @M{x},
@@ -731,7 +726,6 @@ of the objects allocated during the last cycle.
 In particular, for a multiplier of 0,
 the collector will immediately shift back to minor collections
 after doing one cycle of major collections.
-The default value is 50.
 
 }
 
@@ -5885,13 +5879,6 @@ or @id{NULL} if there is a @x{memory allocation error}.
 
 }
 
-@APIEntry{void luaL_openlibs (lua_State *L);|
-@apii{0,0,e}
-
-Opens all standard Lua libraries into the given state.
-
-}
-
 @APIEntry{
 T luaL_opt (L, func, arg, dflt);|
 @apii{0,0,-}
@@ -6073,7 +6060,7 @@ and sets the call result to @T{package.loaded[modname]},
 as if that function has been called through @Lid{require}.
 
 If @id{glb} is true,
-also stores the module into the global @id{modname}.
+also stores the module into the global variable @id{modname}.
 
 Leaves a copy of the module on the stack.
 
@@ -6290,23 +6277,61 @@ Except for the basic and the package libraries,
 each library provides all its functions as fields of a global table
 or as methods of its objects.
 
-To have access to these libraries,
-the @N{C host} program should call the @Lid{luaL_openlibs} function,
-which opens all standard libraries.
+}
+
+
+@sect2{lualib-h| @title{Loading the Libraries in C code}
+
+A @N{C host} program must explicitly load
+the standard libraries into a state,
+if it wants its scripts to use them.
+For that,
+the host program can call the function @Lid{luaL_openlibs}.
 Alternatively,
-the host program can open them individually by using
-@Lid{luaL_requiref} to call
-@defid{luaopen_base} (for the basic library),
-@defid{luaopen_package} (for the package library),
-@defid{luaopen_coroutine} (for the coroutine library),
-@defid{luaopen_string} (for the string library),
-@defid{luaopen_utf8} (for the UTF-8 library),
-@defid{luaopen_table} (for the table library),
-@defid{luaopen_math} (for the mathematical library),
-@defid{luaopen_io} (for the I/O library),
-@defid{luaopen_os} (for the operating system library),
-and @defid{luaopen_debug} (for the debug library).
-These functions are declared in @defid{lualib.h}.
+the host can select which libraries to open,
+by using @Lid{luaL_openselectedlibs}.
+Both functions are defined in the header file @id{lualib.h}.
+@index{lualib.h}
+
+The stand-alone interpreter @id{lua} @see{lua-sa}
+already opens all standard libraries.
+
+@APIEntry{void luaL_openlibs (lua_State *L);|
+@apii{0,0,e}
+
+Opens all standard Lua libraries into the given state.
+
+}
+
+@APIEntry{void luaL_openselectedlibs (lua_State *L, int load, int preload);|
+@apii{0,0,e}
+
+Opens (loads) and preloads selected libraries into the state @id{L}.
+(To @emph{preload} means to add
+the library loader into the table @Lid{package.preload},
+so that the library can be required later by the program.
+Keep in mind that @Lid{require} itself is provided
+by the @emph{package} library.
+If a program does not load that library,
+it will be unable to require anything.)
+
+The integer @id{load} selects which libraries to load;
+the integer @id{preload} selects which to preload, among those not loaded.
+Both are masks formed by a bitwise OR of the following constants:
+@description{
+@item{@defid{LUA_GLIBK} | the basic library.}
+@item{@defid{LUA_LOADLIBK} | the package library.}
+@item{@defid{LUA_COLIBK} | the coroutine library.}
+@item{@defid{LUA_STRLIBK} | the string library.}
+@item{@defid{LUA_UTF8LIBK} | the UTF-8 library.}
+@item{@defid{LUA_TABLIBK} | the table library.}
+@item{@defid{LUA_MATHLIBK} | the mathematical library.}
+@item{@defid{LUA_IOLIBK} | the I/O library.}
+@item{@defid{LUA_OSLIBK} | the operating system library.}
+@item{@defid{LUA_DBLIBK} | the debug library.}
+}
+
+}
 
 }
 

+ 5 - 5
testes/api.lua

@@ -546,9 +546,9 @@ do
   ]], source)
   collectgarbage()
   local m2 = collectgarbage"count" * 1024
-  -- load used fewer than 350 bytes. Code alone has more than 3*N bytes,
+  -- load used fewer than 400 bytes. Code alone has more than 3*N bytes,
   -- and string literal has N bytes. Both were not loaded.
-  assert(m2 > m1 and m2 - m1 < 350)
+  assert(m2 > m1 and m2 - m1 < 400)
   X = 0; code(); assert(X == N and Y == string.rep("a", N))
   X = nil; Y = nil
 
@@ -1122,7 +1122,7 @@ assert(a == nil and c == 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, 2)    -- load only 'package'
+T.loadlib(L1, 2, ~2)    -- load only 'package', preload all others
 a, b, c = T.doremote(L1, [[
   string = require'string'
   local initialG = _G   -- not loaded yet
@@ -1141,7 +1141,7 @@ T.closestate(L1);
 
 
 L1 = T.newstate()
-T.loadlib(L1, 0)
+T.loadlib(L1, 0, 0)
 T.doremote(L1, "a = {}")
 T.testC(L1, [[getglobal "a"; pushstring "x"; pushint 1;
              settable -3]])
@@ -1524,7 +1524,7 @@ end
 
 do   -- garbage collection with no extra memory
   local L = T.newstate()
-  T.loadlib(L, 1 | 2)   -- load _G and 'package'
+  T.loadlib(L, 1 | 2, 0)   -- load _G and 'package'
   local res = (T.doremote(L, [[
     _ENV = _G
     assert(string == nil)

+ 1 - 1
testes/coroutine.lua

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