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