mirror of
https://github.com/CCLeonOS/LeonOS.git
synced 2026-03-03 06:47:00 +00:00
添加 LeonOS 的基本实现,包括: - 核心 API 模块(colors, disk, gps, keys, multishell, parallel, rednet, redstone, settings, vector) - 命令行程序(about, alias, bg, clear, copy, delete, edit, fg, help, list, lua, mkdir, move, paint, peripherals, programs, reboot, set, shutdown, threads) - 系统启动脚本和包管理 - 文档(README.md, LICENSE) - 开发工具(devbin)和更新程序 实现功能: - 完整的线程管理系统 - 兼容 ComputerCraft 的 API 设计 - 改进的 shell 和命令补全系统 - 多标签终端支持 - 设置管理系统
232 lines
4.8 KiB
Lua
232 lines
4.8 KiB
Lua
-- 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
|