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 #include "internal_macros.h" 19 20 // Prefer C regex libraries when compiling w/o exceptions so that we can 21 // correctly report errors. 22 #if defined(BENCHMARK_HAS_NO_EXCEPTIONS) && defined(HAVE_STD_REGEX) && \ 23 (defined(HAVE_GNU_POSIX_REGEX) || defined(HAVE_POSIX_REGEX)) 24 #undef HAVE_STD_REGEX 25 #endif 26 27 #if defined(HAVE_STD_REGEX) 28 #include <regex> 29 #elif defined(HAVE_GNU_POSIX_REGEX) 30 #include <gnuregex.h> 31 #elif defined(HAVE_POSIX_REGEX) 32 #include <regex.h> 33 #else 34 #error No regular expression backend was found! 35 #endif 36 #include <string> 37 38 #include "check.h" 39 40 namespace benchmark { 41 42 // A wrapper around the POSIX regular expression API that provides automatic 43 // cleanup 44 class Regex { 45 public: 46 Regex() : init_(false) {} 47 48 ~Regex(); 49 50 // Compile a regular expression matcher from spec. Returns true on success. 51 // 52 // On failure (and if error is not nullptr), error is populated with a human 53 // readable error message if an error occurs. 54 bool Init(const std::string& spec, std::string* error); 55 56 // Returns whether str matches the compiled regular expression. 57 bool Match(const std::string& str); 58 59 private: 60 bool init_; 61 // Underlying regular expression object 62 #if defined(HAVE_STD_REGEX) 63 std::regex re_; 64 #elif defined(HAVE_POSIX_REGEX) || defined(HAVE_GNU_POSIX_REGEX) 65 regex_t re_; 66 #else 67 #error No regular expression backend implementation available 68 #endif 69 }; 70 71 #if defined(HAVE_STD_REGEX) 72 73 inline bool Regex::Init(const std::string& spec, std::string* error) { 74 #ifdef BENCHMARK_HAS_NO_EXCEPTIONS 75 ((void)error); // suppress unused warning 76 #else 77 try { 78 #endif 79 re_ = std::regex(spec, std::regex_constants::extended); 80 init_ = true; 81 #ifndef BENCHMARK_HAS_NO_EXCEPTIONS 82 } catch (const std::regex_error& e) { 83 if (error) { 84 *error = e.what(); 85 } 86 } 87 #endif 88 return init_; 89 } 90 91 inline Regex::~Regex() {} 92 93 inline bool Regex::Match(const std::string& str) { 94 if (!init_) { 95 return false; 96 } 97 return std::regex_search(str, re_); 98 } 99 100 #else 101 inline bool Regex::Init(const std::string& spec, std::string* error) { 102 int ec = regcomp(&re_, spec.c_str(), REG_EXTENDED | REG_NOSUB); 103 if (ec != 0) { 104 if (error) { 105 size_t needed = regerror(ec, &re_, nullptr, 0); 106 char* errbuf = new char[needed]; 107 regerror(ec, &re_, errbuf, needed); 108 109 // regerror returns the number of bytes necessary to null terminate 110 // the string, so we move that when assigning to error. 111 CHECK_NE(needed, 0); 112 error->assign(errbuf, needed - 1); 113 114 delete[] errbuf; 115 } 116 117 return false; 118 } 119 120 init_ = true; 121 return true; 122 } 123 124 inline Regex::~Regex() { 125 if (init_) { 126 regfree(&re_); 127 } 128 } 129 130 inline bool Regex::Match(const std::string& str) { 131 if (!init_) { 132 return false; 133 } 134 return regexec(&re_, str.c_str(), 0, nullptr, 0) == 0; 135 } 136 #endif 137 138 } // end namespace benchmark 139 140 #endif // BENCHMARK_RE_H_ 141