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"
20 class UnknownFlagsRegistry
{
21 static const u32 MaxUnknownFlags
= 16;
22 const char *UnknownFlagsNames
[MaxUnknownFlags
];
23 u32 NumberOfUnknownFlags
;
26 void add(const char *Name
) {
27 CHECK_LT(NumberOfUnknownFlags
, MaxUnknownFlags
);
28 UnknownFlagsNames
[NumberOfUnknownFlags
++] = Name
;
32 if (!NumberOfUnknownFlags
)
34 Printf("Scudo WARNING: found %d unrecognized flag(s):\n",
35 NumberOfUnknownFlags
);
36 for (u32 I
= 0; I
< NumberOfUnknownFlags
; ++I
)
37 Printf(" %s\n", UnknownFlagsNames
[I
]);
38 NumberOfUnknownFlags
= 0;
41 static UnknownFlagsRegistry UnknownFlags
;
43 void reportUnrecognizedFlags() { UnknownFlags
.report(); }
45 void FlagParser::printFlagDescriptions() {
46 Printf("Available flags for Scudo:\n");
47 for (u32 I
= 0; I
< NumberOfFlags
; ++I
)
48 Printf("\t%s\n\t\t- %s\n", Flags
[I
].Name
, Flags
[I
].Desc
);
51 static bool isSeparator(char C
) {
52 return C
== ' ' || C
== ',' || C
== ':' || C
== '\n' || C
== '\t' ||
56 static bool isSeparatorOrNull(char C
) { return !C
|| isSeparator(C
); }
58 void FlagParser::skipWhitespace() {
59 while (isSeparator(Buffer
[Pos
]))
63 void FlagParser::parseFlag() {
64 const uptr NameStart
= Pos
;
65 while (Buffer
[Pos
] != '=' && !isSeparatorOrNull(Buffer
[Pos
]))
67 if (Buffer
[Pos
] != '=')
68 reportError("expected '='");
69 const char *Name
= Buffer
+ NameStart
;
70 const uptr ValueStart
= ++Pos
;
72 if (Buffer
[Pos
] == '\'' || Buffer
[Pos
] == '"') {
73 const char Quote
= Buffer
[Pos
++];
74 while (Buffer
[Pos
] != 0 && Buffer
[Pos
] != Quote
)
77 reportError("unterminated string");
78 Value
= Buffer
+ ValueStart
+ 1;
79 ++Pos
; // consume the closing quote
81 while (!isSeparatorOrNull(Buffer
[Pos
]))
83 Value
= Buffer
+ ValueStart
;
85 if (!runHandler(Name
, Value
, '='))
86 reportError("flag parsing failed.");
89 void FlagParser::parseFlags() {
98 void FlagParser::parseString(const char *S
) {
101 // Backup current parser state to allow nested parseString() calls.
102 const char *OldBuffer
= Buffer
;
103 const uptr OldPos
= Pos
;
113 inline bool parseBool(const char *Value
, bool *b
) {
114 if (strncmp(Value
, "0", 1) == 0 || strncmp(Value
, "no", 2) == 0 ||
115 strncmp(Value
, "false", 5) == 0) {
119 if (strncmp(Value
, "1", 1) == 0 || strncmp(Value
, "yes", 3) == 0 ||
120 strncmp(Value
, "true", 4) == 0) {
127 void FlagParser::parseStringPair(const char *Name
, const char *Value
) {
128 if (!runHandler(Name
, Value
, '\0'))
129 reportError("flag parsing failed.");
132 bool FlagParser::runHandler(const char *Name
, const char *Value
,
134 for (u32 I
= 0; I
< NumberOfFlags
; ++I
) {
135 const uptr Len
= strlen(Flags
[I
].Name
);
136 if (strncmp(Name
, Flags
[I
].Name
, Len
) != 0 || Name
[Len
] != Sep
)
139 switch (Flags
[I
].Type
) {
140 case FlagType::FT_bool
:
141 Ok
= parseBool(Value
, reinterpret_cast<bool *>(Flags
[I
].Var
));
143 reportInvalidFlag("bool", Value
);
145 case FlagType::FT_int
:
148 long V
= strtol(Value
, &ValueEnd
, 10);
149 if (errno
!= 0 || // strtol failed (over or underflow)
150 V
> INT_MAX
|| V
< INT_MIN
|| // overflows integer
151 // contains unexpected characters
152 (*ValueEnd
!= '"' && *ValueEnd
!= '\'' &&
153 !isSeparatorOrNull(*ValueEnd
))) {
154 reportInvalidFlag("int", Value
);
157 *reinterpret_cast<int *>(Flags
[I
].Var
) = static_cast<int>(V
);
163 // Unrecognized flag. This is not a fatal error, we may print a warning later.
164 UnknownFlags
.add(Name
);
168 void FlagParser::registerFlag(const char *Name
, const char *Desc
, FlagType Type
,
170 CHECK_LT(NumberOfFlags
, MaxFlags
);
171 Flags
[NumberOfFlags
].Name
= Name
;
172 Flags
[NumberOfFlags
].Desc
= Desc
;
173 Flags
[NumberOfFlags
].Type
= Type
;
174 Flags
[NumberOfFlags
].Var
= Var
;