diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 4f1b3ed5..39d93f48 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -9,6 +9,7 @@ on:
- "craftos2-lua/**"
- "craftos2-lua"
- "resources/CraftOSTest.lua"
+ - "resources/CCT-Tests.patch"
pull_request:
paths:
- "src/**"
@@ -26,7 +27,7 @@ jobs:
steps:
- uses: actions/checkout@v1
- name: Download ROM
- run: sudo git clone https://github.com/MCJack123/craftos2-rom /usr/local/share/craftos
+ run: sudo git clone --branch lua-5.2 https://github.com/MCJack123/craftos2-rom /usr/local/share/craftos
- name: Install dependencies
run: |
sudo apt update
@@ -54,7 +55,7 @@ jobs:
steps:
- uses: actions/checkout@v1
- name: Download ROM
- run: sudo git clone https://github.com/MCJack123/craftos2-rom /usr/local/share/craftos
+ run: sudo git clone --branch lua-5.2 https://github.com/MCJack123/craftos2-rom /usr/local/share/craftos
- name: Install dependencies
run: |
sudo apt update
@@ -87,7 +88,7 @@ jobs:
sudo apt install -y libsdl2-dev libsdl2-mixer-dev libhpdf-dev libpng++-dev libwebp-dev libpoco-dev libncurses5-dev nodejs
- name: Build standalone ROM
run: |
- git clone https://github.com/MCJack123/craftos2-rom
+ git clone --branch lua-5.2 https://github.com/MCJack123/craftos2-rom
cd craftos2-rom
node ../resources/packStandaloneROM.js
cd ..
@@ -115,8 +116,8 @@ jobs:
- uses: actions/checkout@v1
- name: Download ROM & CC:T
run: |
- sudo git clone https://github.com/MCJack123/craftos2-rom /usr/local/share/craftos
- git clone --branch v1.19.4-1.108.0 https://github.com/SquidDev-CC/CC-Tweaked ../CC-Tweaked
+ sudo git clone --branch lua-5.2 https://github.com/MCJack123/craftos2-rom /usr/local/share/craftos
+ git clone --branch v1.20.1-1.109.0 https://github.com/cc-tweaked/CC-Tweaked ../CC-Tweaked
patch -p1 -d ../CC-Tweaked < resources/CCT-Tests.patch
- name: Install dependencies
run: |
@@ -145,7 +146,7 @@ jobs:
steps:
- uses: actions/checkout@v1
- name: Download ROM
- run: git clone https://github.com/MCJack123/craftos2-rom "C:\Program Files\CraftOS-PC"
+ run: git clone --branch lua-5.2 https://github.com/MCJack123/craftos2-rom "C:\Program Files\CraftOS-PC"
- name: Restore vcpkg cache
uses: lukka/run-vcpkg@v10
with:
@@ -188,8 +189,8 @@ jobs:
copy x64\Release\CraftOS-PC.pdb CraftOS-PC.pdb
copy x64\ReleaseC\CraftOS-PC.exe CraftOS-PC_console.exe
copy x64\ReleaseC\CraftOS-PC.pdb CraftOS-PC_console.pdb
- copy craftos2-lua\src\lua51.dll lua51.dll
- copy craftos2-lua\src\lua51.pdb lua51.pdb
+ copy craftos2-lua\src\lua52.dll lua52.dll
+ copy craftos2-lua\src\lua52.pdb lua52.pdb
# Remove buildtrees that kill the cache
Remove-Item vcpkg\buildtrees\* -Force -Recurse -ErrorAction SilentlyContinue
- name: Run CraftOSTest
@@ -210,7 +211,7 @@ jobs:
path: |
CraftOS-PC.exe
CraftOS-PC_console.exe
- lua51.dll
+ lua52.dll
- name: Upload artifact symbols
uses: actions/upload-artifact@v2
with:
@@ -218,5 +219,5 @@ jobs:
path: |
CraftOS-PC.pdb
CraftOS-PC_console.pdb
- lua51.pdb
+ lua52.pdb
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index 02b18b40..abe00621 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -6,7 +6,7 @@
{
"label": "Build",
"type": "shell",
- "command": "make -j8",
+ "command": "make",
"group": {
"kind": "build",
"isDefault": true
diff --git a/CraftOS-PC 2.vcxproj b/CraftOS-PC 2.vcxproj
index ed7ec5a9..0a1164e8 100644
--- a/CraftOS-PC 2.vcxproj
+++ b/CraftOS-PC 2.vcxproj
@@ -350,7 +350,7 @@
$(SolutionDir)craftos2-lua\src;%(AdditionalLibraryDirectories)
- kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;lua51d.lib;shlwapi.lib;ws2_32.lib;wldap32.lib;wer.lib;crypt32.lib;normaliz.lib;SDL2maind.lib;iphlpapi.lib;libpng16d.lib;comctl32.lib;%(AdditionalDependencies)
+ kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;lua52d.lib;shlwapi.lib;ws2_32.lib;wldap32.lib;wer.lib;crypt32.lib;normaliz.lib;SDL2maind.lib;iphlpapi.lib;libpng16d.lib;comctl32.lib;%(AdditionalDependencies)
Console
/VERBOSE:LIB %(AdditionalOptions)
true
@@ -367,12 +367,13 @@
true
stdc11
26812;4005
+ true
false
- copy craftos2-lua\src\lua51d.dll x64\Debug\lua51d.dll
+ copy craftos2-lua\src\lua52d.dll x64\Debug\lua52d.dll
@@ -405,7 +406,7 @@
$(SolutionDir)craftos2-lua\src;%(AdditionalLibraryDirectories)
- kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;lua51.lib;shlwapi.lib;ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;SDL2main.lib;iphlpapi.lib;libpng16.lib;comctl32.lib;%(AdditionalDependencies)
+ kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;lua52.lib;shlwapi.lib;ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;SDL2main.lib;iphlpapi.lib;libpng16.lib;comctl32.lib;%(AdditionalDependencies)
Windows
true
@@ -420,12 +421,13 @@
stdc11
26812;4005
stdcpp17
+ true
false
- copy craftos2-lua\src\lua51.dll x64\Release\lua51.dll
+ copy craftos2-lua\src\lua52.dll x64\Release\lua52.dll
@@ -456,7 +458,7 @@
$(SolutionDir)craftos2-lua\src;%(AdditionalLibraryDirectories)
- kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;lua51.lib;shlwapi.lib;ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;SDL2main.lib;iphlpapi.lib;libpng16.lib;comctl32.lib;%(AdditionalDependencies)
+ kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;lua52.lib;shlwapi.lib;ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;SDL2main.lib;iphlpapi.lib;libpng16.lib;comctl32.lib;%(AdditionalDependencies)
Windows
true
@@ -471,12 +473,13 @@
stdc11
26812;4005
stdcpp17
+ true
false
- copy craftos2-lua\src\lua51.dll x64\ReleaseStandalone\lua51.dll
+ copy craftos2-lua\src\lua52.dll x64\ReleaseStandalone\lua52.dll
@@ -507,7 +510,7 @@
$(SolutionDir)craftos2-lua\src;%(AdditionalLibraryDirectories)
- kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;lua51.lib;sdl2.lib;shlwapi.lib;ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;SDL2main.lib;SDL2_mixer.lib;iphlpapi.lib;libpng16.lib;comctl32.lib;%(AdditionalDependencies)
+ kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;lua52.lib;sdl2.lib;shlwapi.lib;ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;SDL2main.lib;SDL2_mixer.lib;iphlpapi.lib;libpng16.lib;comctl32.lib;%(AdditionalDependencies)
Console
true
@@ -522,12 +525,13 @@
stdc17
26812;4005
stdcpp17
+ true
false
- copy craftos2-lua\src\lua51.dll x64\ReleaseC\lua51.dll
+ copy craftos2-lua\src\lua52.dll x64\ReleaseC\lua52.dll
diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md
index 340c793f..2a19ed83 100644
--- a/DOCUMENTATION.md
+++ b/DOCUMENTATION.md
@@ -181,14 +181,14 @@ int multiply(lua_State *L) {
_declspec(dllexport)
#endif
int luaopen_example(lua_State *L) {
- struct luaL_reg M[] =
+ struct luaL_Reg M[] =
{
{"addition", addition},
{"multiply", multiply},
{NULL,NULL}
};
- luaL_register(L, "example", M);
+ luaL_Register(L, "example", M);
return 1;
}
diff --git a/api/Computer.hpp b/api/Computer.hpp
index 26f79559..738fa001 100644
--- a/api/Computer.hpp
+++ b/api/Computer.hpp
@@ -132,7 +132,7 @@ struct Computer {
std::mutex openWebsocketsMutex;
std::vector> startupCallbacks; // List of functions to call when starting up + a userdata to pass as the first argument
- // The following fields are available in API version 10.9 and later.
+ // The following fields are available in API version 12.0 and later.
std::vector droppedFiles; // List of files that were dropped in the current drop set
private:
diff --git a/api/lib.hpp b/api/lib.hpp
index 35d5933d..83a7d72b 100644
--- a/api/lib.hpp
+++ b/api/lib.hpp
@@ -24,9 +24,9 @@ struct Computer;
/// The current version of plugin support.
#if defined(_WIN32) && defined(_DEBUG)
-#define PLUGIN_VERSION 100010
+#define PLUGIN_VERSION 100012
#else
-#define PLUGIN_VERSION 10
+#define PLUGIN_VERSION 12
#endif
/// Most OS's use UTF-8/ASCII for path storage; however, Windows is contrarian and uses UTF-16.
diff --git a/api/peripheral.hpp b/api/peripheral.hpp
index 91bace3a..7a02bbf3 100644
--- a/api/peripheral.hpp
+++ b/api/peripheral.hpp
@@ -56,9 +56,7 @@ class peripheral {
virtual int call(lua_State *L, const char * method)=0;
// This function is deprecated, and no longer works. In fact, it did not work
// in any version of the API. Just leave this as-is.
-#if __cplusplus >= 201402L
[[deprecated]]
-#endif
virtual void update() {}
// This function should return a library_t containing the names of all of the
// methods available to the peripheral. Only the keys, name, and size members
diff --git a/craftos2-lua b/craftos2-lua
index c2da216b..23a41108 160000
--- a/craftos2-lua
+++ b/craftos2-lua
@@ -1 +1 @@
-Subproject commit c2da216bb6375d2032ff3810fef9ff2c1d922d82
+Subproject commit 23a41108e84c59a28c542a5ef5306ef79a849fbe
diff --git a/examples/ccemux.cpp b/examples/ccemux.cpp
index 698c1e33..8e6347e3 100644
--- a/examples/ccemux.cpp
+++ b/examples/ccemux.cpp
@@ -145,11 +145,11 @@ static int ccemux_getVersion(lua_State *L) {
static int ccemux_openEmu(lua_State *L) {
Computer * comp = get_comp(L);
- int id = 0;
+ int id = luaL_optinteger(L, 1, -1);
if (lua_isnumber(L, 1)) id = (int)lua_tointeger(L, 1);
- else if (!lua_isnoneornil(L, 1)) luaL_typerror(L, 1, "number");
- else {
+ if (id < 0) {
std::lock_guard lock(comp->peripherals_mutex);
+ id = 0;
while (functions->getComputerById(id) != NULL) id++;
}
if (functions->attachPeripheral(comp, "computer_" + std::to_string(id), "computer", NULL, "") == NULL) lua_pushnil(L);
@@ -233,7 +233,7 @@ static int ccemux_detach(lua_State *L) {
return 0;
}
-static struct luaL_reg M[] = {
+static struct luaL_Reg M[] = {
{"getVersion", ccemux_getVersion},
{"openEmu", ccemux_openEmu},
{"closeEmu", ccemux_closeEmu},
@@ -252,7 +252,7 @@ static PluginInfo info("ccemux", 3);
extern "C" {
DLLEXPORT int luaopen_ccemux(lua_State *L) {
- luaL_register(L, lua_tostring(L, 1), M);
+ luaL_newlib(L, M);
functions->addVirtualMount(get_comp(L), emuROM, "/rom");
return 1;
}
diff --git a/examples/ccemux.vcxproj b/examples/ccemux.vcxproj
index 59f7435b..c08bf5fc 100644
--- a/examples/ccemux.vcxproj
+++ b/examples/ccemux.vcxproj
@@ -146,7 +146,7 @@
true
true
false
- kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;SDL2.lib;lua51.lib;%(AdditionalDependencies)
+ kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;SDL2.lib;lua52.lib;%(AdditionalDependencies)
$(SolutionDir)craftos2-lua\src
@@ -212,7 +212,7 @@
Windows
true
false
- kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;SDL2d.lib;lua51d.lib;%(AdditionalDependencies)
+ kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;SDL2d.lib;lua52d.lib;%(AdditionalDependencies)
$(SolutionDir)craftos2-lua\src
diff --git a/examples/plugin_base.cpp b/examples/plugin_base.cpp
index 7786e863..27863dda 100644
--- a/examples/plugin_base.cpp
+++ b/examples/plugin_base.cpp
@@ -15,7 +15,7 @@ extern "C" {
// add your functions here...
-static luaL_reg M[] = {
+static luaL_Reg M[] = {
// add functions here as {name, function}...
{NULL, NULL}
};
@@ -26,7 +26,7 @@ static PluginInfo info("myplugin");
extern "C" {
// replace "myplugin" with the plugin name
DLLEXPORT int luaopen_myplugin(lua_State *L) {
- luaL_register(L, "myplugin", M);
+ luaL_newlib(L, M);
return 1;
}
diff --git a/resources/CCT-Test-Bootstrap.lua b/resources/CCT-Test-Bootstrap.lua
index 86cfc4c7..c0bdccc8 100644
--- a/resources/CCT-Test-Bootstrap.lua
+++ b/resources/CCT-Test-Bootstrap.lua
@@ -7,7 +7,7 @@ end
for _,v in ipairs(fs.list("/")) do if not fs.isReadOnly(v) then fs.delete(v) end end
_G._CCPC_FIRST_RUN = nil
_G._CCPC_UPDATED_VERSION = nil
-local logfile = io.open("test-log.txt", "w")
+local logfile = assert(io.open("test-log.txt", "w"))
io.output(logfile)
shell.run("/test-rom/mcfly /test-rom/spec")
logfile:close()
diff --git a/resources/CCT-Tests.patch b/resources/CCT-Tests.patch
index 6e41011c..a910cd85 100644
--- a/resources/CCT-Tests.patch
+++ b/resources/CCT-Tests.patch
@@ -9,7 +9,15 @@ diff -ruN --strip -x .DS_Store projects/core/src/test/resources/test-rom/mcfly.l
diff -ruN --strip -x .DS_Store projects/core/src/test/resources/test-rom/spec/apis/fs_spec.lua b/projects/core/src/test/resources/test-rom/spec/apis/fs_spec.lua
--- a/projects/core/src/test/resources/test-rom/spec/apis/fs_spec.lua 2020-06-29 02:52:34.000000000 -0400
+++ b/projects/core/src/test/resources/test-rom/spec/apis/fs_spec.lua 2020-06-29 01:24:00.000000000 -0400
-@@ -122,7 +122,7 @@
+@@ -88,7 +88,6 @@
+ describe("fs.list", function()
+ it("fails on files", function()
+ expect.error(fs.list, "rom/startup.lua"):eq("/rom/startup.lua: Not a directory")
+- expect.error(fs.list, "startup.lua"):eq("/startup.lua: Not a directory")
+ end)
+
+ it("fails on non-existent nodes", function()
+@@ -122,7 +121,7 @@
describe("fs.makeDir", function()
it("fails on files", function()
@@ -18,7 +26,7 @@ diff -ruN --strip -x .DS_Store projects/core/src/test/resources/test-rom/spec/ap
end)
it("fails on read-only mounts", function()
-@@ -171,7 +171,7 @@
+@@ -171,7 +170,7 @@
end)
it("returns the capacity on the root mount", function()
diff --git a/resources/CraftOS-PC.exe.manifest b/resources/CraftOS-PC.exe.manifest
index c00aaf30..c7645a3d 100644
--- a/resources/CraftOS-PC.exe.manifest
+++ b/resources/CraftOS-PC.exe.manifest
@@ -3,7 +3,7 @@
Advanced ComputerCraft Emulator
diff --git a/resources/CraftOSTest.lua b/resources/CraftOSTest.lua
index 1e649ffa..404cde65 100644
--- a/resources/CraftOSTest.lua
+++ b/resources/CraftOSTest.lua
@@ -7,9 +7,9 @@ if config and config.add then
end
term.setCursorPos(1, 1)
term.setTextColor(colors.lightBlue)
-print("CraftOSTest 1.8")
+print("CraftOSTest 1.9")
term.setTextColor(colors.white)
-if os.version() ~= "CraftOS 1.8" then error("This test is for CraftOS 1.8.") end
+if os.version() ~= "CraftOS 1.9" then error("This test is for CraftOS 1.9.") end
local api_tests = {}
local api = nil
diff --git a/resources/Info.plist b/resources/Info.plist
index 2f2a351d..57866fc1 100644
--- a/resources/Info.plist
+++ b/resources/Info.plist
@@ -21,13 +21,13 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 2.7.6
+ 2.8
CFBundleSignature
????
LSApplicationCategoryType
Unknown
CFBundleVersion
- 2.7.6
+ 2.8
NSHumanReadableCopyright
Copyright (C) 2019-2023 JackMacWindows.
NSHighResolutionCapable
diff --git a/src/Computer.cpp b/src/Computer.cpp
index fe9564f5..91ca8560 100644
--- a/src/Computer.cpp
+++ b/src/Computer.cpp
@@ -49,6 +49,7 @@ std::unordered_set orphanedTerminals;
// Context structure for yieldable load
struct load_ctx {
+ int id;
std::thread thread;
std::mutex lock;
std::condition_variable notify;
@@ -218,6 +219,10 @@ static const char * file_reader(lua_State *L, void * ud, size_t *size) {
// computer thread that it's done. The results are copied back to the
// main state, and the loader returns.
+std::vector load_ctx_stack; // since Lua 5.2+ stores context as ints, we can't store a pointer -
+ // instead, all pointers are placed in this vector and the context is an offset here
+ // (maybe we can store a stack index instead?)
+
static const char * yield_loader(lua_State *L, void* data, size_t *size) {
load_ctx* ctx = (load_ctx*)data;
lua_State *coro = lua_newthread(L);
@@ -226,7 +231,7 @@ static const char * yield_loader(lua_State *L, void* data, size_t *size) {
ctx->argcount = 0;
int status;
do {
- status = lua_resume(coro, ctx->argcount);
+ status = lua_resume(coro, ctx->coro, ctx->argcount);
if (status == 0) {
if (lua_isnoneornil(coro, 1)) return NULL;
else if (lua_isstring(coro, 1)) return lua_tolstring(coro, 1, size);
@@ -249,7 +254,7 @@ static const char * yield_loader(lua_State *L, void* data, size_t *size) {
}
static void load_thread(load_ctx* ctx) {
- int status = lua_load52(ctx->coro, yield_loader, ctx, ctx->name, ctx->mode);
+ int status = lua_load(ctx->coro, yield_loader, ctx, ctx->name, NULL);
if (ctx->status == 3) return;
std::unique_lock lock(ctx->lock);
if (status == 0) {
@@ -274,6 +279,8 @@ static int load_ctx_gc(lua_State *L) {
}
ctx->thread.join();
}
+ load_ctx_stack[ctx->id] = NULL;
+ while (!load_ctx_stack.empty() && load_ctx_stack[load_ctx_stack.size()-1] == NULL) load_ctx_stack.erase(load_ctx_stack.end()-1);
ctx->thread.~thread();
ctx->lock.~mutex();
ctx->notify.~condition_variable();
@@ -282,8 +289,9 @@ static int load_ctx_gc(lua_State *L) {
static int yieldable_load(lua_State *L) {
load_ctx* ctx;
- if (lua_vcontext(L)) {
- ctx = (load_ctx*)lua_vcontext(L);
+ int ctxid = 0;
+ if (lua_getctx(L, &ctxid) == LUA_YIELD) {
+ ctx = load_ctx_stack[ctxid];
std::unique_lock lock(ctx->lock);
ctx->status = 0;
ctx->L = L;
@@ -299,7 +307,7 @@ static int yieldable_load(lua_State *L) {
if (status == 0) { /* OK? */
if (env != 0) { /* 'env' parameter? */
lua_pushvalue(L, env); /* environment for loaded function */
- if (!lua_setfenv(L, -2)) /* set it as 1st upvalue */
+ if (!lua_setupvalue(L, 1, -2)) /* set it as 1st upvalue */
lua_pop(L, 1); /* remove 'env' if not used by previous call */
}
return 1;
@@ -327,6 +335,11 @@ static int yieldable_load(lua_State *L) {
ctx->envidx = lua_isnoneornil(L, 4) ? 0 : 4;
ctx->L = L;
ctx->coro = lua_newthread(L);
+ for (; ctxid < load_ctx_stack.size(); ctxid++)
+ if (load_ctx_stack[ctxid] == NULL) break;
+ if (ctxid == load_ctx_stack.size()) load_ctx_stack.push_back(ctx);
+ else load_ctx_stack[ctxid] = ctx;
+ ctx->id = ctxid;
lua_pushvalue(L, 1);
lua_xmove(L, ctx->coro, 1);
}
@@ -336,12 +349,12 @@ static int yieldable_load(lua_State *L) {
if (ctx->status == 1) {
int argcount = ctx->argcount;
ctx->argcount = lua_gettop(L) - ctx->argcount;
- return lua_vyield(L, argcount, ctx);
+ return lua_yieldk(L, argcount, ctxid, yieldable_load);
} else if (ctx->status == 3) return 0; // this should never happen
}
if (ctx->argcount == 1 && ctx->envidx != 0) { /* OK? */
lua_pushvalue(L, ctx->envidx); /* environment for loaded function */
- if (!lua_setfenv(L, -2)) /* set it as 1st upvalue */
+ if (!lua_setupvalue(L, 1, -2)) /* set it as 1st upvalue */
lua_pop(L, 1); /* remove 'env' if not used by previous call */
}
return ctx->argcount;
@@ -353,6 +366,7 @@ extern int mobile_luaopen(lua_State *L);
static const luaL_Reg lualibs[] = {
{"", luaopen_base},
+ {LUA_COLIBNAME, luaopen_coroutine},
{LUA_OSLIBNAME, luaopen_os},
{LUA_TABLIBNAME, luaopen_table},
{LUA_STRLIBNAME, luaopen_string},
@@ -434,10 +448,10 @@ void runComputer(Computer * self, const path_t& bios_name, const std::string& bi
// Load libraries
const luaL_Reg *lib = lualibs;
+ /* call open functions from 'loadedlibs' and set results to global table */
for (; lib->func; lib++) {
- lua_pushcfunction(L, lib->func);
- lua_pushstring(L, lib->name);
- lua_call(L, 1, 0);
+ luaL_requiref(L, lib->name, lib->func, 1);
+ lua_pop(L, 1); /* remove lib */
}
lua_getglobal(L, "os");
lua_getfield(L, -1, "date");
@@ -465,6 +479,8 @@ void runComputer(Computer * self, const path_t& bios_name, const std::string& bi
// Override the default loader to allow yielding from `load`
lua_pushcfunction(L, yieldable_load);
lua_setglobal(L, "load");
+ // Disable bytecode
+ lua_setdisableflags(L, LUA_DISABLE_BYTECODE);
}
// Load any plugins available
@@ -531,6 +547,8 @@ void runComputer(Computer * self, const path_t& bios_name, const std::string& bi
lua_setfield(L, -2, "addListener");
lua_pushnil(L);
lua_setfield(L, -2, "removeListener");
+ lua_pushnil(L);
+ lua_setfield(L, -2, "websocketServer");
lua_pop(L, 1);
}
lua_getglobal(L, "debug");
@@ -541,14 +559,20 @@ void runComputer(Computer * self, const path_t& bios_name, const std::string& bi
lua_pop(L, 1);
}
if (config.serverMode) {
- lua_getglobal(L, "http");
- lua_pushnil(L);
- lua_setfield(L, -2, "addListener");
- lua_pushnil(L);
- lua_setfield(L, -2, "removeListener");
- lua_pop(L, 1);
+ if (config.http_enable) {
+ lua_getglobal(L, "http");
+ lua_pushnil(L);
+ lua_setfield(L, -2, "addListener");
+ lua_pushnil(L);
+ lua_setfield(L, -2, "removeListener");
+ lua_pushnil(L);
+ lua_setfield(L, -2, "websocketServer");
+ lua_pop(L, 1);
+ }
lua_pushnil(L);
lua_setglobal(L, "mounter");
+ lua_pushnil(L);
+ lua_setglobal(L, "config");
}
// Set default globals
@@ -621,17 +645,17 @@ void runComputer(Computer * self, const path_t& bios_name, const std::string& bi
path_t bios_path_expanded = getROMPath() / bios_name;
std::ifstream bios_file(bios_path_expanded);
if (bios_file.is_open()) {
- status = lua_load(self->coro, file_reader, &bios_file, "@bios.lua");
+ status = lua_load(self->coro, file_reader, &bios_file, "@bios.lua", NULL);
bios_file.close();
} else {
status = LUA_ERRFILE;
- lua_pushstring(L, strerror(errno));
+ lua_pushstring(self->coro, strerror(errno));
}
#endif
if (status || !lua_isfunction(self->coro, -1)) {
/* If something went wrong, error message is at the top of */
/* the stack */
- fprintf(stderr, "Couldn't load BIOS: %s (%s). Please make sure the CraftOS ROM is installed properly. (See https://www.craftos-pc.cc/docs/error-messages for more information.)\n", bios_path_expanded.string().c_str(), lua_tostring(L, -1));
+ fprintf(stderr, "Couldn't load BIOS: %s (%s). Please make sure the CraftOS ROM is installed properly. (See https://www.craftos-pc.cc/docs/error-messages for more information.)\n", bios_path_expanded.string().c_str(), lua_tostring(self->coro, -1));
if (::config.standardsMode) displayFailure(self->term, "Error loading bios.lua");
else queueTask([bios_path_expanded](void* term)->void*{
((Terminal*)term)->showMessage(
@@ -660,13 +684,14 @@ void runComputer(Computer * self, const path_t& bios_name, const std::string& bi
if (config.abortTimeout > 0 || config.standardsMode) self->eventTimeout = SDL_AddTimer(::config.standardsMode ? 7000 : ::config.abortTimeout, eventTimeoutEvent, self);
#endif
while (status == LUA_YIELD && self->running == 1) {
- status = lua_resume(self->coro, narg);
+ status = lua_resume(self->coro, NULL, narg);
if (status == LUA_YIELD) {
- if (lua_gettop(self->coro) && lua_isstring(self->coro, -1)) narg = getNextEvent(self->coro, std::string(lua_tostring(self->coro, -1), lua_strlen(self->coro, -1)));
+ if (lua_gettop(self->coro) && lua_isstring(self->coro, -1)) narg = getNextEvent(self->coro, std::string(lua_tostring(self->coro, -1), lua_rawlen(self->coro, -1)));
else narg = getNextEvent(self->coro, "");
} else if (status != 0 && self->running == 1) {
// Catch runtime error
self->running = 0;
+ lua_checkstack(self->coro, 4);
lua_pushcfunction(self->coro, termPanic);
if (lua_isstring(self->coro, -2)) lua_pushvalue(self->coro, -2);
else lua_pushnil(self->coro);
diff --git a/src/apis/config.cpp b/src/apis/config.cpp
index 8d5c5f0d..3f198329 100644
--- a/src/apis/config.cpp
+++ b/src/apis/config.cpp
@@ -165,7 +165,7 @@ static int config_set(lua_State *L) {
} else luaL_error(L, "Configuration option 'mount_mode' is protected");
} setConfigSetting(disable_lua51_features, boolean);
else if (strcmp(name, "default_computer_settings") == 0)
- config.default_computer_settings = std::string(luaL_checkstring(L, 2), lua_strlen(L, 2));
+ config.default_computer_settings = std::string(luaL_checkstring(L, 2), lua_rawlen(L, 2));
setConfigSetting(logErrors, boolean);
setConfigSettingI(computerSpaceLimit);
setConfigSettingI(maximumFilesOpen);
@@ -198,10 +198,14 @@ static int config_set(lua_State *L) {
setConfigSetting(monitorsUseMouseEvents, boolean);
setConfigSettingI(defaultWidth);
setConfigSettingI(defaultHeight);
+ else if (strcmp(name, "standardsMode") == 0) {
+ config.standardsMode = lua_toboolean(L, 2);
+ lua_setdisableflags(L, config.standardsMode ? LUA_DISABLE_BYTECODE : 0);
+ }
setConfigSetting(standardsMode, boolean);
setConfigSetting(useHardwareRenderer, boolean);
else if (strcmp(name, "preferredHardwareDriver") == 0)
- config.preferredHardwareDriver = std::string(luaL_checkstring(L, 2), lua_strlen(L, 2));
+ config.preferredHardwareDriver = std::string(luaL_checkstring(L, 2), lua_rawlen(L, 2));
setConfigSetting(useVsync, boolean);
setConfigSetting(http_websocket_enabled, boolean);
setConfigSettingI(http_max_websockets);
@@ -224,7 +228,7 @@ static int config_set(lua_State *L) {
config.http_whitelist.clear();
lua_rawgeti(L, 2, 1);
for (int i = 1; lua_isstring(L, -1); i++) {
- config.http_whitelist.push_back(luaL_tostring(L, -1));
+ config.http_whitelist.push_back(luaL_tolstring(L, -1, NULL));
lua_pop(L, 1);
lua_rawgeti(L, 2, i+1);
}
@@ -233,7 +237,7 @@ static int config_set(lua_State *L) {
config.http_blacklist.clear();
lua_rawgeti(L, 2, 1);
for (int i = 1; lua_isstring(L, -1); i++) {
- config.http_blacklist.push_back(luaL_tostring(L, i));
+ config.http_blacklist.push_back(luaL_tolstring(L, i, NULL));
lua_pop(L, 1);
lua_rawgeti(L, 2, i+1);
}
@@ -242,7 +246,7 @@ static int config_set(lua_State *L) {
switch (std::get<0>(userConfig[name])) {
case 0: config.pluginData[name] = lua_toboolean(L, 2) ? "true" : "false"; break;
case 1: config.pluginData[name] = std::to_string(luaL_checkinteger(L, 2)); break;
- case 2: config.pluginData[name] = std::string(luaL_checkstring(L, 2), lua_strlen(L, 2)); break;
+ case 2: config.pluginData[name] = std::string(luaL_checkstring(L, 2), lua_rawlen(L, 2)); break;
case 3: return luaL_error(L, "Invalid type"); // maybe fix this later?
}
if (std::get<1>(userConfig[name]) != nullptr) {
diff --git a/src/apis/fs.cpp b/src/apis/fs.cpp
index ebe96ca5..1fd40b8a 100644
--- a/src/apis/fs.cpp
+++ b/src/apis/fs.cpp
@@ -154,16 +154,17 @@ static int fs_list(lua_State *L) {
lastCFunction = __func__;
std::string str = checkstring(L, 1);
const std::vector possible_paths = fixpath_multiple(get_comp(L), str);
- if (possible_paths.empty()) err(L, 1, "Not a directory");
+ if (possible_paths.empty()) err(L, 1, "No such file");
bool gotdir = false;
std::set entries;
for (const path_t& path : possible_paths) {
if (std::regex_search((*path.begin()).native(), pathregex("^\\d+:"))) {
try {
const FileEntry &d = get_comp(L)->virtualMounts[(unsigned)std::stoul((*path.begin()).native())]->path(path.lexically_relative(*path.begin()));
- gotdir = true;
- if (d.isDir) for (const auto& p : d.dir) entries.insert(p.first);
- else gotdir = false;
+ if (d.isDir) {
+ gotdir = true;
+ for (const auto& p : d.dir) entries.insert(p.first);
+ }
} catch (...) {continue;}
} else {
std::error_code e;
@@ -437,7 +438,14 @@ static int fs_open(lua_State *L) {
lastCFunction = __func__;
Computer * computer = get_comp(L);
const char * mode = luaL_checkstring(L, 2);
- if ((mode[0] != 'r' && mode[0] != 'w' && mode[0] != 'a') || (!(mode[1] == 'b' && mode[2] == '\0') && mode[1] != '\0')) luaL_error(L, "%s: Unsupported mode", mode);
+ if (
+ (mode[0] != 'r' && mode[0] != 'w' && mode[0] != 'a') ||
+ (
+ !(mode[1] == '+' && mode[2] == 'b' && mode[3] == '\0') &&
+ !(mode[1] == '+' && mode[2] == '\0') &&
+ !(mode[1] == 'b' && mode[2] == '\0') &&
+ mode[1] != '\0'
+ )) luaL_error(L, "%s: Unsupported mode", mode);
std::string str = checkstring(L, 1);
const path_t path = mode[0] == 'r' ? fixpath(get_comp(L), str, true) : fixpath_mkdir(get_comp(L), str);
if (path.empty()) {
@@ -466,7 +474,7 @@ static int fs_open(lua_State *L) {
if (d.isDir) {
lua_remove(L, fpid);
lua_pushnil(L);
- if (strcmp(mode, "r") == 0 || strcmp(mode, "rb") == 0) lua_pushfstring(L, "/%s: No such file", fixpath(computer, str, false, false).string().c_str());
+ if (strchr(mode, 'r') != NULL) lua_pushfstring(L, "/%s: Not a file", fixpath(computer, str, false, false).string().c_str());
else lua_pushfstring(L, "/%s: Cannot write to directory", fixpath(computer, str, false, false).string().c_str());
return 2;
}
@@ -484,7 +492,7 @@ static int fs_open(lua_State *L) {
std::error_code e;
if (fs::is_directory(path, e)) {
lua_pushnil(L);
- if (strcmp(mode, "r") == 0 || strcmp(mode, "rb") == 0) lua_pushfstring(L, "/%s: No such file", fixpath(computer, str, false, false).string().c_str());
+ if (strchr(mode, 'r') != NULL) lua_pushfstring(L, "/%s: Not a file", fixpath(computer, str, false, false).string().c_str());
else lua_pushfstring(L, "/%s: Cannot write to directory", fixpath(computer, str, false, false).string().c_str());
return 2;
}
@@ -505,14 +513,21 @@ static int fs_open(lua_State *L) {
std::fstream ** fp = (std::fstream**)lua_newuserdata(L, sizeof(std::fstream*));
fpid = lua_gettop(L);
std::ios::openmode flags = std::ios::binary;
- if (strchr(mode, 'r')) flags |= std::ios::in;
- else if (strchr(mode, 'w')) flags |= std::ios::out | std::ios::trunc;
- else if (strchr(mode, 'a')) flags |= std::ios::in | std::ios::out | std::ios::ate;
+ if (strchr(mode, 'r')) {
+ flags |= std::ios::in;
+ if (strchr(mode, '+')) flags |= std::ios::out;
+ } else if (strchr(mode, 'w')) {
+ flags |= std::ios::out | std::ios::trunc;
+ if (strchr(mode, '+')) flags |= std::ios::in;
+ } else if (strchr(mode, 'a')) {
+ flags |= std::ios::in | std::ios::out | std::ios::ate;
+ if (strchr(mode, '+')) flags |= std::ios::in;
+ }
*fp = new std::fstream(path, flags);
if (!(*fp)->is_open()) {
bool ok = false;
if (strchr(mode, 'a')) {
- (*fp)->open(path, std::ios::out | std::ios::trunc);
+ (*fp)->open(path, (flags & ~std::ios::ate) | std::ios::trunc);
ok = (*fp)->is_open();
}
if (!ok) {
@@ -540,42 +555,24 @@ static int fs_open(lua_State *L) {
lua_pushvalue(L, fpid);
lua_pushcclosure(L, fs_handle_close, 1);
lua_settable(L, -3);
- if (strcmp(mode, "r") == 0) {
- lua_pushstring(L, "readAll");
- lua_pushvalue(L, fpid);
- lua_pushcclosure(L, fs_handle_readAll, 1);
- lua_settable(L, -3);
-
- lua_pushstring(L, "readLine");
- lua_pushvalue(L, fpid);
- lua_pushboolean(L, false);
- lua_pushcclosure(L, fs_handle_readLine, 2);
- lua_settable(L, -3);
-
- lua_pushstring(L, "read");
- lua_pushvalue(L, fpid);
- lua_pushcclosure(L, fs_handle_readChar, 1);
- lua_settable(L, -3);
- } else if (strcmp(mode, "w") == 0 || strcmp(mode, "a") == 0) {
- lua_pushstring(L, "write");
- lua_pushvalue(L, fpid);
- lua_pushcclosure(L, fs_handle_writeString, 1);
- lua_settable(L, -3);
- lua_pushstring(L, "writeLine");
- lua_pushvalue(L, fpid);
- lua_pushcclosure(L, fs_handle_writeLine, 1);
- lua_settable(L, -3);
+ lua_pushstring(L, "seek");
+ lua_pushvalue(L, fpid);
+ lua_pushcclosure(L, fs_handle_seek, 1);
+ lua_settable(L, -3);
- lua_pushstring(L, "flush");
- lua_pushvalue(L, fpid);
- lua_pushcclosure(L, fs_handle_flush, 1);
- lua_settable(L, -3);
- } else if (strcmp(mode, "rb") == 0) {
- lua_pushstring(L, "read");
- lua_pushvalue(L, fpid);
- lua_pushcclosure(L, fs_handle_readByte, 1);
- lua_settable(L, -3);
+ if (mode[0] == 'r' || strchr(mode, '+')) {
+ if (strchr(mode, 'b')) {
+ lua_pushstring(L, "read");
+ lua_pushvalue(L, fpid);
+ lua_pushcclosure(L, fs_handle_readByte, 1);
+ lua_settable(L, -3);
+ } else {
+ lua_pushstring(L, "read");
+ lua_pushvalue(L, fpid);
+ lua_pushcclosure(L, fs_handle_readChar, 1);
+ lua_settable(L, -3);
+ }
lua_pushstring(L, "readAll");
lua_pushvalue(L, fpid);
@@ -584,30 +581,34 @@ static int fs_open(lua_State *L) {
lua_pushstring(L, "readLine");
lua_pushvalue(L, fpid);
- lua_pushboolean(L, true);
- lua_pushcclosure(L, fs_handle_readLine, 2);
+ lua_pushcclosure(L, fs_handle_readLine, 1);
lua_settable(L, -3);
+ }
- lua_pushstring(L, "seek");
- lua_pushvalue(L, fpid);
- lua_pushcclosure(L, fs_handle_seek, 1);
- lua_settable(L, -3);
- } else if (strcmp(mode, "wb") == 0 || strcmp(mode, "ab") == 0) {
- lua_pushstring(L, "write");
+ if (mode[0] == 'w' || mode[0] == 'a' || strchr(mode, '+')) {
+ if (strchr(mode, 'b')) {
+ lua_pushstring(L, "write");
+ lua_pushvalue(L, fpid);
+ lua_pushcclosure(L, fs_handle_writeByte, 1);
+ lua_settable(L, -3);
+ } else {
+ lua_pushstring(L, "write");
+ lua_pushvalue(L, fpid);
+ lua_pushcclosure(L, fs_handle_writeString, 1);
+ lua_settable(L, -3);
+ }
+
+ lua_pushstring(L, "writeLine");
lua_pushvalue(L, fpid);
- lua_pushcclosure(L, fs_handle_writeByte, 1);
+ lua_pushcclosure(L, fs_handle_writeLine, 1);
lua_settable(L, -3);
lua_pushstring(L, "flush");
lua_pushvalue(L, fpid);
lua_pushcclosure(L, fs_handle_flush, 1);
lua_settable(L, -3);
-
- lua_pushstring(L, "seek");
- lua_pushvalue(L, fpid);
- lua_pushcclosure(L, fs_handle_seek, 1);
- lua_settable(L, -3);
}
+
computer->files_open++;
return 1;
}
diff --git a/src/apis/handles/fs_handle.cpp b/src/apis/handles/fs_handle.cpp
index 44d49c5d..c647a3b2 100644
--- a/src/apis/handles/fs_handle.cpp
+++ b/src/apis/handles/fs_handle.cpp
@@ -11,11 +11,9 @@
#include
#include
#include
-#include
#include
#include
#include
-#include
#include
#include "fs_handle.hpp"
#include "../../util.hpp"
@@ -102,10 +100,9 @@ int fs_handle_readLine(lua_State *L) {
std::string retval;
std::getline(*fp, retval);
if (retval.empty() && fp->eof()) return 0;
- if (*retval.rbegin() == '\r' && !lua_toboolean(L, lua_upvalueindex(2))) retval = retval.substr(0, retval.size()-1);
if (lua_toboolean(L, 1) && fp->good()) retval += '\n';
- const std::string out = lua_toboolean(L, lua_upvalueindex(2)) ? retval : makeASCIISafe(retval.c_str(), retval.size());
- lua_pushlstring(L, out.c_str(), out.length());
+ else if (!retval.empty() && retval[retval.size()-1] == '\r') retval.resize(retval.size() - 1);
+ lua_pushlstring(L, retval.c_str(), retval.length());
return 1;
}
@@ -115,43 +112,25 @@ int fs_handle_readChar(lua_State *L) {
if (fp == NULL) return luaL_error(L, "attempt to use a closed file");
if (fp->eof()) return 0;
if (!fp->good()) luaL_error(L, "Could not read file");
- std::string retval;
- for (int i = 0; i < luaL_optinteger(L, 1, 1) && !fp->eof(); i++) {
- uint32_t codepoint;
- const int c = fp->get();
- if (c == EOF) break;
- else if (c > 0x7F) {
- if (c & 64) {
- const int c2 = fp->get();
- if (c2 == EOF) {retval += '?'; break;}
- else if (c2 < 0x80 || c2 & 64) codepoint = 1U<<31;
- else if (c & 32) {
- const int c3 = fp->get();
- if (c3 == EOF) {retval += '?'; break;}
- else if (c3 < 0x80 || c3 & 64) codepoint = 1U<<31;
- else if (c & 16) {
- if (c & 8) codepoint = 1U<<31;
- else {
- const int c4 = fp->get();
- if (c4 == EOF) {retval += '?'; break;}
- else if (c4 < 0x80 || c4 & 64) codepoint = 1U<<31;
- else codepoint = ((c & 0x7) << 18) | ((c2 & 0x3F) << 12) | ((c3 & 0x3F) << 6) | (c4 & 0x3F);
- }
- } else codepoint = ((c & 0xF) << 12) | ((c2 & 0x3F) << 6) | (c3 & 0x3F);
- } else codepoint = ((c & 0x1F) << 6) | (c2 & 0x3F);
- } else codepoint = 1U<<31;
- } else codepoint = (unsigned char)c;
- if (codepoint > 255) retval += '?';
- else {
- if (codepoint == '\r') {
- const int nextc = fp->get();
- if (nextc == '\n') codepoint = nextc;
- else fp->putback((char)nextc);
- }
- retval += (char)codepoint;
+ if (lua_isnumber(L, 1)) {
+ if (lua_tointeger(L, 1) < 0) luaL_error(L, "Cannot read a negative number of characters");
+ const size_t s = lua_tointeger(L, 1);
+ if (s == 0) {
+ if (fp->peek() == EOF || fp->eof()) return 0;
+ lua_pushstring(L, "");
+ return 1;
}
+ char* retval = new char[s];
+ fp->read(retval, s);
+ const size_t actual = fp->gcount();
+ if (actual == 0) {delete[] retval; return 0;}
+ lua_pushlstring(L, retval, actual);
+ delete[] retval;
+ } else {
+ const int retval = fp->get();
+ if (retval == EOF || fp->eof()) return 0;
+ lua_pushlstring(L, (const char *)&retval, 1);
}
- lua_pushlstring(L, retval.c_str(), retval.length());
return 1;
}
@@ -162,6 +141,7 @@ int fs_handle_readByte(lua_State *L) {
if (fp->eof()) return 0;
if (!fp->good()) luaL_error(L, "Could not read file");
if (lua_isnumber(L, 1)) {
+ if (lua_tointeger(L, 1) < 0) luaL_error(L, "Cannot read a negative number of bytes");
const size_t s = lua_tointeger(L, 1);
if (s == 0) {
if (fp->peek() == EOF || fp->eof()) return 0;
@@ -206,14 +186,11 @@ int fs_handle_writeString(lua_State *L) {
std::iostream * fp = *(std::iostream**)lua_touserdata(L, lua_upvalueindex(1));
if (fp == NULL) luaL_error(L, "attempt to use a closed file");
if (lua_isnoneornil(L, 1)) return 0;
- else if (!lua_isstring(L, 1) && !lua_isnumber(L, 1)) luaL_typerror(L, 1, "string");
+ else if (!lua_isstring(L, 1) && !lua_isnumber(L, 1)) luaL_error(L, "bad argument #1 (string expected, got %s)", lua_typename(L, lua_type(L, 1)));
if (fp->fail()) luaL_error(L, "Could not write file");
- std::string str(lua_tostring(L, 1), lua_strlen(L, 1));
- std::wstring wstr;
- for (unsigned char c : str) wstr += (wchar_t)c;
- std::wstring_convert > converter;
- const std::string newstr = converter.to_bytes(wstr);
- fp->write(newstr.c_str(), newstr.size());
+ size_t sz = 0;
+ const char * str = lua_tolstring(L, 1, &sz);
+ fp->write(str, sz);
return 0;
}
@@ -222,14 +199,11 @@ int fs_handle_writeLine(lua_State *L) {
std::iostream * fp = *(std::iostream**)lua_touserdata(L, lua_upvalueindex(1));
if (fp == NULL) luaL_error(L, "attempt to use a closed file");
if (lua_isnoneornil(L, 1)) return 0;
- else if (!lua_isstring(L, 1) && !lua_isnumber(L, 1)) luaL_typerror(L, 1, "string");
+ else if (!lua_isstring(L, 1) && !lua_isnumber(L, 1)) luaL_error(L, "bad argument #1 (string expected, got %s)", lua_typename(L, lua_type(L, 1)));
if (fp->fail()) luaL_error(L, "Could not write file");
- std::string str(lua_tostring(L, 1), lua_strlen(L, 1));
- std::wstring wstr;
- for (unsigned char c : str) wstr += (wchar_t)c;
- std::wstring_convert > converter;
- const std::string newstr = converter.to_bytes(wstr);
- fp->write(newstr.c_str(), newstr.size());
+ size_t sz = 0;
+ const char * str = lua_tolstring(L, 1, &sz);
+ fp->write(str, sz);
fp->put('\n');
return 0;
}
@@ -247,7 +221,7 @@ int fs_handle_writeByte(lua_State *L) {
const char * str = lua_tolstring(L, 1, &sz);
if (sz == 0) return 0;
fp->write(str, sz);
- } else luaL_typerror(L, 1, "number or string");
+ } else luaL_error(L, "bad argument #1 (number or string expected, got %s)", lua_typename(L, lua_type(L, 1)));
return 0;
}
diff --git a/src/apis/handles/http_handle.cpp b/src/apis/handles/http_handle.cpp
index 884891a3..dd35ae4e 100644
--- a/src/apis/handles/http_handle.cpp
+++ b/src/apis/handles/http_handle.cpp
@@ -10,27 +10,15 @@
#ifndef __EMSCRIPTEN__
#include
-#include
-#include
#include
#include
#include
#include
-#include "http_handle.hpp"
#include "../../util.hpp"
+#include "http_handle.hpp"
using namespace Poco::Net;
-struct http_handle_t {
- std::string url;
- HTTPClientSession * session;
- HTTPResponse * handle;
- std::istream * stream;
- bool isBinary;
- std::string failureReason;
- http_handle_t(std::istream * s) : stream(s) {}
-};
-
struct http_res {
std::string body;
HTTPServerResponse * res;
@@ -51,7 +39,7 @@ int http_handle_free(lua_State *L) {
int http_handle_close(lua_State *L) {
lastCFunction = __func__;
http_handle_t** handle = (http_handle_t**)lua_touserdata(L, lua_upvalueindex(1));
- if (*handle == NULL) return luaL_error(L, "attempt to use a closed file");
+ if (*handle == NULL) return 0;
delete (*handle)->handle;
delete (*handle)->session;
delete *handle;
@@ -70,17 +58,7 @@ int http_handle_readAll(lua_State *L) {
ret.append(buffer, sizeof(buffer));
ret.append(buffer, handle->stream->gcount());
ret.erase(std::remove(ret.begin(), ret.end(), '\r'), ret.end());
- std::wstring_convert> converter;
- std::wstring wstr;
- try {wstr = converter.from_bytes(ret.c_str(), ret.c_str() + ret.length());}
- catch (std::exception & e) {
- fprintf(stderr, "http_handle_readAll: Error decoding UTF-8: %s\n", e.what());
- lua_pushlstring(L, ret.c_str(), ret.length());
- return 1;
- }
- std::string out;
- for (wchar_t c : wstr) {if (c < 256) out += (char)c; else out += '?';}
- lua_pushlstring(L, out.c_str(), out.length());
+ lua_pushlstring(L, ret.c_str(), ret.length());
return 1;
}
@@ -94,7 +72,7 @@ int http_handle_readLine(lua_State *L) {
if (retval.empty() && handle->stream->eof()) return 0;
if (lua_toboolean(L, 1)) retval += '\n';
else if (!retval.empty() && retval[retval.size()-1] == '\r') retval = retval.substr(0, retval.size()-1);
- const std::string out = handle->isBinary ? retval : makeASCIISafe(retval.c_str(), retval.size());
+ const std::string out = retval;
lua_pushlstring(L, out.c_str(), out.length());
return 1;
}
diff --git a/src/apis/handles/http_handle.hpp b/src/apis/handles/http_handle.hpp
index cd74bf54..26817704 100644
--- a/src/apis/handles/http_handle.hpp
+++ b/src/apis/handles/http_handle.hpp
@@ -13,6 +13,14 @@
extern "C" {
#include
}
+struct http_handle_t {
+ std::string url;
+ std::string failureReason;
+ Poco::Net::HTTPClientSession * session;
+ Poco::Net::HTTPResponse * handle;
+ std::istream * stream;
+ http_handle_t(std::istream * s) : stream(s) {}
+};
extern int http_handle_free(lua_State *L);
extern int http_handle_close(lua_State *L);
extern int http_handle_readAll(lua_State *L);
diff --git a/src/apis/http.cpp b/src/apis/http.cpp
index d78cc553..0971203b 100644
--- a/src/apis/http.cpp
+++ b/src/apis/http.cpp
@@ -32,10 +32,10 @@
#include
#include
#include
-#include "handles/http_handle.hpp"
#include "../platform.hpp"
#include "../runtime.hpp"
#include "../util.hpp"
+#include "handles/http_handle.hpp"
#ifdef __ANDROID__
extern "C" {extern int Android_JNI_SetupThread(void);}
@@ -54,21 +54,10 @@ struct http_param_t {
std::unordered_map headers;
std::string method;
std::string old_url;
- bool isBinary;
bool redirect;
double timeout;
};
-struct http_handle_t {
- std::string url;
- HTTPClientSession * session;
- HTTPResponse * handle;
- std::istream * stream;
- bool isBinary;
- std::string failureReason;
- http_handle_t(std::istream * s): stream(s) {}
-};
-
struct http_check_t {
std::string url;
std::string status;
@@ -97,32 +86,20 @@ static std::string http_success(lua_State *L, void* data) {
lua_pushcclosure(L, http_handle_readLine, 1);
lua_settable(L, -3);
- if (!handle->isBinary) {
- lua_pushstring(L, "readAll");
- lua_pushvalue(L, -3);
- lua_pushcclosure(L, http_handle_readAll, 1);
- lua_settable(L, -3);
-
- lua_pushstring(L, "read");
- lua_pushvalue(L, -3);
- lua_pushcclosure(L, http_handle_readChar, 1);
- lua_settable(L, -3);
- } else {
- lua_pushstring(L, "readAll");
- lua_pushvalue(L, -3);
- lua_pushcclosure(L, http_handle_readAllByte, 1);
- lua_settable(L, -3);
+ lua_pushstring(L, "readAll");
+ lua_pushvalue(L, -3);
+ lua_pushcclosure(L, http_handle_readAllByte, 1);
+ lua_settable(L, -3);
- lua_pushstring(L, "read");
- lua_pushvalue(L, -3);
- lua_pushcclosure(L, http_handle_readByte, 1);
- lua_settable(L, -3);
+ lua_pushstring(L, "read");
+ lua_pushvalue(L, -3);
+ lua_pushcclosure(L, http_handle_readByte, 1);
+ lua_settable(L, -3);
- lua_pushstring(L, "seek");
- lua_pushvalue(L, -3);
- lua_pushcclosure(L, http_handle_seek, 1);
- lua_settable(L, -3);
- }
+ lua_pushstring(L, "seek");
+ lua_pushvalue(L, -3);
+ lua_pushcclosure(L, http_handle_seek, 1);
+ lua_settable(L, -3);
lua_pushstring(L, "getResponseCode");
lua_pushvalue(L, -3);
@@ -161,32 +138,20 @@ static std::string http_failure(lua_State *L, void* data) {
lua_pushcclosure(L, http_handle_readLine, 1);
lua_settable(L, -3);
- if (!handle->isBinary) {
- lua_pushstring(L, "readAll");
- lua_pushvalue(L, -3);
- lua_pushcclosure(L, http_handle_readAll, 1);
- lua_settable(L, -3);
+ lua_pushstring(L, "readAll");
+ lua_pushvalue(L, -3);
+ lua_pushcclosure(L, http_handle_readAllByte, 1);
+ lua_settable(L, -3);
- lua_pushstring(L, "read");
- lua_pushvalue(L, -3);
- lua_pushcclosure(L, http_handle_readChar, 1);
- lua_settable(L, -3);
- } else {
- lua_pushstring(L, "readAll");
- lua_pushvalue(L, -3);
- lua_pushcclosure(L, http_handle_readAllByte, 1);
- lua_settable(L, -3);
-
- lua_pushstring(L, "read");
- lua_pushvalue(L, -3);
- lua_pushcclosure(L, http_handle_readByte, 1);
- lua_settable(L, -3);
-
- lua_pushstring(L, "seek");
- lua_pushvalue(L, -3);
- lua_pushcclosure(L, http_handle_seek, 1);
- lua_settable(L, -3);
- }
+ lua_pushstring(L, "read");
+ lua_pushvalue(L, -3);
+ lua_pushcclosure(L, http_handle_readByte, 1);
+ lua_settable(L, -3);
+
+ lua_pushstring(L, "seek");
+ lua_pushvalue(L, -3);
+ lua_pushcclosure(L, http_handle_seek, 1);
+ lua_settable(L, -3);
lua_pushstring(L, "getResponseCode");
lua_pushvalue(L, -3);
@@ -280,12 +245,20 @@ static void downloadThread(void* arg) {
else if (uri.getScheme() == "http") {
session = new HTTPClientSession(uri.getHost(), uri.getPort());
} else if (uri.getScheme() == "https") {
- Context::Ptr context = new Context(Context::CLIENT_USE, "", Context::VERIFY_RELAXED, 9, true, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
- addSystemCertificates(context);
+ try {
+ Context::Ptr context = new Context(Context::CLIENT_USE, "", Context::VERIFY_RELAXED, 9, true, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
+ addSystemCertificates(context);
#if POCO_VERSION >= 0x010A0000
- context->disableProtocols(Context::PROTO_TLSV1_3); // Some sites break under TLS 1.3 - disable it to maintain compatibility until fixed (pocoproject/poco#3395)
+ context->disableProtocols(Context::PROTO_TLSV1_3); // Some sites break under TLS 1.3 - disable it to maintain compatibility until fixed (pocoproject/poco#3395)
#endif
- session = new HTTPSClientSession(uri.getHost(), uri.getPort(), context);
+ session = new HTTPSClientSession(uri.getHost(), uri.getPort(), context);
+ } catch (Poco::Exception &e) {
+ http_handle_t * err = new http_handle_t(NULL);
+ err->url = param->url;
+ err->failureReason = e.message();
+ queueEvent(param->comp, http_failure, err);
+ goto downloadThread_finish;
+ }
} else status = "Invalid protocol '" + uri.getScheme() + "'";
}
if (!status.empty()) {
@@ -382,7 +355,6 @@ static void downloadThread(void* arg) {
handle->session = session;
handle->handle = response;
handle->url = param->old_url;
- handle->isBinary = param->isBinary;
if (param->redirect && handle->handle->getStatus() / 100 == 3 && handle->handle->has("Location")) {
std::string location = handle->handle->get("Location");
if (location.find("://") == std::string::npos) {
@@ -500,7 +472,7 @@ static int http_request(lua_State *L) {
lua_pushboolean(L, false);
return 1;
}
- if (!lua_isstring(L, 1) && !lua_istable(L, 1)) luaL_typerror(L, 1, "string or table");
+ if (!lua_isstring(L, 1) && !lua_istable(L, 1)) luaL_error(L, "bad argument #1 (expected string or table, got %s)", lua_typename(L, lua_type(L, 1)));
http_param_t * param = new http_param_t;
param->comp = get_comp(L);
if (lua_istable(L, 1)) {
@@ -511,11 +483,7 @@ static int http_request(lua_State *L) {
lua_pop(L, 1);
lua_getfield(L, 1, "body");
if (!lua_isnil(L, -1) && !lua_isstring(L, -1)) {delete param; return luaL_error(L, "bad field 'body' (string expected, got %s)", lua_typename(L, lua_type(L, -1)));}
- else if (lua_isstring(L, -1)) param->postData = std::string(lua_tostring(L, -1), lua_strlen(L, -1));
- lua_pop(L, 1);
- lua_getfield(L, 1, "binary");
- if (!lua_isnil(L, -1) && !lua_isboolean(L, -1)) {delete param; return luaL_error(L, "bad field 'binary' (boolean expected, got %s)", lua_typename(L, lua_type(L, -1)));}
- else if (lua_isboolean(L, -1)) param->isBinary = lua_toboolean(L, -1);
+ else if (lua_isstring(L, -1)) param->postData = std::string(lua_tostring(L, -1), lua_rawlen(L, -1));
lua_pop(L, 1);
lua_getfield(L, 1, "method");
if (!lua_isnil(L, -1) && !lua_isstring(L, -1)) {delete param; return luaL_error(L, "bad field 'method' (string expected, got %s)", lua_typename(L, lua_type(L, -1)));}
@@ -545,8 +513,7 @@ static int http_request(lua_State *L) {
} else {
param->url = lua_tostring(L, 1);
param->old_url = param->url;
- param->isBinary = false;
- if (lua_isstring(L, 2)) param->postData = std::string(lua_tostring(L, 2), lua_strlen(L, 2));
+ if (lua_isstring(L, 2)) param->postData = std::string(lua_tostring(L, 2), lua_rawlen(L, 2));
if (lua_istable(L, 3)) {
lua_pushvalue(L, 3);
lua_pushnil(L);
@@ -558,7 +525,6 @@ static int http_request(lua_State *L) {
}
lua_pop(L, 1);
}
- if (lua_isboolean(L, 4)) param->isBinary = lua_toboolean(L, 4);
if (lua_isstring(L, 5)) param->method = lua_tostring(L, 5);
param->redirect = !lua_isboolean(L, 6) || lua_toboolean(L, 6);
param->timeout = 0;
@@ -777,13 +743,13 @@ static int http_removeListener(lua_State *L) {
extern int os_startTimer(lua_State *L);
struct ws_handle {
+ bool isServer;
std::string url;
WebSocket * ws;
std::mutex lock;
uint16_t port;
void * clientID = NULL;
ws_handle ** ud = NULL;
- bool binary = false;
};
struct websocket_failure_data {
@@ -804,6 +770,7 @@ struct websocket_closed_data {
std::string url;
std::string reason;
uint16_t code;
+ void* clientID = NULL;
};
static std::string websocket_failure(lua_State *L, void* userp) {
@@ -827,18 +794,6 @@ static std::string websocket_closed(lua_State *L, void* userp) {
return "websocket_closed";
}
-static std::string websocket_closed_server(lua_State *L, void* userp) {
- ws_handle * wsh = (ws_handle*)userp;
- lua_pushnumber(L, wsh->port);
- lua_pushlightuserdata(L, wsh->clientID);
- return "websocket_closed";
-}
-
-static std::string websocket_server_closed(lua_State *L, void* userp) {
- lua_pushnumber(L, (ptrdiff_t)userp);
- return "websocket_server_closed";
-}
-
// WebSocket handle functions
static int websocket_free(lua_State *L) {
lastCFunction = __func__;
@@ -853,9 +808,9 @@ static int websocket_free(lua_State *L) {
static int websocket_close(lua_State *L) {
lastCFunction = __func__;
ws_handle * ws = *(ws_handle**)lua_touserdata(L, lua_upvalueindex(1));
- if (ws == NULL) luaL_error(L, "attempt to use a closed file");
+ if (ws == NULL) return 0;
std::lock_guard lock(ws->lock);
- if (ws->ws == NULL) luaL_error(L, "attempt to use a closed file");
+ if (ws->ws == NULL) return 0;
ws->ws = NULL;
return 0;
}
@@ -868,14 +823,7 @@ static int websocket_send(lua_State *L) {
if (ws == NULL) luaL_error(L, "attempt to use a closed file");
std::lock_guard lock(ws->lock);
if (ws->ws == NULL) return luaL_error(L, "attempt to use a closed file");
- std::string buf;
- if (!lua_toboolean(L, 2) && !ws->binary) {
- std::wstring wstr;
- for (unsigned char c : str) wstr += (wchar_t)c;
- std::wstring_convert > converter;
- buf = converter.to_bytes(wstr);
- } else buf = str;
- if (ws->ws->sendFrame(buf.c_str(), buf.size(), (int)WebSocket::FRAME_FLAG_FIN | (int)(lua_toboolean(L, 2) ? WebSocket::FRAME_BINARY : WebSocket::FRAME_TEXT)) < 1)
+ if (ws->ws->sendFrame(str.c_str(), str.size(), (int)WebSocket::FRAME_FLAG_FIN | (int)(lua_toboolean(L, 2) ? WebSocket::FRAME_BINARY : WebSocket::FRAME_TEXT)) < 1)
websocket_close(L);
return 0;
}
@@ -883,8 +831,8 @@ static int websocket_send(lua_State *L) {
static int websocket_receive(lua_State *L) {
lastCFunction = __func__;
ws_handle * ws = *(ws_handle**)lua_touserdata(L, lua_upvalueindex(1));
- int tm = lua_icontext(L);
- if (tm) {
+ int tm = 0;
+ if (lua_getctx(L, &tm) == LUA_YIELD) {
if (lua_isstring(L, 1)) {
// haha, another string scoping issue :DDD
// can M$ PLEASE fix this? (maybe I need to repro & report? :thinking:)
@@ -894,20 +842,27 @@ static int websocket_receive(lua_State *L) {
}
std::string * ev = new std::string(lua_tostring(L, 1));
std::string * url = new std::string();
- int port = 0;
- if (lua_isnumber(L, 2)) port = lua_tointeger(L, 2);
+ int tmid = 0;
+ if (lua_isnumber(L, 2)) tmid = lua_tointeger(L, 2);
else if (lua_isstring(L, 2)) {
delete url;
url = new std::string(lua_tostring(L, 2));
}
- if (*ev == "websocket_message" && (ws->url.empty() ? port == ws->port : *url == ws->url) && (ws->clientID == NULL || (lua_islightuserdata(L, 5) && lua_touserdata(L, 5) == ws->clientID))) {
+ if (*ev == "websocket_message" && !ws->isServer && *url == ws->url) {
lua_pushvalue(L, 3);
lua_pushvalue(L, 4);
delete ev;
delete url;
return 2;
- } else if ((*ev == "websocket_closed" && *url == ws->url && ws->ws == NULL) ||
- (tm > 0 && *ev == "timer" && lua_isnumber(L, 2) && lua_tointeger(L, 2) == tm)) {
+ } else if (*ev == "websocket_server_message" && ws->isServer && lua_touserdata(L, 2) == ws->clientID) {
+ lua_pushvalue(L, 3);
+ lua_pushvalue(L, 4);
+ delete ev;
+ delete url;
+ return 2;
+ } else if ((*ev == "websocket_closed" && !ws->isServer && *url == ws->url && ws->ws == NULL) ||
+ (*ev == "websocket_server_closed" && ws->isServer && lua_touserdata(L, 2) == ws->clientID && ws->ws == NULL) ||
+ (tm > 0 && *ev == "timer" && lua_isnumber(L, 2) && tmid == tm)) {
lua_pushnil(L);
delete ev;
delete url;
@@ -933,58 +888,83 @@ static int websocket_receive(lua_State *L) {
} else tm = -1;
}
lua_settop(L, 0);
- return lua_iyield(L, 0, tm);
+ return lua_yieldk(L, 0, tm, websocket_receive);
}
+static luaL_Reg websocket_funcs[] = {
+ {"close", websocket_close},
+ {"receive", websocket_receive},
+ {"send", websocket_send},
+ {NULL, NULL}
+};
+
static std::string websocket_success(lua_State *L, void* userp) {
ws_handle ** wsh = (ws_handle**)userp;
luaL_checkstack(L, 10, "Could not grow stack for websocket_success");
- if ((*wsh)->url.empty()) lua_pushnumber(L, (*wsh)->port);
- else lua_pushstring(L, (*wsh)->url.c_str());
-
+ lua_pushstring(L, (*wsh)->url.c_str());
+ lua_createtable(L, 0, 4);
ws_handle ** ws = (ws_handle**)lua_newuserdata(L, sizeof(ws_handle*));
*ws = *wsh;
(*wsh)->ud = ws;
- int pos = lua_gettop(L);
lua_createtable(L, 0, 1);
lua_pushstring(L, "__gc");
lua_pushcfunction(L, websocket_free);
lua_settable(L, -3);
lua_setmetatable(L, -2);
-
- lua_createtable(L, 0, 4);
-
- lua_pushstring(L, "close");
- lua_pushvalue(L, pos);
- lua_pushcclosure(L, websocket_close, 1);
- lua_settable(L, -3);
-
- lua_pushstring(L, "receive");
- lua_pushvalue(L, pos);
- lua_pushcclosure(L, websocket_receive, 1);
- lua_settable(L, -3);
-
- lua_pushstring(L, "send");
- lua_pushvalue(L, pos);
- lua_pushcclosure(L, websocket_send, 1);
- lua_settable(L, -3);
-
- lua_remove(L, pos);
- if ((*ws)->clientID) lua_pushlightuserdata(L, (*ws)->clientID);
+ luaL_setfuncs(L, websocket_funcs, 1);
return "websocket_success";
}
static std::string websocket_message(lua_State *L, void* userp) {
ws_message * message = (ws_message*)userp;
- if (message->url.empty()) lua_pushinteger(L, message->port);
- else lua_pushstring(L, message->url.c_str());
+ lua_pushstring(L, message->url.c_str());
pushstring(L, message->data);
lua_pushboolean(L, message->binary);
- if (message->clientID) lua_pushlightuserdata(L, message->clientID);
delete message;
return "websocket_message";
}
+// websocket_server_connect: port, handle
+// handles have an additional clientID member
+static std::string websocket_server_connect(lua_State *L, void* userp) {
+ ws_handle ** wsh = (ws_handle**)userp;
+ luaL_checkstack(L, 10, "Could not grow stack for websocket_server_connect");
+ lua_pushnumber(L, (*wsh)->port);
+ lua_createtable(L, 0, 4);
+ ws_handle ** ws = (ws_handle**)lua_newuserdata(L, sizeof(ws_handle*));
+ *ws = *wsh;
+ (*wsh)->ud = ws;
+ lua_createtable(L, 0, 1);
+ lua_pushstring(L, "__gc");
+ lua_pushcfunction(L, websocket_free);
+ lua_settable(L, -3);
+ lua_setmetatable(L, -2);
+ luaL_setfuncs(L, websocket_funcs, 1);
+ lua_pushlightuserdata(L, (*ws)->clientID);
+ lua_setfield(L, -2, "clientID");
+ return "websocket_server_connect";
+}
+
+static std::string websocket_server_message(lua_State *L, void* userp) {
+ ws_message * message = (ws_message*)userp;
+ lua_pushlightuserdata(L, message->clientID);
+ pushstring(L, message->data);
+ lua_pushboolean(L, message->binary);
+ delete message;
+ return "websocket_server_message";
+}
+
+static std::string websocket_server_closed(lua_State *L, void* userp) {
+ websocket_closed_data * data = (websocket_closed_data*)userp;
+ lua_pushlightuserdata(L, data->clientID);
+ if (data->code != 0) {
+ pushstring(L, data->reason);
+ lua_pushinteger(L, data->code);
+ }
+ delete data;
+ return "websocket_server_closed";
+}
+
class websocket_server: public HTTPRequestHandler {
public:
Computer * comp;
@@ -997,13 +977,6 @@ class websocket_server: public HTTPRequestHandler {
try {
ws = new WebSocket(request, response);
} catch (NetException &e) {
- websocket_failure_data * data = new websocket_failure_data;
- data->url = "";
- data->reason = e.message();
- data->port = srv->port();
- queueEvent(comp, websocket_failure, data);
- delete ws;
- if (srv != NULL) { try {srv->stop();} catch (...) {} delete srv; }
return;
}
(*retainCount)++;
@@ -1014,14 +987,14 @@ class websocket_server: public HTTPRequestHandler {
ws_handle ws_orig;
ws_handle * wsh = &ws_orig;
wsh->ws = ws;
- wsh->url = "";
+ wsh->isServer = true;
wsh->port = srv->port();
wsh->clientID = &request;
{
std::lock_guard lock(comp->openWebsocketsMutex);
comp->openWebsockets.push_back(&wsh);
}
- queueEvent(comp, websocket_success, &wsh);
+ queueEvent(comp, websocket_server_connect, &wsh);
char * buf = new char[config.http_max_websocket_message];
while (wsh->ws) {
int flags = 0;
@@ -1030,34 +1003,49 @@ class websocket_server: public HTTPRequestHandler {
res = ws->receiveFrame(buf, config.http_max_websocket_message, flags);
if (res < 0 || (res == 0 && flags == 0)) {
wsh->ws = NULL;
- queueEvent(comp, websocket_closed_server, wsh);
+ websocket_closed_data * d = new websocket_closed_data;
+ d->clientID = wsh->clientID;
+ d->code = 0;
+ queueEvent(comp, websocket_server_closed, d);
break;
}
} catch (Poco::TimeoutException &e) {
if (!wsh->ws) {
- queueEvent(comp, websocket_closed_server, wsh);
+ websocket_closed_data * d = new websocket_closed_data;
+ d->clientID = wsh->clientID;
+ d->code = 1006;
+ d->reason = "Timed out";
+ queueEvent(comp, websocket_server_closed, d);
break;
}
continue;
} catch (NetException &e) {
wsh->ws = NULL;
- queueEvent(comp, websocket_closed_server, wsh);
+ websocket_closed_data * d = new websocket_closed_data;
+ d->clientID = wsh->clientID;
+ d->code = 1006;
+ d->reason = e.message();
+ queueEvent(comp, websocket_server_closed, d);
break;
}
if ((flags & 0x0f) == WebSocket::FRAME_OP_CLOSE) {
wsh->ws = NULL;
- queueEvent(comp, websocket_closed_server, wsh);
+ websocket_closed_data * d = new websocket_closed_data;
+ d->clientID = wsh->clientID;
+ if (res >= 2) {
+ d->code = (((uint8_t*)buf)[0] << 8) | ((uint8_t*)buf)[1];
+ d->reason = std::string(buf + 2, res - 2);
+ } else d->code = 0;
+ queueEvent(comp, websocket_server_closed, d);
break;
} else if ((flags & 0x0f) == WebSocket::FRAME_OP_PING) {
ws->sendFrame(buf, res, WebSocket::FRAME_FLAG_FIN | WebSocket::FRAME_OP_PONG);
} else {
ws_message * message = new ws_message;
- message->url = "";
- message->port = wsh->port;
+ message->clientID = wsh->clientID;
message->binary = (flags & WebSocket::FRAME_OP_BITMASK) == WebSocket::FRAME_OP_BINARY;
- message->data = message->binary ? std::string((const char*)buf, res) : makeASCIISafe((const char*)buf, res);
- message->clientID = &request;
- queueEvent(comp, websocket_message, message);
+ message->data = std::string((const char*)buf, res);
+ queueEvent(comp, websocket_server_message, message);
}
std::this_thread::yield();
}
@@ -1067,17 +1055,6 @@ class websocket_server: public HTTPRequestHandler {
if (it != comp->openWebsockets.end()) comp->openWebsockets.erase(it);
}
try {ws->shutdown();} catch (...) {}
- if (--(*retainCount) == 0 && srv != NULL) {
- try {srv->stop();}
- catch (...) {}
- delete srv;
- srv = NULL;
- {
- std::lock_guard lock(comp->openWebsocketsMutex);
- comp->openWebsocketServers.erase(wsh->port);
- }
- queueEvent(comp, websocket_server_closed, (void*)(ptrdiff_t)wsh->port);
- }
std::lock_guard lock(wsh->lock);
wsh->ws = NULL;
if (wsh->ud != NULL) *wsh->ud = NULL;
@@ -1104,7 +1081,7 @@ class websocket_server: public HTTPRequestHandler {
}
}
-static void websocket_client_thread(Computer *comp, const std::string& str, const std::unordered_map& headers, bool binary, double timeout) {
+static void websocket_client_thread(Computer *comp, const std::string& str, const std::unordered_map& headers, double timeout) {
#ifdef __APPLE__
pthread_setname_np("WebSocket Client Thread");
#endif
@@ -1193,9 +1170,9 @@ static void websocket_client_thread(Computer *comp, const std::string& str, cons
#endif
ws_handle wsh_orig;
ws_handle * wsh = &wsh_orig;
+ wsh->isServer = false;
wsh->url = str;
wsh->ws = ws;
- wsh->binary = binary;
{
std::lock_guard lock(comp->openWebsocketsMutex);
comp->openWebsockets.push_back(&wsh);
@@ -1209,7 +1186,6 @@ static void websocket_client_thread(Computer *comp, const std::string& str, cons
res = ws->receiveFrame(buf, config.http_max_websocket_message, flags);
if (res < 0 || (res == 0 && flags == 0)) {
wsh->ws = NULL;
- wsh->url = "";
websocket_closed_data * d = new websocket_closed_data;
d->url = str;
d->code = 0;
@@ -1228,7 +1204,6 @@ static void websocket_client_thread(Computer *comp, const std::string& str, cons
continue;
} catch (NetException &e) {
wsh->ws = NULL;
- wsh->url = "";
websocket_closed_data * d = new websocket_closed_data;
d->url = str;
d->code = 1006;
@@ -1238,7 +1213,6 @@ static void websocket_client_thread(Computer *comp, const std::string& str, cons
}
if ((flags & 0x0f) == WebSocket::FRAME_OP_CLOSE) {
wsh->ws = NULL;
- wsh->url = "";
websocket_closed_data * d = new websocket_closed_data;
d->url = str;
if (res >= 2) {
@@ -1253,7 +1227,7 @@ static void websocket_client_thread(Computer *comp, const std::string& str, cons
ws_message * message = new ws_message;
message->url = str;
message->binary = (flags & WebSocket::FRAME_OP_BITMASK) == WebSocket::FRAME_OP_BINARY;
- message->data = (message->binary || binary) ? std::string((const char*)buf, res) : makeASCIISafe((const char*)buf, res);
+ message->data = std::string((const char*)buf, res);
queueEvent(comp, websocket_message, message);
}
std::this_thread::yield();
@@ -1264,7 +1238,6 @@ static void websocket_client_thread(Computer *comp, const std::string& str, cons
auto it = std::find(comp->openWebsockets.begin(), comp->openWebsockets.end(), (void*)&wsh);
if (it != comp->openWebsockets.end()) comp->openWebsockets.erase(it);
}
- wsh->url = "";
try {ws->shutdown();} catch (...) {}
std::lock_guard lock(wsh->lock);
wsh->ws = NULL;
@@ -1279,35 +1252,7 @@ static int http_websocket(lua_State *L) {
Computer * comp = get_comp(L);
if (comp->openWebsockets.size() >= (size_t)config.http_max_websockets) return luaL_error(L, "Too many websockets already open");
if (!(config.serverMode || config.vanilla) && (lua_isnoneornil(L, 1) || lua_isnumber(L, 1))) {
- int port = luaL_optinteger(L, 1, 80);
- if (port < 0 || port > 65535) luaL_error(L, "bad argument #1 (port out of range)");
- if (comp->openWebsocketServers.find(port) != comp->openWebsocketServers.end()) {
- // if there's already an open server, reuse that
- lua_pushboolean(L, true);
- return 1;
- }
- std::unordered_map headers;
- if (lua_istable(L, 2)) {
- lua_pushvalue(L, 2);
- lua_pushnil(L);
- for (int i = 0; lua_next(L, -2); i++) {
- size_t keyn = 0, valn = 0;
- const char * key = lua_tolstring(L, -2, &keyn), *val = lua_tolstring(L, -1, &valn);
- if (key && val) headers[std::string(key, keyn)] = std::string(val, valn);
- lua_pop(L, 2);
- }
- lua_pop(L, 1);
- } else if (!lua_isnoneornil(L, 2)) luaL_error(L, "bad argument #2 (expected table, got %s)", lua_typename(L, lua_type(L, 2)));
- websocket_server::Factory * f = new websocket_server::Factory(comp, headers);
- try {f->srv = new HTTPServer(f, port);}
- catch (Poco::Exception& e) {
- fprintf(stderr, "Could not open server: %s\n", e.displayText().c_str());
- lua_pushboolean(L, false);
- lua_pushstring(L, e.displayText().c_str());
- return 2;
- }
- comp->openWebsocketServers.insert(port);
- f->srv->start();
+ luaL_error(L, "function has been replaced with http.websocketServer");
} else if (lua_istable(L, 1)) {
Computer * comp = get_comp(L);
if (config.http_max_websockets > 0 && comp->openWebsockets.size() >= (unsigned)config.http_max_websockets) luaL_error(L, "Too many websockets already open");
@@ -1328,14 +1273,11 @@ static int http_websocket(lua_State *L) {
}
}
lua_pop(L, 1);
- lua_getfield(L, 1, "binary");
- bool binary = lua_toboolean(L, -1);
- lua_pop(L, 1);
lua_getfield(L, 1, "timeout");
if (!lua_isnil(L, -1) && !lua_isnumber(L, -1)) luaL_error(L, "bad field 'timeout' (expected number, got %s)", lua_typename(L, lua_type(L, -1)));
double timeout = luaL_optnumber(L, -1, config.http_timeout / 1000.0);
lua_pop(L, 1);
- std::thread th(websocket_client_thread, comp, url, headers, binary, timeout);
+ std::thread th(websocket_client_thread, comp, url, headers, timeout);
setThreadName(th, "WebSocket Client Thread");
th.detach();
} else if (lua_isstring(L, 1)) {
@@ -1354,8 +1296,7 @@ static int http_websocket(lua_State *L) {
}
lua_pop(L, 1);
}
- bool binary = lua_toboolean(L, 3);
- std::thread th(websocket_client_thread, comp, url, headers, binary, config.http_timeout / 1000.0);
+ std::thread th(websocket_client_thread, comp, url, headers, config.http_timeout / 1000.0);
setThreadName(th, "WebSocket Client Thread");
th.detach();
} else luaL_error(L, (config.serverMode || config.vanilla) ? "bad argument #1 (expected string or table, got %s)" : "bad argument #1 (expected string, table, number, or nil, got %s)", lua_typename(L, lua_type(L, 1)));
@@ -1363,6 +1304,138 @@ static int http_websocket(lua_State *L) {
return 1;
}
+/**
+ * Listens for a new connection on the server, and returns its handle.
+ * @param timeout (number, optional) The amount of time to wait
+ * @return The WebSocket handle for the connection, or nil on timeout.
+ * @note Server handles are the same as client handles, but with an additional
+ * clientID member for identifying events.
+ */
+static int websocket_server_listen(lua_State *L) {
+ lastCFunction = __func__;
+ websocket_server::Factory * f = *(websocket_server::Factory**)lua_touserdata(L, lua_upvalueindex(1));
+ int tm = 0;
+ if (lua_getctx(L, &tm) == LUA_YIELD) {
+ if (lua_isstring(L, 1)) {
+ // haha, another string scoping issue :DDD
+ // can M$ PLEASE fix this? (maybe I need to repro & report? :thinking:)
+ if (f == NULL) {
+ lua_pushnil(L);
+ return 1;
+ }
+ std::string * ev = new std::string(lua_tostring(L, 1));
+ if (lua_isnumber(L, 2)) {
+ int id = lua_tointeger(L, 2);
+ if (*ev == "websocket_server_connect" && id == f->srv->port()) {
+ lua_pushvalue(L, 3);
+ delete ev;
+ return 1;
+ } else if (tm > 0 && *ev == "timer" && id == tm) {
+ lua_pushnil(L);
+ delete ev;
+ return 1;
+ } else if (*ev == "terminate") {
+ delete ev;
+ return luaL_error(L, "Terminated");
+ }
+ }
+ delete ev;
+ }
+ } else {
+ if (f == NULL) luaL_error(L, "attempt to use a closed file");
+ // instead of using native timer routines, we're using os.startTimer so we can be resumed
+ if (!lua_isnoneornil(L, 1)) {
+ luaL_checknumber(L, 1);
+ lua_pushcfunction(L, os_startTimer);
+ lua_pushvalue(L, 1);
+ lua_call(L, 1, 1);
+ tm = lua_tointeger(L, -1);
+ lua_pop(L, 1);
+ } else tm = -1;
+ }
+ lua_settop(L, 0);
+ return lua_yieldk(L, 0, tm, websocket_server_listen);
+}
+
+/**
+ * Closes the WebSocket server.
+ */
+static int websocket_server_close(lua_State *L) {
+ lastCFunction = __func__;
+ websocket_server::Factory * f = *(websocket_server::Factory**)lua_touserdata(L, lua_upvalueindex(1));
+ if (f == NULL) return 0;
+ f->srv->stop();
+ delete f->srv;
+ delete f;
+ *(websocket_server::Factory**)lua_touserdata(L, lua_upvalueindex(1)) = NULL;
+ return 0;
+}
+
+static int websocket_server_free(lua_State *L) {
+ lastCFunction = __func__;
+ websocket_server::Factory * f = *(websocket_server::Factory**)lua_touserdata(L, 1);
+ if (f == NULL) return 0;
+ f->srv->stop();
+ delete f->srv;
+ delete f;
+ *(websocket_server::Factory**)lua_touserdata(L, 1) = NULL;
+ return 0;
+}
+
+static luaL_Reg websocket_server_funcs[] = {
+ {"listen", websocket_server_listen},
+ {"close", websocket_server_close},
+ {NULL, NULL}
+};
+
+/**
+ * Creates a new WebSocket server.
+ * @param port (number) The port to listen on
+ * @return Either a WebSocketServer handle, or nil + error
+ */
+static int http_websocketServer(lua_State *L) {
+ if (config.serverMode) return 0;
+ Computer * comp = get_comp(L);
+ int port = luaL_checkinteger(L, 1);
+ if (port < 0 || port > 65535) luaL_error(L, "bad argument #1 (port out of range)");
+ if (comp->openWebsocketServers.find(port) != comp->openWebsocketServers.end()) {
+ // if there's already an open server, reuse that
+ lua_pushnil(L);
+ lua_pushliteral(L, "Port already in use");
+ return 2;
+ }
+ std::unordered_map headers;
+ if (lua_istable(L, 2)) {
+ lua_pushvalue(L, 2);
+ lua_pushnil(L);
+ for (int i = 0; lua_next(L, -2); i++) {
+ size_t keyn = 0, valn = 0;
+ const char * key = lua_tolstring(L, -2, &keyn), *val = lua_tolstring(L, -1, &valn);
+ if (key && val) headers[std::string(key, keyn)] = std::string(val, valn);
+ lua_pop(L, 2);
+ }
+ lua_pop(L, 1);
+ } else if (!lua_isnoneornil(L, 2)) luaL_error(L, "bad argument #2 (expected table, got %s)", lua_typename(L, lua_type(L, 2)));
+ websocket_server::Factory * f = new websocket_server::Factory(comp, headers);
+ try {f->srv = new HTTPServer(f, port);}
+ catch (Poco::Exception& e) {
+ fprintf(stderr, "Could not open server: %s\n", e.displayText().c_str());
+ lua_pushnil(L);
+ lua_pushstring(L, e.displayText().c_str());
+ return 2;
+ }
+ comp->openWebsocketServers.insert(port);
+ f->srv->start();
+ lua_createtable(L, 0, 2);
+ *(websocket_server::Factory**)lua_newuserdata(L, sizeof(websocket_server::Factory*)) = f;
+ lua_createtable(L, 0, 1);
+ lua_pushcfunction(L, websocket_server_free);
+ lua_setfield(L, -2, "__gc");
+ lua_setmetatable(L, -2);
+ luaL_setfuncs(L, websocket_server_funcs, 1);
+ return 1;
+}
+
#ifdef __INTELLISENSE__
#pragma endregion
#endif
@@ -1373,6 +1446,7 @@ static luaL_Reg http_reg[] = {
{"addListener", http_addListener},
{"removeListener", http_removeListener},
{"websocket", http_websocket},
+ {"websocketServer", http_websocketServer},
{NULL, NULL}
};
diff --git a/src/apis/http_emscripten.cpp b/src/apis/http_emscripten.cpp
index df0a29a8..6a86841d 100644
--- a/src/apis/http_emscripten.cpp
+++ b/src/apis/http_emscripten.cpp
@@ -26,7 +26,6 @@ struct http_check_t {
};
struct http_data_t {
- bool isBinary;
Computer * comp;
char** headers;
};
@@ -38,7 +37,6 @@ struct http_param_t {
std::unordered_map headers;
std::string method;
std::string old_url;
- bool isBinary;
bool redirect;
};
@@ -152,22 +150,15 @@ std::string http_success(lua_State *L, void* data) {
lua_pushcclosure(L, http_handle_readAll, 1);
lua_settable(L, -3);
- if (!((http_data_t*)(*handle)->userData)->isBinary) {
- lua_pushstring(L, "readLine");
- lua_pushlightuserdata(L, handle);
- lua_pushcclosure(L, http_handle_readLine, 1);
- lua_settable(L, -3);
+ lua_pushstring(L, "read");
+ lua_pushlightuserdata(L, handle);
+ lua_pushcclosure(L, http_handle_readByte, 1);
+ lua_settable(L, -3);
- lua_pushstring(L, "read");
- lua_pushlightuserdata(L, handle);
- lua_pushcclosure(L, http_handle_readChar, 1);
- lua_settable(L, -3);
- } else {
- lua_pushstring(L, "read");
- lua_pushlightuserdata(L, handle);
- lua_pushcclosure(L, http_handle_readByte, 1);
- lua_settable(L, -3);
- }
+ lua_pushstring(L, "readLine");
+ lua_pushlightuserdata(L, handle);
+ lua_pushcclosure(L, http_handle_readLine, 1);
+ lua_settable(L, -3);
lua_pushstring(L, "getResponseCode");
lua_pushlightuserdata(L, handle);
@@ -221,7 +212,6 @@ int http_request(lua_State *L) {
attr.onsuccess = downloadSucceeded;
attr.onerror = downloadFailed;
http_data_t * data = new http_data_t;
- data->isBinary = lua_isboolean(L, 4) && lua_toboolean(L, 4);
data->comp = get_comp(L);
attr.userData = data;
if (lua_isstring(L, 2)) attr.requestData = lua_tolstring(L, 2, &attr.requestDataSize);
@@ -291,7 +281,7 @@ int http_checkURL(lua_State *L) {
luaL_checkstring(L, 1);
http_param_t * param = new http_param_t;
param->comp = get_comp(L);
- param->url = std::string(lua_tostring(L, 1), lua_strlen(L, 1));
+ param->url = std::string(lua_tostring(L, 1), lua_rawlen(L, 1));
std::thread th(checkThread, param);
setThreadName(th, "HTTP Check Thread");
th.detach();
diff --git a/src/apis/mounter.cpp b/src/apis/mounter.cpp
index 43a1e56e..a5e6c7ae 100644
--- a/src/apis/mounter.cpp
+++ b/src/apis/mounter.cpp
@@ -12,6 +12,7 @@
#include
#include
#include
+#include "../peripheral/debugger.hpp"
#include "../platform.hpp"
#include "../runtime.hpp"
#include "../terminal/SDLTerminal.hpp"
@@ -62,6 +63,7 @@ static int mounter_unmount(lua_State *L) {
if (it == computer->mounts.end()) break;
}
}
+ if (found && computer->debugger && !computer->isDebugger) ((debugger*)computer->debugger)->resetMounts();
lua_pushboolean(L, found);
return 1;
}
@@ -79,7 +81,7 @@ static int mounter_list(lua_State *L) {
lua_pop(L, 1); // table
lua_createtable(L, 1, 0); // table, entries
}
- lua_pushinteger(L, lua_objlen(L, -1) + 1); // table, entries, index
+ lua_pushinteger(L, lua_rawlen(L, -1) + 1); // table, entries, index
if (std::regex_match(std::get<1>(m), std::basic_regex(path_t("\\d+:").native()))) lua_pushfstring(L, "(virtual mount:%s)", std::get<1>(m).substr(0, std::get<1>(m).size()-1).c_str());
else lua_pushstring(L, path_t(std::get<1>(m)).string().c_str()); // table, entries, index, value
lua_settable(L, -3); // table, entries
diff --git a/src/apis/os.cpp b/src/apis/os.cpp
index a6490ca8..f91a9e61 100644
--- a/src/apis/os.cpp
+++ b/src/apis/os.cpp
@@ -26,7 +26,7 @@ static int os_getComputerLabel(lua_State *L) {
static int os_setComputerLabel(lua_State *L) {
lastCFunction = __func__;
Computer * comp = get_comp(L);
- comp->config->label = std::string(luaL_optstring(L, 1, ""), lua_isstring(L, 1) ? lua_strlen(L, 1) : 0);
+ comp->config->label = std::string(luaL_optstring(L, 1, ""), lua_isstring(L, 1) ? lua_rawlen(L, 1) : 0);
if (comp->term != NULL) comp->term->setLabel(comp->config->label.empty() ? "CraftOS Terminal: " + std::string(comp->isDebugger ? "Debugger" : "Computer") + " " + std::to_string(comp->id) : "CraftOS Terminal: " + asciify(comp->config->label));
return 0;
}
@@ -34,7 +34,7 @@ static int os_setComputerLabel(lua_State *L) {
static int os_queueEvent(lua_State *L) {
lastCFunction = __func__;
Computer * computer = get_comp(L);
- const std::string name = std::string(luaL_checkstring(L, 1), lua_strlen(L, 1));
+ const std::string name = std::string(luaL_checkstring(L, 1), lua_rawlen(L, 1));
if (!lua_checkstack(computer->paramQueue, 1)) luaL_error(L, "Could not allocate space for event");
lua_State *param = lua_newthread(computer->paramQueue);
lua_remove(L, 1);
diff --git a/src/apis/periphemu.cpp b/src/apis/periphemu.cpp
index 6610c58d..103ddf4a 100644
--- a/src/apis/periphemu.cpp
+++ b/src/apis/periphemu.cpp
@@ -138,7 +138,7 @@ bool detachPeripheral(Computer * computer, const std::string& side) {
static int periphemu_create(lua_State* L) {
lastCFunction = __func__;
- if (!lua_isstring(L, 1) && !lua_isnumber(L, 1)) return luaL_typerror(L, 1, "string or number");
+ if (!lua_isstring(L, 1) && !lua_isnumber(L, 1)) return luaL_error(L, "bad argument #1 (expected string or number, got %s)", lua_typename(L, lua_type(L, 1)));
Computer * computer = get_comp(L);
const std::string type = luaL_checkstring(L, 2);
std::string side = lua_isnumber(L, 1) ? type + "_" + std::to_string(lua_tointeger(L, 1)) : lua_tostring(L, 1);
diff --git a/src/apis/redstone.cpp b/src/apis/redstone.cpp
index 6ceef9a0..27a47319 100644
--- a/src/apis/redstone.cpp
+++ b/src/apis/redstone.cpp
@@ -19,6 +19,11 @@ static std::vector sides = {
"left"
};
+static const char * _typename(lua_State *L, int num) {
+ if (luaL_getmetafield(L, num, "__name")) return lua_tostring(L, -1);
+ else return luaL_typename(L, num);
+}
+
static int rs_getSides(lua_State *L) {
lua_createtable(L, 6, 0);
for (int i = 0; i < 6; i++) {
@@ -35,7 +40,7 @@ static int rs_getSides(lua_State *L) {
static int rs_getInput(lua_State *L) {
Computer * comp = get_comp(L);
- if (lua_type(L, 1) != LUA_TSTRING) return luaL_error(L, "bad argument #1 (string expected, got %s)", luaL_typename(L, 1));
+ if (lua_type(L, 1) != LUA_TSTRING) return luaL_error(L, "bad argument #1 (string expected, got %s)", _typename(L, 1));
std::string sidestr = lua_tostring(L, 1);
std::transform(sidestr.begin(), sidestr.end(), sidestr.begin(), [](unsigned char c) {return std::tolower(c); });
int side = -1;
@@ -52,7 +57,7 @@ static int rs_getInput(lua_State *L) {
static int rs_getOutput(lua_State *L) {
Computer * comp = get_comp(L);
- if (lua_type(L, 1) != LUA_TSTRING) return luaL_error(L, "bad argument #1 (string expected, got %s)", luaL_typename(L, 1));
+ if (lua_type(L, 1) != LUA_TSTRING) return luaL_error(L, "bad argument #1 (string expected, got %s)", _typename(L, 1));
std::string sidestr = lua_tostring(L, 1);
std::transform(sidestr.begin(), sidestr.end(), sidestr.begin(), [](unsigned char c) {return std::tolower(c); });
int side = -1;
@@ -69,7 +74,7 @@ static int rs_getOutput(lua_State *L) {
static int rs_setOutput(lua_State *L) {
Computer * comp = get_comp(L);
- if (lua_type(L, 1) != LUA_TSTRING) return luaL_error(L, "bad argument #1 (string expected, got %s)", luaL_typename(L, 1));
+ if (lua_type(L, 1) != LUA_TSTRING) return luaL_error(L, "bad argument #1 (string expected, got %s)", _typename(L, 1));
std::string sidestr = lua_tostring(L, 1);
std::transform(sidestr.begin(), sidestr.end(), sidestr.begin(), [](unsigned char c) {return std::tolower(c); });
int side = -1;
@@ -86,7 +91,7 @@ static int rs_setOutput(lua_State *L) {
static int rs_getAnalogInput(lua_State *L) {
Computer * comp = get_comp(L);
- if (lua_type(L, 1) != LUA_TSTRING) return luaL_error(L, "bad argument #1 (string expected, got %s)", luaL_typename(L, 1));
+ if (lua_type(L, 1) != LUA_TSTRING) return luaL_error(L, "bad argument #1 (string expected, got %s)", _typename(L, 1));
std::string sidestr = lua_tostring(L, 1);
std::transform(sidestr.begin(), sidestr.end(), sidestr.begin(), [](unsigned char c) {return std::tolower(c); });
int side = -1;
@@ -103,7 +108,7 @@ static int rs_getAnalogInput(lua_State *L) {
static int rs_getAnalogOutput(lua_State *L) {
Computer * comp = get_comp(L);
- if (lua_type(L, 1) != LUA_TSTRING) return luaL_error(L, "bad argument #1 (string expected, got %s)", luaL_typename(L, 1));
+ if (lua_type(L, 1) != LUA_TSTRING) return luaL_error(L, "bad argument #1 (string expected, got %s)", _typename(L, 1));
std::string sidestr = lua_tostring(L, 1);
std::transform(sidestr.begin(), sidestr.end(), sidestr.begin(), [](unsigned char c) {return std::tolower(c); });
int side = -1;
@@ -120,7 +125,7 @@ static int rs_getAnalogOutput(lua_State *L) {
static int rs_setAnalogOutput(lua_State *L) {
Computer * comp = get_comp(L);
- if (lua_type(L, 1) != LUA_TSTRING) return luaL_error(L, "bad argument #1 (string expected, got %s)", luaL_typename(L, 1));
+ if (lua_type(L, 1) != LUA_TSTRING) return luaL_error(L, "bad argument #1 (string expected, got %s)", _typename(L, 1));
std::string sidestr = lua_tostring(L, 1);
std::transform(sidestr.begin(), sidestr.end(), sidestr.begin(), [](unsigned char c) {return std::tolower(c); });
int side = -1;
@@ -131,7 +136,7 @@ static int rs_setAnalogOutput(lua_State *L) {
}
}
if (side == -1) return luaL_error(L, "bad argument #1 (unknown option %s)", sidestr.c_str());
- if (!lua_isnumber(L, 2)) return luaL_error(L, "bad argument #2 (number expected, got %s)", luaL_typename(L, 2));
+ if (!lua_isnumber(L, 2)) return luaL_error(L, "bad argument #2 (number expected, got %s)", _typename(L, 2));
const lua_Number strength = lua_tonumber(L, 2);
if (isnan(strength)) return luaL_argerror(L, 2, "number expected, got nan");
if (isinf(strength)) return luaL_argerror(L, 2, "number expected, got inf");
@@ -142,7 +147,7 @@ static int rs_setAnalogOutput(lua_State *L) {
static int rs_getBundledInput(lua_State *L) {
Computer * comp = get_comp(L);
- if (lua_type(L, 1) != LUA_TSTRING) return luaL_error(L, "bad argument #1 (string expected, got %s)", luaL_typename(L, 1));
+ if (lua_type(L, 1) != LUA_TSTRING) return luaL_error(L, "bad argument #1 (string expected, got %s)", _typename(L, 1));
std::string sidestr = lua_tostring(L, 1);
std::transform(sidestr.begin(), sidestr.end(), sidestr.begin(), [](unsigned char c) {return std::tolower(c); });
int side = -1;
@@ -159,7 +164,7 @@ static int rs_getBundledInput(lua_State *L) {
static int rs_getBundledOutput(lua_State *L) {
Computer * comp = get_comp(L);
- if (lua_type(L, 1) != LUA_TSTRING) return luaL_error(L, "bad argument #1 (string expected, got %s)", luaL_typename(L, 1));
+ if (lua_type(L, 1) != LUA_TSTRING) return luaL_error(L, "bad argument #1 (string expected, got %s)", _typename(L, 1));
std::string sidestr = lua_tostring(L, 1);
std::transform(sidestr.begin(), sidestr.end(), sidestr.begin(), [](unsigned char c) {return std::tolower(c); });
int side = -1;
@@ -176,7 +181,7 @@ static int rs_getBundledOutput(lua_State *L) {
static int rs_setBundledOutput(lua_State *L) {
Computer * comp = get_comp(L);
- if (lua_type(L, 1) != LUA_TSTRING) return luaL_error(L, "bad argument #1 (string expected, got %s)", luaL_typename(L, 1));
+ if (lua_type(L, 1) != LUA_TSTRING) return luaL_error(L, "bad argument #1 (string expected, got %s)", _typename(L, 1));
std::string sidestr = lua_tostring(L, 1);
std::transform(sidestr.begin(), sidestr.end(), sidestr.begin(), [](unsigned char c) {return std::tolower(c); });
int side = -1;
@@ -187,7 +192,7 @@ static int rs_setBundledOutput(lua_State *L) {
}
}
if (side == -1) return luaL_error(L, "bad argument #1 (unknown option %s)", sidestr.c_str());
- if (!lua_isnumber(L, 2)) return luaL_error(L, "bad argument #2 (number expected, got %s)", luaL_typename(L, 2));
+ if (!lua_isnumber(L, 2)) return luaL_error(L, "bad argument #2 (number expected, got %s)", _typename(L, 2));
const lua_Number strength = lua_tonumber(L, 2);
if (isnan(strength)) return luaL_argerror(L, 2, "number expected, got nan");
if (isinf(strength)) return luaL_argerror(L, 2, "number expected, got inf");
@@ -198,7 +203,7 @@ static int rs_setBundledOutput(lua_State *L) {
static int rs_testBundledInput(lua_State *L) {
Computer * comp = get_comp(L);
- if (lua_type(L, 1) != LUA_TSTRING) return luaL_error(L, "bad argument #1 (string expected, got %s)", luaL_typename(L, 1));
+ if (lua_type(L, 1) != LUA_TSTRING) return luaL_error(L, "bad argument #1 (string expected, got %s)", _typename(L, 1));
std::string sidestr = lua_tostring(L, 1);
std::transform(sidestr.begin(), sidestr.end(), sidestr.begin(), [](unsigned char c) {return std::tolower(c); });
int side = -1;
@@ -209,7 +214,7 @@ static int rs_testBundledInput(lua_State *L) {
}
}
if (side == -1) return luaL_error(L, "bad argument #1 (unknown option %s)", sidestr.c_str());
- if (!lua_isnumber(L, 2)) return luaL_error(L, "bad argument #2 (number expected, got %s)", luaL_typename(L, 2));
+ if (!lua_isnumber(L, 2)) return luaL_error(L, "bad argument #2 (number expected, got %s)", _typename(L, 2));
const lua_Number mask = lua_tonumber(L, 2);
if (isnan(mask)) return luaL_argerror(L, 2, "number expected, got nan");
if (isinf(mask)) return luaL_argerror(L, 2, "number expected, got inf");
@@ -218,7 +223,7 @@ static int rs_testBundledInput(lua_State *L) {
return 1;
}
-static luaL_reg rs_reg[] = {
+static luaL_Reg rs_reg[] = {
{"getSides", rs_getSides},
{"getInput", rs_getInput},
{"getOutput", rs_getOutput},
diff --git a/src/apis/term.cpp b/src/apis/term.cpp
index adef86f0..1b948f5b 100644
--- a/src/apis/term.cpp
+++ b/src/apis/term.cpp
@@ -21,7 +21,7 @@ static int term_write(lua_State *L) {
lastCFunction = __func__;
if (selectedRenderer == 1) {
printf("%s", luaL_checkstring(L, 1));
- headlessCursorX += lua_strlen(L, 1);
+ headlessCursorX += lua_rawlen(L, 1);
return 0;
} else if (selectedRenderer == 4) printf("TW:%d;%s\n", get_comp(L)->term->id, luaL_checkstring(L, 1));
Computer * computer = get_comp(L);
@@ -96,7 +96,7 @@ static int term_setCursorPos(lua_State *L) {
static int term_setCursorBlink(lua_State *L) {
lastCFunction = __func__;
- if (!lua_isboolean(L, 1)) luaL_typerror(L, 1, "boolean");
+ if (!lua_isboolean(L, 1)) luaL_error(L, "bad argument #1 (expected boolean, got %s)", lua_typename(L, lua_type(L, 1)));
if (selectedRenderer != 1) {
Terminal * term = get_comp(L)->term;
std::lock_guard lock(term->locked);
@@ -137,15 +137,19 @@ static int term_getSize(lua_State *L) {
}
Computer * computer = get_comp(L);
Terminal * term = computer->term;
- std::lock_guard lock(term->locked);
- if ((lua_isboolean(L, 1) && lua_toboolean(L, 1)) || (lua_isnumber(L, 1) && lua_tonumber(L, 1) > 0)) {
- lua_pushinteger(L, term->width * Terminal::fontWidth);
- lua_pushinteger(L, term->height * Terminal::fontHeight);
- } else if (lua_isnoneornil(L, 1) || lua_isboolean(L, 1) || (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0)) {
- lua_pushinteger(L, term->width);
- lua_pushinteger(L, term->height);
- } else luaL_typerror(L, 1, "boolean or number");
- return 2;
+ {
+ std::lock_guard lock(term->locked);
+ if ((lua_isboolean(L, 1) && lua_toboolean(L, 1)) || (lua_isnumber(L, 1) && lua_tonumber(L, 1) > 0)) {
+ lua_pushinteger(L, term->width * Terminal::fontWidth);
+ lua_pushinteger(L, term->height * Terminal::fontHeight);
+ } else if (lua_isnoneornil(L, 1) || lua_isboolean(L, 1) || (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0)) {
+ lua_pushinteger(L, term->width);
+ lua_pushinteger(L, term->height);
+ } else goto error;
+ return 2;
+ }
+error:
+ return luaL_error(L, "bad argument #1 (expected boolean or number, got %s)", lua_typename(L, lua_type(L, 1)));
}
static int term_clear(lua_State *L) {
@@ -240,7 +244,7 @@ static int term_blit(lua_State *L) {
lastCFunction = __func__;
if (selectedRenderer == 1) {
printf("%s", lua_tostring(L, 1));
- headlessCursorX += lua_strlen(L, 1);
+ headlessCursorX += lua_rawlen(L, 1);
return 0;
}
Computer * computer = get_comp(L);
@@ -321,7 +325,7 @@ static int term_setPaletteColor(lua_State *L) {
static int term_setGraphicsMode(lua_State *L) {
lastCFunction = __func__;
- if (!lua_isboolean(L, 1) && !lua_isnumber(L, 1)) luaL_typerror(L, 1, "boolean or number");
+ if (!lua_isboolean(L, 1) && !lua_isnumber(L, 1)) luaL_error(L, "bad argument #1 (expected boolean or number, got %s)", lua_typename(L, lua_type(L, 1)));
Computer * computer = get_comp(L);
if (selectedRenderer == 1 || selectedRenderer == 2 || !(computer->config->isColor || computer->isDebugger)) return 0;
if (lua_isnumber(L, 1) && (lua_tointeger(L, 1) < 0 || lua_tointeger(L, 1) > 2)) return luaL_error(L, "bad argument #1 (invalid mode %d)", lua_tointeger(L, 1));
@@ -394,7 +398,7 @@ static int term_drawPixels(lua_State *L) {
const bool isSolidFill = fillType == LUA_TNUMBER;
if (!isSolidFill && fillType != LUA_TTABLE)
- return luaL_typerror(L, 3, "table or number");
+ return luaL_error(L, "bad argument #3 (expected table or number, got %s)", lua_typename(L, lua_type(L, 3)));
bool undefinedWidth;
unsigned width, height;
@@ -409,7 +413,7 @@ static int term_drawPixels(lua_State *L) {
} else {
undefinedWidth = lua_isnoneornil(L, 4);
width_ = luaL_optinteger(L, 4, 0);
- height_ = luaL_optinteger(L, 5, lua_objlen(L, 3));
+ height_ = luaL_optinteger(L, 5, lua_rawlen(L, 3));
}
if (width_ < 0)
@@ -475,7 +479,7 @@ static int term_drawPixels(lua_State *L) {
} else if (lua_istable(L, -1)) {
// lol
const unsigned cool_width = (unsigned) undefinedWidth
- ? (int) min(lua_objlen(L, -1), (size_t) (max(pixelWidth - init_x, 0)))
+ ? (int) min(lua_rawlen(L, -1), (size_t) (max(pixelWidth - init_x, 0)))
: (int) min((int) width, pixelWidth - init_x);
for (unsigned w = max(-init_x, 0); w < cool_width; w++) {
@@ -519,7 +523,7 @@ static int term_getPixels(lua_State* L) {
if (end_w < 0) return luaL_argerror(L, 3, "width cannot be negative");
else if (end_h < 0) return luaL_argerror(L, 4, "height cannot be negative");
else if (!lua_isnoneornil(L, 5) && !lua_isboolean(L, 5))
- return luaL_typerror(L, 5, "boolean");
+ return luaL_error(L, "bad argument #5 (expected boolean, got %s)", lua_typename(L, lua_type(L, 5)));
const bool use_strings = lua_toboolean(L, 5);
@@ -615,21 +619,21 @@ static int term_nativePaletteColor(lua_State *L) {
static int term_showMouse(lua_State *L) {
lastCFunction = __func__;
- if (!lua_isboolean(L, 1)) luaL_typerror(L, 1, "boolean");
+ if (!lua_isboolean(L, 1)) luaL_error(L, "bad argument #1 (expected boolean, got %s)", lua_typename(L, lua_type(L, 1)));
SDL_ShowCursor(lua_toboolean(L, 1));
return 0;
}
static int term_relativeMouse(lua_State *L) {
lastCFunction = __func__;
- if (!lua_isboolean(L, 1)) luaL_typerror(L, 1, "boolean");
+ luaL_checktype(L, 1, LUA_TBOOLEAN);
SDL_SetRelativeMouseMode((SDL_bool)lua_toboolean(L, 1));
return 0;
}
static int term_setFrozen(lua_State *L) {
lastCFunction = __func__;
- if (!lua_isboolean(L, 1)) luaL_typerror(L, 1, "boolean");
+ if (!lua_isboolean(L, 1)) luaL_error(L, "bad argument #1 (expected boolean, got %s)", lua_typename(L, lua_type(L, 1)));
Terminal * term = get_comp(L)->term;
if (term == NULL) return 0;
std::lock_guard lock(term->locked);
@@ -653,7 +657,7 @@ static int term_getFrozen(lua_State *L) {
return 1;
}
-static luaL_reg term_reg[] = {
+static luaL_Reg term_reg[] = {
{"write", term_write},
{"scroll", term_scroll},
{"setCursorPos", term_setCursorPos},
diff --git a/src/peripheral/debugger.cpp b/src/peripheral/debugger.cpp
index 7f2c5f38..1a7d1830 100644
--- a/src/peripheral/debugger.cpp
+++ b/src/peripheral/debugger.cpp
@@ -414,7 +414,7 @@ static int debugger_lib_run(lua_State *L) {
lua_pushcfunction(dbg->thread, _echo);
lua_setfield(dbg->thread, -2, "_echo");
}
- lua_setfenv(dbg->thread, -2); // ..., func (w/env)
+ lua_setupvalue(dbg->thread, -2, 1); // ..., func (w/env)
lua_pushboolean(L, !lua_pcall(dbg->thread, 0, LUA_MULTRET, 0)); // ..., results...
const int top2 = lua_gettop(dbg->thread) - top; // #{..., results...} - #{...} = #{results...}
xcopy(dbg->thread, L, top2); // ...
@@ -473,7 +473,7 @@ static int debugger_lib_getfenv(lua_State *L) {
lua_Debug ar;
lua_getstack(dbg->thread, 0, &ar);
lua_getinfo(dbg->thread, "f", &ar);
- lua_getfenv(dbg->thread, -1);
+ lua_getupvalue(dbg->thread, -1, 1);
lua_xmove(dbg->thread, L, 1);
lua_pop(dbg->thread, 1);
return 1;
@@ -766,11 +766,12 @@ static std::string debugger_print(lua_State *L, void* arg) {
}
static int lua_converttostring (lua_State *L) {
- if (lua_icontext(L)) return 1;
+ int ctx = 0;
+ if (lua_getctx(L, &ctx) == LUA_YIELD) return 1;
luaL_checkany(L, 1);
if (luaL_getmetafield(L, 1, "__tostring")) {
lua_pushvalue(L, 1);
- lua_icall(L, 1, 1, 1); /* call metamethod */
+ lua_callk(L, 1, 1, 1, lua_converttostring); /* call metamethod */
return 1;
}
switch (lua_type(L, 1)) {
@@ -831,6 +832,7 @@ debugger::debugger(lua_State *L, const char * side) {
}
delete p;
monitor->debugger = createDebuggerLibrary();
+ for (const auto mount : computer->mounts) monitor->mounts.push_back(mount);
{
LockGuard lock(computers);
computers->push_back(monitor);
@@ -844,7 +846,7 @@ debugger::debugger(lua_State *L, const char * side) {
lua_sethook(computer->coro, termHook, LUA_MASKLINE | LUA_MASKRET | LUA_MASKCALL | LUA_MASKERROR | LUA_MASKRESUME | LUA_MASKYIELD, 0);
lua_sethook(L, termHook, LUA_MASKLINE | LUA_MASKRET | LUA_MASKCALL | LUA_MASKERROR | LUA_MASKRESUME | LUA_MASKYIELD, 0);
lua_getfield(L, LUA_REGISTRYINDEX, "_coroutine_stack");
- for (size_t i = 1; i <= lua_objlen(L, -1); i++) {
+ for (size_t i = 1; i <= lua_rawlen(L, -1); i++) {
lua_rawgeti(L, -1, (int)i);
if (lua_isthread(L, -1)) lua_sethook(lua_tothread(L, -1), termHook, LUA_MASKLINE | LUA_MASKRET | LUA_MASKCALL | LUA_MASKERROR | LUA_MASKRESUME | LUA_MASKYIELD, 0);
lua_pop(L, 1);
@@ -897,6 +899,11 @@ int debugger::_deinit(lua_State *L) {
return 0;
}
+void debugger::resetMounts() {
+ monitor->mounts.clear();
+ for (const auto mount : computer->mounts) monitor->mounts.push_back(mount);
+}
+
static luaL_Reg debugger_reg[] = {
{"stop", NULL},
{"setBreakpoint", NULL},
diff --git a/src/peripheral/debugger.hpp b/src/peripheral/debugger.hpp
index bf843ca6..b7c48733 100644
--- a/src/peripheral/debugger.hpp
+++ b/src/peripheral/debugger.hpp
@@ -74,6 +74,7 @@ class debugger: public peripheral {
virtual int call(lua_State *L, const char * method) override;
library_t getMethods() const override {return methods;}
void reinitialize(lua_State *L) override;
+ void resetMounts();
};
#endif
\ No newline at end of file
diff --git a/src/peripheral/drive.cpp b/src/peripheral/drive.cpp
index e1634054..33530435 100644
--- a/src/peripheral/drive.cpp
+++ b/src/peripheral/drive.cpp
@@ -224,7 +224,7 @@ int drive::insertDisk(lua_State *L, bool init) {
#endif
} else {
if (init) throw std::invalid_argument("bad argument (expected string or number)");
- else luaL_typerror(L, arg, "string or number");
+ else luaL_error(L, "bad argument #%d (expected string or number, got %s)", arg, lua_typename(L, lua_type(L, arg)));
}
return 0;
// This dirty hack is because Windows randomly attempts to deallocate a std::wstring
diff --git a/src/peripheral/monitor.cpp b/src/peripheral/monitor.cpp
index 3bc532a9..72bdde9a 100644
--- a/src/peripheral/monitor.cpp
+++ b/src/peripheral/monitor.cpp
@@ -110,7 +110,7 @@ int monitor::getSize(lua_State *L) {
} else if (lua_isnoneornil(L, 1) || lua_isboolean(L, 1) || (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0)) {
lua_pushinteger(L, term->width);
lua_pushinteger(L, term->height);
- } else luaL_typerror(L, 1, "boolean or number");
+ } else luaL_error(L, "bad argument #1 (expected boolean or number, got %s)", lua_typename(L, lua_type(L, 1)));
return 2;
}
@@ -243,7 +243,7 @@ int monitor::setPaletteColor(lua_State *L) {
int monitor::setGraphicsMode(lua_State *L) {
lastCFunction = __func__;
- if (!lua_isnumber(L, 1) && !lua_isboolean(L, 1)) luaL_typerror(L, 1, "number");
+ if (!lua_isnumber(L, 1) && !lua_isboolean(L, 1)) luaL_error(L, "bad argument #1 (expected number, got %s)", lua_typename(L, lua_type(L, 1)));
if (selectedRenderer == 1 || selectedRenderer == 2) return 0;
if (lua_isnumber(L, 1) && (lua_tointeger(L, 1) < 0 || lua_tointeger(L, 1) > 2)) return luaL_error(L, "bad argument #1 (invalid mode %d)", lua_tointeger(L, 1));
std::lock_guard lock(term->locked);
@@ -322,7 +322,7 @@ int monitor::drawPixels(lua_State *L) {
const bool isSolidFill = fillType == LUA_TNUMBER;
if (!isSolidFill && fillType != LUA_TTABLE)
- return luaL_typerror(L, 3, "table or number");
+ return luaL_error(L, "bad argument #3 (expected table or number, got %s)", lua_typename(L, lua_type(L, 3)));
bool undefinedWidth;
unsigned width, height;
@@ -337,7 +337,7 @@ int monitor::drawPixels(lua_State *L) {
} else {
undefinedWidth = lua_isnoneornil(L, 4);
width_ = luaL_optinteger(L, 4, 0);
- height_ = luaL_optinteger(L, 5, lua_objlen(L, 3));
+ height_ = luaL_optinteger(L, 5, lua_rawlen(L, 3));
}
if (width_ < 0)
@@ -402,7 +402,7 @@ int monitor::drawPixels(lua_State *L) {
} else if (lua_istable(L, -1)) {
// lol
const unsigned cool_width = (unsigned) undefinedWidth
- ? (int) min(lua_objlen(L, -1), (size_t) (max(pixelWidth - init_x, 0)))
+ ? (int) min(lua_rawlen(L, -1), (size_t) (max(pixelWidth - init_x, 0)))
: (int) min((int) width, pixelWidth - init_x);
for (unsigned w = max(-init_x, 0); w < cool_width; w++) {
@@ -443,7 +443,7 @@ int monitor::getPixels(lua_State* L) {
if (end_w < 0) return luaL_argerror(L, 3, "width cannot be negative");
else if (end_h < 0) return luaL_argerror(L, 4, "height cannot be negative");
else if (!lua_isnoneornil(L, 5) && !lua_isboolean(L, 5))
- return luaL_typerror(L, 5, "boolean");
+ return luaL_error(L, "bad argument #5 (expected boolean, got %s)", lua_typename(L, lua_type(L, 5)));
const bool use_strings = lua_toboolean(L, 5);
@@ -527,7 +527,7 @@ int monitor::screenshot(lua_State *L) {
int monitor::setFrozen(lua_State *L) {
lastCFunction = __func__;
- if (!lua_isboolean(L, 1)) luaL_typerror(L, 1, "boolean");
+ if (!lua_isboolean(L, 1)) luaL_error(L, "bad argument #1 (expected boolean, got %s)", lua_typename(L, lua_type(L, 1)));
if (term == NULL) return 0;
std::lock_guard lock(term->locked);
term->frozen = lua_toboolean(L, 1);
diff --git a/src/peripheral/printer.cpp b/src/peripheral/printer.cpp
index 02ef84c2..e5d0b9cc 100644
--- a/src/peripheral/printer.cpp
+++ b/src/peripheral/printer.cpp
@@ -268,7 +268,7 @@ int printer::getInkLevel(lua_State *L) {
int printer::setPageTitle(lua_State *L) {
lastCFunction = __func__;
- title = std::string(luaL_checkstring(L, 1), lua_strlen(L, 1));
+ title = std::string(luaL_checkstring(L, 1), lua_rawlen(L, 1));
return 0;
}
diff --git a/src/peripheral/speaker.cpp b/src/peripheral/speaker.cpp
index 1b313bd7..215f8dbc 100644
--- a/src/peripheral/speaker.cpp
+++ b/src/peripheral/speaker.cpp
@@ -565,7 +565,7 @@ int speaker::playAudio(lua_State *L) {
luaL_checktype(L, 1, LUA_TTABLE);
const double volume = luaL_optnumber(L, 2, 1.0);
if (volume < 0.0 || volume > 3.0) luaL_error(L, "invalid volume %f", volume);
- size_t len = lua_objlen(L, 1);
+ size_t len = lua_rawlen(L, 1);
if (len > 131072) luaL_error(L, "Audio data is too large");
else if (len == 0) luaL_error(L, "Cannot play empty audio");
if (audioQueue->size() > (config.standardsMode ? 47 : 187)) {
diff --git a/src/platform/CraftOS-PC 2.rc b/src/platform/CraftOS-PC 2.rc
index 11ca7644..53993765 100644
--- a/src/platform/CraftOS-PC 2.rc
+++ b/src/platform/CraftOS-PC 2.rc
@@ -60,8 +60,8 @@ MANIFEST RT_MANIFEST "..\\..\\resources\\CraftOS-PC.e
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 2,7,5,0
- PRODUCTVERSION 2,7,5,0
+ FILEVERSION 2,8,0,0
+ PRODUCTVERSION 2,8,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -77,12 +77,12 @@ BEGIN
BLOCK "040904b0"
BEGIN
VALUE "FileDescription", "CraftOS-PC"
- VALUE "FileVersion", "2.7.6.0"
+ VALUE "FileVersion", "2.8.0.0"
VALUE "InternalName", "CraftOS-PC.exe"
VALUE "LegalCopyright", "Copyright (C) 2019-2023 JackMacWindows."
VALUE "OriginalFilename", "CraftOS-PC.exe"
VALUE "ProductName", "CraftOS-PC"
- VALUE "ProductVersion", "2.7.6.0"
+ VALUE "ProductVersion", "2.8.0.0"
END
END
BLOCK "VarFileInfo"
diff --git a/src/plugin.cpp b/src/plugin.cpp
index fe1dc283..d935bc11 100644
--- a/src/plugin.cpp
+++ b/src/plugin.cpp
@@ -73,7 +73,7 @@ extern bool checkIAPEligibility(const char * identifier);
static const PluginFunctions function_map = {
PLUGIN_VERSION,
- 8,
+ 0,
CRAFTOSPC_VERSION,
selectedRenderer,
&config,
diff --git a/src/runtime.cpp b/src/runtime.cpp
index d9eeb3e3..57cde0ed 100644
--- a/src/runtime.cpp
+++ b/src/runtime.cpp
@@ -22,6 +22,7 @@
#include
#include "main.hpp"
#include "runtime.hpp"
+#include "peripheral/debugger.hpp"
#include "platform.hpp"
#include "terminal/SDLTerminal.hpp"
#include "terminal/CLITerminal.hpp"
@@ -392,6 +393,7 @@ bool addMount(Computer *comp, const path_t& real_path, const std::string& comp_p
if (!selected) return false;
}
comp->mounts.push_back(std::make_tuple(std::list(pathc), real_path, read_only));
+ if (comp->debugger && !comp->isDebugger) ((debugger*)comp->debugger)->resetMounts();
return true;
}
diff --git a/src/terminal/RawTerminal.cpp b/src/terminal/RawTerminal.cpp
index 6c80768b..318a2a9b 100644
--- a/src/terminal/RawTerminal.cpp
+++ b/src/terminal/RawTerminal.cpp
@@ -724,7 +724,7 @@ static void rawInputLoop() {
lua_getfield(comp->rawFileStack, -1, "readAll");
lua_call(comp->rawFileStack, 0, 1);
if (lua_isnil(comp->rawFileStack, -1)) data = ""; // shouldn't happen
- else data = std::string(lua_tostring(comp->rawFileStack, -1), lua_strlen(comp->rawFileStack, -1));
+ else data = std::string(lua_tostring(comp->rawFileStack, -1), lua_rawlen(comp->rawFileStack, -1));
lua_pop(comp->rawFileStack, 1);
lua_getfield(comp->rawFileStack, -1, "close");
lua_call(comp->rawFileStack, 0, 0);
@@ -803,11 +803,11 @@ static void rawInputLoop() {
lua_pushstring(comp->rawFileStack, path.c_str());
uint32_t size;
if (lua_pcall(comp->rawFileStack, 1, 1, 0)) size = 0xFFFFFFFF;
- else size = lua_objlen(comp->rawFileStack, -1);
+ else size = lua_rawlen(comp->rawFileStack, -1);
out.write((char*)&size, 4);
if (size != 0xFFFFFFFF) for (uint32_t i = 0; i < size; i++) {
lua_rawgeti(comp->rawFileStack, -1, i + 1);
- out.write(lua_tostring(comp->rawFileStack, -1), lua_strlen(comp->rawFileStack, -1));
+ out.write(lua_tostring(comp->rawFileStack, -1), lua_rawlen(comp->rawFileStack, -1));
out.put(0);
lua_pop(comp->rawFileStack, 1);
}
@@ -854,11 +854,11 @@ static void rawInputLoop() {
lua_pushstring(comp->rawFileStack, path.c_str());
uint32_t size;
if (lua_pcall(comp->rawFileStack, 1, 1, 0)) size = 0xFFFFFFFF;
- else size = lua_objlen(comp->rawFileStack, -1);
+ else size = lua_rawlen(comp->rawFileStack, -1);
out.write((char*)&size, 4);
if (size != 0xFFFFFFFF) for (uint32_t i = 0; i < size; i++) {
lua_rawgeti(comp->rawFileStack, -1, i + 1);
- out.write(lua_tostring(comp->rawFileStack, -1), lua_strlen(comp->rawFileStack, -1));
+ out.write(lua_tostring(comp->rawFileStack, -1), lua_rawlen(comp->rawFileStack, -1));
out.put(0);
lua_pop(comp->rawFileStack, 1);
}
@@ -868,7 +868,7 @@ static void rawInputLoop() {
lua_pushcfunction(comp->rawFileStack, findLibraryFunction(fs_lib.functions, "makeDir"));
lua_pushstring(comp->rawFileStack, path.c_str());
if (lua_pcall(comp->rawFileStack, 1, 0, 0)) {
- out.write(lua_tostring(comp->rawFileStack, -1), lua_strlen(comp->rawFileStack, -1));
+ out.write(lua_tostring(comp->rawFileStack, -1), lua_rawlen(comp->rawFileStack, -1));
lua_pop(comp->rawFileStack, 1);
}
out.put(0);
@@ -877,7 +877,7 @@ static void rawInputLoop() {
lua_pushcfunction(comp->rawFileStack, findLibraryFunction(fs_lib.functions, "delete"));
lua_pushstring(comp->rawFileStack, path.c_str());
if (lua_pcall(comp->rawFileStack, 1, 0, 0)) {
- out.write(lua_tostring(comp->rawFileStack, -1), lua_strlen(comp->rawFileStack, -1));
+ out.write(lua_tostring(comp->rawFileStack, -1), lua_rawlen(comp->rawFileStack, -1));
lua_pop(comp->rawFileStack, 1);
}
out.put(0);
@@ -887,7 +887,7 @@ static void rawInputLoop() {
lua_pushstring(comp->rawFileStack, path.c_str());
lua_pushstring(comp->rawFileStack, path2.c_str());
if (lua_pcall(comp->rawFileStack, 2, 0, 0)) {
- out.write(lua_tostring(comp->rawFileStack, -1), lua_strlen(comp->rawFileStack, -1));
+ out.write(lua_tostring(comp->rawFileStack, -1), lua_rawlen(comp->rawFileStack, -1));
lua_pop(comp->rawFileStack, 1);
}
out.put(0);
@@ -897,7 +897,7 @@ static void rawInputLoop() {
lua_pushstring(comp->rawFileStack, path.c_str());
lua_pushstring(comp->rawFileStack, path2.c_str());
if (lua_pcall(comp->rawFileStack, 2, 0, 0)) {
- out.write(lua_tostring(comp->rawFileStack, -1), lua_strlen(comp->rawFileStack, -1));
+ out.write(lua_tostring(comp->rawFileStack, -1), lua_rawlen(comp->rawFileStack, -1));
lua_pop(comp->rawFileStack, 1);
}
out.put(0);
@@ -944,10 +944,10 @@ static void rawInputLoop() {
lua_pushstring(comp->rawFileStack, path.c_str());
lua_pushstring(comp->rawFileStack, (std::string((reqtype & CCPC_RAW_FILE_REQUEST_OPEN_APPEND) ? "a" : "w") + ((reqtype & CCPC_RAW_FILE_REQUEST_OPEN_BINARY) ? "b" : "")).c_str());
if (lua_pcall(comp->rawFileStack, 2, 2, 0)) {
- out.write(lua_tostring(comp->rawFileStack, -1), lua_strlen(comp->rawFileStack, -1) + 1);
+ out.write(lua_tostring(comp->rawFileStack, -1), lua_rawlen(comp->rawFileStack, -1) + 1);
lua_pop(comp->rawFileStack, 1);
} else if (lua_isnil(comp->rawFileStack, -2)) {
- out.write(lua_tostring(comp->rawFileStack, -1), lua_strlen(comp->rawFileStack, -1) + 1);
+ out.write(lua_tostring(comp->rawFileStack, -1), lua_rawlen(comp->rawFileStack, -1) + 1);
lua_pop(comp->rawFileStack, 2);
} else {
lua_pop(comp->rawFileStack, 1);
diff --git a/src/terminal/TRoRTerminal.cpp b/src/terminal/TRoRTerminal.cpp
index 98b7a0e6..c2bda8dc 100644
--- a/src/terminal/TRoRTerminal.cpp
+++ b/src/terminal/TRoRTerminal.cpp
@@ -44,7 +44,7 @@ static std::string trorEvent(lua_State *L, void* userp) {
}
delete str;
lua_newtable(L);
- lua_setfenv(L, -2);
+ lua_setupvalue(L, -2, 1);
lua_call(L, 0, LUA_MULTRET);
std::string name = lua_tostring(L, 1);
lua_remove(L, 1);
diff --git a/src/termsupport.cpp b/src/termsupport.cpp
index 793e95cf..f56f76b1 100644
--- a/src/termsupport.cpp
+++ b/src/termsupport.cpp
@@ -411,17 +411,17 @@ static void noDebuggerBreak(lua_State *L, Computer * computer, lua_Debug * ar) {
lua_settable(coro, -3);
lua_newtable(coro);
lua_pushstring(coro, "__index");
- lua_getfenv(L, -2);
+ lua_getupvalue(L, -2, 1);
lua_xmove(L, coro, 1);
lua_settable(coro, -3);
lua_setmetatable(coro, -2);
lua_pushstring(coro, "/rom/programs/lua.lua");
- int status = lua_resume(coro, 2);
+ int status = lua_resume(coro, L, 2);
int narg;
while (status == LUA_YIELD) {
- if (lua_isstring(coro, -1)) narg = getNextEvent(coro, std::string(lua_tostring(coro, -1), lua_strlen(coro, -1)));
+ if (lua_isstring(coro, -1)) narg = getNextEvent(coro, std::string(lua_tostring(coro, -1), lua_rawlen(coro, -1)));
else narg = getNextEvent(coro, "");
- status = lua_resume(coro, narg);
+ status = lua_resume(coro, L, narg);
}
lua_pop(L, 1);
lua_pushnil(L);
@@ -442,18 +442,12 @@ extern "C" {
}
}
-extern "C" {
-#ifdef _WIN32
- __declspec(dllimport)
-#endif
- extern const char KEY_HOOK;
-}
-
void termHook(lua_State *L, lua_Debug *ar) {
std::string name; // For some reason MSVC explodes when this isn't at the top of the function
// I've had issues with it randomly moving scope boundaries around (see apis/config.cpp:101, runtime.cpp:249),
// so I'm not surprised about it happening again.
- if (lua_icontext(L) == 1) {
+ int ctx = 0;
+ if (lua_getctx(L, &ctx) == LUA_YIELD) {
lua_pop(L, 1);
return;
}
@@ -461,7 +455,7 @@ void termHook(lua_State *L, lua_Debug *ar) {
if (computer->debugger != NULL && !computer->isDebugger && (computer->shouldDeinitDebugger || ((debugger*)computer->debugger)->running == false)) {
computer->shouldDeinitDebugger = false;
lua_getfield(L, LUA_REGISTRYINDEX, "_coroutine_stack");
- for (size_t i = 1; i <= lua_objlen(L, -1); i++) {
+ for (size_t i = 1; i <= lua_rawlen(L, -1); i++) {
lua_rawgeti(L, -1, (int)i);
if (lua_isthread(L, -1)) lua_sethook(lua_tothread(L, -1), NULL, 0, 0); //lua_sethook(lua_tothread(L, -1), termHook, LUA_MASKRET | LUA_MASKCALL | LUA_MASKERROR | LUA_MASKRESUME | LUA_MASKYIELD, 0);
lua_pop(L, 1);
@@ -523,7 +517,7 @@ void termHook(lua_State *L, lua_Debug *ar) {
if (debuggerBreak(L, computer, dbg, lua_tostring(L, -2) == NULL ? "Error" : lua_tostring(L, -2))) return;
}
} else if (computer->debugger != NULL && !computer->isDebugger) {
- if (ar->event == LUA_HOOKRET || ar->event == LUA_HOOKTAILRET) {
+ if (ar->event == LUA_HOOKRET) {
debugger * dbg = (debugger*)computer->debugger;
if (dbg->breakType == DEBUGGER_BREAK_TYPE_RETURN && dbg->thread == NULL && debuggerBreak(L, computer, dbg, "Pause")) return;
if (dbg->isProfiling) {
@@ -720,6 +714,7 @@ std::string termGetEvent(lua_State *L) {
computer->waitingForTerminate &= ~1;
return "terminate";
} else if ((computer->waitingForTerminate & 3) == 0) computer->waitingForTerminate |= 1;
+ else return "";
} else if (((selectedRenderer == 0 || selectedRenderer == 5) ? e.key.keysym.sym == SDLK_s : e.key.keysym.sym == 31) && (e.key.keysym.mod & KMOD_CTRL)) {
if (computer->waitingForTerminate & 4) {
computer->waitingForTerminate |= 8;
@@ -727,6 +722,7 @@ std::string termGetEvent(lua_State *L) {
computer->running = 0;
return "terminate";
} else if ((computer->waitingForTerminate & 12) == 0) computer->waitingForTerminate |= 4;
+ else return "";
} else if (((selectedRenderer == 0 || selectedRenderer == 5) ? e.key.keysym.sym == SDLK_r : e.key.keysym.sym == 19) && (e.key.keysym.mod & KMOD_CTRL)) {
if (computer->waitingForTerminate & 16) {
computer->waitingForTerminate |= 32;
@@ -734,6 +730,7 @@ std::string termGetEvent(lua_State *L) {
computer->running = 2;
return "terminate";
} else if ((computer->waitingForTerminate & 48) == 0) computer->waitingForTerminate |= 16;
+ else return "";
} else if (e.key.keysym.sym == SDLK_v && (e.key.keysym.mod & KMOD_SYSMOD) && SDL_HasClipboardText()) {
char * text = SDL_GetClipboardText();
std::string str;
@@ -759,7 +756,7 @@ std::string termGetEvent(lua_State *L) {
std::string str;
try {str = utf8_to_string(e.text.text, std::locale("C"));}
catch (std::exception &ignored) {str = "?";}
- if (!str.empty()) {
+ if (!str.empty() && !(computer->waitingForTerminate & 0x2A)) {
#if defined(__ANDROID__) || defined(__IPHONEOS__)
mobileResetModifiers();
#endif
diff --git a/src/util.cpp b/src/util.cpp
index 9709365e..79fd5731 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -54,12 +54,7 @@ void uncache_state(lua_State *L) {
void load_library(Computer *comp, lua_State *L, const library_t& lib) {
lua_newtable(L);
- luaL_Reg * l = lib.functions;
- for (; l->name; l++) {
- if (l->func == NULL) continue;
- lua_pushcclosure(L, l->func, 0);
- lua_setfield(L, -2, l->name);
- }
+ luaL_setfuncs(L, lib.functions, 0);
lua_setglobal(L, lib.name);
if (lib.init != NULL) lib.init(comp);
}
@@ -230,20 +225,29 @@ path_t fixpath(Computer *comp, const std::string& path, bool exists, bool addExt
if (!found) return path_t();
} else if (pathc.size() > 1) {
bool found = false;
- std::string back = pathc.back();
- pathc.pop_back();
- for (const _path_t& p : max_path.second) {
- path_t sstmp = p;
- for (const std::string& s : pathc) sstmp /= s;
- e.clear();
- if (
- (isVFSPath(p) && (nothrow(comp->virtualMounts[(unsigned)std::stoul(p.substr(0, p.size()-1))]->path(ss/back)) ||
- (nothrow(comp->virtualMounts[(unsigned)std::stoul(p.substr(0, p.size()-1))]->path(sstmp)) && comp->virtualMounts[(unsigned)std::stoul(p.substr(0, p.size()-1))]->path(sstmp).isDir))) ||
- (fs::exists(sstmp/back, e)) || (fs::is_directory(sstmp, e))) {
- ss /= sstmp/back;
- found = true;
- break;
+ std::stack oldback;
+ while (!found && !pathc.empty()) {
+ found = false;
+ std::string back = pathc.back();
+ pathc.pop_back();
+ for (const _path_t& p : max_path.second) {
+ path_t sstmp = p;
+ for (const std::string& s : pathc) sstmp /= s;
+ e.clear();
+ if (
+ (isVFSPath(p) && (nothrow(comp->virtualMounts[(unsigned)std::stoul(p.substr(0, p.size()-1))]->path(ss/back)) ||
+ (nothrow(comp->virtualMounts[(unsigned)std::stoul(p.substr(0, p.size()-1))]->path(sstmp)) && comp->virtualMounts[(unsigned)std::stoul(p.substr(0, p.size()-1))]->path(sstmp).isDir))) ||
+ (fs::exists(sstmp/back, e)) || (fs::is_directory(sstmp, e))) {
+ ss /= sstmp/back;
+ while (!oldback.empty()) {
+ ss /= oldback.top();
+ oldback.pop();
+ }
+ found = true;
+ break;
+ }
}
+ if (!found) oldback.push(back);
}
if (!found) return path_t();
} else {
@@ -340,7 +344,7 @@ static void xcopy_internal(lua_State *from, lua_State *to, int n, int copies_slo
}
default: {
if (luaL_callmeta(from, -1-i, "__tostring")) {
- lua_pushlstring(to, lua_tostring(from, -1), lua_strlen(from, -1));
+ lua_pushlstring(to, lua_tostring(from, -1), lua_rawlen(from, -1));
lua_pop(from, 1);
} else lua_pushfstring(to, "<%s: %p>", lua_typename(from, lua_type(from, -1-i)), lua_topointer(from, -1-i));
break;
@@ -356,19 +360,9 @@ void xcopy(lua_State *from, lua_State *to, int n) {
lua_remove(to, cslot);
}
+// Deprecated as of CCPC v2.8; text mode no longer exists
std::string makeASCIISafe(const char * retval, size_t len) {
- std::wstring_convert> converter;
- std::wstring wstr;
- try {wstr = converter.from_bytes(retval, retval + len);}
- catch (std::exception &e) {
- fprintf(stderr, "fs_handle_readAll: Error decoding UTF-8: %s\n", e.what());
- std::string out;
- for (size_t i = 0; i < len; i++) {if ((unsigned char)retval[i] < 128) out += retval[i]; else out += '?';}
- return out;
- }
- std::string out;
- for (wchar_t c : wstr) {if (c < 256) out += (char)c; else out += '?';}
- return out;
+ return std::string(retval, len);
}
struct IPv6 {uint16_t a, b, c, d, e, f, g, h;};
diff --git a/src/util.hpp b/src/util.hpp
index 05ab0812..4d87d700 100644
--- a/src/util.hpp
+++ b/src/util.hpp
@@ -26,8 +26,8 @@ extern "C" {
#include
#include
-#define CRAFTOSPC_VERSION "v2.7.6"
-#define CRAFTOSPC_CC_VERSION "1.108.0"
+#define CRAFTOSPC_VERSION "v2.8"
+#define CRAFTOSPC_CC_VERSION "1.109.2"
#define CRAFTOSPC_INDEV true
using path_t = std::filesystem::path;
@@ -139,46 +139,28 @@ class Value {
};
// For get_comp
-typedef union {
- void *gc;
- void *p;
- lua_Number n;
- int b;
-} lua_Value;
-
-typedef struct lua_TValue {
- lua_Value value; int tt;
-} TValue;
-
struct lua_State {
- void *next;
- unsigned char tt;
- unsigned char marked;
- unsigned char status;
- void* top; /* first free slot in the stack */
- void* base; /* base of current function */
- void *l_G;
- void *ci; /* call info for current function */
- void* ctx; /* `savedpc' of current function, or context */
- void* stack_last; /* last free slot in the stack */
- void* stack; /* stack base */
- void *end_ci; /* points after end of ci array*/
- void *base_ci; /* array of CallInfo's */
- int stacksize;
- int size_ci; /* size of array `base_ci' */
- unsigned short nCcalls; /* number of nested C calls */
- unsigned short baseCcalls; /* nested C calls when resuming coroutine */
- unsigned char hookmask;
- unsigned char allowhook;
- int basehookcount;
- int hookcount;
- lua_Hook hook;
- TValue l_gt; /* table of globals */
- TValue env; /* temporary place for environments */
- void *openupval; /* list of open upvalues in this stack */
- void *gclist;
- struct lua_longjmp *errorJmp; /* current error recover point */
- ptrdiff_t errfunc; /* current error handling function (stack index) */
+ void *next; uint8_t tt; uint8_t marked;
+ uint8_t status;
+ void* top; /* first free slot in the stack */
+ void* l_G;
+ void *ci; /* call info for current function */
+ const int *oldpc; /* last pc traced */
+ void* stack_last; /* last free slot in the stack */
+ void* stack; /* stack base */
+ int stacksize;
+ unsigned short nny; /* number of non-yieldable calls in stack */
+ unsigned short nCcalls; /* number of nested C calls */
+ uint8_t hookmask;
+ uint8_t allowhook;
+ int basehookcount;
+ int hookcount;
+ lua_Hook hook;
+ void *openupval; /* list of open upvalues in this stack */
+ void *gclist;
+ struct lua_longjmp *errorJmp; /* current error recover point */
+ ptrdiff_t errfunc; /* current error handling function (stack index) */
+ void* base_ci; /* CallInfo for first level (C calling Lua) */
};
inline int log2i(int num) {
diff --git a/vcpkg.json b/vcpkg.json
index c363e8da..1d6b2e92 100644
--- a/vcpkg.json
+++ b/vcpkg.json
@@ -1,6 +1,6 @@
{
"name": "craftos-pc",
- "version-string": "v2.7",
+ "version-string": "v2.8",
"description": "Advanced ComputerCraft emulator",
"dependencies": [
"sdl2",