1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sw=4 et tw=99:
3 : *
4 : * ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
7 : * The contents of this file are subject to the Mozilla Public License Version
8 : * 1.1 (the "License"); you may not use this file except in compliance with
9 : * the License. You may obtain a copy of the License at
10 : * http://www.mozilla.org/MPL/
11 : *
12 : * Software distributed under the License is distributed on an "AS IS" basis,
13 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 : * for the specific language governing rights and limitations under the
15 : * License.
16 : *
17 : * The Original Code is SpiderMonkey JavaScript shell.
18 : *
19 : * The Initial Developer of the Original Code is
20 : * Mozilla Corporation.
21 : * Portions created by the Initial Developer are Copyright (C) 2010
22 : * the Initial Developer. All Rights Reserved.
23 : *
24 : * Contributor(s):
25 : * Christopher D. Leary <cdleary@mozilla.com>
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either of the GNU General Public License Version 2 or later (the "GPL"),
29 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : #ifndef jsoptparse_h__
42 : #define jsoptparse_h__
43 :
44 : #include <stdio.h>
45 :
46 : #include "js/Vector.h"
47 : #include "jsalloc.h"
48 :
49 : namespace js {
50 : namespace cli {
51 :
52 : namespace detail {
53 :
54 : struct BoolOption;
55 : struct MultiStringOption;
56 : struct ValuedOption;
57 : struct StringOption;
58 : struct IntOption;
59 :
60 : enum OptionKind
61 : {
62 : OptionKindBool,
63 : OptionKindString,
64 : OptionKindInt,
65 : OptionKindMultiString,
66 : OptionKindInvalid
67 : };
68 :
69 : struct Option
70 : {
71 : const char *longflag;
72 : const char *help;
73 : OptionKind kind;
74 : char shortflag;
75 : bool terminatesOptions;
76 :
77 312885 : Option(OptionKind kind, char shortflag, const char *longflag, const char *help)
78 312885 : : longflag(longflag), help(help), kind(kind), shortflag(shortflag), terminatesOptions(false)
79 312885 : {}
80 :
81 : virtual ~Option() = 0;
82 :
83 18405 : void setTerminatesOptions(bool enabled) { terminatesOptions = enabled; }
84 94584 : bool getTerminatesOptions() const { return terminatesOptions; }
85 :
86 0 : virtual bool isValued() const { return false; }
87 :
88 : /* Only some valued options are variadic (like MultiStringOptions). */
89 18405 : virtual bool isVariadic() const { return false; }
90 :
91 : /*
92 : * For arguments, the shortflag field is used to indicate whether the
93 : * argument is optional.
94 : */
95 : bool isOptional() { return shortflag; }
96 :
97 0 : void setFlagInfo(char shortflag, const char *longflag, const char *help) {
98 0 : this->shortflag = shortflag;
99 0 : this->longflag = longflag;
100 0 : this->help = help;
101 0 : }
102 :
103 : ValuedOption *asValued();
104 : const ValuedOption *asValued() const;
105 :
106 : #define OPTION_CONVERT_DECL(__cls) \
107 : bool is##__cls##Option() const; \
108 : __cls##Option *as##__cls##Option(); \
109 : const __cls##Option *as##__cls##Option() const;
110 :
111 : OPTION_CONVERT_DECL(Bool)
112 : OPTION_CONVERT_DECL(String)
113 : OPTION_CONVERT_DECL(Int)
114 : OPTION_CONVERT_DECL(MultiString)
115 : };
116 :
117 312885 : inline Option::~Option() {}
118 :
119 : struct BoolOption : public Option
120 : {
121 : size_t argno;
122 : bool value;
123 :
124 202455 : BoolOption(char shortflag, const char *longflag, const char *help)
125 202455 : : Option(OptionKindBool, shortflag, longflag, help), value(false)
126 202455 : {}
127 :
128 202455 : virtual ~BoolOption() {}
129 : };
130 :
131 : struct ValuedOption : public Option
132 : {
133 : const char *metavar;
134 :
135 110430 : ValuedOption(OptionKind kind, char shortflag, const char *longflag, const char *help,
136 : const char *metavar)
137 110430 : : Option(kind, shortflag, longflag, help), metavar(metavar)
138 110430 : {}
139 :
140 : virtual ~ValuedOption() = 0;
141 0 : virtual bool isValued() const { return true; }
142 : };
143 :
144 110430 : inline ValuedOption::~ValuedOption() {}
145 :
146 : struct StringOption : public ValuedOption
147 : {
148 : const char *value;
149 :
150 36810 : StringOption(char shortflag, const char *longflag, const char *help, const char *metavar)
151 36810 : : ValuedOption(OptionKindString, shortflag, longflag, help, metavar), value(NULL)
152 36810 : {}
153 :
154 36810 : virtual ~StringOption() {}
155 : };
156 :
157 : struct IntOption : public ValuedOption
158 : {
159 : int value;
160 :
161 18405 : IntOption(char shortflag, const char *longflag, const char *help, const char *metavar,
162 : int defaultValue)
163 18405 : : ValuedOption(OptionKindInt, shortflag, longflag, help, metavar), value(defaultValue)
164 18405 : {}
165 :
166 18405 : virtual ~IntOption() {}
167 : };
168 :
169 : struct StringArg
170 73620 : {
171 : char *value;
172 : size_t argno;
173 :
174 55215 : StringArg(char *value, size_t argno) : value(value), argno(argno) {}
175 : };
176 :
177 : struct MultiStringOption : public ValuedOption
178 : {
179 : Vector<StringArg, 0, SystemAllocPolicy> strings;
180 :
181 55215 : MultiStringOption(char shortflag, const char *longflag, const char *help, const char *metavar)
182 55215 : : ValuedOption(OptionKindMultiString, shortflag, longflag, help, metavar)
183 55215 : {}
184 :
185 55215 : virtual ~MultiStringOption() {}
186 :
187 0 : virtual bool isVariadic() const { return true; }
188 : };
189 :
190 : } /* namespace detail */
191 :
192 : class MultiStringRange
193 : {
194 : typedef detail::StringArg StringArg;
195 : const StringArg *cur;
196 : const StringArg *end;
197 :
198 : public:
199 55215 : explicit MultiStringRange(const StringArg *cur, const StringArg *end)
200 55215 : : cur(cur), end(end) {
201 55215 : JS_ASSERT(end - cur >= 0);
202 55215 : }
203 :
204 420804 : bool empty() const { return cur == end; }
205 54378 : void popFront() { JS_ASSERT(!empty()); ++cur; }
206 55215 : char *front() const { JS_ASSERT(!empty()); return cur->value; }
207 73620 : size_t argno() const { JS_ASSERT(!empty()); return cur->argno; }
208 : };
209 :
210 : /*
211 : * Builder for describing a command line interface and parsing the resulting
212 : * specification.
213 : *
214 : * - A multi-option is an option that can appear multiple times and still
215 : * parse as valid command line arguments.
216 : * - An "optional argument" is supported for backwards compatibility with prior
217 : * command line interface usage. Once one optional argument has been added,
218 : * *only* optional arguments may be added.
219 : */
220 : class OptionParser
221 : {
222 : public:
223 : enum Result
224 : {
225 : Okay = 0,
226 : Fail, /* As in, allocation fail. */
227 : ParseError, /* Successfully parsed but with an error. */
228 : ParseHelp /* Aborted on help flag. */
229 : };
230 :
231 : private:
232 : typedef Vector<detail::Option *, 0, SystemAllocPolicy> Options;
233 : typedef detail::Option Option;
234 : typedef detail::BoolOption BoolOption;
235 :
236 : Options options;
237 : Options arguments;
238 : BoolOption helpOption;
239 : const char *usage;
240 : const char *ver;
241 : const char *descr;
242 : size_t descrWidth;
243 : size_t helpWidth;
244 : size_t nextArgument;
245 :
246 : static const char prognameMeta[];
247 :
248 : Option *findOption(char shortflag);
249 : const Option *findOption(char shortflag) const;
250 : Option *findOption(const char *longflag);
251 : const Option *findOption(const char *longflag) const;
252 : Option *findArgument(const char *name);
253 : const Option *findArgument(const char *name) const;
254 :
255 : Result error(const char *fmt, ...);
256 : Result extractValue(size_t argc, char **argv, size_t *i, char **value);
257 : Result handleArg(size_t argc, char **argv, size_t *i, bool *optsAllowed);
258 : Result handleOption(Option *opt, size_t argc, char **argv, size_t *i, bool *optsAllowed);
259 :
260 : public:
261 18405 : explicit OptionParser(const char *usage)
262 : : helpOption('h', "help", "Display help information"),
263 18405 : usage(usage), ver(NULL), descr(NULL), descrWidth(80), helpWidth(80), nextArgument(0)
264 18405 : {}
265 :
266 : ~OptionParser();
267 :
268 : Result parseArgs(int argc, char **argv);
269 : Result printHelp(const char *progname);
270 :
271 : /* Metadata */
272 :
273 18405 : void setVersion(const char *version) { ver = version; }
274 18405 : void setHelpWidth(size_t width) { helpWidth = width; }
275 18405 : void setDescriptionWidth(size_t width) { descrWidth = width; }
276 18405 : void setDescription(const char *description) { descr = description; }
277 : void setHelpOption(char shortflag, const char *longflag, const char *help);
278 : void setArgTerminatesOptions(const char *name, bool enabled);
279 :
280 : /* Arguments: no further arguments may be added after a variadic argument. */
281 :
282 : bool addOptionalStringArg(const char *name, const char *help);
283 : bool addOptionalMultiStringArg(const char *name, const char *help);
284 :
285 : const char *getStringArg(const char *name) const;
286 : MultiStringRange getMultiStringArg(const char *name) const;
287 :
288 : /* Options */
289 :
290 : bool addBoolOption(char shortflag, const char *longflag, const char *help);
291 : bool addStringOption(char shortflag, const char *longflag, const char *help,
292 : const char *metavar);
293 : bool addIntOption(char shortflag, const char *longflag, const char *help,
294 : const char *metavar, int defaultValue);
295 : bool addMultiStringOption(char shortflag, const char *longflag, const char *help,
296 : const char *metavar);
297 : bool addOptionalVariadicArg(const char *name);
298 :
299 : int getIntOption(char shortflag) const;
300 : int getIntOption(const char *longflag) const;
301 : const char *getStringOption(char shortflag) const;
302 : const char *getStringOption(const char *longflag) const;
303 : bool getBoolOption(char shortflag) const;
304 : bool getBoolOption(const char *longflag) const;
305 : MultiStringRange getMultiStringOption(char shortflag) const;
306 : MultiStringRange getMultiStringOption(const char *longflag) const;
307 :
308 : /*
309 : * Return whether the help option was present (and thus help was already
310 : * displayed during parse_args).
311 : */
312 : bool getHelpOption() const;
313 : };
314 :
315 : } /* namespace cli */
316 : } /* namespace js */
317 :
318 : #endif /* jsoptparse_h__ */
|