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