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