aboutsummaryrefslogtreecommitdiff
path: root/source/Utility/RegularExpression.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Utility/RegularExpression.cpp')
-rw-r--r--source/Utility/RegularExpression.cpp198
1 files changed, 198 insertions, 0 deletions
diff --git a/source/Utility/RegularExpression.cpp b/source/Utility/RegularExpression.cpp
new file mode 100644
index 000000000000..d58b315d0d1d
--- /dev/null
+++ b/source/Utility/RegularExpression.cpp
@@ -0,0 +1,198 @@
+//===-- 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);
+}