• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1-- The MIT License (MIT)
2
3-- Copyright (c) 2013 - 2015 Peter Melnichenko
4
5-- Permission is hereby granted, free of charge, to any person obtaining a copy of
6-- this software and associated documentation files (the "Software"), to deal in
7-- the Software without restriction, including without limitation the rights to
8-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9-- the Software, and to permit persons to whom the Software is furnished to do so,
10-- subject to the following conditions:
11
12-- The above copyright notice and this permission notice shall be included in all
13-- copies or substantial portions of the Software.
14
15-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17-- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18-- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19-- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20-- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22local function deep_update(t1, t2)
23   for k, v in pairs(t2) do
24      if type(v) == "table" then
25         v = deep_update({}, v)
26      end
27
28      t1[k] = v
29   end
30
31   return t1
32end
33
34-- A property is a tuple {name, callback}.
35-- properties.args is number of properties that can be set as arguments
36-- when calling an object.
37local function class(prototype, properties, parent)
38   -- Class is the metatable of its instances.
39   local cl = {}
40   cl.__index = cl
41
42   if parent then
43      cl.__prototype = deep_update(deep_update({}, parent.__prototype), prototype)
44   else
45      cl.__prototype = prototype
46   end
47
48   if properties then
49      local names = {}
50
51      -- Create setter methods and fill set of property names.
52      for _, property in ipairs(properties) do
53         local name, callback = property[1], property[2]
54
55         cl[name] = function(self, value)
56            if not callback(self, value) then
57               self["_" .. name] = value
58            end
59
60            return self
61         end
62
63         names[name] = true
64      end
65
66      function cl.__call(self, ...)
67         -- When calling an object, if the first argument is a table,
68         -- interpret keys as property names, else delegate arguments
69         -- to corresponding setters in order.
70         if type((...)) == "table" then
71            for name, value in pairs((...)) do
72               if names[name] then
73                  self[name](self, value)
74               end
75            end
76         else
77            local nargs = select("#", ...)
78
79            for i, property in ipairs(properties) do
80               if i > nargs or i > properties.args then
81                  break
82               end
83
84               local arg = select(i, ...)
85
86               if arg ~= nil then
87                  self[property[1]](self, arg)
88               end
89            end
90         end
91
92         return self
93      end
94   end
95
96   -- If indexing class fails, fallback to its parent.
97   local class_metatable = {}
98   class_metatable.__index = parent
99
100   function class_metatable.__call(self, ...)
101      -- Calling a class returns its instance.
102      -- Arguments are delegated to the instance.
103      local object = deep_update({}, self.__prototype)
104      setmetatable(object, self)
105      return object(...)
106   end
107
108   return setmetatable(cl, class_metatable)
109end
110
111local function typecheck(name, types, value)
112   for _, type_ in ipairs(types) do
113      if type(value) == type_ then
114         return true
115      end
116   end
117
118   error(("bad property '%s' (%s expected, got %s)"):format(name, table.concat(types, " or "), type(value)))
119end
120
121local function typechecked(name, ...)
122   local types = {...}
123   return {name, function(_, value) typecheck(name, types, value) end}
124end
125
126local multiname = {"name", function(self, value)
127   typecheck("name", {"string"}, value)
128
129   for alias in value:gmatch("%S+") do
130      self._name = self._name or alias
131      table.insert(self._aliases, alias)
132   end
133
134   -- Do not set _name as with other properties.
135   return true
136end}
137
138local function parse_boundaries(str)
139   if tonumber(str) then
140      return tonumber(str), tonumber(str)
141   end
142
143   if str == "*" then
144      return 0, math.huge
145   end
146
147   if str == "+" then
148      return 1, math.huge
149   end
150
151   if str == "?" then
152      return 0, 1
153   end
154
155   if str:match "^%d+%-%d+$" then
156      local min, max = str:match "^(%d+)%-(%d+)$"
157      return tonumber(min), tonumber(max)
158   end
159
160   if str:match "^%d+%+$" then
161      local min = str:match "^(%d+)%+$"
162      return tonumber(min), math.huge
163   end
164end
165
166local function boundaries(name)
167   return {name, function(self, value)
168      typecheck(name, {"number", "string"}, value)
169
170      local min, max = parse_boundaries(value)
171
172      if not min then
173         error(("bad property '%s'"):format(name))
174      end
175
176      self["_min" .. name], self["_max" .. name] = min, max
177   end}
178end
179
180local actions = {}
181
182local option_action = {"action", function(_, value)
183   typecheck("action", {"function", "string"}, value)
184
185   if type(value) == "string" and not actions[value] then
186      error(("unknown action '%s'"):format(value))
187   end
188end}
189
190local option_init = {"init", function(self)
191   self._has_init = true
192end}
193
194local option_default = {"default", function(self, value)
195   if type(value) ~= "string" then
196      self._init = value
197      self._has_init = true
198      return true
199   end
200end}
201
202local add_help = {"add_help", function(self, value)
203   typecheck("add_help", {"boolean", "string", "table"}, value)
204
205   if self._has_help then
206      table.remove(self._options)
207      self._has_help = false
208   end
209
210   if value then
211      local help = self:flag()
212         :description "Show this help message and exit."
213         :action(function()
214            print(self:get_help())
215            os.exit(0)
216         end)
217
218      if value ~= true then
219         help = help(value)
220      end
221
222      if not help._name then
223         help "-h" "--help"
224      end
225
226      self._has_help = true
227   end
228end}
229
230local Parser = class({
231   _arguments = {},
232   _options = {},
233   _commands = {},
234   _mutexes = {},
235   _require_command = true,
236   _handle_options = true
237}, {
238   args = 3,
239   typechecked("name", "string"),
240   typechecked("description", "string"),
241   typechecked("epilog", "string"),
242   typechecked("usage", "string"),
243   typechecked("help", "string"),
244   typechecked("require_command", "boolean"),
245   typechecked("handle_options", "boolean"),
246   typechecked("action", "function"),
247   typechecked("command_target", "string"),
248   add_help
249})
250
251local Command = class({
252   _aliases = {}
253}, {
254   args = 3,
255   multiname,
256   typechecked("description", "string"),
257   typechecked("epilog", "string"),
258   typechecked("target", "string"),
259   typechecked("usage", "string"),
260   typechecked("help", "string"),
261   typechecked("require_command", "boolean"),
262   typechecked("handle_options", "boolean"),
263   typechecked("action", "function"),
264   typechecked("command_target", "string"),
265   add_help
266}, Parser)
267
268local Argument = class({
269   _minargs = 1,
270   _maxargs = 1,
271   _mincount = 1,
272   _maxcount = 1,
273   _defmode = "unused",
274   _show_default = true
275}, {
276   args = 5,
277   typechecked("name", "string"),
278   typechecked("description", "string"),
279   option_default,
280   typechecked("convert", "function", "table"),
281   boundaries("args"),
282   typechecked("target", "string"),
283   typechecked("defmode", "string"),
284   typechecked("show_default", "boolean"),
285   typechecked("argname", "string", "table"),
286   option_action,
287   option_init
288})
289
290local Option = class({
291   _aliases = {},
292   _mincount = 0,
293   _overwrite = true
294}, {
295   args = 6,
296   multiname,
297   typechecked("description", "string"),
298   option_default,
299   typechecked("convert", "function", "table"),
300   boundaries("args"),
301   boundaries("count"),
302   typechecked("target", "string"),
303   typechecked("defmode", "string"),
304   typechecked("show_default", "boolean"),
305   typechecked("overwrite", "boolean"),
306   typechecked("argname", "string", "table"),
307   option_action,
308   option_init
309}, Argument)
310
311function Argument:_get_argument_list()
312   local buf = {}
313   local i = 1
314
315   while i <= math.min(self._minargs, 3) do
316      local argname = self:_get_argname(i)
317
318      if self._default and self._defmode:find "a" then
319         argname = "[" .. argname .. "]"
320      end
321
322      table.insert(buf, argname)
323      i = i+1
324   end
325
326   while i <= math.min(self._maxargs, 3) do
327      table.insert(buf, "[" .. self:_get_argname(i) .. "]")
328      i = i+1
329
330      if self._maxargs == math.huge then
331         break
332      end
333   end
334
335   if i < self._maxargs then
336      table.insert(buf, "...")
337   end
338
339   return buf
340end
341
342function Argument:_get_usage()
343   local usage = table.concat(self:_get_argument_list(), " ")
344
345   if self._default and self._defmode:find "u" then
346      if self._maxargs > 1 or (self._minargs == 1 and not self._defmode:find "a") then
347         usage = "[" .. usage .. "]"
348      end
349   end
350
351   return usage
352end
353
354function actions.store_true(result, target)
355   result[target] = true
356end
357
358function actions.store_false(result, target)
359   result[target] = false
360end
361
362function actions.store(result, target, argument)
363   result[target] = argument
364end
365
366function actions.count(result, target, _, overwrite)
367   if not overwrite then
368      result[target] = result[target] + 1
369   end
370end
371
372function actions.append(result, target, argument, overwrite)
373   result[target] = result[target] or {}
374   table.insert(result[target], argument)
375
376   if overwrite then
377      table.remove(result[target], 1)
378   end
379end
380
381function actions.concat(result, target, arguments, overwrite)
382   if overwrite then
383      error("'concat' action can't handle too many invocations")
384   end
385
386   result[target] = result[target] or {}
387
388   for _, argument in ipairs(arguments) do
389      table.insert(result[target], argument)
390   end
391end
392
393function Argument:_get_action()
394   local action, init
395
396   if self._maxcount == 1 then
397      if self._maxargs == 0 then
398         action, init = "store_true", nil
399      else
400         action, init = "store", nil
401      end
402   else
403      if self._maxargs == 0 then
404         action, init = "count", 0
405      else
406         action, init = "append", {}
407      end
408   end
409
410   if self._action then
411      action = self._action
412   end
413
414   if self._has_init then
415      init = self._init
416   end
417
418   if type(action) == "string" then
419      action = actions[action]
420   end
421
422   return action, init
423end
424
425-- Returns placeholder for `narg`-th argument.
426function Argument:_get_argname(narg)
427   local argname = self._argname or self:_get_default_argname()
428
429   if type(argname) == "table" then
430      return argname[narg]
431   else
432      return argname
433   end
434end
435
436function Argument:_get_default_argname()
437   return "<" .. self._name .. ">"
438end
439
440function Option:_get_default_argname()
441   return "<" .. self:_get_default_target() .. ">"
442end
443
444-- Returns label to be shown in the help message.
445function Argument:_get_label()
446   return self._name
447end
448
449function Option:_get_label()
450   local variants = {}
451   local argument_list = self:_get_argument_list()
452   table.insert(argument_list, 1, nil)
453
454   for _, alias in ipairs(self._aliases) do
455      argument_list[1] = alias
456      table.insert(variants, table.concat(argument_list, " "))
457   end
458
459   return table.concat(variants, ", ")
460end
461
462function Command:_get_label()
463   return table.concat(self._aliases, ", ")
464end
465
466function Argument:_get_description()
467   if self._default and self._show_default then
468      if self._description then
469         return ("%s (default: %s)"):format(self._description, self._default)
470      else
471         return ("default: %s"):format(self._default)
472      end
473   else
474      return self._description or ""
475   end
476end
477
478function Command:_get_description()
479   return self._description or ""
480end
481
482function Option:_get_usage()
483   local usage = self:_get_argument_list()
484   table.insert(usage, 1, self._name)
485   usage = table.concat(usage, " ")
486
487   if self._mincount == 0 or self._default then
488      usage = "[" .. usage .. "]"
489   end
490
491   return usage
492end
493
494function Argument:_get_default_target()
495   return self._name
496end
497
498function Option:_get_default_target()
499   local res
500
501   for _, alias in ipairs(self._aliases) do
502      if alias:sub(1, 1) == alias:sub(2, 2) then
503         res = alias:sub(3)
504         break
505      end
506   end
507
508   res = res or self._name:sub(2)
509   return (res:gsub("-", "_"))
510end
511
512function Option:_is_vararg()
513   return self._maxargs ~= self._minargs
514end
515
516function Parser:_get_fullname()
517   local parent = self._parent
518   local buf = {self._name}
519
520   while parent do
521      table.insert(buf, 1, parent._name)
522      parent = parent._parent
523   end
524
525   return table.concat(buf, " ")
526end
527
528function Parser:_update_charset(charset)
529   charset = charset or {}
530
531   for _, command in ipairs(self._commands) do
532      command:_update_charset(charset)
533   end
534
535   for _, option in ipairs(self._options) do
536      for _, alias in ipairs(option._aliases) do
537         charset[alias:sub(1, 1)] = true
538      end
539   end
540
541   return charset
542end
543
544function Parser:argument(...)
545   local argument = Argument(...)
546   table.insert(self._arguments, argument)
547   return argument
548end
549
550function Parser:option(...)
551   local option = Option(...)
552
553   if self._has_help then
554      table.insert(self._options, #self._options, option)
555   else
556      table.insert(self._options, option)
557   end
558
559   return option
560end
561
562function Parser:flag(...)
563   return self:option():args(0)(...)
564end
565
566function Parser:command(...)
567   local command = Command():add_help(true)(...)
568   command._parent = self
569   table.insert(self._commands, command)
570   return command
571end
572
573function Parser:mutex(...)
574   local options = {...}
575
576   for i, option in ipairs(options) do
577      assert(getmetatable(option) == Option, ("bad argument #%d to 'mutex' (Option expected)"):format(i))
578   end
579
580   table.insert(self._mutexes, options)
581   return self
582end
583
584local max_usage_width = 70
585local usage_welcome = "Usage: "
586
587function Parser:get_usage()
588   if self._usage then
589      return self._usage
590   end
591
592   local lines = {usage_welcome .. self:_get_fullname()}
593
594   local function add(s)
595      if #lines[#lines]+1+#s <= max_usage_width then
596         lines[#lines] = lines[#lines] .. " " .. s
597      else
598         lines[#lines+1] = (" "):rep(#usage_welcome) .. s
599      end
600   end
601
602   -- This can definitely be refactored into something cleaner
603   local mutex_options = {}
604   local vararg_mutexes = {}
605
606   -- First, put mutexes which do not contain vararg options and remember those which do
607   for _, mutex in ipairs(self._mutexes) do
608      local buf = {}
609      local is_vararg = false
610
611      for _, option in ipairs(mutex) do
612         if option:_is_vararg() then
613            is_vararg = true
614         end
615
616         table.insert(buf, option:_get_usage())
617         mutex_options[option] = true
618      end
619
620      local repr = "(" .. table.concat(buf, " | ") .. ")"
621
622      if is_vararg then
623         table.insert(vararg_mutexes, repr)
624      else
625         add(repr)
626      end
627   end
628
629   -- Second, put regular options
630   for _, option in ipairs(self._options) do
631      if not mutex_options[option] and not option:_is_vararg() then
632         add(option:_get_usage())
633      end
634   end
635
636   -- Put positional arguments
637   for _, argument in ipairs(self._arguments) do
638      add(argument:_get_usage())
639   end
640
641   -- Put mutexes containing vararg options
642   for _, mutex_repr in ipairs(vararg_mutexes) do
643      add(mutex_repr)
644   end
645
646   for _, option in ipairs(self._options) do
647      if not mutex_options[option] and option:_is_vararg() then
648         add(option:_get_usage())
649      end
650   end
651
652   if #self._commands > 0 then
653      if self._require_command then
654         add("<command>")
655      else
656         add("[<command>]")
657      end
658
659      add("...")
660   end
661
662   return table.concat(lines, "\n")
663end
664
665local margin_len = 3
666local margin_len2 = 25
667local margin = (" "):rep(margin_len)
668local margin2 = (" "):rep(margin_len2)
669
670local function make_two_columns(s1, s2)
671   if s2 == "" then
672      return margin .. s1
673   end
674
675   s2 = s2:gsub("\n", "\n" .. margin2)
676
677   if #s1 < (margin_len2-margin_len) then
678      return margin .. s1 .. (" "):rep(margin_len2-margin_len-#s1) .. s2
679   else
680      return margin .. s1 .. "\n" .. margin2 .. s2
681   end
682end
683
684function Parser:get_help()
685   if self._help then
686      return self._help
687   end
688
689   local blocks = {self:get_usage()}
690
691   if self._description then
692      table.insert(blocks, self._description)
693   end
694
695   local labels = {"Arguments:", "Options:", "Commands:"}
696
697   for i, elements in ipairs{self._arguments, self._options, self._commands} do
698      if #elements > 0 then
699         local buf = {labels[i]}
700
701         for _, element in ipairs(elements) do
702            table.insert(buf, make_two_columns(element:_get_label(), element:_get_description()))
703         end
704
705         table.insert(blocks, table.concat(buf, "\n"))
706      end
707   end
708
709   if self._epilog then
710      table.insert(blocks, self._epilog)
711   end
712
713   return table.concat(blocks, "\n\n")
714end
715
716local function get_tip(context, wrong_name)
717   local context_pool = {}
718   local possible_name
719   local possible_names = {}
720
721   for name in pairs(context) do
722      if type(name) == "string" then
723         for i = 1, #name do
724            possible_name = name:sub(1, i - 1) .. name:sub(i + 1)
725
726            if not context_pool[possible_name] then
727               context_pool[possible_name] = {}
728            end
729
730            table.insert(context_pool[possible_name], name)
731         end
732      end
733   end
734
735   for i = 1, #wrong_name + 1 do
736      possible_name = wrong_name:sub(1, i - 1) .. wrong_name:sub(i + 1)
737
738      if context[possible_name] then
739         possible_names[possible_name] = true
740      elseif context_pool[possible_name] then
741         for _, name in ipairs(context_pool[possible_name]) do
742            possible_names[name] = true
743         end
744      end
745   end
746
747   local first = next(possible_names)
748
749   if first then
750      if next(possible_names, first) then
751         local possible_names_arr = {}
752
753         for name in pairs(possible_names) do
754            table.insert(possible_names_arr, "'" .. name .. "'")
755         end
756
757         table.sort(possible_names_arr)
758         return "\nDid you mean one of these: " .. table.concat(possible_names_arr, " ") .. "?"
759      else
760         return "\nDid you mean '" .. first .. "'?"
761      end
762   else
763      return ""
764   end
765end
766
767local ElementState = class({
768   invocations = 0
769})
770
771function ElementState:__call(state, element)
772   self.state = state
773   self.result = state.result
774   self.element = element
775   self.target = element._target or element:_get_default_target()
776   self.action, self.result[self.target] = element:_get_action()
777   return self
778end
779
780function ElementState:error(fmt, ...)
781   self.state:error(fmt, ...)
782end
783
784function ElementState:convert(argument)
785   local converter = self.element._convert
786
787   if converter then
788      local ok, err
789
790      if type(converter) == "function" then
791         ok, err = converter(argument)
792      else
793         ok = converter[argument]
794      end
795
796      if ok == nil then
797         self:error(err and "%s" or "malformed argument '%s'", err or argument)
798      end
799
800      argument = ok
801   end
802
803   return argument
804end
805
806function ElementState:default(mode)
807   return self.element._defmode:find(mode) and self.element._default
808end
809
810local function bound(noun, min, max, is_max)
811   local res = ""
812
813   if min ~= max then
814      res = "at " .. (is_max and "most" or "least") .. " "
815   end
816
817   local number = is_max and max or min
818   return res .. tostring(number) .. " " .. noun ..  (number == 1 and "" or "s")
819end
820
821function ElementState:invoke(alias)
822   self.open = true
823   self.name = ("%s '%s'"):format(alias and "option" or "argument", alias or self.element._name)
824   self.overwrite = false
825
826   if self.invocations >= self.element._maxcount then
827      if self.element._overwrite then
828         self.overwrite = true
829      else
830         self:error("%s must be used %s", self.name, bound("time", self.element._mincount, self.element._maxcount, true))
831      end
832   else
833      self.invocations = self.invocations + 1
834   end
835
836   self.args = {}
837
838   if self.element._maxargs <= 0 then
839      self:close()
840   end
841
842   return self.open
843end
844
845function ElementState:pass(argument)
846   argument = self:convert(argument)
847   table.insert(self.args, argument)
848
849   if #self.args >= self.element._maxargs then
850      self:close()
851   end
852
853   return self.open
854end
855
856function ElementState:complete_invocation()
857   while #self.args < self.element._minargs do
858      self:pass(self.element._default)
859   end
860end
861
862function ElementState:close()
863   if self.open then
864      self.open = false
865
866      if #self.args < self.element._minargs then
867         if self:default("a") then
868            self:complete_invocation()
869         else
870            if #self.args == 0 then
871               if getmetatable(self.element) == Argument then
872                  self:error("missing %s", self.name)
873               elseif self.element._maxargs == 1 then
874                  self:error("%s requires an argument", self.name)
875               end
876            end
877
878            self:error("%s requires %s", self.name, bound("argument", self.element._minargs, self.element._maxargs))
879         end
880      end
881
882      local args = self.args
883
884      if self.element._maxargs <= 1 then
885         args = args[1]
886      end
887
888      if self.element._maxargs == 1 and self.element._minargs == 0 and self.element._mincount ~= self.element._maxcount then
889         args = self.args
890      end
891
892      self.action(self.result, self.target, args, self.overwrite)
893   end
894end
895
896local ParseState = class({
897   result = {},
898   options = {},
899   arguments = {},
900   argument_i = 1,
901   element_to_mutexes = {},
902   mutex_to_used_option = {},
903   command_actions = {}
904})
905
906function ParseState:__call(parser, error_handler)
907   self.parser = parser
908   self.error_handler = error_handler
909   self.charset = parser:_update_charset()
910   self:switch(parser)
911   return self
912end
913
914function ParseState:error(fmt, ...)
915   self.error_handler(self.parser, fmt:format(...))
916end
917
918function ParseState:switch(parser)
919   self.parser = parser
920
921   if parser._action then
922      table.insert(self.command_actions, {action = parser._action, name = parser._name})
923   end
924
925   for _, option in ipairs(parser._options) do
926      option = ElementState(self, option)
927      table.insert(self.options, option)
928
929      for _, alias in ipairs(option.element._aliases) do
930         self.options[alias] = option
931      end
932   end
933
934   for _, mutex in ipairs(parser._mutexes) do
935      for _, option in ipairs(mutex) do
936         if not self.element_to_mutexes[option] then
937            self.element_to_mutexes[option] = {}
938         end
939
940         table.insert(self.element_to_mutexes[option], mutex)
941      end
942   end
943
944   for _, argument in ipairs(parser._arguments) do
945      argument = ElementState(self, argument)
946      table.insert(self.arguments, argument)
947      argument:invoke()
948   end
949
950   self.handle_options = parser._handle_options
951   self.argument = self.arguments[self.argument_i]
952   self.commands = parser._commands
953
954   for _, command in ipairs(self.commands) do
955      for _, alias in ipairs(command._aliases) do
956         self.commands[alias] = command
957      end
958   end
959end
960
961function ParseState:get_option(name)
962   local option = self.options[name]
963
964   if not option then
965      self:error("unknown option '%s'%s", name, get_tip(self.options, name))
966   else
967      return option
968   end
969end
970
971function ParseState:get_command(name)
972   local command = self.commands[name]
973
974   if not command then
975      if #self.commands > 0 then
976         self:error("unknown command '%s'%s", name, get_tip(self.commands, name))
977      else
978         self:error("too many arguments")
979      end
980   else
981      return command
982   end
983end
984
985function ParseState:invoke(option, name)
986   self:close()
987
988   if self.element_to_mutexes[option.element] then
989      for _, mutex in ipairs(self.element_to_mutexes[option.element]) do
990         local used_option = self.mutex_to_used_option[mutex]
991
992         if used_option and used_option ~= option then
993            self:error("option '%s' can not be used together with %s", name, used_option.name)
994         else
995            self.mutex_to_used_option[mutex] = option
996         end
997      end
998   end
999
1000   if option:invoke(name) then
1001      self.option = option
1002   end
1003end
1004
1005function ParseState:pass(arg)
1006   if self.option then
1007      if not self.option:pass(arg) then
1008         self.option = nil
1009      end
1010   elseif self.argument then
1011      if not self.argument:pass(arg) then
1012         self.argument_i = self.argument_i + 1
1013         self.argument = self.arguments[self.argument_i]
1014      end
1015   else
1016      local command = self:get_command(arg)
1017      self.result[command._target or command._name] = true
1018
1019      if self.parser._command_target then
1020         self.result[self.parser._command_target] = command._name
1021      end
1022
1023      self:switch(command)
1024   end
1025end
1026
1027function ParseState:close()
1028   if self.option then
1029      self.option:close()
1030      self.option = nil
1031   end
1032end
1033
1034function ParseState:finalize()
1035   self:close()
1036
1037   for i = self.argument_i, #self.arguments do
1038      local argument = self.arguments[i]
1039      if #argument.args == 0 and argument:default("u") then
1040         argument:complete_invocation()
1041      else
1042         argument:close()
1043      end
1044   end
1045
1046   if self.parser._require_command and #self.commands > 0 then
1047      self:error("a command is required")
1048   end
1049
1050   for _, option in ipairs(self.options) do
1051      local name = option.name or ("option '%s'"):format(option.element._name)
1052
1053      if option.invocations == 0 then
1054         if option:default("u") then
1055            option:invoke(name)
1056            option:complete_invocation()
1057            option:close()
1058         end
1059      end
1060
1061      local mincount = option.element._mincount
1062
1063      if option.invocations < mincount then
1064         if option:default("a") then
1065            while option.invocations < mincount do
1066               option:invoke(name)
1067               option:close()
1068            end
1069         elseif option.invocations == 0 then
1070            self:error("missing %s", name)
1071         else
1072            self:error("%s must be used %s", name, bound("time", mincount, option.element._maxcount))
1073         end
1074      end
1075   end
1076
1077   for i = #self.command_actions, 1, -1 do
1078      self.command_actions[i].action(self.result, self.command_actions[i].name)
1079   end
1080end
1081
1082function ParseState:parse(args)
1083   for _, arg in ipairs(args) do
1084      local plain = true
1085
1086      if self.handle_options then
1087         local first = arg:sub(1, 1)
1088
1089         if self.charset[first] then
1090            if #arg > 1 then
1091               plain = false
1092
1093               if arg:sub(2, 2) == first then
1094                  if #arg == 2 then
1095                     self:close()
1096                     self.handle_options = false
1097                  else
1098                     local equals = arg:find "="
1099                     if equals then
1100                        local name = arg:sub(1, equals - 1)
1101                        local option = self:get_option(name)
1102
1103                        if option.element._maxargs <= 0 then
1104                           self:error("option '%s' does not take arguments", name)
1105                        end
1106
1107                        self:invoke(option, name)
1108                        self:pass(arg:sub(equals + 1))
1109                     else
1110                        local option = self:get_option(arg)
1111                        self:invoke(option, arg)
1112                     end
1113                  end
1114               else
1115                  for i = 2, #arg do
1116                     local name = first .. arg:sub(i, i)
1117                     local option = self:get_option(name)
1118                     self:invoke(option, name)
1119
1120                     if i ~= #arg and option.element._maxargs > 0 then
1121                        self:pass(arg:sub(i + 1))
1122                        break
1123                     end
1124                  end
1125               end
1126            end
1127         end
1128      end
1129
1130      if plain then
1131         self:pass(arg)
1132      end
1133   end
1134
1135   self:finalize()
1136   return self.result
1137end
1138
1139function Parser:error(msg)
1140   io.stderr:write(("%s\n\nError: %s\n"):format(self:get_usage(), msg))
1141   os.exit(1)
1142end
1143
1144-- Compatibility with strict.lua and other checkers:
1145local default_cmdline = rawget(_G, "arg") or {}
1146
1147function Parser:_parse(args, error_handler)
1148   return ParseState(self, error_handler):parse(args or default_cmdline)
1149end
1150
1151function Parser:parse(args)
1152   return self:_parse(args, self.error)
1153end
1154
1155local function xpcall_error_handler(err)
1156   return tostring(err) .. "\noriginal " .. debug.traceback("", 2):sub(2)
1157end
1158
1159function Parser:pparse(args)
1160   local parse_error
1161
1162   local ok, result = xpcall(function()
1163      return self:_parse(args, function(_, err)
1164         parse_error = err
1165         error(err, 0)
1166      end)
1167   end, xpcall_error_handler)
1168
1169   if ok then
1170      return true, result
1171   elseif not parse_error then
1172      error(result, 0)
1173   else
1174      return false, parse_error
1175   end
1176end
1177
1178return function(...)
1179   return Parser(default_cmdline[0]):add_help(true)(...)
1180end
1181