2022-04-24 16:59:22 +00:00
|
|
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
|
|
|
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
|
|
|
|
╚──────────────────────────────────────────────────────────────────────────────╝
|
|
|
|
│ │
|
|
|
|
│ Lua │
|
Bring Lua to 5.4.6. (#1214)
This essentially re-does the work of #875 on top of master.
This is what I did to check that Cosmo's Lua extensions still worked:
```
$ build/bootstrap/make MODE=aarch64 o/aarch64/third_party/lua/lua
$ ape o/aarch64/third_party/lua/lua
>: 10
10
>: 010
8
>: 0b10
2
>: string.byte("\e")
27
>: "Hello, %s" % {"world"}
Hello, world
>: "*" * 3
***
```
`luaL_traceback2` was used to show the stack trace with parameter
values; it's used in `LuaCallWithTrace`, which is used in Redbean to run
Lua code. You should be able to see the extended stack trace by running
something like this: `redbean -e "function a(b)c()end a(2)"` (with
"params" indicating the extended stack trace):
```
stack traceback:
[string "function a(b)c()end a(2)"]:1: in function 'a', params: b = 2;
[string "function a(b)c()end a(2)"]:1: in main chunk
```
@pkulchenko confirmed that I get the expected result with the updated
code.
This is what I did to check that Lua itself still worked:
```
$ cd third_party/lua/test/
$ ape ../../../o/aarch64/third_party/lua/lua all.lua
```
There's one test failure, in `files.lua`:
```
***** FILE 'files.lua'*****
testing i/o
../../../o/aarch64/third_party/lua/lua: files.lua:84: assertion failed!
stack traceback:
[C]: in function 'assert'
files.lua:84: in main chunk
(...tail calls...)
all.lua:195: in main chunk
[C]: in ?
.>>> closing state <<<
```
That isn't a result of these changes; the same test is failing in
master.
The failure is here:
```lua
if not _port then -- invalid seek
local status, msg, code = io.stdin:seek("set", 1000)
assert(not status and type(msg) == "string" and type(code) == "number")
end
```
The test expects a seek to offset 1,000 on stdin to fail — but it
doesn't. `status` ends up being the new offset rather than `nil`.
If I comment out that one test, the remaining tests succeed.
2024-06-16 00:13:08 +00:00
|
|
|
│ Copyright © 2004-2023 Lua.org, PUC-Rio. │
|
2022-04-24 16:59:22 +00:00
|
|
|
│ │
|
|
|
|
│ Permission is hereby granted, free of charge, to any person obtaining │
|
|
|
|
│ a copy of this software and associated documentation files (the │
|
|
|
|
│ "Software"), to deal in the Software without restriction, including │
|
|
|
|
│ without limitation the rights to use, copy, modify, merge, publish, │
|
|
|
|
│ distribute, sublicense, and/or sell copies of the Software, and to │
|
|
|
|
│ permit persons to whom the Software is furnished to do so, subject to │
|
|
|
|
│ the following conditions: │
|
|
|
|
│ │
|
|
|
|
│ The above copyright notice and this permission notice shall be │
|
|
|
|
│ included in all copies or substantial portions of the Software. │
|
|
|
|
│ │
|
|
|
|
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │
|
|
|
|
│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │
|
|
|
|
│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │
|
|
|
|
│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │
|
|
|
|
│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │
|
|
|
|
│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │
|
|
|
|
│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │
|
|
|
|
│ │
|
|
|
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
2021-03-02 13:51:10 +00:00
|
|
|
#define loadlib_c
|
|
|
|
#define LUA_LIB
|
Bring Lua to 5.4.6. (#1214)
This essentially re-does the work of #875 on top of master.
This is what I did to check that Cosmo's Lua extensions still worked:
```
$ build/bootstrap/make MODE=aarch64 o/aarch64/third_party/lua/lua
$ ape o/aarch64/third_party/lua/lua
>: 10
10
>: 010
8
>: 0b10
2
>: string.byte("\e")
27
>: "Hello, %s" % {"world"}
Hello, world
>: "*" * 3
***
```
`luaL_traceback2` was used to show the stack trace with parameter
values; it's used in `LuaCallWithTrace`, which is used in Redbean to run
Lua code. You should be able to see the extended stack trace by running
something like this: `redbean -e "function a(b)c()end a(2)"` (with
"params" indicating the extended stack trace):
```
stack traceback:
[string "function a(b)c()end a(2)"]:1: in function 'a', params: b = 2;
[string "function a(b)c()end a(2)"]:1: in main chunk
```
@pkulchenko confirmed that I get the expected result with the updated
code.
This is what I did to check that Lua itself still worked:
```
$ cd third_party/lua/test/
$ ape ../../../o/aarch64/third_party/lua/lua all.lua
```
There's one test failure, in `files.lua`:
```
***** FILE 'files.lua'*****
testing i/o
../../../o/aarch64/third_party/lua/lua: files.lua:84: assertion failed!
stack traceback:
[C]: in function 'assert'
files.lua:84: in main chunk
(...tail calls...)
all.lua:195: in main chunk
[C]: in ?
.>>> closing state <<<
```
That isn't a result of these changes; the same test is failing in
master.
The failure is here:
```lua
if not _port then -- invalid seek
local status, msg, code = io.stdin:seek("set", 1000)
assert(not status and type(msg) == "string" and type(code) == "number")
end
```
The test expects a seek to offset 1,000 on stdin to fail — but it
doesn't. `status` ends up being the new offset rather than `nil`.
If I comment out that one test, the remaining tests succeed.
2024-06-16 00:13:08 +00:00
|
|
|
|
2023-11-03 13:04:13 +00:00
|
|
|
#include "libc/dlopen/dlfcn.h"
|
2022-08-11 07:15:29 +00:00
|
|
|
#include "libc/runtime/runtime.h"
|
|
|
|
#include "libc/str/str.h"
|
2021-03-07 21:26:57 +00:00
|
|
|
#include "third_party/lua/lauxlib.h"
|
|
|
|
#include "third_party/lua/lprefix.h"
|
|
|
|
#include "third_party/lua/lua.h"
|
|
|
|
#include "third_party/lua/lualib.h"
|
Release Cosmopolitan v3.3
This change upgrades to GCC 12.3 and GNU binutils 2.42. The GNU linker
appears to have changed things so that only a single de-duplicated str
table is present in the binary, and it gets placed wherever the linker
wants, regardless of what the linker script says. To cope with that we
need to stop using .ident to embed licenses. As such, this change does
significant work to revamp how third party licenses are defined in the
codebase, using `.section .notice,"aR",@progbits`.
This new GCC 12.3 toolchain has support for GNU indirect functions. It
lets us support __target_clones__ for the first time. This is used for
optimizing the performance of libc string functions such as strlen and
friends so far on x86, by ensuring AVX systems favor a second codepath
that uses VEX encoding. It shaves some latency off certain operations.
It's a useful feature to have for scientific computing for the reasons
explained by the test/libcxx/openmp_test.cc example which compiles for
fifteen different microarchitectures. Thanks to the upgrades, it's now
also possible to use newer instruction sets, such as AVX512FP16, VNNI.
Cosmo now uses the %gs register on x86 by default for TLS. Doing it is
helpful for any program that links `cosmo_dlopen()`. Such programs had
to recompile their binaries at startup to change the TLS instructions.
That's not great, since it means every page in the executable needs to
be faulted. The work of rewriting TLS-related x86 opcodes, is moved to
fixupobj.com instead. This is great news for MacOS x86 users, since we
previously needed to morph the binary every time for that platform but
now that's no longer necessary. The only platforms where we need fixup
of TLS x86 opcodes at runtime are now Windows, OpenBSD, and NetBSD. On
Windows we morph TLS to point deeper into the TIB, based on a TlsAlloc
assignment, and on OpenBSD/NetBSD we morph %gs back into %fs since the
kernels do not allow us to specify a value for the %gs register.
OpenBSD users are now required to use APE Loader to run Cosmo binaries
and assimilation is no longer possible. OpenBSD kernel needs to change
to allow programs to specify a value for the %gs register, or it needs
to stop marking executable pages loaded by the kernel as mimmutable().
This release fixes __constructor__, .ctor, .init_array, and lastly the
.preinit_array so they behave the exact same way as glibc.
We no longer use hex constants to define math.h symbols like M_PI.
2024-02-20 19:12:09 +00:00
|
|
|
__static_yoink("lua_notice");
|
2022-04-24 16:59:22 +00:00
|
|
|
|
Bring Lua to 5.4.6. (#1214)
This essentially re-does the work of #875 on top of master.
This is what I did to check that Cosmo's Lua extensions still worked:
```
$ build/bootstrap/make MODE=aarch64 o/aarch64/third_party/lua/lua
$ ape o/aarch64/third_party/lua/lua
>: 10
10
>: 010
8
>: 0b10
2
>: string.byte("\e")
27
>: "Hello, %s" % {"world"}
Hello, world
>: "*" * 3
***
```
`luaL_traceback2` was used to show the stack trace with parameter
values; it's used in `LuaCallWithTrace`, which is used in Redbean to run
Lua code. You should be able to see the extended stack trace by running
something like this: `redbean -e "function a(b)c()end a(2)"` (with
"params" indicating the extended stack trace):
```
stack traceback:
[string "function a(b)c()end a(2)"]:1: in function 'a', params: b = 2;
[string "function a(b)c()end a(2)"]:1: in main chunk
```
@pkulchenko confirmed that I get the expected result with the updated
code.
This is what I did to check that Lua itself still worked:
```
$ cd third_party/lua/test/
$ ape ../../../o/aarch64/third_party/lua/lua all.lua
```
There's one test failure, in `files.lua`:
```
***** FILE 'files.lua'*****
testing i/o
../../../o/aarch64/third_party/lua/lua: files.lua:84: assertion failed!
stack traceback:
[C]: in function 'assert'
files.lua:84: in main chunk
(...tail calls...)
all.lua:195: in main chunk
[C]: in ?
.>>> closing state <<<
```
That isn't a result of these changes; the same test is failing in
master.
The failure is here:
```lua
if not _port then -- invalid seek
local status, msg, code = io.stdin:seek("set", 1000)
assert(not status and type(msg) == "string" and type(code) == "number")
end
```
The test expects a seek to offset 1,000 on stdin to fail — but it
doesn't. `status` ends up being the new offset rather than `nil`.
If I comment out that one test, the remaining tests succeed.
2024-06-16 00:13:08 +00:00
|
|
|
|
2022-04-24 16:59:22 +00:00
|
|
|
/*
|
Bring Lua to 5.4.6. (#1214)
This essentially re-does the work of #875 on top of master.
This is what I did to check that Cosmo's Lua extensions still worked:
```
$ build/bootstrap/make MODE=aarch64 o/aarch64/third_party/lua/lua
$ ape o/aarch64/third_party/lua/lua
>: 10
10
>: 010
8
>: 0b10
2
>: string.byte("\e")
27
>: "Hello, %s" % {"world"}
Hello, world
>: "*" * 3
***
```
`luaL_traceback2` was used to show the stack trace with parameter
values; it's used in `LuaCallWithTrace`, which is used in Redbean to run
Lua code. You should be able to see the extended stack trace by running
something like this: `redbean -e "function a(b)c()end a(2)"` (with
"params" indicating the extended stack trace):
```
stack traceback:
[string "function a(b)c()end a(2)"]:1: in function 'a', params: b = 2;
[string "function a(b)c()end a(2)"]:1: in main chunk
```
@pkulchenko confirmed that I get the expected result with the updated
code.
This is what I did to check that Lua itself still worked:
```
$ cd third_party/lua/test/
$ ape ../../../o/aarch64/third_party/lua/lua all.lua
```
There's one test failure, in `files.lua`:
```
***** FILE 'files.lua'*****
testing i/o
../../../o/aarch64/third_party/lua/lua: files.lua:84: assertion failed!
stack traceback:
[C]: in function 'assert'
files.lua:84: in main chunk
(...tail calls...)
all.lua:195: in main chunk
[C]: in ?
.>>> closing state <<<
```
That isn't a result of these changes; the same test is failing in
master.
The failure is here:
```lua
if not _port then -- invalid seek
local status, msg, code = io.stdin:seek("set", 1000)
assert(not status and type(msg) == "string" and type(code) == "number")
end
```
The test expects a seek to offset 1,000 on stdin to fail — but it
doesn't. `status` ends up being the new offset rather than `nil`.
If I comment out that one test, the remaining tests succeed.
2024-06-16 00:13:08 +00:00
|
|
|
**
|
|
|
|
** [jart] This module contains an implementation of loadlib for Unix systems
|
2022-04-24 16:59:22 +00:00
|
|
|
** that have dlfcn, an implementation for Windows, and a stub for other
|
|
|
|
** systems.
|
|
|
|
*/
|
|
|
|
|
2021-03-02 13:51:10 +00:00
|
|
|
|
Bring Lua to 5.4.6. (#1214)
This essentially re-does the work of #875 on top of master.
This is what I did to check that Cosmo's Lua extensions still worked:
```
$ build/bootstrap/make MODE=aarch64 o/aarch64/third_party/lua/lua
$ ape o/aarch64/third_party/lua/lua
>: 10
10
>: 010
8
>: 0b10
2
>: string.byte("\e")
27
>: "Hello, %s" % {"world"}
Hello, world
>: "*" * 3
***
```
`luaL_traceback2` was used to show the stack trace with parameter
values; it's used in `LuaCallWithTrace`, which is used in Redbean to run
Lua code. You should be able to see the extended stack trace by running
something like this: `redbean -e "function a(b)c()end a(2)"` (with
"params" indicating the extended stack trace):
```
stack traceback:
[string "function a(b)c()end a(2)"]:1: in function 'a', params: b = 2;
[string "function a(b)c()end a(2)"]:1: in main chunk
```
@pkulchenko confirmed that I get the expected result with the updated
code.
This is what I did to check that Lua itself still worked:
```
$ cd third_party/lua/test/
$ ape ../../../o/aarch64/third_party/lua/lua all.lua
```
There's one test failure, in `files.lua`:
```
***** FILE 'files.lua'*****
testing i/o
../../../o/aarch64/third_party/lua/lua: files.lua:84: assertion failed!
stack traceback:
[C]: in function 'assert'
files.lua:84: in main chunk
(...tail calls...)
all.lua:195: in main chunk
[C]: in ?
.>>> closing state <<<
```
That isn't a result of these changes; the same test is failing in
master.
The failure is here:
```lua
if not _port then -- invalid seek
local status, msg, code = io.stdin:seek("set", 1000)
assert(not status and type(msg) == "string" and type(code) == "number")
end
```
The test expects a seek to offset 1,000 on stdin to fail — but it
doesn't. `status` ends up being the new offset rather than `nil`.
If I comment out that one test, the remaining tests succeed.
2024-06-16 00:13:08 +00:00
|
|
|
const char *g_lua_path_default = LUA_PATH_DEFAULT; // [jart]
|
2021-08-06 21:12:11 +00:00
|
|
|
|
2021-03-02 13:51:10 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
** LUA_IGMARK is a mark to ignore all before it when building the
|
|
|
|
** luaopen_ function name.
|
|
|
|
*/
|
|
|
|
#if !defined (LUA_IGMARK)
|
|
|
|
#define LUA_IGMARK "-"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
** LUA_CSUBSEP is the character that replaces dots in submodule names
|
|
|
|
** when searching for a C loader.
|
|
|
|
** LUA_LSUBSEP is the character that replaces dots in submodule names
|
|
|
|
** when searching for a Lua loader.
|
|
|
|
*/
|
|
|
|
#if !defined(LUA_CSUBSEP)
|
|
|
|
#define LUA_CSUBSEP LUA_DIRSEP
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if !defined(LUA_LSUBSEP)
|
|
|
|
#define LUA_LSUBSEP LUA_DIRSEP
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/* prefix for open functions in C libraries */
|
|
|
|
#define LUA_POF "luaopen_"
|
|
|
|
|
|
|
|
/* separator for open functions in C libraries */
|
|
|
|
#define LUA_OFSEP "_"
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
** key for table in the registry that keeps handles
|
|
|
|
** for all loaded C libraries
|
|
|
|
*/
|
|
|
|
static const char *const CLIBS = "_CLIBS";
|
|
|
|
|
|
|
|
#define LIB_FAIL "open"
|
|
|
|
|
|
|
|
|
|
|
|
#define setprogdir(L) ((void)0)
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
** Special type equivalent to '(void*)' for functions in gcc
|
|
|
|
** (to suppress warnings when converting function pointers)
|
|
|
|
*/
|
|
|
|
typedef void (*voidf)(void);
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
** system-dependent functions
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
** unload library 'lib'
|
|
|
|
*/
|
|
|
|
static void lsys_unloadlib (void *lib);
|
|
|
|
|
|
|
|
/*
|
|
|
|
** load C library in file 'path'. If 'seeglb', load with all names in
|
|
|
|
** the library global.
|
|
|
|
** Returns the library; in case of error, returns NULL plus an
|
|
|
|
** error string in the stack.
|
|
|
|
*/
|
|
|
|
static void *lsys_load (lua_State *L, const char *path, int seeglb);
|
|
|
|
|
|
|
|
/*
|
|
|
|
** Try to find a function named 'sym' in library 'lib'.
|
|
|
|
** Returns the function; in case of error, returns NULL plus an
|
|
|
|
** error string in the stack.
|
|
|
|
*/
|
|
|
|
static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(LUA_USE_DLOPEN) /* { */
|
|
|
|
/*
|
|
|
|
** {========================================================================
|
|
|
|
** This is an implementation of loadlib based on the dlfcn interface.
|
|
|
|
** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD,
|
|
|
|
** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least
|
|
|
|
** as an emulation layer on top of native functions.
|
|
|
|
** =========================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
** Macro to convert pointer-to-void* to pointer-to-function. This cast
|
|
|
|
** is undefined according to ISO C, but POSIX assumes that it works.
|
|
|
|
** (The '__extension__' in gnu compilers is only to avoid warnings.)
|
|
|
|
*/
|
|
|
|
#if defined(__GNUC__)
|
|
|
|
#define cast_func(p) (__extension__ (lua_CFunction)(p))
|
|
|
|
#else
|
|
|
|
#define cast_func(p) ((lua_CFunction)(p))
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
static void lsys_unloadlib (void *lib) {
|
|
|
|
dlclose(lib);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void *lsys_load (lua_State *L, const char *path, int seeglb) {
|
|
|
|
void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : RTLD_LOCAL));
|
2021-07-28 16:26:35 +00:00
|
|
|
if (l_unlikely(lib == NULL))
|
|
|
|
lua_pushstring(L, dlerror());
|
2021-03-02 13:51:10 +00:00
|
|
|
return lib;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
|
|
|
|
lua_CFunction f = cast_func(dlsym(lib, sym));
|
2021-07-28 16:26:35 +00:00
|
|
|
if (l_unlikely(f == NULL))
|
|
|
|
lua_pushstring(L, dlerror());
|
2021-03-02 13:51:10 +00:00
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* }====================================================== */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#elif defined(LUA_DL_DLL) /* }{ */
|
|
|
|
/*
|
|
|
|
** {======================================================================
|
|
|
|
** This is an implementation of loadlib for Windows using native functions.
|
|
|
|
** =======================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
** optional flags for LoadLibraryEx
|
|
|
|
*/
|
|
|
|
#if !defined(LUA_LLE_FLAGS)
|
|
|
|
#define LUA_LLE_FLAGS 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#undef setprogdir
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
** Replace in the path (on the top of the stack) any occurrence
|
|
|
|
** of LUA_EXEC_DIR with the executable's path.
|
|
|
|
*/
|
|
|
|
static void setprogdir (lua_State *L) {
|
|
|
|
char buff[MAX_PATH + 1];
|
|
|
|
char *lb;
|
|
|
|
DWORD nsize = sizeof(buff)/sizeof(char);
|
|
|
|
DWORD n = GetModuleFileNameA(NULL, buff, nsize); /* get exec. name */
|
|
|
|
if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL)
|
|
|
|
luaL_error(L, "unable to get ModuleFileName");
|
|
|
|
else {
|
|
|
|
*lb = '\0'; /* cut name on the last '\\' to get the path */
|
|
|
|
luaL_gsub(L, lua_tostring(L, -1), LUA_EXEC_DIR, buff);
|
|
|
|
lua_remove(L, -2); /* remove original string */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void pusherror (lua_State *L) {
|
|
|
|
int error = GetLastError();
|
|
|
|
char buffer[128];
|
|
|
|
if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
|
|
|
|
NULL, error, 0, buffer, sizeof(buffer)/sizeof(char), NULL))
|
|
|
|
lua_pushstring(L, buffer);
|
|
|
|
else
|
|
|
|
lua_pushfstring(L, "system error %d\n", error);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void lsys_unloadlib (void *lib) {
|
|
|
|
FreeLibrary((HMODULE)lib);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void *lsys_load (lua_State *L, const char *path, int seeglb) {
|
|
|
|
HMODULE lib = LoadLibraryExA(path, NULL, LUA_LLE_FLAGS);
|
|
|
|
(void)(seeglb); /* not used: symbols are 'global' by default */
|
|
|
|
if (lib == NULL) pusherror(L);
|
|
|
|
return lib;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
|
|
|
|
lua_CFunction f = (lua_CFunction)(voidf)GetProcAddress((HMODULE)lib, sym);
|
|
|
|
if (f == NULL) pusherror(L);
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* }====================================================== */
|
|
|
|
|
|
|
|
|
|
|
|
#else /* }{ */
|
|
|
|
/*
|
|
|
|
** {======================================================
|
|
|
|
** Fallback for other systems
|
|
|
|
** =======================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
#undef LIB_FAIL
|
|
|
|
#define LIB_FAIL "absent"
|
|
|
|
|
|
|
|
|
|
|
|
#define DLMSG "dynamic libraries not enabled; check your Lua installation"
|
|
|
|
|
|
|
|
|
|
|
|
static void lsys_unloadlib (void *lib) {
|
|
|
|
(void)(lib); /* not used */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void *lsys_load (lua_State *L, const char *path, int seeglb) {
|
|
|
|
(void)(path); (void)(seeglb); /* not used */
|
|
|
|
lua_pushliteral(L, DLMSG);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
|
|
|
|
(void)(lib); (void)(sym); /* not used */
|
|
|
|
lua_pushliteral(L, DLMSG);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* }====================================================== */
|
|
|
|
#endif /* } */
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
** {==================================================================
|
|
|
|
** Set Paths
|
|
|
|
** ===================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
** LUA_PATH_VAR and LUA_CPATH_VAR are the names of the environment
|
|
|
|
** variables that Lua check to set its paths.
|
|
|
|
*/
|
|
|
|
#if !defined(LUA_PATH_VAR)
|
|
|
|
#define LUA_PATH_VAR "LUA_PATH"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if !defined(LUA_CPATH_VAR)
|
|
|
|
#define LUA_CPATH_VAR "LUA_CPATH"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
** return registry.LUA_NOENV as a boolean
|
|
|
|
*/
|
|
|
|
static int noenv (lua_State *L) {
|
|
|
|
int b;
|
|
|
|
lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
|
|
|
|
b = lua_toboolean(L, -1);
|
|
|
|
lua_pop(L, 1); /* remove value */
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
** Set a path
|
|
|
|
*/
|
|
|
|
static void setpath (lua_State *L, const char *fieldname,
|
|
|
|
const char *envname,
|
|
|
|
const char *dft) {
|
|
|
|
const char *dftmark;
|
|
|
|
const char *nver = lua_pushfstring(L, "%s%s", envname, LUA_VERSUFFIX);
|
|
|
|
const char *path = getenv(nver); /* try versioned name */
|
|
|
|
if (path == NULL) /* no versioned environment variable? */
|
|
|
|
path = getenv(envname); /* try unversioned name */
|
|
|
|
if (path == NULL || noenv(L)) /* no environment variable? */
|
|
|
|
lua_pushstring(L, dft); /* use default */
|
|
|
|
else if ((dftmark = strstr(path, LUA_PATH_SEP LUA_PATH_SEP)) == NULL)
|
|
|
|
lua_pushstring(L, path); /* nothing to change */
|
|
|
|
else { /* path contains a ";;": insert default path in its place */
|
|
|
|
size_t len = strlen(path);
|
|
|
|
luaL_Buffer b;
|
|
|
|
luaL_buffinit(L, &b);
|
|
|
|
if (path < dftmark) { /* is there a prefix before ';;'? */
|
|
|
|
luaL_addlstring(&b, path, dftmark - path); /* add it */
|
|
|
|
luaL_addchar(&b, *LUA_PATH_SEP);
|
|
|
|
}
|
|
|
|
luaL_addstring(&b, dft); /* add default */
|
|
|
|
if (dftmark < path + len - 2) { /* is there a suffix after ';;'? */
|
|
|
|
luaL_addchar(&b, *LUA_PATH_SEP);
|
|
|
|
luaL_addlstring(&b, dftmark + 2, (path + len - 2) - dftmark);
|
|
|
|
}
|
|
|
|
luaL_pushresult(&b);
|
|
|
|
}
|
|
|
|
setprogdir(L);
|
|
|
|
lua_setfield(L, -3, fieldname); /* package[fieldname] = path value */
|
|
|
|
lua_pop(L, 1); /* pop versioned variable name ('nver') */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* }================================================================== */
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
** return registry.CLIBS[path]
|
|
|
|
*/
|
|
|
|
static void *checkclib (lua_State *L, const char *path) {
|
|
|
|
void *plib;
|
|
|
|
lua_getfield(L, LUA_REGISTRYINDEX, CLIBS);
|
|
|
|
lua_getfield(L, -1, path);
|
|
|
|
plib = lua_touserdata(L, -1); /* plib = CLIBS[path] */
|
|
|
|
lua_pop(L, 2); /* pop CLIBS table and 'plib' */
|
|
|
|
return plib;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
** registry.CLIBS[path] = plib -- for queries
|
|
|
|
** registry.CLIBS[#CLIBS + 1] = plib -- also keep a list of all libraries
|
|
|
|
*/
|
|
|
|
static void addtoclib (lua_State *L, const char *path, void *plib) {
|
|
|
|
lua_getfield(L, LUA_REGISTRYINDEX, CLIBS);
|
|
|
|
lua_pushlightuserdata(L, plib);
|
|
|
|
lua_pushvalue(L, -1);
|
|
|
|
lua_setfield(L, -3, path); /* CLIBS[path] = plib */
|
|
|
|
lua_rawseti(L, -2, luaL_len(L, -2) + 1); /* CLIBS[#CLIBS + 1] = plib */
|
|
|
|
lua_pop(L, 1); /* pop CLIBS table */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
** __gc tag method for CLIBS table: calls 'lsys_unloadlib' for all lib
|
|
|
|
** handles in list CLIBS
|
|
|
|
*/
|
|
|
|
static int gctm (lua_State *L) {
|
|
|
|
lua_Integer n = luaL_len(L, 1);
|
|
|
|
for (; n >= 1; n--) { /* for each handle, in reverse order */
|
|
|
|
lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */
|
|
|
|
lsys_unloadlib(lua_touserdata(L, -1));
|
|
|
|
lua_pop(L, 1); /* pop handle */
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* error codes for 'lookforfunc' */
|
|
|
|
#define ERRLIB 1
|
|
|
|
#define ERRFUNC 2
|
|
|
|
|
|
|
|
/*
|
|
|
|
** Look for a C function named 'sym' in a dynamically loaded library
|
|
|
|
** 'path'.
|
|
|
|
** First, check whether the library is already loaded; if not, try
|
|
|
|
** to load it.
|
|
|
|
** Then, if 'sym' is '*', return true (as library has been loaded).
|
|
|
|
** Otherwise, look for symbol 'sym' in the library and push a
|
|
|
|
** C function with that symbol.
|
|
|
|
** Return 0 and 'true' or a function in the stack; in case of
|
|
|
|
** errors, return an error code and an error message in the stack.
|
|
|
|
*/
|
|
|
|
static int lookforfunc (lua_State *L, const char *path, const char *sym) {
|
|
|
|
void *reg = checkclib(L, path); /* check loaded C libraries */
|
|
|
|
if (reg == NULL) { /* must load library? */
|
|
|
|
reg = lsys_load(L, path, *sym == '*'); /* global symbols if 'sym'=='*' */
|
|
|
|
if (reg == NULL) return ERRLIB; /* unable to load library */
|
|
|
|
addtoclib(L, path, reg);
|
|
|
|
}
|
|
|
|
if (*sym == '*') { /* loading only library (no function)? */
|
|
|
|
lua_pushboolean(L, 1); /* return 'true' */
|
|
|
|
return 0; /* no errors */
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
lua_CFunction f = lsys_sym(L, reg, sym);
|
|
|
|
if (f == NULL)
|
|
|
|
return ERRFUNC; /* unable to find function */
|
|
|
|
lua_pushcfunction(L, f); /* else create new function */
|
|
|
|
return 0; /* no errors */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int ll_loadlib (lua_State *L) {
|
|
|
|
const char *path = luaL_checkstring(L, 1);
|
|
|
|
const char *init = luaL_checkstring(L, 2);
|
|
|
|
int stat = lookforfunc(L, path, init);
|
2021-07-28 16:26:35 +00:00
|
|
|
if (l_likely(stat == 0)) /* no errors? */
|
2021-03-02 13:51:10 +00:00
|
|
|
return 1; /* return the loaded function */
|
|
|
|
else { /* error; error message is on stack top */
|
|
|
|
luaL_pushfail(L);
|
|
|
|
lua_insert(L, -2);
|
|
|
|
lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init");
|
|
|
|
return 3; /* return fail, error message, and where */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
** {======================================================
|
|
|
|
** 'require' function
|
|
|
|
** =======================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
static int readable (const char *filename) {
|
|
|
|
FILE *f = fopen(filename, "r"); /* try to open file */
|
|
|
|
if (f == NULL) return 0; /* open failed */
|
|
|
|
fclose(f);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
** Get the next name in '*path' = 'name1;name2;name3;...', changing
|
|
|
|
** the ending ';' to '\0' to create a zero-terminated string. Return
|
|
|
|
** NULL when list ends.
|
|
|
|
*/
|
|
|
|
static const char *getnextfilename (char **path, char *end) {
|
|
|
|
char *sep;
|
|
|
|
char *name = *path;
|
|
|
|
if (name == end)
|
|
|
|
return NULL; /* no more names */
|
|
|
|
else if (*name == '\0') { /* from previous iteration? */
|
|
|
|
*name = *LUA_PATH_SEP; /* restore separator */
|
|
|
|
name++; /* skip it */
|
|
|
|
}
|
|
|
|
sep = strchr(name, *LUA_PATH_SEP); /* find next separator */
|
|
|
|
if (sep == NULL) /* separator not found? */
|
|
|
|
sep = end; /* name goes until the end */
|
|
|
|
*sep = '\0'; /* finish file name */
|
|
|
|
*path = sep; /* will start next search from here */
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
** Given a path such as ";blabla.so;blublu.so", pushes the string
|
|
|
|
**
|
|
|
|
** no file 'blabla.so'
|
|
|
|
** no file 'blublu.so'
|
|
|
|
*/
|
|
|
|
static void pusherrornotfound (lua_State *L, const char *path) {
|
|
|
|
luaL_Buffer b;
|
|
|
|
luaL_buffinit(L, &b);
|
|
|
|
luaL_addstring(&b, "no file '");
|
|
|
|
luaL_addgsub(&b, path, LUA_PATH_SEP, "'\n\tno file '");
|
|
|
|
luaL_addstring(&b, "'");
|
|
|
|
luaL_pushresult(&b);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static const char *searchpath (lua_State *L, const char *name,
|
|
|
|
const char *path,
|
|
|
|
const char *sep,
|
|
|
|
const char *dirsep) {
|
|
|
|
luaL_Buffer buff;
|
|
|
|
char *pathname; /* path with name inserted */
|
|
|
|
char *endpathname; /* its end */
|
|
|
|
const char *filename;
|
|
|
|
/* separator is non-empty and appears in 'name'? */
|
|
|
|
if (*sep != '\0' && strchr(name, *sep) != NULL)
|
|
|
|
name = luaL_gsub(L, name, sep, dirsep); /* replace it by 'dirsep' */
|
|
|
|
luaL_buffinit(L, &buff);
|
|
|
|
/* add path to the buffer, replacing marks ('?') with the file name */
|
|
|
|
luaL_addgsub(&buff, path, LUA_PATH_MARK, name);
|
|
|
|
luaL_addchar(&buff, '\0');
|
|
|
|
pathname = luaL_buffaddr(&buff); /* writable list of file names */
|
|
|
|
endpathname = pathname + luaL_bufflen(&buff) - 1;
|
|
|
|
while ((filename = getnextfilename(&pathname, endpathname)) != NULL) {
|
|
|
|
if (readable(filename)) /* does file exist and is readable? */
|
|
|
|
return lua_pushstring(L, filename); /* save and return name */
|
|
|
|
}
|
|
|
|
luaL_pushresult(&buff); /* push path to create error message */
|
|
|
|
pusherrornotfound(L, lua_tostring(L, -1)); /* create error message */
|
|
|
|
return NULL; /* not found */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int ll_searchpath (lua_State *L) {
|
|
|
|
const char *f = searchpath(L, luaL_checkstring(L, 1),
|
|
|
|
luaL_checkstring(L, 2),
|
|
|
|
luaL_optstring(L, 3, "."),
|
|
|
|
luaL_optstring(L, 4, LUA_DIRSEP));
|
|
|
|
if (f != NULL) return 1;
|
|
|
|
else { /* error message is on top of the stack */
|
|
|
|
luaL_pushfail(L);
|
|
|
|
lua_insert(L, -2);
|
|
|
|
return 2; /* return fail + error message */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static const char *findfile (lua_State *L, const char *name,
|
|
|
|
const char *pname,
|
|
|
|
const char *dirsep) {
|
|
|
|
const char *path;
|
|
|
|
lua_getfield(L, lua_upvalueindex(1), pname);
|
|
|
|
path = lua_tostring(L, -1);
|
2021-07-28 16:26:35 +00:00
|
|
|
if (l_unlikely(path == NULL))
|
2021-03-02 13:51:10 +00:00
|
|
|
luaL_error(L, "'package.%s' must be a string", pname);
|
|
|
|
return searchpath(L, name, path, ".", dirsep);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int checkload (lua_State *L, int stat, const char *filename) {
|
2021-07-28 16:26:35 +00:00
|
|
|
if (l_likely(stat)) { /* module loaded successfully? */
|
2021-03-02 13:51:10 +00:00
|
|
|
lua_pushstring(L, filename); /* will be 2nd argument to module */
|
|
|
|
return 2; /* return open function and file name */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return luaL_error(L, "error loading module '%s' from file '%s':\n\t%s",
|
|
|
|
lua_tostring(L, 1), filename, lua_tostring(L, -1));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int searcher_Lua (lua_State *L) {
|
|
|
|
const char *filename;
|
|
|
|
const char *name = luaL_checkstring(L, 1);
|
|
|
|
filename = findfile(L, name, "path", LUA_LSUBSEP);
|
|
|
|
if (filename == NULL) return 1; /* module not found in this path */
|
|
|
|
return checkload(L, (luaL_loadfile(L, filename) == LUA_OK), filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
** Try to find a load function for module 'modname' at file 'filename'.
|
|
|
|
** First, change '.' to '_' in 'modname'; then, if 'modname' has
|
|
|
|
** the form X-Y (that is, it has an "ignore mark"), build a function
|
|
|
|
** name "luaopen_X" and look for it. (For compatibility, if that
|
|
|
|
** fails, it also tries "luaopen_Y".) If there is no ignore mark,
|
|
|
|
** look for a function named "luaopen_modname".
|
|
|
|
*/
|
|
|
|
static int loadfunc (lua_State *L, const char *filename, const char *modname) {
|
|
|
|
const char *openfunc;
|
|
|
|
const char *mark;
|
|
|
|
modname = luaL_gsub(L, modname, ".", LUA_OFSEP);
|
|
|
|
mark = strchr(modname, *LUA_IGMARK);
|
|
|
|
if (mark) {
|
|
|
|
int stat;
|
|
|
|
openfunc = lua_pushlstring(L, modname, mark - modname);
|
|
|
|
openfunc = lua_pushfstring(L, LUA_POF"%s", openfunc);
|
|
|
|
stat = lookforfunc(L, filename, openfunc);
|
|
|
|
if (stat != ERRFUNC) return stat;
|
|
|
|
modname = mark + 1; /* else go ahead and try old-style name */
|
|
|
|
}
|
|
|
|
openfunc = lua_pushfstring(L, LUA_POF"%s", modname);
|
|
|
|
return lookforfunc(L, filename, openfunc);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int searcher_C (lua_State *L) {
|
|
|
|
const char *name = luaL_checkstring(L, 1);
|
|
|
|
const char *filename = findfile(L, name, "cpath", LUA_CSUBSEP);
|
|
|
|
if (filename == NULL) return 1; /* module not found in this path */
|
|
|
|
return checkload(L, (loadfunc(L, filename, name) == 0), filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int searcher_Croot (lua_State *L) {
|
|
|
|
const char *filename;
|
|
|
|
const char *name = luaL_checkstring(L, 1);
|
|
|
|
const char *p = strchr(name, '.');
|
|
|
|
int stat;
|
|
|
|
if (p == NULL) return 0; /* is root */
|
|
|
|
lua_pushlstring(L, name, p - name);
|
|
|
|
filename = findfile(L, lua_tostring(L, -1), "cpath", LUA_CSUBSEP);
|
|
|
|
if (filename == NULL) return 1; /* root not found */
|
|
|
|
if ((stat = loadfunc(L, filename, name)) != 0) {
|
|
|
|
if (stat != ERRFUNC)
|
|
|
|
return checkload(L, 0, filename); /* real error */
|
|
|
|
else { /* open function not found */
|
|
|
|
lua_pushfstring(L, "no module '%s' in file '%s'", name, filename);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lua_pushstring(L, filename); /* will be 2nd argument to module */
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int searcher_preload (lua_State *L) {
|
|
|
|
const char *name = luaL_checkstring(L, 1);
|
|
|
|
lua_getfield(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
|
|
|
|
if (lua_getfield(L, -1, name) == LUA_TNIL) { /* not found? */
|
|
|
|
lua_pushfstring(L, "no field package.preload['%s']", name);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
lua_pushliteral(L, ":preload:");
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void findloader (lua_State *L, const char *name) {
|
|
|
|
int i;
|
|
|
|
luaL_Buffer msg; /* to build error message */
|
|
|
|
/* push 'package.searchers' to index 3 in the stack */
|
2021-07-28 16:26:35 +00:00
|
|
|
if (l_unlikely(lua_getfield(L, lua_upvalueindex(1), "searchers")
|
|
|
|
!= LUA_TTABLE))
|
2021-03-02 13:51:10 +00:00
|
|
|
luaL_error(L, "'package.searchers' must be a table");
|
|
|
|
luaL_buffinit(L, &msg);
|
|
|
|
/* iterate over available searchers to find a loader */
|
|
|
|
for (i = 1; ; i++) {
|
|
|
|
luaL_addstring(&msg, "\n\t"); /* error-message prefix */
|
2021-07-28 16:26:35 +00:00
|
|
|
if (l_unlikely(lua_rawgeti(L, 3, i) == LUA_TNIL)) { /* no more searchers? */
|
2021-03-02 13:51:10 +00:00
|
|
|
lua_pop(L, 1); /* remove nil */
|
|
|
|
luaL_buffsub(&msg, 2); /* remove prefix */
|
|
|
|
luaL_pushresult(&msg); /* create error message */
|
|
|
|
luaL_error(L, "module '%s' not found:%s", name, lua_tostring(L, -1));
|
|
|
|
}
|
|
|
|
lua_pushstring(L, name);
|
|
|
|
lua_call(L, 1, 2); /* call it */
|
|
|
|
if (lua_isfunction(L, -2)) /* did it find a loader? */
|
|
|
|
return; /* module loader found */
|
|
|
|
else if (lua_isstring(L, -2)) { /* searcher returned error message? */
|
|
|
|
lua_pop(L, 1); /* remove extra return */
|
|
|
|
luaL_addvalue(&msg); /* concatenate error message */
|
|
|
|
}
|
|
|
|
else { /* no error message */
|
|
|
|
lua_pop(L, 2); /* remove both returns */
|
|
|
|
luaL_buffsub(&msg, 2); /* remove prefix */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int ll_require (lua_State *L) {
|
|
|
|
const char *name = luaL_checkstring(L, 1);
|
|
|
|
lua_settop(L, 1); /* LOADED table will be at index 2 */
|
|
|
|
lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
|
|
|
|
lua_getfield(L, 2, name); /* LOADED[name] */
|
|
|
|
if (lua_toboolean(L, -1)) /* is it there? */
|
|
|
|
return 1; /* package is already loaded */
|
|
|
|
/* else must load package */
|
|
|
|
lua_pop(L, 1); /* remove 'getfield' result */
|
|
|
|
findloader(L, name);
|
|
|
|
lua_rotate(L, -2, 1); /* function <-> loader data */
|
|
|
|
lua_pushvalue(L, 1); /* name is 1st argument to module loader */
|
|
|
|
lua_pushvalue(L, -3); /* loader data is 2nd argument */
|
|
|
|
/* stack: ...; loader data; loader function; mod. name; loader data */
|
|
|
|
lua_call(L, 2, 1); /* run loader to load module */
|
|
|
|
/* stack: ...; loader data; result from loader */
|
|
|
|
if (!lua_isnil(L, -1)) /* non-nil return? */
|
|
|
|
lua_setfield(L, 2, name); /* LOADED[name] = returned value */
|
|
|
|
else
|
|
|
|
lua_pop(L, 1); /* pop nil */
|
|
|
|
if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */
|
|
|
|
lua_pushboolean(L, 1); /* use true as result */
|
|
|
|
lua_copy(L, -1, -2); /* replace loader result */
|
|
|
|
lua_setfield(L, 2, name); /* LOADED[name] = true */
|
|
|
|
}
|
|
|
|
lua_rotate(L, -2, 1); /* loader data <-> module result */
|
|
|
|
return 2; /* return module result and loader data */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* }====================================================== */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static const luaL_Reg pk_funcs[] = {
|
|
|
|
{"loadlib", ll_loadlib},
|
|
|
|
{"searchpath", ll_searchpath},
|
|
|
|
/* placeholders */
|
|
|
|
{"preload", NULL},
|
|
|
|
{"cpath", NULL},
|
|
|
|
{"path", NULL},
|
|
|
|
{"searchers", NULL},
|
|
|
|
{"loaded", NULL},
|
|
|
|
{NULL, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static const luaL_Reg ll_funcs[] = {
|
|
|
|
{"require", ll_require},
|
|
|
|
{NULL, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static void createsearcherstable (lua_State *L) {
|
Bring Lua to 5.4.6. (#1214)
This essentially re-does the work of #875 on top of master.
This is what I did to check that Cosmo's Lua extensions still worked:
```
$ build/bootstrap/make MODE=aarch64 o/aarch64/third_party/lua/lua
$ ape o/aarch64/third_party/lua/lua
>: 10
10
>: 010
8
>: 0b10
2
>: string.byte("\e")
27
>: "Hello, %s" % {"world"}
Hello, world
>: "*" * 3
***
```
`luaL_traceback2` was used to show the stack trace with parameter
values; it's used in `LuaCallWithTrace`, which is used in Redbean to run
Lua code. You should be able to see the extended stack trace by running
something like this: `redbean -e "function a(b)c()end a(2)"` (with
"params" indicating the extended stack trace):
```
stack traceback:
[string "function a(b)c()end a(2)"]:1: in function 'a', params: b = 2;
[string "function a(b)c()end a(2)"]:1: in main chunk
```
@pkulchenko confirmed that I get the expected result with the updated
code.
This is what I did to check that Lua itself still worked:
```
$ cd third_party/lua/test/
$ ape ../../../o/aarch64/third_party/lua/lua all.lua
```
There's one test failure, in `files.lua`:
```
***** FILE 'files.lua'*****
testing i/o
../../../o/aarch64/third_party/lua/lua: files.lua:84: assertion failed!
stack traceback:
[C]: in function 'assert'
files.lua:84: in main chunk
(...tail calls...)
all.lua:195: in main chunk
[C]: in ?
.>>> closing state <<<
```
That isn't a result of these changes; the same test is failing in
master.
The failure is here:
```lua
if not _port then -- invalid seek
local status, msg, code = io.stdin:seek("set", 1000)
assert(not status and type(msg) == "string" and type(code) == "number")
end
```
The test expects a seek to offset 1,000 on stdin to fail — but it
doesn't. `status` ends up being the new offset rather than `nil`.
If I comment out that one test, the remaining tests succeed.
2024-06-16 00:13:08 +00:00
|
|
|
static const lua_CFunction searchers[] = {
|
|
|
|
searcher_preload,
|
|
|
|
searcher_Lua,
|
|
|
|
searcher_C,
|
|
|
|
searcher_Croot,
|
|
|
|
NULL
|
|
|
|
};
|
2021-03-02 13:51:10 +00:00
|
|
|
int i;
|
|
|
|
/* create 'searchers' table */
|
|
|
|
lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);
|
|
|
|
/* fill it with predefined searchers */
|
|
|
|
for (i=0; searchers[i] != NULL; i++) {
|
|
|
|
lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */
|
|
|
|
lua_pushcclosure(L, searchers[i], 1);
|
|
|
|
lua_rawseti(L, -2, i+1);
|
|
|
|
}
|
|
|
|
lua_setfield(L, -2, "searchers"); /* put it in field 'searchers' */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
** create table CLIBS to keep track of loaded C libraries,
|
|
|
|
** setting a finalizer to close all libraries when closing state.
|
|
|
|
*/
|
|
|
|
static void createclibstable (lua_State *L) {
|
|
|
|
luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS); /* create CLIBS table */
|
|
|
|
lua_createtable(L, 0, 1); /* create metatable for CLIBS */
|
|
|
|
lua_pushcfunction(L, gctm);
|
|
|
|
lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */
|
|
|
|
lua_setmetatable(L, -2);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-08-06 21:12:11 +00:00
|
|
|
static const char *GetLuaPathDefault(void) {
|
Bring Lua to 5.4.6. (#1214)
This essentially re-does the work of #875 on top of master.
This is what I did to check that Cosmo's Lua extensions still worked:
```
$ build/bootstrap/make MODE=aarch64 o/aarch64/third_party/lua/lua
$ ape o/aarch64/third_party/lua/lua
>: 10
10
>: 010
8
>: 0b10
2
>: string.byte("\e")
27
>: "Hello, %s" % {"world"}
Hello, world
>: "*" * 3
***
```
`luaL_traceback2` was used to show the stack trace with parameter
values; it's used in `LuaCallWithTrace`, which is used in Redbean to run
Lua code. You should be able to see the extended stack trace by running
something like this: `redbean -e "function a(b)c()end a(2)"` (with
"params" indicating the extended stack trace):
```
stack traceback:
[string "function a(b)c()end a(2)"]:1: in function 'a', params: b = 2;
[string "function a(b)c()end a(2)"]:1: in main chunk
```
@pkulchenko confirmed that I get the expected result with the updated
code.
This is what I did to check that Lua itself still worked:
```
$ cd third_party/lua/test/
$ ape ../../../o/aarch64/third_party/lua/lua all.lua
```
There's one test failure, in `files.lua`:
```
***** FILE 'files.lua'*****
testing i/o
../../../o/aarch64/third_party/lua/lua: files.lua:84: assertion failed!
stack traceback:
[C]: in function 'assert'
files.lua:84: in main chunk
(...tail calls...)
all.lua:195: in main chunk
[C]: in ?
.>>> closing state <<<
```
That isn't a result of these changes; the same test is failing in
master.
The failure is here:
```lua
if not _port then -- invalid seek
local status, msg, code = io.stdin:seek("set", 1000)
assert(not status and type(msg) == "string" and type(code) == "number")
end
```
The test expects a seek to offset 1,000 on stdin to fail — but it
doesn't. `status` ends up being the new offset rather than `nil`.
If I comment out that one test, the remaining tests succeed.
2024-06-16 00:13:08 +00:00
|
|
|
return g_lua_path_default; // [jart]
|
2021-08-06 21:12:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-02 13:51:10 +00:00
|
|
|
LUAMOD_API int luaopen_package (lua_State *L) {
|
|
|
|
createclibstable(L);
|
|
|
|
luaL_newlib(L, pk_funcs); /* create 'package' table */
|
|
|
|
createsearcherstable(L);
|
|
|
|
/* set paths */
|
2021-08-06 21:12:11 +00:00
|
|
|
setpath(L, "path", LUA_PATH_VAR, g_lua_path_default);
|
2021-03-02 13:51:10 +00:00
|
|
|
setpath(L, "cpath", LUA_CPATH_VAR, LUA_CPATH_DEFAULT);
|
|
|
|
/* store config information */
|
|
|
|
lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n"
|
|
|
|
LUA_EXEC_DIR "\n" LUA_IGMARK "\n");
|
|
|
|
lua_setfield(L, -2, "config");
|
|
|
|
/* set field 'loaded' */
|
|
|
|
luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
|
|
|
|
lua_setfield(L, -2, "loaded");
|
|
|
|
/* set field 'preload' */
|
|
|
|
luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
|
|
|
|
lua_setfield(L, -2, "preload");
|
|
|
|
lua_pushglobaltable(L);
|
|
|
|
lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */
|
|
|
|
luaL_setfuncs(L, ll_funcs, 1); /* open lib into global table */
|
|
|
|
lua_pop(L, 1); /* pop global table */
|
|
|
|
return 1; /* return 'package' table */
|
|
|
|
}
|
|
|
|
|