2007-12-30 17:41:49 +01:00
|
|
|
/***************************************************************************
|
|
|
|
|
2011-12-31 03:39:20 +01:00
|
|
|
regexp.c
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2011-12-31 03:39:20 +01:00
|
|
|
(c) 2004 Rob Kudla <pcre-component@kudla.org>
|
2013-08-03 17:38:01 +02:00
|
|
|
(c) 2000-2013 Benoît Minisini <gambas@users.sourceforge.net>
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2011-12-31 03:39:20 +01:00
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2, or (at your option)
|
|
|
|
any later version.
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2011-12-31 03:39:20 +01:00
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2011-12-31 03:39:20 +01:00
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
|
|
MA 02110-1301, USA.
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#define __REGEXP_C
|
|
|
|
|
|
|
|
#include "gb_common.h"
|
|
|
|
|
|
|
|
#include "regexp.h"
|
|
|
|
#include "main.h"
|
|
|
|
|
2013-07-31 23:58:43 +02:00
|
|
|
//#define DEBUG_REPLACE 1
|
|
|
|
|
2013-02-17 17:26:08 +01:00
|
|
|
#define OVECSIZE_INC 99
|
|
|
|
|
2013-07-13 01:57:53 +02:00
|
|
|
DECLARE_METHOD(RegExp_free);
|
|
|
|
|
2013-07-31 23:58:43 +02:00
|
|
|
//---------------------------------------------------------------------------
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
static void compile(void *_object)
|
|
|
|
{
|
|
|
|
int errptr;
|
|
|
|
const char *errstr;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2013-01-30 14:49:59 +01:00
|
|
|
if (!THIS->pattern) {
|
|
|
|
GB.Error("No pattern provided");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-07-11 16:50:13 +02:00
|
|
|
if (THIS->code)
|
|
|
|
free(THIS->code);
|
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
THIS->code = pcre_compile(THIS->pattern, THIS->copts, &errstr, &errptr, NULL);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
if (!THIS->code)
|
2013-02-23 19:16:30 +01:00
|
|
|
{
|
|
|
|
THIS->error = errptr;
|
2011-02-27 10:13:32 +01:00
|
|
|
GB.Error(errstr);
|
2013-02-23 19:16:30 +01:00
|
|
|
}
|
2011-02-27 10:13:32 +01:00
|
|
|
}
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2013-07-31 23:58:43 +02:00
|
|
|
static void exec(void *_object, int lsubject)
|
2011-02-27 10:13:32 +01:00
|
|
|
{
|
2013-02-17 17:26:08 +01:00
|
|
|
int ret;
|
|
|
|
char code[8];
|
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
if (!THIS->code)
|
|
|
|
{
|
|
|
|
GB.Error("No pattern compiled yet");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-07-31 23:58:43 +02:00
|
|
|
if (lsubject < 0)
|
|
|
|
lsubject = GB.StringLength(THIS->subject);
|
|
|
|
|
|
|
|
if (!THIS->subject)
|
2011-02-27 10:13:32 +01:00
|
|
|
{
|
|
|
|
GB.Error("No subject provided");
|
|
|
|
return;
|
|
|
|
}
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2013-02-17 17:26:08 +01:00
|
|
|
for(;;)
|
|
|
|
{
|
|
|
|
ret = pcre_exec(THIS->code,
|
|
|
|
NULL,
|
|
|
|
THIS->subject,
|
2013-07-31 23:58:43 +02:00
|
|
|
lsubject,
|
2013-02-17 17:26:08 +01:00
|
|
|
0,
|
|
|
|
THIS->eopts,
|
|
|
|
THIS->ovector,
|
|
|
|
THIS->ovecsize);
|
|
|
|
|
|
|
|
if (ret > 0)
|
|
|
|
{
|
2013-02-23 19:16:30 +01:00
|
|
|
THIS->error = 0;
|
2013-02-17 17:26:08 +01:00
|
|
|
THIS->count = ret;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (ret < 0)
|
|
|
|
{
|
2013-02-23 19:16:30 +01:00
|
|
|
THIS->error = ret;
|
|
|
|
|
2013-02-17 17:26:08 +01:00
|
|
|
switch (ret)
|
|
|
|
{
|
|
|
|
case PCRE_ERROR_NOMATCH:
|
|
|
|
THIS->count = 0; return;
|
|
|
|
case PCRE_ERROR_NULL:
|
|
|
|
GB.Error("Pattern or subject is null"); return;
|
|
|
|
case PCRE_ERROR_BADOPTION:
|
|
|
|
GB.Error("Unknown option"); return;
|
|
|
|
case PCRE_ERROR_BADMAGIC:
|
|
|
|
case PCRE_ERROR_UNKNOWN_OPCODE:
|
|
|
|
GB.Error("Incorrect PCRE bytecode"); return;
|
|
|
|
case PCRE_ERROR_NOMEMORY:
|
|
|
|
GB.Error("Out of memory"); return;
|
|
|
|
case PCRE_ERROR_BADUTF8:
|
2013-02-24 17:48:32 +01:00
|
|
|
#ifdef PCRE_ERROR_SHORTUTF8
|
2013-02-17 17:26:08 +01:00
|
|
|
case PCRE_ERROR_SHORTUTF8:
|
2013-02-24 17:48:32 +01:00
|
|
|
#endif
|
2013-02-17 17:26:08 +01:00
|
|
|
GB.Error("Bad UTF-8 string"); return;
|
2013-02-24 17:48:32 +01:00
|
|
|
#ifdef PCRE_ERROR_BADUTF8_OFFSET
|
2013-02-17 17:26:08 +01:00
|
|
|
case PCRE_ERROR_BADUTF8_OFFSET:
|
|
|
|
GB.Error("Bad UTF-8 offset"); return;
|
2013-02-24 17:48:32 +01:00
|
|
|
#endif
|
2013-02-17 17:26:08 +01:00
|
|
|
case PCRE_ERROR_INTERNAL:
|
|
|
|
GB.Error("Unexpected internal error"); return;
|
|
|
|
case PCRE_ERROR_BADNEWLINE:
|
|
|
|
GB.Error("Invalid combination of newline options"); return;
|
2013-02-23 19:16:30 +01:00
|
|
|
//case PCRE_ERROR_RECURSELOOP:
|
|
|
|
// GB.Error("Recursion loop detected"); return;
|
2013-02-17 17:26:08 +01:00
|
|
|
//case PCRE_ERROR_JIT_STACKLIMIT:
|
|
|
|
// GB.Error("JIT stack limit reached"); return;
|
|
|
|
default:
|
|
|
|
sprintf(code, "%d", -ret);
|
2013-07-31 23:58:43 +02:00
|
|
|
GB.Error("Unable to run regular expression: error #&1", code);
|
2013-02-17 17:26:08 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
THIS->ovecsize += OVECSIZE_INC;
|
|
|
|
GB.Realloc(POINTER(&THIS->ovector), THIS->ovecsize * sizeof(int));
|
|
|
|
}
|
2011-02-27 10:13:32 +01:00
|
|
|
}
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
static void return_match(void *_object, int index)
|
|
|
|
{
|
2013-12-09 20:04:45 +01:00
|
|
|
int len;
|
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
if (index < 0 || index >= THIS->count)
|
|
|
|
{
|
|
|
|
GB.Error("Out of bounds");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
index *= 2;
|
2013-12-09 20:04:45 +01:00
|
|
|
len = THIS->ovector[index + 1] - THIS->ovector[index];
|
|
|
|
if (len <= 0)
|
2013-12-09 20:06:54 +01:00
|
|
|
GB.ReturnVoidString();
|
2013-12-09 20:04:45 +01:00
|
|
|
else
|
|
|
|
GB.ReturnNewString(&THIS->subject[THIS->ovector[index]], len);
|
2011-02-27 10:13:32 +01:00
|
|
|
}
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2013-07-13 01:57:53 +02:00
|
|
|
bool REGEXP_match(const char *subject, int lsubject, const char *pattern, int lpattern, int coptions, int eoptions)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* The gb.pcre internal routines don't require the GB_BASE to be
|
|
|
|
* initialised by Gambas!
|
|
|
|
*/
|
|
|
|
|
|
|
|
CREGEXP tmp;
|
|
|
|
bool ret = FALSE;
|
|
|
|
|
2015-02-28 16:04:48 +01:00
|
|
|
if (lsubject <= 0)
|
|
|
|
return (lpattern <= 0);
|
|
|
|
|
2013-07-13 01:57:53 +02:00
|
|
|
CLEAR(&tmp);
|
|
|
|
tmp.ovecsize = OVECSIZE_INC;
|
|
|
|
GB.Alloc(POINTER(&tmp.ovector), sizeof(int) * tmp.ovecsize);
|
|
|
|
tmp.copts = coptions;
|
|
|
|
tmp.pattern = GB.NewString(pattern, lpattern);
|
|
|
|
|
|
|
|
compile(&tmp);
|
|
|
|
|
|
|
|
if (tmp.code)
|
|
|
|
{
|
|
|
|
tmp.eopts = eoptions;
|
|
|
|
tmp.subject = GB.NewString(subject, lsubject);
|
|
|
|
|
2013-07-31 23:58:43 +02:00
|
|
|
exec(&tmp, -1);
|
2013-07-13 01:57:53 +02:00
|
|
|
ret = (tmp.ovector[0] != -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
RegExp_free(&tmp, NULL);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-07-31 23:58:43 +02:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
BEGIN_METHOD(RegExp_Compile, GB_STRING pattern; GB_INTEGER coptions)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2008-06-11 12:44:50 +02:00
|
|
|
THIS->copts = VARGOPT(coptions, 0);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2008-06-11 12:44:50 +02:00
|
|
|
GB.FreeString(&THIS->pattern);
|
2010-06-05 01:48:53 +02:00
|
|
|
THIS->pattern = GB.NewString(STRING(pattern), LENGTH(pattern));
|
2011-02-27 10:13:32 +01:00
|
|
|
compile(THIS);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
END_METHOD
|
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
|
|
|
|
BEGIN_METHOD(RegExp_Exec, GB_STRING subject; GB_INTEGER eoptions)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2008-06-11 12:44:50 +02:00
|
|
|
THIS->eopts = VARGOPT(eoptions, 0);
|
|
|
|
|
|
|
|
GB.FreeString(&THIS->subject);
|
2010-06-05 01:48:53 +02:00
|
|
|
THIS->subject = GB.NewString(STRING(subject), LENGTH(subject));
|
2013-07-31 23:58:43 +02:00
|
|
|
exec(THIS, -1);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
END_METHOD
|
|
|
|
|
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
BEGIN_METHOD(RegExp_new, GB_STRING subject; GB_STRING pattern; GB_INTEGER coptions; GB_INTEGER eoptions)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2013-02-17 17:26:08 +01:00
|
|
|
THIS->ovecsize = OVECSIZE_INC;
|
|
|
|
GB.Alloc(POINTER(&THIS->ovector), sizeof(int) * THIS->ovecsize);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
if (MISSING(pattern)) // the user didn't provide a pattern.
|
2008-06-11 12:44:50 +02:00
|
|
|
return;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
THIS->copts = VARGOPT(coptions, 0);
|
|
|
|
THIS->pattern = GB.NewString(STRING(pattern), LENGTH(pattern));
|
2013-07-11 16:50:13 +02:00
|
|
|
THIS->code = NULL;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
compile(THIS);
|
|
|
|
if (!THIS->code) // we didn't get a compiled pattern back.
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (MISSING(subject)) // the user didn't specify any subject text.
|
|
|
|
return;
|
|
|
|
|
|
|
|
THIS->eopts = VARGOPT(eoptions, 0);
|
|
|
|
THIS->subject = GB.NewString(STRING(subject), LENGTH(subject));
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2013-07-31 23:58:43 +02:00
|
|
|
exec(THIS, -1);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
END_METHOD
|
|
|
|
|
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
BEGIN_METHOD_VOID(RegExp_free)
|
|
|
|
|
2013-07-11 16:50:13 +02:00
|
|
|
if (THIS->code)
|
|
|
|
free(THIS->code);
|
2011-02-27 10:13:32 +01:00
|
|
|
GB.FreeString(&THIS->subject);
|
|
|
|
GB.FreeString(&THIS->pattern);
|
|
|
|
GB.Free(POINTER(&THIS->ovector));
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
END_METHOD
|
|
|
|
|
|
|
|
|
2013-07-12 14:43:45 +02:00
|
|
|
BEGIN_METHOD(RegExp_Match, GB_STRING subject; GB_STRING pattern; GB_INTEGER coptions; GB_INTEGER eoptions)
|
2013-07-11 16:50:13 +02:00
|
|
|
|
2013-07-13 01:57:53 +02:00
|
|
|
GB.ReturnBoolean(REGEXP_match(STRING(subject), LENGTH(subject), STRING(pattern), LENGTH(pattern), VARGOPT(coptions, 0), VARGOPT(eoptions, 0)));
|
2013-07-11 16:50:13 +02:00
|
|
|
|
|
|
|
END_METHOD
|
|
|
|
|
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
BEGIN_PROPERTY(RegExp_Pattern)
|
|
|
|
|
|
|
|
GB.ReturnString(THIS->pattern);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
END_PROPERTY
|
|
|
|
|
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
BEGIN_PROPERTY(RegExp_Subject)
|
|
|
|
|
|
|
|
GB.ReturnString(THIS->subject);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
END_PROPERTY
|
|
|
|
|
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
BEGIN_PROPERTY(RegExp_Offset)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
GB.ReturnInteger(THIS->ovector[0]);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
END_PROPERTY
|
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
|
|
|
|
BEGIN_PROPERTY(RegExp_Text)
|
|
|
|
|
|
|
|
if (THIS->count == 0)
|
2011-10-24 21:33:41 +02:00
|
|
|
GB.ReturnVoidString();
|
2011-02-27 10:13:32 +01:00
|
|
|
else
|
|
|
|
return_match(THIS, 0);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
END_PROPERTY
|
|
|
|
|
|
|
|
|
2013-02-23 19:16:30 +01:00
|
|
|
BEGIN_PROPERTY(RegExp_Error)
|
|
|
|
|
|
|
|
GB.ReturnInteger(THIS->error);
|
|
|
|
|
|
|
|
END_PROPERTY
|
|
|
|
|
|
|
|
|
2013-07-31 23:58:43 +02:00
|
|
|
BEGIN_PROPERTY(RegExp_Submatches)
|
|
|
|
|
|
|
|
GB.Deprecated("gb.pcre", "Regexp.Submatches", NULL);
|
|
|
|
GB.ReturnSelf(THIS);
|
|
|
|
|
|
|
|
END_PROPERTY
|
|
|
|
|
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
BEGIN_PROPERTY(RegExp_Submatches_Count)
|
|
|
|
|
|
|
|
GB.ReturnInteger(THIS->count - 1);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
END_PROPERTY
|
|
|
|
|
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
BEGIN_METHOD(RegExp_Submatches_get, GB_INTEGER index)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
int index = VARG(index);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2011-03-12 00:16:26 +01:00
|
|
|
if (index < 0 || index >= THIS->count)
|
2011-02-27 10:13:32 +01:00
|
|
|
{
|
|
|
|
GB.Error("Out of bounds");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
THIS->_submatch = index;
|
|
|
|
RETURN_SELF();
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
END_METHOD
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
BEGIN_PROPERTY(RegExp_Submatch_Text)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2011-03-12 00:16:26 +01:00
|
|
|
return_match(THIS, THIS->_submatch);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
END_PROPERTY
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
BEGIN_PROPERTY(RegExp_Submatch_Offset)
|
|
|
|
|
2011-03-12 00:16:26 +01:00
|
|
|
GB.ReturnInteger(THIS->ovector[2 * THIS->_submatch]);
|
2011-02-27 10:13:32 +01:00
|
|
|
|
|
|
|
END_PROPERTY
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
|
2013-07-31 23:58:43 +02:00
|
|
|
static CREGEXP *_subst_regexp = NULL;
|
|
|
|
|
|
|
|
static void subst_get_submatch(int index, const char **p, int *lp)
|
|
|
|
{
|
|
|
|
if (index <= 0 || index >= _subst_regexp->count)
|
|
|
|
{
|
|
|
|
*p = NULL;
|
|
|
|
*lp = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
index *= 2;
|
|
|
|
*p = &_subst_regexp->subject[_subst_regexp->ovector[index]];
|
|
|
|
*lp = _subst_regexp->ovector[index + 1] - _subst_regexp->ovector[index];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BEGIN_METHOD(RegExp_Replace, GB_STRING subject; GB_STRING pattern; GB_STRING replace; GB_INTEGER coptions; GB_INTEGER eoptions)
|
|
|
|
|
|
|
|
CREGEXP r;
|
|
|
|
char *replace;
|
|
|
|
char *result = NULL;
|
|
|
|
char *subject;
|
|
|
|
int offset;
|
|
|
|
|
|
|
|
CLEAR(&r);
|
|
|
|
r.ovecsize = OVECSIZE_INC;
|
|
|
|
GB.Alloc(POINTER(&r.ovector), sizeof(int) * r.ovecsize);
|
2013-11-17 17:56:56 +01:00
|
|
|
r.copts = VARGOPT(coptions, 0) | PCRE_UNGREEDY;
|
2013-07-31 23:58:43 +02:00
|
|
|
r.pattern = GB.NewString(STRING(pattern), LENGTH(pattern));
|
|
|
|
|
|
|
|
compile(&r);
|
|
|
|
|
|
|
|
if (r.code)
|
|
|
|
{
|
2013-11-17 17:56:56 +01:00
|
|
|
r.eopts = VARGOPT(eoptions, 0);
|
2013-07-31 23:58:43 +02:00
|
|
|
subject = GB.NewString(STRING(subject), LENGTH(subject));
|
|
|
|
|
|
|
|
offset = 0;
|
|
|
|
|
|
|
|
while (offset < LENGTH(subject))
|
|
|
|
{
|
|
|
|
r.subject = &subject[offset];
|
|
|
|
#if DEBUG_REPLACE
|
|
|
|
fprintf(stderr, "\nsubject: (%d) %s\n", offset, r.subject);
|
|
|
|
#endif
|
|
|
|
exec(&r, GB.StringLength(subject) - offset);
|
|
|
|
|
|
|
|
if (r.ovector[0] < 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
_subst_regexp = &r;
|
|
|
|
|
|
|
|
if (r.ovector[0] > 0)
|
|
|
|
{
|
|
|
|
#if DEBUG_REPLACE
|
2014-12-21 15:47:47 +01:00
|
|
|
fprintf(stderr, "add: (%d) %.*s\n", r.ovector[0], r.ovector[0], r.subject);
|
2013-07-31 23:58:43 +02:00
|
|
|
#endif
|
|
|
|
result = GB.AddString(result, r.subject, r.ovector[0]);
|
|
|
|
#if DEBUG_REPLACE
|
|
|
|
fprintf(stderr, "result = %s\n", result);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
replace = GB.SubstString(STRING(replace), LENGTH(replace), (GB_SUBST_CALLBACK)subst_get_submatch);
|
|
|
|
#if DEBUG_REPLACE
|
|
|
|
fprintf(stderr, "replace = %s\n", replace);
|
|
|
|
#endif
|
|
|
|
result = GB.AddString(result, replace, GB.StringLength(replace));
|
|
|
|
#if DEBUG_REPLACE
|
|
|
|
fprintf(stderr, "result = %s\n", result);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
offset += r.ovector[1];
|
2014-12-21 15:47:47 +01:00
|
|
|
|
|
|
|
if (*r.pattern == '^')
|
|
|
|
break;
|
2013-07-31 23:58:43 +02:00
|
|
|
}
|
|
|
|
|
2014-12-21 15:47:47 +01:00
|
|
|
if (offset < LENGTH(subject))
|
|
|
|
result = GB.AddString(result, &subject[offset], LENGTH(subject) - offset);
|
|
|
|
|
2013-07-31 23:58:43 +02:00
|
|
|
_subst_regexp = NULL;
|
|
|
|
|
|
|
|
GB.FreeStringLater(result);
|
|
|
|
#if DEBUG_REPLACE
|
|
|
|
fprintf(stderr, "result = %s\n", result);
|
|
|
|
#endif
|
|
|
|
r.subject = subject;
|
|
|
|
}
|
|
|
|
|
|
|
|
RegExp_free(&r, NULL);
|
|
|
|
|
|
|
|
GB.ReturnString(result);
|
|
|
|
|
|
|
|
END_METHOD
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2007-12-30 17:41:49 +01:00
|
|
|
GB_DESC CRegexpDesc[] =
|
|
|
|
{
|
2013-07-31 23:58:43 +02:00
|
|
|
GB_DECLARE("RegExp", sizeof(CREGEXP)),
|
2011-02-27 10:13:32 +01:00
|
|
|
|
|
|
|
GB_METHOD("_new", NULL, RegExp_new, "[(Subject)s(Pattern)s(CompileOptions)i(ExecOptions)i]"),
|
|
|
|
GB_METHOD("_free", NULL, RegExp_free, NULL),
|
|
|
|
|
|
|
|
GB_METHOD("Compile", NULL, RegExp_Compile, "(Pattern)s[(CompileOptions)i]"),
|
|
|
|
GB_METHOD("Exec", NULL, RegExp_Exec, "(Subject)s[(ExecOptions)i]"),
|
2013-07-11 16:50:13 +02:00
|
|
|
|
2013-07-12 14:43:45 +02:00
|
|
|
GB_STATIC_METHOD("Match", "b", RegExp_Match, "(Subject)s(Pattern)s[(CompileOptions)i(ExecOptions)i]"),
|
2013-07-31 23:58:43 +02:00
|
|
|
GB_STATIC_METHOD("Replace", "s", RegExp_Replace, "(Subject)s(Pattern)s(Replace)s[(CompileOptions)i(ExecOptions)i]"),
|
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
GB_CONSTANT("Caseless", "i", PCRE_CASELESS),
|
|
|
|
GB_CONSTANT("MultiLine", "i", PCRE_MULTILINE),
|
|
|
|
GB_CONSTANT("DotAll", "i", PCRE_DOTALL),
|
|
|
|
GB_CONSTANT("Extended", "i", PCRE_EXTENDED),
|
|
|
|
GB_CONSTANT("Anchored", "i", PCRE_ANCHORED),
|
|
|
|
GB_CONSTANT("DollarEndOnly", "i", PCRE_DOLLAR_ENDONLY),
|
|
|
|
GB_CONSTANT("Extra", "i", PCRE_EXTRA),
|
|
|
|
GB_CONSTANT("NotBOL", "i", PCRE_NOTBOL),
|
|
|
|
GB_CONSTANT("NotEOL", "i", PCRE_NOTEOL),
|
|
|
|
GB_CONSTANT("Ungreedy", "i", PCRE_UNGREEDY),
|
|
|
|
GB_CONSTANT("NotEmpty", "i", PCRE_NOTEMPTY),
|
|
|
|
GB_CONSTANT("UTF8", "i", PCRE_UTF8),
|
|
|
|
GB_CONSTANT("NoAutoCapture", "i", PCRE_NO_AUTO_CAPTURE),
|
|
|
|
GB_CONSTANT("NoUTF8Check", "i", PCRE_NO_UTF8_CHECK),
|
|
|
|
GB_CONSTANT("NoMatch", "i", PCRE_ERROR_NOMATCH),
|
|
|
|
GB_CONSTANT("Null", "i", PCRE_ERROR_NULL),
|
|
|
|
GB_CONSTANT("BadOption", "i", PCRE_ERROR_BADOPTION),
|
|
|
|
GB_CONSTANT("BadMagic", "i", PCRE_ERROR_BADMAGIC),
|
|
|
|
GB_CONSTANT("UnknownNode", "i", PCRE_ERROR_UNKNOWN_NODE),
|
|
|
|
GB_CONSTANT("NoMemory", "i", PCRE_ERROR_NOMEMORY),
|
|
|
|
GB_CONSTANT("NoSubstring", "i", PCRE_ERROR_NOSUBSTRING),
|
|
|
|
GB_CONSTANT("MatchLimit", "i", PCRE_ERROR_MATCHLIMIT),
|
|
|
|
GB_CONSTANT("Callout", "i", PCRE_ERROR_CALLOUT),
|
|
|
|
GB_CONSTANT("BadUTF8", "i", PCRE_ERROR_BADUTF8),
|
2007-12-30 17:41:49 +01:00
|
|
|
#if (((PCRE_MAJOR == 4) && (PCRE_MINOR < 5)) || (PCRE_MAJOR < 4))
|
2011-02-27 10:13:32 +01:00
|
|
|
GB_CONSTANT("BadUTF8Offset", "i", 65535), /* PCRE_ERROR_BADUTF8_OFFSET not defined < 4.5 */
|
2007-12-30 17:41:49 +01:00
|
|
|
#else
|
2011-02-27 10:13:32 +01:00
|
|
|
GB_CONSTANT("BadUTF8Offset", "i", PCRE_ERROR_BADUTF8_OFFSET),
|
2007-12-30 17:41:49 +01:00
|
|
|
#endif
|
|
|
|
|
2013-07-31 23:58:43 +02:00
|
|
|
GB_PROPERTY_READ("SubMatches", ".Regexp.Submatches", RegExp_Submatches),
|
2011-02-27 10:13:32 +01:00
|
|
|
|
|
|
|
GB_PROPERTY_READ("Text", "s", RegExp_Text), /* this is the string matched by the entire pattern */
|
|
|
|
GB_PROPERTY_READ("Offset", "i", RegExp_Offset), /* this is the string matched by the entire pattern */
|
|
|
|
GB_PROPERTY_READ("Pattern", "s", RegExp_Pattern),
|
|
|
|
GB_PROPERTY_READ("Subject", "s", RegExp_Subject),
|
2013-02-23 19:16:30 +01:00
|
|
|
GB_PROPERTY_READ("Error", "i", RegExp_Error),
|
2011-02-27 10:13:32 +01:00
|
|
|
|
2013-07-31 23:58:43 +02:00
|
|
|
GB_METHOD("_get", ".Regexp.Submatch", RegExp_Submatches_get, "(Index)i"),
|
|
|
|
GB_PROPERTY_READ("Count", "i", RegExp_Submatches_Count),
|
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
GB_END_DECLARE
|
2007-12-30 17:41:49 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
GB_DESC CRegexpSubmatchesDesc[] =
|
|
|
|
{
|
2011-08-21 23:46:20 +02:00
|
|
|
GB_DECLARE(".Regexp.Submatches", 0), GB_VIRTUAL_CLASS(),
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2011-08-21 23:46:20 +02:00
|
|
|
GB_METHOD("_get", ".Regexp.Submatch", RegExp_Submatches_get, "(Index)i"),
|
2011-02-27 10:13:32 +01:00
|
|
|
GB_PROPERTY_READ("Count", "i", RegExp_Submatches_Count),
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
GB_END_DECLARE
|
2007-12-30 17:41:49 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
GB_DESC CRegexpSubmatchDesc[] =
|
|
|
|
{
|
2011-08-21 23:46:20 +02:00
|
|
|
GB_DECLARE(".Regexp.Submatch", 0), GB_VIRTUAL_CLASS(),
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
GB_PROPERTY_READ("Offset", "i", RegExp_Submatch_Offset),
|
|
|
|
GB_PROPERTY_READ("Text", "s", RegExp_Submatch_Text),
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2011-02-27 10:13:32 +01:00
|
|
|
GB_END_DECLARE
|
2007-12-30 17:41:49 +01:00
|
|
|
};
|
|
|
|
|