diff options
Diffstat (limited to 'src/corelib/text')
-rw-r--r-- | src/corelib/text/qlocale.cpp | 123 | ||||
-rw-r--r-- | src/corelib/text/qlocale_mac.mm | 4 | ||||
-rw-r--r-- | src/corelib/text/qlocale_p.h | 3 | ||||
-rw-r--r-- | src/corelib/text/qlocale_unix.cpp | 10 | ||||
-rw-r--r-- | src/corelib/text/qlocale_win.cpp | 14 |
5 files changed, 73 insertions, 81 deletions
diff --git a/src/corelib/text/qlocale.cpp b/src/corelib/text/qlocale.cpp index b751ed4579..a630f3a5db 100644 --- a/src/corelib/text/qlocale.cpp +++ b/src/corelib/text/qlocale.cpp @@ -491,105 +491,102 @@ int QLocaleData::findLocaleIndex(QLocaleId lid) return locale_index[fallback]; } -static bool parse_locale_tag(const QString &input, int &i, QString *result, - const QString &separators) -{ - *result = QString(8, Qt::Uninitialized); // worst case according to BCP47 - QChar *pch = result->data(); - const QChar *uc = input.data() + i; - const int l = input.length(); - int size = 0; - for (; i < l && size < 8; ++i, ++size) { - if (separators.contains(*uc)) - break; - if (! ((uc->unicode() >= 'a' && uc->unicode() <= 'z') || - (uc->unicode() >= 'A' && uc->unicode() <= 'Z') || - (uc->unicode() >= '0' && uc->unicode() <= '9')) ) // latin only +static QStringView findTag(QStringView name) +{ + const QString separators = QStringLiteral("_-.@"); + int i = 0; + while (i < name.size() && !separators.contains(name[i])) + i++; + return name.first(i); +} + +static bool validTag(QStringView tag) +{ + // Returns false if any character in tag is not an ASCII letter or digit + for (const QChar uc : tag) { + const char16_t ch = uc.unicode(); + if (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9'))) return false; - *pch++ = *uc++; } - result->truncate(size); - return true; + return tag.size() > 0; } -bool qt_splitLocaleName(const QString &name, QString &lang, QString &script, QString &cntry) +static bool isScript(QStringView tag) { - const int length = name.length(); - - lang = script = cntry = QString(); + // Every script name is 4 characters, a capital followed by three lower-case; + // so a search for tag in allScripts *can* only match if it's aligned. + 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; +} - const QString separators = QStringLiteral("_-.@"); +bool qt_splitLocaleName(QStringView name, QStringView *lang, QStringView *script, QStringView *land) +{ + // Assume each of lang, script and land is nullptr or points to an empty QStringView. enum ParserState { NoState, LangState, ScriptState, CountryState }; ParserState state = LangState; - for (int i = 0; i < length && state != NoState; ) { - QString value; - if (!parse_locale_tag(name, i, &value, separators) ||value.isEmpty()) + while (name.size() && state != NoState) { + const QStringView tag = findTag(name); + if (!validTag(tag)) break; - QChar sep = i < length ? name.at(i) : QChar(); + name = name.sliced(tag.size()); + const bool sep = name.size() > 0; + if (sep) // tag wasn't all that remained; there was a separator + name = name.sliced(1); + switch (state) { case LangState: - if (!sep.isNull() && !separators.contains(sep)) { - state = NoState; - break; - } - lang = value; - if (i == length) { - // just language was specified - state = NoState; - break; - } - state = ScriptState; + if (tag.size() != 2 && tag.size() != 3) + return false; + if (lang) + *lang = tag; + state = sep ? ScriptState : NoState; break; - case ScriptState: { - QString scripts = QString::fromLatin1((const char *)script_code_list, - sizeof(script_code_list) - 1); - if (value.length() == 4 && scripts.indexOf(value) % 4 == 0) { - // script name is always 4 characters - script = value; - state = CountryState; - } else { - // it wasn't a script, maybe it is a country then? - cntry = value; - state = NoState; + case ScriptState: + if (isScript(tag)) { + if (script) + *script = tag; + state = sep ? CountryState : NoState; + break; } - break; - } + // It wasn't a script, assume it's a country. + Q_FALLTHROUGH(); case CountryState: - cntry = value; + if (land) + *land = tag; state = NoState; break; - case NoState: - // shouldn't happen - qWarning("QLocale: This should never happen"); + case NoState: // Precluded by loop condition ! + Q_ASSERT(!"QLocale: This should never happen"); break; } - ++i; } - return lang.length() == 2 || lang.length() == 3; + return state != LangState; } // TODO: kill this ! Still in use by qttools, patch submitted (2020 October). void QLocalePrivate::getLangAndCountry(const QString &name, QLocale::Language &lang, - QLocale::Script &script, QLocale::Country &cntry) + QLocale::Script &script, QLocale::Country &land) { const auto id = QLocaleId::fromName(name); lang = QLocale::Language(id.language_id); script = QLocale::Script(id.script_id); - cntry = QLocale::Country(id.country_id); + land = QLocale::Country(id.country_id); } QLocaleId QLocaleId::fromName(const QString &name) { - QString lang; - QString script; - QString cntry; - if (!qt_splitLocaleName(name, lang, script, cntry)) + QStringView lang; + QStringView script; + QStringView land; + if (!qt_splitLocaleName(name, &lang, &script, &land)) return { QLocale::C, 0, 0 }; QLocale::Language langId = QLocalePrivate::codeToLanguage(lang); if (langId == QLocale::C) return QLocaleId { langId, 0, 0 }; - return { langId, QLocalePrivate::codeToScript(script), QLocalePrivate::codeToCountry(cntry) }; + return { langId, QLocalePrivate::codeToScript(script), QLocalePrivate::codeToCountry(land) }; } QString qt_readEscapedFormatString(QStringView format, int *idx) diff --git a/src/corelib/text/qlocale_mac.mm b/src/corelib/text/qlocale_mac.mm index 7ed7832564..281fedcfab 100644 --- a/src/corelib/text/qlocale_mac.mm +++ b/src/corelib/text/qlocale_mac.mm @@ -70,10 +70,8 @@ static QByteArray envVarLocale() static QString getMacLocaleName() { QString result = QString::fromLocal8Bit(envVarLocale()); - - QString lang, script, cntry; if (result.isEmpty() - || (result != QLatin1String("C") && !qt_splitLocaleName(result, lang, script, cntry))) { + || (result != QLatin1String("C") && !qt_splitLocaleName(result))) { QCFType<CFLocaleRef> l = CFLocaleCopyCurrent(); CFStringRef locale = CFLocaleGetIdentifier(l); result = QString::fromCFString(locale); diff --git a/src/corelib/text/qlocale_p.h b/src/corelib/text/qlocale_p.h index eda8bd0ca4..aad344eccc 100644 --- a/src/corelib/text/qlocale_p.h +++ b/src/corelib/text/qlocale_p.h @@ -489,7 +489,8 @@ inline char QLocaleData::numericToCLocale(QStringView in) const } QString qt_readEscapedFormatString(QStringView format, int *idx); -bool qt_splitLocaleName(const QString &name, QString &lang, QString &script, QString &cntry); +bool qt_splitLocaleName(QStringView name, QStringView *lang = nullptr, + QStringView *script = nullptr, QStringView *cntry = nullptr); int qt_repeatCount(QStringView s); enum { AsciiSpaceMask = (1u << (' ' - 1)) | diff --git a/src/corelib/text/qlocale_unix.cpp b/src/corelib/text/qlocale_unix.cpp index b1edd0dd3c..adc73ad19a 100644 --- a/src/corelib/text/qlocale_unix.cpp +++ b/src/corelib/text/qlocale_unix.cpp @@ -269,12 +269,10 @@ QVariant QSystemLocale::query(QueryType type, QVariant in) const // than one script in the same country, e.g. Sindhi in India. // However, can clients of the UILanguage query cope if we include script ? for (int i = 0; i < lst.size(); ++i) { - QString lang, script, cntry; - if (qt_splitLocaleName(lst.at(i), lang, script, cntry)) { - if (!cntry.length()) - d->uiLanguages.append(lang); - else - d->uiLanguages.append(lang % QLatin1Char('-') % cntry); + QStringView lang, cntry; + if (qt_splitLocaleName(lst.at(i), &lang, nullptr, &cntry)) { + d->uiLanguages.append( + cntry.size() ? lang % QLatin1Char('-') % cntry : lang.toString()); } } return d->uiLanguages.isEmpty() ? QVariant() : QVariant(d->uiLanguages); diff --git a/src/corelib/text/qlocale_win.cpp b/src/corelib/text/qlocale_win.cpp index cb0ef52c6f..f244826c33 100644 --- a/src/corelib/text/qlocale_win.cpp +++ b/src/corelib/text/qlocale_win.cpp @@ -1022,15 +1022,13 @@ static QByteArray getWinLocaleName(LCID id) { QByteArray result; if (id == LOCALE_USER_DEFAULT) { - static QByteArray langEnvVar = qgetenv("LANG"); + static const QByteArray langEnvVar = qgetenv("LANG"); result = langEnvVar; - QString lang, script, cntry; - if ( result == "C" || (!result.isEmpty() - && qt_splitLocaleName(QString::fromLocal8Bit(result), lang, script, cntry)) ) { - long id = 0; - bool ok = false; - id = qstrtoll(result.data(), 0, 0, &ok); - if ( !ok || id == 0 || id < INT_MIN || id > INT_MAX ) + if (result == "C" + || (!result.isEmpty() && qt_splitLocaleName(QString::fromLocal8Bit(result)))) { + bool ok = false; // See if we have a Windows locale code instead of a locale name: + long id = qstrtoll(result.data(), 0, 0, &ok); + if (!ok || id == 0 || id < INT_MIN || id > INT_MAX) // Assume real locale name return result; return winLangCodeToIsoName(int(id)); } |