From d80191df3de194607dbef8964d1b0a59887e44ba Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 14 May 2010 20:04:30 -0700 Subject: [PATCH] Move replace functions from logic to core (bug 4406 part 7, r=fyren). --- core/logic/Profiler.cpp | 7 +- core/logic/Translator.cpp | 6 +- core/logic/common_logic.cpp | 4 +- core/logic/intercom.h | 5 +- core/logic/smn_banning.cpp | 9 +- core/logic/stringutil.cpp | 187 +++++++++++++++++++++++++++++++++++ core/logic/stringutil.h | 4 + core/logic_bridge.cpp | 1 - core/sm_stringutil.cpp | 188 ------------------------------------ core/sm_stringutil.h | 2 - core/smn_string.cpp | 4 +- 11 files changed, 211 insertions(+), 206 deletions(-) diff --git a/core/logic/Profiler.cpp b/core/logic/Profiler.cpp index 5354ca2f..00bbd596 100644 --- a/core/logic/Profiler.cpp +++ b/core/logic/Profiler.cpp @@ -36,6 +36,7 @@ #include #endif #include +#include "stringutil.h" ProfileEngine g_Profiler; IProfiler *sm_profiler = &g_Profiler; @@ -386,9 +387,9 @@ void ProfileEngine::WriteReport(FILE *fp, ProfileReport *report, const char *nam { ar = report->GetReport(i); - smcore.strncopy(new_name, ar->atom_name, sizeof(new_name)); - smcore.ReplaceAll(new_name, sizeof(new_name), "<", "<", true); - smcore.ReplaceAll(new_name, sizeof(new_name), ">", ">", true); + strncopy(new_name, ar->atom_name, sizeof(new_name)); + UTIL_ReplaceAll(new_name, sizeof(new_name), "<", "<", true); + UTIL_ReplaceAll(new_name, sizeof(new_name), ">", ">", true); fprintf(fp, " \n", new_name, diff --git a/core/logic/Translator.cpp b/core/logic/Translator.cpp index 4d380ef1..fddcf0df 100644 --- a/core/logic/Translator.cpp +++ b/core/logic/Translator.cpp @@ -123,11 +123,11 @@ void CPhraseFile::ReparseFile() { if (m_File.compare("common.cfg") == 0) { - smcore.ReplaceAll(path, sizeof(path), "common.cfg", "common.phrases.txt", true); + UTIL_ReplaceAll(path, sizeof(path), "common.cfg", "common.phrases.txt", true); } else if (strstr(path, ".cfg")) { - smcore.ReplaceAll(path, sizeof(path), ".cfg", ".txt", true); + UTIL_ReplaceAll(path, sizeof(path), ".cfg", ".txt", true); } else if (strstr(path, ".txt")) { - smcore.ReplaceAll(path, sizeof(path), ".txt", ".cfg", true); + UTIL_ReplaceAll(path, sizeof(path), ".txt", ".cfg", true); } } diff --git a/core/logic/common_logic.cpp b/core/logic/common_logic.cpp index d22b4c42..56b404b1 100644 --- a/core/logic/common_logic.cpp +++ b/core/logic/common_logic.cpp @@ -74,7 +74,9 @@ static sm_logic_t logic = UTIL_CRC32, stristr, CoreTranslate, - AddCorePhraseFile + AddCorePhraseFile, + UTIL_ReplaceAll, + UTIL_ReplaceEx }; static void logic_init(const sm_core_t* core, sm_logic_t* _logic) diff --git a/core/logic/intercom.h b/core/logic/intercom.h index 308542e5..91bf0af3 100644 --- a/core/logic/intercom.h +++ b/core/logic/intercom.h @@ -42,7 +42,7 @@ using namespace SourceMod; * Add 1 to the RHS of this expression to bump the intercom file * This is to prevent mismatching core/logic binaries */ -#define SM_LOGIC_MAGIC (0x0F47C0DE - 10) +#define SM_LOGIC_MAGIC (0x0F47C0DE - 11) #if defined SM_LOGIC class IVEngineServer @@ -107,7 +107,6 @@ struct sm_core_t void (*LogError)(const char*, ...); const char * (*GetCvarString)(ConVar*); size_t (*Format)(char*, size_t, const char*, ...); - unsigned int (*ReplaceAll)(char*, size_t, const char *, const char *, bool); void (*GenerateError)(IPluginContext *, cell_t, int, const char *, ...); bool (*gnprintf)(char *, size_t, const char *, IPhraseCollection *, void **, unsigned int, unsigned int &, size_t *, const char **); @@ -126,6 +125,8 @@ struct sm_logic_t const char *(*stristr)(const char *, const char *); bool (*CoreTranslate)(char *, size_t, const char *, unsigned int, size_t *, ...); void (*AddCorePhraseFile)(const char *filename); + unsigned int (*ReplaceAll)(char*, size_t, const char *, const char *, bool); + char *(*ReplaceEx)(char *, size_t, const char *, size_t, const char *, size_t, bool); }; typedef void (*LogicInitFunction)(const sm_core_t *core, sm_logic_t *logic); diff --git a/core/logic/smn_banning.cpp b/core/logic/smn_banning.cpp index 6b857398..0230404e 100644 --- a/core/logic/smn_banning.cpp +++ b/core/logic/smn_banning.cpp @@ -34,6 +34,7 @@ #include #include #include +#include "stringutil.h" #define BANFLAG_AUTO (1<<0) /**< Auto-detects whether to ban by steamid or IP */ #define BANFLAG_IP (1<<1) /**< Always ban by IP address */ @@ -117,8 +118,8 @@ static cell_t BanIdentity(IPluginContext *pContext, const cell_t *params) /* Sanitize the input */ char identity[64]; - smcore.strncopy(identity, r_identity, sizeof(identity)); - smcore.ReplaceAll(identity, sizeof(identity), ";", "", true); + strncopy(identity, r_identity, sizeof(identity)); + UTIL_ReplaceAll(identity, sizeof(identity), ";", "", true); cell_t handled = 0; if (ban_cmd[0] != '\0' && g_pOnBanIdentity->GetFunctionCount() > 0) @@ -194,8 +195,8 @@ static cell_t RemoveBan(IPluginContext *pContext, const cell_t *params) } char identity[64]; - smcore.strncopy(identity, r_identity, sizeof(identity)); - smcore.ReplaceAll(identity, sizeof(identity), ";", "", true); + strncopy(identity, r_identity, sizeof(identity)); + UTIL_ReplaceAll(identity, sizeof(identity), ";", "", true); cell_t handled = 0; if (ban_cmd[0] != '\0' && g_pOnRemoveBan->GetFunctionCount() > 0) diff --git a/core/logic/stringutil.cpp b/core/logic/stringutil.cpp index 249c9f0a..6afe21b2 100644 --- a/core/logic/stringutil.cpp +++ b/core/logic/stringutil.cpp @@ -81,4 +81,191 @@ unsigned int strncopy(char *dest, const char *src, size_t count) return (dest - start); } +unsigned int UTIL_ReplaceAll(char *subject, size_t maxlength, const char *search, const char *replace, bool caseSensitive) +{ + size_t searchLen = strlen(search); + size_t replaceLen = strlen(replace); + + char *ptr = subject; + unsigned int total = 0; + while ((ptr = UTIL_ReplaceEx(ptr, maxlength, search, searchLen, replace, replaceLen, caseSensitive)) != NULL) + { + total++; + if (*ptr == '\0') + { + break; + } + } + + return total; +} + +/** + * 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); + } + 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; +} diff --git a/core/logic/stringutil.h b/core/logic/stringutil.h index 5a4fae4b..4d07f069 100644 --- a/core/logic/stringutil.h +++ b/core/logic/stringutil.h @@ -34,6 +34,10 @@ const char *stristr(const char *str, const char *substr); unsigned int strncopy(char *dest, const char *src, size_t count); +unsigned int UTIL_ReplaceAll(char *subject, size_t maxlength, const char *search, + const char *replace, bool caseSensitive = true); +char *UTIL_ReplaceEx(char *subject, size_t maxLen, const char *search, size_t searchLen, + const char *replace, size_t replaceLen, bool caseSensitive = true); #endif /* _INCLUDE_SOURCEMOD_COMMON_STRINGUTIL_H_ */ diff --git a/core/logic_bridge.cpp b/core/logic_bridge.cpp index df280015..b67790bb 100644 --- a/core/logic_bridge.cpp +++ b/core/logic_bridge.cpp @@ -135,7 +135,6 @@ static sm_core_t core_bridge = log_error, get_cvar_string, UTIL_Format, - UTIL_ReplaceAll, generate_error, gnprintf, &serverGlobals diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index 821edd2d..86664ddd 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -1331,194 +1331,6 @@ char *sm_strdup(const char *str) return ptr; } -unsigned int UTIL_ReplaceAll(char *subject, size_t maxlength, const char *search, const char *replace, bool caseSensitive) -{ - size_t searchLen = strlen(search); - size_t replaceLen = strlen(replace); - - char *ptr = subject; - unsigned int total = 0; - while ((ptr = UTIL_ReplaceEx(ptr, maxlength, search, searchLen, replace, replaceLen, caseSensitive)) != NULL) - { - total++; - if (*ptr == '\0') - { - break; - } - } - - return total; -} - -/** - * 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); - } - 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; -} - char *UTIL_TrimWhitespace(char *str, size_t &len) { char *end = str + len - 1; diff --git a/core/sm_stringutil.h b/core/sm_stringutil.h index 4f67fba4..781f1a73 100644 --- a/core/sm_stringutil.h +++ b/core/sm_stringutil.h @@ -56,8 +56,6 @@ bool gnprintf(char *buffer, size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...); size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list ap); char *sm_strdup(const char *str); -unsigned int UTIL_ReplaceAll(char *subject, size_t maxlength, const char *search, const char *replace, bool caseSensitive = true); -char *UTIL_ReplaceEx(char *subject, size_t maxLen, const char *search, size_t searchLen, const char *replace, size_t replaceLen, bool caseSensitive = true); char *UTIL_TrimWhitespace(char *str, size_t &len); size_t UTIL_DecodeHexString(unsigned char *buffer, size_t maxlength, const char *hexstr); char *UTIL_ToLowerCase(const char *str); diff --git a/core/smn_string.cpp b/core/smn_string.cpp index f01b58a3..c26d1650 100644 --- a/core/smn_string.cpp +++ b/core/smn_string.cpp @@ -514,7 +514,7 @@ static cell_t ReplaceString(IPluginContext *pContext, const cell_t *params) return pContext->ThrowNativeError("Cannot replace searches of empty strings"); } - return UTIL_ReplaceAll(text, maxlength, search, replace, caseSensitive); + return logicore.ReplaceAll(text, maxlength, search, replace, caseSensitive); } static cell_t ReplaceStringEx(IPluginContext *pContext, const cell_t *params) @@ -546,7 +546,7 @@ static cell_t ReplaceStringEx(IPluginContext *pContext, const cell_t *params) return pContext->ThrowNativeError("Cannot replace searches of empty strings"); } - char *ptr = UTIL_ReplaceEx(text, maxlength, search, searchLen, replace, replaceLen, caseSensitive); + char *ptr = logicore.ReplaceEx(text, maxlength, search, searchLen, replace, replaceLen, caseSensitive); if (ptr == NULL) {