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