mirror of
https://github.com/20kdc/OC-KittenOS.git
synced 2024-11-23 10:58:06 +11:00
Merge branch 'master' into repository
This commit is contained in:
commit
8bd316338b
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,8 +1,6 @@
|
|||||||
# This is released into the public domain.
|
# This is released into the public domain.
|
||||||
# No warranty is provided, implied or otherwise.
|
# No warranty is provided, implied or otherwise.
|
||||||
|
|
||||||
# leaving in preSH.tar.gz for anyone who's interested
|
|
||||||
# in how NOT to do compression
|
|
||||||
code.tar
|
code.tar
|
||||||
code/data/app-claw/*
|
code/data/app-claw/*
|
||||||
work.tar
|
work.tar
|
||||||
@ -32,7 +30,9 @@ laboratory/*/*/*/*
|
|||||||
inst.lua
|
inst.lua
|
||||||
# Available as the respective release
|
# Available as the respective release
|
||||||
inst-gold.lua
|
inst-gold.lua
|
||||||
com2/code.tar.bd
|
# Compression stuff
|
||||||
|
inst/iSymTab
|
||||||
|
# internal
|
||||||
upldr.sh
|
upldr.sh
|
||||||
upldr-dev.sh
|
upldr-dev.sh
|
||||||
upldr-gold.sh
|
upldr-gold.sh
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
return {
|
return {
|
||||||
["neo"] = {
|
["neo"] = {
|
||||||
desc = "KittenOS NEO Kernel & Base Libs",
|
desc = "KittenOS NEO Kernel & Base Libs",
|
||||||
v = 8,
|
v = 9,
|
||||||
deps = {
|
deps = {
|
||||||
},
|
},
|
||||||
dirs = {
|
dirs = {
|
||||||
@ -18,6 +18,7 @@ return {
|
|||||||
"libs/serial.lua",
|
"libs/serial.lua",
|
||||||
"libs/fmttext.lua",
|
"libs/fmttext.lua",
|
||||||
"libs/neoux.lua",
|
"libs/neoux.lua",
|
||||||
|
"libs/lineedit.lua",
|
||||||
"libs/braille.lua",
|
"libs/braille.lua",
|
||||||
"libs/bmp.lua",
|
"libs/bmp.lua",
|
||||||
"libs/sys-filewrap.lua",
|
"libs/sys-filewrap.lua",
|
||||||
@ -54,7 +55,7 @@ return {
|
|||||||
},
|
},
|
||||||
["neo-everest"] = {
|
["neo-everest"] = {
|
||||||
desc = "KittenOS NEO / Everest (windowing)",
|
desc = "KittenOS NEO / Everest (windowing)",
|
||||||
v = 5,
|
v = 9,
|
||||||
deps = {
|
deps = {
|
||||||
"neo"
|
"neo"
|
||||||
},
|
},
|
||||||
@ -67,7 +68,7 @@ return {
|
|||||||
},
|
},
|
||||||
["neo-icecap"] = {
|
["neo-icecap"] = {
|
||||||
desc = "KittenOS NEO / Icecap",
|
desc = "KittenOS NEO / Icecap",
|
||||||
v = 8,
|
v = 9,
|
||||||
deps = {
|
deps = {
|
||||||
"neo"
|
"neo"
|
||||||
},
|
},
|
||||||
@ -84,7 +85,7 @@ return {
|
|||||||
},
|
},
|
||||||
["neo-secpolicy"] = {
|
["neo-secpolicy"] = {
|
||||||
desc = "KittenOS NEO / Secpolicy",
|
desc = "KittenOS NEO / Secpolicy",
|
||||||
v = 8,
|
v = 9,
|
||||||
deps = {
|
deps = {
|
||||||
},
|
},
|
||||||
dirs = {
|
dirs = {
|
||||||
@ -96,7 +97,7 @@ return {
|
|||||||
},
|
},
|
||||||
["neo-coreapps"] = {
|
["neo-coreapps"] = {
|
||||||
desc = "KittenOS NEO Core Apps",
|
desc = "KittenOS NEO Core Apps",
|
||||||
v = 5,
|
v = 9,
|
||||||
deps = {
|
deps = {
|
||||||
"neo"
|
"neo"
|
||||||
},
|
},
|
||||||
@ -125,7 +126,7 @@ return {
|
|||||||
},
|
},
|
||||||
["neo-logo"] = {
|
["neo-logo"] = {
|
||||||
desc = "KittenOS NEO Logo (data)",
|
desc = "KittenOS NEO Logo (data)",
|
||||||
v = 8,
|
v = 9,
|
||||||
deps = {
|
deps = {
|
||||||
},
|
},
|
||||||
dirs = {
|
dirs = {
|
||||||
@ -175,6 +176,20 @@ return {
|
|||||||
"apps/svc-app-claw-worker.lua"
|
"apps/svc-app-claw-worker.lua"
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
["svc-t"] = {
|
||||||
|
desc = "KittenOS NEO Terminal System",
|
||||||
|
v = 9,
|
||||||
|
deps = {
|
||||||
|
"neo"
|
||||||
|
},
|
||||||
|
dirs = {
|
||||||
|
"apps"
|
||||||
|
},
|
||||||
|
files = {
|
||||||
|
"apps/svc-t.lua",
|
||||||
|
"apps/app-luashell.lua"
|
||||||
|
},
|
||||||
|
},
|
||||||
["neo-meta"] = {
|
["neo-meta"] = {
|
||||||
desc = "KittenOS NEO: Use 'All' to install to other disks",
|
desc = "KittenOS NEO: Use 'All' to install to other disks",
|
||||||
v = 5,
|
v = 5,
|
||||||
@ -190,6 +205,7 @@ return {
|
|||||||
"app-bmpview",
|
"app-bmpview",
|
||||||
"app-flash",
|
"app-flash",
|
||||||
"app-claw",
|
"app-claw",
|
||||||
|
"svc-t",
|
||||||
"app-wget"
|
"app-wget"
|
||||||
},
|
},
|
||||||
dirs = {
|
dirs = {
|
||||||
|
@ -24,7 +24,7 @@ return {
|
|||||||
},
|
},
|
||||||
["neo-docs"] = {
|
["neo-docs"] = {
|
||||||
desc = "KittenOS NEO system documentation",
|
desc = "KittenOS NEO system documentation",
|
||||||
v = 8,
|
v = 9,
|
||||||
deps = {
|
deps = {
|
||||||
"zzz-license-pd"
|
"zzz-license-pd"
|
||||||
},
|
},
|
||||||
@ -43,6 +43,7 @@ return {
|
|||||||
"docs/us-setti",
|
"docs/us-setti",
|
||||||
"docs/us-evrst",
|
"docs/us-evrst",
|
||||||
"docs/us-clawf",
|
"docs/us-clawf",
|
||||||
|
"docs/us-termi",
|
||||||
"docs/ul-seria",
|
"docs/ul-seria",
|
||||||
"docs/ul-fwrap",
|
"docs/ul-fwrap",
|
||||||
"docs/ul-event",
|
"docs/ul-event",
|
||||||
@ -50,6 +51,7 @@ return {
|
|||||||
"docs/ul-neoux",
|
"docs/ul-neoux",
|
||||||
"docs/ul-brail",
|
"docs/ul-brail",
|
||||||
"docs/ul-bmp__",
|
"docs/ul-bmp__",
|
||||||
|
"docs/ul-linee",
|
||||||
"docs/gp-pedan",
|
"docs/gp-pedan",
|
||||||
"docs/repoauthors/neo-docs"
|
"docs/repoauthors/neo-docs"
|
||||||
},
|
},
|
||||||
@ -89,11 +91,12 @@ return {
|
|||||||
"docs/repoauthors/app-allmem"
|
"docs/repoauthors/app-allmem"
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
["app-kmt"] = {
|
["app-telnet"] = {
|
||||||
desc = "Line-terminal for MUDs & such",
|
desc = "TELNET client",
|
||||||
v = 1,
|
v = 0,
|
||||||
deps = {
|
deps = {
|
||||||
"neo",
|
"neo",
|
||||||
|
"svc-t",
|
||||||
"zzz-license-pd"
|
"zzz-license-pd"
|
||||||
},
|
},
|
||||||
dirs = {
|
dirs = {
|
||||||
@ -102,8 +105,8 @@ return {
|
|||||||
"docs/repoauthors"
|
"docs/repoauthors"
|
||||||
},
|
},
|
||||||
files = {
|
files = {
|
||||||
"apps/app-kmt.lua",
|
"apps/app-telnet.lua",
|
||||||
"docs/repoauthors/app-kmt"
|
"docs/repoauthors/app-telnet"
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
["svc-ghostie"] = {
|
["svc-ghostie"] = {
|
||||||
|
@ -226,7 +226,7 @@ window = neoux.create(currentGen())
|
|||||||
while running do
|
while running do
|
||||||
local src, id, k, v = event.pull()
|
local src, id, k, v = event.pull()
|
||||||
if src == "x.neo.sys.manage" then
|
if src == "x.neo.sys.manage" then
|
||||||
if id == "set_setting" then
|
if id == "set_setting" and currentGen ~= logGen then
|
||||||
window.reset(currentGen())
|
window.reset(currentGen())
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
164
code/apps/app-luashell.lua
Normal file
164
code/apps/app-luashell.lua
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
-- This is released into the public domain.
|
||||||
|
-- No warranty is provided, implied or otherwise.
|
||||||
|
|
||||||
|
local _, _, termId = ...
|
||||||
|
local ok = pcall(function ()
|
||||||
|
assert(string.sub(termId, 1, 12) == "x.neo.pub.t/")
|
||||||
|
end)
|
||||||
|
|
||||||
|
local termClose
|
||||||
|
|
||||||
|
if not ok then
|
||||||
|
termId = nil
|
||||||
|
assert(neo.executeAsync("svc-t", function (res)
|
||||||
|
termId = res.access
|
||||||
|
termClose = res.close
|
||||||
|
neo.scheduleTimer(0)
|
||||||
|
end, "luashell"))
|
||||||
|
while not termId do
|
||||||
|
coroutine.yield()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
TERM = neo.requireAccess(termId, "terminal")
|
||||||
|
|
||||||
|
-- Using event makes it easier for stuff
|
||||||
|
-- within the shell to not spectacularly explode.
|
||||||
|
event = require("event")(neo)
|
||||||
|
|
||||||
|
local alive = true
|
||||||
|
event.listen("k.procdie", function (_, _, pid)
|
||||||
|
if pid == TERM.pid then
|
||||||
|
alive = false
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
TERM.write([[
|
||||||
|
KittenOS NEO Shell Usage Notes
|
||||||
|
|
||||||
|
Prefixing = is an alias for 'return '.
|
||||||
|
io.read(): Reads a line.
|
||||||
|
print: 'print with table dumping' impl.
|
||||||
|
TERM: Your terminal. (see us-termi doc.)
|
||||||
|
os.execute(): launch terminal apps!
|
||||||
|
tries '*', 'sys-t-*', 'svc-t-*', 'app-*'
|
||||||
|
example: os.execute("luashell")
|
||||||
|
os.exit(): quit the shell
|
||||||
|
=listCmdApps(): -t- (terminal) apps
|
||||||
|
event: useful for setting up listeners
|
||||||
|
without breaking shell functionality
|
||||||
|
]])
|
||||||
|
|
||||||
|
function listCmdApps()
|
||||||
|
local apps = {}
|
||||||
|
for _, v in ipairs(neo.listApps()) do
|
||||||
|
if v:sub(4, 6) == "-t-" then
|
||||||
|
table.insert(apps, v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return apps
|
||||||
|
end
|
||||||
|
|
||||||
|
local function vPrint(slike, ...)
|
||||||
|
local s = {...}
|
||||||
|
if #s > 1 then
|
||||||
|
for i = 1, #s do
|
||||||
|
if i ~= 1 then TERM.write("\t") end
|
||||||
|
vPrint(slike, s[i])
|
||||||
|
end
|
||||||
|
elseif slike and type(s[1]) == "string" then
|
||||||
|
TERM.write("\"" .. s[1] .. "\"")
|
||||||
|
elseif type(s[1]) ~= "table" then
|
||||||
|
TERM.write(tostring(s[1]))
|
||||||
|
else
|
||||||
|
TERM.write("{")
|
||||||
|
for k, v in pairs(s[1]) do
|
||||||
|
TERM.write("[")
|
||||||
|
vPrint(true, k)
|
||||||
|
TERM.write("] = ")
|
||||||
|
vPrint(true, v)
|
||||||
|
TERM.write(", ")
|
||||||
|
end
|
||||||
|
TERM.write("}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
print = function (...)
|
||||||
|
vPrint(false, ...)
|
||||||
|
TERM.write("\r\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
local ioBuffer = ""
|
||||||
|
|
||||||
|
io = {
|
||||||
|
read = function ()
|
||||||
|
while alive do
|
||||||
|
local pos = ioBuffer:find("\n")
|
||||||
|
if pos then
|
||||||
|
local line = ioBuffer:sub(1, pos):gsub("\r", "")
|
||||||
|
ioBuffer = ioBuffer:sub(pos + 1)
|
||||||
|
return line
|
||||||
|
end
|
||||||
|
local e = {event.pull()}
|
||||||
|
if e[1] == TERM.id then
|
||||||
|
if e[2] == "data" then
|
||||||
|
ioBuffer = ioBuffer .. e[3]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
write = function (s) TERM.write(s) end
|
||||||
|
}
|
||||||
|
|
||||||
|
local originalOS = os
|
||||||
|
os = setmetatable({}, {
|
||||||
|
__index = originalOS
|
||||||
|
})
|
||||||
|
|
||||||
|
function os.exit()
|
||||||
|
alive = false
|
||||||
|
end
|
||||||
|
|
||||||
|
function os.execute(x, ...)
|
||||||
|
local subPid = neo.executeAsync(x, TERM.id, ...)
|
||||||
|
if not subPid then
|
||||||
|
subPid = neo.executeAsync("sys-t-" .. x, TERM.id, ...)
|
||||||
|
end
|
||||||
|
if not subPid then
|
||||||
|
subPid = neo.executeAsync("svc-t-" .. x, TERM.id, ...)
|
||||||
|
end
|
||||||
|
if not subPid then
|
||||||
|
subPid = neo.executeAsync("app-" .. x, TERM.id, ...)
|
||||||
|
end
|
||||||
|
if not subPid then
|
||||||
|
error("cannot find " .. x)
|
||||||
|
end
|
||||||
|
while true do
|
||||||
|
local e = {event.pull()}
|
||||||
|
if e[1] == "k.procdie" then
|
||||||
|
if e[3] == subPid then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
while alive do
|
||||||
|
TERM.write("> ")
|
||||||
|
local code = io.read()
|
||||||
|
if code then
|
||||||
|
local ok, err = pcall(function ()
|
||||||
|
if code:sub(1, 1) == "=" then
|
||||||
|
code = "return " .. code:sub(2)
|
||||||
|
end
|
||||||
|
print(assert(load(code))())
|
||||||
|
end)
|
||||||
|
if not ok then
|
||||||
|
TERM.write(tostring(err) .. "\r\n")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if termClose then
|
||||||
|
termClose()
|
||||||
|
end
|
||||||
|
|
@ -30,32 +30,17 @@ local clipsrc = neo.requireAccess("x.neo.pub.globals", "clipboard")
|
|||||||
local windows = neo.requireAccess("x.neo.pub.window", "windows")
|
local windows = neo.requireAccess("x.neo.pub.window", "windows")
|
||||||
local files = neo.requireAccess("x.neo.pub.base", "files").showFileDialogAsync
|
local files = neo.requireAccess("x.neo.pub.base", "files").showFileDialogAsync
|
||||||
|
|
||||||
|
local lineEdit = require("lineedit")
|
||||||
|
|
||||||
local cursorX = 1
|
local cursorX = 1
|
||||||
local cursorY = math.ceil(#lines / 2)
|
local cursorY = math.ceil(#lines / 2)
|
||||||
local cFlash = true
|
local ctrlFlag, appendFlag
|
||||||
local ctrlFlag, focFlag, appendFlag
|
|
||||||
local dialogLock = false
|
local dialogLock = false
|
||||||
local sW, sH = 37, #lines + 2
|
local sW, sH = 37, #lines + 2
|
||||||
local window = windows(sW, sH)
|
local window = windows(sW, sH)
|
||||||
local filedialog = nil
|
local filedialog = nil
|
||||||
local flush
|
local flush
|
||||||
|
|
||||||
local function splitCur()
|
|
||||||
local s = lines[cursorY]
|
|
||||||
local st = unicode.sub(s, 1, cursorX - 1)
|
|
||||||
local en = unicode.sub(s, cursorX)
|
|
||||||
return st, en
|
|
||||||
end
|
|
||||||
|
|
||||||
local function clampCursorX()
|
|
||||||
local s = lines[cursorY]
|
|
||||||
if unicode.len(s) < (cursorX - 1) then
|
|
||||||
cursorX = unicode.len(s) + 1
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
local cbs = {}
|
local cbs = {}
|
||||||
|
|
||||||
local function fileDialog(writing, callback)
|
local function fileDialog(writing, callback)
|
||||||
@ -139,31 +124,14 @@ local function getline(y)
|
|||||||
-- rX is difficult!
|
-- rX is difficult!
|
||||||
local rX = 1
|
local rX = 1
|
||||||
local Xthold = math.max(1, math.floor(sW / 2) - 1)
|
local Xthold = math.max(1, math.floor(sW / 2) - 1)
|
||||||
local _, cursorXP = unicode.safeTextFormat(lines[cursorY], cursorX)
|
local cLine, cursorXP = unicode.safeTextFormat(lines[cursorY], cursorX)
|
||||||
rX = (math.max(0, math.floor(cursorXP / Xthold) - 1) * Xthold) + 1
|
rX = (math.max(0, math.floor(cursorXP / Xthold) - 1) * Xthold) + 1
|
||||||
local line = lines[rY]
|
local line = lines[rY]
|
||||||
if not line then
|
if not line then
|
||||||
return ("¬"):rep(sW)
|
return ("¬"):rep(sW)
|
||||||
end
|
end
|
||||||
line = unicode.safeTextFormat(line)
|
line = unicode.safeTextFormat(line)
|
||||||
-- <alter RX here by 1 if needed>
|
return lineEdit.draw(sW, line, rY == cursorY and cursorXP, rX)
|
||||||
local tl = unicode.sub(line, rX, rX + sW - 1)
|
|
||||||
cursorXP = (cursorXP - rX) + 1
|
|
||||||
if cFlash then
|
|
||||||
if rY == cursorY then
|
|
||||||
if cursorXP >= 1 then
|
|
||||||
if cursorXP <= sW then
|
|
||||||
local start = unicode.sub(tl, 1, cursorXP - 1)
|
|
||||||
local endx = unicode.sub(tl, cursorXP + 1)
|
|
||||||
tl = start .. "_" .. endx
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
while unicode.len(tl) < sW do
|
|
||||||
tl = tl .. " "
|
|
||||||
end
|
|
||||||
return tl
|
|
||||||
end
|
end
|
||||||
local function delLine()
|
local function delLine()
|
||||||
local contents = lines[cursorY]
|
local contents = lines[cursorY]
|
||||||
@ -179,22 +147,7 @@ local function delLine()
|
|||||||
end
|
end
|
||||||
return contents
|
return contents
|
||||||
end
|
end
|
||||||
-- add a single character
|
local function key(ks, kc, down)
|
||||||
local function putLetter(ch)
|
|
||||||
if ch == "\r" then
|
|
||||||
local a, b = splitCur()
|
|
||||||
lines[cursorY] = a
|
|
||||||
table.insert(lines, cursorY + 1, b)
|
|
||||||
cursorY = cursorY + 1
|
|
||||||
cursorX = 1
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local a, b = splitCur()
|
|
||||||
a = a .. ch
|
|
||||||
lines[cursorY] = a .. b
|
|
||||||
cursorX = unicode.len(a) + 1
|
|
||||||
end
|
|
||||||
local function key(ka, kc, down)
|
|
||||||
if dialogLock then
|
if dialogLock then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
@ -212,18 +165,22 @@ local function key(ka, kc, down)
|
|||||||
sH = 1
|
sH = 1
|
||||||
end
|
end
|
||||||
sW, sH = window.setSize(sW, sH)
|
sW, sH = window.setSize(sW, sH)
|
||||||
|
return false
|
||||||
elseif kc == 208 then -- Down
|
elseif kc == 208 then -- Down
|
||||||
sH = sH + 1
|
sH = sH + 1
|
||||||
sW, sH = window.setSize(sW, sH)
|
sW, sH = window.setSize(sW, sH)
|
||||||
|
return false
|
||||||
elseif kc == 203 then -- Left
|
elseif kc == 203 then -- Left
|
||||||
sW = sW - 1
|
sW = sW - 1
|
||||||
if sW == 0 then
|
if sW == 0 then
|
||||||
sW = 1
|
sW = 1
|
||||||
end
|
end
|
||||||
sW, sH = window.setSize(sW, sH)
|
sW, sH = window.setSize(sW, sH)
|
||||||
|
return false
|
||||||
elseif kc == 205 then -- Right
|
elseif kc == 205 then -- Right
|
||||||
sW = sW + 1
|
sW = sW + 1
|
||||||
sW, sH = window.setSize(sW, sH)
|
sW, sH = window.setSize(sW, sH)
|
||||||
|
return false
|
||||||
elseif kc == 14 then -- ^Backspace
|
elseif kc == 14 then -- ^Backspace
|
||||||
delLine()
|
delLine()
|
||||||
return true
|
return true
|
||||||
@ -240,7 +197,7 @@ local function key(ka, kc, down)
|
|||||||
if cursorY < 1 then
|
if cursorY < 1 then
|
||||||
cursorY = 1
|
cursorY = 1
|
||||||
end
|
end
|
||||||
clampCursorX()
|
cursorX = lineEdit.clamp(lines[cursorY], cursorX)
|
||||||
return true
|
return true
|
||||||
elseif kc == 208 or kc == 209 then -- Go down one - go down page
|
elseif kc == 208 or kc == 209 then -- Go down one - go down page
|
||||||
local moveAmount = 1
|
local moveAmount = 1
|
||||||
@ -251,36 +208,7 @@ local function key(ka, kc, down)
|
|||||||
if cursorY > #lines then
|
if cursorY > #lines then
|
||||||
cursorY = #lines
|
cursorY = #lines
|
||||||
end
|
end
|
||||||
clampCursorX()
|
cursorX = lineEdit.clamp(lines[cursorY], cursorX)
|
||||||
return true
|
|
||||||
elseif kc == 203 then
|
|
||||||
if cursorX > 1 then
|
|
||||||
cursorX = cursorX - 1
|
|
||||||
else
|
|
||||||
if cursorY > 1 then
|
|
||||||
cursorY = cursorY - 1
|
|
||||||
cursorX = unicode.len(lines[cursorY]) + 1
|
|
||||||
else
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
elseif kc == 205 then
|
|
||||||
cursorX = cursorX + 1
|
|
||||||
if clampCursorX() then
|
|
||||||
if cursorY < #lines then
|
|
||||||
cursorY = cursorY + 1
|
|
||||||
cursorX = 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
-- Extra Non-Control Keys
|
|
||||||
if kc == 199 then
|
|
||||||
cursorX = 1
|
|
||||||
return true
|
|
||||||
elseif kc == 207 then
|
|
||||||
cursorX = unicode.len(lines[cursorY]) + 1
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
-- Major Actions
|
-- Major Actions
|
||||||
@ -291,10 +219,13 @@ local function key(ka, kc, down)
|
|||||||
return true
|
return true
|
||||||
elseif kc == 61 then -- F3
|
elseif kc == 61 then -- F3
|
||||||
startLoad()
|
startLoad()
|
||||||
|
return false
|
||||||
elseif kc == 62 then -- F4
|
elseif kc == 62 then -- F4
|
||||||
startSave()
|
startSave()
|
||||||
|
return false
|
||||||
elseif kc == 63 then -- F5
|
elseif kc == 63 then -- F5
|
||||||
clipsrc.setSetting("clipboard", lines[cursorY])
|
clipsrc.setSetting("clipboard", lines[cursorY])
|
||||||
|
return false
|
||||||
elseif kc == 64 then -- F6
|
elseif kc == 64 then -- F6
|
||||||
local tx = clipsrc.getSetting("clipboard") or ""
|
local tx = clipsrc.getSetting("clipboard") or ""
|
||||||
local txi = tx:find("\n")
|
local txi = tx:find("\n")
|
||||||
@ -311,6 +242,7 @@ local function key(ka, kc, down)
|
|||||||
return true
|
return true
|
||||||
elseif kc == 65 then -- F7
|
elseif kc == 65 then -- F7
|
||||||
appendFlag = false
|
appendFlag = false
|
||||||
|
return false
|
||||||
elseif kc == 66 then -- F8
|
elseif kc == 66 then -- F8
|
||||||
if appendFlag then
|
if appendFlag then
|
||||||
local base = clipsrc.getSetting("clipboard")
|
local base = clipsrc.getSetting("clipboard")
|
||||||
@ -322,29 +254,37 @@ local function key(ka, kc, down)
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- Letters
|
-- LEL Keys
|
||||||
if ka == 8 or kc == 211 then
|
local lT, lC, lX = lineEdit.key(ks, kc, lines[cursorY], cursorX)
|
||||||
if cursorX == 1 then
|
if lT then
|
||||||
if cursorY == 1 then
|
lines[cursorY] = lT
|
||||||
return false
|
|
||||||
end
|
|
||||||
local l = table.remove(lines, cursorY)
|
|
||||||
cursorY = cursorY - 1
|
|
||||||
cursorX = unicode.len(lines[cursorY]) + 1
|
|
||||||
lines[cursorY] = lines[cursorY] .. l
|
|
||||||
else
|
|
||||||
local a, b = splitCur()
|
|
||||||
a = unicode.sub(a, 1, unicode.len(a) - 1)
|
|
||||||
lines[cursorY] = a.. b
|
|
||||||
cursorX = cursorX - 1
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
end
|
||||||
if ka ~= 0 then
|
if lC then
|
||||||
putLetter(unicode.char(ka))
|
cursorX = lC
|
||||||
return true
|
|
||||||
end
|
end
|
||||||
return false
|
if lX == "l<" and cursorY > 1 then
|
||||||
|
cursorY = cursorY - 1
|
||||||
|
cursorX = unicode.len(lines[cursorY]) + 1
|
||||||
|
elseif lX == "l>" and cursorY < #lines then
|
||||||
|
cursorY = cursorY + 1
|
||||||
|
cursorX = 1
|
||||||
|
elseif lX == "w<" and cursorY ~= 1 then
|
||||||
|
local l = table.remove(lines, cursorY)
|
||||||
|
cursorY = cursorY - 1
|
||||||
|
cursorX = unicode.len(lines[cursorY]) + 1
|
||||||
|
lines[cursorY] = lines[cursorY] .. l
|
||||||
|
elseif lX == "w>" and cursorY ~= #lines then
|
||||||
|
local l = table.remove(lines, cursorY)
|
||||||
|
cursorX = unicode.len(l) + 1
|
||||||
|
lines[cursorY] = l .. lines[cursorY]
|
||||||
|
elseif lX == "nl" then
|
||||||
|
local line = lines[cursorY]
|
||||||
|
lines[cursorY] = unicode.sub(line, 1, cursorX - 1)
|
||||||
|
table.insert(lines, cursorY + 1, unicode.sub(line, cursorX))
|
||||||
|
cursorX = 1
|
||||||
|
cursorY = cursorY + 1
|
||||||
|
end
|
||||||
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
flush = function ()
|
flush = function ()
|
||||||
@ -353,16 +293,9 @@ flush = function ()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
neo.scheduleTimer(os.uptime() + 0.5)
|
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
local e = {coroutine.yield()}
|
local e = {coroutine.yield()}
|
||||||
if e[1] == "k.timer" and e[2] == focFlag then
|
if e[1] == "x.neo.pub.window" then
|
||||||
cFlash = not cFlash
|
|
||||||
local csY = math.ceil(sH / 2)
|
|
||||||
window.span(1, csY, getline(csY), 0xFFFFFF, 0)
|
|
||||||
focFlag = neo.scheduleTimer(os.uptime() + 0.5)
|
|
||||||
elseif e[1] == "x.neo.pub.window" then
|
|
||||||
if e[2] == window.id then
|
if e[2] == window.id then
|
||||||
if e[3] == "line" then
|
if e[3] == "line" then
|
||||||
window.span(1, e[4], getline(e[4]), 0xFFFFFF, 0)
|
window.span(1, e[4], getline(e[4]), 0xFFFFFF, 0)
|
||||||
@ -373,14 +306,13 @@ while true do
|
|||||||
local csY = math.ceil(sH / 2)
|
local csY = math.ceil(sH / 2)
|
||||||
local nY = math.max(1, math.min(#lines, (math.floor(e[5]) - csY) + cursorY))
|
local nY = math.max(1, math.min(#lines, (math.floor(e[5]) - csY) + cursorY))
|
||||||
cursorY = nY
|
cursorY = nY
|
||||||
clampCursorX()
|
cursorX = lineEdit.clamp(lines[cursorY], cursorX)
|
||||||
flush()
|
flush()
|
||||||
elseif e[3] == "key" then
|
elseif e[3] == "key" then
|
||||||
if key(e[4], e[5], e[6]) then
|
if key(e[4] ~= 0 and unicode.char(e[4]), e[5], e[6]) then
|
||||||
flush()
|
flush()
|
||||||
end
|
end
|
||||||
elseif e[3] == "focus" then
|
elseif e[3] == "focus" then
|
||||||
focFlag = e[4] and neo.scheduleTimer(0)
|
|
||||||
ctrlFlag = false
|
ctrlFlag = false
|
||||||
elseif e[3] == "close" then
|
elseif e[3] == "close" then
|
||||||
return
|
return
|
||||||
@ -392,7 +324,7 @@ while true do
|
|||||||
if c == "\n" then
|
if c == "\n" then
|
||||||
c = "\r"
|
c = "\r"
|
||||||
end
|
end
|
||||||
putLetter(c)
|
key(c, 0, true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
flush()
|
flush()
|
||||||
|
491
code/apps/svc-t.lua
Normal file
491
code/apps/svc-t.lua
Normal file
@ -0,0 +1,491 @@
|
|||||||
|
-- This is released into the public domain.
|
||||||
|
-- No warranty is provided, implied or otherwise.
|
||||||
|
|
||||||
|
-- svc-t.lua : terminal
|
||||||
|
|
||||||
|
local _, _, retTbl, title = ...
|
||||||
|
|
||||||
|
assert(retTbl, "need to alert creator")
|
||||||
|
|
||||||
|
if title ~= nil then
|
||||||
|
assert(type(title) == "string", "title must be string")
|
||||||
|
end
|
||||||
|
|
||||||
|
local function rW()
|
||||||
|
return string.format("%04x", math.random(0, 65535))
|
||||||
|
end
|
||||||
|
|
||||||
|
local id = "neo.pub.t/" .. rW() .. rW() .. rW() .. rW()
|
||||||
|
local closeNow = false
|
||||||
|
|
||||||
|
-- Terminus Registration State --
|
||||||
|
|
||||||
|
local tReg = neo.requireAccess("r." .. id, "registration")
|
||||||
|
local sendSigs = {}
|
||||||
|
|
||||||
|
-- Display State --
|
||||||
|
-- unicode.safeTextFormat'd lines.
|
||||||
|
-- The size of this must not go below 1.
|
||||||
|
local console = {}
|
||||||
|
-- This must not go below 3.
|
||||||
|
local conW = 40
|
||||||
|
local conCX, conCY = 1, 1
|
||||||
|
local conSCX, conSCY = 1, 1
|
||||||
|
-- Performance
|
||||||
|
local consoleShown = {}
|
||||||
|
local conCYShown
|
||||||
|
for i = 1, 14 do
|
||||||
|
console[i] = (" "):rep(conW)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Line Editing State --
|
||||||
|
-- Nil if line editing is off.
|
||||||
|
-- In this case, the console height
|
||||||
|
-- must be adjusted accordingly.
|
||||||
|
local leText = ""
|
||||||
|
-- These are NOT nil'd out,
|
||||||
|
-- particularly not the history buffer.
|
||||||
|
local leCX = 1
|
||||||
|
local leHistory = {
|
||||||
|
-- Size = history buffer size
|
||||||
|
"", "", "", ""
|
||||||
|
}
|
||||||
|
local function cycleHistoryUp()
|
||||||
|
local backupFirst = leHistory[1]
|
||||||
|
for i = 1, #leHistory - 1 do
|
||||||
|
leHistory[i] = leHistory[i + 1]
|
||||||
|
end
|
||||||
|
leHistory[#leHistory] = backupFirst
|
||||||
|
end
|
||||||
|
local function cycleHistoryDown()
|
||||||
|
local backup = leHistory[1]
|
||||||
|
for i = 2, #leHistory do
|
||||||
|
backup, leHistory[i] = leHistory[i], backup
|
||||||
|
end
|
||||||
|
leHistory[1] = backup
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Window --
|
||||||
|
|
||||||
|
local window = neo.requireAccess("x.neo.pub.window", "window")(conW, #console + 1, title)
|
||||||
|
|
||||||
|
-- Core Terminal Functions --
|
||||||
|
|
||||||
|
local function setSize(w, h)
|
||||||
|
conW = w
|
||||||
|
for i = 1, #console do
|
||||||
|
consoleShown[i] = nil
|
||||||
|
end
|
||||||
|
while #console < h do
|
||||||
|
table.insert(console, "")
|
||||||
|
end
|
||||||
|
while #console > h do
|
||||||
|
table.remove(console, 1)
|
||||||
|
end
|
||||||
|
for i = 1, #console do
|
||||||
|
console[i] = unicode.sub(console[i], 1, w) .. (" "):rep(w - unicode.len(console[i]))
|
||||||
|
end
|
||||||
|
if leText then
|
||||||
|
window.setSize(w, h + 1)
|
||||||
|
else
|
||||||
|
window.setSize(w, h)
|
||||||
|
end
|
||||||
|
conCX, conCY = 1, h
|
||||||
|
end
|
||||||
|
|
||||||
|
local function setLineEditing(state)
|
||||||
|
if state and not leText then
|
||||||
|
leText = ""
|
||||||
|
leCX = 1
|
||||||
|
setSize(conW, #console)
|
||||||
|
elseif leText and not state then
|
||||||
|
leText = nil
|
||||||
|
setSize(conW, #console)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function draw(i)
|
||||||
|
if console[i] then
|
||||||
|
window.span(1, i, console[i], 0, 0xFFFFFF)
|
||||||
|
if i == conCY and not leText then
|
||||||
|
window.span(conCX, i, unicode.sub(console[i], conCX, conCX), 0xFFFFFF, 0)
|
||||||
|
end
|
||||||
|
elseif leText then
|
||||||
|
window.span(1, i, require("lineedit").draw(conW, unicode.safeTextFormat(leText, leCX)), 0xFFFFFF, 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local function drawDisplay()
|
||||||
|
for i = 1, #console do
|
||||||
|
if consoleShown[i] ~= console[i] or i == conCY or i == conCYShown then
|
||||||
|
draw(i)
|
||||||
|
consoleShown[i] = console[i]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
conCYShown = conCY
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Terminal Visual --
|
||||||
|
|
||||||
|
local function consoleSD()
|
||||||
|
for i = 1, #console - 1 do
|
||||||
|
console[i] = console[i + 1]
|
||||||
|
end
|
||||||
|
console[#console] = (" "):rep(conW)
|
||||||
|
end
|
||||||
|
local function consoleSU()
|
||||||
|
local backup = (" "):rep(conW)
|
||||||
|
for i = 1, #console do
|
||||||
|
backup, console[i] = console[i], backup
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function consoleCLS()
|
||||||
|
for i = 1, #console do
|
||||||
|
console[i] = (" "):rep(conW)
|
||||||
|
end
|
||||||
|
conCX, conCY = 1, 1
|
||||||
|
end
|
||||||
|
|
||||||
|
local function writeFF()
|
||||||
|
if conCY ~= #console then
|
||||||
|
conCY = conCY + 1
|
||||||
|
else
|
||||||
|
consoleSD()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function writeData(data)
|
||||||
|
-- handle data until completion
|
||||||
|
while #data > 0 do
|
||||||
|
local char = unicode.sub(data, 1, 1)
|
||||||
|
--neo.emergency("svc-t.data: " .. char:byte())
|
||||||
|
data = unicode.sub(data, 2)
|
||||||
|
-- handle character
|
||||||
|
if char == "\t" then
|
||||||
|
-- not ideal, but allowed
|
||||||
|
char = " "
|
||||||
|
end
|
||||||
|
if char == "\r" then
|
||||||
|
conCX = 1
|
||||||
|
elseif char == "\x00" then
|
||||||
|
-- caused by TELNET \r rules
|
||||||
|
elseif char == "\n" then
|
||||||
|
conCX = 1
|
||||||
|
writeFF()
|
||||||
|
elseif char == "\a" then
|
||||||
|
-- Bell (er...)
|
||||||
|
elseif char == "\b" then
|
||||||
|
conCX = math.max(1, conCX - 1)
|
||||||
|
elseif char == "\v" or char == "\f" then
|
||||||
|
writeFF()
|
||||||
|
else
|
||||||
|
local charL = unicode.wlen(char)
|
||||||
|
if (conCX + charL - 1) > conW then
|
||||||
|
conCX = 1
|
||||||
|
writeFF()
|
||||||
|
end
|
||||||
|
local spaces = (" "):rep(charL - 1)
|
||||||
|
console[conCY] = unicode.sub(console[conCY], 1, conCX - 1) .. char .. spaces .. unicode.sub(console[conCY], conCX + charL)
|
||||||
|
conCX = conCX + charL
|
||||||
|
-- Cursor can be (intentionally!) off-screen here
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function writeANSI(s)
|
||||||
|
--neo.emergency("svc-t.ansi: " .. s)
|
||||||
|
-- This supports just about enough to get by.
|
||||||
|
if s == "c" then
|
||||||
|
consoleCLS()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local pfx = s:sub(1, 1)
|
||||||
|
local cmd = s:sub(#s)
|
||||||
|
if pfx == "[" then
|
||||||
|
local np = tonumber(s:sub(2, -2)) or 1
|
||||||
|
if cmd == "A" then
|
||||||
|
conCY = conCY - np
|
||||||
|
elseif cmd == "B" then
|
||||||
|
conCY = conCY + np
|
||||||
|
elseif cmd == "C" then
|
||||||
|
conCX = conCX + np
|
||||||
|
elseif cmd == "D" then
|
||||||
|
conCX = conCX - np
|
||||||
|
elseif cmd == "f" or cmd == "H" then
|
||||||
|
local p = s:find(";")
|
||||||
|
if not p then
|
||||||
|
conCY = np
|
||||||
|
conCX = 1
|
||||||
|
else
|
||||||
|
conCY = tonumber(s:sub(2, p - 1)) or 1
|
||||||
|
conCX = tonumber(s:sub(p + 1, -2)) or 1
|
||||||
|
end
|
||||||
|
elseif cmd == "J" then
|
||||||
|
consoleCLS()
|
||||||
|
elseif cmd == "K" then
|
||||||
|
if s == "[K" or s == "[0K" then
|
||||||
|
-- bash needs this
|
||||||
|
console[conCY] = unicode.sub(console[conCY], 1, conCX - 1) .. (" "):rep(1 + conW - conCX)
|
||||||
|
else
|
||||||
|
console[conCY] = (" "):rep(conW)
|
||||||
|
end
|
||||||
|
elseif cmd == "n" then
|
||||||
|
if s == "[6n" then
|
||||||
|
for _, v in pairs(sendSigs) do
|
||||||
|
v("data", "\x1b[" .. conY .. ";" .. conX .. "R")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif cmd == "s" then
|
||||||
|
conSCX, conSCY = conCX, conCY
|
||||||
|
elseif cmd == "u" then
|
||||||
|
conCX, conCY = conSCX, conSCY
|
||||||
|
end
|
||||||
|
end
|
||||||
|
conCX = math.min(math.max(math.floor(conCX), 1), conW)
|
||||||
|
conCY = math.min(math.max(math.floor(conCY), 1), #console)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- The Terminus --
|
||||||
|
|
||||||
|
local tvBuildingCmd = ""
|
||||||
|
local tvBuildingUTF = ""
|
||||||
|
local tvSubnegotiation = false
|
||||||
|
local function incoming(s)
|
||||||
|
tvBuildingCmd = tvBuildingCmd .. s
|
||||||
|
-- Flush Cmd
|
||||||
|
while #tvBuildingCmd > 0 do
|
||||||
|
if tvBuildingCmd:byte() == 255 then
|
||||||
|
-- It's a command. Uhoh.
|
||||||
|
if #tvBuildingCmd < 2 then break end
|
||||||
|
local cmd = tvBuildingCmd:byte(2)
|
||||||
|
local param = tvBuildingCmd:byte(3)
|
||||||
|
local cmdLen = 2
|
||||||
|
-- Command Lengths
|
||||||
|
if cmd >= 251 and cmd <= 254 then cmdLen = 3 end
|
||||||
|
if #tvBuildingCmd < cmdLen then break end
|
||||||
|
if cmd == 240 then
|
||||||
|
-- SE
|
||||||
|
tvSubnegotiation = false
|
||||||
|
elseif cmd == 250 then
|
||||||
|
-- SB
|
||||||
|
tvSubnegotiation = true
|
||||||
|
elseif cmd == 251 and param == 1 then
|
||||||
|
-- WILL ECHO (respond with DO ECHO, disable line editing)
|
||||||
|
-- test using io.write("\xFF\xFB\x01")
|
||||||
|
for _, v in pairs(sendSigs) do
|
||||||
|
v("telnet", "\xFF\xFD\x01")
|
||||||
|
end
|
||||||
|
setLineEditing(false)
|
||||||
|
elseif cmd == 252 and param == 1 then
|
||||||
|
-- WON'T ECHO (respond with DON'T ECHO, enable line editing)
|
||||||
|
for _, v in pairs(sendSigs) do
|
||||||
|
v("telnet", "\xFF\xFE\x01")
|
||||||
|
end
|
||||||
|
setLineEditing(true)
|
||||||
|
elseif cmd == 251 or cmd == 252 then
|
||||||
|
-- WILL/WON'T (x) (respond with DON'T (X))
|
||||||
|
local res = "\xFF\xFE" .. string.char(param)
|
||||||
|
for _, v in pairs(sendSigs) do
|
||||||
|
v("telnet", res)
|
||||||
|
end
|
||||||
|
elseif cmd == 253 or cmd == 254 then
|
||||||
|
-- DO/DON'T (x) (respond with WON'T (X))
|
||||||
|
local res = "\xFF\xFC" .. string.char(param)
|
||||||
|
for _, v in pairs(sendSigs) do
|
||||||
|
v("telnet", res)
|
||||||
|
end
|
||||||
|
elseif cmd == 255 then
|
||||||
|
if not tvSubnegotiation then
|
||||||
|
tvBuildingUTF = tvBuildingUTF .. "\xFF"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
tvBuildingCmd = tvBuildingCmd:sub(cmdLen + 1)
|
||||||
|
else
|
||||||
|
if not tvSubnegotiation then
|
||||||
|
tvBuildingUTF = tvBuildingUTF .. tvBuildingCmd:sub(1, 1)
|
||||||
|
end
|
||||||
|
tvBuildingCmd = tvBuildingCmd:sub(2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- Flush UTF/Display
|
||||||
|
while #tvBuildingUTF > 0 do
|
||||||
|
local head = tvBuildingUTF:byte()
|
||||||
|
local len = 1
|
||||||
|
local handled = false
|
||||||
|
if head == 27 then
|
||||||
|
local h2 = tvBuildingUTF:byte(2)
|
||||||
|
if h2 == 91 then
|
||||||
|
for i = 3, #tvBuildingUTF do
|
||||||
|
local cmd = tvBuildingUTF:byte(i)
|
||||||
|
if cmd >= 0x40 and cmd <= 0x7E then
|
||||||
|
writeANSI(tvBuildingUTF:sub(2, i))
|
||||||
|
len = i
|
||||||
|
handled = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif h2 then
|
||||||
|
len = 2
|
||||||
|
writeANSI(tvBuildingUTF:sub(2, 2))
|
||||||
|
handled = true
|
||||||
|
end
|
||||||
|
if not handled then break end
|
||||||
|
end
|
||||||
|
if not handled then
|
||||||
|
if head < 192 then
|
||||||
|
len = 1
|
||||||
|
elseif head < 224 then
|
||||||
|
len = 2
|
||||||
|
elseif head < 240 then
|
||||||
|
len = 3
|
||||||
|
elseif head < 248 then
|
||||||
|
len = 4
|
||||||
|
elseif head < 252 then
|
||||||
|
len = 5
|
||||||
|
elseif head < 254 then
|
||||||
|
len = 6
|
||||||
|
end
|
||||||
|
if #tvBuildingUTF < len then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
-- verified one full character...
|
||||||
|
writeData(tvBuildingUTF:sub(1, len))
|
||||||
|
end
|
||||||
|
tvBuildingUTF = tvBuildingUTF:sub(len + 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
tReg(function (_, pid, sendSig)
|
||||||
|
sendSigs[pid] = sendSig
|
||||||
|
return {
|
||||||
|
id = "x." .. id,
|
||||||
|
pid = neo.pid,
|
||||||
|
write = function (text)
|
||||||
|
incoming(tostring(text))
|
||||||
|
drawDisplay()
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end, true)
|
||||||
|
|
||||||
|
if retTbl then
|
||||||
|
coroutine.resume(coroutine.create(retTbl), {
|
||||||
|
access = "x." .. id,
|
||||||
|
close = function ()
|
||||||
|
closeNow = true
|
||||||
|
neo.scheduleTimer(0)
|
||||||
|
end
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local control = false
|
||||||
|
|
||||||
|
local function key(a, c)
|
||||||
|
if control then
|
||||||
|
if c == 203 and conW > 8 then
|
||||||
|
setSize(conW - 1, #console)
|
||||||
|
return
|
||||||
|
elseif c == 200 and #console > 1 then
|
||||||
|
setSize(conW, #console - 1)
|
||||||
|
return
|
||||||
|
elseif c == 205 then
|
||||||
|
setSize(conW + 1, #console)
|
||||||
|
return
|
||||||
|
elseif c == 208 then
|
||||||
|
setSize(conW, #console + 1)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- so with the reserved ones dealt with...
|
||||||
|
if not leText then
|
||||||
|
-- Line Editing not active.
|
||||||
|
-- For now support a bare minimum.
|
||||||
|
for _, v in pairs(sendSigs) do
|
||||||
|
if a == "\x03" then
|
||||||
|
v("telnet", "\xFF\xF4")
|
||||||
|
elseif c == 199 then
|
||||||
|
v("data", "\x1b[H")
|
||||||
|
elseif c == 201 then
|
||||||
|
v("data", "\x1b[5~")
|
||||||
|
elseif c == 207 then
|
||||||
|
v("data", "\x1b[F")
|
||||||
|
elseif c == 209 then
|
||||||
|
v("data", "\x1b[6~")
|
||||||
|
elseif c == 203 then
|
||||||
|
v("data", "\x1b[D")
|
||||||
|
elseif c == 205 then
|
||||||
|
v("data", "\x1b[C")
|
||||||
|
elseif c == 200 then
|
||||||
|
v("data", "\x1b[A")
|
||||||
|
elseif c == 208 then
|
||||||
|
v("data", "\x1b[B")
|
||||||
|
elseif a == "\r" then
|
||||||
|
v("data", "\r\n")
|
||||||
|
elseif a then
|
||||||
|
v("data", a)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif not control then
|
||||||
|
-- Line Editing active and control isn't involved
|
||||||
|
if c == 200 or c == 208 then
|
||||||
|
-- History cursor up (history down)
|
||||||
|
leText = leHistory[#leHistory]
|
||||||
|
leCX = unicode.len(leText) + 1
|
||||||
|
if c == 208 then
|
||||||
|
cycleHistoryUp()
|
||||||
|
else
|
||||||
|
cycleHistoryDown()
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local lT, lC, lX = require("lineedit").key(a, c, leText, leCX)
|
||||||
|
leText = lT or leText
|
||||||
|
leCX = lC or leCX
|
||||||
|
if lX == "nl" then
|
||||||
|
cycleHistoryUp()
|
||||||
|
leHistory[#leHistory] = leText
|
||||||
|
-- the whole thing {
|
||||||
|
local fullText = leText .. "\r\n"
|
||||||
|
writeData(fullText)
|
||||||
|
drawDisplay()
|
||||||
|
for _, v in pairs(sendSigs) do
|
||||||
|
v("data", fullText)
|
||||||
|
end
|
||||||
|
-- }
|
||||||
|
leText = ""
|
||||||
|
leCX = 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
while not closeNow do
|
||||||
|
local e = {coroutine.yield()}
|
||||||
|
if e[1] == "k.procdie" then
|
||||||
|
sendSigs[e[3]] = nil
|
||||||
|
elseif e[1] == "x.neo.pub.window" then
|
||||||
|
if e[3] == "close" then
|
||||||
|
break
|
||||||
|
elseif e[3] == "clipboard" then
|
||||||
|
for i = 1, unicode.len(e[4]) do
|
||||||
|
local c = unicode.sub(e[4], i, i)
|
||||||
|
if c ~= "\r" then
|
||||||
|
if c == "\n" then
|
||||||
|
c = "\r"
|
||||||
|
end
|
||||||
|
key(c, 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
draw(#console + 1)
|
||||||
|
elseif e[3] == "key" then
|
||||||
|
if e[5] == 29 or e[5] == 157 then
|
||||||
|
control = e[6]
|
||||||
|
elseif e[6] then
|
||||||
|
key(e[4] ~= 0 and unicode.char(e[4]), e[5])
|
||||||
|
draw(#console + 1)
|
||||||
|
end
|
||||||
|
elseif e[3] == "line" then
|
||||||
|
draw(e[4])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -600,65 +600,55 @@ end
|
|||||||
local isAltDown = false
|
local isAltDown = false
|
||||||
local isCtrDown = false
|
local isCtrDown = false
|
||||||
local function key(ku, ka, kc, down)
|
local function key(ku, ka, kc, down)
|
||||||
local ku = screens.getMonitorByKeyboard(ku)
|
local ku, lin = screens.getMonitorByKeyboard(ku)
|
||||||
if not ku then return end
|
|
||||||
for k, v in ipairs(monitors) do
|
for k, v in ipairs(monitors) do
|
||||||
if v[2] == mu then
|
if ku and v[2] == ku then
|
||||||
lIM = k
|
lin = k
|
||||||
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if not lin then return end
|
||||||
|
lIM = lin
|
||||||
|
|
||||||
local focus = surfaces[1]
|
local focus = surfaces[1]
|
||||||
if kc == 29 then isCtrDown = down end
|
if kc == 29 then
|
||||||
if kc == 56 then isAltDown = down end
|
isCtrDown = down
|
||||||
if isAltDown then
|
elseif kc == 56 then
|
||||||
if ka == 120 then
|
isAltDown = down
|
||||||
if focus and down then ofsMSurface(focus, 1) end return
|
|
||||||
end
|
|
||||||
if kc == 200 then
|
|
||||||
if focus and down then ofsSurface(focus, 0, -1) end return
|
|
||||||
end
|
|
||||||
if kc == 208 then
|
|
||||||
if focus and down then ofsSurface(focus, 0, 1) end return
|
|
||||||
end
|
|
||||||
if kc == 203 then
|
|
||||||
if focus and down then ofsSurface(focus, -1, 0) end return
|
|
||||||
end
|
|
||||||
if kc == 205 then
|
|
||||||
if focus and down then ofsSurface(focus, 1, 0) end return
|
|
||||||
end
|
|
||||||
if ka == 122 then
|
|
||||||
if focus and down then
|
|
||||||
local n = table.remove(surfaces, 1)
|
|
||||||
table.insert(surfaces, n)
|
|
||||||
changeFocus(n)
|
|
||||||
end return
|
|
||||||
end
|
|
||||||
if ka == 97 then
|
|
||||||
if not down then
|
|
||||||
isAltDown = false
|
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if ka == 3 or ka == 99 then
|
|
||||||
if down then
|
|
||||||
if isCtrDown then
|
|
||||||
error("User-authorized Everest crash.")
|
|
||||||
else
|
|
||||||
if focus then
|
|
||||||
focus[6](focus[8], "close")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if ka == 13 then
|
|
||||||
if down then
|
|
||||||
startLauncher()
|
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
if focus then
|
if isAltDown and ka == 122 then
|
||||||
|
if focus and down then
|
||||||
|
local n = table.remove(surfaces, 1)
|
||||||
|
table.insert(surfaces, n)
|
||||||
|
changeFocus(n)
|
||||||
|
end
|
||||||
|
elseif isAltDown and kc == 200 then
|
||||||
|
if focus and down then ofsSurface(focus, 0, -1) end
|
||||||
|
elseif isAltDown and kc == 208 then
|
||||||
|
if focus and down then ofsSurface(focus, 0, 1) end
|
||||||
|
elseif isAltDown and kc == 203 then
|
||||||
|
if focus and down then ofsSurface(focus, -1, 0) end
|
||||||
|
elseif isAltDown and kc == 205 then
|
||||||
|
if focus and down then ofsSurface(focus, 1, 0) end
|
||||||
|
elseif isAltDown and ka == 120 then
|
||||||
|
if focus and down then ofsMSurface(focus, 1) end
|
||||||
|
elseif isAltDown and ka == 97 then
|
||||||
|
if not down then
|
||||||
|
isAltDown = false
|
||||||
|
end
|
||||||
|
elseif isAltDown and (ka == 3 or ka == 99) then
|
||||||
|
if down then
|
||||||
|
if isCtrDown then
|
||||||
|
error("User-authorized Everest crash.")
|
||||||
|
elseif focus then
|
||||||
|
focus[6](focus[8], "close")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif isAltDown and ka == 13 then
|
||||||
|
if down then
|
||||||
|
startLauncher()
|
||||||
|
end
|
||||||
|
elseif focus then
|
||||||
if kc ~= 56 then
|
if kc ~= 56 then
|
||||||
lIM = focus[1]
|
lIM = focus[1]
|
||||||
end
|
end
|
||||||
|
@ -81,20 +81,12 @@ local function getPfx(xd, pkg)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local endAcPattern = "/[a-z0-9/%.]*$"
|
local function splitAC(ac)
|
||||||
|
local sb = ac:match("/[a-z0-9/%.]*$")
|
||||||
local function matchesSvc(xd, pkg, perm)
|
if sb then
|
||||||
local pfx = getPfx(xd, pkg)
|
return ac:sub(1, #ac - #sb), sb
|
||||||
if pfx then
|
|
||||||
local permAct = perm
|
|
||||||
local paP = permAct:match(endAcPattern)
|
|
||||||
if paP then
|
|
||||||
permAct = permAct:sub(1, #permAct - #paP)
|
|
||||||
end
|
|
||||||
if permAct == pfx then
|
|
||||||
return "allow"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
return ac
|
||||||
end
|
end
|
||||||
|
|
||||||
donkonitDFProvider(function (pkg, pid, sendSig)
|
donkonitDFProvider(function (pkg, pid, sendSig)
|
||||||
@ -130,7 +122,8 @@ donkonitDFProvider(function (pkg, pid, sendSig)
|
|||||||
myApi = getPfx("", pkg),
|
myApi = getPfx("", pkg),
|
||||||
lockPerm = function (perm)
|
lockPerm = function (perm)
|
||||||
-- Are we allowed to?
|
-- Are we allowed to?
|
||||||
if not matchesSvc("x.", pkg, perm) then
|
local permPfx, detail = splitAC(perm)
|
||||||
|
if getPfx("x.", pkg) ~= permPfx then
|
||||||
return false, "You don't own this permission."
|
return false, "You don't own this permission."
|
||||||
end
|
end
|
||||||
local set = "perm|*|" .. perm
|
local set = "perm|*|" .. perm
|
||||||
@ -223,7 +216,11 @@ local function secPolicyStage2(pid, proc, perm, req)
|
|||||||
-- Push to ICECAP thread to avoid deadlock b/c wrong event-pull context
|
-- Push to ICECAP thread to avoid deadlock b/c wrong event-pull context
|
||||||
neo.scheduleTimer(0)
|
neo.scheduleTimer(0)
|
||||||
table.insert(todo, function ()
|
table.insert(todo, function ()
|
||||||
local ok, err = pcall(secpol, nexus, settings, proc.pkg, pid, perm, req, matchesSvc)
|
local fPerm = perm
|
||||||
|
if fPerm:sub(1, 2) == "r." then
|
||||||
|
fPerm = splitAC(fPerm)
|
||||||
|
end
|
||||||
|
local ok, err = pcall(secpol, nexus, settings, proc.pkg, pid, fPerm, req, getPfx("", proc.pkg))
|
||||||
if not ok then
|
if not ok then
|
||||||
neo.emergency("Used fallback policy because of run-err: " .. err)
|
neo.emergency("Used fallback policy because of run-err: " .. err)
|
||||||
req(def)
|
req(def)
|
||||||
@ -243,11 +240,7 @@ rootAccess.securityPolicy = function (pid, proc, perm, req)
|
|||||||
end
|
end
|
||||||
-- Do we need to start it?
|
-- Do we need to start it?
|
||||||
if perm:sub(1, 6) == "x.svc." and not neo.usAccessExists(perm) then
|
if perm:sub(1, 6) == "x.svc." and not neo.usAccessExists(perm) then
|
||||||
local appAct = perm:sub(7)
|
local appAct = splitAC(perm:sub(3))
|
||||||
local paP = appAct:match(endAcPattern)
|
|
||||||
if paP then
|
|
||||||
appAct = appAct:sub(1, #appAct - #paP)
|
|
||||||
end
|
|
||||||
-- Prepare for success
|
-- Prepare for success
|
||||||
onReg[perm] = onReg[perm] or {}
|
onReg[perm] = onReg[perm] or {}
|
||||||
local orp = onReg[perm]
|
local orp = onReg[perm]
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
@ -459,7 +459,7 @@ function retrieveAccess(perm, pkg, pid)
|
|||||||
accesses[uid] = function (pkg, pid)
|
accesses[uid] = function (pkg, pid)
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
return function (f)
|
return function (f, secret)
|
||||||
-- Registration function
|
-- Registration function
|
||||||
ensureType(f, "function")
|
ensureType(f, "function")
|
||||||
local accessObjectCache = {}
|
local accessObjectCache = {}
|
||||||
@ -481,8 +481,10 @@ function retrieveAccess(perm, pkg, pid)
|
|||||||
end
|
end
|
||||||
-- returns nil and fails
|
-- returns nil and fails
|
||||||
end
|
end
|
||||||
-- Announce registration
|
if not secret then
|
||||||
distEvent(nil, "k.registration", uid)
|
-- Announce registration
|
||||||
|
distEvent(nil, "k.registration", uid)
|
||||||
|
end
|
||||||
end, function ()
|
end, function ()
|
||||||
-- Registration becomes null (access is held but other processes cannot retrieve object)
|
-- Registration becomes null (access is held but other processes cannot retrieve object)
|
||||||
if accesses[uid] then
|
if accesses[uid] then
|
||||||
|
73
code/libs/lineedit.lua
Normal file
73
code/libs/lineedit.lua
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
-- This is released into the public domain.
|
||||||
|
-- No warranty is provided, implied or otherwise.
|
||||||
|
|
||||||
|
return {
|
||||||
|
-- note: everything must already be unicode.safeTextFormat'd
|
||||||
|
draw = function (sW, line, cursorX, rX)
|
||||||
|
-- if no camera, provide a default
|
||||||
|
rX = rX or math.max(1, (cursorX or 1) - math.floor(sW * 2 / 3))
|
||||||
|
-- transform into area-relative
|
||||||
|
local tl = unicode.sub(line, rX, rX + sW - 1)
|
||||||
|
-- inject cursor
|
||||||
|
if cursorX then
|
||||||
|
cursorX = (cursorX - rX) + 1
|
||||||
|
if cursorX >= 1 then
|
||||||
|
if cursorX <= sW then
|
||||||
|
tl = unicode.sub(tl, 1, cursorX - 1) .. "_" .. unicode.sub(tl, cursorX + 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return tl .. (" "):rep(sW - unicode.len(tl))
|
||||||
|
end,
|
||||||
|
clamp = function (tl, cursorX)
|
||||||
|
tl = unicode.len(tl)
|
||||||
|
if tl < cursorX - 1 then
|
||||||
|
return tl + 1
|
||||||
|
end
|
||||||
|
return cursorX
|
||||||
|
end,
|
||||||
|
-- returns line, cursorX, special
|
||||||
|
-- return values may be nil if irrelevant
|
||||||
|
key = function (ks, kc, line, cursorX)
|
||||||
|
local cS = unicode.sub(line, 1, cursorX - 1)
|
||||||
|
local cE = unicode.sub(line, cursorX)
|
||||||
|
local ll = unicode.len(line)
|
||||||
|
if kc == 203 then -- navi <
|
||||||
|
if cursorX > 1 then
|
||||||
|
return nil, cursorX - 1
|
||||||
|
else
|
||||||
|
-- cline underflow
|
||||||
|
return nil, nil, "l<"
|
||||||
|
end
|
||||||
|
elseif kc == 205 then -- navi >
|
||||||
|
if cursorX > ll then
|
||||||
|
-- cline overflow
|
||||||
|
return nil, nil, "l>"
|
||||||
|
end
|
||||||
|
return nil, cursorX + 1
|
||||||
|
elseif kc == 199 then -- home
|
||||||
|
return nil, 1
|
||||||
|
elseif kc == 207 then -- end
|
||||||
|
return nil, unicode.len(line) + 1
|
||||||
|
elseif ks == "\8" then -- del
|
||||||
|
if cursorX == 1 then
|
||||||
|
-- weld prev
|
||||||
|
return nil, nil, "w<"
|
||||||
|
else
|
||||||
|
return unicode.sub(cS, 1, unicode.len(cS) - 1) .. cE, cursorX - 1
|
||||||
|
end
|
||||||
|
elseif kc == 211 then -- del
|
||||||
|
if cursorX > ll then
|
||||||
|
return nil, nil, "w>"
|
||||||
|
end
|
||||||
|
return cS .. unicode.sub(cE, 2)
|
||||||
|
elseif ks then -- standard letters
|
||||||
|
if ks == "\r" then
|
||||||
|
-- new line
|
||||||
|
return nil, nil, "nl"
|
||||||
|
end
|
||||||
|
return cS .. ks .. cE, cursorX + unicode.len(ks)
|
||||||
|
end
|
||||||
|
-- :(
|
||||||
|
end
|
||||||
|
}
|
@ -339,6 +339,7 @@ newNeoux = function (event, neo)
|
|||||||
end
|
end
|
||||||
-- Note: w should be at least 2 - this is similar to buttons.
|
-- Note: w should be at least 2 - this is similar to buttons.
|
||||||
neoux.tcfield = function (x, y, w, textprop)
|
neoux.tcfield = function (x, y, w, textprop)
|
||||||
|
local p = 1
|
||||||
return {
|
return {
|
||||||
x = x,
|
x = x,
|
||||||
y = y,
|
y = y,
|
||||||
@ -347,22 +348,24 @@ newNeoux = function (event, neo)
|
|||||||
selectable = true,
|
selectable = true,
|
||||||
key = function (window, update, a, c, d, f)
|
key = function (window, update, a, c, d, f)
|
||||||
if d then
|
if d then
|
||||||
|
local ot = textprop()
|
||||||
|
local le = require("lineedit")
|
||||||
|
p = le.clamp(ot, p)
|
||||||
if c == 63 then
|
if c == 63 then
|
||||||
neo.requireAccess("x.neo.pub.globals", "clipboard").setSetting("clipboard", textprop())
|
neo.requireAccess("x.neo.pub.globals", "clipboard").setSetting("clipboard", ot)
|
||||||
elseif c == 64 then
|
elseif c == 64 then
|
||||||
local contents = neo.requireAccess("x.neo.pub.globals", "clipboard").getSetting("clipboard")
|
local contents = neo.requireAccess("x.neo.pub.globals", "clipboard").getSetting("clipboard")
|
||||||
contents = contents:match("^[^\r\n]*")
|
contents = contents:match("^[^\r\n]*")
|
||||||
textprop(contents)
|
textprop(contents)
|
||||||
update()
|
update()
|
||||||
elseif a == 8 then
|
elseif a ~= 9 then
|
||||||
local str = textprop()
|
local lT, lC, lX = le.key(a ~= 0 and unicode.char(a), c, ot, p)
|
||||||
textprop(unicode.sub(str, 1, unicode.len(str) - 1))
|
if lT or lC then
|
||||||
update()
|
if lT then textprop(lT) end
|
||||||
return true
|
p = lC or p
|
||||||
elseif a >= 32 then
|
update()
|
||||||
textprop(textprop() .. unicode.char(a))
|
return true
|
||||||
update()
|
end
|
||||||
return true
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
@ -377,9 +380,10 @@ newNeoux = function (event, neo)
|
|||||||
fg = bg
|
fg = bg
|
||||||
bg = fg1
|
bg = fg1
|
||||||
end
|
end
|
||||||
local text = unicode.safeTextFormat(textprop())
|
local t, e, r = textprop(), require("lineedit")
|
||||||
text = "[" .. neoux.pad(text, w - 2, false, true, true) .. "]"
|
p = e.clamp(t, p)
|
||||||
window.span(x, y, text, bg, fg)
|
t, r = unicode.safeTextFormat(t, p)
|
||||||
|
window.span(x, y, "[" .. e.draw(w - 2, t, selected and r) .. "]", bg, fg)
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
@ -94,11 +94,25 @@ function getFsNode(fs, parent, fsc, path, mode, impliedName)
|
|||||||
for k, v in ipairs(fsc.list(path)) do
|
for k, v in ipairs(fsc.list(path)) do
|
||||||
local nm = "F: " .. v
|
local nm = "F: " .. v
|
||||||
local fp = path .. v
|
local fp = path .. v
|
||||||
if fsc.isDirectory(fp) then
|
local cDir = fsc.isDirectory(fp)
|
||||||
|
if cDir then
|
||||||
nm = "D: " .. v
|
nm = "D: " .. v
|
||||||
end
|
end
|
||||||
n[k + 1] = {nm, function () return nil, getFsNode(fs, t, fsc, fp, mode, impliedName) end}
|
if (not cDir) and (fscrw or mode == false) and (mode ~= nil) then
|
||||||
|
local vn = v
|
||||||
|
n[k + 1] = {nm, function () return selectUnknown(vn) end}
|
||||||
|
else
|
||||||
|
n[k + 1] = {nm, function () return nil, getFsNode(fs, t, fsc, fp, mode, impliedName) end}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
table.insert(n, {"Copy", function ()
|
||||||
|
local rt, re = require("sys-filewrap").create(fsc, path, false)
|
||||||
|
if not rt then
|
||||||
|
return false, dialog("Open Error: " .. tostring(re), parent)
|
||||||
|
end
|
||||||
|
return nil, setupCopyVirtualEnvironment(fs, parent, rt, path:match("[^/]*$") or "")
|
||||||
|
end})
|
||||||
end
|
end
|
||||||
if fscrw then
|
if fscrw then
|
||||||
if dir then
|
if dir then
|
||||||
@ -151,24 +165,6 @@ function getFsNode(fs, parent, fsc, path, mode, impliedName)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
if not dir then
|
if not dir then
|
||||||
table.insert(n, {"Copy", function ()
|
|
||||||
local rt, re = require("sys-filewrap").create(fsc, path, false)
|
|
||||||
if not rt then
|
|
||||||
return false, dialog("Open Error: " .. tostring(re), parent)
|
|
||||||
end
|
|
||||||
return nil, setupCopyVirtualEnvironment(fs, parent, rt, path:match("[^/]*$") or "")
|
|
||||||
end})
|
|
||||||
if (fscrw or mode == false) and (mode ~= nil) then
|
|
||||||
local tx = "Open"
|
|
||||||
if mode == true then
|
|
||||||
tx = "Save (Overwrite)"
|
|
||||||
elseif mode == "append" then
|
|
||||||
tx = "Append"
|
|
||||||
end
|
|
||||||
if fscrw or mode == false then
|
|
||||||
table.insert(n, {tx, selectUnknown})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elseif impliedName then
|
elseif impliedName then
|
||||||
table.insert(n, {"Implied: " .. impliedName, function ()
|
table.insert(n, {"Implied: " .. impliedName, function ()
|
||||||
return selectUnknown(impliedName)
|
return selectUnknown(impliedName)
|
||||||
|
@ -11,13 +11,19 @@
|
|||||||
-- IRC is usually pretty safe, but no guarantees.
|
-- IRC is usually pretty safe, but no guarantees.
|
||||||
|
|
||||||
-- Returns "allow", "deny", or "ask".
|
-- Returns "allow", "deny", or "ask".
|
||||||
local function actualPolicy(pkg, pid, perm, matchesSvc)
|
local function actualPolicy(pkg, pid, perm, pkgSvcPfx)
|
||||||
-- System stuff is allowed.
|
-- System stuff is allowed.
|
||||||
if pkg:sub(1, 4) == "sys-" then
|
if pkg:sub(1, 4) == "sys-" then
|
||||||
return "allow"
|
return "allow"
|
||||||
end
|
end
|
||||||
|
-- svc-t's job is solely to emulate terminals
|
||||||
|
-- TO INSTALL YOUR OWN TERMINAL EMULATOR:
|
||||||
|
-- perm|app-yourterm|r.neo.t
|
||||||
|
if pkg == "svc-t" and perm == "r.neo.pub.t" then
|
||||||
|
return "allow"
|
||||||
|
end
|
||||||
-- <The following is for apps & services>
|
-- <The following is for apps & services>
|
||||||
-- x.neo.pub (aka Icecap) is open to all
|
-- x.neo.pub.* is open to all
|
||||||
if perm:sub(1, 10) == "x.neo.pub." then
|
if perm:sub(1, 10) == "x.neo.pub." then
|
||||||
return "allow"
|
return "allow"
|
||||||
end
|
end
|
||||||
@ -25,7 +31,8 @@ local function actualPolicy(pkg, pid, perm, matchesSvc)
|
|||||||
if perm == "s.h.component_added" or perm == "s.h.component_removed" or perm == "s.h.tablet_use" or perm == "c.tablet" then
|
if perm == "s.h.component_added" or perm == "s.h.component_removed" or perm == "s.h.tablet_use" or perm == "c.tablet" then
|
||||||
return "allow"
|
return "allow"
|
||||||
end
|
end
|
||||||
if matchesSvc("r.", pkg, perm) then
|
-- Userlevel can register for itself
|
||||||
|
if perm == "r." .. pkgSvcPfx then
|
||||||
return "allow"
|
return "allow"
|
||||||
end
|
end
|
||||||
-- Userlevel has no other registration rights
|
-- Userlevel has no other registration rights
|
||||||
@ -44,8 +51,8 @@ local function actualPolicy(pkg, pid, perm, matchesSvc)
|
|||||||
return "ask"
|
return "ask"
|
||||||
end
|
end
|
||||||
|
|
||||||
return function (nexus, settings, pkg, pid, perm, rsp, matchesSvc)
|
return function (nexus, settings, pkg, pid, perm, rsp, pkgSvcPfx)
|
||||||
local res = actualPolicy(pkg, pid, perm, matchesSvc)
|
local res = actualPolicy(pkg, pid, perm, pkgSvcPfx)
|
||||||
if settings then
|
if settings then
|
||||||
res = settings.getSetting("perm|" .. pkg .. "|" .. perm) or
|
res = settings.getSetting("perm|" .. pkg .. "|" .. perm) or
|
||||||
settings.getSetting("perm|*|" .. perm) or res
|
settings.getSetting("perm|*|" .. perm) or res
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
-- This is released into the public domain.
|
|
||||||
-- No warranty is provided, implied or otherwise.
|
|
||||||
|
|
||||||
-- BDIVIDE r5 edition
|
|
||||||
-- Algorithm simplified for smaller implementation and potentially better compression
|
|
||||||
-- format:
|
|
||||||
-- 0-127 for constants
|
|
||||||
-- <128 + (length - 4)>, <position high>, <position low>
|
|
||||||
-- Position is where in the window it was found, minus 1.
|
|
||||||
-- windowSize must be the same between the encoder and decoder,
|
|
||||||
-- and is the amount of data preserved after cropping.
|
|
||||||
|
|
||||||
io.write("\x00") -- initiation character
|
|
||||||
|
|
||||||
local blk = io.read("*a")
|
|
||||||
local windowSize = 0x10000
|
|
||||||
local windowData = ("\x00"):rep(windowSize)
|
|
||||||
|
|
||||||
local function crop(data)
|
|
||||||
windowData = (windowData .. data):sub(-windowSize)
|
|
||||||
end
|
|
||||||
|
|
||||||
while blk ~= "" do
|
|
||||||
local bestData = blk:sub(1, 1)
|
|
||||||
local bestRes = bestData
|
|
||||||
for lm = 0, 127 do
|
|
||||||
local al = lm + 4
|
|
||||||
local pfx = blk:sub(1, al)
|
|
||||||
if #pfx ~= al then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
local p = windowData:find(pfx, 1, true)
|
|
||||||
if not p then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
local pm = p - 1
|
|
||||||
local thirdByte = pm % 256
|
|
||||||
-- anti ']'-corruption helper
|
|
||||||
if thirdByte ~= 93 then
|
|
||||||
bestData = string.char(128 + lm, math.floor(pm / 256), thirdByte)
|
|
||||||
bestRes = pfx
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- ok, encode!
|
|
||||||
io.write(bestData)
|
|
||||||
crop(bestRes)
|
|
||||||
blk = blk:sub(#bestRes + 1)
|
|
||||||
end
|
|
||||||
|
|
@ -1,88 +0,0 @@
|
|||||||
-- This is released into the public domain.
|
|
||||||
-- No warranty is provided, implied or otherwise.
|
|
||||||
|
|
||||||
-- This program tries to crunch down the installer a bit further.
|
|
||||||
-- Specific target in mind, it has no support for string escapes.
|
|
||||||
-- It also does this:
|
|
||||||
for i = 1, 3 do
|
|
||||||
print(io.read())
|
|
||||||
end
|
|
||||||
|
|
||||||
local sequences = {
|
|
||||||
{"\n", " "},
|
|
||||||
{" ", " "},
|
|
||||||
{" #", "#"},
|
|
||||||
{"# ", "#"},
|
|
||||||
{" ,", ","},
|
|
||||||
{", ", ","},
|
|
||||||
{" (", "("},
|
|
||||||
{"( ", "("},
|
|
||||||
{" )", ")"},
|
|
||||||
{") ", ")"},
|
|
||||||
{" <", "<"},
|
|
||||||
{"< ", "<"},
|
|
||||||
{" >", ">"},
|
|
||||||
{"> ", ">"},
|
|
||||||
{" *", "*"},
|
|
||||||
{"* ", "*"},
|
|
||||||
{" ~", "~"},
|
|
||||||
{"~ ", "~"},
|
|
||||||
{" /", "/"},
|
|
||||||
{"/ ", "/"},
|
|
||||||
{" %", "%"},
|
|
||||||
{"% ", "%"},
|
|
||||||
{" =", "="},
|
|
||||||
{"= ", "="},
|
|
||||||
{" -", "-"},
|
|
||||||
{"- ", "-"},
|
|
||||||
{" +", "+"},
|
|
||||||
{"+ ", "+"},
|
|
||||||
{".. ", ".."},
|
|
||||||
{" ..", ".."},
|
|
||||||
{"\"\" ", "\"\""},
|
|
||||||
{"=0 t", "=0t"},
|
|
||||||
{">0 t", ">0t"},
|
|
||||||
{">1 t", ">1t"},
|
|
||||||
{"=1 w", "=1w"},
|
|
||||||
{"=380 l", "=380l"},
|
|
||||||
{"=127 t", "=127t"},
|
|
||||||
{"<128 t", "<128t"},
|
|
||||||
{"=128 t", "=128t"},
|
|
||||||
{">255 t", ">255t"},
|
|
||||||
{"=512 t", "=512t"}
|
|
||||||
}
|
|
||||||
|
|
||||||
local function pass(buffer)
|
|
||||||
local ob = ""
|
|
||||||
local smode = false
|
|
||||||
while #buffer > 0 do
|
|
||||||
if not smode then
|
|
||||||
local ds = true
|
|
||||||
while ds do
|
|
||||||
ds = false
|
|
||||||
for _, v in ipairs(sequences) do
|
|
||||||
if buffer:sub(1, #(v[1])) == v[1] then
|
|
||||||
buffer = v[2] .. buffer:sub(#(v[1]) + 1)
|
|
||||||
ds = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local ch = buffer:sub(1, 1)
|
|
||||||
buffer = buffer:sub(2)
|
|
||||||
ob = ob .. ch
|
|
||||||
if ch == "\"" then
|
|
||||||
smode = not smode
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return ob
|
|
||||||
end
|
|
||||||
local op = io.read("*a")
|
|
||||||
while true do
|
|
||||||
local np = pass(op)
|
|
||||||
if np == op then
|
|
||||||
io.write(np)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
op = np
|
|
||||||
end
|
|
@ -1,72 +0,0 @@
|
|||||||
-- This is released into the public domain. XX
|
|
||||||
-- No warranty is provided, implied or otherwise. XX
|
|
||||||
local sector = io.write -- XX
|
|
||||||
-- XX
|
|
||||||
-- BUNDIVIDE (r5 edition) reference implementation for integration XX
|
|
||||||
-- Lines ending with XX are not included in the output. XX
|
|
||||||
-- Lines that both start and end with -- are only for use in the output, XX
|
|
||||||
-- and are thus not executed during any sanity-check procedure. XX
|
|
||||||
-- XX
|
|
||||||
Cp,Ct,Cc,Cw="","","",("\x00"):rep(65536)
|
|
||||||
-- High-level breakdown: XX
|
|
||||||
-- CP is unescaper & TAR-sector-breakup. XX
|
|
||||||
-- It'll only begin to input if at least 3 bytes are available, XX
|
|
||||||
-- so you'll want to throw in 2 extra zeroes at the end of stream as done here. XX
|
|
||||||
-- It uses Ct (input buffer) and Cp (output buffer). XX
|
|
||||||
-- Ignore its second argument, as that's a lie, it's just there for a local. XX
|
|
||||||
-- CD is the actual decompressor. It has the same quirk as CP, wanting two more bytes. XX
|
|
||||||
-- It stores to Cc (compressed), and Cw (window). XX
|
|
||||||
-- It uses Ca as the "first null" activation flag. XX
|
|
||||||
-- It outputs that which goes to the window to CP also. XX
|
|
||||||
-- And it also uses a fake local. XX
|
|
||||||
CP = function (d, b)
|
|
||||||
Ct = Ct .. d
|
|
||||||
while #Ct > 2 do
|
|
||||||
b = Ct:byte()
|
|
||||||
Ct = Ct:sub(2)
|
|
||||||
if b == 127 then
|
|
||||||
b = Ct:byte()
|
|
||||||
Ct = Ct:sub(2)
|
|
||||||
if b == 127 then
|
|
||||||
b = Ct:byte() + 254
|
|
||||||
if b > 255 then
|
|
||||||
b = b - 256
|
|
||||||
end
|
|
||||||
Ct = Ct:sub(2)
|
|
||||||
else
|
|
||||||
b = b + 127
|
|
||||||
end
|
|
||||||
end
|
|
||||||
Cp = Cp .. string.char(b)
|
|
||||||
if #Cp == 512 then
|
|
||||||
sector(Cp)
|
|
||||||
Cp = ""
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- XX
|
|
||||||
CD = function (d, b, p)
|
|
||||||
Cc = Cc .. d
|
|
||||||
while #Cc > 2 do
|
|
||||||
b = Cc:byte()
|
|
||||||
if not Ca then
|
|
||||||
Ca, b, Cc = b < 1, "", Cc:sub(2)
|
|
||||||
elseif b < 128 then
|
|
||||||
b, Cc = Cc:sub(1, 1), Cc:sub(2)
|
|
||||||
else
|
|
||||||
p = Cc:byte(2) * 256 + Cc:byte(3) + 1
|
|
||||||
b, Cc = Cw:sub(p, p + b - 125), Cc:sub(4)
|
|
||||||
end
|
|
||||||
CP(b)
|
|
||||||
Cw = (Cw .. b):sub(-65536)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- XX
|
|
||||||
CD(io.read("*a")) -- XX
|
|
||||||
--D.remove("init-bdivide.lua")--
|
|
||||||
--D.rename("init.lua","init-bdivide.lua")--
|
|
||||||
--local Ch=D.open("init-bdivide.lua","rb")--
|
|
||||||
--dieCB=function()D.close(Ch)D.remove("init-bdivide.lua")end--
|
|
||||||
--while true do local t=D.read(Ch, 64)if not t then break end CD(t)end--
|
|
||||||
-- XX
|
|
||||||
CD("\x00\x00")CP("\x00\x00")
|
|
@ -1,20 +0,0 @@
|
|||||||
-- PREPROC: preprocess input to be 7-bit
|
|
||||||
-- This is released into the public domain.
|
|
||||||
-- No warranty is provided, implied or otherwise.
|
|
||||||
|
|
||||||
while true do
|
|
||||||
local c = io.read(1)
|
|
||||||
if not c then return end
|
|
||||||
local bc = c:byte()
|
|
||||||
if bc < 127 then
|
|
||||||
io.write(c)
|
|
||||||
else
|
|
||||||
if bc <= 253 then
|
|
||||||
-- 127(0) through 253(126)
|
|
||||||
io.write("\x7F" .. string.char(bc - 127))
|
|
||||||
else
|
|
||||||
-- 254(0) through 255 (1)
|
|
||||||
io.write("\x7F\x7F" .. string.char(bc - 254))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
27
heroes.lua
27
heroes.lua
@ -1,27 +0,0 @@
|
|||||||
-- This is released into the public domain.
|
|
||||||
-- No warranty is provided, implied or otherwise.
|
|
||||||
|
|
||||||
-- arg is the size of the code.tar file
|
|
||||||
local arg = ...
|
|
||||||
os.execute("lua com2/preproc.lua < code.tar | lua com2/bdivide.lua > com2/code.tar.bd")
|
|
||||||
os.execute("cat insthead.lua")
|
|
||||||
print("sC=" .. math.ceil(tonumber(arg) / 512))
|
|
||||||
local src = io.open("com2/bundiv.lua", "r")
|
|
||||||
while true do
|
|
||||||
local line = src:read()
|
|
||||||
if not line then
|
|
||||||
io.flush()
|
|
||||||
src:close()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local endix = line:sub(#line-1,#line)
|
|
||||||
if endix ~= "XX" then
|
|
||||||
if endix == "--" then
|
|
||||||
-- included
|
|
||||||
print(line:sub(3,#line-2))
|
|
||||||
else
|
|
||||||
print(line)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- XX means ignored.
|
|
||||||
end
|
|
36
inst/bdivide/bga.lua
Normal file
36
inst/bdivide/bga.lua
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
-- This is released into the public domain.
|
||||||
|
-- No warranty is provided, implied or otherwise.
|
||||||
|
|
||||||
|
local bga = {}
|
||||||
|
|
||||||
|
local str = io.read("*a")
|
||||||
|
|
||||||
|
for i = 1, #str - 1 do
|
||||||
|
local bg = str:sub(i, i + 1)
|
||||||
|
bga[bg] = (bga[bg] or 0) + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
local first = {}
|
||||||
|
local second = {}
|
||||||
|
|
||||||
|
local mode = ...
|
||||||
|
|
||||||
|
for k, v in pairs(bga) do
|
||||||
|
if mode == "combined" then
|
||||||
|
print(string.format("%08i: %02x%02x : %s", v, k:byte(1), k:byte(2), k))
|
||||||
|
end
|
||||||
|
first[k:sub(1, 1)] = (first[k:sub(1, 1)] or 0) + v
|
||||||
|
second[k:sub(1, 1)] = (second[k:sub(1, 1)] or 0) + v
|
||||||
|
end
|
||||||
|
|
||||||
|
for k, v in pairs(first) do
|
||||||
|
if mode == "first" then
|
||||||
|
print(string.format("%08i: %s", v, k))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for k, v in pairs(second) do
|
||||||
|
if mode == "second" then
|
||||||
|
print(string.format("%08i: %s", v, k))
|
||||||
|
end
|
||||||
|
end
|
85
inst/bdivide/compress.lua
Normal file
85
inst/bdivide/compress.lua
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
-- This is released into the public domain.
|
||||||
|
-- No warranty is provided, implied or otherwise.
|
||||||
|
|
||||||
|
-- PREPROC (r9 edition): preprocess input to be 7-bit
|
||||||
|
|
||||||
|
local frw = require("libs.frw")
|
||||||
|
|
||||||
|
local
|
||||||
|
-- SHARED WITH DECOMPRESSION ENGINE
|
||||||
|
function p(x, y)
|
||||||
|
if x == 126 then
|
||||||
|
return string.char(y), 3
|
||||||
|
elseif x == 127 then
|
||||||
|
return string.char(128 + y), 3
|
||||||
|
elseif x >= 32 then
|
||||||
|
return string.char(x), 2
|
||||||
|
elseif x == 31 then
|
||||||
|
return "\n", 2
|
||||||
|
elseif x == 30 then
|
||||||
|
return "\x00", 2
|
||||||
|
end
|
||||||
|
return string.char(("enart"):byte(x % 5 + 1), ("ndtelh"):byte((x - x % 5) / 5 + 1)), 2
|
||||||
|
end
|
||||||
|
|
||||||
|
local preprocParts = {}
|
||||||
|
local preprocMaxLen = 0
|
||||||
|
for i = 0, 127 do
|
||||||
|
for j = 0, 127 do
|
||||||
|
local d, l = p(i, j)
|
||||||
|
if d then
|
||||||
|
preprocMaxLen = math.max(preprocMaxLen, #d)
|
||||||
|
l = l - 1
|
||||||
|
if (not preprocParts[d]) or (#preprocParts[d] > l) then
|
||||||
|
if l == 2 then
|
||||||
|
preprocParts[d] = string.char(i, j)
|
||||||
|
else
|
||||||
|
preprocParts[d] = string.char(i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function preprocWithPadding(blk, p)
|
||||||
|
local out = ""
|
||||||
|
local needsPadding = false
|
||||||
|
while blk ~= "" do
|
||||||
|
p(blk)
|
||||||
|
local len = math.min(preprocMaxLen, #blk)
|
||||||
|
while len > 0 do
|
||||||
|
local seg = blk:sub(1, len)
|
||||||
|
if preprocParts[seg] then
|
||||||
|
out = out .. preprocParts[seg]
|
||||||
|
needsPadding = #preprocParts[seg] < 2
|
||||||
|
blk = blk:sub(#seg + 1)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
len = len - 1
|
||||||
|
end
|
||||||
|
assert(len ~= 0)
|
||||||
|
end
|
||||||
|
-- This needsPadding bit is just sort of quickly added in
|
||||||
|
-- to keep this part properly maintained
|
||||||
|
-- even though it might never get used
|
||||||
|
if needsPadding then
|
||||||
|
return out .. "\x00"
|
||||||
|
end
|
||||||
|
return out
|
||||||
|
end
|
||||||
|
|
||||||
|
local bdCore = require("bdivide.core")
|
||||||
|
|
||||||
|
return function (data, lexCrunch)
|
||||||
|
io.stderr:write("preproc: ")
|
||||||
|
local pi = frw.progress()
|
||||||
|
local function p(b)
|
||||||
|
pi(1 - (#b / #data))
|
||||||
|
end
|
||||||
|
data = preprocWithPadding(data, p)
|
||||||
|
io.stderr:write("\nbdivide: ")
|
||||||
|
pi = frw.progress()
|
||||||
|
data = bdCore.bdividePad(bdCore.bdivide(data, p))
|
||||||
|
io.stderr:write("\n")
|
||||||
|
return lexCrunch.process(frw.read("bdivide/instdeco.lua"), {}), data
|
||||||
|
end
|
72
inst/bdivide/core.lua
Normal file
72
inst/bdivide/core.lua
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
-- This is released into the public domain.
|
||||||
|
-- No warranty is provided, implied or otherwise.
|
||||||
|
|
||||||
|
-- BDIVIDE r5 edition
|
||||||
|
-- Algorithm simplified for smaller implementation and potentially better compression
|
||||||
|
-- format:
|
||||||
|
-- 0-127 for constants
|
||||||
|
-- <128 + (length - 4)>, <position high>, <position low>
|
||||||
|
-- Position is where in the window it was found, minus 1.
|
||||||
|
-- windowSize must be the same between the encoder and decoder,
|
||||||
|
-- and is the amount of data preserved after cropping.
|
||||||
|
|
||||||
|
local bdivCore = {}
|
||||||
|
|
||||||
|
function bdivCore.bdivide(blk, p)
|
||||||
|
local out = ""
|
||||||
|
|
||||||
|
local windowSize = 0x10000
|
||||||
|
local windowData = ("\x00"):rep(windowSize)
|
||||||
|
|
||||||
|
while blk ~= "" do
|
||||||
|
p(blk)
|
||||||
|
local bestData = blk:sub(1, 1)
|
||||||
|
assert(blk:byte() < 128, "BDIVIDE does not handle 8-bit data")
|
||||||
|
local bestRes = bestData
|
||||||
|
for lm = 0, 127 do
|
||||||
|
local al = lm + 4
|
||||||
|
local pfx = blk:sub(1, al)
|
||||||
|
if #pfx ~= al then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
local p = windowData:find(pfx, 1, true)
|
||||||
|
if not p then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
local pm = p - 1
|
||||||
|
local thirdByte = pm % 256
|
||||||
|
bestData = string.char(128 + lm, math.floor(pm / 256), thirdByte)
|
||||||
|
bestRes = pfx
|
||||||
|
end
|
||||||
|
-- ok, encode!
|
||||||
|
out = out .. bestData
|
||||||
|
-- crop window
|
||||||
|
windowData = (windowData .. bestRes):sub(-windowSize)
|
||||||
|
blk = blk:sub(#bestRes + 1)
|
||||||
|
end
|
||||||
|
return out
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Adds padding if required
|
||||||
|
function bdivCore.bdividePad(data)
|
||||||
|
local i = 1
|
||||||
|
-- Basically, if it ends on a literal,
|
||||||
|
-- then the literal won't get read without two padding bytes.
|
||||||
|
-- Otherwise (including if no data) it's fine.
|
||||||
|
local needsPadding = false
|
||||||
|
while i <= #data do
|
||||||
|
if data:byte(i) > 127 then
|
||||||
|
i = i + 3
|
||||||
|
needsPadding = false
|
||||||
|
else
|
||||||
|
i = i + 1
|
||||||
|
needsPadding = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if needsPadding then
|
||||||
|
return data .. "\x00\x00"
|
||||||
|
end
|
||||||
|
return data
|
||||||
|
end
|
||||||
|
|
||||||
|
return bdivCore
|
64
inst/bdivide/instdeco.lua
Normal file
64
inst/bdivide/instdeco.lua
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
-- This is released into the public domain.
|
||||||
|
-- No warranty is provided, implied or otherwise.
|
||||||
|
|
||||||
|
-- BDIVIDE (r5 edition) and PREPROC (r9 edition)
|
||||||
|
-- decompression engine for installer
|
||||||
|
|
||||||
|
$bdPPBuffer = ""
|
||||||
|
$bdBDBuffer = ""
|
||||||
|
$bdBDWindow = ("\x00"):rep(2^16)
|
||||||
|
-- High-level breakdown:
|
||||||
|
-- q is unescaper.
|
||||||
|
-- It'll only begin to input if at least 3 bytes are available,
|
||||||
|
-- so you'll want to throw in 2 extra zeroes at the end of stream as done here.
|
||||||
|
-- It uses t (input buffer) and p (output buffer).
|
||||||
|
-- Ignore its second argument, as that's a lie, it's just there for a local.
|
||||||
|
-- L is the actual decompressor. It has the same quirk as q, wanting two more bytes.
|
||||||
|
-- It stores to c (compressed), and w (window).
|
||||||
|
-- It outputs that which goes to the window to q also.
|
||||||
|
-- And it also uses a fake local.
|
||||||
|
|
||||||
|
-- SEE compress.lua FOR THIS FUNCTION
|
||||||
|
function $bdPP(x, y)
|
||||||
|
if x == 126 then
|
||||||
|
return string.char(y), 3
|
||||||
|
elseif x == 127 then
|
||||||
|
return string.char(128 + y), 3
|
||||||
|
elseif x >= 32 then
|
||||||
|
return string.char(x), 2
|
||||||
|
elseif x == 31 then
|
||||||
|
return "\n", 2
|
||||||
|
elseif x == 30 then
|
||||||
|
return "\x00", 2
|
||||||
|
end
|
||||||
|
return string.char(("enart"):byte(x % 5 + 1), ("ndtelh"):byte((x - x % 5) / 5 + 1)), 2
|
||||||
|
end
|
||||||
|
|
||||||
|
${
|
||||||
|
function $engineInput($L|lData)
|
||||||
|
$bdBDBuffer = $bdBDBuffer .. $lData
|
||||||
|
while #$bdBDBuffer > 2 do
|
||||||
|
$lData = $bdBDBuffer:byte()
|
||||||
|
if $lData < 128 then
|
||||||
|
$lData = $bdBDBuffer:sub(1, 1)
|
||||||
|
$bdBDBuffer = $bdBDBuffer:sub(2)
|
||||||
|
else
|
||||||
|
${
|
||||||
|
$L|bdBDPtr = $bdBDBuffer:byte(2) * 256 + $bdBDBuffer:byte(3) + 1
|
||||||
|
$lData = $bdBDWindow:sub($bdBDPtr, $bdBDPtr + $lData - 125)
|
||||||
|
$bdBDBuffer = $bdBDBuffer:sub(4)
|
||||||
|
$}
|
||||||
|
end
|
||||||
|
$bdPPBuffer = $bdPPBuffer .. $lData
|
||||||
|
$bdBDWindow = ($bdBDWindow .. $lData):sub(-2^16)
|
||||||
|
while #$bdPPBuffer > 1 do
|
||||||
|
${
|
||||||
|
$lData, $L|bdPPAdv = $bdPP($bdPPBuffer:byte(), $bdPPBuffer:byte(2))
|
||||||
|
$bdPPBuffer = $bdPPBuffer:sub($bdPPAdv)
|
||||||
|
$}
|
||||||
|
$engineOutput($lData)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
$}
|
||||||
|
|
18
inst/bdvlite/compress.lua
Normal file
18
inst/bdvlite/compress.lua
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
-- This is released into the public domain.
|
||||||
|
-- No warranty is provided, implied or otherwise.
|
||||||
|
|
||||||
|
local frw = require("libs.frw")
|
||||||
|
|
||||||
|
local bdCore = require("bdivide.core")
|
||||||
|
|
||||||
|
return function (data, lexCrunch)
|
||||||
|
io.stderr:write("\nbdivide: ")
|
||||||
|
local pi = frw.progress()
|
||||||
|
local function p(b)
|
||||||
|
pi(1 - (#b / #data))
|
||||||
|
end
|
||||||
|
data = bdCore.bdividePad(bdCore.bdivide(data, p))
|
||||||
|
io.stderr:write("\n")
|
||||||
|
return lexCrunch.process(frw.read("bdvlite/instdeco.lua"), {}), data
|
||||||
|
end
|
||||||
|
|
72
inst/bdvlite/core.lua
Normal file
72
inst/bdvlite/core.lua
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
-- This is released into the public domain.
|
||||||
|
-- No warranty is provided, implied or otherwise.
|
||||||
|
|
||||||
|
-- BDIVIDE r5 edition
|
||||||
|
-- Algorithm simplified for smaller implementation and potentially better compression
|
||||||
|
-- format:
|
||||||
|
-- 0-127 for constants
|
||||||
|
-- <128 + (length - 4)>, <position high>, <position low>
|
||||||
|
-- Position is where in the window it was found, minus 1.
|
||||||
|
-- windowSize must be the same between the encoder and decoder,
|
||||||
|
-- and is the amount of data preserved after cropping.
|
||||||
|
|
||||||
|
local bdivCore = {}
|
||||||
|
|
||||||
|
function bdivCore.bdivide(blk, p)
|
||||||
|
local out = ""
|
||||||
|
|
||||||
|
local windowSize = 0x10000
|
||||||
|
local windowData = ("\x00"):rep(windowSize)
|
||||||
|
|
||||||
|
while blk ~= "" do
|
||||||
|
p(blk)
|
||||||
|
local bestData = blk:sub(1, 1)
|
||||||
|
assert(blk:byte() < 128, "BDIVIDE does not handle 8-bit data")
|
||||||
|
local bestRes = bestData
|
||||||
|
for lm = 0, 127 do
|
||||||
|
local al = lm + 4
|
||||||
|
local pfx = blk:sub(1, al)
|
||||||
|
if #pfx ~= al then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
local p = windowData:find(pfx, 1, true)
|
||||||
|
if not p then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
local pm = p - 1
|
||||||
|
local thirdByte = pm % 256
|
||||||
|
bestData = string.char(128 + lm, math.floor(pm / 256), thirdByte)
|
||||||
|
bestRes = pfx
|
||||||
|
end
|
||||||
|
-- ok, encode!
|
||||||
|
out = out .. bestData
|
||||||
|
-- crop window
|
||||||
|
windowData = (windowData .. bestRes):sub(-windowSize)
|
||||||
|
blk = blk:sub(#bestRes + 1)
|
||||||
|
end
|
||||||
|
return out
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Adds padding if required
|
||||||
|
function bdivCore.bdividePad(data)
|
||||||
|
local i = 1
|
||||||
|
-- Basically, if it ends on a literal,
|
||||||
|
-- then the literal won't get read without two padding bytes.
|
||||||
|
-- Otherwise (including if no data) it's fine.
|
||||||
|
local needsPadding = false
|
||||||
|
while i <= #data do
|
||||||
|
if data:byte(i) > 127 then
|
||||||
|
i = i + 3
|
||||||
|
needsPadding = false
|
||||||
|
else
|
||||||
|
i = i + 1
|
||||||
|
needsPadding = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if needsPadding then
|
||||||
|
return data .. "\x00\x00"
|
||||||
|
end
|
||||||
|
return data
|
||||||
|
end
|
||||||
|
|
||||||
|
return bdivCore
|
30
inst/bdvlite/instdeco.lua
Normal file
30
inst/bdvlite/instdeco.lua
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
-- This is released into the public domain.
|
||||||
|
-- No warranty is provided, implied or otherwise.
|
||||||
|
|
||||||
|
-- BDIVIDE (r5 edition)
|
||||||
|
-- decompression engine used to decompress DEFLATE decompression engine
|
||||||
|
|
||||||
|
$bdBDBuffer = ""
|
||||||
|
$bdBDWindow = ("\x00"):rep(2^16)
|
||||||
|
|
||||||
|
${
|
||||||
|
function $engineInput($L|lData)
|
||||||
|
$bdBDBuffer = $bdBDBuffer .. $lData
|
||||||
|
while #$bdBDBuffer > 2 do
|
||||||
|
$lData = $bdBDBuffer:byte()
|
||||||
|
if $lData < 128 then
|
||||||
|
$lData = $bdBDBuffer:sub(1, 1)
|
||||||
|
$bdBDBuffer = $bdBDBuffer:sub(2)
|
||||||
|
else
|
||||||
|
${
|
||||||
|
$L|bdBDPtr = $bdBDBuffer:byte(2) * 256 + $bdBDBuffer:byte(3) + 1
|
||||||
|
$lData = $bdBDWindow:sub($bdBDPtr, $bdBDPtr + $lData - 125)
|
||||||
|
$bdBDBuffer = $bdBDBuffer:sub(4)
|
||||||
|
$}
|
||||||
|
end
|
||||||
|
$bdBDWindow = ($bdBDWindow .. $lData):sub(-2^16)
|
||||||
|
$engineOutput($lData)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
$}
|
||||||
|
|
78
inst/build.lua
Normal file
78
inst/build.lua
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
-- This is released into the public domain.
|
||||||
|
-- No warranty is provided, implied or otherwise.
|
||||||
|
|
||||||
|
-- KittenOS NEO Installer Generator --
|
||||||
|
local args = {...}
|
||||||
|
|
||||||
|
local cid = args[1]
|
||||||
|
local tarName = args[2]
|
||||||
|
local algorithmsInReverseOrder = {}
|
||||||
|
for i = 3, #args do
|
||||||
|
table.insert(algorithmsInReverseOrder, 1, args[i])
|
||||||
|
end
|
||||||
|
|
||||||
|
local u = require("libs.frw")
|
||||||
|
|
||||||
|
local instSize = 0
|
||||||
|
local function put(data)
|
||||||
|
io.write(data)
|
||||||
|
instSize = instSize + #data
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Installer Lexcrunch Context --
|
||||||
|
local lexCrunch = require("libs.lexcrunch")()
|
||||||
|
|
||||||
|
-- Installer Core --
|
||||||
|
|
||||||
|
-- installerFinalized:
|
||||||
|
-- Stuff that's already finished and put at the end of RISM. Prepend to this.
|
||||||
|
-- installerPayload / installerProgramLength:
|
||||||
|
-- The next-outer chunk that hasn't been written to the end of RISM
|
||||||
|
-- as the compression scheme (if one) has not been applied yet.
|
||||||
|
-- Really, installerProgramLength is only necessary because of the innermost chunk,
|
||||||
|
-- as that chunk has the TAR; additional data that's part of the same effective compression block,
|
||||||
|
-- but requires the program length to avoid it.
|
||||||
|
local installerPayload
|
||||||
|
local installerProgramLength
|
||||||
|
local installerFinalized = ""
|
||||||
|
|
||||||
|
do
|
||||||
|
local tarData = u.read(tarName)
|
||||||
|
local tarSectors = math.floor(#tarData / 512)
|
||||||
|
local installerCore = lexCrunch.process(u.read("instcore.lua"), {["$$SECTORS"] = tostring(tarSectors)})
|
||||||
|
installerPayload = installerCore .. tarData
|
||||||
|
installerProgramLength = #installerCore
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Installer Compression --
|
||||||
|
for _, v in ipairs(algorithmsInReverseOrder) do
|
||||||
|
io.stderr:write("compressing (" .. v .. ")\n")
|
||||||
|
local algImpl = require(v .. ".compress")
|
||||||
|
local algEngine, algData = algImpl(installerPayload, lexCrunch)
|
||||||
|
io.stderr:write("result: " .. #installerPayload .. " -> " .. #algData .. "\n")
|
||||||
|
-- prepend the program length of the last section
|
||||||
|
algEngine = lexCrunch.process("$iBlockingLen = " .. installerProgramLength .. " " .. algEngine, {})
|
||||||
|
-- commit
|
||||||
|
installerPayload = algEngine
|
||||||
|
installerProgramLength = #installerPayload
|
||||||
|
installerFinalized = algData .. installerFinalized
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Installer Final --
|
||||||
|
|
||||||
|
-- This is a special case, so the program length/payload/etc. business has to be repeated.
|
||||||
|
put("--" .. cid .. "\n")
|
||||||
|
put("--This is released into the public domain. No warranty is provided, implied or otherwise.\n")
|
||||||
|
put(lexCrunch.process(u.read("insthead.lua"), {["$$CORESIZE"] = tostring(installerProgramLength)}))
|
||||||
|
|
||||||
|
local RISM = installerPayload .. installerFinalized
|
||||||
|
RISM = RISM:gsub("\xFE", "\xFE\xFE")
|
||||||
|
RISM = RISM:gsub("]]", "]\xFE]")
|
||||||
|
RISM = "\x00" .. RISM
|
||||||
|
put("--[[" .. RISM .. "]]")
|
||||||
|
|
||||||
|
-- Dumping debug info --
|
||||||
|
local dbg = io.open("iSymTab", "wb")
|
||||||
|
lexCrunch.dump(dbg)
|
||||||
|
dbg:close()
|
||||||
|
|
14
inst/deflate/compress.lua
Normal file
14
inst/deflate/compress.lua
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
-- This is released into the public domain.
|
||||||
|
-- No warranty is provided, implied or otherwise.
|
||||||
|
|
||||||
|
-- This is a wrapper around (i.e. does not contain) Zopfli.
|
||||||
|
local frw = require("libs.frw")
|
||||||
|
|
||||||
|
return function (data, lexCrunch)
|
||||||
|
frw.write("tempData.bin", data)
|
||||||
|
os.execute("zopfli --i1 --deflate -c tempData.bin > tempZopf.bin")
|
||||||
|
local res = frw.read("tempZopf.bin")
|
||||||
|
os.execute("rm tempData.bin tempZopf.bin")
|
||||||
|
return lexCrunch.process(frw.read("deflate/instdeco.lua"), {}), res
|
||||||
|
end
|
||||||
|
|
287
inst/deflate/instdeco.lua
Normal file
287
inst/deflate/instdeco.lua
Normal file
@ -0,0 +1,287 @@
|
|||||||
|
-- This is released into the public domain.
|
||||||
|
-- No warranty is provided, implied or otherwise.
|
||||||
|
|
||||||
|
-- THIS NEXT LINE IS CLEARLY AWFUL
|
||||||
|
$bdBDWindow = nil
|
||||||
|
|
||||||
|
-- THE DEFLATE DECOMPRESSOR OF MADNESS --
|
||||||
|
|
||||||
|
-- Core I/O --
|
||||||
|
|
||||||
|
-- $dfAlignToByteRemaining is
|
||||||
|
-- set to 8 in the outer engine
|
||||||
|
|
||||||
|
${
|
||||||
|
function $dfGetIntField($L|lLen, $L|lVal)
|
||||||
|
$lVal = 0
|
||||||
|
for $L|lI = 0, $lLen - 1 do
|
||||||
|
if coroutine.yield() then
|
||||||
|
$lVal = $lVal + 2^$lI
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return $lVal
|
||||||
|
end
|
||||||
|
$}
|
||||||
|
|
||||||
|
-- Huffman Core --
|
||||||
|
-- The approach here is based around 1-prefixed integers.
|
||||||
|
-- These are stored in a flat table.
|
||||||
|
-- So 0b1000 is the pattern 000.
|
||||||
|
|
||||||
|
${
|
||||||
|
function $dfReadHuffmanSymbol($L|lTree, $L|lVal)
|
||||||
|
$lVal = 1
|
||||||
|
while not $lTree[$lVal] do
|
||||||
|
$lVal = ($lVal * 2) + $dfGetIntField(1)
|
||||||
|
end
|
||||||
|
return $lTree[$lVal]
|
||||||
|
end
|
||||||
|
$}
|
||||||
|
|
||||||
|
${
|
||||||
|
function $dfGenHuffmanTree($L|lCodeLens)
|
||||||
|
-- $L|lI (used everywhere; defining inside creates a bug because it gets globalized)
|
||||||
|
$L|lNextCode = {}
|
||||||
|
${
|
||||||
|
-- To explain:
|
||||||
|
-- lNextCode is needed all the way to the end.
|
||||||
|
-- But lBLCount isn't needed after it's used to
|
||||||
|
-- generate lNextCode.
|
||||||
|
-- And lCode is very, very temporary.
|
||||||
|
-- Hence this massive block.
|
||||||
|
$L|lBLCount = {}
|
||||||
|
-- Note the 0
|
||||||
|
for $lI = 0, 15 do
|
||||||
|
$lBLCount[$lI] = 0
|
||||||
|
end
|
||||||
|
for $lI = 0, #$lCodeLens do
|
||||||
|
${
|
||||||
|
$L|lCodeLen = $lCodeLens[$lI]
|
||||||
|
if $lCodeLen ~= 0 then
|
||||||
|
$lBLCount[$lCodeLen] = $lBLCount[$lCodeLen] + 1
|
||||||
|
end
|
||||||
|
$}
|
||||||
|
end
|
||||||
|
|
||||||
|
$L|lCode = 0
|
||||||
|
for $lI = 1, 15 do
|
||||||
|
$lCode = ($lCode + $lBLCount[$lI - 1]) * 2
|
||||||
|
$lNextCode[$lI] = $lCode
|
||||||
|
end
|
||||||
|
$}
|
||||||
|
|
||||||
|
$L|lTree = {}
|
||||||
|
for $lI = 0, #$lCodeLens do
|
||||||
|
${
|
||||||
|
$L|lCodeLen = $lCodeLens[$lI]
|
||||||
|
if $lCodeLen ~= 0 then
|
||||||
|
$L|lPow = math.floor(2 ^ $lCodeLen)
|
||||||
|
assert($lNextCode[$lCodeLen] < $lPow, "Tl" .. $lCodeLen)
|
||||||
|
$L|lK = $lNextCode[$lCodeLen] + $lPow
|
||||||
|
assert(not $lTree[$lK], "conflict @ " .. $lK)
|
||||||
|
$lTree[$lK] = $lI
|
||||||
|
$lNextCode[$lCodeLen] = $lNextCode[$lCodeLen] + 1
|
||||||
|
end
|
||||||
|
$}
|
||||||
|
end
|
||||||
|
return $lTree
|
||||||
|
end
|
||||||
|
$}
|
||||||
|
|
||||||
|
-- DEFLATE fixed trees --
|
||||||
|
${
|
||||||
|
$L|dfFixedTL = {}
|
||||||
|
for $L|lI = 0, 143 do $dfFixedTL[$lI] = 8 end
|
||||||
|
for $lI = 144, 255 do $dfFixedTL[$lI] = 9 end
|
||||||
|
for $lI = 256, 279 do $dfFixedTL[$lI] = 7 end
|
||||||
|
for $lI = 280, 287 do $dfFixedTL[$lI] = 8 end
|
||||||
|
$dfFixedLit = $dfGenHuffmanTree($dfFixedTL)
|
||||||
|
-- last line possibly destroyed dfFixedTL, but that's alright
|
||||||
|
$dfFixedTL = {}
|
||||||
|
for $lI = 0, 31 do $dfFixedTL[$lI] = 5 end
|
||||||
|
$dfFixedDst = $dfGenHuffmanTree($dfFixedTL)
|
||||||
|
$}
|
||||||
|
|
||||||
|
-- DEFLATE LZ Core --
|
||||||
|
|
||||||
|
$dfWindow = ("\x00"):rep(2^15)
|
||||||
|
$dfPushBuf = ""
|
||||||
|
${
|
||||||
|
function $dfOutput($L|lData)
|
||||||
|
$dfWindow = ($dfWindow .. $lData):sub(-2^15)
|
||||||
|
$dfPushBuf = $dfPushBuf .. $lData
|
||||||
|
end
|
||||||
|
$}
|
||||||
|
|
||||||
|
$dfBittblLength = {
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 1, 1, 1, 2, 2, 2, 2,
|
||||||
|
3, 3, 3, 3, 4, 4, 4, 4,
|
||||||
|
5, 5, 5, 5, 0
|
||||||
|
}
|
||||||
|
$dfBasetblLength = {
|
||||||
|
3, 4, 5, 6, 7, 8, 9, 10,
|
||||||
|
11, 13, 15, 17, 19, 23, 27, 31,
|
||||||
|
35, 43, 51, 59, 67, 83, 99, 115,
|
||||||
|
131, 163, 195, 227, 258
|
||||||
|
}
|
||||||
|
$dfBittblDist = {
|
||||||
|
0, 0, 0, 0, 1, 1, 2, 2,
|
||||||
|
3, 3, 4, 4, 5, 5, 6, 6,
|
||||||
|
7, 7, 8, 8, 9, 9, 10, 10,
|
||||||
|
11, 11, 12, 12, 13, 13
|
||||||
|
}
|
||||||
|
$dfBasetblDist = {
|
||||||
|
1, 2, 3, 4, 5, 7, 9, 13,
|
||||||
|
17, 25, 33, 49, 65, 97, 129, 193,
|
||||||
|
257, 385, 513, 769, 1025, 1537, 2049, 3073,
|
||||||
|
4097, 6145, 8193, 12289, 16385, 24577
|
||||||
|
}
|
||||||
|
|
||||||
|
${
|
||||||
|
function $dfReadBlockBody($L|lLit, $L|lDst, $L|lLitSym, $L|lLen, $L|lDCode, $L|lPtr)
|
||||||
|
while true do
|
||||||
|
$lLitSym = $dfReadHuffmanSymbol($lLit)
|
||||||
|
if $lLitSym <= 255 then
|
||||||
|
$dfOutput(string.char($lLitSym))
|
||||||
|
elseif $lLitSym == 256 then
|
||||||
|
return
|
||||||
|
elseif $lLitSym <= 285 then
|
||||||
|
$lLen = $dfBasetblLength[$lLitSym - 256] + $dfGetIntField($dfBittblLength[$lLitSym - 256])
|
||||||
|
$lDCode = $dfReadHuffmanSymbol($lDst)
|
||||||
|
$lPtr = 32769 - ($dfBasetblDist[$lDCode + 1] + $dfGetIntField($dfBittblDist[$lDCode + 1]))
|
||||||
|
for $L|lI = 1, $lLen do
|
||||||
|
$dfOutput($dfWindow:sub($lPtr, $lPtr))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
error("nt" .. v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
$}
|
||||||
|
|
||||||
|
-- Huffman Dynamics --
|
||||||
|
|
||||||
|
${
|
||||||
|
function $dfReadHuffmanDynamicSubcodes($L|lDistLens, $L|lCount, $L|lMetatree, $L|lCode)
|
||||||
|
-- used a lot: $L|lI
|
||||||
|
$lCode = 0
|
||||||
|
$lDistLens[-1] = 0
|
||||||
|
while $lCode < $lCount do
|
||||||
|
-- use a tmpglb since it's just for the chain
|
||||||
|
$L|lInstr = $dfReadHuffmanSymbol($lMetatree)
|
||||||
|
if $lInstr < 16 then
|
||||||
|
$lDistLens[$lCode] = $lInstr
|
||||||
|
$lCode = $lCode + 1
|
||||||
|
elseif $lInstr == 16 then
|
||||||
|
for $lI = 1, 3 + $dfGetIntField(2) do
|
||||||
|
$lDistLens[$lCode] = $lDistLens[$lCode - 1]
|
||||||
|
$lCode = $lCode + 1
|
||||||
|
assert($lCode <= $lCount, "sc.over")
|
||||||
|
end
|
||||||
|
elseif $lInstr == 17 then
|
||||||
|
for $lI = 1, 3 + $dfGetIntField(3) do
|
||||||
|
$lDistLens[$lCode] = 0
|
||||||
|
$lCode = $lCode + 1
|
||||||
|
assert($lCode <= $lCount, "sc.over")
|
||||||
|
end
|
||||||
|
elseif $lInstr == 18 then
|
||||||
|
for $lI = 1, 11 + $dfGetIntField(7) do
|
||||||
|
$lDistLens[$lCode] = 0
|
||||||
|
$lCode = $lCode + 1
|
||||||
|
assert($lCode <= $lCount, "sc.over")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- is this even possible?
|
||||||
|
error("sc.unki")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
$lDistLens[-1] = nil
|
||||||
|
return $lDistLens
|
||||||
|
end
|
||||||
|
$}
|
||||||
|
|
||||||
|
$dfDynamicMetalensScramble = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}
|
||||||
|
|
||||||
|
${
|
||||||
|
function $dfReadHuffmanDynamic($L|lState, $L|lLiteralSize, $L|lDistanceSize, $L|lDistanceLens)
|
||||||
|
-- $L|lI loop variable, used all over
|
||||||
|
-- to save on locals, this is reused
|
||||||
|
-- as metalens
|
||||||
|
$lState = {}
|
||||||
|
for $lI = 0, 18 do $lState[$lI] = 0 end
|
||||||
|
$lLiteralSize = $dfGetIntField(5) + 257
|
||||||
|
$lDistanceSize = $dfGetIntField(5) + 1
|
||||||
|
for $lI = 1, $dfGetIntField(4) + 4 do
|
||||||
|
$lState[$dfDynamicMetalensScramble[$lI]] = $dfGetIntField(3)
|
||||||
|
end
|
||||||
|
-- as metatree
|
||||||
|
$lState = $dfGenHuffmanTree($lState)
|
||||||
|
-- as concatenated subcodes
|
||||||
|
$lState = $dfReadHuffmanDynamicSubcodes({}, $lLiteralSize + $lDistanceSize, $lState)
|
||||||
|
-- The distance lengths are removed from lState,
|
||||||
|
-- while being added to lDistanceLens
|
||||||
|
-- The result is completion
|
||||||
|
$lDistanceLens = {}
|
||||||
|
for $lI = 0, $lDistanceSize - 1 do
|
||||||
|
$lDistanceLens[$lI] = $lState[$lLiteralSize + $lI]
|
||||||
|
$lState[$lLiteralSize + $lI] = nil
|
||||||
|
end
|
||||||
|
return $dfGenHuffmanTree($lState), $dfGenHuffmanTree($lDistanceLens)
|
||||||
|
end
|
||||||
|
$}
|
||||||
|
|
||||||
|
-- Main Thread --
|
||||||
|
|
||||||
|
${
|
||||||
|
$dfThread = coroutine.create(function ($L|lFinal, $L|lLitLen)
|
||||||
|
while true do
|
||||||
|
$lFinal = coroutine.yield()
|
||||||
|
$L|lBlockType = $dfGetIntField(2)
|
||||||
|
if $lBlockType == 0 then
|
||||||
|
-- literal
|
||||||
|
$dfGetIntField($dfAlignToByteRemaining)
|
||||||
|
$lLitLen = $dfGetIntField(16)
|
||||||
|
-- this is weird, ignore it
|
||||||
|
$dfGetIntField(16)
|
||||||
|
for $L|lI = 1, $lLitLen do
|
||||||
|
$dfOutput(string.char($dfGetIntField(8)))
|
||||||
|
end
|
||||||
|
elseif $lBlockType == 1 then
|
||||||
|
-- fixed Huffman
|
||||||
|
$dfReadBlockBody($dfFixedLit, $dfFixedDst)
|
||||||
|
elseif $lBlockType == 2 then
|
||||||
|
-- dynamic Huffman
|
||||||
|
$dfReadBlockBody($dfReadHuffmanDynamic())
|
||||||
|
else
|
||||||
|
error("b3")
|
||||||
|
end
|
||||||
|
while $lFinal do
|
||||||
|
coroutine.yield()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
$}
|
||||||
|
|
||||||
|
-- The Outer Engine --
|
||||||
|
|
||||||
|
coroutine.resume($dfThread)
|
||||||
|
${
|
||||||
|
function $engineInput($L|lData, $L|lByte)
|
||||||
|
for $L|lI = 1, #$lData do
|
||||||
|
$lByte = $lData:byte($lI)
|
||||||
|
$dfAlignToByteRemaining = 8
|
||||||
|
while $dfAlignToByteRemaining > 0 do
|
||||||
|
-- If we're providing the first bit (v = 8), then there are 7 bits remaining.
|
||||||
|
-- So this hits 0 when the *next* 8 yields will provide an as-is byte.
|
||||||
|
$dfAlignToByteRemaining = $dfAlignToByteRemaining - 1
|
||||||
|
assert(coroutine.resume($dfThread, $lByte % 2 == 1))
|
||||||
|
$lByte = math.floor($lByte / 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- flush prepared buffer
|
||||||
|
$engineOutput($dfPushBuf)
|
||||||
|
$dfPushBuf = ""
|
||||||
|
end
|
||||||
|
$}
|
||||||
|
|
76
inst/instcore.lua
Normal file
76
inst/instcore.lua
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
-- KOSNEO installer base
|
||||||
|
-- This is released into the public domain.
|
||||||
|
-- No warranty is provided, implied or otherwise.
|
||||||
|
|
||||||
|
$icScreen = $component.list("screen", true)()
|
||||||
|
$icGPU = $component.list("gpu", true)()
|
||||||
|
|
||||||
|
$icFilename = "Starting..."
|
||||||
|
$icBytesRemaining = 0
|
||||||
|
|
||||||
|
if $icScreen and $icGPU then
|
||||||
|
$icGPU = $component.proxy($icGPU)
|
||||||
|
$icGPU.bind($icScreen)
|
||||||
|
$icGPU.setResolution(50, 5)
|
||||||
|
$icGPU.setBackground(2^24-1)
|
||||||
|
$icGPU.setForeground(0)
|
||||||
|
$icGPU.fill(1, 1, 50, 5, "█")
|
||||||
|
$icGPU.fill(1, 2, 50, 1, " ")
|
||||||
|
$icGPU.set(2, 2, "KittenOS NEO Installer")
|
||||||
|
end
|
||||||
|
|
||||||
|
function $icOctalToNumber($a0)
|
||||||
|
if $a0 == "" then return 0 end
|
||||||
|
return $icOctalToNumber($a0:sub(1, -2)) * 8 + ($a0:byte(#$a0) - 48)
|
||||||
|
end
|
||||||
|
|
||||||
|
$icSectorsRead = 0
|
||||||
|
$iBlockingLen = 512
|
||||||
|
function $iBlockingHook($a0)
|
||||||
|
if $icBytesRemaining > 0 then
|
||||||
|
${
|
||||||
|
$L|icByteAdv = math.min(512, $icBytesRemaining)
|
||||||
|
$icBytesRemaining = $icBytesRemaining - $icByteAdv
|
||||||
|
if $icFile then
|
||||||
|
$filesystem.write($icFile, $a0:sub(1, $icByteAdv))
|
||||||
|
if $icBytesRemaining <= 0 then
|
||||||
|
$filesystem.close($icFile)
|
||||||
|
$icFile = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
$}
|
||||||
|
else
|
||||||
|
$icFilename = $a0:sub(1, 100):gsub("\x00", "")
|
||||||
|
-- this sets up the reading/skipping of data
|
||||||
|
$icBytesRemaining = $icOctalToNumber($a0:sub(125, 135))
|
||||||
|
if $icFilename:sub(1, 2) == "./" and $icFilename ~= "./" then
|
||||||
|
$icFilename = $icFilename:sub(3)
|
||||||
|
if $icFilename:sub(#$icFilename) == "/" then
|
||||||
|
$filesystem.makeDirectory($icFilename)
|
||||||
|
else
|
||||||
|
$icFile = $filesystem.open($icFilename, "wb")
|
||||||
|
if $icBytesRemaining == 0 then
|
||||||
|
$filesystem.close($icFile)
|
||||||
|
$icFile = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- UPDATE DISPLAY --
|
||||||
|
$icSectorsRead = $icSectorsRead + 1
|
||||||
|
if $icScreen and $icGPU then
|
||||||
|
$icGPU.fill(1, 2, 50, 1, " ")
|
||||||
|
$icGPU.set(2, 2, "KittenOS NEO Installer : " .. $icFilename)
|
||||||
|
$icGPU.fill(2, 4, 48, 1, "█")
|
||||||
|
$icGPU.fill(2, 4, math.ceil(48 * $icSectorsRead / $$SECTORS), 1, " ")
|
||||||
|
end
|
||||||
|
if $icSectorsRead % 16 == 0 then
|
||||||
|
$computer.pullSignal(0.01)
|
||||||
|
end
|
||||||
|
if $icSectorsRead == $$SECTORS then
|
||||||
|
$filesystem.close($readInFile)
|
||||||
|
$filesystem.remove("init.neoi.lua")
|
||||||
|
$computer.shutdown(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
67
inst/insthead.lua
Normal file
67
inst/insthead.lua
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
-- KOSNEO installer base
|
||||||
|
-- This is released into the public domain.
|
||||||
|
-- No warranty is provided, implied or otherwise.
|
||||||
|
|
||||||
|
$computer = computer
|
||||||
|
$component = component
|
||||||
|
assert($component, "KittenOS NEO installer: Copy as init.lua to the target disk, then remove other disks & reboot.")
|
||||||
|
|
||||||
|
$filesystem = $component.proxy($computer.getBootAddress())
|
||||||
|
|
||||||
|
$filesystem.remove("init.neoi.lua")
|
||||||
|
$filesystem.rename("init.lua", "init.neoi.lua")
|
||||||
|
$readInFile = $filesystem.open("init.neoi.lua", "rb")
|
||||||
|
|
||||||
|
$iBlockingBuffer = ""
|
||||||
|
$iBlockingLen = $$CORESIZE
|
||||||
|
${
|
||||||
|
function $iBlockingHook($L|lBlock)
|
||||||
|
-- Run the next script (replacement compression engine,)
|
||||||
|
assert(load($lBlock))()
|
||||||
|
end
|
||||||
|
$}
|
||||||
|
|
||||||
|
${
|
||||||
|
function $engineOutput($L|lBlock)
|
||||||
|
$iBlockingBuffer = $iBlockingBuffer .. $lBlock
|
||||||
|
while #$iBlockingBuffer >= $iBlockingLen do
|
||||||
|
$lBlock = $iBlockingBuffer:sub(1, $iBlockingLen)
|
||||||
|
$iBlockingBuffer = $iBlockingBuffer:sub($iBlockingLen + 1)
|
||||||
|
$iBlockingHook($lBlock)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
$}
|
||||||
|
$engineInput = $engineOutput
|
||||||
|
|
||||||
|
while true do
|
||||||
|
$readInBlock = $filesystem.read($readInFile, 1024)
|
||||||
|
${
|
||||||
|
for i = 1, #$readInBlock do
|
||||||
|
-- Read-in state machine
|
||||||
|
|
||||||
|
-- IT IS VERY IMPORTANT that read-in be performed char-by-char.
|
||||||
|
-- This is because of compression chain-loading; if the switch between engines isn't "clean",
|
||||||
|
-- bad stuff happens.
|
||||||
|
|
||||||
|
-- This character becomes invalid once
|
||||||
|
-- it gets passed to engineInput,
|
||||||
|
-- but that's the last step, so it's ok!
|
||||||
|
$L|readInChar = $readInBlock:sub(i, i)
|
||||||
|
if not $readInState then
|
||||||
|
if $readInChar == "\x00" then
|
||||||
|
$readInState = 0
|
||||||
|
end
|
||||||
|
elseif $readInState == 0 then
|
||||||
|
if $readInChar == "\xFE" then
|
||||||
|
$readInState = 1
|
||||||
|
else
|
||||||
|
$engineInput($readInChar)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
$engineInput($readInChar)
|
||||||
|
$readInState = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
$}
|
||||||
|
end
|
||||||
|
|
30
inst/libs/frw.lua
Normal file
30
inst/libs/frw.lua
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
-- This is released into the public domain.
|
||||||
|
-- No warranty is provided, implied or otherwise.
|
||||||
|
|
||||||
|
return {
|
||||||
|
read = function (fn)
|
||||||
|
local f = io.open(fn, "rb")
|
||||||
|
local d = f:read("*a")
|
||||||
|
f:close()
|
||||||
|
return d
|
||||||
|
end,
|
||||||
|
write = function (fn, data)
|
||||||
|
local f = io.open(fn, "wb")
|
||||||
|
f:write(data)
|
||||||
|
f:close()
|
||||||
|
end,
|
||||||
|
progress = function ()
|
||||||
|
io.stderr:write("00% \\")
|
||||||
|
local lastPercent = 0
|
||||||
|
local chr = 0
|
||||||
|
return function (fraction)
|
||||||
|
local percent = math.ceil(fraction * 100)
|
||||||
|
if percent ~= lastPercent then
|
||||||
|
lastPercent = percent
|
||||||
|
chr = (chr + 1) % 4
|
||||||
|
io.stderr:write(string.format("\8\8\8\8\8%02i%% %s", percent, ("\\|/-"):sub(chr + 1, chr + 1)))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
191
inst/libs/lexcrunch.lua
Normal file
191
inst/libs/lexcrunch.lua
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
-- This is released into the public domain.
|
||||||
|
-- No warranty is provided, implied or otherwise.
|
||||||
|
|
||||||
|
-- This library helps in crunching down the installer a bit further.
|
||||||
|
local sequences = {
|
||||||
|
{"\n", " "},
|
||||||
|
{" ", " "},
|
||||||
|
{" #", "#"},
|
||||||
|
{"# ", "#"},
|
||||||
|
{" ,", ","},
|
||||||
|
{", ", ","},
|
||||||
|
{" (", "("},
|
||||||
|
{"( ", "("},
|
||||||
|
{" )", ")"},
|
||||||
|
{") ", ")"},
|
||||||
|
{" {", "{"},
|
||||||
|
{"{ ", "{"},
|
||||||
|
{" }", "}"},
|
||||||
|
{"} ", "}"},
|
||||||
|
{" <", "<"},
|
||||||
|
{"< ", "<"},
|
||||||
|
{" >", ">"},
|
||||||
|
{"> ", ">"},
|
||||||
|
{" *", "*"},
|
||||||
|
{"* ", "*"},
|
||||||
|
{" ~", "~"},
|
||||||
|
{"~ ", "~"},
|
||||||
|
{" /", "/"},
|
||||||
|
{"/ ", "/"},
|
||||||
|
{" %", "%"},
|
||||||
|
{"% ", "%"},
|
||||||
|
{" =", "="},
|
||||||
|
{"= ", "="},
|
||||||
|
{" -", "-"},
|
||||||
|
{"- ", "-"},
|
||||||
|
{" +", "+"},
|
||||||
|
{"+ ", "+"},
|
||||||
|
{".. ", ".."},
|
||||||
|
{" ..", ".."},
|
||||||
|
{"\"\" ", "\"\""},
|
||||||
|
{"=0 t", "=0t"},
|
||||||
|
{">0 t", ">0t"},
|
||||||
|
{">1 t", ">1t"},
|
||||||
|
{"=1 w", "=1w"},
|
||||||
|
{"=380 l", "=380l"},
|
||||||
|
{"=127 t", "=127t"},
|
||||||
|
{"<128 t", "<128t"},
|
||||||
|
{"=128 t", "=128t"},
|
||||||
|
{">255 t", ">255t"},
|
||||||
|
{"=512 t", "=512t"}
|
||||||
|
}
|
||||||
|
|
||||||
|
local function pass(buffer)
|
||||||
|
local ob = ""
|
||||||
|
local smode = false
|
||||||
|
while #buffer > 0 do
|
||||||
|
if not smode then
|
||||||
|
local ds = true
|
||||||
|
while ds do
|
||||||
|
ds = false
|
||||||
|
for _, v in ipairs(sequences) do
|
||||||
|
if buffer:sub(1, #(v[1])) == v[1] then
|
||||||
|
buffer = v[2] .. buffer:sub(#(v[1]) + 1)
|
||||||
|
ds = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local ch = buffer:sub(1, 1)
|
||||||
|
buffer = buffer:sub(2)
|
||||||
|
ob = ob .. ch
|
||||||
|
if ch == "\"" then
|
||||||
|
smode = not smode
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return ob
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Context creation --
|
||||||
|
return function ()
|
||||||
|
local forwardSymTab = {}
|
||||||
|
local reverseSymTab = {}
|
||||||
|
|
||||||
|
local temporaryPool = {}
|
||||||
|
|
||||||
|
local stackFrames = {}
|
||||||
|
|
||||||
|
local log = {}
|
||||||
|
|
||||||
|
local possible = {}
|
||||||
|
for i = 1, 52 do
|
||||||
|
possible[i] = ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"):sub(i, i)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function allocate(reason)
|
||||||
|
for _, v in pairs(possible) do
|
||||||
|
if not reverseSymTab[v] then
|
||||||
|
reverseSymTab[v] = reason
|
||||||
|
return v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function allocTmp(id)
|
||||||
|
assert(not forwardSymTab[id], "var already exists: " .. id)
|
||||||
|
local val = table.remove(temporaryPool, 1)
|
||||||
|
if not val then val = allocate("temporary") end
|
||||||
|
forwardSymTab[id] = val
|
||||||
|
table.insert(log, "allocTmp " .. id .. " -> " .. val)
|
||||||
|
return val
|
||||||
|
end
|
||||||
|
|
||||||
|
local lexCrunch = {}
|
||||||
|
function lexCrunch.dump(file)
|
||||||
|
file:write("forward table:\n")
|
||||||
|
for k, v in pairs(forwardSymTab) do
|
||||||
|
file:write(k .. " -> " .. v .. "\n")
|
||||||
|
end
|
||||||
|
file:write("reverse table (where differing):\n")
|
||||||
|
for k, v in pairs(reverseSymTab) do
|
||||||
|
if forwardSymTab[v] ~= k then
|
||||||
|
file:write(v .. " -> " .. k .. "\n")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
file:write("log:\n")
|
||||||
|
for k, v in ipairs(log) do
|
||||||
|
file:write(v .. "\n")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function lexCrunch.process(op, defines)
|
||||||
|
-- symbol replacement
|
||||||
|
op = op:gsub("%$[%$a-z%{%}%|A-Z0-9]*", function (str)
|
||||||
|
if str:sub(2, 2) == "$" then
|
||||||
|
-- defines
|
||||||
|
assert(defines[str], "no define " .. str)
|
||||||
|
return defines[str]
|
||||||
|
end
|
||||||
|
local com = {}
|
||||||
|
for v in str:sub(2):gmatch("[^%|]*") do
|
||||||
|
table.insert(com, v)
|
||||||
|
end
|
||||||
|
if com[1] == "L" then
|
||||||
|
assert(#com == 2)
|
||||||
|
local id = "$" .. com[2]
|
||||||
|
assert(stackFrames[1], "allocation of " .. id .. " outside of stack frame")
|
||||||
|
table.insert(stackFrames[1], id)
|
||||||
|
return allocTmp(id)
|
||||||
|
elseif com[1] == "{" then
|
||||||
|
assert(#com == 1)
|
||||||
|
table.insert(stackFrames, 1, {})
|
||||||
|
return ""
|
||||||
|
elseif com[1] == "}" then
|
||||||
|
assert(#com == 1)
|
||||||
|
for _, id in ipairs(table.remove(stackFrames, 1)) do
|
||||||
|
table.insert(temporaryPool, forwardSymTab[id])
|
||||||
|
forwardSymTab[id] = nil
|
||||||
|
end
|
||||||
|
return ""
|
||||||
|
else
|
||||||
|
assert(#com == 1)
|
||||||
|
local id = "$" .. com[1]
|
||||||
|
-- normal handling
|
||||||
|
if forwardSymTab[id] then
|
||||||
|
return forwardSymTab[id]
|
||||||
|
end
|
||||||
|
local v = allocate(id)
|
||||||
|
forwardSymTab[id] = v
|
||||||
|
return v
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
-- comment removal
|
||||||
|
while true do
|
||||||
|
local np = op:gsub("%-%-[^\n]*\n", " ")
|
||||||
|
np = np:gsub("%-%-[^\n]*$", "")
|
||||||
|
if np == op then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
op = np
|
||||||
|
end
|
||||||
|
-- stripping
|
||||||
|
while true do
|
||||||
|
local np = pass(op)
|
||||||
|
if np == op then
|
||||||
|
return np
|
||||||
|
end
|
||||||
|
op = np
|
||||||
|
end
|
||||||
|
return op
|
||||||
|
end
|
||||||
|
return lexCrunch
|
||||||
|
end
|
36
inst/status.lua
Normal file
36
inst/status.lua
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
-- This is released into the public domain.
|
||||||
|
-- No warranty is provided, implied or otherwise.
|
||||||
|
|
||||||
|
-- Status Screen --
|
||||||
|
local target = ...
|
||||||
|
local u = require("libs.frw")
|
||||||
|
local instSize = #u.read(target)
|
||||||
|
|
||||||
|
local status = ""
|
||||||
|
local statusDetail = ""
|
||||||
|
local blinkI = ""
|
||||||
|
if instSize > 65536 then
|
||||||
|
blinkI = "5;31;"
|
||||||
|
status = " DO NOT SHIP "
|
||||||
|
statusDetail = "The installer is too big to ship safely.\nIt's possible it may crash on Tier 1 systems.\nUpgrade the compression system or remove existing code."
|
||||||
|
elseif instSize > 64000 then
|
||||||
|
blinkI = "33;"
|
||||||
|
status = " Shippable * "
|
||||||
|
statusDetail = "The installer is getting dangerously large.\nReserve further room for bugfixes."
|
||||||
|
else
|
||||||
|
blinkI = "32;"
|
||||||
|
status = " All Green "
|
||||||
|
statusDetail = "The installer is well within budget with room for features.\nDevelop as normal."
|
||||||
|
end
|
||||||
|
io.stderr:write("\n")
|
||||||
|
local ctS, ctM, ctE = " \x1b[1;" .. blinkI .. "7m", "\x1b[0;7m", "\x1b[0m\n"
|
||||||
|
io.stderr:write(ctS .. " " .. ctM .. " " .. ctE)
|
||||||
|
io.stderr:write(ctS .. status .. ctM .. string.format(" %07i ", 65536 - instSize) .. ctE)
|
||||||
|
io.stderr:write(ctS .. " " .. ctM .. " " .. ctE)
|
||||||
|
io.stderr:write("\n")
|
||||||
|
io.stderr:write(statusDetail .. "\n")
|
||||||
|
io.stderr:write("\n")
|
||||||
|
io.stderr:write("Size: " .. instSize .. "\n")
|
||||||
|
io.stderr:write(" max. 65536\n")
|
||||||
|
io.stderr:write("\n")
|
||||||
|
|
32
inst/symbolGuide.md
Normal file
32
inst/symbolGuide.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# The Symbol Guide
|
||||||
|
|
||||||
|
## lexCrunch commands
|
||||||
|
|
||||||
|
The following prefixes are really special,
|
||||||
|
and are lexcrunch's responsibility:
|
||||||
|
|
||||||
|
"$$THING" : These are defines.
|
||||||
|
"$Thing" : Writes a global into stream. If not already allocated, is allocated a global.
|
||||||
|
|
||||||
|
"${" : Opens a frame.
|
||||||
|
"$}" : Closes a frame. (Attached temps are released.)
|
||||||
|
"$L|THING" : Allocates THING from temp pool, attaches to stack frame, writes to stream.
|
||||||
|
Use inside a comment to erase the written symbol
|
||||||
|
|
||||||
|
## Conventions
|
||||||
|
|
||||||
|
The rest are convention:
|
||||||
|
"$iThing" symbols are Installer Wrapper.
|
||||||
|
"$icThing" symbols are Installer Core.
|
||||||
|
"$dfThing" symbols are DEFLATE Engine.
|
||||||
|
"$bdThing" symbols are BDIVIDE Engine.
|
||||||
|
|
||||||
|
"$a0", "$a1", etc. are Local Symbols.
|
||||||
|
DEPRECATED, THESE ARE AN OLD MECHANISM, USE FRAMED TEMPS INSTEAD.
|
||||||
|
These are reserved only for use in locals.
|
||||||
|
(For loops count.)
|
||||||
|
|
||||||
|
"$lThing" symbols are used to name Local Symbols using aliases.
|
||||||
|
|
||||||
|
NO THEY ARE NOW USED FOR ALL TEMPS, INCLUDING LOCAL SYMBOLS
|
||||||
|
|
10
inst/uncompressed/compress.lua
Normal file
10
inst/uncompressed/compress.lua
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
-- This is released into the public domain.
|
||||||
|
-- No warranty is provided, implied or otherwise.
|
||||||
|
|
||||||
|
-- Example compression engine.
|
||||||
|
-- Given: data, lexCrunch
|
||||||
|
-- returns compressionEngine, compressedData
|
||||||
|
return function (data, lexCrunch)
|
||||||
|
return lexCrunch.process(" $engineInput = $engineOutput ", {}), data
|
||||||
|
end
|
||||||
|
|
97
insthead.lua
97
insthead.lua
@ -1,97 +0,0 @@
|
|||||||
-- KOSNEO inst.
|
|
||||||
-- This is released into the public domain.
|
|
||||||
-- No warranty is provided, implied or otherwise.
|
|
||||||
C, O, G, D = component, computer
|
|
||||||
assert(C, "To install, please copy as init.lua to a blank disk or a system to update, then remove all other disks and reboot.")
|
|
||||||
|
|
||||||
sa = C.list("screen", true)()
|
|
||||||
if sa then
|
|
||||||
G = C.list("gpu", true)()
|
|
||||||
if G then
|
|
||||||
G = C.proxy(G)
|
|
||||||
G.bind(sa)
|
|
||||||
G.setForeground(0xFFFFFF)
|
|
||||||
G.setBackground(0x000000)
|
|
||||||
G.setResolution(50, 5)
|
|
||||||
G.setDepth(1)
|
|
||||||
G.fill(1, 1, 50, 5, " ")
|
|
||||||
G.setBackground(0xFFFFFF)
|
|
||||||
G.setForeground(0x000000)
|
|
||||||
G.fill(1, 2, 50, 1, " ")
|
|
||||||
G.set(2, 2, "KittenOS NEO Installer")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
D = C.proxy(O.getBootAddress())
|
|
||||||
|
|
||||||
tFN,tFSR,tW,tF="Starting...",0,0
|
|
||||||
|
|
||||||
function tO(oct)
|
|
||||||
local v = oct:byte(#oct) - 0x30
|
|
||||||
if #oct > 1 then
|
|
||||||
return (tO(oct:sub(1, #oct - 1)) * 8) + v
|
|
||||||
end
|
|
||||||
return v
|
|
||||||
end
|
|
||||||
function tA(s)
|
|
||||||
if tW > 0 then
|
|
||||||
tW = tW - 1
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if tF then
|
|
||||||
local ta = math.min(512, tFSR)
|
|
||||||
D.write(tF, s:sub(1, ta))
|
|
||||||
tFSR = tFSR - ta
|
|
||||||
if tFSR == 0 then
|
|
||||||
D.close(tF)
|
|
||||||
tF = nil
|
|
||||||
end
|
|
||||||
else
|
|
||||||
tFN = s:sub(1, 100):gsub("\x00", "")
|
|
||||||
local sz = tO(s:sub(125, 135))
|
|
||||||
if tFN:sub(1, 5) ~= "code/" then
|
|
||||||
tW = math.ceil(sz / 512)
|
|
||||||
else
|
|
||||||
tFN = tFN:sub(6)
|
|
||||||
if tFN == "" then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if tFN:sub(#tFN) == "/" then
|
|
||||||
tW = math.ceil(sz / 512)
|
|
||||||
D.makeDirectory(tFN)
|
|
||||||
else
|
|
||||||
tF = D.open(tFN, "wb")
|
|
||||||
tFSR = sz
|
|
||||||
if tFSR == 0 then
|
|
||||||
D.close(tF)
|
|
||||||
tF = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
sN, sC = 0, 0
|
|
||||||
|
|
||||||
function sector(n)
|
|
||||||
tA(n)
|
|
||||||
sN = sN + 1
|
|
||||||
if G then
|
|
||||||
local a = sN / sC
|
|
||||||
G.fill(1, 2, 50, 1, " ")
|
|
||||||
G.set(2, 2, "KittenOS NEO Installer : " .. tFN)
|
|
||||||
G.setForeground(0xFFFFFF)
|
|
||||||
G.setBackground(0x000000)
|
|
||||||
G.fill(2, 4, 48, 1, " ")
|
|
||||||
G.setBackground(0xFFFFFF)
|
|
||||||
G.setForeground(0x000000)
|
|
||||||
G.fill(2, 4, math.ceil(48 * a), 1, " ")
|
|
||||||
end
|
|
||||||
if sN % 8 == 0 then
|
|
||||||
O.pullSignal(0.05)
|
|
||||||
end
|
|
||||||
if sN == sC then
|
|
||||||
dieCB()
|
|
||||||
O.shutdown(true)
|
|
||||||
end
|
|
||||||
end
|
|
@ -3,8 +3,8 @@ ocemu {
|
|||||||
components {
|
components {
|
||||||
{"gpu", "c1-gpu-tier3", 0, 160, 50, 3},
|
{"gpu", "c1-gpu-tier3", 0, 160, 50, 3},
|
||||||
{"gpu", "c1-gpu-tier1", 0, 50, 16, 1},
|
{"gpu", "c1-gpu-tier1", 0, 50, 16, 1},
|
||||||
-- {"screen_sdl2", "c1-screen-tier3", -1, 160, 50, 3},
|
{"screen_sdl2", "c1-screen-tier3", -1, 160, 50, 3},
|
||||||
{"screen_sdl2", "c1-screen-tier1", -1, 50, 16, 1},
|
-- {"screen_sdl2", "c1-screen-tier1", -1, 50, 16, 1},
|
||||||
{"modem", "c1-modem", 1, false},
|
{"modem", "c1-modem", 1, false},
|
||||||
{"eeprom", "c1-eeprom", 9, "lua/bios.lua"},
|
{"eeprom", "c1-eeprom", 9, "lua/bios.lua"},
|
||||||
{"filesystem", "c1-tmpfs", -1, "tmpfs", "tmpfs", false, 5},
|
{"filesystem", "c1-tmpfs", -1, "tmpfs", "tmpfs", false, 5},
|
||||||
|
@ -7,5 +7,5 @@ cp ocemu.cfg.default ocemu.cfg && rm -rf c1-sda c1-sdb tmpfs
|
|||||||
mkdir c1-sda c1-sdb
|
mkdir c1-sda c1-sdb
|
||||||
echo -n c1-sda > c1-eeprom/data.bin
|
echo -n c1-sda > c1-eeprom/data.bin
|
||||||
cd ..
|
cd ..
|
||||||
./package.sh
|
./package.sh $*
|
||||||
cp inst.lua laboratory/c1-sda/init.lua
|
cp inst.lua laboratory/c1-sda/init.lua
|
||||||
|
28
mkucinst.lua
28
mkucinst.lua
@ -1,28 +0,0 @@
|
|||||||
-- This is released into the public domain.
|
|
||||||
-- No warranty is provided, implied or otherwise.
|
|
||||||
|
|
||||||
os.execute("tar -cf code.tar code")
|
|
||||||
os.execute("cat insthead.lua > inst.lua")
|
|
||||||
local f = io.open("inst.lua", "ab")
|
|
||||||
|
|
||||||
local df = io.open("code.tar", "rb")
|
|
||||||
local sc = 0
|
|
||||||
while true do
|
|
||||||
local d = df:read(512)
|
|
||||||
if not d then break end
|
|
||||||
sc = sc + 1
|
|
||||||
end
|
|
||||||
df:close()
|
|
||||||
local df = io.open("code.tar", "rb")
|
|
||||||
f:write("dieCB = function () end")
|
|
||||||
f:write("sC = " .. sc .. "\n")
|
|
||||||
while true do
|
|
||||||
local d = df:read(512)
|
|
||||||
if d then
|
|
||||||
f:write(string.format("sector(%q)", d))
|
|
||||||
else
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
df:close()
|
|
||||||
f:close()
|
|
16
package.sh
16
package.sh
@ -9,15 +9,15 @@ lua claw/clawconv.lua code/data/app-claw/ < claw/code-claw.lua > /dev/null
|
|||||||
rm code.tar
|
rm code.tar
|
||||||
# Hey, look behind you, there's nothing to see here.
|
# Hey, look behind you, there's nothing to see here.
|
||||||
# ... ok, are they seriously all named "Mann"?
|
# ... ok, are they seriously all named "Mann"?
|
||||||
tar --mtime=0 --owner=gray:0 --group=mann:0 -cf code.tar code
|
cd code
|
||||||
|
tar --mtime=0 --owner=gray:0 --group=mann:0 -cf ../code.tar .
|
||||||
|
cd ..
|
||||||
|
|
||||||
# Solely for ensuring that a -gold.lua file can be checked before being pushed to repository.
|
# The Installer Creator
|
||||||
echo -n "-- commit: " > inst.lua
|
cd inst
|
||||||
git status --porcelain=2 --branch | grep branch.oid >> inst.lua
|
lua build.lua `git status --porcelain=2 --branch | grep branch.oid | grep -E -o "[0-9a-f]*$" -` ../code.tar $* > ../inst.lua
|
||||||
lua heroes.lua `wc -c code.tar` | lua com2/bonecrunch.lua >> inst.lua
|
lua status.lua ../inst.lua
|
||||||
echo -n "--[[" >> inst.lua
|
cd ..
|
||||||
cat com2/code.tar.bd >> inst.lua
|
|
||||||
echo -n "]]" >> inst.lua
|
|
||||||
|
|
||||||
# Common Repository Setup Code
|
# Common Repository Setup Code
|
||||||
./package-repo.sh inst.lua
|
./package-repo.sh inst.lua
|
||||||
|
@ -1,609 +0,0 @@
|
|||||||
-- KOSNEO inst.
|
|
||||||
-- This is released into the public domain.
|
|
||||||
-- No warranty is provided, implied or otherwise.
|
|
||||||
|
|
||||||
-- PADPADPADPADPADPADPADPAD
|
|
||||||
|
|
||||||
local C, O, G, D = component, computer
|
|
||||||
local sAddr = C.list("screen", true)()
|
|
||||||
if sAddr then
|
|
||||||
G = C.list("gpu", true)()
|
|
||||||
if G then
|
|
||||||
G = C.proxy(G)
|
|
||||||
G.bind(sAddr)
|
|
||||||
G.setForeground(0xFFFFFF)
|
|
||||||
G.setBackground(0x000000)
|
|
||||||
G.setResolution(50, 5)
|
|
||||||
G.setDepth(1)
|
|
||||||
G.fill(1, 1, 50, 5, " ")
|
|
||||||
G.setBackground(0xFFFFFF)
|
|
||||||
G.setForeground(0x000000)
|
|
||||||
G.fill(1, 2, 50, 1, " ")
|
|
||||||
G.set(2, 2, "KittenOS NEO Installer")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
D = C.proxy(O.getBootAddress())
|
|
||||||
|
|
||||||
local file = nil
|
|
||||||
local fileName = "Starting..."
|
|
||||||
local fileSizeRm = 0
|
|
||||||
local ws = 0
|
|
||||||
|
|
||||||
local convoct
|
|
||||||
convoct = function (oct)
|
|
||||||
local v = oct:byte(#oct) - 0x30
|
|
||||||
if #oct > 1 then
|
|
||||||
return (convoct(oct:sub(1, #oct - 1)) * 8) + v
|
|
||||||
end
|
|
||||||
return v
|
|
||||||
end
|
|
||||||
local function sectorCore(sector)
|
|
||||||
if ws > 0 then
|
|
||||||
ws = ws - 1
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if file then
|
|
||||||
local takeaway = math.min(512, fileSizeRm)
|
|
||||||
D.write(file, sector:sub(1, takeaway))
|
|
||||||
fileSizeRm = fileSizeRm - takeaway
|
|
||||||
if fileSizeRm == 0 then
|
|
||||||
D.close(file)
|
|
||||||
file = nil
|
|
||||||
end
|
|
||||||
else
|
|
||||||
local name = sector:sub(1, 100):gsub("\x00", "")
|
|
||||||
local sz = convoct(sector:sub(125, 135))
|
|
||||||
if name:sub(1, 5) ~= "code/" then
|
|
||||||
ws = math.ceil(sz / 512)
|
|
||||||
else
|
|
||||||
if name:sub(#name, #name) == "/" then
|
|
||||||
ws = math.ceil(sz / 512)
|
|
||||||
D.makeDirectory(name:sub(6))
|
|
||||||
else
|
|
||||||
fileName = name:sub(6)
|
|
||||||
file = D.open(fileName, "wb")
|
|
||||||
fileSizeRm = sz
|
|
||||||
if file then
|
|
||||||
if fileSizeRm == 0 then
|
|
||||||
D.close(file)
|
|
||||||
file = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local dieCB = function () end
|
|
||||||
|
|
||||||
local sectorNum = 0
|
|
||||||
local sectorCount = 0
|
|
||||||
|
|
||||||
local function sector(n)
|
|
||||||
sectorCore(n)
|
|
||||||
sectorNum = sectorNum + 1
|
|
||||||
if G then
|
|
||||||
local a = sectorNum / sectorCount
|
|
||||||
G.fill(1, 2, 50, 1, " ")
|
|
||||||
G.set(2, 2, "KittenOS NEO Installer : " .. fileName)
|
|
||||||
G.setForeground(0xFFFFFF)
|
|
||||||
G.setBackground(0x000000)
|
|
||||||
G.fill(2, 4, 48, 1, " ")
|
|
||||||
G.setBackground(0xFFFFFF)
|
|
||||||
G.setForeground(0x000000)
|
|
||||||
G.fill(2, 4, math.ceil(48 * a), 1, " ")
|
|
||||||
end
|
|
||||||
if sectorNum % 8 == 0 then
|
|
||||||
O.pullSignal(0.05)
|
|
||||||
end
|
|
||||||
if sectorNum == sectorCount then
|
|
||||||
dieCB()
|
|
||||||
O.shutdown(true)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
sectorCount = 260
|
|
||||||
D.remove("init-symsear.lua")
|
|
||||||
D.rename("init.lua", "init-symsear.lua")
|
|
||||||
local instHandle = D.open("init-symsear.lua", "rb")
|
|
||||||
dieCB = function ()
|
|
||||||
D.close(instHandle)
|
|
||||||
D.remove("init-symsear.lua")
|
|
||||||
end
|
|
||||||
local syms = {" ","s","e","t","a","i","\24","(","r",".","\
|
|
||||||
","p","\"","o","c","m",", ","\1","l","n",")","d","u","\17","\9","x","-","\7","\6","\8","\4","\13","\2","\3","\5","g","\14","\21","\11"," then\
|
|
||||||
","1","w"," ","\12","\18","\22","f","F","y",",","\20","re","b","k"," = ","\23","return "," local ","\16","v"," if ","\
|
|
||||||
","\15","\19","\
|
|
||||||
"," ","[","en","/","0","]","path","nction (","\
|
|
||||||
","se","h"," =","or","S","T","le","\
|
|
||||||
local ",")\
|
|
||||||
","= fu","on"," == ","ne",")\
|
|
||||||
","functio","\
|
|
||||||
end\
|
|
||||||
","D","{"," t","n ","oc","lo"," end\
|
|
||||||
","\0\0\0\0\0\0\0\0\0","un"," i","W","\0\0\0\0\0\0","fu","et"," end\
|
|
||||||
","then ","nd","ni","A","ing"," tab","loca","etting",")\
|
|
||||||
","ct","C","P","}","\
|
|
||||||
end\
|
|
||||||
",")\
|
|
||||||
","onit","= ","end\
|
|
||||||
","\0","I","Y"," do\
|
|
||||||
","return\
|
|
||||||
","le.inser"," = func","= \"","al"," r"," e","in","he","nc"," e","j","donkonit","tion ()",") do\
|
|
||||||
"," the","\
|
|
||||||
",")\
|
|
||||||
","ur","#","+","N","cursor",".inse",", v ","nction (w"," neo.req"," for "," then\
|
|
||||||
","\0\0\0\0\0\0\0","nd\
|
|
||||||
","()\
|
|
||||||
","neo.","ath","table","l ","do","2","3",":","H"," = nil\
|
|
||||||
","nd\
|
|
||||||
e","hen\
|
|
||||||
","\7local ","indowCore",")\
|
|
||||||
end\
|
|
||||||
","d\") end\
|
|
||||||
"," = false","if ","pairs(","dow","string\"","ti","O","uestAcces","nd\
|
|
||||||
if ","icode."," if","v in ","pkg, pid","000","750\0000001","end\
|
|
||||||
e","750\0000000"," else\
|
|
||||||
","window","end","00",".neo.sys.","neoux.tc","= {}\
|
|
||||||
","(window, ","5","=","E","R",") end\
|
|
||||||
"," cursor","request","ode/app"," return e","\" the","equire("," "," then",".neo.pub.","hile true"," end"," en","\0\0","B","M"," ret","for ","in ipai"," true\
|
|
||||||
","close","code.sub","error(\"","return t","oroutine"," end\
|
|
||||||
if","end\
|
|
||||||
en","tion ","\", funct",":sub(","vailable"," end\
|
|
||||||
"," l"," == \"","prima"," if type(","ryWindow","window.s"," end\
|
|
||||||
","L","X","~","on ("," in ipair"," for _, v"," for k","\0\0\0\0\0cod","lose()\
|
|
||||||
"," = funct","rror(\"Exp","nsurePath","s.primary","primary","buildingS","unic"," "," re","surfaces","disallowe","ackground","neoux.","ccess","selectUnk"," end\
|
|
||||||
"," = uni","\
|
|
||||||
end\
|
|
||||||
"," f","7","Z","z","for k","rue\
|
|
||||||
end\
|
|
||||||
","ode.len("," end\
|
|
||||||
","lse\
|
|
||||||
",") end","end\
|
|
||||||
"," fu",":sub(1, ","sub(1, 4)"," ","neo","the","if not "," th","tion","unknownA","end\
|
|
||||||
","[1] == \"","= unico","Acces","\
|
|
||||||
end\
|
|
||||||
\
|
|
||||||
l","n\
|
|
||||||
","\") end\
|
|
||||||
","de.len("," end","\" then\
|
|
||||||
","0\0000001","urface","nd\
|
|
||||||
","()\
|
|
||||||
","(surfaces"," if ","\0\0\0\0\0\0\0\0","unc","urn","\
|
|
||||||
"," end\
|
|
||||||
"," neoux","ction","\
|
|
||||||
end\
|
|
||||||
","\
|
|
||||||
","neoux","\24\0\0\0\0\0\0\0\0","\
|
|
||||||
end"," end\
|
|
||||||
end\
|
|
||||||
","\
|
|
||||||
end\
|
|
||||||
"," if "," err","s[1] == \"","unicode."," window"," if ","ocal fun","= false","\0\0\0\0\0\0\0000","\0\0\0\0\0\0\00000","code","_, v in i","()\
|
|
||||||
","d\
|
|
||||||
","f ev == \""," return",", bg, fg"," end"," neoux.","\0\0\0","w.close(","\
|
|
||||||
if ev"," i"," if not ","if kc == ",")\
|
|
||||||
end\
|
|
||||||
","indow","onkonit","00175","table.",", bg, fg)"," l"," end\
|
|
||||||
",") == \"","d\
|
|
||||||
"," return ","rn","ca","q"," tabl"," error(\"","end\
|
|
||||||
re"," in ","hen err","nd\
|
|
||||||
en","nd\
|
|
||||||
","\
|
|
||||||
end","turn ","x.neo.","ion ("," table","false","string","e.len(","d\
|
|
||||||
"," re","1, unicod","cursorX ","local ","end\
|
|
||||||
end\
|
|
||||||
","cal","\" then e","nd\
|
|
||||||
if k","ion","00644\00000"," end\
|
|
||||||
","\
|
|
||||||
end"," window."," e","if not","== \"",", func"," neo.",", functi","\
|
|
||||||
end\
|
|
||||||
end"," r","end\
|
|
||||||
","ion (w)\
|
|
||||||
","\
|
|
||||||
end"," = false\
|
|
||||||
"," ret","tu"," end\
|
|
||||||
","f ","unction","= nil\
|
|
||||||
","th","n\
|
|
||||||
","6","U","_","requir","eturn\
|
|
||||||
"," funct","eturn tr","\
|
|
||||||
\
|
|
||||||
local"," table.","eques","rn ",")\
|
|
||||||
r",".insert(","ode.",")\
|
|
||||||
end","== ","\0\0\0\0\0\0\0c","n\
|
|
||||||
","\0\0\0\0\0","()\
|
|
||||||
"," = nil","able.","n\
|
|
||||||
"," = n","return","000644\0000","Access","able","etu","d\
|
|
||||||
","\
|
|
||||||
if ","end\
|
|
||||||
end","nction (p","ub(1, 4) "," return "," return","lse\
|
|
||||||
","abl","= uni","for k, ","\0\0\0\0\0\0\0\0c","cursorY","ble","bg, fg)\
|
|
||||||
","\
|
|
||||||
e","ind","ret","tring\"","000000"," neo","pairs","then\
|
|
||||||
",")\
|
|
||||||
","le.inse","loc","\
|
|
||||||
end","n error","\
|
|
||||||
end\
|
|
||||||
\
|
|
||||||
","if s[1] =","lse\
|
|
||||||
","turn","ursor","function","neou","\0\0\0\0\0\0c","function ","\0000001","end\
|
|
||||||
e","eo.","Access(\""," re"," lo","\
|
|
||||||
e",")\
|
|
||||||
end","urn ","\
|
|
||||||
re"," end\
|
|
||||||
e"," = f","\0\0\0\0","cal ","\0000000644\0","in ip","\
|
|
||||||
en"," return",")\
|
|
||||||
i","ction ","\
|
|
||||||
end\
|
|
||||||
","ode","equire(\"","r(\"Expect","ctio"," cursorY","if","%","4","<","G","\
|
|
||||||
local f","\
|
|
||||||
ret"," for ","d\
|
|
||||||
if"," erro","true\
|
|
||||||
end","ed\") end","hen ","nd\
|
|
||||||
en","al ","on ","] then\
|
|
||||||
","string\")","for _, ","unicode.l","[1] == ","true\
|
|
||||||
","uestAc","nd\
|
|
||||||
end\
|
|
||||||
"," for k, "," if ev ","then\
|
|
||||||
","\
|
|
||||||
en",")\
|
|
||||||
en","do\
|
|
||||||
","e.ins",".primary"," true","coroutine","return\
|
|
||||||
","airs(",") end\
|
|
||||||
","nd\
|
|
||||||
end\
|
|
||||||
\
|
|
||||||
","\
|
|
||||||
return","window, ","end\
|
|
||||||
e","end\
|
|
||||||
end","750\0000","eturn t",", functio"," e","d\") end","en\
|
|
||||||
","ocal","icode.len","e\
|
|
||||||
","n\
|
|
||||||
","w.close()"," uni","sub(","n ipairs("," for ","end\
|
|
||||||
","ion ()","end\
|
|
||||||
en","quest","cursorY ","eturn","unicode.s","x.neo.pub"," = neo","hen\
|
|
||||||
","then\
|
|
||||||
","string\") ","in ipa"," retur","indowCor"," re","750\00000"," do\
|
|
||||||
",")\
|
|
||||||
if "," then ret","\") end"," en","n\
|
|
||||||
","ipairs"," then err","d\
|
|
||||||
en","= f"," local",".neo.","\24\0\0\0\0\0\0\0","func","()\
|
|
||||||
",")\
|
|
||||||
en","curs","\
|
|
||||||
loca","ode/apps","nd\
|
|
||||||
if "," i"," = neo.r","kg, pid, ","\
|
|
||||||
i","win","code.sub(","require","wind"," else\
|
|
||||||
","close()"," end\
|
|
||||||
e","\
|
|
||||||
\
|
|
||||||
local "," then re","\
|
|
||||||
e",".request","wnAvailab","tion (","\
|
|
||||||
local ","error(","\0000001750\0","n\
|
|
||||||
","d\
|
|
||||||
"," ","uestA","reques","end\
|
|
||||||
end\
|
|
||||||
\
|
|
||||||
","ion ()\
|
|
||||||
"," curso","then\
|
|
||||||
","0001750","surfac",".close("," function","= neo.","if type("," loc","d\
|
|
||||||
e","oroutine."," do\
|
|
||||||
"," else\
|
|
||||||
","tion ()\
|
|
||||||
",", v in ","window.","neo.re","0000","\000000","\
|
|
||||||
end\
|
|
||||||
","ipairs("," ret","\"x.neo.pu","error","\
|
|
||||||
i","\
|
|
||||||
end","()\
|
|
||||||
","= nil\
|
|
||||||
","nsert(","n erro","rror(\"","nil\
|
|
||||||
","cursorX ="," do\
|
|
||||||
"," for","turn f","en\
|
|
||||||
"," table.","\
|
|
||||||
","\") end\
|
|
||||||
","\") end\
|
|
||||||
",".close()\
|
|
||||||
","\
|
|
||||||
re","d\
|
|
||||||
e","\
|
|
||||||
end\
|
|
||||||
","ownAvaila","000644\00000"," false\
|
|
||||||
","\
|
|
||||||
re","false\
|
|
||||||
","ion ()\
|
|
||||||
",")\
|
|
||||||
e","urn end\
|
|
||||||
",")\
|
|
||||||
if","x.neo.sys","indow, ","then\
|
|
||||||
",")\
|
|
||||||
if t","cti","ion ","ion (w","\" then"," = nil\
|
|
||||||
","then","e\" then\
|
|
||||||
"," if","on (w)\
|
|
||||||
",") do\
|
|
||||||
"," en","tAccess(\"","surePath"," end\
|
|
||||||
end","\
|
|
||||||
end\
|
|
||||||
","e.inse"," table.i"," local","oca","n (","0 then\
|
|
||||||
",") end\
|
|
||||||
"," loc","se\
|
|
||||||
","do\
|
|
||||||
","nd\
|
|
||||||
end\
|
|
||||||
"," then e","0000644\0","ion ()\
|
|
||||||
","ocal ","end\
|
|
||||||
if ","e\
|
|
||||||
"," then\
|
|
||||||
"," local","icode.le","\" then "," ==","] == \"","eoux","ndow","\0\0\0\0\0c","nownAvail"," functi","0\000000000","eoux.tc","hen error"," = neo.","table.ins"," window","(window","d\
|
|
||||||
if ","\
|
|
||||||
if ","\
|
|
||||||
local","end\
|
|
||||||
e","nd\
|
|
||||||
end","insert("," local ","k, v i","surface","eturn ","\
|
|
||||||
loc","sub(1, ","end\
|
|
||||||
if ","io","!","$","&","'","*","8","9",";",">","?","@","J","K","Q","V","\\","^","|","<22>","…","ˆ","‰","Œ","<22>","Ž","<22>","<22>","’","“","”","˜","¦","¬","¼","½","Â","ï",}
|
|
||||||
local bytBuf = ""
|
|
||||||
local bitBuf = ""
|
|
||||||
local function getByte()
|
|
||||||
if bytBuf == "" then
|
|
||||||
bytBuf = D.read(instHandle, 64)
|
|
||||||
end
|
|
||||||
local r = bytBuf:byte()
|
|
||||||
bytBuf = bytBuf:sub(2)
|
|
||||||
return r
|
|
||||||
end
|
|
||||||
while true do
|
|
||||||
if getByte() == 0 then break end
|
|
||||||
end
|
|
||||||
local function pb(c, p) if c % (p * 2) ~= c % p then bitBuf = bitBuf .. "1" else bitBuf = bitBuf .. "0" end end
|
|
||||||
local stn = 0
|
|
||||||
local function getBit()
|
|
||||||
if bitBuf == "" then
|
|
||||||
local c = getByte()
|
|
||||||
c = (c - stn) % 256 stn = stn + 3
|
|
||||||
pb(c, 1)
|
|
||||||
pb(c, 2)
|
|
||||||
pb(c, 4)
|
|
||||||
pb(c, 8)
|
|
||||||
pb(c, 16)
|
|
||||||
pb(c, 32)
|
|
||||||
pb(c, 64)
|
|
||||||
pb(c, 128)
|
|
||||||
end
|
|
||||||
local bit = bitBuf:sub(1, 1) == "1"
|
|
||||||
bitBuf = bitBuf:sub(2)
|
|
||||||
return bit
|
|
||||||
end
|
|
||||||
local buf = ""
|
|
||||||
local mode = false
|
|
||||||
local bc2 = 10
|
|
||||||
while true do
|
|
||||||
local bc = getBit()
|
|
||||||
local v = 0
|
|
||||||
if bc then bc = bc2 v = 64 else bc = 6 end
|
|
||||||
for bit = 0, bc - 1 do
|
|
||||||
if getBit() then v = v + (2 ^ bit) end
|
|
||||||
end
|
|
||||||
buf = buf .. syms[v]
|
|
||||||
if mode then
|
|
||||||
while #buf >= 512 do
|
|
||||||
sector(buf:sub(1, 512))
|
|
||||||
buf = buf:sub(513)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if #buf == 27939 then
|
|
||||||
stn = 0
|
|
||||||
bc2 = 11
|
|
||||||
bitBuf = ""
|
|
||||||
syms = {}
|
|
||||||
while #buf > 0 do
|
|
||||||
local len = buf:byte()
|
|
||||||
if len > 127 then error("symlen") end
|
|
||||||
buf = buf:sub(2)
|
|
||||||
local ch = buf:sub(1, len)
|
|
||||||
buf = buf:sub(len + 1)
|
|
||||||
table.insert(syms, ch)
|
|
||||||
end
|
|
||||||
mode = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
--[[ |