diff --git a/core/ustring.cpp b/core/ustring.cpp index a7359f112f..222c445b43 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -35,7 +35,6 @@ #include "ucaps.h" #include "color.h" #include "variant.h" -#include #define MAX_DIGITS 6 #define UPPERCASE(m_c) (((m_c)>='a' && (m_c)<='z')?((m_c)-('a'-'A')):(m_c)) #define LOWERCASE(m_c) (((m_c)>='A' && (m_c)<='Z')?((m_c)+('a'-'A')):(m_c)) @@ -983,7 +982,7 @@ String String::num(double p_num,int p_decimals) { } -String String::num_int64(int64_t p_num) { +String String::num_int64(int64_t p_num, int base, bool capitalize_hex) { bool sign=p_num<0; int64_t num=ABS(p_num); @@ -992,7 +991,7 @@ String String::num_int64(int64_t p_num) { int chars=0; do { - n/=10; + n/=base; chars++; } while(n); @@ -1004,8 +1003,15 @@ String String::num_int64(int64_t p_num) { c[chars]=0; n=num; do { - c[--chars]='0'+(n%10); - n/=10; + int mod = n%base; + if (mod >= 10) { + char a = (capitalize_hex ? 'A' : 'a'); + c[--chars]=a+(mod - 10); + } else { + c[--chars]='0'+mod; + } + + n/=base; } while(n); if (sign) @@ -3520,41 +3526,84 @@ String rtoss(double p_val) { return String::num_scientific(p_val); } +// Right-pad with a character. +String String::rpad(int min_length, const String& character) const { + String s = *this; + int padding = min_length - s.length(); + if (padding > 0) { + for (int i = 0; i < padding; i++) s = s + character; + } + + return s; +} +// Left-pad with a character. +String String::lpad(int min_length, const String& character) const { + String s = *this; + int padding = min_length - s.length(); + if (padding > 0) { + for (int i = 0; i < padding; i++) s = character + s; + } + + return s; +} + // sprintf is implemented in GDScript via: // "fish %s pie" % "frog" // "fish %s %d pie" % ["frog", 12] -const int FORMAT_BUFFER_SIZE = 1024; -const int OUTPUT_BUFFER_SIZE = 1024 * 100; String String::sprintf(const Array& values) const { String formatted; CharType* self = (CharType*)c_str(); bool in_format = false; int value_index = 0; - char format_format[FORMAT_BUFFER_SIZE] = "%d"; + int min_chars; + int num_decimals; + bool in_decimals; + bool pad_with_zeroes; + bool left_justified; + bool show_sign; for (; *self; self++) { const CharType c = *self; if (in_format) { // We have % - lets see what else we get. switch (c) { - case '%': // Manage %% as % + case '%': { // Replace %% with % formatted += chr(c); in_format = false; break; - + } case 'd': // Integer (signed) case 'o': // Octal case 'x': // Hexadecimal (lowercase) - case 'X': // Hexadecimal (uppercase) + case 'X': { // Hexadecimal (uppercase) if (values[value_index].is_num()) { - char buffer[OUTPUT_BUFFER_SIZE]; - int value = values[value_index]; - format_format[1] = c; - format_format[2] = 0; - ::sprintf(buffer, format_format, value); - - formatted += String(buffer); + int64_t value = values[value_index]; + int base; + bool capitalize = false; + switch (c) { + case 'd': base = 10; break; + case 'o': base = 8; break; + case 'x': base = 16; break; + case 'X': base = 16; capitalize = true; break; + } + // Get basic number. + String str = String::num_int64(value, base, capitalize); + + // Sign. + if (show_sign && value >= 0) { + str = str.insert(0, "+"); + } + + // Padding. + String pad_char = pad_with_zeroes ? String("0") : String(" "); + if (left_justified) { + str = str.rpad(min_chars, pad_char); + } else { + str = str.lpad(min_chars, pad_char); + } + + formatted += str; ++value_index; in_format = false; } else { @@ -3562,14 +3611,28 @@ String String::sprintf(const Array& values) const { } break; - - case 'f': // Float + } + case 'f': { // Float if (values[value_index].is_num()) { - char buffer[OUTPUT_BUFFER_SIZE]; double value = values[value_index]; - ::sprintf(buffer, "%f", value); + String str = String::num(value, num_decimals); - formatted += String(buffer); + // Pad decimals out. + str = str.pad_decimals(num_decimals); + + // Show sign + if (show_sign && value >= 0) { + str = str.insert(0, "+"); + } + + // Padding + if (left_justified) { + str = str.rpad(min_chars); + } else { + str = str.lpad(min_chars); + } + + formatted += str; ++value_index; in_format = false; } else { @@ -3577,26 +3640,49 @@ String String::sprintf(const Array& values) const { } break; + } + case 's': { // String + String str = values[value_index]; + // Padding. + if (left_justified) { + str = str.rpad(min_chars); + } else { + str = str.lpad(min_chars); + } - case 's': // String - String value = values[value_index]; - formatted += value; + formatted += str; ++value_index; in_format = false; break; - - // case '-': // Left justify - // break; - - // case '+': // Show + if positive. - // break; - - // case '0': case '1': case '2': case '3': case '4': - // case '5': case '6': case '7': case '8': case '9': - // break; - - // case '.': // Float separtor. - // break; + } + case '-': { // Left justify + left_justified = true; + break; + } + case '+': { // Show + if positive. + show_sign = true; + break; + } + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': { + int n = c - '0'; + if (in_decimals) { + num_decimals *= 10; + num_decimals += n; + } else { + if (c == '0' && min_chars == 0) { + pad_with_zeroes = true; + } else { + min_chars *= 10; + min_chars += n; + } + } + break; + } + case '.': // Float separtor. + in_decimals = true; + num_decimals = 0; // We want to add the value manually. + break; // case '*': // Dyanmic width, based on value. // break; @@ -3608,6 +3694,13 @@ String String::sprintf(const Array& values) const { switch (c) { case '%': in_format = true; + // Back to defaults: + min_chars = 0; + num_decimals = 6; + pad_with_zeroes = false; + left_justified = false; + show_sign = false; + in_decimals = false; break; default: formatted += chr(c); diff --git a/core/ustring.h b/core/ustring.h index ccbbf5e5d2..af5ffb7c35 100644 --- a/core/ustring.h +++ b/core/ustring.h @@ -128,11 +128,13 @@ public: String insert(int p_at_pos,String p_string) const; String pad_decimals(int p_digits) const; String pad_zeros(int p_digits) const; + String lpad(int min_length,const String& character=" ") const; + String rpad(int min_length,const String& character=" ") const; String sprintf(const Array& values) const; static String num(double p_num,int p_decimals=-1); static String num_scientific(double p_num); static String num_real(double p_num); - static String num_int64(int64_t p_num); + static String num_int64(int64_t p_num,int base=10,bool capitalize_hex=false); static String chr(CharType p_char); static String md5(const uint8_t *p_md5); bool is_numeric() const;