a39b641df2a08ff8a6bbcdf12a2b7bbc5f5fcd01
[WebKit-https.git] / JavaScriptCore / kjs / regexp.cpp
1 // -*- c-basic-offset: 2 -*-
2 /*
3  *  This file is part of the KDE libraries
4  *  Copyright (C) 1999-2001,2004 Harri Porten (porten@kde.org)
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public
8  *  License as published by the Free Software Foundation; either
9  *  version 2 of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #include "config.h"
23 #include "regexp.h"
24
25 #include "lexer.h"
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <wtf/Assertions.h>
30
31 namespace KJS {
32
33 RegExp::RegExp(const UString &p, int flags)
34   : m_flags(flags), m_constructionError(0), m_numSubPatterns(0)
35 {
36 #if !USE(POSIX_REGEX)
37
38   int options = 0;
39   if (flags & IgnoreCase)
40     options |= JS_REGEXP_CASELESS;
41   if (flags & Multiline)
42     options |= JS_REGEXP_MULTILINE;
43
44   const char* errorMessage;
45   m_regex = jsRegExpCompile(reinterpret_cast<const JSRegExpChar*>(p.data()), p.size(), options,
46     &m_numSubPatterns, &errorMessage);
47   if (!m_regex) {
48     m_constructionError = strdup(errorMessage);
49     return;
50   }
51
52 #else /* USE(POSIX_REGEX) */
53
54   int regflags = 0;
55 #ifdef REG_EXTENDED
56   regflags |= REG_EXTENDED;
57 #endif
58 #ifdef REG_ICASE
59   if (flags & IgnoreCase)
60     regflags |= REG_ICASE;
61 #endif
62
63   //NOTE: Multiline is not feasible with POSIX regex.
64   //if ( f & Multiline )
65   //    ;
66   // Note: the Global flag is already handled by RegExpProtoFunc::execute
67
68   // FIXME: support \u Unicode escapes.
69
70   int errorCode = regcomp(&m_regex, p.ascii(), regflags);
71   if (errorCode != 0) {
72     char errorMessage[80];
73     regerror(errorCode, &m_regex, errorMessage, sizeof errorMessage);
74     m_constructionError = strdup(errorMessage);
75   }
76
77 #endif
78 }
79
80 RegExp::~RegExp()
81 {
82 #if !USE(POSIX_REGEX)
83   jsRegExpFree(m_regex);
84 #else
85   /* TODO: is this really okay after an error ? */
86   regfree(&m_regex);
87 #endif
88   free(m_constructionError);
89 }
90
91 int RegExp::match(const UString& s, int i, OwnArrayPtr<int>* ovector)
92 {
93   if (i < 0)
94     i = 0;
95   if (ovector)
96     ovector->clear();
97
98   if (i > s.size() || s.isNull())
99     return -1;
100
101 #if !USE(POSIX_REGEX)
102
103   if (!m_regex)
104     return -1;
105
106   // Set up the offset vector for the result.
107   // First 2/3 used for result, the last third used by PCRE.
108   int* offsetVector;
109   int offsetVectorSize;
110   int fixedSizeOffsetVector[3];
111   if (!ovector) {
112     offsetVectorSize = 3;
113     offsetVector = fixedSizeOffsetVector;
114   } else {
115     offsetVectorSize = (m_numSubPatterns + 1) * 3;
116     offsetVector = new int [offsetVectorSize];
117     ovector->set(offsetVector);
118   }
119
120   int numMatches = jsRegExpExecute(m_regex, reinterpret_cast<const JSRegExpChar*>(s.data()), s.size(), i, offsetVector, offsetVectorSize);
121
122   if (numMatches < 0) {
123 #ifndef NDEBUG
124     if (numMatches != JS_REGEXP_ERROR_NOMATCH)
125       fprintf(stderr, "KJS: pcre_exec() failed with result %d\n", numMatches);
126 #endif
127     if (ovector)
128       ovector->clear();
129     return -1;
130   }
131
132   return offsetVector[0];
133
134 #else
135
136   const unsigned maxMatch = 10;
137   regmatch_t rmatch[maxMatch];
138
139   char *str = strdup(s.ascii()); // TODO: why ???
140   if (regexec(&m_regex, str + i, maxMatch, rmatch, 0)) {
141     free(str);
142     return UString::null();
143   }
144   free(str);
145
146   if (!ovector) {
147     *pos = rmatch[0].rm_so + i;
148     return s.substr(rmatch[0].rm_so + i, rmatch[0].rm_eo - rmatch[0].rm_so);
149   }
150
151   // map rmatch array to ovector used in PCRE case
152   m_numSubPatterns = 0;
153   for(unsigned j = 1; j < maxMatch && rmatch[j].rm_so >= 0 ; j++)
154       m_numSubPatterns++;
155   int ovecsize = (m_numSubPatterns+1)*3; // see above
156   *ovector = new int[ovecsize];
157   for (unsigned j = 0; j < m_numSubPatterns + 1; j++) {
158     if (j>maxMatch)
159       break;
160     (*ovector)[2*j] = rmatch[j].rm_so + i;
161     (*ovector)[2*j+1] = rmatch[j].rm_eo + i;
162   }
163
164   *pos = (*ovector)[0];
165   return s.substr((*ovector)[0], (*ovector)[1] - (*ovector)[0]);
166
167 #endif
168 }
169
170 } // namespace KJS