blob: c6a783de3f4e9d8186dc0f81be78c7131e308c89 [file] [log] [blame]
scroggo@google.com161e1ba2013-03-04 16:41:06 +00001/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
scroggo@google.comd9ba9a02013-03-21 19:43:15 +00008#ifndef SK_COMMAND_LINE_FLAGS_H
9#define SK_COMMAND_LINE_FLAGS_H
scroggo@google.com161e1ba2013-03-04 16:41:06 +000010
11#include "SkString.h"
scroggo@google.comb7dbf632013-04-23 15:38:09 +000012#include "SkTArray.h"
sglez@google.com586db932013-07-24 17:24:23 +000013#include "SkTDArray.h"
scroggo@google.com161e1ba2013-03-04 16:41:06 +000014
15/**
scroggo@google.comd9ba9a02013-03-21 19:43:15 +000016 * Including this file (and compiling SkCommandLineFlags.cpp) provides command line
scroggo@google.com161e1ba2013-03-04 16:41:06 +000017 * parsing. In order to use it, use the following macros in global
18 * namespace:
19 *
20 * DEFINE_bool(name, defaultValue, helpString);
21 * DEFINE_string(name, defaultValue, helpString);
22 * DEFINE_int32(name, defaultValue, helpString);
23 * DEFINE_double(name, defaultValue, helpString);
24 *
scroggo@google.comd9ba9a02013-03-21 19:43:15 +000025 * Then, in main, call SkCommandLineFlags::SetUsage() to describe usage and call
26 * SkCommandLineFlags::Parse() to parse the flags. Henceforth, each flag can
scroggo@google.com161e1ba2013-03-04 16:41:06 +000027 * be referenced using
28 *
29 * FLAGS_name
30 *
31 * For example, the line
32 *
33 * DEFINE_bool(boolean, false, "The variable boolean does such and such");
34 *
35 * will create the following variable:
36 *
37 * bool FLAGS_boolean;
38 *
39 * which will initially be set to false, and can be set to true by using the
40 * flag "--boolean" on the commandline. "--noboolean" will set FLAGS_boolean
scroggo@google.com5dc4ca12013-03-21 13:10:59 +000041 * to false. FLAGS_boolean can also be set using "--boolean=true" or
42 * "--boolean true" (where "true" can be replaced by "false", "TRUE", "FALSE",
43 * "1" or "0").
44 *
scroggo@google.com5dc4ca12013-03-21 13:10:59 +000045 * The helpString will be printed if the help flag (-h or -help) is used.
scroggo@google.com161e1ba2013-03-04 16:41:06 +000046 *
47 * Similarly, the line
48 *
49 * DEFINE_int32(integer, .., ..);
50 *
51 * will create
52 *
53 * int32_t FLAGS_integer;
54 *
55 * and
56 *
57 * DEFINE_double(real, .., ..);
58 *
59 * will create
60 *
61 * double FLAGS_real;
62 *
63 * These flags can be set by specifying, for example, "--integer 7" and
64 * "--real 3.14" on the command line.
65 *
66 * Unlike the others, the line
67 *
68 * DEFINE_string(args, .., ..);
69 *
70 * creates an array:
71 *
scroggo@google.comb7dbf632013-04-23 15:38:09 +000072 * SkCommandLineFlags::StringArray FLAGS_args;
scroggo@google.com161e1ba2013-03-04 16:41:06 +000073 *
74 * If the default value is the empty string, FLAGS_args will default to a size
75 * of zero. Otherwise it will default to a size of 1 with the default string
76 * as its value. All strings that follow the flag on the command line (until
77 * a string that begins with '-') will be entries in the array.
78 *
79 * Any flag can be referenced from another file after using the following:
80 *
81 * DECLARE_x(name);
82 *
83 * (where 'x' is the type specified in the DEFINE).
84 *
85 * Inspired by gflags (https://code.google.com/p/gflags/). Is not quite as
86 * robust as gflags, but suits our purposes. For example, allows creating
scroggo@google.comd9ba9a02013-03-21 19:43:15 +000087 * a flag -h or -help which will never be used, since SkCommandLineFlags handles it.
88 * SkCommandLineFlags will also allow creating --flag and --noflag. Uses the same input
scroggo@google.com161e1ba2013-03-04 16:41:06 +000089 * format as gflags and creates similarly named variables (i.e. FLAGS_name).
90 * Strings are handled differently (resulting variable will be an array of
91 * strings) so that a flag can be followed by multiple parameters.
92 */
93
scroggo@google.com161e1ba2013-03-04 16:41:06 +000094class SkFlagInfo;
95
scroggo@google.comd9ba9a02013-03-21 19:43:15 +000096class SkCommandLineFlags {
scroggo@google.com161e1ba2013-03-04 16:41:06 +000097
98public:
99 /**
100 * Call to set the help message to be displayed. Should be called before
scroggo@google.comd9ba9a02013-03-21 19:43:15 +0000101 * Parse.
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000102 */
103 static void SetUsage(const char* usage);
104
105 /**
106 * Call at the beginning of main to parse flags created by DEFINE_x, above.
107 * Must only be called once.
108 */
scroggo@google.comd9ba9a02013-03-21 19:43:15 +0000109 static void Parse(int argc, char** argv);
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000110
scroggo@google.comb7dbf632013-04-23 15:38:09 +0000111 /**
112 * Custom class for holding the arguments for a string flag.
113 * Publicly only has accessors so the strings cannot be modified.
114 */
115 class StringArray {
116 public:
117 const char* operator[](int i) const {
118 SkASSERT(i >= 0 && i < fStrings.count());
119 return fStrings[i].c_str();
120 }
121
122 int count() const {
123 return fStrings.count();
124 }
125
126 bool isEmpty() const { return this->count() == 0; }
127
epoger@google.comdefc4872013-09-19 06:18:27 +0000128 /**
129 * Returns true iff string is equal to one of the strings in this array.
130 */
131 bool contains(const char* string) const {
132 for (int i = 0; i < fStrings.count(); i++) {
133 if (fStrings[i].equals(string)) {
134 return true;
135 }
136 }
137 return false;
138 }
139
caryclark936b7342014-07-11 12:14:51 -0700140 void set(int i, const char* str) {
141 fStrings[i].set(str);
142 }
143
scroggo@google.comb7dbf632013-04-23 15:38:09 +0000144 private:
145 void reset() { fStrings.reset(); }
146
147 void append(const char* string) {
148 fStrings.push_back().set(string);
149 }
150
scroggo@google.com58104a92013-04-24 19:25:26 +0000151 void append(const char* string, size_t length) {
152 fStrings.push_back().set(string, length);
153 }
154
scroggo@google.comb7dbf632013-04-23 15:38:09 +0000155 SkTArray<SkString> fStrings;
156
157 friend class SkFlagInfo;
158 };
159
commit-bot@chromium.orga6f37e72013-08-30 15:52:46 +0000160 /* Takes a list of the form [~][^]match[$]
161 ~ causes a matching test to always be skipped
162 ^ requires the start of the test to match
163 $ requires the end of the test to match
164 ^ and $ requires an exact match
165 If a test does not match any list entry, it is skipped unless some list entry starts with ~
166 */
167 static bool ShouldSkip(const SkTDArray<const char*>& strings, const char* name);
168 static bool ShouldSkip(const StringArray& strings, const char* name);
169
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000170private:
171 static SkFlagInfo* gHead;
172 static SkString gUsage;
173
174 // For access to gHead.
175 friend class SkFlagInfo;
176};
177
178#define TO_STRING2(s) #s
179#define TO_STRING(s) TO_STRING2(s)
180
181#define DEFINE_bool(name, defaultValue, helpString) \
182bool FLAGS_##name; \
183static bool unused_##name = SkFlagInfo::CreateBoolFlag(TO_STRING(name), \
scroggo@google.com09fd4d22013-03-20 14:20:18 +0000184 NULL, \
185 &FLAGS_##name, \
186 defaultValue, \
187 helpString)
188
189// bool 2 allows specifying a short name. No check is done to ensure that shortName
190// is actually shorter than name.
191#define DEFINE_bool2(name, shortName, defaultValue, helpString) \
192bool FLAGS_##name; \
193static bool unused_##name = SkFlagInfo::CreateBoolFlag(TO_STRING(name), \
194 TO_STRING(shortName),\
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000195 &FLAGS_##name, \
196 defaultValue, \
197 helpString)
198
199#define DECLARE_bool(name) extern bool FLAGS_##name;
200
201#define DEFINE_string(name, defaultValue, helpString) \
scroggo@google.comb7dbf632013-04-23 15:38:09 +0000202SkCommandLineFlags::StringArray FLAGS_##name; \
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000203static bool unused_##name = SkFlagInfo::CreateStringFlag(TO_STRING(name), \
scroggo@google.com09fd4d22013-03-20 14:20:18 +0000204 NULL, \
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000205 &FLAGS_##name, \
206 defaultValue, \
207 helpString)
208
scroggo@google.com604e0c22013-04-09 21:25:46 +0000209// string2 allows specifying a short name. There is an assert that shortName
210// is only 1 character.
scroggo@google.com09fd4d22013-03-20 14:20:18 +0000211#define DEFINE_string2(name, shortName, defaultValue, helpString) \
scroggo@google.comb7dbf632013-04-23 15:38:09 +0000212SkCommandLineFlags::StringArray FLAGS_##name; \
scroggo@google.com09fd4d22013-03-20 14:20:18 +0000213static bool unused_##name = SkFlagInfo::CreateStringFlag(TO_STRING(name), \
214 TO_STRING(shortName), \
215 &FLAGS_##name, \
216 defaultValue, \
217 helpString)
218
scroggo@google.comb7dbf632013-04-23 15:38:09 +0000219#define DECLARE_string(name) extern SkCommandLineFlags::StringArray FLAGS_##name;
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000220
221#define DEFINE_int32(name, defaultValue, helpString) \
222int32_t FLAGS_##name; \
223static bool unused_##name = SkFlagInfo::CreateIntFlag(TO_STRING(name), \
224 &FLAGS_##name, \
225 defaultValue, \
226 helpString)
227
228#define DECLARE_int32(name) extern int32_t FLAGS_##name;
229
230#define DEFINE_double(name, defaultValue, helpString) \
231double FLAGS_##name; \
232static bool unused_##name = SkFlagInfo::CreateDoubleFlag(TO_STRING(name), \
233 &FLAGS_##name, \
234 defaultValue, \
235 helpString)
236
237#define DECLARE_double(name) extern double FLAGS_##name;
238
239class SkFlagInfo {
240
241public:
242 enum FlagTypes {
243 kBool_FlagType,
244 kString_FlagType,
245 kInt_FlagType,
246 kDouble_FlagType,
247 };
248
scroggo@google.com58104a92013-04-24 19:25:26 +0000249 /**
250 * Each Create<Type>Flag function creates an SkFlagInfo of the specified type. The SkFlagInfo
251 * object is appended to a list, which is deleted when SkCommandLineFlags::Parse is called.
252 * Therefore, each call should be made before the call to ::Parse. They are not intended
253 * to be called directly. Instead, use the macros described above.
254 * @param name Long version (at least 2 characters) of the name of the flag. This name can
255 * be referenced on the command line as "--name" to set the value of this flag.
256 * @param shortName Short version (one character) of the name of the flag. This name can
257 * be referenced on the command line as "-shortName" to set the value of this flag.
258 * @param p<Type> Pointer to a global variable which holds the value set by SkCommandLineFlags.
259 * @param defaultValue The default value of this flag. The variable pointed to by p<Type> will
260 * be set to this value initially. This is also displayed as part of the help output.
261 * @param helpString Explanation of what this flag changes in the program.
262 */
scroggo@google.com09fd4d22013-03-20 14:20:18 +0000263 static bool CreateBoolFlag(const char* name, const char* shortName, bool* pBool,
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000264 bool defaultValue, const char* helpString) {
scroggo@google.com604e0c22013-04-09 21:25:46 +0000265 SkFlagInfo* info = SkNEW_ARGS(SkFlagInfo, (name, shortName, kBool_FlagType, helpString));
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000266 info->fBoolValue = pBool;
267 *info->fBoolValue = info->fDefaultBool = defaultValue;
268 return true;
269 }
270
scroggo@google.com58104a92013-04-24 19:25:26 +0000271 /**
272 * See comments for CreateBoolFlag.
273 * @param pStrings Unlike the others, this is a pointer to an array of values.
274 * @param defaultValue Thise default will be parsed so that strings separated by spaces
275 * will be added to pStrings.
276 */
scroggo@google.com09fd4d22013-03-20 14:20:18 +0000277 static bool CreateStringFlag(const char* name, const char* shortName,
scroggo@google.comb7dbf632013-04-23 15:38:09 +0000278 SkCommandLineFlags::StringArray* pStrings,
scroggo@google.com58104a92013-04-24 19:25:26 +0000279 const char* defaultValue, const char* helpString);
skia.committer@gmail.com075b0892013-03-05 07:09:08 +0000280
scroggo@google.com58104a92013-04-24 19:25:26 +0000281 /**
282 * See comments for CreateBoolFlag.
283 */
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000284 static bool CreateIntFlag(const char* name, int32_t* pInt,
285 int32_t defaultValue, const char* helpString) {
scroggo@google.com604e0c22013-04-09 21:25:46 +0000286 SkFlagInfo* info = SkNEW_ARGS(SkFlagInfo, (name, NULL, kInt_FlagType, helpString));
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000287 info->fIntValue = pInt;
288 *info->fIntValue = info->fDefaultInt = defaultValue;
289 return true;
290 }
291
scroggo@google.com58104a92013-04-24 19:25:26 +0000292 /**
293 * See comments for CreateBoolFlag.
294 */
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000295 static bool CreateDoubleFlag(const char* name, double* pDouble,
296 double defaultValue, const char* helpString) {
scroggo@google.com604e0c22013-04-09 21:25:46 +0000297 SkFlagInfo* info = SkNEW_ARGS(SkFlagInfo, (name, NULL, kDouble_FlagType, helpString));
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000298 info->fDoubleValue = pDouble;
299 *info->fDoubleValue = info->fDefaultDouble = defaultValue;
300 return true;
301 }
302
303 /**
scroggo@google.com5dc4ca12013-03-21 13:10:59 +0000304 * Returns true if the string matches this flag.
305 * For a boolean flag, also sets the value, since a boolean flag can be set in a number of ways
306 * without looking at the following string:
307 * --name
308 * --noname
309 * --name=true
310 * --name=false
311 * --name=1
312 * --name=0
313 * --name=TRUE
314 * --name=FALSE
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000315 */
scroggo@google.com5dc4ca12013-03-21 13:10:59 +0000316 bool match(const char* string);
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000317
318 FlagTypes getFlagType() const { return fFlagType; }
319
320 void resetStrings() {
321 if (kString_FlagType == fFlagType) {
322 fStrings->reset();
323 } else {
mtklein@google.com330313a2013-08-22 15:37:26 +0000324 SkDEBUGFAIL("Can only call resetStrings on kString_FlagType");
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000325 }
326 }
327
328 void append(const char* string) {
329 if (kString_FlagType == fFlagType) {
scroggo@google.comb7dbf632013-04-23 15:38:09 +0000330 fStrings->append(string);
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000331 } else {
mtklein@google.com330313a2013-08-22 15:37:26 +0000332 SkDEBUGFAIL("Can only append to kString_FlagType");
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000333 }
334 }
335
336 void setInt(int32_t value) {
337 if (kInt_FlagType == fFlagType) {
338 *fIntValue = value;
339 } else {
mtklein@google.com330313a2013-08-22 15:37:26 +0000340 SkDEBUGFAIL("Can only call setInt on kInt_FlagType");
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000341 }
342 }
343
344 void setDouble(double value) {
345 if (kDouble_FlagType == fFlagType) {
346 *fDoubleValue = value;
347 } else {
mtklein@google.com330313a2013-08-22 15:37:26 +0000348 SkDEBUGFAIL("Can only call setDouble on kDouble_FlagType");
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000349 }
350 }
351
scroggo@google.com5dc4ca12013-03-21 13:10:59 +0000352 void setBool(bool value) {
353 if (kBool_FlagType == fFlagType) {
354 *fBoolValue = value;
355 } else {
mtklein@google.com330313a2013-08-22 15:37:26 +0000356 SkDEBUGFAIL("Can only call setBool on kBool_FlagType");
scroggo@google.com5dc4ca12013-03-21 13:10:59 +0000357 }
358 }
359
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000360 SkFlagInfo* next() { return fNext; }
361
362 const SkString& name() const { return fName; }
363
scroggo@google.com8366df02013-03-20 19:50:41 +0000364 const SkString& shortName() const { return fShortName; }
365
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000366 const SkString& help() const { return fHelpString; }
367
368 SkString defaultValue() const {
369 SkString result;
370 switch (fFlagType) {
371 case SkFlagInfo::kBool_FlagType:
372 result.printf("%s", fDefaultBool ? "true" : "false");
373 break;
374 case SkFlagInfo::kString_FlagType:
375 return fDefaultString;
376 case SkFlagInfo::kInt_FlagType:
377 result.printf("%i", fDefaultInt);
378 break;
379 case SkFlagInfo::kDouble_FlagType:
380 result.printf("%2.2f", fDefaultDouble);
381 break;
382 default:
mtklein@google.com330313a2013-08-22 15:37:26 +0000383 SkDEBUGFAIL("Invalid flag type");
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000384 }
385 return result;
386 }
387
388 SkString typeAsString() const {
389 switch (fFlagType) {
390 case SkFlagInfo::kBool_FlagType:
391 return SkString("bool");
392 case SkFlagInfo::kString_FlagType:
393 return SkString("string");
394 case SkFlagInfo::kInt_FlagType:
395 return SkString("int");
396 case SkFlagInfo::kDouble_FlagType:
397 return SkString("double");
398 default:
mtklein@google.com330313a2013-08-22 15:37:26 +0000399 SkDEBUGFAIL("Invalid flag type");
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000400 return SkString();
401 }
402 }
403
404private:
scroggo@google.com604e0c22013-04-09 21:25:46 +0000405 SkFlagInfo(const char* name, const char* shortName, FlagTypes type, const char* helpString)
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000406 : fName(name)
scroggo@google.com604e0c22013-04-09 21:25:46 +0000407 , fShortName(shortName)
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000408 , fFlagType(type)
409 , fHelpString(helpString)
410 , fBoolValue(NULL)
411 , fDefaultBool(false)
412 , fIntValue(NULL)
413 , fDefaultInt(0)
414 , fDoubleValue(NULL)
415 , fDefaultDouble(0)
416 , fStrings(NULL) {
scroggo@google.comd9ba9a02013-03-21 19:43:15 +0000417 fNext = SkCommandLineFlags::gHead;
418 SkCommandLineFlags::gHead = this;
scroggo@google.com604e0c22013-04-09 21:25:46 +0000419 SkASSERT(NULL != name && strlen(name) > 1);
420 SkASSERT(NULL == shortName || 1 == strlen(shortName));
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000421 }
scroggo@google.com58104a92013-04-24 19:25:26 +0000422
423 /**
424 * Set a StringArray to hold the values stored in defaultStrings.
425 * @param array The StringArray to modify.
426 * @param defaultStrings Space separated list of strings that should be inserted into array
427 * individually.
428 */
429 static void SetDefaultStrings(SkCommandLineFlags::StringArray* array,
430 const char* defaultStrings);
431
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000432 // Name of the flag, without initial dashes
433 SkString fName;
scroggo@google.com09fd4d22013-03-20 14:20:18 +0000434 SkString fShortName;
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000435 FlagTypes fFlagType;
436 SkString fHelpString;
437 bool* fBoolValue;
438 bool fDefaultBool;
439 int32_t* fIntValue;
440 int32_t fDefaultInt;
441 double* fDoubleValue;
442 double fDefaultDouble;
scroggo@google.comb7dbf632013-04-23 15:38:09 +0000443 SkCommandLineFlags::StringArray* fStrings;
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000444 // Both for the help string and in case fStrings is empty.
445 SkString fDefaultString;
446
447 // In order to keep a linked list.
448 SkFlagInfo* fNext;
449};
scroggo@google.comd9ba9a02013-03-21 19:43:15 +0000450#endif // SK_COMMAND_LINE_FLAGS_H