core/smn_string.cpp
author Scott Ehlert <ds@alliedmods.net>
Sat Apr 21 17:03:28 2007 +0000 (2007-04-21)
changeset 702 ff520b71249c
parent 681 02f6c1c5fd06
child 748 0433498ab05c
permissions -rw-r--r--
Wow, how did I forget this - exported IMemoryUtils interface
     1 /**
     2  * vim: set ts=4 :
     3  * ===============================================================
     4  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     5  * ===============================================================
     6  *
     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
    11  *
    12  * Version: $Id$
    13  */
    14 
    15 #include <string.h>
    16 #include <stdlib.h>
    17 #include "sm_globals.h"
    18 #include "sm_stringutil.h"
    19 #include "TextParsers.h"
    20 
    21 inline const char *_strstr(const char *str, const char *substr)
    22 {
    23 #ifdef PLATFORM_WINDOWS
    24 	return strstr(str, substr);
    25 #elif defined PLATFORM_LINUX
    26 	return (const char *)strstr(str, substr);
    27 #endif
    28 }
    29 
    30 /*********************************************
    31 *                                            *
    32 * STRING MANIPULATION NATIVE IMPLEMENTATIONS *
    33 *                                            *
    34 *********************************************/
    35 
    36 static cell_t sm_strlen(IPluginContext *pCtx, const cell_t *params)
    37 {
    38 	char *str;
    39 	pCtx->LocalToString(params[1], &str);
    40 
    41 	return strlen(str);
    42 }
    43 
    44 static cell_t sm_contain(IPluginContext *pCtx, const cell_t *params)
    45 {
    46 	typedef const char *(*STRSEARCH)(const char *, const char *);
    47 	STRSEARCH func;
    48 	char *str, *substr;
    49 
    50 	pCtx->LocalToString(params[1], &str);
    51 	pCtx->LocalToString(params[2], &substr);
    52 
    53 	func = (params[3]) ? _strstr : stristr;
    54 	const char *pos = func(str, substr);
    55 	if (pos)
    56 	{
    57 		return (pos - str);
    58 	}
    59 
    60 	return -1;
    61 }
    62 
    63 static cell_t sm_strcmp(IPluginContext *pCtx, const cell_t *params)
    64 {
    65 	typedef int (*STRCOMPARE)(const char *, const char *);
    66 	STRCOMPARE func;
    67 	char *str1, *str2;
    68 
    69 	pCtx->LocalToString(params[1], &str1);
    70 	pCtx->LocalToString(params[2], &str2);
    71 
    72 	func = (params[3]) ? strcmp : stricmp;
    73 
    74 	return (func(str1, str2));
    75 }
    76 
    77 static cell_t sm_strncmp(IPluginContext *pCtx, const cell_t *params)
    78 {
    79 	char *str1, *str2;
    80 
    81 	pCtx->LocalToString(params[1], &str1);
    82 	pCtx->LocalToString(params[2], &str2);
    83 	
    84 	if  (params[4])
    85 	{
    86 		return strncmp(str1, str2, (size_t)params[3]);
    87 	} else {
    88 		return strncasecmp(str1, str2, (size_t)params[3]);
    89 	}
    90 }
    91 
    92 static cell_t sm_strcopy(IPluginContext *pCtx, const cell_t *params)
    93 {
    94 	char *dest, *src;
    95 
    96 	pCtx->LocalToString(params[1], &dest);
    97 	pCtx->LocalToString(params[3], &src);
    98 
    99 	return strncopy(dest, src, params[2]);
   100 }
   101 
   102 static cell_t sm_strconvint(IPluginContext *pCtx, const cell_t *params)
   103 {
   104 	char *str, *dummy;
   105 	pCtx->LocalToString(params[1], &str);
   106 
   107 	return static_cast<cell_t>(strtol(str, &dummy, params[2]));
   108 }
   109 
   110 static cell_t sm_numtostr(IPluginContext *pCtx, const cell_t *params)
   111 {
   112 	char *str;
   113 	pCtx->LocalToString(params[2], &str);
   114 	size_t res = UTIL_Format(str, params[3], "%d", params[1]);
   115 
   116 	return static_cast<cell_t>(res);
   117 }
   118 
   119 static cell_t sm_strtofloat(IPluginContext *pCtx, const cell_t *params)
   120 {
   121 	char *str, *dummy;
   122 	pCtx->LocalToString(params[1], &str);
   123 
   124 	float val = (float)strtod(str, &dummy);
   125 
   126 	return sp_ftoc(val);
   127 }
   128 
   129 static cell_t sm_floattostr(IPluginContext *pCtx, const cell_t *params)
   130 {
   131 	char *str;
   132 	pCtx->LocalToString(params[2], &str);
   133 	size_t res = UTIL_Format(str, params[3], "%f", sp_ctof(params[1]));
   134 
   135 	return static_cast<cell_t>(res);
   136 }
   137 
   138 static cell_t sm_formatex(IPluginContext *pCtx, const cell_t *params)
   139 {
   140 	char *buf, *fmt;
   141 	size_t res;
   142 	int arg = 4;
   143 
   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);
   147 
   148 	return static_cast<cell_t>(res);
   149 }
   150 
   151 static char g_formatbuf[2048];
   152 static cell_t sm_format(IPluginContext *pCtx, const cell_t *params)
   153 {
   154 	char *buf, *fmt, *destbuf;
   155 	cell_t start_addr, end_addr, maxparam;
   156 	size_t res, maxlen;
   157 	int arg = 4;
   158 	bool copy = false;
   159 
   160 	pCtx->LocalToString(params[1], &destbuf);
   161 	pCtx->LocalToString(params[3], &fmt);
   162 
   163 	maxlen = static_cast<size_t>(params[2]);
   164 	start_addr = params[1];
   165 	end_addr = params[1] + maxlen;
   166 	maxparam = params[0];
   167 
   168 	for (cell_t i=3; i<=maxparam; i++)
   169 	{
   170 		if ((params[i] >= start_addr) && (params[i] <= end_addr))
   171 		{
   172 			copy = true;
   173 			break;
   174 		}
   175 	}
   176 	buf = (copy) ? g_formatbuf : destbuf;
   177 	res = atcprintf(buf, maxlen, fmt, pCtx, params, &arg);
   178 
   179 	if (copy)
   180 	{
   181 		memcpy(destbuf, g_formatbuf, res+1);
   182 	}
   183 
   184 	return static_cast<cell_t>(res);
   185 }
   186 
   187 static cell_t sm_vformat(IPluginContext *pContext, const cell_t *params)
   188 {
   189 	int vargPos = static_cast<int>(params[4]);
   190 
   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)));
   194 
   195 	cell_t max = local_params[0];
   196 	if (vargPos > (int)max + 1)
   197 	{
   198 		return pContext->ThrowNativeError("Argument index is invalid: %d", vargPos);
   199 	}
   200 
   201 	cell_t addr_start = params[1];
   202 	cell_t addr_end = addr_start + params[2];
   203 	bool copy = false;
   204 	for (int i=vargPos; i<=max; i++)
   205 	{
   206 		/* Does this clip bounds? */
   207 		if ((local_params[i] >= addr_start)
   208 			&& (local_params[i] <= addr_end))
   209 		{
   210 			copy = true;
   211 			break;
   212 		}
   213 	}
   214 
   215 	/* Get destination info */
   216 	char *format, *destination;
   217 	size_t maxlen = static_cast<size_t>(params[2]);
   218 
   219 	if (copy)
   220 	{
   221 		destination = g_formatbuf;
   222 	} else {
   223 		pContext->LocalToString(params[1], &destination);
   224 	}
   225 
   226 	pContext->LocalToString(params[3], &format);
   227 
   228 	size_t total = atcprintf(destination, maxlen, format, pContext, local_params, &vargPos);
   229 
   230 	/* Perform copy-on-write if we need to */
   231 	if (copy)
   232 	{
   233 		pContext->StringToLocal(params[1], maxlen, g_formatbuf);
   234 	}
   235 
   236 	return total;
   237 }
   238 
   239 /* :TODO: make this UTF8 safe */
   240 static cell_t StrBreak(IPluginContext *pContext, const cell_t *params)
   241 {
   242 	const char *input;
   243 	char *out;
   244 	size_t outMax;
   245 
   246 	/* Get parameters */
   247 	pContext->LocalToString(params[1], (char **)&input);
   248 	pContext->LocalToString(params[2], &out);
   249 	outMax = params[3];
   250 
   251 	const char *inptr = input;
   252 	/* Eat up whitespace */
   253 	while (*inptr != '\0' && IsWhitespace(inptr))
   254 	{
   255 		inptr++;
   256 	}
   257 
   258 	if (*inptr == '\0')
   259 	{
   260 		if (outMax)
   261 		{
   262 			*out = '\0';
   263 		}
   264 		return -1;
   265 	}
   266 
   267 	const char *start, *end = NULL;
   268 
   269 	bool quoted = (*inptr == '"');
   270 	if (quoted)
   271 	{
   272 		inptr++;
   273 		start = inptr;
   274 		/* Read input until we reach a quote. */
   275 		while (*inptr != '\0' && *inptr != '"')
   276 		{
   277 			/* Update the end point, increment the stream. */
   278 			end = inptr++;
   279 		}
   280 		/* Read one more token if we reached an end quote */
   281 		if (*inptr == '"')
   282 		{
   283 			inptr++;
   284 		}
   285 	} else {
   286 		start = inptr;
   287 		/* Read input until we reach a space */
   288 		while (*inptr != '\0' && !IsWhitespace(inptr))
   289 		{
   290 			/* Update the end point, increment the stream. */
   291 			end = inptr++;
   292 		}
   293 	}
   294 
   295 	/* Copy the string we found, if necessary */
   296 	if (end == NULL)
   297 	{
   298 		if (outMax)
   299 		{
   300 			*out = '\0';
   301 		}
   302 	} else if (outMax) {
   303 		char *outptr = out;
   304 		outMax--;
   305 		for (const char *ptr=start;
   306 			(ptr <= end) && ((unsigned)(outptr - out) < (outMax));
   307 			ptr++, outptr++)
   308 			{
   309 			*outptr = *ptr;
   310 		}
   311 		*outptr = '\0';
   312 	}
   313 
   314 	/* Consume more of the string until we reach non-whitespace */
   315 	while (*inptr != '\0' && IsWhitespace(inptr))
   316 	{
   317 		inptr++;
   318 	}
   319 
   320 	if (*inptr == '\0')
   321 	{
   322 		return -1;
   323 	}
   324 
   325 	return inptr - input;
   326 }
   327 
   328 REGISTER_NATIVES(basicStrings)
   329 {
   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},
   345 	{NULL,					NULL},
   346 };