命令行模块

lua-users home
wiki

此模块旨在处理 Lua 脚本的命令行参数。它不尝试与 POSIX(或任何其他标准)兼容,因为它非常面向 Lua,并允许指定任何 Lua 数据类型的参数。

该模块只导出一个函数:cmdline.getparam(其详细描述在函数体前面的注释中给出)。

另请参见:GetOptAlternativeGetOptPosixGetOpt

cmdline.lua

-- 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

test_cmdline.lua

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")

最近更改 · 偏好设置
编辑 · 历史记录
最后编辑于 2009 年 12 月 12 日凌晨 12:40 GMT (差异)