core/sm_stringutil.cpp
author Peace-Maker <januk@freenet.de>
Wed Apr 23 08:55:09 2014 -0400 (2014-04-23)
changeset 4330 98726cea1607
parent 4329 5ac935cb029a
permissions -rw-r--r--
Mark CS:S as supporting HudMsg (bug 6108, r=psychonic).
dvander@370
     1
/**
ds@653
     2
 * vim: set ts=4 :
ds@1330
     3
 * =============================================================================
dvander@1231
     4
 * SourceMod
ds@1947
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
ds@1330
     6
 * =============================================================================
dvander@370
     7
 *
ds@1330
     8
 * This program is free software; you can redistribute it and/or modify it under
ds@1330
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
ds@1330
    10
 * Free Software Foundation.
dvander@1231
    11
 * 
ds@1330
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1330
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1330
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
ds@1330
    15
 * details.
dvander@1231
    16
 *
ds@1330
    17
 * You should have received a copy of the GNU General Public License along with
ds@1330
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@1231
    19
 *
ds@1330
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
ds@1330
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1330
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1330
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
ds@1330
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
ds@1330
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
ds@1330
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1330
    27
 * or <http://www.sourcemod.net/license.php>.
dvander@370
    28
 *
dvander@370
    29
 * Version: $Id$
dvander@370
    30
 */
dvander@370
    31
faluco@230
    32
#include <stdlib.h>
faluco@230
    33
#include <ctype.h>
faluco@274
    34
#include <stdarg.h>
dvander@3872
    35
#include <ITextParsers.h>
faluco@227
    36
#include "sm_stringutil.h"
dvander@592
    37
#include "Logger.h"
dvander@591
    38
#include "PlayerManager.h"
dvander@3004
    39
#include "logic_bridge.h"
dvander@3872
    40
#include "sourcemod.h"
dvander@4329
    41
#include <am-utility.h>
faluco@227
    42
faluco@227
    43
#define LADJUST			0x00000004		/* left adjustment */
faluco@227
    44
#define ZEROPAD			0x00000080		/* zero (as opposed to blank) pad */
ds@609
    45
#define UPPERDIGITS		0x00000200		/* make alpha digits uppercase */
faluco@227
    46
#define to_digit(c)		((c) - '0')
faluco@227
    47
#define is_digit(c)		((unsigned)to_digit(c) <= 9)
faluco@227
    48
faluco@288
    49
#define CHECK_ARGS(x) \
faluco@288
    50
	if ((arg+x) > args) { \
dvander@599
    51
		pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "String formatted incorrectly - parameter %d (total %d)", arg, args); \
faluco@288
    52
		return 0; \
faluco@227
    53
	}
faluco@227
    54
dvander@1620
    55
inline void ReorderTranslationParams(const Translation *pTrans, cell_t *params)
dvander@1620
    56
{
dvander@1620
    57
	cell_t new_params[MAX_TRANSLATE_PARAMS];
dvander@1620
    58
	for (unsigned int i = 0; i < pTrans->fmt_count; i++)
dvander@1620
    59
	{
dvander@1620
    60
		new_params[i] = params[pTrans->fmt_order[i]];
dvander@1620
    61
	}
dvander@1620
    62
	memcpy(params, new_params, pTrans->fmt_count * sizeof(cell_t));
dvander@1620
    63
}
dvander@1620
    64
dvander@1620
    65
size_t Translate(char *buffer,
dvander@1620
    66
				 size_t maxlen,
dvander@1620
    67
				 IPluginContext *pCtx,
dvander@1620
    68
				 const char *key,
dvander@1620
    69
				 cell_t target,
dvander@1620
    70
				 const cell_t *params,
dvander@1620
    71
				 int *arg,
dvander@1620
    72
				 bool *error)
faluco@422
    73
{
faluco@422
    74
	unsigned int langid;
faluco@422
    75
	*error = false;
dvander@464
    76
	Translation pTrans;
dvander@3872
    77
	IPlugin *pl = scripts->FindPluginByContext(pCtx->GetContext());
dvander@464
    78
	unsigned int max_params = 0;
dvander@2042
    79
	IPhraseCollection *pPhrases;
dvander@2042
    80
dvander@2042
    81
	pPhrases = pl->GetPhrases();
faluco@422
    82
faluco@422
    83
try_serverlang:
dvander@2042
    84
	if (target == SOURCEMOD_SERVER_LANGUAGE)
faluco@389
    85
	{
dvander@3004
    86
		langid = translator->GetServerLanguage();
dvander@1620
    87
 	}
dvander@1620
    88
	else if ((target >= 1) && (target <= g_Players.GetMaxClients()))
dvander@1620
    89
	{
dvander@3004
    90
		langid = translator->GetClientLanguage(target);
dvander@1620
    91
	}
dvander@1620
    92
	else
dvander@1620
    93
	{
faluco@422
    94
		pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Translation failed: invalid client index %d", target);
faluco@422
    95
		goto error_out;
faluco@422
    96
	}
faluco@422
    97
dvander@2042
    98
	if (pPhrases->FindTranslation(key, langid, &pTrans) != Trans_Okay)
faluco@422
    99
	{
dvander@3004
   100
		if (target != SOURCEMOD_SERVER_LANGUAGE && langid != translator->GetServerLanguage())
faluco@422
   101
		{
dvander@2042
   102
			target = SOURCEMOD_SERVER_LANGUAGE;
faluco@422
   103
			goto try_serverlang;
dvander@1620
   104
		}
dvander@2042
   105
		else if (langid != SOURCEMOD_LANGUAGE_ENGLISH)
dvander@1620
   106
		{
dvander@2339
   107
			if (pPhrases->FindTranslation(key, SOURCEMOD_LANGUAGE_ENGLISH, &pTrans) != Trans_Okay)
faluco@422
   108
			{
faluco@422
   109
				pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Language phrase \"%s\" not found", key);
faluco@422
   110
				goto error_out;
faluco@422
   111
			}
dvander@1620
   112
		}
dvander@1620
   113
		else
dvander@1620
   114
		{
dvander@919
   115
			pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Language phrase \"%s\" not found", key);
dvander@909
   116
			goto error_out;
faluco@422
   117
		}
faluco@389
   118
	}
faluco@389
   119
dvander@474
   120
	max_params = pTrans.fmt_count;
faluco@1352
   121
dvander@909
   122
	if (max_params)
faluco@389
   123
	{
dvander@1621
   124
		cell_t new_params[MAX_TRANSLATE_PARAMS];
dvander@1621
   125
dvander@909
   126
		/* Check if we're going to over the limit */
dvander@909
   127
		if ((*arg) + (max_params - 1) > (size_t)params[0])
faluco@389
   128
		{
dvander@909
   129
			pCtx->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX, 
dvander@909
   130
				"Translation string formatted incorrectly - missing at least %d parameters", 
dvander@909
   131
				((*arg + (max_params - 1)) - params[0])
dvander@909
   132
				);
faluco@422
   133
			goto error_out;
faluco@389
   134
		}
dvander@909
   135
dvander@1621
   136
		/* If we need to re-order the parameters, do so with a temporary array.
dvander@1621
   137
		 * Otherwise, we could run into trouble with continual formats, a la ShowActivity().
dvander@1621
   138
		 */
dvander@1621
   139
		memcpy(new_params, params, sizeof(cell_t) * (params[0] + 1));
dvander@1621
   140
		ReorderTranslationParams(&pTrans, &new_params[*arg]);
dvander@1621
   141
dvander@1621
   142
		return atcprintf(buffer, maxlen, pTrans.szPhrase, pCtx, new_params, arg);
faluco@389
   143
	}
dvander@1621
   144
	else
