diff --git a/src/Emulator/HLE/Libraries/LibC/printf.h b/src/Emulator/HLE/Libraries/LibC/printf.h index c9506dc9..5137255d 100644 --- a/src/Emulator/HLE/Libraries/LibC/printf.h +++ b/src/Emulator/HLE/Libraries/LibC/printf.h @@ -10,10 +10,10 @@ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -45,26 +45,28 @@ // with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -//copied from Vita3k project at 6/10/2023 (latest update 30/06/2023) -//modifications for adapting va_args parameters +// copied from Vita3k project at 6/10/2023 (latest update 30/06/2023) +// modifications for adapting va_args parameters #pragma once #include -#include #include +#include #include -namespace utils { +#include "va_ctx.h" + +namespace Emulator::HLE::Libraries::LibC { // ntoa conversion buffer size, this must be big enough to hold // one converted numeric number including padded zeros (dynamically created on stack) // 32 byte is a good default -#define PRINTF_NTOA_BUFFER_SIZE 32U +#define PRINTF_NTOA_BUFFER_SIZE 32U // ftoa conversion buffer size, this must be big enough to hold // one converted float number including padded zeros (dynamically created on stack) // 32 byte is a good default -#define PRINTF_FTOA_BUFFER_SIZE 32U +#define PRINTF_FTOA_BUFFER_SIZE 32U // define this to support floating point (%f) #define PRINTF_SUPPORT_FLOAT @@ -76,341 +78,318 @@ namespace utils { // ptrdiff_t is normally defined in as long or long long type #define PRINTF_SUPPORT_PTRDIFF_T - /////////////////////////////////////////////////////////////////////////////// // internal flag definitions -#define FLAGS_ZEROPAD (1U << 0U) -#define FLAGS_LEFT (1U << 1U) -#define FLAGS_PLUS (1U << 2U) -#define FLAGS_SPACE (1U << 3U) -#define FLAGS_HASH (1U << 4U) -#define FLAGS_UPPERCASE (1U << 5U) -#define FLAGS_CHAR (1U << 6U) -#define FLAGS_SHORT (1U << 7U) -#define FLAGS_LONG (1U << 8U) -#define FLAGS_LONG_LONG (1U << 9U) +#define FLAGS_ZEROPAD (1U << 0U) +#define FLAGS_LEFT (1U << 1U) +#define FLAGS_PLUS (1U << 2U) +#define FLAGS_SPACE (1U << 3U) +#define FLAGS_HASH (1U << 4U) +#define FLAGS_UPPERCASE (1U << 5U) +#define FLAGS_CHAR (1U << 6U) +#define FLAGS_SHORT (1U << 7U) +#define FLAGS_LONG (1U << 8U) +#define FLAGS_LONG_LONG (1U << 9U) #define FLAGS_PRECISION (1U << 10U) -#define FLAGS_WIDTH (1U << 11U) - +#define FLAGS_WIDTH (1U << 11U) // output function type typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen); - // wrapper (used as buffer) for output function type typedef struct { - void (*fct)(char character, void* arg); - void* arg; + void (*fct)(char character, void* arg); + void* arg; } out_fct_wrap_type; - // internal buffer output -static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen) -{ - if (idx < maxlen) { - ((char*)buffer)[idx] = character; - } +static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen) { + if (idx < maxlen) { + ((char*)buffer)[idx] = character; + } } - // internal null output -static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen) -{ - (void)character; (void)buffer; (void)idx; (void)maxlen; +static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen) { + (void)character; + (void)buffer; + (void)idx; + (void)maxlen; } - // internal output function wrapper -static inline void _out_fct(char character, void* buffer, size_t idx, size_t maxlen) -{ - (void)idx; (void)maxlen; - // buffer is the output fct pointer - ((out_fct_wrap_type*)buffer)->fct(character, ((out_fct_wrap_type*)buffer)->arg); +static inline void _out_fct(char character, void* buffer, size_t idx, size_t maxlen) { + (void)idx; + (void)maxlen; + // buffer is the output fct pointer + ((out_fct_wrap_type*)buffer)->fct(character, ((out_fct_wrap_type*)buffer)->arg); } - // internal strlen // \return The length of the string (excluding the terminating 0) -static inline unsigned int _strlen(const char* str) -{ - const char* s; - for (s = str; *s; ++s); - return (unsigned int)(s - str); +static inline unsigned int _strlen(const char* str) { + const char* s; + for (s = str; *s; ++s) + ; + return (unsigned int)(s - str); } - // internal test if char is a digit (0-9) // \return true if char is a digit -static inline bool _is_digit(char ch) -{ - return (ch >= '0') && (ch <= '9'); -} - +static inline bool _is_digit(char ch) { return (ch >= '0') && (ch <= '9'); } // internal ASCII string to unsigned int conversion -static inline unsigned int _atoi(const char** str) -{ - unsigned int i = 0U; - while (_is_digit(**str)) { - i = i * 10U + (unsigned int)(*((*str)++) - '0'); - } - return i; +static inline unsigned int _atoi(const char** str) { + unsigned int i = 0U; + while (_is_digit(**str)) { + i = i * 10U + (unsigned int)(*((*str)++) - '0'); + } + return i; } - // internal itoa format -static inline size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags) -{ - const size_t start_idx = idx; +static inline size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, + unsigned int prec, unsigned int width, unsigned int flags) { + const size_t start_idx = idx; - // pad leading zeros - while (!(flags & FLAGS_LEFT) && (len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) { - buf[len++] = '0'; - } - while (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) { - buf[len++] = '0'; - } + // pad leading zeros + while (!(flags & FLAGS_LEFT) && (len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + while (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } - // handle hash - if (flags & FLAGS_HASH) { - if (((len == prec) || (len == width)) && (len > 0U)) { - len--; - if ((base == 16U) && (len > 0U)) { + // handle hash + if (flags & FLAGS_HASH) { + if (((len == prec) || (len == width)) && (len > 0U)) { + len--; + if ((base == 16U) && (len > 0U)) { + len--; + } + } + if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'x'; + } + if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'X'; + } + if (len < PRINTF_NTOA_BUFFER_SIZE) { + buf[len++] = '0'; + } + } + + // handle sign + if ((len == width) && (negative || (flags & FLAGS_PLUS) || (flags & FLAGS_SPACE))) { len--; - } - } - if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { - buf[len++] = 'x'; - } - if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { - buf[len++] = 'X'; } if (len < PRINTF_NTOA_BUFFER_SIZE) { - buf[len++] = '0'; + if (negative) { + buf[len++] = '-'; + } else if (flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } else if (flags & FLAGS_SPACE) { + buf[len++] = ' '; + } } - } - // handle sign - if ((len == width) && (negative || (flags & FLAGS_PLUS) || (flags & FLAGS_SPACE))) { - len--; - } - if (len < PRINTF_NTOA_BUFFER_SIZE) { - if (negative) { - buf[len++] = '-'; + // pad spaces up to given width + if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { + for (size_t i = len; i < width; i++) { + out(' ', buffer, idx++, maxlen); + } } - else if (flags & FLAGS_PLUS) { - buf[len++] = '+'; // ignore the space if the '+' exists - } - else if (flags & FLAGS_SPACE) { - buf[len++] = ' '; - } - } - // pad spaces up to given width - if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { - for (size_t i = len; i < width; i++) { - out(' ', buffer, idx++, maxlen); + // reverse string + for (size_t i = 0U; i < len; i++) { + out(buf[len - i - 1U], buffer, idx++, maxlen); } - } - // reverse string - for (size_t i = 0U; i < len; i++) { - out(buf[len - i - 1U], buffer, idx++, maxlen); - } - - // append pad spaces up to given width - if (flags & FLAGS_LEFT) { - while (idx - start_idx < width) { - out(' ', buffer, idx++, maxlen); + // append pad spaces up to given width + if (flags & FLAGS_LEFT) { + while (idx - start_idx < width) { + out(' ', buffer, idx++, maxlen); + } } - } - return idx; + return idx; } - // internal itoa for 'long' type -static inline size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags) -{ - char buf[PRINTF_NTOA_BUFFER_SIZE]; - size_t len = 0U; +static inline size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, + unsigned int prec, unsigned int width, unsigned int flags) { + char buf[PRINTF_NTOA_BUFFER_SIZE]; + size_t len = 0U; - // write if precision != 0 and value is != 0 - if (!(flags & FLAGS_PRECISION) || value) { - do { - const char digit = (char)(value % base); - buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; - value /= base; - } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); - } + // write if precision != 0 and value is != 0 + if (!(flags & FLAGS_PRECISION) || value) { + do { + const char digit = (char)(value % base); + buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); + } - return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); + return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); } - // internal itoa for 'long long' type #if defined(PRINTF_SUPPORT_LONG_LONG) -static inline size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags) -{ - char buf[PRINTF_NTOA_BUFFER_SIZE]; - size_t len = 0U; +static inline size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, + unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags) { + char buf[PRINTF_NTOA_BUFFER_SIZE]; + size_t len = 0U; - // write if precision != 0 and value is != 0 - if (!(flags & FLAGS_PRECISION) || value) { - do { - const char digit = (char)(value % base); - buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; - value /= base; - } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); - } + // write if precision != 0 and value is != 0 + if (!(flags & FLAGS_PRECISION) || value) { + do { + const char digit = (char)(value % base); + buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); + } - return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); + return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); } #endif // PRINTF_SUPPORT_LONG_LONG - #if defined(PRINTF_SUPPORT_FLOAT) -static inline size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) -{ - char buf[PRINTF_FTOA_BUFFER_SIZE]; - size_t len = 0U; - double diff = 0.0; +static inline size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, + unsigned int flags) { + char buf[PRINTF_FTOA_BUFFER_SIZE]; + size_t len = 0U; + double diff = 0.0; - // if input is larger than thres_max, revert to exponential - const double thres_max = (double)0x7FFFFFFF; + // if input is larger than thres_max, revert to exponential + const double thres_max = (double)0x7FFFFFFF; - // powers of 10 - static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; + // powers of 10 + static const double pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; - // test for negative - bool negative = false; - if (value < 0) { - negative = true; - value = 0 - value; - } - - // set default precision to 6, if not set explicitly - if (!(flags & FLAGS_PRECISION)) { - prec = 6U; - } - // limit precision to 9, cause a prec >= 10 can lead to overflow errors - while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) { - buf[len++] = '0'; - prec--; - } - - int whole = (int)value; - double tmp = (value - whole) * pow10[prec]; - unsigned long frac = (unsigned long)tmp; - diff = tmp - frac; - - if (diff > 0.5) { - ++frac; - // handle rollover, e.g. case 0.99 with prec 1 is 1.0 - if (frac >= pow10[prec]) { - frac = 0; - ++whole; + // test for negative + bool negative = false; + if (value < 0) { + negative = true; + value = 0 - value; } - } - else if ((diff == 0.5) && ((frac == 0U) || (frac & 1U))) { - // if halfway, round up if odd, OR if last digit is 0 - ++frac; - } - // TBD: for very large numbers switch back to native sprintf for exponentials. Anyone want to write code to replace this? - // Normal printf behavior is to print EVERY whole number digit which can be 100s of characters overflowing your buffers == bad - if (value > thres_max) { - return 0U; - } + // set default precision to 6, if not set explicitly + if (!(flags & FLAGS_PRECISION)) { + prec = 6U; + } + // limit precision to 9, cause a prec >= 10 can lead to overflow errors + while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) { + buf[len++] = '0'; + prec--; + } + + int whole = (int)value; + double tmp = (value - whole) * pow10[prec]; + unsigned long frac = (unsigned long)tmp; + diff = tmp - frac; - if (prec == 0U) { - diff = value - (double)whole; if (diff > 0.5) { - // greater than 0.5, round up, e.g. 1.6 -> 2 - ++whole; + ++frac; + // handle rollover, e.g. case 0.99 with prec 1 is 1.0 + if (frac >= pow10[prec]) { + frac = 0; + ++whole; + } + } else if ((diff == 0.5) && ((frac == 0U) || (frac & 1U))) { + // if halfway, round up if odd, OR if last digit is 0 + ++frac; } - else if ((diff == 0.5) && (whole & 1)) { - // exactly 0.5 and ODD, then round up - // 1.5 -> 2, but 2.5 -> 2 - ++whole; + + // TBD: for very large numbers switch back to native sprintf for exponentials. Anyone want to write code to replace this? + // Normal printf behavior is to print EVERY whole number digit which can be 100s of characters overflowing your buffers == bad + if (value > thres_max) { + return 0U; } - } - else { - unsigned int count = prec; - // now do fractional part, as an unsigned number + + if (prec == 0U) { + diff = value - (double)whole; + if (diff > 0.5) { + // greater than 0.5, round up, e.g. 1.6 -> 2 + ++whole; + } else if ((diff == 0.5) && (whole & 1)) { + // exactly 0.5 and ODD, then round up + // 1.5 -> 2, but 2.5 -> 2 + ++whole; + } + } else { + unsigned int count = prec; + // now do fractional part, as an unsigned number + while (len < PRINTF_FTOA_BUFFER_SIZE) { + --count; + buf[len++] = (char)(48U + (frac % 10U)); + if (!(frac /= 10U)) { + break; + } + } + // add extra 0s + while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) { + buf[len++] = '0'; + } + if (len < PRINTF_FTOA_BUFFER_SIZE) { + // add decimal + buf[len++] = '.'; + } + } + + // do whole part, number is reversed while (len < PRINTF_FTOA_BUFFER_SIZE) { - --count; - buf[len++] = (char)(48U + (frac % 10U)); - if (!(frac /= 10U)) { - break; - } + buf[len++] = (char)(48 + (whole % 10)); + if (!(whole /= 10)) { + break; + } } - // add extra 0s - while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) { - buf[len++] = '0'; + + // pad leading zeros + while (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + + // handle sign + if ((len == width) && (negative || (flags & FLAGS_PLUS) || (flags & FLAGS_SPACE))) { + len--; } if (len < PRINTF_FTOA_BUFFER_SIZE) { - // add decimal - buf[len++] = '.'; + if (negative) { + buf[len++] = '-'; + } else if (flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } else if (flags & FLAGS_SPACE) { + buf[len++] = ' '; + } } - } - // do whole part, number is reversed - while (len < PRINTF_FTOA_BUFFER_SIZE) { - buf[len++] = (char)(48 + (whole % 10)); - if (!(whole /= 10)) { - break; + // pad spaces up to given width + if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { + for (size_t i = len; i < width; i++) { + out(' ', buffer, idx++, maxlen); + } } - } - // pad leading zeros - while (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) { - buf[len++] = '0'; - } - - // handle sign - if ((len == width) && (negative || (flags & FLAGS_PLUS) || (flags & FLAGS_SPACE))) { - len--; - } - if (len < PRINTF_FTOA_BUFFER_SIZE) { - if (negative) { - buf[len++] = '-'; + // reverse string + for (size_t i = 0U; i < len; i++) { + out(buf[len - i - 1U], buffer, idx++, maxlen); } - else if (flags & FLAGS_PLUS) { - buf[len++] = '+'; // ignore the space if the '+' exists - } - else if (flags & FLAGS_SPACE) { - buf[len++] = ' '; - } - } - // pad spaces up to given width - if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { - for (size_t i = len; i < width; i++) { - out(' ', buffer, idx++, maxlen); + // append pad spaces up to given width + if (flags & FLAGS_LEFT) { + while (idx < width) { + out(' ', buffer, idx++, maxlen); + } } - } - // reverse string - for (size_t i = 0U; i < len; i++) { - out(buf[len - i - 1U], buffer, idx++, maxlen); - } - - // append pad spaces up to given width - if (flags & FLAGS_LEFT) { - while (idx < width) { - out(' ', buffer, idx++, maxlen); - } - } - - return idx; + return idx; } #endif // PRINTF_SUPPORT_FLOAT -#if 0 + // internal vsnprintf -static inline int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, CPUState &cpu, MemState &mem, module::vargs &va) +static inline int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, VaList* va_list) { unsigned int flags, width, precision, n; size_t idx = 0U; @@ -453,7 +432,8 @@ static inline int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen width = _atoi(&format); } else if (*format == '*') { - const int w = va.next(cpu, mem); + const int w = vaArgInteger(va_list); // const int w = va.next(cpu, mem); + if (w < 0) { flags |= FLAGS_LEFT; // reverse padding width = (unsigned int)-w; @@ -473,7 +453,7 @@ static inline int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen precision = _atoi(&format); } else if (*format == '*') { - precision = (unsigned int)va.next(cpu, mem); + precision = vaArgInteger(va_list); // precision = (unsigned int)va.next(cpu, mem); format++; } } @@ -554,16 +534,19 @@ static inline int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen // signed if (flags & FLAGS_LONG_LONG) { #if defined(PRINTF_SUPPORT_LONG_LONG) - const long long value = va.next(cpu, mem); + auto value = vaArgLongLong(va_list); // const long long value = va.next(cpu, mem); idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); #endif } else if (flags & FLAGS_LONG) { - const long value = va.next(cpu, mem); + auto value = vaArgLong(va_list); // const long value = va.next(cpu, mem); idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); } else { - const int value = (flags & FLAGS_CHAR) ? (char)va.next(cpu, mem) : (flags & FLAGS_SHORT) ? (short int)va.next(cpu, mem): va.next(cpu, mem); + //const int value = (flags & FLAGS_CHAR) ? (char)va.next(cpu, mem) : (flags & FLAGS_SHORT) ? (short int)va.next(cpu, mem): va.next(cpu, mem); + const int value = (flags & FLAGS_CHAR) ? static_cast(vaArgInteger(va_list)) + : (flags & FLAGS_SHORT) ? static_cast(vaArgInteger(va_list)) + : vaArgInteger(va_list); idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); } } @@ -571,15 +554,20 @@ static inline int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen // unsigned if (flags & FLAGS_LONG_LONG) { #if defined(PRINTF_SUPPORT_LONG_LONG) - idx = _ntoa_long_long(out, buffer, idx, maxlen, va.next(cpu, mem), false, base, precision, width, flags); + //idx = _ntoa_long_long(out, buffer, idx, maxlen, va.next(cpu, mem), false, base, precision, width, flags); + idx = _ntoa_long_long(out, buffer, idx, maxlen, static_cast(vaArgLongLong(va_list)), false, base, precision, width, flags); #endif } else if (flags & FLAGS_LONG) { - idx = _ntoa_long(out, buffer, idx, maxlen, va.next(cpu, mem), false, base, precision, width, flags); + // idx = _ntoa_long(out, buffer, idx, maxlen, va.next(cpu, mem), false, base, precision, width, flags); + idx = _ntoa_long(out, buffer, idx, maxlen, static_cast(vaArgLong(va_list)), false, base, precision, width, flags); } else { - const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va.next(cpu, mem) : (flags & FLAGS_SHORT) ? - (unsigned short int)va.next(cpu, mem) : va.next(cpu, mem); + //const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va.next(cpu, mem) : (flags & FLAGS_SHORT) ? + // (unsigned short int)va.next(cpu, mem) : va.next(cpu, mem); + const unsigned int value = (flags & FLAGS_CHAR) ? static_cast(vaArgInteger(va_list)) + : (flags & FLAGS_SHORT) ? static_cast(vaArgInteger(va_list)) + : static_cast(vaArgInteger(va_list)); idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags); } } @@ -589,7 +577,8 @@ static inline int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen #if defined(PRINTF_SUPPORT_FLOAT) case 'f' : case 'F' : - idx = _ftoa(out, buffer, idx, maxlen, va.next(cpu, mem), precision, width, flags); + //idx = _ftoa(out, buffer, idx, maxlen, va.next(cpu, mem), precision, width, flags); + idx = _ftoa(out, buffer, idx, maxlen, vaArgDouble(va_list), precision, width, flags); format++; break; #endif // PRINTF_SUPPORT_FLOAT @@ -602,7 +591,8 @@ static inline int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen } } // char output - out((char)va.next(cpu, mem), buffer, idx++, maxlen); + //out((char)va.next(cpu, mem), buffer, idx++, maxlen); + out(static_cast(vaArgInteger(va_list)), buffer, idx++, maxlen); // post padding if (flags & FLAGS_LEFT) { while (l++ < width) { @@ -614,7 +604,7 @@ static inline int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen } case 's' : { - const char *p = va.next>(cpu, mem).get(mem); + const char* p = vaArgPtr(va_list); // const char *p = va.next>(cpu, mem).get(mem); p = p != nullptr ? p : "(null)"; unsigned int l = _strlen(p); // pre padding @@ -646,11 +636,15 @@ static inline int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen #if defined(PRINTF_SUPPORT_LONG_LONG) const bool is_ll = sizeof(uintptr_t) == sizeof(long long); if (is_ll) { - idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va.next>(cpu, mem).address(), false, 16U, precision, width, flags); + //idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va.next>(cpu, mem).address(), false, 16U, precision, width, flags); + idx = _ntoa_long_long(out, buffer, idx, maxlen, reinterpret_cast(vaArgPtr(va_list)), false, 16U, precision, width, flags); } else { #endif - idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va.next>(cpu, mem).address()), false, 16U, precision, width, flags); + //idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va.next>(cpu, mem).address()), false, 16U, precision, width, flags); + idx = _ntoa_long(out, buffer, idx, maxlen, static_cast(reinterpret_cast(vaArgPtr(va_list))), false, 16U, + precision, width, + flags); #if defined(PRINTF_SUPPORT_LONG_LONG) } #endif @@ -677,6 +671,7 @@ static inline int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen return (int)idx; } +#if 0 /////////////////////////////////////////////////////// /** @@ -708,4 +703,4 @@ inline int snprintf(char* buffer, size_t count, const char* format, CPUState &cp #endif -} +} // namespace Emulator::HLE::Libraries::LibC diff --git a/src/Emulator/HLE/Libraries/LibC/va_ctx.h b/src/Emulator/HLE/Libraries/LibC/va_ctx.h new file mode 100644 index 00000000..2dd613bc --- /dev/null +++ b/src/Emulator/HLE/Libraries/LibC/va_ctx.h @@ -0,0 +1,70 @@ +#include + +namespace Emulator::HLE::Libraries::LibC { + +// https://stackoverflow.com/questions/4958384/what-is-the-format-of-the-x86-64-va-list-structure + +struct VaList { + u32 gp_offset; + u32 fp_offset; + void* overflow_arg_area; + void* reg_save_area; +}; + +template +T vaArgRegSaveAreaGp(VaList* l) { + auto* addr = reinterpret_cast(static_cast(l->reg_save_area) + l->gp_offset); + l->gp_offset += Size; + return *addr; +} +template +T vaArgOverflowArgArea(VaList* l) { + auto ptr = ((reinterpret_cast(l->overflow_arg_area) + (Align - 1)) & ~(Align - 1)); + auto* addr = reinterpret_cast(ptr); + l->overflow_arg_area = reinterpret_cast(ptr + Size); + return *addr; +} + +template +T vaArgRegSaveAreaFp(VaList* l) { + auto* addr = reinterpret_cast(static_cast(l->reg_save_area) + l->fp_offset); + l->fp_offset += Size; + return *addr; +} + +inline int vaArgInteger(VaList* l) { + if (l->gp_offset <= 40) { + return vaArgRegSaveAreaGp(l); + } + return vaArgOverflowArgArea(l); +} + +inline long long vaArgLongLong(VaList* l) { + if (l->gp_offset <= 40) { + return vaArgRegSaveAreaGp(l); + } + return vaArgOverflowArgArea(l); +} +inline long vaArgLong(VaList* l) { + if (l->gp_offset <= 40) { + return vaArgRegSaveAreaGp(l); + } + return vaArgOverflowArgArea(l); +} + +inline double vaArgDouble(VaList* l) { + if (l->fp_offset <= 160) { + return vaArgRegSaveAreaFp(l); + } + return vaArgOverflowArgArea(l); +} + +template +T* vaArgPtr(VaList* l) { + if (l->gp_offset <= 40) { + return vaArgRegSaveAreaGp(l); + } + return vaArgOverflowArgArea(l); +} + +} // namespace Emulator::HLE::Libraries::LibC \ No newline at end of file