summaryrefslogtreecommitdiff
path: root/core/string/ustring.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/string/ustring.cpp')
-rw-r--r--core/string/ustring.cpp297
1 files changed, 121 insertions, 176 deletions
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index 8416ff929e..658dbc98cf 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -38,6 +38,7 @@
#include "core/string/translation.h"
#include "core/string/ucaps.h"
#include "core/variant/variant.h"
+#include "core/version_generated.gen.h"
#include <stdio.h>
#include <stdlib.h>
@@ -129,9 +130,8 @@ Char16String &Char16String::operator+=(char16_t p_char) {
return *this;
}
-Char16String &Char16String::operator=(const char16_t *p_cstr) {
+void Char16String::operator=(const char16_t *p_cstr) {
copy_from(p_cstr);
- return *this;
}
const char16_t *Char16String::get_data() const {
@@ -185,9 +185,8 @@ CharString &CharString::operator+=(char p_char) {
return *this;
}
-CharString &CharString::operator=(const char *p_cstr) {
+void CharString::operator=(const char *p_cstr) {
copy_from(p_cstr);
- return *this;
}
const char *CharString::get_data() const {
@@ -952,10 +951,6 @@ const char32_t *String::get_data() const {
return size() ? &operator[](0) : &zero;
}
-void String::erase(int p_pos, int p_chars) {
- *this = left(MAX(p_pos, 0)) + substr(p_pos + p_chars, length() - ((p_pos + p_chars)));
-}
-
String String::capitalize() const {
String aux = this->camelcase_to_underscore(true).replace("_", " ").strip_edges();
String cap;
@@ -1532,108 +1527,24 @@ String String::num_uint64(uint64_t p_num, int base, bool capitalize_hex) {
}
String String::num_real(double p_num, bool p_trailing) {
- if (Math::is_nan(p_num)) {
- return "nan";
- }
-
- if (Math::is_inf(p_num)) {
- if (signbit(p_num)) {
- return "-inf";
+ if (p_num == (double)(int64_t)p_num) {
+ if (p_trailing) {
+ return num_int64((int64_t)p_num) + ".0";
} else {
- return "inf";
+ return num_int64((int64_t)p_num);
}
}
-
- String s;
- String sd;
-
- // Integer part.
-
- bool neg = p_num < 0;
- p_num = ABS(p_num);
- int intn = (int)p_num;
-
- // Decimal part.
-
- if (intn != p_num) {
- double dec = p_num - (double)(intn);
-
- int digit = 0;
-
-#if REAL_T_IS_DOUBLE
- int decimals = 14;
+#ifdef REAL_T_IS_DOUBLE
+ int decimals = 14;
#else
- int decimals = 6;
+ int decimals = 6;
#endif
- // We want to align the digits to the above sane default, so we only
- // need to subtract log10 for numbers with a positive power of ten.
- if (p_num > 10) {
- decimals -= (int)floor(log10(p_num));
- }
-
- if (decimals > MAX_DECIMALS) {
- decimals = MAX_DECIMALS;
- }
-
- int dec_int = 0;
- int dec_max = 0;
-
- while (true) {
- dec *= 10.0;
- dec_int = dec_int * 10 + (int)dec % 10;
- dec_max = dec_max * 10 + 9;
- digit++;
-
- if ((dec - (double)((int)dec)) < 1e-6) {
- break;
- }
-
- if (digit == decimals) {
- break;
- }
- }
-
- dec *= 10;
- int last = (int)dec % 10;
-
- if (last > 5) {
- if (dec_int == dec_max) {
- dec_int = 0;
- intn++;
- } else {
- dec_int++;
- }
- }
-
- String decimal;
- for (int i = 0; i < digit; i++) {
- char num[2] = { 0, 0 };
- num[0] = '0' + dec_int % 10;
- decimal = num + decimal;
- dec_int /= 10;
- }
- sd = '.' + decimal;
- } else if (p_trailing) {
- sd = ".0";
- } else {
- sd = "";
- }
-
- if (intn == 0) {
- s = "0";
- } else {
- while (intn) {
- char32_t num = '0' + (intn % 10);
- intn /= 10;
- s = num + s;
- }
- }
-
- s = s + sd;
- if (neg) {
- s = "-" + s;
+ // We want to align the digits to the above sane default, so we only
+ // need to subtract log10 for numbers with a positive power of ten.
+ if (p_num > 10) {
+ decimals -= (int)floor(log10(p_num));
}
- return s;
+ return num(p_num, decimals);
}
String String::num_scientific(double p_num) {
@@ -2130,7 +2041,7 @@ int64_t String::hex_to_int() const {
s++;
}
- if (len > 2 && s[0] == '0' && s[1] == 'x') {
+ if (len > 2 && s[0] == '0' && lower_case(s[1]) == 'x') {
s += 2;
}
@@ -2144,7 +2055,7 @@ int64_t String::hex_to_int() const {
} else if (c >= 'a' && c <= 'f') {
n = (c - 'a') + 10;
} else {
- return 0;
+ ERR_FAIL_COND_V_MSG(true, 0, "Invalid hexadecimal notation character \"" + chr(*s) + "\" in string \"" + *this + "\".");
}
// Check for overflow/underflow, with special case to ensure INT64_MIN does not result in error
bool overflow = ((hex > INT64_MAX / 16) && (sign == 1 || (sign == -1 && hex != (INT64_MAX >> 4) + 1))) || (sign == -1 && hex == (INT64_MAX >> 4) + 1 && c > '0');
@@ -2171,7 +2082,7 @@ int64_t String::bin_to_int() const {
s++;
}
- if (len > 2 && s[0] == '0' && s[1] == 'b') {
+ if (len > 2 && s[0] == '0' && lower_case(s[1]) == 'b') {
s += 2;
}
@@ -2310,28 +2221,33 @@ bool String::is_numeric() const {
}
template <class C>
-static double built_in_strtod(const C *string, /* A decimal ASCII floating-point number,
- * optionally preceded by white space. Must
- * have form "-I.FE-X", where I is the integer
- * part of the mantissa, F is the fractional
- * part of the mantissa, and X is the
- * exponent. Either of the signs may be "+",
- * "-", or omitted. Either I or F may be
- * omitted, or both. The decimal point isn't
- * necessary unless F is present. The "E" may
- * actually be an "e". E and X may both be
- * omitted (but not just one). */
- C **endPtr = nullptr) /* If non-nullptr, store terminating Cacter's
- * address here. */
-{
- static const int maxExponent = 511; /* Largest possible base 10 exponent. Any
- * exponent larger than this will already
- * produce underflow or overflow, so there's
- * no need to worry about additional digits.
- */
- static const double powersOf10[] = { /* Table giving binary powers of 10. Entry */
- 10., /* is 10^2^i. Used to convert decimal */
- 100., /* exponents into floating-point numbers. */
+static double built_in_strtod(
+ /* A decimal ASCII floating-point number,
+ * optionally preceded by white space. Must
+ * have form "-I.FE-X", where I is the integer
+ * part of the mantissa, F is the fractional
+ * part of the mantissa, and X is the
+ * exponent. Either of the signs may be "+",
+ * "-", or omitted. Either I or F may be
+ * omitted, or both. The decimal point isn't
+ * necessary unless F is present. The "E" may
+ * actually be an "e". E and X may both be
+ * omitted (but not just one). */
+ const C *string,
+ /* If non-nullptr, store terminating Cacter's
+ * address here. */
+ C **endPtr = nullptr) {
+ /* Largest possible base 10 exponent. Any
+ * exponent larger than this will already
+ * produce underflow or overflow, so there's
+ * no need to worry about additional digits. */
+ static const int maxExponent = 511;
+ /* Table giving binary powers of 10. Entry
+ * is 10^2^i. Used to convert decimal
+ * exponents into floating-point numbers. */
+ static const double powersOf10[] = {
+ 10.,
+ 100.,
1.0e4,
1.0e8,
1.0e16,
@@ -2346,25 +2262,28 @@ static double built_in_strtod(const C *string, /* A decimal ASCII floating-point
const double *d;
const C *p;
int c;
- int exp = 0; /* Exponent read from "EX" field. */
- int fracExp = 0; /* Exponent that derives from the fractional
- * part. Under normal circumstances, it is
- * the negative of the number of digits in F.
- * However, if I is very long, the last digits
- * of I get dropped (otherwise a long I with a
- * large negative exponent could cause an
- * unnecessary overflow on I alone). In this
- * case, fracExp is incremented one for each
- * dropped digit. */
- int mantSize; /* Number of digits in mantissa. */
- int decPt; /* Number of mantissa digits BEFORE decimal
- * point. */
- const C *pExp; /* Temporarily holds location of exponent in
- * string. */
+ /* Exponent read from "EX" field. */
+ int exp = 0;
+ /* Exponent that derives from the fractional
+ * part. Under normal circumstances, it is
+ * the negative of the number of digits in F.
+ * However, if I is very long, the last digits
+ * of I get dropped (otherwise a long I with a
+ * large negative exponent could cause an
+ * unnecessary overflow on I alone). In this
+ * case, fracExp is incremented one for each
+ * dropped digit. */
+ int fracExp = 0;
+ /* Number of digits in mantissa. */
+ int mantSize;
+ /* Number of mantissa digits BEFORE decimal point. */
+ int decPt;
+ /* Temporarily holds location of exponent in string. */
+ const C *pExp;
/*
- * Strip off leading blanks and check for a sign.
- */
+ * Strip off leading blanks and check for a sign.
+ */
p = string;
while (*p == ' ' || *p == '\t' || *p == '\n') {
@@ -2381,9 +2300,9 @@ static double built_in_strtod(const C *string, /* A decimal ASCII floating-point
}
/*
- * Count the number of digits in the mantissa (including the decimal
- * point), and also locate the decimal point.
- */
+ * Count the number of digits in the mantissa (including the decimal
+ * point), and also locate the decimal point.
+ */
decPt = -1;
for (mantSize = 0;; mantSize += 1) {
@@ -2398,11 +2317,11 @@ static double built_in_strtod(const C *string, /* A decimal ASCII floating-point
}
/*
- * Now suck up the digits in the mantissa. Use two integers to collect 9
- * digits each (this is faster than using floating-point). If the mantissa
- * has more than 18 digits, ignore the extras, since they can't affect the
- * value anyway.
- */
+ * Now suck up the digits in the mantissa. Use two integers to collect 9
+ * digits each (this is faster than using floating-point). If the mantissa
+ * has more than 18 digits, ignore the extras, since they can't affect the
+ * value anyway.
+ */
pExp = p;
p -= mantSize;
@@ -2448,8 +2367,8 @@ static double built_in_strtod(const C *string, /* A decimal ASCII floating-point
}
/*
- * Skim off the exponent.
- */
+ * Skim off the exponent.
+ */
p = pExp;
if ((*p == 'E') || (*p == 'e')) {
@@ -2479,10 +2398,10 @@ static double built_in_strtod(const C *string, /* A decimal ASCII floating-point
}
/*
- * Generate a floating-point number that represents the exponent. Do this
- * by processing the exponent one bit at a time to combine many powers of
- * 2 of 10. Then combine the exponent with the fraction.
- */
+ * Generate a floating-point number that represents the exponent. Do this
+ * by processing the exponent one bit at a time to combine many powers of
+ * 2 of 10. Then combine the exponent with the fraction.
+ */
if (exp < 0) {
expSign = true;
@@ -3497,6 +3416,27 @@ char32_t String::unicode_at(int p_idx) const {
return operator[](p_idx);
}
+String String::indent(const String &p_prefix) const {
+ String new_string;
+ int line_start = 0;
+
+ for (int i = 0; i < length(); i++) {
+ const char32_t c = operator[](i);
+ if (c == '\n') {
+ if (i == line_start) {
+ new_string += c; // Leave empty lines empty.
+ } else {
+ new_string += p_prefix + substr(line_start, i - line_start + 1);
+ }
+ line_start = i + 1;
+ }
+ }
+ if (line_start != length()) {
+ new_string += p_prefix + substr(line_start);
+ }
+ return new_string;
+}
+
String String::dedent() const {
String new_string;
String indent;
@@ -3555,7 +3495,7 @@ String String::strip_edges(bool left, bool right) const {
}
if (right) {
- for (int i = (int)(len - 1); i >= 0; i--) {
+ for (int i = len - 1; i >= 0; i--) {
if (operator[](i) <= 32) {
end--;
} else {
@@ -3658,15 +3598,15 @@ String String::simplify_path() const {
for (int i = 0; i < dirs.size(); i++) {
String d = dirs[i];
if (d == ".") {
- dirs.remove(i);
+ dirs.remove_at(i);
i--;
} else if (d == "..") {
if (i == 0) {
- dirs.remove(i);
+ dirs.remove_at(i);
i--;
} else {
- dirs.remove(i);
- dirs.remove(i - 1);
+ dirs.remove_at(i);
+ dirs.remove_at(i - 1);
i -= 2;
}
}
@@ -4273,7 +4213,7 @@ bool String::is_valid_filename() const {
return false;
}
- if (stripped == String()) {
+ if (stripped.is_empty()) {
return false;
}
@@ -4405,7 +4345,7 @@ String String::property_name_encode() const {
// as well as '"', '=' or ' ' (32)
const char32_t *cstr = get_data();
for (int i = 0; cstr[i]; i++) {
- if (cstr[i] == '=' || cstr[i] == '"' || cstr[i] < 33 || cstr[i] > 126) {
+ if (cstr[i] == '=' || cstr[i] == '"' || cstr[i] == ';' || cstr[i] == '[' || cstr[i] == ']' || cstr[i] < 33 || cstr[i] > 126) {
return "\"" + c_escape_multiline() + "\"";
}
}
@@ -4857,15 +4797,20 @@ String TTRN(const String &p_text, const String &p_text_plural, int p_n, const St
return p_text_plural;
}
+/* DTR and DTRN are used for the documentation, handling descriptions extracted
+ * from the XML.
+ * They also replace `$DOCS_URL` with the actual URL to the documentation's branch,
+ * to allow dehardcoding it in the XML and doing proper substitutions everywhere.
+ */
String DTR(const String &p_text, const String &p_context) {
// Comes straight from the XML, so remove indentation and any trailing whitespace.
const String text = p_text.dedent().strip_edges();
if (TranslationServer::get_singleton()) {
- return TranslationServer::get_singleton()->doc_translate(text, p_context);
+ return String(TranslationServer::get_singleton()->doc_translate(text, p_context)).replace("$DOCS_URL", VERSION_DOCS_URL);
}
- return text;
+ return text.replace("$DOCS_URL", VERSION_DOCS_URL);
}
String DTRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context) {
@@ -4873,21 +4818,21 @@ String DTRN(const String &p_text, const String &p_text_plural, int p_n, const St
const String text_plural = p_text_plural.dedent().strip_edges();
if (TranslationServer::get_singleton()) {
- return TranslationServer::get_singleton()->doc_translate_plural(text, text_plural, p_n, p_context);
+ return String(TranslationServer::get_singleton()->doc_translate_plural(text, text_plural, p_n, p_context)).replace("$DOCS_URL", VERSION_DOCS_URL);
}
// Return message based on English plural rule if translation is not possible.
if (p_n == 1) {
- return text;
+ return text.replace("$DOCS_URL", VERSION_DOCS_URL);
}
- return text_plural;
+ return text_plural.replace("$DOCS_URL", VERSION_DOCS_URL);
}
#endif
String RTR(const String &p_text, const String &p_context) {
if (TranslationServer::get_singleton()) {
String rtr = TranslationServer::get_singleton()->tool_translate(p_text, p_context);
- if (rtr == String() || rtr == p_text) {
+ if (rtr.is_empty() || rtr == p_text) {
return TranslationServer::get_singleton()->translate(p_text, p_context);
} else {
return rtr;
@@ -4900,7 +4845,7 @@ String RTR(const String &p_text, const String &p_context) {
String RTRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context) {
if (TranslationServer::get_singleton()) {
String rtr = TranslationServer::get_singleton()->tool_translate_plural(p_text, p_text_plural, p_n, p_context);
- if (rtr == String() || rtr == p_text || rtr == p_text_plural) {
+ if (rtr.is_empty() || rtr == p_text || rtr == p_text_plural) {
return TranslationServer::get_singleton()->translate_plural(p_text, p_text_plural, p_n, p_context);
} else {
return rtr;