@ -10,12 +10,15 @@ elif builder.target_platform == 'mac':
|
||||
elif builder.target_platform == 'windows':
|
||||
binary.compiler.postlink += [binary.Dep('lib_win\\pcre.lib')]
|
||||
|
||||
binary.compiler.defines += ['PCRE_STATIC']
|
||||
|
||||
binary.compiler.defines += [
|
||||
'PCRE_STATIC',
|
||||
'HAVE_STDINT_H',
|
||||
]
|
||||
binary.sources = [
|
||||
'sdk/amxxmodule.cpp',
|
||||
'module.cpp',
|
||||
'CRegEx.cpp',
|
||||
'utils.cpp',
|
||||
]
|
||||
|
||||
AMXX.modules += [builder.Add(binary)]
|
||||
|
@ -1,7 +1,41 @@
|
||||
/* AMX Mod X
|
||||
* Regular Expressions Module
|
||||
*
|
||||
* by the AMX Mod X Development Team
|
||||
*
|
||||
* This file is part of AMX Mod X.
|
||||
*
|
||||
*
|
||||
* 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 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* In addition, as a special exception, the author gives permission to
|
||||
* link the code of this program with the Half-Life Game Engine ("HL
|
||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||
* respects for all of the code used other than the HL Engine and MODs
|
||||
* from Valve. If you modify this file, you may extend this exception
|
||||
* to your version of the file, but you are not obligated to do so. If
|
||||
* you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
*/
|
||||
#include "amxxmodule.h"
|
||||
#include "pcre.h"
|
||||
#include "CRegEx.h"
|
||||
#include <string.h>
|
||||
#include "amxxmodule.h"
|
||||
#include <ctype.h>
|
||||
#include "utils.h"
|
||||
|
||||
RegEx::RegEx()
|
||||
{
|
||||
@ -10,7 +44,10 @@ RegEx::RegEx()
|
||||
re = NULL;
|
||||
mFree = true;
|
||||
subject = NULL;
|
||||
mSubStrings = 0;
|
||||
mSubStrings.clear();
|
||||
mMatchesSubs.clear();
|
||||
mSubsNameTable.clear();
|
||||
mNumSubpatterns = 0;
|
||||
}
|
||||
|
||||
void RegEx::Clear()
|
||||
@ -22,9 +59,12 @@ void RegEx::Clear()
|
||||
re = NULL;
|
||||
mFree = true;
|
||||
if (subject)
|
||||
delete [] subject;
|
||||
delete[] subject;
|
||||
subject = NULL;
|
||||
mSubStrings = 0;
|
||||
mSubStrings.clear();
|
||||
mMatchesSubs.clear();
|
||||
mSubsNameTable.clear();
|
||||
mNumSubpatterns = 0;
|
||||
}
|
||||
|
||||
RegEx::~RegEx()
|
||||
@ -97,57 +137,198 @@ int RegEx::Compile(const char *pattern, const char* flags)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int RegEx::Compile(const char *pattern, int iFlags)
|
||||
{
|
||||
if (!mFree)
|
||||
Clear();
|
||||
|
||||
re = pcre_compile(pattern, iFlags, &mError, &mErrorOffset, NULL);
|
||||
|
||||
if (re == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
mFree = false;
|
||||
|
||||
/**
|
||||
* Retrieve the number of captured groups
|
||||
* including the full match.
|
||||
*/
|
||||
pcre_fullinfo(re, NULL, PCRE_INFO_CAPTURECOUNT, &mNumSubpatterns);
|
||||
++mNumSubpatterns;
|
||||
|
||||
/**
|
||||
* Build the table with the named groups,
|
||||
* which contain an index and a name per group.
|
||||
*/
|
||||
MakeSubpatternsTable(mNumSubpatterns);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int RegEx::Match(const char *str)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (mFree || re == NULL)
|
||||
return -1;
|
||||
|
||||
this->ClearMatch();
|
||||
|
||||
ClearMatch();
|
||||
|
||||
//save str
|
||||
subject = new char[strlen(str)+1];
|
||||
subject = new char[strlen(str) + 1];
|
||||
strcpy(subject, str);
|
||||
|
||||
rc = pcre_exec(re, NULL, subject, (int)strlen(subject), 0, 0, ovector, 30);
|
||||
rc = pcre_exec(re, NULL, subject, (int)strlen(subject), 0, 0, ovector, REGEX_MAX_SUBPATTERNS);
|
||||
|
||||
if (rc < 0)
|
||||
{
|
||||
if (rc == PCRE_ERROR_NOMATCH)
|
||||
{
|
||||
return 0;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
mErrorOffset = rc;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
mSubStrings = rc;
|
||||
RegExSub res;
|
||||
mSubStrings.ensure(rc);
|
||||
|
||||
for (int s = 0; s < rc; ++s)
|
||||
{
|
||||
res.start = ovector[2 * s];
|
||||
res.end = ovector[2 * s + 1];
|
||||
mSubStrings.append(res);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int RegEx::MatchAll(const char *str)
|
||||
{
|
||||
int rr = 0;
|
||||
int rc = 0;
|
||||
int startOffset = 0;
|
||||
int exoptions = 0;
|
||||
int notEmpty = 0;
|
||||
int sizeOffsets = mNumSubpatterns * 3;
|
||||
int subjectLen = strlen(str);
|
||||
|
||||
if (mFree || re == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
ClearMatch();
|
||||
|
||||
subject = new char[subjectLen + 1];
|
||||
strcpy(subject, str);
|
||||
|
||||
RegExSub sub;
|
||||
|
||||
while (1)
|
||||
{
|
||||
rr = pcre_exec(re, NULL, subject, (int)subjectLen, startOffset, exoptions | notEmpty, ovector, REGEX_MAX_SUBPATTERNS);
|
||||
|
||||
/**
|
||||
* The string was already proved to be valid UTF-8
|
||||
*/
|
||||
exoptions |= PCRE_NO_UTF8_CHECK;
|
||||
|
||||
/**
|
||||
* Too many substrings
|
||||
*/
|
||||
if (rr == 0)
|
||||
{
|
||||
rr = sizeOffsets / 3;
|
||||
}
|
||||
|
||||
if (rr > 0)
|
||||
{
|
||||
mMatchesSubs.append(rr);
|
||||
|
||||
for (int s = 0; s < rr; ++s)
|
||||
{
|
||||
sub.start = ovector[2 * s];
|
||||
sub.end = ovector[2 * s + 1];
|
||||
|
||||
mSubStrings.append(sub);
|
||||
}
|
||||
}
|
||||
else if (rr == PCRE_ERROR_NOMATCH)
|
||||
{
|
||||
/**
|
||||
* If we previously set PCRE_NOTEMPTY after a null match,
|
||||
* this is not necessarily the end. We need to advance
|
||||
* the start offset, and continue. Fudge the offset values
|
||||
* to achieve this, unless we're already at the end of the string.
|
||||
*/
|
||||
if (notEmpty && startOffset < (int)subjectLen)
|
||||
{
|
||||
ovector[0] = startOffset;
|
||||
ovector[1] = startOffset + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mErrorOffset = rr;
|
||||
|
||||
if (mMatchesSubs.length())
|
||||
{
|
||||
ClearMatch();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* If we have matched an empty string, mimic what Perl's /g options does.
|
||||
* This turns out to be rather cunning. First we set PCRE_NOTEMPTY and try
|
||||
* the match again at the same point. If this fails (picked up above) we
|
||||
* advance to the next character.
|
||||
*/
|
||||
notEmpty = (ovector[1] == ovector[0]) ? PCRE_NOTEMPTY | PCRE_ANCHORED : 0;
|
||||
|
||||
/**
|
||||
* Advance to the next piece.
|
||||
*/
|
||||
startOffset = ovector[1];
|
||||
}
|
||||
|
||||
if (!mMatchesSubs.length())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void RegEx::ClearMatch()
|
||||
{
|
||||
// Clears match results
|
||||
mErrorOffset = 0;
|
||||
mError = NULL;
|
||||
if (subject)
|
||||
delete [] subject;
|
||||
delete[] subject;
|
||||
subject = NULL;
|
||||
mSubStrings = 0;
|
||||
mSubStrings.clear();
|
||||
mMatchesSubs.clear();
|
||||
}
|
||||
|
||||
const char *RegEx::GetSubstring(int s, char buffer[], int max)
|
||||
const char *getSubstring(char *subject, size_t start, size_t end, char buffer[], size_t max, size_t *outlen)
|
||||
{
|
||||
int i = 0;
|
||||
if (s >= mSubStrings || s < 0)
|
||||
return NULL;
|
||||
size_t i;
|
||||
char * substr_a = subject + start;
|
||||
size_t substr_l = end - start;
|
||||
|
||||
char *substr_a = subject + ovector[2*s];
|
||||
int substr_l = ovector[2*s+1] - ovector[2*s];
|
||||
|
||||
for (i = 0; i<substr_l; i++)
|
||||
for (i = 0; i < substr_l; i++)
|
||||
{
|
||||
if (i >= max)
|
||||
break;
|
||||
@ -156,6 +337,506 @@ const char *RegEx::GetSubstring(int s, char buffer[], int max)
|
||||
|
||||
buffer[i] = '\0';
|
||||
|
||||
if (outlen)
|
||||
{
|
||||
*outlen = i;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
const char *RegEx::GetSubstring(size_t start, char buffer[], size_t max, size_t *outlen)
|
||||
{
|
||||
if (start >= mSubStrings.length())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RegExSub sub = mSubStrings.at(start);
|
||||
|
||||
return getSubstring(subject, sub.start, sub.end, buffer, max, outlen);
|
||||
}
|
||||
|
||||
void RegEx::MakeSubpatternsTable(int numSubpatterns)
|
||||
{
|
||||
int nameCount = 0;
|
||||
int rc = pcre_fullinfo(re, NULL, PCRE_INFO_NAMECOUNT, &nameCount);
|
||||
|
||||
if (rc < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (nameCount > 0)
|
||||
{
|
||||
const char *nameTable;
|
||||
int nameSize = 0;
|
||||
int i = 0;
|
||||
|
||||
int rc1 = pcre_fullinfo(re, NULL, PCRE_INFO_NAMETABLE, &nameTable);
|
||||
int rc2 = pcre_fullinfo(re, NULL, PCRE_INFO_NAMEENTRYSIZE, &nameSize);
|
||||
|
||||
rc = rc2 ? rc2 : rc1;
|
||||
|
||||
if (rc < 0)
|
||||
{
|
||||
mSubsNameTable.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
NamedGroup data;
|
||||
|
||||
while (i++ < nameCount)
|
||||
{
|
||||
data.index = 0xff * (unsigned char)nameTable[0] + (unsigned char)nameTable[1];
|
||||
data.name = nameTable + 2;
|
||||
|
||||
mSubsNameTable.append(ke::Move(data));
|
||||
nameTable += nameSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int RegEx::Replace(char *text, size_t textMaxLen, const char *replace, size_t replaceLen, int flags)
|
||||
{
|
||||
char *output = text;
|
||||
|
||||
/**
|
||||
* Retrieve all matches and store them in
|
||||
* mSubStrings list.
|
||||
*/
|
||||
if (MatchAll(output) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t subjectLen = strlen(subject);
|
||||
size_t total = 0;
|
||||
size_t baseIndex = 0;
|
||||
size_t diffLength = 0;
|
||||
|
||||
char *toReplace = new char[textMaxLen + 1];
|
||||
char *toSearch = NULL;
|
||||
|
||||
/**
|
||||
* All characters which is not matched are not copied when replacing matches.
|
||||
* Then original text (output buffer) should be considerated as empty.
|
||||
*/
|
||||
if (flags & REGEX_FORMAT_NOCOPY)
|
||||
{
|
||||
*output = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
/**
|
||||
* This is used only when we do replace matches.
|
||||
*/
|
||||
toSearch = new char[textMaxLen + 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Loop over all matches found.
|
||||
*/
|
||||
for (size_t i = 0; i < mMatchesSubs.length(); ++i)
|
||||
{
|
||||
char *ptr = toReplace;
|
||||
|
||||
size_t browsed = 0;
|
||||
size_t searchLen = 0;
|
||||
size_t length = 0;
|
||||
|
||||
/**
|
||||
* Build the replace string as it can contain backreference
|
||||
* and this needs to be parsed.
|
||||
*/
|
||||
for (const char *s = replace, *end = s + replaceLen; s < end && browsed <= textMaxLen; ++s, ++browsed)
|
||||
{
|
||||
unsigned int c = *s;
|
||||
|
||||
/**
|
||||
* Supported format specifiers:
|
||||
*
|
||||
* $number : Substitutes the substring matched by group number.
|
||||
* n must be an integer value designating a valid backreference, greater than 0, and of two digits at most.
|
||||
* ${name} : Substitutes the substring matched by the named group name (a maximum of 32 characters).
|
||||
* $& : Substitutes a copy of the whole match.
|
||||
* $` : Substitutes all the text of the input string before the match.
|
||||
* $' : Substitutes all the text of the input string after the match.
|
||||
* $+ : Substitutes the last group that was captured.
|
||||
* $_ : Substitutes the entire input string.
|
||||
* $$ : Substitutes a literal "$".
|
||||
*/
|
||||
if (c == '$' || c == '\\')
|
||||
{
|
||||
switch (*++s)
|
||||
{
|
||||
case '\0':
|
||||
{
|
||||
/**
|
||||
* End of string.
|
||||
* Copy one character.
|
||||
*/
|
||||
*(ptr + browsed) = c;
|
||||
break;
|
||||
}
|
||||
case '&':
|
||||
{
|
||||
/**
|
||||
* Concatenate retrieved full match sub-string.
|
||||
* length - 1 to overwrite EOS.
|
||||
*/
|
||||
GetSubstring(baseIndex, ptr + browsed, textMaxLen, &length);
|
||||
browsed += length - 1;
|
||||
break;
|
||||
}
|
||||
case '`':
|
||||
{
|
||||
/**
|
||||
* Concatenate part of original text up to
|
||||
* first sub-string position.
|
||||
*/
|
||||
length = mSubStrings.at(baseIndex).start;
|
||||
memcpy(ptr + browsed, subject, length);
|
||||
browsed += length - 1;
|
||||
break;
|
||||
}
|
||||
case '\'':
|
||||
{
|
||||
/**
|
||||
* Concatenate part of original text from
|
||||
* last sub-string end position to EOS.
|
||||
*/
|
||||
length = mSubStrings.at(baseIndex).end;
|
||||
memcpy(ptr + browsed, subject + length, subjectLen - length);
|
||||
browsed += (subjectLen - length) - 1;
|
||||
break;
|
||||
}
|
||||
case '+':
|
||||
{
|
||||
/**
|
||||
* Copy the last group that was captured.
|
||||
*/
|
||||
GetSubstring(baseIndex + mMatchesSubs.at(i) - 1, ptr + browsed, textMaxLen, &length);
|
||||
browsed += length - 1;
|
||||
break;
|
||||
}
|
||||
case '_':
|
||||
{
|
||||
/**
|
||||
* Copy the entire input string.
|
||||
*/
|
||||
memcpy(ptr + browsed, subject, subjectLen);
|
||||
browsed += (subjectLen - 1);
|
||||
break;
|
||||
}
|
||||
case '$':
|
||||
case '\\':
|
||||
{
|
||||
/**
|
||||
* Copy the single character $ or \.
|
||||
*/
|
||||
*(ptr + browsed) = c;
|
||||
break;
|
||||
}
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
case '{':
|
||||
{
|
||||
/**
|
||||
* Checking backreference.
|
||||
* Which can be either $n, ${n} or ${name}.
|
||||
*/
|
||||
int backref = -1;
|
||||
const char *walk = s;
|
||||
bool inBrace = false;
|
||||
bool nameCheck = false;
|
||||
|
||||
/**
|
||||
* ${nn}.
|
||||
* ^
|
||||
*/
|
||||
if (*walk == '{')
|
||||
{
|
||||
inBrace = true;
|
||||
++walk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Valid number.
|
||||
* $nn or ${nn}
|
||||
* ^ ^
|
||||
*/
|
||||
if (*walk >= '0' && *walk <= '9')
|
||||
{
|
||||
backref = *walk - '0';
|
||||
++walk;
|
||||
}
|
||||
else if (inBrace)
|
||||
{
|
||||
nameCheck = true;
|
||||
|
||||
/**
|
||||
* Not a valid number.
|
||||
* Checking as string.
|
||||
* ${name}
|
||||
* ^
|
||||
*/
|
||||
if (*walk)
|
||||
{
|
||||
const char *pch = strchr(walk, '}');
|
||||
|
||||
if (pch != NULL)
|
||||
{
|
||||
/**
|
||||
* A named group maximum character is 32 (PCRE).
|
||||
*/
|
||||
char name[32];
|
||||
size_t nameLength = strncopy(name, walk, pch - walk + 1);
|
||||
|
||||
int flags, num = 0;
|
||||
pcre_fullinfo(re, NULL, PCRE_INFO_OPTIONS, &flags);
|
||||
|
||||
/**
|
||||
* If PCRE_DUPNAMES is set, the pcre_copy_named_substring function should be used
|
||||
* as pcre_get_stringnumber output order is not defined.
|
||||
*/
|
||||
if (flags & PCRE_DUPNAMES)
|
||||
{
|
||||
memset(ovector, 0, REGEX_MAX_SUBPATTERNS);
|
||||
|
||||
/**
|
||||
* pcre_copy_named_substring needs a vector containing sub-patterns ranges
|
||||
* for a given match.
|
||||
*/
|
||||
for (size_t j = 0; j < mMatchesSubs.at(i); ++j)
|
||||
{
|
||||
ovector[2 * j] = mSubStrings.at(baseIndex + j).start;
|
||||
ovector[2 * j + 1] = mSubStrings.at(baseIndex + j).end;
|
||||
}
|
||||
|
||||
num = pcre_copy_named_substring(re, subject, ovector, mMatchesSubs.at(i), name, ptr + browsed, (int)textMaxLen);
|
||||
|
||||
if (num != PCRE_ERROR_NOSUBSTRING)
|
||||
{
|
||||
browsed += num - 1;
|
||||
s = pch;
|
||||
break;
|
||||
}
|
||||
++pch;
|
||||
}
|
||||
else
|
||||
{
|
||||
/**
|
||||
* Retrieve sub-pattern index from a give name.
|
||||
*/
|
||||
num = pcre_get_stringnumber(re, name);
|
||||
if (num != PCRE_ERROR_NOSUBSTRING)
|
||||
{
|
||||
backref = num;
|
||||
walk = ++pch;
|
||||
}
|
||||
}
|
||||
|
||||
if (num == PCRE_ERROR_NOSUBSTRING || num >= (int)mMatchesSubs.at(i))
|
||||
{
|
||||
/**
|
||||
* If a sub-string for a given match is not found, or if > to
|
||||
* number of sub-patterns we still need to check if this
|
||||
* group name is a valid one because if so we want to escape it.
|
||||
* Looking at the name table.
|
||||
*/
|
||||
bool found = false;
|
||||
for (size_t i = 0; i < mSubsNameTable.length(); ++i)
|
||||
{
|
||||
if (!mSubsNameTable.at(i).name.compare(name))
|
||||
{
|
||||
--browsed;
|
||||
s = --pch;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!nameCheck)
|
||||
{
|
||||
/**
|
||||
* Valid second number.
|
||||
* $nn or ${nn}
|
||||
* ^ ^
|
||||
*/
|
||||
if (*walk && *walk >= '0' && *walk <= '9')
|
||||
{
|
||||
backref = backref * 10 + *walk - '0';
|
||||
++walk;
|
||||
}
|
||||
|
||||
if (inBrace)
|
||||
{
|
||||
/**
|
||||
* Invalid specifier
|
||||
* Either hit EOS or missing }.
|
||||
* ${n or ${nn or ${nx or ${nnx
|
||||
* ^ ^ ^ ^
|
||||
*/
|
||||
if (*walk == '\0' || *walk != '}')
|
||||
{
|
||||
backref = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
++walk;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
length = walk - s;
|
||||
s = --walk;
|
||||
|
||||
/**
|
||||
* We can't provide a capture number >= to total that pcre_exec has found.
|
||||
* 0 is implicitly accepted, same behavior as $&.
|
||||
*/
|
||||
if (backref >= 0 && (int)backref < mNumSubpatterns)
|
||||
{
|
||||
/**
|
||||
* Valid available index for a given match.
|
||||
*/
|
||||
if (backref < mMatchesSubs.at(i))
|
||||
{
|
||||
/**
|
||||
* Concatenate retrieved sub-string.
|
||||
* length - 1 to overwrite EOS.
|
||||
*/
|
||||
GetSubstring(baseIndex + backref, ptr + browsed, textMaxLen, &length);
|
||||
browsed += length - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/**
|
||||
* Valid unavailable index for a given match.
|
||||
*/
|
||||
--browsed;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/**
|
||||
* If we here it means the syntax is valid but sub-pattern doesn't exist.
|
||||
* So, copy as it is, including $.
|
||||
*/
|
||||
memcpy(ptr + browsed, s - length, length + 1);
|
||||
browsed += length;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
/**
|
||||
* Not a valid format modifier.
|
||||
* So we copy characters as it is.
|
||||
*/
|
||||
*(ptr + browsed) = *s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/**
|
||||
* At this point, direct copy.
|
||||
*/
|
||||
*(ptr + browsed) = c;
|
||||
}
|
||||
}
|
||||
|
||||
*(ptr + browsed) = '\0';
|
||||
|
||||
/**
|
||||
* Concatenate only replace string of each match,
|
||||
* as we don't want to copy unmatched characters.
|
||||
*/
|
||||
if (flags & REGEX_FORMAT_NOCOPY)
|
||||
{
|
||||
/**
|
||||
* We want just the first occurrence.
|
||||
*/
|
||||
if (total++ && (flags & REGEX_FORMAT_FIRSTONLY))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
strncat(output, toReplace, textMaxLen + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
/**
|
||||
* Retrieves full string of a given match.
|
||||
*/
|
||||
const char *search = GetSubstring(baseIndex, toSearch, textMaxLen, &searchLen);
|
||||
|
||||
/**
|
||||
* We get something to replace, but the sub-pattern to search is empty.
|
||||
* We insert replacement either a the start end or string.
|
||||
*/
|
||||
if (*toReplace && !searchLen)
|
||||
{
|
||||
if (output - text > 0)
|
||||
{
|
||||
strncat(output, toReplace, textMaxLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
strncat(toReplace, text, textMaxLen);
|
||||
strncopy(text, toReplace, strlen(toReplace) + 1);
|
||||
}
|
||||
|
||||
++total;
|
||||
}
|
||||
else if ((output = UTIL_ReplaceEx(text + mSubStrings.at(baseIndex).start + diffLength, textMaxLen, search, searchLen, toReplace, browsed, false)) != NULL)
|
||||
{
|
||||
/**
|
||||
* Then we simply do a replace.
|
||||
* Probably not the most efficient, but this should be at least safe.
|
||||
* To avoid issue where the function could find a string which is not at the expected index,
|
||||
* We force the input string to start from index of the full match.
|
||||
*/
|
||||
++total;
|
||||
}
|
||||
|
||||
if (total && (flags & REGEX_FORMAT_FIRSTONLY))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* mMatchesSubs is a flat list containing all sub-patterns of all matches.
|
||||
* A number of sub-patterns can vary per match. So we calculate the position in the list,
|
||||
* from where the first sub-pattern result of current match starts.
|
||||
*/
|
||||
baseIndex += mMatchesSubs.at(i);
|
||||
diffLength += browsed - searchLen;
|
||||
}
|
||||
|
||||
delete[] toReplace;
|
||||
|
||||
if (toSearch != NULL)
|
||||
{
|
||||
delete[] toSearch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of successful replacements.
|
||||
*/
|
||||
return total;
|
||||
}
|
||||
|
@ -1,27 +1,94 @@
|
||||
/* AMX Mod X
|
||||
* Regular Expressions Module
|
||||
*
|
||||
* by the AMX Mod X Development Team
|
||||
*
|
||||
* This file is part of AMX Mod X.
|
||||
*
|
||||
*
|
||||
* 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 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* In addition, as a special exception, the author gives permission to
|
||||
* link the code of this program with the Half-Life Game Engine ("HL
|
||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||
* respects for all of the code used other than the HL Engine and MODs
|
||||
* from Valve. If you modify this file, you may extend this exception
|
||||
* to your version of the file, but you are not obligated to do so. If
|
||||
* you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
*/
|
||||
#ifndef _INCLUDE_CREGEX_H
|
||||
#define _INCLUDE_CREGEX_H
|
||||
|
||||
#include <am-vector.h>
|
||||
#include <am-string.h>
|
||||
|
||||
/**
|
||||
* Maximum number of sub-patterns, here 50 (this should be a multiple of 3).
|
||||
*/
|
||||
#define REGEX_MAX_SUBPATTERNS 150
|
||||
|
||||
/**
|
||||
* Flags to used with regex_replace, to control the replacement behavior.
|
||||
*/
|
||||
#define REGEX_FORMAT_DEFAULT 0 // Uses the standard formatting rules to replace matches.
|
||||
#define REGEX_FORMAT_NOCOPY 1 // The sections that do not match the regular expression are not copied when replacing matches.
|
||||
#define REGEX_FORMAT_FIRSTONLY 2 // Only the first occurrence of a regular expression is replaced.
|
||||
|
||||
class RegEx
|
||||
{
|
||||
public:
|
||||
struct RegExSub {
|
||||
int start, end;
|
||||
};
|
||||
|
||||
struct NamedGroup {
|
||||
ke::AString name;
|
||||
size_t index;
|
||||
};
|
||||
|
||||
RegEx();
|
||||
~RegEx();
|
||||
|
||||
bool isFree(bool set=false, bool val=false);
|
||||
void Clear();
|
||||
|
||||
int Compile(const char *pattern, const char* flags = NULL);
|
||||
int Compile(const char *pattern, int iFlags);
|
||||
int Match(const char *str);
|
||||
int MatchAll(const char *str);
|
||||
int Replace(char *text, size_t text_maxlen, const char *replace, size_t replaceLen, int flags = 0);
|
||||
void ClearMatch();
|
||||
const char *GetSubstring(int s, char buffer[], int max);
|
||||
const char *GetSubstring(size_t start, char buffer[], size_t max, size_t *outlen = NULL);
|
||||
void MakeSubpatternsTable(int numSubpatterns);
|
||||
|
||||
public:
|
||||
int mErrorOffset;
|
||||
const char *mError;
|
||||
int mSubStrings;
|
||||
int Count() { return mSubStrings.length(); }
|
||||
|
||||
private:
|
||||
pcre *re;
|
||||
bool mFree;
|
||||
int ovector[30];
|
||||
int ovector[REGEX_MAX_SUBPATTERNS];
|
||||
char *subject;
|
||||
ke::Vector<RegExSub> mSubStrings;
|
||||
ke::Vector<size_t> mMatchesSubs;
|
||||
ke::Vector<NamedGroup> mSubsNameTable;
|
||||
int mNumSubpatterns;
|
||||
};
|
||||
|
||||
#endif //_INCLUDE_CREGEX_H
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,24 +1,59 @@
|
||||
/* AMX Mod X
|
||||
* Regular Expressions Module
|
||||
*
|
||||
* by the AMX Mod X Development Team
|
||||
*
|
||||
* This file is part of AMX Mod X.
|
||||
*
|
||||
*
|
||||
* 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 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* In addition, as a special exception, the author gives permission to
|
||||
* link the code of this program with the Half-Life Game Engine ("HL
|
||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||
* respects for all of the code used other than the HL Engine and MODs
|
||||
* from Valve. If you modify this file, you may extend this exception
|
||||
* to your version of the file, but you are not obligated to do so. If
|
||||
* you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include "pcre.h"
|
||||
#include "amxxmodule.h"
|
||||
#include "CVector.h"
|
||||
#include <am-vector.h>
|
||||
#include <am-utility.h>
|
||||
#include "CRegEx.h"
|
||||
#include "utils.h"
|
||||
|
||||
CVector<RegEx *> PEL;
|
||||
ke::Vector<RegEx *> PEL;
|
||||
|
||||
int GetPEL()
|
||||
{
|
||||
for (int i=0; i<(int)PEL.size(); i++)
|
||||
for (int i=0; i<(int)PEL.length(); i++)
|
||||
{
|
||||
if (PEL[i]->isFree())
|
||||
return i;
|
||||
}
|
||||
|
||||
RegEx *x = new RegEx();
|
||||
PEL.push_back(x);
|
||||
PEL.append(x);
|
||||
|
||||
return (int)PEL.size() - 1;
|
||||
return (int)PEL.length() - 1;
|
||||
}
|
||||
|
||||
// native Regex:regex_compile(const pattern[], &ret, error[], maxLen, const flags[]="");
|
||||
static cell AMX_NATIVE_CALL regex_compile(AMX *amx, cell *params)
|
||||
{
|
||||
@ -31,17 +66,36 @@ static cell AMX_NATIVE_CALL regex_compile(AMX *amx, cell *params)
|
||||
|
||||
if (x->Compile(regex, flags) == 0)
|
||||
{
|
||||
cell *eOff = MF_GetAmxAddr(amx, params[2]);
|
||||
const char *err = x->mError;
|
||||
*eOff = x->mErrorOffset;
|
||||
*MF_GetAmxAddr(amx, params[2]) = x->mErrorOffset;
|
||||
MF_SetAmxString(amx, params[3], err?err:"unknown", params[4]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return id+1;
|
||||
}// 1.8 includes the last parameter
|
||||
// Regex:regex_match(const string[], const pattern[], &ret, error[], maxLen, const flags[] = "");
|
||||
static cell AMX_NATIVE_CALL regex_match(AMX *amx, cell *params)
|
||||
}
|
||||
|
||||
// native Regex:regex_compile_ex(const pattern[], flags = 0, error[] = "", maxLen = 0, &errcode = 0);
|
||||
static cell AMX_NATIVE_CALL regex_compile_ex(AMX *amx, cell *params)
|
||||
{
|
||||
int len;
|
||||
const char *regex = MF_GetAmxString(amx, params[1], 0, &len);
|
||||
|
||||
int id = GetPEL();
|
||||
RegEx *x = PEL[id];
|
||||
|
||||
if (x->Compile(regex, params[2]) == 0)
|
||||
{
|
||||
const char *err = x->mError;
|
||||
*MF_GetAmxAddr(amx, params[5]) = x->mErrorOffset;
|
||||
MF_SetAmxString(amx, params[3], err ? err : "unknown", params[4]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return id + 1;
|
||||
}
|
||||
|
||||
cell match(AMX *amx, cell *params, bool all)
|
||||
{
|
||||
int len;
|
||||
const char *str = MF_GetAmxString(amx, params[1], 0, &len);
|
||||
@ -49,101 +103,166 @@ static cell AMX_NATIVE_CALL regex_match(AMX *amx, cell *params)
|
||||
|
||||
int id = GetPEL();
|
||||
RegEx *x = PEL[id];
|
||||
|
||||
char* flags = NULL;
|
||||
|
||||
if ((params[0] / sizeof(cell)) >= 6) // compiled with 1.8's extra parameter
|
||||
|
||||
char *flags = NULL;
|
||||
cell *errorCode;
|
||||
int result = 0;
|
||||
|
||||
if (!all)
|
||||
{
|
||||
flags = MF_GetAmxString(amx, params[6], 2, &len);
|
||||
if (*params / sizeof(cell) >= 6) // compiled with 1.8's extra parameter
|
||||
{
|
||||
flags = MF_GetAmxString(amx, params[6], 2, &len);
|
||||
}
|
||||
|
||||
result = x->Compile(regex, flags);
|
||||
errorCode = MF_GetAmxAddr(amx, params[3]);
|
||||
}
|
||||
|
||||
if (x->Compile(regex, flags) == 0)
|
||||
else
|
||||
{
|
||||
result = x->Compile(regex, params[3]);
|
||||
errorCode = MF_GetAmxAddr(amx, params[6]);
|
||||
}
|
||||
|
||||
if (!result)
|
||||
{
|
||||
cell *eOff = MF_GetAmxAddr(amx, params[3]);
|
||||
const char *err = x->mError;
|
||||
*eOff = x->mErrorOffset;
|
||||
MF_SetAmxString(amx, params[4], err?err:"unknown", params[5]);
|
||||
*errorCode = x->mErrorOffset;
|
||||
MF_SetAmxString(amx, params[4], err ? err : "unknown", params[5]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int e = x->Match(str);
|
||||
int e;
|
||||
|
||||
if (all)
|
||||
e = x->MatchAll(str);
|
||||
else
|
||||
e = x->Match(str);
|
||||
|
||||
if (e == -1)
|
||||
{
|
||||
/* there was a match error. destroy this and move on. */
|
||||
cell *res = MF_GetAmxAddr(amx, params[3]);
|
||||
*res = x->mErrorOffset;
|
||||
*errorCode = x->mErrorOffset;
|
||||
x->Clear();
|
||||
return -2;
|
||||
} else if (e == 0) {
|
||||
cell *res = MF_GetAmxAddr(amx, params[3]);
|
||||
*res = 0;
|
||||
}
|
||||
else if (e == 0)
|
||||
{
|
||||
*errorCode = 0;
|
||||
x->Clear();
|
||||
return 0;
|
||||
} else {
|
||||
cell *res = MF_GetAmxAddr(amx, params[3]);
|
||||
*res = x->mSubStrings;
|
||||
}
|
||||
else
|
||||
{
|
||||
*errorCode = x->Count();
|
||||
if (all)
|
||||
return x->Count();
|
||||
}
|
||||
|
||||
return id+1;
|
||||
return id + 1;
|
||||
}
|
||||
// native regex_match_c(const string[], Regex:id, &ret);
|
||||
static cell AMX_NATIVE_CALL regex_match_c(AMX *amx, cell *params)
|
||||
{
|
||||
int len;
|
||||
int id = params[2]-1;
|
||||
const char *str = MF_GetAmxString(amx, params[1], 0, &len);
|
||||
|
||||
if (id >= (int)PEL.size() || id < 0 || PEL[id]->isFree())
|
||||
// native Regex:regex_match(const string[], const pattern[], &ret, error[], maxLen, const flags[] = "");
|
||||
static cell AMX_NATIVE_CALL regex_match(AMX *amx, cell *params)
|
||||
{
|
||||
return match(amx, params, false);
|
||||
}
|
||||
|
||||
// native Regex:regex_match_all(const string[], const pattern[], flags = 0, error[] = "", maxLen = 0, &errcode = 0);
|
||||
static cell AMX_NATIVE_CALL regex_match_all(AMX *amx, cell *params)
|
||||
{
|
||||
return match(amx, params, true);
|
||||
}
|
||||
|
||||
cell match_c(AMX *amx, cell *params, bool all)
|
||||
{
|
||||
int id = params[2] - 1;
|
||||
|
||||
if (id >= (int)PEL.length() || id < 0 || PEL[id]->isFree())
|
||||
{
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid regex handle %d", id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int len;
|
||||
const char *str = MF_GetAmxString(amx, params[1], 0, &len);
|
||||
cell *errorCode = MF_GetAmxAddr(amx, params[3]);
|
||||
|
||||
RegEx *x = PEL[id];
|
||||
|
||||
int e = x->Match(str);
|
||||
int e;
|
||||
if (all)
|
||||
e = x->MatchAll(str);
|
||||
else
|
||||
e = x->Match(str);
|
||||
|
||||
if (e == -1)
|
||||
{
|
||||
/* there was a match error. move on. */
|
||||
cell *res = MF_GetAmxAddr(amx, params[3]);
|
||||
*res = x->mErrorOffset;
|
||||
*errorCode = x->mErrorOffset;
|
||||
|
||||
/* only clear the match results, since the regex object
|
||||
may still be referenced later */
|
||||
may still be referenced later */
|
||||
x->ClearMatch();
|
||||
return -2;
|
||||
} else if (e == 0) {
|
||||
cell *res = MF_GetAmxAddr(amx, params[3]);
|
||||
*res = 0;
|
||||
}
|
||||
else if (e == 0)
|
||||
{
|
||||
*errorCode = 0;
|
||||
|
||||
/* only clear the match results, since the regex object
|
||||
may still be referenced later */
|
||||
may still be referenced later */
|
||||
x->ClearMatch();
|
||||
return 0;
|
||||
} else {
|
||||
cell *res = MF_GetAmxAddr(amx, params[3]);
|
||||
*res = x->mSubStrings;
|
||||
return x->mSubStrings;
|
||||
}
|
||||
else
|
||||
{
|
||||
*errorCode = x->Count();
|
||||
return x->Count();
|
||||
}
|
||||
}
|
||||
|
||||
// native regex_match_c(const string[], Regex:id, &ret);
|
||||
static cell AMX_NATIVE_CALL regex_match_c(AMX *amx, cell *params)
|
||||
{
|
||||
return match_c(amx, params, false);
|
||||
}
|
||||
|
||||
// native regex_match_all_c(const string[], Regex:id, &ret);
|
||||
static cell AMX_NATIVE_CALL regex_match_all_c(AMX *amx, cell *params)
|
||||
{
|
||||
return match_c(amx, params, true);
|
||||
}
|
||||
|
||||
// native regex_substr(Regex:id, str_id, buffer[], maxLen);
|
||||
static cell AMX_NATIVE_CALL regex_substr(AMX *amx, cell *params)
|
||||
{
|
||||
int id = params[1]-1;
|
||||
if (id >= (int)PEL.size() || id < 0 || PEL[id]->isFree())
|
||||
if (id >= (int)PEL.length() || id < 0 || PEL[id]->isFree())
|
||||
{
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid regex handle %d", id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
RegEx *x = PEL[id];
|
||||
//good idea? probably not.
|
||||
static char buffer[4096];
|
||||
static char buffer[16384]; // Same as AMXX buffer.
|
||||
|
||||
const char *ret = x->GetSubstring(params[2], buffer, 4095);
|
||||
size_t length;
|
||||
size_t maxLength = ke::Min<size_t>(params[4], sizeof(buffer) - 1);
|
||||
|
||||
const char *ret = x->GetSubstring(params[2], buffer, maxLength, &length);
|
||||
|
||||
if (ret == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
MF_SetAmxString(amx, params[3], ret, params[4]);
|
||||
if (length >= maxLength && ret[length - 1] & 1 << 7)
|
||||
{
|
||||
maxLength -= UTIL_CheckValidChar((char *)ret + length - 1);
|
||||
}
|
||||
|
||||
MF_SetAmxString(amx, params[3], ret, maxLength);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -154,7 +273,7 @@ static cell AMX_NATIVE_CALL regex_free(AMX *amx, cell *params)
|
||||
int id = *c;
|
||||
*c = 0;
|
||||
id -= 1;
|
||||
if (id >= (int)PEL.size() || id < 0 || PEL[id]->isFree())
|
||||
if (id >= (int)PEL.length() || id < 0 || PEL[id]->isFree())
|
||||
{
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid regex handle %d", id);
|
||||
return 0;
|
||||
@ -166,11 +285,52 @@ static cell AMX_NATIVE_CALL regex_free(AMX *amx, cell *params)
|
||||
return 1;
|
||||
}
|
||||
|
||||
//native regex_replace(Regex:pattern, string[], maxLen, const replace[], flags = REGEX_FORMAT_DEFAULT, &errcode = 0);
|
||||
static cell AMX_NATIVE_CALL regex_replace(AMX *amx, cell *params)
|
||||
{
|
||||
int id = params[1] - 1;
|
||||
if (id >= (int)PEL.length() || id < 0 || PEL[id]->isFree())
|
||||
{
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid regex handle %d", id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int textLen, replaceLen;
|
||||
char *text = MF_GetAmxString(amx, params[2], 0, &textLen);
|
||||
const char *replace = MF_GetAmxString(amx, params[4], 1, &replaceLen);
|
||||
|
||||
cell *erroCode = MF_GetAmxAddr(amx, params[6]);
|
||||
|
||||
RegEx *x = PEL[id];
|
||||
int e = x->Replace(text, params[3] + 1, replace, replaceLen, params[5]);
|
||||
|
||||
if (e == -1)
|
||||
{
|
||||
*erroCode = x->mErrorOffset;
|
||||
x->ClearMatch();
|
||||
return -2;
|
||||
}
|
||||
else if (e == 0)
|
||||
{
|
||||
*erroCode = 0;
|
||||
x->ClearMatch();
|
||||
return 0;
|
||||
}
|
||||
|
||||
MF_SetAmxString(amx, params[2], text, params[3]);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
AMX_NATIVE_INFO regex_Natives[] = {
|
||||
{"regex_compile", regex_compile},
|
||||
{"regex_compile_ex", regex_compile_ex},
|
||||
{"regex_match", regex_match},
|
||||
{"regex_match_c", regex_match_c},
|
||||
{"regex_match_all", regex_match_all},
|
||||
{"regex_match_all_c", regex_match_all_c},
|
||||
{"regex_substr", regex_substr},
|
||||
{"regex_replace", regex_replace},
|
||||
{"regex_free", regex_free},
|
||||
{NULL, NULL},
|
||||
};
|
||||
@ -182,7 +342,7 @@ void OnAmxxAttach()
|
||||
|
||||
void OnAmxxDetach()
|
||||
{
|
||||
for (int i = 0; i<(int)PEL.size(); i++)
|
||||
for (int i = 0; i<(int)PEL.length(); i++)
|
||||
{
|
||||
if (PEL[i])
|
||||
{
|
||||
|
@ -52,8 +52,8 @@
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\;..\sdk;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;REGEX_EXPORTS;PCRE_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\;..\..\..\public\amtl;..\sdk;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;REGEX_EXPORTS;HAVE_STDINT_H;PCRE_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>true</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
@ -75,8 +75,8 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\;..\sdk;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;REGEX_EXPORTS;PCRE_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\;..\..\..\public\amtl;..\sdk;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;REGEX_EXPORTS;HAVE_STDINT_H;PCRE_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<PrecompiledHeader>
|
||||
@ -99,6 +99,7 @@
|
||||
<ClCompile Include="..\CRegEx.cpp" />
|
||||
<ClCompile Include="..\module.cpp" />
|
||||
<ClCompile Include="..\sdk\amxxmodule.cpp" />
|
||||
<ClCompile Include="..\utils.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\CRegEx.h" />
|
||||
@ -107,6 +108,7 @@
|
||||
<ClInclude Include="..\sdk\moduleconfig.h" />
|
||||
<ClInclude Include="..\sdk\CVector.h" />
|
||||
<ClInclude Include="..\sdk\amxxmodule.h" />
|
||||
<ClInclude Include="..\utils.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\..\plugins\include\regex.inc" />
|
||||
|
@ -32,6 +32,9 @@
|
||||
<ClCompile Include="..\sdk\amxxmodule.cpp">
|
||||
<Filter>Module SDK\SDK Base</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\utils.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\CRegEx.h">
|
||||
@ -52,6 +55,9 @@
|
||||
<ClInclude Include="..\sdk\amxxmodule.h">
|
||||
<Filter>Module SDK\SDK Base</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\utils.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\..\plugins\include\regex.inc">
|
||||
|
@ -2,10 +2,10 @@
|
||||
* Perl-Compatible Regular Expressions *
|
||||
*************************************************/
|
||||
|
||||
/* In its original form, this is the .in file that is transformed by
|
||||
"configure" into pcre.h.
|
||||
/* This is the public header file for the PCRE library, to be #included by
|
||||
applications that call the PCRE functions.
|
||||
|
||||
Copyright (c) 1997-2005 University of Cambridge
|
||||
Copyright (c) 1997-2014 University of Cambridge
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@ -39,34 +39,48 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifndef _PCRE_H
|
||||
#define _PCRE_H
|
||||
|
||||
/* The file pcre.h is build by "configure". Do not edit it; instead
|
||||
make changes to pcre.in. */
|
||||
/* The current PCRE version information. */
|
||||
|
||||
#define PCRE_MAJOR 6
|
||||
#define PCRE_MINOR 4
|
||||
#define PCRE_DATE 05-Sep-2005
|
||||
#define PCRE_MAJOR 8
|
||||
#define PCRE_MINOR 35
|
||||
#define PCRE_PRERELEASE
|
||||
#define PCRE_DATE 2014-04-04
|
||||
|
||||
/* Win32 uses DLL by default; it needs special stuff for exported functions. */
|
||||
/* When an application links to a PCRE DLL in Windows, the symbols that are
|
||||
imported have to be identified as such. When building PCRE, the appropriate
|
||||
export setting is defined in pcre_internal.h, which includes this file. So we
|
||||
don't change existing definitions of PCRE_EXP_DECL and PCRECPP_EXP_DECL. */
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifdef PCRE_DEFINITION
|
||||
# ifdef DLL_EXPORT
|
||||
# define PCRE_DATA_SCOPE __declspec(dllexport)
|
||||
#if defined(_WIN32) && !defined(PCRE_STATIC)
|
||||
# ifndef PCRE_EXP_DECL
|
||||
# define PCRE_EXP_DECL extern __declspec(dllimport)
|
||||
# endif
|
||||
# ifdef __cplusplus
|
||||
# ifndef PCRECPP_EXP_DECL
|
||||
# define PCRECPP_EXP_DECL extern __declspec(dllimport)
|
||||
# endif
|
||||
# else
|
||||
# ifndef PCRE_STATIC
|
||||
# define PCRE_DATA_SCOPE extern __declspec(dllimport)
|
||||
# ifndef PCRECPP_EXP_DEFN
|
||||
# define PCRECPP_EXP_DEFN __declspec(dllimport)
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* For other operating systems, we use the standard "extern". */
|
||||
/* By default, we use the standard "extern" declarations. */
|
||||
|
||||
#ifndef PCRE_DATA_SCOPE
|
||||
#ifndef PCRE_EXP_DECL
|
||||
# ifdef __cplusplus
|
||||
# define PCRE_DATA_SCOPE extern "C"
|
||||
# define PCRE_EXP_DECL extern "C"
|
||||
# else
|
||||
# define PCRE_DATA_SCOPE extern
|
||||
# define PCRE_EXP_DECL extern
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
# ifndef PCRECPP_EXP_DECL
|
||||
# define PCRECPP_EXP_DECL extern
|
||||
# endif
|
||||
# ifndef PCRECPP_EXP_DEFN
|
||||
# define PCRECPP_EXP_DEFN
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@ -81,50 +95,162 @@ it is needed here for malloc. */
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Options */
|
||||
/* Public options. Some are compile-time only, some are run-time only, and some
|
||||
are both. Most of the compile-time options are saved with the compiled regex so
|
||||
that they can be inspected during studying (and therefore JIT compiling). Note
|
||||
that pcre_study() has its own set of options. Originally, all the options
|
||||
defined here used distinct bits. However, almost all the bits in a 32-bit word
|
||||
are now used, so in order to conserve them, option bits that were previously
|
||||
only recognized at matching time (i.e. by pcre_exec() or pcre_dfa_exec()) may
|
||||
also be used for compile-time options that affect only compiling and are not
|
||||
relevant for studying or JIT compiling.
|
||||
|
||||
#define PCRE_CASELESS 0x00000001
|
||||
#define PCRE_MULTILINE 0x00000002
|
||||
#define PCRE_DOTALL 0x00000004
|
||||
#define PCRE_EXTENDED 0x00000008
|
||||
#define PCRE_ANCHORED 0x00000010
|
||||
#define PCRE_DOLLAR_ENDONLY 0x00000020
|
||||
#define PCRE_EXTRA 0x00000040
|
||||
#define PCRE_NOTBOL 0x00000080
|
||||
#define PCRE_NOTEOL 0x00000100
|
||||
#define PCRE_UNGREEDY 0x00000200
|
||||
#define PCRE_NOTEMPTY 0x00000400
|
||||
#define PCRE_UTF8 0x00000800
|
||||
#define PCRE_NO_AUTO_CAPTURE 0x00001000
|
||||
#define PCRE_NO_UTF8_CHECK 0x00002000
|
||||
#define PCRE_AUTO_CALLOUT 0x00004000
|
||||
#define PCRE_PARTIAL 0x00008000
|
||||
#define PCRE_DFA_SHORTEST 0x00010000
|
||||
#define PCRE_DFA_RESTART 0x00020000
|
||||
#define PCRE_FIRSTLINE 0x00040000
|
||||
Some options for pcre_compile() change its behaviour but do not affect the
|
||||
behaviour of the execution functions. Other options are passed through to the
|
||||
execution functions and affect their behaviour, with or without affecting the
|
||||
behaviour of pcre_compile().
|
||||
|
||||
Options that can be passed to pcre_compile() are tagged Cx below, with these
|
||||
variants:
|
||||
|
||||
C1 Affects compile only
|
||||
C2 Does not affect compile; affects exec, dfa_exec
|
||||
C3 Affects compile, exec, dfa_exec
|
||||
C4 Affects compile, exec, dfa_exec, study
|
||||
C5 Affects compile, exec, study
|
||||
|
||||
Options that can be set for pcre_exec() and/or pcre_dfa_exec() are flagged with
|
||||
E and D, respectively. They take precedence over C3, C4, and C5 settings passed
|
||||
from pcre_compile(). Those that are compatible with JIT execution are flagged
|
||||
with J. */
|
||||
|
||||
#define PCRE_CASELESS 0x00000001 /* C1 */
|
||||
#define PCRE_MULTILINE 0x00000002 /* C1 */
|
||||
#define PCRE_DOTALL 0x00000004 /* C1 */
|
||||
#define PCRE_EXTENDED 0x00000008 /* C1 */
|
||||
#define PCRE_ANCHORED 0x00000010 /* C4 E D */
|
||||
#define PCRE_DOLLAR_ENDONLY 0x00000020 /* C2 */
|
||||
#define PCRE_EXTRA 0x00000040 /* C1 */
|
||||
#define PCRE_NOTBOL 0x00000080 /* E D J */
|
||||
#define PCRE_NOTEOL 0x00000100 /* E D J */
|
||||
#define PCRE_UNGREEDY 0x00000200 /* C1 */
|
||||
#define PCRE_NOTEMPTY 0x00000400 /* E D J */
|
||||
#define PCRE_UTF8 0x00000800 /* C4 ) */
|
||||
#define PCRE_UTF16 0x00000800 /* C4 ) Synonyms */
|
||||
#define PCRE_UTF32 0x00000800 /* C4 ) */
|
||||
#define PCRE_NO_AUTO_CAPTURE 0x00001000 /* C1 */
|
||||
#define PCRE_NO_UTF8_CHECK 0x00002000 /* C1 E D J ) */
|
||||
#define PCRE_NO_UTF16_CHECK 0x00002000 /* C1 E D J ) Synonyms */
|
||||
#define PCRE_NO_UTF32_CHECK 0x00002000 /* C1 E D J ) */
|
||||
#define PCRE_AUTO_CALLOUT 0x00004000 /* C1 */
|
||||
#define PCRE_PARTIAL_SOFT 0x00008000 /* E D J ) Synonyms */
|
||||
#define PCRE_PARTIAL 0x00008000 /* E D J ) */
|
||||
|
||||
/* This pair use the same bit. */
|
||||
#define PCRE_NEVER_UTF 0x00010000 /* C1 ) Overlaid */
|
||||
#define PCRE_DFA_SHORTEST 0x00010000 /* D ) Overlaid */
|
||||
|
||||
/* This pair use the same bit. */
|
||||
#define PCRE_NO_AUTO_POSSESS 0x00020000 /* C1 ) Overlaid */
|
||||
#define PCRE_DFA_RESTART 0x00020000 /* D ) Overlaid */
|
||||
|
||||
#define PCRE_FIRSTLINE 0x00040000 /* C3 */
|
||||
#define PCRE_DUPNAMES 0x00080000 /* C1 */
|
||||
#define PCRE_NEWLINE_CR 0x00100000 /* C3 E D */
|
||||
#define PCRE_NEWLINE_LF 0x00200000 /* C3 E D */
|
||||
#define PCRE_NEWLINE_CRLF 0x00300000 /* C3 E D */
|
||||
#define PCRE_NEWLINE_ANY 0x00400000 /* C3 E D */
|
||||
#define PCRE_NEWLINE_ANYCRLF 0x00500000 /* C3 E D */
|
||||
#define PCRE_BSR_ANYCRLF 0x00800000 /* C3 E D */
|
||||
#define PCRE_BSR_UNICODE 0x01000000 /* C3 E D */
|
||||
#define PCRE_JAVASCRIPT_COMPAT 0x02000000 /* C5 */
|
||||
#define PCRE_NO_START_OPTIMIZE 0x04000000 /* C2 E D ) Synonyms */
|
||||
#define PCRE_NO_START_OPTIMISE 0x04000000 /* C2 E D ) */
|
||||
#define PCRE_PARTIAL_HARD 0x08000000 /* E D J */
|
||||
#define PCRE_NOTEMPTY_ATSTART 0x10000000 /* E D J */
|
||||
#define PCRE_UCP 0x20000000 /* C3 */
|
||||
|
||||
/* Exec-time and get/set-time error codes */
|
||||
|
||||
#define PCRE_ERROR_NOMATCH (-1)
|
||||
#define PCRE_ERROR_NULL (-2)
|
||||
#define PCRE_ERROR_BADOPTION (-3)
|
||||
#define PCRE_ERROR_BADMAGIC (-4)
|
||||
#define PCRE_ERROR_UNKNOWN_NODE (-5)
|
||||
#define PCRE_ERROR_NOMEMORY (-6)
|
||||
#define PCRE_ERROR_NOSUBSTRING (-7)
|
||||
#define PCRE_ERROR_MATCHLIMIT (-8)
|
||||
#define PCRE_ERROR_CALLOUT (-9) /* Never used by PCRE itself */
|
||||
#define PCRE_ERROR_BADUTF8 (-10)
|
||||
#define PCRE_ERROR_BADUTF8_OFFSET (-11)
|
||||
#define PCRE_ERROR_PARTIAL (-12)
|
||||
#define PCRE_ERROR_BADPARTIAL (-13)
|
||||
#define PCRE_ERROR_INTERNAL (-14)
|
||||
#define PCRE_ERROR_BADCOUNT (-15)
|
||||
#define PCRE_ERROR_DFA_UITEM (-16)
|
||||
#define PCRE_ERROR_DFA_UCOND (-17)
|
||||
#define PCRE_ERROR_DFA_UMLIMIT (-18)
|
||||
#define PCRE_ERROR_DFA_WSSIZE (-19)
|
||||
#define PCRE_ERROR_DFA_RECURSE (-20)
|
||||
#define PCRE_ERROR_NOMATCH (-1)
|
||||
#define PCRE_ERROR_NULL (-2)
|
||||
#define PCRE_ERROR_BADOPTION (-3)
|
||||
#define PCRE_ERROR_BADMAGIC (-4)
|
||||
#define PCRE_ERROR_UNKNOWN_OPCODE (-5)
|
||||
#define PCRE_ERROR_UNKNOWN_NODE (-5) /* For backward compatibility */
|
||||
#define PCRE_ERROR_NOMEMORY (-6)
|
||||
#define PCRE_ERROR_NOSUBSTRING (-7)
|
||||
#define PCRE_ERROR_MATCHLIMIT (-8)
|
||||
#define PCRE_ERROR_CALLOUT (-9) /* Never used by PCRE itself */
|
||||
#define PCRE_ERROR_BADUTF8 (-10) /* Same for 8/16/32 */
|
||||
#define PCRE_ERROR_BADUTF16 (-10) /* Same for 8/16/32 */
|
||||
#define PCRE_ERROR_BADUTF32 (-10) /* Same for 8/16/32 */
|
||||
#define PCRE_ERROR_BADUTF8_OFFSET (-11) /* Same for 8/16 */
|
||||
#define PCRE_ERROR_BADUTF16_OFFSET (-11) /* Same for 8/16 */
|
||||
#define PCRE_ERROR_PARTIAL (-12)
|
||||
#define PCRE_ERROR_BADPARTIAL (-13)
|
||||
#define PCRE_ERROR_INTERNAL (-14)
|
||||
#define PCRE_ERROR_BADCOUNT (-15)
|
||||
#define PCRE_ERROR_DFA_UITEM (-16)
|
||||
#define PCRE_ERROR_DFA_UCOND (-17)
|
||||
#define PCRE_ERROR_DFA_UMLIMIT (-18)
|
||||
#define PCRE_ERROR_DFA_WSSIZE (-19)
|
||||
#define PCRE_ERROR_DFA_RECURSE (-20)
|
||||
#define PCRE_ERROR_RECURSIONLIMIT (-21)
|
||||
#define PCRE_ERROR_NULLWSLIMIT (-22) /* No longer actually used */
|
||||
#define PCRE_ERROR_BADNEWLINE (-23)
|
||||
#define PCRE_ERROR_BADOFFSET (-24)
|
||||
#define PCRE_ERROR_SHORTUTF8 (-25)
|
||||
#define PCRE_ERROR_SHORTUTF16 (-25) /* Same for 8/16 */
|
||||
#define PCRE_ERROR_RECURSELOOP (-26)
|
||||
#define PCRE_ERROR_JIT_STACKLIMIT (-27)
|
||||
#define PCRE_ERROR_BADMODE (-28)
|
||||
#define PCRE_ERROR_BADENDIANNESS (-29)
|
||||
#define PCRE_ERROR_DFA_BADRESTART (-30)
|
||||
#define PCRE_ERROR_JIT_BADOPTION (-31)
|
||||
#define PCRE_ERROR_BADLENGTH (-32)
|
||||
#define PCRE_ERROR_UNSET (-33)
|
||||
|
||||
/* Specific error codes for UTF-8 validity checks */
|
||||
|
||||
#define PCRE_UTF8_ERR0 0
|
||||
#define PCRE_UTF8_ERR1 1
|
||||
#define PCRE_UTF8_ERR2 2
|
||||
#define PCRE_UTF8_ERR3 3
|
||||
#define PCRE_UTF8_ERR4 4
|
||||
#define PCRE_UTF8_ERR5 5
|
||||
#define PCRE_UTF8_ERR6 6
|
||||
#define PCRE_UTF8_ERR7 7
|
||||
#define PCRE_UTF8_ERR8 8
|
||||
#define PCRE_UTF8_ERR9 9
|
||||
#define PCRE_UTF8_ERR10 10
|
||||
#define PCRE_UTF8_ERR11 11
|
||||
#define PCRE_UTF8_ERR12 12
|
||||
#define PCRE_UTF8_ERR13 13
|
||||
#define PCRE_UTF8_ERR14 14
|
||||
#define PCRE_UTF8_ERR15 15
|
||||
#define PCRE_UTF8_ERR16 16
|
||||
#define PCRE_UTF8_ERR17 17
|
||||
#define PCRE_UTF8_ERR18 18
|
||||
#define PCRE_UTF8_ERR19 19
|
||||
#define PCRE_UTF8_ERR20 20
|
||||
#define PCRE_UTF8_ERR21 21
|
||||
#define PCRE_UTF8_ERR22 22 /* Unused (was non-character) */
|
||||
|
||||
/* Specific error codes for UTF-16 validity checks */
|
||||
|
||||
#define PCRE_UTF16_ERR0 0
|
||||
#define PCRE_UTF16_ERR1 1
|
||||
#define PCRE_UTF16_ERR2 2
|
||||
#define PCRE_UTF16_ERR3 3
|
||||
#define PCRE_UTF16_ERR4 4 /* Unused (was non-character) */
|
||||
|
||||
/* Specific error codes for UTF-32 validity checks */
|
||||
|
||||
#define PCRE_UTF32_ERR0 0
|
||||
#define PCRE_UTF32_ERR1 1
|
||||
#define PCRE_UTF32_ERR2 2 /* Unused (was non-character) */
|
||||
#define PCRE_UTF32_ERR3 3
|
||||
|
||||
/* Request types for pcre_fullinfo() */
|
||||
|
||||
@ -141,8 +267,23 @@ extern "C" {
|
||||
#define PCRE_INFO_NAMETABLE 9
|
||||
#define PCRE_INFO_STUDYSIZE 10
|
||||
#define PCRE_INFO_DEFAULT_TABLES 11
|
||||
#define PCRE_INFO_OKPARTIAL 12
|
||||
#define PCRE_INFO_JCHANGED 13
|
||||
#define PCRE_INFO_HASCRORLF 14
|
||||
#define PCRE_INFO_MINLENGTH 15
|
||||
#define PCRE_INFO_JIT 16
|
||||
#define PCRE_INFO_JITSIZE 17
|
||||
#define PCRE_INFO_MAXLOOKBEHIND 18
|
||||
#define PCRE_INFO_FIRSTCHARACTER 19
|
||||
#define PCRE_INFO_FIRSTCHARACTERFLAGS 20
|
||||
#define PCRE_INFO_REQUIREDCHAR 21
|
||||
#define PCRE_INFO_REQUIREDCHARFLAGS 22
|
||||
#define PCRE_INFO_MATCHLIMIT 23
|
||||
#define PCRE_INFO_RECURSIONLIMIT 24
|
||||
#define PCRE_INFO_MATCH_EMPTY 25
|
||||
|
||||
/* Request types for pcre_config() */
|
||||
/* Request types for pcre_config(). Do not re-arrange, in order to remain
|
||||
compatible. */
|
||||
|
||||
#define PCRE_CONFIG_UTF8 0
|
||||
#define PCRE_CONFIG_NEWLINE 1
|
||||
@ -151,19 +292,83 @@ extern "C" {
|
||||
#define PCRE_CONFIG_MATCH_LIMIT 4
|
||||
#define PCRE_CONFIG_STACKRECURSE 5
|
||||
#define PCRE_CONFIG_UNICODE_PROPERTIES 6
|
||||
#define PCRE_CONFIG_MATCH_LIMIT_RECURSION 7
|
||||
#define PCRE_CONFIG_BSR 8
|
||||
#define PCRE_CONFIG_JIT 9
|
||||
#define PCRE_CONFIG_UTF16 10
|
||||
#define PCRE_CONFIG_JITTARGET 11
|
||||
#define PCRE_CONFIG_UTF32 12
|
||||
#define PCRE_CONFIG_PARENS_LIMIT 13
|
||||
|
||||
/* Bit flags for the pcre_extra structure */
|
||||
/* Request types for pcre_study(). Do not re-arrange, in order to remain
|
||||
compatible. */
|
||||
|
||||
#define PCRE_EXTRA_STUDY_DATA 0x0001
|
||||
#define PCRE_EXTRA_MATCH_LIMIT 0x0002
|
||||
#define PCRE_EXTRA_CALLOUT_DATA 0x0004
|
||||
#define PCRE_EXTRA_TABLES 0x0008
|
||||
#define PCRE_STUDY_JIT_COMPILE 0x0001
|
||||
#define PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE 0x0002
|
||||
#define PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE 0x0004
|
||||
#define PCRE_STUDY_EXTRA_NEEDED 0x0008
|
||||
|
||||
/* Bit flags for the pcre[16|32]_extra structure. Do not re-arrange or redefine
|
||||
these bits, just add new ones on the end, in order to remain compatible. */
|
||||
|
||||
#define PCRE_EXTRA_STUDY_DATA 0x0001
|
||||
#define PCRE_EXTRA_MATCH_LIMIT 0x0002
|
||||
#define PCRE_EXTRA_CALLOUT_DATA 0x0004
|
||||
#define PCRE_EXTRA_TABLES 0x0008
|
||||
#define PCRE_EXTRA_MATCH_LIMIT_RECURSION 0x0010
|
||||
#define PCRE_EXTRA_MARK 0x0020
|
||||
#define PCRE_EXTRA_EXECUTABLE_JIT 0x0040
|
||||
|
||||
/* Types */
|
||||
|
||||
struct real_pcre; /* declaration; the definition is private */
|
||||
typedef struct real_pcre pcre;
|
||||
|
||||
struct real_pcre16; /* declaration; the definition is private */
|
||||
typedef struct real_pcre16 pcre16;
|
||||
|
||||
struct real_pcre32; /* declaration; the definition is private */
|
||||
typedef struct real_pcre32 pcre32;
|
||||
|
||||
struct real_pcre_jit_stack; /* declaration; the definition is private */
|
||||
typedef struct real_pcre_jit_stack pcre_jit_stack;
|
||||
|
||||
struct real_pcre16_jit_stack; /* declaration; the definition is private */
|
||||
typedef struct real_pcre16_jit_stack pcre16_jit_stack;
|
||||
|
||||
struct real_pcre32_jit_stack; /* declaration; the definition is private */
|
||||
typedef struct real_pcre32_jit_stack pcre32_jit_stack;
|
||||
|
||||
/* If PCRE is compiled with 16 bit character support, PCRE_UCHAR16 must contain
|
||||
a 16 bit wide signed data type. Otherwise it can be a dummy data type since
|
||||
pcre16 functions are not implemented. There is a check for this in pcre_internal.h. */
|
||||
#ifndef PCRE_UCHAR16
|
||||
#define PCRE_UCHAR16 unsigned short
|
||||
#endif
|
||||
|
||||
#ifndef PCRE_SPTR16
|
||||
#define PCRE_SPTR16 const PCRE_UCHAR16 *
|
||||
#endif
|
||||
|
||||
/* If PCRE is compiled with 32 bit character support, PCRE_UCHAR32 must contain
|
||||
a 32 bit wide signed data type. Otherwise it can be a dummy data type since
|
||||
pcre32 functions are not implemented. There is a check for this in pcre_internal.h. */
|
||||
#ifndef PCRE_UCHAR32
|
||||
#define PCRE_UCHAR32 unsigned int
|
||||
#endif
|
||||
|
||||
#ifndef PCRE_SPTR32
|
||||
#define PCRE_SPTR32 const PCRE_UCHAR32 *
|
||||
#endif
|
||||
|
||||
/* When PCRE is compiled as a C++ library, the subject pointer type can be
|
||||
replaced with a custom type. For conventional use, the public interface is a
|
||||
const char *. */
|
||||
|
||||
#ifndef PCRE_SPTR
|
||||
#define PCRE_SPTR const char *
|
||||
#endif
|
||||
|
||||
/* The structure for passing additional data to pcre_exec(). This is defined in
|
||||
such as way as to be extensible. Always add new fields at the end, in order to
|
||||
remain compatible. */
|
||||
@ -174,8 +379,37 @@ typedef struct pcre_extra {
|
||||
unsigned long int match_limit; /* Maximum number of calls to match() */
|
||||
void *callout_data; /* Data passed back in callouts */
|
||||
const unsigned char *tables; /* Pointer to character tables */
|
||||
unsigned long int match_limit_recursion; /* Max recursive calls to match() */
|
||||
unsigned char **mark; /* For passing back a mark pointer */
|
||||
void *executable_jit; /* Contains a pointer to a compiled jit code */
|
||||
} pcre_extra;
|
||||
|
||||
/* Same structure as above, but with 16 bit char pointers. */
|
||||
|
||||
typedef struct pcre16_extra {
|
||||
unsigned long int flags; /* Bits for which fields are set */
|
||||
void *study_data; /* Opaque data from pcre_study() */
|
||||
unsigned long int match_limit; /* Maximum number of calls to match() */
|
||||
void *callout_data; /* Data passed back in callouts */
|
||||
const unsigned char *tables; /* Pointer to character tables */
|
||||
unsigned long int match_limit_recursion; /* Max recursive calls to match() */
|
||||
PCRE_UCHAR16 **mark; /* For passing back a mark pointer */
|
||||
void *executable_jit; /* Contains a pointer to a compiled jit code */
|
||||
} pcre16_extra;
|
||||
|
||||
/* Same structure as above, but with 32 bit char pointers. */
|
||||
|
||||
typedef struct pcre32_extra {
|
||||
unsigned long int flags; /* Bits for which fields are set */
|
||||
void *study_data; /* Opaque data from pcre_study() */
|
||||
unsigned long int match_limit; /* Maximum number of calls to match() */
|
||||
void *callout_data; /* Data passed back in callouts */
|
||||
const unsigned char *tables; /* Pointer to character tables */
|
||||
unsigned long int match_limit_recursion; /* Max recursive calls to match() */
|
||||
PCRE_UCHAR32 **mark; /* For passing back a mark pointer */
|
||||
void *executable_jit; /* Contains a pointer to a compiled jit code */
|
||||
} pcre32_extra;
|
||||
|
||||
/* The structure for passing out data via the pcre_callout_function. We use a
|
||||
structure so that new fields can be added on the end in future versions,
|
||||
without changing the API of the function, thereby allowing old clients to work
|
||||
@ -186,7 +420,7 @@ typedef struct pcre_callout_block {
|
||||
/* ------------------------ Version 0 ------------------------------- */
|
||||
int callout_number; /* Number compiled into pattern */
|
||||
int *offset_vector; /* The offset vector */
|
||||
const char *subject; /* The subject being matched */
|
||||
PCRE_SPTR subject; /* The subject being matched */
|
||||
int subject_length; /* The length of the subject */
|
||||
int start_match; /* Offset to start of this match attempt */
|
||||
int current_position; /* Where we currently are in the subject */
|
||||
@ -196,9 +430,55 @@ typedef struct pcre_callout_block {
|
||||
/* ------------------- Added for Version 1 -------------------------- */
|
||||
int pattern_position; /* Offset to next item in the pattern */
|
||||
int next_item_length; /* Length of next item in the pattern */
|
||||
/* ------------------- Added for Version 2 -------------------------- */
|
||||
const unsigned char *mark; /* Pointer to current mark or NULL */
|
||||
/* ------------------------------------------------------------------ */
|
||||
} pcre_callout_block;
|
||||
|
||||
/* Same structure as above, but with 16 bit char pointers. */
|
||||
|
||||
typedef struct pcre16_callout_block {
|
||||
int version; /* Identifies version of block */
|
||||
/* ------------------------ Version 0 ------------------------------- */
|
||||
int callout_number; /* Number compiled into pattern */
|
||||
int *offset_vector; /* The offset vector */
|
||||
PCRE_SPTR16 subject; /* The subject being matched */
|
||||
int subject_length; /* The length of the subject */
|
||||
int start_match; /* Offset to start of this match attempt */
|
||||
int current_position; /* Where we currently are in the subject */
|
||||
int capture_top; /* Max current capture */
|
||||
int capture_last; /* Most recently closed capture */
|
||||
void *callout_data; /* Data passed in with the call */
|
||||
/* ------------------- Added for Version 1 -------------------------- */
|
||||
int pattern_position; /* Offset to next item in the pattern */
|
||||
int next_item_length; /* Length of next item in the pattern */
|
||||
/* ------------------- Added for Version 2 -------------------------- */
|
||||
const PCRE_UCHAR16 *mark; /* Pointer to current mark or NULL */
|
||||
/* ------------------------------------------------------------------ */
|
||||
} pcre16_callout_block;
|
||||
|
||||
/* Same structure as above, but with 32 bit char pointers. */
|
||||
|
||||
typedef struct pcre32_callout_block {
|
||||
int version; /* Identifies version of block */
|
||||
/* ------------------------ Version 0 ------------------------------- */
|
||||
int callout_number; /* Number compiled into pattern */
|
||||
int *offset_vector; /* The offset vector */
|
||||
PCRE_SPTR32 subject; /* The subject being matched */
|
||||
int subject_length; /* The length of the subject */
|
||||
int start_match; /* Offset to start of this match attempt */
|
||||
int current_position; /* Where we currently are in the subject */
|
||||
int capture_top; /* Max current capture */
|
||||
int capture_last; /* Most recently closed capture */
|
||||
void *callout_data; /* Data passed in with the call */
|
||||
/* ------------------- Added for Version 1 -------------------------- */
|
||||
int pattern_position; /* Offset to next item in the pattern */
|
||||
int next_item_length; /* Length of next item in the pattern */
|
||||
/* ------------------- Added for Version 2 -------------------------- */
|
||||
const PCRE_UCHAR32 *mark; /* Pointer to current mark or NULL */
|
||||
/* ------------------------------------------------------------------ */
|
||||
} pcre32_callout_block;
|
||||
|
||||
/* Indirection for store get and free functions. These can be set to
|
||||
alternative malloc/free functions if required. Special ones are used in the
|
||||
non-recursive case for "frames". There is also an optional callout function
|
||||
@ -206,50 +486,189 @@ that is triggered by the (?) regex item. For Virtual Pascal, these definitions
|
||||
have to take another form. */
|
||||
|
||||
#ifndef VPCOMPAT
|
||||
PCRE_DATA_SCOPE void *(*pcre_malloc)(size_t);
|
||||
PCRE_DATA_SCOPE void (*pcre_free)(void *);
|
||||
PCRE_DATA_SCOPE void *(*pcre_stack_malloc)(size_t);
|
||||
PCRE_DATA_SCOPE void (*pcre_stack_free)(void *);
|
||||
PCRE_DATA_SCOPE int (*pcre_callout)(pcre_callout_block *);
|
||||
PCRE_EXP_DECL void *(*pcre_malloc)(size_t);
|
||||
PCRE_EXP_DECL void (*pcre_free)(void *);
|
||||
PCRE_EXP_DECL void *(*pcre_stack_malloc)(size_t);
|
||||
PCRE_EXP_DECL void (*pcre_stack_free)(void *);
|
||||
PCRE_EXP_DECL int (*pcre_callout)(pcre_callout_block *);
|
||||
PCRE_EXP_DECL int (*pcre_stack_guard)(void);
|
||||
|
||||
PCRE_EXP_DECL void *(*pcre16_malloc)(size_t);
|
||||
PCRE_EXP_DECL void (*pcre16_free)(void *);
|
||||
PCRE_EXP_DECL void *(*pcre16_stack_malloc)(size_t);
|
||||
PCRE_EXP_DECL void (*pcre16_stack_free)(void *);
|
||||
PCRE_EXP_DECL int (*pcre16_callout)(pcre16_callout_block *);
|
||||
PCRE_EXP_DECL int (*pcre16_stack_guard)(void);
|
||||
|
||||
PCRE_EXP_DECL void *(*pcre32_malloc)(size_t);
|
||||
PCRE_EXP_DECL void (*pcre32_free)(void *);
|
||||
PCRE_EXP_DECL void *(*pcre32_stack_malloc)(size_t);
|
||||
PCRE_EXP_DECL void (*pcre32_stack_free)(void *);
|
||||
PCRE_EXP_DECL int (*pcre32_callout)(pcre32_callout_block *);
|
||||
PCRE_EXP_DECL int (*pcre32_stack_guard)(void);
|
||||
#else /* VPCOMPAT */
|
||||
PCRE_DATA_SCOPE void *pcre_malloc(size_t);
|
||||
PCRE_DATA_SCOPE void pcre_free(void *);
|
||||
PCRE_DATA_SCOPE void *pcre_stack_malloc(size_t);
|
||||
PCRE_DATA_SCOPE void pcre_stack_free(void *);
|
||||
PCRE_DATA_SCOPE int pcre_callout(pcre_callout_block *);
|
||||
PCRE_EXP_DECL void *pcre_malloc(size_t);
|
||||
PCRE_EXP_DECL void pcre_free(void *);
|
||||
PCRE_EXP_DECL void *pcre_stack_malloc(size_t);
|
||||
PCRE_EXP_DECL void pcre_stack_free(void *);
|
||||
PCRE_EXP_DECL int pcre_callout(pcre_callout_block *);
|
||||
PCRE_EXP_DECL int pcre_stack_guard(void);
|
||||
|
||||
PCRE_EXP_DECL void *pcre16_malloc(size_t);
|
||||
PCRE_EXP_DECL void pcre16_free(void *);
|
||||
PCRE_EXP_DECL void *pcre16_stack_malloc(size_t);
|
||||
PCRE_EXP_DECL void pcre16_stack_free(void *);
|
||||
PCRE_EXP_DECL int pcre16_callout(pcre16_callout_block *);
|
||||
PCRE_EXP_DECL int pcre16_stack_guard(void);
|
||||
|
||||
PCRE_EXP_DECL void *pcre32_malloc(size_t);
|
||||
PCRE_EXP_DECL void pcre32_free(void *);
|
||||
PCRE_EXP_DECL void *pcre32_stack_malloc(size_t);
|
||||
PCRE_EXP_DECL void pcre32_stack_free(void *);
|
||||
PCRE_EXP_DECL int pcre32_callout(pcre32_callout_block *);
|
||||
PCRE_EXP_DECL int pcre32_stack_guard(void);
|
||||
#endif /* VPCOMPAT */
|
||||
|
||||
/* User defined callback which provides a stack just before the match starts. */
|
||||
|
||||
typedef pcre_jit_stack *(*pcre_jit_callback)(void *);
|
||||
typedef pcre16_jit_stack *(*pcre16_jit_callback)(void *);
|
||||
typedef pcre32_jit_stack *(*pcre32_jit_callback)(void *);
|
||||
|
||||
/* Exported PCRE functions */
|
||||
|
||||
PCRE_DATA_SCOPE pcre *pcre_compile(const char *, int, const char **, int *,
|
||||
PCRE_EXP_DECL pcre *pcre_compile(const char *, int, const char **, int *,
|
||||
const unsigned char *);
|
||||
PCRE_DATA_SCOPE pcre *pcre_compile2(const char *, int, int *, const char **,
|
||||
PCRE_EXP_DECL pcre16 *pcre16_compile(PCRE_SPTR16, int, const char **, int *,
|
||||
const unsigned char *);
|
||||
PCRE_EXP_DECL pcre32 *pcre32_compile(PCRE_SPTR32, int, const char **, int *,
|
||||
const unsigned char *);
|
||||
PCRE_EXP_DECL pcre *pcre_compile2(const char *, int, int *, const char **,
|
||||
int *, const unsigned char *);
|
||||
PCRE_DATA_SCOPE int pcre_config(int, void *);
|
||||
PCRE_DATA_SCOPE int pcre_copy_named_substring(const pcre *, const char *,
|
||||
PCRE_EXP_DECL pcre16 *pcre16_compile2(PCRE_SPTR16, int, int *, const char **,
|
||||
int *, const unsigned char *);
|
||||
PCRE_EXP_DECL pcre32 *pcre32_compile2(PCRE_SPTR32, int, int *, const char **,
|
||||
int *, const unsigned char *);
|
||||
PCRE_EXP_DECL int pcre_config(int, void *);
|
||||
PCRE_EXP_DECL int pcre16_config(int, void *);
|
||||
PCRE_EXP_DECL int pcre32_config(int, void *);
|
||||
PCRE_EXP_DECL int pcre_copy_named_substring(const pcre *, const char *,
|
||||
int *, int, const char *, char *, int);
|
||||
PCRE_DATA_SCOPE int pcre_copy_substring(const char *, int *, int, int, char *,
|
||||
int);
|
||||
PCRE_DATA_SCOPE int pcre_dfa_exec(const pcre *, const pcre_extra *,
|
||||
PCRE_EXP_DECL int pcre16_copy_named_substring(const pcre16 *, PCRE_SPTR16,
|
||||
int *, int, PCRE_SPTR16, PCRE_UCHAR16 *, int);
|
||||
PCRE_EXP_DECL int pcre32_copy_named_substring(const pcre32 *, PCRE_SPTR32,
|
||||
int *, int, PCRE_SPTR32, PCRE_UCHAR32 *, int);
|
||||
PCRE_EXP_DECL int pcre_copy_substring(const char *, int *, int, int,
|
||||
char *, int);
|
||||
PCRE_EXP_DECL int pcre16_copy_substring(PCRE_SPTR16, int *, int, int,
|
||||
PCRE_UCHAR16 *, int);
|
||||
PCRE_EXP_DECL int pcre32_copy_substring(PCRE_SPTR32, int *, int, int,
|
||||
PCRE_UCHAR32 *, int);
|
||||
PCRE_EXP_DECL int pcre_dfa_exec(const pcre *, const pcre_extra *,
|
||||
const char *, int, int, int, int *, int , int *, int);
|
||||
PCRE_DATA_SCOPE int pcre_exec(const pcre *, const pcre_extra *, const char *,
|
||||
PCRE_EXP_DECL int pcre16_dfa_exec(const pcre16 *, const pcre16_extra *,
|
||||
PCRE_SPTR16, int, int, int, int *, int , int *, int);
|
||||
PCRE_EXP_DECL int pcre32_dfa_exec(const pcre32 *, const pcre32_extra *,
|
||||
PCRE_SPTR32, int, int, int, int *, int , int *, int);
|
||||
PCRE_EXP_DECL int pcre_exec(const pcre *, const pcre_extra *, PCRE_SPTR,
|
||||
int, int, int, int *, int);
|
||||
PCRE_DATA_SCOPE void pcre_free_substring(const char *);
|
||||
PCRE_DATA_SCOPE void pcre_free_substring_list(const char **);
|
||||
PCRE_DATA_SCOPE int pcre_fullinfo(const pcre *, const pcre_extra *, int,
|
||||
PCRE_EXP_DECL int pcre16_exec(const pcre16 *, const pcre16_extra *,
|
||||
PCRE_SPTR16, int, int, int, int *, int);
|
||||
PCRE_EXP_DECL int pcre32_exec(const pcre32 *, const pcre32_extra *,
|
||||
PCRE_SPTR32, int, int, int, int *, int);
|
||||
PCRE_EXP_DECL int pcre_jit_exec(const pcre *, const pcre_extra *,
|
||||
PCRE_SPTR, int, int, int, int *, int,
|
||||
pcre_jit_stack *);
|
||||
PCRE_EXP_DECL int pcre16_jit_exec(const pcre16 *, const pcre16_extra *,
|
||||
PCRE_SPTR16, int, int, int, int *, int,
|
||||
pcre16_jit_stack *);
|
||||
PCRE_EXP_DECL int pcre32_jit_exec(const pcre32 *, const pcre32_extra *,
|
||||
PCRE_SPTR32, int, int, int, int *, int,
|
||||
pcre32_jit_stack *);
|
||||
PCRE_EXP_DECL void pcre_free_substring(const char *);
|
||||
PCRE_EXP_DECL void pcre16_free_substring(PCRE_SPTR16);
|
||||
PCRE_EXP_DECL void pcre32_free_substring(PCRE_SPTR32);
|
||||
PCRE_EXP_DECL void pcre_free_substring_list(const char **);
|
||||
PCRE_EXP_DECL void pcre16_free_substring_list(PCRE_SPTR16 *);
|
||||
PCRE_EXP_DECL void pcre32_free_substring_list(PCRE_SPTR32 *);
|
||||
PCRE_EXP_DECL int pcre_fullinfo(const pcre *, const pcre_extra *, int,
|
||||
void *);
|
||||
PCRE_DATA_SCOPE int pcre_get_named_substring(const pcre *, const char *,
|
||||
PCRE_EXP_DECL int pcre16_fullinfo(const pcre16 *, const pcre16_extra *, int,
|
||||
void *);
|
||||
PCRE_EXP_DECL int pcre32_fullinfo(const pcre32 *, const pcre32_extra *, int,
|
||||
void *);
|
||||
PCRE_EXP_DECL int pcre_get_named_substring(const pcre *, const char *,
|
||||
int *, int, const char *, const char **);
|
||||
PCRE_DATA_SCOPE int pcre_get_stringnumber(const pcre *, const char *);
|
||||
PCRE_DATA_SCOPE int pcre_get_substring(const char *, int *, int, int,
|
||||
PCRE_EXP_DECL int pcre16_get_named_substring(const pcre16 *, PCRE_SPTR16,
|
||||
int *, int, PCRE_SPTR16, PCRE_SPTR16 *);
|
||||
PCRE_EXP_DECL int pcre32_get_named_substring(const pcre32 *, PCRE_SPTR32,
|
||||
int *, int, PCRE_SPTR32, PCRE_SPTR32 *);
|
||||
PCRE_EXP_DECL int pcre_get_stringnumber(const pcre *, const char *);
|
||||
PCRE_EXP_DECL int pcre16_get_stringnumber(const pcre16 *, PCRE_SPTR16);
|
||||
PCRE_EXP_DECL int pcre32_get_stringnumber(const pcre32 *, PCRE_SPTR32);
|
||||
PCRE_EXP_DECL int pcre_get_stringtable_entries(const pcre *, const char *,
|
||||
char **, char **);
|
||||
PCRE_EXP_DECL int pcre16_get_stringtable_entries(const pcre16 *, PCRE_SPTR16,
|
||||
PCRE_UCHAR16 **, PCRE_UCHAR16 **);
|
||||
PCRE_EXP_DECL int pcre32_get_stringtable_entries(const pcre32 *, PCRE_SPTR32,
|
||||
PCRE_UCHAR32 **, PCRE_UCHAR32 **);
|
||||
PCRE_EXP_DECL int pcre_get_substring(const char *, int *, int, int,
|
||||
const char **);
|
||||
PCRE_DATA_SCOPE int pcre_get_substring_list(const char *, int *, int,
|
||||
PCRE_EXP_DECL int pcre16_get_substring(PCRE_SPTR16, int *, int, int,
|
||||
PCRE_SPTR16 *);
|
||||
PCRE_EXP_DECL int pcre32_get_substring(PCRE_SPTR32, int *, int, int,
|
||||
PCRE_SPTR32 *);
|
||||
PCRE_EXP_DECL int pcre_get_substring_list(const char *, int *, int,
|
||||
const char ***);
|
||||
PCRE_DATA_SCOPE int pcre_info(const pcre *, int *, int *);
|
||||
PCRE_DATA_SCOPE const unsigned char *pcre_maketables(void);
|
||||
PCRE_DATA_SCOPE int pcre_refcount(pcre *, int);
|
||||
PCRE_DATA_SCOPE pcre_extra *pcre_study(const pcre *, int, const char **);
|
||||
PCRE_DATA_SCOPE const char *pcre_version(void);
|
||||
PCRE_EXP_DECL int pcre16_get_substring_list(PCRE_SPTR16, int *, int,
|
||||
PCRE_SPTR16 **);
|
||||
PCRE_EXP_DECL int pcre32_get_substring_list(PCRE_SPTR32, int *, int,
|
||||
PCRE_SPTR32 **);
|
||||
PCRE_EXP_DECL const unsigned char *pcre_maketables(void);
|
||||
PCRE_EXP_DECL const unsigned char *pcre16_maketables(void);
|
||||
PCRE_EXP_DECL const unsigned char *pcre32_maketables(void);
|
||||
PCRE_EXP_DECL int pcre_refcount(pcre *, int);
|
||||
PCRE_EXP_DECL int pcre16_refcount(pcre16 *, int);
|
||||
PCRE_EXP_DECL int pcre32_refcount(pcre32 *, int);
|
||||
PCRE_EXP_DECL pcre_extra *pcre_study(const pcre *, int, const char **);
|
||||
PCRE_EXP_DECL pcre16_extra *pcre16_study(const pcre16 *, int, const char **);
|
||||
PCRE_EXP_DECL pcre32_extra *pcre32_study(const pcre32 *, int, const char **);
|
||||
PCRE_EXP_DECL void pcre_free_study(pcre_extra *);
|
||||
PCRE_EXP_DECL void pcre16_free_study(pcre16_extra *);
|
||||
PCRE_EXP_DECL void pcre32_free_study(pcre32_extra *);
|
||||
PCRE_EXP_DECL const char *pcre_version(void);
|
||||
PCRE_EXP_DECL const char *pcre16_version(void);
|
||||
PCRE_EXP_DECL const char *pcre32_version(void);
|
||||
|
||||
/* Utility functions for byte order swaps. */
|
||||
PCRE_EXP_DECL int pcre_pattern_to_host_byte_order(pcre *, pcre_extra *,
|
||||
const unsigned char *);
|
||||
PCRE_EXP_DECL int pcre16_pattern_to_host_byte_order(pcre16 *, pcre16_extra *,
|
||||
const unsigned char *);
|
||||
PCRE_EXP_DECL int pcre32_pattern_to_host_byte_order(pcre32 *, pcre32_extra *,
|
||||
const unsigned char *);
|
||||
PCRE_EXP_DECL int pcre16_utf16_to_host_byte_order(PCRE_UCHAR16 *,
|
||||
PCRE_SPTR16, int, int *, int);
|
||||
PCRE_EXP_DECL int pcre32_utf32_to_host_byte_order(PCRE_UCHAR32 *,
|
||||
PCRE_SPTR32, int, int *, int);
|
||||
|
||||
/* JIT compiler related functions. */
|
||||
|
||||
PCRE_EXP_DECL pcre_jit_stack *pcre_jit_stack_alloc(int, int);
|
||||
PCRE_EXP_DECL pcre16_jit_stack *pcre16_jit_stack_alloc(int, int);
|
||||
PCRE_EXP_DECL pcre32_jit_stack *pcre32_jit_stack_alloc(int, int);
|
||||
PCRE_EXP_DECL void pcre_jit_stack_free(pcre_jit_stack *);
|
||||
PCRE_EXP_DECL void pcre16_jit_stack_free(pcre16_jit_stack *);
|
||||
PCRE_EXP_DECL void pcre32_jit_stack_free(pcre32_jit_stack *);
|
||||
PCRE_EXP_DECL void pcre_assign_jit_stack(pcre_extra *,
|
||||
pcre_jit_callback, void *);
|
||||
PCRE_EXP_DECL void pcre16_assign_jit_stack(pcre16_extra *,
|
||||
pcre16_jit_callback, void *);
|
||||
PCRE_EXP_DECL void pcre32_assign_jit_stack(pcre32_extra *,
|
||||
pcre32_jit_callback, void *);
|
||||
PCRE_EXP_DECL void pcre_jit_free_unused_memory(void);
|
||||
PCRE_EXP_DECL void pcre16_jit_free_unused_memory(void);
|
||||
PCRE_EXP_DECL void pcre32_jit_free_unused_memory(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
241
dlls/regex/utils.cpp
Normal file
241
dlls/regex/utils.cpp
Normal file
@ -0,0 +1,241 @@
|
||||
|
||||
#include "amxxmodule.h"
|
||||
#include <string.h>
|
||||
#include "utils.h"
|
||||
|
||||
#if defined(WIN32)
|
||||
#define strcasecmp stricmp
|
||||
#define strncasecmp _strnicmp
|
||||
#endif
|
||||
|
||||
int UTIL_CheckValidChar(char *c)
|
||||
{
|
||||
int count;
|
||||
int bytecount = 0;
|
||||
|
||||
for (count = 1; (*c & 0xC0) == 0x80; count++)
|
||||
{
|
||||
c--;
|
||||
}
|
||||
|
||||
switch (*c & 0xF0)
|
||||
{
|
||||
case 0xC0:
|
||||
case 0xD0:
|
||||
{
|
||||
bytecount = 2;
|
||||
break;
|
||||
}
|
||||
case 0xE0:
|
||||
{
|
||||
bytecount = 3;
|
||||
break;
|
||||
}
|
||||
case 0xF0:
|
||||
{
|
||||
bytecount = 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bytecount != count)
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int strncopy(char *dest, const char *src, size_t count)
|
||||
{
|
||||
if (!count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *start = dest;
|
||||
while ((*src) && (--count))
|
||||
{
|
||||
*dest++ = *src++;
|
||||
}
|
||||
*dest = '\0';
|
||||
|
||||
return (dest - start);
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: Do not edit this for the love of god unless you have
|
||||
* read the test cases and understand the code behind each one.
|
||||
* While I don't guarantee there aren't mistakes, I do guarantee
|
||||
* that plugins will end up relying on tiny idiosyncrasies of this
|
||||
* function, just like they did with AMX Mod X.
|
||||
*
|
||||
* There are explicitly more cases than the AMX Mod X version because
|
||||
* we're not doing a blind copy. Each case is specifically optimized
|
||||
* for what needs to be done. Even better, we don't have to error on
|
||||
* bad buffer sizes. Instead, this function will smartly cut off the
|
||||
* string in a way that pushes old data out.
|
||||
*/
|
||||
char *UTIL_ReplaceEx(char *subject, size_t maxLen, const char *search, size_t searchLen, const char *replace, size_t replaceLen, bool caseSensitive)
|
||||
{
|
||||
char *ptr = subject;
|
||||
size_t browsed = 0;
|
||||
size_t textLen = strlen(subject);
|
||||
|
||||
/* It's not possible to search or replace */
|
||||
if (searchLen > textLen)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Handle the case of one byte replacement.
|
||||
* It's only valid in one case.
|
||||
*/
|
||||
if (maxLen == 1)
|
||||
{
|
||||
/* If the search matches and the replace length is 0,
|
||||
* we can just terminate the string and be done.
|
||||
*/
|
||||
if ((caseSensitive ? strcmp(subject, search) : strcasecmp(subject, search)) == 0 && replaceLen == 0)
|
||||
{
|
||||
*subject = '\0';
|
||||
return subject;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Subtract one off the maxlength so we can include the null terminator */
|
||||
maxLen--;
|
||||
|
||||
while (*ptr != '\0' && (browsed <= textLen - searchLen))
|
||||
{
|
||||
/* See if we get a comparison */
|
||||
if ((caseSensitive ? strncmp(ptr, search, searchLen) : strncasecmp(ptr, search, searchLen)) == 0)
|
||||
{
|
||||
if (replaceLen > searchLen)
|
||||
{
|
||||
/* First, see if we have enough space to do this operation */
|
||||
if (maxLen - textLen < replaceLen - searchLen)
|
||||
{
|
||||
/* First, see if the replacement length goes out of bounds. */
|
||||
if (browsed + replaceLen >= maxLen)
|
||||
{
|
||||
/* EXAMPLE CASE:
|
||||
* Subject: AABBBCCC
|
||||
* Buffer : 12 bytes
|
||||
* Search : BBB
|
||||
* Replace: DDDDDDDDDD
|
||||
* OUTPUT : AADDDDDDDDD
|
||||
* POSITION: ^
|
||||
*/
|
||||
/* If it does, we'll just bound the length and do a strcpy. */
|
||||
replaceLen = maxLen - browsed;
|
||||
|
||||
/* Note, we add one to the final result for the null terminator */
|
||||
strncopy(ptr, replace, replaceLen + 1);
|
||||
|
||||
/* Don't truncate a multi-byte character */
|
||||
if (*(ptr + replaceLen - 1) & 1 << 7)
|
||||
{
|
||||
replaceLen -= UTIL_CheckValidChar(ptr + replaceLen - 1);
|
||||
*(ptr + replaceLen) = '\0';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* EXAMPLE CASE:
|
||||
* Subject: AABBBCCC
|
||||
* Buffer : 12 bytes
|
||||
* Search : BBB
|
||||
* Replace: DDDDDDD
|
||||
* OUTPUT : AADDDDDDDCC
|
||||
* POSITION: ^
|
||||
*/
|
||||
/* We're going to have some bytes left over... */
|
||||
size_t origBytesToCopy = (textLen - (browsed + searchLen)) + 1;
|
||||
size_t realBytesToCopy = (maxLen - (browsed + replaceLen)) + 1;
|
||||
char *moveFrom = ptr + searchLen + (origBytesToCopy - realBytesToCopy);
|
||||
char *moveTo = ptr + replaceLen;
|
||||
|
||||
/* First, move our old data out of the way. */
|
||||
memmove(moveTo, moveFrom, realBytesToCopy);
|
||||
|
||||
/* Now, do our replacement. */
|
||||
memcpy(ptr, replace, replaceLen);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* EXAMPLE CASE:
|
||||
* Subject: AABBBCCC
|
||||
* Buffer : 12 bytes
|
||||
* Search : BBB
|
||||
* Replace: DDDD
|
||||
* OUTPUT : AADDDDCCC
|
||||
* POSITION: ^
|
||||
*/
|
||||
/* Yes, we have enough space. Do a normal move operation. */
|
||||
char *moveFrom = ptr + searchLen;
|
||||
char *moveTo = ptr + replaceLen;
|
||||
|
||||
/* First move our old data out of the way. */
|
||||
size_t bytesToCopy = (textLen - (browsed + searchLen)) + 1;
|
||||
memmove(moveTo, moveFrom, bytesToCopy);
|
||||
|
||||
/* Now do our replacement. */
|
||||
memcpy(ptr, replace, replaceLen);
|
||||
}
|
||||
}
|
||||
else if (replaceLen < searchLen)
|
||||
{
|
||||
/* EXAMPLE CASE:
|
||||
* Subject: AABBBCCC
|
||||
* Buffer : 12 bytes
|
||||
* Search : BBB
|
||||
* Replace: D
|
||||
* OUTPUT : AADCCC
|
||||
* POSITION: ^
|
||||
*/
|
||||
/* If the replacement does not grow the string length, we do not
|
||||
* need to do any fancy checking at all. Yay!
|
||||
*/
|
||||
char *moveFrom = ptr + searchLen; /* Start after the search pointer */
|
||||
char *moveTo = ptr + replaceLen; /* Copy to where the replacement ends */
|
||||
|
||||
/* Copy our replacement in, if any */
|
||||
if (replaceLen)
|
||||
{
|
||||
memcpy(ptr, replace, replaceLen);
|
||||
}
|
||||
|
||||
/* Figure out how many bytes to move down, including null terminator */
|
||||
size_t bytesToCopy = (textLen - (browsed + searchLen)) + 1;
|
||||
|
||||
/* Move the rest of the string down */
|
||||
memmove(moveTo, moveFrom, bytesToCopy);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* EXAMPLE CASE:
|
||||
* Subject: AABBBCCC
|
||||
* Buffer : 12 bytes
|
||||
* Search : BBB
|
||||
* Replace: DDD
|
||||
* OUTPUT : AADDDCCC
|
||||
* POSITION: ^
|
||||
*/
|
||||
/* We don't have to move anything around, just do a straight copy */
|
||||
memcpy(ptr, replace, replaceLen);
|
||||
}
|
||||
|
||||
return ptr + replaceLen;
|
||||
}
|
||||
ptr++;
|
||||
browsed++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
8
dlls/regex/utils.h
Normal file
8
dlls/regex/utils.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
int UTIL_CheckValidChar(char *c);
|
||||
char *UTIL_ReplaceEx(char *subject, size_t maxLen, const char *search, size_t searchLen, const char *replace, size_t replaceLen, bool caseSensitive);
|
||||
unsigned int strncopy(char *dest, const char *src, size_t count);
|
||||
|
||||
#endif // UTILS_H
|
Reference in New Issue
Block a user