core/sm_stringutil.cpp
author Borja Ferrer <faluco@alliedmods.net>
Fri Jan 12 23:56:02 2007 +0000 (2007-01-12)
changeset 288 d89bf250dac4
parent 276 065d151c41b2
child 351 7c219cde57e7
permissions -rw-r--r--
Added new debugger logger
Added format errors
Paused plugins now have their forwards blocked
Fixed bug where pausing a plugin wouldnt make any effect
     1 #include <stdlib.h>
     2 #include <ctype.h>
     3 #include <stdarg.h>
     4 #include "sm_stringutil.h"
     5 #include "CLogger.h"
     6 
     7 #define LADJUST			0x00000004		/* left adjustment */
     8 #define ZEROPAD			0x00000080		/* zero (as opposed to blank) pad */
     9 #define to_digit(c)		((c) - '0')
    10 #define is_digit(c)		((unsigned)to_digit(c) <= 9)
    11 
    12 #define CHECK_ARGS(x) \
    13 	if ((arg+x) > args) { \
    14 		g_Logger.LogError("String formatted incorrectly - parameter %d (total %d)", arg, args); \
    15 		return 0; \
    16 	}
    17 
    18 //:TODO: review this code before we choose a license
    19 
    20 void AddString(char **buf_p, size_t &maxlen, const char *string, int width, int prec)
    21 {
    22 	int size = 0;
    23 	char *buf;
    24 	static char nlstr[] = {'(','n','u','l','l',')','\0'};
    25 
    26 	buf = *buf_p;
    27 
    28 	if (string == NULL)
    29 	{
    30 		string = nlstr;
    31 		prec = -1;
    32 	}
    33 
    34 	if (prec >= 0)
    35 	{
    36 		for (size = 0; size < prec; size++) 
    37 		{
    38 			if (string[size] == '\0')
    39 			{
    40 				break;
    41 			}
    42 		}
    43 	} else {
    44 		while (string[size++]);
    45 		size--;
    46 	}
    47 
    48 	if (size > (int)maxlen)
    49 	{
    50 		size = maxlen;
    51 	}
    52 
    53 	maxlen -= size;
    54 	width -= size;
    55 
    56 	while (size--)
    57 	{
    58 		*buf++ = *string++;
    59 	}
    60 
    61 	while ((width-- > 0) && maxlen)
    62 	{
    63 		*buf++ = ' ';
    64 		maxlen--;
    65 	}
    66 
    67 	*buf_p = buf;
    68 }
    69 
    70 void AddFloat(char **buf_p, size_t &maxlen, double fval, int width, int prec)
    71 {
    72 	char text[32];
    73 	int digits;
    74 	double signedVal;
    75 	char *buf;
    76 	int val;
    77 
    78 	// get the sign
    79 	signedVal = fval;
    80 	if (fval < 0)
    81 	{
    82 		fval = -fval;
    83 	}
    84 
    85 	// write the float number
    86 	digits = 0;
    87 	val = (int)fval;
    88 	do
    89 	{
    90 		text[digits++] = '0' + val % 10;
    91 		val /= 10;
    92 	} while (val);
    93 
    94 	if (signedVal < 0)
    95 	{
    96 		text[digits++] = '-';
    97 	}
    98 
    99 	buf = *buf_p;
   100 
   101 	while ((digits < width) && maxlen)
   102 	{
   103 		*buf++ = ' ';
   104 		width--;
   105 		maxlen--;
   106 	}
   107 
   108 	while ((digits--) && maxlen)
   109 	{
   110 		*buf++ = text[digits];
   111 		maxlen--;
   112 	}
   113 
   114 	*buf_p = buf;
   115 
   116 	if (prec < 0)
   117 	{
   118 		prec = 6;
   119 	}
   120 	// write the fraction
   121 	digits = 0;
   122 	while (digits < prec)
   123 	{
   124 		fval -= (int)fval;
   125 		fval *= 10.0;
   126 		val = (int)fval;
   127 		text[digits++] = '0' + val % 10;
   128 	}
   129 
   130 	if ((digits > 0) && maxlen)
   131 	{
   132 		buf = *buf_p;
   133 		*buf++ = '.';
   134 		maxlen--;
   135 		for (prec = 0; maxlen && (prec < digits); prec++)
   136 		{
   137 			*buf++ = text[prec];
   138 			maxlen--;
   139 		}
   140 		*buf_p = buf;
   141 	}
   142 }
   143 
   144 void AddUInt(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
   145 {
   146 	char text[32];
   147 	int digits;
   148 	char *buf;
   149 
   150 	digits = 0;
   151 	do
   152 	{
   153 		text[digits++] = '0' + val % 10;
   154 		val /= 10;
   155 	} while (val);
   156 
   157 	buf = *buf_p;
   158 
   159 	if (!(flags & LADJUST))
   160 	{
   161 		while (digits < width && maxlen)
   162 		{
   163 			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
   164 			width--;
   165 			maxlen--;
   166 		}
   167 	}
   168 
   169 	while (digits-- && maxlen)
   170 	{
   171 		*buf++ = text[digits];
   172 		width--;
   173 		maxlen--;
   174 	}
   175 
   176 	if (flags & LADJUST)
   177 	{
   178 		while (width-- && maxlen)
   179 		{
   180 			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
   181 			maxlen--;
   182 		}
   183 	}
   184 
   185 	*buf_p = buf;
   186 }
   187 
   188 void AddInt(char **buf_p, size_t &maxlen, int val, int width, int flags)
   189 {
   190 	char text[32];
   191 	int digits;
   192 	int signedVal;
   193 	char *buf;
   194 	unsigned int unsignedVal;
   195 
   196 	digits = 0;
   197 	signedVal = val;
   198 	if (val < 0)
   199 	{
   200 		/* we want the unsigned version */
   201 		unsignedVal = abs(val);
   202 	} else {
   203 		unsignedVal = val;
   204 	}
   205 	do
   206 	{
   207 		text[digits++] = '0' + unsignedVal % 10;
   208 		unsignedVal /= 10;
   209 	} while (unsignedVal);
   210 
   211 	if (signedVal < 0)
   212 	{
   213 		text[digits++] = '-';
   214 	}
   215 
   216 	buf = *buf_p;
   217 
   218 	if (!(flags & LADJUST))
   219 	{
   220 		while ((digits < width) && maxlen)
   221 		{
   222 			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
   223 			width--;
   224 			maxlen--;
   225 		}
   226 	}
   227 
   228 	while (digits-- && maxlen)
   229 	{
   230 		*buf++ = text[digits];
   231 		width--;
   232 		maxlen--;
   233 	}
   234 
   235 	if (flags & LADJUST)
   236 	{
   237 		while (width-- && maxlen)
   238 		{
   239 			*buf++ = (flags & ZEROPAD) ? '0' : ' ';
   240 			maxlen--;
   241 		}
   242 	}
   243 
   244 	*buf_p = buf;
   245 }
   246 
   247 size_t gnprintf(char *buffer, size_t maxlen, const char *format, void **args)
   248 {
   249 	if (!buffer || !maxlen)
   250 	{
   251 		return 0;
   252 	}
   253 
   254 	int arg = 0;
   255 	char *buf_p;
   256 	char ch;
   257 	int flags;
   258 	int width;
   259 	int prec;
   260 	int n;
   261 	char sign;
   262 	const char *fmt;
   263 	size_t llen = maxlen - 1;
   264 
   265 	buf_p = buffer;
   266 	fmt = format;
   267 
   268 	while (true)
   269 	{
   270 		// run through the format string until we hit a '%' or '\0'
   271 		for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
   272 		{
   273 			*buf_p++ = ch;
   274 			llen--;
   275 		}
   276 		if ((ch == '\0') || (llen <= 0))
   277 		{
   278 			goto done;
   279 		}
   280 
   281 		// skip over the '%'
   282 		fmt++;
   283 
   284 		// reset formatting state
   285 		flags = 0;
   286 		width = 0;
   287 		prec = -1;
   288 		sign = '\0';
   289 
   290 rflag:
   291 		ch = *fmt++;
   292 reswitch:
   293 		switch(ch)
   294 		{
   295 		case '-':
   296 			{
   297 				flags |= LADJUST;
   298 				goto rflag;
   299 			}
   300 		case '.':
   301 			{
   302 				n = 0;
   303 				while(is_digit((ch = *fmt++)))
   304 				{
   305 					n = 10 * n + (ch - '0');
   306 				}
   307 				prec = (n < 0) ? -1 : n;
   308 				goto reswitch;
   309 			}
   310 		case '0':
   311 			{
   312 				flags |= ZEROPAD;
   313 				goto rflag;
   314 			}
   315 		case '1':
   316 		case '2':
   317 		case '3':
   318 		case '4':
   319 		case '5':
   320 		case '6':
   321 		case '7':
   322 		case '8':
   323 		case '9':
   324 			{
   325 				n = 0;
   326 				do
   327 				{
   328 					n = 10 * n + (ch - '0');
   329 					ch = *fmt++;
   330 				} while(is_digit(ch));
   331 				width = n;
   332 				goto reswitch;
   333 			}
   334 		case 'c':
   335 			{
   336 				if (!llen)
   337 				{
   338 					goto done;
   339 				}
   340 				char *c = (char *)args[arg];
   341 				*buf_p++ = *c;
   342 				llen--;
   343 				arg++;
   344 				break;
   345 			}
   346 		case 'd':
   347 		case 'i':
   348 			{
   349 				int *value = (int *)args[arg];
   350 				AddInt(&buf_p, llen, *value, width, flags);
   351 				arg++;
   352 				break;
   353 			}
   354 		case 'u':
   355 			{
   356 				unsigned int *value = (unsigned int *)args[arg];
   357 				AddUInt(&buf_p, llen, *value, width, flags);
   358 				arg++;
   359 				break;
   360 			}
   361 		case 'f':
   362 			{
   363 				float *value = (float *)args[arg];
   364 				AddFloat(&buf_p, llen, *value, width, prec);
   365 				arg++;
   366 				break;
   367 			}
   368 		case 's':
   369 			{
   370 				const char *str = (const char *)args[arg];
   371 				AddString(&buf_p, llen, str, width, prec);
   372 				arg++;
   373 				break;
   374 			}
   375 		case '%':
   376 			{
   377 				if (!llen)
   378 				{
   379 					goto done;
   380 				}
   381 				*buf_p++ = ch;
   382 				llen--;
   383 				break;
   384 			}
   385 		case '\0':
   386 			{
   387 				if (!llen)
   388 				{
   389 					goto done;
   390 				}
   391 				*buf_p++ = '%';
   392 				llen--;
   393 				goto done;
   394 			}
   395 		default:
   396 			{
   397 				if (!llen)
   398 				{
   399 					goto done;
   400 				}
   401 				*buf_p++ = ch;
   402 				llen--;
   403 				break;
   404 			}
   405 		}
   406 	}
   407 
   408 done:
   409 	*buf_p = '\0';
   410 
   411 	return (maxlen - llen - 1);
   412 }
   413 
   414 size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext *pCtx, const cell_t *params, int *param)
   415 {
   416 	if (!buffer || !maxlen)
   417 	{
   418 		return 0;
   419 	}
   420 
   421 	int arg;
   422 	int args = params[0];
   423 	char *buf_p;
   424 	char ch;
   425 	int flags;
   426 	int width;
   427 	int prec;
   428 	int n;
   429 	char sign;
   430 	const char *fmt;
   431 	size_t llen = maxlen - 1;
   432 
   433 	buf_p = buffer;
   434 	arg = *param;
   435 	fmt = format;
   436 
   437 	while (true)
   438 	{
   439 		// run through the format string until we hit a '%' or '\0'
   440 		for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
   441 		{
   442 			*buf_p++ = ch;
   443 			llen--;
   444 		}
   445 		if ((ch == '\0') || (llen <= 0))
   446 		{
   447 			goto done;
   448 		}
   449 
   450 		// skip over the '%'
   451 		fmt++;
   452 
   453 		// reset formatting state
   454 		flags = 0;
   455 		width = 0;
   456 		prec = -1;
   457 		sign = '\0';
   458 
   459 rflag:
   460 		ch = *fmt++;
   461 reswitch:
   462 		switch(ch)
   463 		{
   464 		case '-':
   465 			{
   466 				flags |= LADJUST;
   467 				goto rflag;
   468 			}
   469 		case '.':
   470 			{
   471 				n = 0;
   472 				while(is_digit((ch = *fmt++)))
   473 				{
   474 					n = 10 * n + (ch - '0');
   475 				}
   476 				prec = (n < 0) ? -1 : n;
   477 				goto reswitch;
   478 			}
   479 		case '0':
   480 			{
   481 				flags |= ZEROPAD;
   482 				goto rflag;
   483 			}
   484 		case '1':
   485 		case '2':
   486 		case '3':
   487 		case '4':
   488 		case '5':
   489 		case '6':
   490 		case '7':
   491 		case '8':
   492 		case '9':
   493 			{
   494 				n = 0;
   495 				do
   496 				{
   497 					n = 10 * n + (ch - '0');
   498 					ch = *fmt++;
   499 				} while(is_digit(ch));
   500 				width = n;
   501 				goto reswitch;
   502 			}
   503 		case 'c':
   504 			{
   505 				CHECK_ARGS(0);
   506 				if (!llen)
   507 				{
   508 					goto done;
   509 				}
   510 				char *c;
   511 				pCtx->LocalToString(params[arg], &c);
   512 				*buf_p++ = *c;
   513 				llen--;
   514 				arg++;
   515 				break;
   516 			}
   517 		case 'd':
   518 		case 'i':
   519 			{
   520 				CHECK_ARGS(0);
   521 				cell_t *value;
   522 				pCtx->LocalToPhysAddr(params[arg], &value);
   523 				AddInt(&buf_p, llen, static_cast<int>(*value), width, flags);
   524 				arg++;
   525 				break;
   526 			}
   527 		case 'u':
   528 			{
   529 				CHECK_ARGS(0);
   530 				cell_t *value;
   531 				pCtx->LocalToPhysAddr(params[arg], &value);
   532 				AddUInt(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
   533 				arg++;
   534 				break;
   535 			}
   536 		case 'f':
   537 			{
   538 				CHECK_ARGS(0);
   539 				cell_t *value;
   540 				pCtx->LocalToPhysAddr(params[arg], &value);
   541 				AddFloat(&buf_p, llen, sp_ctof(*value), width, prec);
   542 				arg++;
   543 				break;
   544 			}
   545 		case 's':
   546 			{
   547 				CHECK_ARGS(0);
   548 				char *str;
   549 				pCtx->LocalToString(params[arg], &str);
   550 				AddString(&buf_p, llen, str, width, prec);
   551 				arg++;
   552 				break;
   553 			}
   554 		case '%':
   555 			{
   556 				if (!llen)
   557 				{
   558 					goto done;
   559 				}
   560 				*buf_p++ = ch;
   561 				llen--;
   562 				break;
   563 			}
   564 		case '\0':
   565 			{
   566 				if (!llen)
   567 				{
   568 					goto done;
   569 				}
   570 				*buf_p++ = '%';
   571 				llen--;
   572 				goto done;
   573 			}
   574 		default:
   575 			{
   576 				if (!llen)
   577 				{
   578 					goto done;
   579 				}
   580 				*buf_p++ = ch;
   581 				llen--;
   582 				break;
   583 			}
   584 		}
   585 	}
   586 
   587 done:
   588 	*buf_p = '\0';
   589 	*param = arg;
   590 	return (maxlen - llen - 1);
   591 }
   592 
   593 const char *stristr(const char *str, const char *substr)
   594 {
   595 	if (!*substr)
   596 	{
   597 		return ((char *)str);
   598 	}
   599 
   600 	char *needle = (char *)substr;
   601 	char *prevloc = (char *)str;
   602 	char *haystack = (char *)str;
   603 
   604 	while (*haystack)
   605 	{
   606 		if (tolower(*haystack) == tolower(*needle))
   607 		{
   608 			haystack++;
   609 			if (!*++needle)
   610 			{
   611 				return prevloc;
   612 			}
   613 		} else {
   614 			haystack = ++prevloc;
   615 			needle = (char *)substr;
   616 		}
   617 	}
   618 
   619 	return NULL;
   620 }
   621 
   622 unsigned int strncopy(char *dest, const char *src, size_t count)
   623 {
   624 	if (!count)
   625 	{
   626 		return 0;
   627 	}
   628 
   629 	char *start = dest;
   630 	while ((*src) && (--count))
   631 	{
   632 		*dest++ = *src++;
   633 	}
   634 	*dest = '\0';
   635 
   636 	return (dest - start);
   637 }
   638 
   639 size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
   640 {
   641 	va_list ap;
   642 	va_start(ap, fmt);
   643 	size_t len = vsnprintf(buffer, maxlength, fmt, ap);
   644 	va_end(ap);
   645 
   646 	return (len >= maxlength) ? (maxlength - 1) : len;
   647 }