dvander@1621
   145
	{
dvander@1621
   146
		return atcprintf(buffer, maxlen, pTrans.szPhrase, pCtx, params, arg);
dvander@1621
   147
	}
dvander@1620
   148
	
faluco@422
   149
error_out:
faluco@422
   150
	*error = true;
faluco@422
   151
	return 0;
faluco@389
   152
}
faluco@389
   153
faluco@227
   154
void AddString(char **buf_p, size_t &maxlen, const char *string, int width, int prec)
faluco@227
   155
{
faluco@227
   156
	int size = 0;
faluco@227
   157
	char *buf;
faluco@227
   158
	static char nlstr[] = {'(','n','u','l','l',')','\0'};
faluco@227
   159
faluco@227
   160
	buf = *buf_p;
faluco@227
   161
faluco@227
   162
	if (string == NULL)
faluco@227
   163
	{
faluco@227
   164
		string = nlstr;
faluco@227
   165
		prec = -1;
faluco@227
   166
	}
faluco@227
   167
faluco@227
   168
	if (prec >= 0)
faluco@227
   169
	{
faluco@227
   170
		for (size = 0; size < prec; size++) 
faluco@227
   171
		{
faluco@227
   172
			if (string[size] == '\0')
faluco@227
   173
			{
faluco@227
   174
				break;
faluco@227
   175
			}
faluco@227
   176
		}
faluco@1677
   177
	}
faluco@1677
   178
	else
faluco@1677
   179
	{
faluco@227
   180
		while (string[size++]);
faluco@227
   181
		size--;
faluco@227
   182
	}
faluco@227
   183
faluco@227
   184
	if (size > (int)maxlen)
faluco@227
   185
	{
faluco@227
   186
		size = maxlen;
faluco@227
   187
	}
faluco@227
   188
faluco@227
   189
	maxlen -= size;
faluco@227
   190
	width -= size;
faluco@227
   191
faluco@227
   192
	while (size--)
faluco@227
   193
	{
faluco@227
   194
		*buf++ = *string++;
faluco@227
   195
	}
faluco@227
   196
faluco@227
   197
	while ((width-- > 0) && maxlen)
faluco@227
   198
	{
faluco@227
   199
		*buf++ = ' ';
faluco@227
   200
		maxlen--;
faluco@227
   201
	}
faluco@227
   202
faluco@227
   203
	*buf_p = buf;
faluco@227
   204
}
faluco@227
   205
faluco@1677
   206
void AddFloat(char **buf_p, size_t &maxlen, double fval, int width, int prec, int flags)
faluco@227
   207
{
faluco@1677
   208
	int digits;					// non-fraction part digits
faluco@1677
   209
	double tmp;					// temporary
faluco@1677
   210
	char *buf = *buf_p;			// output buffer pointer
faluco@1677
   211
	int val;					// temporary
faluco@1677
   212
	int sign = 0;				// 0: positive, 1: negative
faluco@1677
   213
	int fieldlength;			// for padding
faluco@1677
   214
	int significant_digits = 0;	// number of significant digits written
faluco@1677
   215
	const int MAX_SIGNIFICANT_DIGITS = 16;
faluco@227
   216
dvander@4329
   217
	if (ke::IsNaN(fval))
dvander@4329
   218
	{
dvander@4327
   219
		AddString(buf_p, maxlen, "NaN", width, prec);
dvander@4327
   220
		return;
dvander@4327
   221
	}
dvander@4327
   222
faluco@1677
   223
	// default precision
faluco@227
   224
	if (prec < 0)
faluco@227
   225
	{
faluco@227
   226
		prec = 6;
faluco@227
   227
	}
faluco@1677
   228
faluco@1677
   229
	// get the sign
faluco@1677
   230
	if (fval < 0)
faluco@1677
   231
	{
faluco@1677
   232
		fval = -fval;
faluco@1677
   233
		sign = 1;
faluco@1677
   234
	}
faluco@1677
   235
faluco@1677
   236
	// compute whole-part digits count
faluco@1677
   237
	digits = (int)log10(fval) + 1;
faluco@1677
   238
faluco@1677
   239
	// Only print 0.something if 0 < fval < 1
faluco@1677
   240
	if (digits < 1)
faluco@227
   241
	{
faluco@1677
   242
		digits = 1;
faluco@1677
   243
	}
faluco@1677
   244
faluco@1677
   245
	// compute the field length
faluco@1677
   246
	fieldlength = digits + prec + ((prec > 0) ? 1 : 0) + sign;
faluco@1677
   247
faluco@1677
   248
	// minus sign BEFORE left padding if padding with zeros
faluco@1677
   249
	if (sign && maxlen && (flags & ZEROPAD))
faluco@1677
   250
	{
faluco@1677
   251
		*buf++ = '-';
faluco@1677
   252
		maxlen--;
faluco@1677
   253
	}
faluco@1677
   254
faluco@1677
   255
	// right justify if required
faluco@1677
   256
	if ((flags & LADJUST) == 0)
faluco@1677
   257
	{
faluco@1677
   258
		while ((fieldlength < width) && maxlen)
faluco@1677
   259
		{
faluco@1677
   260
			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
faluco@1677
   261
			width--;
faluco@1677
   262
			maxlen--;
faluco@1677
   263
		}
faluco@1677
   264
	}
faluco@1677
   265
faluco@1677
   266
	// minus sign AFTER left padding if padding with spaces
faluco@1677
   267
	if (sign && maxlen && !(flags & ZEROPAD))
faluco@1677
   268
	{
faluco@1677
   269
		*buf++ = '-';
faluco@1677
   270
		maxlen--;
faluco@227
   271
	}
faluco@227
   272
faluco@1677
   273
	// write the whole part
faluco@1677
   274
	tmp = pow(10.0, digits-1);
faluco@1677
   275
	while ((digits--) && maxlen)
faluco@227
   276
	{
faluco@1677
   277
		if (++significant_digits > MAX_SIGNIFICANT_DIGITS)
faluco@1677
   278
		{
faluco@1677
   279
			*buf++ = '0';
faluco@1677
   280
		}
faluco@1677
   281
		else
faluco@1677
   282
		{
faluco@1677
   283
			val = (int)(fval / tmp);
faluco@1677
   284
			*buf++ = '0' + val;
faluco@1677
   285
			fval -= val * tmp;
faluco@1677
   286
			tmp *= 0.1;
faluco@1677
   287
		}
faluco@1677
   288
		maxlen--;
faluco@1677
   289
	}
faluco@1677
   290
faluco@1677
   291
	// write the fraction part
dvander@2515
   292
	if (maxlen && prec)
faluco@1677
   293
	{
faluco@227
   294
		*buf++ = '.';
faluco@227
   295
		maxlen--;
faluco@1677
   296
	}
faluco@1677
   297
faluco@1677
   298
	tmp = pow(10.0, prec);
faluco@1677
   299
faluco@1677
   300
	fval *= tmp;
faluco@1677
   301
	while (prec-- && maxlen)
faluco@1677
   302
	{
faluco@1677
   303
		if (++significant_digits > MAX_SIGNIFICANT_DIGITS)
faluco@1677
   304
		{
faluco@1677
   305
			*buf++ = '0';
faluco@1677
   306
		}
faluco@1677
   307
		else
faluco@227
   308
		{
faluco@1677
   309
			tmp *= 0.1;
faluco@1677
   310
			val = (int)(fval / tmp);
faluco@1677
   311
			*buf++ = '0' + val;
faluco@1677
   312
			fval -= val * tmp;
faluco@1677
   313
		}
faluco@1677
   314
		maxlen--;
faluco@1677
   315
	}
faluco@1677
   316
faluco@1677
   317
	// left justify if required
faluco@1677
   318
	if (flags & LADJUST)
faluco@1677
   319
	{
faluco@1677
   320
		while ((fieldlength < width) && maxlen)
faluco@1677
   321
		{
faluco@1677
   322
			// right-padding only with spaces, ZEROPAD is ignored
faluco@1677
   323
			*buf++ = ' ';
faluco@1677
   324
			width--;
faluco@227
   325
			maxlen--;
faluco@227
   326
		}
faluco@227
   327
	}
faluco@1677
   328
faluco@1677
   329
	// update parent's buffer pointer
faluco@1677
   330
	*buf_p = buf;
faluco@227
   331
}
faluco@227
   332
