core/sm_stringutil.cpp
author Borja Ferrer <faluco@alliedmods.net>
Fri Dec 29 23:28:44 2006 +0000 (2006-12-29)
changeset 230 f6abafc7c96c
parent 227 72ab30bba3b9
child 233 968f92668138
permissions -rw-r--r--
fixed a "-1" bug in atcprintf
moved string functions to the stringutils file
added strncopy
faluco@230
     1
#include <stdlib.h>
faluco@230
     2
#include <ctype.h>
faluco@227
     3
#include "sm_stringutil.h"
faluco@227
     4
faluco@227
     5
#define ALT				0x00000001		/* alternate form */
faluco@227
     6
#define HEXPREFIX		0x00000002		/* add 0x or 0X prefix */
faluco@227
     7
#define LADJUST			0x00000004		/* left adjustment */
faluco@227
     8
#define LONGDBL			0x00000008		/* long double */
faluco@227
     9
#define LONGINT			0x00000010		/* long integer */
faluco@227
    10
#define QUADINT			0x00000020		/* quad integer */
faluco@227
    11
#define SHORTINT		0x00000040		/* short integer */
faluco@227
    12
#define ZEROPAD			0x00000080		/* zero (as opposed to blank) pad */
faluco@227
    13
#define FPT				0x00000100		/* floating point number */
faluco@227
    14
#define to_digit(c)		((c) - '0')
faluco@227
    15
#define is_digit(c)		((unsigned)to_digit(c) <= 9)
faluco@227
    16
#define to_char(n)		((n) + '0')
faluco@227
    17
faluco@227
    18
//:TODO: fix this macro when we have a debugger
faluco@227
    19
faluco@227
    20
#define CHECK_ARGS(n)/* \
faluco@227
    21
	if ((arg+n) > args) { \
faluco@227
    22
	LogError(amx, AMX_ERR_PARAMS, "String formatted incorrectly - parameter %d (total %d)", arg, args); \
faluco@227
    23
	return 0; \
faluco@227
    24
	}
faluco@227
    25
*/
faluco@227
    26
faluco@227
    27
void AddString(char **buf_p, size_t &maxlen, const char *string, int width, int prec)
faluco@227
    28
{
faluco@227
    29
	int size = 0;
faluco@227
    30
	char *buf;
faluco@227
    31
	static char nlstr[] = {'(','n','u','l','l',')','\0'};
faluco@227
    32
faluco@227
    33
	buf = *buf_p;
faluco@227
    34
faluco@227
    35
	if (string == NULL)
faluco@227
    36
	{
faluco@227
    37
		string = nlstr;
faluco@227
    38
		prec = -1;
faluco@227
    39
	}
faluco@227
    40
faluco@227
    41
	if (prec >= 0)
faluco@227
    42
	{
faluco@227
    43
		for (size = 0; size < prec; size++) 
faluco@227
    44
		{
faluco@227
    45
			if (string[size] == '\0')
faluco@227
    46
			{
faluco@227
    47
				break;
faluco@227
    48
			}
faluco@227
    49
		}
faluco@227
    50
	} else {
faluco@227
    51
		while (string[size++]);
faluco@227
    52
		size--;
faluco@227
    53
	}
faluco@227
    54
faluco@227
    55
	if (size > (int)maxlen)
faluco@227
    56
	{
faluco@227
    57
		size = maxlen;
faluco@227
    58
	}
faluco@227
    59
faluco@227
    60
	maxlen -= size;
faluco@227
    61
	width -= size;
faluco@227
    62
faluco@227
    63
	while (size--)
faluco@227
    64
	{
faluco@227
    65
		*buf++ = *string++;
faluco@227
    66
	}
faluco@227
    67
faluco@227
    68
	while ((width-- > 0) && maxlen)
faluco@227
    69
	{
faluco@227
    70
		*buf++ = ' ';
faluco@227
    71
		maxlen--;
faluco@227
    72
	}
faluco@227
    73
faluco@227
    74
	*buf_p = buf;
faluco@227
    75
}
faluco@227
    76
faluco@227
    77
