GFX update :D

This commit is contained in:
Astronand committed 2026-10-04 19:45:35 -04:00
1 parent 05ca0f10a2
commit c1b4ef2644
70 files changed
+1383 -5159

No files matched your search

+2 -2
View File
@@ -6,10 +6,10 @@
"printf", "printf",
"printInline", "printInline",
"toHex", "toHex",
"loadcstr",
"userinput" "userinput"
], ],
"Lua.diagnostics.disable": [ "Lua.diagnostics.disable": [
"need-check-nil" "need-check-nil",
"param-type-mismatch"
] ]
} }
@@ -0,0 +1,318 @@
--:Minify:--
local kernel=...
if not kernel.cct then return end
local plt={
[0]=0x000000,0x0b0b0b,0x222222,0x444444,0x555555,0x777777,0x888888,0xaaaaaa,
0xbbbbbb,0xdddddd,0xeeeeee,0x00000b,0x000022,0x000044,0x000055,0x000077,
0x000088,0x0000aa,0x0000bb,0x0000dd,0x0000ee,0x000b00,0x002200,0x004400,
0x005500,0x007700,0x008800,0x00aa00,0x00bb00,0x00dd00,0x00ee00,0x0b0000,
0x220000,0x440000,0x550000,0x770000,0x880000,0xaa0000,0xbb0000,0xdd0000,
0xee0000,0x000033,0x000066,0x000099,0x0000cc,0x0000ff,0x003300,0x003333,
0x003366,0x003399,0x0033cc,0x0033ff,0x006600,0x006633,0x006666,0x006699,
0x0066cc,0x0066ff,0x009900,0x009933,0x009966,0x009999,0x0099cc,0x0099ff,
0x00cc00,0x00cc33,0x00cc66,0x00cc99,0x00cccc,0x00ccff,0x00ff00,0x00ff33,
0x00ff66,0x00ff99,0x00ffcc,0x00ffff,0x330000,0x330033,0x330066,0x330099,
0x3300cc,0x3300ff,0x333300,0x333333,0x333366,0x333399,0x3333cc,0x3333ff,
0x336600,0x336633,0x336666,0x336699,0x3366cc,0x3366ff,0x339900,0x339933,
0x339966,0x339999,0x3399cc,0x3399ff,0x33cc00,0x33cc33,0x33cc66,0x33cc99,
0x33cccc,0x33ccff,0x33ff00,0x33ff33,0x33ff66,0x33ff99,0x33ffcc,0x33ffff,
0x660000,0x660033,0x660066,0x660099,0x6600cc,0x6600ff,0x663300,0x663333,
0x663366,0x663399,0x6633cc,0x6633ff,0x666600,0x666633,0x666666,0x666699,
0x6666cc,0x6666ff,0x669900,0x669933,0x669966,0x669999,0x6699cc,0x6699ff,
0x66cc00,0x66cc33,0x66cc66,0x66cc99,0x66cccc,0x66ccff,0x66ff00,0x66ff33,
0x66ff66,0x66ff99,0x66ffcc,0x66ffff,0x990000,0x990033,0x990066,0x990099,
0x9900cc,0x9900ff,0x993300,0x993333,0x993366,0x993399,0x9933cc,0x9933ff,
0x996600,0x996633,0x996666,0x996699,0x9966cc,0x9966ff,0x999900,0x999933,
0x999966,0x999999,0x9999cc,0x9999ff,0x99cc00,0x99cc33,0x99cc66,0x99cc99,
0x99cccc,0x99ccff,0x99ff00,0x99ff33,0x99ff66,0x99ff99,0x99ffcc,0x99ffff,
0xcc0000,0xcc0033,0xcc0066,0xcc0099,0xcc00cc,0xcc00ff,0xcc3300,0xcc3333,
0xcc3366,0xcc3399,0xcc33cc,0xcc33ff,0xcc6600,0xcc6633,0xcc6666,0xcc6699,
0xcc66cc,0xcc66ff,0xcc9900,0xcc9933,0xcc9966,0xcc9999,0xcc99cc,0xcc99ff,
0xcccc00,0xcccc33,0xcccc66,0xcccc99,0xcccccc,0xccccff,0xccff00,0xccff33,
0xccff66,0xccff99,0xccffcc,0xccffff,0xff0000,0xff0033,0xff0066,0xff0099,
0xff00cc,0xff00ff,0xff3300,0xff3333,0xff3366,0xff3399,0xff33cc,0xff33ff,
0xff6600,0xff6633,0xff6666,0xff6699,0xff66cc,0xff66ff,0xff9900,0xff9933,
0xff9966,0xff9999,0xff99cc,0xff99ff,0xffcc00,0xffcc33,0xffcc66,0xffcc99,
0xffcccc,0xffccff,0xffff00,0xffff33,0xffff66,0xffff99,0xffffcc,0xffffff,
}
local iplt={}
for i=0, #plt do
iplt[plt[i]]=i
end
local l1f,l1d,l2,ops={},{},{},0
local function findClosest(tbl, target)
local closest = nil
local smallestDiff = math.huge
for k, _ in pairs(tbl) do
if k==target then return k end
local diff = math.abs(k - target)
if diff < smallestDiff then
smallestDiff = diff
closest = k
end
end
return closest
end
local function aprox(c24)
ops = ops + 1
if ops % 1024 == 0 then
l1d = {}
l1f = {}
end
if ops % 8192 == 0 then
l2 = {}
end
if l2[c24] ~= nil then
return l2[c24]
end
if l1d[c24] ~= nil then
l1f[c24] = l1f[c24] + 1
if l1f[c24] >= 16 then
l2[c24] = l1d[c24]
l1d[c24] = nil
l1f[c24] = nil
return l2[c24]
end
return l1d[c24]
end
local closestKey = findClosest(iplt, c24)
if not closestKey then return nil end
local value = iplt[closestKey]
l1d[c24] = value
l1f[c24] = 1
return value
end
local function splitFramebufferToStrings(fb, w)
local rows = {}
for i = 1, #fb, w do
local row_chars = {}
for j = 0, w - 1 do
local val = fb[i + j]
if val ~= nil then
table.insert(row_chars, string.char(aprox(val)))
else
break
end
end
table.insert(rows, table.concat(row_chars))
end
return rows
end
local function creategfx(term, id)
local active=false
term.setGraphicsMode(2)
for i=0, #plt do
term.setPaletteColor(i,plt[i])
end
term.setGraphicsMode(false)
term.setPaletteColor(0x1, 0xFFFFFF)
term.setPaletteColor(0x2, 0xFF0000)
term.setPaletteColor(0x4, 0x00FF00)
term.setPaletteColor(0x8, 0x0000FF)
term.setPaletteColor(0x10, 0x00FFFF)
term.setPaletteColor(0x20, 0xFF00FF)
term.setPaletteColor(0x40, 0xFFFF00)
term.setPaletteColor(0x80, 0xFF6D00)
term.setPaletteColor(0x100, 0x6DFF55)
term.setPaletteColor(0x200, 0x24FFFF)
term.setPaletteColor(0x400, 0x924900)
term.setPaletteColor(0x800, 0x6D6D55)
term.setPaletteColor(0x1000, 0xDBDBAA)
term.setPaletteColor(0x2000, 0x6D00FF)
term.setPaletteColor(0x4000, 0xB6FF00)
term.setPaletteColor(0x8000, 0x000000)
local handle={
gplt=function()
return setmetatable({},{__index=plt,__usermeta=false,__pairs=function() return pairs(plt) end})
end,
spixel=function(x,y,c)
term.setPixel(x,y,aprox(c))
end,
gpixel=function(x,y)
return term.getPixel()
end,
drawFB=function(x,y,fb,w)
local f=splitFramebufferToStrings(fb,w)
term.drawPixels(x,y,f)
end,
box=function(x,y,w,h,c,fill)
c=aprox(c)
if not fill then
term.drawPixels(x,y,c,w,1)
term.drawPixels(x,y,c,1,h)
term.drawPixels(x+w-1,y,c,1,h)
term.drawPixels(x,y+h-1,c,w,1)
else
term.drawPixels(x,y,c,w,h)
end
end,
circle=function(xc,yc,r,c,fill)
c=aprox(c)
if not fill then
local x = 0
local y = r
local d = 3 - 2 * r
-- Helper function to plot all 8 symmetric points
local function plot8Points(x, y)
term.setPixel(xc + x, yc + y, c)
term.setPixel(xc - x, yc + y, c)
term.setPixel(xc + x, yc - y, c)
term.setPixel(xc - x, yc - y, c)
term.setPixel(xc + y, yc + x, c)
term.setPixel(xc - y, yc + x, c)
term.setPixel(xc + y, yc - x, c)
term.setPixel(xc - y, yc - x, c)
end
plot8Points(x, y)
while y >= x do
x = x + 1
if d > 0 then
y = y - 1
d = d + 4 * (x - y) + 10
else
d = d + 4 * x + 6
end
plot8Points(x, y)
end
else
local x = 0
local y = r
local d = 3 - 2 * r
-- Helper to fill rows using symmetry
local function fillRows(x, y)
-- Width is (2 * coordinate) + 1 to include the center column
local strX = string.rep(string.char(c), 2 * x + 1)
local strY = string.rep(string.char(c), 2 * y + 1)
-- Draw the horizontal spans
term.drawPixels(xc - x, yc + y, {strX})
term.drawPixels(xc - x, yc - y, {strX})
term.drawPixels(xc - y, yc + x, {strY})
term.drawPixels(xc - y, yc - x, {strY})
end
fillRows(x, y)
while y >= x do
x = x + 1
if d > 0 then
y = y - 1
d = d + 4 * (x - y) + 10
else
d = d + 4 * x + 6
end
fillRows(x, y)
end
end
end,
line=function(x1,y1,x2,y2,c)
x1=math.floor(x1+0.5)
y1=math.floor(y1+0.5)
x2=math.floor(x2+0.5)
y2=math.floor(y2+0.5)
c=aprox(c)
local w,h=term.getSize(2)
local dx=math.abs(x2-x1)
local dy=math.abs(y2-y1)
local sx=x1<x2 and 1 or -1
local sy=y1<y2 and 1 or -1
local err=dx-dy
while true do
if 0<x1 and x1<=w and 0<y1 and y1<=h then
term.setPixel(x1,y1,c)
end
if x1==x2 and y1==y2 then
break
end
local e2=2*err
if e2>-dy then
err=err-dy
x1=x1+sx
end
if e2<dx then
err=err+dx
y1=y1+sy
end
end
end,
setMode=function(state)
if state then
term.setGraphicsMode(2)
for i=0, #plt do
term.setPaletteColor(i,plt[i])
end
active=true
else
term.setGraphicsMode(false)
term.setPaletteColor(0x1, 0xFFFFFF)
term.setPaletteColor(0x2, 0xFF0000)
term.setPaletteColor(0x4, 0x00FF00)
term.setPaletteColor(0x8, 0x0000FF)
term.setPaletteColor(0x10, 0x00FFFF)
term.setPaletteColor(0x20, 0xFF00FF)
term.setPaletteColor(0x40, 0xFFFF00)
term.setPaletteColor(0x80, 0xFF6D00)
term.setPaletteColor(0x100, 0x6DFF55)
term.setPaletteColor(0x200, 0x24FFFF)
term.setPaletteColor(0x400, 0x924900)
term.setPaletteColor(0x800, 0x6D6D55)
term.setPaletteColor(0x1000, 0xDBDBAA)
term.setPaletteColor(0x2000, 0x6D00FF)
term.setPaletteColor(0x4000, 0xB6FF00)
term.setPaletteColor(0x8000, 0x000000)
active=false
end
end,
getMode=function()
return active
end,
size=function()
return term.getSize(2)
end,
drawRun=function(y,x1,x2,c)
term.drawPixels(x1,y,c,{string.rep(string.char(aprox(c)),x1-x2)})
end
}
return handle
end
for id,obj in pairs(kernel.cct.term) do
if obj.setGraphicsMode then
kernel.cct.gfx[id]=creategfx(obj, id)
end
end
+3 -121
View File
@@ -1,121 +1,3 @@
local cp,c=component,computer;local b_addr=c.getBootAddress();local b_fs=cp.proxy(b_addr) ---@diagnostic disable-next-line: undefined-global
local gpu=cp.list("gpu")() and cp.proxy(cp.list("gpu")()) local bootdrive=__UEFI.bootDrive
local e_rom=cp.list("eeprom")() and cp.proxy(cp.list("eeprom")())
local screens={}
for addr in cp.list("screen") do
if gpu then
gpu.bind(addr)
local w,h=gpu.maxResolution()
gpu.setResolution(w,h)
gpu.fill(1,1,w,h," ")
cp.proxy(addr).turnOn()
screens[#screens+1] = {cx=1,cy=1,w=w,h=h,addr=addr}
end
end
local function scroll(scr) gpu.copy(1,2,scr.w,scr.h-1,0,-1);gpu.fill(1,scr.h,scr.w,1," ") end
local function write(t)
if not gpu then return end
for s=1, #screens do
local scr=screens[s]
gpu.bind(scr.addr)
for i=1,#t do
local char=t:sub(i,i)
if char=="\n" then scr.cx=1;scr.cy=scr.cy+1
elseif char=="\t" then scr.cx=scr.cx+(4-((scr.cx-1)%4))
elseif char=="\b" then if scr.cx>1 then scr.cx=scr.cx-1;gpu.set(scr.cx,scr.cy," ") end
else gpu.set(scr.cx,scr.cy,char);scr.cx=scr.cx+1 end
if scr.cx>scr.w then scr.cx=1;scr.cy=scr.cy+1 end
if scr.cy>scr.h then scroll(scr);scr.cy=scr.cy-1 end
end
end
end
local function throw(err)
if gpu then
gpu.setBackground(0x0000AA);
gpu.setForeground(0xFFFFFF);
for i=1, #screens do
gpu.fill(1,1,screens[i].w,screens[i].h," ");
screens[i].cx,screens[i].cy=1,1;
end
write("CRITICAL KERNEL ERROR:\n"..tostring(err))
end
while true do c.pullSignal() end
end
local ok,err=xpcall(function()
local apis={}
local _l={coroutine=1,debug=1,_VERSION=1,assert=1,collectgarbage=1,error=1,getmetatable=1,ipairs=1,load=1,math=1,next=1,pairs=1,pcall=1,rawequal=1,rawget=1,rawlen=1,rawset=1,select=1,setmetatable=1,string=1,table=1,tonumber=1,tostring=1,type=1,xpcall=1,_G=1}
for k,v in pairs(_G) do if not _l[k] then apis[k]=v;_G[k]=nil end end
function sleep(t) local s=c.uptime()+t;while c.uptime()<s do c.pullSignal(s-c.uptime()) end end
local function getFile(path)
local h,err=b_fs.open(path,"r")
if not h then throw("Cannot open: "..path) end
local buf,chk="",""
repeat chk=b_fs.read(h,math.huge);buf=buf..(chk or "") until not chk
b_fs.close(h)
return buf
end
local Kernel=load(getFile("/kernel.lua"),"@Kernel")
local initFs=load(getFile("/oc/initdisks"),"@Init_disks")
local fs=load(getFile("/initfs"),"@InitFs")
if not Kernel then throw("Kernel load failed.") end
if initFs then initFs=initFs(apis, b_fs, b_addr) end
if fs then fs=fs() end
local eQ={}
local function qEv(e,...) table.insert(eQ,{e,...}) end
local efi={
getEpochMs=function() return math.floor(c.uptime()*1000) end,
getUptime=function() return c.uptime()*1000 end,
date=function() return tostring(apis.os.date()) end,
getMachineEvent=function()
if #eQ > 0 then
return table.unpack(table.remove(eQ, 1))
else
return nil
end
end,
getEEPROM=function() return e_rom and e_rom.get() or "" end,
setEEPROM=function(_,t) if e_rom then e_rom.set(t) end end,
getNvram=function() return e_rom and e_rom.getData() or "" end,
setNvram=function(_,t) if e_rom then e_rom.setData(t) end end,
beep=function(freq, timeMs) c.beep(freq, timeMs / 1000) end,
initfs=fs,
disks=initFs,
architecture="oc",
firmware=apis,
reboot=false,
yield=function() coroutine.yield() end,
screenCtl={
print=function(_,t) write(tostring(t).."\n") end,
printInline=function(_,t) write(tostring(t)) end,
clear=function() if gpu then for i=1, #screens do local scr=screens[i];gpu.bind(scr.addr);gpu.fill(1,1,scr.w,scr.h," ");scr.cx,scr.cy=1,1 end end end,
resetCursor=function() for i=1, #screens do local scr=screens[i];scr.cx,scr.cy=1,1 end end,
setBackgroundColor=function(_,cl) if gpu then gpu.setBackground(cl) end end,
setTextColor=function(_,cl) if gpu then gpu.setForeground(cl) end end,
enable=function() end,
disable=function() end
}
}
local kCo=coroutine.create(function()
local s,e=xpcall(Kernel,debug.traceback,efi)
if not s and not efi.reboot then throw(e) end
if efi.reboot then c.shutdown(true) else c.shutdown() end
end)
efi.screenCtl:print("Loaded in "..tostring(c.uptime()).."s")
while true do
local st,e=coroutine.resume(kCo)
c.pushSignal("NoSleep")
local ex=false
while not ex do
local ev={c.pullSignal(0)}
if ev[1]=="key_down" then qEv("keyPressed",1,ev[3]);qEv("keyTyped",1,string.char(ev[3]))
elseif ev[1]=="key_up" then qEv("keyReleased",1,ev[3])
end
if ev[1]=="NoSleep" then ex=true else qEv(table.unpack(ev)) end
end
if st=="error" or coroutine.status(kCo)=="dead" then
if efi.reboot then c.shutdown(true) end
throw("Kernel fault: "..tostring(e))
end
end
end,debug.traceback)
if not ok then throw("Boot fault: "..err) end
+130 -52
View File
@@ -1,68 +1,146 @@
local init local comp,disks,autocomplete,ev,ent,data,path,exit,dirty,ls,eb,sb,bp=components,{},false,nil,true,"","",false,true,{},false
do local c,gpu=comp:getFirst("computer"),comp:getFirst("gpu")
local component_invoke = component.invoke if gpu then sb=gpu:newBuffer(48,32) end
local function boot_invoke(address, method, ...) --c.nvram.data="1/ac/boot.lua"
local result = table.pack(pcall(component_invoke, address, method, ...)) local function resetScreens()
if not result[1] then sb=gpu:newBuffer(64,48)
return nil, result[2] for typ, obj in comp:list() do
if typ=="screen" then gpu:assignBuffer(sb,obj) end
end
end
resetScreens()
local function displayError(err)
if not gpu then return end
gpu:freeAllBuffers()
resetScreens()
sb:pasteText(0,0,"FILL_SPILL",err)
end
local function bootloader()
for typ, obj in comp:list() do
if typ~="massStorage" then goto skip end
disks[tostring(obj.diskId)]=obj
::skip::
end
local function display(text)
print(text)
if not sb then print("NO_SB") return end
sb:pasteText(0,0,"FILL_SPILL",text)
end
local function boot()
local pos = path:find("/", 1, true)
if not pos then displayError("EINVAL") sleep(5) return end
local id,p = path:sub(1,pos-1),path:sub(pos)
if not disks[id] then displayError("ENODEV") sleep(5) return end
local init,err=load(disks[id]:open(p):read(-1),"@init","t",_G)
if err then displayError(err) sleep(5) return end
local ret = {xpcall(init, debug.traceback)}
if not ret[1] then
displayError("EFI PROGRAM ERROR: "..err)
sleep(5)
return false
else else
return table.unpack(result, 2, result.n) if ret[2]=="ENTER_BIOS" then
c.nvram.ENTER_BIOS=true
return true
end end
return table.unpack(ret, 2)
end end
end
-- backwards compatibility, may remove later if c.nvram then
local eeprom = component.list("eeprom")() path=c.nvram.data or ""
computer.getBootAddress = function() eb=c.nvram.ENTER_BIOS
return boot_invoke(eeprom, "getData") c.nvram.ENTER_BIOS=false
end end
computer.setBootAddress = function(address)
return boot_invoke(eeprom, "setData", address)
end
do local function drainev()
local screen = component.list("screen")()
local gpu = component.list("gpu")()
if gpu and screen then
boot_invoke(gpu, "bind", screen)
end
end
local function tryLoadFrom(address)
local handle, reason = boot_invoke(address, "open", "/oc/boot.lua")
if not handle then
return nil, reason
end
local buffer = ""
repeat repeat
local data, reason = boot_invoke(address, "read", handle, math.maxinteger or math.huge) ev={c:getMachineEvent()}
if not data and reason then if ev[1]=="charTyped" then ent=false end
return nil, reason until not ev[1]
end
if path=="" or eb then drainev() ent=false else
display("Press key to enter boot menu...")
sleep(3)
drainev()
if ent then return boot() end
end
local function proc(key)
if key=="\n" then exit=true
elseif key=="\b" then path=path:sub(1,#path-1) dirty=true
elseif key=="\t" then print("autocomplete")
else path=path..key dirty=true end
end
local function get()
data=""
local pos = path:find("/", 1, true)
local trailingslash=false
if path:sub(#path)=="/" then trailingslash=true end
if not pos then
for id in pairs(disks) do
if id:sub(1,#path)==path then
data=data..id.."\n"
end end
buffer = buffer .. (data or "")
until not data
boot_invoke(address, "close", handle)
return load(buffer, "=init")
end end
local reason else
if computer.getBootAddress() then if not trailingslash then
init, reason = tryLoadFrom(computer.getBootAddress()) local n=""
for i=#path, 0, -1 do
if path:sub(i,i)~="/" then
n=path:sub(i,i)..n
else break end
end end
if not init then local ok,ret=pcall(function()
computer.setBootAddress() return disks[path:sub(1,pos-1)]:list(path:sub(pos,#path-#n))
for address in component.list("filesystem") do end)
init, reason = tryLoadFrom(address) if ok then
if init then ls = ret
computer.setBootAddress(address) end
break for _,p in ipairs(ls) do
if p:sub(1,#n) == n then
data=data..p.."\n"
end
end
else
local ok,ret=pcall(function()
return disks[path:sub(1,pos-1)]:list(path:sub(pos))
end)
if ok then
ls=ret
for _,p in ipairs(ls) do
data=data..p.."\n"
end end
end end
end end
if not init then
error("no bootable medium found" .. (reason and (": " .. tostring(reason)) or ""), 0)
end end
end end
local ok, err = xpcall(init,debug.traceback)
if not ok then if not ent then
error(err) while true do
get()
if dirty then
for i=0,31 do sb:clearRow(i) end
display("Select boot file...\n"..path.."\n\n"..data)
dirty=false
end
ev={c:getMachineEvent()}
if ev[1]=="charTyped" then proc(ev[2]) end
if exit then return boot() end
end
end
end
local ret={xpcall(bootloader,debug.traceback)}
if not ret[1] then
displayError(ret[2])
error(ret[2])
else else
return err return table.unpack(ret, 2)
end end
@@ -1,387 +0,0 @@
--:Minify:--
local BOOT_DRIVE_PATH = ({...})[1] or "/$"
---@diagnostic disable-next-line: undefined-global
local term = term
local os = os
local function write(text)
local x, y = term.getCursorPos()
local w, h = term.getSize()
for i = 1, #text do
local c = text:sub(i, i)
if c == "\n" then
y = y + 1
x = 1
elseif c == "\t" then
local tabSize = 4
local spaces = tabSize - ((x - 1) % tabSize)
term.write(string.rep(" ", spaces))
x = x + spaces
elseif c == "\b" then
if x > 1 then
x = x - 1
term.setCursorPos(x, y)
term.write(" ")
term.setCursorPos(x, y)
end
else
if x <= w and y <= h then
term.setCursorPos(x, y)
term.write(c)
x = x + 1
end
end
if x > w then
x = 1
y = y + 1
end
if y - 1 >= h then
term.scroll(1)
y = h
term.setCursorPos(x, y)
end
end
term.setCursorPos(x, y)
end
local function displaySuperBadError(err)
term.setBackgroundColor(0x1)
term.setTextColor(0x4)
term.clear()
term.setCursorPos(1, 1)
term.write("A critical error occurred while loading the system:")
term.setCursorPos(1, 3)
write(err)
while true do end
end
term.setCursorBlink(false)
local ok, err = xpcall(function()
local apis = {BOOT_DRIVE_PATH = BOOT_DRIVE_PATH}
local lua = {
coroutine = true,
debug = true,
_VERSION = true,
assert = true,
collectgarbage = true,
error = true,
gcinfo = true,
getmetatable = true,
ipairs = true,
__inext = true,
load = true,
math = true,
next = true,
pairs = true,
pcall = true,
rawequal = true,
rawget = true,
rawlen = true,
rawset = true,
select = true,
setmetatable = true,
string = true,
table = true,
tonumber = true,
tostring = true,
type = true,
xpcall = true,
_G = true
}
local debug = debug
for i, v in pairs(_G) do
if not lua[i] or lua[i] == nil then
apis[i] = v
_G[i] = nil
end
end
local acekeys={
[apis.keys.enter]="\n",
[apis.keys.tab]="\t",
[apis.keys.backspace]="\b",
[apis.keys.up]="\17",
[apis.keys.down]="\18",
[apis.keys.left]="\19",
[apis.keys.right]="\20",
}
function sleep(time)
local stoptime = apis.os.clock() + (time)
while stoptime > apis.os.clock() do end
end
apis.term.setPaletteColor(0x1, 0xFFFFFF) -- #000000
apis.term.setPaletteColor(0x2, 0xFF0000) -- #FFFFFF
apis.term.setPaletteColor(0x4, 0x00FF00) -- #FF0000
apis.term.setPaletteColor(0x8, 0x0000FF) -- #00FF00
apis.term.setPaletteColor(0x10, 0x00FFFF) -- #0000FF
apis.term.setPaletteColor(0x20, 0xFF00FF) -- #00FFFF
apis.term.setPaletteColor(0x40, 0xFFFF00) -- #FF00FF
apis.term.setPaletteColor(0x80, 0xFF6D00) -- #FFFF00
apis.term.setPaletteColor(0x100, 0x6DFF55) -- #FF6D00
apis.term.setPaletteColor(0x200, 0x24FFFF) -- #6DFF55
apis.term.setPaletteColor(0x400, 0x924900) -- #24FFFF
apis.term.setPaletteColor(0x800, 0x6D6D55) -- #924900
apis.term.setPaletteColor(0x1000, 0xDBDBAA) -- #6D6D55
apis.term.setPaletteColor(0x2000, 0x6D00FF) -- #DBDBAA
apis.term.setPaletteColor(0x4000, 0xB6FF00) -- #6D00FF
apis.term.setPaletteColor(0x8000, 0x000000) -- #B6FF00
local function getFile(path)
local file = apis.fs.open(path, "r")
if not file then
displaySuperBadError("Could not open file: " .. path)
end
local content = file.readAll()
file.close()
return content
end
local Kernel = load(getFile(BOOT_DRIVE_PATH .. "/boot/kernel.lua"),"@Kernel")
local initFs = load(getFile(BOOT_DRIVE_PATH .. "/boot/cct/initdisks"),"@Init_disks")(apis)
local fs = load(getFile(BOOT_DRIVE_PATH .. "/boot/initfs"), "@InitFs")()
if not Kernel then displaySuperBadError("Could not load kernel.") end
if not initFs then displaySuperBadError("Could not load initdisks.") end
if not fs then displaySuperBadError("Could not load initfs.") end
if not apis.fs.exists("/nvram.dat") then
local file = apis.fs.open("/nvram.dat", "w")
file.write("Hello, World!")
file.close()
end
local eeprom
if apis.fs.exists("/startup.lua") then
eeprom="/startup.lua"
elseif apis.fs.exists("/eeprom") then
eeprom="/eeprom"
end
local eventQueue = {}
local function queueEvent(event, ...)
table.insert(eventQueue, {event, ...})
end
local colors = {
[0x000000]=0x0001,
[0xFFFFFF]=0x0002,
[0xFF0000]=0x0004,
[0x00FF00]=0x0008,
[0x0000FF]=0x0010,
[0x00FFFF]=0x0020,
[0xFF00FF]=0x0040,
[0xFFFF00]=0x0080,
[0xFF6D00]=0x0100,
[0x6DFF55]=0x0200,
[0x24FFFF]=0x0400,
[0x924900]=0x0800,
[0x6D6D55]=0x1000,
[0xDBDBAA]=0x2000,
[0x6D00FF]=0x4000,
[0xB6FF00]=0x8000
}
local fg,bg=0x6D6D55,0x000000
local l1f,l1d,l2,ops={},{},{},0
local function findClosest(tbl, target)
local closest = nil
local smallestDiff = math.huge
for k, _ in pairs(tbl) do
local diff = math.abs(k - target)
if diff < smallestDiff then
smallestDiff = diff
closest = k
end
end
return closest
end
local function aprox(c24)
ops = ops + 1
if ops % 1024 == 0 then
l1d = {}
l1f = {}
end
if ops % 8192 == 0 then
l2 = {}
end
if l2[c24] ~= nil then
return l2[c24]
end
if l1d[c24] ~= nil then
l1f[c24] = l1f[c24] + 1
if l1f[c24] >= 16 then
l2[c24] = l1d[c24]
l1d[c24] = nil
l1f[c24] = nil
return l2[c24]
end
return l1d[c24]
end
local closestKey = findClosest(colors, c24)
if not closestKey then return nil end
local value = colors[closestKey]
l1d[c24] = value
l1f[c24] = 1
return value
end
local EFI = {
getEpochMs = function() return apis.os.epoch("utc") end,
getUptime = function() return apis.os.clock() * 1000 end,
date = function() return apis.os.date("!%Y-%m-%dT%H:%M:%SZ", apis.os.epoch("utc") / 1000) end,
getMachineEvent = function()
if #eventQueue > 0 then
return table.unpack(table.remove(eventQueue, 1))
else
return nil
end
end,
getEEPROM = function() return getFile(eeprom) end,
setEEPROM = function(_, text)
local h = apis.fs.open(eeprom, "w")
h.write(text)
h.close()
end,
initfs=fs,
disks=initFs,
screenCtl={
print = function(_, text) write(text .. "\n") end,
printInline = function(_, text) write(text) end,
clear = function()
apis.term.clear()
apis.term.setCursorPos(1, 1)
end,
setCursorPos = function(_, x, y)
apis.term.setCursorPos(x, y)
end,
getCursorPos = function() return apis.term.getCursorPos() end,
getSize = function() return apis.term.getSize() end,
setBackgroundColor = function(_, color)
apis.term.setBackgroundColor(aprox(color))
end,
setTextColor = function(_, color)
apis.term.setTextColor(aprox(color))
end,
getBackgroundColor = function()
return bg
end,
getTextColor = function()
return fg
end,
enable=function() end,
disable=function() end
},
architecture="cct",
getNvram = function() return getFile("/nvram.dat") end,
setNvram = function(_, text)
local h = apis.fs.open("/nvram.dat", "w")
h.write(text)
h.close()
end,
firmware=apis,
reboot=false
}
apis.term.setBackgroundColor(0x8000)
apis.term.setTextColor(0x1000)
apis.term.clear()
apis.term.setCursorPos(1, 1)
local kernelCoro = coroutine.create(function()
---@diagnostic disable-next-line: param-type-mismatch
local ok, err = xpcall(Kernel, debug.traceback, EFI)
if not ok and not EFI.reboot then displaySuperBadError(err) end
if err then
apis.os.reboot()
else
apis.os.shutdown()
end
end)
function EFI.resumeWithTimeout(co, timeout, ...)
local startTime = EFI.getEpochMs()
debug.sethook(co, function()
if EFI.getEpochMs() > startTime + timeout then
return coroutine.yield("timeout")
end
end, "", 1000)
local ret = {coroutine.resume(co, ...)}
if ret[1] and ret[2] == "timeout" then
return "timeout"
elseif ret[1] == false then
return "error", ret[2]
else
debug.sethook(co)
return "success", table.unpack(ret, 2)
end
end
write("Loaded in " .. tostring(apis.os.clock()) .. " seconds.\n")
while true do
local status, err = EFI.resumeWithTimeout(kernelCoro, 50)
apis.os.queueEvent("NoSleep")
local exit = false
while not exit do
local event = {coroutine.yield()}
if event[1] == "key" then
queueEvent("keyPressed", 1, event[2])
if acekeys[event[2]] then
queueEvent("keyTyped", 1, acekeys[event[2]])
end
elseif event[1] == "char" then
queueEvent("keyTyped", 1, event[2])
elseif event[1] == "key_up" then
queueEvent("keyReleased", 1, event[2])
elseif event[1] == "disk" then
queueEvent("componentAdded", "disk")
elseif event[1] == "disk_eject" then
queueEvent("componentRemoved", "disk")
elseif event[1] == "modem_message" then
queueEvent("modem_message", table.unpack(event, 2))
elseif event[1] == "rednet_message" then
queueEvent("rednet_message", table.unpack(event, 2))
elseif event[1] == "http_success" then
queueEvent("http_success", table.unpack(event, 2))
elseif event[1] == "http_failure" then
queueEvent("http_failure", table.unpack(event, 2))
elseif event[1] == "NoSleep" then
exit = true
end
end
if status == "error" or coroutine.status(kernelCoro) == "dead" then
if EFI.reboot then
apis.os.reboot()
end
displaySuperBadError("Kernel error: " .. tostring(err))
coroutine.yield("key")
end
initFs:refresh()
end
end, debug.traceback)
if not ok then displaySuperBadError("Fatal error during boot: " .. err) end
while true do coroutine.yield("key") end
@@ -1,119 +0,0 @@
--:Minify:--
local BOOT_DRIVE_PATH=({...})[1] or "/$"
-- UnBIOS by JackMacWindows
-- This will undo most of the changes/additions made in the BIOS, but some things may remain wrapped if `debug` is unavailable
-- To use, just place a `bios.lua` in the root of the drive, and run this program
-- Here's a list of things that are irreversibly changed:
-- * both `bit` and `bit32` are kept for compatibility
-- * string metatable blocking (on old versions of CC)
-- In addition, if `debug` is not available these things are also irreversibly changed:
-- * old Lua 5.1 `load` function (for loading from a function)
-- * `loadstring` prefixing (before CC:T 1.96.0)
-- * `http.request`
-- * `os.shutdown` and `os.reboot`
-- * `peripheral`
-- * `turtle.equip[Left|Right]`
-- Licensed under the MIT license
local args = {...}
local keptAPIs = {keys=true, bit32 = true, bit = true, ccemux = true, config = true, coroutine = true, debug = true, fs = true, http = true, mounter = true, os = true, periphemu = true, peripheral = true, redstone = true, rs = true, term = true, utf8 = true, _HOST = true, _CC_DEFAULT_SETTINGS = true, _CC_DISABLE_LUA51_FEATURES = true, _VERSION = true, assert = true, collectgarbage = true, error = true, gcinfo = true, getfenv = true, getmetatable = true, ipairs = true, __inext = true,load = true, loadstring = true, math = true, newproxy = true, next = true, pairs = true, pcall = true, rawequal = true, rawget = true, rawlen = true, rawset = true, select = true, setfenv = true, setmetatable = true, string = true, table = true, tonumber = true, tostring = true, type = true, unpack = true, xpcall = true, turtle = true, pocket = true, commands = true, _G = true}
local t = {}
for k in pairs(_G) do if not keptAPIs[k] then table.insert(t, k) end end
for _,k in ipairs(t) do _G[k] = nil end
local native = _G.term.native()
for _, method in ipairs {"nativePaletteColor", "nativePaletteColour", "screenshot"} do native[method] = _G.term[method] end
_G.term = native
if _G.http then
_G.http.checkURL = _G.http.checkURLAsync
_G.http.websocket = _G.http.websocketAsync
end
if _G.commands then _G.commands = _G.commands.native end
if _G.turtle then _G.turtle.native, _G.turtle.craft = nil end
local delete = {os = {"version", "pullEventRaw", "pullEvent", "run", "loadAPI", "unloadAPI", "sleep"}, http = _G.http and {"get", "post", "put", "delete", "patch", "options", "head", "trace", "listen", "checkURLAsync", "websocketAsync"}, fs = {"complete", "isDriveRoot"}}
for k,v in pairs(delete) do for _,a in ipairs(v) do _G[k][a] = nil end end
-- Set up TLCO
-- This functions by crashing `rednet.run` by removing `os.pullEventRaw`. Normally
-- this would cause `parallel` to throw an error, but we replace `error` with an
-- empty placeholder to let it continue and return without throwing. This results
-- in the `pcall` returning successfully, preventing the error-displaying code
-- from running - essentially making it so that `os.shutdown` is called immediately
-- after the new BIOS exits.
--
-- From there, the setup code is placed in `term.native` since it's the first
-- thing called after `parallel` exits. This loads the new BIOS and prepares it
-- for execution. Finally, it overwrites `os.shutdown` with the new function to
-- allow it to be the last function called in the original BIOS, and returns.
-- From there execution continues, calling the `term.redirect` dummy, skipping
-- over the error-handling code (since `pcall` returned ok), and calling
-- `os.shutdown()`. The real `os.shutdown` is re-added, and the new BIOS is tail
-- called, which effectively makes it run as the main chunk.
local olderror = error
_G.error = function() end
_G.term.redirect = function() end
function _G.term.native()
_G.term.native = nil
_G.term.redirect = nil
_G.error = olderror
term.setBackgroundColor(32768)
term.setTextColor(1)
term.setCursorPos(1, 1)
term.setCursorBlink(true)
term.clear()
local file = fs.open(BOOT_DRIVE_PATH.."/boot/cct/boot.lua", "r")
if file == nil then
term.setCursorBlink(false)
term.setTextColor(16384)
term.write("Could not find /boot/cct/boot.lua. UnBIOS cannot continue.")
term.setCursorPos(1, 2)
term.write("Press any key to continue")
coroutine.yield("key")
os.shutdown()
end
local fn, err = loadstring(file.readAll(), "@bootloader")
file.close()
if fn == nil then
term.setCursorBlink(false)
term.setTextColor(16384)
term.write("Could not load /boot/cc/boot.lua. UnBIOS cannot continue.")
term.setCursorPos(1, 2)
term.write(err)
term.setCursorPos(1, 3)
term.write("Press any key to continue")
coroutine.yield("key")
os.shutdown()
end
setfenv(fn, _G)
local oldshutdown = os.shutdown
os.shutdown = function()
os.shutdown = oldshutdown
return fn(BOOT_DRIVE_PATH)
end
end
if debug then
-- Restore functions that were overwritten in the BIOS
-- Apparently this has to be done *after* redefining term.native
local function restoreValue(tab, idx, name, hint)
local i, key, value = 1, debug.getupvalue(tab[idx], hint)
while key ~= name and key ~= nil do
key, value = debug.getupvalue(tab[idx], i)
i=i+1
end
tab[idx] = value or tab[idx]
end
restoreValue(_G, "loadstring", "nativeloadstring", 1)
restoreValue(_G, "load", "nativeload", 5)
if http then restoreValue(http, "request", "nativeHTTPRequest", 3) end
restoreValue(os, "shutdown", "nativeShutdown", 1)
restoreValue(os, "reboot", "nativeReboot", 1)
if turtle then
restoreValue(turtle, "equipLeft", "v", 1)
restoreValue(turtle, "equipRight", "v", 1)
end
do
local i, key, value = 1, debug.getupvalue(peripheral.isPresent, 2)
while key ~= "native" and key ~= nil do
key, value = debug.getupvalue(peripheral.isPresent, i)
i=i+1
end
_G.peripheral = value or peripheral
end
end
@@ -1,272 +0,0 @@
--:Minify:--
local apis = ({...})[1]
local BOOT_DRIVE_PATH = apis.BOOT_DRIVE_PATH
local fs = apis.fs
local native = apis.peripheral
local peripheral = {}
local sides = {"top", "bottom", "left", "right", "front", "back"}
function peripheral.getNames()
local results = {}
for n = 1, #sides do
local side = sides[n]
if native.isPresent(side) then
table.insert(results, side)
if native.hasType(side, "peripheral_hub") then
local remote = native.call(side, "getNamesRemote")
for _, name in ipairs(remote) do
table.insert(results, name)
end
end
end
end
return results
end
function peripheral.isPresent(name)
if native.isPresent(name) then
return true
end
for n = 1, #sides do
local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
return true
end
end
return false
end
function peripheral.getType(peripheral)
if type(peripheral) == "string" then
if native.isPresent(peripheral) then
return native.getType(peripheral)
end
for n = 1, #sides do
local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", peripheral) then
return native.call(side, "getTypeRemote", peripheral)
end
end
return nil
else
local mt = getmetatable(peripheral)
if not mt or mt.__name ~= "peripheral" or type(mt.types) ~= "table" then
error("bad argument #1 (table is not a peripheral)", 2)
end
return table.unpack(mt.types)
end
end
function peripheral.hasType(peripheral, peripheral_type)
if type(peripheral) == "string" then
if native.isPresent(peripheral) then
return native.hasType(peripheral, peripheral_type)
end
for n = 1, #sides do
local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", peripheral) then
return native.call(side, "hasTypeRemote", peripheral, peripheral_type)
end
end
return nil
else
local mt = getmetatable(peripheral)
if not mt or mt.__name ~= "peripheral" or type(mt.types) ~= "table" then
error("bad argument #1 (table is not a peripheral)", 2)
end
return mt.types[peripheral_type] ~= nil
end
end
function peripheral.getMethods(name)
if native.isPresent(name) then
return native.getMethods(name)
end
for n = 1, #sides do
local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
return native.call(side, "getMethodsRemote", name)
end
end
return nil
end
function peripheral.getName(peripheral)
local mt = getmetatable(peripheral)
if not mt or mt.__name ~= "peripheral" or type(mt.name) ~= "string" then
error("bad argument #1 (table is not a peripheral)", 2)
end
return mt.name
end
function peripheral.call(name, method, ...)
if native.isPresent(name) then
return native.call(name, method, ...)
end
for n = 1, #sides do
local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
return native.call(side, "callRemote", name, method, ...)
end
end
return nil
end
function peripheral.wrap(name)
local methods = peripheral.getMethods(name)
if not methods then
return nil
end
local types = { peripheral.getType(name) }
for i = 1, #types do types[types[i]] = true end
local result = setmetatable({}, {
__name = "peripheral",
name = name,
type = types[1],
types = types,
})
for _, method in ipairs(methods) do
result[method] = function(...)
return peripheral.call(name, method, ...)
end
end
return result
end
function peripheral.find(ty, filter)
local results = {}
for _, name in ipairs(peripheral.getNames()) do
if peripheral.hasType(name, ty) then
local wrapped = peripheral.wrap(name)
if filter == nil or filter(name, wrapped) then
table.insert(results, wrapped)
end
end
end
return table.unpack(results)
end
local disks = {}
local internal = {}
local function norm(path)
if not path or path == "" then return "/" end
return fs.combine("/", path)
end
local function createDisk(id, basePath, readonly, periph)
basePath = norm(basePath)
local disk = {address = id, isReadOnly = function() return readonly end}
function disk:spaceUsed()
return fs.getCapacity(basePath) - fs.getFreeSpace(basePath)
end
function disk:spaceTotal() return fs.getCapacity(basePath) end
function disk:list(path)
local p = fs.combine(basePath, path)
if not fs.exists(p) or not fs.isDir(p) then
return nil, "not directory"
end
return fs.list(p)
end
function disk:fileExists(path)
local p = fs.combine(basePath, path)
return fs.exists(p) and not fs.isDir(p)
end
function disk:directoryExists(path)
local p = fs.combine(basePath, path)
return fs.exists(p) and fs.isDir(p)
end
function disk:type(path)
local p = fs.combine(basePath, path)
if not fs.exists(p) then
return nil
elseif fs.isDir(p) then
return "directory"
else
return "file"
end
end
function disk:makeDirectory(path)
local p = fs.combine(basePath, path)
fs.makeDir(p)
return true
end
function disk:remove(path)
local p = fs.combine(basePath, path)
if fs.exists(p) then fs.delete(p) end
return true
end
function disk:setLabel(label) periph.setLabel(label) end
function disk:getLabel(label) return periph.getLabel() end
function disk:attributes(path)
local p = fs.combine(basePath, path)
return fs.attributes(p)
end
function disk:open(path, mode)
local p = fs.combine(basePath, path)
return fs.open(p, mode)
end
return disk
end
internal["$"] = createDisk("$", BOOT_DRIVE_PATH, false, {
setLabel = function(label)
local h = fs.open("/.label", "w")
h.write(label)
h.close()
end,
getLabel = function()
local h = fs.open("/.label", "r")
if not h then return "$" end
local label = h.readAll()
h.close()
return label
end
})
internal["rom"] = createDisk("rom", "/rom", true, {
setLabel = function(label)
error("Device is read-only")
end,
getLabel = function()
return "cctrom"
end
})
local function refresh()
disks={}
for _, disk in ipairs({peripheral.find("drive")}) do
if disk.isDiskPresent() then
disks[tostring(disk.getDiskID())]=createDisk("cctdisk"..tostring(disk.getDiskID()), disk.getMountPath(), false, fs)
end
end
end
local function iter()
refresh()
local combined = {}
for id, obj in pairs(internal) do combined[id] = obj end
for id, obj in pairs(disks) do combined[id] = obj end
return pairs(combined)
end
return {refresh = refresh, list = iter}
@@ -1,6 +0,0 @@
--:Minify:--
local kernel=...
if kernel.gfx then
end
@@ -494,7 +494,7 @@ local ok, err = xpcall(function()
h.close() h.close()
end, end,
firmware=apis, firmware=apis,
reboot=false, status="running",
beep=function() end beep=function() end
} }
@@ -505,7 +505,7 @@ local ok, err = xpcall(function()
local kernelCoro = coroutine.create(function() local kernelCoro = coroutine.create(function()
--pf --pf
---@diagnostic disable-next-line: param-type-mismatch- ---@diagnostic disable-next-line: param-type-mismatch
local ok, err = xpcall(Kernel, debug.traceback, EFI) local ok, err = xpcall(Kernel, debug.traceback, EFI)
if not ok then if not ok then
error(err) error(err)
@@ -569,14 +569,18 @@ local ok, err = xpcall(function()
end end
end end
if status == "error" or coroutine.status(kernelCoro) == "dead" then if status == "error" or coroutine.status(kernelCoro) == "dead" then
if EFI.reboot then if EFI.status=="reboot" then
apis.os.reboot() apis.os.reboot()
elseif EFI.status=="shutdown" then
apis.os.shutdown()
end end
displaySuperBadError("Kernel error: " .. tostring(err)) displaySuperBadError("Kernel error: " .. tostring(err))
coroutine.yield("key") coroutine.yield("key")
elseif status == "success" then elseif status == "success" then
if EFI.reboot then if EFI.status=="reboot" then
apis.os.reboot() apis.os.reboot()
elseif EFI.status=="shutdown" then
apis.os.shutdown()
end end
displaySuperBadError("Kernel error: Attempted to yield main thread\n"..debug.traceback(kernelCoro, "Attempted to yield main thread")) displaySuperBadError("Kernel error: Attempted to yield main thread\n"..debug.traceback(kernelCoro, "Attempted to yield main thread"))
coroutine.yield("key") coroutine.yield("key")
@@ -163,7 +163,7 @@ local function createDisk(id, basePath, readonly, periph)
local disk = {address = id, isReadOnly = function() return readonly end} local disk = {address = id, isReadOnly = function() return readonly end}
function disk:spaceUsed() function disk:spaceUsed()
return fs.getCapacity(basePath) - fs.getFreeSpace(basePath) return (fs.getCapacity(basePath) or 0) - (fs.getFreeSpace(basePath) or 0)
end end
function disk:spaceTotal() return fs.getCapacity(basePath) end function disk:spaceTotal() return fs.getCapacity(basePath) end
@@ -0,0 +1,25 @@
--:Minify:--
local kernel=...
local fifo=kernel.newFifo()
kernel.devfs.data["input"]["mouse1"] = function(op, mode)
if op=="type" then
return "Mouse"
elseif op=="open" then
local h = {
read=function(amount)
local rv=""
for i=1, amount or 1 do
local event = {fifo.pop()}
if event[1] then
rv=rv..event[1]
end
end
---@diagnostic disable-next-line: cast-local-type
if rv=="" then rv=nil end
return rv
end
}
return h
end
end
kernel.cct.mouse={fifo=fifo}
@@ -1,6 +1,8 @@
--:Minify:-- --:Minify:--
local kernel = ... local kernel = ...
local peripheral=kernel.cct.peripheral local peripheral=kernel.cct.peripheral
kernel.cct.gfx={}
kernel.cct.term={}
local colors = { local colors = {
[0xFFFFFF]=0x0001, [0xFFFFFF]=0x0001,
@@ -155,6 +157,7 @@ local function serializeBool(bool)
end end
local function newtty(obj, id, ev) local function newtty(obj, id, ev)
kernel.cct.term[id]=obj
obj.setPaletteColor(0x1, 0xFFFFFF) -- #000000 obj.setPaletteColor(0x1, 0xFFFFFF) -- #000000
obj.setPaletteColor(0x2, 0xFF0000) -- #FFFFFF obj.setPaletteColor(0x2, 0xFF0000) -- #FFFFFF
obj.setPaletteColor(0x4, 0x00FF00) -- #FF0000 obj.setPaletteColor(0x4, 0x00FF00) -- #FF0000
@@ -176,17 +179,6 @@ local function newtty(obj, id, ev)
return "Terminal" return "Terminal"
elseif op=="open" then elseif op=="open" then
local h = { local h = {
read=function(amount)
local rv=""
for i=1, amount or 1 do
local event = {ev()}
if event[1] then
rv=rv..event[1]
end
end
if rv=="" then rv=nil end
return rv
end,
write=function(content) write=function(content)
write(content, obj) write(content, obj)
end, end,
@@ -221,18 +213,16 @@ local function newtty(obj, id, ev)
return false return false
end, end,
gplt=function() gplt=function()
return plt return table.deepcopy(plt)
end,
gfx=function(...)
if kernel.cct.gfx[id] then return kernel.cct.gfx[id] else return false end
end,
id=function()
return id
end end
} }
if mode=="rw" then
return h return h
elseif mode=="r" then
h["write"]=nil
return h
elseif mode=="w" then
h["read"]=nil
return h
end
end end
end end
end end
@@ -259,23 +249,14 @@ kernel.devfs.data["input"]["keyboard1"] = function(op, mode)
rv=rv..event[1] rv=rv..event[1]
end end
end end
---@diagnostic disable-next-line: cast-local-type
if rv=="" then rv=nil end if rv=="" then rv=nil end
return rv return rv
end, end,
write=function(content)
end,
gctrl=function() gctrl=function()
return serializeBool(kernel.cct.ctrl)..";"..serializeBool(kernel.cct.alt) return serializeBool(kernel.cct.ctrl)..";"..serializeBool(kernel.cct.alt)
end end
} }
if mode=="rw" then
return h return h
elseif mode=="r" then
h["write"]=nil
return h
elseif mode=="w" then
h["read"]=nil
return h
end
end end
end end
@@ -71,8 +71,10 @@ kernel.processes.cctdaemon = function()
elseif eventType == "mouse_scroll" then elseif eventType == "mouse_scroll" then
if event[2] == 1 then if event[2] == 1 then
kernel.cct.fifo.push("S") kernel.cct.fifo.push("S")
kernel.cct.mouse.fifo.push("S")
else else
kernel.cct.fifo.push("T") kernel.cct.fifo.push("T")
kernel.cct.mouse.fifo.push("T")
end end
elseif eventType == "http_success" then elseif eventType == "http_success" then
if kernel.cct.httpqueue[event[2]] then if kernel.cct.httpqueue[event[2]] then
@@ -85,6 +87,16 @@ kernel.processes.cctdaemon = function()
kernel.cct.httperror[event[2]]=event[3] kernel.cct.httperror[event[2]]=event[3]
kernel.cct.httpresponse[event[2]]=event[4] kernel.cct.httpresponse[event[2]]=event[4]
end end
elseif eventType == "mouse_click" then
--";X;Y;C"
-- 1 = left
-- 2 = right
-- 3 = middle
kernel.cct.mouse.fifo.push(";"..tostring(event[3])..";"..tostring(event[4])..";"..tostring(event[2]))
elseif eventType == "mouse_drag" then
kernel.cct.mouse.fifo.push(";"..tostring(event[3])..";"..tostring(event[4])..";"..tostring(event[2]))
elseif eventType == "mouse_up" then
kernel.cct.mouse.fifo.push(";"..tostring(event[3])..";"..tostring(event[4])..";"..tostring(event[2]))
else else
if kernel.cct.eventhooks[eventType] then if kernel.cct.eventhooks[eventType] then
local ok,err = xpcall(kernel.cct.eventhooks[eventType], debug.traceback, table.unpack(event)) local ok,err = xpcall(kernel.cct.eventhooks[eventType], debug.traceback, table.unpack(event))
@@ -35,6 +35,14 @@ function kernel.main()
local totalTaskTime = 0 local totalTaskTime = 0
local taskTimes = {} local taskTimes = {}
for id,hook in ipairs(kernel.mainHooks) do
local ok,err = xpcall(hook, debug.traceback)
if not ok then
kernel.log("[MAIN HOOK ERR]: "..err, "ERROR", 0xFF0000)
kernel.mainHooks[id]=nil
end
end
for pid, task in pairs(kernel.tasks) do for pid, task in pairs(kernel.tasks) do
if kernel.exitMain then break end if kernel.exitMain then break end
@@ -42,7 +50,7 @@ function kernel.main()
for id,hook in ipairs(list) do for id,hook in ipairs(list) do
local ok,err = xpcall(hook, debug.traceback, task, pid) local ok,err = xpcall(hook, debug.traceback, task, pid)
if not ok then if not ok then
kernel.log("[MAIN HOOK ERR]: "..err, "ERROR", 0xFF0000) kernel.log("[TASK HOOK ERR]: "..err, "ERROR", 0xFF0000)
list[id]=nil list[id]=nil
end end
end end
@@ -148,4 +156,6 @@ function kernel.main()
kernel.saveLog() kernel.saveLog()
end end
end end
kernel.log("Exited main")
kernel.saveLog()
end end
@@ -1,3 +1,4 @@
---@diagnostic disable-next-line: undefined-global
local cp,c=component,computer;local b_addr=c.getBootAddress();local b_fs=cp.proxy(b_addr) local cp,c=component,computer;local b_addr=c.getBootAddress();local b_fs=cp.proxy(b_addr)
local gpu=cp.list("gpu")() and cp.proxy(cp.list("gpu")()) local gpu=cp.list("gpu")() and cp.proxy(cp.list("gpu")())
local e_rom=cp.list("eeprom")() and cp.proxy(cp.list("eeprom")()) local e_rom=cp.list("eeprom")() and cp.proxy(cp.list("eeprom")())
@@ -121,10 +121,7 @@ function kernel.main()
end end
end end
end end
if kernel.EFI:getEpochMs()>=nextyield then
kernel.EFI:yield() kernel.EFI:yield()
nextyield=kernel.EFI:getEpochMs()+5000
end
end end
local T_prev_avg = (N > 0) and (totalTaskTime / N) or 0 local T_prev_avg = (N > 0) and (totalTaskTime / N) or 0
+8 -5
View File
@@ -74,7 +74,7 @@ function kernel.PANIC(msg)
break break
end end
end end
EFI.reboot=true EFI.status="reboot"
error("KERNEL PANIC") error("KERNEL PANIC")
end end
kernel.panic=kernel.PANIC kernel.panic=kernel.PANIC
@@ -179,7 +179,6 @@ if not root then
if event[1]=="keyTyped" then if event[1]=="keyTyped" then
if tonumber(event[3]) then if tonumber(event[3]) then
if canadates[tonumber(event[3])] then if canadates[tonumber(event[3])] then
ifs.writeAllText("/boot/fstab", "U "..canadates[tonumber(event[3])]..";/\n"..fstab)
fstab="U "..canadates[tonumber(event[3])]..";/\n"..fstab fstab="U "..canadates[tonumber(event[3])]..";/\n"..fstab
ifs.mount(canadates[tonumber(event[3])], "/") ifs.mount(canadates[tonumber(event[3])], "/")
break break
@@ -359,7 +358,7 @@ kernel.perTaskHooks={}
kernel.mainHooks={} kernel.mainHooks={}
kernel.runhooks={} kernel.runhooks={}
-- args {taskobj} -- args {taskobj, pid}
function kernel.execPerTask(func, prior) function kernel.execPerTask(func, prior)
if not kernel.perTaskHooks[prior] then kernel.perTaskHooks[prior]={} end if not kernel.perTaskHooks[prior] then kernel.perTaskHooks[prior]={} end
kernel.perTaskHooks[prior][#kernel.perTaskHooks[prior]+1] = func kernel.perTaskHooks[prior][#kernel.perTaskHooks[prior]+1] = func
@@ -460,6 +459,7 @@ kernel.syscalls["saveLog"]=function()
end end
end end
ifs.writeAllText("/boot/fstab", fstab)
kernel.saveLog() kernel.saveLog()
kernel.log("Running modules") kernel.log("Running modules")
for _,p in ipairs(modules) do for _,p in ipairs(modules) do
@@ -471,7 +471,7 @@ for _,p in ipairs(modules) do
if not code then if not code then
kernel.panic("Failed to read module "..v) kernel.panic("Failed to read module "..v)
end end
local func,err=load(code,"@"..v) local func,err=load(code,"@"..v,"t",_G)
if not func then kernel.panic("ModuLoadErr: "..tostring(err)) end if not func then kernel.panic("ModuLoadErr: "..tostring(err)) end
local status, err = xpcall(func,debug.traceback, kernel) local status, err = xpcall(func,debug.traceback, kernel)
if not status then kernel.panic("ModuRunErr: "..tostring(err)) end if not status then kernel.panic("ModuRunErr: "..tostring(err)) end
@@ -502,10 +502,13 @@ if kernel.status=="panic" then
kernel.panic(kernel.reason) kernel.panic(kernel.reason)
end end
if kernel.status=="reboot" then if kernel.status=="reboot" then
EFI.reboot=true EFI.status="reboot"
return true return true
elseif kernel.status=="halt" then elseif kernel.status=="halt" then
kernel.log("System halted.") kernel.log("System halted.")
kernel.saveLog() kernel.saveLog()
while true do end while true do end
else
EFI.status="shutdown"
return true
end end
@@ -2,6 +2,16 @@
--- @diagnostic disable: duplicate-set-field --- @diagnostic disable: duplicate-set-field
local kernel = ... local kernel = ...
kernel.allowGlobalOverwrites = true kernel.allowGlobalOverwrites = true
local oldtype = type
local oldgetmetatable = getmetatable
function math.round(x)
if x>=0 then
return math.floor(x+0.5)
else
return math.ceil(x-0.5)
end
end
function string.hasSuffix(str, suffix) function string.hasSuffix(str, suffix)
return string.sub(str, #suffix + 1) == suffix return string.sub(str, #suffix + 1) == suffix
@@ -70,6 +80,10 @@ function table.hasVal(tabl, query)
return false return false
end end
function table.readOnly(tabl, typ)
return setmetatable({},{__index=tabl,__newindex=function()error("Table is read-only")end,__usermeta=false,__type=typ})
end
local function serialize(tbl, seen) local function serialize(tbl, seen)
seen = seen or {} seen = seen or {}
@@ -100,6 +114,8 @@ local function serialize(tbl, seen)
output = output .. "\"" .. tostring(v) .. "\"" output = output .. "\"" .. tostring(v) .. "\""
elseif type(v) == "thread" then elseif type(v) == "thread" then
output = output .. "\"" .. tostring(v) .. "\"" output = output .. "\"" .. tostring(v) .. "\""
elseif oldgetmetatable(v) and oldgetmetatable(v).__tostring then
output = output .. tostring(v)
else else
error("serialization of type \"" .. type(v) .. "\" is not supported") error("serialization of type \"" .. type(v) .. "\" is not supported")
end end
@@ -111,8 +127,6 @@ local function serialize(tbl, seen)
return output return output
end end
local oldtype = type
local oldgetmetatable = getmetatable
function type(object, trueType) function type(object, trueType)
if trueType then return oldtype(object) end if trueType then return oldtype(object) end
if oldtype(object) ~= "table" then if oldtype(object) ~= "table" then
@@ -131,7 +145,7 @@ end
function getmetatable(object) function getmetatable(object)
if oldtype(object) ~= "table" then return end if oldtype(object) ~= "table" then return end
if oldtype(oldgetmetatable(object)) == "table" then if oldtype(oldgetmetatable(object)) == "table" then
if oldgetmetatable(object).__isuserdata then if oldgetmetatable(object).__usermeta then
if oldtype(oldgetmetatable(object).__usermeta) == "function" then if oldtype(oldgetmetatable(object).__usermeta) == "function" then
return oldgetmetatable(object).__usermeta() return oldgetmetatable(object).__usermeta()
else else
@@ -251,8 +265,6 @@ local function makeSyscallProxy()
local backing = {} local backing = {}
return setmetatable(backing, { return setmetatable(backing, {
__index = function(self, name) __index = function(self, name)
local raw = rawget(self, name)
if raw ~= nil then return raw end
return function(...) return function(...)
local res = table.pack(coroutine.yield("syscall", name, ...)) local res = table.pack(coroutine.yield("syscall", name, ...))
if res[1] then if res[1] then
@@ -263,7 +275,7 @@ local function makeSyscallProxy()
end end
end, end,
__newindex = function(self, k, v) __newindex = function(self, k, v)
rawset(self, k, v) error("Table is read-only")
end, end,
__metatable=false __metatable=false
}) })
@@ -271,6 +283,5 @@ end
syscall = makeSyscallProxy() syscall = makeSyscallProxy()
_makeSyscallProxy = makeSyscallProxy
table.serialize = serialize table.serialize = serialize
@@ -299,6 +299,7 @@ local function namei(path, noFollow, symDepth)
if not target or target == "" then if not target or target == "" then
error("ENOENT: empty symlink target") error("ENOENT: empty symlink target")
end end
if kernel.config.logSymlinkTraverse then kernel.log(curPath .. " > " .. target) end
local symIsAbs, symTokens = tokenizePath(target) local symIsAbs, symTokens = tokenizePath(target)
@@ -1158,7 +1159,27 @@ function vfs.devlst(fd)
return table.keys(kernel.currentTask.fd[fd].handle) return table.keys(kernel.currentTask.fd[fd].handle)
end end
function vfs.getOpenFds()
local out={}
for i,v in ipairs(kernel.currentTask.fd) do
out[i]=v.path
end
return out
end
function vfs.fsinfo()
local out={mounts={},disks={}}
for i,v in pairs(vfs.mounts) do
out.mounts[i]=v
end
for i,v in pairs(vfs.disks) do
out.disks[i]={size=vfs.disks[i].spaceTotal(),used=vfs.disks[i].spaceUsed(),label=vfs.disks[i].getLabel(),readOnly=vfs.disks[i].isReadOnly(),isVirt=vfs.disks[i].isvirt,address=vfs.disks[i].addressz}
end
return out
end
vfs.resolveMount = resolveMount vfs.resolveMount = resolveMount
vfs.updateMeta = updateMeta
local sys = kernel.syscalls local sys = kernel.syscalls
sys["open"] = vfs.open sys["open"] = vfs.open
@@ -1198,5 +1219,7 @@ sys["fget_suid"] = function(fd)
local fobj = kernel.currentTask and kernel.currentTask.fd[fd] local fobj = kernel.currentTask and kernel.currentTask.fd[fd]
return fobj and fobj.suid_owner or nil return fobj and fobj.suid_owner or nil
end end
sys["getOpenFds"]= vfs.getOpenFds
sys["fsinfo"] = vfs.fsinfo
kernel.log("VFS module loaded") kernel.log("VFS module loaded")
@@ -7,8 +7,12 @@ kernel.searchpaths = {
} }
kernel.reqcache = cache kernel.reqcache = cache
local function wrap(lib)
return setmetatable({},{__index=lib,__newindex=function()error("Table is read-only")end,__usermeta=false,__call=function(s,...) return lib.new(...) end})
end
local function require(module, ...) local function require(module, ...)
if cache[module] then return cache[module].ret end if cache[module] then return wrap(cache[module].ret) end
local args = {...} local args = {...}
for _, path in ipairs(kernel.searchpaths) do for _, path in ipairs(kernel.searchpaths) do
local filepath = path:gsub("?", module) local filepath = path:gsub("?", module)
@@ -36,8 +40,8 @@ local function require(module, ...)
if not ok then if not ok then
error("Error running module "..module..": "..tostring(ret)) error("Error running module "..module..": "..tostring(ret))
end end
cache[module] = {ret = ret, expires = kernel.EFI:getEpochMs() + 120000} cache[module] = {ret = ret}
return ret return wrap(ret)
end end
coroutine.yield() coroutine.yield()
end end
@@ -0,0 +1,3 @@
--:Minify:--
local kernel = ...
@@ -0,0 +1,82 @@
--:Minify:--
local kernel = ...
local proxy = {}
local data = {}
proxy.address = "devfs0000"
proxy.isvirt = true
proxy.isReadOnly = function() return false end
proxy.spaceUsed = function() return 0 end
proxy.spaceTotal = function() return 0 end
proxy.makeDirectory = function() error("EACCES") end
proxy.remove = function() error("EACCES") end
proxy.setLabel = function() error("EACCES") end
proxy.getLabel = function() return "devfs" end
proxy.attributes = function(path) return {
size = 0,
modified = 0,
created = 0
} end
function proxy:open(path, mode)
local steps = kernel.vfs.splitPath(path)
local step = data
for i=1, #steps-1 do
local dat = step[steps[i]]
if type(dat) ~= "table" then error("ENFILE") end
step=dat
end
if type(step[steps[#steps]]) == "function" then
return step[steps[#steps]]("open", mode)
end
error("ENFILE")
end
function proxy:type(path, mode)
local steps = kernel.vfs.splitPath(path)
local step = data
if #steps == 0 then
return "directory"
end
for i=1, #steps-1 do
local dat = step[steps[i]]
if type(dat) ~= "table" then error("ENFILE") end
step=dat
end
if type(step[steps[#steps]]) == "function" then
return step[steps[#steps]]("type", mode)
end
if type(step[steps[#steps]]) == "table" then
return "directory"
end
error("ENOENT")
end
function proxy:list(path)
local steps = kernel.vfs.splitPath(path)
local step = data
if #steps == 0 then
return table.keys(data)
end
for i=1, #steps-1 do
local dat = step[steps[i]]
if type(dat) ~= "table" then error("ENOENT") end
step=dat
end
if type(step[steps[#steps]]) == "table" then
return table.keys(step[steps[#steps]])
end
error("ENOENT")
end
function proxy:fileExists(path)
local ok = pcall(function()
return self:type(path)
end)
return ok
end
kernel.sysfs={}
kernel.sysfs.proxy=proxy
kernel.disks["sysfs0000"]=proxy
@@ -37,7 +37,7 @@ kernel.execPerTask(function(task)
if task.sigq and #task.sigq ~= 0 and task.sigh then if task.sigq and #task.sigq ~= 0 and task.sigh then
local coro = coroutine.create(task.sigh) local coro = coroutine.create(task.sigh)
local status,err=coroutine.resume(coro, table.remove(task.sigq, 1)) local status,err=coroutine.resume(coro, table.remove(task.sigq, 1))
EFI:yeild() kernel.EFI:yield()
if status=="error" or status==false then if status=="error" or status==false then
task.sigd.error=err or "Unknown" task.sigd.error=err or "Unknown"
task.sigd.active=false task.sigd.active=false
@@ -2,3 +2,5 @@
local kernel=... local kernel=...
kernel.unixSockets={} kernel.unixSockets={}
local socket=kernel.socket local socket=kernel.socket
--socket.registerProtocal()
@@ -58,10 +58,12 @@ kernel._U.load = function(a,b,c,d) return origLoad(a,b,c,d or kernel._U) end
function kernel.freshUserEnv() function kernel.freshUserEnv()
local locals = {} local locals = {}
locals.syscall = _makeSyscallProxy()
local env = setmetatable(locals, { local env = setmetatable(locals, {
__index = kernel._U, __index = kernel._U,
__pairs = function(self)
return pairs(kernel._U)
end,
__newindex = function(_, k, v) rawset(locals, k, v) end, __newindex = function(_, k, v) rawset(locals, k, v) end,
__metatable=false __metatable=false
}) })
@@ -33,7 +33,7 @@ local function createVt(id, width, height)
end end
end end
function vt.obj:write(content) function vt.obj.write(content)
local x, y = vt.cursorX, vt.cursorY local x, y = vt.cursorX, vt.cursorY
if x>vt.width then return end if x>vt.width then return end
if y>vt.height then return end if y>vt.height then return end
@@ -79,36 +79,36 @@ local function createVt(id, width, height)
vt.cursorX, vt.cursorY = x, y vt.cursorX, vt.cursorY = x, y
end end
function vt.obj:spos(x, y) function vt.obj.spos(x, y)
vt.cursorX = tonumber(x) vt.cursorX = tonumber(x)
vt.cursorY = tonumber(y) vt.cursorY = tonumber(y)
end end
function vt.obj:gpos() function vt.obj.gpos()
return tostring(vt.cursorX)..";"..tostring(vt.cursorY) return vt.cursorX, vt.cursorY
end end
function vt.obj:sfgc(color) function vt.obj.sfgc(color)
vt.fgColor = tonumber(color) vt.fgColor = tonumber(color)
end end
function vt.obj:sbgc(color) function vt.obj.sbgc(color)
vt.bgColor = tonumber(color) vt.bgColor = tonumber(color)
end end
function vt.obj:gfgc() function vt.obj.gfgc()
return vt.fgColor return vt.fgColor
end end
function vt.obj:gbgc() function vt.obj.gbgc()
return vt.bgColor return vt.bgColor
end end
function vt.obj:gplt() function vt.obj.gplt()
return 24 return 24
end end
function vt.obj:clear() function vt.obj.clear()
for y = 1, vt.height do for y = 1, vt.height do
for x = 1, vt.width do for x = 1, vt.width do
vt.buffer[y][x] = {char = " ", fgColor = vt.fgColor, bgColor = vt.bgColor} vt.buffer[y][x] = {char = " ", fgColor = vt.fgColor, bgColor = vt.bgColor}
@@ -117,12 +117,12 @@ local function createVt(id, width, height)
vt.cursorX, vt.cursorY = 1, 1 vt.cursorX, vt.cursorY = 1, 1
end end
function vt.obj:isvirt() function vt.obj.isvirt()
return true return true
end end
function vt.obj:gctrl() function vt.obj.gfx()
return serializeBool(vt.ctrl)..";"..serializeBool(vt.alt)
end end
return vt return vt
@@ -108,7 +108,7 @@ function sys.spawn(func, name, envars, args, tgid, clearFds)
end end
function sys.execspawn(path, name, envars, args, tgid, keepFds) function sys.execspawn(path, name, envars, args, tgid, keepFds)
local func, euid, suid_active = loadExecutable(path, kernel._U) local func, euid, suid_active = loadExecutable(path)
local caller = kernel.currentTask local caller = kernel.currentTask
local real_uid = caller and caller.uid or kernel.uid local real_uid = caller and caller.uid or kernel.uid
@@ -124,16 +124,19 @@ function sys.execspawn(path, name, envars, args, tgid, keepFds)
return createTask(func, name or path, envars, args, tgid, real_uid, euid, not keepFds) return createTask(func, name or path, envars, args, tgid, real_uid, euid, not keepFds)
end end
function sys.exec(path, args, envars) function sys.exec(path, args, envars, clearFds)
local task = kernel.currentTask local task = kernel.currentTask
local func, euid, _ = loadExecutable(path, kernel._U) local func, euid, _ = loadExecutable(path)
-- no idea why this is here? -- no idea why this is here?
--if task.fd then -- Figured it out it is to close fds on su
-- for fd, _ in pairs(task.fd) do if clearFds then
-- if fd > 2 then pcall(kernel.vfs.close, fd) end if task.fd then
-- end for fd, _ in pairs(task.fd) do
--end if fd > 2 then pcall(kernel.vfs.close, fd) end
end
end
end
task.euid = euid task.euid = euid
task.args = args or {} task.args = args or {}
@@ -1,7 +1,7 @@
--:Minify:-- --:Minify:--
local kernel=... local kernel=...
local debug=debug kernel.debug=debug
kernel._G.debug={ kernel._G.debug={
getinfo=debug.getinfo, getinfo=kernel.debug.getinfo,
traceback=debug.traceback traceback=kernel.debug.traceback
} }
@@ -14,7 +14,7 @@ local data = kernel.vfs.read(handle, 1024 * 1024 * 4)
if not handle then kernel.panic("Failed to read "..kernel.config.initPath) end if not handle then kernel.panic("Failed to read "..kernel.config.initPath) end
kernel.vfs.close(handle) kernel.vfs.close(handle)
local initFunc, err = load(data, "@sysinit", "t", kernel._U) local initFunc, err = load(data, "@init", "t", kernel._U)
if not initFunc then kernel.PANIC("Failed to load init system: " .. err) end if not initFunc then kernel.PANIC("Failed to load init system: " .. err) end
kernel.tasks["1"] = { kernel.tasks["1"] = {
@@ -28,7 +28,7 @@ kernel.tasks["1"] = {
kernel.saveLog() kernel.saveLog()
end), end),
name = "sysinit", name = "init",
status = "R", status = "R",
pid = 1, pid = 1,
tgid = 1, tgid = 1,
@@ -2,11 +2,11 @@
local kernel = ... local kernel = ...
kernel.processes.kgc = function() kernel.processes.kgc = function()
while true do while true do
for i,v in pairs(kernel.reqcache) do --for i,v in pairs(kernel.reqcache) do
if v.expires and kernel.EFI:getEpochMs() > v.expires then -- if v.expires and kernel.EFI:getEpochMs() > v.expires then
kernel.reqcache[i] = nil -- kernel.reqcache[i] = nil
end -- end
end --end
sleep(5) sleep(5)
end end
end end
@@ -1,7 +1,10 @@
--:Minify:-- --:Minify:--
local kernel = ... local kernel = ...
if kernel.firstBoot then if kernel.firstBoot or kernel.config.resetPerms then
if kernel.config.resetPerms then
kernel.log("resetPerms is active, disable it in /boot/boot.cfg", "WARN", 0xFFFF00)
end
kernel.log("Seeding filesystem permissions...") kernel.log("Seeding filesystem permissions...")
local P = kernel.vfs.P local P = kernel.vfs.P
@@ -18,20 +21,23 @@ if kernel.firstBoot then
local function seed(root, data) local function seed(root, data)
for i=1,#data do for i=1,#data do
local entry=data[1] local entry=data[i]
kernel.vfs.chmod(root..entry[1],entry[2],entry[3]) if kernel.vfs.exists(root..entry[1]) then
kernel.vfs.chown(root..entry[1],entry[4]) kernel.vfs.updateMeta(root..entry[1],function(e)
e.perms=entry[4]
e.group=entry[3]
e.owner=entry[2]
end)
end
end end
end end
seed("/", { seed("/", {
{"bin", 0, 0, RWX_RX_RX}, {"bin", 0, 0, RWX_RX_RX},
{"boot", 0, 0, RWX_RX_RX}, {"boot", 0, 0, RWX_RX_RX},
{"dev", 0, 0, RWXRWXRWX},
{"etc", 0, 0, RWX_RX_RX}, {"etc", 0, 0, RWX_RX_RX},
{"home", 0, 0, RWX_RX_RX}, {"home", 0, 0, RWX_RX_RX},
{"lib", 0, 0, RWX_RX_RX}, {"lib", 0, 0, RWX_RX_RX},
{"proc", 0, 0, RWXRWXRWX},
{"root", 0, 0, RW____ }, {"root", 0, 0, RW____ },
{"sbin", 0, 0, RWX_RX_RX}, {"sbin", 0, 0, RWX_RX_RX},
{"tmp", 0, 0, RWXRWXRWX}, {"tmp", 0, 0, RWXRWXRWX},
+1 -1
View File
@@ -58,7 +58,7 @@ syscall.setEnviron("HOME", homedir)
syscall.setEnviron("USER", username) syscall.setEnviron("USER", username)
syscall.setEnviron("SHELL", shell) syscall.setEnviron("SHELL", shell)
local ok, err = pcall(syscall.exec, shell) local ok, err = pcall(syscall.exec, shell, nil, true)
if not ok then if not ok then
print("su: cannot exec shell '" .. shell .. "': " .. tostring(err)) print("su: cannot exec shell '" .. shell .. "': " .. tostring(err))
syscall.exit(1) syscall.exit(1)
File renamed without changes.
File renamed without changes.
+1
View File
@@ -0,0 +1 @@
vector
File renamed without changes.
+19
View File
@@ -0,0 +1,19 @@
function lib.load(fd)
function handle.setPixel(x,y,color24)
function handle.getPixel(x,y)
function handle.setPixels(x,y,w,framebuffer)
function handle.getPixels(x,y,w,h)
function handle.frame(x,y,w,h,writeonly)
integer id
recurse lib.load
function handle.framectl(id)
function frame.move(x,y)
function frame.resize(w,h)
function frame.free()
function handle.sync()
function handle.line(x1,y1,x2,y2)
function handle.box(x,y,w,h,c,fill)
function handle.filledBox(x,y,w,h,c)
function handle.text(x,y,font,text)
function handle.free()
function handle.size()
View File
Whitespace-only changes.
File renamed without changes.
View File
Whitespace-only changes.
File renamed without changes.
-40
View File
@@ -1,40 +0,0 @@
--:Minify:--
local lib = {}
function lib.frame(frame)
local handle = {}
function handle.setPixel(x,y,color24)
end
function handle.getPixel(x,y)
end
function handle.setPixels(x,y,framebuffer)
end
function handle.getPixels(x,y,w,h)
end
function handle.frame(x,y,w,h,writeonly)
end
function handle.framectl(id,x,y,w,h,writeonly)
end
function handle.drawframe()
end
function handle.line()
end
return handle
end
-350
View File
@@ -1,350 +0,0 @@
term.setGraphicsMode(2)
local w,h = term.getSize(2)
local fb={}
for i=1, h do
fb[i]={}
for x=1, w do
fb[i][x]=0
end
end
local function setPixel(x,y,c)
--local old=fb[y]
--fb[y]=string.sub(old,1,x-1)..string.char(c)..string.sub(old,x+1)
fb[y][x]=c
end
local function setPixels(x,y,frame)
local w,h = #fb[1], #fb
for i=1, #frame do
for j=1, #frame[i] do
fb[y+i-1][x+j-1]=frame[i][j]
end
end
end
local function getPixel(x,y)
return fb[y][x]
end
local function getPixels(x,y,w,h)
local ret={}
for i=y, y+h do
ret[#ret+1] = {table.unpack(fb[i], x, x+w)}
end
return ret
end
local colors = {
[0]=0x000000,
0x0b0b0b,
0x222222,
0x444444,
0x555555,
0x777777,
0x888888,
0xaaaaaa,
0xbbbbbb,
0xdddddd,
0xeeeeee,
0x00000b,
0x000022,
0x000044,
0x000055,
0x000077,
0x000088,
0x0000aa,
0x0000bb,
0x0000dd,
0x0000ee,
0x000b00,
0x002200,
0x004400,
0x005500,
0x007700,
0x008800,
0x00aa00,
0x00bb00,
0x00dd00,
0x00ee00,
0x0b0000,
0x220000,
0x440000,
0x550000,
0x770000,
0x880000,
0xaa0000,
0xbb0000,
0xdd0000,
0xee0000,
0x000033,
0x000066,
0x000099,
0x0000cc,
0x0000ff,
0x003300,
0x003333,
0x003366,
0x003399,
0x0033cc,
0x0033ff,
0x006600,
0x006633,
0x006666,
0x006699,
0x0066cc,
0x0066ff,
0x009900,
0x009933,
0x009966,
0x009999,
0x0099cc,
0x0099ff,
0x00cc00,
0x00cc33,
0x00cc66,
0x00cc99,
0x00cccc,
0x00ccff,
0x00ff00,
0x00ff33,
0x00ff66,
0x00ff99,
0x00ffcc,
0x00ffff,
0x330000,
0x330033,
0x330066,
0x330099,
0x3300cc,
0x3300ff,
0x333300,
0x333333,
0x333366,
0x333399,
0x3333cc,
0x3333ff,
0x336600,
0x336633,
0x336666,
0x336699,
0x3366cc,
0x3366ff,
0x339900,
0x339933,
0x339966,
0x339999,
0x3399cc,
0x3399ff,
0x33cc00,
0x33cc33,
0x33cc66,
0x33cc99,
0x33cccc,
0x33ccff,
0x33ff00,
0x33ff33,
0x33ff66,
0x33ff99,
0x33ffcc,
0x33ffff,
0x660000,
0x660033,
0x660066,
0x660099,
0x6600cc,
0x6600ff,
0x663300,
0x663333,
0x663366,
0x663399,
0x6633cc,
0x6633ff,
0x666600,
0x666633,
0x666666,
0x666699,
0x6666cc,
0x6666ff,
0x669900,
0x669933,
0x669966,
0x669999,
0x6699cc,
0x6699ff,
0x66cc00,
0x66cc33,
0x66cc66,
0x66cc99,
0x66cccc,
0x66ccff,
0x66ff00,
0x66ff33,
0x66ff66,
0x66ff99,
0x66ffcc,
0x66ffff,
0x990000,
0x990033,
0x990066,
0x990099,
0x9900cc,
0x9900ff,
0x993300,
0x993333,
0x993366,
0x993399,
0x9933cc,
0x9933ff,
0x996600,
0x996633,
0x996666,
0x996699,
0x9966cc,
0x9966ff,
0x999900,
0x999933,
0x999966,
0x999999,
0x9999cc,
0x9999ff,
0x99cc00,
0x99cc33,
0x99cc66,
0x99cc99,
0x99cccc,
0x99ccff,
0x99ff00,
0x99ff33,
0x99ff66,
0x99ff99,
0x99ffcc,
0x99ffff,
0xcc0000,
0xcc0033,
0xcc0066,
0xcc0099,
0xcc00cc,
0xcc00ff,
0xcc3300,
0xcc3333,
0xcc3366,
0xcc3399,
0xcc33cc,
0xcc33ff,
0xcc6600,
0xcc6633,
0xcc6666,
0xcc6699,
0xcc66cc,
0xcc66ff,
0xcc9900,
0xcc9933,
0xcc9966,
0xcc9999,
0xcc99cc,
0xcc99ff,
0xcccc00,
0xcccc33,
0xcccc66,
0xcccc99,
0xcccccc,
0xccccff,
0xccff00,
0xccff33,
0xccff66,
0xccff99,
0xccffcc,
0xccffff,
0xff0000,
0xff0033,
0xff0066,
0xff0099,
0xff00cc,
0xff00ff,
0xff3300,
0xff3333,
0xff3366,
0xff3399,
0xff33cc,
0xff33ff,
0xff6600,
0xff6633,
0xff6666,
0xff6699,
0xff66cc,
0xff66ff,
0xff9900,
0xff9933,
0xff9966,
0xff9999,
0xff99cc,
0xff99ff,
0xffcc00,
0xffcc33,
0xffcc66,
0xffcc99,
0xffcccc,
0xffccff,
0xffff00,
0xffff33,
0xffff66,
0xffff99,
0xffffcc,
0xffffff,
}
for i=0,255 do
term.setPaletteColor(i,colors[i])
end
term.drawPixels(0,0,fb)
for i=0,255 do
for y=1+i, h-i do
for x=1+i, w-i do
setPixel(x,y,i)
end
end
term.drawPixels(1,1,fb)
os.queueEvent("nosleep")
os.pullEvent()
end
for i=1, 1000 do
pcall(function()
setPixels(math.random(1,w),math.random(1,h),getPixels(math.random(1,w),math.random(1,h),math.random(1,w),math.random(1,h)))
end)
term.drawPixels(1,1,fb)
os.queueEvent("nosleep")
os.pullEvent()
end
setPixels(1,1,getPixels(w-50,h-50,50,50))
term.drawPixels(0,0,fb)
local i=0
for x=1, 16*4, 4 do
for y=1, 16*4, 4 do
setPixel(x,y,i)
setPixel(x+1,y,i)
setPixel(x+2,y,i)
setPixel(x+3,y,i)
setPixel(x,y+1,i)
setPixel(x+1,y+1,i)
setPixel(x+2,y+1,i)
setPixel(x+3,y+1,i)
setPixel(x,y+2,i)
setPixel(x+1,y+2,i)
setPixel(x+2,y+2,i)
setPixel(x+3,y+2,i)
setPixel(x,y+3,i)
setPixel(x+1,y+3,i)
setPixel(x+2,y+3,i)
setPixel(x+3,y+3,i)
i=i+1
end
end
term.drawPixels(0,0,fb)
sleep(5)
term.setGraphicsMode(false)
+9 -4
View File
@@ -6,6 +6,7 @@ syscall.open("/dev/tty/1","w") --stdout (Device 1)
syscall.open("/dev/null","w") --stderr (device 2) syscall.open("/dev/null","w") --stderr (device 2)
local fs = require("fs") local fs = require("fs")
local gfx = syscall.devctl(1,"gfx")
syscall.devctl(1,"clear") syscall.devctl(1,"clear")
syscall.devctl(1,"sfgc",0xFFFFFF) syscall.devctl(1,"sfgc",0xFFFFFF)
@@ -242,6 +243,7 @@ builtinCmds.clear = function()
syscall.devctl(1,"clear") syscall.devctl(1,"clear")
syscall.devctl(1,"sfgc",0xFFFFFF) syscall.devctl(1,"sfgc",0xFFFFFF)
syscall.devctl(1,"spos",1,1) syscall.devctl(1,"spos",1,1)
if gfx then local w,h=gfx.size() gfx.box(0,0,w+5,h+5,0,true) end
end end
builtinCmds.whoami = function() builtinCmds.whoami = function()
@@ -820,10 +822,11 @@ builtinCmds.df = function(...)
end end
local function fmt(n) return opts.h and hfmt(n) or tostring(n) end local function fmt(n) return opts.h and hfmt(n) or tostring(n) end
print(string.format("%-20s %10s %10s %10s %6s %-s","Filesystem","Size","Used","Avail","Use%","Mounted on")) print(string.format("%-20s %10s %10s %10s %6s %-s","Filesystem","Size","Used","Avail","Use%","Mounted on"))
local mounts = {{"$","/"}, {"devfs0000","/dev/"}, {"tmpfs0000","/tmp/"}} local fsinfo = syscall.fsinfo()
for _, m in ipairs(mounts) do for id, obj in pairs(fsinfo.disks) do
local id, mp = m[1], m[2] local use = ((obj.size/obj.used)-1)*100
print(string.format("%-20s %10s %10s %10s %6s %-s", id, "?", "?", "?", "?%", mp)) local avail = obj.size-obj.used
print(string.format("%-20s %10s %10s %10s %6s %-s", id, tostring(obj.size), tostring(obj.used), avail, tostring(use).."%", fsinfo.mounts[id] or ""))
end end
end end
@@ -1218,12 +1221,14 @@ local function runCommand(command)
while true do while true do
local exited, code = syscall.collect(proc) local exited, code = syscall.collect(proc)
if exited then if exited then
if gfx then gfx.setMode(false) end
if code then print("\nTask exited with code:\n"..tostring(code)) end if code then print("\nTask exited with code:\n"..tostring(code)) end
return return
end end
if terminate then if terminate then
local ok2 = syscall.kill(proc, true) local ok2 = syscall.kill(proc, true)
if ok2 then if ok2 then
if gfx then gfx.setMode(false) end
syscall.devctl(1,"sbgc",16); syscall.devctl(1,"sfgc",0xFF0000) syscall.devctl(1,"sbgc",16); syscall.devctl(1,"sfgc",0xFF0000)
print("\nProgram Terminated."); syscall.devctl(1,"sfgc",0xFFFFFF) print("\nProgram Terminated."); syscall.devctl(1,"sfgc",0xFFFFFF)
end end
+6 -4
View File
@@ -173,6 +173,8 @@ end
local luaEnv = setmetatable({}, {__index = _ENV}) local luaEnv = setmetatable({}, {__index = _ENV})
luaEnv._G = luaEnv luaEnv._G = luaEnv
luaEnv._ENV = _ENV
luaEnv._G = _G
luaEnv.print = function(...) luaEnv.print = function(...)
local n = select("#", ...) local n = select("#", ...)
@@ -259,9 +261,9 @@ local function getUserInput(prompt, history)
local key = syscall.read(0) local key = syscall.read(0)
if key and key ~= "" then if key and key ~= "" then
if key == "" then if key == "" then
if cursor > 1 then cursor = cursor - 1; dirty = true end if cursor > 1 then cursor = cursor + 1; dirty = true end
elseif key == "" then elseif key == "" then
if cursor <= #input then cursor = cursor + 1; dirty = true end if cursor <= #input then cursor = cursor - 1; dirty = true end
elseif key == "" then elseif key == "" then
if history and histIdx < #history then if history and histIdx < #history then
histIdx = histIdx + 1 histIdx = histIdx + 1
@@ -298,9 +300,9 @@ local function getUserInput(prompt, history)
end end
c(C_PROMPT); w("HyperionOS " .. _VERSION .. "\n") c(C_PROMPT); w("HyperionOS " .. _VERSION .. "\n")
w("Type \"exit()\" to exit.") w("Interactive Lua REPL. Type \"exit()\" to exit.\n")
c(C_NIL) c(C_NIL)
w("Interactive Lua REPL. exit() to quit.\n\n") w("\n\n")
c(1) c(1)
local history = {} local history = {}
+2
View File
@@ -0,0 +1,2 @@
Hyperion
Astronand
+217
View File
@@ -0,0 +1,217 @@
--:Minify:--
local lib={}
local function check(a,b,ignoreb)
if type(a)~="vector" then error("vector metatable is on non vector object") end
if not ignoreb and b~=nil then
if type(b)~="vector" then error("b must be vector") end
if #a~=#b then error("vectors must be same size") end
end
end
local vector={
add = function(a,b)
check(a,b)
local ret={}
for i=1, #a do
ret[i]=a[i]+b[i]
end
return lib.convert(ret)
end,
sub = function(a,b)
check(a,b)
if type(b)~="vector" then error("b must be vector") end
local ret={}
for i=1, #a do
ret[i]=a[i]-b[i]
end
return lib.convert(ret)
end,
unm = function(a)
local ret={}
for i=1, #a do
ret[i]=-a[i]
end
return lib.convert(ret)
end,
mul = function(a,b)
if type(a)=="number" and type(b)=="vector" then a,b=b,a end
check(a,b,true)
local ret={}
if type(b)=="vector" then
for i=1, #a do
ret[i]=a[i]*b[i]
end
elseif type(b)=="number" then
for i=1, #a do
ret[i]=a[i]*b
end
else
error("b must be vector or number")
end
return lib.convert(ret)
end,
div = function(a,b)
if type(a)=="number" and type(b)=="vector" then a,b=b,a end
check(a,b,true)
local ret={}
if type(b)=="vector" then
for i=1, #a do
ret[i]=a[i]/b[i]
end
elseif type(b)=="number" then
for i=1, #a do
ret[i]=a[i]/b
end
else
error("b must be vector or number")
end
return lib.convert(ret)
end,
dot = function(a,b)
check(a,b)
local out=a[1]*b[1]
for i=2, #a do
out=out+a[i]*b[i]
end
return out
end,
tostring = function(a)
check(a)
local out = "{"
for i=1, #a do
out=out..tostring(a[i])..", "
end
return out:sub(1,#out-2).."}"
end,
equals = function(a,b)
check(a,b)
for i=1, #a do
if a[i]~=b[i] then
return false
end
end
return true
end,
cross = function(a,b)
check(a,b)
if #a~=3 then error("Vectors must be of type 'vec3'") end
if #b~=3 then error("Vectors must be of type 'vec3'") end
return lib.convert({
a.y*b.z-a.z*b.y,
a.z*b.x-a.x*b.z,
a.x*b.y-a.y*b.x
})
end,
length = function(a)
check(a)
local out=a[1]*a[1]
for i=2, #a do
out=out+a[i]*a[i]
end
if type(out)=="vector" then
return out:sqrt()
else
return math.sqrt(out)
end
end,
len = function(a)
return a:length()
end,
normalize = function(a)
return a*(1/a:len())
end,
round = function(a, t)
check(a)
local ret={}
for i=1, #a do
ret[i]=math.floor((a[i]+t*0.5)/t)*t
end
return lib.convert(ret)
end,
exp = function(a, e)
check(a)
local ret={}
for i=1, #a do
ret[i]=a^e
end
return lib.convert(ret)
end,
sqrt = function(a)
check(a)
local ret={}
for i=1, #a do
if type(a[i])=="vector" then
ret[i]=a[i]:sqrt()
else
ret[i]=math.sqrt(a[i])
end
end
return lib.convert(ret)
end
}
local idxtable={
w=4,
x=1,
y=2,
z=3,
}
local function index(self, k)
if idxtable[k] then
return rawget(self,idxtable[k])
elseif vector[k] then
return vector[k]
else
return rawget(self,k)
end
end
local function newindex(self, k, v)
if idxtable[k] then
rawset(self, idxtable[k], v)
else
rawset(self, k, v)
end
end
local meta={
__name="vector",
__type="vector",
__usermeta=function() error("EACCES") end,
__index=index,
__newindex=newindex,
__unm=vector.unm,
__add=vector.add,
__sub=vector.sub,
__mul=vector.mul,
__div=vector.div,
__tostring=vector.tostring,
__eq=vector.equals
}
function lib.new(...)
local vars={...}
return setmetatable(vars,meta)
end
function lib.convert(vars)
return setmetatable(vars,meta)
end
return lib
+217
View File
@@ -0,0 +1,217 @@
--:Minify:--
local lib={}
local function check(a,b,ignoreb)
if type(a)~="vector" then error("a must be vector") end
if not ignoreb and b~=nil then
if type(b)~="vector" then error("b must be vector") end
if #a~=#b then error("vectors must be same size") end
end
end
local vector={
add = function(a,b)
check(a,b)
local ret={}
for i=1, #a do
ret[i]=a[i]+b[i]
end
return lib.convert(ret)
end,
sub = function(a,b)
check(a,b)
if type(b)~="vector" then error("b must be vector") end
local ret={}
for i=1, #a do
ret[i]=a[i]-b[i]
end
return lib.convert(ret)
end,
unm = function(a)
local ret={}
for i=1, #a do
ret[i]=-a[i]
end
return lib.convert(ret)
end,
mul = function(a,b)
if type(a)=="number" and type(b)=="vector" then a,b=b,a end
check(a,b,true)
local ret={}
if type(b)=="vector" then
for i=1, #a do
ret[i]=a[i]*b[i]
end
elseif type(b)=="number" then
for i=1, #a do
ret[i]=a[i]*b
end
else
error("b must be vector or number")
end
return lib.convert(ret)
end,
div = function(a,b)
if type(a)=="number" and type(b)=="vector" then a,b=b,a end
check(a,b,true)
local ret={}
if type(b)=="vector" then
for i=1, #a do
ret[i]=a[i]/b[i]
end
elseif type(b)=="number" then
for i=1, #a do
ret[i]=a[i]/b
end
else
error("b must be vector or number")
end
return lib.convert(ret)
end,
dot = function(a,b)
check(a,b)
local out=a[1]*b[1]
for i=2, #a do
out=out+a[i]*b[i]
end
return out
end,
tostring = function(a)
check(a)
local out = "{"
for i=1, #a do
out=out..tostring(a[i])..", "
end
return out:sub(1,#out-2).."}"
end,
equals = function(a,b)
check(a,b)
for i=1, #a do
if a[i]~=b[i] then
return false
end
end
return true
end,
cross = function(a,b)
check(a,b)
if #a~=3 then error("Vectors must be of type 'vec3'") end
if #b~=3 then error("Vectors must be of type 'vec3'") end
return lib.convert({
a.y*b.z-a.z*b.y,
a.z*b.x-a.x*b.z,
a.x*b.y-a.y*b.x
})
end,
length = function(a)
check(a)
local out=a[1]*a[1]
for i=2, #a do
out=out+a[i]*a[i]
end
if type(out)=="vector" then
return out:sqrt()
else
return math.sqrt(out)
end
end,
len = function(a)
return a:length()
end,
normalize = function(a)
return a*(1/a:len())
end,
round = function(a, t)
check(a)
local ret={}
for i=1, #a do
ret[i]=math.floor((a[i]+t*0.5)/t)*t
end
return lib.convert(ret)
end,
exp = function(a, e)
check(a)
local ret={}
for i=1, #a do
ret[i]=a^e
end
return lib.convert(ret)
end,
sqrt = function(a)
check(a)
local ret={}
for i=1, #a do
if type(a[i])=="vector" then
ret[i]=a[i]:sqrt()
else
ret[i]=math.sqrt(a[i])
end
end
return lib.convert(ret)
end
}
local idxtable={
w=4,
x=1,
y=2,
z=3,
}
local function index(self, k)
if idxtable[k] then
return rawget(self,idxtable[k])
elseif vector[k] then
return vector[k]
else
return rawget(self,k)
end
end
local function newindex(self, k, v)
if idxtable[k] then
rawset(self, idxtable[k], v)
else
rawset(self, k, v)
end
end
local meta={
__name="vector",
__type="vector",
__usermeta=function() error("EACCES") end,
__index=index,
__newindex=newindex,
__unm=vector.unm,
__add=vector.add,
__sub=vector.sub,
__mul=vector.mul,
__div=vector.div,
__tostring=vector.tostring,
__eq=vector.equals
}
function lib.new(...)
local vars={...}
return setmetatable(vars,meta)
end
function lib.convert(vars)
return setmetatable(vars,meta)
end
return lib
+3
View File
@@ -0,0 +1,3 @@
General advanced math libs
VectorX
Matrix
+1
View File
@@ -0,0 +1 @@
1.0.0
+124
View File
@@ -0,0 +1,124 @@
local args={...}
if #args<1 then print("Usage: render3d [file.obj]") end
local fs=require("fs")
local vec=require("vector")
local gfx=syscall.devctl(1,"gfx")
local file = fs.readAllText(args[1])
local obj={v={},f={}}
local lines=string.split(file, "\n")
for i=1, #lines do
local line=lines[i]
if line:sub(1,2)=="v " then
line=line:sub(3)
local s=string.split(line, " ")
obj.v[#obj.v+1]=vec(tonumber(s[1]),tonumber(s[2]),tonumber(s[3]))
elseif line:sub(1,2)=="f " then
line=line:sub(3)
local s=string.split(line, " ")
local vs={}
for c=1, #s do
local v=string.split(s[c], "/")
vs[#vs+1]=tonumber(v[1])
end
obj.f[#obj.f+1]=vec(table.unpack(vs))
end
end
print("Vertices")
for i=1, #obj.v do
print(obj.v[i])
end
print("Faces")
for i=1, #obj.f do
print(obj.f[i])
end
local function projectPoint(point, cameraPos, cameraRot, fov, width, height)
local p=point-cameraPos
local pitch=cameraRot.x
local yaw=cameraRot.y
local cp=math.cos(pitch)
local sp=math.sin(pitch)
local cy=math.cos(yaw)
local sy=math.sin(yaw)
local right=vec(
cy,
0,
-sy
)
local up=vec(
sy*sp,
cp,
cy*sp
)
local forward=vec(
-sy*cp,
sp,
-cy*cp
)
local x=p:dot(right)
local y=p:dot(up)
local z=p:dot(forward)
if z<=0 then
return nil
end
local aspect=width/height
local f=1/math.tan(fov*0.5)
local sx=(x*f/aspect)/z
local sy=(y*f)/z
return vec(
(sx+1)*0.5*width,
(1-sy)*0.5*height
),z
end
local proj={}
local camera=vec(0,0,3)
local rot=vec(0,0,0)
local w,h=gfx.size()
local fov=math.rad(90)
for i=1, #obj.v do
proj[i]={}
proj[i].p,proj[i].z=projectPoint(obj.v[i],camera,rot,fov,w,h)
end
print("Projected")
for i=1, #proj do
print(proj[i].p)
end
gfx.setMode(true)
for i=#obj.f, 1, -1 do
local f=obj.f[i]
local c=math.random(0,0xffffff)
for p=1, #f do
if p~=#f then
print(tostring(proj[f[p]].p.x)..","..tostring(proj[f[p]].p.y).." > "..tostring(proj[f[p+1]].p.x)..","..tostring(proj[f[p+1]].p.y))
gfx.line(proj[f[p]].p.x,proj[f[p]].p.y,proj[f[p+1]].p.x,proj[f[p+1]].p.y,c)
else
print(tostring(proj[f[p]].p.x)..","..tostring(proj[f[p]].p.y).." > "..tostring(proj[f[1]].p.x)..","..tostring(proj[f[1]].p.y))
gfx.line(proj[f[p]].p.x,proj[f[p]].p.y,proj[f[1]].p.x,proj[f[1]].p.y,c)
end
end
end
while true do
sleep(5)
end
@@ -0,0 +1,40 @@
# Blender 5.2.2 LTS
# www.blender.org
mtllib box.mtl
o Cube
v 1.000000 1.000000 -1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 1.000000 1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 1.000000 -1.000000
v -1.000000 -1.000000 -1.000000
v -1.000000 1.000000 1.000000
v -1.000000 -1.000000 1.000000
vn -0.0000 1.0000 -0.0000
vn -0.0000 -0.0000 1.0000
vn -1.0000 -0.0000 -0.0000
vn -0.0000 -1.0000 -0.0000
vn 1.0000 -0.0000 -0.0000
vn -0.0000 -0.0000 -1.0000
vt 0.625000 0.500000
vt 0.875000 0.500000
vt 0.875000 0.750000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.625000 1.000000
vt 0.375000 1.000000
vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.250000
vt 0.125000 0.500000
vt 0.375000 0.500000
vt 0.125000 0.750000
s 0
usemtl Material
f 1/1/1 5/2/1 7/3/1 3/4/1
f 4/5/2 3/4/2 7/6/2 8/7/2
f 8/8/3 7/9/3 5/10/3 6/11/3
f 6/12/4 2/13/4 4/5/4 8/14/4
f 2/13/5 1/1/5 3/4/5 4/5/5
f 6/11/6 5/10/6 1/1/6 2/13/6
+4
View File
@@ -0,0 +1,4 @@
--:Minify:--
local lib = {}
return lib
-23
View File
@@ -1,23 +0,0 @@
local fs=require("fs")
local units=fs.list("/usr/lib/hunit/")
fs.mkdir("/tmp/hunit/")
local errors={}
for i,v in ipairs(units) do
print("running unit "..v)
local code=fs.readAllText("/usr/lib/hunit/"..v)
local func, err=load(code, "@"..v)
if not func then
print(" [ERROR]:"..err)
end
---@diagnostic disable-next-line: param-type-mismatch
local ok, err=pcall(func)
if not ok then
print(" [ERROR]:"..err)
table.insert(errors, v)
else
print(" [SUCCESS]")
end
end
print(tostring(#errors).." units failed")
return 0
-427
View File
@@ -1,427 +0,0 @@
--:Minify:--
local passed, failed = 0, 0
local function pass(msg) syscall.devctl(1,"sfgc",10); print(" PASS "..msg); syscall.devctl(1,"sfgc",1) end
local function fail(msg) syscall.devctl(1,"sfgc",2); print(" FAIL "..msg); syscall.devctl(1,"sfgc",1) end
local function info(msg) syscall.devctl(1,"sfgc",14); print(" .... "..msg); syscall.devctl(1,"sfgc",1) end
local function head(msg) syscall.devctl(1,"sfgc",4); print("\n"..msg); syscall.devctl(1,"sfgc",1) end
local function check(label, ok, err)
if ok then passed = passed + 1; pass(label)
else failed = failed + 1; fail(label.." - "..tostring(err)) end
end
local function writeFile(path, data)
local ok, fd = pcall(syscall.open, path, "w")
if not ok then return false, fd end
local ok2, err = pcall(syscall.write, fd, data)
pcall(syscall.close, fd)
return ok2, err
end
local function readFile(path)
local ok, fd = pcall(syscall.open, path, "r")
if not ok then return false, fd end
local ok2, data = pcall(syscall.read, fd, 65536)
pcall(syscall.close, fd)
return ok2, data
end
local function rmrf(path)
local t = syscall.type(path)
if t == "directory" then
local ok, entries = pcall(syscall.listdir, path)
if ok then
for _, name in ipairs(entries) do
rmrf(path:gsub("/$","").."/"..name)
end
end
pcall(syscall.remove, path)
elseif t == "file" then
pcall(syscall.remove, path)
end
end
local SCRATCH = "/tmp/looptest_scratch"
local SRC_DIR = SCRATCH.."/src"
local BIND_MNT = SCRATCH.."/bind_mnt"
local IMG_PATH = SCRATCH.."/test.hfs"
local IMG_MNT = SCRATCH.."/img_mnt"
local BIND_LOOP = nil
local IMG_LOOP = nil
rmrf(SCRATCH)
pcall(syscall.mkdir, SCRATCH)
pcall(syscall.mkdir, SRC_DIR)
pcall(syscall.mkdir, BIND_MNT)
pcall(syscall.mkdir, IMG_MNT)
pcall(syscall.mkdir, SRC_DIR.."/subdir")
writeFile(SRC_DIR.."/hello.txt", "hello from hyperion\n")
writeFile(SRC_DIR.."/data.txt", "line1\nline2\nline3\n")
writeFile(SRC_DIR.."/subdir/deep.txt", "deep file\n")
head("[ 1 ] bind mode - losetup on a directory")
do
local ok, id = pcall(syscall.losetup, SRC_DIR)
check("losetup(dir) returns a loop id", ok and type(id) == "string" and id:sub(1,4) == "loop", id)
if ok then
BIND_LOOP = id
info("attached as "..id)
end
end
head("[ 2 ] bind mode - mount and read files")
do
if BIND_LOOP then
local mok = pcall(syscall.mount, BIND_MNT, BIND_LOOP)
check("mount(bind_mnt, "..BIND_LOOP..")", mok, "mount failed")
if mok then
local lok, entries = pcall(syscall.listdir, BIND_MNT)
check("listdir through bind mount", lok and type(entries) == "table", entries)
local rok, data = readFile(BIND_MNT.."/hello.txt")
check("read hello.txt through bind", rok and data == "hello from hyperion\n",
rok and ("got: "..tostring(data):sub(1,40)) or tostring(data))
local rok2, data2 = readFile(BIND_MNT.."/subdir/deep.txt")
check("read subdir/deep.txt through bind", rok2 and data2 == "deep file\n",
rok2 and ("got: "..tostring(data2)) or tostring(data2))
end
else
check("mount (skipped - no loop id)", false, "losetup failed in [1]")
end
end
head("[ 3 ] bind mode - write through loop mount, verify on host")
do
if BIND_LOOP then
local wok, werr = writeFile(BIND_MNT.."/written.txt", "written via loop\n")
check("write new file through bind mount", wok, werr)
local rok, data = readFile(BIND_MNT.."/written.txt")
check("read back through bind mount", rok and data == "written via loop\n",
rok and ("got: "..tostring(data)) or tostring(data))
local rok2, data2 = readFile(SRC_DIR.."/written.txt")
check("file visible on host path (bind is transparent)", rok2 and data2 == "written via loop\n",
rok2 and ("got: "..tostring(data2)) or tostring(data2))
else
check("write (skipped)", false, "bind mount not set up")
end
end
head("[ 4 ] bind mode - lodetach while mounted returns EBUSY")
do
if BIND_LOOP then
local ok = pcall(syscall.lodetach, BIND_LOOP)
check("lodetach while mounted is refused (EBUSY)", not ok, "should have errored")
else
check("lodetach busy check (skipped)", false, "no bind loop")
end
end
head("[ 5 ] bind mode - umount then lodetach")
do
if BIND_LOOP then
local uok = pcall(syscall.umount, BIND_MNT)
check("umount(bind_mnt)", uok, "umount failed")
local dok = pcall(syscall.lodetach, BIND_LOOP)
check("lodetach after umount", dok, "lodetach failed")
if dok then BIND_LOOP = nil end
else
check("umount+lodetach (skipped)", false, "no bind loop")
end
end
head("[ 6 ] loimgcreate - serialise directory to HFS image")
do
local ok, imgStr = pcall(syscall.loimgcreate, SRC_DIR)
check("loimgcreate(srcdir) returns a string", ok and type(imgStr) == "string" and #imgStr > 0, imgStr)
if ok then
info("image size: "..#imgStr.." bytes")
local isBHFS = imgStr:sub(1, 4) == "BHFS"
check("image has BHFS magic header", isBHFS,
"got: "..imgStr:sub(1,4):gsub(".", function(c) return string.format("%02X ", c:byte()) end))
check("image has correct version byte (0x01)", imgStr:byte(5) == 1,
"version byte: "..tostring(imgStr:byte(5)))
check("image contains FILE record (type=0x01)", imgStr:find("\001", 9, true) ~= nil, "no FILE type byte found")
check("image contains DIR record (type=0x02)", imgStr:find("\002", 9, true) ~= nil, "no DIR type byte found")
check("image ends with END record (type=0xFF)", imgStr:byte(#imgStr) == 0xFF,
"last byte: 0x"..string.format("%02X", imgStr:byte(#imgStr)))
local wok, werr = pcall(syscall.loimgwrite, imgStr, IMG_PATH)
check("loimgwrite writes image file", wok, werr)
check("image file exists on disk", syscall.type(IMG_PATH) == "file", "file not found")
end
end
head("[ 7 ] HFS image - losetup attaches image file")
do
if syscall.type(IMG_PATH) == "file" then
local ok, id = pcall(syscall.losetup, IMG_PATH)
check("losetup(image.hfs) returns loop id", ok and type(id) == "string", id)
if ok then
IMG_LOOP = id
info("image attached as "..id)
local lok, devs = pcall(syscall.lolist)
local found = false
if lok then
for lid, info_entry in pairs(devs) do
if lid == id then found = true end
end
end
check("lolist() contains new image device", found, "not found in lolist")
end
else
check("losetup image (skipped - no image file)", false, "image not created in [6]")
end
end
head("[ 8 ] HFS image - mount and read files")
do
if IMG_LOOP then
local mok = pcall(syscall.mount, IMG_MNT, IMG_LOOP)
check("mount(img_mnt, "..IMG_LOOP..")", mok, "mount failed")
if mok then
local lok, entries = pcall(syscall.listdir, IMG_MNT)
check("listdir through image mount returns table", lok and type(entries) == "table", entries)
if lok then
local hasHello = false
local hasSubdir = false
for _, e in ipairs(entries) do
if e == "hello.txt" then hasHello = true end
if e == "subdir" then hasSubdir = true end
end
check("hello.txt visible in image root", hasHello, "not listed")
check("subdir/ visible in image root", hasSubdir, "not listed")
end
local rok, data = readFile(IMG_MNT.."/hello.txt")
check("read hello.txt from image", rok and data == "hello from hyperion\n",
rok and ("got: "..tostring(data):sub(1,40)) or tostring(data))
local rok2, data2 = readFile(IMG_MNT.."/data.txt")
check("read data.txt from image", rok2 and data2 == "line1\nline2\nline3\n",
rok2 and ("got: "..tostring(data2)) or tostring(data2))
end
else
check("image mount read (skipped)", false, "no image loop")
end
end
head("[ 9 ] HFS image - write new files into image mount")
do
if IMG_LOOP then
local wok, werr = writeFile(IMG_MNT.."/newfile.txt", "created inside image\n")
check("write new file into image mount", wok, werr)
local rok, data = readFile(IMG_MNT.."/newfile.txt")
check("read back newly written file", rok and data == "created inside image\n",
rok and ("got: "..tostring(data)) or tostring(data))
local wok2, werr2 = writeFile(IMG_MNT.."/hello.txt", "overwritten\n")
check("overwrite existing file in image", wok2, werr2)
local rok2, data2 = readFile(IMG_MNT.."/hello.txt")
check("overwritten content reads back correctly", rok2 and data2 == "overwritten\n",
rok2 and ("got: "..tostring(data2)) or tostring(data2))
local rok3, orig = readFile(IMG_PATH)
check("disk image file is unchanged after in-memory write",
rok3 and orig and orig:find("/hello%.txt") ~= nil,
rok3 and "filename record missing from image" or tostring(orig))
else
check("image write test (skipped)", false, "image not mounted")
end
end
head("[ 10 ] HFS image - sub-directory traversal")
do
if IMG_LOOP then
local t = syscall.type(IMG_MNT.."/subdir")
check("type(subdir) == 'directory'", t == "directory", "got: "..tostring(t))
local lok, entries = pcall(syscall.listdir, IMG_MNT.."/subdir")
check("listdir(subdir) works", lok and type(entries) == "table", entries)
local rok, data = readFile(IMG_MNT.."/subdir/deep.txt")
check("read subdir/deep.txt from image", rok and data == "deep file\n",
rok and ("got: "..tostring(data)) or tostring(data))
local mok = pcall(syscall.mkdir, IMG_MNT.."/subdir/newdir")
check("mkdir inside image mount", mok, "mkdir failed")
check("new dir has type 'directory'",
syscall.type(IMG_MNT.."/subdir/newdir") == "directory",
"wrong type")
local wok, werr = writeFile(IMG_MNT.."/subdir/newdir/x.txt", "x\n")
check("write file in newly created subdir", wok, werr)
else
check("subdir traversal (skipped)", false, "image not mounted")
end
end
head("[ 11 ] HFS image - lodetach while mounted returns EBUSY")
do
if IMG_LOOP then
local ok = pcall(syscall.lodetach, IMG_LOOP)
check("lodetach image while mounted is refused", not ok, "should have errored EBUSY")
else
check("lodetach busy (skipped)", false, "no image loop")
end
end
head("[ 12 ] HFS image - umount then lodetach")
do
if IMG_LOOP then
local uok = pcall(syscall.umount, IMG_MNT)
check("umount(img_mnt)", uok, "umount failed")
local dok = pcall(syscall.lodetach, IMG_LOOP)
check("lodetach after umount", dok, "lodetach failed")
if dok then
local lok, devs = pcall(syscall.lolist)
local found = false
if lok then
for lid in pairs(devs) do
if lid == IMG_LOOP then found = true end
end
end
check("lolist no longer shows detached device", not found, "still present in lolist")
IMG_LOOP = nil
end
else
check("image umount+lodetach (skipped)", false, "no image loop")
end
end
head("[ 13 ] lolist - reflects attached device count")
do
local ok1, id1 = pcall(syscall.losetup, SRC_DIR)
local ok2, id2 = pcall(syscall.losetup, SRC_DIR)
check("attach first device for lolist test", ok1, id1)
check("attach second device for lolist test", ok2, id2)
if ok1 and ok2 then
local lok, devs = pcall(syscall.lolist)
check("lolist() succeeds", lok, devs)
if lok then
local found1, found2 = false, false
for lid in pairs(devs) do
if lid == id1 then found1 = true end
if lid == id2 then found2 = true end
end
check("lolist contains first device", found1, "missing "..id1)
check("lolist contains second device", found2, "missing "..id2)
local count = 0
for _ in pairs(devs) do count = count + 1 end
info("lolist shows "..count.." device(s)")
end
end
if ok1 then pcall(syscall.lodetach, id1) end
if ok2 then pcall(syscall.lodetach, id2) end
end
head("[ 14 ] losetup - non-existent path returns error")
do
local ok = pcall(syscall.losetup, "/tmp/does_not_exist_xyz_looptest")
check("losetup on missing path errors", not ok, "should have errored")
end
head("[ 15 ] mount - same loop device cannot be mounted twice")
do
local ok, id = pcall(syscall.losetup, SRC_DIR)
check("losetup for double-mount test", ok, id)
if ok then
local m1ok = pcall(syscall.mount, BIND_MNT, id)
check("first mount succeeds", m1ok, "mount failed")
if m1ok then
local m2ok = pcall(syscall.mount, IMG_MNT, id)
check("second mount of same device is refused", not m2ok, "should have errored EBUSY")
pcall(syscall.umount, BIND_MNT)
end
pcall(syscall.lodetach, id)
end
end
head("[ 16 ] loimgcreate - on a regular file returns ENOTDIR")
do
local ok = pcall(syscall.loimgcreate, IMG_PATH)
check("loimgcreate on a file errors (ENOTDIR)", not ok, "should have errored")
end
head("[ 17 ] HFS image - binary round-trip (all byte values)")
do
local bytes = {}
for i = 0, 255 do bytes[i+1] = string.char(i) end
local binData = table.concat(bytes)
local binSrc = SCRATCH.."/binsrc"
pcall(syscall.mkdir, binSrc)
writeFile(binSrc.."/binary.bin", binData)
local ok1, imgStr = pcall(syscall.loimgcreate, binSrc)
check("loimgcreate handles binary content", ok1, imgStr)
if ok1 then
local binImg = SCRATCH.."/binary.hfs"
pcall(syscall.loimgwrite, imgStr, binImg)
local ok2, lid = pcall(syscall.losetup, binImg)
check("losetup on binary image", ok2, lid)
if ok2 then
local mnt = SCRATCH.."/binmnt"
pcall(syscall.mkdir, mnt)
local mok = pcall(syscall.mount, mnt, lid)
check("mount binary image", mok, "mount failed")
if mok then
local rok, readBack = readFile(mnt.."/binary.bin")
check("binary file readable from image", rok, readBack)
check("binary data round-trips without corruption",
rok and readBack == binData,
rok and string.format("length in=%d out=%d", #binData, #(readBack or "")) or tostring(readBack))
pcall(syscall.umount, mnt)
end
pcall(syscall.lodetach, lid)
end
end
end
head("[ 18 ] second-run safety - lolist is empty after full cleanup")
do
local lok, devs = pcall(syscall.lolist)
check("lolist() call succeeds", lok, devs)
if lok then
local count = 0
for _ in pairs(devs) do count = count + 1 end
check("no leftover loop devices after all tests", count == 0,
count.." device(s) still attached: "..
(function()
local ids = {}
for id in pairs(devs) do ids[#ids+1] = id end
return table.concat(ids, ", ")
end)())
end
end
rmrf(SCRATCH)
print("")
syscall.devctl(1, "sfgc", failed == 0 and 10 or 2)
print(string.format("Results: %d passed, %d failed", passed, failed))
syscall.devctl(1, "sfgc", 1)
if failed > 0 then syscall.exit(1) end
-151
View File
@@ -1,151 +0,0 @@
--:Minify:--
local args = { ... }
local target = args[1] or "http://example.com"
local function pass(msg) syscall.devctl(1,"sfgc",10); print(" PASS " .. msg); syscall.devctl(1,"sfgc",1) end
local function fail(msg) syscall.devctl(1,"sfgc",2); print(" FAIL " .. msg); syscall.devctl(1,"sfgc",1) end
local function info(msg) syscall.devctl(1,"sfgc",14); print(" .... " .. msg); syscall.devctl(1,"sfgc",1) end
local function head(msg) syscall.devctl(1,"sfgc",4); print("\n" .. msg); syscall.devctl(1,"sfgc",1) end
local passed, failed = 0, 0
local function check(name, ok, err)
if ok then passed = passed + 1; pass(name)
else failed = failed + 1; fail(name .. " - " .. tostring(err)) end
end
head("[ 1 ] socket() creation")
do
local ok, fd = pcall(syscall.socket, "inet", "stream")
check("socket(inet, stream) returns fd", ok and type(fd) == "number", fd)
if ok then
local cok = pcall(syscall.close, fd)
check("close() on socket fd", cok, "close failed")
end
local ok2, fd2 = pcall(syscall.socket, "unix", "stream")
check("socket(unix, stream) returns fd", ok2 and type(fd2) == "number", fd2)
if ok2 then pcall(syscall.close, fd2) end
local ok3 = pcall(syscall.socket, "ax25", "stream")
check("socket(ax25) returns EAFNOSUPPORT", not ok3, "should have errored")
end
head("[ 2 ] connect() to " .. target)
local sockfd
do
local ok, fd = pcall(syscall.socket, "inet", "stream")
check("socket() before connect", ok, fd)
if ok then
sockfd = fd
local cok, cerr = pcall(syscall.connect, fd, target)
check("connect(" .. target .. ")", cok, cerr)
end
end
head("[ 3 ] send() HTTP GET via socket")
do
if sockfd then
local sok, serr = pcall(syscall.send, sockfd, "")
check("send() does not error", sok, serr)
else
check("send() skipped (no socket)", false, "socket creation failed")
end
end
head("[ 4 ] recv() reads HTTP response")
do
if sockfd then
info("waiting for response (recv blocks up to 10s)...")
local ok, body = pcall(syscall.recv, sockfd, 65536)
check("recv() returns non-empty body", ok and body and #body > 0,
ok and "empty response" or tostring(body))
if ok and body and #body > 0 then
info("received " .. #body .. " bytes")
local preview = body:sub(1, 120):gsub("\r", ""):gsub("\n", " ")
info("preview: " .. preview)
end
pcall(syscall.close, sockfd)
sockfd = nil
else
check("recv() skipped (no socket)", false, "socket creation failed")
end
end
head("[ 5 ] httpget() convenience wrapper")
do
info("GET " .. target .. " ...")
local ok, body = pcall(syscall.httpget, target)
check("httpget() succeeds", ok, body)
if ok then
check("httpget() returns non-empty string", type(body) == "string" and #body > 0, "empty")
if type(body) == "string" and #body > 0 then
info("received " .. #body .. " bytes")
local preview = body:sub(1, 120):gsub("\r", ""):gsub("\n", " ")
info("preview: " .. preview)
local hasHtml = body:lower():find("<html") ~= nil
or body:lower():find("<!doctype") ~= nil
or body:find("{") ~= nil
or body:find("HTTP") ~= nil
check("body looks like HTTP content", hasHtml, "no recognisable content markers")
end
end
end
head("[ 6 ] UNIX socket loopback IPC")
do
local sockPath = "/tmp/socktest.sock"
pcall(syscall.remove, sockPath)
local sok, sfd = pcall(syscall.socket, "unix", "stream")
check("server socket(unix,stream)", sok, sfd)
if sok then
local bok = pcall(syscall.bind, sfd, sockPath)
check("bind(" .. sockPath .. ")", bok, "bind failed")
local lok = pcall(syscall.listen, sfd, 1)
check("listen()", lok, "listen failed")
local cok, cfd = pcall(syscall.socket, "unix", "stream")
check("client socket(unix,stream)", cok, cfd)
if cok then
local connok = pcall(syscall.connect, cfd, sockPath)
check("client connect(" .. sockPath .. ")", connok, "connect failed")
local aok, afd = pcall(syscall.accept, sfd)
check("accept() returns client fd", aok, afd)
if connok and aok then
local sendok = pcall(syscall.send, cfd, "hello hyperion")
check("send() from client", sendok, "send failed")
local rok, data = pcall(syscall.recv, afd, 1024)
check("recv() on server side", rok and data == "hello hyperion",
rok and ("got: " .. tostring(data)) or tostring(data))
local repok = pcall(syscall.send, afd, "hello back")
check("send() reply from server", repok, "send failed")
local rok2, data2 = pcall(syscall.recv, cfd, 1024)
check("recv() reply on client", rok2 and data2 == "hello back",
rok2 and ("got: " .. tostring(data2)) or tostring(data2))
pcall(syscall.close, afd)
end
pcall(syscall.close, cfd)
end
pcall(syscall.close, sfd)
pcall(syscall.remove, sockPath)
end
end
print("")
syscall.devctl(1,"sfgc", failed == 0 and 10 or 2)
print(string.format("Results: %d passed, %d failed", passed, failed))
syscall.devctl(1,"sfgc",1)
if failed > 0 then syscall.exit(1) end
@@ -1,3 +0,0 @@
local fs = require("fs")
assert(fs.mkdir("/tmp/hunit/testdir"), "failed to make directory")
assert(fs.isDir("/tmp/hunit/testdir"), "directory does not exist")
@@ -1,10 +0,0 @@
local fd = syscall.VFS_open("/tmp/hunit/testfile.txt", "w")
syscall.VFS_write(fd, "This is a test file")
syscall.VFS_close(fd)
local fd = syscall.VFS_open("/tmp/hunit/testfile.txt", "r")
local text = syscall.VFS_read(fd, 64)
syscall.VFS_close(fd)
if text~="This is a test file" then
error("File failed to write/read")
end
+5 -2
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
Usage: Usage:
python build.py <target> [--arch cct|oc] [--release|--dev] python build.py <target> [--arch cct|oc|ac] [--release|--dev]
Targets: Targets:
build build
@@ -17,6 +17,7 @@ Targets:
Arch flags: Arch flags:
--arch cct --arch cct
--arch oc --arch oc
--arch ac
Release flags: Release flags:
--release --release
@@ -41,6 +42,7 @@ PROD_ROOT = PROJECT_ROOT / "prod"
ARCH_BOOT_DIR = { ARCH_BOOT_DIR = {
"cct": Path("boot") / "cct", "cct": Path("boot") / "cct",
"oc": Path("boot") / "oc", "oc": Path("boot") / "oc",
"ac": Path("boot") / "ac"
} }
@@ -146,6 +148,7 @@ def install_bootloader(arch: str, release: bool):
eeprom = boot_dir / "eeprom" eeprom = boot_dir / "eeprom"
eeprom_dst_name = "startup.lua" if release else "eeprom" eeprom_dst_name = "startup.lua" if release else "eeprom"
eeprom_dst_name = "uefi.lua" if arch=="ac" else eeprom_dst_name
print(f" Installing: eeprom -> Build/{eeprom_dst_name}") print(f" Installing: eeprom -> Build/{eeprom_dst_name}")
shutil.copy2(eeprom, BUILD_ROOT / eeprom_dst_name) shutil.copy2(eeprom, BUILD_ROOT / eeprom_dst_name)
@@ -236,7 +239,7 @@ def inject_makeusers(users, arch):
def main(): def main():
parser = argparse.ArgumentParser(description="HyperionOS build script") parser = argparse.ArgumentParser(description="HyperionOS build script")
parser.add_argument("target", choices=["build", "build-mini", "build-micro", "build-test", "build-mini-test", "build-micro-test", "clean", "prod", "prod-mini"]) parser.add_argument("target", choices=["build", "build-mini", "build-micro", "build-test", "build-mini-test", "build-micro-test", "clean", "prod", "prod-mini"])
parser.add_argument("--arch", choices=["cct", "oc"], default=None, parser.add_argument("--arch", choices=["cct", "oc", "ac"], default=None,
help="Target architecture") help="Target architecture")
parser.add_argument("--release", dest="release", action="store_true", default=True, parser.add_argument("--release", dest="release", action="store_true", default=True,
help="Release build: eeprom placed as startup.lua (default)") help="Release build: eeprom placed as startup.lua (default)")
+4
View File
@@ -0,0 +1,4 @@
# Hyperion-OS Docs
>These docs are a WIP take them as you will
+1
View File
@@ -11,4 +11,5 @@ sleep(ms)
print(...) print(...)
printInline(...) printInline(...)
printf(fmt, ...) printf(fmt, ...)
userinput(fdin, helpstr, replacestr, fdout)
``` ```
+9
View File
@@ -32,4 +32,13 @@ showModLoad<bool>
tmpToDisk<bool> tmpToDisk<bool>
writes tmp to disk instead of ram writes tmp to disk instead of ram
logSymlinkTraverse<bool>
logs symlink traversal (can harm preformance)
moreLogsaves<bool>
enables log debug save points (can harm preformance)
logPathResolution<bool>
logs how a vfs path resolves to a disk path (can harm preformance)
``` ```
+4 -675
View File
@@ -1,680 +1,9 @@
--- @version 1.2.3 --#region userspace
--- @diagnostic disable: missing-return
--- @diagnostic disable: duplicate-set-field
syscall={} syscall={}
--- @alias userinfo {username:string,homedir:string,shell:string,uid:number,gid:number}
--- Sets home directory of User with corresponding uid to homedir --#endregion userspace
--- @param uid integer
--- @param homedir string
--- @return true|nil, nil|string
syscall.sethomedir=function(uid, homedir) end
--- Reads amount from fd and returns content or nil --#region kernel
--- @param fd integer
--- @param amount? integer
--- @return string|nil
syscall.read=function(fd, amount) end
--- Gets information of task with id of pid --#endregion kernel
---@param pid integer
---@return table|nil
syscall.getTask=function(pid) end
--- Connects a client socket to a server address
---@param fd integer
---@param address string
---@return boolean, string|nil
syscall.connect=function(fd, address) end
--- Get current working directory
--- @return string
syscall.getcwd=function() end
--- Detach loop device (must be unmounted first)
--- @param id string
--- @return boolean, string|nil
syscall.lodetach=function(id) end
--- Stops task with id of pid
--- @param pid integer
--- @return boolean, string|nil
syscall.stop=function(pid) return true end
--- Receive bytes from socket (blocking poll, returns "" if no data)
--- @param fd integer
--- @param amount integer
--- @return string
syscall.recv=function(fd, amount) end
--- Write data to file descriptor
--- @param fd integer
--- @param data string
--- @return boolean, string|nil
syscall.write=function(fd, data) end
--- Get parent process ID
--- @return integer
syscall.getppid=function() end
--- Get file information (metadata)
--- @param path string
--- @return table|nil
syscall.lstat=function(path) end
--- Open a file with mode ("r", "w", etc.)
--- @param path string
--- @param mode string
--- @return integer|nil, string|nil
syscall.open=function(path, mode) end
--- Seek in a file descriptor
--- @param fd integer
--- @param offset integer
--- @param whence integer
--- @return integer|nil
syscall.lseek=function(fd, offset, whence) end
--- Set system hostname
--- @param hostname string
--- @return boolean
syscall.setHostname=function(hostname) end
--- Change root directory
--- @param path string
--- @return boolean, string|nil
syscall.chroot=function(path) end
--- Duplicate file descriptor
--- @param src integer
--- @param dst integer
--- @return integer|nil, string|nil
syscall.dup2=function(src, dst) end
--- Get current process ID
--- @return integer
syscall.getpid=function() end
--- Change ownership of a file descriptor
--- @param fd integer
--- @param uid integer
--- @param gid integer
--- @return boolean, string|nil
syscall.fchown=function(fd, uid, gid) end
--- Close a file descriptor
--- @param fd integer
--- @return boolean, string|nil
syscall.close=function(fd) end
--- Unmount a target
--- @param target string
--- @return boolean, string|nil
syscall.umount=function(target) end
--- Get all task IDs
--- @return integer[]
syscall.getTasks=function() end
--- Dump all syscalls for debugging
--- @return table
syscall.sysdump=function() end
--- Change permissions of a file descriptor
--- @param fd integer
--- @param perms integer
--- @return boolean, string|nil
syscall.fchmod=function(fd, perms) end
--- Get system hostname
--- @return string
syscall.getHostname=function() end
--- Listen for incoming connections
--- @param fd integer
--- @param backlog integer
--- @return boolean, string|nil
syscall.listen=function(fd, backlog) end
--- Duplicate a file descriptor
--- @param fd integer
--- @return integer|nil
syscall.dup=function(fd) end
--- Read GPIO pin
--- @param pin integer
--- @return boolean|nil
syscall.gpio_read=function(pin) end
--- Read GPIO pin analog
--- @param pin integer
--- @return number|nil
syscall.gpio_readAnalog=function(pin) end
--- Get SUID bit from fd
--- @param fd integer
--- @return boolean
syscall.fget_suid=function(fd) end
--- Write GPIO pin
--- @param pin integer
--- @param data boolean
syscall.gpio_write=function(pin, data) end
--- Write GPIO pin analog
--- @param pin integer
--- @param data number
syscall.gpio_writeAnalog=function(pin, data) end
--- Set password for user
--- @param uid integer
--- @param newPassword string
--- @return boolean, string|nil
syscall.setpassword=function(uid, newPassword) end
--- Set environment variable
--- @param key string
--- @param value any
--- @return boolean
syscall.setEnviron=function(key, value) end
--- Setup a loop device with filePath
--- @param filePath string
--- @param forceImage boolean
--- @return string|nil, string|nil
syscall.losetup=function(filePath, forceImage) end
--- Reboot the system
syscall.reboot=function() end
--- Get current user ID
--- @return integer
syscall.getuid=function() end
--- Send signal to task
--- @param pid integer
--- @param sigid integer|string
--- @return boolean, string|nil
syscall.sigsend=function(pid, sigid) end
--- Sleep current task for time seconds
--- @param time number
syscall.sleep=function(time) end
--- Exit current task
--- @param code integer|nil
syscall.exit=function(code) end
--- Get environment variable
--- @param key string
--- @return any
syscall.getEnviron=function(key) end
--- Continue a stopped task
--- @param pid integer
--- @return boolean, string|nil
syscall.continue=function(pid) end
--- Create a socket
--- @param domain integer
--- @param socktype integer
--- @return integer|nil
syscall.socket=function(domain, socktype) end
--- Log a message
--- @param text string
--- @param tag string
--- @param color integer
syscall.log=function(text, tag, color) end
--- Write an image to disk
--- @param imgStr string
--- @param destPath string
--- @return boolean, string|nil
syscall.loimgwrite=function(imgStr, destPath) end
--- Check if file exists
--- @param path string
--- @return boolean
syscall.exists=function(path) end
--- Set user ID of current task
--- @param uid integer
--- @return boolean, string|nil
syscall.setuid=function(uid) end
--- Replace current task with executable
--- @param path string
--- @param args? table
--- @param envars? table
syscall.exec=function(path, args, envars) end
--- Spawn a new task from executable
--- @param path string
--- @param name? string
--- @param envars? table
--- @param args? table
--- @param tgid? integer
--- @return integer
syscall.execspawn=function(path, name, envars, args, tgid) end
--- Create image from file
--- @param srcPath string
--- @return string|nil
syscall.loimgcreate=function(srcPath) end
--- Get system time in ms
--- @return number
syscall.time=function() end
--- Create a new user
--- @param username string
--- @param password string
--- @param gid integer
--- @param homedir string
--- @param shell string
--- @return integer|nil
syscall.newuser=function(username, password, gid, homedir, shell) end
--- Spawn a new task from function
--- @param func function
--- @param name? string
--- @param envars? table
--- @param args? table
--- @param tgid? integer
--- @return integer
syscall.spawn=function(func, name, envars, args, tgid) end
--- Collect exit code of a dead child task
--- @param pid integer
--- @return boolean, integer|string
syscall.collect=function(pid) end
--- Set shell of user
--- @param uid integer
--- @param shell string
--- @return boolean
syscall.setshell=function(uid, shell) end
--- Device control
--- @param fd integer
--- @param funcname string
--- @param ... any
--- @return any
syscall.devctl=function(fd, funcname, ...) end
--- List all users
--- @return table
syscall.listusers=function() end
--- Unlock a user account
--- @param uid integer
--- @return boolean
syscall.unlockuser=function(uid) end
--- Mount a disk or loop device
--- @param target string
--- @param diskOrId string
--- @return boolean, string|nil
syscall.mount=function(target, diskOrId) end
--- Accept a client connection on a socket
--- @param fd integer
--- @return integer|nil
syscall.accept=function(fd) end
--- List loop devices
--- @return table
syscall.lolist=function() end
--- Read a symbolic link
--- @param path string
--- @return string|nil
syscall.readlink=function(path) end
--- Delete a user
--- @param uid integer
--- @return boolean
syscall.deleteuser=function(uid) end
--- Remove a file
--- @param path string
--- @return boolean, string|nil
syscall.remove=function(path) end
--- Get type of a path (file, dir, link)
--- @param path string
--- @return string|nil
syscall.type=function(path) end
--- Elevate to root with password (Disabled due to VULN)
--- @param targetUsername string
--- @param password string
--- @return boolean
syscall.elevate=function(targetUsername, password) end
--- Make a directory
--- @param path string
--- @return boolean, string|nil
syscall.mkdir=function(path) end
--- Get UID by username
--- @param username string
--- @return integer|nil
syscall.getuidbyname=function(username) end
--- Get current user name
--- @return string
syscall.whoami=function() end
--- Send file content
--- @param src string
--- @param dest string
--- @param amount integer
--- @return boolean, string|nil
syscall.sendfile=function(src, dest, amount) end
--- Change username of user
--- @param uid integer
--- @param newUsername string
--- @return boolean
syscall.setusername=function(uid, newUsername) end
--- Get effective UID
--- @return integer
syscall.geteuid=function() end
--- Login as user
--- @param uid integer
--- @param password string
--- @return boolean
syscall.login=function(uid, password) end
--- Get system hostname
--- @return string
syscall.getHost=function() end
--- Get system uptime in ms
--- @return number
syscall.getUptime=function() end
--- HTTP GET request
--- @param url string
--- @param headers table|nil
--- @return string|nil
syscall.httpget=function(url, headers) end
--- Get file metadata
--- @param path string
--- @return table|nil
syscall.stat=function(path) end
--- Create symbolic link
--- @param target string
--- @param linkPath string
--- @return boolean, string|nil
syscall.symlink=function(target, linkPath) end
--- Read from fd at offset
--- @param fd integer
--- @param count integer
--- @param offset integer
--- @return string|nil
syscall.pread=function(fd, count, offset) end
--- Change current working directory
--- @param path string
--- @return boolean, string|nil
syscall.chdir=function(path) end
--- Get system architecture
--- @return string
syscall.arch=function() end
--- Write to fd at offset
--- @param fd integer
--- @param data string
--- @param offset integer
--- @return boolean, string|nil
syscall.pwrite=function(fd, data, offset) end
--- Shutdown socket
--- @param fd integer
--- @return boolean, string|nil
syscall.sockshutdown=function(fd) end
--- Resolve hostname to IP
--- @param hostname string
--- @return string|nil
syscall.resolve=function(hostname) end
--- Send data over socket
--- @param fd integer
--- @param data string
--- @return boolean, string|nil
syscall.send=function(fd, data) end
--- Get file descriptor info
--- @param fd integer
--- @return table|nil
syscall.fstat=function(fd) end
--- Change ownership of path
--- @param path string
--- @param uid integer
--- @param gid integer
--- @return boolean, string|nil
syscall.chown=function(path, uid, gid) end
--- Flush file descriptor
--- @param fd integer
--- @return boolean, string|nil
syscall.fsync=function(fd) end
--- Lock user account
--- @param uid integer
--- @return boolean
syscall.lockuser=function(uid) end
--- Get username by UID
--- @param uid integer
--- @return string|nil
syscall.getUsername=function(uid) end
--- Get socket name
--- @param fd integer
--- @return string|nil
syscall.getsockname=function(fd) end
--- Bind socket to address
--- @param fd integer
--- @param address string
--- @return boolean, string|nil
syscall.bind=function(fd, address) end
--- Kill a task
--- @param pid integer
--- @return boolean, string|nil
syscall.kill=function(pid) end
--- Set GID for user
--- @param uid integer
--- @param gid integer
--- @return boolean
syscall.setgid=function(uid, gid) end
--- Get peer name of socket
--- @param fd integer
--- @return string|nil
syscall.getpeername=function(fd) end
--- Set signal handler
--- @param handler function
syscall.sigcatch=function(handler) end
--- Shutdown the system
syscall.shutdown=function() end
--- Check file access mode
--- @param path string
--- @param mode string
--- @return boolean
syscall.access=function(path, mode) end
--- Ignore current signal
syscall.sigignore=function() end
--- Get user information
--- @param uid integer
--- @return userinfo|nil
syscall.getpasswd=function(uid) end
--- Get OS version
--- @return string
syscall.version=function() end
--- Change file permissions
--- @param path string
--- @param perms integer
--- @return boolean
syscall.chmod=function(path, perms) end
--- List directory contents
--- @param path string
--- @return table
syscall.listdir=function(path) end
----------------------------------------------
--- STDLib manifest
----------------------------------------------
--- Gets the index of value or -1
--- @param tabl table
--- @param value string|integer
--- @return integer
table.indexOf=function(tabl, value) end
-- Returns true if tabl has key else false
--- @param tabl table
--- @param query string
--- @return boolean
table.hasKey=function(tabl, query) end
--- Returns true if tabl has value else false
--- @param tabl table
--- @param query any
--- @return boolean
table.hasVal=function(tabl, query) end
--- Creates a deepcopy of tabl
--- @param tabl table
--- @return table
table.deepcopy=function(tabl) end
--- Returns the keys of tabl
--- @param tabl table
--- @return table
table.keys=function(tabl) end
--- Returns the values of tabl
--- @param tabl table
--- @return table
table.values=function(tabl) end
--- Returns a serialized version of tabl
--- @param tabl table
--- @return string
table.serialize=function(tabl) end
--- Returns a merged table with a and b
--- @param ... table
--- @return table
table.merge=function(...) end
--- Gets prefix of string with suffix
--- @param str string
--- @param suffix string
--- @return string
string.getPrefix=function(str, suffix) end
--- Gets suffix of string with prefix
--- @param str string
--- @param prefix string
--- @return string
string.getSuffix=function(str, prefix) end
--- Returns if sting has prefix
--- @param str string
--- @param prefix string
--- @return boolean
string.hasPrefix=function(str, prefix) end
--- Returns if sting has suffix
--- @param str string
--- @param suffix string
--- @return boolean
string.hasSuffix=function(str, suffix) end
--- Joins all args
--- @param str string
--- @param ... string
--- @return string
string.join=function(str, ...) end
--- Joins all strings with delim
--- @param delim string
--- @param ... string
--- @return string
string.delim=function(delim, ...) end
--- Splits a string by delim
--- @param str string
--- @param delim string
--- @return table
string.split=function(str, delim) end
--- Replaces all instances of target with repl
--- @param str string
--- @param target string
--- @param repl string
--- @return string
string.replace=function(str, target, repl) end
--- Converts a number to hex
--- @param num integer
--- @return string
toHex=function(num) end
--- Returns if obj is equal to all in ...
--- @param obj any
--- @param ... any
--- @return boolean
isEqualToAll=function(obj, ...) end
--- Returns if obj is equal to any in ...
--- @param obj any
--- @param ... any
--- @return boolean
isEqualToAny=function(obj, ...) end
--- Prints text to stdout
--- @param ... any
print=function(...) end
--- Prints text to stdout but with no trailing newline
--- @param ... any
printInline=function(...) end
--- Prints text to stdout with format
--- @param fmt string
--- @param ... any
printf=function(fmt, ...) end
--- Gets input from fd
--- @param fd integer
--- @param helpstr string
--- @param replacechar string
--- @param fdo integer
userinput=function(fd, helpstr, replacechar, fdo) end
-388
View File
@@ -1,388 +0,0 @@
--:Minify:--
-- json.lua
--
-- Copyright (c) 2020 rxi
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy of
-- this software and associated documentation files (the "Software"), to deal in
-- the Software without restriction, including without limitation the rights to
-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-- of the Software, and to permit persons to whom the Software is furnished to do
-- so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in all
-- copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
--
local json = { _version = "0.1.2" }
-------------------------------------------------------------------------------
-- Encode
-------------------------------------------------------------------------------
local encode
local escape_char_map = {
[ "\\" ] = "\\",
[ "\"" ] = "\"",
[ "\b" ] = "b",
[ "\f" ] = "f",
[ "\n" ] = "n",
[ "\r" ] = "r",
[ "\t" ] = "t",
}
local escape_char_map_inv = { [ "/" ] = "/" }
for k, v in pairs(escape_char_map) do
escape_char_map_inv[v] = k
end
local function escape_char(c)
return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte()))
end
local function encode_nil(val)
return "null"
end
local function encode_table(val, stack)
local res = {}
stack = stack or {}
-- Circular reference?
if stack[val] then error("circular reference") end
stack[val] = true
if rawget(val, 1) ~= nil or next(val) == nil then
-- Treat as array -- check keys are valid and it is not sparse
local n = 0
for k in pairs(val) do
if type(k) ~= "number" then
error("invalid table: mixed or invalid key types")
end
n = n + 1
end
if n ~= #val then
error("invalid table: sparse array")
end
-- Encode
for i, v in ipairs(val) do
table.insert(res, encode(v, stack))
end
stack[val] = nil
return "[" .. table.concat(res, ",") .. "]"
else
-- Treat as an object
for k, v in pairs(val) do
if type(k) ~= "string" then
error("invalid table: mixed or invalid key types")
end
table.insert(res, encode(k, stack) .. ":" .. encode(v, stack))
end
stack[val] = nil
return "{" .. table.concat(res, ",") .. "}"
end
end
local function encode_string(val)
return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"'
end
local function encode_number(val)
-- Check for NaN, -inf and inf
if val ~= val or val <= -math.huge or val >= math.huge then
error("unexpected number value '" .. tostring(val) .. "'")
end
return string.format("%.14g", val)
end
local type_func_map = {
[ "nil" ] = encode_nil,
[ "table" ] = encode_table,
[ "string" ] = encode_string,
[ "number" ] = encode_number,
[ "boolean" ] = tostring,
}
encode = function(val, stack)
local t = type(val)
local f = type_func_map[t]
if f then
return f(val, stack)
end
error("unexpected type '" .. t .. "'")
end
function json.encode(val)
return ( encode(val) )
end
-------------------------------------------------------------------------------
-- Decode
-------------------------------------------------------------------------------
local parse
local function create_set(...)
local res = {}
for i = 1, select("#", ...) do
res[ select(i, ...) ] = true
end
return res
end
local space_chars = create_set(" ", "\t", "\r", "\n")
local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",")
local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u")
local literals = create_set("true", "false", "null")
local literal_map = {
[ "true" ] = true,
[ "false" ] = false,
[ "null" ] = nil,
}
local function next_char(str, idx, set, negate)
for i = idx, #str do
if set[str:sub(i, i)] ~= negate then
return i
end
end
return #str + 1
end
local function decode_error(str, idx, msg)
local line_count = 1
local col_count = 1
for i = 1, idx - 1 do
col_count = col_count + 1
if str:sub(i, i) == "\n" then
line_count = line_count + 1
col_count = 1
end
end
error( string.format("%s at line %d col %d", msg, line_count, col_count) )
end
local function codepoint_to_utf8(n)
-- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa
local f = math.floor
if n <= 0x7f then
return string.char(n)
elseif n <= 0x7ff then
return string.char(f(n / 64) + 192, n % 64 + 128)
elseif n <= 0xffff then
return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128)
elseif n <= 0x10ffff then
return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128,
f(n % 4096 / 64) + 128, n % 64 + 128)
end
error( string.format("invalid unicode codepoint '%x'", n) )
end
local function parse_unicode_escape(s)
local n1 = tonumber( s:sub(1, 4), 16 )
local n2 = tonumber( s:sub(7, 10), 16 )
-- Surrogate pair?
if n2 then
return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000)
else
return codepoint_to_utf8(n1)
end
end
local function parse_string(str, i)
local res = ""
local j = i + 1
local k = j
while j <= #str do
local x = str:byte(j)
if x < 32 then
decode_error(str, j, "control character in string")
elseif x == 92 then -- `\`: Escape
res = res .. str:sub(k, j - 1)
j = j + 1
local c = str:sub(j, j)
if c == "u" then
local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1)
or str:match("^%x%x%x%x", j + 1)
or decode_error(str, j - 1, "invalid unicode escape in string")
res = res .. parse_unicode_escape(hex)
j = j + #hex
else
if not escape_chars[c] then
decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string")
end
res = res .. escape_char_map_inv[c]
end
k = j + 1
elseif x == 34 then -- `"`: End of string
res = res .. str:sub(k, j - 1)
return res, j + 1
end
j = j + 1
end
decode_error(str, i, "expected closing quote for string")
end
local function parse_number(str, i)
local x = next_char(str, i, delim_chars)
local s = str:sub(i, x - 1)
local n = tonumber(s)
if not n then
decode_error(str, i, "invalid number '" .. s .. "'")
end
return n, x
end
local function parse_literal(str, i)
local x = next_char(str, i, delim_chars)
local word = str:sub(i, x - 1)
if not literals[word] then
decode_error(str, i, "invalid literal '" .. word .. "'")
end
return literal_map[word], x
end
local function parse_array(str, i)
local res = {}
local n = 1
i = i + 1
while 1 do
local x
i = next_char(str, i, space_chars, true)
-- Empty / end of array?
if str:sub(i, i) == "]" then
i = i + 1
break
end
-- Read token
x, i = parse(str, i)
res[n] = x
n = n + 1
-- Next token
i = next_char(str, i, space_chars, true)
local chr = str:sub(i, i)
i = i + 1
if chr == "]" then break end
if chr ~= "," then decode_error(str, i, "expected ']' or ','") end
end
return res, i
end
local function parse_object(str, i)
local res = {}
i = i + 1
while 1 do
local key, val
i = next_char(str, i, space_chars, true)
-- Empty / end of object?
if str:sub(i, i) == "}" then
i = i + 1
break
end
-- Read key
if str:sub(i, i) ~= '"' then
decode_error(str, i, "expected string for key")
end
key, i = parse(str, i)
-- Read ':' delimiter
i = next_char(str, i, space_chars, true)
if str:sub(i, i) ~= ":" then
decode_error(str, i, "expected ':' after key")
end
i = next_char(str, i + 1, space_chars, true)
-- Read value
val, i = parse(str, i)
-- Set
res[key] = val
-- Next token
i = next_char(str, i, space_chars, true)
local chr = str:sub(i, i)
i = i + 1
if chr == "}" then break end
if chr ~= "," then decode_error(str, i, "expected '}' or ','") end
end
return res, i
end
local char_func_map = {
[ '"' ] = parse_string,
[ "0" ] = parse_number,
[ "1" ] = parse_number,
[ "2" ] = parse_number,
[ "3" ] = parse_number,
[ "4" ] = parse_number,
[ "5" ] = parse_number,
[ "6" ] = parse_number,
[ "7" ] = parse_number,
[ "8" ] = parse_number,
[ "9" ] = parse_number,
[ "-" ] = parse_number,
[ "t" ] = parse_literal,
[ "f" ] = parse_literal,
[ "n" ] = parse_literal,
[ "[" ] = parse_array,
[ "{" ] = parse_object,
}
parse = function(str, idx)
local chr = str:sub(idx, idx)
local f = char_func_map[chr]
if f then
return f(str, idx)
end
decode_error(str, idx, "unexpected character '" .. chr .. "'")
end
function json.decode(str)
if type(str) ~= "string" then
error("expected argument of type string, got " .. type(str))
end
local res, idx = parse(str, next_char(str, 1, space_chars, true))
idx = next_char(str, idx, space_chars, true)
if idx <= #str then
decode_error(str, idx, "trailing garbage")
end
return res
end
return json
-55
View File
@@ -1,55 +0,0 @@
local cloptions = {
a = false,
h = false,
l = false,
help = false,
}
local inpArgs = { ... }
local args = {}
for _, v in pairs(inpArgs) do
if v:sub(1, 2) == "--" then
local opt = v:sub(3)
if cloptions[opt] == nil then
print("spm: unrecognized option '" .. v .. "'.")
print("try 'spm --help' for more information.")
return
end
cloptions[opt] = true
elseif v:sub(1, 1) == "-" then
for i = 2, #v do
local opt = v:sub(i, i)
if cloptions[opt] == nil then
print("spm: invalid option '-" .. opt .. "'.")
print("try 'spm --help' for more information.")
return
end
cloptions[opt] = true
end
else
table.insert(args, v)
end
end
local http=http or require("http")
local json=json or require("json")
local xz =xz or require("xz")
if cloptions.help then
print("Usage: spm [COMMAND] [OPTION] [packages]")
print("The Simple package Mannager.")
print("")
print("Commands:")
print(" remove Remove package(s)")
print(" update Updates package(s)")
print(" install Install package(s)")
print(" sync Syncs local registry with servers")
print("")
print("Options:")
print(" --help display this help and exit")
return
end
local function getustar()
end
-1973
View File
File diff suppressed because it is too large. Load diff