core/sm_stringutil.cpp
author David Anderson <dvander@alliedmods.net>
Mon Mar 19 01:44:09 2007 +0000 (2007-03-19)
changeset 647 1e29dcc9ca97
parent 609 caae8c3c1d0c
child 651 7129f1566129
permissions -rw-r--r--
fixed a potential bug with kicking players during authorization
dvander@370
     1
/**
dvander@370
     2
 * ===============================================================
dvander@370
     3
 * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
dvander@370
     4
 * ===============================================================
dvander@370
     5
 *
dvander@370
     6
 * This file is not open source and may not be copied without explicit
dvander@370
     7
 * written permission of AlliedModders LLC.  This file may not be redistributed 
dvander@370
     8
 * in whole or significant part.
dvander@370
     9
 * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
dvander@370
    10
 *
dvander@370
    11
 * Version: $Id$
dvander@370
    12
 */
dvander@370
    13
faluco@230
    14
#include <stdlib.h>
faluco@230
    15
#include <ctype.h>
faluco@274
    16
#include <stdarg.h>
faluco@227
    17
#include "sm_stringutil.h"
dvander@592
    18
#include "Logger.h"
faluco@389
    19
#include "PluginSys.h"
dvander@591
    20
#include "Translator.h"
dvander@591
    21
#include "PlayerManager.h"
faluco@227
    22
faluco@227
    23
#define LADJUST			0x00000004		/* left adjustment */
faluco@227
    24
#define ZEROPAD			0x00000080		/* zero (as opposed to blank) pad */
ds@609
    25
#define UPPERDIGITS		0x00000200		/* make alpha digits uppercase */
faluco@227
    26
#define to_digit(c)		((c) - '0')
faluco@227
    27
#define is_digit(c)		((unsigned)to_digit(c) <= 9)
faluco@227
    28
faluco@288
    29
#define CHECK_ARGS(x) \
faluco@288
    30
	if ((arg+x) > args) { \
dvander@599
    31
		pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "String formatted incorrectly - parameter %d (total %d)", arg, args); \
faluco@288
    32
		return 0; \
faluco@227
    33
	}
faluco@227
    34
faluco@422
    35
inline bool TryServerLanguage(const char *serverlang, unsigned int *langid)
faluco@389
    36
{
faluco@422
    37
	if (!g_Translator.GetLanguageByCode(serverlang, langid))
faluco@422
    38
	{
faluco@422
    39
		if (!g_Translator.GetLanguageByCode("en", langid))
faluco@422
    40
		{
faluco@422
    41
			return false;
faluco@422
    42
		}
faluco@422
    43
	}
faluco@422
    44
	return true;
faluco@422
    45
}
faluco@389
    46
faluco@422
    47
inline bool TryTranslation(CPlugin *pl, const char *key, unsigned int langid, unsigned int langcount, Translation *pTrans)
faluco@422
    48
{
faluco@422
    49
	TransError err = Trans_BadLanguage;
faluco@389
    50
	CPhraseFile *phrfl;
faluco@389
    51
faluco@389
    52
	for (size_t i=0; i<langcount && err!=Trans_Okay; i++)
faluco@389
    53
	{
ds@457
    54
		phrfl = g_Translator.GetFileByIndex(pl->GetLangFileByIndex(i));
faluco@422
    55
		err = phrfl->GetTranslation(key, langid, pTrans);
faluco@389
    56
	}
faluco@389
    57
faluco@422
    58
	return (err == Trans_Okay) ? true : false;
faluco@422
    59
}
faluco@422
    60
faluco@422
    61
