// 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); }