mirror of
https://github.com/20kdc/OC-KittenOS.git
synced 2024-11-26 04:18:05 +11:00
Compare commits
27 Commits
fab88f137c
...
8bd316338b
Author | SHA1 | Date | |
---|---|---|---|
|
8bd316338b | ||
|
3dbea9d3f7 | ||
|
2ebc0840ac | ||
|
da58c88d0d | ||
|
fe17b0fb93 | ||
|
c9157a1b7c | ||
|
ca4b6e5df2 | ||
|
7d1f6d2cae | ||
|
a585ce4a75 | ||
|
3ed1cebe25 | ||
|
7c70a1128c | ||
|
5ac8f9ff11 | ||
|
f761ad5824 | ||
|
aef0043d4a | ||
|
151097cdce | ||
|
bfcb4f9028 | ||
|
cc55e8a66f | ||
|
3c4a3147c4 | ||
|
bc4d626b4e | ||
|
dd21abe8fa | ||
|
22c1c211ef | ||
|
7840f0a231 | ||
|
339571ee9b | ||
|
479412a5bb | ||
|
d2ee505316 | ||
|
f5ba0489b2 | ||
|
20c016f068 |
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,8 +1,6 @@
|
||||
# This is released into the public domain.
|
||||
# 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/data/app-claw/*
|
||||
work.tar
|
||||
@ -32,7 +30,9 @@ laboratory/*/*/*/*
|
||||
inst.lua
|
||||
# Available as the respective release
|
||||
inst-gold.lua
|
||||
com2/code.tar.bd
|
||||
# Compression stuff
|
||||
inst/iSymTab
|
||||
# internal
|
||||
upldr.sh
|
||||
upldr-dev.sh
|
||||
upldr-gold.sh
|
||||
|
@ -3,7 +3,7 @@
|
||||
return {
|
||||
["neo"] = {
|
||||
desc = "KittenOS NEO Kernel & Base Libs",
|
||||
v = 8,
|
||||
v = 9,
|
||||
deps = {
|
||||
},
|
||||
dirs = {
|
||||
@ -18,6 +18,7 @@ return {
|
||||
"libs/serial.lua",
|
||||
"libs/fmttext.lua",
|
||||
"libs/neoux.lua",
|
||||
"libs/lineedit.lua",
|
||||
"libs/braille.lua",
|
||||
"libs/bmp.lua",
|
||||
"libs/sys-filewrap.lua",
|
||||
@ -54,7 +55,7 @@ return {
|
||||
},
|
||||
["neo-everest"] = {
|
||||
desc = "KittenOS NEO / Everest (windowing)",
|
||||
v = 5,
|
||||
v = 9,
|
||||
deps = {
|
||||
"neo"
|
||||
},
|
||||
@ -67,7 +68,7 @@ return {
|
||||
},
|
||||
["neo-icecap"] = {
|
||||
desc = "KittenOS NEO / Icecap",
|
||||
v = 8,
|
||||
v = 9,
|
||||
deps = {
|
||||
"neo"
|
||||
},
|
||||
@ -84,7 +85,7 @@ return {
|
||||
},
|
||||
["neo-secpolicy"] = {
|
||||
desc = "KittenOS NEO / Secpolicy",
|
||||
v = 8,
|
||||
v = 9,
|
||||
deps = {
|
||||
},
|
||||
dirs = {
|
||||
@ -96,7 +97,7 @@ return {
|
||||
},
|
||||
["neo-coreapps"] = {
|
||||
desc = "KittenOS NEO Core Apps",
|
||||
v = 5,
|
||||
v = 9,
|
||||
deps = {
|
||||
"neo"
|
||||
},
|
||||
@ -125,7 +126,7 @@ return {
|
||||
},
|
||||
["neo-logo"] = {
|
||||
desc = "KittenOS NEO Logo (data)",
|
||||
v = 8,
|
||||
v = 9,
|
||||
deps = {
|
||||
},
|
||||
dirs = {
|
||||
@ -175,6 +176,20 @@ return {
|
||||
"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"] = {
|
||||
desc = "KittenOS NEO: Use 'All' to install to other disks",
|
||||
v = 5,
|
||||
@ -190,6 +205,7 @@ return {
|
||||
"app-bmpview",
|
||||
"app-flash",
|
||||
"app-claw",
|
||||
"svc-t",
|
||||
"app-wget"
|
||||
},
|
||||
dirs = {
|
||||
|
@ -24,7 +24,7 @@ return {
|
||||
},
|
||||
["neo-docs"] = {
|
||||
desc = "KittenOS NEO system documentation",
|
||||
v = 8,
|
||||
v = 9,
|
||||
deps = {
|
||||
"zzz-license-pd"
|
||||
},
|
||||
@ -43,6 +43,7 @@ return {
|
||||
"docs/us-setti",
|
||||
"docs/us-evrst",
|
||||
"docs/us-clawf",
|
||||
"docs/us-termi",
|
||||
"docs/ul-seria",
|
||||
"docs/ul-fwrap",
|
||||
"docs/ul-event",
|
||||
@ -50,6 +51,7 @@ return {
|
||||
"docs/ul-neoux",
|
||||
"docs/ul-brail",
|
||||
"docs/ul-bmp__",
|
||||
"docs/ul-linee",
|
||||
"docs/gp-pedan",
|
||||
"docs/repoauthors/neo-docs"
|
||||
},
|
||||
@ -89,11 +91,12 @@ return {
|
||||
"docs/repoauthors/app-allmem"
|
||||
},
|
||||
},
|
||||
["app-kmt"] = {
|
||||
desc = "Line-terminal for MUDs & such",
|
||||
v = 1,
|
||||
["app-telnet"] = {
|
||||
desc = "TELNET client",
|
||||
v = 0,
|
||||
deps = {
|
||||
"neo",
|
||||
"svc-t",
|
||||
"zzz-license-pd"
|
||||
},
|
||||
dirs = {
|
||||
@ -102,8 +105,8 @@ return {
|
||||
"docs/repoauthors"
|
||||
},
|
||||
files = {
|
||||
"apps/app-kmt.lua",
|
||||
"docs/repoauthors/app-kmt"
|
||||
"apps/app-telnet.lua",
|
||||
"docs/repoauthors/app-telnet"
|
||||
},
|
||||
},
|
||||
["svc-ghostie"] = {
|
||||
@ -251,24 +254,6 @@ return {
|
||||
"docs/repoauthors/app-slaunch"
|
||||
},
|
||||
},
|
||||
["svc-virtudev"] = {
|
||||
desc = "a clone of vcomponent",
|
||||
v = 0,
|
||||
deps = {
|
||||
"neo",
|
||||
"zzz-license-pd"
|
||||
},
|
||||
dirs = {
|
||||
"apps",
|
||||
"docs",
|
||||
"docs/repoauthors"
|
||||
},
|
||||
files = {
|
||||
"apps/svc-virtudev.lua",
|
||||
"apps/app-vdrslamp.lua",
|
||||
"docs/repoauthors/svc-virtudev"
|
||||
},
|
||||
},
|
||||
-- libraries
|
||||
["lib-knbs"] = {
|
||||
desc = "NBS reader/writer library",
|
||||
@ -286,6 +271,25 @@ return {
|
||||
"docs/repoauthors/lib-knbs"
|
||||
},
|
||||
},
|
||||
["svc-virtudev"] = {
|
||||
desc = "a clone of vcomponent",
|
||||
v = 1,
|
||||
deps = {
|
||||
"neo",
|
||||
"zzz-license-pd"
|
||||
},
|
||||
dirs = {
|
||||
"apps",
|
||||
"docs",
|
||||
"docs/repoauthors"
|
||||
},
|
||||
files = {
|
||||
"apps/svc-virtudev.lua",
|
||||
"apps/app-vdrslamp.lua",
|
||||
"docs/us-virtu",
|
||||
"docs/repoauthors/svc-virtudev"
|
||||
},
|
||||
},
|
||||
-- licenses (MUST BE IMMUTABLE)
|
||||
["zzz-license-pd"] = {
|
||||
desc = "license file 'Public Domain'",
|
||||
|
@ -226,7 +226,7 @@ window = neoux.create(currentGen())
|
||||
while running do
|
||||
local src, id, k, v = event.pull()
|
||||
if src == "x.neo.sys.manage" then
|
||||
if id == "set_setting" then
|
||||
if id == "set_setting" and currentGen ~= logGen then
|
||||
window.reset(currentGen())
|
||||
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 files = neo.requireAccess("x.neo.pub.base", "files").showFileDialogAsync
|
||||
|
||||
local lineEdit = require("lineedit")
|
||||
|
||||
local cursorX = 1
|
||||
local cursorY = math.ceil(#lines / 2)
|
||||
local cFlash = true
|
||||
local ctrlFlag, focFlag, appendFlag
|
||||
local ctrlFlag, appendFlag
|
||||
local dialogLock = false
|
||||
local sW, sH = 37, #lines + 2
|
||||
local window = windows(sW, sH)
|
||||
local filedialog = nil
|
||||
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 function fileDialog(writing, callback)
|
||||
@ -139,31 +124,14 @@ local function getline(y)
|
||||
-- rX is difficult!
|
||||
local rX = 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
|
||||
local line = lines[rY]
|
||||
if not line then
|
||||
return ("¬"):rep(sW)
|
||||
end
|
||||
line = unicode.safeTextFormat(line)
|
||||
-- <alter RX here by 1 if needed>
|
||||
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
|
||||
return lineEdit.draw(sW, line, rY == cursorY and cursorXP, rX)
|
||||
end
|
||||
local function delLine()
|
||||
local contents = lines[cursorY]
|
||||
@ -179,22 +147,7 @@ local function delLine()
|
||||
end
|
||||
return contents
|
||||
end
|
||||
-- add a single character
|
||||
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)
|
||||
local function key(ks, kc, down)
|
||||
if dialogLock then
|
||||
return false
|
||||
end
|
||||
@ -212,18 +165,22 @@ local function key(ka, kc, down)
|
||||
sH = 1
|
||||
end
|
||||
sW, sH = window.setSize(sW, sH)
|
||||
return false
|
||||
elseif kc == 208 then -- Down
|
||||
sH = sH + 1
|
||||
sW, sH = window.setSize(sW, sH)
|
||||
return false
|
||||
elseif kc == 203 then -- Left
|
||||
sW = sW - 1
|
||||
if sW == 0 then
|
||||
sW = 1
|
||||
end
|
||||
sW, sH = window.setSize(sW, sH)
|
||||
return false
|
||||
elseif kc == 205 then -- Right
|
||||
sW = sW + 1
|
||||
sW, sH = window.setSize(sW, sH)
|
||||
return false
|
||||
elseif kc == 14 then -- ^Backspace
|
||||
delLine()
|
||||
return true
|
||||
@ -240,7 +197,7 @@ local function key(ka, kc, down)
|
||||
if cursorY < 1 then
|
||||
cursorY = 1
|
||||
end
|
||||
clampCursorX()
|
||||
cursorX = lineEdit.clamp(lines[cursorY], cursorX)
|
||||
return true
|
||||
elseif kc == 208 or kc == 209 then -- Go down one - go down page
|
||||
local moveAmount = 1
|
||||
@ -251,36 +208,7 @@ local function key(ka, kc, down)
|
||||
if cursorY > #lines then
|
||||
cursorY = #lines
|
||||
end
|
||||
clampCursorX()
|
||||
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
|
||||
cursorX = lineEdit.clamp(lines[cursorY], cursorX)
|
||||
return true
|
||||
end
|
||||
-- Major Actions
|
||||
@ -291,10 +219,13 @@ local function key(ka, kc, down)
|
||||
return true
|
||||
elseif kc == 61 then -- F3
|
||||
startLoad()
|
||||
return false
|
||||
elseif kc == 62 then -- F4
|
||||
startSave()
|
||||
return false
|
||||
elseif kc == 63 then -- F5
|
||||
clipsrc.setSetting("clipboard", lines[cursorY])
|
||||
return false
|
||||
elseif kc == 64 then -- F6
|
||||
local tx = clipsrc.getSetting("clipboard") or ""
|
||||
local txi = tx:find("\n")
|
||||
@ -311,6 +242,7 @@ local function key(ka, kc, down)
|
||||
return true
|
||||
elseif kc == 65 then -- F7
|
||||
appendFlag = false
|
||||
return false
|
||||
elseif kc == 66 then -- F8
|
||||
if appendFlag then
|
||||
local base = clipsrc.getSetting("clipboard")
|
||||
@ -322,29 +254,37 @@ local function key(ka, kc, down)
|
||||
return true
|
||||
end
|
||||
end
|
||||
-- Letters
|
||||
if ka == 8 or kc == 211 then
|
||||
if cursorX == 1 then
|
||||
if cursorY == 1 then
|
||||
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
|
||||
-- LEL Keys
|
||||
local lT, lC, lX = lineEdit.key(ks, kc, lines[cursorY], cursorX)
|
||||
if lT then
|
||||
lines[cursorY] = lT
|
||||
end
|
||||
if ka ~= 0 then
|
||||
putLetter(unicode.char(ka))
|
||||
return true
|
||||
if lC then
|
||||
cursorX = lC
|
||||
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
|
||||
|
||||
flush = function ()
|
||||
@ -353,16 +293,9 @@ flush = function ()
|
||||
end
|
||||
end
|
||||
|
||||
neo.scheduleTimer(os.uptime() + 0.5)
|
||||
|
||||
while true do
|
||||
local e = {coroutine.yield()}
|
||||
if e[1] == "k.timer" and e[2] == focFlag 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[1] == "x.neo.pub.window" then
|
||||
if e[2] == window.id then
|
||||
if e[3] == "line" then
|
||||
window.span(1, e[4], getline(e[4]), 0xFFFFFF, 0)
|
||||
@ -373,14 +306,13 @@ while true do
|
||||
local csY = math.ceil(sH / 2)
|
||||
local nY = math.max(1, math.min(#lines, (math.floor(e[5]) - csY) + cursorY))
|
||||
cursorY = nY
|
||||
clampCursorX()
|
||||
cursorX = lineEdit.clamp(lines[cursorY], cursorX)
|
||||
flush()
|
||||
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()
|
||||
end
|
||||
elseif e[3] == "focus" then
|
||||
focFlag = e[4] and neo.scheduleTimer(0)
|
||||
ctrlFlag = false
|
||||
elseif e[3] == "close" then
|
||||
return
|
||||
@ -392,7 +324,7 @@ while true do
|
||||
if c == "\n" then
|
||||
c = "\r"
|
||||
end
|
||||
putLetter(c)
|
||||
key(c, 0, true)
|
||||
end
|
||||
end
|
||||
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 isCtrDown = false
|
||||
local function key(ku, ka, kc, down)
|
||||
local ku = screens.getMonitorByKeyboard(ku)
|
||||
if not ku then return end
|
||||
local ku, lin = screens.getMonitorByKeyboard(ku)
|
||||
for k, v in ipairs(monitors) do
|
||||
if v[2] == mu then
|
||||
lIM = k
|
||||
if ku and v[2] == ku then
|
||||
lin = k
|
||||
break
|
||||
end
|
||||
end
|
||||
if not lin then return end
|
||||
lIM = lin
|
||||
|
||||
local focus = surfaces[1]
|
||||
if kc == 29 then isCtrDown = down end
|
||||
if kc == 56 then isAltDown = down end
|
||||
if isAltDown then
|
||||
if ka == 120 then
|
||||
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
|
||||
if kc == 29 then
|
||||
isCtrDown = down
|
||||
elseif kc == 56 then
|
||||
isAltDown = down
|
||||
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
|
||||
lIM = focus[1]
|
||||
end
|
||||
|
@ -81,20 +81,12 @@ local function getPfx(xd, pkg)
|
||||
end
|
||||
end
|
||||
|
||||
local endAcPattern = "/[a-z0-9/%.]*$"
|
||||
|
||||
local function matchesSvc(xd, pkg, perm)
|
||||
local pfx = getPfx(xd, pkg)
|
||||
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
|
||||
local function splitAC(ac)
|
||||
local sb = ac:match("/[a-z0-9/%.]*$")
|
||||
if sb then
|
||||
return ac:sub(1, #ac - #sb), sb
|
||||
end
|
||||
return ac
|
||||
end
|
||||
|
||||
donkonitDFProvider(function (pkg, pid, sendSig)
|
||||
@ -130,7 +122,8 @@ donkonitDFProvider(function (pkg, pid, sendSig)
|
||||
myApi = getPfx("", pkg),
|
||||
lockPerm = function (perm)
|
||||
-- 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."
|
||||
end
|
||||
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
|
||||
neo.scheduleTimer(0)
|
||||
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
|
||||
neo.emergency("Used fallback policy because of run-err: " .. err)
|
||||
req(def)
|
||||
@ -243,11 +240,7 @@ rootAccess.securityPolicy = function (pid, proc, perm, req)
|
||||
end
|
||||
-- Do we need to start it?
|
||||
if perm:sub(1, 6) == "x.svc." and not neo.usAccessExists(perm) then
|
||||
local appAct = perm:sub(7)
|
||||
local paP = appAct:match(endAcPattern)
|
||||
if paP then
|
||||
appAct = appAct:sub(1, #appAct - #paP)
|
||||
end
|
||||
local appAct = splitAC(perm:sub(3))
|
||||
-- Prepare for success
|
||||
onReg[perm] = onReg[perm] or {}
|
||||
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)
|
||||
return nil
|
||||
end
|
||||
return function (f)
|
||||
return function (f, secret)
|
||||
-- Registration function
|
||||
ensureType(f, "function")
|
||||
local accessObjectCache = {}
|
||||
@ -481,8 +481,10 @@ function retrieveAccess(perm, pkg, pid)
|
||||
end
|
||||
-- returns nil and fails
|
||||
end
|
||||
-- Announce registration
|
||||
distEvent(nil, "k.registration", uid)
|
||||
if not secret then
|
||||
-- Announce registration
|
||||
distEvent(nil, "k.registration", uid)
|
||||
end
|
||||
end, function ()
|
||||
-- Registration becomes null (access is held but other processes cannot retrieve object)
|
||||
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
|
||||
-- Note: w should be at least 2 - this is similar to buttons.
|
||||
neoux.tcfield = function (x, y, w, textprop)
|
||||
local p = 1
|
||||
return {
|
||||
x = x,
|
||||
y = y,
|
||||
@ -347,22 +348,24 @@ newNeoux = function (event, neo)
|
||||
selectable = true,
|
||||
key = function (window, update, a, c, d, f)
|
||||
if d then
|
||||
local ot = textprop()
|
||||
local le = require("lineedit")
|
||||
p = le.clamp(ot, p)
|
||||
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
|
||||
local contents = neo.requireAccess("x.neo.pub.globals", "clipboard").getSetting("clipboard")
|
||||
contents = contents:match("^[^\r\n]*")
|
||||
textprop(contents)
|
||||
update()
|
||||
elseif a == 8 then
|
||||
local str = textprop()
|
||||
textprop(unicode.sub(str, 1, unicode.len(str) - 1))
|
||||
update()
|
||||
return true
|
||||
elseif a >= 32 then
|
||||
textprop(textprop() .. unicode.char(a))
|
||||
update()
|
||||
return true
|
||||
elseif a ~= 9 then
|
||||
local lT, lC, lX = le.key(a ~= 0 and unicode.char(a), c, ot, p)
|
||||
if lT or lC then
|
||||
if lT then textprop(lT) end
|
||||
p = lC or p
|
||||
update()
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
@ -377,9 +380,10 @@ newNeoux = function (event, neo)
|
||||
fg = bg
|
||||
bg = fg1
|
||||
end
|
||||
local text = unicode.safeTextFormat(textprop())
|
||||
text = "[" .. neoux.pad(text, w - 2, false, true, true) .. "]"
|
||||
window.span(x, y, text, bg, fg)
|
||||
local t, e, r = textprop(), require("lineedit")
|
||||
p = e.clamp(t, p)
|
||||
t, r = unicode.safeTextFormat(t, p)
|
||||
window.span(x, y, "[" .. e.draw(w - 2, t, selected and r) .. "]", bg, fg)
|
||||
end
|
||||
}
|
||||
end
|
||||
|
@ -94,11 +94,25 @@ function getFsNode(fs, parent, fsc, path, mode, impliedName)
|
||||
for k, v in ipairs(fsc.list(path)) do
|
||||
local nm = "F: " .. v
|
||||
local fp = path .. v
|
||||
if fsc.isDirectory(fp) then
|
||||
local cDir = fsc.isDirectory(fp)
|
||||
if cDir then
|
||||
nm = "D: " .. v
|
||||
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
|
||||
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
|
||||
if fscrw then
|
||||
if dir then
|
||||
@ -151,24 +165,6 @@ function getFsNode(fs, parent, fsc, path, mode, impliedName)
|
||||
end
|
||||
end
|
||||
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
|
||||
table.insert(n, {"Implied: " .. impliedName, function ()
|
||||
return selectUnknown(impliedName)
|
||||
|
@ -11,13 +11,19 @@
|
||||
-- IRC is usually pretty safe, but no guarantees.
|
||||
|
||||
-- Returns "allow", "deny", or "ask".
|
||||
local function actualPolicy(pkg, pid, perm, matchesSvc)
|
||||
local function actualPolicy(pkg, pid, perm, pkgSvcPfx)
|
||||
-- System stuff is allowed.
|
||||
if pkg:sub(1, 4) == "sys-" then
|
||||
return "allow"
|
||||
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>
|
||||
-- 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
|
||||
return "allow"
|
||||
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
|
||||
return "allow"
|
||||
end
|
||||
if matchesSvc("r.", pkg, perm) then
|
||||
-- Userlevel can register for itself
|
||||
if perm == "r." .. pkgSvcPfx then
|
||||
return "allow"
|
||||
end
|
||||
-- Userlevel has no other registration rights
|
||||
@ -44,8 +51,8 @@ local function actualPolicy(pkg, pid, perm, matchesSvc)
|
||||
return "ask"
|
||||
end
|
||||
|
||||
return function (nexus, settings, pkg, pid, perm, rsp, matchesSvc)
|
||||
local res = actualPolicy(pkg, pid, perm, matchesSvc)
|
||||
return function (nexus, settings, pkg, pid, perm, rsp, pkgSvcPfx)
|
||||
local res = actualPolicy(pkg, pid, perm, pkgSvcPfx)
|
||||
if settings then
|
||||
res = settings.getSetting("perm|" .. pkg .. "|" .. perm) or
|
||||
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 {
|
||||
{"gpu", "c1-gpu-tier3", 0, 160, 50, 3},
|
||||
{"gpu", "c1-gpu-tier1", 0, 50, 16, 1},
|
||||
-- {"screen_sdl2", "c1-screen-tier3", -1, 160, 50, 3},
|
||||
{"screen_sdl2", "c1-screen-tier1", -1, 50, 16, 1},
|
||||
{"screen_sdl2", "c1-screen-tier3", -1, 160, 50, 3},
|
||||
-- {"screen_sdl2", "c1-screen-tier1", -1, 50, 16, 1},
|
||||
{"modem", "c1-modem", 1, false},
|
||||
{"eeprom", "c1-eeprom", 9, "lua/bios.lua"},
|
||||
{"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
|
||||
echo -n c1-sda > c1-eeprom/data.bin
|
||||
cd ..
|
||||
./package.sh
|
||||
./package.sh $*
|
||||
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
|
||||
# Hey, look behind you, there's nothing to see here.
|
||||
# ... 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.
|
||||
echo -n "-- commit: " > inst.lua
|
||||
git status --porcelain=2 --branch | grep branch.oid >> inst.lua
|
||||
lua heroes.lua `wc -c code.tar` | lua com2/bonecrunch.lua >> inst.lua
|
||||
echo -n "--[[" >> inst.lua
|
||||
cat com2/code.tar.bd >> inst.lua
|
||||
echo -n "]]" >> inst.lua
|
||||
# The Installer Creator
|
||||
cd inst
|
||||
lua build.lua `git status --porcelain=2 --branch | grep branch.oid | grep -E -o "[0-9a-f]*$" -` ../code.tar $* > ../inst.lua
|
||||
lua status.lua ../inst.lua
|
||||
cd ..
|
||||
|
||||
# Common Repository Setup Code
|
||||
./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
|
||||
--[[ |