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