MineOS/MineOS/Test.pkg
Igor Timofeev ec071c3f6d aefef
2015-12-20 11:27:04 +03:00

3048 lines
79 KiB
Plaintext

--@luaPackageFileSignature
--@luaPackageFileSeparator
--@address.lua
local computer = require("computer")
io.write(computer.address())
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@alias.lua
local shell = require("shell")
local args = shell.parse(...)
if #args == 0 then
for name, value in shell.aliases() do
io.write(name .. " " .. value .. "\n")
end
elseif #args == 1 then
local value = shell.getAlias(args[1])
if value then
io.write(value)
else
io.stderr:write("no such alias")
end
else
shell.setAlias(args[1], args[2])
io.write("alias created: " .. args[1] .. " -> " .. args[2])
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@archive.lua
local archive = require("lib/archive")
local shell = require("shell")
------------------------------------------------------------------------------------------------------------------------------------
local args = {...}
archive.debugMode = true
if args[1] == "pack" then
if not args[2] or not args[3] then
print(" ")
print("Использование: archive pack <имя архива> <архивируемая папка>")
print(" ")
return
end
archive.pack(args[2], args[3])
elseif args[1] == "unpack" then
if not args[2] or not args[3] then
print(" ")
print("Использование: archive unpack <путь к архиву> <папка для сохранения файлов>")
print(" ")
return
end
archive.unpack(args[2], args[3])
elseif args[1] == "download" then
if not args[2] or not args[3] then
print(" ")
print("Использование: archive download <URL-ссылка на архив> <папка для сохранения файлов>")
print(" ")
return
end
print(" ")
print("Загрузка файла по ссылке \"" .. args[2] .. "\"")
shell.execute("wget " .. args[2] .. "TempFile.pkg -fq")
archive.unpack("TempFile.pkg", args[3])
shell.execute("rm TempFile.pkg")
else
print(" ")
print("Использование: archive <pack/unpack/download> ...")
print(" ")
return
end
archive.debugMode = false
------------------------------------------------------------------------------------------------------------------------------------
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@cat.lua
local shell = require("shell")
local args = shell.parse(...)
if #args == 0 then
repeat
local read = io.read("*L")
if read then
io.write(read)
end
until not read
else
for i = 1, #args do
local file, reason = io.open(shell.resolve(args[i]))
if not file then
io.stderr:write(tostring(reason) .. "\n")
os.exit(false)
end
repeat
local line = file:read("*L")
if line then
io.write(line)
end
until not line
file:close()
end
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@cd.lua
local shell = require("shell")
local args = shell.parse(...)
if #args == 0 then
io.write("Usage: cd <dirname>")
else
local result, reason = shell.setWorkingDirectory(shell.resolve(args[1]))
if not result then
io.stderr:write(reason)
end
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@clear.lua
local ecs = require("ECSAPI")
ecs.prepareToExit()
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@components.lua
local component = require("component")
local shell = require("shell")
local text = require("text")
local args, options = shell.parse(...)
local count = tonumber(options.limit) or math.huge
local components = {}
local padTo = 1
if #args == 0 then -- get all components if no filters given.
args[1] = ""
end
for _, filter in ipairs(args) do
for address, name in component.list(filter) do
if name:len() > padTo then
padTo = name:len() + 2
end
components[address] = name
end
end
padTo = padTo + 8 - padTo % 8
for address, name in pairs(components) do
io.write(text.padRight(name, padTo) .. address .. '\n')
if options.l then
local proxy = component.proxy(address)
local padTo = 1
local methods = {}
for name, member in pairs(proxy) do
if type(member) == "table" or type(member) == "function" then
if name:len() > padTo then
padTo = name:len() + 2
end
table.insert(methods, name)
end
end
table.sort(methods)
padTo = padTo + 8 - padTo % 8
for _, name in ipairs(methods) do
local doc = tostring(proxy[name])
io.write(" " .. text.padRight(name, padTo) .. doc .. '\n')
end
end
count = count - 1
if count <= 0 then
break
end
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@cp.lua
local fs = require("filesystem")
local shell = require("shell")
local args, options = shell.parse(...)
if #args < 2 then
io.write("Usage: cp [-inrv] <from...> <to>\n")
io.write(" -i: prompt before overwrite (overrides -n option).\n")
io.write(" -n: do not overwrite an existing file.\n")
io.write(" -r: copy directories recursively.\n")
io.write(" -u: copy only when the SOURCE file differs from the destination\n")
io.write(" file or when the destination file is missing.\n")
io.write(" -v: verbose output.\n")
io.write(" -x: stay on original source file system.")
return
end
local from = {}
for i = 1, #args - 1 do
table.insert(from, shell.resolve(args[i]))
end
local to = shell.resolve(args[#args])
local function status(from, to)
if options.v then
io.write(from .. " -> " .. to .. "\n")
end
os.sleep(0) -- allow interrupting
end
local result, reason
local function prompt(message)
io.write(message .. " [Y/n]\n")
local result = io.read()
return result and (result == "" or result:sub(1, 1):lower() == "y")
end
local function areEqual(path1, path2)
local f1 = io.open(path1, "rb")
if not f1 then
return nil, "could not open `" .. path1 .. "' for update test"
end
local f2 = io.open(path2, "rb")
if not f2 then
f1:close()
return nil, "could not open `" .. path2 .. "' for update test"
end
local result = true
local chunkSize = 4 * 1024
repeat
local s1, s2 = f1:read(chunkSize), f2:read(chunkSize)
if s1 ~= s2 then
result = false
break
end
until not s1 or not s2
f1:close()
f2:close()
return result
end
local function isMount(path)
path = fs.canonical(path)
for _, mountPath in fs.mounts() do
if path == fs.canonical(mountPath) then
return true
end
end
end
local function recurse(fromPath, toPath)
status(fromPath, toPath)
if fs.isDirectory(fromPath) then
if not options.r then
io.write("omitting directory `" .. fromPath .. "'\n")
return true
end
if fs.canonical(fromPath) == fs.canonical(fs.path(toPath)) then
return nil, "cannot copy a directory, `" .. fromPath .. "', into itself, `" .. toPath .. "'\n"
end
if fs.exists(toPath) and not fs.isDirectory(toPath) then
-- my real cp always does this, even with -f, -n or -i.
return nil, "cannot overwrite non-directory `" .. toPath .. "' with directory `" .. fromPath .. "'"
end
if options.x and isMount(fromPath) then
return true
end
fs.makeDirectory(toPath)
for file in fs.list(fromPath) do
local result, reason = recurse(fs.concat(fromPath, file), fs.concat(toPath, file))
if not result then
return nil, reason
end
end
return true
else
if fs.exists(toPath) then
if fs.canonical(fromPath) == fs.canonical(toPath) then
return nil, "`" .. fromPath .. "' and `" .. toPath .. "' are the same file"
end
if fs.isDirectory(toPath) then
if options.i then
if not prompt("overwrite `" .. toPath .. "'?") then
return true
end
elseif options.n then
return true
else -- yes, even for -f
return nil, "cannot overwrite directory `" .. toPath .. "' with non-directory"
end
else
if options.u then
if areEqual(fromPath, toPath) then
return true
end
end
if options.i then
if not prompt("overwrite `" .. toPath .. "'?") then
return true
end
elseif options.n then
return true
end
-- else: default to overwriting
end
fs.remove(toPath)
end
return fs.copy(fromPath, toPath)
end
end
for _, fromPath in ipairs(from) do
local toPath = to
if fs.isDirectory(toPath) then
toPath = fs.concat(toPath, fs.name(fromPath))
end
result, reason = recurse(fromPath, toPath)
if not result then
error(reason, 0)
end
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@date.lua
io.write(os.date("%F %T"))
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@df.lua
local fs = require("filesystem")
local shell = require("shell")
local text = require("text")
local args, options = shell.parse(...)
local function formatSize(size)
if not options.h then
return tostring(size)
end
local sizes = {"", "K", "M", "G"}
local unit = 1
local power = options.si and 1000 or 1024
while size > power and unit < #sizes do
unit = unit + 1
size = size / power
end
return math.floor(size * 10) / 10 .. sizes[unit]
end
local mounts = {}
if #args == 0 then
for proxy, path in fs.mounts() do
mounts[path] = proxy
end
else
for i = 1, #args do
local proxy, path = fs.get(args[i])
if not proxy then
io.stderr:write(args[i], ": no such file or directory\n")
else
mounts[path] = proxy
end
end
end
local result = {{"Filesystem", "Used", "Available", "Use%", "Mounted on"}}
for path, proxy in pairs(mounts) do
local label = proxy.getLabel() or proxy.address
local used, total = proxy.spaceUsed(), proxy.spaceTotal()
local available, percent
if total == math.huge then
used = used or "N/A"
available = "unlimited"
percent = "0%"
else
available = total - used
percent = used / total
if percent ~= percent then -- NaN
available = "N/A"
percent = "N/A"
else
percent = math.ceil(percent * 100) .. "%"
end
end
table.insert(result, {label, formatSize(used), formatSize(available), tostring(percent), path})
end
local m = {}
for _, row in ipairs(result) do
for col, value in ipairs(row) do
m[col] = math.max(m[col] or 1, value:len())
end
end
for _, row in ipairs(result) do
for col, value in ipairs(row) do
io.write(text.padRight(value, m[col] + 2))
end
io.write("\n")
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@dmesg.lua
local event = require "event"
local component = require "component"
local keyboard = require "keyboard"
local args = {...}
local interactive = io.output() == io.stdout
local color, isPal, evt
if interactive then
color, isPal = component.gpu.getForeground()
end
io.write("Press 'Ctrl-C' to exit\n")
pcall(function()
repeat
if #args > 0 then
evt = table.pack(event.pullMultiple("interrupted", table.unpack(args)))
else
evt = table.pack(event.pull())
end
if interactive then component.gpu.setForeground(0xCC2200) end
io.write("[" .. os.date("%T") .. "] ")
if interactive then component.gpu.setForeground(0x44CC00) end
io.write(tostring(evt[1]) .. string.rep(" ", math.max(10 - #tostring(evt[1]), 0) + 1))
if interactive then component.gpu.setForeground(0xB0B00F) end
io.write(tostring(evt[2]) .. string.rep(" ", 37 - #tostring(evt[2])))
if interactive then component.gpu.setForeground(0xFFFFFF) end
if evt.n > 2 then
for i = 3, evt.n do
io.write(" " .. tostring(evt[i]))
end
end
io.write("\n")
until evt[1] == "interrupted"
end)
if interactive then
component.gpu.setForeground(color, isPal)
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@echo.lua
local args = table.pack(...)
for i = 1, #args do
if i > 1 then
io.write(" ")
end
io.write(args[i])
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@edit.lua
local component = require("component")
local event = require("event")
local fs = require("filesystem")
local keyboard = require("keyboard")
local shell = require("shell")
local term = require("term")
local text = require("text")
local unicode = require("unicode")
if not term.isAvailable() then
return
end
local args, options = shell.parse(...)
if #args == 0 then
io.write("Usage: edit <filename>")
return
end
local filename = shell.resolve(args[1])
local readonly = options.r or fs.get(filename) == nil or fs.get(filename).isReadOnly()
if not fs.exists(filename) then
if fs.isDirectory(filename) then
io.stderr:write("file is a directory")
return
elseif readonly then
io.stderr:write("file system is read only")
return
end
end
local function loadConfig()
-- Try to load user settings.
local env = {}
local config = loadfile("/etc/edit.cfg", nil, env)
if config then
pcall(config)
end
-- Fill in defaults.
env.keybinds = env.keybinds or {
left = {{"left"}},
right = {{"right"}},
up = {{"up"}},
down = {{"down"}},
home = {{"home"}},
eol = {{"end"}},
pageUp = {{"pageUp"}},
pageDown = {{"pageDown"}},
backspace = {{"back"}},
delete = {{"delete"}},
deleteLine = {{"control", "delete"}, {"shift", "delete"}},
newline = {{"enter"}},
save = {{"control", "s"}},
close = {{"control", "w"}},
find = {{"control", "f"}},
findnext = {{"control", "g"}, {"control", "n"}, {"f3"}}
}
-- Generate config file if it didn't exist.
if not config then
local root = fs.get("/")
if root and not root.isReadOnly() then
fs.makeDirectory("/etc")
local f = io.open("/etc/edit.cfg", "w")
if f then
local serialization = require("serialization")
for k, v in pairs(env) do
f:write(k.."="..tostring(serialization.serialize(v, math.huge)).."\n")
end
f:close()
end
end
end
return env
end
term.clear()
term.setCursorBlink(true)
local running = true
local buffer = {}
local scrollX, scrollY = 0, 0
local config = loadConfig()
local getKeyBindHandler -- forward declaration for refind()
local function helpStatusText()
local function prettifyKeybind(label, command)
local keybind = type(config.keybinds) == "table" and config.keybinds[command]
if type(keybind) ~= "table" or type(keybind[1]) ~= "table" then return "" end
local alt, control, shift, key
for _, value in ipairs(keybind[1]) do
if value == "alt" then alt = true
elseif value == "control" then control = true
elseif value == "shift" then shift = true
else key = value end
end
if not key then return "" end
return label .. ": [" ..
(control and "Ctrl+" or "") ..
(alt and "Alt+" or "") ..
(shift and "Shift+" or "") ..
unicode.upper(key) ..
"] "
end
return prettifyKeybind("Save", "save") ..
prettifyKeybind("Close", "close") ..
prettifyKeybind("Find", "find")
end
-------------------------------------------------------------------------------
local function setStatus(value)
local w, h = component.gpu.getResolution()
component.gpu.set(1, h, text.padRight(unicode.sub(value, 1, w - 10), w - 10))
end
local function getSize()
local w, h = component.gpu.getResolution()
return w, h - 1
end
local function getCursor()
local cx, cy = term.getCursor()
return cx + scrollX, cy + scrollY
end
local function line()
local cbx, cby = getCursor()
return buffer[cby]
end
local function setCursor(nbx, nby)
local w, h = getSize()
nby = math.max(1, math.min(#buffer, nby))
local ncy = nby - scrollY
if ncy > h then
term.setCursorBlink(false)
local sy = nby - h
local dy = math.abs(scrollY - sy)
scrollY = sy
component.gpu.copy(1, 1 + dy, w, h - dy, 0, -dy)
for by = nby - (dy - 1), nby do
local str = text.padRight(unicode.sub(buffer[by], 1 + scrollX), w)
component.gpu.set(1, by - scrollY, str)
end
elseif ncy < 1 then
term.setCursorBlink(false)
local sy = nby - 1
local dy = math.abs(scrollY - sy)
scrollY = sy
component.gpu.copy(1, 1, w, h - dy, 0, dy)
for by = nby, nby + (dy - 1) do
local str = text.padRight(unicode.sub(buffer[by], 1 + scrollX), w)
component.gpu.set(1, by - scrollY, str)
end
end
term.setCursor(term.getCursor(), nby - scrollY)
nbx = math.max(1, math.min(unicode.len(line()) + 1, nbx))
local ncx = nbx - scrollX
if ncx > w then
term.setCursorBlink(false)
local sx = nbx - w
local dx = math.abs(scrollX - sx)
scrollX = sx
component.gpu.copy(1 + dx, 1, w - dx, h, -dx, 0)
for by = 1 + scrollY, math.min(h + scrollY, #buffer) do
local str = unicode.sub(buffer[by], nbx - (dx - 1), nbx)
str = text.padRight(str, dx)
component.gpu.set(1 + (w - dx), by - scrollY, str)
end
elseif ncx < 1 then
term.setCursorBlink(false)
local sx = nbx - 1
local dx = math.abs(scrollX - sx)
scrollX = sx
component.gpu.copy(1, 1, w - dx, h, dx, 0)
for by = 1 + scrollY, math.min(h + scrollY, #buffer) do
local str = unicode.sub(buffer[by], nbx, nbx + dx)
--str = text.padRight(str, dx)
component.gpu.set(1, by - scrollY, str)
end
end
term.setCursor(nbx - scrollX, nby - scrollY)
component.gpu.set(w - 9, h + 1, text.padLeft(string.format("%d,%d", nby, nbx), 10))
end
local function highlight(bx, by, length, enabled)
local w, h = getSize()
local cx, cy = bx - scrollX, by - scrollY
cx = math.max(1, math.min(w, cx))
cy = math.max(1, math.min(h, cy))
length = math.max(1, math.min(w - cx, length))
local fg, fgp = component.gpu.getForeground()
local bg, bgp = component.gpu.getBackground()
if enabled then
component.gpu.setForeground(bg, bgp)
component.gpu.setBackground(fg, fgp)
end
local value = ""
for x = cx, cx + length - 1 do
value = value .. component.gpu.get(x, cy)
end
component.gpu.set(cx, cy, value)
if enabled then
component.gpu.setForeground(fg, fgp)
component.gpu.setBackground(bg, bgp)
end
end
local function home()
local cbx, cby = getCursor()
setCursor(1, cby)
end
local function ende()
local cbx, cby = getCursor()
setCursor(unicode.len(line()) + 1, cby)
end
local function left()
local cbx, cby = getCursor()
if cbx > 1 then
setCursor(cbx - 1, cby)
return true -- for backspace
elseif cby > 1 then
setCursor(cbx, cby - 1)
ende()
return true -- again, for backspace
end
end
local function right(n)
n = n or 1
local cbx, cby = getCursor()
local be = unicode.len(line()) + 1
if cbx < be then
setCursor(cbx + n, cby)
elseif cby < #buffer then
setCursor(1, cby + 1)
end
end
local function up(n)
n = n or 1
local cbx, cby = getCursor()
if cby > 1 then
setCursor(cbx, cby - n)
if getCursor() > unicode.len(line()) then
ende()
end
end
end
local function down(n)
n = n or 1
local cbx, cby = getCursor()
if cby < #buffer then
setCursor(cbx, cby + n)
if getCursor() > unicode.len(line()) then
ende()
end
end
end
local function delete(fullRow)
local cx, cy = term.getCursor()
local cbx, cby = getCursor()
local w, h = getSize()
local function deleteRow(row)
local content = table.remove(buffer, row)
local rcy = cy + (row - cby)
if rcy <= h then
component.gpu.copy(1, rcy + 1, w, h - rcy, 0, -1)
component.gpu.set(1, h, text.padRight(buffer[row + (h - rcy)], w))
end
return content
end
if fullRow then
term.setCursorBlink(false)
if #buffer > 1 then
deleteRow(cby)
else
buffer[cby] = ""
component.gpu.fill(1, cy, w, 1, " ")
end
setCursor(1, cby)
elseif cbx <= unicode.len(line()) then
term.setCursorBlink(false)
buffer[cby] = unicode.sub(line(), 1, cbx - 1) ..
unicode.sub(line(), cbx + 1)
component.gpu.copy(cx + 1, cy, w - cx, 1, -1, 0)
local br = cbx + (w - cx)
local char = unicode.sub(line(), br, br)
if not char or unicode.len(char) == 0 then
char = " "
end
component.gpu.set(w, cy, char)
elseif cby < #buffer then
term.setCursorBlink(false)
local append = deleteRow(cby + 1)
buffer[cby] = buffer[cby] .. append
component.gpu.set(cx, cy, append)
else
return
end
setStatus(helpStatusText())
end
local function insert(value)
if not value or unicode.len(value) < 1 then
return
end
term.setCursorBlink(false)
local cx, cy = term.getCursor()
local cbx, cby = getCursor()
local w, h = getSize()
buffer[cby] = unicode.sub(line(), 1, cbx - 1) ..
value ..
unicode.sub(line(), cbx)
local len = unicode.len(value)
local n = w - (cx - 1) - len
if n > 0 then
component.gpu.copy(cx, cy, n, 1, len, 0)
end
component.gpu.set(cx, cy, value)
right(len)
setStatus(helpStatusText())
end
local function enter()
term.setCursorBlink(false)
local cx, cy = term.getCursor()
local cbx, cby = getCursor()
local w, h = getSize()
table.insert(buffer, cby + 1, unicode.sub(buffer[cby], cbx))
buffer[cby] = unicode.sub(buffer[cby], 1, cbx - 1)
component.gpu.fill(cx, cy, w - (cx - 1), 1, " ")
if cy < h then
if cy < h - 1 then
component.gpu.copy(1, cy + 1, w, h - (cy + 1), 0, 1)
end
component.gpu.set(1, cy + 1, text.padRight(buffer[cby + 1], w))
end
setCursor(1, cby + 1)
setStatus(helpStatusText())
end
local findText = ""
local function find()
local w, h = getSize()
local cx, cy = term.getCursor()
local cbx, cby = getCursor()
local ibx, iby = cbx, cby
while running do
if unicode.len(findText) > 0 then
local sx, sy
for syo = 1, #buffer do -- iterate lines with wraparound
sy = (iby + syo - 1 + #buffer - 1) % #buffer + 1
sx = string.find(buffer[sy], findText, syo == 1 and ibx or 1, true)
if sx and (sx >= ibx or syo > 1) then
break
end
end
if not sx then -- special case for single matches
sy = iby
sx = string.find(buffer[sy], findText, nil, true)
end
if sx then
cbx, cby = sx, sy
setCursor(cbx, cby)
highlight(cbx, cby, unicode.len(findText), true)
end
end
term.setCursor(7 + unicode.len(findText), h + 1)
setStatus("Find: " .. findText)
local _, _, char, code = event.pull("key_down")
local handler, name = getKeyBindHandler(code)
highlight(cbx, cby, unicode.len(findText), false)
if name == "newline" then
break
elseif name == "close" then
handler()
elseif name == "backspace" then
findText = unicode.sub(findText, 1, -2)
elseif name == "find" or name == "findnext" then
ibx = cbx + 1
iby = cby
elseif not keyboard.isControl(char) then
findText = findText .. unicode.char(char)
end
end
setCursor(cbx, cby)
setStatus(helpStatusText())
end
-------------------------------------------------------------------------------
local keyBindHandlers = {
left = left,
right = right,
up = up,
down = down,
home = home,
eol = ende,
pageUp = function()
local w, h = getSize()
up(h - 1)
end,
pageDown = function()
local w, h = getSize()
down(h - 1)
end,
backspace = function()
if not readonly and left() then
delete()
end
end,
delete = function()
if not readonly then
delete()
end
end,
deleteLine = function()
if not readonly then
delete(true)
end
end,
newline = function()
if not readonly then
enter()
end
end,
save = function()
if readonly then return end
local new = not fs.exists(filename)
local backup
if not new then
backup = filename .. "~"
for i = 1, math.huge do
if not fs.exists(backup) then
break
end
backup = filename .. "~" .. i
end
fs.copy(filename, backup)
end
local f, reason = io.open(filename, "w")
if f then
local chars, firstLine = 0, true
for _, line in ipairs(buffer) do
if not firstLine then
line = "\n" .. line
end
firstLine = false
f:write(line)
chars = chars + unicode.len(line)
end
f:close()
local format
if new then
format = [["%s" [New] %dL,%dC written]]
else
format = [["%s" %dL,%dC written]]
end
setStatus(string.format(format, fs.name(filename), #buffer, chars))
else
setStatus(reason)
end
if not new then
fs.remove(backup)
end
end,
close = function()
-- TODO ask to save if changed
running = false
end,
find = function()
findText = ""
find()
end,
findnext = find
}
getKeyBindHandler = function(code)
if type(config.keybinds) ~= "table" then return end
-- Look for matches, prefer more 'precise' keybinds, e.g. prefer
-- ctrl+del over del.
local result, resultName, resultWeight = nil, nil, 0
for command, keybinds in pairs(config.keybinds) do
if type(keybinds) == "table" and keyBindHandlers[command] then
for _, keybind in ipairs(keybinds) do
if type(keybind) == "table" then
local alt, control, shift, key
for _, value in ipairs(keybind) do
if value == "alt" then alt = true
elseif value == "control" then control = true
elseif value == "shift" then shift = true
else key = value end
end
if (not alt or keyboard.isAltDown()) and
(not control or keyboard.isControlDown()) and
(not shift or keyboard.isShiftDown()) and
code == keyboard.keys[key] and
#keybind > resultWeight
then
resultWeight = #keybind
resultName = command
result = keyBindHandlers[command]
end
end
end
end
end
return result, resultName
end
-------------------------------------------------------------------------------
local function onKeyDown(char, code)
local handler = getKeyBindHandler(code)
if handler then
handler()
elseif readonly and code == keyboard.keys.q then
running = false
elseif not readonly then
if not keyboard.isControl(char) then
insert(unicode.char(char))
elseif unicode.char(char) == "\t" then
insert(" ")
end
end
end
local function onClipboard(value)
value = value:gsub("\r\n", "\n")
local cbx, cby = getCursor()
local start = 1
local l = value:find("\n", 1, true)
if l then
repeat
local line = string.sub(value, start, l - 1)
line = text.detab(line, 2)
insert(line)
enter()
start = l + 1
l = value:find("\n", start, true)
until not l
end
insert(string.sub(value, start))
end
local function onClick(x, y)
setCursor(x + scrollX, y + scrollY)
end
local function onScroll(direction)
local cbx, cby = getCursor()
setCursor(cbx, cby - direction * 12)
end
-------------------------------------------------------------------------------
do
local f = io.open(filename)
if f then
local w, h = getSize()
local chars = 0
for line in f:lines() do
if line:sub(-1) == "\r" then
line = line:sub(1, -2)
end
table.insert(buffer, line)
chars = chars + unicode.len(line)
if #buffer <= h then
component.gpu.set(1, #buffer, line)
end
end
f:close()
if #buffer == 0 then
table.insert(buffer, "")
end
local format
if readonly then
format = [["%s" [readonly] %dL,%dC]]
else
format = [["%s" %dL,%dC]]
end
setStatus(string.format(format, fs.name(filename), #buffer, chars))
else
table.insert(buffer, "")
setStatus(string.format([["%s" [New File] ]], fs.name(filename)))
end
setCursor(1, 1)
end
while running do
local event, address, arg1, arg2, arg3 = event.pull()
if type(address) == "string" and component.isPrimary(address) then
local blink = true
if event == "key_down" then
onKeyDown(arg1, arg2)
elseif event == "clipboard" and not readonly then
onClipboard(arg1)
elseif event == "touch" or event == "drag" then
onClick(arg1, arg2)
elseif event == "scroll" then
onScroll(arg3)
else
blink = false
end
if blink then
term.setCursorBlink(true)
term.setCursorBlink(true) -- force toggle to caret
end
end
end
term.clear()
term.setCursorBlink(false)
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@event.lua
local event = require "event"
while true do
local cyka = {event.pull()}
print("Ивент: "..cyka[1])
for i=2,#cyka do
print("Аргумент "..(i).." = "..cyka[i])
end
print(" ")
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@flash.lua
local component = require("component")
local shell = require("shell")
local fs = require("filesystem")
local args, options = shell.parse(...)
if #args < 1 and not options.l then
io.write("Usage: flash [-qlr] [<bios.lua>] [label]\n")
io.write(" q: quiet mode, don't ask questions.\n")
io.write(" l: print current contents of installed EEPROM.\n")
io.write(" r: save the current contents of installed EEPROM to file.")
return
end
local function printRom()
local eeprom = component.eeprom
io.write(eeprom.get())
end
local function readRom()
local eeprom = component.eeprom
fileName = shell.resolve(args[1])
if not options.q then
if fs.exists(fileName) then
io.write("Are you sure you want to overwrite " .. fileName .. "?\n")
io.write("Type `y` to confirm.\n")
repeat
local response = io.read()
until response and response:lower():sub(1, 1) == "y"
end
io.write("Reading EEPROM " .. eeprom.address .. ".\n" )
end
local bios = eeprom.get()
local file = assert(io.open(fileName, "wb"))
file:write(bios)
file:close()
if not options.q then
io.write("All done!\nThe label is '" .. eeprom.getLabel() .. "'.\n")
end
end
local function writeRom()
local file = assert(io.open(args[1], "rb"))
local bios = file:read("*a")
file:close()
if not options.q then
io.write("Insert the EEPROM you would like to flash.\n")
io.write("When ready to write, type `y` to confirm.\n")
repeat
local response = io.read()
until response and response:lower():sub(1, 1) == "y"
io.write("Beginning to flash EEPROM.\n")
end
local eeprom = component.eeprom
if not options.q then
io.write("Flashing EEPROM " .. eeprom.address .. ".\n")
io.write("Please do NOT power down or restart your computer during this operation!\n")
end
eeprom.set(bios)
local label = args[2]
if not options.q and not label then
io.write("Enter new label for this EEPROM. Leave input blank to leave the label unchanged.\n")
label = io.read()
end
if label and #label > 0 then
eeprom.setLabel(label)
if not options.q then
io.write("Set label to '" .. eeprom.getLabel() .. "'.\n")
end
end
if not options.q then
io.write("All done! You can remove the EEPROM and re-insert the previous one now.\n")
end
end
if options.l then
printRom()
elseif options.r then
readRom()
else
writeRom()
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@hostname.lua
local args = {...}
if args[1] then
local file, reason = io.open("/etc/hostname", "w")
if not file then
io.stderr:write(reason .. "\n")
else
file:write(args[1])
file:close()
os.setenv("HOSTNAME", args[1])
os.setenv("PS1", "$HOSTNAME:$PWD# ")
end
else
local file = io.open("/etc/hostname")
if file then
io.write(file:read("*l"), "\n")
file:close()
else
io.stderr:write("Hostname not set\n")
end
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@install.lua
local component = require("component")
local computer = require("computer")
local event = require("event")
local filesystem = require("filesystem")
local unicode = require("unicode")
local shell = require("shell")
local args, options = shell.parse(...)
local fromAddress = options.from and component.get(options.from) or filesystem.get(os.getenv("_")).address
local candidates = {}
for address in component.list("filesystem", true) do
local dev = component.proxy(address)
if not dev.isReadOnly() and dev.address ~= computer.tmpAddress() and dev.address ~= fromAddress then
table.insert(candidates, dev)
end
end
if #candidates == 0 then
io.write("No writable disks found, aborting.\n")
os.exit()
end
for i = 1, #candidates do
local label = candidates[i].getLabel()
if label then
label = label .. " (" .. candidates[i].address:sub(1, 8) .. "...)"
else
label = candidates[i].address
end
io.write(i .. ") " .. label .. "\n")
end
io.write("To select the device to install to, please enter a number between 1 and " .. #candidates .. ".\n")
io.write("Press 'q' to cancel the installation.\n")
local choice
while not choice do
result = io.read()
if result:sub(1, 1):lower() == "q" then
os.exit()
end
local number = tonumber(result)
if number and number > 0 and number <= #candidates then
choice = candidates[number]
else
io.write("Invalid input, please try again.\n")
end
end
local function findMount(address)
for fs, path in filesystem.mounts() do
if fs.address == component.get(address) then
return path
end
end
end
local name = options.name or "OpenOS"
io.write("Installing " .. name .." to device " .. (choice.getLabel() or choice.address) .. "\n")
os.sleep(0.25)
local cpPath = filesystem.concat(findMount(filesystem.get(os.getenv("_")).address), "bin/cp")
local cpOptions = "-vrx" .. (options.u and "ui " or "")
local cpSource = filesystem.concat(findMount(fromAddress), options.fromDir or "/", "*")
local cpDest = findMount(choice.address) .. "/"
local result, reason = os.execute(cpPath .. " " .. cpOptions .. " " .. cpSource .. " " .. cpDest)
if not result then
error(reason, 0)
end
if not options.nolabelset then pcall(choice.setLabel, name) end
if not options.noreboot then
io.write("All done! " .. ((not options.noboot) and "Set as boot device and r" or "R") .. "eboot now? [Y/n]\n")
local result = io.read()
if not result or result == "" or result:sub(1, 1):lower() == "y" then
if not options.noboot then computer.setBootAddress(choice.address)end
io.write("\nRebooting now!\n")
computer.shutdown(true)
end
end
io.write("Returning to shell.\n")
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@label.lua
local fs = require("filesystem")
local shell = require("shell")
local args, options = shell.parse(...)
if #args < 1 then
io.write("Usage: label [-a] <fs> [<label>]\n")
io.write(" -a File system is specified via label or address instead of by path.")
return
end
local proxy, reason
if options.a then
proxy, reason = fs.proxy(args[1])
else
proxy, reason = fs.get(args[1])
end
if not proxy then
io.stderr:write(reason)
return
end
if #args < 2 then
io.stderr:write(proxy.getLabel() or "no label")
else
local result, reason = proxy.setLabel(args[2])
if not result then
io.stderr:write(reason or "could not set label")
end
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@ln.lua
local component = require("component")
local fs = require("filesystem")
local shell = require("shell")
local dirs = shell.parse(...)
if #dirs == 0 then
io.write("Usage: ln <target> [<name>]")
return
end
local target = shell.resolve(dirs[1])
local linkpath
if #dirs > 1 then
linkpath = shell.resolve(dirs[2])
else
linkpath = fs.concat(shell.getWorkingDirectory(), fs.name(target))
end
local result, reason = fs.link(target, linkpath)
if not result then
io.stderr:write(reason)
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@ls.lua
local component = require("component")
local fs = require("filesystem")
local shell = require("shell")
local text = require('text')
local dirs, options = shell.parse(...)
if #dirs == 0 then
table.insert(dirs, ".")
end
local function formatOutput()
return component.isAvailable("gpu") and io.output() == io.stdout
end
io.output():setvbuf("line")
for i = 1, #dirs do
local path = shell.resolve(dirs[i])
if #dirs > 1 then
if i > 1 then
io.write("\n")
end
io.write(path, ":\n")
end
local list, reason = fs.list(path)
if not list then
io.write(reason .. "\n")
else
local function setColor(c)
if formatOutput() and component.gpu.getForeground() ~= c then
io.stdout:flush()
component.gpu.setForeground(c)
end
end
local lsd = {}
local lsf = {}
local m = 1
for f in list do
m = math.max(m, f:len() + 2)
if f:sub(-1) == "/" then
if options.p then
table.insert(lsd, f)
else
table.insert(lsd, f:sub(1, -2))
end
else
table.insert(lsf, f)
end
end
table.sort(lsd)
table.sort(lsf)
setColor(0x00cc00)
local col = 1
local columns = math.huge
if formatOutput() then
columns = math.max(1, math.floor((component.gpu.getResolution() - 1) / m))
end
for _, d in ipairs(lsd) do
if options.a or d:sub(1, 1) ~= "." then
if options.l or not formatOutput() or col % columns == 0 then
io.write(d .. "\n")
else
io.write(text.padRight(d, m))
end
col = col + 1
end
end
for _, f in ipairs(lsf) do
if fs.isLink(fs.concat(path, f)) then
setColor(0xffff00)
elseif f:sub(-4) == ".lua" then
setColor(0xff5555)
else
setColor(0xcccccc)
end
if options.a or f:sub(1, 1) ~= "." then
if not formatOutput() then
io.write(f)
if options.l then
io.write(" " .. fs.size(fs.concat(path, f)))
end
io.write("\n")
else
io.write(text.padRight(f, m))
if options.l then
setColor(0xcccccc)
io.write(fs.size(fs.concat(path, f)), "\n")
elseif col % columns == 0 then
io.write("\n")
end
end
col = col + 1
end
end
setColor(0xcccccc)
if options.M then
io.write("\n" .. tostring(#lsf) .. " File(s)")
io.write("\n" .. tostring(#lsd) .. " Dir(s)")
end
if not options.l then
io.write("\n")
end
end
end
io.output():setvbuf("no")
io.output():flush()
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@lua.lua
local component = require("component")
local package = require("package")
local term = require("term")
local serialization = require("serialization")
local shell = require("shell")
local args, options = shell.parse(...)
local env = setmetatable({}, {__index = _ENV})
if #args > 0 then
local script, reason = loadfile(args[1], nil, env)
if not script then
io.stderr:write(tostring(reason) .. "\n")
os.exit(false)
end
local result, reason = pcall(script, table.unpack(args, 2))
if not result then
io.stderr:write(reason)
os.exit(false)
end
end
if #args == 0 or options.i then
local function optrequire(...)
local success, module = pcall(require, ...)
if success then
return module
end
end
setmetatable(env, {
__index = function(t, k)
_ENV[k] = _ENV[k] or optrequire(k)
return _ENV[k]
end,
__pairs = function(self)
local t = self
return function(_, key)
local k, v = next(t, key)
if not k and t == env then
t = _ENV
k, v = next(t)
end
if not k and t == _ENV then
t = package.loaded
k, v = next(t)
end
return k, v
end
end
})
local history = {}
local function findTable(t, path)
if type(t) ~= "table" then return nil end
if not path or #path == 0 then return t end
local name = string.match(path, "[^.]+")
for k, v in pairs(t) do
if k == name then
return findTable(v, string.sub(path, #name + 2))
end
end
local mt = getmetatable(t)
if t == env then mt = {__index=_ENV} end
if mt then
return findTable(mt.__index, path)
end
return nil
end
local function findKeys(t, r, prefix, name)
if type(t) ~= "table" then return end
for k, v in pairs(t) do
if string.match(k, "^"..name) then
local postfix = ""
if type(v) == "function" then postfix = "()"
elseif type(v) == "table" and getmetatable(v) and getmetatable(v).__call then postfix = "()"
elseif type(v) == "table" then postfix = "."
end
r[prefix..k..postfix] = true
end
end
local mt = getmetatable(t)
if t == env then mt = {__index=_ENV} end
if mt then
return findKeys(mt.__index, r, prefix, name)
end
end
local function hint(line, index)
line = (line or ""):sub(1, index - 1)
local path = string.match(line, "[a-zA-Z_][a-zA-Z0-9_.]*$")
if not path then return nil end
local suffix = string.match(path, "[^.]+$") or ""
local prefix = string.sub(path, 1, #path - #suffix)
local t = findTable(env, prefix)
if not t then return nil end
local r1, r2 = {}, {}
findKeys(t, r1, string.sub(line, 1, #line - #suffix), suffix)
for k in pairs(r1) do
table.insert(r2, k)
end
table.sort(r2)
return r2
end
component.gpu.setForeground(0xFFFFFF)
term.write(_VERSION .. " Copyright (C) 1994-2015 Lua.org, PUC-Rio\n")
component.gpu.setForeground(0xFFFF00)
term.write("Enter a statement and hit enter to evaluate it.\n")
term.write("Prefix an expression with '=' to show its value.\n")
term.write("Press Ctrl+C to exit the interpreter.\n")
component.gpu.setForeground(0xFFFFFF)
while term.isAvailable() do
local foreground = component.gpu.setForeground(0x00FF00)
term.write(tostring(env._PROMPT or "lua> "))
component.gpu.setForeground(foreground)
local command = term.read(history, nil, hint)
if command == nil then -- eof
return
end
while #history > 10 do
table.remove(history, 1)
end
local code, reason
if string.sub(command, 1, 1) == "=" then
code, reason = load("return " .. string.sub(command, 2), "=stdin", "t", env)
else
code, reason = load(command, "=stdin", "t", env)
end
if code then
local result = table.pack(xpcall(code, debug.traceback))
if not result[1] then
if type(result[2]) == "table" and result[2].reason == "terminated" then
os.exit(result[2].code)
end
io.stderr:write(tostring(result[2]) .. "\n")
else
for i = 2, result.n do
term.write(serialization.serialize(result[i], true) .. "\t", true)
end
if term.getCursor() > 1 then
term.write("\n")
end
end
else
io.stderr:write(tostring(reason) .. "\n")
end
end
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@man.lua
local fs = require("filesystem")
local shell = require("shell")
local args = shell.parse(...)
if #args == 0 then
io.write("Usage: man <topic>\n")
io.write("Where `topic` will usually be the name of a program or library.")
return
end
local topic = args[1]
for path in string.gmatch(os.getenv("MANPATH"), "[^:]+") do
path = shell.resolve(fs.concat(path, topic), "man")
if path and fs.exists(path) and not fs.isDirectory(path) then
os.execute(os.getenv("PAGER") .. " " .. path)
os.exit()
end
end
io.stderr:write("No manual entry for " .. topic)
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@mkdir.lua
local fs = require("filesystem")
local shell = require("shell")
local args = shell.parse(...)
if #args == 0 then
io.write("Usage: mkdir <dirname1> [<dirname2> [...]]")
return
end
for i = 1, #args do
local path = shell.resolve(args[i])
local result, reason = fs.makeDirectory(path)
if not result then
if not reason then
if fs.exists(path) then
reason = "file or folder with that name already exists"
else
reason = "unknown reason"
end
end
io.stderr:write(path .. ": " .. reason .. "\n")
end
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@more.lua
local component = require("component")
local event = require("event")
local keyboard = require("keyboard")
local shell = require("shell")
local term = require("term")
local text = require("text")
local unicode = require("unicode")
local args = shell.parse(...)
if #args == 0 then
io.write("Usage: more <filename1>")
return
end
local file, reason = io.open(shell.resolve(args[1]))
if not file then
io.stderr:write(reason)
return
end
local line = nil
local function readlines(num)
local w, h = component.gpu.getResolution()
num = num or (h - 1)
term.setCursorBlink(false)
for _ = 1, num do
if not line then
line = file:read("*l")
if not line then -- eof
return nil
end
end
local wrapped
wrapped, line = text.wrap(text.detab(line), w, w)
io.write(wrapped .. "\n")
end
term.setCursor(1, h)
term.write(":")
term.setCursorBlink(true)
return true
end
while true do
term.clear()
if not readlines() then
return
end
while true do
local event, address, char, code = event.pull("key_down")
if component.isPrimary(address) then
if code == keyboard.keys.q then
term.setCursorBlink(false)
term.clearLine()
return
elseif code == keyboard.keys.space or code == keyboard.keys.pageDown then
break
elseif code == keyboard.keys.enter or code == keyboard.keys.down then
term.clearLine()
if not readlines(1) then
return
end
end
end
end
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@mount.lua
local fs = require("filesystem")
local shell = require("shell")
local args = shell.parse(...)
if #args == 0 then
for proxy, path in fs.mounts() do
local label = proxy.getLabel() or proxy.address
local mode = proxy.isReadOnly() and "ro" or "rw"
io.write(string.format("%s on %s (%s)\n", label, path, mode))
end
return
end
if #args < 2 then
io.write("Usage: mount [<label|address> <path>]\n")
io.write("Note that the address may be abbreviated.")
return
end
local proxy, reason = fs.proxy(args[1])
if not proxy then
io.stderr:write(reason)
return
end
local result, reason = fs.mount(proxy, shell.resolve(args[2]))
if not result then
io.stderr:write(reason)
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@mv.lua
local fs = require("filesystem")
local shell = require("shell")
local args, options = shell.parse(...)
if #args < 2 then
io.write("Usage: mv [-f] <from> <to>\n")
io.write(" -f: overwrite file if it already exists.")
return
end
local from = shell.resolve(args[1])
local to = shell.resolve(args[2])
if fs.isDirectory(to) then
to = to .. "/" .. fs.name(from)
end
if fs.exists(to) then
if not options.f then
io.stderr:write("target file exists")
return
end
fs.remove(to)
end
local result, reason = os.rename(from, to)
if not result then
io.stderr:write(reason or "unknown error")
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@pastebin.lua
--[[ This program allows downloading and uploading from and to pastebin.com.
Authors: Sangar, Vexatos ]]
local component = require("component")
local fs = require("filesystem")
local internet = require("internet")
local shell = require("shell")
if not component.isAvailable("internet") then
io.stderr:write("This program requires an internet card to run.")
return
end
local args, options = shell.parse(...)
-- This gets code from the website and stores it in the specified file.
local function get(pasteId, filename)
local f, reason = io.open(filename, "w")
if not f then
io.stderr:write("Failed opening file for writing: " .. reason)
return
end
io.write("Downloading from pastebin.com... ")
local url = "http://pastebin.com/raw.php?i=" .. pasteId
local result, response = pcall(internet.request, url)
if result then
io.write("success.\n")
for chunk in response do
if not options.k then
string.gsub(chunk, "\r\n", "\n")
end
f:write(chunk)
end
f:close()
io.write("Saved data to " .. filename .. "\n")
else
io.write("failed.\n")
f:close()
fs.remove(filename)
io.stderr:write("HTTP request failed: " .. response .. "\n")
end
end
-- This makes a string safe for being used in a URL.
function encode(code)
if code then
code = string.gsub(code, "([^%w ])", function (c)
return string.format("%%%02X", string.byte(c))
end)
code = string.gsub(code, " ", "+")
end
return code
end
-- This stores the program in a temporary file, which it will
-- delete after the program was executed.
function run(pasteId, ...)
local tmpFile = os.tmpname()
get(pasteId, tmpFile)
io.write("Running...\n")
local success, reason = shell.execute(tmpFile, nil, ...)
if not success then
io.stderr:write(reason)
end
fs.remove(tmpFile)
end
-- Uploads the specified file as a new paste to pastebin.com.
function put(path)
local config = {}
local configFile = loadfile("/etc/pastebin.conf", "t", config)
if configFile then
local result, reason = pcall(configFile)
if not result then
io.stderr:write("Failed loading config: " .. reason)
end
end
config.key = config.key or "fd92bd40a84c127eeb6804b146793c97"
local file, reason = io.open(path, "r")
if not file then
io.stderr:write("Failed opening file for reading: " .. reason)
return
end
local data = file:read("*a")
file:close()
io.write("Uploading to pastebin.com... ")
local result, response = pcall(internet.request,
"http://pastebin.com/api/api_post.php",
"api_option=paste&" ..
"api_dev_key=" .. config.key .. "&" ..
"api_paste_format=lua&" ..
"api_paste_expire_date=N&" ..
"api_paste_name=" .. encode(fs.name(path)) .. "&" ..
"api_paste_code=" .. encode(data))
if result then
local info = ""
for chunk in response do
info = info .. chunk
end
if string.match(info, "^Bad API request, ") then
io.write("failed.\n")
io.write(info)
else
io.write("success.\n")
local pasteId = string.match(info, "[^/]+$")
io.write("Uploaded as " .. info .. "\n")
io.write('Run "pastebin get ' .. pasteId .. '" to download anywhere.')
end
else
io.write("failed.\n")
io.stderr:write(response)
end
end
local command = args[1]
if command == "put" then
if #args == 2 then
put(shell.resolve(args[2]))
return
end
elseif command == "get" then
if #args == 3 then
local path = shell.resolve(args[3])
if fs.exists(path) then
if not options.f or not os.remove(path) then
io.stderr:write("file already exists")
return
end
end
get(args[2], path)
return
end
elseif command == "run" then
if #args >= 2 then
run(args[2], table.unpack(args, 3))
return
end
end
-- If we come here there was some invalid input.
io.write("Usages:\n")
io.write("pastebin put [-f] <file>\n")
io.write("pastebin get [-f] <id> <file>\n")
io.write("pastebin run [-f] <id> [<arguments...>]\n")
io.write(" -f: Force overwriting existing files.\n")
io.write(" -k: keep line endings as-is (will convert\n")
io.write(" Windows line endings to Unix otherwise).")
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@primary.lua
local component = require("component")
local shell = require("shell")
local args = shell.parse(...)
if #args == 0 then
io.write("Usage: primary <type> [<address>]\n")
io.write("Note that the address may be abbreviated.")
return
end
local componentType = args[1]
if #args > 1 then
local address = args[2]
if not component.get(address) then
io.stderr:write("no component with this address")
return
else
component.setPrimary(componentType, address)
os.sleep(0.1) -- allow signals to be processed
end
end
if component.isAvailable(componentType) then
io.write(component.getPrimary(componentType).address)
else
io.stderr:write("no primary component for this type")
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@pwd.lua
local shell = require("shell")
io.write(shell.getWorkingDirectory())
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@rc.lua
local rc = require('rc')
local args = table.pack(...)
if args.n < 1 then
io.write("Usage: rc <service> [command] [args...]")
return
end
local result, reason = rc.runCommand(table.unpack(args))
if not result then
io.stderr:write(reason .. "\n")
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@reboot.lua
local computer = require("computer")
io.write("Rebooting...")
computer.shutdown(true)
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@redstone.lua
local colors = require("colors")
local component = require("component")
local shell = require("shell")
local sides = require("sides")
if not component.isAvailable("redstone") then
io.stderr:write("This program requires a redstone card or redstone I/O block.")
return
end
local rs = component.redstone
local args, options = shell.parse(...)
if #args == 0 and not options.w and not options.f then
io.write("Usage:\n")
io.write(" redstone <side> [<value>]\n")
if rs.setBundledOutput then
io.write(" redstone -b <side> <color> [<value>]\n")
end
if rs.setWirelessOutput then
io.write(" redstone -w [<value>]\n")
io.write(" redstone -f [<frequency>]\n")
end
return
end
if options.w then
if not rs.setWirelessOutput then
io.stderr:write("wireless redstone not available")
return
end
if #args > 0 then
local value = args[1]
if tonumber(value) then
value = tonumber(value) > 0
else
value = ({["true"]=true,["on"]=true,["yes"]=true})[value] ~= nil
end
rs.setWirelessOutput(value)
end
io.write("in: " .. tostring(rs.getWirelessInput()) .. "\n")
io.write("out: " .. tostring(rs.getWirelessOutput()))
elseif options.f then
if not rs.setWirelessOutput then
io.stderr:write("wireless redstone not available")
return
end
if #args > 0 then
local value = args[1]
if not tonumber(value) then
io.stderr:write("invalid frequency")
return
end
rs.setWirelessFrequency(tonumber(value))
end
io.write("freq: " .. tostring(rs.getWirelessFrequency()) .. "\n")
else
local side = sides[args[1]]
if not side then
io.stderr:write("invalid side")
return
end
if type(side) == "string" then
side = sides[side]
end
if options.b then
if not rs.setBundledOutput then
io.stderr:write("bundled redstone not available")
return
end
local color = colors[args[2]]
if not color then
io.stderr:write("invalid color")
return
end
if type(color) == "string" then
color = colors[color]
end
if #args > 2 then
local value = args[3]
if tonumber(value) then
value = tonumber(value)
else
value = ({["true"]=true,["on"]=true,["yes"]=true})[value] and 255 or 0
end
rs.setBundledOutput(side, color, value)
end
io.write("in: " .. rs.getBundledInput(side, color) .. "\n")
io.write("out: " .. rs.getBundledOutput(side, color))
else
if #args > 1 then
local value = args[2]
if tonumber(value) then
value = tonumber(value)
else
value = ({["true"]=true,["on"]=true,["yes"]=true})[value] and 15 or 0
end
rs.setOutput(side, value)
end
io.write("in: " .. rs.getInput(side) .. "\n")
io.write("out: " .. rs.getOutput(side))
end
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@resolution.lua
local component = require("component")
local shell = require("shell")
local term = require("term")
local args = shell.parse(...)
if #args == 0 then
local w, h = component.gpu.getResolution()
io.write(w .. " " .. h)
return
end
if #args < 2 then
io.write("Usage: resolution [<width> <height>]")
return
end
local w = tonumber(args[1])
local h = tonumber(args[2])
if not w or not h then
io.stderr:write("invalid width or height")
return
end
local result, reason = component.gpu.setResolution(w, h)
if not result then
if reason then -- otherwise we didn't change anything
io.stderr:write(reason)
end
return
end
term.clear()
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@rm.lua
local shell = require("shell")
local args, options = shell.parse(...)
if #args == 0 then
io.write("Usage: rm [-v] <filename1> [<filename2> [...]]\n")
io.write(" -v: verbose output.")
return
end
for i = 1, #args do
local path = shell.resolve(args[i])
if not os.remove(path) then
io.stderr:write(path .. ": no such file, or permission denied\n")
end
if options.v then
io.write("removed '" .. path .. "'\n")
end
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@scale.lua
local ecs = require("ECSAPI")
local gpu = require("component").gpu
local arg = {...}
if arg[1] == "get" or arg[1] == "show" or arg[1] == "print" or arg[1] == "write" or arg[1] == "info" or arg[1] == "help" then
local max1, max2 = gpu.maxResolution()
local cur1, cur2 = gpu.getResolution()
local scale = cur1/max1*100
print(" ")
print("Максимальное поддерживаемое разрешение: " .. max1 .. "x".. max2)
print("Текущее разрешение: " .. cur1.."x"..cur2)
print(" ")
print("Масштаб: "..scale.."%")
print(" ")
else
ecs.setScale(tonumber(arg[1]) or 1, true)
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@set.lua
local args = {...}
if #args < 1 then
for k,v in pairs(os.getenv()) do
io.write(k .. "='" .. string.gsub(v, "'", [['"'"']]) .. "'\n")
end
else
local count = 0
for _, expr in ipairs(args) do
local k, v = string.match(expr, "(.-)=(.*)")
if v then
os.setenv(k, v)
else
if count == 0 then
for i = 1, os.getenv('#') do
os.setenv(i, nil)
end
end
count = count + 1
os.setenv(count, expr)
end
end
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@sh.lua
local component = require("component")
local computer = require("computer")
local event = require("event")
local fs = require("filesystem")
local process = require("process")
local shell = require("shell")
local term = require("term")
local text = require("text")
local unicode = require("unicode")
-------------------------------------------------------------------------------
local memoryStream = {}
function memoryStream:close()
self.closed = true
end
function memoryStream:seek()
return nil, "bad file descriptor"
end
function memoryStream:read(n)
if self.closed then
if self.buffer == "" and self.redirect.read then
return self.redirect.read:read(n)
else
return nil -- eof
end
end
if self.buffer == "" then
self.args = table.pack(coroutine.yield(table.unpack(self.result)))
end
local result = string.sub(self.buffer, 1, n)
self.buffer = string.sub(self.buffer, n + 1)
return result
end
function memoryStream:write(value)
if not self.redirect.write and self.closed then
-- if next is dead, ignore all writes
if coroutine.status(self.next) ~= "dead" then
error("attempt to use a closed stream")
end
return true
end
if self.redirect.write then
self.redirect.write:write(value)
end
if not self.closed then
self.buffer = self.buffer .. value
self.result = table.pack(coroutine.resume(self.next, table.unpack(self.args)))
if coroutine.status(self.next) == "dead" then
self:close()
end
if not self.result[1] then
error(self.result[2], 0)
end
table.remove(self.result, 1)
end
return true
end
function memoryStream.new()
local stream = {closed = false, buffer = "",
redirect = {}, result = {}, args = {}}
local metatable = {__index = memoryStream,
__gc = memoryStream.close,
__metatable = "memorystream"}
return setmetatable(stream, metatable)
end
-------------------------------------------------------------------------------
local function expand(value)
local result = value:gsub("%$(%w+)", os.getenv):gsub("%$%b{}",
function(match) return os.getenv(expand(match:sub(3, -2))) or match end)
return result
end
local function glob(value)
if not value:find("*", 1, true) and not value:find("?", 1, true) then
-- Nothing to do here.
return {expand(value)}
end
local segments = fs.segments(value)
local paths = {value:sub(1, 1) == "/" and "/" or shell.getWorkingDirectory()}
for i, segment in ipairs(segments) do
local nextPaths = {}
local pattern = segment:gsub("*", ".*"):gsub("?", ".")
if pattern == segment then
-- Nothing to do, concatenate as-is.
for _, path in ipairs(paths) do
table.insert(nextPaths, fs.concat(path, segment))
end
else
pattern = "^(" .. pattern .. ")/?$"
for _, path in ipairs(paths) do
for file in fs.list(path) do
if file:match(pattern) then
table.insert(nextPaths, fs.concat(path, file))
end
end
end
if #nextPaths == 0 then
error("no matches found: " .. segment)
end
end
paths = nextPaths
end
for i, path in ipairs(paths) do
paths[i] = expand(path)
end
return paths
end
local function evaluate(value)
local init, results = 1, {""}
repeat
local match = value:match("^%b''", init)
if match then -- single quoted string. no variable expansion.
match = match:sub(2, -2)
init = init + 2
for i, result in ipairs(results) do
results[i] = result .. match
end
else
match = value:match('^%b""', init)
if match then -- double quoted string.
match = match:sub(2, -2)
init = init + 2
else
-- plaintext?
match = value:match("^([^']+)%b''", init)
if not match then -- unmatched single quote.
match = value:match('^([^"]+)%b""', init)
if not match then -- unmatched double quote.
match = value:sub(init)
end
end
end
local newResults = {}
for _, globbed in ipairs(glob(match)) do
for i, result in ipairs(results) do
table.insert(newResults, result .. globbed)
end
end
results = newResults
end
init = init + #match
until init > #value
return results
end
local function parseCommand(tokens, ...)
if #tokens == 0 then
return
end
local program, args = shell.resolveAlias(tokens[1], table.pack(select(2, table.unpack(tokens))))
local eargs = {}
program = evaluate(program)
for i = 2, #program do
table.insert(eargs, program[i])
end
local program, reason = shell.resolve(program[1], "lua")
if not program then
return nil, reason
end
for i = 1, #args do
for _, arg in ipairs(evaluate(args[i])) do
table.insert(eargs, arg)
end
end
args = eargs
-- Find redirects.
local input, output, mode = nil, nil, "write"
tokens = args
args = {}
local function smt(call) -- state metatable factory
local function index(_, token)
if token == "<" or token == ">" or token == ">>" then
return "parse error near " .. token
end
call(token)
return "args" -- default, return to normal arg parsing
end
return {__index=index}
end
local sm = { -- state machine for redirect parsing
args = setmetatable({["<"]="input", [">"]="output", [">>"]="append"},
smt(function(token)
table.insert(args, token)
end)),
input = setmetatable({}, smt(function(token)
input = token
end)),
output = setmetatable({}, smt(function(token)
output = token
mode = "write"
end)),
append = setmetatable({}, smt(function(token)
output = token
mode = "append"
end))
}
-- Run state machine over tokens.
local state = "args"
for i = 1, #tokens do
local token = tokens[i]
state = sm[state][token]
if not sm[state] then
return nil, state
end
end
return program, args, input, output, mode
end
local function parseCommands(command)
local tokens, reason = text.tokenize(command)
if not tokens then
return nil, reason
elseif #tokens == 0 then
return true
end
local commands, command = {}, {}
for i = 1, #tokens do
if tokens[i] == "|" then
if #command == 0 then
return nil, "parse error near '|'"
end
table.insert(commands, command)
command = {}
else
table.insert(command, tokens[i])
end
end
if #command > 0 then -- push tail command
table.insert(commands, command)
end
for i = 1, #commands do
commands[i] = table.pack(parseCommand(commands[i]))
if commands[i][1] == nil then
return nil, commands[i][2]
end
end
return commands
end
-------------------------------------------------------------------------------
local function execute(env, command, ...)
checkArg(1, command, "string")
local commands, reason = parseCommands(command)
if not commands then
return false, reason
end
if #commands == 0 then
return true
end
-- Piping data between programs works like so:
-- program1 gets its output replaced with our custom stream.
-- program2 gets its input replaced with our custom stream.
-- repeat for all programs
-- custom stream triggers execution of 'next' program after write.
-- custom stream triggers yield before read if buffer is empty.
-- custom stream may have 'redirect' entries for fallback/duplication.
local threads, pipes, inputs, outputs = {}, {}, {}, {}
for i = 1, #commands do
local program, args, input, output, mode = table.unpack(commands[i])
local reason
threads[i], reason = process.load(program, env, function()
os.setenv("_", program)
if input then
local file, reason = io.open(shell.resolve(input))
if not file then
error("could not open '" .. input .. "': " .. reason, 0)
end
table.insert(inputs, file)
if pipes[i - 1] then
pipes[i - 1].stream.redirect.read = file
io.input(pipes[i - 1])
else
io.input(file)
end
elseif pipes[i - 1] then
io.input(pipes[i - 1])
end
if output then
local file, reason = io.open(shell.resolve(output), mode == "append" and "a" or "w")
if not file then
error("could not open '" .. output .. "': " .. reason, 0)
end
if mode == "append" then
io.write("\n")
end
table.insert(outputs, file)
if pipes[i] then
pipes[i].stream.redirect.write = file
io.output(pipes[i])
else
io.output(file)
end
elseif pipes[i] then
io.output(pipes[i])
end
io.write('')
end, command)
if not threads[i] then
return false, reason
end
if i < #commands then
pipes[i] = require("buffer").new("rw", memoryStream.new())
pipes[i]:setvbuf("no")
end
if i > 1 then
pipes[i - 1].stream.next = threads[i]
pipes[i - 1].stream.args = args
end
end
local args = select(2, table.unpack(commands[1]))
for _, arg in ipairs(table.pack(...)) do
table.insert(args, arg)
end
table.insert(args, 1, true)
args.n = #args
local result = nil
for i = 1, #threads do
-- Emulate CC behavior by making yields a filtered event.pull()
while args[1] and coroutine.status(threads[i]) ~= "dead" do
result = table.pack(coroutine.resume(threads[i], table.unpack(args, 2, args.n)))
if coroutine.status(threads[i]) ~= "dead" then
args = table.pack(pcall(event.pull, table.unpack(result, 2, result.n)))
end
end
if pipes[i] then
pcall(pipes[i].close, pipes[i])
end
if not result[1] then
if type(result[2]) == "table" and result[2].reason == "terminated" then
if result[2].code then
result[1] = true
result.n = 1
else
result[2] = "terminated"
end
elseif type(result[2]) == "string" then
result[2] = debug.traceback(threads[i], result[2])
end
break
end
end
-- copy env vars from last process; mostly to ensure stuff like cd.lua works
local lastVars = rawget(process.info(threads[#threads]).data, "vars")
if lastVars then
local localVars = process.info().data.vars
for k,v in pairs(lastVars) do
localVars[k] = v
end
end
for _, input in ipairs(inputs) do
input:close()
end
for _, output in ipairs(outputs) do
output:close()
end
if not args[1] then
return false, args[2]
end
return table.unpack(result, 1, result.n)
end
local args, options = shell.parse(...)
local history = {}
local function escapeMagic(text)
return text:gsub('[%(%)%.%%%+%-%*%?%[%^%$]', '%%%1')
end
local function getMatchingPrograms(baseName)
local result = {}
-- TODO only matching files with .lua extension for now, might want to
-- extend this to other extensions at some point? env var? file attrs?
if not baseName or #baseName == 0 then
baseName = "^(.*)%.lua$"
else
baseName = "^(" .. escapeMagic(baseName) .. ".*)%.lua$"
end
for basePath in string.gmatch(os.getenv("PATH"), "[^:]+") do
for file in fs.list(basePath) do
local match = file:match(baseName)
if match then
table.insert(result, match)
end
end
end
return result
end
local function getMatchingFiles(partialPrefix, name)
local baseName = shell.resolve(partialPrefix .. name)
local result, basePath = {}
-- note: we strip the trailing / to make it easier to navigate through
-- directories using tab completion (since entering the / will then serve
-- as the intention to go into the currently hinted one).
-- if we have a directory but no trailing slash there may be alternatives
-- on the same level, so don't look inside that directory... (cont.)
if fs.isDirectory(baseName) and baseName:sub(-1) == "/" then
basePath = baseName
baseName = "^(.-)/?$"
else
basePath = fs.path(baseName) or "/"
baseName = "^(" .. escapeMagic(fs.name(baseName)) .. ".-)/?$"
end
for file in fs.list(basePath) do
local match = file:match(baseName)
if match then
table.insert(result, partialPrefix .. match)
end
end
-- (cont.) but if there's only one match and it's a directory, *then* we
-- do want to add the trailing slash here.
if #result == 1 and fs.isDirectory(result[1]) then
result[1] = result[1] .. "/"
end
return result
end
local function hintHandler(line, cursor)
local line = unicode.sub(line, 1, cursor - 1)
if not line or #line < 1 then
return nil
end
local result
local prefix, partial = string.match(line, "^(.+%s)(.+)$")
local searchInPath = not prefix and not line:find("/")
if searchInPath then
-- first part and no path, look for programs in the $PATH
result = getMatchingPrograms(line)
else -- just look normal files
local partialPrefix = (partial or line)
local name = fs.name(partialPrefix)
partialPrefix = partialPrefix:sub(1, -name:len() - 1)
result = getMatchingFiles(partialPrefix, name)
end
local resultSuffix = ""
if searchInPath then
resultSuffix = " "
elseif #result == 1 and result[1]:sub(-1) ~= '/' then
resultSuffix = " "
end
prefix = prefix or ""
for i = 1, #result do
result[i] = prefix .. result[i] .. resultSuffix
end
table.sort(result)
return result
end
if #args == 0 and (io.input() == io.stdin or options.i) and not options.c then
-- interactive shell.
while true do
if not term.isAvailable() then -- don't clear unless we lost the term
while not term.isAvailable() do
event.pull("term_available")
end
term.clear()
end
while term.isAvailable() do
local foreground = component.gpu.setForeground(0xFF0000)
term.write(expand(os.getenv("PS1") or "$ "))
component.gpu.setForeground(foreground)
local command = term.read(history, nil, hintHandler)
if not command then
term.write("exit\n")
return -- eof
end
while #history > (tonumber(os.getenv("HISTSIZE")) or 10) do
table.remove(history, 1)
end
command = text.trim(command)
if command == "exit" then
return
elseif command ~= "" then
local result, reason = os.execute(command)
if term.getCursor() > 1 then
term.write("\n")
end
if not result then
io.stderr:write((reason and tostring(reason) or "unknown error") .. "\n")
end
end
end
end
elseif #args == 0 and (io.input() ~= io.stdin) then
while true do
io.write(expand(os.getenv("PS1") or "$ "))
local command = io.read("*l")
if not command then
io.write("exit\n")
end
command = text.trim(command)
if command == "exit" then
return
elseif command ~= "" then
local result, reason = os.execute(command)
if not result then
io.stderr:write((reason and tostring(reason) or "unknown error") .. "\n")
end
end
end
else
-- execute command.
local result = table.pack(execute(...))
if not result[1] then
error(result[2], 0)
end
return table.unpack(result, 2)
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@shutdown.lua
local computer = require("computer")
local term = require("term")
term.clear()
computer.shutdown()
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@umount.lua
local fs = require("filesystem")
local shell = require("shell")
local args, options = shell.parse(...)
if #args < 1 then
io.write("Usage: umount [-a] <mount>\n")
io.write(" -a Remove any mounts by file system label or address instead of by path. Note that the address may be abbreviated.")
return
end
local proxy, reason
if options.a then
proxy, reason = fs.proxy(args[1])
if proxy then
proxy = proxy.address
end
else
local path = shell.resolve(args[1])
proxy, reason = fs.get(path)
if proxy then
proxy = reason -- = path
if proxy ~= path then
io.stderr:write("not a mount point")
return
end
end
end
if not proxy then
io.stderr:write(reason)
return
end
if not fs.umount(proxy) then
io.stderr:write("nothing to unmount here")
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@unalias.lua
local shell = require("shell")
local args = shell.parse(...)
if #args < 1 then
io.write("Usage: unalias <name>")
return
end
local result = shell.getAlias(args[1])
if not result then
io.stderr:write("no such alias")
else
shell.setAlias(args[1], nil)
io.write("alias removed: " .. args[1] .. " -> " .. result)
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@unset.lua
local args = {...}
if #args < 1 then
io.write("Usage: unset <varname>[ <varname2> [...]]\n")
else
for _, k in ipairs(args) do
os.setenv(k, nil)
end
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@uptime.lua
local computer = require("computer")
local seconds = math.floor(computer.uptime())
local minutes, hours = 0, 0
if seconds >= 60 then
minutes = math.floor(seconds / 60)
seconds = seconds % 60
end
if minutes >= 60 then
hours = math.floor(minutes / 60)
minutes = minutes % 60
end
io.write(string.format("%02d:%02d:%02d", hours, minutes, seconds))
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@useradd.lua
local computer = require("computer")
local shell = require("shell")
local args = shell.parse(...)
if #args < 1 then
io.write("Usage: useradd <name>")
return
end
local result, reason = computer.addUser(args[1])
if not result then
io.stderr:write(reason)
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@userdel.lua
local computer = require("computer")
local shell = require("shell")
local args = shell.parse(...)
if #args < 1 then
io.write("Usage: userdel <name>")
return
end
if not computer.removeUser(args[1]) then
io.stderr:write("no such user")
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@wget.lua
local component = require("component")
local fs = require("filesystem")
local internet = require("internet")
local shell = require("shell")
local text = require("text")
if not component.isAvailable("internet") then
io.stderr:write("This program requires an internet card to run.")
return
end
local args, options = shell.parse(...)
options.q = options.q or options.Q
if #args < 1 then
io.write("Usage: wget [-fq] <url> [<filename>]\n")
io.write(" -f: Force overwriting existing files.\n")
io.write(" -q: Quiet mode - no status messages.\n")
io.write(" -Q: Superquiet mode - no error messages.")
return
end
local url = text.trim(args[1])
local filename = args[2]
if not filename then
filename = url
local index = string.find(filename, "/[^/]*$")
if index then
filename = string.sub(filename, index + 1)
end
index = string.find(filename, "?", 1, true)
if index then
filename = string.sub(filename, 1, index - 1)
end
end
filename = text.trim(filename)
if filename == "" then
if not options.Q then
io.stderr:write("could not infer filename, please specify one")
end
return nil, "missing target filename" -- for programs using wget as a function
end
filename = shell.resolve(filename)
if fs.exists(filename) then
if not options.f or not os.remove(filename) then
if not options.Q then
io.stderr:write("file already exists")
end
return nil, "file already exists" -- for programs using wget as a function
end
end
local f, reason = io.open(filename, "wb")
if not f then
if not options.Q then
io.stderr:write("failed opening file for writing: " .. reason)
end
return nil, "failed opening file for writing: " .. reason -- for programs using wget as a function
end
if not options.q then
io.write("Downloading... ")
end
local result, response = pcall(internet.request, url)
if result then
local result, reason = pcall(function()
for chunk in response do
f:write(chunk)
end
end)
if not result then
if not options.q then
io.stderr:write("failed.\n")
end
f:close()
fs.remove(filename)
if not options.Q then
io.stderr:write("HTTP request failed: " .. reason .. "\n")
end
return nil, reason -- for programs using wget as a function
end
if not options.q then
io.write("success.\n")
end
f:close()
if not options.q then
io.write("Saved data to " .. filename .. "\n")
end
else
if not options.q then
io.write("failed.\n")
end
f:close()
fs.remove(filename)
if not options.Q then
io.stderr:write("HTTP request failed: " .. response .. "\n")
end
return nil, response -- for programs using wget as a function
end
return true -- for programs using wget as a function
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@which.lua
local shell = require("shell")
local args = shell.parse(...)
if #args == 0 then
io.write("Usage: which <program>")
return
end
for i = 1, #args do
local result, reason = shell.getAlias(args[i])
if result then
result = args[i] .. ": aliased to " .. result
else
result, reason = shell.resolve(args[i], "lua")
end
if result then
io.write(result .. "\n")
else
io.stderr:write(args[i] .. ": " .. reason .. "\n")
end
end
--@luaPackageFileEnd
--@luaPackageFileSeparator
--@yes.lua
--[[Lua implementation of the UN*X yes command--]]
local shell = require("shell")
local args, options = shell.parse(...)
if options.V or options.version then
io.write("yes v:1.0-2\n")
io.write("Inspired by functionality of yes from GNU coreutils\n")
return 0
end
if options.h or options.help then
io.write("Usage: yes [string]...\n")
io.write("OR: yes [-V/h]\n")
io.write("\n")
io.write("yes prints the command line arguments, or 'y', until is killed.\n")
io.write("\n")
io.write("Options:\n")
io.write(" -V, --version Version\n")
io.write(" -h, --help This help\n")
return 0
end
-- If there are no arguments, print 'y' and new line, if there is print it.
if #args == 0 then
while pcall(io.write, "y\n") do
os.sleep(0)
end
else
repeat
local ok = true
for i=1, #args, 1 do
ok = ok and pcall(io.write, args[i], " ")
end
pcall(io.write, "\n")
os.sleep(0)
until not ok
end
return 0
--@luaPackageFileEnd