brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.9 KiB · 3d8c6f3 Raw
179 lines · cpp
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-exception6//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 18namespace scudo {19 20class UnknownFlagsRegistry {21  static const u32 MaxUnknownFlags = 16;22  const char *UnknownFlagsNames[MaxUnknownFlags];23  u32 NumberOfUnknownFlags;24 25public: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};41static UnknownFlagsRegistry UnknownFlags;42 43void reportUnrecognizedFlags() { UnknownFlags.report(); }44 45void 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 51static bool isSeparator(char C) {52  return C == ' ' || C == ',' || C == ':' || C == '\n' || C == '\t' ||53         C == '\r';54}55 56static bool isSeparatorOrNull(char C) { return !C || isSeparator(C); }57 58void FlagParser::skipWhitespace() {59  while (isSeparator(Buffer[Pos]))60    ++Pos;61}62 63void 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 quote80  } 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 89void FlagParser::parseFlags() {90  while (true) {91    skipWhitespace();92    if (Buffer[Pos] == 0)93      break;94    parseFlag();95  }96}97 98void 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 113inline 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 127void FlagParser::parseStringPair(const char *Name, const char *Value) {128  if (!runHandler(Name, Value, '\0'))129    reportError("flag parsing failed.");130}131 132bool 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 integer151          // contains unexpected characters152          (*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 168void 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 scudo179