Command Line Module

lua-users home

This module is intended for processing command line parameters of Lua scripts. It doesn't try to be POSIX (or any other standard) compliant, since it is very Lua-oriented and allows to specify parameters of any Lua data type.

The module exports just one function: cmdline.getparam (its detailed description is given in the comment preceding the function body).

See also: GetOpt, AlternativeGetOpt and PosixGetOpt


-- started: 2008-04-12 by Shmuel Zeigerman
-- license: public domain

local ipairs,pairs,setfenv,tonumber,loadstring,type =
local tinsert, tconcat = table.insert, table.concat

local function commonerror (msg)
  return nil, ("[cmdline]: " .. msg)

local function argerror (msg, numarg)
  msg = msg and (": " .. msg) or ""
  return nil, ("[cmdline]: bad argument #" .. numarg .. msg)

local function iderror (numarg)
  return argerror("ID not valid", numarg)

local function idcheck (id)
  return id:match("^[%a_][%w_]*$") and true

  t_out = getparam(t_in [,options] [,params])

  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

  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.

  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
    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
      tinsert(t_out, v)
  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
    if #unknown > 0 then
      return commonerror("unknown options: " .. tconcat(unknown, ", "))
  if params then
    local missing = {}
    for _,v in ipairs(params) do
      if t_out[v]==nil then tinsert(missing, v) end
    if #missing > 0 then
      return commonerror("missing parameters: " .. tconcat(missing, ", "))
  return t_out


require "cmdline"
local getparam = cmdline.getparam
local function assertgood(...) return assert(getparam(...)) end
local function assertbad(...) return assert(not getparam(...)) end

local t_in = {
  "!var9={} and 5 and 6",

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

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

local t_out = assertgood(t_in, options) -- options checking
assertbad(t_in, {}) -- no options permitted

local t_out = assertgood(t_in, nil, {3, "var1"}) -- parameters checking
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")

RecentChanges · preferences
edit · history
Last edited December 11, 2009 11:40 pm GMT (diff)