1 //===-- flags_parser.cc -----------------------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "flags_parser.h"
18 class UnknownFlagsRegistry {
19 static const u32 MaxUnknownFlags = 16;
20 const char *UnknownFlagsNames[MaxUnknownFlags];
21 u32 NumberOfUnknownFlags;
24 void add(const char *Name) {
25 CHECK_LT(NumberOfUnknownFlags, MaxUnknownFlags);
26 UnknownFlagsNames[NumberOfUnknownFlags++] = Name;
30 if (!NumberOfUnknownFlags)
32 Printf("Scudo WARNING: found %d unrecognized flag(s):\n",
33 NumberOfUnknownFlags);
34 for (u32 I = 0; I < NumberOfUnknownFlags; ++I)
35 Printf(" %s\n", UnknownFlagsNames[I]);
36 NumberOfUnknownFlags = 0;
39 static UnknownFlagsRegistry UnknownFlags;
41 void reportUnrecognizedFlags() { UnknownFlags.report(); }
43 void FlagParser::printFlagDescriptions() {
44 Printf("Available flags for Scudo:\n");
45 for (u32 I = 0; I < NumberOfFlags; ++I)
46 Printf("\t%s\n\t\t- %s\n", Flags[I].Name, Flags[I].Desc);
49 static bool isSeparator(char C) {
50 return C == ' ' || C == ',' || C == ':' || C == '\n' || C == '\t' ||
54 static bool isSeparatorOrNull(char C) { return !C || isSeparator(C); }
56 void FlagParser::skipWhitespace() {
57 while (isSeparator(Buffer[Pos]))
61 void FlagParser::parseFlag() {
62 const uptr NameStart = Pos;
63 while (Buffer[Pos] != '=' && !isSeparatorOrNull(Buffer[Pos]))
65 if (Buffer[Pos] != '=')
66 reportError("expected '='");
67 const char *Name = Buffer + NameStart;
68 const uptr ValueStart = ++Pos;
70 if (Buffer[Pos] == '\'' || Buffer[Pos] == '"') {
71 const char Quote = Buffer[Pos++];
72 while (Buffer[Pos] != 0 && Buffer[Pos] != Quote)
75 reportError("unterminated string");
76 Value = Buffer + ValueStart + 1;
77 ++Pos; // consume the closing quote
79 while (!isSeparatorOrNull(Buffer[Pos]))
81 Value = Buffer + ValueStart;
83 if (!runHandler(Name, Value))
84 reportError("flag parsing failed.");
87 void FlagParser::parseFlags() {
96 void FlagParser::parseString(const char *S) {
99 // Backup current parser state to allow nested parseString() calls.
100 const char *OldBuffer = Buffer;
101 const uptr OldPos = Pos;
111 INLINE bool parseBool(const char *Value, bool *b) {
112 if (strncmp(Value, "0", 1) == 0 || strncmp(Value, "no", 2) == 0 ||
113 strncmp(Value, "false", 5) == 0) {
117 if (strncmp(Value, "1", 1) == 0 || strncmp(Value, "yes", 3) == 0 ||
118 strncmp(Value, "true", 4) == 0) {
125 bool FlagParser::runHandler(const char *Name, const char *Value) {
126 for (u32 I = 0; I < NumberOfFlags; ++I) {
127 const uptr Len = strlen(Flags[I].Name);
128 if (strncmp(Name, Flags[I].Name, Len) != 0 || Name[Len] != '=')
131 switch (Flags[I].Type) {
132 case FlagType::FT_bool:
133 Ok = parseBool(Value, reinterpret_cast<bool *>(Flags[I].Var));
135 reportInvalidFlag("bool", Value);
137 case FlagType::FT_int:
139 *reinterpret_cast<int *>(Flags[I].Var) =
140 static_cast<int>(strtol(Value, &ValueEnd, 10));
142 *ValueEnd == '"' || *ValueEnd == '\'' || isSeparatorOrNull(*ValueEnd);
144 reportInvalidFlag("int", Value);
149 // Unrecognized flag. This is not a fatal error, we may print a warning later.
150 UnknownFlags.add(Name);
154 void FlagParser::registerFlag(const char *Name, const char *Desc, FlagType Type,
156 CHECK_LT(NumberOfFlags, MaxFlags);
157 Flags[NumberOfFlags].Name = Name;
158 Flags[NumberOfFlags].Desc = Desc;
159 Flags[NumberOfFlags].Type = Type;
160 Flags[NumberOfFlags].Var = Var;