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