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