blob: d0e74502d8f98ce5eca8e474bb8db73dc3540878 [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"
scroggo@google.com161e1ba2013-03-04 16:41:06 +000013
14/**
scroggo@google.comd9ba9a02013-03-21 19:43:15 +000015 * Including this file (and compiling SkCommandLineFlags.cpp) provides command line
scroggo@google.com161e1ba2013-03-04 16:41:06 +000016 * parsing. In order to use it, use the following macros in global
17 * namespace:
18 *
19 * DEFINE_bool(name, defaultValue, helpString);
20 * DEFINE_string(name, defaultValue, helpString);
21 * DEFINE_int32(name, defaultValue, helpString);
22 * DEFINE_double(name, defaultValue, helpString);
23 *
scroggo@google.comd9ba9a02013-03-21 19:43:15 +000024 * Then, in main, call SkCommandLineFlags::SetUsage() to describe usage and call
25 * SkCommandLineFlags::Parse() to parse the flags. Henceforth, each flag can
scroggo@google.com161e1ba2013-03-04 16:41:06 +000026 * be referenced using
27 *
28 * FLAGS_name
29 *
30 * For example, the line
31 *
32 * DEFINE_bool(boolean, false, "The variable boolean does such and such");
33 *
34 * will create the following variable:
35 *
36 * bool FLAGS_boolean;
37 *
38 * which will initially be set to false, and can be set to true by using the
39 * flag "--boolean" on the commandline. "--noboolean" will set FLAGS_boolean
scroggo@google.com5dc4ca12013-03-21 13:10:59 +000040 * to false. FLAGS_boolean can also be set using "--boolean=true" or
41 * "--boolean true" (where "true" can be replaced by "false", "TRUE", "FALSE",
42 * "1" or "0").
43 *
scroggo@google.com5dc4ca12013-03-21 13:10:59 +000044 * The helpString will be printed if the help flag (-h or -help) is used.
scroggo@google.com161e1ba2013-03-04 16:41:06 +000045 *
46 * Similarly, the line
47 *
48 * DEFINE_int32(integer, .., ..);
49 *
50 * will create
51 *
52 * int32_t FLAGS_integer;
53 *
54 * and
55 *
56 * DEFINE_double(real, .., ..);
57 *
58 * will create
59 *
60 * double FLAGS_real;
61 *
62 * These flags can be set by specifying, for example, "--integer 7" and
63 * "--real 3.14" on the command line.
64 *
65 * Unlike the others, the line
66 *
67 * DEFINE_string(args, .., ..);
68 *
69 * creates an array:
70 *
scroggo@google.comb7dbf632013-04-23 15:38:09 +000071 * SkCommandLineFlags::StringArray FLAGS_args;
scroggo@google.com161e1ba2013-03-04 16:41:06 +000072 *
73 * If the default value is the empty string, FLAGS_args will default to a size
74 * of zero. Otherwise it will default to a size of 1 with the default string
75 * as its value. All strings that follow the flag on the command line (until
76 * a string that begins with '-') will be entries in the array.
77 *
78 * Any flag can be referenced from another file after using the following:
79 *
80 * DECLARE_x(name);
81 *
82 * (where 'x' is the type specified in the DEFINE).
83 *
84 * Inspired by gflags (https://code.google.com/p/gflags/). Is not quite as
85 * robust as gflags, but suits our purposes. For example, allows creating
scroggo@google.comd9ba9a02013-03-21 19:43:15 +000086 * a flag -h or -help which will never be used, since SkCommandLineFlags handles it.
87 * SkCommandLineFlags will also allow creating --flag and --noflag. Uses the same input
scroggo@google.com161e1ba2013-03-04 16:41:06 +000088 * format as gflags and creates similarly named variables (i.e. FLAGS_name).
89 * Strings are handled differently (resulting variable will be an array of
90 * strings) so that a flag can be followed by multiple parameters.
91 */
92
epoger@google.comed5eb4e2013-07-23 17:56:20 +000093
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
128 private:
129 void reset() { fStrings.reset(); }
130
131 void append(const char* string) {
132 fStrings.push_back().set(string);
133 }
134
scroggo@google.com58104a92013-04-24 19:25:26 +0000135 void append(const char* string, size_t length) {
136 fStrings.push_back().set(string, length);
137 }
138
scroggo@google.comb7dbf632013-04-23 15:38:09 +0000139 SkTArray<SkString> fStrings;
140
141 friend class SkFlagInfo;
142 };
143
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000144private:
145 static SkFlagInfo* gHead;
146 static SkString gUsage;
147
148 // For access to gHead.
149 friend class SkFlagInfo;
150};
151
152#define TO_STRING2(s) #s
153#define TO_STRING(s) TO_STRING2(s)
154
155#define DEFINE_bool(name, defaultValue, helpString) \
156bool FLAGS_##name; \
157static bool unused_##name = SkFlagInfo::CreateBoolFlag(TO_STRING(name), \
scroggo@google.com09fd4d22013-03-20 14:20:18 +0000158 NULL, \
159 &FLAGS_##name, \
160 defaultValue, \
161 helpString)
162
163// bool 2 allows specifying a short name. No check is done to ensure that shortName
164// is actually shorter than name.
165#define DEFINE_bool2(name, shortName, defaultValue, helpString) \
166bool FLAGS_##name; \
167static bool unused_##name = SkFlagInfo::CreateBoolFlag(TO_STRING(name), \
168 TO_STRING(shortName),\
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000169 &FLAGS_##name, \
170 defaultValue, \
171 helpString)
172
173#define DECLARE_bool(name) extern bool FLAGS_##name;
174
175#define DEFINE_string(name, defaultValue, helpString) \
scroggo@google.comb7dbf632013-04-23 15:38:09 +0000176SkCommandLineFlags::StringArray FLAGS_##name; \
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000177static bool unused_##name = SkFlagInfo::CreateStringFlag(TO_STRING(name), \
scroggo@google.com09fd4d22013-03-20 14:20:18 +0000178 NULL, \
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000179 &FLAGS_##name, \
180 defaultValue, \
181 helpString)
182
scroggo@google.com604e0c22013-04-09 21:25:46 +0000183// string2 allows specifying a short name. There is an assert that shortName
184// is only 1 character.
scroggo@google.com09fd4d22013-03-20 14:20:18 +0000185#define DEFINE_string2(name, shortName, defaultValue, helpString) \
scroggo@google.comb7dbf632013-04-23 15:38:09 +0000186SkCommandLineFlags::StringArray FLAGS_##name; \
scroggo@google.com09fd4d22013-03-20 14:20:18 +0000187static bool unused_##name = SkFlagInfo::CreateStringFlag(TO_STRING(name), \
188 TO_STRING(shortName), \
189 &FLAGS_##name, \
190 defaultValue, \
191 helpString)
192
scroggo@google.comb7dbf632013-04-23 15:38:09 +0000193#define DECLARE_string(name) extern SkCommandLineFlags::StringArray FLAGS_##name;
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000194
195#define DEFINE_int32(name, defaultValue, helpString) \
196int32_t FLAGS_##name; \
197static bool unused_##name = SkFlagInfo::CreateIntFlag(TO_STRING(name), \
198 &FLAGS_##name, \
199 defaultValue, \
200 helpString)
201
202#define DECLARE_int32(name) extern int32_t FLAGS_##name;
203
204#define DEFINE_double(name, defaultValue, helpString) \
205double FLAGS_##name; \
206static bool unused_##name = SkFlagInfo::CreateDoubleFlag(TO_STRING(name), \
207 &FLAGS_##name, \
208 defaultValue, \
209 helpString)
210
211#define DECLARE_double(name) extern double FLAGS_##name;
212
213class SkFlagInfo {
214
215public:
216 enum FlagTypes {
217 kBool_FlagType,
218 kString_FlagType,
219 kInt_FlagType,
220 kDouble_FlagType,
221 };
222
scroggo@google.com58104a92013-04-24 19:25:26 +0000223 /**
224 * Each Create<Type>Flag function creates an SkFlagInfo of the specified type. The SkFlagInfo
225 * object is appended to a list, which is deleted when SkCommandLineFlags::Parse is called.
226 * Therefore, each call should be made before the call to ::Parse. They are not intended
227 * to be called directly. Instead, use the macros described above.
228 * @param name Long version (at least 2 characters) of the name of the flag. This name can
229 * be referenced on the command line as "--name" to set the value of this flag.
230 * @param shortName Short version (one character) of the name of the flag. This name can
231 * be referenced on the command line as "-shortName" to set the value of this flag.
232 * @param p<Type> Pointer to a global variable which holds the value set by SkCommandLineFlags.
233 * @param defaultValue The default value of this flag. The variable pointed to by p<Type> will
234 * be set to this value initially. This is also displayed as part of the help output.
235 * @param helpString Explanation of what this flag changes in the program.
236 */
scroggo@google.com09fd4d22013-03-20 14:20:18 +0000237 static bool CreateBoolFlag(const char* name, const char* shortName, bool* pBool,
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000238 bool defaultValue, const char* helpString) {
scroggo@google.com604e0c22013-04-09 21:25:46 +0000239 SkFlagInfo* info = SkNEW_ARGS(SkFlagInfo, (name, shortName, kBool_FlagType, helpString));
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000240 info->fBoolValue = pBool;
241 *info->fBoolValue = info->fDefaultBool = defaultValue;
242 return true;
243 }
244
scroggo@google.com58104a92013-04-24 19:25:26 +0000245 /**
246 * See comments for CreateBoolFlag.
247 * @param pStrings Unlike the others, this is a pointer to an array of values.
248 * @param defaultValue Thise default will be parsed so that strings separated by spaces
249 * will be added to pStrings.
250 */
scroggo@google.com09fd4d22013-03-20 14:20:18 +0000251 static bool CreateStringFlag(const char* name, const char* shortName,
scroggo@google.comb7dbf632013-04-23 15:38:09 +0000252 SkCommandLineFlags::StringArray* pStrings,
scroggo@google.com58104a92013-04-24 19:25:26 +0000253 const char* defaultValue, const char* helpString);
skia.committer@gmail.com075b0892013-03-05 07:09:08 +0000254
scroggo@google.com58104a92013-04-24 19:25:26 +0000255 /**
256 * See comments for CreateBoolFlag.
257 */
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000258 static bool CreateIntFlag(const char* name, int32_t* pInt,
259 int32_t defaultValue, const char* helpString) {
scroggo@google.com604e0c22013-04-09 21:25:46 +0000260 SkFlagInfo* info = SkNEW_ARGS(SkFlagInfo, (name, NULL, kInt_FlagType, helpString));
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000261 info->fIntValue = pInt;
262 *info->fIntValue = info->fDefaultInt = defaultValue;
263 return true;
264 }
265
scroggo@google.com58104a92013-04-24 19:25:26 +0000266 /**
267 * See comments for CreateBoolFlag.
268 */
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000269 static bool CreateDoubleFlag(const char* name, double* pDouble,
270 double defaultValue, const char* helpString) {
scroggo@google.com604e0c22013-04-09 21:25:46 +0000271 SkFlagInfo* info = SkNEW_ARGS(SkFlagInfo, (name, NULL, kDouble_FlagType, helpString));
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000272 info->fDoubleValue = pDouble;
273 *info->fDoubleValue = info->fDefaultDouble = defaultValue;
274 return true;
275 }
276
277 /**
scroggo@google.com5dc4ca12013-03-21 13:10:59 +0000278 * Returns true if the string matches this flag.
279 * For a boolean flag, also sets the value, since a boolean flag can be set in a number of ways
280 * without looking at the following string:
281 * --name
282 * --noname
283 * --name=true
284 * --name=false
285 * --name=1
286 * --name=0
287 * --name=TRUE
288 * --name=FALSE
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000289 */
scroggo@google.com5dc4ca12013-03-21 13:10:59 +0000290 bool match(const char* string);
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000291
292 FlagTypes getFlagType() const { return fFlagType; }
293
294 void resetStrings() {
295 if (kString_FlagType == fFlagType) {
296 fStrings->reset();
297 } else {
298 SkASSERT(!"Can only call resetStrings on kString_FlagType");
299 }
300 }
301
302 void append(const char* string) {
303 if (kString_FlagType == fFlagType) {
scroggo@google.comb7dbf632013-04-23 15:38:09 +0000304 fStrings->append(string);
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000305 } else {
306 SkASSERT(!"Can only append to kString_FlagType");
307 }
308 }
309
310 void setInt(int32_t value) {
311 if (kInt_FlagType == fFlagType) {
312 *fIntValue = value;
313 } else {
314 SkASSERT(!"Can only call setInt on kInt_FlagType");
315 }
316 }
317
318 void setDouble(double value) {
319 if (kDouble_FlagType == fFlagType) {
320 *fDoubleValue = value;
321 } else {
322 SkASSERT(!"Can only call setDouble on kDouble_FlagType");
323 }
324 }
325
scroggo@google.com5dc4ca12013-03-21 13:10:59 +0000326 void setBool(bool value) {
327 if (kBool_FlagType == fFlagType) {
328 *fBoolValue = value;
329 } else {
330 SkASSERT(!"Can only call setBool on kBool_FlagType");
331 }
332 }
333
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000334 SkFlagInfo* next() { return fNext; }
335
336 const SkString& name() const { return fName; }
337
scroggo@google.com8366df02013-03-20 19:50:41 +0000338 const SkString& shortName() const { return fShortName; }
339
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000340 const SkString& help() const { return fHelpString; }
341
342 SkString defaultValue() const {
343 SkString result;
344 switch (fFlagType) {
345 case SkFlagInfo::kBool_FlagType:
346 result.printf("%s", fDefaultBool ? "true" : "false");
347 break;
348 case SkFlagInfo::kString_FlagType:
349 return fDefaultString;
350 case SkFlagInfo::kInt_FlagType:
351 result.printf("%i", fDefaultInt);
352 break;
353 case SkFlagInfo::kDouble_FlagType:
354 result.printf("%2.2f", fDefaultDouble);
355 break;
356 default:
357 SkASSERT(!"Invalid flag type");
358 }
359 return result;
360 }
361
362 SkString typeAsString() const {
363 switch (fFlagType) {
364 case SkFlagInfo::kBool_FlagType:
365 return SkString("bool");
366 case SkFlagInfo::kString_FlagType:
367 return SkString("string");
368 case SkFlagInfo::kInt_FlagType:
369 return SkString("int");
370 case SkFlagInfo::kDouble_FlagType:
371 return SkString("double");
372 default:
373 SkASSERT(!"Invalid flag type");
374 return SkString();
375 }
376 }
377
378private:
scroggo@google.com604e0c22013-04-09 21:25:46 +0000379 SkFlagInfo(const char* name, const char* shortName, FlagTypes type, const char* helpString)
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000380 : fName(name)
scroggo@google.com604e0c22013-04-09 21:25:46 +0000381 , fShortName(shortName)
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000382 , fFlagType(type)
383 , fHelpString(helpString)
384 , fBoolValue(NULL)
385 , fDefaultBool(false)
386 , fIntValue(NULL)
387 , fDefaultInt(0)
388 , fDoubleValue(NULL)
389 , fDefaultDouble(0)
390 , fStrings(NULL) {
scroggo@google.comd9ba9a02013-03-21 19:43:15 +0000391 fNext = SkCommandLineFlags::gHead;
392 SkCommandLineFlags::gHead = this;
scroggo@google.com604e0c22013-04-09 21:25:46 +0000393 SkASSERT(NULL != name && strlen(name) > 1);
394 SkASSERT(NULL == shortName || 1 == strlen(shortName));
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000395 }
scroggo@google.com58104a92013-04-24 19:25:26 +0000396
397 /**
398 * Set a StringArray to hold the values stored in defaultStrings.
399 * @param array The StringArray to modify.
400 * @param defaultStrings Space separated list of strings that should be inserted into array
401 * individually.
402 */
403 static void SetDefaultStrings(SkCommandLineFlags::StringArray* array,
404 const char* defaultStrings);
405
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000406 // Name of the flag, without initial dashes
407 SkString fName;
scroggo@google.com09fd4d22013-03-20 14:20:18 +0000408 SkString fShortName;
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000409 FlagTypes fFlagType;
410 SkString fHelpString;
411 bool* fBoolValue;
412 bool fDefaultBool;
413 int32_t* fIntValue;
414 int32_t fDefaultInt;
415 double* fDoubleValue;
416 double fDefaultDouble;
scroggo@google.comb7dbf632013-04-23 15:38:09 +0000417 SkCommandLineFlags::StringArray* fStrings;
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000418 // Both for the help string and in case fStrings is empty.
419 SkString fDefaultString;
420
421 // In order to keep a linked list.
422 SkFlagInfo* fNext;
423};
scroggo@google.comd9ba9a02013-03-21 19:43:15 +0000424#endif // SK_COMMAND_LINE_FLAGS_H