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"
21 inline const char *_strstr(const char *str, const char *substr)
23 #ifdef PLATFORM_WINDOWS
24 return strstr(str, substr);
25 #elif defined PLATFORM_LINUX
26 return (const char *)strstr(str, substr);
30 /*********************************************
32 * STRING MANIPULATION NATIVE IMPLEMENTATIONS *
34 *********************************************/
36 static cell_t sm_strlen(IPluginContext *pCtx, const cell_t *params)
39 pCtx->LocalToString(params[1], &str);
44 static cell_t sm_contain(IPluginContext *pCtx, const cell_t *params)
46 typedef const char *(*STRSEARCH)(const char *, const char *);
50 pCtx->LocalToString(params[1], &str);
51 pCtx->LocalToString(params[2], &substr);
53 func = (params[3]) ? _strstr : stristr;
54 const char *pos = func(str, substr);
63 static cell_t sm_strcmp(IPluginContext *pCtx, const cell_t *params)
65 typedef int (*STRCOMPARE)(const char *, const char *);
69 pCtx->LocalToString(params[1], &str1);
70 pCtx->LocalToString(params[2], &str2);
72 func = (params[3]) ? strcmp : stricmp;
74 return (func(str1, str2));
77 static cell_t sm_strncmp(IPluginContext *pCtx, const cell_t *params)
81 pCtx->LocalToString(params[1], &str1);
82 pCtx->LocalToString(params[2], &str2);
86 return strncmp(str1, str2, (size_t)params[3]);
88 return strncasecmp(str1, str2, (size_t)params[3]);
92 static cell_t sm_strcopy(IPluginContext *pCtx, const cell_t *params)
96 pCtx->LocalToString(params[1], &dest);
97 pCtx->LocalToString(params[3], &src);
99 return strncopy(dest, src, params[2]);
102 static cell_t sm_strconvint(IPluginContext *pCtx, const cell_t *params)
105 pCtx->LocalToString(params[1], &str);
107 return static_cast<cell_t>(strtol(str, &dummy, params[2]));
110 static cell_t sm_numtostr(IPluginContext *pCtx, const cell_t *params)
113 pCtx->LocalToString(params[2], &str);
114 size_t res = UTIL_Format(str, params[3], "%d", params[1]);
116 return static_cast<cell_t>(res);
119 static cell_t sm_strtofloat(IPluginContext *pCtx, const cell_t *params)
122 pCtx->LocalToString(params[1], &str);
124 float val = (float)strtod(str, &dummy);
129 static cell_t sm_floattostr(IPluginContext *pCtx, const cell_t *params)
132 pCtx->LocalToString(params[2], &str);
133 size_t res = UTIL_Format(str, params[3], "%f", sp_ctof(params[1]));
135 return static_cast<cell_t>(res);
138 static cell_t sm_formatex(IPluginContext *pCtx, const cell_t *params)
144 pCtx->LocalToString(params[1], &buf);
145 pCtx->LocalToString(params[3], &fmt);
146 res = atcprintf(buf, static_cast<size_t>(params[2]), fmt, pCtx, params, &arg);
148 return static_cast<cell_t>(res);
151 static char g_formatbuf[2048];
152 static cell_t sm_format(IPluginContext *pCtx, const cell_t *params)
154 char *buf, *fmt, *destbuf;
155 cell_t start_addr, end_addr, maxparam;
160 pCtx->LocalToString(params[1], &destbuf);
161 pCtx->LocalToString(params[3], &fmt);
163 maxlen = static_cast<size_t>(params[2]);
164 start_addr = params[1];
165 end_addr = params[1] + maxlen;
166 maxparam = params[0];
168 for (cell_t i=3; i<=maxparam; i++)
170 if ((params[i] >= start_addr) && (params[i] <= end_addr))
176 buf = (copy) ? g_formatbuf : destbuf;
177 res = atcprintf(buf, maxlen, fmt, pCtx, params, &arg);
181 memcpy(destbuf, g_formatbuf, res+1);
184 return static_cast<cell_t>(res);
187 static cell_t sm_vformat(IPluginContext *pContext, const cell_t *params)
189 int vargPos = static_cast<int>(params[4]);
191 /* Get the parent parameter array */
192 sp_context_t *ctx = pContext->GetContext();
193 cell_t *local_params = (cell_t *)(ctx->memory + ctx->frm + (2 * sizeof(cell_t)));
195 cell_t max = local_params[0];
196 if (vargPos > (int)max + 1)
198 return pContext->ThrowNativeError("Argument index is invalid: %d", vargPos);
201 cell_t addr_start = params[1];
202 cell_t addr_end = addr_start + params[2];
204 for (int i=vargPos; i<=max; i++)
206 /* Does this clip bounds? */
207 if ((local_params[i] >= addr_start)
208 && (local_params[i] <= addr_end))
215 /* Get destination info */
216 char *format, *destination;
217 size_t maxlen = static_cast<size_t>(params[2]);
221 destination = g_formatbuf;
223 pContext->LocalToString(params[1], &destination);
226 pContext->LocalToString(params[3], &format);
228 size_t total = atcprintf(destination, maxlen, format, pContext, local_params, &vargPos);
230 /* Perform copy-on-write if we need to */
233 pContext->StringToLocal(params[1], maxlen, g_formatbuf);
239 /* :TODO: make this UTF8 safe */
240 static cell_t StrBreak(IPluginContext *pContext, const cell_t *params)
247 pContext->LocalToString(params[1], (char **)&input);
248 pContext->LocalToString(params[2], &out);
251 const char *inptr = input;
252 /* Eat up whitespace */
253 while (*inptr != '\0' && IsWhitespace(inptr))
267 const char *start, *end = NULL;
269 bool quoted = (*inptr == '"');
274 /* Read input until we reach a quote. */
275 while (*inptr != '\0' && *inptr != '"')
277 /* Update the end point, increment the stream. */
280 /* Read one more token if we reached an end quote */
287 /* Read input until we reach a space */
288 while (*inptr != '\0' && !IsWhitespace(inptr))
290 /* Update the end point, increment the stream. */
295 /* Copy the string we found, if necessary */
305 for (const char *ptr=start;
306 (ptr <= end) && ((unsigned)(outptr - out) < (outMax));
314 /* Consume more of the string until we reach non-whitespace */
315 while (*inptr != '\0' && IsWhitespace(inptr))
325 return inptr - input;
328 REGISTER_NATIVES(basicStrings)
330 {"strlen", sm_strlen},
331 {"StrBreak", StrBreak},
332 {"StrContains", sm_contain},
333 {"strcmp", sm_strcmp},
334 {"StrCompare", sm_strcmp}, /* Backwards compat shim */
335 {"strncmp", sm_strncmp},
336 {"strcopy", sm_strcopy},
337 {"StrCopy", sm_strcopy}, /* Backwards compat shim */
338 {"StringToInt", sm_strconvint},
339 {"IntToString", sm_numtostr},
340 {"StringToFloat", sm_strtofloat},
341 {"FloatToString", sm_floattostr},
342 {"Format", sm_format},
343 {"FormatEx", sm_formatex},
344 {"VFormat", sm_vformat},