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