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