| 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-- |
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 */
14 #include <stdlib.h>
15 #include <ctype.h>
16 #include <stdarg.h>
17 #include "sm_stringutil.h"
18 #include "CLogger.h"
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)
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 }
31 //:TODO: review this code before we choose a license
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'};
39 buf = *buf_p;
41 if (string == NULL)
42 {
43 string = nlstr;
44 prec = -1;
45 }
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 }
61 if (size > (int)maxlen)
62 {
63 size = maxlen;
64 }
66 maxlen -= size;
67 width -= size;
69 while (size--)
70 {
71 *buf++ = *string++;
72 }
74 while ((width-- > 0) && maxlen)
75 {
76 *buf++ = ' ';
77 maxlen--;
78 }
80 *buf_p = buf;
81 }
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;
91 // get the sign
92 signedVal = fval;
93 if (fval < 0)
94 {
95 fval = -fval;
96 }
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);
107 if (signedVal < 0)
108 {
109 text[digits++] = '-';
110 }
112 buf = *buf_p;
114 while ((digits < width) && maxlen)
115 {
116 *buf++ = ' ';
117 width--;
118 maxlen--;
119 }
121 while ((digits--) && maxlen)
122 {
123 *buf++ = text[digits];
124 maxlen--;
125 }
127 *buf_p = buf;
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 }
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 }
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;
163 digits = 0;
164 do
165 {
166 text[digits++] = '0' + val % 10;
167 val /= 10;
168 } while (val);
170 buf = *buf_p;
172 if (!(flags & LADJUST))
173 {
174 while (digits < width && maxlen)
175 {
176 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
177 width--;
178 maxlen--;
179 }
180 }
182 while (digits-- && maxlen)
183 {
184 *buf++ = text[digits];
185 width--;
186 maxlen--;
187 }
189 if (flags & LADJUST)
190 {
191 while (width-- && maxlen)
192 {
193 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
194 maxlen--;
195 }
196 }
198 *buf_p = buf;
199 }
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;
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);
224 if (signedVal < 0)
225 {
226 text[digits++] = '-';
227 }
229 buf = *buf_p;
231 if (!(flags & LADJUST))
232 {
233 while ((digits < width) && maxlen)
234 {
235 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
236 width--;
237 maxlen--;
238 }
239 }
241 while (digits-- && maxlen)
242 {
243 *buf++ = text[digits];
244 width--;
245 maxlen--;
246 }
248 if (flags & LADJUST)
249 {
250 while (width-- && maxlen)
251 {
252 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
253 maxlen--;
254 }
255 }
257 *buf_p = buf;
258 }
260 size_t gnprintf(char *buffer, size_t maxlen, const char *format, void **args)
261 {
262 if (!buffer || !maxlen)
263 {
264 return 0;
265 }
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;
278 buf_p = buffer;
279 fmt = format;
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 }
294 // skip over the '%'
295 fmt++;
297 // reset formatting state
298 flags = 0;
299 width = 0;
300 prec = -1;
301 sign = '\0';
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 }
421 done:
422 *buf_p = '\0';
424 return (maxlen - llen - 1);
425 }
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 }
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;
446 buf_p = buffer;
447 arg = *param;
448 fmt = format;
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 }
463 // skip over the '%'
464 fmt++;
466 // reset formatting state
467 flags = 0;
468 width = 0;
469 prec = -1;
470 sign = '\0';
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 }
600 done:
601 *buf_p = '\0';
602 *param = arg;
603 return (maxlen - llen - 1);
604 }
606 const char *stristr(const char *str, const char *substr)
607 {
608 if (!*substr)
609 {
610 return ((char *)str);
611 }
613 char *needle = (char *)substr;
614 char *prevloc = (char *)str;
615 char *haystack = (char *)str;
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 }
632 return NULL;
633 }
635 unsigned int strncopy(char *dest, const char *src, size_t count)
636 {
637 if (!count)
638 {
639 return 0;
640 }
642 char *start = dest;
643 while ((*src) && (--count))
644 {
645 *dest++ = *src++;
646 }
647 *dest = '\0';
649 return (dest - start);
650 }
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);
659 return (len >= maxlength) ? (maxlength - 1) : len;
660 }