poelzi@107: -- Lua command line option parser. poelzi@107: -- Interface based on Pythons optparse. poelzi@107: -- http://docs.python.org/lib/module-optparse.html poelzi@107: -- (c) 2008 David Manura, Licensed under the same terms as Lua (MIT license) poelzi@107: -- poelzi@107: -- To be used like this: poelzi@107: -- t={usage="", version=""} poelzi@107: -- op=OptionParser(t) poelzi@107: -- op=add_option{"", action=, dest=, help=""} poelzi@107: -- poelzi@107: -- with : poelzi@107: -- the option string to be used (can be anything, if one letter opt, then should be -x val, more letters: -xy=val ) poelzi@107: -- one of poelzi@107: -- - store: store in options as key, val poelzi@107: -- - store_true: stores key, true poelzi@107: -- - store_false: stores key, false poelzi@107: -- is the key under which the option is saved poelzi@107: -- poelzi@107: -- options,args = op.parse_args() poelzi@107: -- poelzi@107: -- now options is the table of options (key, val) and args is the table with non-option arguments. poelzi@107: -- You can use op.fail(message) for failing and op.print_help() for printing the usage as you like. poelzi@107: poelzi@107: --module('utils.optparse') poelzi@107: poelzi@107: local function OptionParser(t) poelzi@107: local usage = t.usage poelzi@107: local version = t.version poelzi@107: local commands = t.commands poelzi@107: poelzi@107: local o = {} poelzi@107: local option_descriptions = {} poelzi@107: local option_of = {} poelzi@107: poelzi@107: function o.fail(s) -- extension poelzi@107: io.stderr:write(s .. '\n') poelzi@107: os.exit(1) poelzi@107: end poelzi@107: poelzi@107: function o.add_option(optdesc) poelzi@107: option_descriptions[#option_descriptions+1] = optdesc poelzi@107: for _,v in pairs(optdesc) do poelzi@107: option_of[v] = optdesc poelzi@107: end poelzi@107: end poelzi@107: function o.parse_args() poelzi@107: -- expand options (e.g. "--input=file" -> "--input", "file") poelzi@107: local arg = {unpack(arg)} poelzi@107: for i=#arg,1,-1 do local v = arg[i] poelzi@107: local flag, val = v:match('^(%-%-%w+)=(.*)') poelzi@107: if flag then poelzi@107: arg[i] = flag poelzi@107: table.insert(arg, i+1, val) poelzi@107: end poelzi@107: end poelzi@107: poelzi@107: local options = {} poelzi@107: for _,optdesc in ipairs(option_descriptions) do poelzi@107: options[optdesc["dest"]] = optdesc.default poelzi@107: end poelzi@107: local args = {} poelzi@107: local i = 1 poelzi@107: while i <= #arg do local v = arg[i] poelzi@107: local optdesc = option_of[v] poelzi@107: if optdesc then poelzi@107: local action = optdesc.action poelzi@107: local val poelzi@107: if action == 'store' or action == nil then poelzi@107: i = i + 1 poelzi@107: val = arg[i] poelzi@107: if not val then o.fail('option requires an argument ' .. v) end poelzi@107: elseif action == 'store_true' then poelzi@107: val = true poelzi@107: elseif action == 'store_false' then poelzi@107: val = false poelzi@107: end poelzi@107: options[optdesc.dest] = val poelzi@107: else poelzi@107: if v:match('^%-') then o.fail('invalid option ' .. v) end poelzi@107: args[#args+1] = v poelzi@107: end poelzi@107: i = i + 1 poelzi@107: end poelzi@107: if options.help then poelzi@107: o.print_help() poelzi@107: os.exit() poelzi@107: end poelzi@107: if options.version then poelzi@107: io.stdout:write(t.version .. "\n") poelzi@107: os.exit() poelzi@107: end poelzi@107: return options, args poelzi@107: end poelzi@107: poelzi@107: local function flags_str(optdesc) poelzi@107: local sflags = {} poelzi@107: local action = optdesc.action poelzi@107: for _,flag in ipairs(optdesc) do poelzi@107: local sflagend poelzi@107: if action == nil or action == 'store' then poelzi@107: local metavar = optdesc.metavar or optdesc.dest:upper() poelzi@107: sflagend = #flag == 2 and ' ' .. metavar poelzi@107: or '=' .. metavar poelzi@107: else poelzi@107: sflagend = '' poelzi@107: end poelzi@107: sflags[#sflags+1] = flag .. sflagend poelzi@107: end poelzi@107: return table.concat(sflags, ', ') poelzi@107: end poelzi@107: poelzi@107: function o.print_help() poelzi@107: io.stdout:write("Usage: " .. usage:gsub('%%prog', arg[0]) .. "\n") poelzi@107: io.stdout:write("\n") poelzi@107: io.stdout:write("Options:\n") poelzi@107: for _,optdesc in ipairs(option_descriptions) do poelzi@107: io.stdout:write(" " .. flags_str(optdesc) .. poelzi@107: " " .. optdesc.help .. "\n") poelzi@107: end poelzi@107: if commands then poelzi@107: io.stdout:write("\nCommands:\n") poelzi@107: for _,command in ipairs(commands) do poelzi@107: io.stdout:write(" " .. command[1] .. poelzi@107: string.rep(" ", 30-#command[1]) .. poelzi@107: command[2] .. "\n") poelzi@107: end poelzi@107: end poelzi@107: poelzi@107: end poelzi@107: o.add_option{"--help", action="store_true", dest="help", poelzi@107: help="show this help message and exit"} poelzi@107: if t.version then poelzi@107: o.add_option{"--version", action="store_true", dest="version", poelzi@107: help="output version info."} poelzi@107: end poelzi@107: return o poelzi@107: end poelzi@107: poelzi@107: return OptionParser