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>.
35 #include <sm_platform.h>
36 #include "stringutil.h"
38 const char *stristr(const char *str, const char *substr)
45 char *needle = (char *)substr;
46 char *prevloc = (char *)str;
47 char *haystack = (char *)str;
51 if (tolower(*haystack) == tolower(*needle))
62 needle = (char *)substr;
69 unsigned int strncopy(char *dest, const char *src, size_t count)
77 while ((*src) && (--count))
83 return (dest - start);
86 unsigned int UTIL_ReplaceAll(char *subject, size_t maxlength, const char *search, const char *replace, bool caseSensitive)
88 size_t searchLen = strlen(search);
89 size_t replaceLen = strlen(replace);
92 unsigned int total = 0;
93 while ((ptr = UTIL_ReplaceEx(ptr, maxlength, search, searchLen, replace, replaceLen, caseSensitive)) != NULL)
106 * NOTE: Do not edit this for the love of god unless you have
107 * read the test cases and understand the code behind each one.
108 * While I don't guarantee there aren't mistakes, I do guarantee
109 * that plugins will end up relying on tiny idiosyncrasies of this
110 * function, just like they did with AMX Mod X.
112 * There are explicitly more cases than the AMX Mod X version because
113 * we're not doing a blind copy. Each case is specifically optimized
114 * for what needs to be done. Even better, we don't have to error on
115 * bad buffer sizes. Instead, this function will smartly cut off the
116 * string in a way that pushes old data out.
118 char *UTIL_ReplaceEx(char *subject, size_t maxLen, const char *search, size_t searchLen, const char *replace, size_t replaceLen, bool caseSensitive)
122 size_t textLen = strlen(subject);
124 /* It's not possible to search or replace */
125 if (searchLen > textLen)
130 /* Handle the case of one byte replacement.
131 * It's only valid in one case.
135 /* If the search matches and the replace length is 0,
136 * we can just terminate the string and be done.
138 if ((caseSensitive ? strcmp(subject, search) : strcasecmp(subject, search)) == 0 && replaceLen == 0)
149 /* Subtract one off the maxlength so we can include the null terminator */
152 while (*ptr != '\0' && (browsed <= textLen - searchLen))
154 /* See if we get a comparison */
155 if ((caseSensitive ? strncmp(ptr, search, searchLen) : strncasecmp(ptr, search, searchLen)) == 0)
157 if (replaceLen > searchLen)
159 /* First, see if we have enough space to do this operation */
160 if (maxLen - textLen < replaceLen - searchLen)
162 /* First, see if the replacement length goes out of bounds. */
163 if (browsed + replaceLen >= maxLen)
169 * Replace: DDDDDDDDDD
170 * OUTPUT : AADDDDDDDDD
173 /* If it does, we'll just bound the length and do a strcpy. */
174 replaceLen = maxLen - browsed;
175 /* Note, we add one to the final result for the null terminator */
176 strncopy(ptr, replace, replaceLen+1);
185 * OUTPUT : AADDDDDDDCC
188 /* We're going to have some bytes left over... */
189 size_t origBytesToCopy = (textLen - (browsed + searchLen)) + 1;
190 size_t realBytesToCopy = (maxLen - (browsed + replaceLen)) + 1;
191 char *moveFrom = ptr + searchLen + (origBytesToCopy - realBytesToCopy);
192 char *moveTo = ptr + replaceLen;
194 /* First, move our old data out of the way. */
195 memmove(moveTo, moveFrom, realBytesToCopy);
197 /* Now, do our replacement. */
198 memcpy(ptr, replace, replaceLen);
211 /* Yes, we have enough space. Do a normal move operation. */
212 char *moveFrom = ptr + searchLen;
213 char *moveTo = ptr + replaceLen;
215 /* First move our old data out of the way. */
216 size_t bytesToCopy = (textLen - (browsed + searchLen)) + 1;
217 memmove(moveTo, moveFrom, bytesToCopy);
219 /* Now do our replacement. */
220 memcpy(ptr, replace, replaceLen);
223 else if (replaceLen < searchLen)
233 /* If the replacement does not grow the string length, we do not
234 * need to do any fancy checking at all. Yay!
236 char *moveFrom = ptr + searchLen; /* Start after the search pointer */
237 char *moveTo = ptr + replaceLen; /* Copy to where the replacement ends */
239 /* Copy our replacement in, if any */
242 memcpy(ptr, replace, replaceLen);
245 /* Figure out how many bytes to move down, including null terminator */
246 size_t bytesToCopy = (textLen - (browsed + searchLen)) + 1;
248 /* Move the rest of the string down */
249 memmove(moveTo, moveFrom, bytesToCopy);
261 /* We don't have to move anything around, just do a straight copy */
262 memcpy(ptr, replace, replaceLen);
265 return ptr + replaceLen;
274 size_t UTIL_DecodeHexString(unsigned char *buffer, size_t maxlength, const char *hexstr)
277 size_t length = strlen(hexstr);
279 for (size_t i = 0; i < length; i++)
281 if (written >= maxlength)
283 buffer[written++] = hexstr[i];
284 if (hexstr[i] == '\\' && hexstr[i + 1] == 'x')
288 /* Get the hex part. */
291 s_byte[0] = hexstr[i + 2];
292 s_byte[1] = hexstr[i + 3];
294 /* Read it as an integer */
295 sscanf(s_byte, "%x", &r_byte);
297 buffer[written - 1] = r_byte;