This commit is contained in:
IonutParau 2026-02-14 15:21:47 +01:00
parent a2ddcfa030
commit 51224a46a2
7 changed files with 327 additions and 16 deletions

View File

@ -40,5 +40,6 @@ shell.setWorkingDirectory(os.getenv("HOME"))
local home_shrc = shell.resolve(".shrc")
if fs.exists(home_shrc) then
assert(loadfile(shell.resolve("source", "lua")))(home_shrc)
local resolved = shell.resolve("source", "lua")
assert(loadfile(resolved))(home_shrc)
end

View File

@ -14,12 +14,10 @@ do
end
while true do
debug.print("try shell")
local result, reason = xpcall(require("shell").getShell(), function(msg)
return tostring(msg).."\n"..debug.traceback()
end)
if not result then
debug.print(reason)
io.stderr:write((reason ~= nil and tostring(reason) or "unknown error") .. "\n")
io.write("Press any key to continue.\n")
os.sleep(0.5)

View File

@ -446,6 +446,12 @@ static int luaArch_unicode_sub(lua_State *L) {
size_t len = nn_unicode_lenPermissive(s, slen);
// OpenOS does this...
if(len == 0) {
lua_pushstring(L, "");
return 1;
}
int start = lua_tointeger(L, 2);
int end = lua_tointeger(L, 3);
@ -464,6 +470,11 @@ static int luaArch_unicode_sub(lua_State *L) {
if(end < 0) end = 0;
if(end >= len) end = len-1;
if(start > end) {
lua_pushstring(L, "");
return 1;
}
nn_codepoint *cp = malloc(sizeof(*cp) * len);
nn_unicode_codepointsPermissive(s, slen, cp);
@ -484,6 +495,11 @@ static int luaArch_unicode_wlen(lua_State *L) {
return 1;
}
static int luaArch_unicode_wtrunc(lua_State *L) {
lua_pushvalue(L, 1);
return 1;
}
static void luaArch_loadEnv(lua_State *L) {
lua_createtable(L, 0, 10);
int computer = lua_gettop(L);
@ -547,8 +563,10 @@ static void luaArch_loadEnv(lua_State *L) {
lua_setfield(L, component, "len");
lua_pushcfunction(L, luaArch_unicode_sub);
lua_setfield(L, component, "sub");
lua_pushcfunction(L, luaArch_unicode_wlen);
lua_pushcfunction(L, luaArch_unicode_len);
lua_setfield(L, component, "wlen");
lua_pushcfunction(L, luaArch_unicode_wtrunc);
lua_setfield(L, component, "wtrunc");
lua_setglobal(L, "unicode");
}

View File

@ -21,8 +21,9 @@ function coroutine.resume(co, ...)
end
end
local clist, cinvoke, computer, component, print = component.list, component.invoke, computer, component, print
local clist, cinvoke, computer, component, print, unicode = component.list, component.invoke, computer, component, print, unicode
debug.print = print
debug.sysyield = sysyield
function component.list(ctype, exact)
local list = clist()
@ -155,6 +156,44 @@ function computer.pullSignal(timeout)
end
end
unicode.upper, unicode.lower = string.upper, string.lower
unicode.isWide = function(s)
local c = unicode.sub(s, 1, 1)
return unicode.wlen(c) > unicode.len(c)
end
unicode.wtrunc = function(str,space)
space = space - 1
return unicode.sub(str, 1, space)
end
unicode.sub = function(str, a, b)
if not b then b = utf8.len(str) end
if not a then a = 1 end
-- a = math.max(a,1)
if a < 0 then
-- negative
a = utf8.len(str) + a + 1
end
if b < 0 then
b = utf8.len(str) + b + 1
end
if a > b then return "" end
if b >= utf8.len(str) then b = #str else b = utf8.offset(str,b+1)-1 end
if a > utf8.len(str) then return "" end
a = utf8.offset(str,a)
return str:sub(a,b)
-- return str:sub(a, b)
end
function checkArg(arg, val, ...)
local t = {...}
for i=1,#t do
@ -165,7 +204,7 @@ end
if os.getenv("NN_REPL") == "1" then
while true do
io.write("lua> ")
io.write("\x1b[34mlua>\x1b[0m ")
io.flush()
local l = io.read("l")
if not l then break end
@ -176,6 +215,7 @@ if os.getenv("NN_REPL") == "1" then
f, err = load(l, "=repl")
if f then f() else print(err) end
end
coroutine.yield()
end
io.write("\n")
print("exiting repl")

View File

@ -153,12 +153,16 @@ nn_Exit ne_fsState_handler(nn_FilesystemRequest *req) {
switch(mode[0]) {
case 'r':
mode = "rb";
break;
case 'w':
mode = "wb";
break;
case 'a':
mode = "ab";
break;
default:
mode = "rb";
break;
}
ne_fsState_truepath(state, truepath, path);
@ -568,15 +572,21 @@ nn_Exit ne_gpu_handler(nn_GPURequest *req) {
x = req->x;
y = req->y;
for(int i = 0; i < req->width; i++) {
const char *s = req->text;
for(int i = 0; i < req->width;) {
if(!ne_inScreenBuf(activeBuf, x, y)) break;
size_t w = nn_unicode_validateFirstChar(s + i, req->width - i);
ne_Pixel p = {
.fg = state->currentFg,
.bg = state->currentBg,
.isFgPalette = state->isFgPalette,
.isBgPalette = state->isBgPalette,
.codepoint = req->text[i],
.codepoint = (unsigned char)s[i],
};
if(w > 0) {
p.codepoint = nn_unicode_firstCodepoint(s + i);
i += w;
} else i++;
ne_setPixel(activeBuf, x, y, p);
x += dx;
y += dy;
@ -592,8 +602,7 @@ nn_Exit ne_gpu_handler(nn_GPURequest *req) {
y = req->y;
w = req->width;
h = req->height;
if(x < 1) x = 1;
if(y < 1) y = 1;
// prevent CPU DoS
if(w >= activeBuf->width) w = activeBuf->width - 1;
if(h >= activeBuf->height) h = activeBuf->height - 1;
@ -609,6 +618,93 @@ nn_Exit ne_gpu_handler(nn_GPURequest *req) {
ne_setPixel(activeBuf, x + ox, y + oy, p);
}
}
ne_remapScreen(activeBuf);
return NN_OK;
case NN_GPU_COPY:
if(activeBuf == NULL) {
nn_setError(C, "no screen");
return NN_EBADCALL;
}
x = req->x;
y = req->y;
w = req->width;
h = req->height;
// prevent CPU DoS
if(w >= activeBuf->width) w = activeBuf->width - 1;
if(h >= activeBuf->height) h = activeBuf->height - 1;
ne_Pixel *buf = malloc(sizeof(*buf) * w * h);
if(buf == NULL) return NN_ENOMEM;
for(int oy = 0; oy < h; oy++) {
for(int ox = 0; ox < w; ox++) {
buf[oy * w + ox] = ne_getPixel(activeBuf, x + ox, y + oy);
}
}
for(int oy = 0; oy < h; oy++) {
for(int ox = 0; ox < w; ox++) {
p = buf[oy * w + ox];
ne_setPixel(activeBuf, x + ox + req->tx, y + oy + req->ty, p);
}
}
free(buf);
ne_remapScreen(activeBuf);
return NN_OK;
case NN_GPU_GETDEPTH:
if(activeBuf != NULL) {
req->x = activeBuf->depth;
} else {
req->x = req->gpuConf->maxDepth;
}
return NN_OK;
case NN_GPU_GETVIEWPORT:
if(activeBuf == NULL) {
nn_setError(C, "no screen");
return NN_EBADCALL;
}
req->width = activeBuf->width;
req->height = activeBuf->height;
return NN_OK;
case NN_GPU_GETFOREGROUND:
req->x = state->currentFg;
req->y = state->isFgPalette ? 1 : 0;
return NN_OK;
case NN_GPU_GETBACKGROUND:
req->x = state->currentBg;
req->y = state->isBgPalette ? 1 : 0;
return NN_OK;
case NN_GPU_SETFOREGROUND:
x = req->x;
y = req->y;
if(y != 0) {
// validate the palette index
if(activeBuf == NULL || x < 0 || x >= activeBuf->maxPalette) {
nn_setError(C, "invalid palette index");
return NN_EBADCALL;
}
}
req->x = state->currentFg;
req->y = state->isFgPalette ? 1 : 0;
state->currentFg = x;
state->isFgPalette = y != 0;
ne_remapScreen(activeBuf);
return NN_OK;
case NN_GPU_SETBACKGROUND:
x = req->x;
y = req->y;
if(y != 0) {
// validate the palette index
if(activeBuf == NULL || x < 0 || x >= activeBuf->maxPalette) {
nn_setError(C, "invalid palette index");
return NN_EBADCALL;
}
}
req->x = state->currentBg;
req->y = state->isBgPalette ? 1 : 0;
state->currentBg = x;
state->isBgPalette = y != 0;
ne_remapScreen(activeBuf);
return NN_OK;
}
return NN_OK;
@ -620,11 +716,19 @@ Color ne_processColor(unsigned int color) {
return GetColor(color);
}
double ne_timeProc(void *_) {
(void)_;
double t = GetTime();
return (int)(t*100) / 100.0;
}
int main() {
nn_Context ctx;
nn_initContext(&ctx);
nn_initPalettes();
ctx.time = ne_timeProc;
SetConfigFlags(FLAG_WINDOW_RESIZABLE);
InitWindow(800, 600, "NeoNucleus Test Emulator");

View File

@ -2752,11 +2752,15 @@ nn_Exit nn_gpu_handler(nn_ComponentRequest *req) {
greq.text = (char *)nn_tolstring(C, 0, &len);
greq.width = len;
greq.x = nn_toboolean(C, 1) ? 1 : 0;
return state->handler(&greq);
err = state->handler(&greq);
if(err) return err;
return nn_pushbool(C, true);
}
if(nn_strcmp(method, "unbind") == 0) {
greq.action = NN_GPU_UNBIND;
return state->handler(&greq);
err = state->handler(&greq);
if(err) return err;
return nn_pushbool(C, true);
}
if(nn_strcmp(method, "getScreen") == 0) {
char buf[NN_MAX_ADDRESS];
@ -2798,6 +2802,148 @@ nn_Exit nn_gpu_handler(nn_ComponentRequest *req) {
req->returnCount = 1;
return nn_pushbool(C, true);
}
if(nn_strcmp(method, "get") == 0) {
nn_costComponent(C, req->compAddress, conf.setPerTick);
if(nn_checkinteger(C, 0, "bad argument #1 (integer expected)")) return NN_EBADCALL;
if(nn_checkinteger(C, 1, "bad argument #2 (integer expected)")) return NN_EBADCALL;
greq.action = NN_GPU_GET;
greq.x = nn_tointeger(C, 0);
greq.y = nn_tointeger(C, 1);
err = state->handler(&greq);
if(err) return err;
req->returnCount = 5;
char buf[NN_MAX_UNICODE_BUFFER];
size_t len = nn_unicode_codepointToChar(buf, greq.codepoint);
err = nn_pushlstring(C, buf, len);
if(err) return err;
err = nn_pushinteger(C, greq.width);
if(err) return err;
err = nn_pushinteger(C, greq.height);
if(err) return err;
if(greq.dest == -1) err = nn_pushnull(C);
else err = nn_pushinteger(C, greq.dest);
if(err) return err;
if(greq.src == -1) err = nn_pushnull(C);
else err = nn_pushinteger(C, greq.src);
if(err) return err;
return NN_OK;
}
if(nn_strcmp(method, "fill") == 0) {
nn_costComponent(C, req->compAddress, conf.fillPerTick);
if(nn_checkinteger(C, 0, "bad argument #1 (integer expected)")) return NN_EBADCALL;
if(nn_checkinteger(C, 1, "bad argument #2 (integer expected)")) return NN_EBADCALL;
if(nn_checkinteger(C, 2, "bad argument #3 (integer expected)")) return NN_EBADCALL;
if(nn_checkinteger(C, 3, "bad argument #4 (integer expected)")) return NN_EBADCALL;
if(nn_checkstring(C, 4, "bad argument #5 (string expected)")) return NN_EBADCALL;
greq.action = NN_GPU_FILL;
size_t len;
const char *text = nn_tolstring(C, 4, &len);
if(nn_unicode_validateFirstChar(text, len) == 0) {
nn_setError(C, "invalid UTF-8 character");
return NN_EBADCALL;
}
greq.codepoint = nn_unicode_firstCodepoint(text);
greq.x = nn_tointeger(C, 0);
greq.y = nn_tointeger(C, 1);
greq.width = nn_tointeger(C, 2);
greq.height = nn_tointeger(C, 3);
err = state->handler(&greq);
if(err) return err;
req->returnCount = 1;
return nn_pushbool(C, true);
}
if(nn_strcmp(method, "copy") == 0) {
nn_costComponent(C, req->compAddress, conf.copyPerTick);
if(nn_checkinteger(C, 0, "bad argument #1 (integer expected)")) return NN_EBADCALL;
if(nn_checkinteger(C, 1, "bad argument #2 (integer expected)")) return NN_EBADCALL;
if(nn_checkinteger(C, 2, "bad argument #3 (integer expected)")) return NN_EBADCALL;
if(nn_checkinteger(C, 3, "bad argument #4 (integer expected)")) return NN_EBADCALL;
if(nn_checkinteger(C, 4, "bad argument #5 (integer expected)")) return NN_EBADCALL;
if(nn_checkinteger(C, 5, "bad argument #6 (integer expected)")) return NN_EBADCALL;
greq.action = NN_GPU_COPY;
greq.x = nn_tointeger(C, 0);
greq.y = nn_tointeger(C, 1);
greq.width = nn_tointeger(C, 2);
greq.height = nn_tointeger(C, 3);
greq.tx = nn_tointeger(C, 4);
greq.ty = nn_tointeger(C, 5);
err = state->handler(&greq);
if(err) return err;
req->returnCount = 1;
return nn_pushbool(C, true);
}
if(nn_strcmp(method, "getDepth") == 0) {
greq.action = NN_GPU_GETDEPTH;
err = state->handler(&greq);
if(err) return err;
req->returnCount = 1;
return nn_pushinteger(C, greq.x);
}
if(nn_strcmp(method, "getViewport") == 0) {
greq.action = NN_GPU_GETVIEWPORT;
err = state->handler(&greq);
if(err) return err;
req->returnCount = 2;
err = nn_pushinteger(C, greq.width);
if(err) return err;
return nn_pushinteger(C, greq.height);
}
if(nn_strcmp(method, "setForeground") == 0) {
if(nn_checkinteger(C, 0, "bad argument #1 (integer expected)")) return NN_EBADCALL;
err = nn_defaultboolean(C, 1, false);
if(err) return err;
if(nn_checkinteger(C, 1, "bad argument #2 (boolean expected)")) return NN_EBADCALL;
greq.action = NN_GPU_SETFOREGROUND;
greq.x = nn_tointeger(C, 0);
greq.y = nn_toboolean(C, 1) ? 1 : 0;
err = state->handler(&greq);
if(err) return err;
req->returnCount = 2;
err = nn_pushinteger(C, greq.x);
if(err) return err;
err = nn_pushbool(C, greq.y != 0);
if(err) return err;
return NN_OK;
}
if(nn_strcmp(method, "getForeground") == 0) {
greq.action = NN_GPU_GETFOREGROUND;
err = state->handler(&greq);
if(err) return err;
req->returnCount = 2;
err = nn_pushinteger(C, greq.x);
if(err) return err;
err = nn_pushbool(C, greq.y != 0);
if(err) return err;
return NN_OK;
}
if(nn_strcmp(method, "setBackground") == 0) {
if(nn_checkinteger(C, 0, "bad argument #1 (integer expected)")) return NN_EBADCALL;
err = nn_defaultboolean(C, 1, false);
if(err) return err;
if(nn_checkinteger(C, 1, "bad argument #2 (boolean expected)")) return NN_EBADCALL;
greq.action = NN_GPU_SETBACKGROUND;
greq.x = nn_tointeger(C, 0);
greq.y = nn_toboolean(C, 1) ? 1 : 0;
err = state->handler(&greq);
if(err) return err;
req->returnCount = 2;
err = nn_pushinteger(C, greq.x);
if(err) return err;
err = nn_pushbool(C, greq.y != 0);
if(err) return err;
return NN_OK;
}
if(nn_strcmp(method, "getBackground") == 0) {
greq.action = NN_GPU_GETBACKGROUND;
err = state->handler(&greq);
if(err) return err;
req->returnCount = 2;
err = nn_pushinteger(C, greq.x);
if(err) return err;
err = nn_pushbool(C, greq.y != 0);
if(err) return err;
return NN_OK;
}
nn_setError(C, "method not yet implemented");
return NN_EBADCALL;
}
@ -3254,7 +3400,7 @@ size_t nn_unicode_codepointSize(nn_codepoint codepoint) {
return 1;
}
size_t nn_unicode_codepointToChar(char buffer[NN_MAXIMUM_UNICODE_BUFFER], nn_codepoint codepoint) {
size_t nn_unicode_codepointToChar(char buffer[NN_MAX_UNICODE_BUFFER], nn_codepoint codepoint) {
size_t codepointSize = nn_unicode_codepointSize(codepoint);
if (codepointSize == 1) {
@ -3304,7 +3450,9 @@ size_t nn_unicode_wlen(const char *s, size_t len) {
for(size_t i = 0; i < len;) {
nn_codepoint codepoint = nn_unicode_firstCodepoint(s + i);
size_t size = nn_unicode_codepointSize(codepoint);
wlen += nn_unicode_charWidth(codepoint);
size_t width = nn_unicode_charWidth(codepoint);
if(width == 0) width = 1;
wlen += width;
i += size;
}
return wlen;
@ -3315,12 +3463,14 @@ size_t nn_unicode_wlenPermissive(const char *s, size_t len) {
for(size_t i = 0; i < len;) {
if(nn_unicode_validateFirstChar(s + i, len - i) == 0) {
size_t width = nn_unicode_charWidth((unsigned char)s[i]);
if(width == 0) width = 1;
wlen += width;
i++;
} else {
nn_codepoint codepoint = nn_unicode_firstCodepoint(s + i);
size_t size = nn_unicode_codepointSize(codepoint);
size_t width = nn_unicode_charWidth(codepoint);
if(width == 0) width = 1;
wlen += width;
i += size;
}

View File

@ -85,7 +85,7 @@ extern "C" {
#define NN_MAX_USERNAME 128
// the maximum size of a UTF-8 character
#define NN_MAXIMUM_UNICODE_BUFFER 4
#define NN_MAX_UNICODE_BUFFER 4
// the maximum size of a component error message. If the error is bigger than this,
// it is truncated.
@ -126,7 +126,7 @@ nn_codepoint nn_unicode_firstCodepoint(const char *s);
size_t nn_unicode_codepointSize(nn_codepoint codepoint);
// Writes the UTF-8 bytes for a given codepoint into buffer.
// It does NOT write a NULL terminator, but it does return the length.
size_t nn_unicode_codepointToChar(char buffer[NN_MAXIMUM_UNICODE_BUFFER], nn_codepoint codepoint);
size_t nn_unicode_codepointToChar(char buffer[NN_MAX_UNICODE_BUFFER], nn_codepoint codepoint);
// the width, on a screen, for a codepoint.
// This matters for emojies.
size_t nn_unicode_charWidth(nn_codepoint codepoint);