2 * ===============================================================
3 * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
4 * ===============================================================
6 * This file is not open source and may not be copied without explicit
7 * written permission of AlliedModders LLC. This file may not be redistributed
8 * in whole or significant part.
9 * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
16 #include "sm_globals.h"
17 #include "sm_stringutil.h"
18 #include "TextParsers.h"
20 inline const char *_strstr(const char *str, const char *substr)
22 #ifdef PLATFORM_WINDOWS
23 return strstr(str, substr);
24 #elif defined PLATFORM_LINUX
25 return (const char *)strstr(str, substr);
29 /*********************************************
31 * STRING MANIPULATION NATIVE IMPLEMENTATIONS *
33 *********************************************/
35 static cell_t sm_strlen(IPluginContext *pCtx, const cell_t *params)
38 pCtx->LocalToString(params[1], &str);
43 static cell_t sm_contain(IPluginContext *pCtx, const cell_t *params)
45 typedef const char *(*STRSEARCH)(const char *, const char *);
49 pCtx->LocalToString(params[1], &str);
50 pCtx->LocalToString(params[2], &substr);
52 func = (params[3]) ? _strstr : stristr;
53 const char *pos = func(str, substr);
62 static cell_t sm_strcmp(IPluginContext *pCtx, const cell_t *params)
64 typedef int (*STRCOMPARE)(const char *, const char *);
68 pCtx->LocalToString(params[1], &str1);
69 pCtx->LocalToString(params[2], &str2);
71 func = (params[3]) ? strcmp : stricmp;
73 return (func(str1, str2));
76 static cell_t sm_strcopy(IPluginContext *pCtx, const cell_t *params)
80 pCtx->LocalToString(params[1], &dest);
81 pCtx->LocalToString(params[3], &src);
83 return strncopy(dest, src, params[2]);
86 static cell_t sm_strconvint(IPluginContext *pCtx, const cell_t *params)
89 pCtx->LocalToString(params[1], &str);
91 return static_cast<cell_t>(strtol(str, &dummy, params[2]));
94 static cell_t sm_numtostr(IPluginContext *pCtx, const cell_t *params)
97 pCtx->LocalToString(params[2], &str);
98 size_t res = UTIL_Format(str, params[3], "%d", params[1]);
100 return static_cast<cell_t>(res);
103 static cell_t sm_strtofloat(IPluginContext *pCtx, const cell_t *params)
106 pCtx->LocalToString(params[1], &str);
108 float val = (float)strtod(str, &dummy);
113 static cell_t sm_floattostr(IPluginContext *pCtx, const cell_t *params)
116 pCtx->LocalToString(params[2], &str);
117 size_t res = UTIL_Format(str, params[3], "%f", sp_ctof(params[1]));
119 return static_cast<cell_t>(res);
122 static cell_t sm_formatex(IPluginContext *pCtx, const cell_t *params)
128 pCtx->LocalToString(params[1], &buf);
129 pCtx->LocalToString(params[3], &fmt);
130 res = atcprintf(buf, static_cast<size_t>(params[2]), fmt, pCtx, params, &arg);
132 return static_cast<cell_t>(res);
135 static char g_formatbuf[2048];
136 static cell_t sm_format(IPluginContext *pCtx, const cell_t *params)
138 char *buf, *fmt, *destbuf;
139 cell_t start_addr, end_addr, maxparam;
144 pCtx->LocalToString(params[1], &destbuf);
145 pCtx->LocalToString(params[3], &fmt);
147 maxlen = static_cast<size_t>(params[2]);
148 start_addr = params[1];
149 end_addr = params[1] + maxlen;
150 maxparam = params[0];
152 for (cell_t i=3; i<=maxparam; i++)
154 if ((params[i] >= start_addr) && (params[i] <= end_addr))
160 buf = (copy) ? g_formatbuf : destbuf;
161 res = atcprintf(buf, maxlen, fmt, pCtx, params, &arg);
165 memcpy(destbuf, g_formatbuf, res+1);
168 return static_cast<cell_t>(res);
171 static cell_t sm_vformat(IPluginContext *pContext, const cell_t *params)
173 int vargPos = static_cast<int>(params[4]);
175 /* Get the parent parameter array */
176 sp_context_t *ctx = pContext->GetContext();
177 cell_t *local_params = (cell_t *)(ctx->memory + ctx->frm + (2 * sizeof(cell_t)));
179 cell_t max = local_params[0];
180 if (vargPos > (int)max + 1)
182 return pContext->ThrowNativeError("Argument index is invalid: %d", vargPos);
185 cell_t addr_start = params[1];
186 cell_t addr_end = addr_start + params[2];
188 for (int i=vargPos; i<=max; i++)
190 /* Does this clip bounds? */
191 if ((local_params[i] >= addr_start)
192 && (local_params[i] <= addr_end))
199 /* Get destination info */
200 char *format, *destination;
201 size_t maxlen = static_cast<size_t>(params[2]);
205 destination = g_formatbuf;
207 pContext->LocalToString(params[1], &destination);
210 pContext->LocalToString(params[3], &format);
212 size_t total = atcprintf(destination, maxlen, format, pContext, local_params, &vargPos);
214 /* Perform copy-on-write if we need to */
217 pContext->StringToLocal(params[1], maxlen, g_formatbuf);
223 /* :TODO: make this UTF8 safe */
224 static cell_t StrBreak(IPluginContext *pContext, const cell_t *params)
231 pContext->LocalToString(params[1], (char **)&input);
232 pContext->LocalToString(params[2], &out);
235 const char *inptr = input;
236 /* Eat up whitespace */
237 while (*inptr != '\0' && IsWhitespace(inptr))
251 const char *start, *end = NULL;
253 bool quoted = (*inptr == '"');
258 /* Read input until we reach a quote. */
259 while (*inptr != '\0' && *inptr != '"')
261 /* Update the end point, increment the stream. */
264 /* Read one more token if we reached an end quote */
271 /* Read input until we reach a space */
272 while (*inptr != '\0' && !IsWhitespace(inptr))
274 /* Update the end point, increment the stream. */
279 /* Copy the string we found, if necessary */
289 for (const char *ptr=start;
290 (ptr <= end) && ((unsigned)(outptr - out) < (outMax));
298 /* Consume more of the string until we reach non-whitespace */
299 while (*inptr != '\0' && IsWhitespace(inptr))
309 return inptr - input;
312 REGISTER_NATIVES(basicStrings)
314 {"strlen", sm_strlen},
315 {"StrBreak", StrBreak},
316 {"StrContains", sm_contain},
317 {"StrCompare", sm_strcmp},
318 {"StrCopy", sm_strcopy},
319 {"StringToInt", sm_strconvint},
320 {"IntToString", sm_numtostr},
321 {"StringToFloat", sm_strtofloat},
322 {"FloatToString", sm_floattostr},
323 {"Format", sm_format},
324 {"FormatEx", sm_formatex},
325 {"VFormat", sm_vformat},