diff --git a/dlls/regex/CRegEx.cpp b/dlls/regex/CRegEx.cpp index 819fb774..efa374c4 100755 --- a/dlls/regex/CRegEx.cpp +++ b/dlls/regex/CRegEx.cpp @@ -1,3 +1,35 @@ +/* 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 "pcre.h" #include "CRegEx.h" #include @@ -97,6 +129,23 @@ 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; + + return 1; +} + int RegEx::Match(const char *str) { int rc = 0; diff --git a/dlls/regex/CRegEx.h b/dlls/regex/CRegEx.h index 542cd27c..498ab929 100755 --- a/dlls/regex/CRegEx.h +++ b/dlls/regex/CRegEx.h @@ -1,3 +1,35 @@ +/* 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 @@ -10,6 +42,7 @@ public: void Clear(); int Compile(const char *pattern, const char* flags = NULL); + int Compile(const char *pattern, int iFlags); int Match(const char *str); void ClearMatch(); const char *GetSubstring(int s, char buffer[], int max); diff --git a/dlls/regex/module.cpp b/dlls/regex/module.cpp index 411cb62c..48c58bd4 100755 --- a/dlls/regex/module.cpp +++ b/dlls/regex/module.cpp @@ -1,3 +1,35 @@ +/* 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 #include "pcre.h" #include "amxxmodule.h" @@ -19,6 +51,7 @@ int GetPEL() return (int)PEL.size() - 1; } + // native Regex:regex_compile(const pattern[], &ret, error[], maxLen, const flags[]=""); static cell AMX_NATIVE_CALL regex_compile(AMX *amx, cell *params) { @@ -39,7 +72,30 @@ static cell AMX_NATIVE_CALL regex_compile(AMX *amx, cell *params) } return id+1; -}// 1.8 includes the last parameter +} + +// native Regex:regex_compile_ex(const pattern[], flags = 0, error[] = "", maxLen = 0, &RegexError:errcode = REGEX_ERROR_NONE); +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) + { + cell *eOff = MF_GetAmxAddr(amx, params[5]); + const char *err = x->mError; + *eOff = 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) { @@ -86,6 +142,7 @@ static cell AMX_NATIVE_CALL regex_match(AMX *amx, cell *params) return id+1; } + // native regex_match_c(const string[], Regex:id, &ret); static cell AMX_NATIVE_CALL regex_match_c(AMX *amx, cell *params) { @@ -125,6 +182,47 @@ static cell AMX_NATIVE_CALL regex_match_c(AMX *amx, cell *params) } } +// native regex_match_ex(Regex:id, const string[], &RegexError:ret = REGEX_ERROR_NONE); +static cell AMX_NATIVE_CALL regex_match_ex(AMX *amx, cell *params) +{ + int id = params[1] - 1; + + if (id >= (int)PEL.size() || 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[2], 0, &len); + + RegEx *x = PEL[id]; + + int e = x->Match(str); + if (e == -1) + { + /* there was a match error. move on. */ + cell *res = MF_GetAmxAddr(amx, params[3]); + *res = x->mErrorOffset; + + /* only clear the match results, since the regex object + may still be referenced later */ + x->ClearMatch(); + return -2; + } + else if (e == 0) + { + /* only clear the match results, since the regex object + may still be referenced later */ + x->ClearMatch(); + return 0; + } + else + { + return x->mSubStrings; + } +} + static cell AMX_NATIVE_CALL regex_substr(AMX *amx, cell *params) { int id = params[1]-1; @@ -168,8 +266,10 @@ static cell AMX_NATIVE_CALL regex_free(AMX *amx, cell *params) 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_ex", regex_match_ex}, {"regex_substr", regex_substr}, {"regex_free", regex_free}, {NULL, NULL}, diff --git a/plugins/include/regex.inc b/plugins/include/regex.inc index c56cfe66..62b616da 100755 --- a/plugins/include/regex.inc +++ b/plugins/include/regex.inc @@ -18,6 +18,7 @@ #pragma library regex #endif + enum Regex { REGEX_MATCH_FAIL = -2, @@ -26,6 +27,70 @@ enum Regex REGEX_OK }; + +/** + * @section Flags for compiling regex expressions. + * These come directly from the pcre library and can be used in MatchRegex and CompileRegex. + * + * @note To be used with regex_compile_ex. + * Only available in 1.8.3 and above. + */ +#define PCRE_CASELESS 0x00000001 /* Ignore Case */ +#define PCRE_MULTILINE 0x00000002 /* Multilines (affects ^ and $ so that they match the start/end of a line rather than matching the start/end of the string). */ +#define PCRE_DOTALL 0x00000004 /* Single line (affects . so that it matches any character, even new line characters). */ +#define PCRE_EXTENDED 0x00000008 /* Pattern extension (ignore whitespace and # comments). */ +#define PCRE_ANCHORED 0x00000010 /* Force pattern anchoring. */ +#define PCRE_DOLLAR_ENDONLY 0x00000020 /* $ not to match newline at end. */ +#define PCRE_UNGREEDY 0x00000200 /* Invert greediness of quantifiers */ +#define PCRE_NOTEMPTY 0x00000400 /* An empty string is not a valid match. */ +#define PCRE_UTF8 0x00000800 /* Use UTF-8 Chars */ +#define PCRE_NO_UTF8_CHECK 0x00002000 /* Do not check the pattern for UTF-8 validity (only relevant if PCRE_UTF8 is set) */ +#define PCRE_UCP 0x20000000 /* Use Unicode properties for \ed, \ew, etc. */ + +/** + * Regex expression error codes. + * + * @note To be used with regex_compile_ex and regex_match_ex natives. + * Only available in 1.8.3 and above. + */ +enum RegexError +{ + REGEX_ERROR_NONE = 0, /* No error */ + REGEX_ERROR_NOMATCH = -1, /* No match was found */ + REGEX_ERROR_NULL = -2, + REGEX_ERROR_BADOPTION = -3, + REGEX_ERROR_BADMAGIC = -4, + REGEX_ERROR_UNKNOWN_OPCODE = -5, + REGEX_ERROR_NOMEMORY = -6, + REGEX_ERROR_NOSUBSTRING = -7, + REGEX_ERROR_MATCHLIMIT = -8, + REGEX_ERROR_CALLOUT = -9, /* Never used by PCRE itself */ + REGEX_ERROR_BADUTF8 = -10, + REGEX_ERROR_BADUTF8_OFFSET = -11, + REGEX_ERROR_PARTIAL = -12, + REGEX_ERROR_BADPARTIAL = -13, + REGEX_ERROR_INTERNAL = -14, + REGEX_ERROR_BADCOUNT = -15, + REGEX_ERROR_DFA_UITEM = -16, + REGEX_ERROR_DFA_UCOND = -17, + REGEX_ERROR_DFA_UMLIMIT = -18, + REGEX_ERROR_DFA_WSSIZE = -19, + REGEX_ERROR_DFA_RECURSE = -20, + REGEX_ERROR_RECURSIONLIMIT = -21, + REGEX_ERROR_NULLWSLIMIT = -22, /* No longer actually used */ + REGEX_ERROR_BADNEWLINE = -23, + REGEX_ERROR_BADOFFSET = -24, + REGEX_ERROR_SHORTUTF8 = -25, + REGEX_ERROR_RECURSELOOP = -26, + REGEX_ERROR_JIT_STACKLIMIT = -27, + REGEX_ERROR_BADMODE = -28, + REGEX_ERROR_BADENDIANNESS = -29, + REGEX_ERROR_DFA_BADRESTART = -30, + REGEX_ERROR_JIT_BADOPTION = -31, + REGEX_ERROR_BADLENGTH = -32, +}; + + /** * Precompile a regular expression. Use this if you intend on using the * same expression multiple times. Pass the regex handle returned here to @@ -72,6 +137,49 @@ native Regex:regex_compile(const pattern[], &ret, error[], maxLen, const flags[] */ native regex_match_c(const string[], Regex:pattern, &ret); +/** + * Precompile a regular expression. + * + * @note Use this if you intend on using the ame expression multiple times. + * Pass the regex handle returned here to regex_match_ex to check for matches. + * + * @note Unlike regex_compile, this allows you to use directly PCRE flags, and + * to get a more complete set of regular expression error codes. + * Only available in 1.8.3 and above. + * + * @param pattern The regular expression pattern. + * @param flags General flags for the regular expression, see PCRE_* defines. + * @param error Error message encountered, if applicable. + * @param maxLen Maximum string length of the error buffer. + * @param errcode Regex type error code encountered, if applicable. + * + * @return Valid regex handle (> 0) on success, or -1 on failure. + */ +native Regex:regex_compile_ex(const pattern[], flags = 0, error[]= "", maxLen = 0, &RegexError:errcode = REGEX_ERROR_NONE); + +/** + * Matches a string against a pre-compiled regular expression pattern. + * + * @note Use the regex handle passed to this function to extract + * matches with regex_substr(). + * + * @note You should free the returned handle with regex_free() + * when you are done with this pattern. + * + * @note Unlike regex_match_c(), this allows you to get a more complete + * set of regular expression error codes and parameter is optional. + * Only available in 1.8.3 and above. + * + * @param str The string to check. + * @param regex Regex Handle from regex_compile_ex() + * @param ret Error code, if applicable. + * + * @return -2 = Matching error (error code is stored in ret) + * 0 = No match. + * >1 = Number of results. + */ +native regex_match_ex(Handle:regex, const str[], &RegexError:ret = REGEX_ERROR_NONE); + /** * Matches a string against a regular expression pattern. * @@ -106,29 +214,31 @@ native Regex:regex_match(const string[], const pattern[], &ret, error[], maxLen, /** * Returns a matched substring from a regex handle. - * Substring ids start at 0 and end at ret-1, where ret is from the corresponding - * regex_match or regex_match_c function call. + * + * @note Substring ids start at 0 and end at ret - 1, where ret is from the corresponding + * regex_match, regex_match_c or regex_match_ex function call. * * @param id The regex handle to extract data from. * @param str_id The index of the expression to get - starts at 0, and ends at ret - 1. * @param buffer The buffer to set to the matching substring. * @param maxLen The maximum string length of the buffer. * + * @return 1 on success, otherwise 0 on failure. */ native regex_substr(Regex:id, str_id, buffer[], maxLen); /** * Frees the memory associated with a regex result, and sets the handle to 0. - * This must be called on all results from regex_match() when you are done extracting - * the results with regex_substr(). - * The results of regex_compile() (and subsequently, regex_match_c()) only need to be freed - * when you are done using the pattern. + * + * @note This must be called on all results from regex_match() when you are done extracting + * the results with regex_substr(). * + * @note The results of regex_compile() or regex_compile_ex() (and subsequently, regex_match_c() or regex_match_ex()) + * only need to be freed when you are done using the pattern. + * + * @note Do not use the handle again after freeing it! * * @param id The regex handle to free. - * * @noreturn - * - * @note Do not use the handle again after freeing it! */ native regex_free(&Regex:id);