v1
This commit is contained in:
+130
-65
@@ -1,45 +1,58 @@
|
||||
-- CMC.lua — Command Controller (AtlasOS Shell/CPU v2.0)
|
||||
-- in[1] = cmd_rx ← IOC.out[4] (IN|command)
|
||||
-- in[2] = mem_rx ← MMC.out[1] (FS response)
|
||||
-- out[1] = text_tx → IOC.in[2] (OUT|text)
|
||||
-- out[2] = clear_tx → IOC.in[3] (1 = clear)
|
||||
-- out[3] = color_tx → IOC.in[4] (R,G,B)
|
||||
-- out[1] = disp_tx → IOC.in[2] (OUT|text / CLR / COL|R,G,B)
|
||||
-- out[4] = mem_tx → MMC.in[1] (FS request)
|
||||
|
||||
local state = 0
|
||||
local ST_IDLE = 0
|
||||
local ST_WAIT_FS = 1
|
||||
local state = ST_IDLE
|
||||
|
||||
local uid, gid, cwd, curUser = 0, 0, "/", "root"
|
||||
|
||||
local pendingCmd = nil
|
||||
local lastRespSeq = 0
|
||||
|
||||
local outQueue = {}
|
||||
local pendingCmd = nil
|
||||
|
||||
local function parseMsg(msg)
|
||||
local p = msg:find("|")
|
||||
return p and msg:sub(1, p - 1) or msg, p and msg:sub(p + 1) or nil
|
||||
end
|
||||
|
||||
local function printOut(t)
|
||||
out[1] = "OUT|" .. tostring(t)
|
||||
end
|
||||
|
||||
local function printErr(t)
|
||||
out[1] = "OUT|" .. tostring(t)
|
||||
end
|
||||
|
||||
local function doClear()
|
||||
out[2] = 1
|
||||
end
|
||||
|
||||
local function doColor(r, g, b)
|
||||
out[3] = r .. "," .. g .. "," .. b
|
||||
local function resolvePath(path)
|
||||
if not path or path == "" then return cwd end
|
||||
if path:sub(1, 1) == "/" then return path end
|
||||
if cwd:sub(-1) == "/" then return cwd .. path end
|
||||
return cwd .. "/" .. path
|
||||
end
|
||||
|
||||
local function fsReq(op, arg)
|
||||
local msg = op
|
||||
if arg then msg = msg .. "|" .. arg end
|
||||
out[4] = msg
|
||||
out[4] = op .. (arg and ("|" .. arg) or "")
|
||||
end
|
||||
|
||||
-- queue items: op, value (op = "t" text, "c" color, "x" clear)
|
||||
local function qText(v)
|
||||
outQueue[#outQueue + 1] = { "t", tostring(v) }
|
||||
end
|
||||
|
||||
local function qErr(v)
|
||||
outQueue[#outQueue + 1] = { "c", "255,40,40" }
|
||||
outQueue[#outQueue + 1] = { "t", tostring(v) }
|
||||
outQueue[#outQueue + 1] = { "c", "0,255,0" }
|
||||
end
|
||||
|
||||
local function qClear()
|
||||
outQueue[#outQueue + 1] = { "x" }
|
||||
end
|
||||
|
||||
local function qColor(r, g, b)
|
||||
outQueue[#outQueue + 1] = { "c", r .. "," .. g .. "," .. b }
|
||||
end
|
||||
|
||||
local function queueLines(lines)
|
||||
for i = 1, #lines do
|
||||
qText(lines[i])
|
||||
end
|
||||
end
|
||||
|
||||
local cmds = {}
|
||||
@@ -49,20 +62,26 @@ local function reg(name, fn, desc)
|
||||
end
|
||||
|
||||
reg("help", function(a)
|
||||
local t = "AtlasOS v2.0 commands:\n"
|
||||
local lines = { curUser .. " " .. cwd .. "> help" }
|
||||
lines[#lines + 1] = "AtlasOS v2.0:"
|
||||
for n, e in pairs(cmds) do
|
||||
t = t .. " " .. n .. " " .. e.desc .. "\n"
|
||||
lines[#lines + 1] = " " .. n .. " " .. e.desc
|
||||
end
|
||||
return t
|
||||
end, "Show help")
|
||||
queueLines(lines)
|
||||
end, "This help")
|
||||
|
||||
reg("echo", function(a)
|
||||
if #a == 0 then error("echo: missing text") end
|
||||
return table.concat(a, " ")
|
||||
local out = ""
|
||||
for i = 1, #a do
|
||||
if #out > 0 then out = out .. " " end
|
||||
out = out .. tostring(a[i])
|
||||
end
|
||||
queueLines({ curUser .. " " .. cwd .. "> echo " .. out, out })
|
||||
end, "Echo text")
|
||||
|
||||
reg("clear", function(a)
|
||||
doClear()
|
||||
qClear()
|
||||
end, "Clear screen")
|
||||
|
||||
reg("color", function(a)
|
||||
@@ -72,12 +91,16 @@ reg("color", function(a)
|
||||
r = math.floor(math.max(0, math.min(255, r)))
|
||||
g = math.floor(math.max(0, math.min(255, g)))
|
||||
b = math.floor(math.max(0, math.min(255, b)))
|
||||
doColor(r, g, b)
|
||||
printOut("Color set to " .. r .. "," .. g .. "," .. b)
|
||||
qColor(r, g, b)
|
||||
queueLines({ curUser .. " " .. cwd .. "> color",
|
||||
"Color set to " .. r .. "," .. g .. "," .. b })
|
||||
end, "Set color R G B")
|
||||
|
||||
reg("status", function(a)
|
||||
return "AtlasOS v2.0 | User: " .. curUser .. "(" .. uid .. ") | CWD: " .. cwd
|
||||
pendingCmd = { name = "status",
|
||||
prompt = curUser .. " " .. cwd .. "> status" }
|
||||
state = ST_WAIT_FS
|
||||
fsReq("STATFS", "")
|
||||
end, "System status")
|
||||
|
||||
reg("ls", function(a)
|
||||
@@ -87,39 +110,46 @@ reg("ls", function(a)
|
||||
if a[i]:sub(1, 1) == "-" then
|
||||
opts[a[i]] = true
|
||||
else
|
||||
path = a[i]
|
||||
path = resolvePath(a[i])
|
||||
end
|
||||
end
|
||||
pendingCmd = { name = "ls", path = path, opts = opts }
|
||||
local cmdStr = "ls"
|
||||
if #a > 0 then cmdStr = "ls " .. table.concat(a, " ") end
|
||||
pendingCmd = { name = "ls", opts = opts, path = path,
|
||||
prompt = curUser .. " " .. cwd .. "> " .. cmdStr }
|
||||
state = ST_WAIT_FS
|
||||
fsReq("LS", path)
|
||||
end, "List directory [path]")
|
||||
|
||||
reg("cat", function(a)
|
||||
if #a == 0 then error("cat: missing path") end
|
||||
pendingCmd = { name = "cat", path = a[1] }
|
||||
if #a == 0 then error("cat: need path") end
|
||||
local path = resolvePath(a[1])
|
||||
pendingCmd = { name = "cat", path = path,
|
||||
prompt = curUser .. " " .. cwd .. "> cat " .. a[1] }
|
||||
state = ST_WAIT_FS
|
||||
fsReq("READ", a[1] .. "|0|8192")
|
||||
fsReq("READ", path .. "|0|8192")
|
||||
end, "Show file content")
|
||||
|
||||
reg("cd", function(a)
|
||||
local path = a[1]
|
||||
if not path then path = "/" end
|
||||
pendingCmd = { name = "cd", path = path }
|
||||
local path = a[1] and resolvePath(a[1]) or "/"
|
||||
pendingCmd = { name = "cd", path = path,
|
||||
prompt = curUser .. " " .. cwd .. "> cd " .. (a[1] or "") }
|
||||
state = ST_WAIT_FS
|
||||
fsReq("CHDIR", path)
|
||||
end, "Change directory [path]")
|
||||
|
||||
reg("stat", function(a)
|
||||
if #a == 0 then error("stat: missing path") end
|
||||
pendingCmd = { name = "stat", path = a[1] }
|
||||
if #a == 0 then error("stat: need path") end
|
||||
local path = resolvePath(a[1])
|
||||
pendingCmd = { name = "stat", path = path,
|
||||
prompt = curUser .. " " .. cwd .. "> stat " .. a[1] }
|
||||
state = ST_WAIT_FS
|
||||
fsReq("STAT", a[1])
|
||||
fsReq("STAT", path)
|
||||
end, "Show file metadata")
|
||||
|
||||
local function execCmd(cmdStr)
|
||||
local parts = {}
|
||||
for t in cmdStr:gmatch("%S+") do
|
||||
for t in cmdStr:gmatch("[^ ]+") do
|
||||
parts[#parts + 1] = t
|
||||
end
|
||||
if #parts == 0 then return end
|
||||
@@ -132,15 +162,15 @@ local function execCmd(cmdStr)
|
||||
|
||||
local entry = cmds[name]
|
||||
if not entry then
|
||||
printErr("Unknown: " .. name .. ". Try 'help'.")
|
||||
qText(curUser .. " " .. cwd .. "> " .. cmdStr)
|
||||
qErr("Unknown: " .. name .. ". Try 'help'.")
|
||||
return
|
||||
end
|
||||
|
||||
local ok, result = pcall(entry.fn, args)
|
||||
local ok, msg = pcall(entry.fn, args)
|
||||
if not ok then
|
||||
printErr(tostring(result))
|
||||
elseif result ~= nil then
|
||||
printOut(result)
|
||||
qText(curUser .. " " .. cwd .. "> " .. cmdStr)
|
||||
qErr(tostring(msg))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -150,41 +180,64 @@ local function handleFSResponse(op, data)
|
||||
|
||||
if op == "ERR" then
|
||||
local code = data or "EIO"
|
||||
local m = cmd.path
|
||||
if code == "ENOENT" then
|
||||
printErr(cmd.path .. ": No such file or directory")
|
||||
m = m .. ": No such file or directory"
|
||||
elseif code == "EACCES" then
|
||||
printErr(cmd.path .. ": Permission denied")
|
||||
m = m .. ": Permission denied"
|
||||
elseif code == "ENOTDIR" then
|
||||
printErr(cmd.path .. ": Not a directory")
|
||||
m = m .. ": Not a directory"
|
||||
elseif code == "EISDIR" then
|
||||
printErr(cmd.path .. ": Is a directory")
|
||||
m = m .. ": Is a directory"
|
||||
else
|
||||
printErr(cmd.path .. ": " .. code)
|
||||
m = m .. ": " .. code
|
||||
end
|
||||
qText(cmd.prompt)
|
||||
qErr(m)
|
||||
pendingCmd = nil
|
||||
state = ST_IDLE
|
||||
return
|
||||
end
|
||||
|
||||
local lines = { cmd.prompt }
|
||||
|
||||
if cmd.name == "ls" then
|
||||
local showAll = (cmd.opts["-la"] or cmd.opts["-a"])
|
||||
local names = {}
|
||||
for n in data:gmatch("([^|]+)") do
|
||||
names[#names + 1] = n
|
||||
end
|
||||
local outLines = {}
|
||||
for _, n in ipairs(names) do
|
||||
if n ~= "." and n ~= ".." or showAll then
|
||||
outLines[#outLines + 1] = n
|
||||
lines[#lines + 1] = n
|
||||
end
|
||||
end
|
||||
if #outLines == 0 then outLines[1] = "(empty)" end
|
||||
printOut(table.concat(outLines, "\n"))
|
||||
if #lines == 1 then lines[#lines + 1] = "(empty)" end
|
||||
|
||||
elseif cmd.name == "cat" then
|
||||
printOut(data)
|
||||
if data and #data > 0 then
|
||||
for line in data:gmatch("[^\n]+") do
|
||||
lines[#lines + 1] = line
|
||||
end
|
||||
else
|
||||
lines[#lines + 1] = "(empty)"
|
||||
end
|
||||
|
||||
elseif cmd.name == "cd" then
|
||||
cwd = data
|
||||
printOut(cwd)
|
||||
lines[#lines + 1] = cwd
|
||||
|
||||
elseif cmd.name == "status" then
|
||||
local parts = {}
|
||||
for s in data:gmatch("([^|]+)") do
|
||||
parts[#parts + 1] = s
|
||||
end
|
||||
local total = tonumber(parts[1]) or 8192
|
||||
local used = tonumber(parts[2]) or 0
|
||||
lines[#lines + 1] = "AtlasOS v2.0 User: " .. curUser .. "(" .. uid .. ")"
|
||||
lines[#lines + 1] = "CWD: " .. cwd
|
||||
lines[#lines + 1] = "Mem: " .. (total - used) .. "/" .. total .. " free"
|
||||
|
||||
elseif cmd.name == "stat" then
|
||||
local parts = {}
|
||||
for s in data:gmatch("([^|]+)") do
|
||||
@@ -192,15 +245,15 @@ local function handleFSResponse(op, data)
|
||||
end
|
||||
if #parts >= 6 then
|
||||
local typ = parts[2] == "d" and "directory" or "file"
|
||||
local out = "Inode: " .. parts[1] .. " Type: " .. typ .. "\n"
|
||||
out = out .. "Mode: " .. parts[3] .. " UID: " .. parts[4] .. " GID: " .. parts[5] .. "\n"
|
||||
out = out .. "Size: " .. parts[6] .. " Modified: " .. (parts[7] or "?")
|
||||
printOut(out)
|
||||
lines[#lines + 1] = "Inode: " .. parts[1] .. " Type: " .. typ
|
||||
lines[#lines + 1] = "Mode: " .. parts[3] .. " UID: " .. parts[4] .. " GID: " .. parts[5]
|
||||
lines[#lines + 1] = "Size: " .. parts[6] .. " Modified: " .. (parts[7] or "?")
|
||||
else
|
||||
printOut(data)
|
||||
lines[#lines + 1] = data
|
||||
end
|
||||
end
|
||||
|
||||
queueLines(lines)
|
||||
pendingCmd = nil
|
||||
state = ST_IDLE
|
||||
end
|
||||
@@ -208,6 +261,18 @@ end
|
||||
inp = {}
|
||||
|
||||
function upd()
|
||||
if #outQueue > 0 then
|
||||
local item = outQueue[1]
|
||||
table.remove(outQueue, 1)
|
||||
if item[1] == "t" then
|
||||
out[1] = "OUT|" .. tostring(item[2])
|
||||
elseif item[1] == "c" then
|
||||
out[1] = "COL|" .. tostring(item[2])
|
||||
elseif item[1] == "x" then
|
||||
out[1] = "CLR"
|
||||
end
|
||||
end
|
||||
|
||||
if state == ST_IDLE then
|
||||
if inp[1] ~= nil then
|
||||
local op, cmd = parseMsg(tostring(inp[1]))
|
||||
|
||||
Reference in New Issue
Block a user