blob: be39fcd4f8879ba9fc23462f5a5f00a7743ed05a [file] [log] [blame]
Dynamic Tools Team517193e2019-09-11 14:48:41 +00001//===-- 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 <stdlib.h>
14#include <string.h>
15
16namespace scudo {
17
18class UnknownFlagsRegistry {
19 static const u32 MaxUnknownFlags = 16;
20 const char *UnknownFlagsNames[MaxUnknownFlags];
21 u32 NumberOfUnknownFlags;
22
23public:
24 void add(const char *Name) {
25 CHECK_LT(NumberOfUnknownFlags, MaxUnknownFlags);
26 UnknownFlagsNames[NumberOfUnknownFlags++] = Name;
27 }
28
29 void report() {
30 if (!NumberOfUnknownFlags)
31 return;
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;
37 }
38};
39static UnknownFlagsRegistry UnknownFlags;
40
41void reportUnrecognizedFlags() { UnknownFlags.report(); }
42
43void 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);
47}
48
49static bool isSeparator(char C) {
50 return C == ' ' || C == ',' || C == ':' || C == '\n' || C == '\t' ||
51 C == '\r';
52}
53
54static bool isSeparatorOrNull(char C) { return !C || isSeparator(C); }
55
56void FlagParser::skipWhitespace() {
57 while (isSeparator(Buffer[Pos]))
58 ++Pos;
59}
60
61void FlagParser::parseFlag() {
62 const uptr NameStart = Pos;
63 while (Buffer[Pos] != '=' && !isSeparatorOrNull(Buffer[Pos]))
64 ++Pos;
65 if (Buffer[Pos] != '=')
66 reportError("expected '='");
67 const char *Name = Buffer + NameStart;
68 const uptr ValueStart = ++Pos;
69 const char *Value;
70 if (Buffer[Pos] == '\'' || Buffer[Pos] == '"') {
71 const char Quote = Buffer[Pos++];
72 while (Buffer[Pos] != 0 && Buffer[Pos] != Quote)
73 ++Pos;
74 if (Buffer[Pos] == 0)
75 reportError("unterminated string");
76 Value = Buffer + ValueStart + 1;
77 ++Pos; // consume the closing quote
78 } else {
79 while (!isSeparatorOrNull(Buffer[Pos]))
80 ++Pos;
81 Value = Buffer + ValueStart;
82 }
83 if (!runHandler(Name, Value))
84 reportError("flag parsing failed.");
85}
86
87void FlagParser::parseFlags() {
88 while (true) {
89 skipWhitespace();
90 if (Buffer[Pos] == 0)
91 break;
92 parseFlag();
93 }
94}
95
96void FlagParser::parseString(const char *S) {
97 if (!S)
98 return;
99 // Backup current parser state to allow nested parseString() calls.
100 const char *OldBuffer = Buffer;
101 const uptr OldPos = Pos;
102 Buffer = S;
103 Pos = 0;
104
105 parseFlags();
106
107 Buffer = OldBuffer;
108 Pos = OldPos;
109}
110
Dynamic Tools Team09e6d482019-11-26 18:18:14 -0800111inline bool parseBool(const char *Value, bool *b) {
Dynamic Tools Team517193e2019-09-11 14:48:41 +0000112 if (strncmp(Value, "0", 1) == 0 || strncmp(Value, "no", 2) == 0 ||
113 strncmp(Value, "false", 5) == 0) {
114 *b = false;
115 return true;
116 }
117 if (strncmp(Value, "1", 1) == 0 || strncmp(Value, "yes", 3) == 0 ||
118 strncmp(Value, "true", 4) == 0) {
119 *b = true;
120 return true;
121 }
122 return false;
123}
124
125bool 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] != '=')
129 continue;
130 bool Ok = false;
131 switch (Flags[I].Type) {
132 case FlagType::FT_bool:
133 Ok = parseBool(Value, reinterpret_cast<bool *>(Flags[I].Var));
134 if (!Ok)
135 reportInvalidFlag("bool", Value);
136 break;
137 case FlagType::FT_int:
138 char *ValueEnd;
139 *reinterpret_cast<int *>(Flags[I].Var) =
140 static_cast<int>(strtol(Value, &ValueEnd, 10));
141 Ok =
142 *ValueEnd == '"' || *ValueEnd == '\'' || isSeparatorOrNull(*ValueEnd);
143 if (!Ok)
144 reportInvalidFlag("int", Value);
145 break;
146 }
147 return Ok;
148 }
149 // Unrecognized flag. This is not a fatal error, we may print a warning later.
150 UnknownFlags.add(Name);
151 return true;
152}
153
154void FlagParser::registerFlag(const char *Name, const char *Desc, FlagType Type,
155 void *Var) {
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;
161 ++NumberOfFlags;
162}
163
164} // namespace scudo