lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


My getopt is below. I call it "Unix-style" because it can be used to
implement programs that conform to the POSIX utility syntax guidelines,
and because it doesn't support GNUish long options. (I'm a BSD hacker.)
In the traditional C API, main() usually contains something like:

        while((opt = getopt(argc, argv, "a:...V")) != -1)
                switch(opt) {
                case('a'):
                        /* ... */
                        continue;
		/* ... */
		case('V'):
			printf("myprog version 0.0\n");
			exit(0);
                default:
                        usage();
                }
	argc -= optind;
	argv += optind;

Lua lacks a switch statement but it has closures, so my getopt has rather
different usage in order to be more Lunar. The loop over the options is
inside getopt, and instead of a switch you pass in a dispatch table whose
keys are option letters and whose values are option handler functions.
Options that take arguments have a _ appended to their keys. The first
argument to getopt is the array of command-line arguments, and its return
value is the rest of the arguments left after option processing. There's a
special "usage" element in the dispatch table for handling errors, in
which case getopt returns usage's return values. You can break the loop
early by throwing an exception, but then you won't conform to the
standard. For example,

	rest = getopt(arg, {
		a_    = function (param)
				-- ...
			end,
		-- ...
		V     = version,
		usage = usage
	})

I hope that is clear :-)

Tony.
-- 
f.anthony.n.finch  <dot@dotat.at>  http://dotat.at/
FAIR ISLE: SOUTHWEST VEERING NORTHWEST 7 TO SEVERE GALE 9, PERHAPS STORM 10
LATER. VERY ROUGH OR HIGH. SQUALLY SHOWERS. MODERATE OR GOOD.


--
-- Unix-style getopt
--
-- Written by Tony Finch <dot@dotat.at> <fanf2@cam.ac.uk>
-- at the University of Cambridge Computing Service.
-- You may do anything with this, at your own risk.
--
-- $Cambridge: users/fanf2/pstx/getopt.lua,v 1.5 2008/05/19 19:21:19 fanf2 Exp $
--

local string = require "string"
local table  = require "table"

local match  = string.match
local sub    = string.sub
local remove = table.remove
local setMT  = setmetatable

module "getopt"

function getopt(argv, handler)
   repeat
      local arg = argv[1]
      -- ran out of arguments
      if arg == nil then
	 return argv
      end
      -- explicit end of options
      if arg == "--" then
	 remove(argv,1)
	 return argv
      end
      local opt = match(arg, "^%-(%w)")
      -- remaining arguments are not options
      if not opt then
	 return argv
      end
      -- option with parameter
      local fun = handler[opt.."_"]
      if fun then
	 remove(argv,1)
	 -- parameter immediately follows option,
	 -- or is the following argument
	 local param = sub(arg,3)
	 if #param == 0 then
	    param = argv[1]
	    remove(argv,1)
	 end
	 fun(param, opt)
      else
	 if #arg == 2 then
	    -- bare option
	    remove(argv,1)
	 else
	    -- keep rest of clustered options
	    argv[1] = "-"..sub(arg,3)
	 end
	 fun = handler[opt]
	 if fun then
	    fun(true, opt)
	 else
	    return handler.usage()
	 end
      end
   until false
end

-- allow the user to call getopt() as well as getopt.getopt()

local function MTgetopt(module, argv, handler)
   return getopt(argv, handler)
end

setMT(_M, { __call = MTgetopt })

-- eof