mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
Reduction of moose.lua sizing working now!
This commit is contained in:
350
Utils/luarocks/share/lua/5.1/pl/lapp.lua
Normal file
350
Utils/luarocks/share/lua/5.1/pl/lapp.lua
Normal file
@@ -0,0 +1,350 @@
|
||||
--- Simple command-line parsing using human-readable specification.
|
||||
-- Supports GNU-style parameters.
|
||||
-- <pre class=example>
|
||||
-- lapp = require 'pl.lapp'
|
||||
-- local args = lapp [[
|
||||
-- Does some calculations
|
||||
-- -o,--offset (default 0.0) Offset to add to scaled number
|
||||
-- -s,--scale (number) Scaling factor
|
||||
-- <number> (number ) Number to be scaled
|
||||
-- ]]
|
||||
--
|
||||
-- print(args.offset + args.scale * args.number)
|
||||
-- </pre>
|
||||
-- Lines begining with '-' are flags; there may be a short and a long name;
|
||||
-- lines begining wih '<var>' are arguments. Anything in parens after
|
||||
-- the flag/argument is either a default, a type name or a range constraint.
|
||||
-- <p>See <a href="../../index.html#lapp">the Guide</a>
|
||||
-- @class module
|
||||
-- @name pl.lapp
|
||||
|
||||
local status,sip = pcall(require,'pl.sip')
|
||||
if not status then
|
||||
sip = require 'sip'
|
||||
end
|
||||
local match = sip.match_at_start
|
||||
local append,tinsert = table.insert,table.insert
|
||||
|
||||
--[[
|
||||
module('pl.lapp')
|
||||
]]
|
||||
|
||||
local function lines(s) return s:gmatch('([^\n]*)\n') end
|
||||
local function lstrip(str) return str:gsub('^%s+','') end
|
||||
local function strip(str) return lstrip(str):gsub('%s+$','') end
|
||||
local function at(s,k) return s:sub(k,k) end
|
||||
local function isdigit(s) return s:find('^%d+$') == 1 end
|
||||
|
||||
local lapp = {}
|
||||
|
||||
local open_files,parms,aliases,parmlist,usage,windows,script
|
||||
|
||||
lapp.callback = false -- keep Strict happy
|
||||
|
||||
local filetypes = {
|
||||
stdin = {io.stdin,'file-in'}, stdout = {io.stdout,'file-out'},
|
||||
stderr = {io.stderr,'file-out'}
|
||||
}
|
||||
|
||||
--- controls whether to dump usage on error.
|
||||
-- Defaults to true
|
||||
lapp.show_usage_error = true
|
||||
|
||||
--- quit this script immediately.
|
||||
-- @param msg optional message
|
||||
-- @param no_usage suppress 'usage' display
|
||||
function lapp.quit(msg,no_usage)
|
||||
if msg then
|
||||
io.stderr:write(msg..'\n\n')
|
||||
end
|
||||
if not no_usage then
|
||||
io.stderr:write(usage)
|
||||
end
|
||||
os.exit(1);
|
||||
end
|
||||
|
||||
--- print an error to stderr and quit.
|
||||
-- @param msg a message
|
||||
-- @param no_usage suppress 'usage' display
|
||||
function lapp.error(msg,no_usage)
|
||||
if not lapp.show_usage_error then
|
||||
no_usage = true
|
||||
end
|
||||
lapp.quit(script..':'..msg,no_usage)
|
||||
end
|
||||
|
||||
--- open a file.
|
||||
-- This will quit on error, and keep a list of file objects for later cleanup.
|
||||
-- @param file filename
|
||||
-- @param opt same as second parameter of <code>io.open</code>
|
||||
function lapp.open (file,opt)
|
||||
local val,err = io.open(file,opt)
|
||||
if not val then lapp.error(err,true) end
|
||||
append(open_files,val)
|
||||
return val
|
||||
end
|
||||
|
||||
--- quit if the condition is false.
|
||||
-- @param condn a condition
|
||||
-- @param msg an optional message
|
||||
function lapp.assert(condn,msg)
|
||||
if not condn then
|
||||
lapp.error(msg)
|
||||
end
|
||||
end
|
||||
|
||||
local function range_check(x,min,max,parm)
|
||||
lapp.assert(min <= x and max >= x,parm..' out of range')
|
||||
end
|
||||
|
||||
local function xtonumber(s)
|
||||
local val = tonumber(s)
|
||||
if not val then lapp.error("unable to convert to number: "..s) end
|
||||
return val
|
||||
end
|
||||
|
||||
local function is_filetype(type)
|
||||
return type == 'file-in' or type == 'file-out'
|
||||
end
|
||||
|
||||
local types
|
||||
|
||||
local function convert_parameter(ps,val)
|
||||
if ps.converter then
|
||||
val = ps.converter(val)
|
||||
end
|
||||
if ps.type == 'number' then
|
||||
val = xtonumber(val)
|
||||
elseif is_filetype(ps.type) then
|
||||
val = lapp.open(val,(ps.type == 'file-in' and 'r') or 'w' )
|
||||
elseif ps.type == 'boolean' then
|
||||
val = true
|
||||
end
|
||||
if ps.constraint then
|
||||
ps.constraint(val)
|
||||
end
|
||||
return val
|
||||
end
|
||||
|
||||
--- add a new type to Lapp. These appear in parens after the value like
|
||||
-- a range constraint, e.g. '<ival> (integer) Process PID'
|
||||
-- @param name name of type
|
||||
-- @param converter either a function to convert values, or a Lua type name.
|
||||
-- @param constraint optional function to verify values, should use lapp.error
|
||||
-- if failed.
|
||||
function lapp.add_type (name,converter,constraint)
|
||||
types[name] = {converter=converter,constraint=constraint}
|
||||
end
|
||||
|
||||
local function force_short(short)
|
||||
lapp.assert(#short==1,short..": short parameters should be one character")
|
||||
end
|
||||
|
||||
local function process_default (sval)
|
||||
local val = tonumber(sval)
|
||||
if val then -- we have a number!
|
||||
return val,'number'
|
||||
elseif filetypes[sval] then
|
||||
local ft = filetypes[sval]
|
||||
return ft[1],ft[2]
|
||||
else
|
||||
if sval:match '^["\']' then sval = sval:sub(2,-2) end
|
||||
return sval,'string'
|
||||
end
|
||||
end
|
||||
|
||||
--- process a Lapp options string.
|
||||
-- Usually called as lapp().
|
||||
-- @param str the options text
|
||||
-- @return a table with parameter-value pairs
|
||||
function lapp.process_options_string(str)
|
||||
local results = {}
|
||||
local opts = {at_start=true}
|
||||
local varargs
|
||||
open_files = {}
|
||||
parms = {}
|
||||
aliases = {}
|
||||
parmlist = {}
|
||||
types = {}
|
||||
|
||||
local function check_varargs(s)
|
||||
local res,cnt = s:gsub('^%.%.%.%s*','')
|
||||
return res, (cnt > 0)
|
||||
end
|
||||
|
||||
local function set_result(ps,parm,val)
|
||||
if not ps.varargs then
|
||||
results[parm] = val
|
||||
else
|
||||
if not results[parm] then
|
||||
results[parm] = { val }
|
||||
else
|
||||
append(results[parm],val)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
usage = str
|
||||
|
||||
for line in lines(str) do
|
||||
local res = {}
|
||||
local optspec,optparm,i1,i2,defval,vtype,constraint,rest
|
||||
line = lstrip(line)
|
||||
local function check(str)
|
||||
return match(str,line,res)
|
||||
end
|
||||
|
||||
-- flags: either '-<short>', '-<short>,--<long>' or '--<long>'
|
||||
if check '-$v{short}, --$v{long} $' or check '-$v{short} $' or check '--$v{long} $' then
|
||||
if res.long then
|
||||
optparm = res.long
|
||||
if res.short then aliases[res.short] = optparm end
|
||||
else
|
||||
optparm = res.short
|
||||
end
|
||||
if res.short then force_short(res.short) end
|
||||
res.rest, varargs = check_varargs(res.rest)
|
||||
elseif check '$<{name} $' then -- is it <parameter_name>?
|
||||
-- so <input file...> becomes input_file ...
|
||||
optparm,rest = res.name:match '([^%.]+)(.*)'
|
||||
optparm = optparm:gsub('%A','_')
|
||||
varargs = rest == '...'
|
||||
append(parmlist,optparm)
|
||||
end
|
||||
if res.rest then -- this is not a pure doc line
|
||||
line = res.rest
|
||||
res = {}
|
||||
-- do we have (default <val>) or (<type>)?
|
||||
if match('$({def} $',line,res) or match('$({def}',line,res) then
|
||||
local typespec = strip(res.def)
|
||||
if match('default $',typespec,res) then
|
||||
defval,vtype = process_default(res[1])
|
||||
elseif match('$f{min}..$f{max}',typespec,res) then
|
||||
local min,max = res.min,res.max
|
||||
vtype = 'number'
|
||||
constraint = function(x)
|
||||
range_check(x,min,max,optparm)
|
||||
end
|
||||
else -- () just contains type of required parameter
|
||||
vtype = typespec
|
||||
end
|
||||
else -- must be a plain flag, no extra parameter required
|
||||
defval = false
|
||||
vtype = 'boolean'
|
||||
end
|
||||
local ps = {
|
||||
type = vtype,
|
||||
defval = defval,
|
||||
required = defval == nil,
|
||||
comment = res.rest or optparm,
|
||||
constraint = constraint,
|
||||
varargs = varargs
|
||||
}
|
||||
varargs = nil
|
||||
if types[vtype] then
|
||||
local converter = types[vtype].converter
|
||||
if type(converter) == 'string' then
|
||||
ps.type = converter
|
||||
else
|
||||
ps.converter = converter
|
||||
end
|
||||
ps.constraint = types[vtype].constraint
|
||||
end
|
||||
parms[optparm] = ps
|
||||
end
|
||||
end
|
||||
-- cool, we have our parms, let's parse the command line args
|
||||
local iparm = 1
|
||||
local iextra = 1
|
||||
local i = 1
|
||||
local parm,ps,val
|
||||
|
||||
while i <= #arg do
|
||||
local theArg = arg[i]
|
||||
local res = {}
|
||||
-- look for a flag, -<short flags> or --<long flag>
|
||||
if match('--$v{long}',theArg,res) or match('-$v{short}',theArg,res) then
|
||||
if res.long then -- long option
|
||||
parm = res.long
|
||||
elseif #res.short == 1 then
|
||||
parm = res.short
|
||||
else
|
||||
local parmstr = res.short
|
||||
parm = at(parmstr,1)
|
||||
if isdigit(at(parmstr,2)) then
|
||||
-- a short option followed by a digit is an exception (for AW;))
|
||||
-- push ahead into the arg array
|
||||
tinsert(arg,i+1,parmstr:sub(2))
|
||||
else
|
||||
-- push multiple flags into the arg array!
|
||||
for k = 2,#parmstr do
|
||||
tinsert(arg,i+k-1,'-'..at(parmstr,k))
|
||||
end
|
||||
end
|
||||
end
|
||||
if parm == 'h' or parm == 'help' then
|
||||
lapp.quit()
|
||||
end
|
||||
if aliases[parm] then parm = aliases[parm] end
|
||||
else -- a parameter
|
||||
parm = parmlist[iparm]
|
||||
if not parm then
|
||||
-- extra unnamed parameters are indexed starting at 1
|
||||
parm = iextra
|
||||
ps = { type = 'string' }
|
||||
parms[parm] = ps
|
||||
iextra = iextra + 1
|
||||
else
|
||||
ps = parms[parm]
|
||||
end
|
||||
if not ps.varargs then
|
||||
iparm = iparm + 1
|
||||
end
|
||||
val = theArg
|
||||
end
|
||||
ps = parms[parm]
|
||||
if not ps then lapp.error("unrecognized parameter: "..parm) end
|
||||
if ps.type ~= 'boolean' then -- we need a value! This should follow
|
||||
if not val then
|
||||
i = i + 1
|
||||
val = arg[i]
|
||||
end
|
||||
lapp.assert(val,parm.." was expecting a value")
|
||||
end
|
||||
ps.used = true
|
||||
val = convert_parameter(ps,val)
|
||||
set_result(ps,parm,val)
|
||||
if is_filetype(ps.type) then
|
||||
set_result(ps,parm..'_name',theArg)
|
||||
end
|
||||
if lapp.callback then
|
||||
lapp.callback(parm,theArg,res)
|
||||
end
|
||||
i = i + 1
|
||||
val = nil
|
||||
end
|
||||
-- check unused parms, set defaults and check if any required parameters were missed
|
||||
for parm,ps in pairs(parms) do
|
||||
if not ps.used then
|
||||
if ps.required then lapp.error("missing required parameter: "..parm) end
|
||||
set_result(ps,parm,ps.defval)
|
||||
end
|
||||
end
|
||||
return results
|
||||
end
|
||||
|
||||
if arg then
|
||||
script = arg[0]:gsub('.+[\\/]',''):gsub('%.%a+$','')
|
||||
else
|
||||
script = "inter"
|
||||
end
|
||||
|
||||
|
||||
setmetatable(lapp, {
|
||||
__call = function(tbl,str) return lapp.process_options_string(str) end,
|
||||
})
|
||||
|
||||
|
||||
return lapp
|
||||
|
||||
|
||||
Reference in New Issue
Block a user