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