//===-- RegularExpression.cpp -----------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "lldb/Utility/RegularExpression.h" #include "llvm/ADT/StringRef.h" #include // Enable enhanced mode if it is available. This allows for things like \d for // digit, \s for space, and many more, but it isn't available everywhere. #if defined(REG_ENHANCED) #define DEFAULT_COMPILE_FLAGS (REG_ENHANCED | REG_EXTENDED) #else #define DEFAULT_COMPILE_FLAGS (REG_EXTENDED) #endif using namespace lldb_private; RegularExpression::RegularExpression() : m_re(), m_comp_err(1), m_preg() { memset(&m_preg, 0, sizeof(m_preg)); } // Constructor that compiles "re" using "flags" and stores the resulting // compiled regular expression into this object. RegularExpression::RegularExpression(llvm::StringRef str) : RegularExpression() { Compile(str); } RegularExpression::RegularExpression(const RegularExpression &rhs) : RegularExpression() { Compile(rhs.GetText()); } const RegularExpression &RegularExpression:: operator=(const RegularExpression &rhs) { if (&rhs != this) Compile(rhs.GetText()); return *this; } // Destructor // // Any previously compiled regular expression contained in this object will be // freed. RegularExpression::~RegularExpression() { Free(); } // Compile a regular expression using the supplied regular expression text and // flags. The compiled regular expression lives in this object so that it can // be readily used for regular expression matches. Execute() can be called // after the regular expression is compiled. Any previously compiled regular // expression contained in this object will be freed. // // RETURNS // True if the regular expression compiles successfully, false // otherwise. bool RegularExpression::Compile(llvm::StringRef str) { Free(); // regcomp() on darwin does not recognize "" as a valid regular expression, // so we substitute it with an equivalent non-empty one. m_re = str.empty() ? "()" : str; m_comp_err = ::regcomp(&m_preg, m_re.c_str(), DEFAULT_COMPILE_FLAGS); return m_comp_err == 0; } // Execute a regular expression match using the compiled regular expression // that is already in this object against the match string "s". If any parens // are used for regular expression matches "match_count" should indicate the // number of regmatch_t values that are present in "match_ptr". The regular // expression will be executed using the "execute_flags". bool RegularExpression::Execute(llvm::StringRef str, Match *match) const { int err = 1; if (m_comp_err == 0) { // Argument to regexec must be null-terminated. std::string reg_str = str; if (match) { err = ::regexec(&m_preg, reg_str.c_str(), match->GetSize(), match->GetData(), 0); } else { err = ::regexec(&m_preg, reg_str.c_str(), 0, nullptr, 0); } } if (err != 0) { // The regular expression didn't compile, so clear the matches if (match) match->Clear(); return false; } return true; } bool RegularExpression::Match::GetMatchAtIndex(llvm::StringRef s, uint32_t idx, std::string &match_str) const { llvm::StringRef match_str_ref; if (GetMatchAtIndex(s, idx, match_str_ref)) { match_str = match_str_ref.str(); return true; } return false; } bool RegularExpression::Match::GetMatchAtIndex( llvm::StringRef s, uint32_t idx, llvm::StringRef &match_str) const { if (idx < m_matches.size()) { if (m_matches[idx].rm_eo == -1 && m_matches[idx].rm_so == -1) return false; if (m_matches[idx].rm_eo == m_matches[idx].rm_so) { // Matched the empty string... match_str = llvm::StringRef(); return true; } else if (m_matches[idx].rm_eo > m_matches[idx].rm_so) { match_str = s.substr(m_matches[idx].rm_so, m_matches[idx].rm_eo - m_matches[idx].rm_so); return true; } } return false; } bool RegularExpression::Match::GetMatchSpanningIndices( llvm::StringRef s, uint32_t idx1, uint32_t idx2, llvm::StringRef &match_str) const { if (idx1 < m_matches.size() && idx2 < m_matches.size()) { if (m_matches[idx1].rm_so == m_matches[idx2].rm_eo) { // Matched the empty string... match_str = llvm::StringRef(); return true; } else if (m_matches[idx1].rm_so < m_matches[idx2].rm_eo) { match_str = s.substr(m_matches[idx1].rm_so, m_matches[idx2].rm_eo - m_matches[idx1].rm_so); return true; } } return false; } // Returns true if the regular expression compiled and is ready for execution. bool RegularExpression::IsValid() const { return m_comp_err == 0; } // Returns the text that was used to compile the current regular expression. llvm::StringRef RegularExpression::GetText() const { return m_re; } // Free any contained compiled regular expressions. void RegularExpression::Free() { if (m_comp_err == 0) { m_re.clear(); regfree(&m_preg); // Set a compile error since we no longer have a valid regex m_comp_err = 1; } } size_t RegularExpression::GetErrorAsCString(char *err_str, size_t err_str_max_len) const { if (m_comp_err == 0) { if (err_str && err_str_max_len) *err_str = '\0'; return 0; } return ::regerror(m_comp_err, &m_preg, err_str, err_str_max_len); } bool RegularExpression::operator<(const RegularExpression &rhs) const { return (m_re < rhs.m_re); }