1 //===-- RegularExpression.cpp -----------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "lldb/Utility/RegularExpression.h" 11 12 // C Includes 13 // C++ Includes 14 #include <cstring> 15 16 // Other libraries and framework includes 17 #include "llvm/ADT/StringRef.h" 18 19 // Project includes 20 #include "lldb/Utility/Error.h" 21 22 //---------------------------------------------------------------------- 23 // Enable enhanced mode if it is available. This allows for things like 24 // \d for digit, \s for space, and many more, but it isn't available 25 // everywhere. 26 //---------------------------------------------------------------------- 27 #if defined(REG_ENHANCED) 28 #define DEFAULT_COMPILE_FLAGS (REG_ENHANCED | REG_EXTENDED) 29 #else 30 #define DEFAULT_COMPILE_FLAGS (REG_EXTENDED) 31 #endif 32 33 using namespace lldb_private; 34 35 RegularExpression::RegularExpression() : m_re(), m_comp_err(1), m_preg() { 36 memset(&m_preg, 0, sizeof(m_preg)); 37 } 38 39 //---------------------------------------------------------------------- 40 // Constructor that compiles "re" using "flags" and stores the 41 // resulting compiled regular expression into this object. 42 //---------------------------------------------------------------------- 43 RegularExpression::RegularExpression(llvm::StringRef str) 44 : m_re(), m_comp_err(1), m_preg() { 45 memset(&m_preg, 0, sizeof(m_preg)); 46 Compile(str); 47 } 48 49 RegularExpression::RegularExpression(const RegularExpression &rhs) { 50 memset(&m_preg, 0, sizeof(m_preg)); 51 Compile(rhs.GetText()); 52 } 53 54 const RegularExpression &RegularExpression:: 55 operator=(const RegularExpression &rhs) { 56 if (&rhs != this) 57 Compile(rhs.GetText()); 58 return *this; 59 } 60 61 //---------------------------------------------------------------------- 62 // Destructor 63 // 64 // Any previously compiled regular expression contained in this 65 // object will be freed. 66 //---------------------------------------------------------------------- 67 RegularExpression::~RegularExpression() { Free(); } 68 69 //---------------------------------------------------------------------- 70 // Compile a regular expression using the supplied regular 71 // expression text and flags. The compiled regular expression lives 72 // in this object so that it can be readily used for regular 73 // expression matches. Execute() can be called after the regular 74 // expression is compiled. Any previously compiled regular 75 // expression contained in this object will be freed. 76 // 77 // RETURNS 78 // True if the regular expression compiles successfully, false 79 // otherwise. 80 //---------------------------------------------------------------------- 81 bool RegularExpression::Compile(llvm::StringRef str) { 82 Free(); 83 84 if (!str.empty()) { 85 m_re = str; 86 m_comp_err = ::regcomp(&m_preg, m_re.c_str(), DEFAULT_COMPILE_FLAGS); 87 } else { 88 // No valid regular expression 89 m_comp_err = 1; 90 } 91 92 return m_comp_err == 0; 93 } 94 95 //---------------------------------------------------------------------- 96 // Execute a regular expression match using the compiled regular 97 // expression that is already in this object against the match 98 // string "s". If any parens are used for regular expression 99 // matches "match_count" should indicate the number of regmatch_t 100 // values that are present in "match_ptr". The regular expression 101 // will be executed using the "execute_flags". 102 //--------------------------------------------------------------------- 103 bool RegularExpression::Execute(llvm::StringRef str, Match *match) const { 104 int err = 1; 105 if (m_comp_err == 0) { 106 // Argument to regexec must be null-terminated. 107 std::string reg_str = str; 108 if (match) { 109 err = ::regexec(&m_preg, reg_str.c_str(), match->GetSize(), 110 match->GetData(), 0); 111 } else { 112 err = ::regexec(&m_preg, reg_str.c_str(), 0, nullptr, 0); 113 } 114 } 115 116 if (err != 0) { 117 // The regular expression didn't compile, so clear the matches 118 if (match) 119 match->Clear(); 120 return false; 121 } 122 return true; 123 } 124 125 bool RegularExpression::Match::GetMatchAtIndex(llvm::StringRef s, uint32_t idx, 126 std::string &match_str) const { 127 llvm::StringRef match_str_ref; 128 if (GetMatchAtIndex(s, idx, match_str_ref)) { 129 match_str = match_str_ref.str(); 130 return true; 131 } 132 return false; 133 } 134 135 bool RegularExpression::Match::GetMatchAtIndex( 136 llvm::StringRef s, uint32_t idx, llvm::StringRef &match_str) const { 137 if (idx < m_matches.size()) { 138 if (m_matches[idx].rm_eo == -1 && m_matches[idx].rm_so == -1) 139 return false; 140 141 if (m_matches[idx].rm_eo == m_matches[idx].rm_so) { 142 // Matched the empty string... 143 match_str = llvm::StringRef(); 144 return true; 145 } else if (m_matches[idx].rm_eo > m_matches[idx].rm_so) { 146 match_str = s.substr(m_matches[idx].rm_so, 147 m_matches[idx].rm_eo - m_matches[idx].rm_so); 148 return true; 149 } 150 } 151 return false; 152 } 153 154 bool RegularExpression::Match::GetMatchSpanningIndices( 155 llvm::StringRef s, uint32_t idx1, uint32_t idx2, 156 llvm::StringRef &match_str) const { 157 if (idx1 < m_matches.size() && idx2 < m_matches.size()) { 158 if (m_matches[idx1].rm_so == m_matches[idx2].rm_eo) { 159 // Matched the empty string... 160 match_str = llvm::StringRef(); 161 return true; 162 } else if (m_matches[idx1].rm_so < m_matches[idx2].rm_eo) { 163 match_str = s.substr(m_matches[idx1].rm_so, 164 m_matches[idx2].rm_eo - m_matches[idx1].rm_so); 165 return true; 166 } 167 } 168 return false; 169 } 170 171 //---------------------------------------------------------------------- 172 // Returns true if the regular expression compiled and is ready 173 // for execution. 174 //---------------------------------------------------------------------- 175 bool RegularExpression::IsValid() const { return m_comp_err == 0; } 176 177 //---------------------------------------------------------------------- 178 // Returns the text that was used to compile the current regular 179 // expression. 180 //---------------------------------------------------------------------- 181 llvm::StringRef RegularExpression::GetText() const { return m_re; } 182 183 //---------------------------------------------------------------------- 184 // Free any contained compiled regular expressions. 185 //---------------------------------------------------------------------- 186 void RegularExpression::Free() { 187 if (m_comp_err == 0) { 188 m_re.clear(); 189 regfree(&m_preg); 190 // Set a compile error since we no longer have a valid regex 191 m_comp_err = 1; 192 } 193 } 194 195 size_t RegularExpression::GetErrorAsCString(char *err_str, 196 size_t err_str_max_len) const { 197 if (m_comp_err == 0) { 198 if (err_str && err_str_max_len) 199 *err_str = '\0'; 200 return 0; 201 } 202 203 return ::regerror(m_comp_err, &m_preg, err_str, err_str_max_len); 204 } 205 206 bool RegularExpression::operator<(const RegularExpression &rhs) const { 207 return (m_re < rhs.m_re); 208 } 209