| //===-- RegularExpression.cpp -----------------------------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "lldb/Utility/RegularExpression.h" |
| |
| #include "llvm/ADT/StringRef.h" |
| |
| #include <string> |
| |
| //---------------------------------------------------------------------- |
| // 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) |
| : m_re(), m_comp_err(1), m_preg() { |
| memset(&m_preg, 0, sizeof(m_preg)); |
| Compile(str); |
| } |
| |
| RegularExpression::RegularExpression(const RegularExpression &rhs) { |
| memset(&m_preg, 0, sizeof(m_preg)); |
| 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); |
| } |