Added basic sprintf functionality (e.g. "fish %d %s" % [12, Vector2(1, 2)])
This commit is contained in:
parent
d6d85a23c9
commit
7a41f8c604
|
@ -487,7 +487,7 @@ struct test_27_data {
|
|||
|
||||
bool test_27() {
|
||||
|
||||
OS::get_singleton()->print("\n\nTest 26: begins_with\n");
|
||||
OS::get_singleton()->print("\n\nTest 27: begins_with\n");
|
||||
test_27_data tc[] = {
|
||||
{"res://foobar", "res://", true},
|
||||
{"res", "res://", false},
|
||||
|
@ -504,11 +504,87 @@ bool test_27() {
|
|||
}
|
||||
if (!state) {
|
||||
OS::get_singleton()->print("\n\t Failure on:\n\t\tstring: ", tc[i].data, "\n\t\tbegin: ", tc[i].begin, "\n\t\texpected: ", tc[i].expected ? "true" : "false", "\n");
|
||||
break;
|
||||
}
|
||||
};
|
||||
return state;
|
||||
};
|
||||
|
||||
|
||||
bool test_28() {
|
||||
|
||||
OS::get_singleton()->print("\n\nTest 28: sprintf\n");
|
||||
|
||||
bool success, state = true;
|
||||
char output_format[] = "\tTest:\t%ls => %ls (%s)\n";
|
||||
String format, output;
|
||||
Array args;
|
||||
|
||||
// %%
|
||||
format = "fish %% frog";
|
||||
args.clear();
|
||||
output = format.sprintf(args);
|
||||
success = (format.sprintf(args) == String("fish % frog"));
|
||||
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
|
||||
if (!success) state = false;
|
||||
|
||||
// Int
|
||||
format = "fish %d frog";
|
||||
args.clear();
|
||||
args.push_back(5);
|
||||
output = format.sprintf(args);
|
||||
success = (format.sprintf(args) == String("fish 5 frog"));
|
||||
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
|
||||
if (!success) state = false;
|
||||
|
||||
// Hex (lower)
|
||||
format = "fish %x frog";
|
||||
args.clear();
|
||||
args.push_back(45);
|
||||
output = format.sprintf(args);
|
||||
success = (format.sprintf(args) == String("fish 2d frog"));
|
||||
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
|
||||
if (!success) state = false;
|
||||
|
||||
// Hex (upper)
|
||||
format = "fish %X frog";
|
||||
args.clear();
|
||||
args.push_back(45);
|
||||
output = format.sprintf(args);
|
||||
success = (format.sprintf(args) == String("fish 2D frog"));
|
||||
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
|
||||
if (!success) state = false;
|
||||
|
||||
// Octal
|
||||
format = "fish %o frog";
|
||||
args.clear();
|
||||
args.push_back(99);
|
||||
output = format.sprintf(args);
|
||||
success = (format.sprintf(args) == String("fish 143 frog"));
|
||||
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
|
||||
if (!success) state = false;
|
||||
|
||||
// Real
|
||||
format = "fish %f frog";
|
||||
args.clear();
|
||||
args.push_back(99.99);
|
||||
output = format.sprintf(args);
|
||||
success = (format.sprintf(args) == String("fish 99.990000 frog"));
|
||||
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
|
||||
if (!success) state = false;
|
||||
|
||||
// String
|
||||
format = "fish %s frog";
|
||||
args.clear();
|
||||
args.push_back("cheese");
|
||||
output = format.sprintf(args);
|
||||
success = (format.sprintf(args) == String("fish cheese frog"));
|
||||
OS::get_singleton()->print(output_format , format.c_str(), output.c_str(), success ? "OK" : "FAIL");
|
||||
if (!success) state = false;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
typedef bool (*TestFunc)(void);
|
||||
|
||||
TestFunc test_funcs[] = {
|
||||
|
@ -540,6 +616,7 @@ TestFunc test_funcs[] = {
|
|||
test_25,
|
||||
test_26,
|
||||
test_27,
|
||||
test_28,
|
||||
0
|
||||
|
||||
};
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include "io/md5.h"
|
||||
#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))
|
||||
|
@ -3518,4 +3520,100 @@ String rtoss(double p_val) {
|
|||
return String::num_scientific(p_val);
|
||||
}
|
||||
|
||||
// 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";
|
||||
|
||||
for (; *self; self++) {
|
||||
const CharType c = *self;
|
||||
|
||||
if (in_format) { // We have % - lets see what else we get.
|
||||
switch (c) {
|
||||
case '%': // Manage %% as %
|
||||
formatted += chr(c);
|
||||
in_format = false;
|
||||
break;
|
||||
|
||||
case 'd': // Integer (signed)
|
||||
case 'o': // Octal
|
||||
case 'x': // Hexadecimal (lowercase)
|
||||
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);
|
||||
++value_index;
|
||||
in_format = false;
|
||||
} else {
|
||||
// TODO: Error?
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'f': // Float
|
||||
if (values[value_index].is_num()) {
|
||||
char buffer[OUTPUT_BUFFER_SIZE];
|
||||
double value = values[value_index];
|
||||
::sprintf(buffer, "%f", value);
|
||||
|
||||
formatted += String(buffer);
|
||||
++value_index;
|
||||
in_format = false;
|
||||
} else {
|
||||
// TODO: Error?
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 's': // String
|
||||
String value = values[value_index];
|
||||
formatted += value;
|
||||
++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 '*': // Dyanmic width, based on value.
|
||||
// break;
|
||||
|
||||
//default:
|
||||
// TODO: error?
|
||||
}
|
||||
} else { // Not in format string.
|
||||
switch (c) {
|
||||
case '%':
|
||||
in_format = true;
|
||||
break;
|
||||
default:
|
||||
formatted += chr(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return formatted;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
#include "typedefs.h"
|
||||
#include "vector.h"
|
||||
#include "array.h"
|
||||
|
||||
/**
|
||||
@author red <red@killy>
|
||||
|
@ -127,6 +128,7 @@ 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 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);
|
||||
|
@ -203,7 +205,7 @@ public:
|
|||
String xml_unescape() const;
|
||||
String c_escape() const;
|
||||
String c_unescape() const;
|
||||
|
||||
|
||||
String percent_encode() const;
|
||||
String percent_decode() const;
|
||||
|
||||
|
|
|
@ -736,6 +736,20 @@ void Variant::evaluate(const Operator& p_op, const Variant& p_a, const Variant&
|
|||
}
|
||||
#endif
|
||||
_RETURN( p_a._data._int % p_b._data._int );
|
||||
|
||||
} else if (p_a.type==STRING) {
|
||||
const String *str=reinterpret_cast<const String*>(p_a._data._mem);
|
||||
|
||||
if (p_b.type==ARRAY) {
|
||||
// e.g. "frog %s %d" % ["fish", 12]
|
||||
const Array *arr=reinterpret_cast<const Array*>(p_b._data._mem);
|
||||
_RETURN(str->sprintf(*arr));
|
||||
} else {
|
||||
// e.g. "frog %d" % 12
|
||||
Array arr;
|
||||
arr.push_back(p_b);
|
||||
_RETURN(str->sprintf(arr));
|
||||
}
|
||||
}
|
||||
|
||||
r_valid=false;
|
||||
|
|
Loading…
Reference in New Issue