2 * Copyright 2013 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #ifndef SK_COMMAND_LINE_FLAGS_H
9 #define SK_COMMAND_LINE_FLAGS_H
13 #include "SkTDArray.h"
16 * Including this file (and compiling SkCommandLineFlags.cpp) provides command line
17 * parsing. In order to use it, use the following macros in global
20 * DEFINE_bool(name, defaultValue, helpString);
21 * DEFINE_string(name, defaultValue, helpString);
22 * DEFINE_int32(name, defaultValue, helpString);
23 * DEFINE_double(name, defaultValue, helpString);
25 * Then, in main, call SkCommandLineFlags::SetUsage() to describe usage and call
26 * SkCommandLineFlags::Parse() to parse the flags. Henceforth, each flag can
31 * For example, the line
33 * DEFINE_bool(boolean, false, "The variable boolean does such and such");
35 * will create the following variable:
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
41 * to false. FLAGS_boolean can also be set using "--boolean=true" or
42 * "--boolean true" (where "true" can be replaced by "false", "TRUE", "FALSE",
45 * The helpString will be printed if the help flag (-h or -help) is used.
49 * DEFINE_int32(integer, .., ..);
53 * int32_t FLAGS_integer;
57 * DEFINE_double(real, .., ..);
63 * These flags can be set by specifying, for example, "--integer 7" and
64 * "--real 3.14" on the command line.
66 * Unlike the others, the line
68 * DEFINE_string(args, .., ..);
72 * SkCommandLineFlags::StringArray FLAGS_args;
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.
79 * Any flag can be referenced from another file after using the following:
83 * (where 'x' is the type specified in the DEFINE).
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
87 * 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
89 * 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.
96 class SkCommandLineFlags {
100 * Call to set the help message to be displayed. Should be called before
103 static void SetUsage(const char* usage);
106 * Call at the beginning of main to parse flags created by DEFINE_x, above.
107 * Must only be called once.
109 static void Parse(int argc, char** argv);
112 * Custom class for holding the arguments for a string flag.
113 * Publicly only has accessors so the strings cannot be modified.
117 const char* operator[](int i) const {
118 SkASSERT(i >= 0 && i < fStrings.count());
119 return fStrings[i].c_str();
123 return fStrings.count();
126 bool isEmpty() const { return this->count() == 0; }
129 * Returns true iff string is equal to one of the strings in this array.
131 bool contains(const char* string) const {
132 for (int i = 0; i < fStrings.count(); i++) {
133 if (fStrings[i].equals(string)) {
141 void reset() { fStrings.reset(); }
143 void append(const char* string) {
144 fStrings.push_back().set(string);
147 void append(const char* string, size_t length) {
148 fStrings.push_back().set(string, length);
151 SkTArray<SkString> fStrings;
153 friend class SkFlagInfo;
156 /* Takes a list of the form [~][^]match[$]
157 ~ causes a matching test to always be skipped
158 ^ requires the start of the test to match
159 $ requires the end of the test to match
160 ^ and $ requires an exact match
161 If a test does not match any list entry, it is skipped unless some list entry starts with ~
163 static bool ShouldSkip(const SkTDArray<const char*>& strings, const char* name);
164 static bool ShouldSkip(const StringArray& strings, const char* name);
167 static SkFlagInfo* gHead;
168 static SkString gUsage;
170 // For access to gHead.
171 friend class SkFlagInfo;
174 #define TO_STRING2(s) #s
175 #define TO_STRING(s) TO_STRING2(s)
177 #define DEFINE_bool(name, defaultValue, helpString) \
179 static bool unused_##name = SkFlagInfo::CreateBoolFlag(TO_STRING(name), \
185 // bool 2 allows specifying a short name. No check is done to ensure that shortName
186 // is actually shorter than name.
187 #define DEFINE_bool2(name, shortName, defaultValue, helpString) \
189 static bool unused_##name = SkFlagInfo::CreateBoolFlag(TO_STRING(name), \
190 TO_STRING(shortName),\
195 #define DECLARE_bool(name) extern bool FLAGS_##name;
197 #define DEFINE_string(name, defaultValue, helpString) \
198 SkCommandLineFlags::StringArray FLAGS_##name; \
199 static bool unused_##name = SkFlagInfo::CreateStringFlag(TO_STRING(name), \
205 // string2 allows specifying a short name. There is an assert that shortName
206 // is only 1 character.
207 #define DEFINE_string2(name, shortName, defaultValue, helpString) \
208 SkCommandLineFlags::StringArray FLAGS_##name; \
209 static bool unused_##name = SkFlagInfo::CreateStringFlag(TO_STRING(name), \
210 TO_STRING(shortName), \
215 #define DECLARE_string(name) extern SkCommandLineFlags::StringArray FLAGS_##name;
217 #define DEFINE_int32(name, defaultValue, helpString) \
218 int32_t FLAGS_##name; \
219 static bool unused_##name = SkFlagInfo::CreateIntFlag(TO_STRING(name), \
224 #define DECLARE_int32(name) extern int32_t FLAGS_##name;
226 #define DEFINE_double(name, defaultValue, helpString) \
227 double FLAGS_##name; \
228 static bool unused_##name = SkFlagInfo::CreateDoubleFlag(TO_STRING(name), \
233 #define DECLARE_double(name) extern double FLAGS_##name;
246 * Each Create<Type>Flag function creates an SkFlagInfo of the specified type. The SkFlagInfo
247 * object is appended to a list, which is deleted when SkCommandLineFlags::Parse is called.
248 * Therefore, each call should be made before the call to ::Parse. They are not intended
249 * to be called directly. Instead, use the macros described above.
250 * @param name Long version (at least 2 characters) of the name of the flag. This name can
251 * be referenced on the command line as "--name" to set the value of this flag.
252 * @param shortName Short version (one character) of the name of the flag. This name can
253 * be referenced on the command line as "-shortName" to set the value of this flag.
254 * @param p<Type> Pointer to a global variable which holds the value set by SkCommandLineFlags.
255 * @param defaultValue The default value of this flag. The variable pointed to by p<Type> will
256 * be set to this value initially. This is also displayed as part of the help output.
257 * @param helpString Explanation of what this flag changes in the program.
259 static bool CreateBoolFlag(const char* name, const char* shortName, bool* pBool,
260 bool defaultValue, const char* helpString) {
261 SkFlagInfo* info = SkNEW_ARGS(SkFlagInfo, (name, shortName, kBool_FlagType, helpString));
262 info->fBoolValue = pBool;
263 *info->fBoolValue = info->fDefaultBool = defaultValue;
268 * See comments for CreateBoolFlag.
269 * @param pStrings Unlike the others, this is a pointer to an array of values.
270 * @param defaultValue Thise default will be parsed so that strings separated by spaces
271 * will be added to pStrings.
273 static bool CreateStringFlag(const char* name, const char* shortName,
274 SkCommandLineFlags::StringArray* pStrings,
275 const char* defaultValue, const char* helpString);
278 * See comments for CreateBoolFlag.
280 static bool CreateIntFlag(const char* name, int32_t* pInt,
281 int32_t defaultValue, const char* helpString) {
282 SkFlagInfo* info = SkNEW_ARGS(SkFlagInfo, (name, NULL, kInt_FlagType, helpString));
283 info->fIntValue = pInt;
284 *info->fIntValue = info->fDefaultInt = defaultValue;
289 * See comments for CreateBoolFlag.
291 static bool CreateDoubleFlag(const char* name, double* pDouble,
292 double defaultValue, const char* helpString) {
293 SkFlagInfo* info = SkNEW_ARGS(SkFlagInfo, (name, NULL, kDouble_FlagType, helpString));
294 info->fDoubleValue = pDouble;
295 *info->fDoubleValue = info->fDefaultDouble = defaultValue;
300 * Returns true if the string matches this flag.
301 * For a boolean flag, also sets the value, since a boolean flag can be set in a number of ways
302 * without looking at the following string:
312 bool match(const char* string);
314 FlagTypes getFlagType() const { return fFlagType; }
316 void resetStrings() {
317 if (kString_FlagType == fFlagType) {
320 SkDEBUGFAIL("Can only call resetStrings on kString_FlagType");
324 void append(const char* string) {
325 if (kString_FlagType == fFlagType) {
326 fStrings->append(string);
328 SkDEBUGFAIL("Can only append to kString_FlagType");
332 void setInt(int32_t value) {
333 if (kInt_FlagType == fFlagType) {
336 SkDEBUGFAIL("Can only call setInt on kInt_FlagType");
340 void setDouble(double value) {
341 if (kDouble_FlagType == fFlagType) {
342 *fDoubleValue = value;
344 SkDEBUGFAIL("Can only call setDouble on kDouble_FlagType");
348 void setBool(bool value) {
349 if (kBool_FlagType == fFlagType) {
352 SkDEBUGFAIL("Can only call setBool on kBool_FlagType");
356 SkFlagInfo* next() { return fNext; }
358 const SkString& name() const { return fName; }
360 const SkString& shortName() const { return fShortName; }
362 const SkString& help() const { return fHelpString; }
364 SkString defaultValue() const {
367 case SkFlagInfo::kBool_FlagType:
368 result.printf("%s", fDefaultBool ? "true" : "false");
370 case SkFlagInfo::kString_FlagType:
371 return fDefaultString;
372 case SkFlagInfo::kInt_FlagType:
373 result.printf("%i", fDefaultInt);
375 case SkFlagInfo::kDouble_FlagType:
376 result.printf("%2.2f", fDefaultDouble);
379 SkDEBUGFAIL("Invalid flag type");
384 SkString typeAsString() const {
386 case SkFlagInfo::kBool_FlagType:
387 return SkString("bool");
388 case SkFlagInfo::kString_FlagType:
389 return SkString("string");
390 case SkFlagInfo::kInt_FlagType:
391 return SkString("int");
392 case SkFlagInfo::kDouble_FlagType:
393 return SkString("double");
395 SkDEBUGFAIL("Invalid flag type");
401 SkFlagInfo(const char* name, const char* shortName, FlagTypes type, const char* helpString)
403 , fShortName(shortName)
405 , fHelpString(helpString)
407 , fDefaultBool(false)
413 fNext = SkCommandLineFlags::gHead;
414 SkCommandLineFlags::gHead = this;
415 SkASSERT(NULL != name && strlen(name) > 1);
416 SkASSERT(NULL == shortName || 1 == strlen(shortName));
420 * Set a StringArray to hold the values stored in defaultStrings.
421 * @param array The StringArray to modify.
422 * @param defaultStrings Space separated list of strings that should be inserted into array
425 static void SetDefaultStrings(SkCommandLineFlags::StringArray* array,
426 const char* defaultStrings);
428 // Name of the flag, without initial dashes
432 SkString fHelpString;
437 double* fDoubleValue;
438 double fDefaultDouble;
439 SkCommandLineFlags::StringArray* fStrings;
440 // Both for the help string and in case fStrings is empty.
441 SkString fDefaultString;
443 // In order to keep a linked list.
446 #endif // SK_COMMAND_LINE_FLAGS_H