1*3cab2bb3Spatrick //===-- flags_parser.cpp ----------------------------------------*- C++ -*-===//
2*3cab2bb3Spatrick //
3*3cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*3cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
5*3cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*3cab2bb3Spatrick //
7*3cab2bb3Spatrick //===----------------------------------------------------------------------===//
8*3cab2bb3Spatrick
9*3cab2bb3Spatrick #include "flags_parser.h"
10*3cab2bb3Spatrick #include "common.h"
11*3cab2bb3Spatrick #include "report.h"
12*3cab2bb3Spatrick
13*3cab2bb3Spatrick #include <stdlib.h>
14*3cab2bb3Spatrick #include <string.h>
15*3cab2bb3Spatrick
16*3cab2bb3Spatrick namespace scudo {
17*3cab2bb3Spatrick
18*3cab2bb3Spatrick class UnknownFlagsRegistry {
19*3cab2bb3Spatrick static const u32 MaxUnknownFlags = 16;
20*3cab2bb3Spatrick const char *UnknownFlagsNames[MaxUnknownFlags];
21*3cab2bb3Spatrick u32 NumberOfUnknownFlags;
22*3cab2bb3Spatrick
23*3cab2bb3Spatrick public:
add(const char * Name)24*3cab2bb3Spatrick void add(const char *Name) {
25*3cab2bb3Spatrick CHECK_LT(NumberOfUnknownFlags, MaxUnknownFlags);
26*3cab2bb3Spatrick UnknownFlagsNames[NumberOfUnknownFlags++] = Name;
27*3cab2bb3Spatrick }
28*3cab2bb3Spatrick
report()29*3cab2bb3Spatrick void report() {
30*3cab2bb3Spatrick if (!NumberOfUnknownFlags)
31*3cab2bb3Spatrick return;
32*3cab2bb3Spatrick Printf("Scudo WARNING: found %d unrecognized flag(s):\n",
33*3cab2bb3Spatrick NumberOfUnknownFlags);
34*3cab2bb3Spatrick for (u32 I = 0; I < NumberOfUnknownFlags; ++I)
35*3cab2bb3Spatrick Printf(" %s\n", UnknownFlagsNames[I]);
36*3cab2bb3Spatrick NumberOfUnknownFlags = 0;
37*3cab2bb3Spatrick }
38*3cab2bb3Spatrick };
39*3cab2bb3Spatrick static UnknownFlagsRegistry UnknownFlags;
40*3cab2bb3Spatrick
reportUnrecognizedFlags()41*3cab2bb3Spatrick void reportUnrecognizedFlags() { UnknownFlags.report(); }
42*3cab2bb3Spatrick
printFlagDescriptions()43*3cab2bb3Spatrick void FlagParser::printFlagDescriptions() {
44*3cab2bb3Spatrick Printf("Available flags for Scudo:\n");
45*3cab2bb3Spatrick for (u32 I = 0; I < NumberOfFlags; ++I)
46*3cab2bb3Spatrick Printf("\t%s\n\t\t- %s\n", Flags[I].Name, Flags[I].Desc);
47*3cab2bb3Spatrick }
48*3cab2bb3Spatrick
isSeparator(char C)49*3cab2bb3Spatrick static bool isSeparator(char C) {
50*3cab2bb3Spatrick return C == ' ' || C == ',' || C == ':' || C == '\n' || C == '\t' ||
51*3cab2bb3Spatrick C == '\r';
52*3cab2bb3Spatrick }
53*3cab2bb3Spatrick
isSeparatorOrNull(char C)54*3cab2bb3Spatrick static bool isSeparatorOrNull(char C) { return !C || isSeparator(C); }
55*3cab2bb3Spatrick
skipWhitespace()56*3cab2bb3Spatrick void FlagParser::skipWhitespace() {
57*3cab2bb3Spatrick while (isSeparator(Buffer[Pos]))
58*3cab2bb3Spatrick ++Pos;
59*3cab2bb3Spatrick }
60*3cab2bb3Spatrick
parseFlag()61*3cab2bb3Spatrick void FlagParser::parseFlag() {
62*3cab2bb3Spatrick const uptr NameStart = Pos;
63*3cab2bb3Spatrick while (Buffer[Pos] != '=' && !isSeparatorOrNull(Buffer[Pos]))
64*3cab2bb3Spatrick ++Pos;
65*3cab2bb3Spatrick if (Buffer[Pos] != '=')
66*3cab2bb3Spatrick reportError("expected '='");
67*3cab2bb3Spatrick const char *Name = Buffer + NameStart;
68*3cab2bb3Spatrick const uptr ValueStart = ++Pos;
69*3cab2bb3Spatrick const char *Value;
70*3cab2bb3Spatrick if (Buffer[Pos] == '\'' || Buffer[Pos] == '"') {
71*3cab2bb3Spatrick const char Quote = Buffer[Pos++];
72*3cab2bb3Spatrick while (Buffer[Pos] != 0 && Buffer[Pos] != Quote)
73*3cab2bb3Spatrick ++Pos;
74*3cab2bb3Spatrick if (Buffer[Pos] == 0)
75*3cab2bb3Spatrick reportError("unterminated string");
76*3cab2bb3Spatrick Value = Buffer + ValueStart + 1;
77*3cab2bb3Spatrick ++Pos; // consume the closing quote
78*3cab2bb3Spatrick } else {
79*3cab2bb3Spatrick while (!isSeparatorOrNull(Buffer[Pos]))
80*3cab2bb3Spatrick ++Pos;
81*3cab2bb3Spatrick Value = Buffer + ValueStart;
82*3cab2bb3Spatrick }
83*3cab2bb3Spatrick if (!runHandler(Name, Value))
84*3cab2bb3Spatrick reportError("flag parsing failed.");
85*3cab2bb3Spatrick }
86*3cab2bb3Spatrick
parseFlags()87*3cab2bb3Spatrick void FlagParser::parseFlags() {
88*3cab2bb3Spatrick while (true) {
89*3cab2bb3Spatrick skipWhitespace();
90*3cab2bb3Spatrick if (Buffer[Pos] == 0)
91*3cab2bb3Spatrick break;
92*3cab2bb3Spatrick parseFlag();
93*3cab2bb3Spatrick }
94*3cab2bb3Spatrick }
95*3cab2bb3Spatrick
parseString(const char * S)96*3cab2bb3Spatrick void FlagParser::parseString(const char *S) {
97*3cab2bb3Spatrick if (!S)
98*3cab2bb3Spatrick return;
99*3cab2bb3Spatrick // Backup current parser state to allow nested parseString() calls.
100*3cab2bb3Spatrick const char *OldBuffer = Buffer;
101*3cab2bb3Spatrick const uptr OldPos = Pos;
102*3cab2bb3Spatrick Buffer = S;
103*3cab2bb3Spatrick Pos = 0;
104*3cab2bb3Spatrick
105*3cab2bb3Spatrick parseFlags();
106*3cab2bb3Spatrick
107*3cab2bb3Spatrick Buffer = OldBuffer;
108*3cab2bb3Spatrick Pos = OldPos;
109*3cab2bb3Spatrick }
110*3cab2bb3Spatrick
parseBool(const char * Value,bool * b)111*3cab2bb3Spatrick inline bool parseBool(const char *Value, bool *b) {
112*3cab2bb3Spatrick if (strncmp(Value, "0", 1) == 0 || strncmp(Value, "no", 2) == 0 ||
113*3cab2bb3Spatrick strncmp(Value, "false", 5) == 0) {
114*3cab2bb3Spatrick *b = false;
115*3cab2bb3Spatrick return true;
116*3cab2bb3Spatrick }
117*3cab2bb3Spatrick if (strncmp(Value, "1", 1) == 0 || strncmp(Value, "yes", 3) == 0 ||
118*3cab2bb3Spatrick strncmp(Value, "true", 4) == 0) {
119*3cab2bb3Spatrick *b = true;
120*3cab2bb3Spatrick return true;
121*3cab2bb3Spatrick }
122*3cab2bb3Spatrick return false;
123*3cab2bb3Spatrick }
124*3cab2bb3Spatrick
runHandler(const char * Name,const char * Value)125*3cab2bb3Spatrick bool FlagParser::runHandler(const char *Name, const char *Value) {
126*3cab2bb3Spatrick for (u32 I = 0; I < NumberOfFlags; ++I) {
127*3cab2bb3Spatrick const uptr Len = strlen(Flags[I].Name);
128*3cab2bb3Spatrick if (strncmp(Name, Flags[I].Name, Len) != 0 || Name[Len] != '=')
129*3cab2bb3Spatrick continue;
130*3cab2bb3Spatrick bool Ok = false;
131*3cab2bb3Spatrick switch (Flags[I].Type) {
132*3cab2bb3Spatrick case FlagType::FT_bool:
133*3cab2bb3Spatrick Ok = parseBool(Value, reinterpret_cast<bool *>(Flags[I].Var));
134*3cab2bb3Spatrick if (!Ok)
135*3cab2bb3Spatrick reportInvalidFlag("bool", Value);
136*3cab2bb3Spatrick break;
137*3cab2bb3Spatrick case FlagType::FT_int:
138*3cab2bb3Spatrick char *ValueEnd;
139*3cab2bb3Spatrick *reinterpret_cast<int *>(Flags[I].Var) =
140*3cab2bb3Spatrick static_cast<int>(strtol(Value, &ValueEnd, 10));
141*3cab2bb3Spatrick Ok =
142*3cab2bb3Spatrick *ValueEnd == '"' || *ValueEnd == '\'' || isSeparatorOrNull(*ValueEnd);
143*3cab2bb3Spatrick if (!Ok)
144*3cab2bb3Spatrick reportInvalidFlag("int", Value);
145*3cab2bb3Spatrick break;
146*3cab2bb3Spatrick }
147*3cab2bb3Spatrick return Ok;
148*3cab2bb3Spatrick }
149*3cab2bb3Spatrick // Unrecognized flag. This is not a fatal error, we may print a warning later.
150*3cab2bb3Spatrick UnknownFlags.add(Name);
151*3cab2bb3Spatrick return true;
152*3cab2bb3Spatrick }
153*3cab2bb3Spatrick
registerFlag(const char * Name,const char * Desc,FlagType Type,void * Var)154*3cab2bb3Spatrick void FlagParser::registerFlag(const char *Name, const char *Desc, FlagType Type,
155*3cab2bb3Spatrick void *Var) {
156*3cab2bb3Spatrick CHECK_LT(NumberOfFlags, MaxFlags);
157*3cab2bb3Spatrick Flags[NumberOfFlags].Name = Name;
158*3cab2bb3Spatrick Flags[NumberOfFlags].Desc = Desc;
159*3cab2bb3Spatrick Flags[NumberOfFlags].Type = Type;
160*3cab2bb3Spatrick Flags[NumberOfFlags].Var = Var;
161*3cab2bb3Spatrick ++NumberOfFlags;
162*3cab2bb3Spatrick }
163*3cab2bb3Spatrick
164*3cab2bb3Spatrick } // namespace scudo
165