dvander@1965
   333
void AddBinary(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
dvander@1965
   334
{
dvander@1965
   335
	char text[32];
dvander@1965
   336
	int digits;
dvander@1965
   337
	char *buf;
dvander@1965
   338
dvander@1965
   339
	digits = 0;
dvander@1965
   340
	do
dvander@1965
   341
	{
dvander@1965
   342
		if (val & 1)
dvander@1965
   343
		{
dvander@1965
   344
			text[digits++] = '1';
dvander@1965
   345
		}
dvander@1965
   346
		else
dvander@1965
   347
		{
dvander@1965
   348
			text[digits++] = '0';
dvander@1965
   349
		}
dvander@1965
   350
		val >>= 1;
dvander@1965
   351
	} while (val);
dvander@1965
   352
dvander@1965
   353
	buf = *buf_p;
dvander@1965
   354
dvander@1965
   355
	if (!(flags & LADJUST))
dvander@1965
   356
	{
dvander@1965
   357
		while (digits < width && maxlen)
dvander@1965
   358
		{
dvander@1965
   359
			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
dvander@1965
   360
			width--;
dvander@1965
   361
			maxlen--;
dvander@1965
   362
		}
dvander@1965
   363
	}
dvander@1965
   364
dvander@1965
   365
	while (digits-- && maxlen)
dvander@1965
   366
	{
dvander@1965
   367
		*buf++ = text[digits];
dvander@1965
   368
		width--;
dvander@1965
   369
		maxlen--;
dvander@1965
   370
	}
dvander@1965
   371
dvander@1965
   372
	if (flags & LADJUST)
dvander@1965
   373
	{
dvander@1965
   374
		while (width-- && maxlen)
dvander@1965
   375
		{
dvander@1965
   376
			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
dvander@1965
   377
			maxlen--;
dvander@1965
   378
		}
dvander@1965
   379
	}
dvander@1965
   380
dvander@1965
   381
	*buf_p = buf;
dvander@1965
   382
}
dvander@1965
   383
faluco@227
   384
void AddUInt(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
faluco@227
   385
{
faluco@227
   386
	char text[32];
faluco@227
   387
	int digits;
faluco@227
   388
	char *buf;
faluco@227
   389
faluco@227
   390
	digits = 0;
faluco@227
   391
	do
faluco@227
   392
	{
faluco@227
   393
		text[digits++] = '0' + val % 10;
faluco@227
   394
		val /= 10;
faluco@227
   395
	} while (val);
faluco@227
   396
faluco@227
   397
	buf = *buf_p;
faluco@227
   398
faluco@227
   399
	if (!(flags & LADJUST))
faluco@227
   400
	{
faluco@227
   401
		while (digits < width && maxlen)
faluco@227
   402
		{
faluco@227
   403
			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
faluco@227
   404
			width--;
faluco@227
   405
			maxlen--;
faluco@227
   406
		}
faluco@227
   407
	}
faluco@227
   408
faluco@227
   409
	while (digits-- && maxlen)
faluco@227
   410
	{
faluco@227
   411
		*buf++ = text[digits];
faluco@227
   412
		width--;
faluco@227
   413
		maxlen--;
faluco@227
   414
	}
faluco@227
   415
faluco@227
   416
	if (flags & LADJUST)
faluco@227
   417
	{
faluco@227
   418
		while (width-- && maxlen)
faluco@227
   419
		{
faluco@227
   420
			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
faluco@227
   421
			maxlen--;
faluco@227
   422
		}
faluco@227
   423
	}
faluco@227
   424
faluco@227
   425
	*buf_p = buf;
faluco@227
   426
}
faluco@227
   427
faluco@227
   428
void AddInt(char **buf_p, size_t &maxlen, int val, int width, int flags)
faluco@227
   429
{
faluco@227
   430
	char text[32];
faluco@227
   431
	int digits;
faluco@227
   432
	int signedVal;
faluco@227
   433
	char *buf;
faluco@227
   434
	unsigned int unsignedVal;
faluco@227
   435
faluco@227
   436
	digits = 0;
faluco@227
   437
	signedVal = val;
faluco@227
   438
	if (val < 0)
faluco@227
   439
	{
faluco@227
   440
		/* we want the unsigned version */
faluco@227
   441
		unsignedVal = abs(val);
faluco@1677
   442
	}
faluco@1677
   443
	else
faluco@1677
   444
	{
faluco@227
   445
		unsignedVal = val;
faluco@227
   446
	}
faluco@1677
   447
faluco@227
   448
	do
faluco@227
   449
	{
faluco@227
   450
		text[digits++] = '0' + unsignedVal % 10;
faluco@227
   451
		unsignedVal /= 10;
faluco@227
   452
	} while (unsignedVal);
faluco@227
   453
faluco@227
   454
	if (signedVal < 0)
faluco@227
   455
	{
faluco@227
   456
		text[digits++] = '-';
faluco@227
   457
	}
faluco@227
   458
faluco@227
   459
	buf = *buf_p;
faluco@227
   460
faluco@227
   461
	if (!(flags & LADJUST))
faluco@227
   462
	{
faluco@227
   463
		while ((digits < width) && maxlen)
faluco@227
   464
		{
faluco@227
   465
			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
faluco@227
   466
			width--;
faluco@227
   467
			maxlen--;
faluco@227
   468
		}
faluco@227
   469
	}
faluco@227
   470
faluco@227
   471
	while (digits-- && maxlen)
faluco@227
   472
	{
faluco@227
   473
		*buf++ = text[digits];
faluco@227
   474
		width--;
faluco@227
   475
		maxlen--;
faluco@227
   476
	}
faluco@227
   477
faluco@227
   478
	if (flags & LADJUST)
faluco@227
   479
	{
faluco@227
   480
		while (width-- && maxlen)
faluco@227
   481
		{
faluco@227
   482
			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
faluco@227
   483
			maxlen--;
faluco@227
   484
		}
faluco@227
   485
	}
faluco@227
   486
faluco@227
   487
	*buf_p = buf;
faluco@227
   488
}
faluco@227
   489
ds@544
   490
void AddHex(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
ds@544
   491
{
ds@544
   492
	char text[32];
ds@544
   493
	int digits;
ds@544
   494
	char *buf;
ds@544
   495
	char digit;
ds@544
   496
	int hexadjust;
ds@544
   497
ds@544
   498
	if (flags & UPPERDIGITS)
ds@544
   499
	{
ds@544
   500
		hexadjust = 'A' - '9' - 1;
faluco@1677
   501
	}
faluco@1677
   502
	else
faluco@1677
   503
	{
ds@544
   504
		hexadjust = 'a' - '9' - 1;
ds@544
   505
	}
ds@544
   506
ds@544
   507
	digits = 0;
ds@544
   508
	do 
ds@544
   509
	{
ds@544
   510
		digit = ('0' + val % 16);
ds@544
   511
		if (digit > '9')
ds@544
   512
		{
ds@544
   513
			digit += hexadjust;
ds@544
   514
		}
ds@544
   515
ds@544
   516
		text[digits++] = digit;
ds@544
   517
		val /= 16;
ds@544
   518
	} while(val);
ds@544
   519
ds@544
   520
	buf = *buf_p;
ds@544
   521
ds@544
   522
	if (!(flags & LADJUST))
ds@544
   523
	{
ds@544
   524
		while (digits < width && maxlen)
ds@544
   525
		{
ds@544
   526
			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
ds@544
   527
			width--;
ds@544
   528
			maxlen--;
ds@544
   529
		}
ds@544
   530
	}
ds@544
   531
ds@544
   532
	while (digits-- && maxlen)
ds@544
   533
	{
ds@544
   534
		*buf++ = text[digits];
ds@544
   535
		width--;
ds@544
   536
		maxlen--;
ds@544
   537
	}
ds@544
   538
ds@544
   539
	if (flags & LADJUST)
ds@544
   540
	{
ds@544
   541
		while (width-- && maxlen)
ds@544
   542
		{
ds@544
   543
			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
ds@544
   544
			maxlen--;
ds@544
   545
		}
ds@544
   546
	}
ds@544
   547
ds@544
   548
	*buf_p = buf;
ds@544
   549
}
ds@544
   550
dvander@2042
   551
bool gnprintf(char *buffer,
dvander@2042
   552
			  size_t maxlen,
dvander@2042
   553
			  const char *format,
dvander@2042
   554
			  IPhraseCollection *pPhrases,
dvander@2042
   555
			  void **params,
dvander@2042
   556
			  unsigned int numparams,
dvander@2042
   557
			  unsigned int &curparam,
dvander@2042
   558
			  size_t *pOutLength,
dvander@2042
   559
			  const char **pFailPhrase)
dvander@276
   560
{
dvander@276
   561
	if (!buffer || !maxlen)
dvander@276
   562
	{
dvander@2042
   563
		if (pOutLength != NULL)
dvander@2042
   564
		{
dvander@2042
   565
			*pOutLength = 0;
dvander@2042
   566
		}
dvander@2042
   567
		return true;
dvander@2042
   568
	}
dvander@2042
   569
dvander@2042
   570
	if (numparams > MAX_TRANSLATE_PARAMS)
dvander@2042
   571
	{
dvander@2042
   572
		if (pFailPhrase != NULL)
dvander@2042
   573
		{
dvander@2042
   574
			*pFailPhrase = NULL;
dvander@2042
   575
		}
dvander@2042
   576
		return false;
dvander@276
   577
	}
dvander@276
   578
dvander@276
   579
	int arg = 0;
dvander@276
   580
	char *buf_p;
dvander@276
   581
	char ch;
dvander@276
   582
	int flags;
dvander@276
   583
	int width;
dvander@276
   584
	int prec;
dvander@276
   585
	int n;
dvander@276
   586
	char sign;
dvander@276
   587
	const char *fmt;
dvander@276
   588
	size_t llen = maxlen - 1;
dvander@276
   589
dvander@276
   590
	buf_p = buffer;
dvander@276
   591
	fmt = format;
dvander@276
   592
dvander@276
   593
	while (true)
dvander@276
   594
	{
dvander@276
   595
		// run through the format string until we hit a '%' or '\0'
dvander@276
   596
		for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
dvander@276
   597
		{
dvander@276
   598
			*buf_p++ = ch;
dvander@276
   599
			llen--;
dvander@276
   600
		}
dvander@276
   601
		if ((ch == '\0') || (llen <= 0))
dvander@276
   602
		{
dvander@276
   603
			goto done;
dvander@276
   604
		}
dvander@276
   605
dvander@276
   606
		// skip over the '%'
dvander@276
   607
		fmt++;
dvander@276
   608
dvander@276
   609
		// reset formatting state
dvander@276
   610
		flags = 0;
dvander@276
   611
		width = 0;
dvander@276
   612
		prec = -1;
dvander@276
   613
		sign = '\0';
dvander@276
   614
dvander@276
   615
rflag:
dvander@276
   616
		ch = *fmt++;
dvander@276
   617
reswitch:
dvander@276
   618
		switch(ch)
dvander@276
   619
		{
dvander@276
   620
		case '-':
dvander@276
   621
			{
dvander@276
   622
				flags |= LADJUST;
dvander@276
   623
				goto rflag;
dvander@276
   624
			}
dvander@276
   625
		case '.':
dvander@276
   626
			{
dvander@276
   627
				n = 0;
dvander@276
   628
				while(is_digit((ch = *fmt++)))
dvander@276
   629
				{
dvander@276
   630
					n = 10 * n + (ch - '0');
dvander@276
   631
				}
dvander@276
   632
				prec = (n < 0) ? -1 : n;
dvander@276
   633
				goto reswitch;
dvander@276
   634
			}
dvander@276
   635
		case '0':
dvander@276
   636
			{
dvander@276
   637
				flags |= ZEROPAD;
dvander@276
   638
				goto rflag;
dvander@276
   639
			}
dvander@276
   640
		case '1':
dvander@276
   641
		case '2':
dvander@276
   642
		case '3':
dvander@276
   643
		case '4':
dvander@276
   644
		case '5':
dvander@276
   645
		case '6':
dvander@276
   646
		case '7':
dvander@276
   647
		case '8':
dvander@276
   648
		case '9':
dvander@276
   649
			{
dvander@276
   650
				n = 0;
dvander@276
   651
				do
dvander@276
   652
				{
dvander@276
   653
					n = 10 * n + (ch - '0');
dvander@276
   654
					ch = *fmt++;
dvander@276
   655
				} while(is_digit(ch));
dvander@276
   656
				width = n;
dvander@276
   657
				goto reswitch;
dvander@276
   658
			}
dvander@276
   659
		case 'c':
dvander@276
   660
			{
dvander@276
   661
				if (!llen)
dvander@276
   662
				{
dvander@276
   663
					goto done;
dvander@276
   664
				}
dvander@2042
   665
				if (curparam >= numparams)
dvander@2042
   666
				{
dvander@2042
   667
					if (pFailPhrase != NULL)
dvander@2042
   668
					{
dvander@2042
   669
						*pFailPhrase = NULL;
dvander@2042
   670
					}
dvander@2042
   671
					return false;
dvander@2042
   672
				}
dvander@2042
   673
				char *c = (char *)params[curparam];
dvander@2042
   674
				curparam++;
dvander@276
   675
				*buf_p++ = *c;
dvander@276
   676
				llen--;
dvander@276
   677
				arg++;
dvander@276
   678
				break;
dvander@276
   679
			}
dvander@1965
   680
		case 'b':
dvander@1965
   681
			{
dvander@2042
   682
				if (curparam >= numparams)
dvander@2042
   683
				{
dvander@2042
   684
					if (pFailPhrase != NULL)
dvander@2042
   685
					{
dvander@2042
   686
						*pFailPhrase = NULL;
dvander@2042
   687
					}
dvander@2042
   688
					return false;
dvander@2042
   689
				}
dvander@2042
   690
				int *value = (int *)params[curparam];
dvander@2042
   691
				curparam++;
dvander@1965
   692
				AddBinary(&buf_p, llen, *value, width, flags);
dvander@1965
   693
				arg++;
dvander@1965
   694
				break;
dvander@1965
   695
			}
dvander@276
   696
		case 'd':
dvander@276
   697
		case 'i':
dvander@276
   698
			{
dvander@2042
   699
				if (curparam >= numparams)
dvander@2042
   700
				{
dvander@2042
   701
					if (pFailPhrase != NULL)
dvander@2042
   702
					{
dvander@2042
   703
						*pFailPhrase = NULL;
dvander@2042
   704
					}
dvander@2042
   705
					return false;
dvander@2042
   706
				}
dvander@2042
   707
				int *value = (int *)params[curparam];
dvander@2042
   708
				curparam++;
dvander@276
   709
				AddInt(&buf_p, llen, *value, width, flags);
dvander@276
   710
				arg++;
dvander@276
   711
				break;
dvander@276
   712
			}
dvander@276
   713
		case 'u':
dvander@276
   714
			{
dvander@2042
   715
				if (curparam >= numparams)
dvander@2042
   716
				{
dvander@2042
   717
					if (pFailPhrase != NULL)
dvander@2042
   718
					{
dvander@2042
   719
						*pFailPhrase = NULL;
dvander@2042
   720
					}
dvander@2042
   721
					return false;
dvander@2042
   722
				}
dvander@2042
   723
				unsigned int *value = (unsigned int *)params[curparam];
dvander@2042
   724
				curparam++;
dvander@276
   725
				AddUInt(&buf_p, llen, *value, width, flags);
dvander@276
   726
				arg++;
dvander@276
   727
				break;
dvander@276
   728
			}
dvander@276
   729
		case 'f':
dvander@276
   730
			{
dvander@2042
   731
				if (curparam >= numparams)
dvander@2042
   732
				{
dvander@2042
   733
					if (pFailPhrase != NULL)
dvander@2042
   734
					{
dvander@2042
   735
						*pFailPhrase = NULL;
dvander@2042
   736
					}
dvander@2042
   737
					return false;
dvander@2042
   738
				}
dvander@2042
   739
				float *value = (float *)params[curparam];
dvander@2042
   740
				curparam++;
faluco@1677
   741
				AddFloat(&buf_p, llen, *value, width, prec, flags);
dvander@276
   742
				arg++;
dvander@276
   743
				break;
dvander@276
   744
			}
dvander@276
   745
		case 's':
dvander@276
   746
			{
dvander@2042
   747
				if (curparam >= numparams)
dvander@2042
   748
				{
dvander@2042
   749
					if (pFailPhrase != NULL)
dvander@2042
   750
					{
dvander@2042
   751
						*pFailPhrase = NULL;
dvander@2042
   752
					}
dvander@2042
   753
					return false;
dvander@2042
   754
				}
dvander@2042
   755
				const char *str = (const char *)params[curparam];
dvander@2042
   756
				curparam++;
dvander@276
   757
				AddString(&buf_p, llen, str, width, prec);
dvander@276
   758
				arg++;
dvander@276
   759
				break;
dvander@276
   760
			}
dvander@2042
   761
		case 'T':
dvander@2042
   762
		case 't':
dvander@2042
   763
			{
dvander@2042
   764
				int target;
dvander@2042
   765
				const char *key;
dvander@2042
   766
				size_t out_length;
dvander@2042
   767
				Translation trans;
dvander@2042
   768
				unsigned int lang_id;
dvander@2042
   769
dvander@2042
   770
				if (curparam >= numparams)
dvander@2042
   771
				{
dvander@2042
   772
					if (pFailPhrase != NULL)
dvander@2042
   773
					{
dvander@2042
   774
						*pFailPhrase = NULL;
dvander@2042
   775
					}
dvander@2042
   776
					return false;
dvander@2042
   777
				}
dvander@2042
   778
				key = (const char *)(params[curparam]);
dvander@2042
   779
				curparam++;
dvander@2042
   780
dvander@2042
   781
				if (ch == 'T')
dvander@2042
   782
				{
dvander@2042
   783
					if (curparam >= numparams)
dvander@2042
   784
					{
dvander@2042
   785
						if (pFailPhrase != NULL)
dvander@2042
   786
						{
dvander@2042
   787
							*pFailPhrase = NULL;
dvander@2042
   788
						}
dvander@2042
   789
						return false;
dvander@2042
   790
					}
dvander@2042
   791
					target = *((int *)(params[curparam]));
dvander@2042
   792
					curparam++;
dvander@2042
   793
				}
dvander@2042
   794
				else
dvander@2042
   795
				{
dvander@3004
   796
					target = translator->GetGlobalTarget();
dvander@2042
   797
				}
dvander@2042
   798
dvander@2042
   799
try_again:
dvander@2042
   800
				if (target == SOURCEMOD_SERVER_LANGUAGE)
dvander@2042
   801
				{
dvander@3004
   802
					lang_id = translator->GetServerLanguage();
dvander@2042
   803
				}
dvander@2042
   804
				else if (target >= 1 && target <= g_Players.GetMaxClients())
dvander@2042
   805
				{
dvander@3004
   806
					lang_id = translator->GetClientLanguage(target);
dvander@2042
   807
				}
dvander@2042
   808
				else
dvander@2042
   809
				{
dvander@3004
   810
					lang_id = translator->GetServerLanguage();
dvander@2042
   811
				}
dvander@2042
   812
dvander@2042
   813
				if (pPhrases == NULL)
dvander@2042
   814
				{
dvander@2042
   815
					if (pFailPhrase != NULL)
dvander@2042
   816
					{
dvander@2042
   817
						*pFailPhrase = key;
dvander@2042
   818
					}
dvander@2042
   819
					return false;
dvander@2042
   820
				}
dvander@2042
   821
dvander@2042
   822
				if (pPhrases->FindTranslation(key, lang_id, &trans) != Trans_Okay)
dvander@2042
   823
				{
dvander@3004
   824
					if (target != SOURCEMOD_SERVER_LANGUAGE && lang_id != translator->GetServerLanguage())
dvander@2042
   825
					{
dvander@2042
   826
						target = SOURCEMOD_SERVER_LANGUAGE;
dvander@2042
   827
						goto try_again;
dvander@2042
   828
					}
dvander@2042
   829
					else if (lang_id != SOURCEMOD_LANGUAGE_ENGLISH)
dvander@2042
   830
					{
dvander@2042
   831
						if (pPhrases->FindTranslation(key, SOURCEMOD_LANGUAGE_ENGLISH, &trans) != Trans_Okay)
dvander@2042
   832
						{
dvander@2042
   833
							if (pFailPhrase != NULL)
dvander@2042
   834
							{
dvander@2042
   835
								*pFailPhrase = key;
dvander@2042
   836
							}
dvander@2042
   837
							return false;
dvander@2042
   838
						}
dvander@2042
   839
					}
dvander@2042
   840
					else
dvander@2042
   841
					{
dvander@2042
   842
						if (pFailPhrase != NULL)
dvander@2042
   843
						{
dvander@2042
   844
							*pFailPhrase = key;
dvander@2042
   845
						}
dvander@2042
   846
						return false;
dvander@2042
   847
					}
dvander@2042
   848
				}
dvander@2042
   849
dvander@2042
   850
				if (trans.fmt_count)
dvander@2042
   851
				{
dvander@2042
   852
					unsigned int i;
dvander@2042
   853
					void *new_params[MAX_TRANSLATE_PARAMS];
dvander@2042
   854
dvander@2042
   855
					if (curparam + trans.fmt_count > numparams)
dvander@2042
   856
					{
dvander@2042
   857
						if (pFailPhrase != NULL)
dvander@2042
   858
						{
dvander@2042
   859
							*pFailPhrase = NULL;
dvander@2042
   860
						}
dvander@2042
   861
						return false;
dvander@2042
   862
					}
dvander@2042
   863
dvander@2042
   864
					/* Copy the array and re-order the stack */
dvander@2042
   865
					memcpy(new_params, params, sizeof(void *) * numparams);
dvander@2042
   866
					for (i = 0; i < trans.fmt_count; i++)
dvander@2042
   867
					{
pred@2799
   868
						new_params[curparam + i] = const_cast<void *>(params[curparam + trans.fmt_order[i]]);
dvander@2042
   869
					}
dvander@2042
   870
dvander@2042
   871
					if (!gnprintf(buf_p,
dvander@2042
   872
							llen,
dvander@2042
   873
							trans.szPhrase,
dvander@2042
   874
							pPhrases,
dvander@2042
   875
							new_params,
dvander@2042
   876
							numparams,
dvander@2042
   877
							curparam,
dvander@2042
   878
							&out_length,
dvander@2042
   879
							pFailPhrase))
dvander@2042
   880
					{
dvander@2042
   881
						return false;
dvander@2042
   882
					}
dvander@2042
   883
				}
dvander@2042
   884
				else
dvander@2042
   885
				{
dvander@2042
   886
					if (!gnprintf(buf_p,
dvander@2042
   887
						llen,
dvander@2042
   888
						trans.szPhrase,
dvander@2042
   889
						pPhrases,
dvander@2042
   890
						params,
dvander@2042
   891
						numparams,
dvander@2042
   892
						curparam,
dvander@2042
   893
						&out_length,
dvander@2042
   894
						pFailPhrase))
dvander@2042
   895
					{
dvander@2042
   896
						return false;
dvander@2042
   897
					}
dvander@2042
   898
				}
dvander@2042
   899
dvander@2042
   900
				buf_p += out_length;
dvander@2042
   901
				llen -= out_length;
dvander@2042
   902
dvander@2042
   903
				break;
dvander@2042
   904
			}
ds@544
   905
		case 'X':
ds@544
   906
			{
dvander@2042
   907
				if (curparam >= numparams)
dvander@2042
   908
				{
dvander@2042
   909
					if (pFailPhrase != NULL)
dvander@2042
   910
					{
dvander@2042
   911
						*pFailPhrase = NULL;
dvander@2042
   912
					}
dvander@2042
   913
					return false;
dvander@2042
   914
				}
dvander@2042
   915
				unsigned int *value = (unsigned int *)params[curparam];
dvander@2042
   916
				curparam++;
ds@544
   917
				flags |= UPPERDIGITS;
ds@544
   918
				AddHex(&buf_p, llen, *value, width, flags);
ds@544
   919
				arg++;
ds@544
   920
				break;
ds@544
   921
			}
ds@544
   922
		case 'x':
ds@544
   923
			{
dvander@2042
   924
				if (curparam >= numparams)
dvander@2042
   925
				{
dvander@2042
   926
					if (pFailPhrase != NULL)
dvander@2042
   927
					{
dvander@2042
   928
						*pFailPhrase = NULL;
dvander@2042
   929
					}
dvander@2042
   930
					return false;
dvander@2042
   931
				}
dvander@2042
   932
				unsigned int *value = (unsigned int *)params[curparam];
dvander@2042
   933
				curparam++;
ds@544
   934
				AddHex(&buf_p, llen, *value, width, flags);
ds@544
   935
				arg++;
ds@544
   936
				break;
ds@544
   937
			}
dvander@276
   938
		case '%':
dvander@276
   939
			{
dvander@276
   940
				if (!llen)
dvander@276
   941
				{
dvander@276
   942
					goto done;
dvander@276
   943
				}
dvander@276
   944
				*buf_p++ = ch;
dvander@276
   945
				llen--;
dvander@276
   946
				break;
dvander@276
   947
			}
dvander@276
   948
		case '\0':
dvander@276
   949
			{
dvander@276
   950
				if (!llen)
dvander@276
   951
				{
dvander@276
   952
					goto done;
dvander@276
   953
				}
dvander@276
   954
				*buf_p++ = '%';
dvander@276
   955
				llen--;
dvander@276
   956
				goto done;
dvander@276
   957
			}
dvander@276
   958
		default:
dvander@276
   959
			{
dvander@276
   960
				if (!llen)
dvander@276
   961
				{
dvander@276
   962
					goto done;
dvander@276
   963
				}
dvander@276
   964
				*buf_p++ = ch;
dvander@276
   965
				llen--;
dvander@276
   966
				break;
dvander@276
   967
			}
dvander@276
   968
		}
dvander@276
   969
	}
dvander@276
   970
dvander@276
   971
done:
dvander@276
   972
	*buf_p = '\0';
dvander@276
   973
dvander@2042
   974
	if (pOutLength != NULL)
dvander@2042
   975
	{
dvander@2042
   976
		*pOutLength = (maxlen - llen - 1);
dvander@2042
   977
	}
dvander@2042
   978
dvander@2042
   979
	return true;
dvander@276
   980
}
dvander@276
   981
faluco@227
   982
size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext *pCtx, const cell_t *params, int *param)
faluco@227
   983
{
dvander@276
   984
	if (!buffer || !maxlen)
dvander@276
   985
	{
dvander@276
   986
		return 0;
dvander@276
   987
	}
dvander@276
   988
faluco@227
   989
	int arg;
faluco@288
   990
	int args = params[0];
faluco@227
   991
	char *buf_p;
faluco@227
   992
	char ch;
faluco@227
   993
	int flags;
faluco@227
   994
	int width;
faluco@227
   995
	int prec;
faluco@227
   996
	int n;
faluco@227
   997
	char sign;
faluco@227
   998
	const char *fmt;
faluco@230
   999
	size_t llen = maxlen - 1;
faluco@227
  1000
faluco@227
  1001
	buf_p = buffer;
faluco@227
  1002
	arg = *param;
faluco@227
  1003
	fmt = format;
faluco@227
  1004
faluco@227
  1005
	while (true)
faluco@227
  1006
	{
faluco@227
  1007
		// run through the format string until we hit a '%' or '\0'
faluco@227
  1008
		for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
faluco@227
  1009
		{
faluco@227
  1010
			*buf_p++ = ch;
faluco@227
  1011
			llen--;
faluco@227
  1012
		}
faluco@227
  1013
		if ((ch == '\0') || (llen <= 0))
faluco@227
  1014
		{
faluco@227
  1015
			goto done;
faluco@227
  1016
		}
faluco@227
  1017
faluco@227
  1018
		// skip over the '%'
faluco@227
  1019
		fmt++;
faluco@227
  1020
faluco@227
  1021
		// reset formatting state
faluco@227
  1022
		flags = 0;
faluco@227
  1023
		width = 0;
faluco@227
  1024
		prec = -1;
faluco@227
  1025
		sign = '\0';
faluco@227
  1026
faluco@227
  1027
rflag:
faluco@227
  1028
		ch = *fmt++;
faluco@227
  1029
reswitch:
faluco@227
  1030
		switch(ch)
faluco@227
  1031
		{
faluco@227
  1032
		case '-':
faluco@227
  1033
			{
faluco@227
  1034
				flags |= LADJUST;
faluco@227
  1035
				goto rflag;
faluco@227
  1036
			}
faluco@227
  1037
		case '.':
faluco@227
  1038
			{
faluco@227
  1039
				n = 0;
faluco@227
  1040
				while(is_digit((ch = *fmt++)))
faluco@227
  1041
				{
faluco@227
  1042
					n = 10 * n + (ch - '0');
faluco@227
  1043
				}
faluco@227
  1044
				prec = (n < 0) ? -1 : n;
faluco@227
  1045
				goto reswitch;
faluco@227
  1046
			}
faluco@227
  1047
		case '0':
faluco@227
  1048
			{
faluco@227
  1049
				flags |= ZEROPAD;
faluco@227
  1050
				goto rflag;
faluco@227
  1051
			}
faluco@227
  1052
		case '1':
faluco@227
  1053
		case '2':
faluco@227
  1054
		case '3':
faluco@227
  1055
		case '4':
faluco@227
  1056
		case '5':
faluco@227
  1057
		case '6':
faluco@227
  1058
		case '7':
faluco@227
  1059
		case '8':
faluco@227
  1060
		case '9':
faluco@227
  1061
			{
faluco@227
  1062
				n = 0;
faluco@227
  1063
				do
faluco@227
  1064
				{
faluco@227
  1065
					n = 10 * n + (ch - '0');
faluco@227
  1066
					ch = *fmt++;
faluco@227
  1067
				} while(is_digit(ch));
faluco@227
  1068
				width = n;
faluco@227
  1069
				goto reswitch;
faluco@227
  1070
			}
faluco@227
  1071
		case 'c':
faluco@227
  1072
			{
faluco@227
  1073
				CHECK_ARGS(0);
faluco@230
  1074
				if (!llen)
faluco@227
  1075
				{
faluco@227
  1076
					goto done;
faluco@227
  1077
				}
faluco@227
  1078
				char *c;
faluco@227
  1079
				pCtx->LocalToString(params[arg], &c);
faluco@227
  1080
				*buf_p++ = *c;
faluco@227
  1081
				llen--;
faluco@227
  1082
				arg++;
faluco@227
  1083
				break;
faluco@227
  1084
			}
dvander@1965
  1085
		case 'b':
dvander@1965
  1086
			{
dvander@1965
  1087
				CHECK_ARGS(0);
dvander@1965
  1088
				cell_t *value;
dvander@1965
  1089
				pCtx->LocalToPhysAddr(params[arg], &value);
dvander@1965
  1090
				AddBinary(&buf_p, llen, *value, width, flags);
dvander@1965
  1091
				arg++;
dvander@1965
  1092
				break;
dvander@1965
  1093
			}
faluco@227
  1094
		case 'd':
faluco@227
  1095
		case 'i':
faluco@227
  1096
			{
faluco@227
  1097
				CHECK_ARGS(0);
faluco@227
  1098
				cell_t *value;
faluco@227
  1099
				pCtx->LocalToPhysAddr(params[arg], &value);
faluco@227
  1100
				AddInt(&buf_p, llen, static_cast<int>(*value), width, flags);
faluco@227
  1101
				arg++;
faluco@227
  1102
				break;
faluco@227
  1103
			}
faluco@227
  1104
		case 'u':
faluco@227
  1105
			{
faluco@227
  1106
				CHECK_ARGS(0);
faluco@227
  1107
				cell_t *value;
faluco@227
  1108
				pCtx->LocalToPhysAddr(params[arg], &value);
faluco@227
  1109
				AddUInt(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
faluco@227
  1110
				arg++;
faluco@227
  1111
				break;
faluco@227
  1112
			}
faluco@227
  1113
		case 'f':
faluco@227
  1114
			{
faluco@227
  1115
				CHECK_ARGS(0);
faluco@227
  1116
				cell_t *value;
faluco@227
  1117
				pCtx->LocalToPhysAddr(params[arg], &value);
faluco@1677
  1118
				AddFloat(&buf_p, llen, sp_ctof(*value), width, prec, flags);
faluco@227
  1119
				arg++;
faluco@227
  1120
				break;
faluco@227
  1121
			}
dvander@905
  1122
		case 'L':
dvander@905
  1123
			{
dvander@905
  1124
				CHECK_ARGS(0);
dvander@905
  1125
				cell_t *value;
dvander@905
  1126
				pCtx->LocalToPhysAddr(params[arg], &value);
dvander@905
  1127
				char buffer[255];
dvander@906
  1128
				if (*value)
dvander@905
  1129
				{
dvander@906
  1130
					CPlayer *player = g_Players.GetPlayerByIndex(*value);
dvander@906
  1131
					if (!player || !player->IsConnected())
dvander@906
  1132
					{
dvander@906
  1133
						return pCtx->ThrowNativeError("Client index %d is invalid", *value);
dvander@906
  1134
					}
dvander@906
  1135
					const char *auth = player->GetAuthString();
dvander@906
  1136
					if (!auth || auth[0] == '\0')
dvander@906
  1137
					{
dvander@906
  1138
						auth = "STEAM_ID_PENDING";
dvander@906
  1139
					}
skamonkey@3913
  1140
					int userid = GetPlayerUserId(player->GetEdict());
dvander@906
  1141
					UTIL_Format(buffer, 
dvander@906
  1142
						sizeof(buffer), 
dvander@906
  1143
						"%s<%d><%s><>", 
dvander@906
  1144
						player->GetName(),
dvander@906
  1145
						userid,
dvander@906
  1146
						auth);
faluco@1677
  1147
				}
faluco@1677
  1148
				else
faluco@1677
  1149
				{
dvander@906
  1150
					UTIL_Format(buffer,
dvander@906
  1151
						sizeof(buffer),
dvander@906
  1152
						"Console<0><Console><Console>");
dvander@905
  1153
				}
dvander@905
  1154
				AddString(&buf_p, llen, buffer, width, prec);
dvander@905
  1155
				arg++;
dvander@905
  1156
				break;
dvander@905
  1157
			}
dvander@1420
  1158
		case 'N':
dvander@1420
  1159
			{
dvander@1420
  1160
				CHECK_ARGS(0);
dvander@1420
  1161
				cell_t *value;
dvander@1420
  1162
				pCtx->LocalToPhysAddr(params[arg], &value);
dvander@1420
  1163
dvander@1420
  1164
				const char *name = "Console";
dvander@1420
  1165
				if (*value)
dvander@1420
  1166
				{
dvander@1420
  1167
					CPlayer *player = g_Players.GetPlayerByIndex(*value);
dvander@1420
  1168
					if (!player || !player->IsConnected())
dvander@1420
  1169
					{
dvander@1420
  1170
						return pCtx->ThrowNativeError("Client index %d is invalid", *value);
dvander@1420
  1171
					}
dvander@1420
  1172
					name = player->GetName();
dvander@1420
  1173
				}
dvander@1420
  1174
				AddString(&buf_p, llen, name, width, prec);
dvander@1420
  1175
				arg++;
dvander@1420
  1176
				break;
dvander@1420
  1177
			}
faluco@227
  1178
		case 's':
faluco@227
  1179
			{
faluco@227
  1180
				CHECK_ARGS(0);
faluco@227
  1181
				char *str;
dvander@535
  1182
				int err;
dvander@535
  1183
				if ((err=pCtx->LocalToString(params[arg], &str)) != SP_ERROR_NONE)
dvander@535
  1184
				{
dvander@535
  1185
					pCtx->ThrowNativeErrorEx(err, "Could not deference string");
dvander@535
  1186
					return 0;
dvander@535
  1187
				}
faluco@227
  1188
				AddString(&buf_p, llen, str, width, prec);
faluco@227
  1189
				arg++;
faluco@227
  1190
				break;
faluco@227
  1191
			}
faluco@389
  1192
		case 'T':
faluco@389
  1193
			{
dvander@888
  1194
				CHECK_ARGS(1);
faluco@389
  1195
				char *key;
faluco@422
  1196
				bool error;
faluco@422
  1197
				size_t res;
ds@669
  1198
				cell_t *target;
dvander@888
  1199
				pCtx->LocalToString(params[arg++], &key);
ds@669
  1200
				pCtx->LocalToPhysAddr(params[arg++], &target);
ds@669
  1201
				res = Translate(buf_p, llen, pCtx, key, *target, params, &arg, &error);
faluco@422
  1202
				if (error)
faluco@422
  1203
				{
faluco@422
  1204
					return 0;
faluco@422
  1205
				}
faluco@422
  1206
				buf_p += res;
faluco@422
  1207
				llen -= res;
faluco@422
  1208
				break;
faluco@422
  1209
			}
faluco@422
  1210
		case 't':
faluco@422
  1211
			{
faluco@422
  1212
				CHECK_ARGS(0);
faluco@422
  1213
				char *key;
faluco@422
  1214
				bool error;
faluco@422
  1215
				size_t res;
faluco@422
  1216
				cell_t target = g_SourceMod.GetGlobalTarget();
faluco@422
  1217
				pCtx->LocalToString(params[arg++], &key);
faluco@422
  1218
				res = Translate(buf_p, llen, pCtx, key, target, params, &arg, &error);
faluco@422
  1219
				if (error)
faluco@422
  1220
				{
faluco@422
  1221
					return 0;
faluco@422
  1222
				}
faluco@422
  1223
				buf_p += res;
faluco@422
  1224
				llen -= res;
faluco@389
  1225
				break;
faluco@389
  1226
			}
ds@544
  1227
		case 'X':
ds@544
  1228
			{
ds@544
  1229
				CHECK_ARGS(0);
ds@544
  1230
				cell_t *value;
ds@544
  1231
				pCtx->LocalToPhysAddr(params[arg], &value);
ds@544
  1232
				flags |= UPPERDIGITS;
ds@544
  1233
				AddHex(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
ds@544
  1234
				arg++;
ds@544
  1235
				break;
ds@544
  1236
			}
ds@544
  1237
		case 'x':
ds@544
  1238
			{
ds@544
  1239
				CHECK_ARGS(0);
ds@544
  1240
				cell_t *value;
ds@544
  1241
				pCtx->LocalToPhysAddr(params[arg], &value);
ds@544
  1242
				AddHex(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
ds@544
  1243
				arg++;
ds@544
  1244
				break;
ds@544
  1245
			}
faluco@227
  1246
		case '%':
faluco@227
  1247
			{
faluco@230
  1248
				if (!llen)
faluco@227
  1249
				{
faluco@227
  1250
					goto done;
faluco@227
  1251
				}
faluco@227
  1252
				*buf_p++ = ch;
faluco@227
  1253
				llen--;
faluco@227
  1254
				break;
faluco@227
  1255
			}
faluco@227
  1256
		case '\0':
faluco@227
  1257
			{
faluco@230
  1258
				if (!llen)
faluco@227
  1259
				{
faluco@227
  1260
					goto done;
faluco@227
  1261
				}
faluco@227
  1262
				*buf_p++ = '%';
faluco@227
  1263
				llen--;
faluco@227
  1264
				goto done;
faluco@227
  1265
			}
faluco@227
  1266
		default:
faluco@227
  1267
			{
faluco@230
  1268
				if (!llen)
faluco@227
  1269
				{
faluco@227
  1270
					goto done;
faluco@227
  1271
				}
faluco@227
  1272
				*buf_p++ = ch;
faluco@227
  1273
				llen--;
faluco@227
  1274
				break;
faluco@227
  1275
			}
faluco@227
  1276
		}
faluco@227
  1277
	}
faluco@227
  1278
faluco@227
  1279
done:
faluco@227
  1280
	*buf_p = '\0';
faluco@227
  1281
	*param = arg;
faluco@236
  1282
	return (maxlen - llen - 1);
faluco@227
  1283
}
faluco@230
  1284
dvander@233
  1285
unsigned int strncopy(char *dest, const char *src, size_t count)
faluco@230
  1286
{
faluco@230
  1287
	if (!count)
faluco@230
  1288
	{
faluco@230
  1289
		return 0;
faluco@230
  1290
	}
faluco@230
  1291
faluco@230
  1292
	char *start = dest;
faluco@230
  1293
	while ((*src) && (--count))
faluco@230
  1294
	{
faluco@230
  1295
		*dest++ = *src++;
faluco@230
  1296
	}
faluco@230
  1297
	*dest = '\0';
faluco@230
  1298
faluco@230
  1299
	return (dest - start);
faluco@230
  1300
}
faluco@274
  1301
faluco@274
  1302
size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
faluco@274
  1303
{
faluco@274
  1304
	va_list ap;
faluco@274
  1305
	va_start(ap, fmt);
faluco@274
  1306
	size_t len = vsnprintf(buffer, maxlength, fmt, ap);
faluco@274
  1307
	va_end(ap);
faluco@274
  1308
faluco@651
  1309
	if (len >= maxlength)
faluco@651
  1310
	{
faluco@651
  1311
		buffer[maxlength - 1] = '\0';
faluco@651
  1312
		return (maxlength - 1);
faluco@1677
  1313
	}
faluco@1677
  1314
	else
faluco@1677
  1315
	{
faluco@651
  1316
		return len;
faluco@651
  1317
	}
dvander@351
  1318
}
dvander@351
  1319
dvander@663
  1320
size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list ap)
dvander@663
  1321
{
dvander@663
  1322
	size_t len = vsnprintf(buffer, maxlength, fmt, ap);
dvander@663
  1323
dvander@663
  1324
	if (len >= maxlength)
dvander@663
  1325
	{
dvander@663
  1326
		buffer[maxlength - 1] = '\0';
dvander@663
  1327
		return (maxlength - 1);
faluco@1677
  1328
	}
faluco@1677
  1329
	else
faluco@1677
  1330
	{
dvander@663
  1331
		return len;
dvander@663
  1332
	}
dvander@663
  1333
}
dvander@663
  1334
ds@504
  1335
char *sm_strdup(const char *str)
ds@504
  1336
{
ds@504
  1337
	char *ptr = new char[strlen(str)+1];
ds@504
  1338
	strcpy(ptr, str);
ds@504
  1339
	return ptr;
ds@504
  1340
}
dvander@833
  1341
dvander@1738
  1342
char *UTIL_TrimWhitespace(char *str, size_t &len)
dvander@1738
  1343
{
dvander@1738
  1344
	char *end = str + len - 1;
dvander@1738
  1345
dvander@1738
  1346
	if (!len)
dvander@1738
  1347
	{
dvander@1738
  1348
		return str;
dvander@1738
  1349
	}
dvander@1738
  1350
dvander@1738
  1351
	/* Iterate backwards through string until we reach first non-whitespace char */
dvander@1738
  1352
	while (end >= str && textparsers->IsWhitespace(end))
dvander@1738
  1353
	{
dvander@1738
  1354
		end--;
dvander@1738
  1355
		len--;
dvander@1738
  1356
	}
dvander@1738
  1357
dvander@1738
  1358
	/* Replace first whitespace char (at the end) with null terminator.
dvander@1738
  1359
	 * If there is none, we're just replacing the null terminator. 
dvander@1738
  1360
	 */
dvander@1738
  1361
	*(end + 1) = '\0';
dvander@1738
  1362
dvander@1738
  1363
	while (*str != '\0' && textparsers->IsWhitespace(str))
dvander@1738
  1364
	{
dvander@1738
  1365
		str++;
dvander@1738
  1366
		len--;
dvander@1738
  1367
	}
dvander@1738
  1368
dvander@1738
  1369
	return str;
dvander@1738
  1370
}
dvander@1738
  1371
dvander@2806
  1372
char *UTIL_ToLowerCase(const char *str)
dvander@2806
  1373
{
dvander@2806
  1374
	size_t len = strlen(str);
dvander@2806
  1375
	char *buffer = new char[len + 1];
dvander@2806
  1376
	for (size_t i = 0; i < len; i++)
dvander@2806
  1377
	{
dvander@2806
  1378
		if (str[i] >= 'A' && str[i] <= 'Z')
dvander@2806
  1379
			buffer[i] = tolower(str[i]);
dvander@2806
  1380
		else
dvander@2806
  1381
			buffer[i] = str[i];
dvander@2806
  1382
	}
dvander@2806
  1383
	buffer[len] = '\0';
dvander@2806
  1384
	return buffer;
dvander@2806
  1385
}
dvander@2806
  1386