diff options
Diffstat (limited to 'src/corelib/text/qlocale.cpp')
-rw-r--r-- | src/corelib/text/qlocale.cpp | 243 |
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. |