• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (C) 1999-2001, 2004 Harri Porten (porten@kde.org)
3  *  Copyright (c) 2007, 2008 Apple Inc. All rights reserved.
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this library; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  *
19  */
20 
21 #include "config.h"
22 #include "RegExp.h"
23 
24 #include "JIT.h"
25 #include "Lexer.h"
26 #include "WRECGenerator.h"
27 #include <pcre/pcre.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <wtf/Assertions.h>
32 #include <wtf/OwnArrayPtr.h>
33 
34 namespace JSC {
35 
36 #if ENABLE(WREC)
37 using namespace WREC;
38 #endif
39 
RegExp(JSGlobalData * globalData,const UString & pattern)40 inline RegExp::RegExp(JSGlobalData* globalData, const UString& pattern)
41     : m_pattern(pattern)
42     , m_flagBits(0)
43     , m_regExp(0)
44     , m_constructionError(0)
45     , m_numSubpatterns(0)
46 {
47 #if ENABLE(WREC)
48     m_wrecFunction = Generator::compileRegExp(globalData, pattern, &m_numSubpatterns, &m_constructionError, m_executablePool);
49     if (m_wrecFunction || m_constructionError)
50         return;
51     // Fall through to non-WREC case.
52 #else
53     UNUSED_PARAM(globalData);
54 #endif
55     m_regExp = jsRegExpCompile(reinterpret_cast<const UChar*>(pattern.data()), pattern.size(),
56         JSRegExpDoNotIgnoreCase, JSRegExpSingleLine, &m_numSubpatterns, &m_constructionError);
57 }
58 
create(JSGlobalData * globalData,const UString & pattern)59 PassRefPtr<RegExp> RegExp::create(JSGlobalData* globalData, const UString& pattern)
60 {
61     return adoptRef(new RegExp(globalData, pattern));
62 }
63 
RegExp(JSGlobalData * globalData,const UString & pattern,const UString & flags)64 inline RegExp::RegExp(JSGlobalData* globalData, const UString& pattern, const UString& flags)
65     : m_pattern(pattern)
66     , m_flags(flags)
67     , m_flagBits(0)
68     , m_regExp(0)
69     , m_constructionError(0)
70     , m_numSubpatterns(0)
71 {
72     // NOTE: The global flag is handled on a case-by-case basis by functions like
73     // String::match and RegExpObject::match.
74     if (flags.find('g') != -1)
75         m_flagBits |= Global;
76 
77     // FIXME: Eliminate duplication by adding a way ask a JSRegExp what its flags are?
78     JSRegExpIgnoreCaseOption ignoreCaseOption = JSRegExpDoNotIgnoreCase;
79     if (flags.find('i') != -1) {
80         m_flagBits |= IgnoreCase;
81         ignoreCaseOption = JSRegExpIgnoreCase;
82     }
83 
84     JSRegExpMultilineOption multilineOption = JSRegExpSingleLine;
85     if (flags.find('m') != -1) {
86         m_flagBits |= Multiline;
87         multilineOption = JSRegExpMultiline;
88     }
89 
90 #if ENABLE(WREC)
91     m_wrecFunction = Generator::compileRegExp(globalData, pattern, &m_numSubpatterns, &m_constructionError, m_executablePool, (m_flagBits & IgnoreCase), (m_flagBits & Multiline));
92     if (m_wrecFunction || m_constructionError)
93         return;
94     // Fall through to non-WREC case.
95 #else
96     UNUSED_PARAM(globalData);
97 #endif
98     m_regExp = jsRegExpCompile(reinterpret_cast<const UChar*>(pattern.data()), pattern.size(),
99         ignoreCaseOption, multilineOption, &m_numSubpatterns, &m_constructionError);
100 }
101 
create(JSGlobalData * globalData,const UString & pattern,const UString & flags)102 PassRefPtr<RegExp> RegExp::create(JSGlobalData* globalData, const UString& pattern, const UString& flags)
103 {
104     return adoptRef(new RegExp(globalData, pattern, flags));
105 }
106 
~RegExp()107 RegExp::~RegExp()
108 {
109     jsRegExpFree(m_regExp);
110 }
111 
match(const UString & s,int startOffset,OwnArrayPtr<int> * ovector)112 int RegExp::match(const UString& s, int startOffset, OwnArrayPtr<int>* ovector)
113 {
114     if (startOffset < 0)
115         startOffset = 0;
116     if (ovector)
117         ovector->clear();
118 
119     if (startOffset > s.size() || s.isNull())
120         return -1;
121 
122 #if ENABLE(WREC)
123     if (m_wrecFunction) {
124         int offsetVectorSize = (m_numSubpatterns + 1) * 2;
125         int* offsetVector = new int [offsetVectorSize];
126         for (int j = 0; j < offsetVectorSize; ++j)
127             offsetVector[j] = -1;
128 
129         OwnArrayPtr<int> nonReturnedOvector;
130         if (!ovector)
131             nonReturnedOvector.set(offsetVector);
132         else
133             ovector->set(offsetVector);
134 
135         int result = m_wrecFunction(s.data(), startOffset, s.size(), offsetVector);
136 
137         if (result < 0) {
138 #ifndef NDEBUG
139             // TODO: define up a symbol, rather than magic -1
140             if (result != -1)
141                 fprintf(stderr, "jsRegExpExecute failed with result %d\n", result);
142 #endif
143             if (ovector)
144                 ovector->clear();
145         }
146         return result;
147     } else
148 #endif
149     if (m_regExp) {
150         // Set up the offset vector for the result.
151         // First 2/3 used for result, the last third used by PCRE.
152         int* offsetVector;
153         int offsetVectorSize;
154         int fixedSizeOffsetVector[3];
155         if (!ovector) {
156             offsetVectorSize = 3;
157             offsetVector = fixedSizeOffsetVector;
158         } else {
159             offsetVectorSize = (m_numSubpatterns + 1) * 3;
160             offsetVector = new int [offsetVectorSize];
161             ovector->set(offsetVector);
162         }
163 
164         int numMatches = jsRegExpExecute(m_regExp, reinterpret_cast<const UChar*>(s.data()), s.size(), startOffset, offsetVector, offsetVectorSize);
165 
166         if (numMatches < 0) {
167 #ifndef NDEBUG
168             if (numMatches != JSRegExpErrorNoMatch)
169                 fprintf(stderr, "jsRegExpExecute failed with result %d\n", numMatches);
170 #endif
171             if (ovector)
172                 ovector->clear();
173             return -1;
174         }
175 
176         return offsetVector[0];
177     }
178 
179     return -1;
180 }
181 
182 } // namespace JSC
183