mirror of
https://github.com/Ale32bit/Capy64.git
synced 2025-01-18 10:36:44 +00:00
Rewrite everything
This commit is contained in:
parent
bcb358ed9d
commit
8b5fa96a74
38 changed files with 469 additions and 4154 deletions
|
@ -1,17 +0,0 @@
|
|||
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)
|
|
@ -1,5 +0,0 @@
|
|||
local term = require("term")
|
||||
local colors = require("colors")
|
||||
term.setBackground(colors.black)
|
||||
term.clear()
|
||||
term.setPos(1, 1)
|
|
@ -1 +0,0 @@
|
|||
shell.exit()
|
|
@ -1,94 +0,0 @@
|
|||
-- 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 <close> = 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
|
|
@ -1,73 +0,0 @@
|
|||
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 <close> = 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.sleep(10)
|
||||
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.sleep(100)
|
||||
end
|
||||
end
|
||||
|
||||
parallel.waitForAny(draw, melt, random)
|
|
@ -1,17 +0,0 @@
|
|||
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)
|
|
@ -1,25 +0,0 @@
|
|||
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
|
|
@ -1,75 +0,0 @@
|
|||
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
|
|
@ -1,14 +0,0 @@
|
|||
local fs = require("fs")
|
||||
local args = { ... }
|
||||
|
||||
if #args == 0 then
|
||||
print("Usage: mkdir <directory>")
|
||||
return
|
||||
end
|
||||
|
||||
local dir = shell.resolve(args[1])
|
||||
if fs.exists(dir) then
|
||||
error("Path already exists", 0)
|
||||
end
|
||||
|
||||
fs.makeDir(dir)
|
|
@ -1 +0,0 @@
|
|||
print(shell.getDir())
|
|
@ -1,8 +0,0 @@
|
|||
local timer = require("timer")
|
||||
local machine = require("machine")
|
||||
|
||||
print("Goodbye!")
|
||||
|
||||
timer.sleep(1000)
|
||||
|
||||
machine.reboot()
|
|
@ -1,10 +0,0 @@
|
|||
local fs = require("fs")
|
||||
|
||||
local args = { ... }
|
||||
if #args == 0 then
|
||||
print("Usage: rm <file>")
|
||||
return
|
||||
end
|
||||
|
||||
local file = shell.resolve(args[1])
|
||||
fs.delete(file, true)
|
|
@ -1,143 +0,0 @@
|
|||
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
|
|
@ -1,8 +0,0 @@
|
|||
local timer = require("timer")
|
||||
local machine = require("machine")
|
||||
|
||||
print("Goodbye!")
|
||||
|
||||
timer.sleep(1000)
|
||||
|
||||
machine.shutdown()
|
|
@ -1 +0,0 @@
|
|||
print(string.format("%s @ %s - %s", os.version(), _HOST, _VERSION))
|
|
@ -1,34 +0,0 @@
|
|||
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 <url> [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 <close>, err = http.get(args[1], nil, {
|
||||
binary = true,
|
||||
})
|
||||
if not response then
|
||||
error(err, 0)
|
||||
end
|
||||
|
||||
local file <close> = fs.open(outputPath, "wb")
|
||||
file:write(response:readAll())
|
||||
file:close()
|
||||
response:close()
|
||||
|
||||
print("File written to " .. outputPath)
|
|
@ -1,3 +0,0 @@
|
|||
package.path = "/lib/?.lua;/lib/?/init.lua;" .. package.path
|
||||
|
||||
_G.io = require("io")
|
|
@ -1,15 +0,0 @@
|
|||
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
|
|
@ -1,90 +0,0 @@
|
|||
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 requestId = http.requestAsync(url, body, headers, options)
|
||||
local ev, id, data, info
|
||||
repeat
|
||||
ev, id, data, info = event.pull("http_response", "http_failure")
|
||||
until id == requestId
|
||||
|
||||
if ev == "http_failure" then
|
||||
return nil, data
|
||||
end
|
||||
|
||||
return data, info
|
||||
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 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 requestId = http.websocketAsync(url, headers)
|
||||
local ev, id, par
|
||||
repeat
|
||||
ev, id, par = event.pull("websocket_connect", "websocket_failure")
|
||||
until id == requestId
|
||||
|
||||
if ev == "http_failure" then
|
||||
return nil, par
|
||||
end
|
||||
|
||||
return buildWebsocketHandle(par)
|
||||
end
|
|
@ -1,14 +0,0 @@
|
|||
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
|
|
@ -1,15 +0,0 @@
|
|||
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()
|
Binary file not shown.
Before Width: | Height: | Size: 48 KiB |
|
@ -1,47 +0,0 @@
|
|||
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.setSize(51, 19)
|
||||
gpu.setScale(2)
|
||||
|
||||
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
|
|
@ -1,94 +0,0 @@
|
|||
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;
|
|
@ -1,52 +0,0 @@
|
|||
-- 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
|
|
@ -1,282 +0,0 @@
|
|||
local expect = require("expect").expect
|
||||
local event = require("event")
|
||||
local term = require("term")
|
||||
|
||||
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 = 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 == "paste" 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 + (#par1 - 1))
|
||||
end
|
||||
|
||||
elseif evt == "key_down" then
|
||||
if par2 == "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 par2 == "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 par2 == "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 par2 == "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 par2 == "left" then
|
||||
if cursor_pos < #buffer then
|
||||
clearCompletion()
|
||||
cursor_pos = cursor_pos + 1
|
||||
end
|
||||
|
||||
elseif par2 == "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 par2 == "tab" then
|
||||
if comp_id > 0 then
|
||||
dirty = true
|
||||
buffer = buffer .. completions[comp_id]
|
||||
end
|
||||
|
||||
elseif par2 == "home" then
|
||||
cursor_pos = #buffer
|
||||
|
||||
elseif par2 == "end" then
|
||||
cursor_pos = 0
|
||||
|
||||
elseif par2 == "enter" then
|
||||
clearCompletion()
|
||||
print()
|
||||
break
|
||||
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
|
|
@ -1,61 +0,0 @@
|
|||
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
|
File diff suppressed because it is too large
Load diff
|
@ -4,6 +4,14 @@ 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 BASE_URL = "https://api.github.com/repos/%s/contents/%s"
|
||||
local REPOSITORY = "Capy64/CapyOS"
|
||||
local JSON_URL = "https://raw.githubusercontent.com/Capy64/CapyOS/main/lib/json.lua"
|
||||
-- This token only has read-only access to repository files
|
||||
local GITHUB_TOKEN = "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"
|
||||
|
||||
local bootSleep = 2000
|
||||
local bg = 0x0
|
||||
|
@ -16,6 +24,8 @@ term.clear()
|
|||
term.setSize(51, 19)
|
||||
gpu.setScale(2)
|
||||
|
||||
local w, h = term.getSize()
|
||||
|
||||
local function sleep(n)
|
||||
local timerId = timer.start(n)
|
||||
repeat
|
||||
|
@ -54,7 +64,96 @@ local function drawVendorImage()
|
|||
end
|
||||
end
|
||||
|
||||
local w, h = term.getSize()
|
||||
local nPrint = print
|
||||
local function print( text )
|
||||
local x, y = term.getPos()
|
||||
term.write(tostring(text))
|
||||
if y == h then
|
||||
term.scroll(1)
|
||||
term.setPos(1, y)
|
||||
else
|
||||
term.setPos(1, y + 1)
|
||||
end
|
||||
end
|
||||
|
||||
local function printError( text )
|
||||
term.setForeground(0xff0000)
|
||||
print(text)
|
||||
term.setForeground(0xffffff)
|
||||
end
|
||||
|
||||
local function hget(url, headers)
|
||||
local requestId = http.requestAsync(url, nil, headers, {binary = true})
|
||||
|
||||
local ev, rId, par, info
|
||||
repeat
|
||||
ev, rId, par, info = event.pull("http_response", "http_failure")
|
||||
until rId == requestId
|
||||
|
||||
if ev == "http_failure" then
|
||||
return nil, par
|
||||
end
|
||||
local content = par:read("a")
|
||||
par:close()
|
||||
return content, info
|
||||
end
|
||||
|
||||
local function promptKey()
|
||||
print("Press any key to continue")
|
||||
event.pull("key_down")
|
||||
end
|
||||
|
||||
local function repo(path)
|
||||
return string.format(BASE_URL, REPOSITORY, path or "")
|
||||
end
|
||||
|
||||
local json
|
||||
local function recursiveDownload(path)
|
||||
path = path or ""
|
||||
local index = json.decode(hget(repo(path), {
|
||||
Authorization = "Bearer " .. GITHUB_TOKEN
|
||||
}))
|
||||
|
||||
|
||||
for i, v in ipairs(index) do
|
||||
if v.type == "dir" then
|
||||
if not fs.exists(v.path) then
|
||||
fs.makeDir(v.path)
|
||||
end
|
||||
recursiveDownload(v.path)
|
||||
elseif v.type == "file" then
|
||||
print("Downloading " .. v.path)
|
||||
local fileContent = hget(v.download_url)
|
||||
local f = fs.open(v.path, "wb")
|
||||
f:write(fileContent)
|
||||
f:close()
|
||||
print("Written to " .. v.path)
|
||||
end
|
||||
end
|
||||
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
|
||||
|
||||
json = load(jsonLib)()
|
||||
|
||||
recursiveDownload()
|
||||
|
||||
flagInstalled()
|
||||
|
||||
print("CapyOS installed!")
|
||||
promptKey()
|
||||
end
|
||||
|
||||
term.setBlink(false)
|
||||
|
||||
|
@ -148,6 +247,10 @@ end
|
|||
|
||||
audio.beep(1000, 0.4, 0.2)
|
||||
|
||||
if shouldInstallOS() then
|
||||
installOS()
|
||||
end
|
||||
|
||||
bootScreen()
|
||||
|
||||
term.clear()
|
|
@ -1,11 +1,12 @@
|
|||
using Capy64.API;
|
||||
using Capy64.Runtime.Objects.Handlers;
|
||||
using Capy64.Runtime.Extensions;
|
||||
using KeraLua;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Capy64.Runtime.Objects;
|
||||
|
||||
namespace Capy64.Runtime.Libraries;
|
||||
|
||||
|
@ -491,8 +492,7 @@ public class FileSystem : IPlugin
|
|||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
var path = Resolve(L.CheckString(1));
|
||||
var mode = L.CheckString(2);
|
||||
|
||||
var mode = L.OptString(2, "r");
|
||||
|
||||
var errorMessage = "invalid file mode";
|
||||
if (mode.Length < 1 && mode.Length > 2)
|
||||
|
@ -542,25 +542,8 @@ public class FileSystem : IPlugin
|
|||
}
|
||||
|
||||
var fileStream = File.Open(path, fileMode, fileAccess, FileShare.ReadWrite);
|
||||
|
||||
if (fileAccess == FileAccess.Read)
|
||||
{
|
||||
if (binaryMode)
|
||||
BinaryReadHandle.Push(L, new(fileStream));
|
||||
else
|
||||
ReadHandle.Push(L, new(fileStream));
|
||||
}
|
||||
else if (fileAccess == FileAccess.Write)
|
||||
{
|
||||
if (binaryMode)
|
||||
BinaryWriteHandle.Push(L, new(fileStream));
|
||||
else
|
||||
WriteHandle.Push(L, new(fileStream));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
L.PushObject(fileStream);
|
||||
L.SetMetaTable(FileHandle.ObjectType);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
using Capy64.API;
|
||||
using Capy64.Runtime.Extensions;
|
||||
using Capy64.Runtime.Objects.Handlers;
|
||||
using Capy64.Runtime.Objects;
|
||||
using KeraLua;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.WebSockets;
|
||||
|
@ -209,10 +210,12 @@ public class HTTP : IPlugin
|
|||
LK.PushInteger(requestId);
|
||||
|
||||
// arg 2, response data
|
||||
if ((bool)options["binary"])
|
||||
L.PushObject(stream);
|
||||
L.SetMetaTable(FileHandle.ObjectType);
|
||||
/*if ((bool)options["binary"])
|
||||
BinaryReadHandle.Push(LK, new(stream));
|
||||
else
|
||||
ReadHandle.Push(LK, new(stream));
|
||||
ReadHandle.Push(LK, new(stream));*/
|
||||
|
||||
// arg 3, response info
|
||||
LK.NewTable();
|
||||
|
|
333
Capy64/Runtime/Objects/FileHandle.cs
Normal file
333
Capy64/Runtime/Objects/FileHandle.cs
Normal file
|
@ -0,0 +1,333 @@
|
|||
using Capy64.API;
|
||||
using KeraLua;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Capy64.Runtime.Objects;
|
||||
|
||||
public class FileHandle : IPlugin
|
||||
{
|
||||
public const string ObjectType = "file";
|
||||
|
||||
private static LuaRegister[] Methods = new LuaRegister[]
|
||||
{
|
||||
new()
|
||||
{
|
||||
name = "read",
|
||||
function = L_Read,
|
||||
},
|
||||
new()
|
||||
{
|
||||
name = "write",
|
||||
function = L_Write,
|
||||
},
|
||||
new()
|
||||
{
|
||||
name = "lines",
|
||||
function = L_Lines,
|
||||
},
|
||||
new()
|
||||
{
|
||||
name = "flush",
|
||||
function = L_Flush,
|
||||
},
|
||||
new()
|
||||
{
|
||||
name = "seek",
|
||||
function = L_Seek,
|
||||
},
|
||||
new()
|
||||
{
|
||||
name = "close",
|
||||
function = L_Close,
|
||||
},
|
||||
new(),
|
||||
};
|
||||
|
||||
private static LuaRegister[] MetaMethods = new LuaRegister[]
|
||||
{
|
||||
new()
|
||||
{
|
||||
name = "__index",
|
||||
},
|
||||
new()
|
||||
{
|
||||
name = "__gc",
|
||||
function = F_GC,
|
||||
},
|
||||
new()
|
||||
{
|
||||
name = "__close",
|
||||
function = F_GC,
|
||||
},
|
||||
new()
|
||||
{
|
||||
name = "__tostring",
|
||||
function = F_ToString,
|
||||
},
|
||||
|
||||
new(),
|
||||
};
|
||||
|
||||
public void LuaInit(Lua L)
|
||||
{
|
||||
CreateMeta(L);
|
||||
}
|
||||
|
||||
public static void CreateMeta(Lua L)
|
||||
{
|
||||
L.NewMetaTable(ObjectType);
|
||||
L.SetFuncs(MetaMethods, 0);
|
||||
L.NewLibTable(Methods);
|
||||
L.SetFuncs(Methods, 0);
|
||||
L.SetField(-2, "__index");
|
||||
L.Pop(1);
|
||||
}
|
||||
|
||||
private static char CheckMode(string mode)
|
||||
{
|
||||
var modes = "nlLa";
|
||||
var i = modes.IndexOf(mode.TrimStart('*')[0]);
|
||||
return modes[i];
|
||||
}
|
||||
|
||||
private static Stream ToStream(Lua L, bool gc = false)
|
||||
{
|
||||
return L.CheckObject<Stream>(1, ObjectType, gc);
|
||||
}
|
||||
|
||||
private static Stream CheckStream(Lua L, bool gc = false)
|
||||
{
|
||||
var obj = L.CheckObject<Stream>(1, ObjectType, gc);
|
||||
if (obj is null)
|
||||
{
|
||||
L.Error("attempt to use a closed file");
|
||||
return null;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static bool ReadNumber(Lua L, Stream stream)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool ReadLine(Lua L, Stream stream, bool chop)
|
||||
{
|
||||
var buffer = new byte[stream.Length];
|
||||
int i = 0;
|
||||
int c = 0;
|
||||
for (; i < stream.Length; i++)
|
||||
{
|
||||
c = stream.ReadByte();
|
||||
if (c == -1 || c == '\n')
|
||||
break;
|
||||
buffer[i] = (byte)c;
|
||||
}
|
||||
|
||||
if (!chop && c == '\n')
|
||||
buffer[i++] = (byte)c;
|
||||
|
||||
Array.Resize(ref buffer, i);
|
||||
L.PushBuffer(buffer);
|
||||
|
||||
return c == '\n' || L.RawLen(-1) > 0;
|
||||
}
|
||||
|
||||
private static void ReadAll(Lua L, Stream stream)
|
||||
{
|
||||
var buffer = new byte[stream.Length];
|
||||
var read = stream.Read(buffer, 0, buffer.Length);
|
||||
Array.Resize(ref buffer, read);
|
||||
L.PushBuffer(buffer);
|
||||
}
|
||||
|
||||
private static bool ReadChars(Lua L, Stream stream, int n)
|
||||
{
|
||||
var buffer = new byte[n];
|
||||
var read = stream.Read(buffer, 0, n);
|
||||
Array.Resize(ref buffer, read);
|
||||
L.PushBuffer(buffer);
|
||||
return read != 0;
|
||||
}
|
||||
|
||||
private static int L_Read(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
bool success = false;
|
||||
|
||||
var stream = CheckStream(L);
|
||||
|
||||
if (!stream.CanRead)
|
||||
{
|
||||
L.PushNil();
|
||||
L.PushString("Attempt to read from a write-only stream");
|
||||
return 2;
|
||||
}
|
||||
|
||||
var nargs = L.GetTop() - 1;
|
||||
if (nargs == 0)
|
||||
{
|
||||
L.PushString("l");
|
||||
}
|
||||
|
||||
if (L.Type(2) == LuaType.Number)
|
||||
{
|
||||
success = ReadChars(L, stream, (int)L.ToNumber(2));
|
||||
}
|
||||
else
|
||||
{
|
||||
var p = L.CheckString(2);
|
||||
var mode = CheckMode(p);
|
||||
switch (mode)
|
||||
{
|
||||
case 'n':
|
||||
success = ReadNumber(L, stream);
|
||||
break;
|
||||
case 'l':
|
||||
success = ReadLine(L, stream, true);
|
||||
break;
|
||||
case 'L':
|
||||
success = ReadLine(L, stream, false);
|
||||
break;
|
||||
case 'a':
|
||||
ReadAll(L, stream);
|
||||
success = true;
|
||||
break;
|
||||
default:
|
||||
return L.ArgumentError(2, "invalid format");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!success)
|
||||
{
|
||||
L.Pop(1);
|
||||
L.PushNil();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int L_Write(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var nargs = L.GetTop();
|
||||
|
||||
var stream = CheckStream(L);
|
||||
if (!stream.CanWrite)
|
||||
{
|
||||
L.PushNil();
|
||||
L.PushString("Attempt to write to a read-only stream");
|
||||
return 2;
|
||||
}
|
||||
|
||||
for (int arg = 2; arg <= nargs; arg++)
|
||||
{
|
||||
if (L.Type(arg) == LuaType.Number)
|
||||
{
|
||||
stream.WriteByte((byte)L.ToNumber(arg));
|
||||
}
|
||||
else
|
||||
{
|
||||
var buffer = L.CheckBuffer(arg);
|
||||
stream.Write(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
return L.FileResult(1, null);
|
||||
}
|
||||
|
||||
private static int L_Lines(IntPtr state)
|
||||
{
|
||||
return 0;
|
||||
var L = Lua.FromIntPtr(state);
|
||||
var maxargn = 250;
|
||||
|
||||
var n = L.GetTop() - 1;
|
||||
var stream = CheckStream(L, false);
|
||||
L.ArgumentCheck(n <= maxargn, maxargn + 2, "too many arguments");
|
||||
L.PushCopy(1);
|
||||
L.PushInteger(n);
|
||||
L.PushBoolean(false);
|
||||
L.Rotate(2, 3);
|
||||
L.PushCClosure(null, 3 + n); // todo
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int L_Flush(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var stream = CheckStream(L, false);
|
||||
|
||||
stream.Flush();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int L_Seek(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var stream = CheckStream(L, false);
|
||||
|
||||
var whence = L.CheckOption(2, "cur", new[]
|
||||
{
|
||||
"set", // begin 0
|
||||
"cur", // current 1
|
||||
"end", // end 2
|
||||
null,
|
||||
});
|
||||
|
||||
var offset = L.OptInteger(3, 0);
|
||||
|
||||
var newPosition = stream.Seek(offset, (SeekOrigin)whence);
|
||||
|
||||
L.PushInteger(newPosition);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int L_Close(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var stream = CheckStream(L, true);
|
||||
stream.Close();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static unsafe int F_ToString(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
var stream = ToStream(L);
|
||||
if (stream is not null)
|
||||
{
|
||||
L.PushString("file ({0:X})", (ulong)&stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
L.PushString("file (closed)");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int F_GC(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var stream = ToStream(L, true);
|
||||
if (stream is not null)
|
||||
stream.Close();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -1,508 +0,0 @@
|
|||
using KeraLua;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Capy64.Runtime.Objects.Handlers;
|
||||
|
||||
public class BinaryReadHandle
|
||||
{
|
||||
public const string ObjectType = "BinaryReadHandle";
|
||||
|
||||
private static readonly Dictionary<string, LuaFunction> functions = new()
|
||||
{
|
||||
["readAll"] = L_ReadAll,
|
||||
["seek"] = L_Seek,
|
||||
["readByte"] = L_ReadByte,
|
||||
["readShort"] = L_ReadShort,
|
||||
["readInt"] = L_ReadInt,
|
||||
["readLong"] = L_ReadLong,
|
||||
["readSByte"] = L_ReadSByte,
|
||||
["readUShort"] = L_ReadUShort,
|
||||
["readUInt"] = L_ReadUInt,
|
||||
["readULong"] = L_ReadULong,
|
||||
["readHalf"] = L_ReadHalf,
|
||||
["readFloat"] = L_ReadFloat,
|
||||
["readDouble"] = L_ReadDouble,
|
||||
["readChar"] = L_ReadChar,
|
||||
["readString"] = L_ReadString,
|
||||
["readBoolean"] = L_ReadBoolean,
|
||||
["close"] = L_Close,
|
||||
};
|
||||
|
||||
public static void Push(Lua L, BinaryReader stream)
|
||||
{
|
||||
L.PushObject(stream);
|
||||
|
||||
if (L.NewMetaTable(ObjectType))
|
||||
{
|
||||
L.PushString("__index");
|
||||
L.NewTable();
|
||||
foreach (var pair in functions)
|
||||
{
|
||||
L.PushString(pair.Key);
|
||||
L.PushCFunction(pair.Value);
|
||||
L.SetTable(-3);
|
||||
}
|
||||
L.SetTable(-3);
|
||||
|
||||
L.PushString("__close");
|
||||
L.PushCFunction(L_Close);
|
||||
L.SetTable(-3);
|
||||
L.PushString("__gc");
|
||||
L.PushCFunction(L_Close);
|
||||
L.SetTable(-3);
|
||||
}
|
||||
|
||||
L.SetMetaTable(-2);
|
||||
}
|
||||
|
||||
private static int L_Read(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var stream = L.CheckObject<BinaryReader>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
if (L.IsInteger(2))
|
||||
{
|
||||
if (stream.BaseStream.Position >= stream.BaseStream.Length)
|
||||
{
|
||||
L.PushNil();
|
||||
return 0;
|
||||
}
|
||||
stream.ReadChars((int)L.ToInteger(2));
|
||||
}
|
||||
else if (L.IsString(2))
|
||||
{
|
||||
var option = L.ToString(2);
|
||||
option = option.TrimStart('*');
|
||||
if (option.Length == 0)
|
||||
{
|
||||
L.ArgumentError(2, "invalid option");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stream.BaseStream.Position >= stream.BaseStream.Length)
|
||||
{
|
||||
L.PushNil();
|
||||
return 0;
|
||||
}
|
||||
|
||||
var reader = new StreamReader(stream.BaseStream);
|
||||
|
||||
switch (option[0])
|
||||
{
|
||||
case 'a':
|
||||
L.PushString(reader.ReadToEnd());
|
||||
break;
|
||||
case 'l':
|
||||
L.PushString(reader.ReadLine());
|
||||
break;
|
||||
case 'n':
|
||||
L.Error("Not yet implemented!");
|
||||
break;
|
||||
default:
|
||||
L.ArgumentError(2, "invalid option");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
L.ArgumentError(2, "number or string expected");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int L_ReadAll(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var stream = L.CheckObject<BinaryReader>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
if (stream.BaseStream.Position >= stream.BaseStream.Length)
|
||||
{
|
||||
L.PushNil();
|
||||
return 0;
|
||||
}
|
||||
|
||||
var chars = stream.ReadChars((int)stream.BaseStream.Length);
|
||||
var buffer = Encoding.ASCII.GetBytes(chars);
|
||||
|
||||
L.PushBuffer(buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int L_Seek(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var stream = L.CheckObject<BinaryReader>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
var whence = L.CheckOption(2, "cur", new[]
|
||||
{
|
||||
"set", // begin 0
|
||||
"cur", // current 1
|
||||
"end", // end 2
|
||||
null,
|
||||
});
|
||||
|
||||
var offset = L.OptInteger(3, 0);
|
||||
|
||||
var newPosition = stream.BaseStream.Seek(offset, (SeekOrigin)whence);
|
||||
|
||||
L.PushInteger(newPosition);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int L_ReadByte(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var count = (int)L.OptNumber(2, 1);
|
||||
L.ArgumentCheck(count >= 1, 2, "count must be a positive integer");
|
||||
|
||||
var stream = L.CheckObject<BinaryReader>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
if (stream.BaseStream.Position >= stream.BaseStream.Length)
|
||||
{
|
||||
L.PushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (count == 1)
|
||||
{
|
||||
var b = stream.ReadByte();
|
||||
L.PushInteger(b);
|
||||
return 1;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
var bs = stream.ReadBytes(count);
|
||||
foreach (var b in bs)
|
||||
{
|
||||
L.PushInteger(b);
|
||||
}
|
||||
return bs.Length;
|
||||
}
|
||||
}
|
||||
|
||||
private static int L_ReadShort(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var stream = L.CheckObject<BinaryReader>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
if (stream.BaseStream.Position >= stream.BaseStream.Length)
|
||||
{
|
||||
L.PushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
var b = stream.ReadInt16();
|
||||
L.PushInteger(b);
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int L_ReadInt(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var stream = L.CheckObject<BinaryReader>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
if (stream.BaseStream.Position > stream.BaseStream.Length)
|
||||
{
|
||||
L.PushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
var b = stream.ReadInt32();
|
||||
L.PushInteger(b);
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int L_ReadLong(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var stream = L.CheckObject<BinaryReader>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
if (stream.BaseStream.Position > stream.BaseStream.Length)
|
||||
{
|
||||
L.PushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
var b = stream.ReadInt64();
|
||||
L.PushInteger(b);
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int L_ReadSByte(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var stream = L.CheckObject<BinaryReader>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
if (stream.BaseStream.Position > stream.BaseStream.Length)
|
||||
{
|
||||
L.PushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
var b = stream.ReadSByte();
|
||||
L.PushInteger(b);
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int L_ReadUShort(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var stream = L.CheckObject<BinaryReader>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
if (stream.BaseStream.Position > stream.BaseStream.Length)
|
||||
{
|
||||
L.PushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
var b = stream.ReadUInt16();
|
||||
L.PushInteger(b);
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int L_ReadUInt(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var stream = L.CheckObject<BinaryReader>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
if (stream.BaseStream.Position > stream.BaseStream.Length)
|
||||
{
|
||||
L.PushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
var b = stream.ReadUInt32();
|
||||
L.PushInteger(b);
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int L_ReadULong(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var stream = L.CheckObject<BinaryReader>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
if (stream.BaseStream.Position > stream.BaseStream.Length)
|
||||
{
|
||||
L.PushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
var b = stream.ReadUInt64();
|
||||
L.PushInteger((long)b);
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int L_ReadHalf(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var stream = L.CheckObject<BinaryReader>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
if (stream.BaseStream.Position > stream.BaseStream.Length)
|
||||
{
|
||||
L.PushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
var b = stream.ReadHalf();
|
||||
L.PushNumber((double)b);
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int L_ReadFloat(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var stream = L.CheckObject<BinaryReader>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
if (stream.BaseStream.Position > stream.BaseStream.Length)
|
||||
{
|
||||
L.PushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
var b = stream.ReadSingle();
|
||||
L.PushNumber((double)b);
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int L_ReadDouble(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var stream = L.CheckObject<BinaryReader>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
if (stream.BaseStream.Position > stream.BaseStream.Length)
|
||||
{
|
||||
L.PushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
var b = stream.ReadDouble();
|
||||
L.PushNumber((double)b);
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int L_ReadChar(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var stream = L.CheckObject<BinaryReader>(1, ObjectType, false);
|
||||
|
||||
var count = (int)L.OptNumber(2, 1);
|
||||
L.ArgumentCheck(count >= 1, 2, "count must be a positive integer");
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
if (stream.BaseStream.Position >= stream.BaseStream.Length)
|
||||
{
|
||||
L.PushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (count == 1)
|
||||
{
|
||||
var b = stream.ReadChar();
|
||||
L.PushString(b.ToString());
|
||||
return 1;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
var bs = stream.ReadChars(count);
|
||||
foreach (var b in bs)
|
||||
{
|
||||
L.PushString(b.ToString());
|
||||
}
|
||||
return bs.Length;
|
||||
}
|
||||
}
|
||||
|
||||
private static int L_ReadString(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var stream = L.CheckObject<BinaryReader>(1, ObjectType, false);
|
||||
|
||||
var count = (int)L.OptNumber(2, 1);
|
||||
L.ArgumentCheck(count >= 1, 2, "count must be a positive integer");
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
if (stream.BaseStream.Position >= stream.BaseStream.Length)
|
||||
{
|
||||
L.PushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (count == 1)
|
||||
{
|
||||
var b = stream.ReadChar();
|
||||
L.PushString(b.ToString());
|
||||
return 1;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
var bs = stream.ReadBytes(count);
|
||||
L.PushBuffer(bs);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static int L_ReadBoolean(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var stream = L.CheckObject<BinaryReader>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
if (stream.BaseStream.Position > stream.BaseStream.Length)
|
||||
{
|
||||
L.PushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
var b = stream.ReadBoolean();
|
||||
L.PushBoolean(b);
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int L_Close(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var stream = L.CheckObject<BinaryReader>(1, ObjectType, true);
|
||||
|
||||
if (stream is null)
|
||||
return 0;
|
||||
|
||||
stream.Dispose();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -1,395 +0,0 @@
|
|||
using KeraLua;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Capy64.Runtime.Objects.Handlers;
|
||||
|
||||
public class BinaryWriteHandle
|
||||
{
|
||||
public const string ObjectType = "BinaryWriteHandle";
|
||||
|
||||
private static readonly Dictionary<string, LuaFunction> functions = new()
|
||||
{
|
||||
["seek"] = L_Seek,
|
||||
["writeByte"] = L_WriteByte,
|
||||
["writeShort"] = L_WriteShort,
|
||||
["writeInt"] = L_WriteInt,
|
||||
["writeLong"] = L_WriteLong,
|
||||
["writeSByte"] = L_WriteSByte,
|
||||
["writeUShort"] = L_WriteUShort,
|
||||
["writeUInt"] = L_WriteUInt,
|
||||
["writeULong"] = L_WriteULong,
|
||||
["writeHalf"] = L_WriteHalf,
|
||||
["writeFloat"] = L_WriteFloat,
|
||||
["writeDouble"] = L_WriteDouble,
|
||||
["writeChar"] = L_WriteChar,
|
||||
["writeString"] = L_WriteString,
|
||||
["writeBoolean"] = L_WriteBoolean,
|
||||
["flush"] = L_Flush,
|
||||
["close"] = L_Close,
|
||||
};
|
||||
|
||||
public static void Push(Lua L, BinaryWriter stream)
|
||||
{
|
||||
L.PushObject(stream);
|
||||
|
||||
if (L.NewMetaTable(ObjectType))
|
||||
{
|
||||
L.PushString("__index");
|
||||
L.NewTable();
|
||||
foreach (var pair in functions)
|
||||
{
|
||||
L.PushString(pair.Key);
|
||||
L.PushCFunction(pair.Value);
|
||||
L.SetTable(-3);
|
||||
}
|
||||
L.SetTable(-3);
|
||||
|
||||
L.PushString("__close");
|
||||
L.PushCFunction(L_Close);
|
||||
L.SetTable(-3);
|
||||
L.PushString("__gc");
|
||||
L.PushCFunction(L_Close);
|
||||
L.SetTable(-3);
|
||||
}
|
||||
|
||||
L.SetMetaTable(-2);
|
||||
}
|
||||
|
||||
private static int L_Seek(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var stream = L.CheckObject<BinaryWriter>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
var whence = L.CheckOption(2, "cur", new[]
|
||||
{
|
||||
"set", // begin 0
|
||||
"cur", // current 1
|
||||
"end", // end 2
|
||||
null,
|
||||
});
|
||||
|
||||
var offset = L.OptInteger(3, 0);
|
||||
|
||||
var newPosition = stream.BaseStream.Seek(offset, (SeekOrigin)whence);
|
||||
|
||||
L.PushInteger(newPosition);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int L_WriteByte(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
byte[] buffer;
|
||||
if (L.IsInteger(2))
|
||||
{
|
||||
buffer = new[]
|
||||
{
|
||||
(byte)L.ToInteger(2),
|
||||
};
|
||||
}
|
||||
else if (L.IsTable(2))
|
||||
{
|
||||
var len = L.RawLen(2);
|
||||
buffer = new byte[len];
|
||||
|
||||
for (int i = 1; i <= len; i++)
|
||||
{
|
||||
L.PushInteger(i);
|
||||
L.GetTable(2);
|
||||
var b = L.CheckInteger(-1);
|
||||
L.Pop(1);
|
||||
buffer[i - 1] = (byte)b;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
L.ArgumentError(2, "integer or table expected, got " + L.Type(2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
var stream = L.CheckObject<BinaryWriter>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
stream.Write(buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int L_WriteShort(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var b = L.CheckInteger(2);
|
||||
|
||||
var stream = L.CheckObject<BinaryWriter>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
stream.Write((short)b);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int L_WriteInt(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var b = L.CheckInteger(2);
|
||||
|
||||
var stream = L.CheckObject<BinaryWriter>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
stream.Write((int)b);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int L_WriteLong(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var b = L.CheckInteger(2);
|
||||
|
||||
var stream = L.CheckObject<BinaryWriter>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
stream.Write(b);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int L_WriteSByte(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var b = L.CheckInteger(2);
|
||||
|
||||
var stream = L.CheckObject<BinaryWriter>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
stream.Write((sbyte)b);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int L_WriteUShort(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var b = L.CheckInteger(2);
|
||||
|
||||
var stream = L.CheckObject<BinaryWriter>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
stream.Write((ushort)b);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int L_WriteUInt(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var b = L.CheckInteger(2);
|
||||
|
||||
var stream = L.CheckObject<BinaryWriter>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
stream.Write((uint)b);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int L_WriteULong(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var b = L.CheckInteger(2);
|
||||
|
||||
var stream = L.CheckObject<BinaryWriter>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
stream.Write((ulong)b);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int L_WriteHalf(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var b = L.CheckNumber(2);
|
||||
|
||||
var stream = L.CheckObject<BinaryWriter>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
stream.Write((Half)b);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int L_WriteFloat(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var b = L.CheckNumber(2);
|
||||
|
||||
var stream = L.CheckObject<BinaryWriter>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
stream.Write((float)b);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int L_WriteDouble(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var b = L.CheckNumber(2);
|
||||
|
||||
var stream = L.CheckObject<BinaryWriter>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
stream.Write((double)b);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int L_WriteChar(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
byte[] buffer;
|
||||
if (L.IsString(2))
|
||||
{
|
||||
var str = L.ToString(2);
|
||||
buffer = Encoding.ASCII.GetBytes(str);
|
||||
}
|
||||
else if (L.IsTable(2))
|
||||
{
|
||||
var len = L.RawLen(2);
|
||||
var tmpBuffer = new List<byte>();
|
||||
|
||||
for (int i = 1; i <= len; i++)
|
||||
{
|
||||
L.PushInteger(i);
|
||||
L.GetTable(2);
|
||||
var b = L.CheckString(-1);
|
||||
L.Pop(1);
|
||||
var chunk = Encoding.ASCII.GetBytes(b);
|
||||
foreach (var c in chunk)
|
||||
{
|
||||
tmpBuffer.Add(c);
|
||||
}
|
||||
}
|
||||
|
||||
buffer = tmpBuffer.ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
L.ArgumentError(2, "integer or table expected, got " + L.Type(2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
var stream = L.CheckObject<BinaryWriter>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
stream.Write(buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int L_WriteString(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var b = L.CheckString(2);
|
||||
|
||||
var stream = L.CheckObject<BinaryWriter>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
stream.Write(b);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int L_WriteBoolean(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
L.CheckType(2, LuaType.Boolean);
|
||||
var b = L.ToBoolean(2);
|
||||
|
||||
var stream = L.CheckObject<BinaryWriter>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
stream.Write(b);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int L_Flush(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var stream = L.CheckObject<BinaryWriter>(1, ObjectType, false);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
stream.Flush();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int L_Close(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var stream = L.CheckObject<BinaryWriter>(1, ObjectType, true);
|
||||
|
||||
if (stream is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
stream.Dispose();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -1,127 +0,0 @@
|
|||
using KeraLua;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Capy64.Runtime.Objects.Handlers;
|
||||
|
||||
public class ReadHandle
|
||||
{
|
||||
public const string ObjectType = "ReadHandle";
|
||||
|
||||
private static readonly Dictionary<string, LuaFunction> functions = new()
|
||||
{
|
||||
["readAll"] = L_ReadAll,
|
||||
["readLine"] = L_ReadLine,
|
||||
["read"] = L_Read,
|
||||
["close"] = L_Close,
|
||||
};
|
||||
|
||||
public static void Push(Lua L, StreamReader stream)
|
||||
{
|
||||
L.PushObject(stream);
|
||||
|
||||
if (L.NewMetaTable(ObjectType))
|
||||
{
|
||||
L.PushString("__index");
|
||||
L.NewTable();
|
||||
foreach (var pair in functions)
|
||||
{
|
||||
L.PushString(pair.Key);
|
||||
L.PushCFunction(pair.Value);
|
||||
L.SetTable(-3);
|
||||
}
|
||||
L.SetTable(-3);
|
||||
|
||||
L.PushString("__close");
|
||||
L.PushCFunction(L_Close);
|
||||
L.SetTable(-3);
|
||||
L.PushString("__gc");
|
||||
L.PushCFunction(L_Close);
|
||||
L.SetTable(-3);
|
||||
}
|
||||
|
||||
L.SetMetaTable(-2);
|
||||
}
|
||||
|
||||
private static int L_ReadAll(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var handle = L.CheckObject<StreamReader>(1, ObjectType, false);
|
||||
|
||||
if (handle is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
if (handle.EndOfStream)
|
||||
{
|
||||
L.PushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
var content = handle.ReadToEnd();
|
||||
L.PushString(content);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int L_ReadLine(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var handle = L.CheckObject<StreamReader>(1, ObjectType, false);
|
||||
|
||||
if (handle is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
var line = handle.ReadLine();
|
||||
|
||||
if (line is null)
|
||||
L.PushNil();
|
||||
else
|
||||
L.PushString(line);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int L_Read(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var count = (int)L.OptNumber(2, 1);
|
||||
L.ArgumentCheck(count >= 1, 2, "count must be a positive integer");
|
||||
|
||||
var handle = L.CheckObject<StreamReader>(1, ObjectType, false);
|
||||
|
||||
if (handle is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
if (handle.EndOfStream)
|
||||
{
|
||||
L.PushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
var chunk = new char[count];
|
||||
|
||||
handle.Read(chunk, 0, count);
|
||||
|
||||
L.PushString(new string(chunk));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int L_Close(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var handle = L.CheckObject<StreamReader>(1, ObjectType, true);
|
||||
|
||||
if (handle is null)
|
||||
return 0;
|
||||
|
||||
handle.Dispose();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
using KeraLua;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Capy64.Runtime.Objects.Handlers;
|
||||
|
||||
public class WriteHandle
|
||||
{
|
||||
public const string ObjectType = "WriteHandle";
|
||||
|
||||
private static readonly Dictionary<string, LuaFunction> functions = new()
|
||||
{
|
||||
["write"] = L_Write,
|
||||
["writeLine"] = L_WriteLine,
|
||||
["flush"] = L_Flush,
|
||||
["close"] = L_Close,
|
||||
};
|
||||
|
||||
public static void Push(Lua L, StreamWriter stream)
|
||||
{
|
||||
L.PushObject(stream);
|
||||
|
||||
if (L.NewMetaTable(ObjectType))
|
||||
{
|
||||
L.PushString("__index");
|
||||
L.NewTable();
|
||||
foreach (var pair in functions)
|
||||
{
|
||||
L.PushString(pair.Key);
|
||||
L.PushCFunction(pair.Value);
|
||||
L.SetTable(-3);
|
||||
}
|
||||
L.SetTable(-3);
|
||||
|
||||
L.PushString("__close");
|
||||
L.PushCFunction(L_Close);
|
||||
L.SetTable(-3);
|
||||
L.PushString("__gc");
|
||||
L.PushCFunction(L_Close);
|
||||
L.SetTable(-3);
|
||||
}
|
||||
|
||||
L.SetMetaTable(-2);
|
||||
}
|
||||
|
||||
private static int L_Write(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var handle = L.CheckObject<StreamWriter>(1, ObjectType, false);
|
||||
|
||||
var content = L.CheckString(2);
|
||||
|
||||
if (handle is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
handle.Write(content);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int L_WriteLine(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var handle = L.CheckObject<StreamWriter>(1, ObjectType, false);
|
||||
|
||||
var content = L.CheckString(2);
|
||||
|
||||
if (handle is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
handle.WriteLine(content);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int L_Flush(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var handle = L.CheckObject<StreamWriter>(1, ObjectType, false);
|
||||
|
||||
if (handle is null)
|
||||
L.Error("handle is closed");
|
||||
|
||||
handle.Flush();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int L_Close(IntPtr state)
|
||||
{
|
||||
var L = Lua.FromIntPtr(state);
|
||||
|
||||
var handle = L.CheckObject<StreamWriter>(1, ObjectType, true);
|
||||
|
||||
if (handle is null)
|
||||
return 0;
|
||||
|
||||
handle.Dispose();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@ using System.Collections.Generic;
|
|||
using System.Net.WebSockets;
|
||||
using System.Threading;
|
||||
|
||||
namespace Capy64.Runtime.Objects.Handlers;
|
||||
namespace Capy64.Runtime.Objects;
|
||||
|
||||
public class WebSocketClient
|
||||
{
|
|
@ -84,8 +84,6 @@ internal class RuntimeManager : IPlugin
|
|||
|
||||
private void InitBIOS()
|
||||
{
|
||||
InstallOS(false);
|
||||
|
||||
_game.Discord.SetPresence("Booting up...");
|
||||
|
||||
luaState = new LuaState();
|
||||
|
@ -104,8 +102,11 @@ internal class RuntimeManager : IPlugin
|
|||
luaState.Thread.PushCFunction(L_OpenDataFolder);
|
||||
luaState.Thread.SetGlobal("openDataFolder");
|
||||
|
||||
luaState.Thread.PushCFunction(L_InstallOS);
|
||||
luaState.Thread.SetGlobal("installOS");
|
||||
luaState.Thread.PushCFunction(L_ShouldInstallOS);
|
||||
luaState.Thread.SetGlobal("shouldInstallOS");
|
||||
|
||||
luaState.Thread.PushCFunction(L_FlagInstalled);
|
||||
luaState.Thread.SetGlobal("flagInstalled");
|
||||
|
||||
luaState.Thread.PushCFunction(L_Exit);
|
||||
luaState.Thread.SetGlobal("exit");
|
||||
|
@ -153,16 +154,6 @@ internal class RuntimeManager : IPlugin
|
|||
_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", FileSystem.DataPath, true, true);
|
||||
File.Create(installedFilePath).Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private static int L_OpenDataFolder(IntPtr state)
|
||||
{
|
||||
var path = FileSystem.DataPath;
|
||||
|
@ -179,9 +170,22 @@ internal class RuntimeManager : IPlugin
|
|||
return 0;
|
||||
}
|
||||
|
||||
private static int L_InstallOS(IntPtr state)
|
||||
private static int L_ShouldInstallOS(IntPtr state)
|
||||
{
|
||||
InstallOS(true);
|
||||
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();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue