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 <string.h>
11 #include "lldb/Core/RegularExpression.h"
12 #include "llvm/ADT/StringRef.h"
13 #include "lldb/Core/Error.h"
14
15
16 //----------------------------------------------------------------------
17 // Enable enhanced mode if it is available. This allows for things like
18 // \d for digit, \s for space, and many more, but it isn't available
19 // everywhere.
20 //----------------------------------------------------------------------
21 #if defined(REG_ENHANCED)
22 #define DEFAULT_COMPILE_FLAGS (REG_ENHANCED|REG_EXTENDED)
23 #else
24 #define DEFAULT_COMPILE_FLAGS (REG_EXTENDED)
25 #endif
26
27 using namespace lldb_private;
28
29 //----------------------------------------------------------------------
30 // Default constructor
31 //----------------------------------------------------------------------
RegularExpression()32 RegularExpression::RegularExpression() :
33 m_re(),
34 m_comp_err (1),
35 m_preg()
36 {
37 memset(&m_preg,0,sizeof(m_preg));
38 }
39
40 //----------------------------------------------------------------------
41 // Constructor that compiles "re" using "flags" and stores the
42 // resulting compiled regular expression into this object.
43 //----------------------------------------------------------------------
RegularExpression(const char * re)44 RegularExpression::RegularExpression(const char* re) :
45 m_re(),
46 m_comp_err (1),
47 m_preg()
48 {
49 memset(&m_preg,0,sizeof(m_preg));
50 Compile(re);
51 }
52
RegularExpression(const RegularExpression & rhs)53 RegularExpression::RegularExpression(const RegularExpression &rhs)
54 {
55 memset(&m_preg,0,sizeof(m_preg));
56 Compile(rhs.GetText());
57 }
58
59 const RegularExpression &
operator =(const RegularExpression & rhs)60 RegularExpression::operator= (const RegularExpression &rhs)
61 {
62 if (&rhs != this)
63 Compile (rhs.GetText());
64 return *this;
65 }
66 //----------------------------------------------------------------------
67 // Destructor
68 //
69 // Any previously compiled regular expression contained in this
70 // object will be freed.
71 //----------------------------------------------------------------------
~RegularExpression()72 RegularExpression::~RegularExpression()
73 {
74 Free();
75 }
76
77 //----------------------------------------------------------------------
78 // Compile a regular expression using the supplied regular
79 // expression text and flags. The compiled regular expression lives
80 // in this object so that it can be readily used for regular
81 // expression matches. Execute() can be called after the regular
82 // expression is compiled. Any previously compiled regular
83 // expression contained in this object will be freed.
84 //
85 // RETURNS
86 // True if the regular expression compiles successfully, false
87 // otherwise.
88 //----------------------------------------------------------------------
89 bool
Compile(const char * re)90 RegularExpression::Compile(const char* re)
91 {
92 Free();
93
94 if (re && re[0])
95 {
96 m_re = re;
97 m_comp_err = ::regcomp (&m_preg, re, DEFAULT_COMPILE_FLAGS);
98 }
99 else
100 {
101 // No valid regular expression
102 m_comp_err = 1;
103 }
104
105 return m_comp_err == 0;
106 }
107
108 //----------------------------------------------------------------------
109 // Execute a regular expression match using the compiled regular
110 // expression that is already in this object against the match
111 // string "s". If any parens are used for regular expression
112 // matches "match_count" should indicate the number of regmatch_t
113 // values that are present in "match_ptr". The regular expression
114 // will be executed using the "execute_flags".
115 //---------------------------------------------------------------------
116 bool
Execute(const char * s,Match * match) const117 RegularExpression::Execute (const char* s, Match *match) const
118 {
119 int err = 1;
120 if (s != NULL && m_comp_err == 0)
121 {
122 if (match)
123 {
124 err = ::regexec (&m_preg,
125 s,
126 match->GetSize(),
127 match->GetData(),
128 0);
129 }
130 else
131 {
132 err = ::regexec (&m_preg,
133 s,
134 0,
135 NULL,
136 0);
137 }
138 }
139
140 if (err != 0)
141 {
142 // The regular expression didn't compile, so clear the matches
143 if (match)
144 match->Clear();
145 return false;
146 }
147 return true;
148 }
149
150 bool
GetMatchAtIndex(const char * s,uint32_t idx,std::string & match_str) const151 RegularExpression::Match::GetMatchAtIndex (const char* s, uint32_t idx, std::string& match_str) const
152 {
153 llvm::StringRef match_str_ref;
154 if (GetMatchAtIndex(s, idx, match_str_ref))
155 {
156 match_str = std::move(match_str_ref.str());
157 return true;
158 }
159 return false;
160 }
161
162 bool
GetMatchAtIndex(const char * s,uint32_t idx,llvm::StringRef & match_str) const163 RegularExpression::Match::GetMatchAtIndex (const char* s, uint32_t idx, llvm::StringRef& match_str) const
164 {
165 if (idx < m_matches.size())
166 {
167 if (m_matches[idx].rm_eo == -1 && m_matches[idx].rm_so == -1)
168 return false;
169
170 if (m_matches[idx].rm_eo == m_matches[idx].rm_so)
171 {
172 // Matched the empty string...
173 match_str = llvm::StringRef();
174 return true;
175 }
176 else if (m_matches[idx].rm_eo > m_matches[idx].rm_so)
177 {
178 match_str = llvm::StringRef (s + m_matches[idx].rm_so, m_matches[idx].rm_eo - m_matches[idx].rm_so);
179 return true;
180 }
181 }
182 return false;
183 }
184
185 bool
GetMatchSpanningIndices(const char * s,uint32_t idx1,uint32_t idx2,llvm::StringRef & match_str) const186 RegularExpression::Match::GetMatchSpanningIndices (const char* s, uint32_t idx1, uint32_t idx2, llvm::StringRef& match_str) const
187 {
188 if (idx1 < m_matches.size() && idx2 < m_matches.size())
189 {
190 if (m_matches[idx1].rm_so == m_matches[idx2].rm_eo)
191 {
192 // Matched the empty string...
193 match_str = llvm::StringRef();
194 return true;
195 }
196 else if (m_matches[idx1].rm_so < m_matches[idx2].rm_eo)
197 {
198 match_str = llvm::StringRef (s + m_matches[idx1].rm_so, m_matches[idx2].rm_eo - m_matches[idx1].rm_so);
199 return true;
200 }
201 }
202 return false;
203 }
204
205
206 //----------------------------------------------------------------------
207 // Returns true if the regular expression compiled and is ready
208 // for execution.
209 //----------------------------------------------------------------------
210 bool
IsValid() const211 RegularExpression::IsValid () const
212 {
213 return m_comp_err == 0;
214 }
215
216 //----------------------------------------------------------------------
217 // Returns the text that was used to compile the current regular
218 // expression.
219 //----------------------------------------------------------------------
220 const char*
GetText() const221 RegularExpression::GetText () const
222 {
223 if (m_re.empty())
224 return NULL;
225 return m_re.c_str();
226 }
227
228 //----------------------------------------------------------------------
229 // Free any contained compiled regular expressions.
230 //----------------------------------------------------------------------
231 void
Free()232 RegularExpression::Free()
233 {
234 if (m_comp_err == 0)
235 {
236 m_re.clear();
237 regfree(&m_preg);
238 // Set a compile error since we no longer have a valid regex
239 m_comp_err = 1;
240 }
241 }
242
243 size_t
GetErrorAsCString(char * err_str,size_t err_str_max_len) const244 RegularExpression::GetErrorAsCString (char *err_str, size_t err_str_max_len) const
245 {
246 if (m_comp_err == 0)
247 {
248 if (err_str && err_str_max_len)
249 *err_str = '\0';
250 return 0;
251 }
252
253 return ::regerror (m_comp_err, &m_preg, err_str, err_str_max_len);
254 }
255
256 bool
operator <(const RegularExpression & rhs) const257 RegularExpression::operator < (const RegularExpression& rhs) const
258 {
259 return (m_re < rhs.m_re);
260 }
261
262