sourcemod/core/smn_string.cpp

329 lines
7.4 KiB
C++
Raw Normal View History

/**
* vim: set ts=4 :
* ===============================================================
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
* ===============================================================
*
* This file is not open source and may not be copied without explicit
* written permission of AlliedModders LLC. This file may not be redistributed
* in whole or significant part.
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
*
* Version: $Id$
*/
#include <string.h>
#include <stdlib.h>
#include "sm_globals.h"
#include "sm_stringutil.h"
#include "TextParsers.h"
inline const char *_strstr(const char *str, const char *substr)
{
#ifdef PLATFORM_WINDOWS
return strstr(str, substr);
#elif defined PLATFORM_LINUX
return (const char *)strstr(str, substr);
#endif
}
/*********************************************
* *
* STRING MANIPULATION NATIVE IMPLEMENTATIONS *
* *
*********************************************/
static cell_t sm_strlen(IPluginContext *pCtx, const cell_t *params)
{
char *str;
pCtx->LocalToString(params[1], &str);
return strlen(str);
}
static cell_t sm_contain(IPluginContext *pCtx, const cell_t *params)
{
typedef const char *(*STRSEARCH)(const char *, const char *);
STRSEARCH func;
char *str, *substr;
pCtx->LocalToString(params[1], &str);
pCtx->LocalToString(params[2], &substr);
func = (params[3]) ? _strstr : stristr;
const char *pos = func(str, substr);
if (pos)
{
return (pos - str);
}
return -1;
}
static cell_t sm_strcmp(IPluginContext *pCtx, const cell_t *params)
{
typedef int (*STRCOMPARE)(const char *, const char *);
STRCOMPARE func;
char *str1, *str2;
pCtx->LocalToString(params[1], &str1);
pCtx->LocalToString(params[2], &str2);
func = (params[3]) ? strcmp : stricmp;
return (func(str1, str2));
}
static cell_t sm_strcopy(IPluginContext *pCtx, const cell_t *params)
{
char *dest, *src;
pCtx->LocalToString(params[1], &dest);
pCtx->LocalToString(params[3], &src);
return strncopy(dest, src, params[2]);
}
static cell_t sm_strconvint(IPluginContext *pCtx, const cell_t *params)
{
char *str, *dummy;
pCtx->LocalToString(params[1], &str);
return static_cast<cell_t>(strtol(str, &dummy, params[2]));
}
static cell_t sm_numtostr(IPluginContext *pCtx, const cell_t *params)
{
char *str;
pCtx->LocalToString(params[2], &str);
size_t res = UTIL_Format(str, params[3], "%d", params[1]);
return static_cast<cell_t>(res);
}
static cell_t sm_strtofloat(IPluginContext *pCtx, const cell_t *params)
{
char *str, *dummy;
pCtx->LocalToString(params[1], &str);
float val = (float)strtod(str, &dummy);
return sp_ftoc(val);
}
static cell_t sm_floattostr(IPluginContext *pCtx, const cell_t *params)
{
char *str;
pCtx->LocalToString(params[2], &str);
size_t res = UTIL_Format(str, params[3], "%f", sp_ctof(params[1]));
return static_cast<cell_t>(res);
}
static cell_t sm_formatex(IPluginContext *pCtx, const cell_t *params)
{
char *buf, *fmt;
size_t res;
int arg = 4;
pCtx->LocalToString(params[1], &buf);
pCtx->LocalToString(params[3], &fmt);
res = atcprintf(buf, static_cast<size_t>(params[2]), fmt, pCtx, params, &arg);
return static_cast<cell_t>(res);
}
static char g_formatbuf[2048];
static cell_t sm_format(IPluginContext *pCtx, const cell_t *params)
{
char *buf, *fmt, *destbuf;
cell_t start_addr, end_addr, maxparam;
size_t res, maxlen;
int arg = 4;
bool copy = false;
pCtx->LocalToString(params[1], &destbuf);
pCtx->LocalToString(params[3], &fmt);
maxlen = static_cast<size_t>(params[2]);
start_addr = params[1];
end_addr = params[1] + maxlen;
maxparam = params[0];
for (cell_t i=3; i<=maxparam; i++)
{
if ((params[i] >= start_addr) && (params[i] <= end_addr))
{
copy = true;
break;
}
}
buf = (copy) ? g_formatbuf : destbuf;
res = atcprintf(buf, maxlen, fmt, pCtx, params, &arg);
if (copy)
{
memcpy(destbuf, g_formatbuf, res+1);
}
return static_cast<cell_t>(res);
}
static cell_t sm_vformat(IPluginContext *pContext, const cell_t *params)
{
int vargPos = static_cast<int>(params[4]);
/* Get the parent parameter array */
sp_context_t *ctx = pContext->GetContext();
cell_t *local_params = (cell_t *)(ctx->memory + ctx->frm + (2 * sizeof(cell_t)));
cell_t max = local_params[0];
if (vargPos > (int)max + 1)
{
return pContext->ThrowNativeError("Argument index is invalid: %d", vargPos);
}
cell_t addr_start = params[1];
cell_t addr_end = addr_start + params[2];
bool copy = false;
for (int i=vargPos; i<=max; i++)
{
/* Does this clip bounds? */
if ((local_params[i] >= addr_start)
&& (local_params[i] <= addr_end))
{
copy = true;
break;
}
}
/* Get destination info */
char *format, *destination;
size_t maxlen = static_cast<size_t>(params[2]);
if (copy)
{
destination = g_formatbuf;
} else {
pContext->LocalToString(params[1], &destination);
}
pContext->LocalToString(params[3], &format);
size_t total = atcprintf(destination, maxlen, format, pContext, local_params, &vargPos);
/* Perform copy-on-write if we need to */
if (copy)
{
pContext->StringToLocal(params[1], maxlen, g_formatbuf);
}
return total;
}
/* :TODO: make this UTF8 safe */
static cell_t StrBreak(IPluginContext *pContext, const cell_t *params)
{
const char *input;
char *out;
size_t outMax;
/* Get parameters */
pContext->LocalToString(params[1], (char **)&input);
pContext->LocalToString(params[2], &out);
outMax = params[3];
const char *inptr = input;
/* Eat up whitespace */
while (*inptr != '\0' && IsWhitespace(inptr))
{
inptr++;
}
if (*inptr == '\0')
{
if (outMax)
{
*out = '\0';
}
return -1;
}
const char *start, *end = NULL;
bool quoted = (*inptr == '"');
if (quoted)
{
inptr++;
start = inptr;
/* Read input until we reach a quote. */
while (*inptr != '\0' && *inptr != '"')
{
/* Update the end point, increment the stream. */
end = inptr++;
}
/* Read one more token if we reached an end quote */
if (*inptr == '"')
{
inptr++;
}
} else {
start = inptr;
/* Read input until we reach a space */
while (*inptr != '\0' && !IsWhitespace(inptr))
{
/* Update the end point, increment the stream. */
end = inptr++;
}
}
/* Copy the string we found, if necessary */
if (end == NULL)
{
if (outMax)
{
*out = '\0';
}
} else if (outMax) {
char *outptr = out;
outMax--;
for (const char *ptr=start;
(ptr <= end) && ((unsigned)(outptr - out) < (outMax));
ptr++, outptr++)
{
*outptr = *ptr;
}
*outptr = '\0';
}
/* Consume more of the string until we reach non-whitespace */
while (*inptr != '\0' && IsWhitespace(inptr))
{
inptr++;
}
if (*inptr == '\0')
{
return -1;
}
return inptr - input;
}
REGISTER_NATIVES(basicStrings)
{
{"strlen", sm_strlen},
{"StrBreak", StrBreak},
{"StrContains", sm_contain},
{"StrCompare", sm_strcmp},
{"StrCopy", sm_strcopy},
{"StringToInt", sm_strconvint},
{"IntToString", sm_numtostr},
{"StringToFloat", sm_strtofloat},
{"FloatToString", sm_floattostr},
{"Format", sm_format},
{"FormatEx", sm_formatex},
{"VFormat", sm_vformat},
{NULL, NULL},
};