299 lines
6.9 KiB
Lua
299 lines
6.9 KiB
Lua
@[[if not svar.get("PRINT_DMESG_LEVEL") then
|
|
svar.set("PRINT_DMESG_LEVEL", "1")
|
|
end]]
|
|
|
|
---@module kio "Kernel I/O"
|
|
kio = {}
|
|
|
|
local _stream = {}
|
|
function _stream:read(amt)
|
|
local buf = ""
|
|
local lc = ""
|
|
if (amt == "*l") then -- Our line ending is \n
|
|
repeat
|
|
lc = self.proto.read(self.udat, 1)
|
|
if (lc ~= "\n") then
|
|
buf = buf .. (lc or "")
|
|
end
|
|
until not lc or lc == "" or lc == "\n"
|
|
return buf
|
|
--elseif (amt == "*n") then
|
|
|
|
elseif (amt == "*a") then
|
|
local pos = self:seek("cur", 0)
|
|
local send = self:seek("end", 0)
|
|
self:seek("set", pos)
|
|
amt = send - pos
|
|
end
|
|
return self.proto.read(self.udat, amt)
|
|
end
|
|
|
|
function _stream:write(data)
|
|
return self.proto.write(self.udat, data)
|
|
end
|
|
|
|
function _stream:seek(whence, amt)
|
|
if not amt then
|
|
amt = whence or 0
|
|
whence = "cur"
|
|
end
|
|
return self.proto.seek(self.udat, whence, amt)
|
|
end
|
|
|
|
function _stream:eof()
|
|
local pos = self:seek("cur", 0)
|
|
local send = self:seek("end", 0)
|
|
self:seek("set", pos)
|
|
return pos == send
|
|
end
|
|
|
|
function _stream:close()
|
|
return self.proto.close(self.udat)
|
|
end
|
|
|
|
function _stream:size()
|
|
local pos = self:seek("cur", 0)
|
|
local send = self:seek("end", 0)
|
|
self:seek("set", pos)
|
|
return send
|
|
end
|
|
|
|
function kio.create_stream(udat, proto)
|
|
return setmetatable({udat=udat, proto=proto}, {__index=_stream})
|
|
end
|
|
|
|
@[[local kio_errc = 0
|
|
function kio_err(name, rtn)]]
|
|
kio.errno["@[{name}]"] = @[{kio_errc}]
|
|
kio_errors[@[{kio_errc}]] = "@[{rtn}]"
|
|
@[[kio_errc = kio_errc + 1
|
|
end]]
|
|
|
|
kio.errno = {}
|
|
local kio_errors = {}
|
|
@[[
|
|
kio_err("FILE_NOT_FOUND", "not found")
|
|
kio_err("FILE_DIRECTORY", "file is a directory")
|
|
kio_err("DEV_TIMEOUT", "device timeout")
|
|
kio_err("IO_ERROR", "generic i/o error")
|
|
kio_err("UNSUPPORTED_OPERATION", "unsupported operation")
|
|
kio_err("NOT_ALLOWED", "not allowed")
|
|
kio_err("TOO_MANY_SYMLINKS", "too many symlinks")
|
|
kio_err("DEV_FULL", "device is full")
|
|
kio_err("DEV_READ_ONLY", "device is read only")
|
|
]]
|
|
|
|
kio.geterror = function(e)
|
|
return nil, kio_errors[e] or "generic error"
|
|
end
|
|
|
|
function kio.invoke(path, method, ...)
|
|
local dev, rpath = vfs.resolve(path)
|
|
return dev.dev[method](dev.dev, rpath, ...)
|
|
end
|
|
|
|
function kio.has_ads(path)
|
|
|
|
end
|
|
|
|
function kio.ads_exists(path, ads)
|
|
|
|
end
|
|
|
|
function kio.has_acl(path)
|
|
|
|
end
|
|
|
|
---@func calc_seek
|
|
---@arg whence string "Like io.seek's whence."
|
|
---@arg amt integer "The amount to seek."
|
|
---@arg size integer "The size of the stream."
|
|
---@arg pos integer "The current position."
|
|
---@return integer "The new position"
|
|
---@desc "This function calculates the new position for seeking."
|
|
function kio.calc_seek(whence, amt, size, pos)
|
|
if (whence == "cur") then
|
|
pos = pos + amt
|
|
elseif (whence == "end") then
|
|
pos = size + amt
|
|
elseif (whence == "set") then
|
|
pos = amt
|
|
end
|
|
if pos > size then
|
|
pos = size
|
|
elseif pos < 1 then
|
|
pos = 1
|
|
end
|
|
return pos
|
|
end
|
|
|
|
---@func filestream
|
|
---@arg path string "Path to the file"
|
|
---@arg mode string "File mode"
|
|
---@return stream "The stream for the file."
|
|
---@desc "This creates a stream from a file."
|
|
function kio.filestream(path, mode)
|
|
local dev, rpath = vfs.resolve(path)
|
|
local h = dev:open(rpath, mode)
|
|
local stat = dev:stat(rpath)
|
|
return kio.create_stream({dev=dev, hand=h, stat=stat}, {
|
|
read = function(self, amt)
|
|
return self.dev:read(self.hand, amt)
|
|
end,
|
|
seek = function(self, whence, amt)
|
|
local pos = self.dev:seek(self.hand, 0)
|
|
local npos = kio.calc_seek(whence, amt, self.stat.size, pos)
|
|
return self.dev:seek(self.hand, npos-pos)
|
|
end,
|
|
write = function(self, data)
|
|
return self.dev:write(self.hand, data)
|
|
end,
|
|
close = function(self)
|
|
return self.dev:close(self.hand)
|
|
end
|
|
})
|
|
end
|
|
|
|
---@func dir
|
|
---@arg udat table "The data to pass to to prototype"
|
|
---@arg proto function "The prototype function for the iterator"
|
|
---@return function "The iterator."
|
|
---@desc "Creates a directory iterator."
|
|
function kio.dir(udat, proto)
|
|
return function()
|
|
return proto(udat)
|
|
end
|
|
end
|
|
|
|
---@func memstream
|
|
---@arg str string "The string to create a stream of."
|
|
---@arg write boolean "If the stream should be writable or not."
|
|
---@return stream "The memory stream."
|
|
---@desc "Creates a memory stream."
|
|
---@note "stream:close() returns the string."
|
|
function kio.memstream(str, write)
|
|
return kio.create_stream({str=str, pos=1, write=write}, {
|
|
read = function(self, amt)
|
|
local dat = self.str:sub(self.pos, self.pos+amt-1)
|
|
self.pos = self.pos+#dat
|
|
return dat
|
|
end,
|
|
write = function(self, dat)
|
|
if (write) then
|
|
local startstr = self.str:sub(1, self.pos-1)
|
|
local endstr = self.str:sub(self.pos+#dat)
|
|
self.str = startstr..dat..endstr
|
|
self.pos = self.pos + #dat
|
|
end
|
|
end,
|
|
seek = function(self, whence, amt)
|
|
self.pos = kio.calc_seek(whence, amt, #self.str, self.pos)
|
|
return self.pos
|
|
end,
|
|
close = function(self)
|
|
return self.str
|
|
end
|
|
})
|
|
end
|
|
|
|
kio.loglevel = {
|
|
DEBUG = 0,
|
|
INFO = 1,
|
|
WARNING = 2,
|
|
ERROR = 3,
|
|
PANIC = 255
|
|
}
|
|
|
|
kio.levels = {
|
|
[0] = "DEBUG",
|
|
"INFO",
|
|
"WARNING",
|
|
"ERROR",
|
|
[255] = "PANIC"
|
|
}
|
|
|
|
---@func dprint
|
|
---@arg level integer "The log level"
|
|
---@arg status string "The message."
|
|
---@desc "This method logs to the kernel log and wherever else is set up to be printed to."
|
|
function kio.dprint(level, status)
|
|
local stack = {}
|
|
local lkexec = {}
|
|
local i = 0
|
|
while lkexec do
|
|
lkexec = debug.getinfo(i)
|
|
stack[#stack+1] = lkexec
|
|
end
|
|
local src = stack[#stack].source:sub(2)
|
|
local spart = vfs.parts(src)
|
|
local exec = spart[#spart]:match("^(.+)%.([^%.]+)$")
|
|
local message = string.format("[%.2f] [%s] [%s] %s", computer.uptime(), levels[level], exec, status)
|
|
dmesgs[#dmesgs+1] = {ut=computer.uptime,lvl=level,x=exec,st=status}
|
|
if (level < $[{PRINT_DMESG_LEVEL}]) then
|
|
sig.push {
|
|
type = "dprint",
|
|
msg = message
|
|
}
|
|
end
|
|
end
|
|
|
|
---@func dmesg
|
|
---@see kio.dprint
|
|
kio.dmesg = dprint
|
|
|
|
---@func panic
|
|
---@arg msg string "The error message to display."
|
|
function kio.panic(msg)
|
|
dmesg(255, "Kernel panic!")
|
|
end
|
|
|
|
---@func create_pipe
|
|
---@return stream "Pipe in"
|
|
---@return stream "Pipe out"
|
|
---@desc "Creates a pipe."
|
|
function kio.create_pipe()
|
|
local pipecore = kio.memstream()
|
|
local pipein = kio.create_stream({
|
|
dat = pipecore
|
|
}, {
|
|
read = function()
|
|
-- no
|
|
end,
|
|
seek = function()
|
|
-- no
|
|
end,
|
|
write = function(self, dat)
|
|
self.dat:seek("end", 0)
|
|
self.dat:write(dat)
|
|
end,
|
|
close = function()
|
|
-- *no*
|
|
end
|
|
})
|
|
local pipeout = kio.create_stream({
|
|
dat = pipecore,
|
|
pos = 1
|
|
}, {
|
|
read = function(self, amt)
|
|
self.dat:seek("set", self.pos)
|
|
local dat = self.dat:read()
|
|
self.pos = self.pos+#dat
|
|
return dat
|
|
end,
|
|
seek = function()end,
|
|
write = function()end,
|
|
close = function()end
|
|
})
|
|
return pipein, pipeout
|
|
end
|
|
|
|
---@func init
|
|
---@desc "Only called once. Sets up the kio library."
|
|
function kio.init()
|
|
---@func create_buffer
|
|
---@arg blocking boolean "True if read calls to a buffer that doesn't contain enough data block."
|
|
---@arg pid integer "This is set to the PID of the process which handles the buffers."
|
|
---@return table "The buffer for use anywhere."
|
|
kio.create_buffer = create_buffer
|
|
kio.init = false
|
|
end |