命令行模块 |
|
该模块只导出一个函数:cmdline.getparam(其详细描述在函数体前面的注释中给出)。
另请参见:GetOpt、AlternativeGetOpt 和 PosixGetOpt
-- started: 2008-04-12 by Shmuel Zeigerman -- license: public domain local ipairs,pairs,setfenv,tonumber,loadstring,type = ipairs,pairs,setfenv,tonumber,loadstring,type local tinsert, tconcat = table.insert, table.concat module(...) local function commonerror (msg) return nil, ("[cmdline]: " .. msg) end local function argerror (msg, numarg) msg = msg and (": " .. msg) or "" return nil, ("[cmdline]: bad argument #" .. numarg .. msg) end local function iderror (numarg) return argerror("ID not valid", numarg) end local function idcheck (id) return id:match("^[%a_][%w_]*$") and true end --[[------------------------------------------------------------------------ Syntax: t_out = getparam(t_in [,options] [,params]) Parameters: t_in: table - list of string arguments to be processed in order (usually it is the `arg' table created by the Lua interpreter). * if an argument begins with $, the $ is skipped and the rest is inserted into the array part of the output table. * if an argument begins with -, the rest is a sequence of variables (separated by commas or semicolons) that are all set to true; example: -var1,var2 --> var1,var2 = true,true * if an argument begins with !, the rest is a Lua chunk; example: !a=(40+3)*5;b=20;name="John";window={w=600,h=480} * if an argument contains =, then it is an assignment in the form var1,...=value (no space is allowed around the =) * if value begins with $, the $ is skipped, the rest is a string example: var1,var2=$ --> var1,var2 = "","" example: var1,var2=$125 --> var1,var2 = "125","125" example: var1,var2=$$125 --> var1,var2 = "$125","$125" * if value is convertible to number, it is a number example: var1,var2=125 --> var1,var2 = 125,125 * otherwise it is a string example: name=John --> name = "John" * if an argument neither begins with one of the special characters (-,!,$), nor contains =, it is inserted as is into the array part of the output table. options (optional): a list of names of all command-line options and parameters permitted in the application; used to check that each found option is valid; no checks are done if not supplied. params (optional): a list of names of all command-line parameters required by the application; used to check that each required parameter is present; no checks are done if not supplied. Returns: On success: the output table, e.g. { [1]="./myfile.txt", name="John", age=40 } On error: nil followed by error message string. --]]------------------------------------------------------------------------ function getparam (t_in, options, params) local t_out = {} for i,v in ipairs(t_in) do local prefix, command = v:sub(1,1), v:sub(2) if prefix == "$" then tinsert(t_out, command) elseif prefix == "-" then for id in command:gmatch"[^,;]+" do if not idcheck(id) then return iderror(i) end t_out[id] = true end elseif prefix == "!" then local f, err = loadstring(command) if not f then return argerror(err, i) end setfenv(f, t_out)() elseif v:find("=") then local ids, val = v:match("^([^=]+)%=(.*)") -- no space around = if not ids then return argerror("invalid assignment syntax", i) end val = val:sub(1,1)=="$" and val:sub(2) or tonumber(val) or val for id in ids:gmatch"[^,;]+" do if not idcheck(id) then return iderror(i) end t_out[id] = val end else tinsert(t_out, v) end end if options then local lookup, unknown = {}, {} for _,v in ipairs(options) do lookup[v] = true end for k,_ in pairs(t_out) do if lookup[k]==nil and type(k)=="string" then tinsert(unknown, k) end end if #unknown > 0 then return commonerror("unknown options: " .. tconcat(unknown, ", ")) end end if params then local missing = {} for _,v in ipairs(params) do if t_out[v]==nil then tinsert(missing, v) end end if #missing > 0 then return commonerror("missing parameters: " .. tconcat(missing, ", ")) end end return t_out end
require "cmdline" local getparam = cmdline.getparam local function assertgood(...) return assert(getparam(...)) end local function assertbad(...) return assert(not getparam(...)) end local t_in = { "var1,var1b=John", "var2,var2b=$Peter", "var3,var3b=$005", "var4,var4b=005", "!var5=8/2;var6=var5*40;var7=\"Ann\"", "!var8=nil", "!var9={} and 5 and 6", "-a,b2,c", "abcd", "/bin", "$-abc" } local function test1(t_out) assert (t_out.var1 == "John" and t_out.var1b == "John") assert (t_out.var2 == "Peter" and t_out.var2b == "Peter") assert (t_out.var3 == "005" and t_out.var3b == "005") assert (t_out.var4 == 5 and t_out.var4b == 5) assert (t_out.var5 == 4) assert (t_out.var6 == 160) assert (t_out.var7 == "Ann") assert (t_out.var8 == nil) assert (t_out.var9 == 6) assert (t_out.a==true and t_out.b2==true and t_out.c==true) assert (t_out[1] == "abcd") assert (t_out[2] == "/bin") assert (t_out[3] == "-abc") end local options = { "var1", "var1b", "var2", "var2b", "var3", "var3b", "var4", "var4b", "var5", "var6", "var7", "var8", "var9", "a", "b2", "c" } local t_out = assertgood(t_in) -- no options checking test1(t_out) local t_out = assertgood(t_in, options) -- options checking test1(t_out) assertbad(t_in, {}) -- no options permitted local t_out = assertgood(t_in, nil, {3, "var1"}) -- parameters checking test1(t_out) assertbad(t_in, nil, {"var0"}) -- parameter missing local t_bad = { -- bad syntax tests {"!abc"}, {"--88"}, {"-a,8,b"}, {"=8a=1"} } for _,v in ipairs(t_bad) do assertbad(v) end print ("OK: test_cmdline")