@@ -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/syslog.lua" | ||||
--#include "module/sched.lua" | --#include "module/sched.lua" | ||||
--#include "module/buffer.lua" | |||||
--#include "module/fs.lua" | --#include "module/fs.lua" | ||||
--#include "module/io.lua" | |||||
--#include "module/newio.lua" | |||||
--#include "module/devfs.lua" | --#include "module/devfs.lua" | ||||
--#include "module/devfs/syslog.lua" | --#include "module/devfs/syslog.lua" | ||||
--#include "module/vt-task.lua" | |||||
--#include "module/loadfile.lua" | --#include "module/loadfile.lua" | ||||
--#include "module/term.lua" | |||||
os.spawnfile("/boot/exec/init.lua","init") | |||||
os.spawnfile("/boot/exec/init.lua") | |||||
os.sched() | 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)(...) | return loadfile(p)(...) | ||||
end | end | ||||
function os.spawnfile(p,n) -- spawns a new process from file *p* with name *n* | 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 | end | ||||
function require(f) -- searches for a library with name *f* and returns what the library returns, if possible | 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" | 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 | 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* | function os.spawn(f,n) -- creates a process from function *f* with name *n* | ||||
tTasks[nPid] = { | tTasks[nPid] = { | ||||
c=coroutine.create(f), -- actual coroutine | c=coroutine.create(f), -- actual coroutine | ||||
@@ -27,9 +27,12 @@ function vtemu(gpua,scra) | |||||
end | end | ||||
end)) end,string.format("ttyd[%s:%s]",gpua:sub(1,8),scra:sub(1,8))) | end)) end,string.format("ttyd[%s:%s]",gpua:sub(1,8),scra:sub(1,8))) | ||||
local function bread() | local function bread() | ||||
while not buf:find("\n") do | |||||
coroutine.yield() | |||||
end | |||||
local n = buf:find("\n") | local n = buf:find("\n") | ||||
if not n then return nil end | |||||
r, buf = buf:sub(1,n), buf:sub(n+1) | r, buf = buf:sub(1,n), buf:sub(n+1) | ||||
dprint("bread",r) | |||||
return r | return r | ||||
end | end | ||||
return bread, write, function() io.write("\27[2J\27[H") end | return bread, write, function() io.write("\27[2J\27[H") end | ||||