v1.8.0 - Fixed a bug with shell not executing files in the working directory, added json library, changed all configs to json, added config auto-generation so they don't reset after an update.
This commit is contained in:
+5
-4
@@ -1,12 +1,12 @@
|
|||||||
local agcfg = {
|
local agcfg = {
|
||||||
["halyde"] = {
|
["halyde"] = {
|
||||||
["maindir"] = "",
|
["maindir"] = "",
|
||||||
["version"] = "1.7.2",
|
["version"] = "1.8.0",
|
||||||
["description"] = "A universal, customizable and feature-packed operating system for OpenComputers.",
|
["description"] = "A universal, customizable and feature-packed operating system for OpenComputers.",
|
||||||
["directories"] = {
|
["directories"] = {
|
||||||
"halyde/apps",
|
"halyde/apps",
|
||||||
"halyde/apps/helpdb",
|
"halyde/apps/helpdb",
|
||||||
"halyde/config",
|
"halyde/config/generate",
|
||||||
"halyde/core",
|
"halyde/core",
|
||||||
"halyde/lib",
|
"halyde/lib",
|
||||||
"home"
|
"home"
|
||||||
@@ -38,8 +38,8 @@ local agcfg = {
|
|||||||
"halyde/apps/mv.lua",
|
"halyde/apps/mv.lua",
|
||||||
"halyde/apps/rm.lua",
|
"halyde/apps/rm.lua",
|
||||||
"halyde/config/oslogo.ans",
|
"halyde/config/oslogo.ans",
|
||||||
"halyde/config/shell.cfg",
|
"halyde/config/generate/shell.cfg",
|
||||||
"halyde/config/startupapps.cfg",
|
"halyde/config/generate/startupapps.cfg",
|
||||||
"halyde/core/boot.lua",
|
"halyde/core/boot.lua",
|
||||||
"halyde/core/cormgr.lua",
|
"halyde/core/cormgr.lua",
|
||||||
"halyde/core/datatools.lua",
|
"halyde/core/datatools.lua",
|
||||||
@@ -51,6 +51,7 @@ local agcfg = {
|
|||||||
"halyde/lib/computer.lua",
|
"halyde/lib/computer.lua",
|
||||||
"halyde/lib/event.lua",
|
"halyde/lib/event.lua",
|
||||||
"halyde/lib/filesystem.lua",
|
"halyde/lib/filesystem.lua",
|
||||||
|
"halyde/lib/json.lua",
|
||||||
"halyde/lib/raster.lua"
|
"halyde/lib/raster.lua"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
Ahome/
|
Ahome/
|
||||||
Ahalyde/lib/
|
Ahalyde/lib/
|
||||||
Ahalyde/core/
|
Ahalyde/core/
|
||||||
Ahalyde/config/
|
Ahalyde/config/generate/
|
||||||
Ahalyde/apps/helpdb/
|
Ahalyde/apps/helpdb/
|
||||||
Ahalyde/apps/
|
Ahalyde/apps/
|
||||||
V1.7.2
|
V1.8.0
|
||||||
Ainit.lua
|
Ainit.lua
|
||||||
Ahalyde/apps/helpdb/cat.txt
|
Ahalyde/apps/helpdb/cat.txt
|
||||||
Ahalyde/apps/helpdb/cd.txt
|
Ahalyde/apps/helpdb/cd.txt
|
||||||
@@ -31,8 +31,8 @@ Ahalyde/apps/mkdir.lua
|
|||||||
Ahalyde/apps/mv.lua
|
Ahalyde/apps/mv.lua
|
||||||
Ahalyde/apps/rm.lua
|
Ahalyde/apps/rm.lua
|
||||||
Ahalyde/config/oslogo.ans
|
Ahalyde/config/oslogo.ans
|
||||||
Ahalyde/config/shell.cfg
|
Ahalyde/config/generate/shell.cfg
|
||||||
Ahalyde/config/startupapps.cfg
|
Ahalyde/config/generate/startupapps.cfg
|
||||||
Ahalyde/core/boot.lua
|
Ahalyde/core/boot.lua
|
||||||
Ahalyde/core/cormgr.lua
|
Ahalyde/core/cormgr.lua
|
||||||
Ahalyde/core/datatools.lua
|
Ahalyde/core/datatools.lua
|
||||||
@@ -44,4 +44,5 @@ Ahalyde/lib/component.lua
|
|||||||
Ahalyde/lib/computer.lua
|
Ahalyde/lib/computer.lua
|
||||||
Ahalyde/lib/event.lua
|
Ahalyde/lib/event.lua
|
||||||
Ahalyde/lib/filesystem.lua
|
Ahalyde/lib/filesystem.lua
|
||||||
|
Ahalyde/lib/json.lua
|
||||||
Ahalyde/lib/raster.lua
|
Ahalyde/lib/raster.lua
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
{"prompt":"\u001b[92m%s > \u001b[0m","aliases":{"move":"mv","copy":"cp","ag":"argentum","rename":"mv","..":"cd ..","man":"help","del":"rm","delete":"rm","ren":"mv","remove":"rm","list":"ls","wget":"download","dir":"ls"},"splashMessages":["Made by John Haly- I mean Cerulean Blue.","Welcome! Type \"help\" to get started.","Also try KOCOS!","Welcome back, Commander. We have no idea what we're doing.","99.9% bug-free. The remaining 0.1% are features.","0 days since last error.","Everything is fine. The fire is decorative.","Please don't feed the background processes.","Also has fetch!","Anything red is no man's land. Trust me.","Machine...","Abort, Retry, Fail?","What's the deal with /argentum/store?","So cutting-edge you can't hold it in your hand.","Americans are the reason you see colors on-screen. I'm talking about ANSI escape codes, not politics.","Shoutout to Ponali!"],"path":["/halyde/apps/"],"startupMessage":"\n │\n │ Halyde 1.8.0\n │ %s\n │\n ","defaultWorkingDirectory":"/home/"}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
["/halyde/core/fullkb.lua","/halyde/core/evmgr.lua","/halyde/core/shell.lua"]
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
local shellcfg = {
|
|
||||||
["startupMessage"] = "\n │\n │ ".._OSVERSION..'\n │ %s\n │\n ', -- message shown on startup. %s will be replaced with splash message.
|
|
||||||
["prompt"] = "\x1b[92m%s > \x1b[0m", -- shell prompt. %s will be replaced with working directory.
|
|
||||||
["path"] = { -- default locations where programs will be run from
|
|
||||||
"/halyde/apps/"
|
|
||||||
}, ["aliases"] = { -- shell command aliases
|
|
||||||
["copy"] = "cp",
|
|
||||||
["move"] = "mv",
|
|
||||||
["rename"] = "mv",
|
|
||||||
["ren"] = "mv",
|
|
||||||
["dir"] = "ls",
|
|
||||||
["list"] = "ls",
|
|
||||||
["man"] = "help",
|
|
||||||
["del"] = "rm",
|
|
||||||
["delete"] = "rm",
|
|
||||||
["remove"] = "rm",
|
|
||||||
[".."] = "cd ..",
|
|
||||||
["wget"] = "download",
|
|
||||||
["ag"] = "argentum"
|
|
||||||
}, ["defaultWorkingDirectory"] = "/home/", -- the working directory that gets set when halyde starts
|
|
||||||
["splashMessages"] = { -- messages shown on startup
|
|
||||||
"Made by John Haly- I mean Cerulean Blue.",
|
|
||||||
'Welcome! Type "help" to get started.',
|
|
||||||
"Also try KOCOS!",
|
|
||||||
"Welcome back, Commander. We have no idea what we're doing.",
|
|
||||||
"99.9% bug-free. The remaining 0.1% are features.",
|
|
||||||
"0 days since last error.",
|
|
||||||
"Everything is fine. The fire is decorative.",
|
|
||||||
"Please don't feed the background processes.",
|
|
||||||
"Also has fetch!",
|
|
||||||
"Anything red is no man's land. Trust me.",
|
|
||||||
"Machine...",
|
|
||||||
"Abort, Retry, Fail?",
|
|
||||||
"What's the deal with /argentum/store?",
|
|
||||||
"So cutting-edge you can't hold it in your hand.",
|
|
||||||
"Americans are the reason you see colors on-screen. I'm talking about ANSI escape codes, not politics.",
|
|
||||||
"Shoutout to Ponali!"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return shellcfg
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
/halyde/core/fullkb.lua
|
|
||||||
/halyde/core/evmgr.lua
|
|
||||||
/halyde/core/shell.lua
|
|
||||||
+10
-1
@@ -1,7 +1,7 @@
|
|||||||
local loadfile = ...
|
local loadfile = ...
|
||||||
local filesystem = loadfile("/halyde/lib/filesystem.lua")(loadfile)
|
local filesystem = loadfile("/halyde/lib/filesystem.lua")(loadfile)
|
||||||
|
|
||||||
_G._OSVERSION = "Halyde 1.7.2"
|
_G._OSVERSION = "Halyde 1.8.0"
|
||||||
_G._OSLOGO = ""
|
_G._OSLOGO = ""
|
||||||
local handle, tmpdata = filesystem.open("/halyde/config/oslogo.ans", "r"), nil
|
local handle, tmpdata = filesystem.open("/halyde/config/oslogo.ans", "r"), nil
|
||||||
repeat
|
repeat
|
||||||
@@ -85,4 +85,13 @@ preload("computer")
|
|||||||
--assert(handle:write("Bazinga!"))
|
--assert(handle:write("Bazinga!"))
|
||||||
--handle:close()
|
--handle:close()
|
||||||
|
|
||||||
|
local fs = import("filesystem")
|
||||||
|
if not fs.exists("/halyde/config/shell.json") then
|
||||||
|
fs.copy("/halyde/config/generate/shell.json", "/halyde/config/shell.json")
|
||||||
|
end
|
||||||
|
if not fs.exists("/halyde/config/startupapps.json") then
|
||||||
|
fs.copy("/halyde/config/generate/startupapps.json", "/halyde/config/startupapps.json")
|
||||||
|
end
|
||||||
|
fs = nil
|
||||||
|
|
||||||
import("/halyde/core/cormgr.lua")
|
import("/halyde/core/cormgr.lua")
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ _G.cormgr.corList = {}
|
|||||||
|
|
||||||
local component = import("component")
|
local component = import("component")
|
||||||
local filesystem = import("filesystem")
|
local filesystem = import("filesystem")
|
||||||
|
local json = import("json")
|
||||||
local gpu = component.proxy(component.list("gpu")())
|
local gpu = component.proxy(component.list("gpu")())
|
||||||
|
|
||||||
function _G.cormgr.loadCoroutine(path, ...)
|
function _G.cormgr.loadCoroutine(path, ...)
|
||||||
@@ -55,14 +56,13 @@ local function runCoroutines()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local handle = filesystem.open("/halyde/config/startupapps.cfg", "r")
|
local handle, data, tmpdata = filesystem.open("/halyde/config/startupapps.json", "r"), "", nil
|
||||||
local data = ""
|
|
||||||
local tmpdata
|
|
||||||
repeat
|
repeat
|
||||||
tmpdata = handle:read(math.huge or math.maxinteger)
|
tmpdata = handle:read(math.huge or math.maxinteger)
|
||||||
data = data .. (tmpdata or "")
|
data = data .. (tmpdata or "")
|
||||||
until not tmpdata
|
until not tmpdata
|
||||||
for line in data:gmatch("([^\n]*)\n?") do
|
handle:close()
|
||||||
|
for _, line in ipairs(json.decode(data)) do
|
||||||
if line ~= "" then
|
if line ~= "" then
|
||||||
--[[ if _G.print then
|
--[[ if _G.print then
|
||||||
print(line)
|
print(line)
|
||||||
|
|||||||
@@ -12,13 +12,12 @@ keyboard.altDown = false
|
|||||||
while true do
|
while true do
|
||||||
local args
|
local args
|
||||||
repeat
|
repeat
|
||||||
args = {computer.pullSignal(0)}
|
args = {computer.uptime(), computer.pullSignal(0)}
|
||||||
if args and args[1] then
|
if args and args[2] then
|
||||||
--ocelot.log("Sending signal "..args..","..computer.uptime())
|
|
||||||
table.insert(evmgr.eventQueue, args)
|
table.insert(evmgr.eventQueue, args)
|
||||||
if keyboard then
|
if keyboard then
|
||||||
if args[1] == "key_down" then
|
if args[2] == "key_down" then
|
||||||
local keycode = args[4]
|
local keycode = args[5]
|
||||||
local key = keyboard.keys[keycode]
|
local key = keyboard.keys[keycode]
|
||||||
if key == "lcontrol" then
|
if key == "lcontrol" then
|
||||||
keyboard.ctrlDown = true
|
keyboard.ctrlDown = true
|
||||||
@@ -30,8 +29,8 @@ while true do
|
|||||||
end
|
end
|
||||||
cormgr.corList[#cormgr.corList] = nil
|
cormgr.corList[#cormgr.corList] = nil
|
||||||
end
|
end
|
||||||
elseif args[1] == "key_up" then
|
elseif args[2] == "key_up" then
|
||||||
local keycode = args[4]
|
local keycode = args[5]
|
||||||
local key = keyboard.keys[keycode]
|
local key = keyboard.keys[keycode]
|
||||||
if key == "lcontrol" then
|
if key == "lcontrol" then
|
||||||
keyboard.ctrlDown = false
|
keyboard.ctrlDown = false
|
||||||
|
|||||||
+22
-18
@@ -1,7 +1,14 @@
|
|||||||
local shellcfg = import("/halyde/config/shell.cfg")
|
local fs = import("filesystem")
|
||||||
|
local json = import("json")
|
||||||
|
local handle, data, tmpdata = fs.open("/halyde/config/shell.json", "r"), "", nil
|
||||||
|
repeat
|
||||||
|
tmpdata = handle:read(math.huge)
|
||||||
|
data = data .. (tmpdata or "")
|
||||||
|
until not tmpdata
|
||||||
|
handle:close()
|
||||||
|
local shellcfg = json.decode(data)
|
||||||
import("/halyde/core/termlib.lua")
|
import("/halyde/core/termlib.lua")
|
||||||
local event = import("event")
|
local event = import("event")
|
||||||
local filesystem = import("filesystem")
|
|
||||||
local component = import("component")
|
local component = import("component")
|
||||||
local gpu = component.proxy(component.list("gpu")())
|
local gpu = component.proxy(component.list("gpu")())
|
||||||
|
|
||||||
@@ -51,39 +58,36 @@ function _G.shell.run(command)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- execute the program
|
-- execute the program
|
||||||
local foundfile = false
|
local PATH = table.copy(shellcfg.path)
|
||||||
|
table.insert(PATH, shell.workingDirectory)
|
||||||
if not args[1] then
|
if not args[1] then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if filesystem.exists(args[1]) and not filesystem.isDirectory(args[1]) then
|
if fs.exists(args[1]) and not fs.isDirectory(args[1]) then
|
||||||
foundfile = true
|
|
||||||
local path = args[1]
|
local path = args[1]
|
||||||
table.remove(args, 1)
|
table.remove(args, 1)
|
||||||
runAsCoroutine(path, table.unpack(args))
|
runAsCoroutine(path, table.unpack(args))
|
||||||
else
|
return
|
||||||
for _, item in pairs(shellcfg["path"]) do
|
end
|
||||||
if filesystem.exists(item..args[1]) and not filesystem.isDirectory(item .. args[1]) then
|
for _, item in pairs(PATH) do
|
||||||
foundfile = true
|
if fs.exists(item..args[1]) and not fs.isDirectory(item .. args[1]) then
|
||||||
local path = item..args[1]
|
local path = fs.concat(item, args[1])
|
||||||
table.remove(args, 1)
|
table.remove(args, 1)
|
||||||
runAsCoroutine(path, table.unpack(args))
|
runAsCoroutine(path, table.unpack(args))
|
||||||
break
|
return
|
||||||
else -- try to look for it without the file extension
|
else -- try to look for it without the file extension
|
||||||
local files = filesystem.list(item)
|
local files = fs.list(item)
|
||||||
for _, file in pairs(files) do
|
for _, file in pairs(files) do
|
||||||
if args[1] == file:match("(.+)%.[^%.]+$") and not filesystem.isDirectory(item .. file) then
|
-- previous pattern: (.+)%.[^%.]+$
|
||||||
foundfile = true
|
if args[1] == file:match("(.+)%.[^%.]+$") and not fs.isDirectory(item .. file) then
|
||||||
table.remove(args, 1)
|
table.remove(args, 1)
|
||||||
runAsCoroutine(item .. file, table.unpack(args))
|
runAsCoroutine(item .. file, table.unpack(args))
|
||||||
break
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
if not foundfile then
|
|
||||||
print("No such file or command: "..args[1])
|
print("No such file or command: "..args[1])
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
print(shellcfg["startupMessage"]:format(shellcfg.splashMessages[math.random(1, #shellcfg.splashMessages)]))
|
print(shellcfg["startupMessage"]:format(shellcfg.splashMessages[math.random(1, #shellcfg.splashMessages)]))
|
||||||
|
|||||||
@@ -208,8 +208,8 @@ function _G.read(readHistoryType, prefix, defaultText)
|
|||||||
while true do
|
while true do
|
||||||
--ocelot.log(curtext)
|
--ocelot.log(curtext)
|
||||||
termlib.cursorPosX = termlib.cursorPosX - 1
|
termlib.cursorPosX = termlib.cursorPosX - 1
|
||||||
local args = {event.pull("key_down", 0.5)}
|
local args = {event.pull("key_down", "clipboard", 0.5)}
|
||||||
if args[4] then
|
if args[1] == "key_down" and args[4] then
|
||||||
cursorWhite = true
|
cursorWhite = true
|
||||||
local keycode = args[4]
|
local keycode = args[4]
|
||||||
local key = keyboard.keys[keycode]
|
local key = keyboard.keys[keycode]
|
||||||
@@ -258,6 +258,8 @@ function _G.read(readHistoryType, prefix, defaultText)
|
|||||||
end
|
end
|
||||||
termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY
|
termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY
|
||||||
termlib.write(prefix .. curtext)
|
termlib.write(prefix .. curtext)
|
||||||
|
elseif args[1] == "clipboard" then
|
||||||
|
|
||||||
else
|
else
|
||||||
cursorWhite = not cursorWhite
|
cursorWhite = not cursorWhite
|
||||||
end
|
end
|
||||||
|
|||||||
+23
-24
@@ -4,39 +4,38 @@ local event = {}
|
|||||||
--local ocelot = component.proxy(component.list("ocelot")())
|
--local ocelot = component.proxy(component.list("ocelot")())
|
||||||
function event.pull(...)
|
function event.pull(...)
|
||||||
local args = {...}
|
local args = {...}
|
||||||
local evtype, timeout
|
local evtypes, timeout = {}, nil
|
||||||
|
|
||||||
if #args == 0 then
|
for _, arg in pairs(args) do
|
||||||
-- No arguments, wait for any event indefinitely
|
if type(arg) == "number" and not timeout then -- It's a timeout
|
||||||
evtype = nil
|
timeout = arg
|
||||||
timeout = nil
|
else -- It's an event type
|
||||||
elseif #args == 1 then
|
table.insert(evtypes, tostring(arg))
|
||||||
-- If one argument is provided, it could be either the event type or timeout
|
|
||||||
if type(args[1]) == "number" then
|
|
||||||
-- It's a timeout
|
|
||||||
evtype = nil
|
|
||||||
timeout = args[1]
|
|
||||||
else
|
|
||||||
-- It's an event type
|
|
||||||
evtype = args[1]
|
|
||||||
timeout = nil
|
|
||||||
end
|
end
|
||||||
else
|
|
||||||
-- Both event type and timeout provided
|
|
||||||
evtype = args[1]
|
|
||||||
timeout = args[2]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local startTime = computer.uptime()
|
local startTime = computer.uptime()
|
||||||
local result = {}
|
|
||||||
|
|
||||||
repeat
|
while true do
|
||||||
-- Check event queue for matching event
|
-- Check event queue for matching event
|
||||||
for i = 1, #evmgr.eventQueue do
|
for i = 1, #evmgr.eventQueue do
|
||||||
if not evtype or evmgr.eventQueue[i][1] == evtype then
|
local foundevent = false
|
||||||
|
for _, evtype in pairs(evtypes) do
|
||||||
|
if evtypes[1] then -- event type(s) specified
|
||||||
|
if evmgr.eventQueue[i][2] == evtype and evmgr.eventQueue[i][1] >= startTime then
|
||||||
|
foundevent = true
|
||||||
|
end
|
||||||
|
else -- event type(s) not specified
|
||||||
|
if evmgr.eventQueue[i][1] >= startTime then
|
||||||
|
foundevent = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if foundevent then
|
||||||
-- Found matching event (or any event if no type specified)
|
-- Found matching event (or any event if no type specified)
|
||||||
result = table.copy(evmgr.eventQueue[i])
|
local result = table.copy(evmgr.eventQueue[i])
|
||||||
table.remove(evmgr.eventQueue, i)
|
table.remove(evmgr.eventQueue, i)
|
||||||
|
table.remove(result, 1) -- remove the time of event argument
|
||||||
return table.unpack(result)
|
return table.unpack(result)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -48,7 +47,7 @@ function event.pull(...)
|
|||||||
|
|
||||||
-- Yield to allow other processes to run and more events to be added
|
-- Yield to allow other processes to run and more events to be added
|
||||||
coroutine.yield()
|
coroutine.yield()
|
||||||
until false -- Loop until we find an event or timeout
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return event
|
return event
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
-- json.lua by rxi
|
||||||
|
-- Minified with luamin
|
||||||
|
-- Original: https://github.com/rxi/json.lua
|
||||||
|
local a={_version="0.1.2"}local b;local c={["\\"]="\\",["\""]="\"",["\b"]="b",["\f"]="f",["\n"]="n",["\r"]="r",["\t"]="t"}local d={["/"]="/"}for e,f in pairs(c)do d[f]=e end;local function g(h)return"\\"..(c[h]or string.format("u%04x",h:byte()))end;local function i(j)return"null"end;local function k(j,l)local m={}l=l or{}if l[j]then error("circular reference")end;l[j]=true;if rawget(j,1)~=nil or next(j)==nil then local n=0;for e in pairs(j)do if type(e)~="number"then error("invalid table: mixed or invalid key types")end;n=n+1 end;if n~=#j then error("invalid table: sparse array")end;for o,f in ipairs(j)do table.insert(m,b(f,l))end;l[j]=nil;return"["..table.concat(m,",").."]"else for e,f in pairs(j)do if type(e)~="string"then error("invalid table: mixed or invalid key types")end;table.insert(m,b(e,l)..":"..b(f,l))end;l[j]=nil;return"{"..table.concat(m,",").."}"end end;local function p(j)return'"'..j:gsub('[%z\1-\31\\"]',g)..'"'end;local function q(j)if j~=j or j<=-math.huge or j>=math.huge then error("unexpected number value '"..tostring(j).."'")end;return string.format("%.14g",j)end;local r={["nil"]=i,["table"]=k,["string"]=p,["number"]=q,["boolean"]=tostring}b=function(j,l)local s=type(j)local t=r[s]if t then return t(j,l)end;error("unexpected type '"..s.."'")end;function a.encode(j)return b(j)end;local u;local function v(...)local m={}for o=1,select("#",...)do m[select(o,...)]=true end;return m end;local w=v(" ","\t","\r","\n")local x=v(" ","\t","\r","\n","]","}",",")local y=v("\\","/",'"',"b","f","n","r","t","u")local z=v("true","false","null")local A={["true"]=true,["false"]=false,["null"]=nil}local function B(C,D,E,F)for o=D,#C do if E[C:sub(o,o)]~=F then return o end end;return#C+1 end;local function G(C,D,H)local I=1;local J=1;for o=1,D-1 do J=J+1;if C:sub(o,o)=="\n"then I=I+1;J=1 end end;error(string.format("%s at line %d col %d",H,I,J))end;local function K(n)local t=math.floor;if n<=0x7f then return string.char(n)elseif n<=0x7ff then return string.char(t(n/64)+192,n%64+128)elseif n<=0xffff then return string.char(t(n/4096)+224,t(n%4096/64)+128,n%64+128)elseif n<=0x10ffff then return string.char(t(n/262144)+240,t(n%262144/4096)+128,t(n%4096/64)+128,n%64+128)end;error(string.format("invalid unicode codepoint '%x'",n))end;local function L(M)local N=tonumber(M:sub(1,4),16)local O=tonumber(M:sub(7,10),16)if O then return K((N-0xd800)*0x400+O-0xdc00+0x10000)else return K(N)end end;local function P(C,o)local m=""local Q=o+1;local e=Q;while Q<=#C do local R=C:byte(Q)if R<32 then G(C,Q,"control character in string")elseif R==92 then m=m..C:sub(e,Q-1)Q=Q+1;local h=C:sub(Q,Q)if h=="u"then local S=C:match("^[dD][89aAbB]%x%x\\u%x%x%x%x",Q+1)or C:match("^%x%x%x%x",Q+1)or G(C,Q-1,"invalid unicode escape in string")m=m..L(S)Q=Q+#S else if not y[h]then G(C,Q-1,"invalid escape char '"..h.."' in string")end;m=m..d[h]end;e=Q+1 elseif R==34 then m=m..C:sub(e,Q-1)return m,Q+1 end;Q=Q+1 end;G(C,o,"expected closing quote for string")end;local function T(C,o)local R=B(C,o,x)local M=C:sub(o,R-1)local n=tonumber(M)if not n then G(C,o,"invalid number '"..M.."'")end;return n,R end;local function U(C,o)local R=B(C,o,x)local V=C:sub(o,R-1)if not z[V]then G(C,o,"invalid literal '"..V.."'")end;return A[V],R end;local function W(C,o)local m={}local n=1;o=o+1;while 1 do local R;o=B(C,o,w,true)if C:sub(o,o)=="]"then o=o+1;break end;R,o=u(C,o)m[n]=R;n=n+1;o=B(C,o,w,true)local X=C:sub(o,o)o=o+1;if X=="]"then break end;if X~=","then G(C,o,"expected ']' or ','")end end;return m,o end;local function Y(C,o)local m={}o=o+1;while 1 do local Z,j;o=B(C,o,w,true)if C:sub(o,o)=="}"then o=o+1;break end;if C:sub(o,o)~='"'then G(C,o,"expected string for key")end;Z,o=u(C,o)o=B(C,o,w,true)if C:sub(o,o)~=":"then G(C,o,"expected ':' after key")end;o=B(C,o+1,w,true)j,o=u(C,o)m[Z]=j;o=B(C,o,w,true)local X=C:sub(o,o)o=o+1;if X=="}"then break end;if X~=","then G(C,o,"expected '}' or ','")end end;return m,o end;local _={['"']=P,["0"]=T,["1"]=T,["2"]=T,["3"]=T,["4"]=T,["5"]=T,["6"]=T,["7"]=T,["8"]=T,["9"]=T,["-"]=T,["t"]=U,["f"]=U,["n"]=U,["["]=W,["{"]=Y}u=function(C,D)local X=C:sub(D,D)local t=_[X]if t then return t(C,D)end;G(C,D,"unexpected character '"..X.."'")end;function a.decode(C)if type(C)~="string"then error("expected argument of type string, got "..type(C))end;local m,D=u(C,B(C,1,w,true))D=B(C,D,w,true)if D<=#C then G(C,D,"trailing garbage")end;return m end;return a
|
||||||
Reference in New Issue
Block a user