2 * vim: set ts=4 sw=4 tw=99 et :
3 * =============================================================================
5 * Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
6 * =============================================================================
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, version 3.0, as published by the
10 * Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to link the
21 * code of this program (as well as its derivative works) to "Half-Life 2," the
22 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
23 * by the Valve Corporation. You must obey the GNU General Public License in
24 * all respects for all other code used. Additionally, AlliedModders LLC grants
25 * this exception to all derivative works. AlliedModders LLC defines further
26 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
27 * or <http://www.sourcemod.net/license.php>.
34 #include "stringutil.h"
36 const char *stristr(const char *str, const char *substr)
43 char *needle = (char *)substr;
44 char *prevloc = (char *)str;
45 char *haystack = (char *)str;
49 if (tolower(*haystack) == tolower(*needle))
60 needle = (char *)substr;
67 unsigned int strncopy(char *dest, const char *src, size_t count)
75 while ((*src) && (--count))
81 return (dest - start);
84 unsigned int UTIL_ReplaceAll(char *subject, size_t maxlength, const char *search, const char *replace, bool caseSensitive)
86 size_t searchLen = strlen(search);
87 size_t replaceLen = strlen(replace);
90 unsigned int total = 0;
91 while ((ptr = UTIL_ReplaceEx(ptr, maxlength, search, searchLen, replace, replaceLen, caseSensitive)) != NULL)
104 * NOTE: Do not edit this for the love of god unless you have
105 * read the test cases and understand the code behind each one.
106 * While I don't guarantee there aren't mistakes, I do guarantee
107 * that plugins will end up relying on tiny idiosyncrasies of this
108 * function, just like they did with AMX Mod X.
110 * There are explicitly more cases than the AMX Mod X version because
111 * we're not doing a blind copy. Each case is specifically optimized
112 * for what needs to be done. Even better, we don't have to error on
113 * bad buffer sizes. Instead, this function will smartly cut off the
114 * string in a way that pushes old data out.
116 char *UTIL_ReplaceEx(char *subject, size_t maxLen, const char *search, size_t searchLen, const char *replace, size_t replaceLen, bool caseSensitive)
120 size_t textLen = strlen(subject);
122 /* It's not possible to search or replace */
123 if (searchLen > textLen)
128 /* Handle the case of one byte replacement.
129 * It's only valid in one case.
133 /* If the search matches and the replace length is 0,
134 * we can just terminate the string and be done.
136 if ((caseSensitive ? strcmp(subject, search) : strcasecmp(subject, search)) == 0 && replaceLen == 0)
147 /* Subtract one off the maxlength so we can include the null terminator */
150 while (*ptr != '\0' && (browsed <= textLen - searchLen))
152 /* See if we get a comparison */
153 if ((caseSensitive ? strncmp(ptr, search, searchLen) : strncasecmp(ptr, search, searchLen)) == 0)
155 if (replaceLen > searchLen)
157 /* First, see if we have enough space to do this operation */
158 if (maxLen - textLen < replaceLen - searchLen)
160 /* First, see if the replacement length goes out of bounds. */
161 if (browsed + replaceLen >= maxLen)
167 * Replace: DDDDDDDDDD
168 * OUTPUT : AADDDDDDDDD
171 /* If it does, we'll just bound the length and do a strcpy. */
172 replaceLen = maxLen - browsed;
173 /* Note, we add one to the final result for the null terminator */
174 strncopy(ptr, replace, replaceLen+1);
183 * OUTPUT : AADDDDDDDCC
186 /* We're going to have some bytes left over... */
187 size_t origBytesToCopy = (textLen - (browsed + searchLen)) + 1;
188 size_t realBytesToCopy = (maxLen - (browsed + replaceLen)) + 1;
189 char *moveFrom = ptr + searchLen + (origBytesToCopy - realBytesToCopy);
190 char *moveTo = ptr + replaceLen;
192 /* First, move our old data out of the way. */
193 memmove(moveTo, moveFrom, realBytesToCopy);
195 /* Now, do our replacement. */
196 memcpy(ptr, replace, replaceLen);
209 /* Yes, we have enough space. Do a normal move operation. */
210 char *moveFrom = ptr + searchLen;
211 char *moveTo = ptr + replaceLen;
213 /* First move our old data out of the way. */
214 size_t bytesToCopy = (textLen - (browsed + searchLen)) + 1;
215 memmove(moveTo, moveFrom, bytesToCopy);
217 /* Now do our replacement. */
218 memcpy(ptr, replace, replaceLen);
221 else if (replaceLen < searchLen)
231 /* If the replacement does not grow the string length, we do not
232 * need to do any fancy checking at all. Yay!
234 char *moveFrom = ptr + searchLen; /* Start after the search pointer */
235 char *moveTo = ptr + replaceLen; /* Copy to where the replacement ends */
237 /* Copy our replacement in, if any */
240 memcpy(ptr, replace, replaceLen);
243 /* Figure out how many bytes to move down, including null terminator */
244 size_t bytesToCopy = (textLen - (browsed + searchLen)) + 1;
246 /* Move the rest of the string down */
247 memmove(moveTo, moveFrom, bytesToCopy);
259 /* We don't have to move anything around, just do a straight copy */
260 memcpy(ptr, replace, replaceLen);
263 return ptr + replaceLen;