Explorar o código

Completed implementing standard formatting.

Bil Bas (Spooner) %!s(int64=10) %!d(string=hai) anos
pai
achega
6306254d37
Modificáronse 2 ficheiros con 135 adicións e 40 borrados
  1. 132 39
      core/ustring.cpp
  2. 3 1
      core/ustring.h

+ 132 - 39
core/ustring.cpp

@@ -35,7 +35,6 @@
 #include "ucaps.h"
 #include "color.h"
 #include "variant.h"
-#include <stdio.h>
 #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);
+
+						// 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 += String(buffer);
+						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);

+ 3 - 1
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;