From 9de47809439057341a87612c9a37ef2e2e3aaf74 Mon Sep 17 00:00:00 2001 From: RD42 <42702181+dashr9230@users.noreply.github.com> Date: Tue, 25 Jun 2024 22:37:19 +0800 Subject: [PATCH] [bot] Implement `n_format(...)` * Implement `format_amxstring(...)` * Implement `get_amxaddr(...)` * Implement `AddString(...)` * Implement `AddFloat(...)` * Implement `AddInt(...)` * Implement `AddHex(...)` * Implement `AddBin(...)` * Implement `__WHOA_DONT_CALL_ME_PLZ_K_lol_o_O()` * Implement `atcprintf(...)` --- bot/bot.vcproj | 6 + bot/format.cpp | 464 ++++++++++++++++++++++++++++++++++++++++++++++ bot/format.h | 8 + bot/scrcore.cpp | 18 ++ bot/scrcustom.cpp | 4 +- 5 files changed, 498 insertions(+), 2 deletions(-) create mode 100644 bot/format.cpp create mode 100644 bot/format.h diff --git a/bot/bot.vcproj b/bot/bot.vcproj index 87cefa7..2167b70 100644 --- a/bot/bot.vcproj +++ b/bot/bot.vcproj @@ -116,6 +116,12 @@ + + + + diff --git a/bot/format.cpp b/bot/format.cpp new file mode 100644 index 0000000..943e7ed --- /dev/null +++ b/bot/format.cpp @@ -0,0 +1,464 @@ +// Taken, graciously, from AMXMODX +// + +#include "main.h" +#include "../server/amx/amx.h" + +#include "format.h" + +cell* get_amxaddr(AMX *amx,cell amx_addr); + +#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') +#define CHECK_ARGS(n) \ + if ((arg+n) > args) { \ + LogError(amx, AMX_ERR_PARAMS, "String formatted incorrectly - parameter %d (total %d)", arg, args); \ + return 0; \ + } + +template +void AddString(U **buf_p, size_t &maxlen, const cell *string, int width, int prec) +{ + int size = 0; + U *buf; + static cell 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++ = static_cast(*string++); + + while (width-- > 0 && maxlen) + { + *buf++ = ' '; + maxlen--; + } + + *buf_p = buf; +} + +template +void AddFloat(U **buf_p, size_t &maxlen, double fval, int width, int prec) +{ + U text[32]; + int digits; + double signedVal; + U *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; + } +} + +template +void AddInt(U **buf_p, size_t &maxlen, int val, int width, int flags) +{ + U text[32]; + int digits; + int signedVal; + U *buf; + + digits = 0; + signedVal = val; + if (val < 0) + val = -val; + do { + text[digits++] = '0' + val % 10; + val /= 10; + } while (val); + + //if (signedVal < 0) + //text[digits++] = '-'; + + buf = *buf_p; + + if (signedVal < 0) + { + if (flags & ZEROPAD) + { + *buf++ = '-'; + } + else + { + text[digits++] = '-'; + } + } + + 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; +} + +template +void AddHex(U **buf_p, size_t &maxlen, int val, int width, int flags) +{ + U text[32]; + int digits; + //int signedVal; + U *buf; + + digits = 0; + + do + { + text[digits] = '0' + val % 16; + if (text[digits] > '9') text[digits] += 7; // Shift to letters + digits++; + val /= 16; // val >>= 4; + } + while (val); + + //text[digits++] = 'x'; + //text[digits++] = '0'; + + 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; +} + +template +void AddBin(U **buf_p, size_t &maxlen, int val, int width, int flags) +{ + U text[32]; + int digits; + //int signedVal; + U *buf; + + digits = 0; + + do + { + text[digits++] = '0' + (val & 1); + val >>= 1; // val >>= 4; + } + while (val); + + //text[digits++] = 'x'; + //text[digits++] = '0'; + + 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; +} + +template +size_t atcprintf(D *buffer, size_t maxlen, const S *format, AMX *amx, cell *params, int *param) +{ + int arg; + int args = params[0] / sizeof(cell); + D *buf_p; + D ch; + int flags; + int width; + int prec; + int n; + char sign; + const S *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 = static_cast(*fmt); + llen && ((ch = static_cast(*fmt)) != '\0' && ch != '%'); + fmt++) + { + *buf_p++ = static_cast(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 = static_cast(*fmt++); +reswitch: + switch(ch) + { + case '-': + flags |= LADJUST; + goto rflag; + case '.': + if (( ch = static_cast(*fmt)) == '*') + { + prec = *get_amxaddr(amx, params[arg++]); + fmt++; + goto rflag; + } + else + { + n = 0; + while( is_digit( ( ch = static_cast(*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 = static_cast(*fmt++); + } while( is_digit( ch ) ); + width = n; + goto reswitch; + case '*': + width = *get_amxaddr(amx, params[arg++]); + goto rflag; + case 'b': + AddBin(&buf_p, llen, *get_amxaddr(amx, params[arg]), width, flags); + arg++; + break; + case 'c': + *buf_p++ = static_cast(*get_amxaddr(amx, params[arg])); + arg++; + break; + case 'd': + case 'i': + AddInt(&buf_p, llen, *get_amxaddr(amx, params[arg]), width, flags); + arg++; + break; + case 'f': + AddFloat(&buf_p, llen, amx_ctof(*get_amxaddr(amx, params[arg])), width, prec); + arg++; + break; + case 's': + AddString(&buf_p, llen, get_amxaddr(amx, params[arg]), width, prec); + arg++; + break; + case 'h': + case 'x': + AddHex(&buf_p, llen, *get_amxaddr(amx, params[arg]), width, flags); + arg++; + break; + case '%': + *buf_p++ = static_cast(ch); + if (!llen) + goto done; + llen--; + break; + case '\0': + *buf_p++ = static_cast('%'); + if (!llen) + goto done; + llen--; + goto done; + break; + default: + *buf_p++ = static_cast(ch); + if (!llen) + goto done; + llen--; + break; + } + } + +done: + *buf_p = static_cast(0); + *param = arg; + return maxlen-llen; +} + +/** + * HACKHACK: The compiler will generate code for each case we need. + * Don't remove this, otherwise files that use certain code generations + * will have extern problems. For each case you need, add dummy code + * here. + */ +void __WHOA_DONT_CALL_ME_PLZ_K_lol_o_O() +{ + //acsprintf + atcprintf((cell *)NULL, 0, (const char *)NULL, NULL, NULL, NULL); + //accprintf + atcprintf((cell *)NULL, 0, (cell *)NULL, NULL, NULL, NULL); + //ascprintf + atcprintf((char *)NULL, 0, (cell *)NULL, NULL, NULL, NULL); +} + diff --git a/bot/format.h b/bot/format.h new file mode 100644 index 0000000..a1441a6 --- /dev/null +++ b/bot/format.h @@ -0,0 +1,8 @@ +#ifndef _INCLUDE_FORMATTING_H +#define _INCLUDE_FORMATTING_H + +//Amx Templatized Cell Printf +template +size_t atcprintf(D *buffer, size_t maxlen, const S *format, AMX *amx, cell *params, int *param); + +#endif //_INCLUDE_FORMATTING_H diff --git a/bot/scrcore.cpp b/bot/scrcore.cpp index 3a285de..c7e2b12 100644 --- a/bot/scrcore.cpp +++ b/bot/scrcore.cpp @@ -1,5 +1,7 @@ #include "main.h" +#include +#include "format.h" //---------------------------------------------------------------------------------- @@ -143,6 +145,13 @@ void AMXPrintError(CGameMode* pGameMode, AMX *amx, int error) //---------------------------------------------------------------------------------- +cell* get_amxaddr(AMX *amx,cell amx_addr) +{ + return (cell *)(amx->base + (int)(((AMX_HEADER *)amx->base)->dat + amx_addr)); +} + +//---------------------------------------------------------------------------------- + int set_amxstring(AMX *amx,cell amx_addr,const char *source,int max) { cell* dest = (cell *)(amx->base + (int)(((AMX_HEADER *)amx->base)->dat + amx_addr)); @@ -155,3 +164,12 @@ int set_amxstring(AMX *amx,cell amx_addr,const char *source,int max) //---------------------------------------------------------------------------------- +char* format_amxstring(AMX *amx, cell *params, int parm, int &len) +{ + static char outbuf[4096]; + cell *addr = get_amxaddr(amx, params[parm++]); + len = atcprintf(outbuf, sizeof(outbuf)-1, addr, amx, params, &parm); + return outbuf; +} + +//---------------------------------------------------------------------------------- diff --git a/bot/scrcustom.cpp b/bot/scrcustom.cpp index 8cd19e6..30e493f 100644 --- a/bot/scrcustom.cpp +++ b/bot/scrcustom.cpp @@ -26,8 +26,8 @@ static cell AMX_NATIVE_CALL n_printf(AMX *amx, cell *params) // native format(output[], len, const format[], {Float,_}:...) static cell AMX_NATIVE_CALL n_format(AMX *amx, cell *params) { - // TODO: n_format - return 0; + int len; + return set_amxstring(amx, params[1], format_amxstring(amx, params, 3, len), params[2]); } // native SetTimer(funcname[], interval, repeating)