diff --git a/common/src/Utilities/vssprintf.cpp b/common/src/Utilities/vssprintf.cpp index 3e46384eac..5a130c8214 100644 --- a/common/src/Utilities/vssprintf.cpp +++ b/common/src/Utilities/vssprintf.cpp @@ -1,754 +1,3 @@ -// -// Code base on: vsprintf.c -// -// Print formatting routines -// -// Copyright (C) 2002 Michael Ringgaard. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the project nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -// SUCH DAMAGE. -// - -// modified by gigahers and air to write formatted output directly into a std::string container. - -#include "PrecompiledHeader.h" - -#ifdef _WIN32 - -#include - -#ifdef KERNEL -#define NOFLOAT -#endif - -#define ZEROPAD 1 // Pad with zero (not to be confused with Zero's PAD plugin) -#define SIGN 2 // Unsigned/signed long -#define PLUS 4 // Show plus -#define SPACE 8 // Space if plus -#define LEFT 16 // Left justified -#define SPECIAL 32 // 0x -#define LARGE 64 // Use 'ABCDEF' instead of 'abcdef' - -#define is_digit(c) ((c) >= '0' && (c) <= '9') - -#ifdef __linux__ -#define _CVTBUFSIZE (309 + 40) -#endif - -static const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz"; -static const char *upper_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - -#ifdef NEED_STRLEN -static size_t strnlen(const char *s, size_t count) -{ - const char *sc; - for (sc = s; *sc != '\0' && count--; ++sc) - ; - return sc - s; -} -#endif - -static void cvt(char (&buf)[_CVTBUFSIZE], double arg, int preci, int &decpt, int &sign, int eflag) -{ - int r2; - double fi, fj; - char *p, *p1; - - r2 = 0; - sign = 0; - p = &buf[0]; - if (arg < 0) { - sign = 1; - arg = -arg; - } - arg = modf(arg, &fi); - p1 = &buf[_CVTBUFSIZE]; - - if (fi != 0) { - while (fi != 0) { - fj = modf(fi / 10, &fi); - *--p1 = (int)((fj + .03) * 10) + '0'; - r2++; - } - while (p1 < &buf[_CVTBUFSIZE]) - *p++ = *p1++; - } else if (arg > 0) { - while ((fj = arg * 10) < 1) { - arg = fj; - r2--; - } - } - - p1 = &buf[preci]; - - if (eflag == 0) - p1 += r2; - decpt = r2; - if (p1 < &buf[0]) { - buf[0] = '\0'; - return; - } - while (p <= p1 && p < &buf[_CVTBUFSIZE]) { - arg *= 10; - arg = modf(arg, &fj); - *p++ = (int)fj + '0'; - } - if (p1 >= &buf[_CVTBUFSIZE]) { - buf[_CVTBUFSIZE - 1] = '\0'; - return; - } - p = p1; - *p1 += 5; - while (*p1 > '9') { - *p1 = '0'; - if (p1 > buf) - ++*--p1; - else { - *p1 = '1'; - decpt++; - if (eflag == 0) { - if (p > buf) - *p = '0'; - p++; - } - } - } - *p = '\0'; - return; -} - -static void ecvtbuf(char (&buf)[_CVTBUFSIZE], double arg, int preci, int &decpt, int &sign) -{ - cvt(buf, arg, preci, decpt, sign, 1); -} - -static void fcvtbuf(char (&buf)[_CVTBUFSIZE], double arg, int preci, int &decpt, int &sign) -{ - cvt(buf, arg, preci, decpt, sign, 0); -} - -static int skip_atoi(const char **s) -{ - int i = 0; - while (is_digit(**s)) - i = i * 10 + *((*s)++) - '0'; - return i; -} - -template -static void number(std::string &dest, T num, int base, int size, int precision, int type) -{ - char c, sign, tmp[88]; - const char *dig = digits; - int i; - - if (type & LARGE) - dig = upper_digits; - if (type & LEFT) - type &= ~ZEROPAD; - if (base < 2 || base > 36) - return; - - c = (type & ZEROPAD) ? '0' : ' '; - sign = 0; - if (type & SIGN) { - if (num < 0) { - sign = '-'; - num = -num; - size--; - } else if (type & PLUS) { - sign = '+'; - size--; - } else if (type & SPACE) { - sign = ' '; - size--; - } - } - - if (type & SPECIAL) { - if (base == 16) - size -= 2; - else if (base == 8) - size--; - } - - i = 0; - - if (num == 0) - tmp[i++] = '0'; - else { - if (base == 16) { - while (num != 0) { - tmp[i++] = dig[num & 0xf]; - num = (uint)num >> 4; - } - } else { - while (num != 0) { - tmp[i++] = dig[num % (uint)base]; - num /= (uint)base; - } - } - } - - if (i > precision) - precision = i; - size -= precision; - if (!(type & (ZEROPAD | LEFT))) - while (size-- > 0) - dest += ' '; - if (sign) - dest += sign; - - if (type & SPECIAL) { - if (base == 8) - dest += '0'; - else if (base == 16) { - dest += '0'; - dest += digits[33]; - } - } - - - if (!(type & LEFT) && size > 0) { - dest.append(size, c); - size = 0; - } - if (i < precision) - dest.append(precision - i, '0'); - while (i-- > 0) - dest += tmp[i]; - if (size > 0) - dest.append(size, ' '); - - //if (!(type & LEFT)) while (size-- > 0) dest += c; - //while (i < precision--) dest += '0'; - //while (i-- > 0) dest += tmp[i]; - //while (size-- > 0) dest += ' '; -} - -static void eaddr(std::string &dest, unsigned char *addr, int size, int precision, int type) -{ - char tmp[24]; - const char *dig = digits; - int i, len; - - if (type & LARGE) - dig = upper_digits; - len = 0; - for (i = 0; i < 6; i++) { - if (i != 0) - tmp[len++] = ':'; - tmp[len++] = dig[addr[i] >> 4]; - tmp[len++] = dig[addr[i] & 0x0F]; - } - - if (!(type & LEFT)) - while (len < size--) - dest += ' '; - for (i = 0; i < len; ++i) - dest += tmp[i]; - while (len < size--) - dest += ' '; -} - -static void iaddr(std::string &dest, unsigned char *addr, int size, int precision, int type) -{ - char tmp[24]; - int i, n, len; - - len = 0; - for (i = 0; i < 4; i++) { - if (i != 0) - tmp[len++] = '.'; - n = addr[i]; - - if (n == 0) - tmp[len++] = digits[0]; - else { - if (n >= 100) { - tmp[len++] = digits[n / 100]; - n = n % 100; - tmp[len++] = digits[n / 10]; - n = n % 10; - } else if (n >= 10) { - tmp[len++] = digits[n / 10]; - n = n % 10; - } - - tmp[len++] = digits[n]; - } - } - - if (!(type & LEFT)) - while (len < size--) - dest += ' '; - for (i = 0; i < len; ++i) - dest += tmp[i]; - while (len < size--) - dest += ' '; -} - -#ifndef NOFLOAT - -static void cfltcvt(double value, char *buffer, char fmt, int precision) -{ - int decpt, sign, exp, pos; - char cvtbuf[_CVTBUFSIZE]; - int capexp = 0; - int magnitude; - - if (fmt == 'G' || fmt == 'E') { - capexp = 1; - fmt += 'a' - 'A'; - } - - if (fmt == 'g') { - ecvtbuf(cvtbuf, value, precision, decpt, sign); - - magnitude = decpt - 1; - if (magnitude < -4 || magnitude > precision - 1) { - fmt = 'e'; - precision -= 1; - } else { - fmt = 'f'; - precision -= decpt; - } - } - - if (fmt == 'e') { - ecvtbuf(cvtbuf, value, precision + 1, decpt, sign); - - const char *digits = cvtbuf; - - if (sign) - *buffer++ = '-'; - *buffer++ = *digits; - if (precision > 0) - *buffer++ = '.'; - memcpy(buffer, digits + 1, precision); - buffer += precision; - *buffer++ = capexp ? 'E' : 'e'; - - if (decpt == 0) { - if (value == 0.0) - exp = 0; - else - exp = -1; - } else - exp = decpt - 1; - - if (exp < 0) { - *buffer++ = '-'; - exp = -exp; - } else - *buffer++ = '+'; - - buffer[2] = (exp % 10) + '0'; - exp = exp / 10; - buffer[1] = (exp % 10) + '0'; - exp = exp / 10; - buffer[0] = (exp % 10) + '0'; - buffer += 3; - } else if (fmt == 'f') { - fcvtbuf(cvtbuf, value, precision, decpt, sign); - - const char *digits = cvtbuf; - - if (sign) - *buffer++ = '-'; - if (*digits) { - if (decpt <= 0) { - *buffer++ = '0'; - *buffer++ = '.'; - for (pos = 0; pos < -decpt; pos++) - *buffer++ = '0'; - while (*digits) - *buffer++ = *digits++; - } else { - pos = 0; - while (*digits) { - if (pos++ == decpt) - *buffer++ = '.'; - *buffer++ = *digits++; - } - } - } else { - *buffer++ = '0'; - if (precision > 0) { - *buffer++ = '.'; - for (pos = 0; pos < precision; pos++) - *buffer++ = '0'; - } - } - } - - *buffer = '\0'; -} - -static void forcdecpt(char *buffer) -{ - while (*buffer) { - if (*buffer == '.') - return; - if (*buffer == 'e' || *buffer == 'E') - break; - buffer++; - } - - if (*buffer) { - int n = strlen(buffer); - while (n > 0) { - buffer[n + 1] = buffer[n]; - n--; - } - - *buffer = '.'; - } else { - *buffer++ = '.'; - *buffer = '\0'; - } -} - -static void cropzeros(char *buffer) -{ - char *stop; - - while (*buffer && *buffer != '.') - buffer++; - if (*buffer++) { - while (*buffer && *buffer != 'e' && *buffer != 'E') - buffer++; - stop = buffer--; - while (*buffer == '0') - buffer--; - if (*buffer == '.') - buffer--; - while ((*++buffer = *stop++) != 0) - ; - } -} - -static void flt(std::string &dest, double num, int size, int precision, char fmt, int flags) -{ - char tmp[80]; - char c, sign; - int n; - - // Left align means no zero padding - if (flags & LEFT) - flags &= ~ZEROPAD; - - // Determine padding and sign char - c = (flags & ZEROPAD) ? '0' : ' '; - sign = 0; - if (flags & SIGN) { - if (num < 0.0) { - sign = '-'; - num = -num; - size--; - } else if (flags & PLUS) { - sign = '+'; - size--; - } else if (flags & SPACE) { - sign = ' '; - size--; - } - } - - // Compute the precision value - if (precision < 0) - precision = 6; // Default precision: 6 - else if (precision == 0 && fmt == 'g') - precision = 1; // ANSI specified - - // Convert floating point number to text - cfltcvt(num, tmp, fmt, precision); - - // '#' and precision == 0 means force a decimal point - if ((flags & SPECIAL) && precision == 0) - forcdecpt(tmp); - - // 'g' format means crop zero unless '#' given - if (fmt == 'g' && !(flags & SPECIAL)) - cropzeros(tmp); - - n = strlen(tmp); - - // Output number with alignment and padding - size -= n; - - if (!(flags & (ZEROPAD | LEFT)) && size > 0) { - dest.append(size, ' '); - size = 0; - } - if (sign) - dest += sign; - if (!(flags & LEFT) && size > 0) { - dest.append(size, c); - size = 0; - } - dest.append(tmp, n); - if (size > 0) - dest.append(size, ' '); -} - -#endif - -/////////////////////////////////////////////////////////////////////////// -// This is a "mostly" direct replacement for vsprintf, that is more secure and easier -// to use than vsnprintf or vsprintf_s. See the docs for ssprintf for usage notes. -static void vssappendf(std::string &dest, const char *format, va_list args) -{ - int base; - - int flags; // Flags to number() - - int field_width; // Width of output field - int precision; // Min. # of digits for integers; max number of chars for from string - int qualifier; // 'h', 'l', or 'L' for integer fields - - for (const char *fmt = format; *fmt; ++fmt) { - if (*fmt != '%') { - dest += *fmt; - continue; - } - - // Process flags - flags = 0; - repeat: - fmt++; // This also skips first '%' - switch (*fmt) { - case '-': - flags |= LEFT; - goto repeat; - case '+': - flags |= PLUS; - goto repeat; - case ' ': - flags |= SPACE; - goto repeat; - case '#': - flags |= SPECIAL; - goto repeat; - case '0': - flags |= ZEROPAD; - goto repeat; - } - - // Get field width - field_width = -1; - if (is_digit(*fmt)) - field_width = skip_atoi(&fmt); - else if (*fmt == '*') { - fmt++; - field_width = va_arg(args, int); - if (field_width < 0) { - field_width = -field_width; - flags |= LEFT; - } - } - - // Get the precision - precision = -1; - if (*fmt == '.') { - ++fmt; - if (is_digit(*fmt)) - precision = skip_atoi(&fmt); - else if (*fmt == '*') { - ++fmt; - precision = va_arg(args, int); - } - if (precision < 0) - precision = 0; - } - - // Get the conversion qualifier - qualifier = -1; - if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { - qualifier = *fmt; - fmt++; - } - - // Default base - base = 10; - - switch (*fmt) { - case 'c': - if (!(flags & LEFT)) - while (--field_width > 0) - dest += ' '; - dest += (unsigned char)va_arg(args, int); - while (--field_width > 0) - dest += ' '; - continue; - - case 's': { - // let's add support for std::string as a formatted parameter! (air) - if (qualifier == 'h') { - static const std::string nullstring(""); - - const std::string *ss = va_arg(args, std::string *); - if (ss == NULL) - ss = &nullstring; - int len = ss->length(); - if (precision < 0) { - // no precision override so just copy the whole string. - if (!(flags & LEFT) && (len < field_width)) { - dest.append(field_width - len, ' '); - field_width = 0; - } - dest += *ss; - } else { - if (len > precision) - len = precision; - if (!(flags & LEFT) && (len < field_width)) { - dest.append(field_width - len, ' '); - field_width = 0; - } - dest.append(ss->begin(), ss->begin() + len); - } - - if (len < field_width) - dest.append(field_width - len, ' '); - } else { - const char *s = va_arg(args, char *); - if (!s) - s = ""; - - int len = strlen(s); - if (precision < 0) { - if (!(flags & LEFT)) - while (len < field_width--) - dest += ' '; - dest += s; - } else { - if (len > precision) - len = precision; - if (!(flags & LEFT)) - while (len < field_width--) - dest += ' '; - dest.append(s, s + len); - } - while (len < field_width--) - dest += ' '; - } - } - continue; - - case 'p': { - if (field_width == -1) { - field_width = 2 * sizeof(void *); - flags |= ZEROPAD; - } - // use sptr as it avoids warnings during template code gen. - number(dest, (sptr)va_arg(args, void *), 16, field_width, precision, flags); - } - continue; - - case 'n': - if (qualifier == 'l') { - long *ip = va_arg(args, long *); - *ip = dest.length(); - } else { - int *ip = va_arg(args, int *); - *ip = dest.length(); - } - continue; - - // What the hell is %a? (air) - case 'A': - flags |= LARGE; - - case 'a': - if (qualifier == 'l') - eaddr(dest, va_arg(args, unsigned char *), field_width, precision, flags); - else - iaddr(dest, va_arg(args, unsigned char *), field_width, precision, flags); - continue; - - // Integer number formats - set up the flags and "break" - case 'o': - base = 8; - break; - - case 'X': - flags |= LARGE; - - case 'x': - base = 16; - break; - - case 'd': - case 'i': - flags |= SIGN; - - case 'u': - break; - -#ifndef NOFLOAT - - case 'E': - case 'G': - case 'e': - case 'f': - case 'g': - flt(dest, va_arg(args, double), field_width, precision, *fmt, flags | SIGN); - continue; - -#endif - - default: - if (*fmt != '%') - dest += '%'; - if (*fmt) - dest += *fmt; - else - --fmt; - continue; - } - - if (qualifier == 'L') { - // 64-bit integer support! (air) - number(dest, va_arg(args, s64), base, field_width, precision, flags); - } else { - s32 num; - // Modern 32 bit compilers pass parameters into va_arg by 32 bit scale always, - // so no point in using or checking for the 'h' parameter. - /*if (qualifier == 'h') - num = va_arg(args, int); - else*/ // 'l' qualifier or no qualifier means 32 bits on all our std target platforms. - num = va_arg(args, s32); - - number(dest, num, base, field_width, precision, flags); - } - } -} - -#else -// To keep trace of license :) - /* PCSX2 - PS2 Emulator for PCs * Copyright (C) 2002-2015 PCSX2 Dev Team * @@ -764,6 +13,8 @@ static void vssappendf(std::string &dest, const char *format, va_list args) * If not, see . */ +#include "PrecompiledHeader.h" + // Note: std::vsnprintf requires C++11 (and the function must return the total // number of characters which would have been written even if a truncation occured) // Note2: Code is only used in debugger (perf is not important) @@ -784,16 +35,13 @@ static void vssappendf(std::string &dest, const char *format, va_list args) return; } - // VLA extension. Not sure it is supported on windows. Maybe one days in C++ standard - // Performance is not important here - char output[size]; - std::vsnprintf(output, size, format, args); - dest += output; + std::vector output; + output.resize(size + 1); + std::vsnprintf(output.data(), size, format, args); + + dest += output.data(); } - -#endif - void ssappendf(std::string &dest, const char *format, ...) { va_list args;