17db96d56Sopenharmony_ci"""Parser for command line options. 27db96d56Sopenharmony_ci 37db96d56Sopenharmony_ciThis module helps scripts to parse the command line arguments in 47db96d56Sopenharmony_cisys.argv. It supports the same conventions as the Unix getopt() 57db96d56Sopenharmony_cifunction (including the special meanings of arguments of the form `-' 67db96d56Sopenharmony_ciand `--'). Long options similar to those supported by GNU software 77db96d56Sopenharmony_cimay be used as well via an optional third argument. This module 87db96d56Sopenharmony_ciprovides two functions and an exception: 97db96d56Sopenharmony_ci 107db96d56Sopenharmony_cigetopt() -- Parse command line options 117db96d56Sopenharmony_cignu_getopt() -- Like getopt(), but allow option and non-option arguments 127db96d56Sopenharmony_cito be intermixed. 137db96d56Sopenharmony_ciGetoptError -- exception (class) raised with 'opt' attribute, which is the 147db96d56Sopenharmony_cioption involved with the exception. 157db96d56Sopenharmony_ci""" 167db96d56Sopenharmony_ci 177db96d56Sopenharmony_ci# Long option support added by Lars Wirzenius <liw@iki.fi>. 187db96d56Sopenharmony_ci# 197db96d56Sopenharmony_ci# Gerrit Holl <gerrit@nl.linux.org> moved the string-based exceptions 207db96d56Sopenharmony_ci# to class-based exceptions. 217db96d56Sopenharmony_ci# 227db96d56Sopenharmony_ci# Peter Åstrand <astrand@lysator.liu.se> added gnu_getopt(). 237db96d56Sopenharmony_ci# 247db96d56Sopenharmony_ci# TODO for gnu_getopt(): 257db96d56Sopenharmony_ci# 267db96d56Sopenharmony_ci# - GNU getopt_long_only mechanism 277db96d56Sopenharmony_ci# - allow the caller to specify ordering 287db96d56Sopenharmony_ci# - RETURN_IN_ORDER option 297db96d56Sopenharmony_ci# - GNU extension with '-' as first character of option string 307db96d56Sopenharmony_ci# - optional arguments, specified by double colons 317db96d56Sopenharmony_ci# - an option string with a W followed by semicolon should 327db96d56Sopenharmony_ci# treat "-W foo" as "--foo" 337db96d56Sopenharmony_ci 347db96d56Sopenharmony_ci__all__ = ["GetoptError","error","getopt","gnu_getopt"] 357db96d56Sopenharmony_ci 367db96d56Sopenharmony_ciimport os 377db96d56Sopenharmony_citry: 387db96d56Sopenharmony_ci from gettext import gettext as _ 397db96d56Sopenharmony_ciexcept ImportError: 407db96d56Sopenharmony_ci # Bootstrapping Python: gettext's dependencies not built yet 417db96d56Sopenharmony_ci def _(s): return s 427db96d56Sopenharmony_ci 437db96d56Sopenharmony_ciclass GetoptError(Exception): 447db96d56Sopenharmony_ci opt = '' 457db96d56Sopenharmony_ci msg = '' 467db96d56Sopenharmony_ci def __init__(self, msg, opt=''): 477db96d56Sopenharmony_ci self.msg = msg 487db96d56Sopenharmony_ci self.opt = opt 497db96d56Sopenharmony_ci Exception.__init__(self, msg, opt) 507db96d56Sopenharmony_ci 517db96d56Sopenharmony_ci def __str__(self): 527db96d56Sopenharmony_ci return self.msg 537db96d56Sopenharmony_ci 547db96d56Sopenharmony_cierror = GetoptError # backward compatibility 557db96d56Sopenharmony_ci 567db96d56Sopenharmony_cidef getopt(args, shortopts, longopts = []): 577db96d56Sopenharmony_ci """getopt(args, options[, long_options]) -> opts, args 587db96d56Sopenharmony_ci 597db96d56Sopenharmony_ci Parses command line options and parameter list. args is the 607db96d56Sopenharmony_ci argument list to be parsed, without the leading reference to the 617db96d56Sopenharmony_ci running program. Typically, this means "sys.argv[1:]". shortopts 627db96d56Sopenharmony_ci is the string of option letters that the script wants to 637db96d56Sopenharmony_ci recognize, with options that require an argument followed by a 647db96d56Sopenharmony_ci colon (i.e., the same format that Unix getopt() uses). If 657db96d56Sopenharmony_ci specified, longopts is a list of strings with the names of the 667db96d56Sopenharmony_ci long options which should be supported. The leading '--' 677db96d56Sopenharmony_ci characters should not be included in the option name. Options 687db96d56Sopenharmony_ci which require an argument should be followed by an equal sign 697db96d56Sopenharmony_ci ('='). 707db96d56Sopenharmony_ci 717db96d56Sopenharmony_ci The return value consists of two elements: the first is a list of 727db96d56Sopenharmony_ci (option, value) pairs; the second is the list of program arguments 737db96d56Sopenharmony_ci left after the option list was stripped (this is a trailing slice 747db96d56Sopenharmony_ci of the first argument). Each option-and-value pair returned has 757db96d56Sopenharmony_ci the option as its first element, prefixed with a hyphen (e.g., 767db96d56Sopenharmony_ci '-x'), and the option argument as its second element, or an empty 777db96d56Sopenharmony_ci string if the option has no argument. The options occur in the 787db96d56Sopenharmony_ci list in the same order in which they were found, thus allowing 797db96d56Sopenharmony_ci multiple occurrences. Long and short options may be mixed. 807db96d56Sopenharmony_ci 817db96d56Sopenharmony_ci """ 827db96d56Sopenharmony_ci 837db96d56Sopenharmony_ci opts = [] 847db96d56Sopenharmony_ci if type(longopts) == type(""): 857db96d56Sopenharmony_ci longopts = [longopts] 867db96d56Sopenharmony_ci else: 877db96d56Sopenharmony_ci longopts = list(longopts) 887db96d56Sopenharmony_ci while args and args[0].startswith('-') and args[0] != '-': 897db96d56Sopenharmony_ci if args[0] == '--': 907db96d56Sopenharmony_ci args = args[1:] 917db96d56Sopenharmony_ci break 927db96d56Sopenharmony_ci if args[0].startswith('--'): 937db96d56Sopenharmony_ci opts, args = do_longs(opts, args[0][2:], longopts, args[1:]) 947db96d56Sopenharmony_ci else: 957db96d56Sopenharmony_ci opts, args = do_shorts(opts, args[0][1:], shortopts, args[1:]) 967db96d56Sopenharmony_ci 977db96d56Sopenharmony_ci return opts, args 987db96d56Sopenharmony_ci 997db96d56Sopenharmony_cidef gnu_getopt(args, shortopts, longopts = []): 1007db96d56Sopenharmony_ci """getopt(args, options[, long_options]) -> opts, args 1017db96d56Sopenharmony_ci 1027db96d56Sopenharmony_ci This function works like getopt(), except that GNU style scanning 1037db96d56Sopenharmony_ci mode is used by default. This means that option and non-option 1047db96d56Sopenharmony_ci arguments may be intermixed. The getopt() function stops 1057db96d56Sopenharmony_ci processing options as soon as a non-option argument is 1067db96d56Sopenharmony_ci encountered. 1077db96d56Sopenharmony_ci 1087db96d56Sopenharmony_ci If the first character of the option string is `+', or if the 1097db96d56Sopenharmony_ci environment variable POSIXLY_CORRECT is set, then option 1107db96d56Sopenharmony_ci processing stops as soon as a non-option argument is encountered. 1117db96d56Sopenharmony_ci 1127db96d56Sopenharmony_ci """ 1137db96d56Sopenharmony_ci 1147db96d56Sopenharmony_ci opts = [] 1157db96d56Sopenharmony_ci prog_args = [] 1167db96d56Sopenharmony_ci if isinstance(longopts, str): 1177db96d56Sopenharmony_ci longopts = [longopts] 1187db96d56Sopenharmony_ci else: 1197db96d56Sopenharmony_ci longopts = list(longopts) 1207db96d56Sopenharmony_ci 1217db96d56Sopenharmony_ci # Allow options after non-option arguments? 1227db96d56Sopenharmony_ci if shortopts.startswith('+'): 1237db96d56Sopenharmony_ci shortopts = shortopts[1:] 1247db96d56Sopenharmony_ci all_options_first = True 1257db96d56Sopenharmony_ci elif os.environ.get("POSIXLY_CORRECT"): 1267db96d56Sopenharmony_ci all_options_first = True 1277db96d56Sopenharmony_ci else: 1287db96d56Sopenharmony_ci all_options_first = False 1297db96d56Sopenharmony_ci 1307db96d56Sopenharmony_ci while args: 1317db96d56Sopenharmony_ci if args[0] == '--': 1327db96d56Sopenharmony_ci prog_args += args[1:] 1337db96d56Sopenharmony_ci break 1347db96d56Sopenharmony_ci 1357db96d56Sopenharmony_ci if args[0][:2] == '--': 1367db96d56Sopenharmony_ci opts, args = do_longs(opts, args[0][2:], longopts, args[1:]) 1377db96d56Sopenharmony_ci elif args[0][:1] == '-' and args[0] != '-': 1387db96d56Sopenharmony_ci opts, args = do_shorts(opts, args[0][1:], shortopts, args[1:]) 1397db96d56Sopenharmony_ci else: 1407db96d56Sopenharmony_ci if all_options_first: 1417db96d56Sopenharmony_ci prog_args += args 1427db96d56Sopenharmony_ci break 1437db96d56Sopenharmony_ci else: 1447db96d56Sopenharmony_ci prog_args.append(args[0]) 1457db96d56Sopenharmony_ci args = args[1:] 1467db96d56Sopenharmony_ci 1477db96d56Sopenharmony_ci return opts, prog_args 1487db96d56Sopenharmony_ci 1497db96d56Sopenharmony_cidef do_longs(opts, opt, longopts, args): 1507db96d56Sopenharmony_ci try: 1517db96d56Sopenharmony_ci i = opt.index('=') 1527db96d56Sopenharmony_ci except ValueError: 1537db96d56Sopenharmony_ci optarg = None 1547db96d56Sopenharmony_ci else: 1557db96d56Sopenharmony_ci opt, optarg = opt[:i], opt[i+1:] 1567db96d56Sopenharmony_ci 1577db96d56Sopenharmony_ci has_arg, opt = long_has_args(opt, longopts) 1587db96d56Sopenharmony_ci if has_arg: 1597db96d56Sopenharmony_ci if optarg is None: 1607db96d56Sopenharmony_ci if not args: 1617db96d56Sopenharmony_ci raise GetoptError(_('option --%s requires argument') % opt, opt) 1627db96d56Sopenharmony_ci optarg, args = args[0], args[1:] 1637db96d56Sopenharmony_ci elif optarg is not None: 1647db96d56Sopenharmony_ci raise GetoptError(_('option --%s must not have an argument') % opt, opt) 1657db96d56Sopenharmony_ci opts.append(('--' + opt, optarg or '')) 1667db96d56Sopenharmony_ci return opts, args 1677db96d56Sopenharmony_ci 1687db96d56Sopenharmony_ci# Return: 1697db96d56Sopenharmony_ci# has_arg? 1707db96d56Sopenharmony_ci# full option name 1717db96d56Sopenharmony_cidef long_has_args(opt, longopts): 1727db96d56Sopenharmony_ci possibilities = [o for o in longopts if o.startswith(opt)] 1737db96d56Sopenharmony_ci if not possibilities: 1747db96d56Sopenharmony_ci raise GetoptError(_('option --%s not recognized') % opt, opt) 1757db96d56Sopenharmony_ci # Is there an exact match? 1767db96d56Sopenharmony_ci if opt in possibilities: 1777db96d56Sopenharmony_ci return False, opt 1787db96d56Sopenharmony_ci elif opt + '=' in possibilities: 1797db96d56Sopenharmony_ci return True, opt 1807db96d56Sopenharmony_ci # No exact match, so better be unique. 1817db96d56Sopenharmony_ci if len(possibilities) > 1: 1827db96d56Sopenharmony_ci # XXX since possibilities contains all valid continuations, might be 1837db96d56Sopenharmony_ci # nice to work them into the error msg 1847db96d56Sopenharmony_ci raise GetoptError(_('option --%s not a unique prefix') % opt, opt) 1857db96d56Sopenharmony_ci assert len(possibilities) == 1 1867db96d56Sopenharmony_ci unique_match = possibilities[0] 1877db96d56Sopenharmony_ci has_arg = unique_match.endswith('=') 1887db96d56Sopenharmony_ci if has_arg: 1897db96d56Sopenharmony_ci unique_match = unique_match[:-1] 1907db96d56Sopenharmony_ci return has_arg, unique_match 1917db96d56Sopenharmony_ci 1927db96d56Sopenharmony_cidef do_shorts(opts, optstring, shortopts, args): 1937db96d56Sopenharmony_ci while optstring != '': 1947db96d56Sopenharmony_ci opt, optstring = optstring[0], optstring[1:] 1957db96d56Sopenharmony_ci if short_has_arg(opt, shortopts): 1967db96d56Sopenharmony_ci if optstring == '': 1977db96d56Sopenharmony_ci if not args: 1987db96d56Sopenharmony_ci raise GetoptError(_('option -%s requires argument') % opt, 1997db96d56Sopenharmony_ci opt) 2007db96d56Sopenharmony_ci optstring, args = args[0], args[1:] 2017db96d56Sopenharmony_ci optarg, optstring = optstring, '' 2027db96d56Sopenharmony_ci else: 2037db96d56Sopenharmony_ci optarg = '' 2047db96d56Sopenharmony_ci opts.append(('-' + opt, optarg)) 2057db96d56Sopenharmony_ci return opts, args 2067db96d56Sopenharmony_ci 2077db96d56Sopenharmony_cidef short_has_arg(opt, shortopts): 2087db96d56Sopenharmony_ci for i in range(len(shortopts)): 2097db96d56Sopenharmony_ci if opt == shortopts[i] != ':': 2107db96d56Sopenharmony_ci return shortopts.startswith(':', i+1) 2117db96d56Sopenharmony_ci raise GetoptError(_('option -%s not recognized') % opt, opt) 2127db96d56Sopenharmony_ci 2137db96d56Sopenharmony_ciif __name__ == '__main__': 2147db96d56Sopenharmony_ci import sys 2157db96d56Sopenharmony_ci print(getopt(sys.argv[1:], "a:b", ["alpha=", "beta"])) 216