From 6e7e89e9cffd0a467923efb2220b0cde76b65334 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Fri, 29 Dec 2006 03:21:09 +0000 Subject: [PATCH] added atcprintf --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40232 --- core/sm_stringutil.cpp | 425 +++++++++++++++++++++++++++++++++++++++++ core/sm_stringutil.h | 12 ++ 2 files changed, 437 insertions(+) create mode 100644 core/sm_stringutil.cpp create mode 100644 core/sm_stringutil.h diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp new file mode 100644 index 00000000..6b817cda --- /dev/null +++ b/core/sm_stringutil.cpp @@ -0,0 +1,425 @@ +#include "sm_stringutil.h" + +#define ALT 0x00000001 /* alternate form */ +#define HEXPREFIX 0x00000002 /* add 0x or 0X prefix */ +#define LADJUST 0x00000004 /* left adjustment */ +#define LONGDBL 0x00000008 /* long double */ +#define LONGINT 0x00000010 /* long integer */ +#define QUADINT 0x00000020 /* quad integer */ +#define SHORTINT 0x00000040 /* short integer */ +#define ZEROPAD 0x00000080 /* zero (as opposed to blank) pad */ +#define FPT 0x00000100 /* floating point number */ +#define to_digit(c) ((c) - '0') +#define is_digit(c) ((unsigned)to_digit(c) <= 9) +#define to_char(n) ((n) + '0') + +//:TODO: fix this macro when we have a debugger + +#define CHECK_ARGS(n)/* \ + if ((arg+n) > args) { \ + LogError(amx, AMX_ERR_PARAMS, "String formatted incorrectly - parameter %d (total %d)", arg, args); \ + return 0; \ + } +*/ + +void AddString(char **buf_p, size_t &maxlen, const char *string, int width, int prec) +{ + int size = 0; + char *buf; + static char nlstr[] = {'(','n','u','l','l',')','\0'}; + + buf = *buf_p; + + if (string == NULL) + { + string = nlstr; + prec = -1; + } + + if (prec >= 0) + { + for (size = 0; size < prec; size++) + { + if (string[size] == '\0') + { + break; + } + } + } else { + while (string[size++]); + size--; + } + + if (size > (int)maxlen) + { + size = maxlen; + } + + maxlen -= size; + width -= size; + + while (size--) + { + *buf++ = *string++; + } + + while ((width-- > 0) && maxlen) + { + *buf++ = ' '; + maxlen--; + } + + *buf_p = buf; +} + +void AddFloat(char **buf_p, size_t &maxlen, double fval, int width, int prec) +{ + char text[32]; + int digits; + double signedVal; + char *buf; + int val; + + // get the sign + signedVal = fval; + if (fval < 0) + { + fval = -fval; + } + + // write the float number + digits = 0; + val = (int)fval; + do + { + text[digits++] = '0' + val % 10; + val /= 10; + } while (val); + + if (signedVal < 0) + { + text[digits++] = '-'; + } + + buf = *buf_p; + + while ((digits < width) && maxlen) + { + *buf++ = ' '; + width--; + maxlen--; + } + + while ((digits--) && maxlen) + { + *buf++ = text[digits]; + maxlen--; + } + + *buf_p = buf; + + if (prec < 0) + { + prec = 6; + } + // write the fraction + digits = 0; + while (digits < prec) + { + fval -= (int)fval; + fval *= 10.0; + val = (int)fval; + text[digits++] = '0' + val % 10; + } + + if ((digits > 0) && maxlen) + { + buf = *buf_p; + *buf++ = '.'; + maxlen--; + for (prec = 0; maxlen && (prec < digits); prec++) + { + *buf++ = text[prec]; + maxlen--; + } + *buf_p = buf; + } +} + +void AddUInt(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags) +{ + char text[32]; + int digits; + char *buf; + + digits = 0; + do + { + text[digits++] = '0' + val % 10; + val /= 10; + } while (val); + + buf = *buf_p; + + if (!(flags & LADJUST)) + { + while (digits < width && maxlen) + { + *buf++ = (flags & ZEROPAD) ? '0' : ' '; + width--; + maxlen--; + } + } + + while (digits-- && maxlen) + { + *buf++ = text[digits]; + width--; + maxlen--; + } + + if (flags & LADJUST) + { + while (width-- && maxlen) + { + *buf++ = (flags & ZEROPAD) ? '0' : ' '; + maxlen--; + } + } + + *buf_p = buf; +} + +void AddInt(char **buf_p, size_t &maxlen, int val, int width, int flags) +{ + char text[32]; + int digits; + int signedVal; + char *buf; + unsigned int unsignedVal; + + digits = 0; + signedVal = val; + if (val < 0) + { + /* we want the unsigned version */ + unsignedVal = abs(val); + } else { + unsignedVal = val; + } + do + { + text[digits++] = '0' + unsignedVal % 10; + unsignedVal /= 10; + } while (unsignedVal); + + if (signedVal < 0) + { + text[digits++] = '-'; + } + + buf = *buf_p; + + if (!(flags & LADJUST)) + { + while ((digits < width) && maxlen) + { + *buf++ = (flags & ZEROPAD) ? '0' : ' '; + width--; + maxlen--; + } + } + + while (digits-- && maxlen) + { + *buf++ = text[digits]; + width--; + maxlen--; + } + + if (flags & LADJUST) + { + while (width-- && maxlen) + { + *buf++ = (flags & ZEROPAD) ? '0' : ' '; + maxlen--; + } + } + + *buf_p = buf; +} + +size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext *pCtx, const cell_t *params, int *param) +{ + int arg; + //int args = params[0] / sizeof(cell); //:TODO: wrong, i think params[0] has now the param count not the byte count + // either way this is only used when the above macro is fixed, until then not needed + char *buf_p; + char ch; + int flags; + int width; + int prec; + int n; + char sign; + const char *fmt; + size_t llen = maxlen; + + buf_p = buffer; + arg = *param; + fmt = format; + + while (true) + { + // run through the format string until we hit a '%' or '\0' + for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++) + { + *buf_p++ = ch; + llen--; + } + if ((ch == '\0') || (llen <= 0)) + { + goto done; + } + + // skip over the '%' + fmt++; + + // reset formatting state + flags = 0; + width = 0; + prec = -1; + sign = '\0'; + +rflag: + ch = *fmt++; +reswitch: + switch(ch) + { + case '-': + { + flags |= LADJUST; + goto rflag; + } + case '.': + { + n = 0; + while(is_digit((ch = *fmt++))) + { + n = 10 * n + (ch - '0'); + } + prec = (n < 0) ? -1 : n; + goto reswitch; + } + case '0': + { + flags |= ZEROPAD; + goto rflag; + } + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + n = 0; + do + { + n = 10 * n + (ch - '0'); + ch = *fmt++; + } while(is_digit(ch)); + width = n; + goto reswitch; + } + case 'c': + { + CHECK_ARGS(0); + if (llen <= 1) + { + goto done; + } + char *c; + pCtx->LocalToString(params[arg], &c); + *buf_p++ = *c; + llen--; + arg++; + break; + } + case 'd': + case 'i': + { + CHECK_ARGS(0); + cell_t *value; + pCtx->LocalToPhysAddr(params[arg], &value); + AddInt(&buf_p, llen, static_cast(*value), width, flags); + arg++; + break; + } + case 'u': + { + CHECK_ARGS(0); + cell_t *value; + pCtx->LocalToPhysAddr(params[arg], &value); + AddUInt(&buf_p, llen, static_cast(*value), width, flags); + arg++; + break; + } + case 'f': + { + CHECK_ARGS(0); + cell_t *value; + pCtx->LocalToPhysAddr(params[arg], &value); + AddFloat(&buf_p, llen, ctof(*value), width, prec); + arg++; + break; + } + case 's': + { + CHECK_ARGS(0); + char *str; + pCtx->LocalToString(params[arg], &str); + AddString(&buf_p, llen, str, width, prec); + arg++; + break; + } + case '%': + { + if (llen <= 1) + { + goto done; + } + *buf_p++ = ch; + llen--; + break; + } + case '\0': + { + if (llen <= 1) + { + goto done; + } + *buf_p++ = '%'; + llen--; + goto done; + } + default: + { + if (llen <= 1) + { + goto done; + } + *buf_p++ = ch; + llen--; + break; + } + } + } + +done: + *buf_p = '\0'; + *param = arg; + return (maxlen - llen); +} diff --git a/core/sm_stringutil.h b/core/sm_stringutil.h new file mode 100644 index 00000000..b9ae216a --- /dev/null +++ b/core/sm_stringutil.h @@ -0,0 +1,12 @@ +#ifndef _INCLUDE_SOURCEMOD_STRINGUTIL_H_ +#define _INCLUDE_SOURCEMOD_STRINGUTIL_H_ + +#include +#include "sp_vm_api.h" +#include "sp_vm_typeutil.h" + +using namespace SourcePawn; + +size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext *pCtx, const cell_t *params, int *param); + +#endif // _INCLUDE_SOURCEMOD_STRINGUTIL_H_