Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/compiler-rt/lib/scudo/standalone/flags_parser.cpp
35291 views
1
//===-- flags_parser.cpp ----------------------------------------*- C++ -*-===//
2
//
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
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "flags_parser.h"
10
#include "common.h"
11
#include "report.h"
12
13
#include <errno.h>
14
#include <limits.h>
15
#include <stdlib.h>
16
#include <string.h>
17
18
namespace scudo {
19
20
class UnknownFlagsRegistry {
21
static const u32 MaxUnknownFlags = 16;
22
const char *UnknownFlagsNames[MaxUnknownFlags];
23
u32 NumberOfUnknownFlags;
24
25
public:
26
void add(const char *Name) {
27
CHECK_LT(NumberOfUnknownFlags, MaxUnknownFlags);
28
UnknownFlagsNames[NumberOfUnknownFlags++] = Name;
29
}
30
31
void report() {
32
if (!NumberOfUnknownFlags)
33
return;
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;
39
}
40
};
41
static UnknownFlagsRegistry UnknownFlags;
42
43
void reportUnrecognizedFlags() { UnknownFlags.report(); }
44
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);
49
}
50
51
static bool isSeparator(char C) {
52
return C == ' ' || C == ',' || C == ':' || C == '\n' || C == '\t' ||
53
C == '\r';
54
}
55
56
static bool isSeparatorOrNull(char C) { return !C || isSeparator(C); }
57
58
void FlagParser::skipWhitespace() {
59
while (isSeparator(Buffer[Pos]))
60
++Pos;
61
}
62
63
void FlagParser::parseFlag() {
64
const uptr NameStart = Pos;
65
while (Buffer[Pos] != '=' && !isSeparatorOrNull(Buffer[Pos]))
66
++Pos;
67
if (Buffer[Pos] != '=')
68
reportError("expected '='");
69
const char *Name = Buffer + NameStart;
70
const uptr ValueStart = ++Pos;
71
const char *Value;
72
if (Buffer[Pos] == '\'' || Buffer[Pos] == '"') {
73
const char Quote = Buffer[Pos++];
74
while (Buffer[Pos] != 0 && Buffer[Pos] != Quote)
75
++Pos;
76
if (Buffer[Pos] == 0)
77
reportError("unterminated string");
78
Value = Buffer + ValueStart + 1;
79
++Pos; // consume the closing quote
80
} else {
81
while (!isSeparatorOrNull(Buffer[Pos]))
82
++Pos;
83
Value = Buffer + ValueStart;
84
}
85
if (!runHandler(Name, Value, '='))
86
reportError("flag parsing failed.");
87
}
88
89
void FlagParser::parseFlags() {
90
while (true) {
91
skipWhitespace();
92
if (Buffer[Pos] == 0)
93
break;
94
parseFlag();
95
}
96
}
97
98
void FlagParser::parseString(const char *S) {
99
if (!S)
100
return;
101
// Backup current parser state to allow nested parseString() calls.
102
const char *OldBuffer = Buffer;
103
const uptr OldPos = Pos;
104
Buffer = S;
105
Pos = 0;
106
107
parseFlags();
108
109
Buffer = OldBuffer;
110
Pos = OldPos;
111
}
112
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) {
116
*b = false;
117
return true;
118
}
119
if (strncmp(Value, "1", 1) == 0 || strncmp(Value, "yes", 3) == 0 ||
120
strncmp(Value, "true", 4) == 0) {
121
*b = true;
122
return true;
123
}
124
return false;
125
}
126
127
void FlagParser::parseStringPair(const char *Name, const char *Value) {
128
if (!runHandler(Name, Value, '\0'))
129
reportError("flag parsing failed.");
130
}
131
132
bool FlagParser::runHandler(const char *Name, const char *Value,
133
const char Sep) {
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)
137
continue;
138
bool Ok = false;
139
switch (Flags[I].Type) {
140
case FlagType::FT_bool:
141
Ok = parseBool(Value, reinterpret_cast<bool *>(Flags[I].Var));
142
if (!Ok)
143
reportInvalidFlag("bool", Value);
144
break;
145
case FlagType::FT_int:
146
char *ValueEnd;
147
errno = 0;
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);
155
break;
156
}
157
*reinterpret_cast<int *>(Flags[I].Var) = static_cast<int>(V);
158
Ok = true;
159
break;
160
}
161
return Ok;
162
}
163
// Unrecognized flag. This is not a fatal error, we may print a warning later.
164
UnknownFlags.add(Name);
165
return true;
166
}
167
168
void FlagParser::registerFlag(const char *Name, const char *Desc, FlagType Type,
169
void *Var) {
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;
175
++NumberOfFlags;
176
}
177
178
} // namespace scudo
179
180