]> git.lyx.org Git - lyx.git/blob - lib/scripts/lyxwin_getopt.py
Remove profiling.py
[lyx.git] / lib / scripts / lyxwin_getopt.py
1 """Parser for command line options.
2
3 This module helps scripts to parse the command line arguments in
4 sys.argv.  It supports the same conventions as the Unix getopt()
5 function (including the special meanings of arguments of the form `-'
6 and `--').  Long options similar to those supported by GNU software
7 may be used as well via an optional third argument.  This module
8 provides two functions and an exception:
9
10 getopt() -- Parse command line options
11 gnu_getopt() -- Like getopt(), but allow option and non-option arguments
12 to be intermixed.
13 GetoptError -- exception (class) raised with 'opt' attribute, which is the
14 option involved with the exception.
15 """
16
17 # Long option support added by Lars Wirzenius <liw@iki.fi>.
18 #
19 # Gerrit Holl <gerrit@nl.linux.org> moved the string-based exceptions
20 # to class-based exceptions.
21 #
22 # Peter Åstrand <astrand@lysator.liu.se> added gnu_getopt().
23 #
24 # TODO for gnu_getopt():
25 #
26 # - GNU getopt_long_only mechanism
27 # - allow the caller to specify ordering
28 # - RETURN_IN_ORDER option
29 # - GNU extension with '-' as first character of option string
30 # - optional arguments, specified by double colons
31 # - an option string with a W followed by semicolon should
32 #   treat "-W foo" as "--foo"
33
34 __all__ = ["GetoptError","error","getopt","gnu_getopt"]
35
36 import os
37 try:
38     from gettext import gettext as _
39 except ImportError:
40     # Bootstrapping Python: gettext's dependencies not built yet
41     def _(s): return s
42
43 class GetoptError(Exception):
44     opt = ''
45     msg = ''
46     def __init__(self, msg, opt=''):
47         self.msg = msg
48         self.opt = opt
49         Exception.__init__(self, msg, opt)
50
51     def __str__(self):
52         return self.msg
53
54 error = GetoptError # backward compatibility
55
56 def getopt(args, shortopts, longopts = []):
57     """getopt(args, options[, long_options]) -> opts, args
58
59     Parses command line options and parameter list.  args is the
60     argument list to be parsed, without the leading reference to the
61     running program.  Typically, this means "sys.argv[1:]".  shortopts
62     is the string of option letters that the script wants to
63     recognize, with options that require an argument followed by a
64     colon (i.e., the same format that Unix getopt() uses).  If
65     specified, longopts is a list of strings with the names of the
66     long options which should be supported.  The leading '--'
67     characters should not be included in the option name.  Options
68     which require an argument should be followed by an equal sign
69     ('=').
70
71     The return value consists of two elements: the first is a list of
72     (option, value) pairs; the second is the list of program arguments
73     left after the option list was stripped (this is a trailing slice
74     of the first argument).  Each option-and-value pair returned has
75     the option as its first element, prefixed with a hyphen (e.g.,
76     '-x'), and the option argument as its second element, or an empty
77     string if the option has no argument.  The options occur in the
78     list in the same order in which they were found, thus allowing
79     multiple occurrences.  Long and short options may be mixed.
80
81     """
82
83     opts = []
84     if type(longopts) == str:
85         longopts = [longopts]
86     else:
87         longopts = list(longopts)
88     while args and args[0].startswith(b'-') and args[0] != '-':
89         if args[0] == '--':
90             args = args[1:]
91             break
92         if args[0].startswith(b'--'):
93             opts, args = do_longs(opts, args[0][2:], longopts, args[1:])
94         else:
95             opts, args = do_shorts(opts, args[0][1:], shortopts, args[1:])
96
97     return opts, args
98
99 def gnu_getopt(args, shortopts, longopts = []):
100     """getopt(args, options[, long_options]) -> opts, args
101
102     This function works like getopt(), except that GNU style scanning
103     mode is used by default. This means that option and non-option
104     arguments may be intermixed. The getopt() function stops
105     processing options as soon as a non-option argument is
106     encountered.
107
108     If the first character of the option string is `+', or if the
109     environment variable POSIXLY_CORRECT is set, then option
110     processing stops as soon as a non-option argument is encountered.
111
112     """
113
114     opts = []
115     prog_args = []
116     if isinstance(longopts, str):
117         longopts = [longopts]
118     else:
119         longopts = list(longopts)
120
121     # Allow options after non-option arguments?
122     if shortopts.startswith(b'+'):
123         shortopts = shortopts[1:]
124         all_options_first = True
125     elif os.environ.get("POSIXLY_CORRECT"):
126         all_options_first = True
127     else:
128         all_options_first = False
129
130     while args:
131         if args[0] == '--':
132             prog_args += args[1:]
133             break
134
135         if args[0][:2] == '--':
136             opts, args = do_longs(opts, args[0][2:], longopts, args[1:])
137         elif args[0][:1] == '-' and args[0] != '-':
138             opts, args = do_shorts(opts, args[0][1:], shortopts, args[1:])
139         else:
140             if all_options_first:
141                 prog_args += args
142                 break
143             else:
144                 prog_args.append(args[0])
145                 args = args[1:]
146
147     return opts, prog_args
148
149 def do_longs(opts, opt, longopts, args):
150     try:
151         i = opt.index('=')
152     except ValueError:
153         optarg = None
154     else:
155         opt, optarg = opt[:i], opt[i+1:]
156
157     has_arg, opt = long_has_args(opt, longopts)
158     if has_arg:
159         if optarg is None:
160             if not args:
161                 raise GetoptError(_('option --%s requires argument') % opt, opt)
162             optarg, args = args[0], args[1:]
163     elif optarg is not None:
164         raise GetoptError(_('option --%s must not have an argument') % opt, opt)
165     opts.append(('--' + opt, optarg or ''))
166     return opts, args
167
168 # Return:
169 #   has_arg?
170 #   full option name
171 def long_has_args(opt, longopts):
172     possibilities = [o for o in longopts if o.startswith(opt)]
173     if not possibilities:
174         raise GetoptError(_('option --%s not recognized') % opt, opt)
175     # Is there an exact match?
176     if opt in possibilities:
177         return False, opt
178     elif opt + '=' in possibilities:
179         return True, opt
180     # No exact match, so better be unique.
181     if len(possibilities) > 1:
182         # XXX since possibilities contains all valid continuations, might be
183         # nice to work them into the error msg
184         raise GetoptError(_('option --%s not a unique prefix') % opt, opt)
185     assert len(possibilities) == 1
186     unique_match = possibilities[0]
187     has_arg = unique_match.endswith('=')
188     if has_arg:
189         unique_match = unique_match[:-1]
190     return has_arg, unique_match
191
192 def do_shorts(opts, optstring, shortopts, args):
193     while optstring != '':
194         opt, optstring = optstring[0], optstring[1:]
195         if short_has_arg(opt, shortopts):
196             if optstring == '':
197                 if not args:
198                     raise GetoptError(_('option -%s requires argument') % opt,
199                                       opt)
200                 optstring, args = args[0], args[1:]
201             optarg, optstring = optstring, ''
202         else:
203             optarg = ''
204         opts.append(('-' + opt, optarg))
205     return opts, args
206
207 def short_has_arg(opt, shortopts):
208     for i in range(len(shortopts)):
209         if opt == shortopts[i] != ':':
210             return shortopts.startswith(b':', i+1)
211     raise GetoptError(_('option -%s not recognized') % opt, opt)
212
213 if __name__ == '__main__':
214     import sys
215     print(getopt(sys.argv[1:], "a:b", ["alpha=", "beta"]))