opus/sys/modules/opus/util.lua

847 lines
16 KiB
Lua
Raw Normal View History

2016-12-11 19:24:52 +00:00
local Util = { }
2017-10-09 00:03:01 +00:00
local fs = _G.fs
local http = _G.http
local os = _G.os
local term = _G.term
local textutils = _G.textutils
2019-03-06 16:48:09 +00:00
local _sformat = string.format
local _srep = string.rep
local _ssub = string.sub
2020-03-30 06:07:20 +00:00
local _unpack = table.unpack
local _bor = bit32.bor
local _bxor = bit32.bxor
local byteArrayMT
2020-03-30 06:07:20 +00:00
byteArrayMT = {
__tostring = function(a) return string.char(_unpack(a)) end,
__index = {
toHex = function(self) return ("%02x"):rep(#self):format(_unpack(self)) end,
isEqual = function(self, t)
if type(t) ~= "table" then return false end
if #self ~= #t then return false end
local ret = 0
for i = 1, #self do
ret = _bor(ret, _bxor(self[i], t[i]))
end
return ret == 0
end,
sub = function(self, a, b)
local len = #self+1
local start = a%len
local stop = (b or len-1)%len
local ret = {}
local i = 1
for j = start, stop, start<stop and 1 or -1 do
ret[i] = self[j]
i = i+1
end
return setmetatable(ret, byteArrayMT)
end
}
}
Util.byteArrayMT = byteArrayMT
2019-03-06 16:48:09 +00:00
function Util.hexToByteArray(str)
local r = {}
str = tostring(str)
for b in str:gmatch("%x%x?") do
r[#r+1] = tonumber(b, 16)
end
2020-03-30 06:07:20 +00:00
return setmetatable(r, byteArrayMT)
end
function Util.byteArrayToHex(tbl)
2019-06-29 20:35:33 +00:00
if not tbl then error('byteArrayToHex: invalid table', 2) end
2020-03-30 06:07:20 +00:00
return ("%02x"):rep(#tbl):format(_unpack(tbl))
end
2016-12-11 19:24:52 +00:00
function Util.tryTimed(timeout, f, ...)
2018-01-24 22:39:38 +00:00
local c = os.clock()
repeat
local ret = f(...)
if ret then
return ret
end
until os.clock()-c >= timeout
2016-12-11 19:24:52 +00:00
end
function Util.tryTimes(attempts, f, ...)
2018-01-24 22:39:38 +00:00
local result
for _ = 1, attempts do
result = { f(...) }
if result[1] then
2020-03-30 06:07:20 +00:00
return _unpack(result)
2018-01-24 22:39:38 +00:00
end
end
2020-03-30 06:07:20 +00:00
return _unpack(result)
2016-12-11 19:24:52 +00:00
end
2019-03-06 16:48:09 +00:00
function Util.timer()
2019-07-27 04:13:24 +00:00
local ct = os.clock()
return function()
return os.clock() - ct
end
2019-03-01 16:27:27 +00:00
end
2019-03-06 16:48:09 +00:00
Util.Timer = Util.timer -- deprecate
2017-05-14 04:53:59 +00:00
function Util.throttle(fn)
2018-01-24 22:39:38 +00:00
local ts = os.clock()
2019-06-30 18:47:45 +00:00
local timeout = .295
2018-01-24 22:39:38 +00:00
return function(...)
local nts = os.clock()
if nts > ts + timeout then
os.sleep(0)
ts = os.clock()
if fn then
fn(...)
end
end
end
2017-05-14 03:45:59 +00:00
end
2017-05-09 05:57:00 +00:00
function Util.tostring(pattern, ...)
2016-12-11 19:24:52 +00:00
2018-01-24 22:39:38 +00:00
local function serialize(tbl, width)
local str = '{\n'
for k, v in pairs(tbl) do
local value
if type(v) == 'table' then
2019-03-06 16:48:09 +00:00
value = _sformat('table: %d', Util.size(v))
2018-01-24 22:39:38 +00:00
else
value = tostring(v)
end
2019-03-06 16:48:09 +00:00
str = str .. _sformat(' %s: %s\n', k, value)
2018-01-24 22:39:38 +00:00
end
--if #str < width then
--str = str:gsub('\n', '') .. ' }'
--else
str = str .. '}'
--end
return str
end
if type(pattern) == 'string' then
2019-05-12 14:02:46 +00:00
if select('#', ...) == 0 then
return pattern
end
2019-03-06 16:48:09 +00:00
return _sformat(pattern, ...)
2018-01-24 22:39:38 +00:00
elseif type(pattern) == 'table' then
return serialize(pattern, term.current().getSize())
end
return tostring(pattern)
2017-05-09 05:57:00 +00:00
end
function Util.print(pattern, ...)
2018-01-24 22:39:38 +00:00
print(Util.tostring(pattern, ...))
2016-12-11 19:24:52 +00:00
end
function Util.getVersion()
2018-01-24 22:39:38 +00:00
local version
2018-01-24 22:39:38 +00:00
if _G._CC_VERSION then
version = tonumber(_G._CC_VERSION:match('[%d]+%.?[%d][%d]'))
end
if not version and _G._HOST then
version = tonumber(_G._HOST:match('[%d]+%.?[%d][%d]'))
end
2018-01-24 22:39:38 +00:00
return version or 1.7
end
2017-10-12 21:58:35 +00:00
function Util.getMinecraftVersion()
2018-01-24 22:39:38 +00:00
local mcVersion = _G._MC_VERSION or 'unknown'
if _G._HOST then
local version = _G._HOST:match('%S+ %S+ %((%S.+)%)')
if version then
mcVersion = version:match('Minecraft (%S+)') or version
end
end
return mcVersion
2017-10-12 21:58:35 +00:00
end
function Util.checkMinecraftVersion(minVersion)
2018-01-24 22:39:38 +00:00
local version = Util.getMinecraftVersion()
local function convert(v)
local m1, m2, m3 = v:match('(%d)%.(%d)%.?(%d?)')
return tonumber(m1) * 10000 + tonumber(m2) * 100 + (tonumber(m3) or 0)
end
2017-10-12 21:58:35 +00:00
2018-01-24 22:39:38 +00:00
return convert(version) >= convert(tostring(minVersion))
2017-10-12 21:58:35 +00:00
end
function Util.signum(num)
if num > 0 then
return 1
elseif num < 0 then
return -1
else
return 0
end
end
2019-02-23 23:36:17 +00:00
function Util.clamp(num, low, high)
return num < low and low or num > high and high or num
end
2016-12-11 19:24:52 +00:00
-- http://lua-users.org/wiki/SimpleRound
function Util.round(num, idp)
2018-01-24 22:39:38 +00:00
local mult = 10^(idp or 0)
2018-12-09 19:52:52 +00:00
return Util.signum(num) * math.floor(math.abs(num) * mult + 0.5) / mult
2016-12-11 19:24:52 +00:00
end
function Util.randomFloat(max, min)
2018-01-24 22:39:38 +00:00
min = min or 0
max = max or 1
return (max-min) * math.random() + min
2016-12-11 19:24:52 +00:00
end
--[[ Table functions ]] --
function Util.clear(t)
2018-01-24 22:39:38 +00:00
local keys = Util.keys(t)
for _,k in pairs(keys) do
t[k] = nil
end
2016-12-11 19:24:52 +00:00
end
function Util.empty(t)
2018-01-24 22:39:38 +00:00
return not next(t)
2016-12-11 19:24:52 +00:00
end
function Util.key(t, value)
2018-01-24 22:39:38 +00:00
for k,v in pairs(t) do
if v == value then
return k
end
end
2016-12-11 19:24:52 +00:00
end
function Util.keys(t)
2018-01-24 22:39:38 +00:00
local keys = { }
for k in pairs(t) do
keys[#keys+1] = k
end
return keys
2016-12-11 19:24:52 +00:00
end
function Util.merge(obj, args)
2018-01-24 22:39:38 +00:00
if args then
for k,v in pairs(args) do
obj[k] = v
end
end
return obj
2016-12-11 19:24:52 +00:00
end
function Util.deepMerge(obj, args)
2018-01-24 22:39:38 +00:00
if args then
for k,v in pairs(args) do
if type(v) == 'table' then
if not obj[k] then
obj[k] = { }
end
Util.deepMerge(obj[k], v)
else
obj[k] = v
end
end
end
2016-12-11 19:24:52 +00:00
end
function Util.transpose(t)
2018-01-24 22:39:38 +00:00
local tt = { }
for k,v in pairs(t) do
tt[v] = k
end
return tt
2016-12-11 19:24:52 +00:00
end
2017-10-18 23:51:55 +00:00
function Util.contains(t, value)
2018-01-24 22:39:38 +00:00
for k,v in pairs(t) do
if v == value then
return k
end
end
2017-10-18 23:51:55 +00:00
end
2016-12-11 19:24:52 +00:00
function Util.find(t, name, value)
2018-01-24 22:39:38 +00:00
for k,v in pairs(t) do
if v[name] == value then
return v, k
end
end
2016-12-11 19:24:52 +00:00
end
function Util.findAll(t, name, value)
2018-01-24 22:39:38 +00:00
local rt = { }
for _,v in pairs(t) do
if v[name] == value then
table.insert(rt, v)
end
end
return rt
2016-12-11 19:24:52 +00:00
end
function Util.shallowCopy(t)
2018-11-06 21:43:24 +00:00
if not t then error('Util.shallowCopy: invalid table', 2) end
2018-01-24 22:39:38 +00:00
local t2 = { }
for k,v in pairs(t) do
t2[k] = v
end
return t2
2016-12-11 19:24:52 +00:00
end
function Util.deepCopy(t)
2018-01-24 22:39:38 +00:00
if type(t) ~= 'table' then
return t
end
--local mt = getmetatable(t)
local res = {}
for k,v in pairs(t) do
if type(v) == 'table' then
v = Util.deepCopy(v)
end
res[k] = v
end
--setmetatable(res,mt)
return res
2016-12-11 19:24:52 +00:00
end
-- http://snippets.luacode.org/?p=snippets/Filter_a_table_in-place_119
function Util.filterInplace(t, predicate)
2018-01-24 22:39:38 +00:00
local j = 1
2016-12-11 19:24:52 +00:00
2018-01-24 22:39:38 +00:00
for i = 1,#t do
local v = t[i]
if predicate(v) then
t[j] = v
j = j + 1
end
end
2016-12-11 19:24:52 +00:00
2018-01-24 22:39:38 +00:00
while t[j] ~= nil do
t[j] = nil
j = j + 1
end
2016-12-11 19:24:52 +00:00
2018-01-24 22:39:38 +00:00
return t
2016-12-11 19:24:52 +00:00
end
function Util.filter(it, f)
2018-01-24 22:39:38 +00:00
local ot = { }
for k,v in pairs(it) do
if f(v) then
ot[k] = v
end
end
return ot
2016-12-11 19:24:52 +00:00
end
2018-12-21 00:28:26 +00:00
function Util.reduce(t, fn, acc)
2019-02-26 13:17:53 +00:00
acc = acc or 0
2018-12-21 00:28:26 +00:00
for _, v in pairs(t) do
2019-02-26 13:17:53 +00:00
acc = fn(acc, v)
2018-12-21 00:28:26 +00:00
end
return acc
end
2016-12-11 19:24:52 +00:00
function Util.size(list)
2018-01-24 22:39:38 +00:00
if type(list) == 'table' then
local length = 0
for _ in pairs(list) do
length = length + 1
end
return length
end
return 0
2016-12-11 19:24:52 +00:00
end
2018-12-24 00:49:28 +00:00
local function isArray(value)
-- dubious
return type(value) == "table" and (value[1] or next(value) == nil)
end
function Util.removeByValue(t, e)
2018-01-24 22:39:38 +00:00
for k,v in pairs(t) do
if v == e then
2018-12-24 00:49:28 +00:00
if isArray(t) then
table.remove(t, k)
else
t[k] = nil
end
2018-01-24 22:39:38 +00:00
break
end
end
end
2019-01-02 08:04:24 +00:00
function Util.any(t, fn)
for _,v in pairs(t) do
if fn(v) then
return true
end
end
end
2018-12-24 00:49:28 +00:00
function Util.every(t, fn)
for _,v in pairs(t) do
if not fn(v) then
return false
end
end
return true
end
2016-12-11 19:24:52 +00:00
function Util.each(list, func)
2018-01-24 22:39:38 +00:00
for index, value in pairs(list) do
func(value, index, list)
end
2016-12-11 19:24:52 +00:00
end
2017-10-20 08:23:17 +00:00
function Util.rpairs(t)
2018-01-24 22:39:38 +00:00
local tkeys = Util.keys(t)
local i = #tkeys
return function()
local key = tkeys[i]
local k,v = key, t[key]
i = i - 1
if v then
return k, v
end
end
2017-10-20 08:23:17 +00:00
end
2016-12-11 19:24:52 +00:00
-- http://stackoverflow.com/questions/15706270/sort-a-table-in-lua
function Util.spairs(t, order)
2018-01-24 22:39:38 +00:00
local keys = Util.keys(t)
-- if order function given, sort by it by passing the table and keys a, b,
-- otherwise just sort the keys
if order then
table.sort(keys, function(a,b) return order(t[a], t[b]) end)
else
table.sort(keys)
end
-- return the iterator function
local i = 0
return function()
i = i + 1
if keys[i] then
return keys[i], t[keys[i]]
end
end
2016-12-11 19:24:52 +00:00
end
function Util.first(t, order)
2018-01-24 22:39:38 +00:00
local keys = Util.keys(t)
if order then
table.sort(keys, function(a,b) return order(t[a], t[b]) end)
else
table.sort(keys)
end
return keys[1], t[keys[1]]
2016-12-11 19:24:52 +00:00
end
--[[ File functions ]]--
2019-07-11 01:02:46 +00:00
function Util.readFile(fname, flags)
local f = fs.open(fname, flags or "r")
2018-01-24 22:39:38 +00:00
if f then
local t = f.readAll()
f.close()
return t
end
2016-12-11 19:24:52 +00:00
end
2019-03-12 03:54:00 +00:00
function Util.backup(fname)
2019-03-12 06:00:07 +00:00
local backup = fname .. '.bak'
if backup then
fs.delete(backup)
end
fs.copy(fname, backup)
2019-03-12 03:48:22 +00:00
end
2016-12-11 19:24:52 +00:00
function Util.writeFile(fname, data)
2018-10-30 02:03:46 +00:00
if not fname or not data then error('Util.writeFile: invalid parameters', 2) end
2019-03-13 00:04:28 +00:00
if fs.exists(fname) then
local diff = #data - fs.getSize(fname)
if diff > 0 then
if fs.getFreeSpace(fs.getDir(fname)) < diff then
error('Insufficient disk space for ' .. fname)
end
end
end
2018-01-24 22:39:38 +00:00
local file = io.open(fname, "w")
if not file then
error('Unable to open ' .. fname, 2)
end
file:write(data)
file:close()
2016-12-11 19:24:52 +00:00
end
function Util.readLines(fname)
2018-01-24 22:39:38 +00:00
local file = fs.open(fname, "r")
if file then
local t = {}
local line = file.readLine()
while line do
table.insert(t, line)
line = file.readLine()
end
file.close()
return t
end
2016-12-11 19:24:52 +00:00
end
function Util.writeLines(fname, lines)
2018-01-24 22:39:38 +00:00
local file = fs.open(fname, 'w')
if file then
for _,line in ipairs(lines) do
file.writeLine(line)
end
file.close()
return true
end
2016-12-11 19:24:52 +00:00
end
function Util.readTable(fname)
2018-01-24 22:39:38 +00:00
local t = Util.readFile(fname)
if t then
return textutils.unserialize(t)
end
2016-12-11 19:24:52 +00:00
end
function Util.writeTable(fname, data)
2018-01-24 22:39:38 +00:00
Util.writeFile(fname, textutils.serialize(data))
2016-12-11 19:24:52 +00:00
end
function Util.loadTable(fname)
2018-01-24 22:39:38 +00:00
local fc = Util.readFile(fname)
if not fc then
return false, 'Unable to read file'
end
2019-07-20 22:23:48 +00:00
local s, m = loadstring('return ' .. fc, fname)
2018-01-24 22:39:38 +00:00
if s then
s, m = pcall(s)
if s then
return m
end
end
return s, m
2016-12-11 19:24:52 +00:00
end
2017-09-27 19:42:40 +00:00
--[[ loading and running functions ]] --
2019-04-19 23:03:34 +00:00
function Util.httpGet(url, headers, isBinary)
local h, msg = http.get(url, headers, isBinary)
2018-01-24 22:39:38 +00:00
if h then
local contents = h.readAll()
h.close()
return contents
end
return h, msg
2017-10-09 00:03:01 +00:00
end
function Util.download(url, filename)
2018-01-24 22:39:38 +00:00
local contents, msg = Util.httpGet(url)
if not contents then
2019-03-06 16:48:09 +00:00
error(_sformat('Failed to download %s\n%s', url, msg), 2)
2018-01-24 22:39:38 +00:00
end
2016-12-11 19:24:52 +00:00
2018-01-24 22:39:38 +00:00
if filename then
Util.writeFile(filename, contents)
end
return contents
2016-12-11 19:24:52 +00:00
end
function Util.loadUrl(url, env) -- loadfile equivalent
2018-01-24 22:39:38 +00:00
local c, msg = Util.httpGet(url)
if not c then
return c, msg
end
return load(c, url, nil, env)
2016-12-11 19:24:52 +00:00
end
function Util.runUrl(env, url, ...) -- os.run equivalent
2018-01-24 22:39:38 +00:00
setmetatable(env, { __index = _G })
local fn, m = Util.loadUrl(url, env)
if fn then
return pcall(fn, ...)
end
return fn, m
2017-09-26 19:18:44 +00:00
end
function Util.run(env, path, ...)
2018-01-24 22:39:38 +00:00
if type(env) ~= 'table' then error('Util.run: env must be a table', 2) end
setmetatable(env, { __index = _G })
local fn, m = loadfile(path, env)
if fn then
return pcall(fn, ...)
end
return fn, m
2016-12-11 19:24:52 +00:00
end
2017-09-27 19:42:40 +00:00
function Util.runFunction(env, fn, ...)
2019-07-20 22:23:48 +00:00
setfenv(fn, env)
2018-01-24 22:39:38 +00:00
setmetatable(env, { __index = _G })
return pcall(fn, ...)
2017-09-27 19:42:40 +00:00
end
2016-12-11 19:24:52 +00:00
--[[ String functions ]] --
function Util.toBytes(n)
2018-01-24 22:39:38 +00:00
if not tonumber(n) then error('Util.toBytes: n must be a number', 2) end
if n >= 1000000 or n <= -1000000 then
2019-03-06 16:48:09 +00:00
return _sformat('%sM', math.floor(n/1000000 * 10) / 10)
2018-01-24 22:39:38 +00:00
elseif n >= 10000 or n <= -10000 then
2019-03-06 16:48:09 +00:00
return _sformat('%sK', math.floor(n/1000))
2018-01-24 22:39:38 +00:00
elseif n >= 1000 or n <= -1000 then
2019-03-06 16:48:09 +00:00
return _sformat('%sK', math.floor(n/1000 * 10) / 10)
2018-01-24 22:39:38 +00:00
end
return tostring(n)
2016-12-11 19:24:52 +00:00
end
2017-10-09 00:03:01 +00:00
function Util.insertString(str, istr, pos)
2018-01-24 22:39:38 +00:00
return str:sub(1, pos - 1) .. istr .. str:sub(pos)
2016-12-27 03:26:43 +00:00
end
2016-12-11 19:24:52 +00:00
function Util.split(str, pattern)
2019-06-18 19:19:24 +00:00
if not str or type(str) ~= 'string' then error('Util.split: Invalid parameters', 2) end
2018-01-24 22:39:38 +00:00
pattern = pattern or "(.-)\n"
local t = {}
local function helper(line) table.insert(t, line) return "" end
helper((str:gsub(pattern, helper)))
return t
2016-12-11 19:24:52 +00:00
end
function Util.matches(str, pattern)
2018-01-24 22:39:38 +00:00
pattern = pattern or '%S+'
local t = { }
for s in str:gmatch(pattern) do
table.insert(t, s)
end
return t
2016-12-11 19:24:52 +00:00
end
2018-11-04 18:00:37 +00:00
function Util.startsWith(s, match)
2019-03-06 16:48:09 +00:00
return _ssub(s, 1, #match) == match
2017-09-15 05:08:04 +00:00
end
2019-03-06 16:48:09 +00:00
-- return a fixed length string using specified alignment
function Util.widthify(s, len, align)
2018-01-24 22:39:38 +00:00
s = s or ''
local slen = #s
2019-03-06 16:48:09 +00:00
if slen > len then
return _ssub(s, 1, len)
2019-03-07 18:14:16 +00:00
2019-03-06 16:48:09 +00:00
elseif slen == len then
return s
2019-03-07 18:14:16 +00:00
elseif align == 'center' then
local space = math.floor((len - slen) / 2)
s = _srep(' ', space) .. s
return s .. _srep(' ', len - #s)
2019-03-06 16:48:09 +00:00
elseif align == 'right' then
2019-03-07 18:14:16 +00:00
return _srep(' ', len - slen) .. s
2019-03-06 16:48:09 +00:00
2018-01-24 22:39:38 +00:00
end
2019-03-06 16:48:09 +00:00
2019-03-07 18:14:16 +00:00
return s .. _srep(' ', len - slen)
2016-12-11 19:24:52 +00:00
end
-- http://snippets.luacode.org/?p=snippets/trim_whitespace_from_string_76
function Util.trim(s)
2019-11-09 02:54:41 +00:00
return s:find('^%s*$') and '' or s:match('^%s*(.*%S)')
2016-12-11 19:24:52 +00:00
end
2017-10-08 21:45:01 +00:00
2016-12-11 19:24:52 +00:00
-- trim whitespace from left end of string
function Util.triml(s)
2019-11-09 02:54:41 +00:00
return s:match('^%s*(.*)')
2016-12-11 19:24:52 +00:00
end
2017-10-08 21:45:01 +00:00
2016-12-11 19:24:52 +00:00
-- trim whitespace from right end of string
function Util.trimr(s)
2019-11-09 02:54:41 +00:00
return s:find('^%s*$') and '' or s:match('^(.*%S)')
2016-12-11 19:24:52 +00:00
end
-- end http://snippets.luacode.org/?p=snippets/trim_whitespace_from_string_76
local function wrap(text, max, lines)
local index = 1
repeat
if #text <= max then
table.insert(lines, text)
text = ''
elseif text:sub(max+1, max+1) == ' ' then
table.insert(lines, text:sub(index, max))
text = text:sub(max + 2)
2018-01-24 22:39:38 +00:00
else
local x = text:sub(1, max)
local s = x:match('(.*) ') or x
text = text:sub(#s + 1)
table.insert(lines, s)
2018-01-24 22:39:38 +00:00
end
text = text:match('^%s*(.*)')
until not text or #text == 0
return lines
2016-12-11 19:24:52 +00:00
end
function Util.wordWrap(str, limit)
2018-01-24 22:39:38 +00:00
local lines = { }
2016-12-11 19:24:52 +00:00
for _,line in ipairs(Util.split(str)) do
wrap(line, limit, lines)
2018-01-24 22:39:38 +00:00
end
2016-12-11 19:24:52 +00:00
2018-01-24 22:39:38 +00:00
return lines
2016-12-11 19:24:52 +00:00
end
2019-04-07 14:09:47 +00:00
-- https://github.com/MightyPirates/OpenComputers
function Util.parse(...)
2019-07-27 04:13:24 +00:00
local params = table.pack(...)
local args = {}
local options = {}
local doneWithOptions = false
for i = 1, params.n do
local param = params[i]
if not doneWithOptions and type(param) == "string" then
if param == "--" then
doneWithOptions = true -- stop processing options at `--`
elseif param:sub(1, 2) == "--" then
local key, value = param:match("%-%-(.-)=(.*)")
if not key then
key, value = param:sub(3), true
end
options[key] = value
elseif param:sub(1, 1) == "-" and param ~= "-" then
for j = 2, string.len(param) do
options[string.sub(param, j, j)] = true
end
else
table.insert(args, param)
end
else
table.insert(args, param)
end
end
return args, options
2019-04-07 14:09:47 +00:00
end
function Util.args(arg)
2018-01-24 22:39:38 +00:00
local options, args = { }, { }
local k = 1
while k <= #arg do
local v = arg[k]
2019-03-06 16:48:09 +00:00
if _ssub(v, 1, 1) == '-' then
local opt = _ssub(v, 2)
2018-01-24 22:39:38 +00:00
options[opt] = arg[k + 1]
k = k + 1
else
table.insert(args, v)
end
k = k + 1
end
return options, args
end
2018-01-13 20:17:26 +00:00
2016-12-11 19:24:52 +00:00
-- http://lua-users.org/wiki/AlternativeGetOpt
local function getopt( arg, options )
2018-01-24 22:39:38 +00:00
local tab = {}
for k, v in ipairs(arg) do
if type(v) == 'string' then
2019-03-06 16:48:09 +00:00
if _ssub( v, 1, 2) == "--" then
2018-01-24 22:39:38 +00:00
local x = string.find( v, "=", 1, true )
2019-03-06 16:48:09 +00:00
if x then tab[ _ssub( v, 3, x-1 ) ] = _ssub( v, x+1 )
else tab[ _ssub( v, 3 ) ] = true
2018-01-24 22:39:38 +00:00
end
2019-03-06 16:48:09 +00:00
elseif _ssub( v, 1, 1 ) == "-" then
2018-01-24 22:39:38 +00:00
local y = 2
local l = string.len(v)
local jopt
while ( y <= l ) do
2019-03-06 16:48:09 +00:00
jopt = _ssub( v, y, y )
2018-01-24 22:39:38 +00:00
if string.find( options, jopt, 1, true ) then
if y < l then
2019-03-06 16:48:09 +00:00
tab[ jopt ] = _ssub( v, y+1 )
2018-01-24 22:39:38 +00:00
y = l
else
tab[ jopt ] = arg[ k + 1 ]
end
else
tab[ jopt ] = true
end
y = y + 1
end
end
end
end
return tab
2016-12-11 19:24:52 +00:00
end
function Util.showOptions(options)
2018-01-24 22:39:38 +00:00
print('Arguments: ')
for _, v in pairs(options) do
2019-03-06 16:48:09 +00:00
print(_sformat('-%s %s', v.arg, v.desc))
2018-01-24 22:39:38 +00:00
end
2016-12-11 19:24:52 +00:00
end
function Util.getOptions(options, args, ignoreInvalid)
2018-01-24 22:39:38 +00:00
local argLetters = ''
for _,o in pairs(options) do
if o.type ~= 'flag' then
argLetters = argLetters .. o.arg
end
end
local rawOptions = getopt(args, argLetters)
for k,ro in pairs(rawOptions) do
local found = false
for _,o in pairs(options) do
if o.arg == k then
found = true
if o.type == 'number' then
o.value = tonumber(ro)
elseif o.type == 'help' then
Util.showOptions(options)
return false
else
o.value = ro
end
end
end
if not found and not ignoreInvalid then
print('Invalid argument')
Util.showOptions(options)
return false
end
end
return true, Util.size(rawOptions)
2016-12-11 19:24:52 +00:00
end
2019-07-27 04:13:24 +00:00
-- https://www.lua.org/pil/9.3.html
function Util.permutation(tbl)
local function permgen(a, n)
if n == 0 then
coroutine.yield(a)
else
for i=1,n do
a[n], a[i] = a[i], a[n]
permgen(a, n - 1)
a[n], a[i] = a[i], a[n]
end
end
end
local co = coroutine.create(function() permgen(tbl, #tbl) end)
return function()
local _, res = coroutine.resume(co)
return res
end
end
2016-12-11 19:24:52 +00:00
return Util