Added CLI parser library
This library can easily process flags, arguments, and flags with arguments.
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
local cliParse = {}
|
||||
local cliParseConfig
|
||||
|
||||
function cliParse.config(config)
|
||||
-- Check if config is valid
|
||||
checkArg(1, config, "table")
|
||||
for flagName, argCount in pairs(config) do
|
||||
if type(flagName) ~= "string" then
|
||||
error("Flag name " .. tostring(flagName) .. " must be a string")
|
||||
end
|
||||
if type(argCount) == "table" then -- Min and max arg count specified
|
||||
if type(argCount[1]) ~= "number" then
|
||||
error("Min args for flag " .. flagName .. " must be a number")
|
||||
end
|
||||
if argCount[1] < 0 then
|
||||
error("Min args for flag " .. flagName .. " must not be lower than 0")
|
||||
end
|
||||
if type(argCount[2]) ~= "number" then
|
||||
error("Max args for flag " .. flagName .. " must be a number")
|
||||
end
|
||||
if argCount[2] < 0 then
|
||||
error("Max args for flag " .. flagName .. " must not be lower than 0")
|
||||
end
|
||||
if argCount[2] < argCount[1] then
|
||||
error("Max args for flag " .. flagName .. " must be more than or equal to min args")
|
||||
end
|
||||
elseif type(argCount) == "number" then -- Required arg count specified
|
||||
if argCount < 0 then
|
||||
error("Required args for flag " .. flagName .. " must not be lower than 0")
|
||||
end
|
||||
else
|
||||
error("Arg count for flag " .. flagName .. " must be either a table of 2 numbers or a number")
|
||||
end
|
||||
-- Config is all good, set it
|
||||
cliParseConfig = config
|
||||
end
|
||||
end
|
||||
|
||||
function cliParse.parse(...)
|
||||
local args = { ... }
|
||||
local returnTable = { ["flags"] = {}, ["args"] = {} } -- This will be filled out and returned in the end
|
||||
|
||||
for i = 1, #args do -- This is used instead of pairs() so that the code can skip ahead when it finds arguments instead of flags by just incrementing i
|
||||
local flagList = {}
|
||||
if args[i]:sub(1, 2) == "--" then -- Long flag
|
||||
flagList = { args[i]:sub(3) }
|
||||
elseif args[i]:sub(1, 1) == "-" then -- Short flag(s)
|
||||
for i2 = 2, #args[i] do -- i is 2 to account for the - character at the start
|
||||
table.insert(flagList, args[i]:sub(i2, i2))
|
||||
end
|
||||
end
|
||||
for flagIndex, flag in ipairs(flagList) do -- Yes, this has to be in the argument loop for the skipahead to work.
|
||||
local flagConfig = cliParseConfig[flag]
|
||||
if flagConfig then -- This is a real flag
|
||||
returnTable.flags[flag] = {}
|
||||
if type(flagConfig) == "table" then
|
||||
if flagIndex ~= #flagList then -- This flag is in a chain and it's not the last one
|
||||
if flagConfig[1] ~= 0 then
|
||||
return false, "Flag " .. flag .. " expects at least " .. flagConfig[1] .. " arguments, got 0"
|
||||
end
|
||||
else
|
||||
for i2 = 1, flagConfig[1] do -- Iterate through the items AFTER the flags to find the minimum arguments
|
||||
if args[i + i2]:sub(1, 1) ~= "-" then -- This checks for both long and short flags
|
||||
table.insert(returnTable.flags[flag], args[i + i2]) -- Insert the argument found into the return table
|
||||
else
|
||||
return false, "Flag " .. flag .. " expects at least " .. flagConfig[1] .. " arguments, got " .. i2
|
||||
end
|
||||
end
|
||||
i = i + flagConfig[1]
|
||||
local i2IncrementAmount -- See line 71 and 76
|
||||
for i2 = 1, flagConfig[2] - flagConfig[1] do -- Now search for the max args
|
||||
if args[i + i2]:sub(1, 1) ~= "-" then -- This checks for both long and short flags
|
||||
table.insert(returnTable.flags[flag], args[i + i2]) -- Insert the argument found into the return table
|
||||
else
|
||||
i2IncrementAmount = i2 - 1
|
||||
-- Since the current argument is NOT a valid one, decrement by 1 to return to the last valid one (this is important when adding i2 to i)
|
||||
break
|
||||
end
|
||||
end
|
||||
i = i + (i2IncrementAmount or flagConfig[2])
|
||||
end
|
||||
else -- Flag required args are a single number
|
||||
if flagIndex ~= #flagList then -- This flag is in a chain and it's not the last one
|
||||
if flagConfig ~= 0 then
|
||||
return false, "Flag " .. flag .. " expects " .. flagConfig .. " arguments, got 0"
|
||||
end
|
||||
else
|
||||
for i2 = 1, flagConfig do -- Now search for the max args
|
||||
if args[i + i2]:sub(1, 1) ~= "-" then -- This checks for both long and short flags
|
||||
table.insert(returnTable.flags[flag], args[i + i2]) -- Insert the argument found into the return table
|
||||
else
|
||||
return false, "Flag " .. flag .. " expects " .. flagConfig[1] .. " arguments, got " .. i2
|
||||
end
|
||||
end
|
||||
i = i + flagConfig
|
||||
end
|
||||
end
|
||||
else
|
||||
return false, "Unexpected flag: " .. flag
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for _, arg in pairs(args) do
|
||||
local foundArg = false
|
||||
for _, flag in pairs(returnTable.flags) do -- A loop in a loop... Peak efficiency
|
||||
if table.find(flag, arg) or arg:sub(1, 1) == "-" then -- AAAND ANOTHER LOOP?!
|
||||
foundArg = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not foundArg then
|
||||
table.insert(returnTable.args, arg)
|
||||
end
|
||||
end
|
||||
|
||||
return returnTable
|
||||
end
|
||||
|
||||
return cliParse
|
||||
Reference in New Issue
Block a user