kjs Library: regexp.cpp Source File (kjs Library)

| # kjs Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# regexp.cpp

    00001 // -*- c-basic-offset: 2 -*-
    00002 /*
    00003  *  This file is part of the KDE libraries
    00004  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
    00005  *
    00006  *  This library is free software; you can redistribute it and/or
    00007  *  modify it under the terms of the GNU Lesser General Public
    00008  *  License as published by the Free Software Foundation; either
    00009  *  version 2 of the License, or (at your option) any later version.
    00010  *
    00011  *  This library is distributed in the hope that it will be useful,
    00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00014  *  Lesser General Public License for more details.
    00015  *
    00016  *  You should have received a copy of the GNU Lesser General Public
    00017  *  License along with this library; if not, write to the Free Software
    00018  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    00019  *
    00020  */
    00021
    00022 #include "regexp.h"
    00023
    00024 #include "lexer.h"
    00025 #include <stdio.h>
    00026 #include <stdlib.h>
    00027 #include <string.h>
    00028
    00029 using namespace KJS;
    00030
    00031 RegExp::RegExp(const UString &p, int f)
    00032   : pat(p), flgs(f), m_notEmpty(false), valid(true)
    00033 {
    00034   nrSubPatterns = 0; // determined in match() with POSIX regex.
    00035
    00036   // JS regexps can contain Unicode escape sequences (\uxxxx) which
    00037   // are rather uncommon elsewhere. As our regexp libs don't understand
    00038   // them we do the unescaping ourselves internally.
    00039   UString intern;
    00040   if (p.find('\\') >= 0) {
    00041     bool escape = false;
    00042     for (int i = 0; i < p.size(); ++i) {
    00043       UChar c = p[i];
    00044       if (escape) {
    00045         escape = false;
    00046         // we only care about \uxxxx
    00047         if (c == 'u' && i + 4 < p.size()) {
    00048           int c0 = p[i+1].unicode();
    00049           int c1 = p[i+2].unicode();
    00050           int c2 = p[i+3].unicode();
    00051           int c3 = p[i+4].unicode();
    00052           if (Lexer::isHexDigit(c0) && Lexer::isHexDigit(c1) &&
    00053               Lexer::isHexDigit(c2) && Lexer::isHexDigit(c3)) {
    00054             c = Lexer::convertUnicode(c0, c1, c2, c3);
    00055             intern += UString(&c, 1);
    00056             i += 4;
    00057             continue;
    00058           }
    00059         }
    00060         intern += UString('\\');
    00061         intern += UString(&c, 1);
    00062       } else {
    00063         if (c == '\\')
    00064           escape = true;
    00065         else
    00066           intern += UString(&c, 1);
    00067       }
    00068     }
    00069   } else {
    00070     intern = p;
    00071   }
    00072
    00073 #ifdef HAVE_PCREPOSIX
    00074   int pcreflags = 0;
    00075   const char *perrormsg;
    00076   int errorOffset;
    00077
    00078   if (flgs & IgnoreCase)
    00079     pcreflags |= PCRE_CASELESS;
    00080
    00081   if (flgs & Multiline)
    00082     pcreflags |= PCRE_MULTILINE;
    00083
    00084   pcregex = pcre_compile(intern.ascii(), pcreflags,
    00085              &perrormsg, &errorOffset, NULL);
    00086   if (!pcregex) {
    00087 #ifndef NDEBUG
    00088     fprintf(stderr, "KJS: pcre_compile() failed with '%s'\n", perrormsg);
    00089 #endif
    00090     valid = false;
    00091     return;
    00092   }
    00093
    00094 #ifdef PCRE_INFO_CAPTURECOUNT
    00095   // Get number of subpatterns that will be returned
    00096   int rc = pcre_fullinfo( pcregex, NULL, PCRE_INFO_CAPTURECOUNT, &nrSubPatterns);
    00097   if (rc != 0)
    00098 #endif
    00099     nrSubPatterns = 0; // fallback. We always need the first pair of offsets.
    00100
    00101 #else /* HAVE_PCREPOSIX */
    00102
    00103   int regflags = 0;
    00104 #ifdef REG_EXTENDED
    00105   regflags |= REG_EXTENDED;
    00106 #endif
    00107 #ifdef REG_ICASE
    00108   if ( f & IgnoreCase )
    00109     regflags |= REG_ICASE;
    00110 #endif
    00111
    00112   //NOTE: Multiline is not feasible with POSIX regex.
    00113   //if ( f & Multiline )
    00114   //    ;
    00115   // Note: the Global flag is already handled by RegExpProtoFunc::execute
    00116
    00117   if (regcomp(&preg, intern.ascii(), regflags) == 0)
    00118     regcomp(&preg, "", regflags);
    00119   else
    00120     valid = false;
    00121 #endif
    00122 }
    00123
    00124 RegExp::~RegExp()
    00125 {
    00126 #ifdef HAVE_PCREPOSIX
    00127   if (pcregex)
    00128     pcre_free(pcregex);
    00129 #else
    00130   /* TODO: is this really okay after an error ? */
    00131   regfree(&preg);
    00132 #endif
    00133 }
    00134
    00135 UString RegExp::match(const UString &s, int i, int *pos, int **ovector)
    00136 {
    00137   if (i < 0)
    00138     i = 0;
    00139   if (ovector)
    00140     *ovector = 0L;
    00141   int dummyPos;
    00142   if (!pos)
    00143     pos = &dummyPos;
    00144   *pos = -1;
    00145   if (i > s.size() || s.isNull())
    00146     return UString::null;
    00147
    00148 #ifdef HAVE_PCREPOSIX
    00149   CString buffer(s.cstring());
    00150   int bufferSize = buffer.size();
    00151   int ovecsize = (nrSubPatterns+1)*3; // see pcre docu
    00152   if (ovector) *ovector = new int[ovecsize];
    00153   if (!pcregex)
    00154     return UString::null;
    00155
    00156   if (pcre_exec(pcregex, NULL, buffer.c_str(), bufferSize, i,
    00157                 m_notEmpty ? (PCRE_NOTEMPTY | PCRE_ANCHORED) : 0, // see man pcretest
    00158                 ovector ? *ovector : 0L, ovecsize) == PCRE_ERROR_NOMATCH)
    00159   {
    00160     // Failed to match.
    00161     if ((flgs & Global) && m_notEmpty && ovector)
    00162     {
    00163       // We set m_notEmpty ourselves, to look for a non-empty match
    00164       // (see man pcretest or pcretest.c for details).
    00165       // So we don't stop here, we want to try again at i+1.
    00166 #ifndef NDEBUG
    00167       fprintf(stderr, "No match after m_notEmpty. +1 and keep going.\n");
    00168 #endif
    00169       m_notEmpty = 0;
    00170       if (pcre_exec(pcregex, NULL, buffer.c_str(), bufferSize, i+1, 0,
    00171                     ovector ? *ovector : 0L, ovecsize) == PCRE_ERROR_NOMATCH)
    00172         return UString::null;
    00173     }
    00174     else // done
    00175       return UString::null;
    00176   }
    00177
    00178   // Got a match, proceed with it.
    00179
    00180   if (!ovector)
    00181     return UString::null; // don't rely on the return value if you pass ovector==0
    00182 #else
    00183   const uint maxMatch = 10;
    00184   regmatch_t rmatch[maxMatch];
    00185
    00186   char *str = strdup(s.ascii()); // TODO: why ???
    00187   if (regexec(&preg, str + i, maxMatch, rmatch, 0)) {
    00188     free(str);
    00189     return UString::null;
    00190   }
    00191   free(str);
    00192
    00193   if (!ovector) {
    00194     *pos = rmatch[0].rm_so + i;
    00195     return s.substr(rmatch[0].rm_so + i, rmatch[0].rm_eo - rmatch[0].rm_so);
    00196   }
    00197
    00198   // map rmatch array to ovector used in PCRE case
    00199   nrSubPatterns = 0;
    00200   for(uint j = 1; j < maxMatch && rmatch[j].rm_so >= 0 ; j++)
    00201       nrSubPatterns++;
    00202   int ovecsize = (nrSubPatterns+1)*3; // see above
    00203   *ovector = new int[ovecsize];
    00204   for (uint j = 0; j < nrSubPatterns + 1; j++) {
    00205     if (j>maxMatch)
    00206       break;
    00207     (*ovector)[2*j] = rmatch[j].rm_so + i;
    00208     (*ovector)[2*j+1] = rmatch[j].rm_eo + i;
    00209   }
    00210 #endif
    00211
    00212   *pos = (*ovector)[0];
    00213 #ifdef HAVE_PCREPOSIX  // TODO check this stuff in non-pcre mode
    00214   if ( *pos == (*ovector)[1] && (flgs & Global) )
    00215   {
    00216     // empty match, next try will be with m_notEmpty=true
    00217     m_notEmpty=true;
    00218   }
    00219 #endif
    00220   return s.substr((*ovector)[0], (*ovector)[1] - (*ovector)[0]);
    00221 }
    00222
    00223 #if 0 // unused
    00224 bool RegExp::test(const UString &s, int)
    00225 {
    00226 #ifdef HAVE_PCREPOSIX
    00227   int ovector[300];
    00228   CString buffer(s.cstring());
    00229
    00230   if (s.isNull() ||
    00231       pcre_exec(pcregex, NULL, buffer.c_str(), buffer.size(), 0,
    00232         0, ovector, 300) == PCRE_ERROR_NOMATCH)
    00233     return false;
    00234   else
    00235     return true;
    00236
    00237 #else
    00238
    00239   char *str = strdup(s.ascii());
    00240   int r = regexec(&preg, str, 0, 0, 0);
    00241   free(str);
    00242
    00243   return r == 0;
    00244 #endif
    00245 }
    00246 #endif

This file is part of the documentation for kjs Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:23:07 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003