mirror of
https://github.com/zenith391/OCEmu.git
synced 2025-09-16 00:06:38 -04:00
Lets upload the really bad emulator code!
This commit is contained in:
parent
4a02fc5739
commit
e2355d6dad
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
src/lua
|
||||
src/loot
|
||||
src/unifont.hex
|
||||
ocemu2d.love
|
||||
log.txt
|
21
Makefile
Normal file
21
Makefile
Normal file
@ -0,0 +1,21 @@
|
||||
ASSETS=https://github.com/MightyPirates/OpenComputers/trunk/src/main/resources/assets/opencomputers
|
||||
|
||||
all: src/lua src/loot src/unifont.hex ocemu2d
|
||||
|
||||
src/lua:
|
||||
svn export $(ASSETS)/lua src/lua
|
||||
|
||||
src/loot:
|
||||
svn export $(ASSETS)/loot src/loot
|
||||
|
||||
src/unifont.hex:
|
||||
svn export $(ASSETS)/unifont.hex src/unifont.hex
|
||||
|
||||
ocemu2d:
|
||||
cd src; zip -r -9 ../ocemu2d.love *; cd ..
|
||||
|
||||
clean:
|
||||
rm -f ocemu2d.love
|
||||
rm -rf src/lua
|
||||
rm -rf src/loot
|
||||
rm -f src/unifont.hex
|
20
licenses/lua-compat-5.2_LICENSE
Normal file
20
licenses/lua-compat-5.2_LICENSE
Normal file
@ -0,0 +1,20 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Hisham Muhammad
|
||||
|
||||
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.
|
19
licenses/lua-utf8-simple_LICENSE
Normal file
19
licenses/lua-utf8-simple_LICENSE
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright © 2015 blitmap <coroutines@gmail.com>
|
||||
|
||||
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.
|
29
list.lua
Normal file
29
list.lua
Normal file
@ -0,0 +1,29 @@
|
||||
local args = { ... }
|
||||
if #args ~= 1 then
|
||||
return
|
||||
end
|
||||
local component = require("component")
|
||||
local address = component.get(args[1])
|
||||
local proxy = component.proxy(address)
|
||||
local keys = {}
|
||||
for k,v in pairs(proxy) do
|
||||
if type(v) == "table" then
|
||||
keys[#keys+1] = k
|
||||
end
|
||||
end
|
||||
table.sort(keys,function(a,b) return a:reverse() < b:reverse() end)
|
||||
local file = io.open("list.txt","wb")
|
||||
file = file:write("-- " .. proxy.type .. " component\nlocal obj = {}\n\n")
|
||||
for i = 1,#keys do
|
||||
local k = keys[i]
|
||||
local doc = ""
|
||||
local comment = "-- no doc"
|
||||
if component.doc(address,k) ~= nil then
|
||||
doc = component.doc(address,k):match("%((.-)%)"):gsub("[%[%]]","") .. ","
|
||||
doc = doc:gsub("(.-):.-,",function(a) return a .. "," end):sub(1,-2)
|
||||
comment = component.doc(address,k):match("%-%-.*")
|
||||
end
|
||||
file:write("function obj." .. k .. "(" .. doc .. ") " .. comment .."\n\t--STUB\n\tcprint(\"" .. proxy.type .. "." .. k .. "\"" .. (doc ~= "" and "," or "") .. doc .. ")\nend\n")
|
||||
end
|
||||
file:write("\nlocal cec = {}\n\nreturn obj,cec")
|
||||
file:close()
|
139
src/apis/component.lua
Normal file
139
src/apis/component.lua
Normal file
@ -0,0 +1,139 @@
|
||||
local env = ...
|
||||
|
||||
local r = math.random
|
||||
function gen_uuid()
|
||||
return string.format("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||
r(0,255),r(0,255),r(0,255),r(0,255),
|
||||
r(0,255),r(0,255),
|
||||
r(64,79),r(0,255),
|
||||
r(128,191),r(0,255),
|
||||
r(0,255),r(0,255),r(0,255),r(0,255),r(0,255),r(0,255))
|
||||
end
|
||||
|
||||
local proxylist = {}
|
||||
local slotlist = {}
|
||||
local emuicc = {}
|
||||
local doclist = {}
|
||||
|
||||
-- Load components
|
||||
local components = conf.components
|
||||
for k,v in pairs(components) do
|
||||
local address
|
||||
if type(v[2]) == "string" then
|
||||
address = v[2]
|
||||
else
|
||||
math.randomseed(type(v[2]) == "number" and v[2] or k)
|
||||
address = gen_uuid()
|
||||
end
|
||||
v[2] = address
|
||||
local proxy, cec, doc = love.filesystem.load("component/" .. v[1] .. ".lua")(table.unpack(v,2))
|
||||
proxy.address = address
|
||||
proxy.type = v[1]
|
||||
proxylist[address] = proxy
|
||||
emuicc[address] = cec
|
||||
doclist[address] = doc
|
||||
slotlist[address] = v[3]
|
||||
end
|
||||
|
||||
component = {}
|
||||
|
||||
function component.exists(address)
|
||||
checkArg(1,address,"string")
|
||||
if proxylist[address] ~= nil then
|
||||
return proxylist[address].type
|
||||
end
|
||||
end
|
||||
function component.list(filter, exact)
|
||||
checkArg(1,filter,"string","nil")
|
||||
local data = {}
|
||||
local tbl = {}
|
||||
for k,v in pairs(proxylist) do
|
||||
if filter == nil or (exact and v.type == filter) or (not exact and v.type:find(filter, nil, true)) then
|
||||
data[#data + 1] = k
|
||||
data[#data + 1] = v.type
|
||||
tbl[k] = v.type
|
||||
end
|
||||
end
|
||||
local place = 1
|
||||
return setmetatable(tbl,{__call = function()
|
||||
local addr,type = data[place], data[place + 1]
|
||||
place = place + 2
|
||||
return addr,type
|
||||
end})
|
||||
end
|
||||
function component.invoke(address, method, ...)
|
||||
checkArg(1,address,"string")
|
||||
checkArg(2,method,"string")
|
||||
if proxylist[address] ~= nil then
|
||||
if proxylist[address][method] == nil then
|
||||
error("no such method",2)
|
||||
end
|
||||
return proxylist[address][method](...)
|
||||
end
|
||||
end
|
||||
function component.cecinvoke(address, method, ...)
|
||||
checkArg(1,address,"string")
|
||||
checkArg(2,method,"string")
|
||||
if emuicc[address] ~= nil then
|
||||
if emuicc[address][method] == nil then
|
||||
error("no such method",2)
|
||||
end
|
||||
return emuicc[address][method](...)
|
||||
end
|
||||
end
|
||||
|
||||
env.component = {list = component.list}
|
||||
|
||||
function env.component.type(address)
|
||||
checkArg(1,address,"string")
|
||||
if proxylist[address] ~= nil then
|
||||
return proxylist[address].type
|
||||
end
|
||||
return nil, "no such component"
|
||||
end
|
||||
|
||||
function env.component.slot(address)
|
||||
checkArg(1,address,"string")
|
||||
if proxylist[address] ~= nil then
|
||||
return slotlist[address] or -1
|
||||
end
|
||||
return nil, "no such component"
|
||||
end
|
||||
|
||||
function env.component.methods(address)
|
||||
checkArg(1,address,"string")
|
||||
if proxylist[address] ~= nil then
|
||||
local methods = {}
|
||||
for k,v in pairs(proxylist[address]) do
|
||||
if type(v) == "function" then
|
||||
methods[k] = {direct=true} -- TODO: getter, setter?
|
||||
end
|
||||
end
|
||||
return methods
|
||||
end
|
||||
end
|
||||
|
||||
function env.component.invoke(address, method, ...)
|
||||
checkArg(1,address,"string")
|
||||
checkArg(2,method,"string")
|
||||
if proxylist[address] ~= nil then
|
||||
if proxylist[address][method] == nil then
|
||||
error("no such method",2)
|
||||
end
|
||||
return true, proxylist[address][method](...)
|
||||
end
|
||||
end
|
||||
|
||||
function env.component.doc(address, method)
|
||||
checkArg(1,address,"string")
|
||||
checkArg(2,method,"string")
|
||||
if proxylist[address] ~= nil then
|
||||
if proxylist[address][method] == nil then
|
||||
error("no such method",2)
|
||||
end
|
||||
if doclist[address] ~= nil then
|
||||
return doclist[address][method]
|
||||
end
|
||||
return nil
|
||||
end
|
||||
end
|
70
src/apis/computer.lua
Normal file
70
src/apis/computer.lua
Normal file
@ -0,0 +1,70 @@
|
||||
local env = ...
|
||||
|
||||
local tmpaddr = "tmp-address"
|
||||
|
||||
computer = {}
|
||||
|
||||
function computer.setTempAddress(str)
|
||||
tmpaddr = str
|
||||
end
|
||||
|
||||
env.computer = {}
|
||||
|
||||
function env.computer.realTime()
|
||||
--STUB
|
||||
--cprint("computer.realTime") -- Spammy
|
||||
return 0
|
||||
end
|
||||
function env.computer.uptime()
|
||||
--STUB
|
||||
cprint("computer.uptime")
|
||||
return love.timer.getTime() - machine.starttime
|
||||
end
|
||||
function env.computer.address()
|
||||
cprint("computer.address")
|
||||
return component.list("computer",true)()
|
||||
end
|
||||
function env.computer.freeMemory()
|
||||
--STUB
|
||||
cprint("computer.freeMemory")
|
||||
return 10000
|
||||
end
|
||||
function env.computer.totalMemory()
|
||||
--STUB
|
||||
cprint("computer.totalMemory")
|
||||
return 10000
|
||||
end
|
||||
function env.computer.pushSignal(name, ...)
|
||||
--TODO
|
||||
cprint("computer.pushSignal", name, ...)
|
||||
table.insert(machine.signals, {name, ... })
|
||||
end
|
||||
function env.computer.tmpAddress()
|
||||
--STUB
|
||||
cprint("computer.tmpAddress")
|
||||
return tmpaddr
|
||||
end
|
||||
function env.computer.users()
|
||||
--STUB
|
||||
cprint("computer.users")
|
||||
end
|
||||
function env.computer.addUser(username)
|
||||
--STUB
|
||||
cprint("computer.addUser", username)
|
||||
return nil, "player must be online"
|
||||
end
|
||||
function env.computer.removeUser(username)
|
||||
--STUB
|
||||
cprint("computer.removeUser", username)
|
||||
return false
|
||||
end
|
||||
function env.computer.energy()
|
||||
--STUB
|
||||
cprint("computer.energy")
|
||||
return math.huge
|
||||
end
|
||||
function env.computer.maxEnergy()
|
||||
--STUB
|
||||
cprint("computer.maxEnergy")
|
||||
return math.huge
|
||||
end
|
1
src/apis/os.lua
Normal file
1
src/apis/os.lua
Normal file
@ -0,0 +1 @@
|
||||
local env = ...
|
14
src/apis/system.lua
Normal file
14
src/apis/system.lua
Normal file
@ -0,0 +1,14 @@
|
||||
local env = ...
|
||||
|
||||
env.system = {}
|
||||
|
||||
function env.system.allowBytecode()
|
||||
--STUB, move to a config
|
||||
cprint("system.allowBytecode")
|
||||
return false
|
||||
end
|
||||
function env.system.timeout()
|
||||
--STUB, move to a config
|
||||
cprint("system.timeout")
|
||||
return math.huge
|
||||
end
|
86
src/apis/unicode.lua
Normal file
86
src/apis/unicode.lua
Normal file
@ -0,0 +1,86 @@
|
||||
local env = ...
|
||||
|
||||
local utf8 = require('utf8_simple')
|
||||
local lua_utf8 = require("utf8")
|
||||
|
||||
function z(val)
|
||||
local size = val < 0x10000 and (val < 0x800 and (val < 0x80 and 1 or 2) or 3) or 4
|
||||
if size == 1 then return string.char(val) end
|
||||
local b = {string.char((240*2^(4-size)%256)+(val/2^(size*6-6))%(2^(7-size)))}
|
||||
for i = size*6-12,0,-6 do
|
||||
b[#b+1] = string.char(128+(val/2^i)%64)
|
||||
end
|
||||
return table.concat(b)
|
||||
end
|
||||
|
||||
env.unicode = {}
|
||||
|
||||
function env.unicode.lower(str)
|
||||
-- STUB
|
||||
cprint("unicode.lower", str)
|
||||
checkArg(1,str,"string")
|
||||
return string.lower(str)
|
||||
end
|
||||
function env.unicode.upper(str)
|
||||
-- STUB
|
||||
cprint("unicode.upper", str)
|
||||
checkArg(1,str,"string")
|
||||
return string.upper(str)
|
||||
end
|
||||
function env.unicode.char(...)
|
||||
-- TODO
|
||||
cprint("unicode.char", ...)
|
||||
--return lua_utf8.char(...) -- Why does this return "%U"
|
||||
local output = {}
|
||||
local codes = { ... }
|
||||
for i = 1,#codes do
|
||||
output[i] = z(codes[i])
|
||||
end
|
||||
return table.concat(output)
|
||||
end
|
||||
function env.unicode.len(str)
|
||||
-- TODO
|
||||
cprint("unicode.len", str)
|
||||
checkArg(1,str,"string")
|
||||
return lua_utf8.len(str)
|
||||
end
|
||||
function env.unicode.reverse(str)
|
||||
-- TODO
|
||||
cprint("unicode.reverse", str)
|
||||
checkArg(1,str,"string")
|
||||
return utf8.reverse(str)
|
||||
end
|
||||
function env.unicode.sub(str, i, j)
|
||||
-- TODO
|
||||
cprint("unicode.sub", str, i, j)
|
||||
return utf8.sub(str, i, j)
|
||||
end
|
||||
function env.unicode.isWide(str)
|
||||
-- STUB
|
||||
cprint("unicode.isWide", str)
|
||||
checkArg(1,str,"string")
|
||||
return false
|
||||
end
|
||||
function env.unicode.charWidth(str)
|
||||
-- STUB
|
||||
cprint("unicode.charWidth", str)
|
||||
checkArg(1,str,"string")
|
||||
return 1
|
||||
end
|
||||
function env.unicode.wlen(str)
|
||||
-- STUB
|
||||
cprint("unicode.wlen", str)
|
||||
checkArg(1,str,"string")
|
||||
return lua_utf8.len(str)
|
||||
end
|
||||
function env.unicode.wtrunc(str, count)
|
||||
-- STUB
|
||||
cprint("unicode.wtrunc", str, count)
|
||||
checkArg(1,str,"string")
|
||||
checkArg(2,count,"number")
|
||||
local len = lua_utf8.len(str)
|
||||
if count >= len then
|
||||
error("String index out of range: " .. len,2)
|
||||
end
|
||||
return utf8.sub(str, 1, count-1)
|
||||
end
|
1
src/apis/userdata.lua
Normal file
1
src/apis/userdata.lua
Normal file
@ -0,0 +1 @@
|
||||
local env = ...
|
648
src/compat52.lua
Normal file
648
src/compat52.lua
Normal file
@ -0,0 +1,648 @@
|
||||
-- utility module to make the Lua 5.1 standard libraries behave more like Lua 5.2
|
||||
|
||||
if _VERSION == "Lua 5.1" then
|
||||
local _type, _select, _unpack, _error = type, select, unpack, error
|
||||
|
||||
bit32 = require("bit")
|
||||
|
||||
-- detect LuaJIT (including LUAJIT_ENABLE_LUA52COMPAT compilation flag)
|
||||
local is_luajit = (string.dump(function() end) or ""):sub(1, 3) == "\027LJ"
|
||||
local is_luajit52 = is_luajit and
|
||||
#setmetatable({}, { __len = function() return 1 end }) == 1
|
||||
|
||||
local weak_meta = { __mode = "kv" }
|
||||
-- table that maps each running coroutine to the coroutine that resumed it
|
||||
-- this is used to build complete tracebacks when "coroutine-friendly" pcall
|
||||
-- is used.
|
||||
local pcall_previous = setmetatable({}, weak_meta)
|
||||
local pcall_callOf = setmetatable({}, weak_meta)
|
||||
local xpcall_running = setmetatable({}, weak_meta)
|
||||
local coroutine_running = coroutine.running
|
||||
|
||||
-- the most powerful getmetatable we can get (preferably from debug)
|
||||
local sudo_getmetatable = getmetatable
|
||||
|
||||
if _type(debug) == "table" then
|
||||
|
||||
if _type(debug.getmetatable) == "function" then
|
||||
sudo_getmetatable = debug.getmetatable
|
||||
end
|
||||
|
||||
if not is_luajit52 then
|
||||
local _G, package = _G, package
|
||||
local debug_setfenv = debug.setfenv
|
||||
debug.setuservalue = function(obj, value)
|
||||
if _type(obj) ~= "userdata" then
|
||||
_error("bad argument #1 to 'setuservalue' (userdata expected, got "..
|
||||
_type(obj)..")", 2)
|
||||
end
|
||||
if value == nil then value = _G end
|
||||
if _type(value) ~= "table" then
|
||||
_error("bad argument #2 to 'setuservalue' (table expected, got "..
|
||||
_type(value)..")", 2)
|
||||
end
|
||||
return debug_setfenv(obj, value)
|
||||
end
|
||||
|
||||
local debug_getfenv = debug.getfenv
|
||||
debug.getuservalue = function(obj)
|
||||
if _type(obj) ~= "userdata" then
|
||||
return nil
|
||||
else
|
||||
local v = debug_getfenv(obj)
|
||||
if v == _G or v == package then
|
||||
return nil
|
||||
end
|
||||
return v
|
||||
end
|
||||
end
|
||||
|
||||
local debug_setmetatable = debug.setmetatable
|
||||
if _type(debug_setmetatable) == "function" then
|
||||
debug.setmetatable = function(value, tab)
|
||||
debug_setmetatable(value, tab)
|
||||
return value
|
||||
end
|
||||
end
|
||||
end -- not luajit with compat52 enabled
|
||||
|
||||
if not is_luajit then
|
||||
local debug_getinfo = debug.getinfo
|
||||
local function calculate_trace_level(co, level)
|
||||
if level ~= nil then
|
||||
for out = 1, 1/0 do
|
||||
local info = (co==nil) and debug_getinfo(out, "") or debug_getinfo(co, out, "")
|
||||
if info == nil then
|
||||
local max = out-1
|
||||
if level <= max then
|
||||
return level
|
||||
end
|
||||
return nil, level-max
|
||||
end
|
||||
end
|
||||
end
|
||||
return 1
|
||||
end
|
||||
|
||||
local stack_pattern = "\nstack traceback:"
|
||||
local stack_replace = ""
|
||||
local debug_traceback = debug.traceback
|
||||
debug.traceback = function (co, msg, level)
|
||||
local lvl
|
||||
local nilmsg
|
||||
if _type(co) ~= "thread" then
|
||||
co, msg, level = coroutine_running(), co, msg
|
||||
end
|
||||
if msg == nil then
|
||||
msg = ""
|
||||
nilmsg = true
|
||||
elseif _type(msg) ~= "string" then
|
||||
return msg
|
||||
end
|
||||
if co == nil then
|
||||
msg = debug_traceback(msg, level or 1)
|
||||
else
|
||||
local xpco = xpcall_running[co]
|
||||
if xpco ~= nil then
|
||||
lvl, level = calculate_trace_level(xpco, level)
|
||||
if lvl then
|
||||
msg = debug_traceback(xpco, msg, lvl)
|
||||
else
|
||||
msg = msg..stack_pattern
|
||||
end
|
||||
lvl, level = calculate_trace_level(co, level)
|
||||
if lvl then
|
||||
local trace = debug_traceback(co, "", lvl)
|
||||
msg = msg..trace:gsub(stack_pattern, stack_replace)
|
||||
end
|
||||
else
|
||||
co = pcall_callOf[co] or co
|
||||
lvl, level = calculate_trace_level(co, level)
|
||||
if lvl then
|
||||
msg = debug_traceback(co, msg, lvl)
|
||||
else
|
||||
msg = msg..stack_pattern
|
||||
end
|
||||
end
|
||||
co = pcall_previous[co]
|
||||
while co ~= nil do
|
||||
lvl, level = calculate_trace_level(co, level)
|
||||
if lvl then
|
||||
local trace = debug_traceback(co, "", lvl)
|
||||
msg = msg..trace:gsub(stack_pattern, stack_replace)
|
||||
end
|
||||
co = pcall_previous[co]
|
||||
end
|
||||
end
|
||||
if nilmsg then
|
||||
msg = msg:gsub("^\n", "")
|
||||
end
|
||||
msg = msg:gsub("\n\t%(tail call%): %?", "\000")
|
||||
msg = msg:gsub("\n\t%.%.%.\n", "\001\n")
|
||||
msg = msg:gsub("\n\t%.%.%.$", "\001")
|
||||
msg = msg:gsub("(%z+)\001(%z+)", function(some, other)
|
||||
return "\n\t(..."..#some+#other.."+ tail call(s)...)"
|
||||
end)
|
||||
msg = msg:gsub("\001(%z+)", function(zeros)
|
||||
return "\n\t(..."..#zeros.."+ tail call(s)...)"
|
||||
end)
|
||||
msg = msg:gsub("(%z+)\001", function(zeros)
|
||||
return "\n\t(..."..#zeros.."+ tail call(s)...)"
|
||||
end)
|
||||
msg = msg:gsub("%z+", function(zeros)
|
||||
return "\n\t(..."..#zeros.." tail call(s)...)"
|
||||
end)
|
||||
msg = msg:gsub("\001", function(zeros)
|
||||
return "\n\t..."
|
||||
end)
|
||||
return msg
|
||||
end
|
||||
end -- is not luajit
|
||||
end -- debug table available
|
||||
|
||||
if not is_luajit52 then
|
||||
local _pairs = pairs
|
||||
pairs = function(t)
|
||||
local mt = sudo_getmetatable(t)
|
||||
if _type(mt) == "table" and _type(mt.__pairs) == "function" then
|
||||
return mt.__pairs(t)
|
||||
else
|
||||
return _pairs(t)
|
||||
end
|
||||
end
|
||||
|
||||
local _ipairs = ipairs
|
||||
ipairs = function(t)
|
||||
local mt = sudo_getmetatable(t)
|
||||
if _type(mt) == "table" and _type(mt.__ipairs) == "function" then
|
||||
return mt.__ipairs(t)
|
||||
else
|
||||
return _ipairs(t)
|
||||
end
|
||||
end
|
||||
end -- not luajit with compat52 enabled
|
||||
|
||||
if not is_luajit then
|
||||
local function check_mode(mode, prefix)
|
||||
local has = { text = false, binary = false }
|
||||
for i = 1,#mode do
|
||||
local c = mode:sub(i, i)
|
||||
if c == "t" then has.text = true end
|
||||
if c == "b" then has.binary = true end
|
||||
end
|
||||
local t = prefix:sub(1, 1) == "\27" and "binary" or "text"
|
||||
if not has[t] then
|
||||
return "attempt to load a "..t.." chunk (mode is '"..mode.."')"
|
||||
end
|
||||
end
|
||||
|
||||
local _setfenv = setfenv
|
||||
local _load, _loadstring = load, loadstring
|
||||
load = function(ld, source, mode, env)
|
||||
mode = mode or "bt"
|
||||
local chunk, msg
|
||||
if _type( ld ) == "string" then
|
||||
if mode ~= "bt" then
|
||||
local merr = check_mode(mode, ld)
|
||||
if merr then return nil, merr end
|
||||
end
|
||||
chunk, msg = _loadstring(ld, source)
|
||||
else
|
||||
local ld_type = _type(ld)
|
||||
if ld_type ~= "function" then
|
||||
_error("bad argument #1 to 'load' (function expected, got "..ld_type..")", 2)
|
||||
end
|
||||
if mode ~= "bt" then
|
||||
local checked, merr = false, nil
|
||||
local function checked_ld()
|
||||
if checked then
|
||||
return ld()
|
||||
else
|
||||
checked = true
|
||||
local v = ld()
|
||||
merr = check_mode(mode, v or "")
|
||||
if merr then return nil end
|
||||
return v
|
||||
end
|
||||
end
|
||||
chunk, msg = _load(checked_ld, source)
|
||||
if merr then return nil, merr end
|
||||
else
|
||||
chunk, msg = _load(ld, source)
|
||||
end
|
||||
end
|
||||
if not chunk then
|
||||
return chunk, msg
|
||||
end
|
||||
if env ~= nil then
|
||||
_setfenv(chunk, env)
|
||||
end
|
||||
return chunk
|
||||
end
|
||||
|
||||
loadstring = load
|
||||
|
||||
local _loadfile = loadfile
|
||||
local io_open = io.open
|
||||
loadfile = function(file, mode, env)
|
||||
mode = mode or "bt"
|
||||
if mode ~= "bt" then
|
||||
local f = io_open(file, "rb")
|
||||
if f then
|
||||
local prefix = f:read(1)
|
||||
f:close()
|
||||
if prefix then
|
||||
local merr = check_mode(mode, prefix)
|
||||
if merr then return nil, merr end
|
||||
end
|
||||
end
|
||||
end
|
||||
local chunk, msg = _loadfile(file)
|
||||
if not chunk then
|
||||
return chunk, msg
|
||||
end
|
||||
if env ~= nil then
|
||||
_setfenv(chunk, env)
|
||||
end
|
||||
return chunk
|
||||
end
|
||||
end -- not luajit
|
||||
|
||||
if not is_luajit52 then
|
||||
function rawlen(v)
|
||||
local t = _type(v)
|
||||
if t ~= "string" and t ~= "table" then
|
||||
_error("bad argument #1 to 'rawlen' (table or string expected)", 2)
|
||||
end
|
||||
return #v
|
||||
end
|
||||
end -- not luajit with compat52 enabled
|
||||
|
||||
local gc_isrunning = true
|
||||
local _collectgarbage = collectgarbage
|
||||
local math_floor = math.floor
|
||||
collectgarbage = function(opt, ...)
|
||||
opt = opt or "collect"
|
||||
local v = 0
|
||||
if opt == "collect" then
|
||||
v = _collectgarbage(opt, ...)
|
||||
if not gc_isrunning then _collectgarbage("stop") end
|
||||
elseif opt == "stop" then
|
||||
gc_isrunning = false
|
||||
return _collectgarbage(opt, ...)
|
||||
elseif opt == "restart" then
|
||||
gc_isrunning = true
|
||||
return _collectgarbage(opt, ...)
|
||||
elseif opt == "count" then
|
||||
v = _collectgarbage(opt, ...)
|
||||
return v, (v-math_floor(v))*1024
|
||||
elseif opt == "step" then
|
||||
v = _collectgarbage(opt, ...)
|
||||
if not gc_isrunning then _collectgarbage("stop") end
|
||||
elseif opt == "isrunning" then
|
||||
return gc_isrunning
|
||||
elseif opt ~= "generational" and opt ~= "incremental" then
|
||||
return _collectgarbage(opt, ...)
|
||||
end
|
||||
return v
|
||||
end
|
||||
|
||||
if not is_luajit52 then
|
||||
local os_execute = os.execute
|
||||
local bit32_rshift = bit32.rshift
|
||||
os.execute = function(cmd)
|
||||
local code = os_execute(cmd)
|
||||
-- Lua 5.1 does not report exit by signal.
|
||||
if code == 0 then
|
||||
return true, "exit", code
|
||||
else
|
||||
return nil, "exit", bit32_rshift(code, 8)
|
||||
end
|
||||
end
|
||||
end -- not luajit with compat52 enabled
|
||||
|
||||
if not is_luajit52 then
|
||||
table.pack = function(...)
|
||||
return { n = _select('#', ...), ... }
|
||||
end
|
||||
|
||||
table.unpack = _unpack
|
||||
end -- not luajit with compat52 enabled
|
||||
|
||||
|
||||
local main_coroutine = coroutine.create(function() end)
|
||||
|
||||
local _assert = assert
|
||||
local _pcall = pcall
|
||||
local coroutine_create = coroutine.create
|
||||
coroutine.create = function (func)
|
||||
local success, result = _pcall(coroutine_create, func)
|
||||
if not success then
|
||||
_assert(_type(func) == "function", "bad argument #1 (function expected)")
|
||||
result = coroutine_create(function(...) return func(...) end)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
local pcall_mainOf = setmetatable({}, weak_meta)
|
||||
|
||||
if not is_luajit52 then
|
||||
coroutine.running = function()
|
||||
local co = coroutine_running()
|
||||
if co then
|
||||
return pcall_mainOf[co] or co, false
|
||||
else
|
||||
return main_coroutine, true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local coroutine_yield = coroutine.yield
|
||||
coroutine.yield = function(...)
|
||||
local co, flag = coroutine_running()
|
||||
if co and not flag then
|
||||
return coroutine_yield(...)
|
||||
else
|
||||
_error("attempt to yield from outside a coroutine", 0)
|
||||
end
|
||||
end
|
||||
|
||||
if not is_luajit then
|
||||
local coroutine_resume = coroutine.resume
|
||||
coroutine.resume = function(co, ...)
|
||||
if co == main_coroutine then
|
||||
return false, "cannot resume non-suspended coroutine"
|
||||
else
|
||||
return coroutine_resume(co, ...)
|
||||
end
|
||||
end
|
||||
|
||||
local coroutine_status = coroutine.status
|
||||
coroutine.status = function(co)
|
||||
local notmain = coroutine_running()
|
||||
if co == main_coroutine then
|
||||
return notmain and "normal" or "running"
|
||||
else
|
||||
return coroutine_status(co)
|
||||
end
|
||||
end
|
||||
|
||||
local function pcall_results(current, call, success, ...)
|
||||
if coroutine_status(call) == "suspended" then
|
||||
return pcall_results(current, call, coroutine_resume(call, coroutine_yield(...)))
|
||||
end
|
||||
if pcall_previous then
|
||||
pcall_previous[call] = nil
|
||||
local main = pcall_mainOf[call]
|
||||
if main == current then current = nil end
|
||||
pcall_callOf[main] = current
|
||||
end
|
||||
pcall_mainOf[call] = nil
|
||||
return success, ...
|
||||
end
|
||||
local function pcall_exec(current, call, ...)
|
||||
local main = pcall_mainOf[current] or current
|
||||
pcall_mainOf[call] = main
|
||||
if pcall_previous then
|
||||
pcall_previous[call] = current
|
||||
pcall_callOf[main] = call
|
||||
end
|
||||
return pcall_results(current, call, coroutine_resume(call, ...))
|
||||
end
|
||||
local coroutine_create52 = coroutine.create
|
||||
local function pcall_coroutine(func)
|
||||
if _type(func) ~= "function" then
|
||||
local callable = func
|
||||
func = function (...) return callable(...) end
|
||||
end
|
||||
return coroutine_create52(func)
|
||||
end
|
||||
pcall = function (func, ...)
|
||||
local current = coroutine_running()
|
||||
if not current then return _pcall(func, ...) end
|
||||
return pcall_exec(current, pcall_coroutine(func), ...)
|
||||
end
|
||||
|
||||
local _tostring = tostring
|
||||
local function xpcall_catch(current, call, msgh, success, ...)
|
||||
if not success then
|
||||
xpcall_running[current] = call
|
||||
local ok, result = _pcall(msgh, ...)
|
||||
xpcall_running[current] = nil
|
||||
if not ok then
|
||||
return false, "error in error handling (".._tostring(result)..")"
|
||||
end
|
||||
return false, result
|
||||
end
|
||||
return true, ...
|
||||
end
|
||||
local _xpcall = xpcall
|
||||
xpcall = function(f, msgh, ...)
|
||||
local current = coroutine_running()
|
||||
if not current then
|
||||
local args, n = { ... }, _select('#', ...)
|
||||
return _xpcall(function() return f(_unpack(args, 1, n)) end, msgh)
|
||||
end
|
||||
local call = pcall_coroutine(f)
|
||||
return xpcall_catch(current, call, msgh, pcall_exec(current, call, ...))
|
||||
end
|
||||
end -- not luajit
|
||||
|
||||
if not is_luajit then
|
||||
local math_log = math.log
|
||||
math.log = function(x, base)
|
||||
if base ~= nil then
|
||||
return math_log(x)/math_log(base)
|
||||
else
|
||||
return math_log(x)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local package = package
|
||||
if not is_luajit then
|
||||
local io_open = io.open
|
||||
local table_concat = table.concat
|
||||
package.searchpath = function(name, path, sep, rep)
|
||||
sep = (sep or "."):gsub("(%p)", "%%%1")
|
||||
rep = (rep or package.config:sub(1, 1)):gsub("(%%)", "%%%1")
|
||||
local pname = name:gsub(sep, rep):gsub("(%%)", "%%%1")
|
||||
local msg = {}
|
||||
for subpath in path:gmatch("[^;]+") do
|
||||
local fpath = subpath:gsub("%?", pname)
|
||||
local f = io_open(fpath, "r")
|
||||
if f then
|
||||
f:close()
|
||||
return fpath
|
||||
end
|
||||
msg[#msg+1] = "\n\tno file '" .. fpath .. "'"
|
||||
end
|
||||
return nil, table_concat(msg)
|
||||
end
|
||||
end -- not luajit
|
||||
|
||||
local p_index = { searchers = package.loaders }
|
||||
local _rawset = rawset
|
||||
setmetatable(package, {
|
||||
__index = p_index,
|
||||
__newindex = function(p, k, v)
|
||||
if k == "searchers" then
|
||||
_rawset(p, "loaders", v)
|
||||
p_index.searchers = v
|
||||
else
|
||||
_rawset(p, k, v)
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
local string_gsub = string.gsub
|
||||
local function fix_pattern(pattern)
|
||||
return (string_gsub(pattern, "%z", "%%z"))
|
||||
end
|
||||
|
||||
local string_find = string.find
|
||||
function string.find(s, pattern, ...)
|
||||
return string_find(s, fix_pattern(pattern), ...)
|
||||
end
|
||||
|
||||
local string_gmatch = string.gmatch
|
||||
function string.gmatch(s, pattern)
|
||||
return string_gmatch(s, fix_pattern(pattern))
|
||||
end
|
||||
|
||||
function string.gsub(s, pattern, ...)
|
||||
return string_gsub(s, fix_pattern(pattern), ...)
|
||||
end
|
||||
|
||||
local string_match = string.match
|
||||
function string.match(s, pattern, ...)
|
||||
return string_match(s, fix_pattern(pattern), ...)
|
||||
end
|
||||
|
||||
if not is_luajit then
|
||||
local string_rep = string.rep
|
||||
function string.rep(s, n, sep)
|
||||
if sep ~= nil and sep ~= "" and n >= 2 then
|
||||
return s .. string_rep(sep..s, n-1)
|
||||
else
|
||||
return string_rep(s, n)
|
||||
end
|
||||
end
|
||||
end -- not luajit
|
||||
|
||||
if not is_luajit then
|
||||
local _tostring = tostring
|
||||
local string_format = string.format
|
||||
do
|
||||
local addqt = {
|
||||
["\n"] = "\\\n",
|
||||
["\\"] = "\\\\",
|
||||
["\""] = "\\\""
|
||||
}
|
||||
|
||||
local function addquoted(c)
|
||||
return addqt[c] or string_format("\\%03d", c:byte())
|
||||
end
|
||||
|
||||
function string.format(fmt, ...)
|
||||
local args, n = { ... }, _select('#', ...)
|
||||
local i = 0
|
||||
local function adjust_fmt(lead, mods, kind)
|
||||
if #lead % 2 == 0 then
|
||||
i = i + 1
|
||||
if kind == "s" then
|
||||
args[i] = _tostring(args[i])
|
||||
elseif kind == "q" then
|
||||
args[i] = '"'..string_gsub(args[i], "[%z%c\\\"\n]", addquoted)..'"'
|
||||
return lead.."%"..mods.."s"
|
||||
end
|
||||
end
|
||||
end
|
||||
fmt = string_gsub(fmt, "(%%*)%%([%d%.%-%+%# ]*)(%a)", adjust_fmt)
|
||||
return string_format(fmt, _unpack(args, 1, n))
|
||||
end
|
||||
end
|
||||
end -- not luajit
|
||||
|
||||
local io_open = io.open
|
||||
local io_write = io.write
|
||||
local io_output = io.output
|
||||
function io.write(...)
|
||||
local res, msg, errno = io_write(...)
|
||||
if res then
|
||||
return io_output()
|
||||
else
|
||||
return nil, msg, errno
|
||||
end
|
||||
end
|
||||
|
||||
if not is_luajit then
|
||||
local lines_iterator
|
||||
do
|
||||
local function helper( st, var_1, ... )
|
||||
if var_1 == nil then
|
||||
if st.doclose then st.f:close() end
|
||||
if (...) ~= nil then
|
||||
_error((...), 2)
|
||||
end
|
||||
end
|
||||
return var_1, ...
|
||||
end
|
||||
|
||||
function lines_iterator(st)
|
||||
return helper(st, st.f:read(_unpack(st, 1, st.n)))
|
||||
end
|
||||
end
|
||||
|
||||
local valid_format = { ["*l"] = true, ["*n"] = true, ["*a"] = true }
|
||||
|
||||
local io_input = io.input
|
||||
function io.lines(fname, ...)
|
||||
local doclose, file, msg
|
||||
if fname ~= nil then
|
||||
doclose, file, msg = true, io_open(fname, "r")
|
||||
if not file then _error(msg, 2) end
|
||||
else
|
||||
doclose, file = false, io_input()
|
||||
end
|
||||
local st = { f=file, doclose=doclose, n=_select('#', ...), ... }
|
||||
for i = 1, st.n do
|
||||
if _type(st[i]) ~= "number" and not valid_format[st[i]] then
|
||||
_error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2)
|
||||
end
|
||||
end
|
||||
return lines_iterator, st
|
||||
end
|
||||
|
||||
do
|
||||
local io_stdout = io.stdout
|
||||
local io_type = io.type
|
||||
local file_meta = sudo_getmetatable(io_stdout)
|
||||
if _type(file_meta) == "table" and _type(file_meta.__index) == "table" then
|
||||
local file_write = file_meta.__index.write
|
||||
file_meta.__index.write = function(self, ...)
|
||||
local res, msg, errno = file_write(self, ...)
|
||||
if res then
|
||||
return self
|
||||
else
|
||||
return nil, msg, errno
|
||||
end
|
||||
end
|
||||
|
||||
file_meta.__index.lines = function(self, ...)
|
||||
if io_type(self) == "closed file" then
|
||||
_error("attempt to use a closed file", 2)
|
||||
end
|
||||
local st = { f=self, doclose=false, n=_select('#', ...), ... }
|
||||
for i = 1, st.n do
|
||||
if _type(st[i]) ~= "number" and not valid_format[st[i]] then
|
||||
_error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2)
|
||||
end
|
||||
end
|
||||
return lines_iterator, st
|
||||
end
|
||||
end
|
||||
end
|
||||
end -- not luajit
|
||||
|
||||
end
|
107
src/compat52/mstrict.lua
Normal file
107
src/compat52/mstrict.lua
Normal file
@ -0,0 +1,107 @@
|
||||
|
||||
--- Stricter version of compat52.
|
||||
-- Attempts to emulate Lua 5.2 when built without LUA_COMPAT_ALL.
|
||||
|
||||
|
||||
if _VERSION == "Lua 5.1" then
|
||||
|
||||
require("compat52")
|
||||
|
||||
local function not_available()
|
||||
error("This function is not available in Lua 5.2!", 2)
|
||||
end
|
||||
|
||||
local exclude_from_G = {
|
||||
module = not_available,
|
||||
getfenv = not_available,
|
||||
setfenv = not_available,
|
||||
loadstring = not_available,
|
||||
unpack = not_available,
|
||||
loadlib = not_available,
|
||||
math = {
|
||||
log10 = not_available,
|
||||
mod = not_available,
|
||||
},
|
||||
table = {
|
||||
getn = not_available,
|
||||
setn = not_available,
|
||||
},
|
||||
string = {
|
||||
gfind = not_available,
|
||||
},
|
||||
}
|
||||
|
||||
local next = next
|
||||
local function make_pairs_iterator(lookup)
|
||||
return function(st, var)
|
||||
local k, v = next(st, var)
|
||||
if k ~= nil then
|
||||
local new_v = lookup[k]
|
||||
if new_v ~= nil then v = new_v end
|
||||
return k, v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local rawget = rawget
|
||||
local function make_ipairs_iterator(lookup)
|
||||
return function(st, var)
|
||||
var = var + 1
|
||||
local v = rawget(st, var)
|
||||
if v ~= nil then
|
||||
local new_v = lookup[var]
|
||||
if new_v ~= nil then v = new_v end
|
||||
return var, v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function make_copy(value, excl)
|
||||
local v_type, e_type = type(value), type(excl)
|
||||
if v_type == e_type then
|
||||
if v_type == "table" then
|
||||
local l_table = {}
|
||||
for k, v in pairs(excl) do
|
||||
l_table[k] = make_copy(rawget(value, k), v)
|
||||
end
|
||||
local pairs_iterator = make_pairs_iterator(l_table)
|
||||
local ipairs_iterator = make_ipairs_iterator(l_table)
|
||||
return setmetatable({}, {
|
||||
__index = function(_, k)
|
||||
local v = l_table[k]
|
||||
if v ~= nil then
|
||||
return v
|
||||
else
|
||||
return value[k]
|
||||
end
|
||||
end,
|
||||
__newindex = function(_, k, v)
|
||||
if l_table[k] ~= nil then
|
||||
l_table[k] = nil
|
||||
end
|
||||
value[k] = v
|
||||
end,
|
||||
__pairs = function()
|
||||
return pairs_iterator, value, nil
|
||||
end,
|
||||
__ipairs = function()
|
||||
return ipairs_iterator, value, 0
|
||||
end,
|
||||
}), l_table
|
||||
elseif v_type == "function" then
|
||||
return excl
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local new_G, G_lookup = make_copy(_G, exclude_from_G)
|
||||
G_lookup._G = new_G
|
||||
|
||||
return function()
|
||||
setfenv(2, new_G)
|
||||
end
|
||||
else
|
||||
return function() end
|
||||
end
|
||||
|
||||
-- vi: set expandtab softtabstop=3 shiftwidth=3 :
|
23
src/compat52/strict.lua
Normal file
23
src/compat52/strict.lua
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
--- Stricter version of compat52.
|
||||
-- Attempts to emulate Lua 5.2 when built without LUA_COMPAT_ALL.
|
||||
|
||||
require("compat52")
|
||||
|
||||
if _VERSION == "Lua 5.1" then
|
||||
|
||||
module = nil
|
||||
setfenv = nil
|
||||
getfenv = nil
|
||||
math.log10 = nil
|
||||
loadstring = nil
|
||||
table.maxn = nil
|
||||
unpack = nil
|
||||
-- functions deprecated in Lua 5.1 are also not available:
|
||||
table.getn = nil
|
||||
table.setn = nil
|
||||
loadlib = nil
|
||||
math.mod = nil
|
||||
string.gfind = nil
|
||||
|
||||
end
|
23
src/component/computer.lua
Normal file
23
src/component/computer.lua
Normal file
@ -0,0 +1,23 @@
|
||||
-- computer component
|
||||
local obj = {}
|
||||
|
||||
function obj.isRunning() -- Returns whether the computer is running.
|
||||
--STUB
|
||||
cprint("computer.isRunning")
|
||||
end
|
||||
function obj.beep(frequency, duration) -- Plays a tone, useful to alert users via audible feedback.
|
||||
--STUB
|
||||
cprint("computer.beep", frequency, duration)
|
||||
end
|
||||
function obj.stop() -- Stops the computer. Returns true if the state changed.
|
||||
--STUB
|
||||
cprint("computer.stop")
|
||||
end
|
||||
function obj.start() -- Starts the computer. Returns true if the state changed.
|
||||
--STUB
|
||||
cprint("computer.start")
|
||||
end
|
||||
|
||||
local cec = {}
|
||||
|
||||
return obj,cec
|
53
src/component/eeprom.lua
Normal file
53
src/component/eeprom.lua
Normal file
@ -0,0 +1,53 @@
|
||||
local address, slot, filename = ...
|
||||
|
||||
local code = love.filesystem.read(filename)
|
||||
local data = ""
|
||||
local label = "EEPROM"
|
||||
|
||||
-- eeprom component
|
||||
local obj = {}
|
||||
|
||||
function obj.getData() -- Get the currently stored byte array.
|
||||
cprint("eeprom.getData")
|
||||
return data
|
||||
end
|
||||
function obj.setData(newdata) -- Overwrite the currently stored byte array.
|
||||
cprint("eeprom.setData", newdata)
|
||||
data = newdata -- TODO
|
||||
end
|
||||
function obj.getDataSize() -- Get the storage capacity of this EEPROM.
|
||||
cprint("eeprom.getDataSize")
|
||||
return math.huge -- STUB
|
||||
end
|
||||
function obj.getSize() -- Get the storage capacity of this EEPROM.
|
||||
cprint("eeprom.getSize")
|
||||
return math.huge -- STUB
|
||||
end
|
||||
function obj.getLabel() -- Get the label of the EEPROM.
|
||||
cprint("eeprom.getLabel")
|
||||
return label
|
||||
end
|
||||
function obj.setLabel(newlabel) -- Set the label of the EEPROM.
|
||||
cprint("eeprom.setLabel", newlabel)
|
||||
label = newlabel -- TODO
|
||||
end
|
||||
function obj.getChecksum() -- Get the checksum of the data on this EEPROM.
|
||||
cprint("eeprom.getChecksum")
|
||||
return "1badbabe" -- STUB
|
||||
end
|
||||
function obj.get() -- Get the currently stored byte array.
|
||||
cprint("eeprom.get")
|
||||
return code
|
||||
end
|
||||
function obj.set(newcode) -- Overwrite the currently stored byte array.
|
||||
cprint("eeprom.set", newcode)
|
||||
code = newcode -- TODO
|
||||
end
|
||||
function obj.makeReadonly(checksum) -- Make this EEPROM readonly if it isn't already. This process cannot be reversed!
|
||||
--STUB
|
||||
print("eeprom.makeReadonly", checksum)
|
||||
end
|
||||
|
||||
local cec = {}
|
||||
|
||||
return obj,cec
|
139
src/component/filesystem.lua
Normal file
139
src/component/filesystem.lua
Normal file
@ -0,0 +1,139 @@
|
||||
local address, slot, directory, readonly = ...
|
||||
|
||||
if not love.filesystem.exists(directory) then
|
||||
love.filesystem.createDirectory(directory)
|
||||
end
|
||||
|
||||
if directory == "tmpfs" then
|
||||
computer.setTempAddress(address)
|
||||
end
|
||||
|
||||
local label = ("/" .. directory):match(".*/(.+)")
|
||||
local handles = {}
|
||||
|
||||
local function cleanPath(path)
|
||||
local path = path:gsub("\\", "/")
|
||||
|
||||
local tPath = {}
|
||||
for part in path:gmatch("[^/]+") do
|
||||
if part ~= "" and part ~= "." then
|
||||
if part == ".." and #tPath > 0 and tPath[#tPath] ~= ".." then
|
||||
table.remove(tPath)
|
||||
else
|
||||
table.insert(tPath, part:sub(1,255))
|
||||
end
|
||||
end
|
||||
end
|
||||
return table.concat(tPath, "/")
|
||||
end
|
||||
|
||||
-- filesystem component
|
||||
local obj = {}
|
||||
|
||||
function obj.read(handle, count) -- Reads up to the specified amount of data from an open file descriptor with the specified handle. Returns nil when EOF is reached.
|
||||
--TODO
|
||||
cprint("filesystem.read", handle, count)
|
||||
if count == math.huge then count = nil end
|
||||
local ret = { handles[handle]:read(count) }
|
||||
if ret[1] ~= nil then ret[2] = nil end
|
||||
if ret[1] == "" and count ~= 0 then ret[1] = nil end
|
||||
return table.unpack(ret)
|
||||
end
|
||||
function obj.lastModified(path) -- Returns the (real world) timestamp of when the object at the specified absolute path in the file system was modified.
|
||||
--STUB
|
||||
cprint("filesystem.lastModified", path)
|
||||
end
|
||||
function obj.spaceUsed() -- The currently used capacity of the file system, in bytes.
|
||||
--STUB
|
||||
cprint("filesystem.spaceUsed")
|
||||
end
|
||||
function obj.rename(from, to) -- Renames/moves an object from the first specified absolute path in the file system to the second.
|
||||
--STUB
|
||||
cprint("filesystem.rename", from, to)
|
||||
end
|
||||
function obj.close(handle) -- Closes an open file descriptor with the specified handle.
|
||||
--TODO
|
||||
cprint("filesystem.close", handle)
|
||||
handles[handle]:close()
|
||||
handles[handle] = nil
|
||||
end
|
||||
function obj.write(handle, value) -- Writes the specified data to an open file descriptor with the specified handle.
|
||||
--STUB
|
||||
cprint("filesystem.write", handle, value)
|
||||
end
|
||||
function obj.remove(path) -- Removes the object at the specified absolute path in the file system.
|
||||
--STUB
|
||||
cprint("filesystem.remove", path)
|
||||
end
|
||||
function obj.size(path) -- Returns the size of the object at the specified absolute path in the file system.
|
||||
--STUB
|
||||
cprint("filesystem.size", path)
|
||||
end
|
||||
function obj.seek(handle, whence, offset) -- Seeks in an open file descriptor with the specified handle. Returns the new pointer position.
|
||||
--STUB
|
||||
cprint("filesystem.seek", handle, whence, offset)
|
||||
end
|
||||
function obj.spaceTotal() -- The overall capacity of the file system, in bytes.
|
||||
--STUB
|
||||
cprint("filesystem.spaceTotal")
|
||||
end
|
||||
function obj.getLabel() -- Get the current label of the file system.
|
||||
--TODO
|
||||
cprint("filesystem.getLabel")
|
||||
return label
|
||||
end
|
||||
function obj.setLabel(value) -- Sets the label of the file system. Returns the new value, which may be truncated.
|
||||
--TODO
|
||||
cprint("filesystem.setLabel", value)
|
||||
label = value
|
||||
end
|
||||
function obj.open(path, mode) -- Opens a new file descriptor and returns its handle.
|
||||
--TODO
|
||||
cprint("filesystem.open", path, mode)
|
||||
if mode == nil then mode = "r" end
|
||||
compCheckArg(1,path,"string")
|
||||
compCheckArg(2,mode,"string")
|
||||
local file = love.filesystem.newFile(directory .. "/" .. path, mode:sub(1,1))
|
||||
if not file then return nil end
|
||||
while true do
|
||||
local rnddescrpt = math.random(1000000000,9999999999)
|
||||
if handles[rnddescrpt] == nil then
|
||||
handles[rnddescrpt] = file
|
||||
return rnddescrpt
|
||||
end
|
||||
end
|
||||
end
|
||||
function obj.exists(path) -- Returns whether an object exists at the specified absolute path in the file system.
|
||||
--TODO
|
||||
cprint("filesystem.exists", path)
|
||||
return love.filesystem.exists(directory .. "/" .. path)
|
||||
end
|
||||
function obj.list(path) -- Returns a list of names of objects in the directory at the specified absolute path in the file system.
|
||||
--TODO
|
||||
cprint("filesystem.list", path)
|
||||
local list = love.filesystem.getDirectoryItems(directory .. "/" .. path)
|
||||
for i = 1,#list do
|
||||
if love.filesystem.isDirectory(directory .. "/" .. path .. "/" .. list[i]) then
|
||||
list[i] = list[i] .. "/"
|
||||
end
|
||||
end
|
||||
return list
|
||||
end
|
||||
function obj.isReadOnly() -- Returns whether the file system is read-only.
|
||||
--STUB
|
||||
cprint("filesystem.isReadOnly")
|
||||
return readonly
|
||||
end
|
||||
function obj.makeDirectory(path) -- Creates a directory at the specified absolute path in the file system. Creates parent directories, if necessary.
|
||||
--STUB
|
||||
cprint("filesystem.makeDirectory", path)
|
||||
end
|
||||
function obj.isDirectory(path) -- Returns whether the object at the specified absolute path in the file system is a directory.
|
||||
--STUB
|
||||
cprint("filesystem.isDirectory", path)
|
||||
return love.filesystem.isDirectory(directory .. "/" .. path)
|
||||
end
|
||||
|
||||
local cec = {}
|
||||
|
||||
return obj,cec
|
202
src/component/gpu.lua
Normal file
202
src/component/gpu.lua
Normal file
@ -0,0 +1,202 @@
|
||||
local address, slot, maxwidth, maxheight, maxtier = ...
|
||||
|
||||
local lua_utf8 = require("utf8")
|
||||
|
||||
local bindaddress
|
||||
local depthTbl = {1,4,8}
|
||||
local rdepthTbl = {1,nil,nil,2,nil,nil,nil,3}
|
||||
|
||||
-- gpu component
|
||||
local obj = {}
|
||||
|
||||
function obj.bind(address) -- Binds the GPU to the screen with the specified address.
|
||||
cprint("gpu.bind", address)
|
||||
compCheckArg(1,address,"string")
|
||||
local thing = component.exists(address)
|
||||
if thing == nil then
|
||||
return nil, "invalid address"
|
||||
elseif thing ~= "screen" then
|
||||
return nil, "not a screen"
|
||||
end
|
||||
bindaddress = address
|
||||
end
|
||||
function obj.getForeground() -- Get the current foreground color and whether it's from the palette or not.
|
||||
cprint("gpu.getForeground")
|
||||
if bindaddress == nil then
|
||||
return nil, "no screen"
|
||||
end
|
||||
return component.cecinvoke(bindaddress, "getForeground")
|
||||
end
|
||||
function obj.setForeground(value, palette) -- Sets the foreground color to the specified value. Optionally takes an explicit palette index. Returns the old value and if it was from the palette its palette index.
|
||||
cprint("gpu.setForeground", value, palette)
|
||||
compCheckArg(1,value,"number")
|
||||
compCheckArg(2,palette,"boolean","nil")
|
||||
if bindaddress == nil then
|
||||
return nil, "no screen"
|
||||
end
|
||||
if palette and component.cecinvoke(bindaddress, "getDepth") == 1 then
|
||||
error("color palette not suppported",3)
|
||||
end
|
||||
if palette == true and (value < 0 or value > 15) then
|
||||
error("invalid palette index",3)
|
||||
end
|
||||
return component.cecinvoke(bindaddress, "setForeground", value, palette)
|
||||
end
|
||||
function obj.getBackground() -- Get the current background color and whether it's from the palette or not.
|
||||
cprint("gpu.getBackground")
|
||||
if bindaddress == nil then
|
||||
return nil, "no screen"
|
||||
end
|
||||
return component.cecinvoke(bindaddress, "getBackground")
|
||||
end
|
||||
function obj.setBackground(value, palette) -- Sets the background color to the specified value. Optionally takes an explicit palette index. Returns the old value and if it was from the palette its palette index.
|
||||
cprint("gpu.setBackground", value, palette)
|
||||
compCheckArg(1,value,"number")
|
||||
compCheckArg(2,palette,"boolean","nil")
|
||||
if bindaddress == nil then
|
||||
return nil, "no screen"
|
||||
end
|
||||
if palette and component.cecinvoke(bindaddress, "getDepth") == 1 then
|
||||
error("color palette not suppported",3)
|
||||
end
|
||||
value = math.floor(value)
|
||||
if palette and (value < 0 or value > 15) then
|
||||
error("invalid palette index",3)
|
||||
end
|
||||
return component.cecinvoke(bindaddress, "setBackground", value, palette)
|
||||
end
|
||||
function obj.getDepth() -- Returns the currently set color depth.
|
||||
cprint("gpu.getDepth")
|
||||
return depthTbl[component.cecinvoke(bindaddress, "getDepth")]
|
||||
end
|
||||
function obj.setDepth(depth) -- Set the color depth. Returns the previous value.
|
||||
cprint("gpu.setDepth", depth)
|
||||
compCheckArg(1,depth,"number")
|
||||
if bindaddress == nil then
|
||||
return nil, "no screen"
|
||||
end
|
||||
local scrmax = component.cecinvoke(bindaddress, "maxDepth")
|
||||
if rdepthTbl[depth] == nil or rdepthTbl[depth] > math.max(scrmax, maxtier) then
|
||||
error("unsupported depth",3)
|
||||
end
|
||||
return component.cecinvoke(bindaddress, "setDepth", rdepthTbl[depth])
|
||||
end
|
||||
function obj.maxDepth() -- Get the maximum supported color depth.
|
||||
cprint("gpu.maxDepth")
|
||||
return depthTbl[math.min(component.cecinvoke(bindaddress, "maxDepth"), maxtier)]
|
||||
end
|
||||
function obj.fill(x, y, width, height, char) -- Fills a portion of the screen at the specified position with the specified size with the specified character.
|
||||
cprint("gpu.fill", x, y, width, height, char)
|
||||
compCheckArg(1,x,"number")
|
||||
compCheckArg(2,y,"number")
|
||||
compCheckArg(3,width,"number")
|
||||
compCheckArg(4,height,"number")
|
||||
compCheckArg(5,char,"string")
|
||||
if bindaddress == nil then
|
||||
return nil, "no screen"
|
||||
end
|
||||
if lua_utf8.len(char) ~= 1 then
|
||||
return nil, "invalid fill value"
|
||||
end
|
||||
return component.cecinvoke(bindaddress, "fill", x, y, width, height, char)
|
||||
end
|
||||
function obj.getScreen() -- Get the address of the screen the GPU is currently bound to.
|
||||
cprint("gpu.getScreen")
|
||||
return bindaddress
|
||||
end
|
||||
function obj.getResolution() -- Get the current screen resolution.
|
||||
cprint("gpu.getResolution")
|
||||
if bindaddress == nil then
|
||||
return nil, "no screen"
|
||||
end
|
||||
return component.cecinvoke(bindaddress, "getResolution")
|
||||
end
|
||||
function obj.setResolution(width, height) -- Set the screen resolution. Returns true if the resolution changed.
|
||||
cprint("gpu.setResolution", width, height)
|
||||
compCheckArg(1,width,"number")
|
||||
compCheckArg(2,height,"number")
|
||||
if bindaddress == nil then
|
||||
return nil, "no screen"
|
||||
end
|
||||
return component.cecinvoke(bindaddress, "setResolution", width, height)
|
||||
end
|
||||
function obj.maxResolution() -- Get the maximum screen resolution.
|
||||
cprint("gpu.maxResolution")
|
||||
if bindaddress == nil then
|
||||
return nil, "no screen"
|
||||
end
|
||||
local smw,smh = component.cecinvoke(bindaddress, "maxResolution")
|
||||
return math.min(smw, maxwidth), math.min(smh, maxheight)
|
||||
end
|
||||
function obj.getPaletteColor(index) -- Get the palette color at the specified palette index.
|
||||
cprint("gpu.getPaletteColor", index)
|
||||
compCheckArg(1,index,"number")
|
||||
if bindaddress == nil then
|
||||
return nil, "no screen"
|
||||
end
|
||||
if component.cecinvoke(bindaddress, "getDepth") == 1 then
|
||||
return "palette not available"
|
||||
end
|
||||
index = math.floor(index)
|
||||
if index < 0 or index > 15 then
|
||||
error("invalid palette index",3)
|
||||
end
|
||||
return component.cecinvoke(bindaddress, "getPaletteColor", index)
|
||||
end
|
||||
function obj.setPaletteColor(index, color) -- Set the palette color at the specified palette index. Returns the previous value.
|
||||
cprint("gpu.setPaletteColor", index, color)
|
||||
compCheckArg(1,index,"number")
|
||||
compCheckArg(2,color,"number")
|
||||
if bindaddress == nil then
|
||||
return nil, "no screen"
|
||||
end
|
||||
if component.cecinvoke(bindaddress, "getDepth") == 1 then
|
||||
return "palette not available"
|
||||
end
|
||||
index = math.floor(index)
|
||||
if index < 0 or index > 15 then
|
||||
error("invalid palette index",3)
|
||||
end
|
||||
return component.cecinvoke(bindaddress, "setPaletteColor", index, color)
|
||||
end
|
||||
function obj.get(x, y) -- Get the value displayed on the screen at the specified index, as well as the foreground and background color. If the foreground or background is from the palette, returns the palette indices as fourth and fifth results, else nil, respectively.
|
||||
cprint("gpu.get", x, y)
|
||||
compCheckArg(1,x,"number")
|
||||
compCheckArg(2,y,"number")
|
||||
if bindaddress == nil then
|
||||
return nil, "no screen"
|
||||
end
|
||||
local w,h = component.cecinvoke(bindaddress, "getResolution")
|
||||
if x < 1 or x > w or y < 1 or y > h then
|
||||
error("index out of bounds",3)
|
||||
end
|
||||
return component.cecinvoke(bindaddress, "get", x, y)
|
||||
end
|
||||
function obj.set(x, y, value, vertical) -- Plots a string value to the screen at the specified position. Optionally writes the string vertically.
|
||||
cprint("gpu.set", x, y, value, vertical)
|
||||
compCheckArg(1,x,"number")
|
||||
compCheckArg(2,y,"number")
|
||||
compCheckArg(3,value,"string")
|
||||
compCheckArg(4,vertical,"boolean","nil")
|
||||
if bindaddress == nil then
|
||||
return nil, "no screen"
|
||||
end
|
||||
return component.cecinvoke(bindaddress, "set", x, y, value, vertical)
|
||||
end
|
||||
function obj.copy(x, y, width, height, tx, ty) -- Copies a portion of the screen from the specified location with the specified size by the specified translation.
|
||||
cprint("gpu.copy", x, y, width, height, tx, ty)
|
||||
compCheckArg(1,x,"number")
|
||||
compCheckArg(2,y,"number")
|
||||
compCheckArg(3,width,"number")
|
||||
compCheckArg(4,height,"number")
|
||||
compCheckArg(5,tx,"number")
|
||||
compCheckArg(6,ty,"number")
|
||||
if bindaddress == nil then
|
||||
return nil, "no screen"
|
||||
end
|
||||
return component.cecinvoke(bindaddress, "copy", x, y, width, height, tx, ty)
|
||||
end
|
||||
|
||||
local cec = {}
|
||||
|
||||
return obj,cec
|
92
src/component/keyboard.lua
Normal file
92
src/component/keyboard.lua
Normal file
@ -0,0 +1,92 @@
|
||||
local address = ...
|
||||
|
||||
local lua_utf8 = require("utf8")
|
||||
|
||||
-- Conversion table for Love2D keys to LWJGL key codes
|
||||
local keys = {
|
||||
["q"] = 16, ["w"] = 17, ["e"] = 18, ["r"] = 19,
|
||||
["t"] = 20, ["y"] = 21, ["u"] = 22, ["i"] = 23,
|
||||
["o"] = 24, ["p"] = 25, ["a"] = 30, ["s"] = 31,
|
||||
["d"] = 32, ["f"] = 33, ["g"] = 34, ["h"] = 35,
|
||||
["j"] = 36, ["k"] = 37, ["l"] = 38, ["z"] = 44,
|
||||
["x"] = 45, ["c"] = 46, ["v"] = 47, ["b"] = 48,
|
||||
["n"] = 49, ["m"] = 50,
|
||||
["1"] = 2, ["2"] = 3, ["3"] = 4, ["4"] = 5, ["5"] = 6,
|
||||
["6"] = 7, ["7"] = 8, ["8"] = 9, ["9"] = 10, ["0"] = 11,
|
||||
[" "] = 57,
|
||||
|
||||
["'"] = 40, [","] = 51, ["-"] = 12, ["."] = 52, ["/"] = 53,
|
||||
[":"] = 146, [";"] = 39, ["="] = 13, ["@"] = 145, ["["] = 26,
|
||||
["\\"] = 43, ["]"] = 27, ["^"] = 144, ["_"] = 147, ["`"] = 41,
|
||||
|
||||
["up"] = 200,
|
||||
["down"] = 208,
|
||||
["right"] = 205,
|
||||
["left"] = 203,
|
||||
["home"] = 199,
|
||||
["end"] = 207,
|
||||
["pageup"] = 201,
|
||||
["pagedown"] = 209,
|
||||
["insert"] = 210,
|
||||
["backspace"] = 14,
|
||||
["tab"] = 15,
|
||||
["return"] = 28,
|
||||
["delete"] = 211,
|
||||
["capslock"] = 58,
|
||||
["numlock"] = 69,
|
||||
["scrolllock"] = 70,
|
||||
|
||||
["f1"] = 59,
|
||||
["f2"] = 60,
|
||||
["f3"] = 61,
|
||||
["f4"] = 62,
|
||||
["f5"] = 63,
|
||||
["f6"] = 64,
|
||||
["f7"] = 65,
|
||||
["f8"] = 66,
|
||||
["f9"] = 67,
|
||||
["f10"] = 68,
|
||||
["f12"] = 88,
|
||||
["f13"] = 100,
|
||||
["f14"] = 101,
|
||||
["f15"] = 102,
|
||||
["f16"] = 103,
|
||||
["f17"] = 104,
|
||||
["f18"] = 105,
|
||||
|
||||
["rshift"] = 54,
|
||||
["lshift"] = 42,
|
||||
["rctrl"] = 157,
|
||||
["lctrl"] = 29,
|
||||
["ralt"] = 184,
|
||||
["lalt"] = 56,
|
||||
}
|
||||
|
||||
local code2char = {}
|
||||
|
||||
function love.textinput(t)
|
||||
cprint("textinput",t)
|
||||
kbdcodes[#kbdcodes].char = lua_utf8.codepoint(t)
|
||||
code2char[kbdcodes[#kbdcodes].code] = kbdcodes[#kbdcodes].char
|
||||
end
|
||||
|
||||
function love.keypressed(key)
|
||||
cprint("keypressed",key)
|
||||
table.insert(kbdcodes,{type="key_down",addr=address,code=keys[key]})
|
||||
end
|
||||
|
||||
function love.keyreleased(key)
|
||||
cprint("keyreleased",key)
|
||||
table.insert(kbdcodes,{type="key_up",addr=address,code=keys[key],char=code2char[keys[key]]})
|
||||
end
|
||||
|
||||
-- keyboard component
|
||||
|
||||
-- Much complex
|
||||
local obj = {}
|
||||
|
||||
-- Such methods
|
||||
local cec = {}
|
||||
|
||||
-- Wow
|
||||
return obj,cec
|
245
src/component/screen.lua
Normal file
245
src/component/screen.lua
Normal file
@ -0,0 +1,245 @@
|
||||
local address, slot, maxwidth, maxheight, maxtier = ...
|
||||
|
||||
local lua_utf8 = require("utf8")
|
||||
|
||||
local width, height, tier = maxwidth, maxheight, maxtier
|
||||
local scrfgc, scrfgp = 0xFFFFFF
|
||||
local scrbgc, scrfgp = 0x000000
|
||||
local palcol
|
||||
if tier == 3 then
|
||||
palcol = {}
|
||||
for i = 0,15 do
|
||||
palcol[i] = i * 0x111111
|
||||
end
|
||||
else
|
||||
palcol = {[0]=0xFFFFFF,0xFFCC33,0xCC66CC,0x6699FF,0xFFFF33,0x33CC33,0xFF6699,0x333333,0xCCCCCC,0x336699,0x9933CC,0x333399,0x663300,0x336600,0xFF3333,0x000000}
|
||||
end
|
||||
local screen = {txt = {}, fg = {}, bg = {}, fgp = {}, bgp = {}}
|
||||
for y = 1,height do
|
||||
screen.txt[y] = {}
|
||||
screen.fg[y] = {}
|
||||
screen.bg[y] = {}
|
||||
screen.fgp[y] = {}
|
||||
screen.bgp[y] = {}
|
||||
for x = 1,width do
|
||||
screen.txt[y][x] = " "
|
||||
screen.fg[y][x] = scrfgc
|
||||
screen.bg[y][x] = scrbgc
|
||||
screen.fgp[y][x] = scrfgp
|
||||
screen.bgp[y][x] = scrbgp
|
||||
end
|
||||
end
|
||||
|
||||
function z(val)
|
||||
local size = val < 0x10000 and (val < 0x800 and (val < 0x80 and 1 or 2) or 3) or 4
|
||||
if size == 1 then return string.char(val) end
|
||||
local b = {string.char((240*2^(4-size)%256)+(val/2^(size*6-6))%(2^(7-size)))}
|
||||
for i = size*6-12,0,-6 do
|
||||
b[#b+1] = string.char(128+(val/2^i)%64)
|
||||
end
|
||||
return table.concat(b)
|
||||
end
|
||||
|
||||
love.window.setMode(width*8, height*16,{})
|
||||
|
||||
local idata = love.image.newImageData(width*8, height*16)
|
||||
idata:mapPixel(function() return 0,0,0,255 end)
|
||||
local image = love.graphics.newImage(idata)
|
||||
|
||||
function love.draw()
|
||||
love.graphics.draw(image)
|
||||
end
|
||||
|
||||
local function breakColor(color)
|
||||
return math.floor(color/65536%256), math.floor(color/256%256), math.floor(color%256)
|
||||
end
|
||||
|
||||
local function renderChar(char,x,y,fr,fg,fb,br,bg,bb)
|
||||
if unifont[char] ~= nil then
|
||||
char = unifont[char]
|
||||
local size = #char/16
|
||||
for i = 1,#char,size do
|
||||
local line = tonumber(char:sub(i,i+size-1),16)
|
||||
local cx = x
|
||||
for j = size*4-1,0,-1 do
|
||||
local bit = math.floor(line/2^j)%2
|
||||
if bit == 0 then
|
||||
idata:setPixel(cx,y,br,bg,bb,255)
|
||||
else
|
||||
idata:setPixel(cx,y,fr,fg,fb,255)
|
||||
end
|
||||
cx = cx + 1
|
||||
end
|
||||
y = y + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function setPos(x,y,c,fr,fg,fb,br,bg,bb)
|
||||
screen.txt[y][x] = z(c)
|
||||
screen.fg[y][x] = scrfgc
|
||||
screen.bg[y][x] = scrbgc
|
||||
screen.fgp[y][x] = scrfgp
|
||||
screen.bgp[y][x] = scrbgp
|
||||
renderChar(c,(x-1)*8,(y-1)*16,fr,fg,fb,br,bg,bb)
|
||||
end
|
||||
|
||||
-- screen component
|
||||
local obj = {}
|
||||
|
||||
function obj.isTouchModeInverted() -- Whether touch mode is inverted (sneak-activate opens GUI, instead of normal activate).
|
||||
--STUB
|
||||
cprint("screen.isTouchModeInverted")
|
||||
return false
|
||||
end
|
||||
function obj.setTouchModeInverted(value) -- Sets whether to invert touch mode (sneak-activate opens GUI, instead of normal activate).
|
||||
--STUB
|
||||
cprint("screen.setTouchModeInverted", value)
|
||||
end
|
||||
function obj.isPrecise() -- Returns whether the screen is in high precision mode (sub-pixel mouse event positions).
|
||||
--STUB
|
||||
cprint("screen.isPrecise")
|
||||
return false
|
||||
end
|
||||
function obj.setPrecise(enabled) -- Set whether to use high precision mode (sub-pixel mouse event positions).
|
||||
--STUB
|
||||
cprint("screen.setPrecise", enabled)
|
||||
end
|
||||
function obj.turnOff() -- Turns off the screen. Returns true if it was on.
|
||||
--STUB
|
||||
cprint("screen.turnOff")
|
||||
return false
|
||||
end
|
||||
function obj.turnOn() -- Turns the screen on. Returns true if it was off.
|
||||
--STUB
|
||||
cprint("screen.turnOn")
|
||||
return false
|
||||
end
|
||||
function obj.isOn() -- Returns whether the screen is currently on.
|
||||
--STUB
|
||||
cprint("screen.isOn")
|
||||
return true
|
||||
end
|
||||
function obj.getAspectRatio() -- The aspect ratio of the screen. For multi-block screens this is the number of blocks, horizontal and vertical.
|
||||
--STUB
|
||||
cprint("screen.getAspectRatio")
|
||||
return 1, 1
|
||||
end
|
||||
function obj.getKeyboards() -- The list of keyboards attached to the screen.
|
||||
--STUB
|
||||
cprint("screen.getKeyboards")
|
||||
return {}
|
||||
end
|
||||
|
||||
local cec = {}
|
||||
|
||||
function cec.getForeground() -- Get the current foreground color and whether it's from the palette or not.
|
||||
cprint("(cec) screen.getForeground")
|
||||
return scrfgc, nil
|
||||
end
|
||||
function cec.setForeground(value, palette) -- Sets the foreground color to the specified value. Optionally takes an explicit palette index. Returns the old value and if it was from the palette its palette index.
|
||||
cprint("(cec) screen.setForeground", value, palette)
|
||||
local old = scrfgc
|
||||
scrfgc = palette and palcol[value] or value
|
||||
scrfgp = palette and value
|
||||
return old, nil
|
||||
end
|
||||
function cec.getBackground() -- Get the current background color and whether it's from the palette or not.
|
||||
cprint("(cec) screen.getBackground")
|
||||
return scrbgc, nil
|
||||
end
|
||||
function cec.setBackground(value, palette) -- Sets the background color to the specified value. Optionally takes an explicit palette index. Returns the old value and if it was from the palette its palette index.
|
||||
cprint("(cec) screen.setBackground", value, palette)
|
||||
local old = scrbgc
|
||||
scrbgc = palette and palcol[value] or value
|
||||
scrbgp = palette and value
|
||||
return old, nil
|
||||
end
|
||||
function cec.getDepth() -- Returns the currently set color depth.
|
||||
cprint("(cec) screen.getDepth")
|
||||
return tier
|
||||
end
|
||||
function cec.setDepth(depth) -- Set the color depth. Returns the previous value.
|
||||
cprint("(cec) screen.setDepth", depth)
|
||||
tier = math.min(depth, maxtier)
|
||||
end
|
||||
function cec.maxDepth() -- Get the maximum supported color depth.
|
||||
cprint("(cec) screen.maxDepth")
|
||||
return maxtier
|
||||
end
|
||||
function cec.fill(x1, y1, w, h, char) -- Fills a portion of the screen at the specified position with the specified size with the specified character.
|
||||
--STUB
|
||||
cprint("(cec) screen.fill", x1, y1, w, h, char)
|
||||
if w <= 0 or h <= 0 then
|
||||
return true
|
||||
end
|
||||
local x2 = x1+w-1
|
||||
local y2 = y1+h-1
|
||||
if x2 < 1 or y2 < 1 or x1 > width or y1 > height then
|
||||
return true
|
||||
end
|
||||
local fr,fg,fb = breakColor(scrfgc)
|
||||
local br,bg,bb = breakColor(scrbgc)
|
||||
local code = lua_utf8.codepoint(char)
|
||||
for y = y1,y2 do
|
||||
for x = x1,x2 do
|
||||
setPos(x,y,code,fr,fg,fb,br,bg,bb)
|
||||
end
|
||||
end
|
||||
end
|
||||
function cec.getResolution() -- Get the current screen resolution.
|
||||
cprint("(cec) screen.getResolution")
|
||||
return width, height
|
||||
end
|
||||
function cec.setResolution(newwidth, newheight) -- Set the screen resolution. Returns true if the resolution changed.
|
||||
cprint("(cec) screen.setResolution", newwidth, newheight)
|
||||
width, height = math.min(newwidth, maxwidth), math.min(newheight, maxheight)
|
||||
end
|
||||
function cec.maxResolution() -- Get the maximum screen resolution.
|
||||
cprint("(cec) screen.maxResolution")
|
||||
return maxwidth, maxheight
|
||||
end
|
||||
function cec.getPaletteColor(index) -- Get the palette color at the specified palette index.
|
||||
cprint("(cec) screen.getPaletteColor", index)
|
||||
return palcol[index]
|
||||
end
|
||||
function cec.setPaletteColor(index, color) -- Set the palette color at the specified palette index. Returns the previous value.
|
||||
--TODO
|
||||
cprint("(cec) screen.setPaletteColor", index, color)
|
||||
palcol[index] = color
|
||||
end
|
||||
function cec.get(x, y) -- Get the value displayed on the screen at the specified index, as well as the foreground and background color. If the foreground or background is from the palette, returns the palette indices as fourth and fifth results, else nil, respectively.
|
||||
cprint("(cec) screen.get", x, y)
|
||||
return screen.txt[y][x], screen.fg[y][x], screen.bg[y][x], screen.fgp[y][x], screen.bgp[y][x]
|
||||
end
|
||||
function cec.set(x, y, value, vertical) -- Plots a string value to the screen at the specified position. Optionally writes the string vertically.
|
||||
cprint("(cec) screen.set", x, y, value, vertical)
|
||||
local fr,fg,fb = breakColor(scrfgc)
|
||||
local br,bg,bb = breakColor(scrbgc)
|
||||
if vertical and x >= 1 and x <= width and y <= height then
|
||||
for _,c in lua_utf8.codes(value) do
|
||||
if y >= 1 then
|
||||
setPos(x,y,c,fr,fg,fb,br,bg,bb)
|
||||
end
|
||||
y = y + 1
|
||||
if y > height then break end
|
||||
end
|
||||
image:refresh()
|
||||
elseif not vertical and y >= 1 and y <= height and x <= width then
|
||||
for _,c in lua_utf8.codes(value) do
|
||||
if x >= 1 then
|
||||
setPos(x,y,c,fr,fg,fb,br,bg,bb)
|
||||
end
|
||||
x = x + #unifont[c]/32
|
||||
if x > width then break end
|
||||
end
|
||||
image:refresh()
|
||||
end
|
||||
return true
|
||||
end
|
||||
function cec.copy(x, y, width, height, tx, ty) -- Copies a portion of the screen from the specified location with the specified size by the specified translation.
|
||||
--STUB
|
||||
cprint("(cec) screen.copy", x, y, width, height, tx, ty)
|
||||
end
|
||||
|
||||
return obj,cec
|
6
src/conf.lua
Normal file
6
src/conf.lua
Normal file
@ -0,0 +1,6 @@
|
||||
function love.conf(t)
|
||||
t.identity = "ocemu2d"
|
||||
t.window = nil
|
||||
t.modules.joystick = false
|
||||
t.modules.physics = false
|
||||
end
|
272
src/main.lua
Normal file
272
src/main.lua
Normal file
@ -0,0 +1,272 @@
|
||||
require("compat52.strict")
|
||||
|
||||
conf = {
|
||||
-- Format: string:type, (string or number or nil):address, (number or nil):slot, component parameters
|
||||
-- Read component files for parameter documentation
|
||||
components = {
|
||||
{"gpu",nil,0,160,50,3},
|
||||
{"screen",nil,nil,80,25,3},
|
||||
{"eeprom",nil,9,"lua/bios.lua"},
|
||||
{"filesystem",nil,5,"loot/OpenOS",true},
|
||||
{"filesystem",nil,nil,"tmpfs",false},
|
||||
{"computer"},
|
||||
{"keyboard"},
|
||||
}
|
||||
}
|
||||
|
||||
machine = {
|
||||
starttime = love.timer.getTime(),
|
||||
signals = {},
|
||||
}
|
||||
|
||||
local function _checkArg(pos, n, have, ...)
|
||||
have = type(have)
|
||||
local function check(want, ...)
|
||||
if not want then
|
||||
return false
|
||||
else
|
||||
return have == want or check(...)
|
||||
end
|
||||
end
|
||||
if not check(...) then
|
||||
local msg = string.format("bad argument #%d (%s expected, got %s)", n, table.concat({...}, " or "), have)
|
||||
error(msg, pos)
|
||||
end
|
||||
end
|
||||
|
||||
function checkArg(...)
|
||||
_checkArg(4, ...)
|
||||
end
|
||||
|
||||
function compCheckArg(...)
|
||||
_checkArg(5, ...)
|
||||
end
|
||||
|
||||
if true then
|
||||
cprint = print
|
||||
else
|
||||
cprint = function() end
|
||||
end
|
||||
|
||||
local env = {
|
||||
_VERSION = "Lua 5.2",
|
||||
assert = assert,
|
||||
bit32 = {
|
||||
arshift = bit32.arshift,
|
||||
band = bit32.band,
|
||||
bnot = bit32.bnot,
|
||||
bor = bit32.bor,
|
||||
btest = bit32.btest,
|
||||
bxor = bit32.bxor,
|
||||
extract = bit32.extract,
|
||||
lrotate = bit32.lrotate,
|
||||
lshift = bit32.lshift,
|
||||
replace = bit32.replace,
|
||||
rrotate = bit32.rrotate,
|
||||
rshift = bit32.rshift,
|
||||
},
|
||||
collectgarbage = collectgarbage,
|
||||
coroutine = {
|
||||
create = coroutine.create,
|
||||
resume = coroutine.resume,
|
||||
running = coroutine.running,
|
||||
status = coroutine.status,
|
||||
wrap = coroutine.wrap,
|
||||
yield = coroutine.yield,
|
||||
},
|
||||
debug = {
|
||||
debug = debug.debug,
|
||||
gethook = debug.gethook,
|
||||
getinfo = debug.getinfo,
|
||||
getlocal = debug.getlocal,
|
||||
getmetatable = debug.getmetatable,
|
||||
getregistry = debug.getregistry,
|
||||
getupvalue = debug.getupvalue,
|
||||
getuservalue = debug.getuservalue,
|
||||
sethook = debug.sethook,
|
||||
setlocal = debug.setlocal,
|
||||
setmetatable = debug.setmetatable,
|
||||
setupvalue = debug.setupvalue,
|
||||
setuservalue = debug.setuservalue,
|
||||
traceback = debug.traceback,
|
||||
upvalueid = debug.upvalueid,
|
||||
upvaluejoin = debug.upvaluejoin,
|
||||
},
|
||||
dofile = dofile,
|
||||
error = error,
|
||||
getmetatable = getmetatable,
|
||||
io = {
|
||||
close = io.close,
|
||||
flush = io.flush,
|
||||
input = io.input,
|
||||
lines = io.lines,
|
||||
open = io.open,
|
||||
output = io.output,
|
||||
popen = io.popen,
|
||||
read = io.read,
|
||||
stderr = io.stderr,
|
||||
stdin = io.stdin,
|
||||
stdout = io.stdout,
|
||||
tmpfile = io.tmpfile,
|
||||
type = io.type,
|
||||
write = io.write,
|
||||
},
|
||||
ipairs = ipairs,
|
||||
load = load,
|
||||
loadfile = loadfile,
|
||||
math = {
|
||||
abs = math.abs,
|
||||
acos = math.acos,
|
||||
asin = math.asin,
|
||||
atan = math.atan,
|
||||
atan2 = math.atan2,
|
||||
ceil = math.ceil,
|
||||
cos = math.cos,
|
||||
cosh = math.cosh,
|
||||
deg = math.deg,
|
||||
exp = math.exp,
|
||||
floor = math.floor,
|
||||
fmod = math.fmod,
|
||||
frexp = math.frexp,
|
||||
huge = math.huge,
|
||||
ldexp = math.ldexp,
|
||||
log = math.log,
|
||||
max = math.max,
|
||||
min = math.min,
|
||||
modf = math.modf,
|
||||
pi = 3.1415926535898,
|
||||
pow = math.pow,
|
||||
rad = math.rad,
|
||||
random = math.random,
|
||||
randomseed = math.randomseed,
|
||||
sin = math.sin,
|
||||
sinh = math.sinh,
|
||||
sqrt = math.sqrt,
|
||||
tan = math.tan,
|
||||
tanh = math.tanh,
|
||||
},
|
||||
next = next,
|
||||
os = {
|
||||
clock = os.clock,
|
||||
date = os.date,
|
||||
difftime = os.difftime,
|
||||
execute = os.execute,
|
||||
exit = os.exit,
|
||||
getenv = os.getenv,
|
||||
remove = os.remove,
|
||||
rename = os.rename,
|
||||
setlocale = os.setlocale,
|
||||
time = os.time,
|
||||
tmpname = os.tmpname,
|
||||
},
|
||||
pairs = pairs,
|
||||
pcall = pcall,
|
||||
print = print,
|
||||
rawequal = rawequal,
|
||||
rawget = rawget,
|
||||
rawlen = rawlen,
|
||||
rawset = rawset,
|
||||
require = require,
|
||||
select = select,
|
||||
setmetatable = setmetatable,
|
||||
string = {
|
||||
byte = string.byte,
|
||||
char = string.char,
|
||||
dump = string.dump,
|
||||
find = string.find,
|
||||
format = string.format,
|
||||
gmatch = string.gmatch,
|
||||
gsub = string.gsub,
|
||||
len = string.len,
|
||||
lower = string.lower,
|
||||
match = string.match,
|
||||
rep = string.rep,
|
||||
reverse = string.reverse,
|
||||
sub = string.sub,
|
||||
upper = string.upper,
|
||||
},
|
||||
table = {
|
||||
concat = table.concat,
|
||||
insert = table.insert,
|
||||
pack = table.pack,
|
||||
remove = table.remove,
|
||||
sort = table.sort,
|
||||
unpack = table.unpack,
|
||||
},
|
||||
tonumber = tonumber,
|
||||
tostring = tostring,
|
||||
type = type,
|
||||
xpcall = xpcall,
|
||||
}
|
||||
setmetatable(env,{
|
||||
__index = function(_,k)
|
||||
cprint("Missing environment access", "env." .. k)
|
||||
end,
|
||||
})
|
||||
|
||||
-- load unifont
|
||||
unifont = {}
|
||||
for line in love.filesystem.lines("unifont.hex") do
|
||||
local a,b = line:match("(.+):(.*)")
|
||||
unifont[tonumber(a,16)] = b
|
||||
end
|
||||
|
||||
-- load api's into environment
|
||||
love.filesystem.load("apis/computer.lua")(env)
|
||||
love.filesystem.load("apis/os.lua")(env)
|
||||
love.filesystem.load("apis/system.lua")(env)
|
||||
love.filesystem.load("apis/unicode.lua")(env)
|
||||
love.filesystem.load("apis/userdata.lua")(env)
|
||||
love.filesystem.load("apis/component.lua")(env)
|
||||
|
||||
-- load machine.lua
|
||||
local machine_data, err = love.filesystem.read("lua/machine.lua")
|
||||
if machine_data == nil then
|
||||
error("Failed to load machine.lua:\n\t" .. tostring(err))
|
||||
end
|
||||
local machine_fn, err = load(machine_data,"=kernel","t",env)
|
||||
if machine_fn == nil then
|
||||
error("Failed to parse machine.lua\n\t" .. tostring(err))
|
||||
end
|
||||
local machine_thread = coroutine.create(machine_fn)
|
||||
local results = { coroutine.resume(machine_thread) }
|
||||
if results[1] then
|
||||
if #results ~= 1 then
|
||||
error("Unexpected result during initialization:\n\t",table.concat(results,", ",2))
|
||||
end
|
||||
else
|
||||
error("Failed to initialize machine.lua\n\t" .. tostring(results[2]))
|
||||
end
|
||||
cprint("Machine.lua booted ...")
|
||||
|
||||
local resume_thread
|
||||
function resume_thread(...)
|
||||
if coroutine.status(machine_thread) ~= "dead" then
|
||||
cprint("resume",...)
|
||||
local results = { coroutine.resume(machine_thread, ...) }
|
||||
cprint("yield",table.unpack(results))
|
||||
if type(results[2]) == "function" then
|
||||
resume_thread(results[2]())
|
||||
end
|
||||
if coroutine.status(machine_thread) == "dead" and type(results[2]) ~= "function" then
|
||||
cprint("machine.lua has died")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
kbdcodes = {}
|
||||
|
||||
function love.update(dt)
|
||||
if #kbdcodes > 0 then
|
||||
local kbdcode = kbdcodes[1]
|
||||
table.remove(kbdcodes,1)
|
||||
table.insert(machine.signals,{kbdcode.type,kbdcode.addr,kbdcode.char or 0,kbdcode.code})
|
||||
end
|
||||
if #machine.signals > 0 then
|
||||
signal = machine.signals[1]
|
||||
table.remove(machine.signals, 1)
|
||||
resume_thread(table.unpack(signal))
|
||||
else
|
||||
resume_thread()
|
||||
end
|
||||
end
|
126
src/utf8_simple.lua
Normal file
126
src/utf8_simple.lua
Normal file
@ -0,0 +1,126 @@
|
||||
-- ABNF from RFC 3629
|
||||
--
|
||||
-- UTF8-octets = *( UTF8-char )
|
||||
-- UTF8-char = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4
|
||||
-- UTF8-1 = %x00-7F
|
||||
-- UTF8-2 = %xC2-DF UTF8-tail
|
||||
-- UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) /
|
||||
-- %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )
|
||||
-- UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /
|
||||
-- %xF4 %x80-8F 2( UTF8-tail )
|
||||
-- UTF8-tail = %x80-BF
|
||||
|
||||
-- 0xxxxxxx | 007F (127)
|
||||
-- 110xxxxx 10xxxxxx | 07FF (2047)
|
||||
-- 1110xxxx 10xxxxxx 10xxxxxx | FFFF (65535)
|
||||
-- 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx | 10FFFF (1114111)
|
||||
|
||||
local pattern = '[%z\1-\127\194-\244][\128-\191]*'
|
||||
|
||||
-- helper function
|
||||
local posrelat =
|
||||
function (pos, len)
|
||||
if pos < 0 then
|
||||
pos = len + pos + 1
|
||||
end
|
||||
|
||||
return pos
|
||||
end
|
||||
|
||||
local utf8 = {}
|
||||
|
||||
-- THE MEAT
|
||||
|
||||
-- maps f over s's utf8 characters f can accept args: (visual_index, utf8_character, byte_index)
|
||||
utf8.map =
|
||||
function (s, f, no_subs)
|
||||
local i = 0
|
||||
|
||||
if no_subs then
|
||||
for b, e in s:gmatch('()' .. pattern .. '()') do
|
||||
i = i + 1
|
||||
local c = e - b
|
||||
f(i, c, b)
|
||||
end
|
||||
else
|
||||
for b, c in s:gmatch('()(' .. pattern .. ')') do
|
||||
i = i + 1
|
||||
f(i, c, b)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- THE REST
|
||||
|
||||
-- generator for the above -- to iterate over all utf8 chars
|
||||
utf8.chars =
|
||||
function (s, no_subs)
|
||||
return coroutine.wrap(function () return utf8.map(s, coroutine.yield, no_subs) end)
|
||||
end
|
||||
|
||||
-- returns the number of characters in a UTF-8 string
|
||||
utf8.len =
|
||||
function (s)
|
||||
-- count the number of non-continuing bytes
|
||||
return select(2, s:gsub('[^\128-\193]', ''))
|
||||
end
|
||||
|
||||
-- replace all utf8 chars with mapping
|
||||
utf8.replace =
|
||||
function (s, map)
|
||||
return s:gsub(pattern, map)
|
||||
end
|
||||
|
||||
-- reverse a utf8 string
|
||||
utf8.reverse =
|
||||
function (s)
|
||||
-- reverse the individual greater-than-single-byte characters
|
||||
s = s:gsub(pattern, function (c) return #c > 1 and c:reverse() end)
|
||||
|
||||
return s:reverse()
|
||||
end
|
||||
|
||||
-- strip non-ascii characters from a utf8 string
|
||||
utf8.strip =
|
||||
function (s)
|
||||
return s:gsub(pattern, function (c) return #c > 1 and '' end)
|
||||
end
|
||||
|
||||
-- like string.sub() but i, j are utf8 strings
|
||||
-- a utf8-safe string.sub()
|
||||
utf8.sub =
|
||||
function (s, i, j)
|
||||
local l = utf8.len(s)
|
||||
|
||||
i = posrelat(i, l)
|
||||
j = j and posrelat(j, l) or l
|
||||
|
||||
if i < 1 then i = 1 end
|
||||
if j > l then j = l end
|
||||
|
||||
if i > j then return '' end
|
||||
|
||||
local diff = j - i
|
||||
local iter = utf8.chars(s, true)
|
||||
|
||||
-- advance up to i
|
||||
for _ = 1, i - 1 do iter() end
|
||||
|
||||
local c, b = select(2, iter())
|
||||
|
||||
-- i and j are the same, single-charaacter sub
|
||||
if diff == 0 then
|
||||
return string.sub(s, b, b + c - 1)
|
||||
end
|
||||
|
||||
i = b
|
||||
|
||||
-- advance up to j
|
||||
for _ = 1, diff - 1 do iter() end
|
||||
|
||||
c, b = select(2, iter())
|
||||
|
||||
return string.sub(s, i, b + c - 1)
|
||||
end
|
||||
|
||||
return utf8
|
Loading…
x
Reference in New Issue
Block a user