core/smn_string.cpp
author Scott Ehlert <ds@alliedmods.net>
Thu Mar 22 21:50:20 2007 +0000 (2007-03-22)
changeset 653 ef60870067ff
parent 631 76dc2aa558e5
child 680 b5f7893fd4f6
permissions -rw-r--r--
More consistency of some sort...

Oh god, what has possessed me to do this?
     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_strcopy(IPluginContext *pCtx, const cell_t *params)
    78 {
    79 	char *dest, *src;
    80 
    81 	pCtx->LocalToString(params[1], &dest);
    82 	pCtx->LocalToString(params[3], &src);
    83 
    84 	return strncopy(dest, src, params[2]);
    85 }
    86 
    87 static cell_t sm_strconvint(IPluginContext *pCtx, const cell_t *params)
    88 {
    89 	char *str, *dummy;
    90 	pCtx->LocalToString(params[1], &str);
    91 
    92 	return static_cast<cell_t>(strtol(str, &dummy, params[2]));
    93 }
    94 
    95 static cell_t sm_numtostr(IPluginContext *pCtx, const cell_t *params)
    96 {
    97 	char *str;
    98 	pCtx->LocalToString(params[2], &str);
    99 	size_t res = UTIL_Format(str, params[3], "%d", params[1]);
   100 
   101 	return static_cast<cell_t>(res);
   102 }
   103 
   104 static cell_t sm_strtofloat(IPluginContext *pCtx, const cell_t *params)
   105 {
   106 	char *str, *dummy;
   107 	pCtx->LocalToString(params[1], &str);
   108 
   109 	float val = (float)strtod(str, &dummy);
   110 
   111 	return sp_ftoc(val);
   112 }
   113 
   114 static cell_t sm_floattostr(IPluginContext *pCtx, const cell_t *params)
   115 {
   116 	char *str;
   117 	pCtx->LocalToString(params[2], &str);
   118 	size_t res = UTIL_Format(str, params[3], "%f", sp_ctof(params[1]));
   119 
   120 	return static_cast<cell_t>(res);
   121 }
   122 
   123 static cell_t sm_formatex(IPluginContext *pCtx, const cell_t *params)
   124 {
   125 	char *buf, *fmt;
   126 	size_t res;
   127 	int arg = 4;
   128 
   129 	pCtx->LocalToString(params[1], &buf);
   130 	pCtx->LocalToString(params[3], &fmt);
   131 	res = atcprintf(buf, static_cast<size_t>(params[2]), fmt, pCtx, params, &arg);
   132 
   133 	return static_cast<cell_t>(res);
   134 }
   135 
   136 static char g_formatbuf[2048];
   137 static cell_t sm_format(IPluginContext *pCtx, const cell_t *params)
   138 {
   139 	char *buf, *fmt, *destbuf;
   140 	cell_t start_addr, end_addr, maxparam;
   141 	size_t res, maxlen;
   142 	int arg = 4;
   143 	bool copy = false;
   144 
   145 	pCtx->LocalToString(params[1], &destbuf);
   146 	pCtx->LocalToString(params[3], &fmt);
   147 
   148 	maxlen = static_cast<size_t>(params[2]);
   149 	start_addr = params[1];
   150 	end_addr = params[1] + maxlen;
   151 	maxparam = params[0];
   152 
   153 	for (cell_t i=3; i<=maxparam; i++)
   154 	{
   155 		if ((params[i] >= start_addr) && (params[i] <= end_addr))
   156 		{
   157 			copy = true;
   158 			break;
   159 		}
   160 	}
   161 	buf = (copy) ? g_formatbuf : destbuf;
   162 	res = atcprintf(buf, maxlen, fmt, pCtx, params, &arg);
   163 
   164 	if (copy)
   165 	{
   166 		memcpy(destbuf, g_formatbuf, res+1);
   167 	}
   168 
   169 	return static_cast<cell_t>(res);
   170 }
   171 
   172 static cell_t sm_vformat(IPluginContext *pContext, const cell_t *params)
   173 {
   174 	int vargPos = static_cast<int>(params[4]);
   175 
   176 	/* Get the parent parameter array */
   177 	sp_context_t *ctx = pContext->GetContext();
   178 	cell_t *local_params = (cell_t *)(ctx->memory + ctx->frm + (2 * sizeof(cell_t)));
   179 
   180 	cell_t max = local_params[0];
   181 	if (vargPos > (int)max + 1)
   182 	{
   183 		return pContext->ThrowNativeError("Argument index is invalid: %d", vargPos);
   184 	}
   185 
   186 	cell_t addr_start = params[1];
   187 	cell_t addr_end = addr_start + params[2];
   188 	bool copy = false;
   189 	for (int i=vargPos; i<=max; i++)
   190 	{
   191 		/* Does this clip bounds? */
   192 		if ((local_params[i] >= addr_start)
   193 			&& (local_params[i] <= addr_end))
   194 		{
   195 			copy = true;
   196 			break;
   197 		}
   198 	}
   199 
   200 	/* Get destination info */
   201 	char *format, *destination;
   202 	size_t maxlen = static_cast<size_t>(params[2]);
   203 
   204 	if (copy)
   205 	{
   206 		destination = g_formatbuf;
   207 	} else {
   208 		pContext->LocalToString(params[1], &destination);
   209 	}
   210 
   211 	pContext->LocalToString(params[3], &format);
   212 
   213 	size_t total = atcprintf(destination, maxlen, format, pContext, local_params, &vargPos);
   214 
   215 	/* Perform copy-on-write if we need to */
   216 	if (copy)
   217 	{
   218 		pContext->StringToLocal(params[1], maxlen, g_formatbuf);
   219 	}
   220 
   221 	return total;
   222 }
   223 
   224 /* :TODO: make this UTF8 safe */
   225 static cell_t StrBreak(IPluginContext *pContext, const cell_t *params)
   226 {
   227 	const char *input;
   228 	char *out;
   229 	size_t outMax;
   230 
   231 	/* Get parameters */
   232 	pContext->LocalToString(params[1], (char **)&input);
   233 	pContext->LocalToString(params[2], &out);
   234 	outMax = params[3];
   235 
   236 	const char *inptr = input;
   237 	/* Eat up whitespace */
   238 	while (*inptr != '\0' && IsWhitespace(inptr))
   239 	{
   240 		inptr++;
   241 	}
   242 
   243 	if (*inptr == '\0')
   244 	{
   245 		if (outMax)
   246 		{
   247 			*out = '\0';
   248 		}
   249 		return -1;
   250 	}
   251 
   252 	const char *start, *end = NULL;
   253 
   254 	bool quoted = (*inptr == '"');
   255 	if (quoted)
   256 	{
   257 		inptr++;
   258 		start = inptr;
   259 		/* Read input until we reach a quote. */
   260 		while (*inptr != '\0' && *inptr != '"')
   261 		{
   262 			/* Update the end point, increment the stream. */
   263 			end = inptr++;
   264 		}
   265 		/* Read one more token if we reached an end quote */
   266 		if (*inptr == '"')
   267 		{
   268 			inptr++;
   269 		}
   270 	} else {
   271 		start = inptr;
   272 		/* Read input until we reach a space */
   273 		while (*inptr != '\0' && !IsWhitespace(inptr))
   274 		{
   275 			/* Update the end point, increment the stream. */
   276 			end = inptr++;
   277 		}
   278 	}
   279 
   280 	/* Copy the string we found, if necessary */
   281 	if (end == NULL)
   282 	{
   283 		if (outMax)
   284 		{
   285 			*out = '\0';
   286 		}
   287 	} else if (outMax) {
   288 		char *outptr = out;
   289 		outMax--;
   290 		for (const char *ptr=start;
   291 			(ptr <= end) && ((unsigned)(outptr - out) < (outMax));
   292 			ptr++, outptr++)
   293 			{
   294 			*outptr = *ptr;
   295 		}
   296 		*outptr = '\0';
   297 	}
   298 
   299 	/* Consume more of the string until we reach non-whitespace */
   300 	while (*inptr != '\0' && IsWhitespace(inptr))
   301 	{
   302 		inptr++;
   303 	}
   304 
   305 	if (*inptr == '\0')
   306 	{
   307 		return -1;
   308 	}
   309 
   310 	return inptr - input;
   311 }
   312 
   313 REGISTER_NATIVES(basicStrings)
   314 {
   315 	{"strlen",				sm_strlen},
   316 	{"StrBreak",			StrBreak},
   317 	{"StrContains",			sm_contain},
   318 	{"StrCompare",			sm_strcmp},
   319 	{"StrCopy",				sm_strcopy},
   320 	{"StringToInt",			sm_strconvint},
   321 	{"IntToString",			sm_numtostr},
   322 	{"StringToFloat",		sm_strtofloat},
   323 	{"FloatToString",		sm_floattostr},
   324 	{"Format",				sm_format},
   325 	{"FormatEx",			sm_formatex},
   326 	{"VFormat",				sm_vformat},
   327 	{NULL,					NULL},
   328 };