From ca8387a9e114a0c862c5da1de6636c46d17b5d9a Mon Sep 17 00:00:00 2001 From: IonutParau Date: Tue, 10 Feb 2026 21:37:22 +0100 Subject: [PATCH] bugfixes and useful constants --- rewrite/luaarch.c | 59 ++++++++++++++++--- rewrite/machine.lua | 20 +++++-- rewrite/main.c | 50 +++++++++++++++- rewrite/neonucleus.c | 105 +++++++++++++++++++++++++++++---- rewrite/neonucleus.h | 134 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 344 insertions(+), 24 deletions(-) diff --git a/rewrite/luaarch.c b/rewrite/luaarch.c index 43b61c1..b865edd 100644 --- a/rewrite/luaarch.c +++ b/rewrite/luaarch.c @@ -53,29 +53,26 @@ static luaArch *luaArch_from(lua_State *L) { } // pushes an NN value from a Lua stack index -static void luaArch_luaToNN(luaArch *arch, int luaIdx) { +static nn_Exit luaArch_luaToNN(luaArch *arch, int luaIdx) { lua_State *L = arch->L; nn_Computer *C = arch->computer; if(lua_isnoneornil(L, luaIdx)) { - nn_pushnull(C); - return; + return nn_pushnull(C); } if(lua_isnumber(L, luaIdx)) { - nn_pushnumber(C, lua_tonumber(L, luaIdx)); - return; + return nn_pushnumber(C, lua_tonumber(L, luaIdx)); } if(lua_isstring(L, luaIdx)) { size_t len; const char *s = lua_tolstring(L, luaIdx, &len); - nn_pushlstring(C, s, len); - return; + return nn_pushlstring(C, s, len); } if(lua_isboolean(L, luaIdx)) { - nn_pushbool(C, lua_toboolean(L, luaIdx)); - return; + return nn_pushbool(C, lua_toboolean(L, luaIdx)); } luaL_error(L, "bad Lua value: %s", luaL_typename(L, luaIdx)); + return NN_EBADSTATE; } // pushes a Lua value from an NN stack index @@ -233,6 +230,45 @@ static int luaArch_computer_isOverused(lua_State *L) { return 1; } +static int luaArch_computer_pushSignal(lua_State *L) { + luaArch *arch = luaArch_from(L); + nn_Computer *c = arch->computer; + size_t signalCount = lua_gettop(L); + nn_Exit err; + for(int i = 1; i <= signalCount; i++) { + err = luaArch_luaToNN(arch, i); + if(err) { + nn_setErrorFromExit(c, err); + luaL_error(L, "%s", nn_getError(c)); + } + } + err = nn_pushSignal(c, signalCount); + if(err) { + nn_setErrorFromExit(c, err); + luaL_error(L, "%s", nn_getError(c)); + } + return 0; +} + +static int luaArch_computer_popSignal(lua_State *L) { + luaArch *arch = luaArch_from(L); + nn_Computer *c = arch->computer; + // no signals queued + if(nn_countSignals(c) == 0) return 0; + nn_clearstack(c); + size_t signalCount; + nn_Exit err = nn_popSignal(c, &signalCount); + if(err) goto fail; + for(size_t i = 0; i < signalCount; i++) { + luaArch_nnToLua(arch, i); + } + return signalCount; +fail: + nn_setErrorFromExit(c, err); + luaL_error(L, "%s", nn_getError(c)); + return 0; +} + static int luaArch_component_list(lua_State *L) { luaArch *arch = luaArch_from(L); lua_createtable(L, 64, 0); @@ -406,6 +442,10 @@ static void luaArch_loadEnv(lua_State *L) { lua_setfield(L, computer, "shutdown"); lua_pushcfunction(L, luaArch_computer_isOverused); lua_setfield(L, computer, "isOverused"); + lua_pushcfunction(L, luaArch_computer_pushSignal); + lua_setfield(L, computer, "pushSignal"); + lua_pushcfunction(L, luaArch_computer_popSignal); + lua_setfield(L, computer, "popSignal"); lua_setglobal(L, "computer"); lua_createtable(L, 0, 10); int component = lua_gettop(L); @@ -460,6 +500,7 @@ static nn_Exit luaArch_handler(nn_ArchitectureRequest *req) { lua_settop(arch->L, 1); int ret = 0; int res = lua_resume(arch->L, NULL, 0, &ret); + //printf("res: %d\n", res); if(res == LUA_OK) { // halted, fuck lua_pop(arch->L, ret); diff --git a/rewrite/machine.lua b/rewrite/machine.lua index a32a606..1017d6d 100644 --- a/rewrite/machine.lua +++ b/rewrite/machine.lua @@ -3,6 +3,7 @@ -- Do not use in a serious context, you will be hacked. -- There is no sandboxing here. + local sysyieldobj = {} local function sysyield() @@ -13,10 +14,7 @@ local resume = coroutine.resume function coroutine.resume(co, ...) local t = {resume(co, ...)} - -- NOTE: user can trigger false sysyields - -- by simply yielding an object who's - -- __eql always returns true. - if t[1] and t[2] == sysyieldobj then + if t[1] and rawequal(t[2], sysyieldobj) then coroutine.yield(sysyieldobj) else return table.unpack(t) @@ -143,6 +141,20 @@ function computer.setArchitecture(arch) return ok, err end +function computer.pullSignal(timeout) + timeout = timeout or math.huge + local deadline = computer.uptime() + timeout + while true do + if computer.uptime() >= deadline then return end + local t = {computer.popSignal()} + if #t == 0 then + sysyield() + else + return table.unpack(t) + end + end +end + function checkArg(arg, val, ...) local t = {...} for i=1,#t do diff --git a/rewrite/main.c b/rewrite/main.c index 3bc077b..1e62580 100644 --- a/rewrite/main.c +++ b/rewrite/main.c @@ -8,6 +8,7 @@ #include #include #include +#include nn_Architecture getLuaArch(); @@ -19,6 +20,7 @@ nn_Architecture getLuaArch(); #define NE_PATHSEP '/' #include #include + #include typedef DIR ne_dir; @@ -40,6 +42,25 @@ nn_Architecture getLuaArch(); bool ne_exists(const char *path) { return access(path, F_OK) == 0; } + + size_t ne_sizeAt(const char *path) { + struct stat buf; + if(stat(path, &buf) != 0) return 0; + if(S_ISDIR(buf.st_mode)) return 0; + return buf.st_size; + } + + bool ne_isDirectory(const char *path) { + struct stat buf; + if(stat(path, &buf) != 0) return false; + return S_ISDIR(buf.st_mode); + } + + size_t ne_lastModified(const char *path) { + struct stat buf; + if(stat(path, &buf) != 0) return 0; + return buf.st_mtime; + } #endif static const char minBIOS[] = { @@ -212,8 +233,35 @@ nn_Exit ne_fsState_handler(nn_FilesystemRequest *req) { ne_fsState_truepath(state, truepath, req->strarg1); req->size = ne_exists(truepath) ? 1 : 0; return NN_OK; + case NN_FS_SIZE: + ne_fsState_truepath(state, truepath, req->strarg1); + if(!ne_exists(truepath)) { + nn_setError(C, "no such file or directory"); + return NN_EBADCALL; + } + req->size = ne_sizeAt(truepath); + return NN_OK; + case NN_FS_LASTMODIFIED: + ne_fsState_truepath(state, truepath, req->strarg1); + if(!ne_exists(truepath)) { + nn_setError(C, "no such file or directory"); + return NN_EBADCALL; + } + req->size = ne_lastModified(truepath); + return NN_OK; + case NN_FS_ISDIRECTORY: + ne_fsState_truepath(state, truepath, req->strarg1); + if(!ne_exists(truepath)) { + nn_setError(C, "no such file or directory"); + return NN_EBADCALL; + } + req->size = ne_isDirectory(truepath) ? 1 : 0; + return NN_OK; + default: + break; } - return NN_OK; + nn_setError(C, "not implemented"); + return NN_EBADCALL; } ne_FsState *ne_newFS(const char *path, bool readonly) { diff --git a/rewrite/neonucleus.c b/rewrite/neonucleus.c index b6d80ab..05c6937 100644 --- a/rewrite/neonucleus.c +++ b/rewrite/neonucleus.c @@ -29,7 +29,7 @@ bool nn_decRef(nn_refc_t *refc) { #else // we need atomics for thread-safe reference counting that will be used // for managing the lifetimes of various resources -// TODO: provide a way to use non-atomic values, and evaluate if the context should contain a method for atomics. +// TODO: evaluate if the context should contain a method for atomics. #include typedef atomic_size_t nn_refc_t; @@ -1026,6 +1026,8 @@ void nn_setErrorFromExit(nn_Computer *computer, nn_Exit exit) { } nn_Exit nn_tick(nn_Computer *computer) { + nn_resetCallBudget(computer); + nn_resetComponentBudgets(computer); nn_Exit err; if(computer->state == NN_BOOTUP) { // init state @@ -1045,8 +1047,6 @@ nn_Exit nn_tick(nn_Computer *computer) { nn_setErrorFromExit(computer, NN_EBADSTATE); return NN_EBADSTATE; } - nn_resetCallBudget(computer); - nn_resetComponentBudgets(computer); computer->state = NN_RUNNING; nn_ArchitectureRequest req; req.computer = computer; @@ -1072,6 +1072,7 @@ nn_Exit nn_addComponent(nn_Computer *computer, nn_ComponentType *ctype, const ch c.slot = slot; c.userdata = userdata; c.state = NULL; + c.budgetUsed = 0; nn_ComponentRequest req; req.typeUserdata = ctype->userdata; @@ -1249,6 +1250,16 @@ const char *nn_getComponentDoc(nn_Computer *computer, const char *address, const return NULL; } +void *nn_getComponentUserdata(nn_Computer *computer, const char *address) { + for(size_t i = 0; i < computer->componentLen; i++) { + nn_Component *c = &computer->components[i]; + if(nn_strcmp(c->address, address) == 0) { + return c->userdata; + } + } + return 0; +} + static void nn_retainValue(nn_Value val) { switch(val.type) { case NN_VAL_NULL: @@ -1347,11 +1358,6 @@ size_t nn_getCallBudget(nn_Computer *computer) { return computer->totalCallBudget; } -void nn_callCost(nn_Computer *computer, size_t callIntensity) { - if(computer->callBudget < callIntensity) computer->callBudget = 0; - else computer->callBudget -= callIntensity; -} - size_t nn_callBudgetRemaining(nn_Computer *computer) { return computer->callBudget; } @@ -2270,9 +2276,10 @@ nn_Exit nn_filesystem_handler(nn_ComponentRequest *req) { } fsreq.action = NN_FS_READ; fsreq.fd = nn_tonumber(computer, 0); - size_t requested = nn_tonumber(computer, 1); + double requested = nn_tonumber(computer, 1); if(requested > NN_MAX_READ) requested = NN_MAX_READ; - char buf[requested]; + if(requested < 0) requested = 0; + char buf[(size_t)requested]; fsreq.strarg1 = buf; fsreq.strarg1len = requested; err = state->handler(&fsreq); @@ -2433,6 +2440,84 @@ nn_Exit nn_filesystem_handler(nn_ComponentRequest *req) { req->returnCount = 1; return nn_pushbool(computer, fsreq.size != 0); } + if(nn_strcmp(method, "size") == 0) { + if(nn_getstacksize(computer) < 1) { + nn_setError(computer, "bad argument #1 (string expected)"); + return NN_EBADCALL; + } + if(!nn_isstring(computer, 0)) { + nn_setError(computer, "bad argument #1 (string expected)"); + return NN_EBADCALL; + } + char truepath[NN_MAX_PATH]; + size_t pathlen; + const char *path = nn_tolstring(computer, 0, &pathlen); + if(pathlen >= NN_MAX_PATH) { + nn_setError(computer, "path too long"); + return NN_EBADCALL; + } + nn_simplifyPath(path, truepath); + + fsreq.action = NN_FS_SIZE; + fsreq.strarg1 = truepath; + fsreq.strarg1len = nn_strlen(truepath); + err = state->handler(&fsreq); + if(err) return err; + req->returnCount = 1; + return nn_pushnumber(computer, fsreq.size); + } + if(nn_strcmp(method, "lastModified") == 0) { + if(nn_getstacksize(computer) < 1) { + nn_setError(computer, "bad argument #1 (string expected)"); + return NN_EBADCALL; + } + if(!nn_isstring(computer, 0)) { + nn_setError(computer, "bad argument #1 (string expected)"); + return NN_EBADCALL; + } + char truepath[NN_MAX_PATH]; + size_t pathlen; + const char *path = nn_tolstring(computer, 0, &pathlen); + if(pathlen >= NN_MAX_PATH) { + nn_setError(computer, "path too long"); + return NN_EBADCALL; + } + nn_simplifyPath(path, truepath); + + fsreq.action = NN_FS_SIZE; + fsreq.strarg1 = truepath; + fsreq.strarg1len = nn_strlen(truepath); + err = state->handler(&fsreq); + if(err) return err; + req->returnCount = 1; + return nn_pushnumber(computer, fsreq.size * 1000); + } + if(nn_strcmp(method, "isDirectory") == 0) { + if(nn_getstacksize(computer) < 1) { + nn_setError(computer, "bad argument #1 (string expected)"); + return NN_EBADCALL; + } + if(!nn_isstring(computer, 0)) { + nn_setError(computer, "bad argument #1 (string expected)"); + return NN_EBADCALL; + } + char truepath[NN_MAX_PATH]; + size_t pathlen; + const char *path = nn_tolstring(computer, 0, &pathlen); + if(pathlen >= NN_MAX_PATH) { + nn_setError(computer, "path too long"); + return NN_EBADCALL; + } + nn_simplifyPath(path, truepath); + + fsreq.action = NN_FS_ISDIRECTORY; + fsreq.strarg1 = truepath; + fsreq.strarg1len = nn_strlen(truepath); + err = state->handler(&fsreq); + if(err) return err; + req->returnCount = 1; + return nn_pushbool(computer, fsreq.size != 0); + } } return NN_OK; } diff --git a/rewrite/neonucleus.h b/rewrite/neonucleus.h index fd1b53a..6568700 100644 --- a/rewrite/neonucleus.h +++ b/rewrite/neonucleus.h @@ -499,6 +499,7 @@ const nn_Method *nn_getComponentMethods(nn_Computer *computer, const char *addre const char *nn_getComponentAddress(nn_Computer *computer, size_t idx); // Returns the doc-string associated with a method. const char *nn_getComponentDoc(nn_Computer *computer, const char *address, const char *method); +void *nn_getComponentUserdata(nn_Computer *computer, const char *address); // this uses the call stack. // Component calls must not call other components, it just doesn't work. @@ -1111,6 +1112,139 @@ const char *nn_depthName(int depth); #define NN_BUTTON_RIGHT 1 #define NN_BUTTON_MIDDLE 2 +// OC keycodes +// taken from https://github.com/MightyPirates/OpenComputers/blob/52da41b5e171b43fea80342dc75d808f97a0f797/src/main/resources/assets/opencomputers/loot/openos/lib/core/full_keyboard.lua +#define NN_KEY_UNKNOWN 0 +#define NN_KEY_1 0x02 +#define NN_KEY_2 0x03 +#define NN_KEY_3 0x04 +#define NN_KEY_4 0x05 +#define NN_KEY_5 0x06 +#define NN_KEY_6 0x07 +#define NN_KEY_7 0x08 +#define NN_KEY_8 0x09 +#define NN_KEY_9 0x0A +#define NN_KEY_0 0x0B +#define NN_KEY_A 0x1E +#define NN_KEY_B 0x30 +#define NN_KEY_C 0x2E +#define NN_KEY_D 0x20 +#define NN_KEY_E 0x12 +#define NN_KEY_F 0x21 +#define NN_KEY_G 0x22 +#define NN_KEY_H 0x23 +#define NN_KEY_I 0x17 +#define NN_KEY_J 0x24 +#define NN_KEY_K 0x25 +#define NN_KEY_L 0x26 +#define NN_KEY_M 0x32 +#define NN_KEY_N 0x31 +#define NN_KEY_O 0x18 +#define NN_KEY_P 0x19 +#define NN_KEY_Q 0x10 +#define NN_KEY_R 0x13 +#define NN_KEY_S 0x1F +#define NN_KEY_T 0x14 +#define NN_KEY_U 0x16 +#define NN_KEY_V 0x2F +#define NN_KEY_W 0x11 +#define NN_KEY_X 0x2D +#define NN_KEY_Y 0x15 +#define NN_KEY_Z 0x2C + +#define NN_KEY_APOSTROPHE 0x28 +#define NN_KEY_AT 0x91 +#define NN_KEY_BACK 0x0E +#define NN_KEY_BACKSLASH 0x2B +// caps-lock +#define NN_KEY_CAPITAL 0x3A +#define NN_KEY_COLON 0x92 +#define NN_KEY_COMMA 0x33 +#define NN_KEY_ENTER 0x1C +#define NN_KEY_EQUALS 0x0D +// accent grave +#define NN_KEY_GRAVE 0x29 +#define NN_KEY_LBRACKET 0x1A +#define NN_KEY_LCONTROL 0x1D +// left alt +#define NN_KEY_LMENU 0x38 +#define NN_KEY_LSHIFT 0x2A +#define NN_KEY_MINUS 0x0C +#define NN_KEY_NUMLOCK 0x45 +#define NN_KEY_PAUSE 0xC5 +#define NN_KEY_PERIOD 0x34 +#define NN_KEY_RBRACKET 0x1B +#define NN_KEY_RCONTROL 0x9D +// right alt +#define NN_KEY_RMENU 0xB8 +#define NN_KEY_RSHIFT 0x36 +// scroll lock +#define NN_KEY_SCROLL 0x46 +#define NN_KEY_SEMICOLON 0x27 +#define NN_KEY_SLASH 0x35 +#define NN_KEY_SPACE 0x39 +#define NN_KEY_STOP 0x95 +#define NN_KEY_TAB 0x0F +#define NN_KEY_UNDERLINE 0x93 + +#define NN_KEY_UP 0xC8 +#define NN_KEY_DOWN 0xD0 +#define NN_KEY_LEFT 0xCB +#define NN_KEY_RIGHT 0xCD +#define NN_KEY_HOME 0xC7 +#define NN_KEY_END 0xCF +#define NN_KEY_PAGEUP 0xC9 +#define NN_KEY_PAGEDOWN 0xD1 +#define NN_KEY_INSERT 0xD2 +#define NN_KEY_DELETE 0xD3 + +#define NN_KEY_F1 0x3B +#define NN_KEY_F2 0x3C +#define NN_KEY_F3 0x3D +#define NN_KEY_F4 0x3E +#define NN_KEY_F5 0x3F +#define NN_KEY_F6 0x40 +#define NN_KEY_F7 0x41 +#define NN_KEY_F8 0x42 +#define NN_KEY_F9 0x43 +#define NN_KEY_F10 0x44 +#define NN_KEY_F11 0x57 +#define NN_KEY_F12 0x58 +#define NN_KEY_F13 0x64 +#define NN_KEY_F14 0x65 +#define NN_KEY_F15 0x66 +#define NN_KEY_F16 0x67 +#define NN_KEY_F17 0x68 +#define NN_KEY_F18 0x69 +#define NN_KEY_F19 0x71 + +#define NN_KEYS_KANA 0x70 +#define NN_KEYS_KANJI 0x94 +#define NN_KEYS_CONVERT 0x79 +#define NN_KEYS_NOCONVERT 0x7B +#define NN_KEYS_YEN 0x7D +#define NN_KEYS_CIRCUMFLEX 0x90 +#define NN_KEYS_AX 0x96 + +#define NN_KEYS_NUMPAD0 0x52 +#define NN_KEYS_NUMPAD1 0x4F +#define NN_KEYS_NUMPAD2 0x50 +#define NN_KEYS_NUMPAD3 0x51 +#define NN_KEYS_NUMPAD4 0x4B +#define NN_KEYS_NUMPAD5 0x4C +#define NN_KEYS_NUMPAD6 0x4D +#define NN_KEYS_NUMPAD7 0x47 +#define NN_KEYS_NUMPAD8 0x48 +#define NN_KEYS_NUMPAD9 0x49 +#define NN_KEYS_NUMPADMUL 0x37 +#define NN_KEYS_NUMPADDIV 0xB5 +#define NN_KEYS_NUMPADSUB 0x4A +#define NN_KEYS_NUMPADADD 0x4E +#define NN_KEYS_NUMPADDECIMAL 0x53 +#define NN_KEYS_NUMPADCOMMA 0xB3 +#define NN_KEYS_NUMPADENTER 0x9C +#define NN_KEYS_NUMPADEQUALS 0x8D + // pushes a screen_resized signal nn_Exit nn_pushScreenResized(nn_Computer *computer, const char *screenAddress, int newWidth, int newHeight); // pushes a touch signal