summaryrefslogtreecommitdiffstats
path: root/src/corelib/text/qlocale.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/text/qlocale.cpp')
-rw-r--r--src/corelib/text/qlocale.cpp243
1 files changed, 116 insertions, 127 deletions
diff --git a/src/corelib/text/qlocale.cpp b/src/corelib/text/qlocale.cpp
index 65b8e03890..0525d5ac23 100644
--- a/src/corelib/text/qlocale.cpp
+++ b/src/corelib/text/qlocale.cpp
@@ -46,6 +46,8 @@ QT_WARNING_DISABLE_GCC("-Wfree-nonheap-object") // false positive tracking
#include "private/qgregoriancalendar_p.h"
#include "qcalendar.h"
+#include <q20iterator.h>
+
QT_BEGIN_NAMESPACE
QT_IMPL_METATYPE_EXTERN_TAGGED(QList<Qt::DayOfWeek>, QList_Qt__DayOfWeek)
@@ -175,7 +177,7 @@ QLocale::Script QLocalePrivate::codeToScript(QStringView code) noexcept
unsigned char c3 = code[3].toLower().toLatin1();
const unsigned char *c = script_code_list;
- for (int i = 0; i < QLocale::LastScript; ++i, c += 4) {
+ for (qsizetype i = 0; i < QLocale::LastScript; ++i, c += 4) {
if (c0 == c[0] && c1 == c[1] && c2 == c[2] && c3 == c[3])
return QLocale::Script(i);
}
@@ -461,9 +463,9 @@ QByteArray QLocalePrivate::bcp47Name(char separator) const
return m_data->id().withLikelySubtagsRemoved().name(separator);
}
-static int findLocaleIndexById(const QLocaleId &localeId)
+static qsizetype findLocaleIndexById(const QLocaleId &localeId)
{
- quint16 idx = locale_index[localeId.language_id];
+ qsizetype idx = locale_index[localeId.language_id];
// If there are no locales for specified language (so we we've got the
// default language, which has no associated script or country), give up:
if (localeId.language_id && idx == 0)
@@ -480,14 +482,14 @@ static int findLocaleIndexById(const QLocaleId &localeId)
return -1;
}
-int QLocaleData::findLocaleIndex(QLocaleId lid)
+qsizetype QLocaleData::findLocaleIndex(QLocaleId lid)
{
QLocaleId localeId = lid;
QLocaleId likelyId = localeId.withLikelySubtagsAdded();
const ushort fallback = likelyId.language_id;
// Try a straight match with the likely data:
- int index = findLocaleIndexById(likelyId);
+ qsizetype index = findLocaleIndexById(likelyId);
if (index >= 0)
return index;
QVarLengthArray<QLocaleId, 6> tried;
@@ -530,13 +532,13 @@ int QLocaleData::findLocaleIndex(QLocaleId lid)
return locale_index[fallback];
}
-static QStringView findTag(QStringView name)
+static QStringView findTag(QStringView name) noexcept
{
- const QString separators = QStringLiteral("_-.@");
- int i = 0;
- while (i < name.size() && !separators.contains(name[i]))
- i++;
- return name.first(i);
+ const std::u16string_view v(name.utf16(), size_t(name.size()));
+ const auto i = v.find_first_of(u"_-.@");
+ if (i == std::string_view::npos)
+ return name;
+ return name.first(qsizetype(i));
}
static bool validTag(QStringView tag)
@@ -557,7 +559,7 @@ static bool isScript(QStringView tag)
static const QString allScripts =
QString::fromLatin1(reinterpret_cast<const char *>(script_code_list),
sizeof(script_code_list) - 1);
- return tag.length() == 4 && allScripts.indexOf(tag) % 4 == 0;
+ return tag.size() == 4 && allScripts.indexOf(tag) % 4 == 0;
}
bool qt_splitLocaleName(QStringView name, QStringView *lang, QStringView *script, QStringView *land)
@@ -618,9 +620,9 @@ QLocaleId QLocaleId::fromName(QStringView name)
return { langId, QLocalePrivate::codeToScript(script), QLocalePrivate::codeToTerritory(land) };
}
-QString qt_readEscapedFormatString(QStringView format, int *idx)
+QString qt_readEscapedFormatString(QStringView format, qsizetype *idx)
{
- int &i = *idx;
+ qsizetype &i = *idx;
Q_ASSERT(format.at(i) == u'\'');
++i;
@@ -796,7 +798,7 @@ static const QLocaleData *defaultData()
return default_data;
}
-static uint defaultIndex()
+static qsizetype defaultIndex()
{
const QLocaleData *const data = defaultData();
#ifndef QT_NO_SYSTEMLOCALE
@@ -807,8 +809,8 @@ static uint defaultIndex()
}
#endif
- Q_ASSERT(data >= locale_data);
- Q_ASSERT(data < locale_data + std::size(locale_data));
+ using QtPrivate::q_points_into_range;
+ Q_ASSERT(q_points_into_range(data, locale_data, std::end(locale_data)));
return data - locale_data;
}
@@ -834,7 +836,7 @@ QDataStream &operator>>(QDataStream &ds, QLocale &l)
}
#endif // QT_NO_DATASTREAM
-static const int locale_data_size = sizeof(locale_data)/sizeof(QLocaleData) - 1;
+static constexpr qsizetype locale_data_size = q20::ssize(locale_data) - 1; // trailing guard
Q_CONSTINIT QBasicAtomicInt QLocalePrivate::s_generation = Q_BASIC_ATOMIC_INITIALIZER(0);
Q_GLOBAL_STATIC(QSharedDataPointer<QLocalePrivate>, defaultLocalePrivate,
@@ -844,8 +846,8 @@ static QLocalePrivate *localePrivateByName(QStringView name)
{
if (name == u"C")
return c_private();
- const int index = QLocaleData::findLocaleIndex(QLocaleId::fromName(name));
- Q_ASSERT(index >= 0 && size_t(index) < std::size(locale_data) - 1);
+ const qsizetype index = QLocaleData::findLocaleIndex(QLocaleId::fromName(name));
+ Q_ASSERT(index >= 0 && index < locale_data_size);
return new QLocalePrivate(locale_data + index, index,
locale_data[index].m_language_id == QLocale::C
? QLocale::OmitGroupSeparator : QLocale::DefaultNumberOptions);
@@ -857,8 +859,8 @@ static QLocalePrivate *findLocalePrivate(QLocale::Language language, QLocale::Sc
if (language == QLocale::C)
return c_private();
- int index = QLocaleData::findLocaleIndex(QLocaleId { language, script, territory });
- Q_ASSERT(index >= 0 && size_t(index) < std::size(locale_data) - 1);
+ qsizetype index = QLocaleData::findLocaleIndex(QLocaleId { language, script, territory });
+ Q_ASSERT(index >= 0 && index < locale_data_size);
const QLocaleData *data = locale_data + index;
QLocale::NumberOptions numberOptions = QLocale::DefaultNumberOptions;
@@ -873,29 +875,41 @@ static QLocalePrivate *findLocalePrivate(QLocale::Language language, QLocale::Sc
return new QLocalePrivate(data, index, numberOptions);
}
-QString QLocaleData::decimalPoint() const
+static std::optional<QString>
+systemLocaleString(const QLocaleData *that, QSystemLocale::QueryType type)
{
#ifndef QT_NO_SYSTEMLOCALE
- if (this == &systemLocaleData) {
- auto res = systemLocale()->query(QSystemLocale::DecimalPoint).toString();
- if (!res.isEmpty())
- return res;
- }
+ if (that != &systemLocaleData)
+ return std::nullopt;
+
+ QVariant v = systemLocale()->query(type);
+ if (v.metaType() != QMetaType::fromType<QString>())
+ return std::nullopt;
+
+ return v.toString();
+#else
+ Q_UNUSED(that)
+ Q_UNUSED(type)
+ return std::nullopt;
#endif
- return decimalSeparator().getData(single_character_data);
+}
+
+static QString localeString(const QLocaleData *that, QSystemLocale::QueryType type,
+ QLocaleData::DataRange range)
+{
+ if (auto opt = systemLocaleString(that, type))
+ return *opt;
+ return range.getData(single_character_data);
+}
+
+QString QLocaleData::decimalPoint() const
+{
+ return localeString(this, QSystemLocale::DecimalPoint, decimalSeparator());
}
QString QLocaleData::groupSeparator() const
{
- // Empty => don't do grouping
-#ifndef QT_NO_SYSTEMLOCALE
- if (this == &systemLocaleData) {
- QVariant res = systemLocale()->query(QSystemLocale::GroupSeparator);
- if (!res.isNull())
- return res.toString();
- }
-#endif
- return groupDelim().getData(single_character_data);
+ return localeString(this, QSystemLocale::GroupSeparator, groupDelim());
}
QString QLocaleData::percentSign() const
@@ -910,14 +924,7 @@ QString QLocaleData::listSeparator() const
QString QLocaleData::zeroDigit() const
{
-#ifndef QT_NO_SYSTEMLOCALE
- if (this == &systemLocaleData) {
- auto res = systemLocale()->query(QSystemLocale::ZeroDigit).toString();
- if (!res.isEmpty())
- return res;
- }
-#endif
- return zero().getData(single_character_data);
+ return localeString(this, QSystemLocale::ZeroDigit, zero());
}
char32_t QLocaleData::zeroUcs() const
@@ -938,26 +945,12 @@ char32_t QLocaleData::zeroUcs() const
QString QLocaleData::negativeSign() const
{
-#ifndef QT_NO_SYSTEMLOCALE
- if (this == &systemLocaleData) {
- auto res = systemLocale()->query(QSystemLocale::NegativeSign).toString();
- if (!res.isEmpty())
- return res;
- }
-#endif
- return minus().getData(single_character_data);
+ return localeString(this, QSystemLocale::NegativeSign, minus());
}
QString QLocaleData::positiveSign() const
{
-#ifndef QT_NO_SYSTEMLOCALE
- if (this == &systemLocaleData) {
- auto res = systemLocale()->query(QSystemLocale::PositiveSign).toString();
- if (!res.isEmpty())
- return res;
- }
-#endif
- return plus().getData(single_character_data);
+ return localeString(this, QSystemLocale::PositiveSign, plus());
}
QString QLocaleData::exponentSeparator() const
@@ -2099,7 +2092,7 @@ QString QLocale::toString(QDate date, FormatType format) const
static bool timeFormatContainsAP(QStringView format)
{
- int i = 0;
+ qsizetype i = 0;
while (i < format.size()) {
if (format.at(i).unicode() == '\'') {
qt_readEscapedFormatString(format, &i);
@@ -2620,21 +2613,17 @@ static bool qIsUpper(char c)
The \a format defaults to \c{'g'}. It can be any of the following:
\table
- \header \li Format \li Meaning
- \row \li \c 'e' \li format as [-]9.9e[+|-]999
- \row \li \c 'E' \li format as [-]9.9E[+|-]999
- \row \li \c 'f' \li format as [-]9.9
- \row \li \c 'F' \li same as \c 'f' except for INF and NAN (see below)
- \row \li \c 'g' \li use \c 'e' or \c 'f' format, whichever is more concise
- \row \li \c 'G' \li use \c 'E' or \c 'F' format, whichever is more concise
+ \header \li Format \li Meaning \li Meaning of \a precision
+ \row \li \c 'e' \li format as [-]9.9e[+|-]999 \li number of digits \e after the decimal point
+ \row \li \c 'E' \li format as [-]9.9E[+|-]999 \li "
+ \row \li \c 'f' \li format as [-]9.9 \li "
+ \row \li \c 'F' \li same as \c 'f' except for INF and NAN (see below) \li "
+ \row \li \c 'g' \li use \c 'e' or \c 'f' format, whichever is more concise \li maximum number of significant digits (trailing zeroes are omitted)
+ \row \li \c 'G' \li use \c 'E' or \c 'F' format, whichever is more concise \li "
\endtable
- For the \c 'e', \c 'E', \c 'f' and \c 'F' formats, the \a precision
- represents the number of digits \e after the decimal point. For the \c 'g'
- and \c 'G' formats, the \a precision represents the maximum number of
- significant digits (trailing zeroes are omitted). The special \a precision
- value QLocale::FloatingPointShortest selects the shortest representation
- that, when read as a number, gets back the original floating-point
+ The special \a precision value QLocale::FloatingPointShortest selects the
+ shortest representation that, when read as a number, gets back the original floating-point
value. Aside from that, any negative \a precision is ignored in favor of the
default, 6.
@@ -3325,7 +3314,7 @@ QString QCalendarBackend::dateTimeToString(QStringView format, const QDateTime &
day = parts.day;
}
- int i = 0;
+ qsizetype i = 0;
while (i < format.size()) {
if (format.at(i).unicode() == '\'') {
result.append(qt_readEscapedFormatString(format, &i));
@@ -3586,7 +3575,7 @@ QString QLocaleData::doubleToString(double d, int precision, DoubleForm form,
Q_ASSERT(!zero.at(0).isSurrogate());
char16_t z = zero.at(0).unicode();
char16_t *const value = reinterpret_cast<char16_t *>(digits.data());
- for (int i = 0; i < digits.length(); ++i)
+ for (qsizetype i = 0; i < digits.size(); ++i)
value[i] = unicodeForDigit(value[i] - '0', z);
}
@@ -3634,7 +3623,7 @@ QString QLocaleData::doubleToString(double d, int precision, DoubleForm form,
// Assume digitCount < 95, so we can ignore the 3-digit
// exponent case (we'll set useDecimal false anyway).
- const int digitCount = digits.length() / zero.size();
+ const qsizetype digitCount = digits.size() / zero.size();
if (!mustMarkDecimal) {
// Decimal separator is skipped if at end; adjust if
// that happens for only one form:
@@ -3668,7 +3657,7 @@ QString QLocaleData::doubleToString(double d, int precision, DoubleForm form,
// Pad with zeros. LeftAdjusted overrides ZeroPadded.
if (flags & ZeroPadded && !(flags & LeftAdjusted)) {
- for (int i = numStr.length() / zero.length() + prefix.size(); i < width; ++i)
+ for (qsizetype i = numStr.size() / zero.size() + prefix.size(); i < width; ++i)
numStr.prepend(zero);
}
}
@@ -3691,30 +3680,30 @@ QString QLocaleData::decimalForm(QString &&digits, int decpt, int precision,
for (; decpt < 0; ++decpt)
digits.prepend(zero);
} else {
- for (int i = digits.length() / digitWidth; i < decpt; ++i)
+ for (qsizetype i = digits.size() / digitWidth; i < decpt; ++i)
digits.append(zero);
}
switch (pm) {
case PMDecimalDigits:
- for (int i = digits.length() / digitWidth - decpt; i < precision; ++i)
+ for (qsizetype i = digits.size() / digitWidth - decpt; i < precision; ++i)
digits.append(zero);
break;
case PMSignificantDigits:
- for (int i = digits.length() / digitWidth; i < precision; ++i)
+ for (qsizetype i = digits.size() / digitWidth; i < precision; ++i)
digits.append(zero);
break;
case PMChopTrailingZeros:
- Q_ASSERT(digits.length() / digitWidth <= qMax(decpt, 1) || !digits.endsWith(zero));
+ Q_ASSERT(digits.size() / digitWidth <= qMax(decpt, 1) || !digits.endsWith(zero));
break;
}
- if (mustMarkDecimal || decpt < digits.length() / digitWidth)
+ if (mustMarkDecimal || decpt < digits.size() / digitWidth)
digits.insert(decpt * digitWidth, decimalPoint());
if (groupDigits) {
const QString group = groupSeparator();
- int i = decpt - m_grouping_least;
+ qsizetype i = decpt - m_grouping_least;
if (i >= m_grouping_top) {
digits.insert(i * digitWidth, group);
while ((i -= m_grouping_higher) >= m_grouping_top)
@@ -3739,19 +3728,19 @@ QString QLocaleData::exponentForm(QString &&digits, int decpt, int precision,
switch (pm) {
case PMDecimalDigits:
- for (int i = digits.length() / digitWidth; i < precision + 1; ++i)
+ for (qsizetype i = digits.size() / digitWidth; i < precision + 1; ++i)
digits.append(zero);
break;
case PMSignificantDigits:
- for (int i = digits.length() / digitWidth; i < precision; ++i)
+ for (qsizetype i = digits.size() / digitWidth; i < precision; ++i)
digits.append(zero);
break;
case PMChopTrailingZeros:
- Q_ASSERT(digits.length() / digitWidth <= 1 || !digits.endsWith(zero));
+ Q_ASSERT(digits.size() / digitWidth <= 1 || !digits.endsWith(zero));
break;
}
- if (mustMarkDecimal || digits.length() > digitWidth)
+ if (mustMarkDecimal || digits.size() > digitWidth)
digits.insert(digitWidth, decimalPoint());
digits.append(exponentSeparator());
@@ -3800,7 +3789,7 @@ QString QLocaleData::applyIntegerFormatting(QString &&numStr, bool negative, int
{
const QString zero = base == 10 ? zeroDigit() : QStringLiteral("0");
const auto digitWidth = zero.size();
- const auto digitCount = numStr.length() / digitWidth;
+ const auto digitCount = numStr.size() / digitWidth;
const auto basePrefix = [&] () -> QStringView {
if (flags & ShowBase) {
@@ -3817,11 +3806,11 @@ QString QLocaleData::applyIntegerFormatting(QString &&numStr, bool negative, int
const QString prefix = signPrefix(negative, flags) + basePrefix;
// Count how much of width we've used up. Each digit counts as one
- int usedWidth = digitCount + prefix.size();
+ qsizetype usedWidth = digitCount + prefix.size();
if (base == 10 && flags & GroupDigits) {
const QString group = groupSeparator();
- int i = digitCount - m_grouping_least;
+ qsizetype i = digitCount - m_grouping_least;
if (i >= m_grouping_top) {
numStr.insert(i * digitWidth, group);
++usedWidth;
@@ -3837,7 +3826,7 @@ QString QLocaleData::applyIntegerFormatting(QString &&numStr, bool negative, int
if (noPrecision)
precision = 1;
- for (int i = numStr.length(); i < precision; ++i) {
+ for (qsizetype i = numStr.size(); i < precision; ++i) {
numStr.prepend(zero);
usedWidth++;
}
@@ -3845,7 +3834,7 @@ QString QLocaleData::applyIntegerFormatting(QString &&numStr, bool negative, int
// LeftAdjusted overrides ZeroPadded; and sprintf() only pads when
// precision is not specified in the format string.
if (noPrecision && flags & ZeroPadded && !(flags & LeftAdjusted)) {
- for (int i = usedWidth; i < width; ++i)
+ for (qsizetype i = usedWidth; i < width; ++i)
numStr.prepend(zero);
}
@@ -3874,11 +3863,11 @@ bool QLocaleData::numberToCLocale(QStringView s, QLocale::NumberOptions number_o
auto length = s.size();
decltype(length) idx = 0;
- int digitsInGroup = 0;
- int decpt_idx = -1;
- int last_separator_idx = -1;
- int start_of_digits_idx = -1;
- int exponent_idx = -1;
+ qsizetype digitsInGroup = 0;
+ qsizetype decpt_idx = -1;
+ qsizetype last_separator_idx = -1;
+ qsizetype start_of_digits_idx = -1;
+ qsizetype exponent_idx = -1;
while (idx < length) {
const QStringView in = QStringView(uc + idx, uc[idx].isHighSurrogate() ? 2 : 1);
@@ -3993,7 +3982,7 @@ bool QLocaleData::validateChars(QStringView str, NumberMode numMode, QByteArray
int decDigits, QLocale::NumberOptions number_options) const
{
buff->clear();
- buff->reserve(str.length());
+ buff->reserve(str.size());
enum { Whole, Fractional, Exponent } state = Whole;
const bool scientific = numMode == DoubleScientificMode;
@@ -4089,7 +4078,7 @@ double QLocaleData::stringToDouble(QStringView str, bool *ok,
}
int processed = 0;
bool nonNullOk = false;
- double d = qt_asciiToDouble(buff.constData(), buff.length() - 1, nonNullOk, processed);
+ double d = qt_asciiToDouble(buff.constData(), buff.size() - 1, nonNullOk, processed);
if (ok != nullptr)
*ok = nonNullOk;
return d;
@@ -4123,17 +4112,8 @@ qulonglong QLocaleData::stringToUnsLongLong(QStringView str, int base, bool *ok,
qlonglong QLocaleData::bytearrayToLongLong(QByteArrayView num, int base, bool *ok)
{
- if (num.isEmpty() || num.at(0) == '\0') {
- if (ok != nullptr)
- *ok = false;
- return 0;
- }
-
- bool _ok;
- const char *endptr;
- const qlonglong l = qstrntoll(num.data(), num.size(), &endptr, base, &_ok);
-
- if (!_ok || endptr == num.data()) {
+ auto [l, endptr] = qstrntoll(num.data(), num.size(), base);
+ if (!endptr) {
if (ok != nullptr)
*ok = false;
return 0;
@@ -4159,17 +4139,8 @@ qlonglong QLocaleData::bytearrayToLongLong(QByteArrayView num, int base, bool *o
qulonglong QLocaleData::bytearrayToUnsLongLong(QByteArrayView num, int base, bool *ok)
{
- if (num.isEmpty() || num.at(0) == '\0') {
- if (ok != nullptr)
- *ok = false;
- return 0;
- }
-
- bool _ok;
- const char *endptr;
- const qulonglong l = qstrntoull(num.data(), num.size(), &endptr, base, &_ok);
-
- if (!_ok || endptr == num.data()) {
+ auto [l, endptr] = qstrntoull(num.data(), num.size(), base);
+ if (!endptr) {
if (ok != nullptr)
*ok = false;
return 0;
@@ -4225,7 +4196,7 @@ QString QLocale::currencySymbol(QLocale::CurrencySymbolFormat format) const
case CurrencyIsoCode: {
const char *code = d->m_data->m_currency_iso_code;
if (auto len = qstrnlen(code, 3))
- return QString::fromLatin1(code, int(len));
+ return QString::fromLatin1(code, qsizetype(len));
break;
}
}
@@ -4417,17 +4388,35 @@ QStringList QLocale::uiLanguages() const
locales.append(QLocale(entry));
if (locales.isEmpty())
locales.append(systemLocale()->fallbackLocale());
+ // If the system locale (isn't C and) didn't include itself in the list,
+ // or as fallback, presume to know better than it and put its name
+ // first. (Known issue, QTBUG-104930, on some macOS versions when in
+ // locale en_DE.) Our translation system might have a translation for a
+ // locale the platform doesn't believe in.
+ const QString name = bcp47Name();
+ if (!name.isEmpty() && language() != C && !uiLanguages.contains(name)) {
+ // That uses contains(name) as a cheap pre-test, but there may be an
+ // entry that matches this on purging likely subtags.
+ const QLocaleId mine = d->m_data->id().withLikelySubtagsRemoved();
+ const auto isMine = [mine](const QString &entry) {
+ return QLocaleId::fromName(entry).withLikelySubtagsRemoved() == mine;
+ };
+ if (std::none_of(uiLanguages.constBegin(), uiLanguages.constEnd(), isMine)) {
+ locales.prepend(*this);
+ uiLanguages.prepend(name);
+ }
+ }
} else
#endif
{
locales.append(*this);
}
- for (int i = locales.size(); i-- > 0; ) {
+ for (qsizetype i = locales.size(); i-- > 0; ) {
const QLocale &locale = locales.at(i);
const auto data = locale.d->m_data;
QLocaleId id = data->id();
- int j;
+ qsizetype j;
QByteArray prior;
if (isSystem && i < uiLanguages.size()) {
// Adding likely-adjusted forms to system locale's list.