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