Files
LeonOS/data/computercraft/lua/rom/modules/main/rc/io.lua

232 lines
4.8 KiB
Lua
Raw Normal View History

-- rc.io
local expect = require("cc.expect").expect
local thread = require("rc.thread")
local colors = require("colors")
local term = require("term")
local fs = require("fs")
local rc = require("rc")
local io = {}
local _file = {}
function _file:read(...)
local args = table.pack(...)
local ret = {}
if args.n == 0 then
args[1] = "l"
args.n = 1
end
if not (self.handle.read and pcall(self.handle.read, 0)) then
return nil, "bad file descriptor"
end
if self.handle.flush then self.handle.flush() end
for i=1, args.n, 1 do
local format = args[i]
if format:sub(1,1) == "*" then
format = format:sub(2)
end
if format == "a" then
ret[#ret+1] = self.handle.readAll()
elseif format == "l" or format == "L" then
ret[#ret+1] = self.handle.readLine(format == "L")
elseif type(format) == "number" then
ret[#ret+1] = self.handle.read(format)
else
error("invalid format '"..format.."'", 2)
end
end
return table.unpack(ret, 1, args.n)
end
function _file:lines(...)
local formats = {...}
if #formats == 0 then
formats[1] = "l"
end
return function()
return self:read(table.unpack(formats))
end
end
function _file:write(...)
local args = table.pack(...)
if not (self.handle.write and pcall(self.handle.write, "")) then
return nil, "bad file descriptor"
end
for i=1, args.n, 1 do
self.handle.write(args[i])
end
return self
end
function _file:seek(whence, offset)
expect(1, whence, "string", "nil")
expect(2, offset, "number", "nil")
if self.handle.seek then
return self.handle.seek(whence, offset)
else
return nil, "bad file descriptor"
end
end
function _file:flush()
if self.handle.flush then self.handle.flush() end
return self
end
function _file:close()
self.closed = true
pcall(self.handle.close)
end
local function iofile(handle)
return setmetatable({handle = handle, closed = false}, {__index = _file})
end
local stdin_rbuf = ""
io.stdin = iofile {
read = function(n)
while #stdin_rbuf < n do
stdin_rbuf = stdin_rbuf .. term.read() .. "\n"
end
local ret = stdin_rbuf:sub(1, n)
stdin_rbuf = stdin_rbuf:sub(#ret+1)
return ret
end,
readLine = function(trail)
local nl = stdin_rbuf:find("\n")
if nl then
local ret = stdin_rbuf:sub(1, nl+1)
if not trail then ret = ret:sub(1, -2) end
stdin_rbuf = stdin_rbuf:sub(#ret+1)
return ret
else
return stdin_rbuf .. term.read() .. (trail and "\n" or "")
end
end
}
io.stdout = iofile {
write = rc.write
}
io.stderr = iofile {
write = function(text)
local old = term.getTextColor()
term.setTextColor(colors.red)
rc.write(text)
term.setTextColor(old)
end
}
function io.open(file, mode)
expect(1, file, "string")
expect(2, mode, "string", "nil")
mode = (mode or "r"):match("[rwa]") .. "b"
local handle, err = fs.open(file, mode)
if not handle then
return nil, err
end
return iofile(handle)
end
function io.input(file)
expect(1, file, "string", "table", "nil")
local vars = thread.vars()
if type(file) == "string" then file = assert(io.open(file, "r")) end
if file then vars.input = file end
return vars.input or io.stdin
end
function io.output(file)
expect(1, file, "string", "table", "nil")
local vars = thread.vars()
if type(file) == "string" then file = assert(io.open(file, "w")) end
if file then vars.output = file end
return vars.output or io.stdout
end
function io.read(...)
return io.input():read(...)
end
function io.write(...)
return io.output():write(...)
end
function io.flush(file)
expect(1, file, "table", "nil")
return (file or io.output):flush()
end
function io.close(file)
expect(1, file, "table", "nil")
return (file or io.output):close()
end
function io.lines(file, ...)
expect(1, file, "string", "nil")
if file then file = assert(io.open(file, "r")) end
local formats = table.pack(...)
return (file or io.stdin):lines(table.unpack(formats, 1, formats.n))
end
function io.type(obj)
if type(obj) == "table" then
local is_file = true
for k, v in pairs(_file) do
if (not obj[k]) or v ~= obj[k] then
is_file = false
end
end
if is_file then
return obj.closed and "closed file" or "file"
end
end
end
-- loadfile and dofile here as well
function _G.loadfile(file, mode, env)
expect(1, file, "string")
expect(2, mode, "string", "nil")
expect(3, env, "table", "nil")
local handle, err = io.open(file, "r")
if not handle then
return nil, file .. ": " .. err
end
local data = handle:read("a")
handle:close()
return load(data, "="..file, mode or "bt", env)
end
function _G.dofile(file, ...)
expect(1, file, "string")
local func, err = loadfile(file)
if not func then
error(err)
end
return func(...)
end
return io