1 //===-- flags_parser.cpp ----------------------------------------*- 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
;