size_t Translate(char *buffer, size_t maxlen, IPluginContext *pCtx, const char *key, cell_t target, const cell_t *params, int *arg, bool *error)
faluco@422
    62
{
faluco@422
    63
	unsigned int langid;
faluco@422
    64
	char *langname = NULL;
faluco@422
    65
	*error = false;
dvander@464
    66
	Translation pTrans;
dvander@464
    67
	CPlugin *pl = (CPlugin *)g_PluginSys.FindPluginByContext(pCtx->GetContext());
dvander@464
    68
	size_t langcount = pl->GetLangFileCount();
dvander@464
    69
	void *new_params[MAX_TRANSLATE_PARAMS];
dvander@464
    70
	unsigned int max_params = 0;
faluco@422
    71
faluco@422
    72
try_serverlang:
faluco@422
    73
	if (target == LANG_SERVER)
faluco@389
    74
	{
faluco@422
    75
		langname = "en"; //:TODO: read serverlang
faluco@422
    76
		if (!TryServerLanguage(langname ? langname : "en", &langid))
faluco@422
    77
		{
ds@470
    78
			pCtx->ThrowNativeError("Translation failure: English language not found");
faluco@422
    79
			goto error_out;
faluco@422
    80
		}
dvander@448
    81
	} else if ((target >= 1) && (target <= g_Players.GetMaxClients())) {
faluco@422
    82
		langname = "en"; //:TODO: read player's lang
faluco@422
    83
		if (!langname || !g_Translator.GetLanguageByCode(langname, &langid))
faluco@422
    84
		{
faluco@422
    85
			if (langname && !strcmp(langname, "en"))
faluco@422
    86
			{
ds@470
    87
				pCtx->ThrowNativeError("Translation failure: English language not found");
faluco@422
    88
				goto error_out;
faluco@422
    89
			}
faluco@422
    90
			target = LANG_SERVER;
faluco@422
    91
			goto try_serverlang;
faluco@422
    92
		}
faluco@422
    93
	} else {
faluco@422
    94
		pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Translation failed: invalid client index %d", target);
faluco@422
    95
		goto error_out;
faluco@422
    96
	}
faluco@422
    97
faluco@422
    98
	if (!TryTranslation(pl, key, langid, langcount, &pTrans))
faluco@422
    99
	{
faluco@422
   100
		if (target != LANG_SERVER)
faluco@422
   101
		{
faluco@422
   102
			target = LANG_SERVER;
faluco@422
   103
			goto try_serverlang;
faluco@422
   104
		} else {
faluco@422
   105
			if (!g_Translator.GetLanguageByCode("en", &langid)
faluco@422
   106
				|| !TryTranslation(pl, key, langid, langcount, &pTrans))
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
			}
faluco@422
   111
		}
faluco@389
   112
	}
faluco@389
   113
dvander@474
   114
	max_params = pTrans.fmt_count;
dvander@474
   115
faluco@389
   116
	for (size_t i=0; i<max_params; i++)
faluco@389
   117
	{
faluco@389
   118
		pCtx->LocalToPhysAddr(params[*arg], reinterpret_cast<cell_t **>(&new_params[i]));
faluco@389
   119
		(*arg)++;
faluco@389
   120
		if ((*arg) + i > (size_t)params[0])
faluco@389
   121
		{
faluco@422
   122
			pCtx->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX, "Translation string formatted incorrectly - parameter %d (total %d)", (*arg) + i, params[0]);
faluco@422
   123
			goto error_out;
faluco@389
   124
		}
faluco@389
   125
	}
faluco@389
   126
faluco@389
   127
	return g_Translator.Translate(buffer, maxlen, new_params, &pTrans);
faluco@422
   128
error_out:
faluco@422
   129
	*error = true;
faluco@422
   130
	return 0;
faluco@389
   131
}
faluco@389
   132
dvander@276
   133
//:TODO: review this code before we choose a license
dvander@276
   134
faluco@227
   135
void AddString(char **buf_p, size_t &maxlen, const char *string, int width, int prec)
faluco@227
   136
{
faluco@227
   137
	int size = 0;
faluco@227
   138
	char *buf;
faluco@227
   139
	static char nlstr[] = {'(','n','u','l','l',')','\0'};
faluco@227
   140
faluco@227
   141
	buf = *buf_p;
faluco@227
   142
faluco@227
   143
	if (string == NULL)
faluco@227
   144
	{
faluco@227
   145
		string = nlstr;
faluco@227
   146
		prec = -1;
faluco@227
   147
	}
faluco@227
   148
faluco@227
   149
	if (prec >= 0)
faluco@227
   150
	{
faluco@227
   151
		for (size = 0; size < prec; size++) 
faluco@227
   152
		{
faluco@227
   153
			if (string[size] == '\0')
faluco@227
   154
			{
faluco@227
   155
				break;
faluco@227
   156
			}
faluco@227
   157
		}
faluco@227
   158
	} else {
faluco@227
   159
		while (string[size++]);
faluco@227
   160
		size--;
faluco@227
   161
	}
faluco@227
   162
faluco@227
   163
	if (size > (int)maxlen)
faluco@227
   164
	{
faluco@227
   165
		size = maxlen;
faluco@227
   166
	}
faluco@227
   167
faluco@227
   168
	maxlen -= size;
faluco@227
   169
	width -= size;
faluco@227
   170
faluco@227
   171
	while (size--)
faluco@227
   172
	{
faluco@227
   173
		*buf++ = *string++;
faluco@227
   174
	}
faluco@227
   175
faluco@227
   176
	while ((width-- > 0) && maxlen)
faluco@227
   177
	{
faluco@227
   178
		*buf++ = ' ';
faluco@227
   179
		maxlen--;
faluco@227
   180
	}
faluco@227
   181
faluco@227
   182
	*buf_p = buf;
faluco@227
   183
}
faluco@227
   184
faluco@227
   185
