core/sm_stringutil.cpp
branchrefac-jit
changeset 2284 026da5437111
parent 2192 7602d7fb60d9
child 2288 15c77b21589a
     1.1 --- a/core/sm_stringutil.cpp	Fri Jul 11 06:51:21 2008 +0000
     1.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.3 @@ -1,1582 +0,0 @@
     1.4 -/**
     1.5 - * vim: set ts=4 :
     1.6 - * =============================================================================
     1.7 - * SourceMod
     1.8 - * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     1.9 - * =============================================================================
    1.10 - *
    1.11 - * This program is free software; you can redistribute it and/or modify it under
    1.12 - * the terms of the GNU General Public License, version 3.0, as published by the
    1.13 - * Free Software Foundation.
    1.14 - * 
    1.15 - * This program is distributed in the hope that it will be useful, but WITHOUT
    1.16 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    1.17 - * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    1.18 - * details.
    1.19 - *
    1.20 - * You should have received a copy of the GNU General Public License along with
    1.21 - * this program.  If not, see <http://www.gnu.org/licenses/>.
    1.22 - *
    1.23 - * As a special exception, AlliedModders LLC gives you permission to link the
    1.24 - * code of this program (as well as its derivative works) to "Half-Life 2," the
    1.25 - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    1.26 - * by the Valve Corporation.  You must obey the GNU General Public License in
    1.27 - * all respects for all other code used.  Additionally, AlliedModders LLC grants
    1.28 - * this exception to all derivative works.  AlliedModders LLC defines further
    1.29 - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    1.30 - * or <http://www.sourcemod.net/license.php>.
    1.31 - *
    1.32 - * Version: $Id$
    1.33 - */
    1.34 -
    1.35 -#include <stdlib.h>
    1.36 -#include <ctype.h>
    1.37 -#include <stdarg.h>
    1.38 -#include "sm_stringutil.h"
    1.39 -#include "Logger.h"
    1.40 -#include "PluginSys.h"
    1.41 -#include "Translator.h"
    1.42 -#include "PlayerManager.h"
    1.43 -
    1.44 -#define LADJUST			0x00000004		/* left adjustment */
    1.45 -#define ZEROPAD			0x00000080		/* zero (as opposed to blank) pad */
    1.46 -#define UPPERDIGITS		0x00000200		/* make alpha digits uppercase */
    1.47 -#define to_digit(c)		((c) - '0')
    1.48 -#define is_digit(c)		((unsigned)to_digit(c) <= 9)
    1.49 -
    1.50 -#define CHECK_ARGS(x) \
    1.51 -	if ((arg+x) > args) { \
    1.52 -		pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "String formatted incorrectly - parameter %d (total %d)", arg, args); \
    1.53 -		return 0; \
    1.54 -	}
    1.55 -
    1.56 -inline void ReorderTranslationParams(const Translation *pTrans, cell_t *params)
    1.57 -{
    1.58 -	cell_t new_params[MAX_TRANSLATE_PARAMS];
    1.59 -	for (unsigned int i = 0; i < pTrans->fmt_count; i++)
    1.60 -	{
    1.61 -		new_params[i] = params[pTrans->fmt_order[i]];
    1.62 -	}
    1.63 -	memcpy(params, new_params, pTrans->fmt_count * sizeof(cell_t));
    1.64 -}
    1.65 -
    1.66 -size_t Translate(char *buffer,
    1.67 -				 size_t maxlen,
    1.68 -				 IPluginContext *pCtx,
    1.69 -				 const char *key,
    1.70 -				 cell_t target,
    1.71 -				 const cell_t *params,
    1.72 -				 int *arg,
    1.73 -				 bool *error)
    1.74 -{
    1.75 -	unsigned int langid;
    1.76 -	*error = false;
    1.77 -	Translation pTrans;
    1.78 -	CPlugin *pl = (CPlugin *)g_PluginSys.FindPluginByContext(pCtx->GetContext());
    1.79 -	unsigned int max_params = 0;
    1.80 -	IPhraseCollection *pPhrases;
    1.81 -
    1.82 -	pPhrases = pl->GetPhrases();
    1.83 -
    1.84 -try_serverlang:
    1.85 -	if (target == SOURCEMOD_SERVER_LANGUAGE)
    1.86 -	{
    1.87 -		langid = g_Translator.GetServerLanguage();
    1.88 - 	}
    1.89 -	else if ((target >= 1) && (target <= g_Players.GetMaxClients()))
    1.90 -	{
    1.91 -		langid = g_Translator.GetClientLanguage(target);
    1.92 -	}
    1.93 -	else
    1.94 -	{
    1.95 -		pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Translation failed: invalid client index %d", target);
    1.96 -		goto error_out;
    1.97 -	}
    1.98 -
    1.99 -	if (pPhrases->FindTranslation(key, langid, &pTrans) != Trans_Okay)
   1.100 -	{
   1.101 -		if (target != SOURCEMOD_SERVER_LANGUAGE && langid != g_Translator.GetServerLanguage())
   1.102 -		{
   1.103 -			target = SOURCEMOD_SERVER_LANGUAGE;
   1.104 -			goto try_serverlang;
   1.105 -		}
   1.106 -		else if (langid != SOURCEMOD_LANGUAGE_ENGLISH)
   1.107 -		{
   1.108 -			if (!pPhrases->FindTranslation(key, SOURCEMOD_LANGUAGE_ENGLISH, &pTrans))
   1.109 -			{
   1.110 -				pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Language phrase \"%s\" not found", key);
   1.111 -				goto error_out;
   1.112 -			}
   1.113 -		}
   1.114 -		else
   1.115 -		{
   1.116 -			pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Language phrase \"%s\" not found", key);
   1.117 -			goto error_out;
   1.118 -		}
   1.119 -	}
   1.120 -
   1.121 -	max_params = pTrans.fmt_count;
   1.122 -
   1.123 -	if (max_params)
   1.124 -	{
   1.125 -		cell_t new_params[MAX_TRANSLATE_PARAMS];
   1.126 -
   1.127 -		/* Check if we're going to over the limit */
   1.128 -		if ((*arg) + (max_params - 1) > (size_t)params[0])
   1.129 -		{
   1.130 -			pCtx->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX, 
   1.131 -				"Translation string formatted incorrectly - missing at least %d parameters", 
   1.132 -				((*arg + (max_params - 1)) - params[0])
   1.133 -				);
   1.134 -			goto error_out;
   1.135 -		}
   1.136 -
   1.137 -		/* If we need to re-order the parameters, do so with a temporary array.
   1.138 -		 * Otherwise, we could run into trouble with continual formats, a la ShowActivity().
   1.139 -		 */
   1.140 -		memcpy(new_params, params, sizeof(cell_t) * (params[0] + 1));
   1.141 -		ReorderTranslationParams(&pTrans, &new_params[*arg]);
   1.142 -
   1.143 -		return atcprintf(buffer, maxlen, pTrans.szPhrase, pCtx, new_params, arg);
   1.144 -	}
   1.145 -	else
   1.146 -	{
   1.147 -		return atcprintf(buffer, maxlen, pTrans.szPhrase, pCtx, params, arg);
   1.148 -	}
   1.149 -	
   1.150 -error_out:
   1.151 -	*error = true;
   1.152 -	return 0;
   1.153 -}
   1.154 -
   1.155 -void AddString(char **buf_p, size_t &maxlen, const char *string, int width, int prec)
   1.156 -{
   1.157 -	int size = 0;
   1.158 -	char *buf;
   1.159 -	static char nlstr[] = {'(','n','u','l','l',')','\0'};
   1.160 -
   1.161 -	buf = *buf_p;
   1.162 -
   1.163 -	if (string == NULL)
   1.164 -	{
   1.165 -		string = nlstr;
   1.166 -		prec = -1;
   1.167 -	}
   1.168 -
   1.169 -	if (prec >= 0)
   1.170 -	{
   1.171 -		for (size = 0; size < prec; size++) 
   1.172 -		{
   1.173 -			if (string[size] == '\0')
   1.174 -			{
   1.175 -				break;
   1.176 -			}
   1.177 -		}
   1.178 -	}
   1.179 -	else
   1.180 -	{
   1.181 -		while (string[size++]);
   1.182 -		size--;
   1.183 -	}
   1.184 -
   1.185 -	if (size > (int)maxlen)
   1.186 -	{
   1.187 -		size = maxlen;
   1.188 -	}
   1.189 -
   1.190 -	maxlen -= size;
   1.191 -	width -= size;
   1.192 -
   1.193 -	while (size--)
   1.194 -	{
   1.195 -		*buf++ = *string++;
   1.196 -	}
   1.197 -
   1.198 -	while ((width-- > 0) && maxlen)
   1.199 -	{
   1.200 -		*buf++ = ' ';
   1.201 -		maxlen--;
   1.202 -	}
   1.203 -
   1.204 -	*buf_p = buf;
   1.205 -}
   1.206 -
   1.207 -void AddFloat(char **buf_p, size_t &maxlen, double fval, int width, int prec, int flags)
   1.208 -{
   1.209 -	int digits;					// non-fraction part digits
   1.210 -	double tmp;					// temporary
   1.211 -	char *buf = *buf_p;			// output buffer pointer
   1.212 -	int val;					// temporary
   1.213 -	int sign = 0;				// 0: positive, 1: negative
   1.214 -	int fieldlength;			// for padding
   1.215 -	int significant_digits = 0;	// number of significant digits written
   1.216 -	const int MAX_SIGNIFICANT_DIGITS = 16;
   1.217 -
   1.218 -	// default precision
   1.219 -	if (prec < 0)
   1.220 -	{
   1.221 -		prec = 6;
   1.222 -	}
   1.223 -
   1.224 -	// get the sign
   1.225 -	if (fval < 0)
   1.226 -	{
   1.227 -		fval = -fval;
   1.228 -		sign = 1;
   1.229 -	}
   1.230 -
   1.231 -	// compute whole-part digits count
   1.232 -	digits = (int)log10(fval) + 1;
   1.233 -
   1.234 -	// Only print 0.something if 0 < fval < 1
   1.235 -	if (digits < 1)
   1.236 -	{
   1.237 -		digits = 1;
   1.238 -	}
   1.239 -
   1.240 -	// compute the field length
   1.241 -	fieldlength = digits + prec + ((prec > 0) ? 1 : 0) + sign;
   1.242 -
   1.243 -	// minus sign BEFORE left padding if padding with zeros
   1.244 -	if (sign && maxlen && (flags & ZEROPAD))
   1.245 -	{
   1.246 -		*buf++ = '-';
   1.247 -		maxlen--;
   1.248 -	}
   1.249 -
   1.250 -	// right justify if required
   1.251 -	if ((flags & LADJUST) == 0)
   1.252 -	{
   1.253 -		while ((fieldlength < width) && maxlen)
   1.254 -		{
   1.255 -			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
   1.256 -			width--;
   1.257 -			maxlen--;
   1.258 -		}
   1.259 -	}
   1.260 -
   1.261 -	// minus sign AFTER left padding if padding with spaces
   1.262 -	if (sign && maxlen && !(flags & ZEROPAD))
   1.263 -	{
   1.264 -		*buf++ = '-';
   1.265 -		maxlen--;
   1.266 -	}
   1.267 -
   1.268 -	// write the whole part
   1.269 -	tmp = pow(10.0, digits-1);
   1.270 -	while ((digits--) && maxlen)
   1.271 -	{
   1.272 -		if (++significant_digits > MAX_SIGNIFICANT_DIGITS)
   1.273 -		{
   1.274 -			*buf++ = '0';
   1.275 -		}
   1.276 -		else
   1.277 -		{
   1.278 -			val = (int)(fval / tmp);
   1.279 -			*buf++ = '0' + val;
   1.280 -			fval -= val * tmp;
   1.281 -			tmp *= 0.1;
   1.282 -		}
   1.283 -		maxlen--;
   1.284 -	}
   1.285 -
   1.286 -	// write the fraction part
   1.287 -	if (maxlen)
   1.288 -	{
   1.289 -		*buf++ = '.';
   1.290 -		maxlen--;
   1.291 -	}
   1.292 -
   1.293 -	tmp = pow(10.0, prec);
   1.294 -
   1.295 -	fval *= tmp;
   1.296 -	while (prec-- && maxlen)
   1.297 -	{
   1.298 -		if (++significant_digits > MAX_SIGNIFICANT_DIGITS)
   1.299 -		{
   1.300 -			*buf++ = '0';
   1.301 -		}
   1.302 -		else
   1.303 -		{
   1.304 -			tmp *= 0.1;
   1.305 -			val = (int)(fval / tmp);
   1.306 -			*buf++ = '0' + val;
   1.307 -			fval -= val * tmp;
   1.308 -		}
   1.309 -		maxlen--;
   1.310 -	}
   1.311 -
   1.312 -	// left justify if required
   1.313 -	if (flags & LADJUST)
   1.314 -	{
   1.315 -		while ((fieldlength < width) && maxlen)
   1.316 -		{
   1.317 -			// right-padding only with spaces, ZEROPAD is ignored
   1.318 -			*buf++ = ' ';
   1.319 -			width--;
   1.320 -			maxlen--;
   1.321 -		}
   1.322 -	}
   1.323 -
   1.324 -	// update parent's buffer pointer
   1.325 -	*buf_p = buf;
   1.326 -}
   1.327 -
   1.328 -void AddBinary(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
   1.329 -{
   1.330 -	char text[32];
   1.331 -	int digits;
   1.332 -	char *buf;
   1.333 -
   1.334 -	digits = 0;
   1.335 -	do
   1.336 -	{
   1.337 -		if (val & 1)
   1.338 -		{
   1.339 -			text[digits++] = '1';
   1.340 -		}
   1.341 -		else
   1.342 -		{
   1.343 -			text[digits++] = '0';
   1.344 -		}
   1.345 -		val >>= 1;
   1.346 -	} while (val);
   1.347 -
   1.348 -	buf = *buf_p;
   1.349 -
   1.350 -	if (!(flags & LADJUST))
   1.351 -	{
   1.352 -		while (digits < width && maxlen)
   1.353 -		{
   1.354 -			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
   1.355 -			width--;
   1.356 -			maxlen--;
   1.357 -		}
   1.358 -	}
   1.359 -
   1.360 -	while (digits-- && maxlen)
   1.361 -	{
   1.362 -		*buf++ = text[digits];
   1.363 -		width--;
   1.364 -		maxlen--;
   1.365 -	}
   1.366 -
   1.367 -	if (flags & LADJUST)
   1.368 -	{
   1.369 -		while (width-- && maxlen)
   1.370 -		{
   1.371 -			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
   1.372 -			maxlen--;
   1.373 -		}
   1.374 -	}
   1.375 -
   1.376 -	*buf_p = buf;
   1.377 -}
   1.378 -
   1.379 -void AddUInt(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
   1.380 -{
   1.381 -	char text[32];
   1.382 -	int digits;
   1.383 -	char *buf;
   1.384 -
   1.385 -	digits = 0;
   1.386 -	do
   1.387 -	{
   1.388 -		text[digits++] = '0' + val % 10;
   1.389 -		val /= 10;
   1.390 -	} while (val);
   1.391 -
   1.392 -	buf = *buf_p;
   1.393 -
   1.394 -	if (!(flags & LADJUST))
   1.395 -	{
   1.396 -		while (digits < width && maxlen)
   1.397 -		{
   1.398 -			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
   1.399 -			width--;
   1.400 -			maxlen--;
   1.401 -		}
   1.402 -	}
   1.403 -
   1.404 -	while (digits-- && maxlen)
   1.405 -	{
   1.406 -		*buf++ = text[digits];
   1.407 -		width--;
   1.408 -		maxlen--;
   1.409 -	}
   1.410 -
   1.411 -	if (flags & LADJUST)
   1.412 -	{
   1.413 -		while (width-- && maxlen)
   1.414 -		{
   1.415 -			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
   1.416 -			maxlen--;
   1.417 -		}
   1.418 -	}
   1.419 -
   1.420 -	*buf_p = buf;
   1.421 -}
   1.422 -
   1.423 -void AddInt(char **buf_p, size_t &maxlen, int val, int width, int flags)
   1.424 -{
   1.425 -	char text[32];
   1.426 -	int digits;
   1.427 -	int signedVal;
   1.428 -	char *buf;
   1.429 -	unsigned int unsignedVal;
   1.430 -
   1.431 -	digits = 0;
   1.432 -	signedVal = val;
   1.433 -	if (val < 0)
   1.434 -	{
   1.435 -		/* we want the unsigned version */
   1.436 -		unsignedVal = abs(val);
   1.437 -	}
   1.438 -	else
   1.439 -	{
   1.440 -		unsignedVal = val;
   1.441 -	}
   1.442 -
   1.443 -	do
   1.444 -	{
   1.445 -		text[digits++] = '0' + unsignedVal % 10;
   1.446 -		unsignedVal /= 10;
   1.447 -	} while (unsignedVal);
   1.448 -
   1.449 -	if (signedVal < 0)
   1.450 -	{
   1.451 -		text[digits++] = '-';
   1.452 -	}
   1.453 -
   1.454 -	buf = *buf_p;
   1.455 -
   1.456 -	if (!(flags & LADJUST))
   1.457 -	{
   1.458 -		while ((digits < width) && maxlen)
   1.459 -		{
   1.460 -			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
   1.461 -			width--;
   1.462 -			maxlen--;
   1.463 -		}
   1.464 -	}
   1.465 -
   1.466 -	while (digits-- && maxlen)
   1.467 -	{
   1.468 -		*buf++ = text[digits];
   1.469 -		width--;
   1.470 -		maxlen--;
   1.471 -	}
   1.472 -
   1.473 -	if (flags & LADJUST)
   1.474 -	{
   1.475 -		while (width-- && maxlen)
   1.476 -		{
   1.477 -			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
   1.478 -			maxlen--;
   1.479 -		}
   1.480 -	}
   1.481 -
   1.482 -	*buf_p = buf;
   1.483 -}
   1.484 -
   1.485 -void AddHex(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
   1.486 -{
   1.487 -	char text[32];
   1.488 -	int digits;
   1.489 -	char *buf;
   1.490 -	char digit;
   1.491 -	int hexadjust;
   1.492 -
   1.493 -	if (flags & UPPERDIGITS)
   1.494 -	{
   1.495 -		hexadjust = 'A' - '9' - 1;
   1.496 -	}
   1.497 -	else
   1.498 -	{
   1.499 -		hexadjust = 'a' - '9' - 1;
   1.500 -	}
   1.501 -
   1.502 -	digits = 0;
   1.503 -	do 
   1.504 -	{
   1.505 -		digit = ('0' + val % 16);
   1.506 -		if (digit > '9')
   1.507 -		{
   1.508 -			digit += hexadjust;
   1.509 -		}
   1.510 -
   1.511 -		text[digits++] = digit;
   1.512 -		val /= 16;
   1.513 -	} while(val);
   1.514 -
   1.515 -	buf = *buf_p;
   1.516 -
   1.517 -	if (!(flags & LADJUST))
   1.518 -	{
   1.519 -		while (digits < width && maxlen)
   1.520 -		{
   1.521 -			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
   1.522 -			width--;
   1.523 -			maxlen--;
   1.524 -		}
   1.525 -	}
   1.526 -
   1.527 -	while (digits-- && maxlen)
   1.528 -	{
   1.529 -		*buf++ = text[digits];
   1.530 -		width--;
   1.531 -		maxlen--;
   1.532 -	}
   1.533 -
   1.534 -	if (flags & LADJUST)
   1.535 -	{
   1.536 -		while (width-- && maxlen)
   1.537 -		{
   1.538 -			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
   1.539 -			maxlen--;
   1.540 -		}
   1.541 -	}
   1.542 -
   1.543 -	*buf_p = buf;
   1.544 -}
   1.545 -
   1.546 -bool gnprintf(char *buffer,
   1.547 -			  size_t maxlen,
   1.548 -			  const char *format,
   1.549 -			  IPhraseCollection *pPhrases,
   1.550 -			  void **params,
   1.551 -			  unsigned int numparams,
   1.552 -			  unsigned int &curparam,
   1.553 -			  size_t *pOutLength,
   1.554 -			  const char **pFailPhrase)
   1.555 -{
   1.556 -	if (!buffer || !maxlen)
   1.557 -	{
   1.558 -		if (pOutLength != NULL)
   1.559 -		{
   1.560 -			*pOutLength = 0;
   1.561 -		}
   1.562 -		return true;
   1.563 -	}
   1.564 -
   1.565 -	if (numparams > MAX_TRANSLATE_PARAMS)
   1.566 -	{
   1.567 -		if (pFailPhrase != NULL)
   1.568 -		{
   1.569 -			*pFailPhrase = NULL;
   1.570 -		}
   1.571 -		return false;
   1.572 -	}
   1.573 -
   1.574 -	int arg = 0;
   1.575 -	char *buf_p;
   1.576 -	char ch;
   1.577 -	int flags;
   1.578 -	int width;
   1.579 -	int prec;
   1.580 -	int n;
   1.581 -	char sign;
   1.582 -	const char *fmt;
   1.583 -	size_t llen = maxlen - 1;
   1.584 -
   1.585 -	buf_p = buffer;
   1.586 -	fmt = format;
   1.587 -
   1.588 -	while (true)
   1.589 -	{
   1.590 -		// run through the format string until we hit a '%' or '\0'
   1.591 -		for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
   1.592 -		{
   1.593 -			*buf_p++ = ch;
   1.594 -			llen--;
   1.595 -		}
   1.596 -		if ((ch == '\0') || (llen <= 0))
   1.597 -		{
   1.598 -			goto done;
   1.599 -		}
   1.600 -
   1.601 -		// skip over the '%'
   1.602 -		fmt++;
   1.603 -
   1.604 -		// reset formatting state
   1.605 -		flags = 0;
   1.606 -		width = 0;
   1.607 -		prec = -1;
   1.608 -		sign = '\0';
   1.609 -
   1.610 -rflag:
   1.611 -		ch = *fmt++;
   1.612 -reswitch:
   1.613 -		switch(ch)
   1.614 -		{
   1.615 -		case '-':
   1.616 -			{
   1.617 -				flags |= LADJUST;
   1.618 -				goto rflag;
   1.619 -			}
   1.620 -		case '.':
   1.621 -			{
   1.622 -				n = 0;
   1.623 -				while(is_digit((ch = *fmt++)))
   1.624 -				{
   1.625 -					n = 10 * n + (ch - '0');
   1.626 -				}
   1.627 -				prec = (n < 0) ? -1 : n;
   1.628 -				goto reswitch;
   1.629 -			}
   1.630 -		case '0':
   1.631 -			{
   1.632 -				flags |= ZEROPAD;
   1.633 -				goto rflag;
   1.634 -			}
   1.635 -		case '1':
   1.636 -		case '2':
   1.637 -		case '3':
   1.638 -		case '4':
   1.639 -		case '5':
   1.640 -		case '6':
   1.641 -		case '7':
   1.642 -		case '8':
   1.643 -		case '9':
   1.644 -			{
   1.645 -				n = 0;
   1.646 -				do
   1.647 -				{
   1.648 -					n = 10 * n + (ch - '0');
   1.649 -					ch = *fmt++;
   1.650 -				} while(is_digit(ch));
   1.651 -				width = n;
   1.652 -				goto reswitch;
   1.653 -			}
   1.654 -		case 'c':
   1.655 -			{
   1.656 -				if (!llen)
   1.657 -				{
   1.658 -					goto done;
   1.659 -				}
   1.660 -				if (curparam >= numparams)
   1.661 -				{
   1.662 -					if (pFailPhrase != NULL)
   1.663 -					{
   1.664 -						*pFailPhrase = NULL;
   1.665 -					}
   1.666 -					return false;
   1.667 -				}
   1.668 -				char *c = (char *)params[curparam];
   1.669 -				curparam++;
   1.670 -				*buf_p++ = *c;
   1.671 -				llen--;
   1.672 -				arg++;
   1.673 -				break;
   1.674 -			}
   1.675 -		case 'b':
   1.676 -			{
   1.677 -				if (curparam >= numparams)
   1.678 -				{
   1.679 -					if (pFailPhrase != NULL)
   1.680 -					{
   1.681 -						*pFailPhrase = NULL;
   1.682 -					}
   1.683 -					return false;
   1.684 -				}
   1.685 -				int *value = (int *)params[curparam];
   1.686 -				curparam++;
   1.687 -				AddBinary(&buf_p, llen, *value, width, flags);
   1.688 -				arg++;
   1.689 -				break;
   1.690 -			}
   1.691 -		case 'd':
   1.692 -		case 'i':
   1.693 -			{
   1.694 -				if (curparam >= numparams)
   1.695 -				{
   1.696 -					if (pFailPhrase != NULL)
   1.697 -					{
   1.698 -						*pFailPhrase = NULL;
   1.699 -					}
   1.700 -					return false;
   1.701 -				}
   1.702 -				int *value = (int *)params[curparam];
   1.703 -				curparam++;
   1.704 -				AddInt(&buf_p, llen, *value, width, flags);
   1.705 -				arg++;
   1.706 -				break;
   1.707 -			}
   1.708 -		case 'u':
   1.709 -			{
   1.710 -				if (curparam >= numparams)
   1.711 -				{
   1.712 -					if (pFailPhrase != NULL)
   1.713 -					{
   1.714 -						*pFailPhrase = NULL;
   1.715 -					}
   1.716 -					return false;
   1.717 -				}
   1.718 -				unsigned int *value = (unsigned int *)params[curparam];
   1.719 -				curparam++;
   1.720 -				AddUInt(&buf_p, llen, *value, width, flags);
   1.721 -				arg++;
   1.722 -				break;
   1.723 -			}
   1.724 -		case 'f':
   1.725 -			{
   1.726 -				if (curparam >= numparams)
   1.727 -				{
   1.728 -					if (pFailPhrase != NULL)
   1.729 -					{
   1.730 -						*pFailPhrase = NULL;
   1.731 -					}
   1.732 -					return false;
   1.733 -				}
   1.734 -				float *value = (float *)params[curparam];
   1.735 -				curparam++;
   1.736 -				AddFloat(&buf_p, llen, *value, width, prec, flags);
   1.737 -				arg++;
   1.738 -				break;
   1.739 -			}
   1.740 -		case 's':
   1.741 -			{
   1.742 -				if (curparam >= numparams)
   1.743 -				{
   1.744 -					if (pFailPhrase != NULL)
   1.745 -					{
   1.746 -						*pFailPhrase = NULL;
   1.747 -					}
   1.748 -					return false;
   1.749 -				}
   1.750 -				const char *str = (const char *)params[curparam];
   1.751 -				curparam++;
   1.752 -				AddString(&buf_p, llen, str, width, prec);
   1.753 -				arg++;
   1.754 -				break;
   1.755 -			}
   1.756 -		case 'T':
   1.757 -		case 't':
   1.758 -			{
   1.759 -				int target;
   1.760 -				const char *key;
   1.761 -				size_t out_length;
   1.762 -				Translation trans;
   1.763 -				unsigned int lang_id;
   1.764 -
   1.765 -				if (curparam >= numparams)
   1.766 -				{
   1.767 -					if (pFailPhrase != NULL)
   1.768 -					{
   1.769 -						*pFailPhrase = NULL;
   1.770 -					}
   1.771 -					return false;
   1.772 -				}
   1.773 -				key = (const char *)(params[curparam]);
   1.774 -				curparam++;
   1.775 -
   1.776 -				if (ch == 'T')
   1.777 -				{
   1.778 -					if (curparam >= numparams)
   1.779 -					{
   1.780 -						if (pFailPhrase != NULL)
   1.781 -						{
   1.782 -							*pFailPhrase = NULL;
   1.783 -						}
   1.784 -						return false;
   1.785 -					}
   1.786 -					target = *((int *)(params[curparam]));
   1.787 -					curparam++;
   1.788 -				}
   1.789 -				else
   1.790 -				{
   1.791 -					target = g_Translator.GetGlobalTarget();
   1.792 -				}
   1.793 -
   1.794 -try_again:
   1.795 -				if (target == SOURCEMOD_SERVER_LANGUAGE)
   1.796 -				{
   1.797 -					lang_id = g_Translator.GetServerLanguage();
   1.798 -				}
   1.799 -				else if (target >= 1 && target <= g_Players.GetMaxClients())
   1.800 -				{
   1.801 -					lang_id = g_Translator.GetClientLanguage(target);
   1.802 -				}
   1.803 -				else
   1.804 -				{
   1.805 -					lang_id = g_Translator.GetServerLanguage();
   1.806 -				}
   1.807 -
   1.808 -				if (pPhrases == NULL)
   1.809 -				{
   1.810 -					if (pFailPhrase != NULL)
   1.811 -					{
   1.812 -						*pFailPhrase = key;
   1.813 -					}
   1.814 -					return false;
   1.815 -				}
   1.816 -
   1.817 -				if (pPhrases->FindTranslation(key, lang_id, &trans) != Trans_Okay)
   1.818 -				{
   1.819 -					if (target != SOURCEMOD_SERVER_LANGUAGE && lang_id != g_Translator.GetServerLanguage())
   1.820 -					{
   1.821 -						target = SOURCEMOD_SERVER_LANGUAGE;
   1.822 -						goto try_again;
   1.823 -					}
   1.824 -					else if (lang_id != SOURCEMOD_LANGUAGE_ENGLISH)
   1.825 -					{
   1.826 -						if (pPhrases->FindTranslation(key, SOURCEMOD_LANGUAGE_ENGLISH, &trans) != Trans_Okay)
   1.827 -						{
   1.828 -							if (pFailPhrase != NULL)
   1.829 -							{
   1.830 -								*pFailPhrase = key;
   1.831 -							}
   1.832 -							return false;
   1.833 -						}
   1.834 -					}
   1.835 -					else
   1.836 -					{
   1.837 -						if (pFailPhrase != NULL)
   1.838 -						{
   1.839 -							*pFailPhrase = key;
   1.840 -						}
   1.841 -						return false;
   1.842 -					}
   1.843 -				}
   1.844 -
   1.845 -				if (trans.fmt_count)
   1.846 -				{
   1.847 -					unsigned int i;
   1.848 -					void *new_params[MAX_TRANSLATE_PARAMS];
   1.849 -
   1.850 -					if (curparam + trans.fmt_count > numparams)
   1.851 -					{
   1.852 -						if (pFailPhrase != NULL)
   1.853 -						{
   1.854 -							*pFailPhrase = NULL;
   1.855 -						}
   1.856 -						return false;
   1.857 -					}
   1.858 -
   1.859 -					/* Copy the array and re-order the stack */
   1.860 -					memcpy(new_params, params, sizeof(void *) * numparams);
   1.861 -					for (i = 0; i < trans.fmt_count; i++)
   1.862 -					{
   1.863 -						new_params[i] = const_cast<void *>(params[curparam + trans.fmt_order[i]]);
   1.864 -					}
   1.865 -
   1.866 -					if (!gnprintf(buf_p,
   1.867 -							llen,
   1.868 -							trans.szPhrase,
   1.869 -							pPhrases,
   1.870 -							new_params,
   1.871 -							numparams,
   1.872 -							curparam,
   1.873 -							&out_length,
   1.874 -							pFailPhrase))
   1.875 -					{
   1.876 -						return false;
   1.877 -					}
   1.878 -				}
   1.879 -				else
   1.880 -				{
   1.881 -					if (!gnprintf(buf_p,
   1.882 -						llen,
   1.883 -						trans.szPhrase,
   1.884 -						pPhrases,
   1.885 -						params,
   1.886 -						numparams,
   1.887 -						curparam,
   1.888 -						&out_length,
   1.889 -						pFailPhrase))
   1.890 -					{
   1.891 -						return false;
   1.892 -					}
   1.893 -				}
   1.894 -
   1.895 -				buf_p += out_length;
   1.896 -				llen -= out_length;
   1.897 -
   1.898 -				break;
   1.899 -			}
   1.900 -		case 'X':
   1.901 -			{
   1.902 -				if (curparam >= numparams)
   1.903 -				{
   1.904 -					if (pFailPhrase != NULL)
   1.905 -					{
   1.906 -						*pFailPhrase = NULL;
   1.907 -					}
   1.908 -					return false;
   1.909 -				}
   1.910 -				unsigned int *value = (unsigned int *)params[curparam];
   1.911 -				curparam++;
   1.912 -				flags |= UPPERDIGITS;
   1.913 -				AddHex(&buf_p, llen, *value, width, flags);
   1.914 -				arg++;
   1.915 -				break;
   1.916 -			}
   1.917 -		case 'x':
   1.918 -			{
   1.919 -				if (curparam >= numparams)
   1.920 -				{
   1.921 -					if (pFailPhrase != NULL)
   1.922 -					{
   1.923 -						*pFailPhrase = NULL;
   1.924 -					}
   1.925 -					return false;
   1.926 -				}
   1.927 -				unsigned int *value = (unsigned int *)params[curparam];
   1.928 -				curparam++;
   1.929 -				AddHex(&buf_p, llen, *value, width, flags);
   1.930 -				arg++;
   1.931 -				break;
   1.932 -			}
   1.933 -		case '%':
   1.934 -			{
   1.935 -				if (!llen)
   1.936 -				{
   1.937 -					goto done;
   1.938 -				}
   1.939 -				*buf_p++ = ch;
   1.940 -				llen--;
   1.941 -				break;
   1.942 -			}
   1.943 -		case '\0':
   1.944 -			{
   1.945 -				if (!llen)
   1.946 -				{
   1.947 -					goto done;
   1.948 -				}
   1.949 -				*buf_p++ = '%';
   1.950 -				llen--;
   1.951 -				goto done;
   1.952 -			}
   1.953 -		default:
   1.954 -			{
   1.955 -				if (!llen)
   1.956 -				{
   1.957 -					goto done;
   1.958 -				}
   1.959 -				*buf_p++ = ch;
   1.960 -				llen--;
   1.961 -				break;
   1.962 -			}
   1.963 -		}
   1.964 -	}
   1.965 -
   1.966 -done:
   1.967 -	*buf_p = '\0';
   1.968 -
   1.969 -	if (pOutLength != NULL)
   1.970 -	{
   1.971 -		*pOutLength = (maxlen - llen - 1);
   1.972 -	}
   1.973 -
   1.974 -	return true;
   1.975 -}
   1.976 -
   1.977 -size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext *pCtx, const cell_t *params, int *param)
   1.978 -{
   1.979 -	if (!buffer || !maxlen)
   1.980 -	{
   1.981 -		return 0;
   1.982 -	}
   1.983 -
   1.984 -	int arg;
   1.985 -	int args = params[0];
   1.986 -	char *buf_p;
   1.987 -	char ch;
   1.988 -	int flags;
   1.989 -	int width;
   1.990 -	int prec;
   1.991 -	int n;
   1.992 -	char sign;
   1.993 -	const char *fmt;
   1.994 -	size_t llen = maxlen - 1;
   1.995 -
   1.996 -	buf_p = buffer;
   1.997 -	arg = *param;
   1.998 -	fmt = format;
   1.999 -
  1.1000 -	while (true)
  1.1001 -	{
  1.1002 -		// run through the format string until we hit a '%' or '\0'
  1.1003 -		for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
  1.1004 -		{
  1.1005 -			*buf_p++ = ch;
  1.1006 -			llen--;
  1.1007 -		}
  1.1008 -		if ((ch == '\0') || (llen <= 0))
  1.1009 -		{
  1.1010 -			goto done;
  1.1011 -		}
  1.1012 -
  1.1013 -		// skip over the '%'
  1.1014 -		fmt++;
  1.1015 -
  1.1016 -		// reset formatting state
  1.1017 -		flags = 0;
  1.1018 -		width = 0;
  1.1019 -		prec = -1;
  1.1020 -		sign = '\0';
  1.1021 -
  1.1022 -rflag:
  1.1023 -		ch = *fmt++;
  1.1024 -reswitch:
  1.1025 -		switch(ch)
  1.1026 -		{
  1.1027 -		case '-':
  1.1028 -			{
  1.1029 -				flags |= LADJUST;
  1.1030 -				goto rflag;
  1.1031 -			}
  1.1032 -		case '.':
  1.1033 -			{
  1.1034 -				n = 0;
  1.1035 -				while(is_digit((ch = *fmt++)))
  1.1036 -				{
  1.1037 -					n = 10 * n + (ch - '0');
  1.1038 -				}
  1.1039 -				prec = (n < 0) ? -1 : n;
  1.1040 -				goto reswitch;
  1.1041 -			}
  1.1042 -		case '0':
  1.1043 -			{
  1.1044 -				flags |= ZEROPAD;
  1.1045 -				goto rflag;
  1.1046 -			}
  1.1047 -		case '1':
  1.1048 -		case '2':
  1.1049 -		case '3':
  1.1050 -		case '4':
  1.1051 -		case '5':
  1.1052 -		case '6':
  1.1053 -		case '7':
  1.1054 -		case '8':
  1.1055 -		case '9':
  1.1056 -			{
  1.1057 -				n = 0;
  1.1058 -				do
  1.1059 -				{
  1.1060 -					n = 10 * n + (ch - '0');
  1.1061 -					ch = *fmt++;
  1.1062 -				} while(is_digit(ch));
  1.1063 -				width = n;
  1.1064 -				goto reswitch;
  1.1065 -			}
  1.1066 -		case 'c':
  1.1067 -			{
  1.1068 -				CHECK_ARGS(0);
  1.1069 -				if (!llen)
  1.1070 -				{
  1.1071 -					goto done;
  1.1072 -				}
  1.1073 -				char *c;
  1.1074 -				pCtx->LocalToString(params[arg], &c);
  1.1075 -				*buf_p++ = *c;
  1.1076 -				llen--;
  1.1077 -				arg++;
  1.1078 -				break;
  1.1079 -			}
  1.1080 -		case 'b':
  1.1081 -			{
  1.1082 -				CHECK_ARGS(0);
  1.1083 -				cell_t *value;
  1.1084 -				pCtx->LocalToPhysAddr(params[arg], &value);
  1.1085 -				AddBinary(&buf_p, llen, *value, width, flags);
  1.1086 -				arg++;
  1.1087 -				break;
  1.1088 -			}
  1.1089 -		case 'd':
  1.1090 -		case 'i':
  1.1091 -			{
  1.1092 -				CHECK_ARGS(0);
  1.1093 -				cell_t *value;
  1.1094 -				pCtx->LocalToPhysAddr(params[arg], &value);
  1.1095 -				AddInt(&buf_p, llen, static_cast<int>(*value), width, flags);
  1.1096 -				arg++;
  1.1097 -				break;
  1.1098 -			}
  1.1099 -		case 'u':
  1.1100 -			{
  1.1101 -				CHECK_ARGS(0);
  1.1102 -				cell_t *value;
  1.1103 -				pCtx->LocalToPhysAddr(params[arg], &value);
  1.1104 -				AddUInt(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
  1.1105 -				arg++;
  1.1106 -				break;
  1.1107 -			}
  1.1108 -		case 'f':
  1.1109 -			{
  1.1110 -				CHECK_ARGS(0);
  1.1111 -				cell_t *value;
  1.1112 -				pCtx->LocalToPhysAddr(params[arg], &value);
  1.1113 -				AddFloat(&buf_p, llen, sp_ctof(*value), width, prec, flags);
  1.1114 -				arg++;
  1.1115 -				break;
  1.1116 -			}
  1.1117 -		case 'L':
  1.1118 -			{
  1.1119 -				CHECK_ARGS(0);
  1.1120 -				cell_t *value;
  1.1121 -				pCtx->LocalToPhysAddr(params[arg], &value);
  1.1122 -				char buffer[255];
  1.1123 -				if (*value)
  1.1124 -				{
  1.1125 -					CPlayer *player = g_Players.GetPlayerByIndex(*value);
  1.1126 -					if (!player || !player->IsConnected())
  1.1127 -					{
  1.1128 -						return pCtx->ThrowNativeError("Client index %d is invalid", *value);
  1.1129 -					}
  1.1130 -					const char *auth = player->GetAuthString();
  1.1131 -					if (!auth || auth[0] == '\0')
  1.1132 -					{
  1.1133 -						auth = "STEAM_ID_PENDING";
  1.1134 -					}
  1.1135 -					int userid = engine->GetPlayerUserId(player->GetEdict());
  1.1136 -					UTIL_Format(buffer, 
  1.1137 -						sizeof(buffer), 
  1.1138 -						"%s<%d><%s><>", 
  1.1139 -						player->GetName(),
  1.1140 -						userid,
  1.1141 -						auth);
  1.1142 -				}
  1.1143 -				else
  1.1144 -				{
  1.1145 -					UTIL_Format(buffer,
  1.1146 -						sizeof(buffer),
  1.1147 -						"Console<0><Console><Console>");
  1.1148 -				}
  1.1149 -				AddString(&buf_p, llen, buffer, width, prec);
  1.1150 -				arg++;
  1.1151 -				break;
  1.1152 -			}
  1.1153 -		case 'N':
  1.1154 -			{
  1.1155 -				CHECK_ARGS(0);
  1.1156 -				cell_t *value;
  1.1157 -				pCtx->LocalToPhysAddr(params[arg], &value);
  1.1158 -
  1.1159 -				const char *name = "Console";
  1.1160 -				if (*value)
  1.1161 -				{
  1.1162 -					CPlayer *player = g_Players.GetPlayerByIndex(*value);
  1.1163 -					if (!player || !player->IsConnected())
  1.1164 -					{
  1.1165 -						return pCtx->ThrowNativeError("Client index %d is invalid", *value);
  1.1166 -					}
  1.1167 -					name = player->GetName();
  1.1168 -				}
  1.1169 -				AddString(&buf_p, llen, name, width, prec);
  1.1170 -				arg++;
  1.1171 -				break;
  1.1172 -			}
  1.1173 -		case 's':
  1.1174 -			{
  1.1175 -				CHECK_ARGS(0);
  1.1176 -				char *str;
  1.1177 -				int err;
  1.1178 -				if ((err=pCtx->LocalToString(params[arg], &str)) != SP_ERROR_NONE)
  1.1179 -				{
  1.1180 -					pCtx->ThrowNativeErrorEx(err, "Could not deference string");
  1.1181 -					return 0;
  1.1182 -				}
  1.1183 -				AddString(&buf_p, llen, str, width, prec);
  1.1184 -				arg++;
  1.1185 -				break;
  1.1186 -			}
  1.1187 -		case 'T':
  1.1188 -			{
  1.1189 -				CHECK_ARGS(1);
  1.1190 -				char *key;
  1.1191 -				bool error;
  1.1192 -				size_t res;
  1.1193 -				cell_t *target;
  1.1194 -				pCtx->LocalToString(params[arg++], &key);
  1.1195 -				pCtx->LocalToPhysAddr(params[arg++], &target);
  1.1196 -				res = Translate(buf_p, llen, pCtx, key, *target, params, &arg, &error);
  1.1197 -				if (error)
  1.1198 -				{
  1.1199 -					return 0;
  1.1200 -				}
  1.1201 -				buf_p += res;
  1.1202 -				llen -= res;
  1.1203 -				break;
  1.1204 -			}
  1.1205 -		case 't':
  1.1206 -			{
  1.1207 -				CHECK_ARGS(0);
  1.1208 -				char *key;
  1.1209 -				bool error;
  1.1210 -				size_t res;
  1.1211 -				cell_t target = g_SourceMod.GetGlobalTarget();
  1.1212 -				pCtx->LocalToString(params[arg++], &key);
  1.1213 -				res = Translate(buf_p, llen, pCtx, key, target, params, &arg, &error);
  1.1214 -				if (error)
  1.1215 -				{
  1.1216 -					return 0;
  1.1217 -				}
  1.1218 -				buf_p += res;
  1.1219 -				llen -= res;
  1.1220 -				break;
  1.1221 -			}
  1.1222 -		case 'X':
  1.1223 -			{
  1.1224 -				CHECK_ARGS(0);
  1.1225 -				cell_t *value;
  1.1226 -				pCtx->LocalToPhysAddr(params[arg], &value);
  1.1227 -				flags |= UPPERDIGITS;
  1.1228 -				AddHex(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
  1.1229 -				arg++;
  1.1230 -				break;
  1.1231 -			}
  1.1232 -		case 'x':
  1.1233 -			{
  1.1234 -				CHECK_ARGS(0);
  1.1235 -				cell_t *value;
  1.1236 -				pCtx->LocalToPhysAddr(params[arg], &value);
  1.1237 -				AddHex(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
  1.1238 -				arg++;
  1.1239 -				break;
  1.1240 -			}
  1.1241 -		case '%':
  1.1242 -			{
  1.1243 -				if (!llen)
  1.1244 -				{
  1.1245 -					goto done;
  1.1246 -				}
  1.1247 -				*buf_p++ = ch;
  1.1248 -				llen--;
  1.1249 -				break;
  1.1250 -			}
  1.1251 -		case '\0':
  1.1252 -			{
  1.1253 -				if (!llen)
  1.1254 -				{
  1.1255 -					goto done;
  1.1256 -				}
  1.1257 -				*buf_p++ = '%';
  1.1258 -				llen--;
  1.1259 -				goto done;
  1.1260 -			}
  1.1261 -		default:
  1.1262 -			{
  1.1263 -				if (!llen)
  1.1264 -				{
  1.1265 -					goto done;
  1.1266 -				}
  1.1267 -				*buf_p++ = ch;
  1.1268 -				llen--;
  1.1269 -				break;
  1.1270 -			}
  1.1271 -		}
  1.1272 -	}
  1.1273 -
  1.1274 -done:
  1.1275 -	*buf_p = '\0';
  1.1276 -	*param = arg;
  1.1277 -	return (maxlen - llen - 1);
  1.1278 -}
  1.1279 -
  1.1280 -const char *stristr(const char *str, const char *substr)
  1.1281 -{
  1.1282 -	if (!*substr)
  1.1283 -	{
  1.1284 -		return ((char *)str);
  1.1285 -	}
  1.1286 -
  1.1287 -	char *needle = (char *)substr;
  1.1288 -	char *prevloc = (char *)str;
  1.1289 -	char *haystack = (char *)str;
  1.1290 -
  1.1291 -	while (*haystack)
  1.1292 -	{
  1.1293 -		if (tolower(*haystack) == tolower(*needle))
  1.1294 -		{
  1.1295 -			haystack++;
  1.1296 -			if (!*++needle)
  1.1297 -			{
  1.1298 -				return prevloc;
  1.1299 -			}
  1.1300 -		}
  1.1301 -		else
  1.1302 -		{
  1.1303 -			haystack = ++prevloc;
  1.1304 -			needle = (char *)substr;
  1.1305 -		}
  1.1306 -	}
  1.1307 -
  1.1308 -	return NULL;
  1.1309 -}
  1.1310 -
  1.1311 -unsigned int strncopy(char *dest, const char *src, size_t count)
  1.1312 -{
  1.1313 -	if (!count)
  1.1314 -	{
  1.1315 -		return 0;
  1.1316 -	}
  1.1317 -
  1.1318 -	char *start = dest;
  1.1319 -	while ((*src) && (--count))
  1.1320 -	{
  1.1321 -		*dest++ = *src++;
  1.1322 -	}
  1.1323 -	*dest = '\0';
  1.1324 -
  1.1325 -	return (dest - start);
  1.1326 -}
  1.1327 -
  1.1328 -size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
  1.1329 -{
  1.1330 -	va_list ap;
  1.1331 -	va_start(ap, fmt);
  1.1332 -	size_t len = vsnprintf(buffer, maxlength, fmt, ap);
  1.1333 -	va_end(ap);
  1.1334 -
  1.1335 -	if (len >= maxlength)
  1.1336 -	{
  1.1337 -		buffer[maxlength - 1] = '\0';
  1.1338 -		return (maxlength - 1);
  1.1339 -	}
  1.1340 -	else
  1.1341 -	{
  1.1342 -		return len;
  1.1343 -	}
  1.1344 -}
  1.1345 -
  1.1346 -size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list ap)
  1.1347 -{
  1.1348 -	size_t len = vsnprintf(buffer, maxlength, fmt, ap);
  1.1349 -
  1.1350 -	if (len >= maxlength)
  1.1351 -	{
  1.1352 -		buffer[maxlength - 1] = '\0';
  1.1353 -		return (maxlength - 1);
  1.1354 -	}
  1.1355 -	else
  1.1356 -	{
  1.1357 -		return len;
  1.1358 -	}
  1.1359 -}
  1.1360 -
  1.1361 -char *sm_strdup(const char *str)
  1.1362 -{
  1.1363 -	char *ptr = new char[strlen(str)+1];
  1.1364 -	strcpy(ptr, str);
  1.1365 -	return ptr;
  1.1366 -}
  1.1367 -
  1.1368 -unsigned int UTIL_ReplaceAll(char *subject, size_t maxlength, const char *search, const char *replace)
  1.1369 -{
  1.1370 -	size_t searchLen = strlen(search);
  1.1371 -	size_t replaceLen = strlen(replace);
  1.1372 -
  1.1373 -	char *ptr = subject;
  1.1374 -	unsigned int total = 0;
  1.1375 -	while ((ptr = UTIL_ReplaceEx(ptr, maxlength, search, searchLen, replace, replaceLen)) != NULL)
  1.1376 -	{
  1.1377 -		total++;
  1.1378 -		if (*ptr == '\0')
  1.1379 -		{
  1.1380 -			break;
  1.1381 -		}
  1.1382 -	}
  1.1383 -
  1.1384 -	return total;
  1.1385 -}
  1.1386 -
  1.1387 -/**
  1.1388 - * NOTE: Do not edit this for the love of god unless you have 
  1.1389 - * read the test cases and understand the code behind each one.
  1.1390 - * While I don't guarantee there aren't mistakes, I do guarantee
  1.1391 - * that plugins will end up relying on tiny idiosyncrasies of this
  1.1392 - * function, just like they did with AMX Mod X.
  1.1393 - *
  1.1394 - * There are explicitly more cases than the AMX Mod X version because
  1.1395 - * we're not doing a blind copy.  Each case is specifically optimized
  1.1396 - * for what needs to be done.  Even better, we don't have to error on
  1.1397 - * bad buffer sizes.  Instead, this function will smartly cut off the 
  1.1398 - * string in a way that pushes old data out.
  1.1399 - */
  1.1400 -char *UTIL_ReplaceEx(char *subject, size_t maxLen, const char *search, size_t searchLen, const char *replace, size_t replaceLen)
  1.1401 -{
  1.1402 -	char *ptr = subject;
  1.1403 -	size_t browsed = 0;
  1.1404 -	size_t textLen = strlen(subject);
  1.1405 -
  1.1406 -	/* It's not possible to search or replace */
  1.1407 -	if (searchLen > textLen)
  1.1408 -	{
  1.1409 -		return NULL;
  1.1410 -	}
  1.1411 -
  1.1412 -	/* Handle the case of one byte replacement.
  1.1413 -	 * It's only valid in one case.
  1.1414 -	 */
  1.1415 -	if (maxLen == 1)
  1.1416 -	{
  1.1417 -		/* If the search matches and the replace length is 0, 
  1.1418 -		 * we can just terminate the string and be done.
  1.1419 -		 */
  1.1420 -		if (strcmp(subject, search) == 0 && replaceLen == 0)
  1.1421 -		{
  1.1422 -			*subject = '\0';
  1.1423 -			return subject;
  1.1424 -		}
  1.1425 -		else
  1.1426 -		{
  1.1427 -			return NULL;
  1.1428 -		}
  1.1429 -	}
  1.1430 -
  1.1431 -	/* Subtract one off the maxlength so we can include the null terminator */
  1.1432 -	maxLen--;
  1.1433 -
  1.1434 -	while (*ptr != '\0' && (browsed <= textLen - searchLen))
  1.1435 -	{
  1.1436 -		/* See if we get a comparison */
  1.1437 -		if (strncmp(ptr, search, searchLen) == 0)
  1.1438 -		{
  1.1439 -			if (replaceLen > searchLen)
  1.1440 -			{
  1.1441 -				/* First, see if we have enough space to do this operation */
  1.1442 -				if (maxLen - textLen < replaceLen - searchLen)
  1.1443 -				{
  1.1444 -					/* First, see if the replacement length goes out of bounds. */
  1.1445 -					if (browsed + replaceLen >= maxLen)
  1.1446 -					{
  1.1447 -						/* EXAMPLE CASE:
  1.1448 -						 * Subject: AABBBCCC
  1.1449 -						 * Buffer : 12 bytes
  1.1450 -						 * Search : BBB
  1.1451 -						 * Replace: DDDDDDDDDD
  1.1452 -						 * OUTPUT : AADDDDDDDDD
  1.1453 -						 * POSITION:           ^
  1.1454 -						 */
  1.1455 -						/* If it does, we'll just bound the length and do a strcpy. */
  1.1456 -						replaceLen = maxLen - browsed;
  1.1457 -						/* Note, we add one to the final result for the null terminator */
  1.1458 -						strncopy(ptr, replace, replaceLen+1);
  1.1459 -					}
  1.1460 -					else
  1.1461 -					{
  1.1462 -						/* EXAMPLE CASE:
  1.1463 -						 * Subject: AABBBCCC
  1.1464 -						 * Buffer : 12 bytes
  1.1465 -						 * Search : BBB
  1.1466 -						 * Replace: DDDDDDD
  1.1467 -						 * OUTPUT : AADDDDDDDCC
  1.1468 -						 * POSITION:         ^
  1.1469 -						 */
  1.1470 -						/* We're going to have some bytes left over... */
  1.1471 -						size_t origBytesToCopy = (textLen - (browsed + searchLen)) + 1;
  1.1472 -						size_t realBytesToCopy = (maxLen - (browsed + replaceLen)) + 1;
  1.1473 -						char *moveFrom = ptr + searchLen + (origBytesToCopy - realBytesToCopy);
  1.1474 -						char *moveTo = ptr + replaceLen;
  1.1475 -
  1.1476 -						/* First, move our old data out of the way. */
  1.1477 -						memmove(moveTo, moveFrom, realBytesToCopy);
  1.1478 -
  1.1479 -						/* Now, do our replacement. */
  1.1480 -						memcpy(ptr, replace, replaceLen);
  1.1481 -					}
  1.1482 -				}
  1.1483 -				else
  1.1484 -				{
  1.1485 -					/* EXAMPLE CASE:
  1.1486 -					 * Subject: AABBBCCC
  1.1487 -					 * Buffer : 12 bytes
  1.1488 -					 * Search : BBB
  1.1489 -					 * Replace: DDDD
  1.1490 -					 * OUTPUT : AADDDDCCC
  1.1491 -					 * POSITION:      ^
  1.1492 -					 */
  1.1493 -					/* Yes, we have enough space.  Do a normal move operation. */
  1.1494 -					char *moveFrom = ptr + searchLen;
  1.1495 -					char *moveTo = ptr + replaceLen;
  1.1496 -
  1.1497 -					/* First move our old data out of the way. */
  1.1498 -					size_t bytesToCopy = (textLen - (browsed + searchLen)) + 1;
  1.1499 -					memmove(moveTo, moveFrom, bytesToCopy);
  1.1500 -
  1.1501 -					/* Now do our replacement. */
  1.1502 -					memcpy(ptr, replace, replaceLen);
  1.1503 -				}
  1.1504 -			}
  1.1505 -			else if (replaceLen < searchLen)
  1.1506 -			{
  1.1507 -				/* EXAMPLE CASE:
  1.1508 -				 * Subject: AABBBCCC
  1.1509 -				 * Buffer : 12 bytes
  1.1510 -				 * Search : BBB
  1.1511 -				 * Replace: D
  1.1512 -				 * OUTPUT : AADCCC
  1.1513 -				 * POSOTION:   ^
  1.1514 -				 */
  1.1515 -				/* If the replacement does not grow the string length, we do not
  1.1516 -				 * need to do any fancy checking at all.  Yay!
  1.1517 -				 */
  1.1518 -				char *moveFrom = ptr + searchLen;		/* Start after the search pointer */
  1.1519 -				char *moveTo = ptr + replaceLen;		/* Copy to where the replacement ends */
  1.1520 -
  1.1521 -				/* Copy our replacement in, if any */
  1.1522 -				if (replaceLen)
  1.1523 -				{
  1.1524 -					memcpy(ptr, replace, replaceLen);
  1.1525 -				}
  1.1526 -
  1.1527 -				/* Figure out how many bytes to move down, including null terminator */
  1.1528 -				size_t bytesToCopy = (textLen - (browsed + searchLen)) + 1;
  1.1529 -
  1.1530 -				/* Move the rest of the string down */
  1.1531 -				memmove(moveTo, moveFrom, bytesToCopy);
  1.1532 -			}
  1.1533 -			else
  1.1534 -			{
  1.1535 -				/* EXAMPLE CASE:
  1.1536 -				 * Subject: AABBBCCC
  1.1537 -				 * Buffer : 12 bytes
  1.1538 -				 * Search : BBB
  1.1539 -				 * Replace: DDD
  1.1540 -				 * OUTPUT : AADDDCCC
  1.1541 -				 * POSITION:     ^
  1.1542 -				 */
  1.1543 -				/* We don't have to move anything around, just do a straight copy */
  1.1544 -				memcpy(ptr, replace, replaceLen);
  1.1545 -			}
  1.1546 -
  1.1547 -			return ptr + replaceLen;
  1.1548 -		}
  1.1549 -		ptr++;
  1.1550 -		browsed++;
  1.1551 -	}
  1.1552 -
  1.1553 -	return NULL;
  1.1554 -}
  1.1555 -
  1.1556 -char *UTIL_TrimWhitespace(char *str, size_t &len)
  1.1557 -{
  1.1558 -	char *end = str + len - 1;
  1.1559 -
  1.1560 -	if (!len)
  1.1561 -	{
  1.1562 -		return str;
  1.1563 -	}
  1.1564 -
  1.1565 -	/* Iterate backwards through string until we reach first non-whitespace char */
  1.1566 -	while (end >= str && textparsers->IsWhitespace(end))
  1.1567 -	{
  1.1568 -		end--;
  1.1569 -		len--;
  1.1570 -	}
  1.1571 -
  1.1572 -	/* Replace first whitespace char (at the end) with null terminator.
  1.1573 -	 * If there is none, we're just replacing the null terminator. 
  1.1574 -	 */
  1.1575 -	*(end + 1) = '\0';
  1.1576 -
  1.1577 -	while (*str != '\0' && textparsers->IsWhitespace(str))
  1.1578 -	{
  1.1579 -		str++;
  1.1580 -		len--;
  1.1581 -	}
  1.1582 -
  1.1583 -	return str;
  1.1584 -}
  1.1585 -