2 * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2013, Rene Gollent, rene@gollent.com.
4 * Distributed under the terms of the MIT License.
16 #include <Referenceable.h>
19 // #pragma mark - RegExp::Data
22 struct RegExp::Data
: public BReferenceable
{
23 Data(const char* pattern
, PatternType patternType
, bool caseSensitive
)
27 // convert the shell pattern to a regular expression
28 BString patternString
;
29 if (patternType
== PATTERN_TYPE_WILDCARD
) {
30 while (*pattern
!= '\0') {
37 patternString
+= ".*";
41 // find the matching ']' first
42 const char* end
= pattern
;
51 // Empty bracket expression. It will never match
52 // anything. Strictly speaking this is not
53 // considered an error, but we handle it like one.
60 // We need to avoid "[." ... ".]", "[=" ... "=]", and
61 // "[:" ... ":]" sequences, since those have special
62 // meaning in regular expressions. If we encounter
63 // a '[' followed by either of '.', '=', or ':', we
64 // replace the '[' by "[.[.]".
65 while (pattern
< end
) {
67 if (c
== '[' && pattern
< end
) {
72 patternString
+= "[.[.]";
86 // Quotes the next character. Works the same way for
87 // regular expressions.
88 if (*pattern
== '\0') {
93 patternString
+= '\\';
94 patternString
+= *pattern
++;
107 patternString
+= '\\';
115 pattern
= patternString
.String();
118 int flags
= REG_EXTENDED
;
122 fError
= regcomp(&fCompiledExpression
, pattern
, flags
);
128 regfree(&fCompiledExpression
);
136 const regex_t
* CompiledExpression() const
138 return &fCompiledExpression
;
143 regex_t fCompiledExpression
;
147 // #pragma mark - RegExp::MatchResultData
150 struct RegExp::MatchResultData
: public BReferenceable
{
151 MatchResultData(const regex_t
* compiledExpression
, const char* string
)
157 // fMatchCount is always set to the number of matching groups in the
158 // expression (or 0 if an error occured). Some of the "matches" in
159 // the array may still point to the (-1,-1) range if they don't
160 // actually match anything.
161 fMatchCount
= compiledExpression
->re_nsub
+ 1;
162 fMatches
= new regmatch_t
[fMatchCount
];
163 if (regexec(compiledExpression
, string
, fMatchCount
, fMatches
, 0)
176 size_t MatchCount() const
181 const regmatch_t
* Matches() const
188 regmatch_t
* fMatches
;
192 // #pragma mark - RegExp
202 RegExp::RegExp(const char* pattern
, PatternType patternType
,
207 SetPattern(pattern
, patternType
, caseSensitive
);
211 RegExp::RegExp(const RegExp
& other
)
216 fData
->AcquireReference();
223 fData
->ReleaseReference();
228 RegExp::SetPattern(const char* pattern
, PatternType patternType
,
232 fData
->ReleaseReference();
236 Data
* newData
= new(std::nothrow
) Data(pattern
, patternType
, caseSensitive
);
240 BReference
<Data
> dataReference(newData
, true);
241 if (!newData
->IsValid())
244 fData
= dataReference
.Detach();
250 RegExp::Match(const char* string
) const
253 return MatchResult();
256 new(std::nothrow
) MatchResultData(fData
->CompiledExpression(),
262 RegExp::operator=(const RegExp
& other
)
265 fData
->ReleaseReference();
270 fData
->AcquireReference();
276 // #pragma mark - RegExp::MatchResult
279 RegExp::MatchResult::MatchResult()
286 RegExp::MatchResult::MatchResult(MatchResultData
* data
)
293 RegExp::MatchResult::MatchResult(const MatchResult
& other
)
298 fData
->AcquireReference();
302 RegExp::MatchResult::~MatchResult()
305 fData
->ReleaseReference();
310 RegExp::MatchResult::HasMatched() const
312 return fData
!= NULL
&& fData
->MatchCount() > 0;
317 RegExp::MatchResult::StartOffset() const
319 return fData
!= NULL
&& fData
->MatchCount() > 0
320 ? fData
->Matches()[0].rm_so
: 0;
325 RegExp::MatchResult::EndOffset() const
327 return fData
!= NULL
&& fData
->MatchCount() > 0
328 ? fData
->Matches()[0].rm_eo
: 0;
333 RegExp::MatchResult::GroupCount() const
338 size_t matchCount
= fData
->MatchCount();
339 return matchCount
> 0 ? matchCount
- 1 : 0;
344 RegExp::MatchResult::GroupStartOffsetAt(size_t index
) const
346 return fData
!= NULL
&& fData
->MatchCount() > index
+ 1
347 ? fData
->Matches()[index
+ 1].rm_so
: 0;
352 RegExp::MatchResult::GroupEndOffsetAt(size_t index
) const
354 return fData
!= NULL
&& fData
->MatchCount() > index
+ 1
355 ? fData
->Matches()[index
+ 1].rm_eo
: 0;
360 RegExp::MatchResult::operator=(const MatchResult
& other
)
363 fData
->ReleaseReference();
368 fData
->AcquireReference();