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