CommandLineFlags.h 18 KB

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