Flutter Engine
The Flutter Engine
CommandLineFlags.cpp
Go to the documentation of this file.
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
9#include "src/base/SkTSort.h"
11
12#include <stdlib.h>
13
14template <typename T> static void ignore_result(const T&) {}
15
17 const char* shortName,
19 const char* defaultValue,
20 const char* helpString,
21 const char* extendedHelpString) {
23 new SkFlagInfo(name, shortName, kString_FlagType, helpString, extendedHelpString);
24 info->fDefaultString.set(defaultValue);
25
26 info->fStrings = pStrings;
27 SetDefaultStrings(pStrings, defaultValue);
28 return true;
29}
30
31void SkFlagInfo::SetDefaultStrings(CommandLineFlags::StringArray* pStrings,
32 const char* defaultValue) {
33 pStrings->reset();
34 if (nullptr == defaultValue) {
35 return;
36 }
37 // If default is "", leave the array empty.
38 size_t defaultLength = strlen(defaultValue);
39 if (defaultLength > 0) {
40 const char* const defaultEnd = defaultValue + defaultLength;
41 const char* begin = defaultValue;
42 while (true) {
43 while (begin < defaultEnd && ' ' == *begin) {
44 begin++;
45 }
46 if (begin < defaultEnd) {
47 const char* end = begin + 1;
48 while (end < defaultEnd && ' ' != *end) {
49 end++;
50 }
51 size_t length = end - begin;
52 pStrings->append(begin, length);
53 begin = end + 1;
54 } else {
55 break;
56 }
57 }
58 }
59}
60
61static bool string_is_in(const char* target, const char* set[], size_t len) {
62 for (size_t i = 0; i < len; i++) {
63 if (0 == strcmp(target, set[i])) {
64 return true;
65 }
66 }
67 return false;
68}
69
70/**
71 * Check to see whether string represents a boolean value.
72 * @param string C style string to parse.
73 * @param result Pointer to a boolean which will be set to the value in the string, if the
74 * string represents a boolean.
75 * @param boolean True if the string represents a boolean, false otherwise.
76 */
77static bool parse_bool_arg(const char* string, bool* result) {
78 static const char* trueValues[] = {"1", "TRUE", "true"};
79 if (string_is_in(string, trueValues, std::size(trueValues))) {
80 *result = true;
81 return true;
82 }
83 static const char* falseValues[] = {"0", "FALSE", "false"};
84 if (string_is_in(string, falseValues, std::size(falseValues))) {
85 *result = false;
86 return true;
87 }
88 SkDebugf("Parameter \"%s\" not supported.\n", string);
89 return false;
90}
91
92bool SkFlagInfo::match(const char* string) {
93 if (SkStrStartsWith(string, '-') && strlen(string) > 1) {
94 string++;
95 const SkString* compareName;
96 if (SkStrStartsWith(string, '-') && strlen(string) > 1) {
97 string++;
98 // There were two dashes. Compare against full name.
99 compareName = &fName;
100 } else {
101 // One dash. Compare against the short name.
102 compareName = &fShortName;
103 }
104 if (kBool_FlagType == fFlagType) {
105 // In this case, go ahead and set the value.
106 if (compareName->equals(string)) {
107 *fBoolValue = true;
108 return true;
109 }
110 if (SkStrStartsWith(string, "no") && strlen(string) > 2) {
111 string += 2;
112 // Only allow "no" to be prepended to the full name.
113 if (fName.equals(string)) {
114 *fBoolValue = false;
115 return true;
116 }
117 return false;
118 }
119 int equalIndex = SkStrFind(string, "=");
120 if (equalIndex > 0) {
121 // The string has an equal sign. Check to see if the string matches.
122 SkString flag(string, equalIndex);
123 if (flag.equals(*compareName)) {
124 // Check to see if the remainder beyond the equal sign is true or false:
125 string += equalIndex + 1;
126 parse_bool_arg(string, fBoolValue);
127 return true;
128 } else {
129 return false;
130 }
131 }
132 }
133 return compareName->equals(string);
134 }
135
136 // Has no dash
137 return false;
138}
139
140SkFlagInfo* CommandLineFlags::gHead;
141SkString CommandLineFlags::gUsage;
142
143void CommandLineFlags::SetUsage(const char* usage) { gUsage.set(usage); }
144
145void CommandLineFlags::PrintUsage() { SkDebugf("%s", gUsage.c_str()); }
146
147// Maximum line length for the help message.
148#define LINE_LENGTH 72
149
150static void print_indented(const SkString& text) {
151 size_t length = text.size();
152 const char* currLine = text.c_str();
153 const char* stop = currLine + length;
154 while (currLine < stop) {
155 int lineBreak = SkStrFind(currLine, "\n");
156 if (lineBreak < 0) {
157 lineBreak = static_cast<int>(strlen(currLine));
158 }
159 if (lineBreak > LINE_LENGTH) {
160 // No line break within line length. Will need to insert one.
161 // Find a space before the line break.
162 int spaceIndex = LINE_LENGTH - 1;
163 while (spaceIndex > 0 && currLine[spaceIndex] != ' ') {
164 spaceIndex--;
165 }
166 int gap;
167 if (0 == spaceIndex) {
168 // No spaces on the entire line. Go ahead and break mid word.
169 spaceIndex = LINE_LENGTH;
170 gap = 0;
171 } else {
172 // Skip the space on the next line
173 gap = 1;
174 }
175 SkDebugf(" %.*s\n", spaceIndex, currLine);
176 currLine += spaceIndex + gap;
177 } else {
178 // the line break is within the limit. Break there.
179 lineBreak++;
180 SkDebugf(" %.*s", lineBreak, currLine);
181 currLine += lineBreak;
182 }
183 }
184}
185
187 SkDebugf(" --%s", flag->name().c_str());
188 const SkString& shortName = flag->shortName();
189 if (shortName.size() > 0) {
190 SkDebugf(" or -%s", shortName.c_str());
191 }
192 SkDebugf(":\ttype: %s", flag->typeAsString().c_str());
193 if (flag->defaultValue().size() > 0) {
194 SkDebugf("\tdefault: %s", flag->defaultValue().c_str());
195 }
196 SkDebugf("\n");
197 const SkString& help = flag->help();
199 SkDebugf("\n");
200}
203 print_indented(flag->extendedHelp());
204 SkDebugf("\n");
205}
206
207namespace {
208struct CompareFlagsByName {
209 bool operator()(SkFlagInfo* a, SkFlagInfo* b) const {
210 return strcmp(a->name().c_str(), b->name().c_str()) < 0;
211 }
212};
213} // namespace
214
215void CommandLineFlags::Parse(int argc, const char* const* argv) {
216 // Only allow calling this function once.
217 static bool gOnce;
218 if (gOnce) {
219 SkDebugf("Parse should only be called once at the beginning of main!\n");
220 SkASSERT(false);
221 return;
222 }
223 gOnce = true;
224
225 bool helpPrinted = false;
226 bool flagsPrinted = false;
227 // Loop over argv, starting with 1, since the first is just the name of the program.
228 for (int i = 1; i < argc; i++) {
229 if (0 == strcmp("-h", argv[i]) || 0 == strcmp("--help", argv[i])) {
230 // Print help message.
231 SkTDArray<const char*> helpFlags;
232 for (int j = i + 1; j < argc; j++) {
233 if (SkStrStartsWith(argv[j], '-')) {
234 break;
235 }
236 helpFlags.append(1, &argv[j]);
237 }
238 if (0 == helpFlags.size()) {
239 // Only print general help message if help for specific flags is not requested.
240 SkDebugf("%s\n%s\n", argv[0], gUsage.c_str());
241 }
242 if (!flagsPrinted) {
243 SkDebugf("Flags:\n");
244 flagsPrinted = true;
245 }
246 if (0 == helpFlags.size()) {
247 // If no flags followed --help, print them all
248 SkTDArray<SkFlagInfo*> allFlags;
249 for (SkFlagInfo* flag = CommandLineFlags::gHead; flag; flag = flag->next()) {
250 allFlags.push_back(flag);
251 }
252 SkTQSort(allFlags.begin(), allFlags.end(), CompareFlagsByName());
253 for (SkFlagInfo* flag : allFlags) {
255 if (flag->extendedHelp().size() > 0) {
256 SkDebugf(" Use '--help %s' for more information.\n",
257 flag->name().c_str());
258 }
259 }
260 } else {
261 for (SkFlagInfo* flag = CommandLineFlags::gHead; flag; flag = flag->next()) {
262 for (int k = 0; k < helpFlags.size(); k++) {
263 if (flag->name().equals(helpFlags[k]) ||
264 flag->shortName().equals(helpFlags[k])) {
266 helpFlags.remove(k);
267 break;
268 }
269 }
270 }
271 }
272 if (helpFlags.size() > 0) {
273 SkDebugf("Requested help for unrecognized flags:\n");
274 for (int k = 0; k < helpFlags.size(); k++) {
275 SkDebugf(" --%s\n", helpFlags[k]);
276 }
277 }
278 helpPrinted = true;
279 }
280 if (!helpPrinted) {
281 SkFlagInfo* matchedFlag = nullptr;
282 SkFlagInfo* flag = gHead;
283 int startI = i;
284 while (flag != nullptr) {
285 if (flag->match(argv[startI])) {
286 i = startI;
287 if (matchedFlag) {
288 // Don't redefine the same flag with different types.
289 SkASSERT(matchedFlag->getFlagType() == flag->getFlagType());
290 } else {
291 matchedFlag = flag;
292 }
293 switch (flag->getFlagType()) {
295 // Can be handled by match, above, but can also be set by the next
296 // string.
297 if (i + 1 < argc && !SkStrStartsWith(argv[i + 1], '-')) {
298 i++;
299 bool value;
300 if (parse_bool_arg(argv[i], &value)) {
301 flag->setBool(value);
302 }
303 }
304 break;
306 flag->resetStrings();
307 // Add all arguments until another flag is reached.
308 while (i + 1 < argc) {
309 char* end = nullptr;
310 // Negative numbers aren't flags.
311 ignore_result(strtod(argv[i + 1], &end));
312 if (end == argv[i + 1] && SkStrStartsWith(argv[i + 1], '-')) {
313 break;
314 }
315 i++;
316 flag->append(argv[i]);
317 }
318 break;
320 i++;
321 flag->setInt(atoi(argv[i]));
322 break;
324 i++;
325 flag->setDouble(atof(argv[i]));
326 break;
327 default: SkDEBUGFAIL("Invalid flag type");
328 }
329 }
330 flag = flag->next();
331 }
332 if (!matchedFlag) {
333#if defined(SK_BUILD_FOR_MAC)
334 if (SkStrStartsWith(argv[i], "NSDocumentRevisions") ||
335 SkStrStartsWith(argv[i], "-NSDocumentRevisions")) {
336 i++; // skip YES
337 } else
338#endif
339 SkDebugf("Got unknown flag '%s'. Exiting.\n", argv[i]);
340 exit(-1);
341 }
342 }
343 }
344 // Since all of the flags have been set, release the memory used by each
345 // flag. FLAGS_x can still be used after this.
346 SkFlagInfo* flag = gHead;
347 gHead = nullptr;
348 while (flag != nullptr) {
349 SkFlagInfo* next = flag->next();
350 delete flag;
351 flag = next;
352 }
353 if (helpPrinted) {
354 exit(0);
355 }
356}
357
358namespace {
359
360template <typename Strings> bool ShouldSkipImpl(const Strings& strings, const char* name) {
361 int count = strings.size();
362 size_t testLen = strlen(name);
363 bool anyExclude = count == 0;
364 for (int i = 0; i < strings.size(); ++i) {
365 const char* matchName = strings[i];
366 size_t matchLen = strlen(matchName);
367 bool matchExclude, matchStart, matchEnd;
368 if ((matchExclude = matchName[0] == '~')) {
369 anyExclude = true;
370 matchName++;
371 matchLen--;
372 }
373 if ((matchStart = matchName[0] == '^')) {
374 matchName++;
375 matchLen--;
376 }
377 if ((matchEnd = matchName[matchLen - 1] == '$')) {
378 matchLen--;
379 }
380 if (matchStart
381 ? (!matchEnd || matchLen == testLen) && strncmp(name, matchName, matchLen) == 0
382 : matchEnd
383 ? matchLen <= testLen &&
384 strncmp(name + testLen - matchLen, matchName, matchLen) == 0
385 : strstr(name, matchName) != nullptr) {
386 return matchExclude;
387 }
388 }
389 return !anyExclude;
390}
391
392} // namespace
393
395 return ShouldSkipImpl(strings, name);
396}
397bool CommandLineFlags::ShouldSkip(const StringArray& strings, const char* name) {
398 return ShouldSkipImpl(strings, name);
399}
static void print_indented(const SkString &text)
static bool parse_bool_arg(const char *string, bool *result)
static void print_extended_help_for_flag(const SkFlagInfo *flag)
static void ignore_result(const T &)
#define LINE_LENGTH
static void print_help_for_flag(const SkFlagInfo *flag)
static bool string_is_in(const char *target, const char *set[], size_t len)
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
int count
Definition: FontMgrTest.cpp:50
static float next(float f)
#define SkDEBUGFAIL(message)
Definition: SkAssert.h:118
#define SkASSERT(cond)
Definition: SkAssert.h:116
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
static bool SkStrStartsWith(const char string[], const char prefixStr[])
Definition: SkString.h:26
static int SkStrFind(const char string[], const char substring[])
Definition: SkString.h:41
void SkTQSort(T *begin, T *end, const C &lessThan)
Definition: SkTSort.h:194
static bool ShouldSkip(const SkTDArray< const char * > &strings, const char *name)
static void PrintUsage()
static void Parse(int argc, const char *const *argv)
static void SetUsage(const char *usage)
FlagTypes getFlagType() const
const SkString & name() const
const SkString & shortName() const
static bool CreateStringFlag(const char *name, const char *shortName, CommandLineFlags::StringArray *pStrings, const char *defaultValue, const char *helpString, const char *extendedHelpString)
bool match(const char *string)
SkString defaultValue() const
size_t size() const
Definition: SkString.h:131
void set(const SkString &src)
Definition: SkString.h:186
bool equals(const SkString &) const
Definition: SkString.cpp:324
const char * c_str() const
Definition: SkString.h:133
T * end()
Definition: SkTDArray.h:152
int size() const
Definition: SkTDArray.h:138
void push_back(const T &v)
Definition: SkTDArray.h:219
T * begin()
Definition: SkTDArray.h:150
T * append()
Definition: SkTDArray.h:191
void remove(int index, int count=1)
Definition: SkTDArray.h:210
static const char * begin(const StringSlice &s)
Definition: editor.cpp:252
static bool b
struct MyStruct a[10]
FlutterSemanticsFlag flag
glong glong end
uint8_t value
GAsyncResult * result
uint32_t * target
size_t length
std::u16string text
char ** argv
Definition: library.h:9
exit(kErrorExitCode)
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not set
Definition: switches.h:76
help
Definition: zip.py:79
#define T
Definition: precompiler.cc:65
static void usage(char *argv0)