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