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