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