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