@@ -1,171 +0,0 @@ | |||
buffer = {} | |||
local metatable = { | |||
__index = buffer, | |||
__metatable = "file", | |||
__close = buffer.close | |||
} | |||
function buffer.new(mode, stream) | |||
local result = { | |||
closed = false, | |||
tty = false, | |||
mode = {}, | |||
stream = stream, | |||
bufferRead = "", | |||
bufferWrite = "", | |||
bufferSize = math.max(512, math.min(8 * 1024, computer.freeMemory() / 8)), | |||
bufferMode = "full", | |||
readTimeout = math.huge, | |||
} | |||
mode = mode or "r" | |||
for i = 1, mode:len() do | |||
result.mode[mode:sub(i, i)] = true | |||
end | |||
-- when stream closes, result should close first | |||
-- when result closes, stream should close after | |||
-- when stream closes, it is removed from the proc | |||
stream.close = setmetatable({close = stream.close,parent = result},{__call = buffer.close}) | |||
return setmetatable(result, metatable) | |||
end | |||
function buffer:close() | |||
-- self is either the buffer, or the stream.close callable | |||
local meta = getmetatable(self) | |||
if meta == metatable.__metatable then | |||
return self.stream:close() | |||
end | |||
local parent = self.parent | |||
if parent.mode.w or parent.mode.a then | |||
parent:flush() | |||
end | |||
parent.closed = true | |||
return self.close(parent.stream) | |||
end | |||
function buffer:flush() | |||
if #self.bufferWrite > 0 then | |||
local tmp = self.bufferWrite | |||
self.bufferWrite = "" | |||
local result, reason = self.stream:write(tmp) | |||
if not result then | |||
return nil, reason or "bad file descriptor" | |||
end | |||
end | |||
return self | |||
end | |||
function buffer:lines(...) | |||
local args = table.pack(...) | |||
return function() | |||
local result = table.pack(self:read(table.unpack(args, 1, args.n))) | |||
if not result[1] and result[2] then | |||
error(result[2]) | |||
end | |||
return table.unpack(result, 1, result.n) | |||
end | |||
end | |||
local function readChunk(self) | |||
if computer.uptime() > self.timeout then | |||
error("timeout") | |||
end | |||
local result, reason = self.stream:read(math.max(1,self.bufferSize)) | |||
if result then | |||
self.bufferRead = self.bufferRead .. result | |||
return self | |||
else -- error or eof | |||
return result, reason | |||
end | |||
end | |||
function buffer:readLine(chop, timeout) | |||
self.timeout = timeout or (computer.uptime() + self.readTimeout) | |||
local start = 1 | |||
while true do | |||
local buf = self.bufferRead | |||
local i = buf:find("[\r\n]", start) | |||
local c = i and buf:sub(i,i) | |||
local is_cr = c == "\r" | |||
if i and (not is_cr or i < #buf) then | |||
local n = buf:sub(i+1,i+1) | |||
if is_cr and n == "\n" then | |||
c = c .. n | |||
end | |||
local result = buf:sub(1, i - 1) .. (chop and "" or c) | |||
self.bufferRead = buf:sub(i + #c) | |||
return result | |||
else | |||
start = #self.bufferRead - (is_cr and 1 or 0) | |||
local result, reason = readChunk(self) | |||
if not result then | |||
if reason then | |||
return result, reason | |||
else -- eof | |||
result = #self.bufferRead > 0 and self.bufferRead or nil | |||
self.bufferRead = "" | |||
return result | |||
end | |||
end | |||
end | |||
coroutine.yield() | |||
end | |||
end | |||
function buffer:read(...) | |||
if not self.mode.r then | |||
return nil, "read mode was not enabled for this stream" | |||
end | |||
if self.mode.w or self.mode.a then | |||
self:flush() | |||
end | |||
if select("#", ...) == 0 then | |||
return self:readLine(true) | |||
end | |||
return self:formatted_read(readChunk, ...) | |||
end | |||
function buffer:setvbuf(mode, size) | |||
mode = mode or self.bufferMode | |||
size = size or self.bufferSize | |||
assert(mode == "no" or mode == "full" or mode == "line", | |||
"bad argument #1 (no, full or line expected, got " .. tostring(mode) .. ")") | |||
assert(mode == "no" or type(size) == "number", | |||
"bad argument #2 (number expected, got " .. type(size) .. ")") | |||
self.bufferMode = mode | |||
self.bufferSize = size | |||
return self.bufferMode, self.bufferSize | |||
end | |||
function buffer:write(...) | |||
if self.closed then | |||
return nil, "bad file descriptor" | |||
end | |||
if not self.mode.w and not self.mode.a then | |||
return nil, "write mode was not enabled for this stream" | |||
end | |||
local args = table.pack(...) | |||
for i = 1, args.n do | |||
if type(args[i]) == "number" then | |||
args[i] = tostring(args[i]) | |||
end | |||
checkArg(i, args[i], "string") | |||
end | |||
for i = 1, args.n do | |||
local arg = args[i] | |||
local result, reason | |||
result, reason = self.stream:write(arg) | |||
if not result then | |||
return nil, reason | |||
end | |||
end | |||
return self | |||
end |
@@ -0,0 +1,7 @@ | |||
if component.list("chat_box")() then | |||
function dprint(...) | |||
for k,v in pairs({...}) do | |||
component.invoke(component.list("chat_box")(),"say",v) | |||
end | |||
end | |||
end |
@@ -1,12 +1,12 @@ | |||
--#include "module/chatbox-dprint.lua" | |||
--#include "module/syslog.lua" | |||
--#include "module/sched.lua" | |||
--#include "module/buffer.lua" | |||
--#include "module/fs.lua" | |||
--#include "module/io.lua" | |||
--#include "module/newio.lua" | |||
--#include "module/devfs.lua" | |||
--#include "module/devfs/syslog.lua" | |||
--#include "module/vt-task.lua" | |||
--#include "module/loadfile.lua" | |||
--#include "module/term.lua" | |||
os.spawnfile("/boot/exec/init.lua","init") | |||
os.spawnfile("/boot/exec/init.lua") | |||
os.sched() |
@@ -1,116 +0,0 @@ | |||
do | |||
io = {} | |||
function io.close(file) | |||
return (file or io.output()):close() | |||
end | |||
function io.flush() | |||
return io.output():flush() | |||
end | |||
function io.lines(filename, ...) | |||
if filename then | |||
local file, reason = io.open(filename) | |||
if not file then | |||
error(reason, 2) | |||
end | |||
local args = table.pack(...) | |||
return function() | |||
local result = table.pack(file:read(table.unpack(args, 1, args.n))) | |||
if not result[1] then | |||
if result[2] then | |||
error(result[2], 2) | |||
else -- eof | |||
file:close() | |||
return nil | |||
end | |||
end | |||
return table.unpack(result, 1, result.n) | |||
end | |||
else | |||
return io.input():lines() | |||
end | |||
end | |||
function io.open(path, mode) | |||
local stream, result = fs.open(path, mode) | |||
if stream then | |||
return buffer.new(mode, stream) | |||
else | |||
return nil, result | |||
end | |||
end | |||
local fdt = {[0]="STDIN","STDOUT","STDERR"} | |||
local function getfh(fd) | |||
return os.getenv(fdt[fd] or "FILE"..tostring(fd)) | |||
end | |||
local function setfh(fd,fh) | |||
os.setenv(fdt[fd] or "FILE"..tostring(fd),fh) | |||
end | |||
function io.stream(fd,file,mode) | |||
checkArg(1,fd,'number') | |||
assert(fd>=0,'fd must be >= 0. 0 is input, 1 is stdout, 2 is stderr') | |||
if file then | |||
if type(file) == "string" then | |||
local result, reason = io.open(file, mode) | |||
if not result then | |||
error(reason, 2) | |||
end | |||
file = result | |||
elseif not io.type(file) then | |||
error("bad argument #1 (string or file expected, got " .. type(file) .. ")", 2) | |||
end | |||
setfh(fd,file) | |||
end | |||
return getfh(fd) | |||
end | |||
function io.input(file) | |||
return io.stream(0, file, 'r') | |||
end | |||
function io.output(file) | |||
return io.stream(1, file,'w') | |||
end | |||
function io.error(file) | |||
return io.stream(2, file,'w') | |||
end | |||
function io.read(...) | |||
return io.input():read(...) | |||
end | |||
function io.tmpfile() | |||
local name = os.tmpname() | |||
if name then | |||
return io.open(name, "a") | |||
end | |||
end | |||
function io.type(object) | |||
if type(object) == "table" then | |||
if getmetatable(object) == "file" then | |||
if object.stream.handle then | |||
return "file" | |||
else | |||
return "closed file" | |||
end | |||
end | |||
end | |||
return nil | |||
end | |||
function io.write(...) | |||
return io.output():write(...) | |||
end | |||
function print(...) | |||
for k,v in ipairs({...}) do | |||
io.write(tostring(v).."\n") | |||
end | |||
end | |||
end |
@@ -8,7 +8,8 @@ function runfile(p,...) -- runs file *p* with arbitrary arguments in the current | |||
return loadfile(p)(...) | |||
end | |||
function os.spawnfile(p,n) -- spawns a new process from file *p* with name *n* | |||
return os.spawn(function() xpcall(loadfile(p),function(e) dprint(e.."\n"..debug.traceback) end) end,n) | |||
dprint(p,n) | |||
return os.spawn(function() xpcall(loadfile(p),function(e) dprint(e.."\n"..debug.traceback()) end) end,n or p) | |||
end | |||
function require(f) -- searches for a library with name *f* and returns what the library returns, if possible | |||
local lib = os.getenv("LIB") or "/boot/lib" | |||
@@ -0,0 +1,34 @@ | |||
io = {} | |||
function io.input(fd) | |||
if type(fd) == "string" then | |||
fd=fs.open(fd,"rb") | |||
end | |||
if fd then | |||
os.setenv("STDIN",fd) | |||
end | |||
return os.getenv("STDIN") | |||
end | |||
function io.output(fd) | |||
if type(fd) == "string" then | |||
fd=fs.open(fd,"wb") | |||
end | |||
if fd then | |||
os.setenv("STDOUT",fd) | |||
end | |||
return os.getenv("STDOUT") | |||
end | |||
io.open = fs.open | |||
function io.read(...) | |||
return io.input():read() | |||
end | |||
function io.write(...) | |||
io.output():write(...) | |||
end | |||
function print(...) | |||
for k,v in ipairs({...}) do | |||
io.write(tostring(v).."\n") | |||
end | |||
end |
@@ -1,5 +1,5 @@ | |||
do | |||
local tTasks,nPid,nTimeout,cPid = {},1,0,0 -- table of tasks, next process ID, event timeout, current PID | |||
local tTasks,nPid,nTimeout,cPid = {},1,1,0 -- table of tasks, next process ID, event timeout, current PID | |||
function os.spawn(f,n) -- creates a process from function *f* with name *n* | |||
tTasks[nPid] = { | |||
c=coroutine.create(f), -- actual coroutine | |||
@@ -27,9 +27,12 @@ function vtemu(gpua,scra) | |||
end | |||
end)) end,string.format("ttyd[%s:%s]",gpua:sub(1,8),scra:sub(1,8))) | |||
local function bread() | |||
while not buf:find("\n") do | |||
coroutine.yield() | |||
end | |||
local n = buf:find("\n") | |||
if not n then return nil end | |||
r, buf = buf:sub(1,n), buf:sub(n+1) | |||
dprint("bread",r) | |||
return r | |||
end | |||
return bread, write, function() io.write("\27[2J\27[H") end | |||