blob: c705948348d1d28210ade06eaeb16d8beba6d6cb [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"
12#include "SkTDArray.h"
13
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 *
71 * SkTDArray<const char*> FLAGS_args;
72 *
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
93
94class 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
111private:
112 static SkFlagInfo* gHead;
113 static SkString gUsage;
114
115 // For access to gHead.
116 friend class SkFlagInfo;
117};
118
119#define TO_STRING2(s) #s
120#define TO_STRING(s) TO_STRING2(s)
121
122#define DEFINE_bool(name, defaultValue, helpString) \
123bool FLAGS_##name; \
124static bool unused_##name = SkFlagInfo::CreateBoolFlag(TO_STRING(name), \
scroggo@google.com09fd4d22013-03-20 14:20:18 +0000125 NULL, \
126 &FLAGS_##name, \
127 defaultValue, \
128 helpString)
129
130// bool 2 allows specifying a short name. No check is done to ensure that shortName
131// is actually shorter than name.
132#define DEFINE_bool2(name, shortName, defaultValue, helpString) \
133bool FLAGS_##name; \
134static bool unused_##name = SkFlagInfo::CreateBoolFlag(TO_STRING(name), \
135 TO_STRING(shortName),\
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000136 &FLAGS_##name, \
137 defaultValue, \
138 helpString)
139
140#define DECLARE_bool(name) extern bool FLAGS_##name;
141
142#define DEFINE_string(name, defaultValue, helpString) \
143SkTDArray<const char*> FLAGS_##name; \
144static bool unused_##name = SkFlagInfo::CreateStringFlag(TO_STRING(name), \
scroggo@google.com09fd4d22013-03-20 14:20:18 +0000145 NULL, \
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000146 &FLAGS_##name, \
147 defaultValue, \
148 helpString)
149
scroggo@google.com604e0c22013-04-09 21:25:46 +0000150// string2 allows specifying a short name. There is an assert that shortName
151// is only 1 character.
scroggo@google.com09fd4d22013-03-20 14:20:18 +0000152#define DEFINE_string2(name, shortName, defaultValue, helpString) \
153SkTDArray<const char*> FLAGS_##name; \
154static bool unused_##name = SkFlagInfo::CreateStringFlag(TO_STRING(name), \
155 TO_STRING(shortName), \
156 &FLAGS_##name, \
157 defaultValue, \
158 helpString)
159
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000160#define DECLARE_string(name) extern SkTDArray<const char*> FLAGS_##name;
161
162#define DEFINE_int32(name, defaultValue, helpString) \
163int32_t FLAGS_##name; \
164static bool unused_##name = SkFlagInfo::CreateIntFlag(TO_STRING(name), \
165 &FLAGS_##name, \
166 defaultValue, \
167 helpString)
168
169#define DECLARE_int32(name) extern int32_t FLAGS_##name;
170
171#define DEFINE_double(name, defaultValue, helpString) \
172double FLAGS_##name; \
173static bool unused_##name = SkFlagInfo::CreateDoubleFlag(TO_STRING(name), \
174 &FLAGS_##name, \
175 defaultValue, \
176 helpString)
177
178#define DECLARE_double(name) extern double FLAGS_##name;
179
180class SkFlagInfo {
181
182public:
183 enum FlagTypes {
184 kBool_FlagType,
185 kString_FlagType,
186 kInt_FlagType,
187 kDouble_FlagType,
188 };
189
190 // Create flags of the desired type, and append to the list.
scroggo@google.com09fd4d22013-03-20 14:20:18 +0000191 static bool CreateBoolFlag(const char* name, const char* shortName, bool* pBool,
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000192 bool defaultValue, const char* helpString) {
scroggo@google.com604e0c22013-04-09 21:25:46 +0000193 SkFlagInfo* info = SkNEW_ARGS(SkFlagInfo, (name, shortName, kBool_FlagType, helpString));
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000194 info->fBoolValue = pBool;
195 *info->fBoolValue = info->fDefaultBool = defaultValue;
196 return true;
197 }
198
scroggo@google.com09fd4d22013-03-20 14:20:18 +0000199 static bool CreateStringFlag(const char* name, const char* shortName,
200 SkTDArray<const char*>* pStrings,
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000201 const char* defaultValue, const char* helpString) {
scroggo@google.com604e0c22013-04-09 21:25:46 +0000202 SkFlagInfo* info = SkNEW_ARGS(SkFlagInfo, (name, shortName, kString_FlagType, helpString));
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000203 info->fDefaultString.set(defaultValue);
skia.committer@gmail.com075b0892013-03-05 07:09:08 +0000204
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000205 info->fStrings = pStrings;
206 info->fStrings->reset();
207 // If default is "", leave the array empty.
208 if (info->fDefaultString.size() > 0) {
209 info->fStrings->append(1, &defaultValue);
210 }
211 return true;
212 }
213
214 static bool CreateIntFlag(const char* name, int32_t* pInt,
215 int32_t defaultValue, const char* helpString) {
scroggo@google.com604e0c22013-04-09 21:25:46 +0000216 SkFlagInfo* info = SkNEW_ARGS(SkFlagInfo, (name, NULL, kInt_FlagType, helpString));
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000217 info->fIntValue = pInt;
218 *info->fIntValue = info->fDefaultInt = defaultValue;
219 return true;
220 }
221
222 static bool CreateDoubleFlag(const char* name, double* pDouble,
223 double defaultValue, const char* helpString) {
scroggo@google.com604e0c22013-04-09 21:25:46 +0000224 SkFlagInfo* info = SkNEW_ARGS(SkFlagInfo, (name, NULL, kDouble_FlagType, helpString));
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000225 info->fDoubleValue = pDouble;
226 *info->fDoubleValue = info->fDefaultDouble = defaultValue;
227 return true;
228 }
229
230 /**
scroggo@google.com5dc4ca12013-03-21 13:10:59 +0000231 * Returns true if the string matches this flag.
232 * For a boolean flag, also sets the value, since a boolean flag can be set in a number of ways
233 * without looking at the following string:
234 * --name
235 * --noname
236 * --name=true
237 * --name=false
238 * --name=1
239 * --name=0
240 * --name=TRUE
241 * --name=FALSE
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000242 */
scroggo@google.com5dc4ca12013-03-21 13:10:59 +0000243 bool match(const char* string);
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000244
245 FlagTypes getFlagType() const { return fFlagType; }
246
247 void resetStrings() {
248 if (kString_FlagType == fFlagType) {
249 fStrings->reset();
250 } else {
251 SkASSERT(!"Can only call resetStrings on kString_FlagType");
252 }
253 }
254
255 void append(const char* string) {
256 if (kString_FlagType == fFlagType) {
257 fStrings->append(1, &string);
258 } else {
259 SkASSERT(!"Can only append to kString_FlagType");
260 }
261 }
262
263 void setInt(int32_t value) {
264 if (kInt_FlagType == fFlagType) {
265 *fIntValue = value;
266 } else {
267 SkASSERT(!"Can only call setInt on kInt_FlagType");
268 }
269 }
270
271 void setDouble(double value) {
272 if (kDouble_FlagType == fFlagType) {
273 *fDoubleValue = value;
274 } else {
275 SkASSERT(!"Can only call setDouble on kDouble_FlagType");
276 }
277 }
278
scroggo@google.com5dc4ca12013-03-21 13:10:59 +0000279 void setBool(bool value) {
280 if (kBool_FlagType == fFlagType) {
281 *fBoolValue = value;
282 } else {
283 SkASSERT(!"Can only call setBool on kBool_FlagType");
284 }
285 }
286
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000287 SkFlagInfo* next() { return fNext; }
288
289 const SkString& name() const { return fName; }
290
scroggo@google.com8366df02013-03-20 19:50:41 +0000291 const SkString& shortName() const { return fShortName; }
292
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000293 const SkString& help() const { return fHelpString; }
294
295 SkString defaultValue() const {
296 SkString result;
297 switch (fFlagType) {
298 case SkFlagInfo::kBool_FlagType:
299 result.printf("%s", fDefaultBool ? "true" : "false");
300 break;
301 case SkFlagInfo::kString_FlagType:
302 return fDefaultString;
303 case SkFlagInfo::kInt_FlagType:
304 result.printf("%i", fDefaultInt);
305 break;
306 case SkFlagInfo::kDouble_FlagType:
307 result.printf("%2.2f", fDefaultDouble);
308 break;
309 default:
310 SkASSERT(!"Invalid flag type");
311 }
312 return result;
313 }
314
315 SkString typeAsString() const {
316 switch (fFlagType) {
317 case SkFlagInfo::kBool_FlagType:
318 return SkString("bool");
319 case SkFlagInfo::kString_FlagType:
320 return SkString("string");
321 case SkFlagInfo::kInt_FlagType:
322 return SkString("int");
323 case SkFlagInfo::kDouble_FlagType:
324 return SkString("double");
325 default:
326 SkASSERT(!"Invalid flag type");
327 return SkString();
328 }
329 }
330
331private:
scroggo@google.com604e0c22013-04-09 21:25:46 +0000332 SkFlagInfo(const char* name, const char* shortName, FlagTypes type, const char* helpString)
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000333 : fName(name)
scroggo@google.com604e0c22013-04-09 21:25:46 +0000334 , fShortName(shortName)
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000335 , fFlagType(type)
336 , fHelpString(helpString)
337 , fBoolValue(NULL)
338 , fDefaultBool(false)
339 , fIntValue(NULL)
340 , fDefaultInt(0)
341 , fDoubleValue(NULL)
342 , fDefaultDouble(0)
343 , fStrings(NULL) {
scroggo@google.comd9ba9a02013-03-21 19:43:15 +0000344 fNext = SkCommandLineFlags::gHead;
345 SkCommandLineFlags::gHead = this;
scroggo@google.com604e0c22013-04-09 21:25:46 +0000346 SkASSERT(NULL != name && strlen(name) > 1);
347 SkASSERT(NULL == shortName || 1 == strlen(shortName));
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000348 }
349 // Name of the flag, without initial dashes
350 SkString fName;
scroggo@google.com09fd4d22013-03-20 14:20:18 +0000351 SkString fShortName;
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000352 FlagTypes fFlagType;
353 SkString fHelpString;
354 bool* fBoolValue;
355 bool fDefaultBool;
356 int32_t* fIntValue;
357 int32_t fDefaultInt;
358 double* fDoubleValue;
359 double fDefaultDouble;
360 SkTDArray<const char*>* fStrings;
361 // Both for the help string and in case fStrings is empty.
362 SkString fDefaultString;
363
364 // In order to keep a linked list.
365 SkFlagInfo* fNext;
366};
scroggo@google.comd9ba9a02013-03-21 19:43:15 +0000367#endif // SK_COMMAND_LINE_FLAGS_H