xref: /minix3/libexec/httpd/lua/optparse.lua (revision 340f5e56603e4275faeb89a9aacace41ba22d661)
1*340f5e56SDavid van Moolenbroek-- Lua command line option parser.
2*340f5e56SDavid van Moolenbroek-- Interface based on Pythons optparse.
3*340f5e56SDavid van Moolenbroek-- http://docs.python.org/lib/module-optparse.html
4*340f5e56SDavid van Moolenbroek-- (c) 2008 David Manura, Licensed under the same terms as Lua (MIT license)
5*340f5e56SDavid van Moolenbroek--
6*340f5e56SDavid van Moolenbroek-- To be used like this:
7*340f5e56SDavid van Moolenbroek-- t={usage="<some usage message>", version="<version string>"}
8*340f5e56SDavid van Moolenbroek-- op=OptionParser(t)
9*340f5e56SDavid van Moolenbroek-- op=add_option{"<opt>", action=<action>, dest=<dest>, help="<help message for this option>"}
10*340f5e56SDavid van Moolenbroek--
11*340f5e56SDavid van Moolenbroek-- with :
12*340f5e56SDavid van Moolenbroek--   <opt> the option string to be used (can be anything, if one letter opt, then should be -x val, more letters: -xy=val )
13*340f5e56SDavid van Moolenbroek--   <action> one of
14*340f5e56SDavid van Moolenbroek--   - store: store in options as key, val
15*340f5e56SDavid van Moolenbroek--   - store_true: stores key, true
16*340f5e56SDavid van Moolenbroek--   - store_false: stores key, false
17*340f5e56SDavid van Moolenbroek--   <dest> is the key under which the option is saved
18*340f5e56SDavid van Moolenbroek--
19*340f5e56SDavid van Moolenbroek-- options,args = op.parse_args()
20*340f5e56SDavid van Moolenbroek--
21*340f5e56SDavid van Moolenbroek-- now options is the table of options (key, val) and args is the table with non-option arguments.
22*340f5e56SDavid van Moolenbroek-- You can use op.fail(message) for failing and op.print_help() for printing the usage as you like.
23*340f5e56SDavid van Moolenbroek
24*340f5e56SDavid van Moolenbroekfunction OptionParser(t)
25*340f5e56SDavid van Moolenbroek  local usage = t.usage
26*340f5e56SDavid van Moolenbroek  local version = t.version
27*340f5e56SDavid van Moolenbroek
28*340f5e56SDavid van Moolenbroek  local o = {}
29*340f5e56SDavid van Moolenbroek  local option_descriptions = {}
30*340f5e56SDavid van Moolenbroek  local option_of = {}
31*340f5e56SDavid van Moolenbroek
32*340f5e56SDavid van Moolenbroek  function o.fail(s) -- extension
33*340f5e56SDavid van Moolenbroek    io.stderr:write(s .. '\n')
34*340f5e56SDavid van Moolenbroek    os.exit(1)
35*340f5e56SDavid van Moolenbroek  end
36*340f5e56SDavid van Moolenbroek
37*340f5e56SDavid van Moolenbroek  function o.add_option(optdesc)
38*340f5e56SDavid van Moolenbroek    option_descriptions[#option_descriptions+1] = optdesc
39*340f5e56SDavid van Moolenbroek    for _,v in ipairs(optdesc) do
40*340f5e56SDavid van Moolenbroek      option_of[v] = optdesc
41*340f5e56SDavid van Moolenbroek    end
42*340f5e56SDavid van Moolenbroek  end
43*340f5e56SDavid van Moolenbroek  function o.parse_args()
44*340f5e56SDavid van Moolenbroek    -- expand options (e.g. "--input=file" -> "--input", "file")
45*340f5e56SDavid van Moolenbroek    local arg = {unpack(arg)}
46*340f5e56SDavid van Moolenbroek    for i=#arg,1,-1 do local v = arg[i]
47*340f5e56SDavid van Moolenbroek      local flag, val = v:match('^(%-%-%w+)=(.*)')
48*340f5e56SDavid van Moolenbroek      if flag then
49*340f5e56SDavid van Moolenbroek        arg[i] = flag
50*340f5e56SDavid van Moolenbroek        table.insert(arg, i+1, val)
51*340f5e56SDavid van Moolenbroek      end
52*340f5e56SDavid van Moolenbroek    end
53*340f5e56SDavid van Moolenbroek
54*340f5e56SDavid van Moolenbroek    local options = {}
55*340f5e56SDavid van Moolenbroek    local args = {}
56*340f5e56SDavid van Moolenbroek    local i = 1
57*340f5e56SDavid van Moolenbroek    while i <= #arg do local v = arg[i]
58*340f5e56SDavid van Moolenbroek      local optdesc = option_of[v]
59*340f5e56SDavid van Moolenbroek      if optdesc then
60*340f5e56SDavid van Moolenbroek        local action = optdesc.action
61*340f5e56SDavid van Moolenbroek        local val
62*340f5e56SDavid van Moolenbroek        if action == 'store' or action == nil then
63*340f5e56SDavid van Moolenbroek          i = i + 1
64*340f5e56SDavid van Moolenbroek          val = arg[i]
65*340f5e56SDavid van Moolenbroek          if not val then o.fail('option requires an argument ' .. v) end
66*340f5e56SDavid van Moolenbroek        elseif action == 'store_true' then
67*340f5e56SDavid van Moolenbroek          val = true
68*340f5e56SDavid van Moolenbroek        elseif action == 'store_false' then
69*340f5e56SDavid van Moolenbroek          val = false
70*340f5e56SDavid van Moolenbroek        end
71*340f5e56SDavid van Moolenbroek        options[optdesc.dest] = val
72*340f5e56SDavid van Moolenbroek      else
73*340f5e56SDavid van Moolenbroek        if v:match('^%-') then o.fail('invalid option ' .. v) end
74*340f5e56SDavid van Moolenbroek        args[#args+1] = v
75*340f5e56SDavid van Moolenbroek      end
76*340f5e56SDavid van Moolenbroek      i = i + 1
77*340f5e56SDavid van Moolenbroek    end
78*340f5e56SDavid van Moolenbroek    if options.help then
79*340f5e56SDavid van Moolenbroek      o.print_help()
80*340f5e56SDavid van Moolenbroek      os.exit()
81*340f5e56SDavid van Moolenbroek    end
82*340f5e56SDavid van Moolenbroek    if options.version then
83*340f5e56SDavid van Moolenbroek      io.stdout:write(t.version .. "\n")
84*340f5e56SDavid van Moolenbroek      os.exit()
85*340f5e56SDavid van Moolenbroek    end
86*340f5e56SDavid van Moolenbroek    return options, args
87*340f5e56SDavid van Moolenbroek  end
88*340f5e56SDavid van Moolenbroek
89*340f5e56SDavid van Moolenbroek  local function flags_str(optdesc)
90*340f5e56SDavid van Moolenbroek    local sflags = {}
91*340f5e56SDavid van Moolenbroek    local action = optdesc.action
92*340f5e56SDavid van Moolenbroek    for _,flag in ipairs(optdesc) do
93*340f5e56SDavid van Moolenbroek      local sflagend
94*340f5e56SDavid van Moolenbroek      if action == nil or action == 'store' then
95*340f5e56SDavid van Moolenbroek        local metavar = optdesc.metavar or optdesc.dest:upper()
96*340f5e56SDavid van Moolenbroek        sflagend = #flag == 2 and ' ' .. metavar
97*340f5e56SDavid van Moolenbroek                              or  '=' .. metavar
98*340f5e56SDavid van Moolenbroek      else
99*340f5e56SDavid van Moolenbroek        sflagend = ''
100*340f5e56SDavid van Moolenbroek      end
101*340f5e56SDavid van Moolenbroek      sflags[#sflags+1] = flag .. sflagend
102*340f5e56SDavid van Moolenbroek    end
103*340f5e56SDavid van Moolenbroek    return table.concat(sflags, ', ')
104*340f5e56SDavid van Moolenbroek  end
105*340f5e56SDavid van Moolenbroek
106*340f5e56SDavid van Moolenbroek  function o.print_help()
107*340f5e56SDavid van Moolenbroek    io.stdout:write("Usage: " .. usage:gsub('%%prog', arg[0]) .. "\n")
108*340f5e56SDavid van Moolenbroek    io.stdout:write("\n")
109*340f5e56SDavid van Moolenbroek    io.stdout:write("Options:\n")
110*340f5e56SDavid van Moolenbroek    for _,optdesc in ipairs(option_descriptions) do
111*340f5e56SDavid van Moolenbroek      io.stdout:write("  " .. flags_str(optdesc) ..
112*340f5e56SDavid van Moolenbroek                      "  " .. optdesc.help .. "\n")
113*340f5e56SDavid van Moolenbroek    end
114*340f5e56SDavid van Moolenbroek  end
115*340f5e56SDavid van Moolenbroek  o.add_option{"--help", action="store_true", dest="help",
116*340f5e56SDavid van Moolenbroek               help="show this help message and exit"}
117*340f5e56SDavid van Moolenbroek  if t.version then
118*340f5e56SDavid van Moolenbroek    o.add_option{"--version", action="store_true", dest="version",
119*340f5e56SDavid van Moolenbroek                 help="output version info."}
120*340f5e56SDavid van Moolenbroek  end
121*340f5e56SDavid van Moolenbroek  return o
122*340f5e56SDavid van Moolenbroekend
123*340f5e56SDavid van Moolenbroek
124