Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2
* vim: set ts=8 sts=2 et sw=2 tw=80:
3
* This Source Code Form is subject to the terms of the Mozilla Public
4
* License, v. 2.0. If a copy of the MPL was not distributed with this
5
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#ifndef shell_jsoptparse_h
8
#define shell_jsoptparse_h
9
10
#include <stdio.h>
11
12
#include "js/AllocPolicy.h"
13
#include "js/Vector.h"
14
15
namespace js {
16
namespace cli {
17
18
namespace detail {
19
20
struct BoolOption;
21
struct MultiStringOption;
22
struct ValuedOption;
23
struct StringOption;
24
struct IntOption;
25
26
enum OptionKind {
27
OptionKindBool,
28
OptionKindString,
29
OptionKindInt,
30
OptionKindMultiString,
31
OptionKindInvalid
32
};
33
34
struct Option {
35
const char* longflag;
36
const char* help;
37
OptionKind kind;
38
char shortflag;
39
bool terminatesOptions;
40
41
Option(OptionKind kind, char shortflag, const char* longflag,
42
const char* help)
43
: longflag(longflag),
44
help(help),
45
kind(kind),
46
shortflag(shortflag),
47
terminatesOptions(false) {}
48
49
virtual ~Option() = 0;
50
51
void setTerminatesOptions(bool enabled) { terminatesOptions = enabled; }
52
bool getTerminatesOptions() const { return terminatesOptions; }
53
54
virtual bool isValued() const { return false; }
55
56
/* Only some valued options are variadic (like MultiStringOptions). */
57
virtual bool isVariadic() const { return false; }
58
59
/*
60
* For arguments, the shortflag field is used to indicate whether the
61
* argument is optional.
62
*/
63
bool isOptional() { return shortflag; }
64
65
void setFlagInfo(char shortflag, const char* longflag, const char* help) {
66
this->shortflag = shortflag;
67
this->longflag = longflag;
68
this->help = help;
69
}
70
71
ValuedOption* asValued();
72
const ValuedOption* asValued() const;
73
74
#define OPTION_CONVERT_DECL(__cls) \
75
bool is##__cls##Option() const; \
76
__cls##Option* as##__cls##Option(); \
77
const __cls##Option* as##__cls##Option() const;
78
79
OPTION_CONVERT_DECL(Bool)
80
OPTION_CONVERT_DECL(String)
81
OPTION_CONVERT_DECL(Int)
82
OPTION_CONVERT_DECL(MultiString)
83
};
84
85
inline Option::~Option() {}
86
87
struct BoolOption : public Option {
88
size_t argno;
89
bool value;
90
91
BoolOption(char shortflag, const char* longflag, const char* help)
92
: Option(OptionKindBool, shortflag, longflag, help), value(false) {}
93
94
virtual ~BoolOption() {}
95
};
96
97
struct ValuedOption : public Option {
98
const char* metavar;
99
100
ValuedOption(OptionKind kind, char shortflag, const char* longflag,
101
const char* help, const char* metavar)
102
: Option(kind, shortflag, longflag, help), metavar(metavar) {}
103
104
virtual ~ValuedOption() = 0;
105
virtual bool isValued() const override { return true; }
106
};
107
108
inline ValuedOption::~ValuedOption() {}
109
110
struct StringOption : public ValuedOption {
111
const char* value;
112
113
StringOption(char shortflag, const char* longflag, const char* help,
114
const char* metavar)
115
: ValuedOption(OptionKindString, shortflag, longflag, help, metavar),
116
value(nullptr) {}
117
118
virtual ~StringOption() {}
119
};
120
121
struct IntOption : public ValuedOption {
122
int value;
123
124
IntOption(char shortflag, const char* longflag, const char* help,
125
const char* metavar, int defaultValue)
126
: ValuedOption(OptionKindInt, shortflag, longflag, help, metavar),
127
value(defaultValue) {}
128
129
virtual ~IntOption() {}
130
};
131
132
struct StringArg {
133
char* value;
134
size_t argno;
135
136
StringArg(char* value, size_t argno) : value(value), argno(argno) {}
137
};
138
139
struct MultiStringOption : public ValuedOption {
140
Vector<StringArg, 0, SystemAllocPolicy> strings;
141
142
MultiStringOption(char shortflag, const char* longflag, const char* help,
143
const char* metavar)
144
: ValuedOption(OptionKindMultiString, shortflag, longflag, help,
145
metavar) {}
146
147
virtual ~MultiStringOption() {}
148
149
virtual bool isVariadic() const override { return true; }
150
};
151
152
} /* namespace detail */
153
154
class MultiStringRange {
155
typedef detail::StringArg StringArg;
156
const StringArg* cur;
157
const StringArg* end;
158
159
public:
160
explicit MultiStringRange(const StringArg* cur, const StringArg* end)
161
: cur(cur), end(end) {
162
MOZ_ASSERT(end - cur >= 0);
163
}
164
165
bool empty() const { return cur == end; }
166
void popFront() {
167
MOZ_ASSERT(!empty());
168
++cur;
169
}
170
char* front() const {
171
MOZ_ASSERT(!empty());
172
return cur->value;
173
}
174
size_t argno() const {
175
MOZ_ASSERT(!empty());
176
return cur->argno;
177
}
178
};
179
180
/*
181
* Builder for describing a command line interface and parsing the resulting
182
* specification.
183
*
184
* - A multi-option is an option that can appear multiple times and still
185
* parse as valid command line arguments.
186
* - An "optional argument" is supported for backwards compatibility with prior
187
* command line interface usage. Once one optional argument has been added,
188
* *only* optional arguments may be added.
189
*/
190
class OptionParser {
191
public:
192
enum Result {
193
Okay = 0,
194
Fail, /* As in, allocation fail. */
195
ParseError, /* Successfully parsed but with an error. */
196
EarlyExit /* Successfully parsed but exits the program,
197
* for example with --help and --version. */
198
};
199
200
private:
201
typedef Vector<detail::Option*, 0, SystemAllocPolicy> Options;
202
typedef detail::Option Option;
203
typedef detail::BoolOption BoolOption;
204
205
Options options;
206
Options arguments;
207
BoolOption helpOption;
208
BoolOption versionOption;
209
const char* usage;
210
const char* version;
211
const char* descr;
212
size_t descrWidth;
213
size_t helpWidth;
214
size_t nextArgument;
215
216
// If '--' is passed, all remaining arguments should be interpreted as the
217
// argument at index 'restArgument'. Defaults to the next unassigned
218
// argument.
219
int restArgument;
220
221
static const char prognameMeta[];
222
223
Option* findOption(char shortflag);
224
const Option* findOption(char shortflag) const;
225
Option* findOption(const char* longflag);
226
const Option* findOption(const char* longflag) const;
227
int findArgumentIndex(const char* name) const;
228
Option* findArgument(const char* name);
229
const Option* findArgument(const char* name) const;
230
231
Result error(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3);
232
Result extractValue(size_t argc, char** argv, size_t* i, char** value);
233
Result handleArg(size_t argc, char** argv, size_t* i, bool* optsAllowed);
234
Result handleOption(Option* opt, size_t argc, char** argv, size_t* i,
235
bool* optsAllowed);
236
237
public:
238
explicit OptionParser(const char* usage)
239
: helpOption('h', "help", "Display help information"),
240
versionOption('v', "version", "Display version information and exit"),
241
usage(usage),
242
version(nullptr),
243
descr(nullptr),
244
descrWidth(80),
245
helpWidth(80),
246
nextArgument(0),
247
restArgument(-1) {}
248
249
~OptionParser();
250
251
Result parseArgs(int argc, char** argv);
252
Result printHelp(const char* progname);
253
Result printVersion();
254
255
/* Metadata */
256
257
void setVersion(const char* v) { version = v; }
258
void setHelpWidth(size_t width) { helpWidth = width; }
259
void setDescriptionWidth(size_t width) { descrWidth = width; }
260
void setDescription(const char* description) { descr = description; }
261
void setHelpOption(char shortflag, const char* longflag, const char* help);
262
void setArgTerminatesOptions(const char* name, bool enabled);
263
void setArgCapturesRest(const char* name);
264
265
/* Arguments: no further arguments may be added after a variadic argument. */
266
267
bool addOptionalStringArg(const char* name, const char* help);
268
bool addOptionalMultiStringArg(const char* name, const char* help);
269
270
const char* getStringArg(const char* name) const;
271
MultiStringRange getMultiStringArg(const char* name) const;
272
273
/* Options */
274
275
bool addBoolOption(char shortflag, const char* longflag, const char* help);
276
bool addStringOption(char shortflag, const char* longflag, const char* help,
277
const char* metavar);
278
bool addIntOption(char shortflag, const char* longflag, const char* help,
279
const char* metavar, int defaultValue);
280
bool addMultiStringOption(char shortflag, const char* longflag,
281
const char* help, const char* metavar);
282
bool addOptionalVariadicArg(const char* name);
283
284
int getIntOption(char shortflag) const;
285
int getIntOption(const char* longflag) const;
286
const char* getStringOption(char shortflag) const;
287
const char* getStringOption(const char* longflag) const;
288
bool getBoolOption(char shortflag) const;
289
bool getBoolOption(const char* longflag) const;
290
MultiStringRange getMultiStringOption(char shortflag) const;
291
MultiStringRange getMultiStringOption(const char* longflag) const;
292
293
/*
294
* Return whether the help option was present (and thus help was already
295
* displayed during parse_args).
296
*/
297
bool getHelpOption() const;
298
};
299
300
} /* namespace cli */
301
} /* namespace js */
302
303
#endif /* shell_jsoptparse_h */