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