xref: /netbsd-src/libexec/httpd/lua/optparse.lua (revision 89bb3c6008af54d099dbc3eae581135aa5d073ac)
1390458faSmrg-- Lua command line option parser.
2390458faSmrg-- Interface based on Pythons optparse.
3390458faSmrg-- http://docs.python.org/lib/module-optparse.html
4390458faSmrg-- (c) 2008 David Manura, Licensed under the same terms as Lua (MIT license)
5390458faSmrg--
6390458faSmrg-- To be used like this:
7390458faSmrg-- t={usage="<some usage message>", version="<version string>"}
8390458faSmrg-- op=OptionParser(t)
9390458faSmrg-- op=add_option{"<opt>", action=<action>, dest=<dest>, help="<help message for this option>"}
10390458faSmrg--
11390458faSmrg-- with :
12390458faSmrg--   <opt> the option string to be used (can be anything, if one letter opt, then should be -x val, more letters: -xy=val )
13390458faSmrg--   <action> one of
14390458faSmrg--   - store: store in options as key, val
15390458faSmrg--   - store_true: stores key, true
16390458faSmrg--   - store_false: stores key, false
17390458faSmrg--   <dest> is the key under which the option is saved
18390458faSmrg--
19390458faSmrg-- options,args = op.parse_args()
20390458faSmrg--
21390458faSmrg-- now options is the table of options (key, val) and args is the table with non-option arguments.
22390458faSmrg-- You can use op.fail(message) for failing and op.print_help() for printing the usage as you like.
23390458faSmrg
24390458faSmrgfunction OptionParser(t)
25390458faSmrg  local usage = t.usage
26390458faSmrg  local version = t.version
27390458faSmrg
28390458faSmrg  local o = {}
29390458faSmrg  local option_descriptions = {}
30390458faSmrg  local option_of = {}
31390458faSmrg
32390458faSmrg  function o.fail(s) -- extension
33390458faSmrg    io.stderr:write(s .. '\n')
34390458faSmrg    os.exit(1)
35390458faSmrg  end
36390458faSmrg
37390458faSmrg  function o.add_option(optdesc)
38390458faSmrg    option_descriptions[#option_descriptions+1] = optdesc
39390458faSmrg    for _,v in ipairs(optdesc) do
40390458faSmrg      option_of[v] = optdesc
41390458faSmrg    end
42390458faSmrg  end
43390458faSmrg  function o.parse_args()
44390458faSmrg    -- expand options (e.g. "--input=file" -> "--input", "file")
45*89bb3c60Ssevan    local arg = {table.unpack(arg)}
46390458faSmrg    for i=#arg,1,-1 do local v = arg[i]
47390458faSmrg      local flag, val = v:match('^(%-%-%w+)=(.*)')
48390458faSmrg      if flag then
49390458faSmrg        arg[i] = flag
50390458faSmrg        table.insert(arg, i+1, val)
51390458faSmrg      end
52390458faSmrg    end
53390458faSmrg
54390458faSmrg    local options = {}
55390458faSmrg    local args = {}
56390458faSmrg    local i = 1
57390458faSmrg    while i <= #arg do local v = arg[i]
58390458faSmrg      local optdesc = option_of[v]
59390458faSmrg      if optdesc then
60390458faSmrg        local action = optdesc.action
61390458faSmrg        local val
62390458faSmrg        if action == 'store' or action == nil then
63390458faSmrg          i = i + 1
64390458faSmrg          val = arg[i]
65390458faSmrg          if not val then o.fail('option requires an argument ' .. v) end
66390458faSmrg        elseif action == 'store_true' then
67390458faSmrg          val = true
68390458faSmrg        elseif action == 'store_false' then
69390458faSmrg          val = false
70390458faSmrg        end
71390458faSmrg        options[optdesc.dest] = val
72390458faSmrg      else
73390458faSmrg        if v:match('^%-') then o.fail('invalid option ' .. v) end
74390458faSmrg        args[#args+1] = v
75390458faSmrg      end
76390458faSmrg      i = i + 1
77390458faSmrg    end
78390458faSmrg    if options.help then
79390458faSmrg      o.print_help()
80390458faSmrg      os.exit()
81390458faSmrg    end
82390458faSmrg    if options.version then
83390458faSmrg      io.stdout:write(t.version .. "\n")
84390458faSmrg      os.exit()
85390458faSmrg    end
86390458faSmrg    return options, args
87390458faSmrg  end
88390458faSmrg
89390458faSmrg  local function flags_str(optdesc)
90390458faSmrg    local sflags = {}
91390458faSmrg    local action = optdesc.action
92390458faSmrg    for _,flag in ipairs(optdesc) do
93390458faSmrg      local sflagend
94390458faSmrg      if action == nil or action == 'store' then
95390458faSmrg        local metavar = optdesc.metavar or optdesc.dest:upper()
96390458faSmrg        sflagend = #flag == 2 and ' ' .. metavar
97390458faSmrg                              or  '=' .. metavar
98390458faSmrg      else
99390458faSmrg        sflagend = ''
100390458faSmrg      end
101390458faSmrg      sflags[#sflags+1] = flag .. sflagend
102390458faSmrg    end
103390458faSmrg    return table.concat(sflags, ', ')
104390458faSmrg  end
105390458faSmrg
106390458faSmrg  function o.print_help()
107390458faSmrg    io.stdout:write("Usage: " .. usage:gsub('%%prog', arg[0]) .. "\n")
108390458faSmrg    io.stdout:write("\n")
109390458faSmrg    io.stdout:write("Options:\n")
110390458faSmrg    for _,optdesc in ipairs(option_descriptions) do
111390458faSmrg      io.stdout:write("  " .. flags_str(optdesc) ..
112390458faSmrg                      "  " .. optdesc.help .. "\n")
113390458faSmrg    end
114390458faSmrg  end
115390458faSmrg  o.add_option{"--help", action="store_true", dest="help",
116390458faSmrg               help="show this help message and exit"}
117390458faSmrg  if t.version then
118390458faSmrg    o.add_option{"--version", action="store_true", dest="version",
119390458faSmrg                 help="output version info."}
120390458faSmrg  end
121390458faSmrg  return o
122390458faSmrgend
123390458faSmrg
124