void AddFloat(char **buf_p, size_t &maxlen, double fval, int width, int prec)
faluco@227
    78
{
faluco@227
    79
	char text[32];
faluco@227
    80
	int digits;
faluco@227
    81
	double signedVal;
faluco@227
    82
	char *buf;
faluco@227
    83
	int val;
faluco@227
    84
faluco@227
    85
	// get the sign
faluco@227
    86
	signedVal = fval;
faluco@227
    87
	if (fval < 0)
faluco@227
    88
	{
faluco@227
    89
		fval = -fval;
faluco@227
    90
	}
faluco@227
    91
faluco@227
    92
	// write the float number
faluco@227
    93
	digits = 0;
faluco@227
    94
	val = (int)fval;
faluco@227
    95
	do
faluco@227
    96
	{
faluco@227
    97
		text[digits++] = '0' + val % 10;
faluco@227
    98
		val /= 10;
faluco@227
    99
	} while (val);
faluco@227
   100
faluco@227
   101
	if (signedVal < 0)
faluco@227
   102
	{
faluco@227
   103
		text[digits++] = '-';
faluco@227
   104
	}
faluco@227
   105
faluco@227
   106
	buf = *buf_p;
faluco@227
   107
faluco@227
   108
	while ((digits < width) && maxlen)
faluco@227
   109
	{
faluco@227
   110
		*buf++ = ' ';
faluco@227
   111
		width--;
faluco@227
   112
		maxlen--;
faluco@227
   113
	}
faluco@227
   114
faluco@227
   115
	while ((digits--) && maxlen)
faluco@227
   116
	{
faluco@227
   117
		*buf++ = text[digits];
faluco@227
   118
		maxlen--;
faluco@227
   119
	}
faluco@227
   120
faluco@227
   121
	*buf_p = buf;
faluco@227
   122
faluco@227
   123
	if (prec < 0)
faluco@227
   124
	{
faluco@227
   125
		prec = 6;
faluco@227
   126
	}
faluco@227
   127
	// write the fraction
faluco@227
   128
	digits = 0;
faluco@227
   129
	while (digits < prec)
faluco@227
   130
	{
faluco@227
   131
		fval -= (int)fval;
faluco@227
   132
		fval *= 10.0;
faluco@227
   133
		val = (int)fval;
faluco@227
   134
		text[digits++] = '0' + val % 10;
faluco@227
   135
	}
faluco@227
   136
faluco@227
   137
	if ((digits > 0) && maxlen)
faluco@227
   138
	{
faluco@227
   139
		buf = *buf_p;
faluco@227
   140
		*buf++ = '.';
faluco@227
   141
		maxlen--;
faluco@227
   142
		for (prec = 0; maxlen && (prec < digits); prec++)
faluco@227
   143
		{
faluco@227
   144
			*buf++ = text[prec];
faluco@227
   145
			maxlen--;
faluco@227
   146
		}
faluco@227
   147
		*buf_p = buf;
faluco@227
   148
	}
faluco@227
   149
}
faluco@227
   150
faluco@227
   151
