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