diff --git a/Capy64/Assets/Lua/CapyOS/bin/cd.lua b/Capy64/Assets/Lua/CapyOS/bin/cd.lua new file mode 100644 index 0000000..3a77dfc --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/bin/cd.lua @@ -0,0 +1,17 @@ +local args = {...} +local fs = require("fs") + +local dir = args[1] + +if not dir then + dir = shell.homePath +end + +dir = shell.resolve(dir) + +if not fs.isDir(dir) then + error("No such directory: " .. dir, 0) + return false +end + +shell.setDir(dir) \ No newline at end of file diff --git a/Capy64/Assets/Lua/CapyOS/bin/clear.lua b/Capy64/Assets/Lua/CapyOS/bin/clear.lua new file mode 100644 index 0000000..5cb133d --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/bin/clear.lua @@ -0,0 +1,5 @@ +local term = require("term") +local colors = require("colors") +term.setBackground(colors.black) +term.clear() +term.setPos(1, 1) \ No newline at end of file diff --git a/Capy64/Assets/Lua/CapyOS/bin/exit.lua b/Capy64/Assets/Lua/CapyOS/bin/exit.lua new file mode 100644 index 0000000..b90092c --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/bin/exit.lua @@ -0,0 +1 @@ +shell.exit() diff --git a/Capy64/Assets/Lua/CapyOS/bin/fun/mandelbrot.lua b/Capy64/Assets/Lua/CapyOS/bin/fun/mandelbrot.lua new file mode 100644 index 0000000..1dcbf6c --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/bin/fun/mandelbrot.lua @@ -0,0 +1,94 @@ +-- Mandelbrot in Capy64 + +local gpu = require("gpu") +local timer = require("timer") +local event = require("event") +local term = require("term") + +-- lower = closer = slower +local scale = 4 + +-- higher = more detailed = slower +local iterations = 100 + +local pscale = scale +local w, h = gpu.getSize() +local px = pscale / w +local colorUnit = math.floor(0xffffff / iterations) +-- todo: make it interactive +local dx, dy = 0, 0 +local cx, cy = math.floor(w / 2), math.floor(h / 2) + +-- z = z^2 + c +local function mandelbrot(zr, zi, cr, ci) + return zr ^ 2 - zi ^ 2 + cr, + 2 * zr * zi + ci +end + +local function iter(cr, ci) + local zr, zi = 0, 0 + for i = 1, iterations do + zr, zi = mandelbrot(zr, zi, cr, ci) + if math.abs(zr) >= (pscale >= 2 and pscale or 2) or math.abs(zi) >= (pscale >= 2 and pscale or 2) then + return false, colorUnit, i + end + end + + return true, 0, iterations +end + +local function draw() + local buffer = gpu.newBuffer() + + for y = 0, h - 1 do + for x = 0, w - 1 do + local _, _, i = iter((x - cx + dx * pscale) * px, (y - cy + dy * pscale) * px) + buffer[y * w + x] = colorUnit * (iterations - i) + end + end + + gpu.setBuffer(buffer) +end + +-- no idea why it's needed +timer.sleep(1) + +draw() + +local tw, th = term.getSize() + +while true do + term.setPos(1, th) + term.setBackground(0) + term.setForeground(0xffffff) + term.write("X: " .. dx .. "; Y: " .. dy .. "; S: " .. pscale .. "; " .. px .. "!") + local ev = { event.pull("key_down") } + if ev[1] == "key_down" then + local key = ev[3] + if key == "up" then + dy = dy - 10 / pscale + elseif key == "down" then + dy = dy + 10 / pscale + elseif key == "right" then + dx = dx + 10 / pscale + elseif key == "left" then + dx = dx - 10 / pscale + elseif key == "enter" then + draw() + elseif key == "page_down" then + pscale = pscale * 1.25 + dx = dx * pscale + dy = dy * pscale + elseif key == "page_up" then + pscale = pscale / 1.25 + dx = dx / pscale + dy = dy / pscale + elseif key == "r" then + pscale = scale + dx = 0 + dy = 0 + end + end + + px = pscale / w +end diff --git a/Capy64/Assets/Lua/CapyOS/bin/fun/melt.lua b/Capy64/Assets/Lua/CapyOS/bin/fun/melt.lua new file mode 100644 index 0000000..fd2adc4 --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/bin/fun/melt.lua @@ -0,0 +1,73 @@ +local gpu = require("gpu") +local timer = require("timer") +local event = require("event") +local colors = require("colors") +local parallel = require("parallel") + +local melts = 2 ^ 12 + +local function contains(arr, val) + for k, v in ipairs(arr) do + if v == val then + return true + end + end + return false +end + +local function melt() + local w, h = gpu.getSize() + local x, y = 0, 0 + + while true do + local buffer = gpu.getBuffer() + for i = 1, melts do + local nx = math.random(x, w) + local ny = math.random(y, h) + + local c = buffer[ny * w + nx] + buffer[(ny + 1) * w + nx] = c + end + gpu.setBuffer(buffer) + + timer.delay(10):await() + end +end + +local function draw() + local ox, oy + while true do + local ev, b, x, y = event.pull("mouse_move", "mouse_down") + + if ev == "mouse_down" then + if b == 1 then + ox = x + oy = y + end + elseif ev == "mouse_move" then + if contains(b, 1) then + gpu.plot(x, y, colors.red) + gpu.drawLine(x, y, ox, oy, colors.red) + ox, oy = x, y + end + end + end +end + +local function random() + local w, h = gpu.getSize() + while true do + for i = 1, 24 do + gpu.drawString( + math.random(-7, w), + math.random(-13, h), + math.random(0, 0xffffff), + string.char(math.random(32, 127)) + ) + end + + timer.delay(100):await() + end +end + +parallel.waitForAny(draw, melt, random) diff --git a/Capy64/Assets/Lua/CapyOS/bin/hello.lua b/Capy64/Assets/Lua/CapyOS/bin/hello.lua new file mode 100644 index 0000000..de32216 --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/bin/hello.lua @@ -0,0 +1,17 @@ +local timer = require("timer") +local colors = require("colors") +local term = require("term") + +local function slowPrint(text, delay) + for i = 1, #text do + local ch = text:sub(i, i) + io.write(ch) + timer.sleep(delay) + end + print() +end + +local color = colors[math.random(1, #colors)] + +term.setForeground(color) +slowPrint("Hello, World!", 50) diff --git a/Capy64/Assets/Lua/CapyOS/bin/ls.lua b/Capy64/Assets/Lua/CapyOS/bin/ls.lua new file mode 100644 index 0000000..58a0607 --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/bin/ls.lua @@ -0,0 +1,25 @@ +local args = { ... } +local fs = require("fs") +local term = require("term") +local colors = require("colors") +local dir = shell.getDir() + +if args[1] then + dir = shell.resolve(args[1]) +end + +if not fs.isDir(dir) then + error("No such directory: " .. dir, 0) + return false +end + +local files = fs.list(dir) +for k, v in ipairs(files) do + if fs.isDir(fs.combine(dir, v)) then + term.setForeground(colors.lightBlue) + print(v .. "/") + else + term.setForeground(colors.white) + print(v) + end +end diff --git a/Capy64/Assets/Lua/CapyOS/bin/lua.lua b/Capy64/Assets/Lua/CapyOS/bin/lua.lua new file mode 100644 index 0000000..1fc9038 --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/bin/lua.lua @@ -0,0 +1,75 @@ +local term = require("term") +local io = require("io") +local colors = require("colors") +local colours = colors + +local tArgs = { ... } +if #tArgs > 0 then + print("This is an interactive Lua prompt.") + print("To run a lua program, just type its name.") + return +end + +--local pretty = require "cc.pretty" + +local bRunning = true +local tCommandHistory = {} +local tEnv = { + ["exit"] = setmetatable({}, { + __tostring = function() return "Call exit() to exit." end, + __call = function() bRunning = false end, + }), +} +setmetatable(tEnv, { __index = _ENV }) + +for k, v in pairs(package.loaded) do + tEnv[k] = v +end + +term.setForeground(colours.yellow) +print(_VERSION .. " interactive prompt") +print("Call exit() to exit.") +term.setForeground(colours.white) + +while bRunning do + term.setForeground(colours.yellow) + io.write("> ") + term.setForeground(colours.white) + + local s = io.read(nil, tCommandHistory) + if s:match("%S") and tCommandHistory[#tCommandHistory] ~= s then + table.insert(tCommandHistory, s) + end + + local nForcePrint = 0 + local func, e = load(s, "=lua", "t", tEnv) + local func2 = load("return " .. s, "=lua", "t", tEnv) + if not func then + if func2 then + func = func2 + e = nil + nForcePrint = 1 + end + else + if func2 then + func = func2 + end + end + + if func then + local tResults = table.pack(pcall(func)) + if tResults[1] then + local n = 1 + while n < tResults.n or n <= nForcePrint do + local value = tResults[n + 1] + print(tostring(value)) + n = n + 1 + end + else + io.stderr.print(tResults[2]) + end + else + io.stderr.print(e) + end + +end diff --git a/Capy64/Assets/Lua/CapyOS/bin/mkdir.lua b/Capy64/Assets/Lua/CapyOS/bin/mkdir.lua new file mode 100644 index 0000000..614a3e6 --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/bin/mkdir.lua @@ -0,0 +1,14 @@ +local fs = require("fs") +local args = { ... } + +if #args == 0 then + print("Usage: mkdir ") + return +end + +local dir = shell.resolve(args[1]) +if fs.exists(dir) then + error("Path already exists", 0) +end + +fs.makeDir(dir) diff --git a/Capy64/Assets/Lua/CapyOS/bin/pwd.lua b/Capy64/Assets/Lua/CapyOS/bin/pwd.lua new file mode 100644 index 0000000..b619fb5 --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/bin/pwd.lua @@ -0,0 +1 @@ +print(shell.getDir()) diff --git a/Capy64/Assets/Lua/CapyOS/bin/reboot.lua b/Capy64/Assets/Lua/CapyOS/bin/reboot.lua new file mode 100644 index 0000000..3dfbb5a --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/bin/reboot.lua @@ -0,0 +1,8 @@ +local timer = require("timer") +local machine = require("machine") + +print("Goodbye!") + +timer.sleep(1000) + +machine.reboot() diff --git a/Capy64/Assets/Lua/CapyOS/bin/rm.lua b/Capy64/Assets/Lua/CapyOS/bin/rm.lua new file mode 100644 index 0000000..428fcad --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/bin/rm.lua @@ -0,0 +1,10 @@ +local fs = require("fs") + +local args = { ... } +if #args == 0 then + print("Usage: rm ") + return +end + +local file = shell.resolve(args[1]) +fs.delete(file, true) diff --git a/Capy64/Assets/Lua/CapyOS/bin/shell.lua b/Capy64/Assets/Lua/CapyOS/bin/shell.lua new file mode 100644 index 0000000..81d2654 --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/bin/shell.lua @@ -0,0 +1,143 @@ +local term = require("term") +local colors = require("colors") +local fs = require("fs") +local machine = require("machine") + +local exit = false +local shell = {} + +shell.path = "./?;./?.lua;/bin/?.lua" +shell.homePath = "/home" + +local currentDir = shell.homePath + +local function buildEnvironment(path, args) + local arg = { table.unpack(args, 2) } + arg[0] = path + + return setmetatable({ + shell = shell, + arg = arg + }, { __index = _G }) +end + +local function tokenise(...) + local sLine = table.concat({ ... }, " ") + local tWords = {} + local bQuoted = false + for match in string.gmatch(sLine .. "\"", "(.-)\"") do + if bQuoted then + table.insert(tWords, match) + else + for m in string.gmatch(match, "[^ \t]+") do + table.insert(tWords, m) + end + end + bQuoted = not bQuoted + end + return tWords +end + +function shell.getDir() + return currentDir +end + +function shell.setDir(path) + currentDir = path +end + +function shell.resolve(path) + if path:sub(1, 1) == "/" then + return fs.combine("", path) + end + + if path:sub(1, 1) == "~" then + return fs.combine(shell.homePath, path) + end + + return fs.combine(currentDir, path) +end + +function shell.resolveProgram(path) + if path:sub(1, 1) == "/" then + return shell.resolve(path) + end + + for seg in shell.path:gmatch("[^;]+") do + local resolved = shell.resolve(seg:gsub("%?", path)) + if fs.exists(resolved) and not fs.isDir(resolved) then + return resolved + end + end +end + +function shell.run(...) + local args = tokenise(...) + local command = args[1] + local path = shell.resolveProgram(command) + + if not path then + io.stderr.print("Command not found: " .. command) + return false + end + + local env = buildEnvironment(command, args) + + local func, err = loadfile(path, "t", env) + + if not func then + io.stderr.print(err) + return false + end + + local ok, err = pcall(func, table.unpack(args, 2)) + if not ok then + io.stderr.print(err) + return false + end + + return true +end + +function shell.exit() + exit = true +end + +if not fs.exists(shell.homePath) then + fs.makeDir(shell.homePath) +end + +local history = {} +local lastExecSuccess = true +while not exit do + machine.setRPC(os.version(), "On shell") + + term.setBackground(colors.black) + term.setForeground(colors.white) + io.write(":") + term.setForeground(colors.lightBlue) + if currentDir == shell.homePath then + io.write("~") + else + io.write(currentDir) + end + + if lastExecSuccess then + term.setForeground(colors.yellow) + else + term.setForeground(colors.red) + end + io.write("$ ") + + term.setForeground(colors.white) + local line = io.read(nil, history) + + if line:match("%S") and history[#history] ~= line then + table.insert(history, line) + end + + if line:match("%S") then + machine.setRPC(os.version(), "Running: " .. line) + lastExecSuccess = shell.run(line) + end +end diff --git a/Capy64/Assets/Lua/CapyOS/bin/shutdown.lua b/Capy64/Assets/Lua/CapyOS/bin/shutdown.lua new file mode 100644 index 0000000..b1fb35b --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/bin/shutdown.lua @@ -0,0 +1,8 @@ +local timer = require("timer") +local machine = require("machine") + +print("Goodbye!") + +timer.sleep(1000) + +machine.shutdown() diff --git a/Capy64/Assets/Lua/CapyOS/bin/version.lua b/Capy64/Assets/Lua/CapyOS/bin/version.lua new file mode 100644 index 0000000..7204cb3 --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/bin/version.lua @@ -0,0 +1,2 @@ +local machine = require("machine") +print(string.format("%s @ %s - %s", os.version(), machine.version(), _VERSION)) diff --git a/Capy64/Assets/Lua/CapyOS/bin/wget.lua b/Capy64/Assets/Lua/CapyOS/bin/wget.lua new file mode 100644 index 0000000..0933652 --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/bin/wget.lua @@ -0,0 +1,34 @@ +local http = require("http") +local fs = require("fs") + +local args = { ... } + +if not http then + error("HTTP is not enabled", 0) +end + +if #args == 0 then + print("Usage: wget [outputPath]") + return false +end + +local outputName = args[2] or fs.getName(args[1]) +local outputPath = shell.resolve(outputName) + +if not http.checkURL(args[1]) then + error("Invalid URL", 0) +end + +local response, err = http.get(args[1], nil, { + binary = true, +}) +if not response then + error(err, 0) +end + +local file = fs.open(outputPath, "wb") +file:write(response:readAll()) +file:close() +response:close() + +print("File written to " .. outputPath) diff --git a/Capy64/Assets/Lua/CapyOS/boot/autorun/00_package.lua b/Capy64/Assets/Lua/CapyOS/boot/autorun/00_package.lua new file mode 100644 index 0000000..2cc7dd8 --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/boot/autorun/00_package.lua @@ -0,0 +1,3 @@ +package.path = "/lib/?.lua;/lib/?/init.lua;" .. package.path + +_G.io = require("io") diff --git a/Capy64/Assets/Lua/CapyOS/boot/autorun/01_stdio.lua b/Capy64/Assets/Lua/CapyOS/boot/autorun/01_stdio.lua new file mode 100644 index 0000000..32f6864 --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/boot/autorun/01_stdio.lua @@ -0,0 +1,15 @@ +function _G.print(...) + local args = { ... } + local size = #args + local lines = 0 + for n, v in ipairs(args) do + local s = tostring(v) + if n < size then + s = s .. "\t" + end + lines = lines + io.write(s) + end + lines = lines + io.write("\n") + + return lines +end diff --git a/Capy64/Assets/Lua/CapyOS/boot/autorun/01_task.lua b/Capy64/Assets/Lua/CapyOS/boot/autorun/01_task.lua new file mode 100644 index 0000000..d64f1a1 --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/boot/autorun/01_task.lua @@ -0,0 +1,20 @@ +local event = require("event") + +local function awaiter(task) + local status = task:getStatus() + local uuid = task:getID() + if status == "running" then + local _, taskId, result, err + repeat + _, taskId, result, err = event.pull("task_finish") + until taskId == uuid + return result, err + elseif status == "succeeded" then + return task:getResult(), nil + elseif status == "failed" then + return nil, task:getError() + end +end + +-- Second argument freezes the awaiter function, so it cannot be modified +event.setAwaiter(awaiter, true) \ No newline at end of file diff --git a/Capy64/Assets/Lua/CapyOS/boot/autorun/02_http.lua b/Capy64/Assets/Lua/CapyOS/boot/autorun/02_http.lua new file mode 100644 index 0000000..b0dabe0 --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/boot/autorun/02_http.lua @@ -0,0 +1,77 @@ +local http = require("http") +local event = require("event") +local expect = require("expect").expect + + +function http.request(url, body, headers, options) + expect(1, url, "string") + expect(2, body, "string", "nil") + expect(3, headers, "table", "nil") + expect(4, options, "table", "nil") + + if not http.checkURL(url) then + return nil, "Invalid URL" + end + + local task = http.requestAsync(url, body, headers, options) + return task:await() +end + +function http.get(url, headers, options) + expect(1, url, "string") + expect(2, headers, "table", "nil") + expect(3, options, "table", "nil") + + return http.request(url, nil, headers, options) +end + +function http.post(url, body, headers, options) + expect(1, url, "string") + expect(2, body, "string", "nil") + expect(3, headers, "table", "nil") + expect(4, options, "table", "nil") + + return http.request(url, body, headers, options) +end + +local WebSocketHandle +local function buildWebsocketHandle(handle) + if not handle then + return nil + end + if not WebSocketHandle then + WebSocketHandle = getmetatable(handle) or { __index = {} } + function WebSocketHandle.__index:close() + self:closeAsync() + local _, id + repeat + _, id = event.pull("websocket_close") + until id == self:getRequestID() + end + + function WebSocketHandle.__index:receive() + local _, id, par + repeat + _, id, par = event.pull("websocket_message") + until id == self:getRequestID() + + return par + end + end + + return handle +end + +function http.websocket(url, headers) + expect(1, url, "string") + expect(2, headers, "table", "nil") + + if not http.checkURL(url) then + return nil, "Invalid URL" + end + + local task = http.websocketAsync(url, headers) + local client, err = task:await() + + return buildWebsocketHandle(client), err +end diff --git a/Capy64/Assets/Lua/CapyOS/boot/autorun/02_timer.lua b/Capy64/Assets/Lua/CapyOS/boot/autorun/02_timer.lua new file mode 100644 index 0000000..ae933fc --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/boot/autorun/02_timer.lua @@ -0,0 +1,14 @@ +local timer = require("timer") +local event = require("event") +local expect = require("expect").expect +local range = require("expect").range + +function timer.sleep(n) + expect(1, n, "number") + range(1, 1) + + local timerId = timer.start(n) + repeat + local _, par = event.pull("timer") + until par == timerId +end diff --git a/Capy64/Assets/Lua/CapyOS/boot/autorun/99_shell.lua b/Capy64/Assets/Lua/CapyOS/boot/autorun/99_shell.lua new file mode 100644 index 0000000..3c5ef7c --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/boot/autorun/99_shell.lua @@ -0,0 +1,15 @@ +local term = require("term") +local colors = require("colors") +local machine = require("machine") + +term.setForeground(0x59c9ff) +term.setBackground(colors.black) +term.clear() +term.setPos(1, 1) + +term.write(os.version()) +term.setPos(1, 2) + +dofile("/bin/shell.lua") + +machine.shutdown() diff --git a/Capy64/Assets/Lua/CapyOS/boot/vendor.bmp b/Capy64/Assets/Lua/CapyOS/boot/vendor.bmp new file mode 100644 index 0000000..8d23632 Binary files /dev/null and b/Capy64/Assets/Lua/CapyOS/boot/vendor.bmp differ diff --git a/Capy64/Assets/Lua/CapyOS/init.lua b/Capy64/Assets/Lua/CapyOS/init.lua new file mode 100644 index 0000000..c25bb13 --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/init.lua @@ -0,0 +1,44 @@ +local version = "0.0.2" + +print("Starting CapyOS") + +local term = require("term") +local fs = require("fs") +local gpu = require("gpu") + +local nPrint = print +local function showError(err) + nPrint(err) + local x, y = term.getPos() + term.setForeground(0xff0000) + term.setPos(1, y) + term.write(err) + + term.setPos(1, y + 1) + term.setForeground(0xffffff) + term.write("Press any key to continue") + + coroutine.yield("key_down") +end + +function os.version() + return "CapyOS " .. version +end + +term.setPos(1, 1) +term.write(_HOST) + +local files = fs.list("/boot/autorun") +for i = 1, #files do + local func, err = loadfile("/boot/autorun/" .. files[i]) + if not func then + showError(err) + break + end + + local ok, err = pcall(func) + if not ok then + showError(debug.traceback(err)) + break + end +end diff --git a/Capy64/Assets/Lua/CapyOS/lib/colors.lua b/Capy64/Assets/Lua/CapyOS/lib/colors.lua new file mode 100644 index 0000000..b0fa97d --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/lib/colors.lua @@ -0,0 +1,94 @@ +local expect = require("expect") + +local palette = { + { + "white", + 0xf0f0f0 + }, + { + "orange", + 0xf2b233 + }, + { + "magenta", + 0xe57fd8 + }, + { + "lightBlue", + 0x99b2f2 + }, + { + "yellow", + 0xdede6c + }, + { + "lime", + 0x7fcc19 + }, + { + "pink", + 0xf2b2cc + }, + { + "gray", + 0x4c4c4c + }, + { + "lightGray", + 0x999999 + }, + { + "cyan", + 0x4c99b2 + }, + { + "purple", + 0xb266e5 + }, + { + "blue", + 0x3366cc + }, + { + "brown", + 0x7f664c + }, + { + "green", + 0x57a64e + }, + { + "red", + 0xcc4c4c + }, + { + "black", + 0x111111 + } +} + +local colors = {} +for k, v in ipairs(palette) do + colors[v[1]] = v[2] + colors[k] = v[2] +end + +function colors.packRGB(r, g, b) + expect(1, r, "number") + expect(2, g, "number") + expect(3, b, "number") + + return (r << 16) + + (g << 8) + + b +end + +function colors.unpackRGB(rgb) + expect(1, rgb, "number") + + return (rgb >> 16) & 0xff, + (rgb >> 8) & 0xff, + rgb & 0xff +end + +return colors; diff --git a/Capy64/Assets/Lua/CapyOS/lib/expect.lua b/Capy64/Assets/Lua/CapyOS/lib/expect.lua new file mode 100644 index 0000000..976928f --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/lib/expect.lua @@ -0,0 +1,52 @@ +-- Credits: https://github.com/Ocawesome101/recrafted + +-- cc.expect + +local _expect = {} + +local function checkType(index, valueType, value, ...) + local expected = table.pack(...) + local isType = false + + for i = 1, expected.n, 1 do + if type(value) == expected[i] then + isType = true + break + end + end + + if not isType then + error(string.format("bad %s %s (%s expected, got %s)", valueType, + index, table.concat(expected, " or "), type(value)), 3) + end + + return value +end + +function _expect.expect(index, value, ...) + return checkType(("#%d"):format(index), "argument", value, ...) +end + +function _expect.field(tbl, index, ...) + _expect.expect(1, tbl, "table") + _expect.expect(2, index, "string") + return checkType(("%q"):format(index), "field", tbl[index], ...) +end + +function _expect.range(num, min, max) + _expect.expect(1, num, "number") + _expect.expect(2, min, "number", "nil") + _expect.expect(3, max, "number", "nil") + min = min or -math.huge + max = max or math.huge + if num < min or num > max then + error(("number outside of range (expected %d to be within %d and %d") + :format(num, min, max), 2) + end +end + +setmetatable(_expect, { __call = function(_, ...) + return _expect.expect(...) +end }) + +return _expect diff --git a/Capy64/Assets/Lua/CapyOS/lib/io.lua b/Capy64/Assets/Lua/CapyOS/lib/io.lua new file mode 100644 index 0000000..9367689 --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/lib/io.lua @@ -0,0 +1,275 @@ +local expect = require("expect").expect +local event = require("event") +local term = require("term") +local keys = require("keys") +local machine = require("machine") + +local io = {} + +function io.write(text) + text = tostring(text) + + local lines = 0 + local w, h = term.getSize() + + local function inc_cy(cy) + lines = lines + 1 + + if cy > h - 1 then + term.scroll(1) + return cy + else + return cy + 1 + end + end + + while #text > 0 do + local nl = text:find("\n") or #text + local chunk = text:sub(1, nl) + text = text:sub(#chunk + 1) + + local has_nl = chunk:sub( -1) == "\n" + if has_nl then chunk = chunk:sub(1, -2) end + + local cx, cy = term.getPos() + while #chunk > 0 do + if cx > w then + term.setPos(1, inc_cy(cy)) + cx, cy = term.getPos() + end + + local to_write = chunk:sub(1, w - cx + 1) + term.write(to_write) + + chunk = chunk:sub(#to_write + 1) + cx, cy = term.getPos() + end + + if has_nl then + term.setPos(1, inc_cy(cy)) + end + end + + return lines +end + +local empty = {} +function io.read(replace, history, complete, default) + expect(1, replace, "string", "nil") + expect(2, history, "table", "nil") + expect(3, complete, "function", "nil") + expect(4, default, "string", "nil") + + if replace then replace = replace:sub(1, 1) end + local hist = history or {} + history = {} + for i = 1, #hist, 1 do + history[i] = hist[i] + end + + local buffer = default or "" + local prev_buf = buffer + history[#history + 1] = buffer + + local hist_pos = #history + local cursor_pos = 0 + + local stx, sty = term.getPos() + local w, h = term.getSize() + + local dirty = false + local completions = {} + local comp_id = 0 + + local function clearCompletion() + if completions[comp_id] then + write((" "):rep(#completions[comp_id])) + end + end + + local function full_redraw(force) + if force or dirty then + if complete and buffer ~= prev_buf then + completions = complete(buffer) or empty + comp_id = math.min(1, #completions) + end + prev_buf = buffer + + term.setPos(stx, sty) + local text = buffer + if replace then text = replace:rep(#text) end + local ln = io.write(text) + + if completions[comp_id] then + local oldfg = term.getForeground() + local oldbg = term.getBackground() + term.setForeground(colors.white) + term.setBackground(colors.gray) + ln = ln + write(completions[comp_id]) + term.setForeground(oldfg) + term.setBackground(oldbg) + else + ln = ln + io.write(" ") + end + + if sty + ln > h then + sty = sty - (sty + ln - h) + end + end + + -- set cursor to the appropriate spot + local cx, cy = stx, sty + cx = cx + #buffer - cursor_pos -- + #(completions[comp_id] or "") + while cx > w do + cx = cx - w + cy = cy + 1 + end + term.setPos(cx, cy) + end + + term.setBlink(true) + + while true do + full_redraw() + -- get input + local evt, par1, par2, mods = event.pull() + + if evt == "char" then + dirty = true + clearCompletion() + if cursor_pos == 0 then + buffer = buffer .. par1 + elseif cursor_pos == #buffer then + buffer = par1 .. buffer + else + buffer = buffer:sub(0, -cursor_pos - 1) .. par1 .. buffer:sub( -cursor_pos) + end + elseif evt == "key_down" then + if par1 == keys.back and #buffer > 0 then + dirty = true + if cursor_pos == 0 then + buffer = buffer:sub(1, -2) + clearCompletion() + elseif cursor_pos < #buffer then + buffer = buffer:sub(0, -cursor_pos - 2) .. buffer:sub( -cursor_pos) + end + elseif par1 == keys.delete and cursor_pos > 0 then + dirty = true + + if cursor_pos == #buffer then + buffer = buffer:sub(2) + elseif cursor_pos == 1 then + buffer = buffer:sub(1, -2) + else + buffer = buffer:sub(0, -cursor_pos - 1) .. buffer:sub( -cursor_pos + 1) + end + cursor_pos = cursor_pos - 1 + elseif par1 == keys.up then + if #completions > 1 then + dirty = true + clearCompletion() + if comp_id > 1 then + comp_id = comp_id - 1 + else + comp_id = #completions + end + elseif hist_pos > 1 then + cursor_pos = 0 + + history[hist_pos] = buffer + hist_pos = hist_pos - 1 + + buffer = (" "):rep(#buffer) + full_redraw(true) + + buffer = history[hist_pos] + dirty = true + end + elseif par1 == keys.down then + if #completions > 1 then + dirty = true + clearCompletion() + if comp_id < #completions then + comp_id = comp_id + 1 + else + comp_id = 1 + end + elseif hist_pos < #history then + cursor_pos = 0 + + history[hist_pos] = buffer + hist_pos = hist_pos + 1 + + buffer = (" "):rep(#buffer) + full_redraw(true) + + buffer = history[hist_pos] + dirty = true + end + elseif par1 == keys.left then + if cursor_pos < #buffer then + clearCompletion() + cursor_pos = cursor_pos + 1 + end + elseif par1 == keys.right then + if cursor_pos > 0 then + cursor_pos = cursor_pos - 1 + elseif comp_id > 0 then + dirty = true + buffer = buffer .. completions[comp_id] + end + elseif par1 == keys.tab then + if comp_id > 0 then + dirty = true + buffer = buffer .. completions[comp_id] + end + elseif par1 == keys.home then + cursor_pos = #buffer + elseif par1 == keys["end"] then + cursor_pos = 0 + elseif par1 == keys.enter then + clearCompletion() + print() + break + elseif mods & keys.mods.ctrl ~= 0 then + if par1 == keys.v then + dirty = true + clearCompletion() + local text = machine.getClipboard() + if text then + if cursor_pos == 0 then + buffer = buffer .. text + elseif cursor_pos == #buffer then + buffer = text .. buffer + else + buffer = buffer:sub(0, -cursor_pos - 1) .. text .. + buffer:sub( -cursor_pos + (#text - 1)) + end + end + end + end + end + end + + term.setBlink(false) + + return buffer +end + +io.stderr = {} + +function io.stderr.write(text) + local fg = term.getForeground() + term.setForeground(0xff0000) + io.write(text) + term.setForeground(fg) +end + +function io.stderr.print(...) + local fg = term.getForeground() + term.setForeground(0xff0000) + print(...) + term.setForeground(fg) +end + +return io diff --git a/Capy64/Assets/Lua/CapyOS/lib/json.lua b/Capy64/Assets/Lua/CapyOS/lib/json.lua new file mode 100644 index 0000000..711ef78 --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/lib/json.lua @@ -0,0 +1,388 @@ +-- +-- json.lua +-- +-- Copyright (c) 2020 rxi +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy of +-- this software and associated documentation files (the "Software"), to deal in +-- the Software without restriction, including without limitation the rights to +-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +-- of the Software, and to permit persons to whom the Software is furnished to do +-- so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in all +-- copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +-- SOFTWARE. +-- + +local json = { _version = "0.1.2" } + +------------------------------------------------------------------------------- +-- Encode +------------------------------------------------------------------------------- + +local encode + +local escape_char_map = { + [ "\\" ] = "\\", + [ "\"" ] = "\"", + [ "\b" ] = "b", + [ "\f" ] = "f", + [ "\n" ] = "n", + [ "\r" ] = "r", + [ "\t" ] = "t", +} + +local escape_char_map_inv = { [ "/" ] = "/" } +for k, v in pairs(escape_char_map) do + escape_char_map_inv[v] = k +end + + +local function escape_char(c) + return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte())) +end + + +local function encode_nil(val) + return "null" +end + + +local function encode_table(val, stack) + local res = {} + stack = stack or {} + + -- Circular reference? + if stack[val] then error("circular reference") end + + stack[val] = true + + if rawget(val, 1) ~= nil or next(val) == nil then + -- Treat as array -- check keys are valid and it is not sparse + local n = 0 + for k in pairs(val) do + if type(k) ~= "number" then + error("invalid table: mixed or invalid key types") + end + n = n + 1 + end + if n ~= #val then + error("invalid table: sparse array") + end + -- Encode + for i, v in ipairs(val) do + table.insert(res, encode(v, stack)) + end + stack[val] = nil + return "[" .. table.concat(res, ",") .. "]" + + else + -- Treat as an object + for k, v in pairs(val) do + if type(k) ~= "string" then + error("invalid table: mixed or invalid key types") + end + table.insert(res, encode(k, stack) .. ":" .. encode(v, stack)) + end + stack[val] = nil + return "{" .. table.concat(res, ",") .. "}" + end +end + + +local function encode_string(val) + return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"' +end + + +local function encode_number(val) + -- Check for NaN, -inf and inf + if val ~= val or val <= -math.huge or val >= math.huge then + error("unexpected number value '" .. tostring(val) .. "'") + end + return string.format("%.14g", val) +end + + +local type_func_map = { + [ "nil" ] = encode_nil, + [ "table" ] = encode_table, + [ "string" ] = encode_string, + [ "number" ] = encode_number, + [ "boolean" ] = tostring, +} + + +encode = function(val, stack) + local t = type(val) + local f = type_func_map[t] + if f then + return f(val, stack) + end + error("unexpected type '" .. t .. "'") +end + + +function json.encode(val) + return ( encode(val) ) +end + + +------------------------------------------------------------------------------- +-- Decode +------------------------------------------------------------------------------- + +local parse + +local function create_set(...) + local res = {} + for i = 1, select("#", ...) do + res[ select(i, ...) ] = true + end + return res +end + +local space_chars = create_set(" ", "\t", "\r", "\n") +local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",") +local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u") +local literals = create_set("true", "false", "null") + +local literal_map = { + [ "true" ] = true, + [ "false" ] = false, + [ "null" ] = nil, +} + + +local function next_char(str, idx, set, negate) + for i = idx, #str do + if set[str:sub(i, i)] ~= negate then + return i + end + end + return #str + 1 +end + + +local function decode_error(str, idx, msg) + local line_count = 1 + local col_count = 1 + for i = 1, idx - 1 do + col_count = col_count + 1 + if str:sub(i, i) == "\n" then + line_count = line_count + 1 + col_count = 1 + end + end + error( string.format("%s at line %d col %d", msg, line_count, col_count) ) +end + + +local function codepoint_to_utf8(n) + -- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa + local f = math.floor + if n <= 0x7f then + return string.char(n) + elseif n <= 0x7ff then + return string.char(f(n / 64) + 192, n % 64 + 128) + elseif n <= 0xffff then + return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128) + elseif n <= 0x10ffff then + return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128, + f(n % 4096 / 64) + 128, n % 64 + 128) + end + error( string.format("invalid unicode codepoint '%x'", n) ) +end + + +local function parse_unicode_escape(s) + local n1 = tonumber( s:sub(1, 4), 16 ) + local n2 = tonumber( s:sub(7, 10), 16 ) + -- Surrogate pair? + if n2 then + return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000) + else + return codepoint_to_utf8(n1) + end +end + + +local function parse_string(str, i) + local res = "" + local j = i + 1 + local k = j + + while j <= #str do + local x = str:byte(j) + + if x < 32 then + decode_error(str, j, "control character in string") + + elseif x == 92 then -- `\`: Escape + res = res .. str:sub(k, j - 1) + j = j + 1 + local c = str:sub(j, j) + if c == "u" then + local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1) + or str:match("^%x%x%x%x", j + 1) + or decode_error(str, j - 1, "invalid unicode escape in string") + res = res .. parse_unicode_escape(hex) + j = j + #hex + else + if not escape_chars[c] then + decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string") + end + res = res .. escape_char_map_inv[c] + end + k = j + 1 + + elseif x == 34 then -- `"`: End of string + res = res .. str:sub(k, j - 1) + return res, j + 1 + end + + j = j + 1 + end + + decode_error(str, i, "expected closing quote for string") +end + + +local function parse_number(str, i) + local x = next_char(str, i, delim_chars) + local s = str:sub(i, x - 1) + local n = tonumber(s) + if not n then + decode_error(str, i, "invalid number '" .. s .. "'") + end + return n, x +end + + +local function parse_literal(str, i) + local x = next_char(str, i, delim_chars) + local word = str:sub(i, x - 1) + if not literals[word] then + decode_error(str, i, "invalid literal '" .. word .. "'") + end + return literal_map[word], x +end + + +local function parse_array(str, i) + local res = {} + local n = 1 + i = i + 1 + while 1 do + local x + i = next_char(str, i, space_chars, true) + -- Empty / end of array? + if str:sub(i, i) == "]" then + i = i + 1 + break + end + -- Read token + x, i = parse(str, i) + res[n] = x + n = n + 1 + -- Next token + i = next_char(str, i, space_chars, true) + local chr = str:sub(i, i) + i = i + 1 + if chr == "]" then break end + if chr ~= "," then decode_error(str, i, "expected ']' or ','") end + end + return res, i +end + + +local function parse_object(str, i) + local res = {} + i = i + 1 + while 1 do + local key, val + i = next_char(str, i, space_chars, true) + -- Empty / end of object? + if str:sub(i, i) == "}" then + i = i + 1 + break + end + -- Read key + if str:sub(i, i) ~= '"' then + decode_error(str, i, "expected string for key") + end + key, i = parse(str, i) + -- Read ':' delimiter + i = next_char(str, i, space_chars, true) + if str:sub(i, i) ~= ":" then + decode_error(str, i, "expected ':' after key") + end + i = next_char(str, i + 1, space_chars, true) + -- Read value + val, i = parse(str, i) + -- Set + res[key] = val + -- Next token + i = next_char(str, i, space_chars, true) + local chr = str:sub(i, i) + i = i + 1 + if chr == "}" then break end + if chr ~= "," then decode_error(str, i, "expected '}' or ','") end + end + return res, i +end + + +local char_func_map = { + [ '"' ] = parse_string, + [ "0" ] = parse_number, + [ "1" ] = parse_number, + [ "2" ] = parse_number, + [ "3" ] = parse_number, + [ "4" ] = parse_number, + [ "5" ] = parse_number, + [ "6" ] = parse_number, + [ "7" ] = parse_number, + [ "8" ] = parse_number, + [ "9" ] = parse_number, + [ "-" ] = parse_number, + [ "t" ] = parse_literal, + [ "f" ] = parse_literal, + [ "n" ] = parse_literal, + [ "[" ] = parse_array, + [ "{" ] = parse_object, +} + + +parse = function(str, idx) + local chr = str:sub(idx, idx) + local f = char_func_map[chr] + if f then + return f(str, idx) + end + decode_error(str, idx, "unexpected character '" .. chr .. "'") +end + + +function json.decode(str) + if type(str) ~= "string" then + error("expected argument of type string, got " .. type(str)) + end + local res, idx = parse(str, next_char(str, 1, space_chars, true)) + idx = next_char(str, idx, space_chars, true) + if idx <= #str then + decode_error(str, idx, "trailing garbage") + end + return res +end + + +return json diff --git a/Capy64/Assets/Lua/CapyOS/lib/keys.lua b/Capy64/Assets/Lua/CapyOS/lib/keys.lua new file mode 100644 index 0000000..1cef85e --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/lib/keys.lua @@ -0,0 +1,179 @@ +local keys = { + none = 0, + back = 8, + tab = 9, + enter = 13, + pause = 19, + caps_lock = 20, + kana = 21, + kanji = 25, + escape = 27, + ime_convert = 28, + ime_no_convert = 29, + space = 32, + page_up = 33, + page_down = 34, + ["end"] = 35, + home = 36, + left = 37, + up = 38, + right = 39, + down = 40, + select = 41, + print = 42, + execute = 43, + print_screen = 44, + insert = 45, + delete = 46, + help = 47, + zero = 48, + one = 49, + two = 50, + three = 51, + four = 52, + five = 53, + six = 54, + seven = 55, + eight = 56, + nine = 57, + a = 65, + b = 66, + c = 67, + d = 68, + e = 69, + f = 70, + g = 71, + h = 72, + i = 73, + j = 74, + k = 75, + l = 76, + m = 77, + n = 78, + o = 79, + p = 80, + q = 81, + r = 82, + s = 83, + t = 84, + u = 85, + v = 86, + w = 87, + x = 88, + y = 89, + z = 90, + left_windows = 91, + right_windows = 92, + apps = 93, + sleep = 95, + num_pad0 = 96, + num_pad1 = 97, + num_pad2 = 98, + num_pad3 = 99, + num_pad4 = 100, + num_pad5 = 101, + num_pad6 = 102, + num_pad7 = 103, + num_pad8 = 104, + num_pad9 = 105, + multiply = 106, + add = 107, + separator = 108, + subtract = 109, + decimal = 110, + divide = 111, + f1 = 112, + f2 = 113, + f3 = 114, + f4 = 115, + f5 = 116, + f6 = 117, + f7 = 118, + f8 = 119, + f9 = 120, + f10 = 121, + f11 = 122, + f12 = 123, + f13 = 124, + f14 = 125, + f15 = 126, + f16 = 127, + f17 = 128, + f18 = 129, + f19 = 130, + f20 = 131, + f21 = 132, + f22 = 133, + f23 = 134, + f24 = 135, + num_lock = 144, + scroll = 145, + left_shift = 160, + right_shift = 161, + left_control = 162, + right_control = 163, + left_alt = 164, + right_alt = 165, + browser_back = 166, + browser_forward = 167, + browser_refresh = 168, + browser_stop = 169, + browser_search = 170, + browser_favorites = 171, + browser_home = 172, + volume_mute = 173, + volume_down = 174, + volume_up = 175, + media_next_track = 176, + media_previous_track = 177, + media_stop = 178, + media_play_pause = 179, + launch_mail = 180, + select_media = 181, + launch_application1 = 182, + launch_application2 = 183, + semicolon = 186, + plus = 187, + comma = 188, + minus = 189, + period = 190, + question = 191, + tilde = 192, + chat_pad_green = 202, + chat_pad_orange = 203, + open_brackets = 219, + pipe = 220, + close_brackets = 221, + quotes = 222, + oem8 = 223, + backslash = 226, + process_key = 229, + copy = 242, + auto = 243, + enl_w = 244, + attn = 246, + crsel = 247, + exsel = 248, + erase_eof = 249, + play = 250, + zoom = 251, + pa1 = 253, + clear = 254, +} + +keys.mods = { + none = 0, + left_shift = 1, + right_shift = 2, + left_alt = 4, + right_alt = 8, + left_control = 16, + right_control = 32, +} + +keys.mods.shift = keys.mods.left_shift | keys.mods.right_shift +keys.mods.alt = keys.mods.left_alt | keys.mods.right_alt +keys.mods.control = keys.mods.left_control | keys.mods.right_control +keys.mods.ctrl = keys.mods.control + +return keys \ No newline at end of file diff --git a/Capy64/Assets/Lua/CapyOS/lib/parallel.lua b/Capy64/Assets/Lua/CapyOS/lib/parallel.lua new file mode 100644 index 0000000..bdb79b8 --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/lib/parallel.lua @@ -0,0 +1,61 @@ +local expect = require("expect") + +local parallel = {} + +local function contains(array, value) + for k, v in pairs(array) do + if v == value then + return true + end + end + return false +end + +local function run(threads, exitOnAny) + local alive = #threads + local filters = {} + local ev = {} + while true do + for i, thread in pairs(threads) do + if not filters[i] or #filters[i] == 0 or contains(filters[i], ev[1]) or ev[1] == "interrupt" then + local pars = table.pack(coroutine.resume(thread, table.unpack(ev))) + if pars[1] then + filters[i] = table.pack(table.unpack(pars, 2)) + else + error(pars[2], 0) + end + end + + if coroutine.status(thread) == "dead" then + alive = alive - 1 + if exitOnAny or alive <= 0 then + return + end + end + end + + ev = table.pack(coroutine.yield()) + end +end + +function parallel.waitForAll(...) + local threads = {} + for k, v in ipairs({ ... }) do + expect(k, v, "function") + table.insert(threads, coroutine.create(v)) + end + + return run(threads, false) +end + +function parallel.waitForAny(...) + local threads = {} + for k, v in ipairs({ ... }) do + expect(k, v, "function") + table.insert(threads, coroutine.create(v)) + end + + return run(threads, true) +end + +return parallel diff --git a/Capy64/Assets/Lua/CapyOS/lib/utfstring.lua b/Capy64/Assets/Lua/CapyOS/lib/utfstring.lua new file mode 100644 index 0000000..b442b6d --- /dev/null +++ b/Capy64/Assets/Lua/CapyOS/lib/utfstring.lua @@ -0,0 +1,1776 @@ +local expect = require "expect" + +local UTFString = {} +local UTFString_mt = { __index = UTFString, __name = "UTFString" } + +local function toUTF8(s) + -- convert from ANSI if the string is invalid in UTF-8 + local ss = "" + local iter, invar, i = utf8.codes(s) + local ok, c + while i do + local oi = i + ok, i, c = pcall(iter, invar, i) + if not ok then i, ss = oi + 1, ss .. utf8.char(string.byte(s, utf8.offset(s, oi) + 1)) + elseif c then ss = ss .. utf8.char(c) end + end + return ss +end + +function UTFString:new(s) + return setmetatable({ str = toUTF8(s) }, UTFString_mt) +end + +setmetatable(UTFString, { __call = UTFString.new }) + +local utf8_case_conv_utl, utf8_case_conv_ltu = nil, {} -- defined at bottom of file + +-- string library implementation + +function UTFString:byte(i, j) + expect(1, i, "number", "nil") + expect(2, j, "number", "nil") + return utf8.codepoint(self.str, i, j) +end + +UTFString.char = utf8.char +UTFString.dump = string.dump + +function UTFString:find(pattern, init, plain) + expect(1, pattern, "string", "table") + expect(2, init, "number", "nil") + if type(pattern) == "table" then + if getmetatable(pattern) ~= UTFString_mt then error("bad argument #1 (expected string or UTFString, got table)", + 2) end + pattern = pattern.str + else pattern = toUTF8(pattern) end + pattern = string.gsub(string.gsub(pattern, "(.)%.", + function(s) if s == "%" then return "%." else return s .. utf8.charpattern end end), "^%.", utf8.charpattern) + local s, e = string.find(self.str, pattern, init and utf8.offset(self.str, init), plain) + if not s then return nil end + return utf8.len(string.sub(self.str, 1, s - 1)) + 1, utf8.len(string.sub(self.str, 1, e - 1)) + 1 +end + +function UTFString:format(...) + local args = table.pack(...) + for i = 1, args.n do + if type(args[i]) == "table" and getmetatable(args[i]) == UTFString_mt then args[i] = args[i].str + elseif type(args[i]) == "string" then args[i] = toUTF8(args[i]) end + end + return UTFString(string.format(self.str, table.unpack(args, 1, args.n))) +end + +function UTFString:gmatch(pattern) + expect(1, pattern, "string", "table") + if type(pattern) == "table" then + if getmetatable(pattern) ~= UTFString_mt then error("bad argument #1 (expected string or UTFString, got table)", + 2) end + pattern = pattern.str + else pattern = toUTF8(pattern) end + pattern = string.gsub(string.gsub(pattern, "(.)%.", + function(s) if s == "%" then return "%." else return s .. utf8.charpattern end end), "^%.", utf8.charpattern) + local iter = string.gmatch(self.str, pattern) + return function() + local matches = table.pack(iter()) + for i = 1, matches.n do + local tt = type(matches[i]) + if tt == "string" then matches[i] = UTFString(matches[i]) + elseif tt == "number" then matches[i] = utf8.len(string.sub(self.str, 1, matches[i])) + 1 end + end + return table.unpack(matches, 1, matches.n) + end +end + +function UTFString:gsub(pattern, repl, n) + expect(1, pattern, "string", "table") + expect(2, repl, "string", "table", "function") + expect(3, n, "number", "nil") + if type(pattern) == "table" then + if getmetatable(pattern) ~= UTFString_mt then error("bad argument #1 (expected string or UTFString, got table)", + 2) end + pattern = pattern.str + else pattern = toUTF8(pattern) end + if type(repl) == "table" and getmetatable(repl) == UTFString_mt then repl = repl.str + elseif type(repl) == "string" then repl = toUTF8(repl) end + pattern = string.gsub(string.gsub(pattern, "(.)%.", + function(s) if s == "%" then return "%." else return s .. utf8.charpattern end end), "^%.", utf8.charpattern) + local s, total = string.gsub(self.str, pattern, repl, n) + return UTFString(s), total +end + +function UTFString:len() + return utf8.len(self.str) +end + +function UTFString:lower() + local s = "" + for _, c in utf8.codes(self.str) do + if utf8_case_conv_utl[c] then + if type(utf8_case_conv_utl[c]) == "table" then s = s .. utf8.char(table.unpack(utf8_case_conv_utl[c])) + else s = s .. utf8.char(utf8_case_conv_utl[c]) end + else s = s .. utf8.char(c) end + end + return UTFString(s) +end + +function UTFString:match(pattern, init) + expect(1, pattern, "string", "table") + expect(2, init, "number", "nil") + if type(pattern) == "table" then + if getmetatable(pattern) ~= UTFString_mt then error("bad argument #1 (expected string or UTFString, got table)", + 2) end + pattern = pattern.str + else pattern = toUTF8(pattern) end + pattern = string.gsub(string.gsub(pattern, "(.)%.", + function(s) if s == "%" then return "%." else return s .. utf8.charpattern end end), "^%.", utf8.charpattern) + local matches = table.pack(string.match(self.str, pattern, init and utf8.offset(self.str, init))) + for i = 1, matches.n do + local tt = type(matches[i]) + if tt == "string" then matches[i] = UTFString(matches[i]) + elseif tt == "number" then matches[i] = utf8.len(string.sub(self.str, 1, matches[i])) + 1 end + end + return table.unpack(matches, 1, matches.n) +end + +function UTFString:pack(...) + return UTFString(string.pack(self.str, ...)) +end + +function UTFString:packsize() + return string.packsize(self.str) +end + +function UTFString:rep(n, sep) + expect(1, n, "number") + expect(2, sep, "string", "table", "nil") + if type(sep) == "table" then + if getmetatable(sep) ~= UTFString_mt then error("bad argument #2 (expected string or UTFString, got table)", 2) end + sep = sep.str + elseif sep then sep = toUTF8(sep) end + return UTFString(string.rep(self.str, n, sep)) +end + +function UTFString:reverse() + local codes = { n = 0 } + for _, c in utf8.codes(self.str) do + codes.n = codes.n + 1 + codes[codes.n] = c + end + local s = "" + for i = codes.n, 1, -1 do s = s .. utf8.char(codes[i]) end + return UTFString(s) +end + +function UTFString:sub(i, j) + expect(1, i, "number") + expect(2, j, "number", "nil") + return UTFString(string.sub(self.str, utf8.offset(self.str, i), j and utf8.offset(self.str, j))) +end + +function UTFString:unpack(s, pos) + expect(1, s, "string", "table") + expect(2, pos, "number", "nil") + if type(s) == "table" then + if getmetatable(s) ~= UTFString_mt then error("bad argument #1 (expected string or UTFString, got table)", 2) end + s = s.str + if pos then pos = utf8.offset(s, pos) end + end + return string.unpack(self.str, s, pos) +end + +function UTFString:upper() + local s = "" + for _, c in utf8.codes(self.str) do + if utf8_case_conv_ltu[c] then + if type(utf8_case_conv_ltu[c]) == "table" then s = s .. utf8.char(table.unpack(utf8_case_conv_ltu[c])) + else s = s .. utf8.char(utf8_case_conv_ltu[c]) end + else s = s .. utf8.char(c) end + end + return UTFString(s) +end + +-- metamethods + +function UTFString_mt:__len() + return utf8.len(self.str) +end + +function UTFString_mt.__concat(a, b) + if type(a) == "string" then return UTFString(a .. b.str) + elseif type(b) == "string" then return UTFString(a.str .. b) + else + if type(a) ~= "table" or getmetatable(a) ~= UTFString_mt then error("attempt to concatenate " .. + type(a) .. " and UTFString", 2) + elseif type(b) ~= "table" or getmetatable(b) ~= UTFString_mt then error("attempt to concatenate UTFString and " + .. type(b), 2) end + return UTFString(a.str .. b.str) + end +end + +function UTFString_mt.__eq(a, b) + if type(a) == "string" then return a == b.str + elseif type(b) == "string" then return a.str == b + elseif type(a) ~= "table" or type(b) ~= "table" or getmetatable(a) ~= UTFString_mt or getmetatable(b) ~= UTFString_mt then return false + else return a.str == b.str end +end + +function UTFString_mt.__lt(a, b) + if type(a) == "string" then return a < b.str + elseif type(b) == "string" then return a.str < b + else + if type(a) ~= "table" or getmetatable(a) ~= UTFString_mt then error("attempt to compare " .. + type(a) .. " and UTFString", 2) + elseif type(b) ~= "table" or getmetatable(b) ~= UTFString_mt then error("attempt to compare UTFString and " .. + type(b), 2) end + return a.str < b.str + end +end + +function UTFString_mt.__le(a, b) + if type(a) == "string" then return a <= b.str + elseif type(b) == "string" then return a.str <= b + else + if type(a) ~= "table" or getmetatable(a) ~= UTFString_mt then error("attempt to compare " .. + type(a) .. " and UTFString", 2) + elseif type(b) ~= "table" or getmetatable(b) ~= UTFString_mt then error("attempt to compare UTFString and " .. + type(b), 2) end + return a.str <= b.str + end +end + +function UTFString_mt:__tostring() + local str = "" + for _, c in utf8.codes(self.str) do + if c > 255 then str = str .. "?" + else str = str .. string.char(c) end + end + return str +end + +-- tables for UTF-8 case conversion + +utf8_case_conv_utl = { + [0x0041] = 0x0061, + [0x0042] = 0x0062, + [0x0043] = 0x0063, + [0x0044] = 0x0064, + [0x0045] = 0x0065, + [0x0046] = 0x0066, + [0x0047] = 0x0067, + [0x0048] = 0x0068, + [0x0049] = 0x0069, + + [0x004A] = 0x006A, + [0x004B] = 0x006B, + [0x004C] = 0x006C, + [0x004D] = 0x006D, + [0x004E] = 0x006E, + [0x004F] = 0x006F, + [0x0050] = 0x0070, + [0x0051] = 0x0071, + [0x0052] = 0x0072, + [0x0053] = 0x0073, + [0x0054] = 0x0074, + [0x0055] = 0x0075, + [0x0056] = 0x0076, + [0x0057] = 0x0077, + [0x0058] = 0x0078, + [0x0059] = 0x0079, + [0x005A] = 0x007A, + [0x00B5] = 0x03BC, + [0x00C0] = 0x00E0, + [0x00C1] = 0x00E1, + [0x00C2] = 0x00E2, + [0x00C3] = 0x00E3, + [0x00C4] = 0x00E4, + [0x00C5] = 0x00E5, + [0x00C6] = 0x00E6, + [0x00C7] = 0x00E7, + [0x00C8] = 0x00E8, + [0x00C9] = 0x00E9, + [0x00CA] = 0x00EA, + [0x00CB] = 0x00EB, + [0x00CC] = 0x00EC, + [0x00CD] = 0x00ED, + [0x00CE] = 0x00EE, + [0x00CF] = 0x00EF, + [0x00D0] = 0x00F0, + [0x00D1] = 0x00F1, + [0x00D2] = 0x00F2, + [0x00D3] = 0x00F3, + [0x00D4] = 0x00F4, + [0x00D5] = 0x00F5, + [0x00D6] = 0x00F6, + [0x00D8] = 0x00F8, + [0x00D9] = 0x00F9, + [0x00DA] = 0x00FA, + [0x00DB] = 0x00FB, + [0x00DC] = 0x00FC, + [0x00DD] = 0x00FD, + [0x00DE] = 0x00FE, + [0x00DF] = { 0x0073, 0x0073 }, + [0x0100] = 0x0101, + [0x0102] = 0x0103, + [0x0104] = 0x0105, + [0x0106] = 0x0107, + [0x0108] = 0x0109, + [0x010A] = 0x010B, + [0x010C] = 0x010D, + [0x010E] = 0x010F, + [0x0110] = 0x0111, + [0x0112] = 0x0113, + [0x0114] = 0x0115, + [0x0116] = 0x0117, + [0x0118] = 0x0119, + [0x011A] = 0x011B, + [0x011C] = 0x011D, + [0x011E] = 0x011F, + [0x0120] = 0x0121, + [0x0122] = 0x0123, + [0x0124] = 0x0125, + [0x0126] = 0x0127, + [0x0128] = 0x0129, + [0x012A] = 0x012B, + [0x012C] = 0x012D, + [0x012E] = 0x012F, + [0x0130] = { 0x0069, 0x0307 }, + + [0x0132] = 0x0133, + [0x0134] = 0x0135, + [0x0136] = 0x0137, + [0x0139] = 0x013A, + [0x013B] = 0x013C, + [0x013D] = 0x013E, + [0x013F] = 0x0140, + [0x0141] = 0x0142, + [0x0143] = 0x0144, + [0x0145] = 0x0146, + [0x0147] = 0x0148, + [0x0149] = { 0x02BC, 0x006E }, + [0x014A] = 0x014B, + [0x014C] = 0x014D, + [0x014E] = 0x014F, + [0x0150] = 0x0151, + [0x0152] = 0x0153, + [0x0154] = 0x0155, + [0x0156] = 0x0157, + [0x0158] = 0x0159, + [0x015A] = 0x015B, + [0x015C] = 0x015D, + [0x015E] = 0x015F, + [0x0160] = 0x0161, + [0x0162] = 0x0163, + [0x0164] = 0x0165, + [0x0166] = 0x0167, + [0x0168] = 0x0169, + [0x016A] = 0x016B, + [0x016C] = 0x016D, + [0x016E] = 0x016F, + [0x0170] = 0x0171, + [0x0172] = 0x0173, + [0x0174] = 0x0175, + [0x0176] = 0x0177, + [0x0178] = 0x00FF, + [0x0179] = 0x017A, + [0x017B] = 0x017C, + [0x017D] = 0x017E, + [0x017F] = 0x0073, + [0x0181] = 0x0253, + [0x0182] = 0x0183, + [0x0184] = 0x0185, + [0x0186] = 0x0254, + [0x0187] = 0x0188, + [0x0189] = 0x0256, + [0x018A] = 0x0257, + [0x018B] = 0x018C, + [0x018E] = 0x01DD, + [0x018F] = 0x0259, + [0x0190] = 0x025B, + [0x0191] = 0x0192, + [0x0193] = 0x0260, + [0x0194] = 0x0263, + [0x0196] = 0x0269, + [0x0197] = 0x0268, + [0x0198] = 0x0199, + [0x019C] = 0x026F, + [0x019D] = 0x0272, + [0x019F] = 0x0275, + [0x01A0] = 0x01A1, + [0x01A2] = 0x01A3, + [0x01A4] = 0x01A5, + [0x01A6] = 0x0280, + [0x01A7] = 0x01A8, + [0x01A9] = 0x0283, + [0x01AC] = 0x01AD, + [0x01AE] = 0x0288, + [0x01AF] = 0x01B0, + [0x01B1] = 0x028A, + [0x01B2] = 0x028B, + [0x01B3] = 0x01B4, + [0x01B5] = 0x01B6, + [0x01B7] = 0x0292, + [0x01B8] = 0x01B9, + [0x01BC] = 0x01BD, + [0x01C4] = 0x01C6, + [0x01C5] = 0x01C6, + [0x01C7] = 0x01C9, + [0x01C8] = 0x01C9, + [0x01CA] = 0x01CC, + [0x01CB] = 0x01CC, + [0x01CD] = 0x01CE, + [0x01CF] = 0x01D0, + [0x01D1] = 0x01D2, + [0x01D3] = 0x01D4, + [0x01D5] = 0x01D6, + [0x01D7] = 0x01D8, + [0x01D9] = 0x01DA, + [0x01DB] = 0x01DC, + [0x01DE] = 0x01DF, + [0x01E0] = 0x01E1, + [0x01E2] = 0x01E3, + [0x01E4] = 0x01E5, + [0x01E6] = 0x01E7, + [0x01E8] = 0x01E9, + [0x01EA] = 0x01EB, + [0x01EC] = 0x01ED, + [0x01EE] = 0x01EF, + [0x01F0] = { 0x006A, 0x030C }, + [0x01F1] = 0x01F3, + [0x01F2] = 0x01F3, + [0x01F4] = 0x01F5, + [0x01F6] = 0x0195, + [0x01F7] = 0x01BF, + [0x01F8] = 0x01F9, + [0x01FA] = 0x01FB, + [0x01FC] = 0x01FD, + [0x01FE] = 0x01FF, + [0x0200] = 0x0201, + [0x0202] = 0x0203, + [0x0204] = 0x0205, + [0x0206] = 0x0207, + [0x0208] = 0x0209, + [0x020A] = 0x020B, + [0x020C] = 0x020D, + [0x020E] = 0x020F, + [0x0210] = 0x0211, + [0x0212] = 0x0213, + [0x0214] = 0x0215, + [0x0216] = 0x0217, + [0x0218] = 0x0219, + [0x021A] = 0x021B, + [0x021C] = 0x021D, + [0x021E] = 0x021F, + [0x0220] = 0x019E, + [0x0222] = 0x0223, + [0x0224] = 0x0225, + [0x0226] = 0x0227, + [0x0228] = 0x0229, + [0x022A] = 0x022B, + [0x022C] = 0x022D, + [0x022E] = 0x022F, + [0x0230] = 0x0231, + [0x0232] = 0x0233, + [0x023A] = 0x2C65, + [0x023B] = 0x023C, + [0x023D] = 0x019A, + [0x023E] = 0x2C66, + [0x0241] = 0x0242, + [0x0243] = 0x0180, + [0x0244] = 0x0289, + [0x0245] = 0x028C, + [0x0246] = 0x0247, + [0x0248] = 0x0249, + [0x024A] = 0x024B, + [0x024C] = 0x024D, + [0x024E] = 0x024F, + [0x0345] = 0x03B9, + [0x0370] = 0x0371, + [0x0372] = 0x0373, + [0x0376] = 0x0377, + [0x037F] = 0x03F3, + [0x0386] = 0x03AC, + [0x0388] = 0x03AD, + [0x0389] = 0x03AE, + [0x038A] = 0x03AF, + [0x038C] = 0x03CC, + [0x038E] = 0x03CD, + [0x038F] = 0x03CE, + [0x0390] = { 0x03B9, 0x0308, 0x0301 }, + [0x0391] = 0x03B1, + [0x0392] = 0x03B2, + [0x0393] = 0x03B3, + [0x0394] = 0x03B4, + [0x0395] = 0x03B5, + [0x0396] = 0x03B6, + [0x0397] = 0x03B7, + [0x0398] = 0x03B8, + [0x0399] = 0x03B9, + [0x039A] = 0x03BA, + [0x039B] = 0x03BB, + [0x039C] = 0x03BC, + [0x039D] = 0x03BD, + [0x039E] = 0x03BE, + [0x039F] = 0x03BF, + [0x03A0] = 0x03C0, + [0x03A1] = 0x03C1, + [0x03A3] = 0x03C3, + [0x03A4] = 0x03C4, + [0x03A5] = 0x03C5, + [0x03A6] = 0x03C6, + [0x03A7] = 0x03C7, + [0x03A8] = 0x03C8, + [0x03A9] = 0x03C9, + [0x03AA] = 0x03CA, + [0x03AB] = 0x03CB, + [0x03B0] = { 0x03C5, 0x0308, 0x0301 }, + [0x03C2] = 0x03C3, + [0x03CF] = 0x03D7, + [0x03D0] = 0x03B2, + [0x03D1] = 0x03B8, + [0x03D5] = 0x03C6, + [0x03D6] = 0x03C0, + [0x03D8] = 0x03D9, + [0x03DA] = 0x03DB, + [0x03DC] = 0x03DD, + [0x03DE] = 0x03DF, + [0x03E0] = 0x03E1, + [0x03E2] = 0x03E3, + [0x03E4] = 0x03E5, + [0x03E6] = 0x03E7, + [0x03E8] = 0x03E9, + [0x03EA] = 0x03EB, + [0x03EC] = 0x03ED, + [0x03EE] = 0x03EF, + [0x03F0] = 0x03BA, + [0x03F1] = 0x03C1, + [0x03F4] = 0x03B8, + [0x03F5] = 0x03B5, + [0x03F7] = 0x03F8, + [0x03F9] = 0x03F2, + [0x03FA] = 0x03FB, + [0x03FD] = 0x037B, + [0x03FE] = 0x037C, + [0x03FF] = 0x037D, + [0x0400] = 0x0450, + [0x0401] = 0x0451, + [0x0402] = 0x0452, + [0x0403] = 0x0453, + [0x0404] = 0x0454, + [0x0405] = 0x0455, + [0x0406] = 0x0456, + [0x0407] = 0x0457, + [0x0408] = 0x0458, + [0x0409] = 0x0459, + [0x040A] = 0x045A, + [0x040B] = 0x045B, + [0x040C] = 0x045C, + [0x040D] = 0x045D, + [0x040E] = 0x045E, + [0x040F] = 0x045F, + [0x0410] = 0x0430, + [0x0411] = 0x0431, + [0x0412] = 0x0432, + [0x0413] = 0x0433, + [0x0414] = 0x0434, + [0x0415] = 0x0435, + [0x0416] = 0x0436, + [0x0417] = 0x0437, + [0x0418] = 0x0438, + [0x0419] = 0x0439, + [0x041A] = 0x043A, + [0x041B] = 0x043B, + [0x041C] = 0x043C, + [0x041D] = 0x043D, + [0x041E] = 0x043E, + [0x041F] = 0x043F, + [0x0420] = 0x0440, + [0x0421] = 0x0441, + [0x0422] = 0x0442, + [0x0423] = 0x0443, + [0x0424] = 0x0444, + [0x0425] = 0x0445, + [0x0426] = 0x0446, + [0x0427] = 0x0447, + [0x0428] = 0x0448, + [0x0429] = 0x0449, + [0x042A] = 0x044A, + [0x042B] = 0x044B, + [0x042C] = 0x044C, + [0x042D] = 0x044D, + [0x042E] = 0x044E, + [0x042F] = 0x044F, + [0x0460] = 0x0461, + [0x0462] = 0x0463, + [0x0464] = 0x0465, + [0x0466] = 0x0467, + [0x0468] = 0x0469, + [0x046A] = 0x046B, + [0x046C] = 0x046D, + [0x046E] = 0x046F, + [0x0470] = 0x0471, + [0x0472] = 0x0473, + [0x0474] = 0x0475, + [0x0476] = 0x0477, + [0x0478] = 0x0479, + [0x047A] = 0x047B, + [0x047C] = 0x047D, + [0x047E] = 0x047F, + [0x0480] = 0x0481, + [0x048A] = 0x048B, + [0x048C] = 0x048D, + [0x048E] = 0x048F, + [0x0490] = 0x0491, + [0x0492] = 0x0493, + [0x0494] = 0x0495, + [0x0496] = 0x0497, + [0x0498] = 0x0499, + [0x049A] = 0x049B, + [0x049C] = 0x049D, + [0x049E] = 0x049F, + [0x04A0] = 0x04A1, + [0x04A2] = 0x04A3, + [0x04A4] = 0x04A5, + [0x04A6] = 0x04A7, + [0x04A8] = 0x04A9, + [0x04AA] = 0x04AB, + [0x04AC] = 0x04AD, + [0x04AE] = 0x04AF, + [0x04B0] = 0x04B1, + [0x04B2] = 0x04B3, + [0x04B4] = 0x04B5, + [0x04B6] = 0x04B7, + [0x04B8] = 0x04B9, + [0x04BA] = 0x04BB, + [0x04BC] = 0x04BD, + [0x04BE] = 0x04BF, + [0x04C0] = 0x04CF, + [0x04C1] = 0x04C2, + [0x04C3] = 0x04C4, + [0x04C5] = 0x04C6, + [0x04C7] = 0x04C8, + [0x04C9] = 0x04CA, + [0x04CB] = 0x04CC, + [0x04CD] = 0x04CE, + [0x04D0] = 0x04D1, + [0x04D2] = 0x04D3, + [0x04D4] = 0x04D5, + [0x04D6] = 0x04D7, + [0x04D8] = 0x04D9, + [0x04DA] = 0x04DB, + [0x04DC] = 0x04DD, + [0x04DE] = 0x04DF, + [0x04E0] = 0x04E1, + [0x04E2] = 0x04E3, + [0x04E4] = 0x04E5, + [0x04E6] = 0x04E7, + [0x04E8] = 0x04E9, + [0x04EA] = 0x04EB, + [0x04EC] = 0x04ED, + [0x04EE] = 0x04EF, + [0x04F0] = 0x04F1, + [0x04F2] = 0x04F3, + [0x04F4] = 0x04F5, + [0x04F6] = 0x04F7, + [0x04F8] = 0x04F9, + [0x04FA] = 0x04FB, + [0x04FC] = 0x04FD, + [0x04FE] = 0x04FF, + [0x0500] = 0x0501, + [0x0502] = 0x0503, + [0x0504] = 0x0505, + [0x0506] = 0x0507, + [0x0508] = 0x0509, + [0x050A] = 0x050B, + [0x050C] = 0x050D, + [0x050E] = 0x050F, + [0x0510] = 0x0511, + [0x0512] = 0x0513, + [0x0514] = 0x0515, + [0x0516] = 0x0517, + [0x0518] = 0x0519, + [0x051A] = 0x051B, + [0x051C] = 0x051D, + [0x051E] = 0x051F, + [0x0520] = 0x0521, + [0x0522] = 0x0523, + [0x0524] = 0x0525, + [0x0526] = 0x0527, + [0x0528] = 0x0529, + [0x052A] = 0x052B, + [0x052C] = 0x052D, + [0x052E] = 0x052F, + [0x0531] = 0x0561, + [0x0532] = 0x0562, + [0x0533] = 0x0563, + [0x0534] = 0x0564, + [0x0535] = 0x0565, + [0x0536] = 0x0566, + [0x0537] = 0x0567, + [0x0538] = 0x0568, + [0x0539] = 0x0569, + [0x053A] = 0x056A, + [0x053B] = 0x056B, + [0x053C] = 0x056C, + [0x053D] = 0x056D, + [0x053E] = 0x056E, + [0x053F] = 0x056F, + [0x0540] = 0x0570, + [0x0541] = 0x0571, + [0x0542] = 0x0572, + [0x0543] = 0x0573, + [0x0544] = 0x0574, + [0x0545] = 0x0575, + [0x0546] = 0x0576, + [0x0547] = 0x0577, + [0x0548] = 0x0578, + [0x0549] = 0x0579, + [0x054A] = 0x057A, + [0x054B] = 0x057B, + [0x054C] = 0x057C, + [0x054D] = 0x057D, + [0x054E] = 0x057E, + [0x054F] = 0x057F, + [0x0550] = 0x0580, + [0x0551] = 0x0581, + [0x0552] = 0x0582, + [0x0553] = 0x0583, + [0x0554] = 0x0584, + [0x0555] = 0x0585, + [0x0556] = 0x0586, + [0x0587] = { 0x0565, 0x0582 }, + [0x10A0] = 0x2D00, + [0x10A1] = 0x2D01, + [0x10A2] = 0x2D02, + [0x10A3] = 0x2D03, + [0x10A4] = 0x2D04, + [0x10A5] = 0x2D05, + [0x10A6] = 0x2D06, + [0x10A7] = 0x2D07, + [0x10A8] = 0x2D08, + [0x10A9] = 0x2D09, + [0x10AA] = 0x2D0A, + [0x10AB] = 0x2D0B, + [0x10AC] = 0x2D0C, + [0x10AD] = 0x2D0D, + [0x10AE] = 0x2D0E, + [0x10AF] = 0x2D0F, + [0x10B0] = 0x2D10, + [0x10B1] = 0x2D11, + [0x10B2] = 0x2D12, + [0x10B3] = 0x2D13, + [0x10B4] = 0x2D14, + [0x10B5] = 0x2D15, + [0x10B6] = 0x2D16, + [0x10B7] = 0x2D17, + [0x10B8] = 0x2D18, + [0x10B9] = 0x2D19, + [0x10BA] = 0x2D1A, + [0x10BB] = 0x2D1B, + [0x10BC] = 0x2D1C, + [0x10BD] = 0x2D1D, + [0x10BE] = 0x2D1E, + [0x10BF] = 0x2D1F, + [0x10C0] = 0x2D20, + [0x10C1] = 0x2D21, + [0x10C2] = 0x2D22, + [0x10C3] = 0x2D23, + [0x10C4] = 0x2D24, + [0x10C5] = 0x2D25, + [0x10C7] = 0x2D27, + [0x10CD] = 0x2D2D, + [0x13F8] = 0x13F0, + [0x13F9] = 0x13F1, + [0x13FA] = 0x13F2, + [0x13FB] = 0x13F3, + [0x13FC] = 0x13F4, + [0x13FD] = 0x13F5, + [0x1C80] = 0x0432, + [0x1C81] = 0x0434, + [0x1C82] = 0x043E, + [0x1C83] = 0x0441, + [0x1C84] = 0x0442, + [0x1C85] = 0x0442, + [0x1C86] = 0x044A, + [0x1C87] = 0x0463, + [0x1C88] = 0xA64B, + [0x1C90] = 0x10D0, + [0x1C91] = 0x10D1, + [0x1C92] = 0x10D2, + [0x1C93] = 0x10D3, + [0x1C94] = 0x10D4, + [0x1C95] = 0x10D5, + [0x1C96] = 0x10D6, + [0x1C97] = 0x10D7, + [0x1C98] = 0x10D8, + [0x1C99] = 0x10D9, + [0x1C9A] = 0x10DA, + [0x1C9B] = 0x10DB, + [0x1C9C] = 0x10DC, + [0x1C9D] = 0x10DD, + [0x1C9E] = 0x10DE, + [0x1C9F] = 0x10DF, + [0x1CA0] = 0x10E0, + [0x1CA1] = 0x10E1, + [0x1CA2] = 0x10E2, + [0x1CA3] = 0x10E3, + [0x1CA4] = 0x10E4, + [0x1CA5] = 0x10E5, + [0x1CA6] = 0x10E6, + [0x1CA7] = 0x10E7, + [0x1CA8] = 0x10E8, + [0x1CA9] = 0x10E9, + [0x1CAA] = 0x10EA, + [0x1CAB] = 0x10EB, + [0x1CAC] = 0x10EC, + [0x1CAD] = 0x10ED, + [0x1CAE] = 0x10EE, + [0x1CAF] = 0x10EF, + [0x1CB0] = 0x10F0, + [0x1CB1] = 0x10F1, + [0x1CB2] = 0x10F2, + [0x1CB3] = 0x10F3, + [0x1CB4] = 0x10F4, + [0x1CB5] = 0x10F5, + [0x1CB6] = 0x10F6, + [0x1CB7] = 0x10F7, + [0x1CB8] = 0x10F8, + [0x1CB9] = 0x10F9, + [0x1CBA] = 0x10FA, + [0x1CBD] = 0x10FD, + [0x1CBE] = 0x10FE, + [0x1CBF] = 0x10FF, + [0x1E00] = 0x1E01, + [0x1E02] = 0x1E03, + [0x1E04] = 0x1E05, + [0x1E06] = 0x1E07, + [0x1E08] = 0x1E09, + [0x1E0A] = 0x1E0B, + [0x1E0C] = 0x1E0D, + [0x1E0E] = 0x1E0F, + [0x1E10] = 0x1E11, + [0x1E12] = 0x1E13, + [0x1E14] = 0x1E15, + [0x1E16] = 0x1E17, + [0x1E18] = 0x1E19, + [0x1E1A] = 0x1E1B, + [0x1E1C] = 0x1E1D, + [0x1E1E] = 0x1E1F, + [0x1E20] = 0x1E21, + [0x1E22] = 0x1E23, + [0x1E24] = 0x1E25, + [0x1E26] = 0x1E27, + [0x1E28] = 0x1E29, + [0x1E2A] = 0x1E2B, + [0x1E2C] = 0x1E2D, + [0x1E2E] = 0x1E2F, + [0x1E30] = 0x1E31, + [0x1E32] = 0x1E33, + [0x1E34] = 0x1E35, + [0x1E36] = 0x1E37, + [0x1E38] = 0x1E39, + [0x1E3A] = 0x1E3B, + [0x1E3C] = 0x1E3D, + [0x1E3E] = 0x1E3F, + [0x1E40] = 0x1E41, + [0x1E42] = 0x1E43, + [0x1E44] = 0x1E45, + [0x1E46] = 0x1E47, + [0x1E48] = 0x1E49, + [0x1E4A] = 0x1E4B, + [0x1E4C] = 0x1E4D, + [0x1E4E] = 0x1E4F, + [0x1E50] = 0x1E51, + [0x1E52] = 0x1E53, + [0x1E54] = 0x1E55, + [0x1E56] = 0x1E57, + [0x1E58] = 0x1E59, + [0x1E5A] = 0x1E5B, + [0x1E5C] = 0x1E5D, + [0x1E5E] = 0x1E5F, + [0x1E60] = 0x1E61, + [0x1E62] = 0x1E63, + [0x1E64] = 0x1E65, + [0x1E66] = 0x1E67, + [0x1E68] = 0x1E69, + [0x1E6A] = 0x1E6B, + [0x1E6C] = 0x1E6D, + [0x1E6E] = 0x1E6F, + [0x1E70] = 0x1E71, + [0x1E72] = 0x1E73, + [0x1E74] = 0x1E75, + [0x1E76] = 0x1E77, + [0x1E78] = 0x1E79, + [0x1E7A] = 0x1E7B, + [0x1E7C] = 0x1E7D, + [0x1E7E] = 0x1E7F, + [0x1E80] = 0x1E81, + [0x1E82] = 0x1E83, + [0x1E84] = 0x1E85, + [0x1E86] = 0x1E87, + [0x1E88] = 0x1E89, + [0x1E8A] = 0x1E8B, + [0x1E8C] = 0x1E8D, + [0x1E8E] = 0x1E8F, + [0x1E90] = 0x1E91, + [0x1E92] = 0x1E93, + [0x1E94] = 0x1E95, + [0x1E96] = { 0x0068, 0x0331 }, + [0x1E97] = { 0x0074, 0x0308 }, + [0x1E98] = { 0x0077, 0x030A }, + [0x1E99] = { 0x0079, 0x030A }, + [0x1E9A] = { 0x0061, 0x02BE }, + [0x1E9B] = 0x1E61, + [0x1E9E] = { 0x0073, 0x0073 }, + --1E9E; S;0x00DF, ; # LATIN CAPITAL LETTER SHARP S + [0x1EA0] = 0x1EA1, + [0x1EA2] = 0x1EA3, + [0x1EA4] = 0x1EA5, + [0x1EA6] = 0x1EA7, + [0x1EA8] = 0x1EA9, + [0x1EAA] = 0x1EAB, + [0x1EAC] = 0x1EAD, + [0x1EAE] = 0x1EAF, + [0x1EB0] = 0x1EB1, + [0x1EB2] = 0x1EB3, + [0x1EB4] = 0x1EB5, + [0x1EB6] = 0x1EB7, + [0x1EB8] = 0x1EB9, + [0x1EBA] = 0x1EBB, + [0x1EBC] = 0x1EBD, + [0x1EBE] = 0x1EBF, + [0x1EC0] = 0x1EC1, + [0x1EC2] = 0x1EC3, + [0x1EC4] = 0x1EC5, + [0x1EC6] = 0x1EC7, + [0x1EC8] = 0x1EC9, + [0x1ECA] = 0x1ECB, + [0x1ECC] = 0x1ECD, + [0x1ECE] = 0x1ECF, + [0x1ED0] = 0x1ED1, + [0x1ED2] = 0x1ED3, + [0x1ED4] = 0x1ED5, + [0x1ED6] = 0x1ED7, + [0x1ED8] = 0x1ED9, + [0x1EDA] = 0x1EDB, + [0x1EDC] = 0x1EDD, + [0x1EDE] = 0x1EDF, + [0x1EE0] = 0x1EE1, + [0x1EE2] = 0x1EE3, + [0x1EE4] = 0x1EE5, + [0x1EE6] = 0x1EE7, + [0x1EE8] = 0x1EE9, + [0x1EEA] = 0x1EEB, + [0x1EEC] = 0x1EED, + [0x1EEE] = 0x1EEF, + [0x1EF0] = 0x1EF1, + [0x1EF2] = 0x1EF3, + [0x1EF4] = 0x1EF5, + [0x1EF6] = 0x1EF7, + [0x1EF8] = 0x1EF9, + [0x1EFA] = 0x1EFB, + [0x1EFC] = 0x1EFD, + [0x1EFE] = 0x1EFF, + [0x1F08] = 0x1F00, + [0x1F09] = 0x1F01, + [0x1F0A] = 0x1F02, + [0x1F0B] = 0x1F03, + [0x1F0C] = 0x1F04, + [0x1F0D] = 0x1F05, + [0x1F0E] = 0x1F06, + [0x1F0F] = 0x1F07, + [0x1F18] = 0x1F10, + [0x1F19] = 0x1F11, + [0x1F1A] = 0x1F12, + [0x1F1B] = 0x1F13, + [0x1F1C] = 0x1F14, + [0x1F1D] = 0x1F15, + [0x1F28] = 0x1F20, + [0x1F29] = 0x1F21, + [0x1F2A] = 0x1F22, + [0x1F2B] = 0x1F23, + [0x1F2C] = 0x1F24, + [0x1F2D] = 0x1F25, + [0x1F2E] = 0x1F26, + [0x1F2F] = 0x1F27, + [0x1F38] = 0x1F30, + [0x1F39] = 0x1F31, + [0x1F3A] = 0x1F32, + [0x1F3B] = 0x1F33, + [0x1F3C] = 0x1F34, + [0x1F3D] = 0x1F35, + [0x1F3E] = 0x1F36, + [0x1F3F] = 0x1F37, + [0x1F48] = 0x1F40, + [0x1F49] = 0x1F41, + [0x1F4A] = 0x1F42, + [0x1F4B] = 0x1F43, + [0x1F4C] = 0x1F44, + [0x1F4D] = 0x1F45, + [0x1F50] = { 0x03C5, 0x0313 }, + [0x1F52] = { 0x03C5, 0x0313, 0x0300 }, + [0x1F54] = { 0x03C5, 0x0313, 0x0301 }, + [0x1F56] = { 0x03C5, 0x0313, 0x0342 }, + [0x1F59] = 0x1F51, + [0x1F5B] = 0x1F53, + [0x1F5D] = 0x1F55, + [0x1F5F] = 0x1F57, + [0x1F68] = 0x1F60, + [0x1F69] = 0x1F61, + [0x1F6A] = 0x1F62, + [0x1F6B] = 0x1F63, + [0x1F6C] = 0x1F64, + [0x1F6D] = 0x1F65, + [0x1F6E] = 0x1F66, + [0x1F6F] = 0x1F67, + [0x1F80] = { 0x1F00, 0x03B9 }, + [0x1F81] = { 0x1F01, 0x03B9 }, + [0x1F82] = { 0x1F02, 0x03B9 }, + [0x1F83] = { 0x1F03, 0x03B9 }, + [0x1F84] = { 0x1F04, 0x03B9 }, + [0x1F85] = { 0x1F05, 0x03B9 }, + [0x1F86] = { 0x1F06, 0x03B9 }, + [0x1F87] = { 0x1F07, 0x03B9 }, + [0x1F88] = { 0x1F00, 0x03B9 }, + --1F88; S;0x1F80, ; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI + [0x1F89] = { 0x1F01, 0x03B9 }, + --1F89; S;0x1F81, ; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI + [0x1F8A] = { 0x1F02, 0x03B9 }, + --1F8A; S;0x1F82, ; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI + [0x1F8B] = { 0x1F03, 0x03B9 }, + --1F8B; S;0x1F83, ; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI + [0x1F8C] = { 0x1F04, 0x03B9 }, + --1F8C; S;0x1F84, ; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI + [0x1F8D] = { 0x1F05, 0x03B9 }, + --1F8D; S;0x1F85, ; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI + [0x1F8E] = { 0x1F06, 0x03B9 }, + --1F8E; S;0x1F86, ; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI + [0x1F8F] = { 0x1F07, 0x03B9 }, + --1F8F; S;0x1F87, ; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI + [0x1F90] = { 0x1F20, 0x03B9 }, + [0x1F91] = { 0x1F21, 0x03B9 }, + [0x1F92] = { 0x1F22, 0x03B9 }, + [0x1F93] = { 0x1F23, 0x03B9 }, + [0x1F94] = { 0x1F24, 0x03B9 }, + [0x1F95] = { 0x1F25, 0x03B9 }, + [0x1F96] = { 0x1F26, 0x03B9 }, + [0x1F97] = { 0x1F27, 0x03B9 }, + [0x1F98] = { 0x1F20, 0x03B9 }, + --1F98; S;0x1F90, ; # GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI + [0x1F99] = { 0x1F21, 0x03B9 }, + --1F99; S;0x1F91, ; # GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI + [0x1F9A] = { 0x1F22, 0x03B9 }, + --1F9A; S;0x1F92, ; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI + [0x1F9B] = { 0x1F23, 0x03B9 }, + --1F9B; S;0x1F93, ; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI + [0x1F9C] = { 0x1F24, 0x03B9 }, + --1F9C; S;0x1F94, ; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI + [0x1F9D] = { 0x1F25, 0x03B9 }, + --1F9D; S;0x1F95, ; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI + [0x1F9E] = { 0x1F26, 0x03B9 }, + --1F9E; S;0x1F96, ; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI + [0x1F9F] = { 0x1F27, 0x03B9 }, + --1F9F; S;0x1F97, ; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI + [0x1FA0] = { 0x1F60, 0x03B9 }, + [0x1FA1] = { 0x1F61, 0x03B9 }, + [0x1FA2] = { 0x1F62, 0x03B9 }, + [0x1FA3] = { 0x1F63, 0x03B9 }, + [0x1FA4] = { 0x1F64, 0x03B9 }, + [0x1FA5] = { 0x1F65, 0x03B9 }, + [0x1FA6] = { 0x1F66, 0x03B9 }, + [0x1FA7] = { 0x1F67, 0x03B9 }, + [0x1FA8] = { 0x1F60, 0x03B9 }, + --1FA8; S;0x1FA0, ; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI + [0x1FA9] = { 0x1F61, 0x03B9 }, + --1FA9; S;0x1FA1, ; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI + [0x1FAA] = { 0x1F62, 0x03B9 }, + --1FAA; S;0x1FA2, ; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI + [0x1FAB] = { 0x1F63, 0x03B9 }, + --1FAB; S;0x1FA3, ; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI + [0x1FAC] = { 0x1F64, 0x03B9 }, + --1FAC; S;0x1FA4, ; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI + [0x1FAD] = { 0x1F65, 0x03B9 }, + --1FAD; S;0x1FA5, ; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI + [0x1FAE] = { 0x1F66, 0x03B9 }, + --1FAE; S;0x1FA6, ; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI + [0x1FAF] = { 0x1F67, 0x03B9 }, + --1FAF; S;0x1FA7, ; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI + [0x1FB2] = { 0x1F70, 0x03B9 }, + [0x1FB3] = { 0x03B1, 0x03B9 }, + [0x1FB4] = { 0x03AC, 0x03B9 }, + [0x1FB6] = { 0x03B1, 0x0342 }, + [0x1FB7] = { 0x03B1, 0x0342, 0x03B9 }, + [0x1FB8] = 0x1FB0, + [0x1FB9] = 0x1FB1, + [0x1FBA] = 0x1F70, + [0x1FBB] = 0x1F71, + [0x1FBC] = { 0x03B1, 0x03B9 }, + --1FBC; S;0x1FB3, ; # GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI + [0x1FBE] = 0x03B9, + [0x1FC2] = { 0x1F74, 0x03B9 }, + [0x1FC3] = { 0x03B7, 0x03B9 }, + [0x1FC4] = { 0x03AE, 0x03B9 }, + [0x1FC6] = { 0x03B7, 0x0342 }, + [0x1FC7] = { 0x03B7, 0x0342, 0x03B9 }, + [0x1FC8] = 0x1F72, + [0x1FC9] = 0x1F73, + [0x1FCA] = 0x1F74, + [0x1FCB] = 0x1F75, + [0x1FCC] = { 0x03B7, 0x03B9 }, + --1FCC; S;0x1FC3, ; # GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI + [0x1FD2] = { 0x03B9, 0x0308, 0x0300 }, + [0x1FD3] = { 0x03B9, 0x0308, 0x0301 }, + [0x1FD6] = { 0x03B9, 0x0342 }, + [0x1FD7] = { 0x03B9, 0x0308, 0x0342 }, + [0x1FD8] = 0x1FD0, + [0x1FD9] = 0x1FD1, + [0x1FDA] = 0x1F76, + [0x1FDB] = 0x1F77, + [0x1FE2] = { 0x03C5, 0x0308, 0x0300 }, + [0x1FE3] = { 0x03C5, 0x0308, 0x0301 }, + [0x1FE4] = { 0x03C1, 0x0313 }, + [0x1FE6] = { 0x03C5, 0x0342 }, + [0x1FE7] = { 0x03C5, 0x0308, 0x0342 }, + [0x1FE8] = 0x1FE0, + [0x1FE9] = 0x1FE1, + [0x1FEA] = 0x1F7A, + [0x1FEB] = 0x1F7B, + [0x1FEC] = 0x1FE5, + [0x1FF2] = { 0x1F7C, 0x03B9 }, + [0x1FF3] = { 0x03C9, 0x03B9 }, + [0x1FF4] = { 0x03CE, 0x03B9 }, + [0x1FF6] = { 0x03C9, 0x0342 }, + [0x1FF7] = { 0x03C9, 0x0342, 0x03B9 }, + [0x1FF8] = 0x1F78, + [0x1FF9] = 0x1F79, + [0x1FFA] = 0x1F7C, + [0x1FFB] = 0x1F7D, + [0x1FFC] = { 0x03C9, 0x03B9 }, + --1FFC; S;0x1FF3, ; # GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI + [0x2126] = 0x03C9, + [0x212A] = 0x006B, + [0x212B] = 0x00E5, + [0x2132] = 0x214E, + [0x2160] = 0x2170, + [0x2161] = 0x2171, + [0x2162] = 0x2172, + [0x2163] = 0x2173, + [0x2164] = 0x2174, + [0x2165] = 0x2175, + [0x2166] = 0x2176, + [0x2167] = 0x2177, + [0x2168] = 0x2178, + [0x2169] = 0x2179, + [0x216A] = 0x217A, + [0x216B] = 0x217B, + [0x216C] = 0x217C, + [0x216D] = 0x217D, + [0x216E] = 0x217E, + [0x216F] = 0x217F, + [0x2183] = 0x2184, + [0x24B6] = 0x24D0, + [0x24B7] = 0x24D1, + [0x24B8] = 0x24D2, + [0x24B9] = 0x24D3, + [0x24BA] = 0x24D4, + [0x24BB] = 0x24D5, + [0x24BC] = 0x24D6, + [0x24BD] = 0x24D7, + [0x24BE] = 0x24D8, + [0x24BF] = 0x24D9, + [0x24C0] = 0x24DA, + [0x24C1] = 0x24DB, + [0x24C2] = 0x24DC, + [0x24C3] = 0x24DD, + [0x24C4] = 0x24DE, + [0x24C5] = 0x24DF, + [0x24C6] = 0x24E0, + [0x24C7] = 0x24E1, + [0x24C8] = 0x24E2, + [0x24C9] = 0x24E3, + [0x24CA] = 0x24E4, + [0x24CB] = 0x24E5, + [0x24CC] = 0x24E6, + [0x24CD] = 0x24E7, + [0x24CE] = 0x24E8, + [0x24CF] = 0x24E9, + [0x2C00] = 0x2C30, + [0x2C01] = 0x2C31, + [0x2C02] = 0x2C32, + [0x2C03] = 0x2C33, + [0x2C04] = 0x2C34, + [0x2C05] = 0x2C35, + [0x2C06] = 0x2C36, + [0x2C07] = 0x2C37, + [0x2C08] = 0x2C38, + [0x2C09] = 0x2C39, + [0x2C0A] = 0x2C3A, + [0x2C0B] = 0x2C3B, + [0x2C0C] = 0x2C3C, + [0x2C0D] = 0x2C3D, + [0x2C0E] = 0x2C3E, + [0x2C0F] = 0x2C3F, + [0x2C10] = 0x2C40, + [0x2C11] = 0x2C41, + [0x2C12] = 0x2C42, + [0x2C13] = 0x2C43, + [0x2C14] = 0x2C44, + [0x2C15] = 0x2C45, + [0x2C16] = 0x2C46, + [0x2C17] = 0x2C47, + [0x2C18] = 0x2C48, + [0x2C19] = 0x2C49, + [0x2C1A] = 0x2C4A, + [0x2C1B] = 0x2C4B, + [0x2C1C] = 0x2C4C, + [0x2C1D] = 0x2C4D, + [0x2C1E] = 0x2C4E, + [0x2C1F] = 0x2C4F, + [0x2C20] = 0x2C50, + [0x2C21] = 0x2C51, + [0x2C22] = 0x2C52, + [0x2C23] = 0x2C53, + [0x2C24] = 0x2C54, + [0x2C25] = 0x2C55, + [0x2C26] = 0x2C56, + [0x2C27] = 0x2C57, + [0x2C28] = 0x2C58, + [0x2C29] = 0x2C59, + [0x2C2A] = 0x2C5A, + [0x2C2B] = 0x2C5B, + [0x2C2C] = 0x2C5C, + [0x2C2D] = 0x2C5D, + [0x2C2E] = 0x2C5E, + [0x2C60] = 0x2C61, + [0x2C62] = 0x026B, + [0x2C63] = 0x1D7D, + [0x2C64] = 0x027D, + [0x2C67] = 0x2C68, + [0x2C69] = 0x2C6A, + [0x2C6B] = 0x2C6C, + [0x2C6D] = 0x0251, + [0x2C6E] = 0x0271, + [0x2C6F] = 0x0250, + [0x2C70] = 0x0252, + [0x2C72] = 0x2C73, + [0x2C75] = 0x2C76, + [0x2C7E] = 0x023F, + [0x2C7F] = 0x0240, + [0x2C80] = 0x2C81, + [0x2C82] = 0x2C83, + [0x2C84] = 0x2C85, + [0x2C86] = 0x2C87, + [0x2C88] = 0x2C89, + [0x2C8A] = 0x2C8B, + [0x2C8C] = 0x2C8D, + [0x2C8E] = 0x2C8F, + [0x2C90] = 0x2C91, + [0x2C92] = 0x2C93, + [0x2C94] = 0x2C95, + [0x2C96] = 0x2C97, + [0x2C98] = 0x2C99, + [0x2C9A] = 0x2C9B, + [0x2C9C] = 0x2C9D, + [0x2C9E] = 0x2C9F, + [0x2CA0] = 0x2CA1, + [0x2CA2] = 0x2CA3, + [0x2CA4] = 0x2CA5, + [0x2CA6] = 0x2CA7, + [0x2CA8] = 0x2CA9, + [0x2CAA] = 0x2CAB, + [0x2CAC] = 0x2CAD, + [0x2CAE] = 0x2CAF, + [0x2CB0] = 0x2CB1, + [0x2CB2] = 0x2CB3, + [0x2CB4] = 0x2CB5, + [0x2CB6] = 0x2CB7, + [0x2CB8] = 0x2CB9, + [0x2CBA] = 0x2CBB, + [0x2CBC] = 0x2CBD, + [0x2CBE] = 0x2CBF, + [0x2CC0] = 0x2CC1, + [0x2CC2] = 0x2CC3, + [0x2CC4] = 0x2CC5, + [0x2CC6] = 0x2CC7, + [0x2CC8] = 0x2CC9, + [0x2CCA] = 0x2CCB, + [0x2CCC] = 0x2CCD, + [0x2CCE] = 0x2CCF, + [0x2CD0] = 0x2CD1, + [0x2CD2] = 0x2CD3, + [0x2CD4] = 0x2CD5, + [0x2CD6] = 0x2CD7, + [0x2CD8] = 0x2CD9, + [0x2CDA] = 0x2CDB, + [0x2CDC] = 0x2CDD, + [0x2CDE] = 0x2CDF, + [0x2CE0] = 0x2CE1, + [0x2CE2] = 0x2CE3, + [0x2CEB] = 0x2CEC, + [0x2CED] = 0x2CEE, + [0x2CF2] = 0x2CF3, + [0xA640] = 0xA641, + [0xA642] = 0xA643, + [0xA644] = 0xA645, + [0xA646] = 0xA647, + [0xA648] = 0xA649, + [0xA64A] = 0xA64B, + [0xA64C] = 0xA64D, + [0xA64E] = 0xA64F, + [0xA650] = 0xA651, + [0xA652] = 0xA653, + [0xA654] = 0xA655, + [0xA656] = 0xA657, + [0xA658] = 0xA659, + [0xA65A] = 0xA65B, + [0xA65C] = 0xA65D, + [0xA65E] = 0xA65F, + [0xA660] = 0xA661, + [0xA662] = 0xA663, + [0xA664] = 0xA665, + [0xA666] = 0xA667, + [0xA668] = 0xA669, + [0xA66A] = 0xA66B, + [0xA66C] = 0xA66D, + [0xA680] = 0xA681, + [0xA682] = 0xA683, + [0xA684] = 0xA685, + [0xA686] = 0xA687, + [0xA688] = 0xA689, + [0xA68A] = 0xA68B, + [0xA68C] = 0xA68D, + [0xA68E] = 0xA68F, + [0xA690] = 0xA691, + [0xA692] = 0xA693, + [0xA694] = 0xA695, + [0xA696] = 0xA697, + [0xA698] = 0xA699, + [0xA69A] = 0xA69B, + [0xA722] = 0xA723, + [0xA724] = 0xA725, + [0xA726] = 0xA727, + [0xA728] = 0xA729, + [0xA72A] = 0xA72B, + [0xA72C] = 0xA72D, + [0xA72E] = 0xA72F, + [0xA732] = 0xA733, + [0xA734] = 0xA735, + [0xA736] = 0xA737, + [0xA738] = 0xA739, + [0xA73A] = 0xA73B, + [0xA73C] = 0xA73D, + [0xA73E] = 0xA73F, + [0xA740] = 0xA741, + [0xA742] = 0xA743, + [0xA744] = 0xA745, + [0xA746] = 0xA747, + [0xA748] = 0xA749, + [0xA74A] = 0xA74B, + [0xA74C] = 0xA74D, + [0xA74E] = 0xA74F, + [0xA750] = 0xA751, + [0xA752] = 0xA753, + [0xA754] = 0xA755, + [0xA756] = 0xA757, + [0xA758] = 0xA759, + [0xA75A] = 0xA75B, + [0xA75C] = 0xA75D, + [0xA75E] = 0xA75F, + [0xA760] = 0xA761, + [0xA762] = 0xA763, + [0xA764] = 0xA765, + [0xA766] = 0xA767, + [0xA768] = 0xA769, + [0xA76A] = 0xA76B, + [0xA76C] = 0xA76D, + [0xA76E] = 0xA76F, + [0xA779] = 0xA77A, + [0xA77B] = 0xA77C, + [0xA77D] = 0x1D79, + [0xA77E] = 0xA77F, + [0xA780] = 0xA781, + [0xA782] = 0xA783, + [0xA784] = 0xA785, + [0xA786] = 0xA787, + [0xA78B] = 0xA78C, + [0xA78D] = 0x0265, + [0xA790] = 0xA791, + [0xA792] = 0xA793, + [0xA796] = 0xA797, + [0xA798] = 0xA799, + [0xA79A] = 0xA79B, + [0xA79C] = 0xA79D, + [0xA79E] = 0xA79F, + [0xA7A0] = 0xA7A1, + [0xA7A2] = 0xA7A3, + [0xA7A4] = 0xA7A5, + [0xA7A6] = 0xA7A7, + [0xA7A8] = 0xA7A9, + [0xA7AA] = 0x0266, + [0xA7AB] = 0x025C, + [0xA7AC] = 0x0261, + [0xA7AD] = 0x026C, + [0xA7AE] = 0x026A, + [0xA7B0] = 0x029E, + [0xA7B1] = 0x0287, + [0xA7B2] = 0x029D, + [0xA7B3] = 0xAB53, + [0xA7B4] = 0xA7B5, + [0xA7B6] = 0xA7B7, + [0xA7B8] = 0xA7B9, + [0xA7BA] = 0xA7BB, + [0xA7BC] = 0xA7BD, + [0xA7BE] = 0xA7BF, + [0xA7C2] = 0xA7C3, + [0xA7C4] = 0xA794, + [0xA7C5] = 0x0282, + [0xA7C6] = 0x1D8E, + [0xA7C7] = 0xA7C8, + [0xA7C9] = 0xA7CA, + [0xA7F5] = 0xA7F6, + [0xAB70] = 0x13A0, + [0xAB71] = 0x13A1, + [0xAB72] = 0x13A2, + [0xAB73] = 0x13A3, + [0xAB74] = 0x13A4, + [0xAB75] = 0x13A5, + [0xAB76] = 0x13A6, + [0xAB77] = 0x13A7, + [0xAB78] = 0x13A8, + [0xAB79] = 0x13A9, + [0xAB7A] = 0x13AA, + [0xAB7B] = 0x13AB, + [0xAB7C] = 0x13AC, + [0xAB7D] = 0x13AD, + [0xAB7E] = 0x13AE, + [0xAB7F] = 0x13AF, + [0xAB80] = 0x13B0, + [0xAB81] = 0x13B1, + [0xAB82] = 0x13B2, + [0xAB83] = 0x13B3, + [0xAB84] = 0x13B4, + [0xAB85] = 0x13B5, + [0xAB86] = 0x13B6, + [0xAB87] = 0x13B7, + [0xAB88] = 0x13B8, + [0xAB89] = 0x13B9, + [0xAB8A] = 0x13BA, + [0xAB8B] = 0x13BB, + [0xAB8C] = 0x13BC, + [0xAB8D] = 0x13BD, + [0xAB8E] = 0x13BE, + [0xAB8F] = 0x13BF, + [0xAB90] = 0x13C0, + [0xAB91] = 0x13C1, + [0xAB92] = 0x13C2, + [0xAB93] = 0x13C3, + [0xAB94] = 0x13C4, + [0xAB95] = 0x13C5, + [0xAB96] = 0x13C6, + [0xAB97] = 0x13C7, + [0xAB98] = 0x13C8, + [0xAB99] = 0x13C9, + [0xAB9A] = 0x13CA, + [0xAB9B] = 0x13CB, + [0xAB9C] = 0x13CC, + [0xAB9D] = 0x13CD, + [0xAB9E] = 0x13CE, + [0xAB9F] = 0x13CF, + [0xABA0] = 0x13D0, + [0xABA1] = 0x13D1, + [0xABA2] = 0x13D2, + [0xABA3] = 0x13D3, + [0xABA4] = 0x13D4, + [0xABA5] = 0x13D5, + [0xABA6] = 0x13D6, + [0xABA7] = 0x13D7, + [0xABA8] = 0x13D8, + [0xABA9] = 0x13D9, + [0xABAA] = 0x13DA, + [0xABAB] = 0x13DB, + [0xABAC] = 0x13DC, + [0xABAD] = 0x13DD, + [0xABAE] = 0x13DE, + [0xABAF] = 0x13DF, + [0xABB0] = 0x13E0, + [0xABB1] = 0x13E1, + [0xABB2] = 0x13E2, + [0xABB3] = 0x13E3, + [0xABB4] = 0x13E4, + [0xABB5] = 0x13E5, + [0xABB6] = 0x13E6, + [0xABB7] = 0x13E7, + [0xABB8] = 0x13E8, + [0xABB9] = 0x13E9, + [0xABBA] = 0x13EA, + [0xABBB] = 0x13EB, + [0xABBC] = 0x13EC, + [0xABBD] = 0x13ED, + [0xABBE] = 0x13EE, + [0xABBF] = 0x13EF, + [0xFB00] = { 0x0066, 0x0066 }, + [0xFB01] = { 0x0066, 0x0069 }, + [0xFB02] = { 0x0066, 0x006C }, + [0xFB03] = { 0x0066, 0x0066, 0x0069 }, + [0xFB04] = { 0x0066, 0x0066, 0x006C }, + [0xFB05] = { 0x0073, 0x0074 }, + [0xFB06] = { 0x0073, 0x0074 }, + [0xFB13] = { 0x0574, 0x0576 }, + [0xFB14] = { 0x0574, 0x0565 }, + [0xFB15] = { 0x0574, 0x056B }, + [0xFB16] = { 0x057E, 0x0576 }, + [0xFB17] = { 0x0574, 0x056D }, + [0xFF21] = 0xFF41, + [0xFF22] = 0xFF42, + [0xFF23] = 0xFF43, + [0xFF24] = 0xFF44, + [0xFF25] = 0xFF45, + [0xFF26] = 0xFF46, + [0xFF27] = 0xFF47, + [0xFF28] = 0xFF48, + [0xFF29] = 0xFF49, + [0xFF2A] = 0xFF4A, + [0xFF2B] = 0xFF4B, + [0xFF2C] = 0xFF4C, + [0xFF2D] = 0xFF4D, + [0xFF2E] = 0xFF4E, + [0xFF2F] = 0xFF4F, + [0xFF30] = 0xFF50, + [0xFF31] = 0xFF51, + [0xFF32] = 0xFF52, + [0xFF33] = 0xFF53, + [0xFF34] = 0xFF54, + [0xFF35] = 0xFF55, + [0xFF36] = 0xFF56, + [0xFF37] = 0xFF57, + [0xFF38] = 0xFF58, + [0xFF39] = 0xFF59, + [0xFF3A] = 0xFF5A, + [0x10400] = 0x10428, + [0x10401] = 0x10429, + [0x10402] = 0x1042A, + [0x10403] = 0x1042B, + [0x10404] = 0x1042C, + [0x10405] = 0x1042D, + [0x10406] = 0x1042E, + [0x10407] = 0x1042F, + [0x10408] = 0x10430, + [0x10409] = 0x10431, + [0x1040A] = 0x10432, + [0x1040B] = 0x10433, + [0x1040C] = 0x10434, + [0x1040D] = 0x10435, + [0x1040E] = 0x10436, + [0x1040F] = 0x10437, + [0x10410] = 0x10438, + [0x10411] = 0x10439, + [0x10412] = 0x1043A, + [0x10413] = 0x1043B, + [0x10414] = 0x1043C, + [0x10415] = 0x1043D, + [0x10416] = 0x1043E, + [0x10417] = 0x1043F, + [0x10418] = 0x10440, + [0x10419] = 0x10441, + [0x1041A] = 0x10442, + [0x1041B] = 0x10443, + [0x1041C] = 0x10444, + [0x1041D] = 0x10445, + [0x1041E] = 0x10446, + [0x1041F] = 0x10447, + [0x10420] = 0x10448, + [0x10421] = 0x10449, + [0x10422] = 0x1044A, + [0x10423] = 0x1044B, + [0x10424] = 0x1044C, + [0x10425] = 0x1044D, + [0x10426] = 0x1044E, + [0x10427] = 0x1044F, + [0x104B0] = 0x104D8, + [0x104B1] = 0x104D9, + [0x104B2] = 0x104DA, + [0x104B3] = 0x104DB, + [0x104B4] = 0x104DC, + [0x104B5] = 0x104DD, + [0x104B6] = 0x104DE, + [0x104B7] = 0x104DF, + [0x104B8] = 0x104E0, + [0x104B9] = 0x104E1, + [0x104BA] = 0x104E2, + [0x104BB] = 0x104E3, + [0x104BC] = 0x104E4, + [0x104BD] = 0x104E5, + [0x104BE] = 0x104E6, + [0x104BF] = 0x104E7, + [0x104C0] = 0x104E8, + [0x104C1] = 0x104E9, + [0x104C2] = 0x104EA, + [0x104C3] = 0x104EB, + [0x104C4] = 0x104EC, + [0x104C5] = 0x104ED, + [0x104C6] = 0x104EE, + [0x104C7] = 0x104EF, + [0x104C8] = 0x104F0, + [0x104C9] = 0x104F1, + [0x104CA] = 0x104F2, + [0x104CB] = 0x104F3, + [0x104CC] = 0x104F4, + [0x104CD] = 0x104F5, + [0x104CE] = 0x104F6, + [0x104CF] = 0x104F7, + [0x104D0] = 0x104F8, + [0x104D1] = 0x104F9, + [0x104D2] = 0x104FA, + [0x104D3] = 0x104FB, + [0x10C80] = 0x10CC0, + [0x10C81] = 0x10CC1, + [0x10C82] = 0x10CC2, + [0x10C83] = 0x10CC3, + [0x10C84] = 0x10CC4, + [0x10C85] = 0x10CC5, + [0x10C86] = 0x10CC6, + [0x10C87] = 0x10CC7, + [0x10C88] = 0x10CC8, + [0x10C89] = 0x10CC9, + [0x10C8A] = 0x10CCA, + [0x10C8B] = 0x10CCB, + [0x10C8C] = 0x10CCC, + [0x10C8D] = 0x10CCD, + [0x10C8E] = 0x10CCE, + [0x10C8F] = 0x10CCF, + [0x10C90] = 0x10CD0, + [0x10C91] = 0x10CD1, + [0x10C92] = 0x10CD2, + [0x10C93] = 0x10CD3, + [0x10C94] = 0x10CD4, + [0x10C95] = 0x10CD5, + [0x10C96] = 0x10CD6, + [0x10C97] = 0x10CD7, + [0x10C98] = 0x10CD8, + [0x10C99] = 0x10CD9, + [0x10C9A] = 0x10CDA, + [0x10C9B] = 0x10CDB, + [0x10C9C] = 0x10CDC, + [0x10C9D] = 0x10CDD, + [0x10C9E] = 0x10CDE, + [0x10C9F] = 0x10CDF, + [0x10CA0] = 0x10CE0, + [0x10CA1] = 0x10CE1, + [0x10CA2] = 0x10CE2, + [0x10CA3] = 0x10CE3, + [0x10CA4] = 0x10CE4, + [0x10CA5] = 0x10CE5, + [0x10CA6] = 0x10CE6, + [0x10CA7] = 0x10CE7, + [0x10CA8] = 0x10CE8, + [0x10CA9] = 0x10CE9, + [0x10CAA] = 0x10CEA, + [0x10CAB] = 0x10CEB, + [0x10CAC] = 0x10CEC, + [0x10CAD] = 0x10CED, + [0x10CAE] = 0x10CEE, + [0x10CAF] = 0x10CEF, + [0x10CB0] = 0x10CF0, + [0x10CB1] = 0x10CF1, + [0x10CB2] = 0x10CF2, + [0x118A0] = 0x118C0, + [0x118A1] = 0x118C1, + [0x118A2] = 0x118C2, + [0x118A3] = 0x118C3, + [0x118A4] = 0x118C4, + [0x118A5] = 0x118C5, + [0x118A6] = 0x118C6, + [0x118A7] = 0x118C7, + [0x118A8] = 0x118C8, + [0x118A9] = 0x118C9, + [0x118AA] = 0x118CA, + [0x118AB] = 0x118CB, + [0x118AC] = 0x118CC, + [0x118AD] = 0x118CD, + [0x118AE] = 0x118CE, + [0x118AF] = 0x118CF, + [0x118B0] = 0x118D0, + [0x118B1] = 0x118D1, + [0x118B2] = 0x118D2, + [0x118B3] = 0x118D3, + [0x118B4] = 0x118D4, + [0x118B5] = 0x118D5, + [0x118B6] = 0x118D6, + [0x118B7] = 0x118D7, + [0x118B8] = 0x118D8, + [0x118B9] = 0x118D9, + [0x118BA] = 0x118DA, + [0x118BB] = 0x118DB, + [0x118BC] = 0x118DC, + [0x118BD] = 0x118DD, + [0x118BE] = 0x118DE, + [0x118BF] = 0x118DF, + [0x16E40] = 0x16E60, + [0x16E41] = 0x16E61, + [0x16E42] = 0x16E62, + [0x16E43] = 0x16E63, + [0x16E44] = 0x16E64, + [0x16E45] = 0x16E65, + [0x16E46] = 0x16E66, + [0x16E47] = 0x16E67, + [0x16E48] = 0x16E68, + [0x16E49] = 0x16E69, + [0x16E4A] = 0x16E6A, + [0x16E4B] = 0x16E6B, + [0x16E4C] = 0x16E6C, + [0x16E4D] = 0x16E6D, + [0x16E4E] = 0x16E6E, + [0x16E4F] = 0x16E6F, + [0x16E50] = 0x16E70, + [0x16E51] = 0x16E71, + [0x16E52] = 0x16E72, + [0x16E53] = 0x16E73, + [0x16E54] = 0x16E74, + [0x16E55] = 0x16E75, + [0x16E56] = 0x16E76, + [0x16E57] = 0x16E77, + [0x16E58] = 0x16E78, + [0x16E59] = 0x16E79, + [0x16E5A] = 0x16E7A, + [0x16E5B] = 0x16E7B, + [0x16E5C] = 0x16E7C, + [0x16E5D] = 0x16E7D, + [0x16E5E] = 0x16E7E, + [0x16E5F] = 0x16E7F, + [0x1E900] = 0x1E922, + [0x1E901] = 0x1E923, + [0x1E902] = 0x1E924, + [0x1E903] = 0x1E925, + [0x1E904] = 0x1E926, + [0x1E905] = 0x1E927, + [0x1E906] = 0x1E928, + [0x1E907] = 0x1E929, + [0x1E908] = 0x1E92A, + [0x1E909] = 0x1E92B, + [0x1E90A] = 0x1E92C, + [0x1E90B] = 0x1E92D, + [0x1E90C] = 0x1E92E, + [0x1E90D] = 0x1E92F, + [0x1E90E] = 0x1E930, + [0x1E90F] = 0x1E931, + [0x1E910] = 0x1E932, + [0x1E911] = 0x1E933, + [0x1E912] = 0x1E934, + [0x1E913] = 0x1E935, + [0x1E914] = 0x1E936, + [0x1E915] = 0x1E937, + [0x1E916] = 0x1E938, + [0x1E917] = 0x1E939, + [0x1E918] = 0x1E93A, + [0x1E919] = 0x1E93B, + [0x1E91A] = 0x1E93C, + [0x1E91B] = 0x1E93D, + [0x1E91C] = 0x1E93E, + [0x1E91D] = 0x1E93F, + [0x1E91E] = 0x1E940, + [0x1E91F] = 0x1E941, + [0x1E920] = 0x1E942, + [0x1E921] = 0x1E943, +} +for k, v in pairs(utf8_case_conv_utl) do utf8_case_conv_ltu[v] = k end + +return UTFString diff --git a/Capy64/Assets/Lua/README.txt b/Capy64/Assets/Lua/README.txt new file mode 100644 index 0000000..6e32c38 --- /dev/null +++ b/Capy64/Assets/Lua/README.txt @@ -0,0 +1,5 @@ +If you are looking for your data directory look in: + +Windows: %APPDATA%\Capy64\data +Mac: $HOME/.local/share/Capy64/data +Linux: $HOME/.local/share/Capy64/data \ No newline at end of file diff --git a/Capy64/Assets/bios.lua b/Capy64/Assets/Lua/bios.lua similarity index 75% rename from Capy64/Assets/bios.lua rename to Capy64/Assets/Lua/bios.lua index 21918ea..e1bbcb5 100644 --- a/Capy64/Assets/bios.lua +++ b/Capy64/Assets/Lua/bios.lua @@ -19,13 +19,8 @@ local gpu = require("gpu") local fs = require("fs") local machine = require("machine") local audio = require("audio") -local http = require("http") local event = require("event") - -local INDEX_URL = "https://raw.github.com/Ale32bit/CapyOS/deploy/index.json" -local JSON_URL = "https://raw.github.com/Ale32bit/CapyOS/main/lib/json.lua" - local bootSleep = 2000 local bg = 0x0 local fg = 0xffffff @@ -95,64 +90,11 @@ local function printError( text ) term.setForeground(0xffffff) end -local function hget(url, headers) - local response, err = http.requestAsync(url, nul, headers, {binary = true}):await() - - if not response then - return nil, err - end - - local content = response.content:read("a") - response.content:close() - return content, response -end - local function promptKey() print("Press any key to continue") event.pull("key_down") end -local function installOS() - term.clear() - term.setPos(1, 1) - - print("Installing CapyOS...") - - local jsonLib, par = hget(JSON_URL) - if not jsonLib then - printError(par) - promptKey() - return - end - - local json = load(jsonLib)() - local indexData, par = hget(INDEX_URL) - if not indexData then - printError(par) - promptKey() - return - end - local index = json.decode(indexData) - - for i, v in ipairs(index) do - local dirname = fs.getDir(v.path) - if not fs.exists(dirname) then - fs.makeDir(dirname) - end - print("Downloading " .. v.path) - local fileContent = hget(v.raw_url) - local f = fs.open(v.path, "w") - f:write(fileContent) - f:close() - print("Written to " .. v.path) - end - - flagInstalled() - - print("CapyOS installed!") - promptKey() -end - term.setBlink(false) local function setupScreen() @@ -245,10 +187,6 @@ end audio.beep(1000, 0.2, 0.2, "square") -if shouldInstallOS() then - installOS() -end - bootScreen() term.clear() diff --git a/Capy64/Capy64.csproj b/Capy64/Capy64.csproj index e012d5b..0bcec27 100644 --- a/Capy64/Capy64.csproj +++ b/Capy64/Capy64.csproj @@ -26,9 +26,9 @@ - + PreserveNewest - + @@ -46,17 +46,15 @@ - - - PreserveNewest - - - + + + + diff --git a/Capy64/Runtime/RuntimeManager.cs b/Capy64/Runtime/RuntimeManager.cs index edb12bd..9ef93fb 100644 --- a/Capy64/Runtime/RuntimeManager.cs +++ b/Capy64/Runtime/RuntimeManager.cs @@ -97,6 +97,8 @@ internal class RuntimeManager : IComponent { _game.Discord.SetPresence("Booting up..."); + InstallOS(false); + luaState = new LuaState(); _game.LuaRuntime = luaState; luaState.Init(); @@ -114,16 +116,13 @@ internal class RuntimeManager : IComponent luaState.Thread.PushCFunction(L_OpenDataFolder); luaState.Thread.SetGlobal("openDataFolder"); - luaState.Thread.PushCFunction(L_ShouldInstallOS); - luaState.Thread.SetGlobal("shouldInstallOS"); - - luaState.Thread.PushCFunction(L_FlagInstalled); - luaState.Thread.SetGlobal("flagInstalled"); + luaState.Thread.PushCFunction(L_InstallOS); + luaState.Thread.SetGlobal("installOS"); luaState.Thread.PushCFunction(L_Exit); luaState.Thread.SetGlobal("exit"); - var status = luaState.Thread.LoadFile("Assets/bios.lua"); + var status = luaState.Thread.LoadFile("Assets/Lua/bios.lua"); if (status != LuaStatus.OK) { throw new LuaException(luaState.Thread.ToString(-1)); @@ -132,8 +131,6 @@ internal class RuntimeManager : IComponent private void InitOS() { - _game.Discord.SetPresence("On CapyOS"); - luaState = new LuaState(); _game.LuaRuntime = luaState; luaState.Init(); @@ -148,6 +145,11 @@ internal class RuntimeManager : IComponent emitter.Register(); + if (!File.Exists(Path.Combine(FileSystem.DataPath, "init.lua"))) + { + throw new LuaException("Operating System not found\nMissing init.lua"); + } + var initContent = File.ReadAllText(Path.Combine(FileSystem.DataPath, "init.lua")); var status = luaState.Thread.LoadString(initContent, "=init.lua"); if (status != LuaStatus.OK) @@ -173,6 +175,16 @@ internal class RuntimeManager : IComponent _game.Exit(); } + public static void InstallOS(bool force = false) + { + var installedFilePath = Path.Combine(Capy64.AppDataPath, ".installed"); + if (!File.Exists(installedFilePath) || force) + { + FileSystem.CopyDirectory("Assets/Lua/CapyOS", FileSystem.DataPath, true, true); + File.Create(installedFilePath).Dispose(); + } + } + private static int L_OpenDataFolder(IntPtr state) { var path = FileSystem.DataPath; @@ -189,22 +201,9 @@ internal class RuntimeManager : IComponent return 0; } - private static int L_ShouldInstallOS(IntPtr state) + private static int L_InstallOS(IntPtr state) { - var L = Lua.FromIntPtr(state); - var installedFilePath = Path.Combine(Capy64.AppDataPath, ".installed"); - - L.PushBoolean(!File.Exists(installedFilePath)); - - return 1; - } - - private static int L_FlagInstalled(IntPtr state) - { - var installedFilePath = Path.Combine(Capy64.AppDataPath, ".installed"); - if (!File.Exists(installedFilePath)) - File.Create(installedFilePath).Dispose(); - + InstallOS(true); return 0; }