1// Copyright 2015 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15#ifndef BENCHMARK_RE_H_ 16#define BENCHMARK_RE_H_ 17 18#if defined(HAVE_STD_REGEX) 19#include <regex> 20#elif defined(HAVE_GNU_POSIX_REGEX) 21#include <gnuregex.h> 22#elif defined(HAVE_POSIX_REGEX) 23#include <regex.h> 24#else 25#error No regular expression backend was found! 26#endif 27#include <string> 28 29#include "check.h" 30 31namespace benchmark { 32 33// A wrapper around the POSIX regular expression API that provides automatic 34// cleanup 35class Regex { 36 public: 37 Regex() : init_(false) {} 38 39 ~Regex(); 40 41 // Compile a regular expression matcher from spec. Returns true on success. 42 // 43 // On failure (and if error is not nullptr), error is populated with a human 44 // readable error message if an error occurs. 45 bool Init(const std::string& spec, std::string* error); 46 47 // Returns whether str matches the compiled regular expression. 48 bool Match(const std::string& str); 49 50 private: 51 bool init_; 52// Underlying regular expression object 53#if defined(HAVE_STD_REGEX) 54 std::regex re_; 55#elif defined(HAVE_POSIX_REGEX) || defined(HAVE_GNU_POSIX_REGEX) 56 regex_t re_; 57#else 58#error No regular expression backend implementation available 59#endif 60}; 61 62#if defined(HAVE_STD_REGEX) 63 64inline bool Regex::Init(const std::string& spec, std::string* error) { 65 try { 66 re_ = std::regex(spec, std::regex_constants::extended); 67 68 init_ = true; 69 } catch (const std::regex_error& e) { 70 if (error) { 71 *error = e.what(); 72 } 73 } 74 return init_; 75} 76 77inline Regex::~Regex() {} 78 79inline bool Regex::Match(const std::string& str) { 80 if (!init_) { 81 return false; 82 } 83 return std::regex_search(str, re_); 84} 85 86#else 87inline bool Regex::Init(const std::string& spec, std::string* error) { 88 int ec = regcomp(&re_, spec.c_str(), REG_EXTENDED | REG_NOSUB); 89 if (ec != 0) { 90 if (error) { 91 size_t needed = regerror(ec, &re_, nullptr, 0); 92 char* errbuf = new char[needed]; 93 regerror(ec, &re_, errbuf, needed); 94 95 // regerror returns the number of bytes necessary to null terminate 96 // the string, so we move that when assigning to error. 97 CHECK_NE(needed, 0); 98 error->assign(errbuf, needed - 1); 99 100 delete[] errbuf; 101 } 102 103 return false; 104 } 105 106 init_ = true; 107 return true; 108} 109 110inline Regex::~Regex() { 111 if (init_) { 112 regfree(&re_); 113 } 114} 115 116inline bool Regex::Match(const std::string& str) { 117 if (!init_) { 118 return false; 119 } 120 return regexec(&re_, str.c_str(), 0, nullptr, 0) == 0; 121} 122#endif 123 124} // end namespace benchmark 125 126#endif // BENCHMARK_RE_H_ 127