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