bugfixes and useful constants

This commit is contained in:
IonutParau 2026-02-10 21:37:22 +01:00
parent 9c5e4a3d5b
commit ca8387a9e1
5 changed files with 344 additions and 24 deletions

View File

@ -53,29 +53,26 @@ static luaArch *luaArch_from(lua_State *L) {
} }
// pushes an NN value from a Lua stack index // 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; lua_State *L = arch->L;
nn_Computer *C = arch->computer; nn_Computer *C = arch->computer;
if(lua_isnoneornil(L, luaIdx)) { if(lua_isnoneornil(L, luaIdx)) {
nn_pushnull(C); return nn_pushnull(C);
return;
} }
if(lua_isnumber(L, luaIdx)) { if(lua_isnumber(L, luaIdx)) {
nn_pushnumber(C, lua_tonumber(L, luaIdx)); return nn_pushnumber(C, lua_tonumber(L, luaIdx));
return;
} }
if(lua_isstring(L, luaIdx)) { if(lua_isstring(L, luaIdx)) {
size_t len; size_t len;
const char *s = lua_tolstring(L, luaIdx, &len); const char *s = lua_tolstring(L, luaIdx, &len);
nn_pushlstring(C, s, len); return nn_pushlstring(C, s, len);
return;
} }
if(lua_isboolean(L, luaIdx)) { if(lua_isboolean(L, luaIdx)) {
nn_pushbool(C, lua_toboolean(L, luaIdx)); return nn_pushbool(C, lua_toboolean(L, luaIdx));
return;
} }
luaL_error(L, "bad Lua value: %s", luaL_typename(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 // pushes a Lua value from an NN stack index
@ -233,6 +230,45 @@ static int luaArch_computer_isOverused(lua_State *L) {
return 1; 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) { static int luaArch_component_list(lua_State *L) {
luaArch *arch = luaArch_from(L); luaArch *arch = luaArch_from(L);
lua_createtable(L, 64, 0); lua_createtable(L, 64, 0);
@ -406,6 +442,10 @@ static void luaArch_loadEnv(lua_State *L) {
lua_setfield(L, computer, "shutdown"); lua_setfield(L, computer, "shutdown");
lua_pushcfunction(L, luaArch_computer_isOverused); lua_pushcfunction(L, luaArch_computer_isOverused);
lua_setfield(L, 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_setglobal(L, "computer");
lua_createtable(L, 0, 10); lua_createtable(L, 0, 10);
int component = lua_gettop(L); int component = lua_gettop(L);
@ -460,6 +500,7 @@ static nn_Exit luaArch_handler(nn_ArchitectureRequest *req) {
lua_settop(arch->L, 1); lua_settop(arch->L, 1);
int ret = 0; int ret = 0;
int res = lua_resume(arch->L, NULL, 0, &ret); int res = lua_resume(arch->L, NULL, 0, &ret);
//printf("res: %d\n", res);
if(res == LUA_OK) { if(res == LUA_OK) {
// halted, fuck // halted, fuck
lua_pop(arch->L, ret); lua_pop(arch->L, ret);

View File

@ -3,6 +3,7 @@
-- Do not use in a serious context, you will be hacked. -- Do not use in a serious context, you will be hacked.
-- There is no sandboxing here. -- There is no sandboxing here.
local sysyieldobj = {} local sysyieldobj = {}
local function sysyield() local function sysyield()
@ -13,10 +14,7 @@ local resume = coroutine.resume
function coroutine.resume(co, ...) function coroutine.resume(co, ...)
local t = {resume(co, ...)} local t = {resume(co, ...)}
-- NOTE: user can trigger false sysyields if t[1] and rawequal(t[2], sysyieldobj) then
-- by simply yielding an object who's
-- __eql always returns true.
if t[1] and t[2] == sysyieldobj then
coroutine.yield(sysyieldobj) coroutine.yield(sysyieldobj)
else else
return table.unpack(t) return table.unpack(t)
@ -143,6 +141,20 @@ function computer.setArchitecture(arch)
return ok, err return ok, err
end 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, ...) function checkArg(arg, val, ...)
local t = {...} local t = {...}
for i=1,#t do for i=1,#t do

View File

@ -8,6 +8,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h>
nn_Architecture getLuaArch(); nn_Architecture getLuaArch();
@ -19,6 +20,7 @@ nn_Architecture getLuaArch();
#define NE_PATHSEP '/' #define NE_PATHSEP '/'
#include <dirent.h> #include <dirent.h>
#include <unistd.h> #include <unistd.h>
#include <sys/stat.h>
typedef DIR ne_dir; typedef DIR ne_dir;
@ -40,6 +42,25 @@ nn_Architecture getLuaArch();
bool ne_exists(const char *path) { bool ne_exists(const char *path) {
return access(path, F_OK) == 0; 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 #endif
static const char minBIOS[] = { static const char minBIOS[] = {
@ -212,8 +233,35 @@ nn_Exit ne_fsState_handler(nn_FilesystemRequest *req) {
ne_fsState_truepath(state, truepath, req->strarg1); ne_fsState_truepath(state, truepath, req->strarg1);
req->size = ne_exists(truepath) ? 1 : 0; req->size = ne_exists(truepath) ? 1 : 0;
return NN_OK; 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; 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;
}
nn_setError(C, "not implemented");
return NN_EBADCALL;
} }
ne_FsState *ne_newFS(const char *path, bool readonly) { ne_FsState *ne_newFS(const char *path, bool readonly) {

View File

@ -29,7 +29,7 @@ bool nn_decRef(nn_refc_t *refc) {
#else #else
// we need atomics for thread-safe reference counting that will be used // we need atomics for thread-safe reference counting that will be used
// for managing the lifetimes of various resources // 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 <stdatomic.h> #include <stdatomic.h>
typedef atomic_size_t nn_refc_t; 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_Exit nn_tick(nn_Computer *computer) {
nn_resetCallBudget(computer);
nn_resetComponentBudgets(computer);
nn_Exit err; nn_Exit err;
if(computer->state == NN_BOOTUP) { if(computer->state == NN_BOOTUP) {
// init state // init state
@ -1045,8 +1047,6 @@ nn_Exit nn_tick(nn_Computer *computer) {
nn_setErrorFromExit(computer, NN_EBADSTATE); nn_setErrorFromExit(computer, NN_EBADSTATE);
return NN_EBADSTATE; return NN_EBADSTATE;
} }
nn_resetCallBudget(computer);
nn_resetComponentBudgets(computer);
computer->state = NN_RUNNING; computer->state = NN_RUNNING;
nn_ArchitectureRequest req; nn_ArchitectureRequest req;
req.computer = computer; req.computer = computer;
@ -1072,6 +1072,7 @@ nn_Exit nn_addComponent(nn_Computer *computer, nn_ComponentType *ctype, const ch
c.slot = slot; c.slot = slot;
c.userdata = userdata; c.userdata = userdata;
c.state = NULL; c.state = NULL;
c.budgetUsed = 0;
nn_ComponentRequest req; nn_ComponentRequest req;
req.typeUserdata = ctype->userdata; req.typeUserdata = ctype->userdata;
@ -1249,6 +1250,16 @@ const char *nn_getComponentDoc(nn_Computer *computer, const char *address, const
return NULL; 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) { static void nn_retainValue(nn_Value val) {
switch(val.type) { switch(val.type) {
case NN_VAL_NULL: case NN_VAL_NULL:
@ -1347,11 +1358,6 @@ size_t nn_getCallBudget(nn_Computer *computer) {
return computer->totalCallBudget; 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) { size_t nn_callBudgetRemaining(nn_Computer *computer) {
return computer->callBudget; return computer->callBudget;
} }
@ -2270,9 +2276,10 @@ nn_Exit nn_filesystem_handler(nn_ComponentRequest *req) {
} }
fsreq.action = NN_FS_READ; fsreq.action = NN_FS_READ;
fsreq.fd = nn_tonumber(computer, 0); 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; 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.strarg1 = buf;
fsreq.strarg1len = requested; fsreq.strarg1len = requested;
err = state->handler(&fsreq); err = state->handler(&fsreq);
@ -2433,6 +2440,84 @@ nn_Exit nn_filesystem_handler(nn_ComponentRequest *req) {
req->returnCount = 1; req->returnCount = 1;
return nn_pushbool(computer, fsreq.size != 0); 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; return NN_OK;
} }

View File

@ -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); const char *nn_getComponentAddress(nn_Computer *computer, size_t idx);
// Returns the doc-string associated with a method. // Returns the doc-string associated with a method.
const char *nn_getComponentDoc(nn_Computer *computer, const char *address, const char *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. // this uses the call stack.
// Component calls must not call other components, it just doesn't work. // 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_RIGHT 1
#define NN_BUTTON_MIDDLE 2 #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 // pushes a screen_resized signal
nn_Exit nn_pushScreenResized(nn_Computer *computer, const char *screenAddress, int newWidth, int newHeight); nn_Exit nn_pushScreenResized(nn_Computer *computer, const char *screenAddress, int newWidth, int newHeight);
// pushes a touch signal // pushes a touch signal