void AddFloat(char **buf_p, size_t &maxlen, double fval, int width, int prec)
faluco@227
   186
{
faluco@227
   187
	char text[32];
faluco@227
   188
	int digits;
faluco@227
   189
	double signedVal;
faluco@227
   190
	char *buf;
faluco@227
   191
	int val;
faluco@227
   192
faluco@227
   193
	// get the sign
faluco@227
   194
	signedVal = fval;
faluco@227
   195
	if (fval < 0)
faluco@227
   196
	{
faluco@227
   197
		fval = -fval;
faluco@227
   198
	}
faluco@227
   199
faluco@227
   200
	// write the float number
faluco@227
   201
	digits = 0;
faluco@227
   202
	val = (int)fval;
faluco@227
   203
	do
faluco@227
   204
	{
faluco@227
   205
		text[digits++] = '0' + val % 10;
faluco@227
   206
		val /= 10;
faluco@227
   207
	} while (val);
faluco@227
   208
faluco@227
   209
	if (signedVal < 0)
faluco@227
   210
	{
faluco@227
   211
		text[digits++] = '-';
faluco@227
   212
	}
faluco@227
   213
faluco@227
   214
	buf = *buf_p;
faluco@227
   215
faluco@227
   216
	while ((digits < width) && maxlen)
faluco@227
   217
	{
faluco@227
   218
		*buf++ = ' ';
faluco@227
   219
		width--;
faluco@227
   220
		maxlen--;
faluco@227
   221
	}
faluco@227
   222
faluco@227
   223
	while ((digits--) && maxlen)
faluco@227
   224
	{
faluco@227
   225
		*buf++ = text[digits];
faluco@227
   226
		maxlen--;
faluco@227
   227
	}
faluco@227
   228
faluco@227
   229
	*buf_p = buf;
faluco@227
   230
faluco@227
   231
	if (prec < 0)
faluco@227
   232
	{
faluco@227
   233
		prec = 6;
faluco@227
   234
	}
faluco@227
   235
	// write the fraction
faluco@227
   236
	digits = 0;
faluco@227
   237
	while (digits < prec)
faluco@227
   238
	{
faluco@227
   239
		fval -= (int)fval;
faluco@227
   240
		fval *= 10.0;
faluco@227
   241
		val = (int)fval;
faluco@227
   242
		text[digits++] = '0' + val % 10;
faluco@227
   243
	}
faluco@227
   244
faluco@227
   245
	if ((digits > 0) && maxlen)
faluco@227
   246
	{
faluco@227
   247
		buf = *buf_p;
faluco@227
   248
		*buf++ = '.';
faluco@227
   249
		maxlen--;
faluco@227
   250
		for (prec = 0; maxlen && (prec < digits); prec++)
faluco@227
   251
		{
faluco@227
   252
			*buf++ = text[prec];
faluco@227
   253
			maxlen--;
faluco@227
   254
		}
faluco@227
   255
		*buf_p = buf;
faluco@227
   256
	}
faluco@227
   257
}
faluco@227
   258
faluco@227
   259
