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