blob: 2d124b6edacca141fd6053b33301a920c4bb8dc5 [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
8#include "SkFlags.h"
9
10SkFlagInfo* SkFlags::gHead;
11SkString SkFlags::gUsage;
12
13void SkFlags::SetUsage(const char* usage) {
14 gUsage.set(usage);
15}
16
17// Maximum line length for the help message.
18#define LINE_LENGTH 80
19
scroggo@google.com8366df02013-03-20 19:50:41 +000020static void print_help_for_flag(const SkFlagInfo* flag) {
21 SkDebugf("\t--%s", flag->name().c_str());
22 const SkString& shortName = flag->shortName();
23 if (shortName.size() > 0) {
24 SkDebugf(" or -%s", shortName.c_str());
25 }
26 SkDebugf(":\ttype: %s", flag->typeAsString().c_str());
27 if (flag->defaultValue().size() > 0) {
28 SkDebugf("\tdefault: %s", flag->defaultValue().c_str());
29 }
30 SkDebugf("\n");
31 const SkString& help = flag->help();
32 size_t length = help.size();
33 const char* currLine = help.c_str();
34 const char* stop = currLine + length;
35 while (currLine < stop) {
36 if (strlen(currLine) < LINE_LENGTH) {
37 // Only one line length's worth of text left.
38 SkDebugf("\t\t%s\n", currLine);
39 break;
40 }
41 int lineBreak = SkStrFind(currLine, "\n");
42 if (lineBreak < 0 || lineBreak > LINE_LENGTH) {
43 // No line break within line length. Will need to insert one.
44 // Find a space before the line break.
45 int spaceIndex = LINE_LENGTH - 1;
46 while (spaceIndex > 0 && currLine[spaceIndex] != ' ') {
47 spaceIndex--;
48 }
49 int gap;
50 if (0 == spaceIndex) {
51 // No spaces on the entire line. Go ahead and break mid word.
52 spaceIndex = LINE_LENGTH;
53 gap = 0;
54 } else {
55 // Skip the space on the next line
56 gap = 1;
57 }
58 SkDebugf("\t\t%.*s\n", spaceIndex, currLine);
59 currLine += spaceIndex + gap;
60 } else {
61 // the line break is within the limit. Break there.
62 lineBreak++;
63 SkDebugf("\t\t%.*s", lineBreak, currLine);
64 currLine += lineBreak;
65 }
66 }
67 SkDebugf("\n");
68}
69
scroggo@google.com161e1ba2013-03-04 16:41:06 +000070void SkFlags::ParseCommandLine(int argc, char** argv) {
71 // Only allow calling this function once.
72 static bool gOnce;
73 if (gOnce) {
74 SkDebugf("ParseCommandLine should only be called once at the beginning"
75 " of main!\n");
76 SkASSERT(false);
77 return;
78 }
79 gOnce = true;
80
81 bool helpPrinted = false;
82 // Loop over argv, starting with 1, since the first is just the name of the program.
83 for (int i = 1; i < argc; i++) {
84 if (0 == strcmp("-h", argv[i]) || 0 == strcmp("--h", argv[i])
85 || 0 == strcmp("-help", argv[i]) || 0 == strcmp("--help", argv[i])) {
86 // Print help message.
scroggo@google.com8366df02013-03-20 19:50:41 +000087 SkTDArray<const char*> helpFlags;
88 for (int j = i + 1; j < argc; j++) {
89 if (SkStrStartsWith(argv[j], '-')) {
90 break;
91 }
92 helpFlags.append(1, &argv[j]);
93 }
94 if (0 == helpFlags.count()) {
95 // Only print general help message if help for specific flags is not requested.
96 SkDebugf("%s\n%s\n", argv[0], gUsage.c_str());
97 }
scroggo@google.com161e1ba2013-03-04 16:41:06 +000098 SkDebugf("Flags:\n");
99 SkFlagInfo* flag = SkFlags::gHead;
100 while (flag != NULL) {
scroggo@google.com8366df02013-03-20 19:50:41 +0000101 // If no flags followed --help, print them all
102 bool printFlag = 0 == helpFlags.count();
103 if (!printFlag) {
104 for (int k = 0; k < helpFlags.count(); k++) {
105 if (flag->name().equals(helpFlags[k]) ||
106 flag->shortName().equals(helpFlags[k])) {
107 printFlag = true;
108 helpFlags.remove(k);
109 break;
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000110 }
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000111 }
112 }
scroggo@google.com8366df02013-03-20 19:50:41 +0000113 if (printFlag) {
114 print_help_for_flag(flag);
115 }
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000116 flag = flag->next();
117 }
scroggo@google.com8366df02013-03-20 19:50:41 +0000118 if (helpFlags.count() > 0) {
119 SkDebugf("Requested help for unrecognized flags:\n");
120 for (int k = 0; k < helpFlags.count(); k++) {
121 SkDebugf("\t--%s\n", helpFlags[k]);
122 }
123 }
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000124 helpPrinted = true;
125 }
126 if (!helpPrinted) {
127 bool flagMatched = false;
128 SkFlagInfo* flag = gHead;
129 while (flag != NULL) {
130 if (flag->match(argv[i])) {
131 flagMatched = true;
132 switch (flag->getFlagType()) {
133 case SkFlagInfo::kBool_FlagType:
134 // Handled by match, above
135 break;
136 case SkFlagInfo::kString_FlagType:
137 flag->resetStrings();
138 // Add all arguments until another flag is reached.
139 while (i+1 < argc && !SkStrStartsWith(argv[i+1], '-')) {
140 i++;
141 flag->append(argv[i]);
142 }
143 break;
144 case SkFlagInfo::kInt_FlagType:
145 i++;
146 flag->setInt(atoi(argv[i]));
147 break;
148 case SkFlagInfo::kDouble_FlagType:
149 i++;
150 flag->setDouble(atof(argv[i]));
151 break;
152 default:
153 SkASSERT(!"Invalid flag type");
154 }
155 break;
156 }
157 flag = flag->next();
158 }
159 if (!flagMatched) {
scroggo@google.com0f2cd172013-03-20 20:04:27 +0000160 SkDebugf("Got unknown flag \"%s\". Exiting.\n", argv[i]);
161 exit(-1);
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000162 }
163 }
164 }
165 // Since all of the flags have been set, release the memory used by each
166 // flag. FLAGS_x can still be used after this.
167 SkFlagInfo* flag = gHead;
168 gHead = NULL;
169 while (flag != NULL) {
170 SkFlagInfo* next = flag->next();
171 SkDELETE(flag);
172 flag = next;
173 }
174 if (helpPrinted) {
175 exit(0);
176 }
177}