/src/skia/tools/flags/CommandLineFlags.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
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 | | |
8 | | #ifndef SK_COMMAND_LINE_FLAGS_H |
9 | | #define SK_COMMAND_LINE_FLAGS_H |
10 | | |
11 | | #include "include/core/SkString.h" |
12 | | #include "include/private/base/SkTArray.h" |
13 | | #include "include/private/base/SkTDArray.h" |
14 | | #include "src/core/SkTHash.h" |
15 | | |
16 | | /** |
17 | | * Including this file (and compiling CommandLineFlags.cpp) provides command line |
18 | | * parsing. In order to use it, use the following macros in global |
19 | | * namespace: |
20 | | * |
21 | | * DEFINE_bool(name, defaultValue, helpString); |
22 | | * DEFINE_string(name, defaultValue, helpString); |
23 | | * DEFINE_int(name, defaultValue, helpString); |
24 | | * DEFINE_double(name, defaultValue, helpString); |
25 | | * |
26 | | * Then, in main, call CommandLineFlags::SetUsage() to describe usage and call |
27 | | * CommandLineFlags::Parse() to parse the flags. Henceforth, each flag can |
28 | | * be referenced using |
29 | | * |
30 | | * FLAGS_name |
31 | | * |
32 | | * For example, the line |
33 | | * |
34 | | * DEFINE_bool(boolean, false, "The variable boolean does such and such"); |
35 | | * |
36 | | * will create the following variable: |
37 | | * |
38 | | * bool FLAGS_boolean; |
39 | | * |
40 | | * which will initially be set to false, and can be set to true by using the |
41 | | * flag "--boolean" on the commandline. "--noboolean" will set FLAGS_boolean |
42 | | * to false. FLAGS_boolean can also be set using "--boolean=true" or |
43 | | * "--boolean true" (where "true" can be replaced by "false", "TRUE", "FALSE", |
44 | | * "1" or "0"). |
45 | | * |
46 | | * The helpString will be printed if the help flag (-h or -help) is used. |
47 | | * |
48 | | * Similarly, the line |
49 | | * |
50 | | * DEFINE_int(integer, .., ..); |
51 | | * |
52 | | * will create |
53 | | * |
54 | | * int FLAGS_integer; |
55 | | * |
56 | | * and |
57 | | * |
58 | | * DEFINE_double(real, .., ..); |
59 | | * |
60 | | * will create |
61 | | * |
62 | | * double FLAGS_real; |
63 | | * |
64 | | * These flags can be set by specifying, for example, "--integer 7" and |
65 | | * "--real 3.14" on the command line. Unsigned integers are parsed from the |
66 | | * command line using strtoul() so will detect the base (0 for octal, and |
67 | | * 0x or 0X for hex, otherwise assumes decimal). |
68 | | * |
69 | | * Unlike the others, the line |
70 | | * |
71 | | * DEFINE_string(args, .., ..); |
72 | | * |
73 | | * creates an array: |
74 | | * |
75 | | * CommandLineFlags::StringArray FLAGS_args; |
76 | | * |
77 | | * If the default value is the empty string, FLAGS_args will default to a size |
78 | | * of zero. Otherwise it will default to a size of 1 with the default string |
79 | | * as its value. All strings that follow the flag on the command line (until |
80 | | * a string that begins with '-') will be entries in the array. |
81 | | * |
82 | | * DEFINE_extended_string(args, .., .., extendedHelpString); |
83 | | * |
84 | | * creates a similar string array flag as DEFINE_string. The flag will have extended help text |
85 | | * (extendedHelpString) that can the user can see with '--help <args>' flag. |
86 | | * |
87 | | * Any flag can be referenced from another file after using the following: |
88 | | * |
89 | | * DECLARE_x(name); |
90 | | * |
91 | | * (where 'x' is the type specified in the DEFINE). |
92 | | * |
93 | | * Inspired by gflags (https://code.google.com/p/gflags/). Is not quite as |
94 | | * robust as gflags, but suits our purposes. For example, allows creating |
95 | | * a flag -h or -help which will never be used, since CommandLineFlags handles it. |
96 | | * CommandLineFlags will also allow creating --flag and --noflag. Uses the same input |
97 | | * format as gflags and creates similarly named variables (i.e. FLAGS_name). |
98 | | * Strings are handled differently (resulting variable will be an array of |
99 | | * strings) so that a flag can be followed by multiple parameters. |
100 | | */ |
101 | | |
102 | | class SkFlagInfo; |
103 | | |
104 | | class CommandLineFlags { |
105 | | public: |
106 | | /** |
107 | | * Call to set the help message to be displayed. Should be called before |
108 | | * Parse. |
109 | | */ |
110 | | static void SetUsage(const char* usage); |
111 | | |
112 | | /** |
113 | | * Call this to display the help message. Should be called after SetUsage. |
114 | | */ |
115 | | static void PrintUsage(); |
116 | | |
117 | | /** |
118 | | * Call at the beginning of main to parse flags created by DEFINE_x, above. |
119 | | * Must only be called once. |
120 | | */ |
121 | | static void Parse(int argc, const char* const* argv); |
122 | | |
123 | | /** |
124 | | * Custom class for holding the arguments for a string flag. |
125 | | * Publicly only has accessors so the strings cannot be modified. |
126 | | */ |
127 | | class StringArray { |
128 | | public: |
129 | 148 | StringArray() {} |
130 | 0 | explicit StringArray(const skia_private::TArray<SkString>& strings) : fStrings(strings) {} |
131 | 22 | const char* operator[](int i) const { |
132 | 22 | SkASSERT(i >= 0 && i < fStrings.size()); |
133 | 22 | return fStrings[i].c_str(); |
134 | 22 | } |
135 | | |
136 | 0 | int size() const { return fStrings.size(); } |
137 | | |
138 | 0 | bool isEmpty() const { return this->size() == 0; } |
139 | | |
140 | | /** |
141 | | * Returns true iff string is equal to one of the strings in this array. |
142 | | */ |
143 | 0 | bool contains(const char* string) const { |
144 | 0 | for (int i = 0; i < fStrings.size(); i++) { |
145 | 0 | if (fStrings[i].equals(string)) { |
146 | 0 | return true; |
147 | 0 | } |
148 | 0 | } |
149 | 0 | return false; |
150 | 0 | } |
151 | | |
152 | 0 | void set(int i, const char* str) { |
153 | 0 | if (i >= fStrings.size()) { |
154 | 0 | this->append(str); |
155 | 0 | return; |
156 | 0 | } |
157 | 0 | fStrings[i].set(str); |
158 | 0 | } |
159 | | |
160 | 0 | const SkString* begin() const { return fStrings.begin(); } |
161 | 0 | const SkString* end() const { return fStrings.end(); } |
162 | | |
163 | | /** |
164 | | * Parses and validates a string flag that requires exactly one value out of a set of |
165 | | * possible values. Returns a non-empty message in the case of errors. |
166 | | */ |
167 | | template <class E> |
168 | | SkString parseAndValidate(const char* name, |
169 | | const skia_private::THashMap<SkString, E>& possibleValues, |
170 | | E* out) const { |
171 | | if (size() == 0) { |
172 | | return SkStringPrintf("Flag %s is required.", name); |
173 | | } |
174 | | if (size() != 1) { |
175 | | return SkStringPrintf("Flag %s takes 1 value, got %d.", name, size()); |
176 | | } |
177 | | E* found = possibleValues.find(SkString(operator[](0))); |
178 | | if (found != nullptr) { |
179 | | *out = *found; |
180 | | return SkString(); |
181 | | } |
182 | | return SkStringPrintf("Unknown value for flag %s: %s.", name, operator[](0)); |
183 | | } |
184 | | |
185 | | private: |
186 | 148 | void reset() { fStrings.clear(); } |
187 | | |
188 | 0 | void append(const char* string) { fStrings.push_back().set(string); } |
189 | | |
190 | 74 | void append(const char* string, size_t length) { fStrings.push_back().set(string, length); } |
191 | | |
192 | | skia_private::TArray<SkString> fStrings; |
193 | | |
194 | | friend class SkFlagInfo; |
195 | | }; |
196 | | |
197 | | /* Takes a list of the form [~][^]match[$] |
198 | | ~ causes a matching test to always be skipped |
199 | | ^ requires the start of the test to match |
200 | | $ requires the end of the test to match |
201 | | ^ and $ requires an exact match |
202 | | If a test does not match any list entry, it is skipped unless some list entry starts with ~ |
203 | | */ |
204 | | static bool ShouldSkip(const SkTDArray<const char*>& strings, const char* name); |
205 | | static bool ShouldSkip(const StringArray& strings, const char* name); |
206 | | |
207 | | private: |
208 | | static SkFlagInfo* gHead; |
209 | | static SkString gUsage; |
210 | | |
211 | | // For access to gHead. |
212 | | friend class SkFlagInfo; |
213 | | }; |
214 | | |
215 | | #define TO_STRING2(s) #s |
216 | | #define TO_STRING(s) TO_STRING2(s) |
217 | | |
218 | | #define DEFINE_bool(name, defaultValue, helpString) \ |
219 | | bool FLAGS_##name; \ |
220 | | [[maybe_unused]] static bool unused_##name = SkFlagInfo::CreateBoolFlag( \ |
221 | | TO_STRING(name), nullptr, &FLAGS_##name, defaultValue, helpString) |
222 | | |
223 | | // bool 2 allows specifying a short name. No check is done to ensure that shortName |
224 | | // is actually shorter than name. |
225 | | #define DEFINE_bool2(name, shortName, defaultValue, helpString) \ |
226 | | bool FLAGS_##name; \ |
227 | | [[maybe_unused]] static bool unused_##name = SkFlagInfo::CreateBoolFlag( \ |
228 | | TO_STRING(name), TO_STRING(shortName), &FLAGS_##name, defaultValue, helpString) |
229 | | |
230 | | #define DECLARE_bool(name) extern bool FLAGS_##name; |
231 | | |
232 | | #define DEFINE_string(name, defaultValue, helpString) \ |
233 | | CommandLineFlags::StringArray FLAGS_##name; \ |
234 | | [[maybe_unused]] static bool unused_##name = SkFlagInfo::CreateStringFlag( \ |
235 | | TO_STRING(name), nullptr, &FLAGS_##name, defaultValue, helpString, nullptr) |
236 | | #define DEFINE_extended_string(name, defaultValue, helpString, extendedHelpString) \ |
237 | | CommandLineFlags::StringArray FLAGS_##name; \ |
238 | | [[maybe_unused]] static bool unused_##name = SkFlagInfo::CreateStringFlag( \ |
239 | | TO_STRING(name), nullptr, &FLAGS_##name, defaultValue, helpString, extendedHelpString) |
240 | | |
241 | | // string2 allows specifying a short name. There is an assert that shortName |
242 | | // is only 1 character. |
243 | | #define DEFINE_string2(name, shortName, defaultValue, helpString) \ |
244 | | CommandLineFlags::StringArray FLAGS_##name; \ |
245 | | [[maybe_unused]] static bool unused_##name = SkFlagInfo::CreateStringFlag(TO_STRING(name), \ |
246 | | TO_STRING(shortName),\ |
247 | | &FLAGS_##name, \ |
248 | | defaultValue, \ |
249 | | helpString, \ |
250 | | nullptr) |
251 | | |
252 | | #define DECLARE_string(name) extern CommandLineFlags::StringArray FLAGS_##name; |
253 | | |
254 | | #define DEFINE_int(name, defaultValue, helpString) \ |
255 | | int FLAGS_##name; \ |
256 | | [[maybe_unused]] static bool unused_##name = \ |
257 | | SkFlagInfo::CreateIntFlag(TO_STRING(name), &FLAGS_##name, defaultValue, helpString) |
258 | | |
259 | | #define DEFINE_int_2(name, shortName, defaultValue, helpString) \ |
260 | | int FLAGS_##name; \ |
261 | | [[maybe_unused]] static bool unused_##name = SkFlagInfo::CreateIntFlag( \ |
262 | | TO_STRING(name), TO_STRING(shortName), &FLAGS_##name, defaultValue, helpString) |
263 | | |
264 | | #define DECLARE_int(name) extern int FLAGS_##name; |
265 | | |
266 | | #define DEFINE_double(name, defaultValue, helpString) \ |
267 | | double FLAGS_##name; \ |
268 | | [[maybe_unused]] static bool unused_##name = \ |
269 | | SkFlagInfo::CreateDoubleFlag(TO_STRING(name), &FLAGS_##name, defaultValue, helpString) |
270 | | |
271 | | #define DECLARE_double(name) extern double FLAGS_##name; |
272 | | |
273 | | class SkFlagInfo { |
274 | | public: |
275 | | enum FlagTypes { |
276 | | kBool_FlagType, |
277 | | kString_FlagType, |
278 | | kInt_FlagType, |
279 | | kDouble_FlagType, |
280 | | }; |
281 | | |
282 | | /** |
283 | | * Each Create<Type>Flag function creates an SkFlagInfo of the specified type. The SkFlagInfo |
284 | | * object is appended to a list, which is deleted when CommandLineFlags::Parse is called. |
285 | | * Therefore, each call should be made before the call to ::Parse. They are not intended |
286 | | * to be called directly. Instead, use the macros described above. |
287 | | * @param name Long version (at least 2 characters) of the name of the flag. This name can |
288 | | * be referenced on the command line as "--name" to set the value of this flag. |
289 | | * @param shortName Short version (one character) of the name of the flag. This name can |
290 | | * be referenced on the command line as "-shortName" to set the value of this flag. |
291 | | * @param p<Type> Pointer to a global variable which holds the value set by CommandLineFlags. |
292 | | * @param defaultValue The default value of this flag. The variable pointed to by p<Type> will |
293 | | * be set to this value initially. This is also displayed as part of the help output. |
294 | | * @param helpString Explanation of what this flag changes in the program. |
295 | | */ |
296 | | static bool CreateBoolFlag(const char* name, |
297 | | const char* shortName, |
298 | | bool* pBool, |
299 | | bool defaultValue, |
300 | 86 | const char* helpString) { |
301 | 86 | SkFlagInfo* info = new SkFlagInfo(name, shortName, kBool_FlagType, helpString, nullptr); |
302 | 86 | info->fBoolValue = pBool; |
303 | 86 | *info->fBoolValue = info->fDefaultBool = defaultValue; |
304 | 86 | return true; |
305 | 86 | } |
306 | | |
307 | | /** |
308 | | * See comments for CreateBoolFlag. |
309 | | * @param pStrings Unlike the others, this is a pointer to an array of values. |
310 | | * @param defaultValue Thise default will be parsed so that strings separated by spaces |
311 | | * will be added to pStrings. |
312 | | */ |
313 | | static bool CreateStringFlag(const char* name, |
314 | | const char* shortName, |
315 | | CommandLineFlags::StringArray* pStrings, |
316 | | const char* defaultValue, |
317 | | const char* helpString, |
318 | | const char* extendedHelpString); |
319 | | |
320 | | /** |
321 | | * See comments for CreateBoolFlag. |
322 | | */ |
323 | | static bool CreateIntFlag(const char* name, |
324 | | int* pInt, |
325 | | int defaultValue, |
326 | 0 | const char* helpString) { |
327 | 0 | SkFlagInfo* info = new SkFlagInfo(name, nullptr, kInt_FlagType, helpString, nullptr); |
328 | 0 | info->fIntValue = pInt; |
329 | 0 | *info->fIntValue = info->fDefaultInt = defaultValue; |
330 | 0 | return true; |
331 | 0 | } |
332 | | |
333 | | static bool CreateIntFlag(const char* name, |
334 | | const char* shortName, |
335 | | int* pInt, |
336 | | int defaultValue, |
337 | 0 | const char* helpString) { |
338 | 0 | SkFlagInfo* info = new SkFlagInfo(name, shortName, kInt_FlagType, helpString, nullptr); |
339 | 0 | info->fIntValue = pInt; |
340 | 0 | *info->fIntValue = info->fDefaultInt = defaultValue; |
341 | 0 | return true; |
342 | 0 | } |
343 | | |
344 | | /** |
345 | | * See comments for CreateBoolFlag. |
346 | | */ |
347 | | static bool CreateDoubleFlag(const char* name, |
348 | | double* pDouble, |
349 | | double defaultValue, |
350 | 0 | const char* helpString) { |
351 | 0 | SkFlagInfo* info = new SkFlagInfo(name, nullptr, kDouble_FlagType, helpString, nullptr); |
352 | 0 | info->fDoubleValue = pDouble; |
353 | 0 | *info->fDoubleValue = info->fDefaultDouble = defaultValue; |
354 | 0 | return true; |
355 | 0 | } |
356 | | |
357 | | /** |
358 | | * Returns true if the string matches this flag. |
359 | | * For a boolean flag, also sets the value, since a boolean flag can be set in a number of ways |
360 | | * without looking at the following string: |
361 | | * --name |
362 | | * --noname |
363 | | * --name=true |
364 | | * --name=false |
365 | | * --name=1 |
366 | | * --name=0 |
367 | | * --name=TRUE |
368 | | * --name=FALSE |
369 | | */ |
370 | | bool match(const char* string); |
371 | | |
372 | 0 | FlagTypes getFlagType() const { return fFlagType; } |
373 | | |
374 | 0 | void resetStrings() { |
375 | 0 | if (kString_FlagType == fFlagType) { |
376 | 0 | fStrings->reset(); |
377 | 0 | } else { |
378 | 0 | SkDEBUGFAIL("Can only call resetStrings on kString_FlagType"); |
379 | 0 | } |
380 | 0 | } Unexecuted instantiation: SkFlagInfo::resetStrings() Unexecuted instantiation: SkFlagInfo::resetStrings() |
381 | | |
382 | 0 | void append(const char* string) { |
383 | 0 | if (kString_FlagType == fFlagType) { |
384 | 0 | fStrings->append(string); |
385 | 0 | } else { |
386 | 0 | SkDEBUGFAIL("Can only append to kString_FlagType"); |
387 | 0 | } |
388 | 0 | } Unexecuted instantiation: SkFlagInfo::append(char const*) Unexecuted instantiation: SkFlagInfo::append(char const*) |
389 | | |
390 | 0 | void setInt(int value) { |
391 | 0 | if (kInt_FlagType == fFlagType) { |
392 | 0 | *fIntValue = value; |
393 | 0 | } else { |
394 | 0 | SkDEBUGFAIL("Can only call setInt on kInt_FlagType"); |
395 | 0 | } |
396 | 0 | } Unexecuted instantiation: SkFlagInfo::setInt(int) Unexecuted instantiation: SkFlagInfo::setInt(int) |
397 | | |
398 | 0 | void setDouble(double value) { |
399 | 0 | if (kDouble_FlagType == fFlagType) { |
400 | 0 | *fDoubleValue = value; |
401 | 0 | } else { |
402 | 0 | SkDEBUGFAIL("Can only call setDouble on kDouble_FlagType"); |
403 | 0 | } |
404 | 0 | } Unexecuted instantiation: SkFlagInfo::setDouble(double) Unexecuted instantiation: SkFlagInfo::setDouble(double) |
405 | | |
406 | 0 | void setBool(bool value) { |
407 | 0 | if (kBool_FlagType == fFlagType) { |
408 | 0 | *fBoolValue = value; |
409 | 0 | } else { |
410 | 0 | SkDEBUGFAIL("Can only call setBool on kBool_FlagType"); |
411 | 0 | } |
412 | 0 | } Unexecuted instantiation: SkFlagInfo::setBool(bool) Unexecuted instantiation: SkFlagInfo::setBool(bool) |
413 | | |
414 | 0 | SkFlagInfo* next() { return fNext; } |
415 | | |
416 | 0 | const SkString& name() const { return fName; } |
417 | | |
418 | 0 | const SkString& shortName() const { return fShortName; } |
419 | | |
420 | 0 | const SkString& help() const { return fHelpString; } |
421 | 0 | const SkString& extendedHelp() const { return fExtendedHelpString; } |
422 | | |
423 | 0 | SkString defaultValue() const { |
424 | 0 | SkString result; |
425 | 0 | switch (fFlagType) { |
426 | 0 | case SkFlagInfo::kBool_FlagType: |
427 | 0 | result.printf("%s", fDefaultBool ? "true" : "false"); |
428 | 0 | break; |
429 | 0 | case SkFlagInfo::kString_FlagType: return fDefaultString; |
430 | 0 | case SkFlagInfo::kInt_FlagType: result.printf("%i", fDefaultInt); break; |
431 | 0 | case SkFlagInfo::kDouble_FlagType: result.printf("%2.2f", fDefaultDouble); break; |
432 | 0 | default: SkDEBUGFAIL("Invalid flag type"); |
433 | 0 | } |
434 | 0 | return result; |
435 | 0 | } Unexecuted instantiation: SkFlagInfo::defaultValue() const Unexecuted instantiation: SkFlagInfo::defaultValue() const |
436 | | |
437 | 0 | SkString typeAsString() const { |
438 | 0 | switch (fFlagType) { |
439 | 0 | case SkFlagInfo::kBool_FlagType: return SkString("bool"); |
440 | 0 | case SkFlagInfo::kString_FlagType: return SkString("string"); |
441 | 0 | case SkFlagInfo::kInt_FlagType: return SkString("int"); |
442 | 0 | case SkFlagInfo::kDouble_FlagType: return SkString("double"); |
443 | 0 | default: SkDEBUGFAIL("Invalid flag type"); return SkString(); |
444 | 0 | } |
445 | 0 | } Unexecuted instantiation: SkFlagInfo::typeAsString() const Unexecuted instantiation: SkFlagInfo::typeAsString() const |
446 | | |
447 | | private: |
448 | | SkFlagInfo(const char* name, |
449 | | const char* shortName, |
450 | | FlagTypes type, |
451 | | const char* helpString, |
452 | | const char* extendedHelpString) |
453 | | : fName(name) |
454 | | , fShortName(shortName) |
455 | | , fFlagType(type) |
456 | | , fHelpString(helpString) |
457 | | , fExtendedHelpString(extendedHelpString) |
458 | | , fBoolValue(nullptr) |
459 | | , fDefaultBool(false) |
460 | | , fIntValue(nullptr) |
461 | | , fDefaultInt(0) |
462 | | , fDoubleValue(nullptr) |
463 | | , fDefaultDouble(0) |
464 | 234 | , fStrings(nullptr) { |
465 | 234 | fNext = CommandLineFlags::gHead; |
466 | 234 | CommandLineFlags::gHead = this; |
467 | 234 | SkASSERT(name && strlen(name) > 1); |
468 | 234 | SkASSERT(nullptr == shortName || 1 == strlen(shortName)); |
469 | 234 | } SkFlagInfo::SkFlagInfo(char const*, char const*, SkFlagInfo::FlagTypes, char const*, char const*) Line | Count | Source | 464 | 222 | , fStrings(nullptr) { | 465 | 222 | fNext = CommandLineFlags::gHead; | 466 | 222 | CommandLineFlags::gHead = this; | 467 | 222 | SkASSERT(name && strlen(name) > 1); | 468 | 222 | SkASSERT(nullptr == shortName || 1 == strlen(shortName)); | 469 | 222 | } |
SkFlagInfo::SkFlagInfo(char const*, char const*, SkFlagInfo::FlagTypes, char const*, char const*) Line | Count | Source | 464 | 12 | , fStrings(nullptr) { | 465 | 12 | fNext = CommandLineFlags::gHead; | 466 | 12 | CommandLineFlags::gHead = this; | 467 | 12 | SkASSERT(name && strlen(name) > 1); | 468 | 12 | SkASSERT(nullptr == shortName || 1 == strlen(shortName)); | 469 | 12 | } |
|
470 | | |
471 | | /** |
472 | | * Set a StringArray to hold the values stored in defaultStrings. |
473 | | * @param array The StringArray to modify. |
474 | | * @param defaultStrings Space separated list of strings that should be inserted into array |
475 | | * individually. |
476 | | */ |
477 | | static void SetDefaultStrings(CommandLineFlags::StringArray* array, const char* defaultStrings); |
478 | | |
479 | | // Name of the flag, without initial dashes |
480 | | SkString fName; |
481 | | SkString fShortName; |
482 | | FlagTypes fFlagType; |
483 | | SkString fHelpString; |
484 | | SkString fExtendedHelpString; |
485 | | bool* fBoolValue; |
486 | | bool fDefaultBool; |
487 | | int* fIntValue; |
488 | | int fDefaultInt; |
489 | | double* fDoubleValue; |
490 | | double fDefaultDouble; |
491 | | CommandLineFlags::StringArray* fStrings; |
492 | | // Both for the help string and in case fStrings is empty. |
493 | | SkString fDefaultString; |
494 | | |
495 | | // In order to keep a linked list. |
496 | | SkFlagInfo* fNext; |
497 | | }; |
498 | | #endif // SK_COMMAND_LINE_FLAGS_H |