3 * ===============================================================
4 * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
5 * ===============================================================
7 * This file is not open source and may not be copied without explicit
8 * written permission of AlliedModders LLC. This file may not be redistributed
9 * in whole or significant part.
10 * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
17 #include "sm_globals.h"
18 #include "sm_stringutil.h"
19 #include "TextParsers.h"
22 inline const char *_strstr(const char *str, const char *substr)
24 #ifdef PLATFORM_WINDOWS
25 return strstr(str, substr);
26 #elif defined PLATFORM_LINUX
27 return (const char *)strstr(str, substr);
31 /*********************************************
33 * STRING MANIPULATION NATIVE IMPLEMENTATIONS *
35 *********************************************/
37 static cell_t sm_strlen(IPluginContext *pCtx, const cell_t *params)
40 pCtx->LocalToString(params[1], &str);
45 static cell_t sm_contain(IPluginContext *pCtx, const cell_t *params)
47 typedef const char *(*STRSEARCH)(const char *, const char *);
51 pCtx->LocalToString(params[1], &str);
52 pCtx->LocalToString(params[2], &substr);
54 func = (params[3]) ? _strstr : stristr;
55 const char *pos = func(str, substr);
64 static cell_t sm_strcmp(IPluginContext *pCtx, const cell_t *params)
66 typedef int (*STRCOMPARE)(const char *, const char *);
70 pCtx->LocalToString(params[1], &str1);
71 pCtx->LocalToString(params[2], &str2);
73 func = (params[3]) ? strcmp : stricmp;
75 return (func(str1, str2));
78 static cell_t sm_strncmp(IPluginContext *pCtx, const cell_t *params)
82 pCtx->LocalToString(params[1], &str1);
83 pCtx->LocalToString(params[2], &str2);
87 return strncmp(str1, str2, (size_t)params[3]);
89 return strncasecmp(str1, str2, (size_t)params[3]);
93 static cell_t sm_strcopy(IPluginContext *pCtx, const cell_t *params)
97 pCtx->LocalToString(params[1], &dest);
98 pCtx->LocalToString(params[3], &src);
100 return strncopy(dest, src, params[2]);
103 static cell_t sm_strconvint(IPluginContext *pCtx, const cell_t *params)
106 pCtx->LocalToString(params[1], &str);
108 return static_cast<cell_t>(strtol(str, &dummy, params[2]));
111 static cell_t sm_numtostr(IPluginContext *pCtx, const cell_t *params)
114 pCtx->LocalToString(params[2], &str);
115 size_t res = UTIL_Format(str, params[3], "%d", params[1]);
117 return static_cast<cell_t>(res);
120 static cell_t sm_strtofloat(IPluginContext *pCtx, const cell_t *params)
123 pCtx->LocalToString(params[1], &str);
125 float val = (float)strtod(str, &dummy);
130 static cell_t sm_floattostr(IPluginContext *pCtx, const cell_t *params)
133 pCtx->LocalToString(params[2], &str);
134 size_t res = UTIL_Format(str, params[3], "%f", sp_ctof(params[1]));
136 return static_cast<cell_t>(res);
139 static cell_t sm_formatex(IPluginContext *pCtx, const cell_t *params)
145 pCtx->LocalToString(params[1], &buf);
146 pCtx->LocalToString(params[3], &fmt);
147 res = atcprintf(buf, static_cast<size_t>(params[2]), fmt, pCtx, params, &arg);
149 return static_cast<cell_t>(res);
152 static char g_formatbuf[2048];
153 static cell_t sm_format(IPluginContext *pCtx, const cell_t *params)
155 char *buf, *fmt, *destbuf;
156 cell_t start_addr, end_addr, maxparam;
161 pCtx->LocalToString(params[1], &destbuf);
162 pCtx->LocalToString(params[3], &fmt);
164 maxlen = static_cast<size_t>(params[2]);
165 start_addr = params[1];
166 end_addr = params[1] + maxlen;
167 maxparam = params[0];
169 for (cell_t i=3; i<=maxparam; i++)
171 if ((params[i] >= start_addr) && (params[i] <= end_addr))
177 buf = (copy) ? g_formatbuf : destbuf;
178 res = atcprintf(buf, maxlen, fmt, pCtx, params, &arg);
182 memcpy(destbuf, g_formatbuf, res+1);
185 return static_cast<cell_t>(res);
188 static cell_t sm_vformat(IPluginContext *pContext, const cell_t *params)
190 int vargPos = static_cast<int>(params[4]);
192 /* Get the parent parameter array */
193 sp_context_t *ctx = pContext->GetContext();
194 cell_t *local_params = (cell_t *)(ctx->memory + ctx->frm + (2 * sizeof(cell_t)));
196 cell_t max = local_params[0];
197 if (vargPos > (int)max + 1)
199 return pContext->ThrowNativeError("Argument index is invalid: %d", vargPos);
202 cell_t addr_start = params[1];
203 cell_t addr_end = addr_start + params[2];
205 for (int i=vargPos; i<=max; i++)
207 /* Does this clip bounds? */
208 if ((local_params[i] >= addr_start)
209 && (local_params[i] <= addr_end))
216 /* Get destination info */
217 char *format, *destination;
218 size_t maxlen = static_cast<size_t>(params[2]);
222 destination = g_formatbuf;
224 pContext->LocalToString(params[1], &destination);
227 pContext->LocalToString(params[3], &format);
229 size_t total = atcprintf(destination, maxlen, format, pContext, local_params, &vargPos);
231 /* Perform copy-on-write if we need to */
234 pContext->StringToLocal(params[1], maxlen, g_formatbuf);
240 /* :TODO: make this UTF8 safe */
241 static cell_t StrBreak(IPluginContext *pContext, const cell_t *params)
248 pContext->LocalToString(params[1], (char **)&input);
249 pContext->LocalToString(params[2], &out);
252 const char *inptr = input;
253 /* Eat up whitespace */
254 while (*inptr != '\0' && IsWhitespace(inptr))
268 const char *start, *end = NULL;
270 bool quoted = (*inptr == '"');
275 /* Read input until we reach a quote. */
276 while (*inptr != '\0' && *inptr != '"')
278 /* Update the end point, increment the stream. */
281 /* Read one more token if we reached an end quote */
288 /* Read input until we reach a space */
289 while (*inptr != '\0' && !IsWhitespace(inptr))
291 /* Update the end point, increment the stream. */
296 /* Copy the string we found, if necessary */
306 for (const char *ptr=start;
307 (ptr <= end) && ((unsigned)(outptr - out) < (outMax));
315 /* Consume more of the string until we reach non-whitespace */
316 while (*inptr != '\0' && IsWhitespace(inptr))
326 return inptr - input;
329 static cell_t GetCharBytes(IPluginContext *pContext, const cell_t *params)
332 pContext->LocalToString(params[1], &str);
334 return _GetUTF8CharBytes(str);
337 static cell_t IsCharAlpha(IPluginContext *pContext, const cell_t *params)
339 char chr = params[1];
341 if (_GetUTF8CharBytes(&chr) != 1)
349 static cell_t IsCharNumeric(IPluginContext *pContext, const cell_t *params)
351 char chr = params[1];
353 if (_GetUTF8CharBytes(&chr) != 1)
361 static cell_t IsCharSpace(IPluginContext *pContext, const cell_t *params)
363 char chr = params[1];
365 if (_GetUTF8CharBytes(&chr) != 1)
373 static cell_t IsCharMB(IPluginContext *pContext, const cell_t *params)
375 char chr = params[1];
377 unsigned int bytes = _GetUTF8CharBytes(&chr);
386 static cell_t IsCharUpper(IPluginContext *pContext, const cell_t *params)
388 char chr = params[1];
390 if (_GetUTF8CharBytes(&chr) != 1)
398 static cell_t IsCharLower(IPluginContext *pContext, const cell_t *params)
400 char chr = params[1];
402 if (_GetUTF8CharBytes(&chr) != 1)
410 REGISTER_NATIVES(basicStrings)
412 {"GetCharBytes", GetCharBytes},
413 {"IntToString", sm_numtostr},
414 {"IsCharAlpha", IsCharAlpha},
415 {"IsCharLower", IsCharLower},
416 {"IsCharMB", IsCharMB},
417 {"IsCharNumeric", IsCharNumeric},
418 {"IsCharSpace", IsCharSpace},
419 {"IsCharUpper", IsCharUpper},
420 {"strlen", sm_strlen},
421 {"StrBreak", StrBreak},
422 {"StrContains", sm_contain},
423 {"strcmp", sm_strcmp},
424 {"StrCompare", sm_strcmp}, /* Backwards compat shim */
425 {"strncmp", sm_strncmp},
426 {"strcopy", sm_strcopy},
427 {"StrCopy", sm_strcopy}, /* Backwards compat shim */
428 {"StringToInt", sm_strconvint},
429 {"StringToFloat", sm_strtofloat},
430 {"FloatToString", sm_floattostr},
431 {"Format", sm_format},
432 {"FormatEx", sm_formatex},
433 {"VFormat", sm_vformat},