void AddUInt(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
faluco@227
   152
{
faluco@227
   153
	char text[32];
faluco@227
   154
	int digits;
faluco@227
   155
	char *buf;
faluco@227
   156
faluco@227
   157
	digits = 0;
faluco@227
   158
	do
faluco@227
   159
	{
faluco@227
   160
		text[digits++] = '0' + val % 10;
faluco@227
   161
		val /= 10;
faluco@227
   162
	} while (val);
faluco@227
   163
faluco@227
   164
	buf = *buf_p;
faluco@227
   165
faluco@227
   166
	if (!(flags & LADJUST))
faluco@227
   167
	{
faluco@227
   168
		while (digits < width && maxlen)
faluco@227
   169
		{
faluco@227
   170
			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
faluco@227
   171
			width--;
faluco@227
   172
			maxlen--;
faluco@227
   173
		}
faluco@227
   174
	}
faluco@227
   175
faluco@227
   176
	while (digits-- && maxlen)
faluco@227
   177
	{
faluco@227
   178
		*buf++ = text[digits];
faluco@227
   179
		width--;
faluco@227
   180
		maxlen--;
faluco@227
   181
	}
faluco@227
   182
faluco@227
   183
	if (flags & LADJUST)
faluco@227
   184
	{
faluco@227
   185
		while (width-- && maxlen)
faluco@227
   186
		{
faluco@227
   187
			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
faluco@227
   188
			maxlen--;
faluco@227
   189
		}
faluco@227
   190
	}
faluco@227
   191
faluco@227
   192
	*buf_p = buf;
faluco@227
   193
}
faluco@227
   194
faluco@227
   195
void AddInt(char **buf_p, size_t &maxlen, int val, int width, int flags)
faluco@227
   196
{
faluco@227
   197
	char text[32];
faluco@227
   198
	int digits;
faluco@227
   199
	int signedVal;
faluco@227
   200
	char *buf;
faluco@227
   201
	unsigned int unsignedVal;
faluco@227
   202
faluco@227
   203
	digits = 0;
faluco@227
   204
	signedVal = val;
faluco@227
   205
	if (val < 0)
faluco@227
   206
	{
faluco@227
   207
		/* we want the unsigned version */
faluco@227
   208
		unsignedVal = abs(val);
faluco@227
   209
	} else {
faluco@227
   210
		unsignedVal = val;
faluco@227
   211
	}
faluco@227
   212
	do
faluco@227
   213
	{
faluco@227
   214
		text[digits++] = '0' + unsignedVal % 10;
faluco@227
   215
		unsignedVal /= 10;
faluco@227
   216
	} while (unsignedVal);
faluco@227
   217
faluco@227
   218
	if (signedVal < 0)
faluco@227
   219
	{
faluco@227
   220
		text[digits++] = '-';
faluco@227
   221
	}
faluco@227
   222
faluco@227
   223
	buf = *buf_p;
faluco@227
   224
faluco@227
   225
	if (!(flags & LADJUST))
faluco@227
   226
	{
faluco@227
   227
		while ((digits < width) && maxlen)
faluco@227
   228
		{
faluco@227
   229
			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
faluco@227
   230
			width--;
faluco@227
   231
			maxlen--;
faluco@227
   232
		}
faluco@227
   233
	}
faluco@227
   234
faluco@227
   235
	while (digits-- && maxlen)
faluco@227
   236
	{
faluco@227
   237
		*buf++ = text[digits];
faluco@227
   238
		width--;
faluco@227
   239
		maxlen--;
faluco@227
   240
	}
faluco@227
   241
faluco@227
   242
	if (flags & LADJUST)
faluco@227
   243
	{
faluco@227
   244
		while (width-- && maxlen)
faluco@227
   245
		{
faluco@227
   246
			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
faluco@227
   247
			maxlen--;
faluco@227
   248
		}
faluco@227
   249
	}
faluco@227
   250
faluco@227
   251
	*buf_p = buf;
faluco@227
   252
}
faluco@227
   253
faluco@227
   254
size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext *pCtx, const cell_t *params, int *param)
faluco@227
   255
{
faluco@227
   256
	int arg;
faluco@227
   257
	//int args = params[0] / sizeof(cell); //:TODO: wrong, i think params[0] has now the param count not the byte count
faluco@227
   258
	// either way this is only used when the above macro is fixed, until then not needed
faluco@227
   259
	char *buf_p;
faluco@227
   260
	char ch;
faluco@227
   261
	int flags;
faluco@227
   262
	int width;
faluco@227
   263
	int prec;
faluco@227
   264
	int n;
faluco@227
   265
	char sign;
faluco@227
   266
	const char *fmt;
faluco@230
   267
	size_t llen = maxlen - 1;
faluco@227
   268
faluco@227
   269
	buf_p = buffer;
faluco@227
   270
	arg = *param;
faluco@227
   271
	fmt = format;
faluco@227
   272
faluco@227
   273
	while (true)
faluco@227
   274
	{
faluco@227
   275
		// run through the format string until we hit a '%' or '\0'
faluco@227
   276
		for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
faluco@227
   277
		{
faluco@227
   278
			*buf_p++ = ch;
faluco@227
   279
			llen--;
faluco@227
   280
		}
faluco@227
   281
		if ((ch == '\0') || (llen <= 0))
faluco@227
   282
		{
faluco@227
   283
			goto done;
faluco@227
   284
		}
faluco@227
   285
faluco@227
   286
		// skip over the '%'
faluco@227
   287
		fmt++;
faluco@227
   288
faluco@227
   289
		// reset formatting state
faluco@227
   290
		flags = 0;
faluco@227
   291
		width = 0;
faluco@227
   292
		prec = -1;
faluco@227
   293
		sign = '\0';
faluco@227
   294
faluco@227
   295
rflag:
faluco@227
   296
		ch = *fmt++;
faluco@227
   297
reswitch:
faluco@227
   298
		switch(ch)
faluco@227
   299
		{
faluco@227
   300
		case '-':
faluco@227
   301
			{
faluco@227
   302
				flags |= LADJUST;
faluco@227
   303
				goto rflag;
faluco@227
   304
			}
faluco@227
   305
		case '.':
faluco@227
   306
			{
faluco@227
   307
				n = 0;
faluco@227
   308
				while(is_digit((ch = *fmt++)))
faluco@227
   309
				{
faluco@227
   310
					n = 10 * n + (ch - '0');
faluco@227
   311
				}
faluco@227
   312
				prec = (n < 0) ? -1 : n;
faluco@227
   313
				goto reswitch;
faluco@227
   314
			}
faluco@227
   315
		case '0':
faluco@227
   316
			{
faluco@227
   317
				flags |= ZEROPAD;
faluco@227
   318
				goto rflag;
faluco@227
   319
			}
faluco@227
   320
		case '1':
faluco@227
   321
		case '2':
faluco@227
   322
		case '3':
faluco@227
   323
		case '4':
faluco@227
   324
		case '5':
faluco@227
   325
		case '6':
faluco@227
   326
		case '7':
faluco@227
   327
		case '8':
faluco@227
   328
		case '9':
faluco@227
   329
			{
faluco@227
   330
				n = 0;
faluco@227
   331
				do
faluco@227
   332
				{
faluco@227
   333
					n = 10 * n + (ch - '0');
faluco@227
   334
					ch = *fmt++;
faluco@227
   335
				} while(is_digit(ch));
faluco@227
   336
				width = n;
faluco@227
   337
				goto reswitch;
faluco@227
   338
			}
faluco@227
   339
		case 'c':
faluco@227
   340
			{
faluco@227
   341
				CHECK_ARGS(0);
faluco@230
   342
				if (!llen)
faluco@227
   343
				{
faluco@227
   344
					goto done;
faluco@227
   345
				}
faluco@227
   346
				char *c;
faluco@227
   347
				pCtx->LocalToString(params[arg], &c);
faluco@227
   348
				*buf_p++ = *c;
faluco@227
   349
				llen--;
faluco@227
   350
				arg++;
faluco@227
   351
				break;
faluco@227
   352
			}
faluco@227
   353
		case 'd':
faluco@227
   354
		case 'i':
faluco@227
   355
			{
faluco@227
   356
				CHECK_ARGS(0);
faluco@227
   357
				cell_t *value;
faluco@227
   358
				pCtx->LocalToPhysAddr(params[arg], &value);
faluco@227
   359
				AddInt(&buf_p, llen, static_cast<int>(*value), width, flags);
faluco@227
   360
				arg++;
faluco@227
   361
				break;
faluco@227
   362
			}
faluco@227
   363
		case 'u':
faluco@227
   364
			{
faluco@227
   365
				CHECK_ARGS(0);
faluco@227
   366
				cell_t *value;
faluco@227
   367
				pCtx->LocalToPhysAddr(params[arg], &value);
faluco@227
   368
				AddUInt(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
faluco@227
   369
				arg++;
faluco@227
   370
				break;
faluco@227
   371
			}
faluco@227
   372
		case 'f':
faluco@227
   373
			{
faluco@227
   374
				CHECK_ARGS(0);
faluco@227
   375
				cell_t *value;
faluco@227
   376
				pCtx->LocalToPhysAddr(params[arg], &value);
faluco@227
   377
				AddFloat(&buf_p, llen, ctof(*value), width, prec);
faluco@227
   378
				arg++;
faluco@227
   379
				break;
faluco@227
   380
			}
faluco@227
   381
		case 's':
faluco@227
   382
			{
faluco@227
   383
				CHECK_ARGS(0);
faluco@227
   384
				char *str;
faluco@227
   385
				pCtx->LocalToString(params[arg], &str);
faluco@227
   386
				AddString(&buf_p, llen, str, width, prec);
faluco@227
   387
				arg++;
faluco@227
   388
				break;
faluco@227
   389
			}
faluco@227
   390
		case '%':
faluco@227
   391
			{
faluco@230
   392
				if (!llen)
faluco@227
   393
				{
faluco@227
   394
					goto done;
faluco@227
   395
				}
faluco@227
   396
				*buf_p++ = ch;
faluco@227
   397
				llen--;
faluco@227
   398
				break;
faluco@227
   399
			}
faluco@227
   400
		case '\0':
faluco@227
   401
			{
faluco@230
   402
				if (!llen)
faluco@227
   403
				{
faluco@227
   404
					goto done;
faluco@227
   405
				}
faluco@227
   406
				*buf_p++ = '%';
faluco@227
   407
				llen--;
faluco@227
   408
				goto done;
faluco@227
   409
			}
faluco@227
   410
		default:
faluco@227
   411
			{
faluco@230
   412
				if (!llen)
faluco@227
   413
				{
faluco@227
   414
					goto done;
faluco@227
   415
				}
faluco@227
   416
				*buf_p++ = ch;
faluco@227
   417
				llen--;
faluco@227
   418
				break;
faluco@227
   419
			}
faluco@227
   420
		}
faluco@227
   421
	}
faluco@227
   422
faluco@227
   423
done:
faluco@227
   424
	*buf_p = '\0';
faluco@227
   425
	*param = arg;
faluco@227
   426
	return (maxlen - llen);
faluco@227
   427
}
faluco@230
   428
faluco@230
   429
const char *stristr(const char *str, const char *substr)
faluco@230
   430
{
faluco@230
   431
	if (!*substr)
faluco@230
   432
	{
faluco@230
   433
		return ((char *)str);
faluco@230
   434
	}
faluco@230
   435
faluco@230
   436
	char *needle = (char *)substr;
faluco@230
   437
	char *prevloc = (char *)str;
faluco@230
   438
	char *haystack = (char *)str;
faluco@230
   439
faluco@230
   440
	while (*haystack)
faluco@230
   441
	{
faluco@230
   442
		if (tolower(*haystack) == tolower(*needle))
faluco@230
   443
		{
faluco@230
   444
			haystack++;
faluco@230
   445
			if (!*++needle)
faluco@230
   446
			{
faluco@230
   447
				return prevloc;
faluco@230
   448
			}
faluco@230
   449
		} else {
faluco@230
   450
			haystack = ++prevloc;
faluco@230
   451
			needle = (char *)substr;
faluco@230
   452
		}
faluco@230
   453
	}
faluco@230
   454
faluco@230
   455
	return NULL;
faluco@230
   456
}
faluco@230
   457
faluco@230
   458
inline int StrConvInt(const char *str)
faluco@230
   459
{
faluco@230
   460
	char *dummy;
faluco@230
   461
	return strtol(str, &dummy, 10);
faluco@230
   462
}
faluco@230
   463
faluco@230
   464
inline float StrConvFloat(const char *str)
faluco@230
   465
{
faluco@230
   466
	char *dummy;
faluco@230
   467
	return (float)strtod(str, &dummy);
faluco@230
   468
}
faluco@230
   469
faluco@230
   470
int strncopy(char *dest, const char *src, size_t count)
faluco@230
   471
{
faluco@230
   472
	if (!count)
faluco@230
   473
	{
faluco@230
   474
		return 0;
faluco@230
   475
	}
faluco@230
   476
faluco@230
   477
	char *start = dest;
faluco@230
   478
	while ((*src) && (--count))
faluco@230
   479
	{
faluco@230
   480
		*dest++ = *src++;
faluco@230
   481
	}
faluco@230
   482
	*dest = '\0';
faluco@230
   483
faluco@230
   484
	return (dest - start);
faluco@230
   485
}