void AddUInt(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
faluco@227
   260
{
faluco@227
   261
	char text[32];
faluco@227
   262
	int digits;
faluco@227
   263
	char *buf;
faluco@227
   264
faluco@227
   265
	digits = 0;
faluco@227
   266
	do
faluco@227
   267
	{
faluco@227
   268
		text[digits++] = '0' + val % 10;
faluco@227
   269
		val /= 10;
faluco@227
   270
	} while (val);
faluco@227
   271
faluco@227
   272
	buf = *buf_p;
faluco@227
   273
faluco@227
   274
	if (!(flags & LADJUST))
faluco@227
   275
	{
faluco@227
   276
		while (digits < width && maxlen)
faluco@227
   277
		{
faluco@227
   278
			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
faluco@227
   279
			width--;
faluco@227
   280
			maxlen--;
faluco@227
   281
		}
faluco@227
   282
	}
faluco@227
   283
faluco@227
   284
	while (digits-- && maxlen)
faluco@227
   285
	{
faluco@227
   286
		*buf++ = text[digits];
faluco@227
   287
		width--;
faluco@227
   288
		maxlen--;
faluco@227
   289
	}
faluco@227
   290
faluco@227
   291
	if (flags & LADJUST)
faluco@227
   292
	{
faluco@227
   293
		while (width-- && maxlen)
faluco@227
   294
		{
faluco@227
   295
			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
faluco@227
   296
			maxlen--;
faluco@227
   297
		}
faluco@227
   298
	}
faluco@227
   299
faluco@227
   300
	*buf_p = buf;
faluco@227
   301
}
faluco@227
   302
faluco@227
   303
void AddInt(char **buf_p, size_t &maxlen, int val, int width, int flags)
faluco@227
   304
{
faluco@227
   305
	char text[32];
faluco@227
   306
	int digits;
faluco@227
   307
	int signedVal;
faluco@227
   308
	char *buf;
faluco@227
   309
	unsigned int unsignedVal;
faluco@227
   310
faluco@227
   311
	digits = 0;
faluco@227
   312
	signedVal = val;
faluco@227
   313
	if (val < 0)
faluco@227
   314
	{
faluco@227
   315
		/* we want the unsigned version */
faluco@227
   316
		unsignedVal = abs(val);
faluco@227
   317
	} else {
faluco@227
   318
		unsignedVal = val;
faluco@227
   319
	}
faluco@227
   320
	do
faluco@227
   321
	{
faluco@227
   322
		text[digits++] = '0' + unsignedVal % 10;
faluco@227
   323
		unsignedVal /= 10;
faluco@227
   324
	} while (unsignedVal);
faluco@227
   325
faluco@227
   326
	if (signedVal < 0)
faluco@227
   327
	{
faluco@227
   328
		text[digits++] = '-';
faluco@227
   329
	}
faluco@227
   330
faluco@227
   331
	buf = *buf_p;
faluco@227
   332
faluco@227
   333
	if (!(flags & LADJUST))
faluco@227
   334
	{
faluco@227
   335
		while ((digits < width) && maxlen)
faluco@227
   336
		{
faluco@227
   337
			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
faluco@227
   338
			width--;
faluco@227
   339
			maxlen--;
faluco@227
   340
		}
faluco@227
   341
	}
faluco@227
   342
faluco@227
   343
	while (digits-- && maxlen)
faluco@227
   344
	{
faluco@227
   345
		*buf++ = text[digits];
faluco@227
   346
		width--;
faluco@227
   347
		maxlen--;
faluco@227
   348
	}
faluco@227
   349
faluco@227
   350
	if (flags & LADJUST)
faluco@227
   351
	{
faluco@227
   352
		while (width-- && maxlen)
faluco@227
   353
		{
faluco@227
   354
			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
faluco@227
   355
			maxlen--;
faluco@227
   356
		}
faluco@227
   357
	}
faluco@227
   358
faluco@227
   359
	*buf_p = buf;
faluco@227
   360
}
faluco@227
   361
ds@544
   362
void AddHex(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
ds@544
   363
{
ds@544
   364
	char text[32];
ds@544
   365
	int digits;
ds@544
   366
	char *buf;
ds@544
   367
	char digit;
ds@544
   368
	int hexadjust;
ds@544
   369
ds@544
   370
	if (flags & UPPERDIGITS)
ds@544
   371
	{
ds@544
   372
		hexadjust = 'A' - '9' - 1;
ds@544
   373
	} else {
ds@544
   374
		hexadjust = 'a' - '9' - 1;
ds@544
   375
	}
ds@544
   376
ds@544
   377
	digits = 0;
ds@544
   378
	do 
ds@544
   379
	{
ds@544
   380
		digit = ('0' + val % 16);
ds@544
   381
		if (digit > '9')
ds@544
   382
		{
ds@544
   383
			digit += hexadjust;
ds@544
   384
		}
ds@544
   385
ds@544
   386
		text[digits++] = digit;
ds@544
   387
		val /= 16;
ds@544
   388
	} while(val);
ds@544
   389
ds@544
   390
	buf = *buf_p;
ds@544
   391
ds@544
   392
	if (!(flags & LADJUST))
ds@544
   393
	{
ds@544
   394
		while (digits < width && maxlen)
ds@544
   395
		{
ds@544
   396
			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
ds@544
   397
			width--;
ds@544
   398
			maxlen--;
ds@544
   399
		}
ds@544
   400
	}
ds@544
   401
ds@544
   402
	while (digits-- && maxlen)
ds@544
   403
	{
ds@544
   404
		*buf++ = text[digits];
ds@544
   405
		width--;
ds@544
   406
		maxlen--;
ds@544
   407
	}
ds@544
   408
ds@544
   409
	if (flags & LADJUST)
ds@544
   410
	{
ds@544
   411
		while (width-- && maxlen)
ds@544
   412
		{
ds@544
   413
			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
ds@544
   414
			maxlen--;
ds@544
   415
		}
ds@544
   416
	}
ds@544
   417
ds@544
   418
	*buf_p = buf;
ds@544
   419
}
ds@544
   420
dvander@276
   421
size_t gnprintf(char *buffer, size_t maxlen, const char *format, void **args)
dvander@276
   422
{
dvander@276
   423
	if (!buffer || !maxlen)
dvander@276
   424
	{
dvander@276
   425
		return 0;
dvander@276
   426
	}
dvander@276
   427
dvander@276
   428
	int arg = 0;
dvander@276
   429
	char *buf_p;
dvander@276
   430
	char ch;
dvander@276
   431
	int flags;
dvander@276
   432
	int width;
dvander@276
   433
	int prec;
dvander@276
   434
	int n;
dvander@276
   435
	char sign;
dvander@276
   436
	const char *fmt;
dvander@276
   437
	size_t llen = maxlen - 1;
dvander@276
   438
dvander@276
   439
	buf_p = buffer;
dvander@276
   440
	fmt = format;
dvander@276
   441
dvander@276
   442
	while (true)
dvander@276
   443
	{
dvander@276
   444
		// run through the format string until we hit a '%' or '\0'
dvander@276
   445
		for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
dvander@276
   446
		{
dvander@276
   447
			*buf_p++ = ch;
dvander@276
   448
			llen--;
dvander@276
   449
		}
dvander@276
   450
		if ((ch == '\0') || (llen <= 0))
dvander@276
   451
		{
dvander@276
   452
			goto done;
dvander@276
   453
		}
dvander@276
   454
dvander@276
   455
		// skip over the '%'
dvander@276
   456
		fmt++;
dvander@276
   457
dvander@276
   458
		// reset formatting state
dvander@276
   459
		flags = 0;
dvander@276
   460
		width = 0;
dvander@276
   461
		prec = -1;
dvander@276
   462
		sign = '\0';
dvander@276
   463
dvander@276
   464
rflag:
dvander@276
   465
		ch = *fmt++;
dvander@276
   466
reswitch:
dvander@276
   467
		switch(ch)
dvander@276
   468
		{
dvander@276
   469
		case '-':
dvander@276
   470
			{
dvander@276
   471
				flags |= LADJUST;
dvander@276
   472
				goto rflag;
dvander@276
   473
			}
dvander@276
   474
		case '.':
dvander@276
   475
			{
dvander@276
   476
				n = 0;
dvander@276
   477
				while(is_digit((ch = *fmt++)))
dvander@276
   478
				{
dvander@276
   479
					n = 10 * n + (ch - '0');
dvander@276
   480
				}
dvander@276
   481
				prec = (n < 0) ? -1 : n;
dvander@276
   482
				goto reswitch;
dvander@276
   483
			}
dvander@276
   484
		case '0':
dvander@276
   485
			{
dvander@276
   486
				flags |= ZEROPAD;
dvander@276
   487
				goto rflag;
dvander@276
   488
			}
dvander@276
   489
		case '1':
dvander@276
   490
		case '2':
dvander@276
   491
		case '3':
dvander@276
   492
		case '4':
dvander@276
   493
		case '5':
dvander@276
   494
		case '6':
dvander@276
   495
		case '7':
dvander@276
   496
		case '8':
dvander@276
   497
		case '9':
dvander@276
   498
			{
dvander@276
   499
				n = 0;
dvander@276
   500
				do
dvander@276
   501
				{
dvander@276
   502
					n = 10 * n + (ch - '0');
dvander@276
   503
					ch = *fmt++;
dvander@276
   504
				} while(is_digit(ch));
dvander@276
   505
				width = n;
dvander@276
   506
				goto reswitch;
dvander@276
   507
			}
dvander@276
   508
		case 'c':
dvander@276
   509
			{
dvander@276
   510
				if (!llen)
dvander@276
   511
				{
dvander@276
   512
					goto done;
dvander@276
   513
				}
dvander@276
   514
				char *c = (char *)args[arg];
dvander@276
   515
				*buf_p++ = *c;
dvander@276
   516
				llen--;
dvander@276
   517
				arg++;
dvander@276
   518
				break;
dvander@276
   519
			}
dvander@276
   520
		case 'd':
dvander@276
   521
		case 'i':
dvander@276
   522
			{
dvander@276
   523
				int *value = (int *)args[arg];
dvander@276
   524
				AddInt(&buf_p, llen, *value, width, flags);
dvander@276
   525
				arg++;
dvander@276
   526
				break;
dvander@276
   527
			}
dvander@276
   528
		case 'u':
dvander@276
   529
			{
dvander@276
   530
				unsigned int *value = (unsigned int *)args[arg];
dvander@276
   531
				AddUInt(&buf_p, llen, *value, width, flags);
dvander@276
   532
				arg++;
dvander@276
   533
				break;
dvander@276
   534
			}
dvander@276
   535
		case 'f':
dvander@276
   536
			{
dvander@276
   537
				float *value = (float *)args[arg];
dvander@276
   538
				AddFloat(&buf_p, llen, *value, width, prec);
dvander@276
   539
				arg++;
dvander@276
   540
				break;
dvander@276
   541
			}
dvander@276
   542
		case 's':
dvander@276
   543
			{
dvander@276
   544
				const char *str = (const char *)args[arg];
dvander@276
   545
				AddString(&buf_p, llen, str, width, prec);
dvander@276
   546
				arg++;
dvander@276
   547
				break;
dvander@276
   548
			}
ds@544
   549
		case 'X':
ds@544
   550
			{
ds@544
   551
				unsigned int *value = (unsigned int *)args[arg];
ds@544
   552
				flags |= UPPERDIGITS;
ds@544
   553
				AddHex(&buf_p, llen, *value, width, flags);
ds@544
   554
				arg++;
ds@544
   555
				break;
ds@544
   556
			}
ds@544
   557
		case 'x':
ds@544
   558
			{
ds@544
   559
				unsigned int *value = (unsigned int *)args[arg];
ds@544
   560
				AddHex(&buf_p, llen, *value, width, flags);
ds@544
   561
				arg++;
ds@544
   562
				break;
ds@544
   563
			}
dvander@276
   564
		case '%':
dvander@276
   565
			{
dvander@276
   566
				if (!llen)
dvander@276
   567
				{
dvander@276
   568
					goto done;
dvander@276
   569
				}
dvander@276
   570
				*buf_p++ = ch;
dvander@276
   571
				llen--;
dvander@276
   572
				break;
dvander@276
   573
			}
dvander@276
   574
		case '\0':
dvander@276
   575
			{
dvander@276
   576
				if (!llen)
dvander@276
   577
				{
dvander@276
   578
					goto done;
dvander@276
   579
				}
dvander@276
   580
				*buf_p++ = '%';
dvander@276
   581
				llen--;
dvander@276
   582
				goto done;
dvander@276
   583
			}
dvander@276
   584
		default:
dvander@276
   585
			{
dvander@276
   586
				if (!llen)
dvander@276
   587
				{
dvander@276
   588
					goto done;
dvander@276
   589
				}
dvander@276
   590
				*buf_p++ = ch;
dvander@276
   591
				llen--;
dvander@276
   592
				break;
dvander@276
   593
			}
dvander@276
   594
		}
dvander@276
   595
	}
dvander@276
   596
dvander@276
   597
done:
dvander@276
   598
	*buf_p = '\0';
dvander@276
   599
dvander@276
   600
	return (maxlen - llen - 1);
dvander@276
   601
}
dvander@276
   602
faluco@227
   603
size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext *pCtx, const cell_t *params, int *param)
faluco@227
   604
{
dvander@276
   605
	if (!buffer || !maxlen)
dvander@276
   606
	{
dvander@276
   607
		return 0;
dvander@276
   608
	}
dvander@276
   609
faluco@227
   610
	int arg;
faluco@288
   611
	int args = params[0];
faluco@227
   612
	char *buf_p;
faluco@227
   613
	char ch;
faluco@227
   614
	int flags;
faluco@227
   615
	int width;
faluco@227
   616
	int prec;
faluco@227
   617
	int n;
faluco@227
   618
	char sign;
faluco@227
   619
	const char *fmt;
faluco@230
   620
	size_t llen = maxlen - 1;
faluco@227
   621
faluco@227
   622
	buf_p = buffer;
faluco@227
   623
	arg = *param;
faluco@227
   624
	fmt = format;
faluco@227
   625
faluco@227
   626
	while (true)
faluco@227
   627
	{
faluco@227
   628
		// run through the format string until we hit a '%' or '\0'
faluco@227
   629
		for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
faluco@227
   630
		{
faluco@227
   631
			*buf_p++ = ch;
faluco@227
   632
			llen--;
faluco@227
   633
		}
faluco@227
   634
		if ((ch == '\0') || (llen <= 0))
faluco@227
   635
		{
faluco@227
   636
			goto done;
faluco@227
   637
		}
faluco@227
   638
faluco@227
   639
		// skip over the '%'
faluco@227
   640
		fmt++;
faluco@227
   641
faluco@227
   642
		// reset formatting state
faluco@227
   643
		flags = 0;
faluco@227
   644
		width = 0;
faluco@227
   645
		prec = -1;
faluco@227
   646
		sign = '\0';
faluco@227
   647
faluco@227
   648
rflag:
faluco@227
   649
		ch = *fmt++;
faluco@227
   650
reswitch:
faluco@227
   651
		switch(ch)
faluco@227
   652
		{
faluco@227
   653
		case '-':
faluco@227
   654
			{
faluco@227
   655
				flags |= LADJUST;
faluco@227
   656
				goto rflag;
faluco@227
   657
			}
faluco@227
   658
		case '.':
faluco@227
   659
			{
faluco@227
   660
				n = 0;
faluco@227
   661
				while(is_digit((ch = *fmt++)))
faluco@227
   662
				{
faluco@227
   663
					n = 10 * n + (ch - '0');
faluco@227
   664
				}
faluco@227
   665
				prec = (n < 0) ? -1 : n;
faluco@227
   666
				goto reswitch;
faluco@227
   667
			}
faluco@227
   668
		case '0':
faluco@227
   669
			{
faluco@227
   670
				flags |= ZEROPAD;
faluco@227
   671
				goto rflag;
faluco@227
   672
			}
faluco@227
   673
		case '1':
faluco@227
   674
		case '2':
faluco@227
   675
		case '3':
faluco@227
   676
		case '4':
faluco@227
   677
		case '5':
faluco@227
   678
		case '6':
faluco@227
   679
		case '7':
faluco@227
   680
		case '8':
faluco@227
   681
		case '9':
faluco@227
   682
			{
faluco@227
   683
				n = 0;
faluco@227
   684
				do
faluco@227
   685
				{
faluco@227
   686
					n = 10 * n + (ch - '0');
faluco@227
   687
					ch = *fmt++;
faluco@227
   688
				} while(is_digit(ch));
faluco@227
   689
				width = n;
faluco@227
   690
				goto reswitch;
faluco@227
   691
			}
faluco@227
   692
		case 'c':
faluco@227
   693
			{
faluco@227
   694
				CHECK_ARGS(0);
faluco@230
   695
				if (!llen)
faluco@227
   696
				{
faluco@227
   697
					goto done;
faluco@227
   698
				}
faluco@227
   699
				char *c;
faluco@227
   700
				pCtx->LocalToString(params[arg], &c);
faluco@227
   701
				*buf_p++ = *c;
faluco@227
   702
				llen--;
faluco@227
   703
				arg++;
faluco@227
   704
				break;
faluco@227
   705
			}
faluco@227
   706
		case 'd':
faluco@227
   707
		case 'i':
faluco@227
   708
			{
faluco@227
   709
				CHECK_ARGS(0);
faluco@227
   710
				cell_t *value;
faluco@227
   711
				pCtx->LocalToPhysAddr(params[arg], &value);
faluco@227
   712
				AddInt(&buf_p, llen, static_cast<int>(*value), width, flags);
faluco@227
   713
				arg++;
faluco@227
   714
				break;
faluco@227
   715
			}
faluco@227
   716
		case 'u':
faluco@227
   717
			{
faluco@227
   718
				CHECK_ARGS(0);
faluco@227
   719
				cell_t *value;
faluco@227
   720
				pCtx->LocalToPhysAddr(params[arg], &value);
faluco@227
   721
				AddUInt(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
faluco@227
   722
				arg++;
faluco@227
   723
				break;
faluco@227
   724
			}
faluco@227
   725
		case 'f':
faluco@227
   726
			{
faluco@227
   727
				CHECK_ARGS(0);
faluco@227
   728
				cell_t *value;
faluco@227
   729
				pCtx->LocalToPhysAddr(params[arg], &value);
dvander@233
   730
				AddFloat(&buf_p, llen, sp_ctof(*value), width, prec);
faluco@227
   731
				arg++;
faluco@227
   732
				break;
faluco@227
   733
			}
faluco@227
   734
		case 's':
faluco@227
   735
			{
faluco@227
   736
				CHECK_ARGS(0);
faluco@227
   737
				char *str;
dvander@535
   738
				int err;
dvander@535
   739
				if ((err=pCtx->LocalToString(params[arg], &str)) != SP_ERROR_NONE)
dvander@535
   740
				{
dvander@535
   741
					pCtx->ThrowNativeErrorEx(err, "Could not deference string");
dvander@535
   742
					return 0;
dvander@535
   743
				}
faluco@227
   744
				AddString(&buf_p, llen, str, width, prec);
faluco@227
   745
				arg++;
faluco@227
   746
				break;
faluco@227
   747
			}
faluco@389
   748
		case 'T':
faluco@389
   749
			{
faluco@389
   750
				CHECK_ARGS(0);
faluco@389
   751
				char *key;
faluco@422
   752
				bool error;
faluco@422
   753
				size_t res;
faluco@389
   754
				cell_t target = params[arg++];
faluco@389
   755
				pCtx->LocalToString(params[arg++], &key);
faluco@422
   756
				res = Translate(buf_p, llen, pCtx, key, target, params, &arg, &error);
faluco@422
   757
				if (error)
faluco@422
   758
				{
faluco@422
   759
					return 0;
faluco@422
   760
				}
faluco@422
   761
				buf_p += res;
faluco@422
   762
				llen -= res;
faluco@422
   763
				break;
faluco@422
   764
			}
faluco@422
   765
		case 't':
faluco@422
   766
			{
faluco@422
   767
				CHECK_ARGS(0);
faluco@422
   768
				char *key;
faluco@422
   769
				bool error;
faluco@422
   770
				size_t res;
faluco@422
   771
				cell_t target = g_SourceMod.GetGlobalTarget();
faluco@422
   772
				pCtx->LocalToString(params[arg++], &key);
faluco@422
   773
				res = Translate(buf_p, llen, pCtx, key, target, params, &arg, &error);
faluco@422
   774
				if (error)
faluco@422
   775
				{
faluco@422
   776
					return 0;
faluco@422
   777
				}
faluco@422
   778
				buf_p += res;
faluco@422
   779
				llen -= res;
faluco@389
   780
				break;
faluco@389
   781
			}
ds@544
   782
		case 'X':
ds@544
   783
			{
ds@544
   784
				CHECK_ARGS(0);
ds@544
   785
				cell_t *value;
ds@544
   786
				pCtx->LocalToPhysAddr(params[arg], &value);
ds@544
   787
				flags |= UPPERDIGITS;
ds@544
   788
				AddHex(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
ds@544
   789
				arg++;
ds@544
   790
				break;
ds@544
   791
			}
ds@544
   792
		case 'x':
ds@544
   793
			{
ds@544
   794
				CHECK_ARGS(0);
ds@544
   795
				cell_t *value;
ds@544
   796
				pCtx->LocalToPhysAddr(params[arg], &value);
ds@544
   797
				AddHex(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
ds@544
   798
				arg++;
ds@544
   799
				break;
ds@544
   800
			}
faluco@227
   801
		case '%':
faluco@227
   802
			{
faluco@230
   803
				if (!llen)
faluco@227
   804
				{
faluco@227
   805
					goto done;
faluco@227
   806
				}
faluco@227
   807
				*buf_p++ = ch;
faluco@227
   808
				llen--;
faluco@227
   809
				break;
faluco@227
   810
			}
faluco@227
   811
		case '\0':
faluco@227
   812
			{
faluco@230
   813
				if (!llen)
faluco@227
   814
				{
faluco@227
   815
					goto done;
faluco@227
   816
				}
faluco@227
   817
				*buf_p++ = '%';
faluco@227
   818
				llen--;
faluco@227
   819
				goto done;
faluco@227
   820
			}
faluco@227
   821
		default:
faluco@227
   822
			{
faluco@230
   823
				if (!llen)
faluco@227
   824
				{
faluco@227
   825
					goto done;
faluco@227
   826
				}
faluco@227
   827
				*buf_p++ = ch;
faluco@227
   828
				llen--;
faluco@227
   829
				break;
faluco@227
   830
			}
faluco@227
   831
		}
faluco@227
   832
	}
faluco@227
   833
faluco@227
   834
done:
faluco@227
   835
	*buf_p = '\0';
faluco@227
   836
	*param = arg;
faluco@236
   837
	return (maxlen - llen - 1);
faluco@227
   838
}
faluco@230
   839
faluco@230
   840
const char *stristr(const char *str, const char *substr)
faluco@230
   841
{
faluco@230
   842
	if (!*substr)
faluco@230
   843
	{
faluco@230
   844
		return ((char *)str);
faluco@230
   845
	}
faluco@230
   846
faluco@230
   847
	char *needle = (char *)substr;
faluco@230
   848
	char *prevloc = (char *)str;
faluco@230
   849
	char *haystack = (char *)str;
faluco@230
   850
faluco@230
   851
	while (*haystack)
faluco@230
   852
	{
faluco@230
   853
		if (tolower(*haystack) == tolower(*needle))
faluco@230
   854
		{
faluco@230
   855
			haystack++;
faluco@230
   856
			if (!*++needle)
faluco@230
   857
			{
faluco@230
   858
				return prevloc;
faluco@230
   859
			}
faluco@230
   860
		} else {
faluco@230
   861
			haystack = ++prevloc;
faluco@230
   862
			needle = (char *)substr;
faluco@230
   863
		}
faluco@230
   864
	}
faluco@230
   865
faluco@230
   866
	return NULL;
faluco@230
   867
}
faluco@230
   868
dvander@233
   869
unsigned int strncopy(char *dest, const char *src, size_t count)
faluco@230
   870
{
faluco@230
   871
	if (!count)
faluco@230
   872
	{
faluco@230
   873
		return 0;
faluco@230
   874
	}
faluco@230
   875
faluco@230
   876
	char *start = dest;
faluco@230
   877
	while ((*src) && (--count))
faluco@230
   878
	{
faluco@230
   879
		*dest++ = *src++;
faluco@230
   880
	}
faluco@230
   881
	*dest = '\0';
faluco@230
   882
faluco@230
   883
	return (dest - start);
faluco@230
   884
}
faluco@274
   885
faluco@274
   886
size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
faluco@274
   887
{
faluco@274
   888
	va_list ap;
faluco@274
   889
	va_start(ap, fmt);
faluco@274
   890
	size_t len = vsnprintf(buffer, maxlength, fmt, ap);
faluco@274
   891
	va_end(ap);
faluco@274
   892
faluco@274
   893
	return (len >= maxlength) ? (maxlength - 1) : len;
dvander@351
   894
}
dvander@351
   895
ds@504
   896
char *sm_strdup(const char *str)
ds@504
   897
{
ds@504
   898
	char *ptr = new char[strlen(str)+1];
ds@504
   899
	strcpy(ptr, str);
ds@504
   900
	return ptr;
ds@504
   901
}