diff options
Diffstat (limited to 'src/corelib/tools/qlocale.cpp')
-rw-r--r-- | src/corelib/tools/qlocale.cpp | 3281 |
1 files changed, 3281 insertions, 0 deletions
diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp new file mode 100644 index 0000000000..5c4085af41 --- /dev/null +++ b/src/corelib/tools/qlocale.cpp @@ -0,0 +1,3281 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qglobal.h" + +#ifndef QT_NO_SYSTEMLOCALE +QT_BEGIN_NAMESPACE +class QSystemLocale; +static QSystemLocale *QSystemLocale_globalSystemLocale(); +QT_END_NAMESPACE +#endif + +#include "qplatformdefs.h" + +#include "qdatastream.h" +#include "qstring.h" +#include "qlocale.h" +#include "qlocale_p.h" +#include "qlocale_tools_p.h" +#include "qdatetime_p.h" +#include "qnamespace.h" +#include "qdatetime.h" +#include "qstringlist.h" +#include "qvariant.h" +#include "qstringbuilder.h" +#if defined(Q_WS_WIN) +# include "qt_windows.h" +# include <time.h> +#endif +#if !defined(QWS) && defined(Q_OS_MAC) +# include "private/qcore_mac_p.h" +# include <CoreFoundation/CoreFoundation.h> +#endif +#include "private/qnumeric_p.h" +#include "private/qsystemlibrary_p.h" + +QT_BEGIN_NAMESPACE + +#if defined(Q_OS_SYMBIAN) +void qt_symbianUpdateSystemPrivate(); +void qt_symbianInitSystemLocale(); +#endif + +#ifndef QT_NO_SYSTEMLOCALE +static QSystemLocale *_systemLocale = 0; +Q_GLOBAL_STATIC_WITH_ARGS(QSystemLocale, QSystemLocale_globalSystemLocale, (true)) +static QLocalePrivate *system_lp = 0; +Q_GLOBAL_STATIC(QLocalePrivate, globalLocalePrivate) +#endif + +#ifdef QT_USE_ICU +extern bool qt_initIcu(const QString &localeName); +#endif + +/****************************************************************************** +** Helpers for accessing Qt locale database +*/ + +QT_BEGIN_INCLUDE_NAMESPACE +#include "qlocale_data_p.h" +QT_END_INCLUDE_NAMESPACE + +QLocale::Language QLocalePrivate::codeToLanguage(const QString &code) +{ + int len = code.length(); + if (len != 2 && len != 3) + return QLocale::C; + ushort uc1 = len-- > 0 ? code[0].toLower().unicode() : 0; + ushort uc2 = len-- > 0 ? code[1].toLower().unicode() : 0; + ushort uc3 = len-- > 0 ? code[2].toLower().unicode() : 0; + + if (uc1 == 'n' && uc2 == 'o' && uc3 == 0) + uc2 = 'b'; + + const unsigned char *c = language_code_list; + for (; *c != 0; c += 3) { + if (uc1 == c[0] && uc2 == c[1] && uc3 == c[2]) + return QLocale::Language((c - language_code_list)/3); + } + + return QLocale::C; +} + +QLocale::Script QLocalePrivate::codeToScript(const QString &code) +{ + int len = code.length(); + if (len != 4) + return QLocale::AnyScript; + + // script is titlecased in our data + unsigned char c0 = code.at(0).toUpper().toLatin1(); + unsigned char c1 = code.at(1).toLower().toLatin1(); + unsigned char c2 = code.at(2).toLower().toLatin1(); + unsigned char c3 = code.at(3).toLower().toLatin1(); + + const unsigned char *c = script_code_list; + for (int 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); + } + return QLocale::AnyScript; +} + +QLocale::Country QLocalePrivate::codeToCountry(const QString &code) +{ + int len = code.length(); + if (len != 2 && len != 3) + return QLocale::AnyCountry; + ushort uc1 = len-- > 0 ? code[0].toUpper().unicode() : 0; + ushort uc2 = len-- > 0 ? code[1].toUpper().unicode() : 0; + ushort uc3 = len-- > 0 ? code[2].toUpper().unicode() : 0; + + const unsigned char *c = country_code_list; + for (; *c != 0; c += 3) { + if (uc1 == c[0] && uc2 == c[1] && uc3 == c[2]) + return QLocale::Country((c - country_code_list)/3); + } + + return QLocale::AnyCountry; +} + +QString QLocalePrivate::languageCode() const +{ + if (m_language_id == QLocale::AnyLanguage) + return QString(); + if (m_language_id == QLocale::C) + return QLatin1String("C"); + + const unsigned char *c = language_code_list + 3*(uint(m_language_id)); + + QString code(c[2] == 0 ? 2 : 3, Qt::Uninitialized); + + code[0] = ushort(c[0]); + code[1] = ushort(c[1]); + if (c[2] != 0) + code[2] = ushort(c[2]); + + return code; +} + +QString QLocalePrivate::scriptCode() const +{ + if (m_script_id == QLocale::AnyScript || m_script_id > QLocale::LastScript) + return QString(); + const unsigned char *c = script_code_list + 4*(uint(m_script_id)); + return QString::fromLatin1((const char *)c, 4); +} + +QString QLocalePrivate::countryCode() const +{ + if (m_country_id == QLocale::AnyCountry) + return QString(); + + const unsigned char *c = country_code_list + 3*(uint(m_country_id)); + + QString code(c[2] == 0 ? 2 : 3, Qt::Uninitialized); + + code[0] = ushort(c[0]); + code[1] = ushort(c[1]); + if (c[2] != 0) + code[2] = ushort(c[2]); + + return code; +} + +QString QLocalePrivate::bcp47Name() const +{ + if (m_language_id == QLocale::AnyLanguage) + return QString(); + if (m_language_id == QLocale::C) + return QLatin1String("C"); + const unsigned char *lang = language_code_list + 3*(uint(m_language_id)); + const unsigned char *script = + (m_script_id != QLocale::AnyScript ? script_code_list + 4*(uint(m_script_id)) : 0); + const unsigned char *country = + (m_country_id != QLocale::AnyCountry ? country_code_list + 3*(uint(m_country_id)) : 0); + char len = (lang[2] != 0 ? 3 : 2) + (script ? 4+1 : 0) + (country ? (country[2] != 0 ? 3 : 2)+1 : 0); + QString name(len, Qt::Uninitialized); + QChar *uc = name.data(); + *uc++ = ushort(lang[0]); + *uc++ = ushort(lang[1]); + if (lang[2] != 0) + *uc++ = ushort(lang[2]); + if (script) { + *uc++ = QLatin1Char('-'); + *uc++ = ushort(script[0]); + *uc++ = ushort(script[1]); + *uc++ = ushort(script[2]); + *uc++ = ushort(script[3]); + } + if (country) { + *uc++ = QLatin1Char('-'); + *uc++ = ushort(country[0]); + *uc++ = ushort(country[1]); + if (country[2] != 0) + *uc++ = ushort(country[2]); + } + return name; +} + +const QLocalePrivate *QLocalePrivate::findLocale(QLocale::Language language, QLocale::Script script, QLocale::Country country) +{ + const unsigned language_id = language; + const unsigned script_id = script; + const unsigned country_id = country; + + uint idx = locale_index[language_id]; + + const QLocalePrivate *d = locale_data + idx; + + if (idx == 0) // default language has no associated country + return d; + + if (script == QLocale::AnyScript && country == QLocale::AnyCountry) + return d; + + Q_ASSERT(d->languageId() == language_id); + + if (country == QLocale::AnyCountry) { + while (d->m_language_id == language_id && d->m_script_id != script_id) + ++d; + if (d->m_language_id == language_id && d->m_script_id == script_id) + return d; + } else if (script == QLocale::AnyScript) { + while (d->m_language_id == language_id) { + if (d->m_script_id == script_id && d->m_country_id == country_id) + return d; + ++d; + } + } else { + // both script and country are explicitly specified + while (d->m_language_id == language_id) { + if (d->m_script_id == script_id && d->m_country_id == country_id) + return d; + ++d; + } + } + + return locale_data + idx; +} + +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 + return false; + *pch++ = *uc++; + } + result->truncate(size); + return true; +} + +bool qt_splitLocaleName(const QString &name, QString &lang, QString &script, QString &cntry) +{ + const int length = name.length(); + + lang = script = cntry = QString(); + + const QString separators = QLatin1String("_-.@"); + 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()) + break; + QChar sep = i < length ? name.at(i) : QChar(); + 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; + break; + case ScriptState: { + QString scripts = QString::fromLatin1((const char *)script_code_list, sizeof(script_code_list)); + 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; + } + break; + } + case CountryState: + cntry = value; + state = NoState; + break; + case NoState: + // shouldn't happen + qWarning("QLocale: This should never happen"); + break; + } + ++i; + } + return lang.length() == 2 || lang.length() == 3; +} + +void QLocalePrivate::getLangAndCountry(const QString &name, QLocale::Language &lang, + QLocale::Script &script, QLocale::Country &cntry) +{ + lang = QLocale::C; + script = QLocale::AnyScript; + cntry = QLocale::AnyCountry; + + QString lang_code; + QString script_code; + QString cntry_code; + if (!qt_splitLocaleName(name, lang_code, script_code, cntry_code)) + return; + + lang = QLocalePrivate::codeToLanguage(lang_code); + if (lang == QLocale::C) + return; + script = QLocalePrivate::codeToScript(script_code); + cntry = QLocalePrivate::codeToCountry(cntry_code); +} + +static const QLocalePrivate *findLocale(const QString &name) +{ + QLocale::Language lang; + QLocale::Script script; + QLocale::Country cntry; + QLocalePrivate::getLangAndCountry(name, lang, script, cntry); + + return QLocalePrivate::findLocale(lang, script, cntry); +} + +QString qt_readEscapedFormatString(const QString &format, int *idx) +{ + int &i = *idx; + + Q_ASSERT(format.at(i) == QLatin1Char('\'')); + ++i; + if (i == format.size()) + return QString(); + if (format.at(i).unicode() == '\'') { // "''" outside of a quoted stirng + ++i; + return QLatin1String("'"); + } + + QString result; + + while (i < format.size()) { + if (format.at(i).unicode() == '\'') { + if (i + 1 < format.size() && format.at(i + 1).unicode() == '\'') { + // "''" inside of a quoted string + result.append(QLatin1Char('\'')); + i += 2; + } else { + break; + } + } else { + result.append(format.at(i++)); + } + } + if (i < format.size()) + ++i; + + return result; +} + +int qt_repeatCount(const QString &s, int i) +{ + QChar c = s.at(i); + int j = i + 1; + while (j < s.size() && s.at(j) == c) + ++j; + return j - i; +} + +static const QLocalePrivate *default_lp = 0; +static uint default_number_options = 0; + +#ifndef QT_NO_SYSTEMLOCALE + + +/****************************************************************************** +** Default system locale behavior +*/ + +/*! + Constructs a QSystemLocale object. The constructor will automatically + install this object as the system locale and remove any earlier installed + system locales. +*/ +QSystemLocale::QSystemLocale() +{ + delete _systemLocale; + _systemLocale = this; + + if (system_lp) + system_lp->m_language_id = 0; +} + +/*! \internal */ +QSystemLocale::QSystemLocale(bool) +{ } + +/*! + Deletes the object. +*/ +QSystemLocale::~QSystemLocale() +{ + if (_systemLocale == this) { + _systemLocale = 0; + + if (system_lp) + system_lp->m_language_id = 0; + } +} + +static const QSystemLocale *systemLocale() +{ + if (_systemLocale) + return _systemLocale; +#if defined(Q_OS_SYMBIAN) + qt_symbianInitSystemLocale(); +#endif + return QSystemLocale_globalSystemLocale(); +} + +void QLocalePrivate::updateSystemPrivate() +{ + const QSystemLocale *sys_locale = systemLocale(); + if (!system_lp) + system_lp = globalLocalePrivate(); + + // tell the object that the system locale has changed. + sys_locale->query(QSystemLocale::LocaleChanged, QVariant()); + + *system_lp = *sys_locale->fallbackLocale().d(); + +#if defined(Q_OS_SYMBIAN) + qt_symbianUpdateSystemPrivate(); +#endif + + QVariant res = sys_locale->query(QSystemLocale::LanguageId, QVariant()); + if (!res.isNull()) { + system_lp->m_language_id = res.toInt(); + system_lp->m_script_id = QLocale::AnyScript; // default for compatibility + } + res = sys_locale->query(QSystemLocale::CountryId, QVariant()); + if (!res.isNull()) { + system_lp->m_country_id = res.toInt(); + system_lp->m_script_id = QLocale::AnyScript; // default for compatibility + } + res = sys_locale->query(QSystemLocale::ScriptId, QVariant()); + if (!res.isNull()) + system_lp->m_script_id = res.toInt(); + + res = sys_locale->query(QSystemLocale::DecimalPoint, QVariant()); + if (!res.isNull()) + system_lp->m_decimal = res.toString().at(0).unicode(); + + res = sys_locale->query(QSystemLocale::GroupSeparator, QVariant()); + if (!res.isNull()) + system_lp->m_group = res.toString().at(0).unicode(); + + res = sys_locale->query(QSystemLocale::ZeroDigit, QVariant()); + if (!res.isNull()) + system_lp->m_zero = res.toString().at(0).unicode(); + + res = sys_locale->query(QSystemLocale::NegativeSign, QVariant()); + if (!res.isNull()) + system_lp->m_minus = res.toString().at(0).unicode(); + + res = sys_locale->query(QSystemLocale::PositiveSign, QVariant()); + if (!res.isNull()) + system_lp->m_plus = res.toString().at(0).unicode(); + +#ifdef QT_USE_ICU + if (!default_lp) + qt_initIcu(system_lp->bcp47Name()); +#endif + +} +#endif + +static const QLocalePrivate *systemPrivate() +{ +#ifndef QT_NO_SYSTEMLOCALE + // copy over the information from the fallback locale and modify + if (!system_lp || system_lp->m_language_id == 0) + QLocalePrivate::updateSystemPrivate(); + + return system_lp; +#else + return locale_data; +#endif +} + +static const QLocalePrivate *defaultPrivate() +{ + if (!default_lp) + default_lp = systemPrivate(); + return default_lp; +} + +static QString getLocaleListData(const ushort *data, int size, int index) +{ + static const ushort separator = ';'; + while (index && size > 0) { + while (*data != separator) + ++data, --size; + --index; + ++data; + --size; + } + const ushort *end = data; + while (size > 0 && *end != separator) + ++end, --size; + if (end-data == 0) + return QString(); + return QString::fromRawData(reinterpret_cast<const QChar*>(data), end-data); +} + +static inline QString getLocaleData(const ushort *data, int size) +{ + return size ? QString::fromRawData(reinterpret_cast<const QChar*>(data), size) : QString(); +} + + +#ifndef QT_NO_DATASTREAM +QDataStream &operator<<(QDataStream &ds, const QLocale &l) +{ + ds << l.name(); + return ds; +} + +QDataStream &operator>>(QDataStream &ds, QLocale &l) +{ + QString s; + ds >> s; + l = QLocale(s); + return ds; +} +#endif // QT_NO_DATASTREAM + + +static const int locale_data_size = sizeof(locale_data)/sizeof(QLocalePrivate) - 1; + +static const QLocalePrivate *dataPointerHelper(quint16 index) +{ +#ifndef QT_NO_SYSTEMLOCALE + Q_ASSERT(index <= locale_data_size); + if (index == locale_data_size) + return system_lp; +#else + Q_ASSERT(index < locale_data_size); +#endif + + return &locale_data[index]; +} + +static quint16 localePrivateIndex(const QLocalePrivate *p) +{ +#ifndef QT_NO_SYSTEMLOCALE + Q_ASSERT((p >= locale_data && p - locale_data < locale_data_size) + || (p != 0 && p == system_lp)); + quint16 index = p == system_lp ? locale_data_size : p - locale_data; +#else + Q_ASSERT(p >= locale_data && p - locale_data < locale_data_size); + quint16 index = p - locale_data; +#endif + + return index; +} + +/*! + Constructs a QLocale object with the specified \a name, + which has the format + "language[_script][_country][.codeset][@modifier]" or "C", where: + + \list + \i language is a lowercase, two-letter, ISO 639 language code, + \i script is a titlecase, four-letter, ISO 15924 script code, + \i country is an uppercase, two- or three-letter, ISO 3166 country code (also "419" as defined by United Nations), + \i and codeset and modifier are ignored. + \endlist + + The separator can be either underscore or a minus sign. + + If the string violates the locale format, or language is not + a valid ISO 369 code, the "C" locale is used instead. If country + is not present, or is not a valid ISO 3166 code, the most + appropriate country is chosen for the specified language. + + The language, script and country codes are converted to their respective + \c Language, \c Script and \c Country enums. After this conversion is + performed the constructor behaves exactly like QLocale(Country, Script, + Language). + + This constructor is much slower than QLocale(Country, Script, Language). + + \sa bcp47Name() +*/ + +QLocale::QLocale(const QString &name) + : v(0) +{ + p.numberOptions = 0; + p.index = localePrivateIndex(findLocale(name)); +} + +/*! + Constructs a QLocale object initialized with the default locale. If + no default locale was set using setDefaultLocale(), this locale will + be the same as the one returned by system(). + + \sa setDefault() +*/ + +QLocale::QLocale() + : v(0) +{ + p.numberOptions = default_number_options; + p.index = localePrivateIndex(defaultPrivate()); +} + +/*! + Constructs a QLocale object with the specified \a language and \a + country. + + \list + \i If the language/country pair is found in the database, it is used. + \i If the language is found but the country is not, or if the country + is \c AnyCountry, the language is used with the most + appropriate available country (for example, Germany for German), + \i If neither the language nor the country are found, QLocale + defaults to the default locale (see setDefault()). + \endlist + + The language and country that are actually used can be queried + using language() and country(). + + \sa setDefault() language() country() +*/ + +QLocale::QLocale(Language language, Country country) + : v(0) +{ + const QLocalePrivate *d = QLocalePrivate::findLocale(language, QLocale::AnyScript, country); + + // If not found, should default to system + if (d->languageId() == QLocale::C && language != QLocale::C) { + p.numberOptions = default_number_options; + p.index = localePrivateIndex(defaultPrivate()); + } else { + p.numberOptions = 0; + p.index = localePrivateIndex(d); + } +} +\ +/*! + \since 4.8 + + Constructs a QLocale object with the specified \a language, \a script and + \a country. + + \list + \i If the language/script/country is found in the database, it is used. + \i If both \a script is AnyScript and \a country is AnyCountry, the + language is used with the most appropriate available script and country + (for example, Germany for German), + \i If either \a script is AnyScript or \a country is AnyCountry, the + language is used with the first locale that matches the given \a script + and \a country. + \i If neither the language nor the country are found, QLocale + defaults to the default locale (see setDefault()). + \endlist + + The language, script and country that are actually used can be queried + using language(), script() and country(). + + \sa setDefault() language() script() country() +*/ + +QLocale::QLocale(Language language, Script script, Country country) + : v(0) +{ + const QLocalePrivate *d = QLocalePrivate::findLocale(language, script, country); + + // If not found, should default to system + if (d->languageId() == QLocale::C && language != QLocale::C) { + p.numberOptions = default_number_options; + p.index = localePrivateIndex(defaultPrivate()); + } else { + p.numberOptions = 0; + p.index = localePrivateIndex(d); + } +} + +/*! + Constructs a QLocale object as a copy of \a other. +*/ + +QLocale::QLocale(const QLocale &other) +{ + v = other.v; +} + +const QLocalePrivate *QLocale::d() const +{ + return dataPointerHelper(p.index); +} + +/*! + Assigns \a other to this QLocale object and returns a reference + to this QLocale object. +*/ + +QLocale &QLocale::operator=(const QLocale &other) +{ + v = other.v; + return *this; +} + +/*! + \since 4.2 + + Sets the \a options related to number conversions for this + QLocale instance. +*/ +void QLocale::setNumberOptions(NumberOptions options) +{ + p.numberOptions = options; +} + +/*! + \since 4.2 + + Returns the options related to number conversions for this + QLocale instance. + + By default, no options are set for the standard locales. +*/ +QLocale::NumberOptions QLocale::numberOptions() const +{ + return static_cast<NumberOption>(p.numberOptions); +} + +/*! + \since 4.8 + + Returns \a str quoted according to the current locale using the given + quotation \a style. +*/ +QString QLocale::quoteString(const QString &str, QuotationStyle style) const +{ + return quoteString(&str, style); +} + +/*! + \since 4.8 + + \overload +*/ +QString QLocale::quoteString(const QStringRef &str, QuotationStyle style) const +{ +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QVariant res; + if (style == QLocale::AlternateQuotation) + res = systemLocale()->query(QSystemLocale::StringToAlternateQuotation, QVariant::fromValue(str)); + if (res.isNull() || style == QLocale::StandardQuotation) + res = systemLocale()->query(QSystemLocale::StringToStandardQuotation, QVariant::fromValue(str)); + if (!res.isNull()) + return res.toString(); + } +#endif + + if (style == QLocale::StandardQuotation) + return QChar(d()->m_quotation_start) % str % QChar(d()->m_quotation_end); + else + return QChar(d()->m_alternate_quotation_start) % str % QChar(d()->m_alternate_quotation_end); +} + +/*! + \since 4.8 + + Returns a string that represents a join of a given \a list of strings with + a separator defined by the locale. +*/ +QString QLocale::createSeparatedList(const QStringList &list) const +{ +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QVariant res; + res = systemLocale()->query(QSystemLocale::ListToSeparatedString, QVariant::fromValue(list)); + + if (!res.isNull()) + return res.toString(); + } +#endif + + const int size = list.size(); + if (size == 1) { + return list.at(0); + } else if (size == 2) { + QString format = getLocaleData(list_pattern_part_data + d()->m_list_pattern_part_two_idx, d()->m_list_pattern_part_two_size); + return format.arg(list.at(0), list.at(1)); + } else if (size > 2) { + QString formatStart = getLocaleData(list_pattern_part_data + d()->m_list_pattern_part_start_idx, d()->m_list_pattern_part_start_size); + QString formatMid = getLocaleData(list_pattern_part_data + d()->m_list_pattern_part_mid_idx, d()->m_list_pattern_part_mid_size); + QString formatEnd = getLocaleData(list_pattern_part_data + d()->m_list_pattern_part_end_idx, d()->m_list_pattern_part_end_size); + QString result = formatStart.arg(list.at(0), list.at(1)); + for (int i = 2; i < size - 1; ++i) + result = formatMid.arg(result, list.at(i)); + result = formatEnd.arg(result, list.at(size - 1)); + return result; + } + + return QString(); +} + +/*! + \nonreentrant + + Sets the global default locale to \a locale. These + values are used when a QLocale object is constructed with + no arguments. If this function is not called, the system's + locale is used. + + \warning In a multithreaded application, the default locale + should be set at application startup, before any non-GUI threads + are created. + + \sa system() c() +*/ + +void QLocale::setDefault(const QLocale &locale) +{ + default_lp = locale.d(); + default_number_options = locale.numberOptions(); + +#ifdef QT_USE_ICU + qt_initIcu(locale.bcp47Name()); +#endif +} + +/*! + Returns the language of this locale. + + \sa script(), country(), languageToString(), bcp47Name() +*/ +QLocale::Language QLocale::language() const +{ + return Language(d()->languageId()); +} + +/*! + \since 4.8 + + Returns the script of this locale. + + \sa language(), country(), languageToString(), scriptToString(), bcp47Name() +*/ +QLocale::Script QLocale::script() const +{ + return Script(d()->m_script_id); +} + +/*! + Returns the country of this locale. + + \sa language(), script(), countryToString(), bcp47Name() +*/ +QLocale::Country QLocale::country() const +{ + return Country(d()->countryId()); +} + +/*! + Returns the language and country of this locale as a + string of the form "language_country", where + language is a lowercase, two-letter ISO 639 language code, + and country is an uppercase, two- or three-letter ISO 3166 country code. + + Note that even if QLocale object was constructed with an explicit script, + name() will not contain it for compatibility reasons. Use bcp47Name() instead + if you need a full locale name. + + \sa QLocale(const QString &), language(), script(), country(), bcp47Name() +*/ + +QString QLocale::name() const +{ + Language l = language(); + + QString result = d()->languageCode(); + + if (l == C) + return result; + + Country c = country(); + if (c == AnyCountry) + return result; + + result.append(QLatin1Char('_')); + result.append(d()->countryCode()); + + return result; +} + +/*! + \since 4.8 + + Returns the dash-separated language, script and country (and possibly other BCP47 fields) + of this locale as a string. + + Unlike the uiLanguages() the returned value of the bcp47Name() represents + the locale name of the QLocale data but not the language the user-interface + should be in. + + This function tries to conform the locale name to BCP47. + + \sa language(), country(), script(), uiLanguages() +*/ +QString QLocale::bcp47Name() const +{ + return d()->bcp47Name(); +} + +/*! + Returns a QString containing the name of \a language. + + \sa countryToString(), scriptToString(), bcp47Name() +*/ + +QString QLocale::languageToString(Language language) +{ + if (uint(language) > uint(QLocale::LastLanguage)) + return QLatin1String("Unknown"); + return QLatin1String(language_name_list + language_name_index[language]); +} + +/*! + Returns a QString containing the name of \a country. + + \sa languageToString(), scriptToString(), country(), bcp47Name() +*/ + +QString QLocale::countryToString(Country country) +{ + if (uint(country) > uint(QLocale::LastCountry)) + return QLatin1String("Unknown"); + return QLatin1String(country_name_list + country_name_index[country]); +} + +/*! + \since 4.8 + + Returns a QString containing the name of \a script. + + \sa languageToString(), countryToString(), script(), bcp47Name() +*/ +QString QLocale::scriptToString(QLocale::Script script) +{ + if (uint(script) > uint(QLocale::LastScript)) + return QLatin1String("Unknown"); + return QLatin1String(script_name_list + script_name_index[script]); +} + +/*! + Returns the short int represented by the localized string \a s, + using base \a base. If \a base is 0 the base is determined + automatically using the following rules: If the string begins with + "0x", it is assumed to be hexadecimal; if it begins with "0", it + is assumed to be octal; otherwise it is assumed to be decimal. + + If the conversion fails the function returns 0. + + If \a ok is not 0, failure is reported by setting *ok to false, and + success by setting *ok to true. + + This function ignores leading and trailing whitespace. + + \sa toUShort(), toString() +*/ + +short QLocale::toShort(const QString &s, bool *ok, int base) const +{ + qlonglong i = toLongLong(s, ok, base); + if (i < SHRT_MIN || i > SHRT_MAX) { + if (ok != 0) + *ok = false; + return 0; + } + return short(i); +} + +/*! + Returns the unsigned short int represented by the localized string + \a s, using base \a base. If \a base is 0 the base is determined + automatically using the following rules: If the string begins with + "0x", it is assumed to be hexadecimal; if it begins with "0", it + is assumed to be octal; otherwise it is assumed to be decimal. + + If the conversion fails the function returns 0. + + If \a ok is not 0, failure is reported by setting *ok to false, and + success by setting *ok to true. + + This function ignores leading and trailing whitespace. + + \sa toShort(), toString() +*/ + +ushort QLocale::toUShort(const QString &s, bool *ok, int base) const +{ + qulonglong i = toULongLong(s, ok, base); + if (i > USHRT_MAX) { + if (ok != 0) + *ok = false; + return 0; + } + return ushort(i); +} + +/*! + Returns the int represented by the localized string \a s, using + base \a base. If \a base is 0 the base is determined automatically + using the following rules: If the string begins with "0x", it is + assumed to be hexadecimal; if it begins with "0", it is assumed to + be octal; otherwise it is assumed to be decimal. + + If the conversion fails the function returns 0. + + If \a ok is not 0, failure is reported by setting *ok to false, and + success by setting *ok to true. + + This function ignores leading and trailing whitespace. + + \sa toUInt(), toString() +*/ + +int QLocale::toInt(const QString &s, bool *ok, int base) const +{ + qlonglong i = toLongLong(s, ok, base); + if (i < INT_MIN || i > INT_MAX) { + if (ok != 0) + *ok = false; + return 0; + } + return int(i); +} + +/*! + Returns the unsigned int represented by the localized string \a s, + using base \a base. If \a base is 0 the base is determined + automatically using the following rules: If the string begins with + "0x", it is assumed to be hexadecimal; if it begins with "0", it + is assumed to be octal; otherwise it is assumed to be decimal. + + If the conversion fails the function returns 0. + + If \a ok is not 0, failure is reported by setting *ok to false, and + success by setting *ok to true. + + This function ignores leading and trailing whitespace. + + \sa toInt(), toString() +*/ + +uint QLocale::toUInt(const QString &s, bool *ok, int base) const +{ + qulonglong i = toULongLong(s, ok, base); + if (i > UINT_MAX) { + if (ok != 0) + *ok = false; + return 0; + } + return uint(i); +} + +/*! + Returns the long long int represented by the localized string \a + s, using base \a base. If \a base is 0 the base is determined + automatically using the following rules: If the string begins with + "0x", it is assumed to be hexadecimal; if it begins with "0", it + is assumed to be octal; otherwise it is assumed to be decimal. + + If the conversion fails the function returns 0. + + If \a ok is not 0, failure is reported by setting *ok to false, and + success by setting *ok to true. + + This function ignores leading and trailing whitespace. + + \sa toInt(), toULongLong(), toDouble(), toString() +*/ + + +qlonglong QLocale::toLongLong(const QString &s, bool *ok, int base) const +{ + QLocalePrivate::GroupSeparatorMode mode + = p.numberOptions & RejectGroupSeparator + ? QLocalePrivate::FailOnGroupSeparators + : QLocalePrivate::ParseGroupSeparators; + + return d()->stringToLongLong(s, base, ok, mode); +} + +// ### Qt5: make the return type for toULongLong() qulonglong. + +/*! + Returns the unsigned long long int represented by the localized + string \a s, using base \a base. If \a base is 0 the base is + determined automatically using the following rules: If the string + begins with "0x", it is assumed to be hexadecimal; if it begins + with "0", it is assumed to be octal; otherwise it is assumed to be + decimal. + + If the conversion fails the function returns 0. + + If \a ok is not 0, failure is reported by setting *ok to false, and + success by setting *ok to true. + + This function ignores leading and trailing whitespace. + + \sa toLongLong(), toInt(), toDouble(), toString() +*/ + +qlonglong QLocale::toULongLong(const QString &s, bool *ok, int base) const +{ + QLocalePrivate::GroupSeparatorMode mode + = p.numberOptions & RejectGroupSeparator + ? QLocalePrivate::FailOnGroupSeparators + : QLocalePrivate::ParseGroupSeparators; + + return d()->stringToUnsLongLong(s, base, ok, mode); +} + +/*! + Returns the float represented by the localized string \a s, or 0.0 + if the conversion failed. + + If \a ok is not 0, reports failure by setting + *ok to false and success by setting *ok to true. + + This function ignores leading and trailing whitespace. + + \sa toDouble(), toInt(), toString() +*/ + +#define QT_MAX_FLOAT 3.4028234663852886e+38 + +float QLocale::toFloat(const QString &s, bool *ok) const +{ + bool myOk; + double d = toDouble(s, &myOk); + if (!myOk || d > QT_MAX_FLOAT || d < -QT_MAX_FLOAT) { + if (ok != 0) + *ok = false; + return 0.0; + } + if (ok != 0) + *ok = true; + return float(d); +} + +/*! + Returns the double represented by the localized string \a s, or + 0.0 if the conversion failed. + + If \a ok is not 0, reports failure by setting + *ok to false and success by setting *ok to true. + + Unlike QString::toDouble(), this function does not fall back to + the "C" locale if the string cannot be interpreted in this + locale. + + \snippet doc/src/snippets/code/src_corelib_tools_qlocale.cpp 3 + + Notice that the last conversion returns 1234.0, because '.' is the + thousands group separator in the German locale. + + This function ignores leading and trailing whitespace. + + \sa toFloat(), toInt(), toString() +*/ + +double QLocale::toDouble(const QString &s, bool *ok) const +{ + QLocalePrivate::GroupSeparatorMode mode + = p.numberOptions & RejectGroupSeparator + ? QLocalePrivate::FailOnGroupSeparators + : QLocalePrivate::ParseGroupSeparators; + + return d()->stringToDouble(s, ok, mode); +} + +/*! + Returns a localized string representation of \a i. + + \sa toLongLong() +*/ + +QString QLocale::toString(qlonglong i) const +{ + int flags = p.numberOptions & OmitGroupSeparator + ? 0 + : QLocalePrivate::ThousandsGroup; + + return d()->longLongToString(i, -1, 10, -1, flags); +} + +/*! + \overload + + \sa toULongLong() +*/ + +QString QLocale::toString(qulonglong i) const +{ + int flags = p.numberOptions & OmitGroupSeparator + ? 0 + : QLocalePrivate::ThousandsGroup; + + return d()->unsLongLongToString(i, -1, 10, -1, flags); +} + +/*! + Returns a localized string representation of the given \a date in the + specified \a format. + If \a format is an empty string, an empty string is returned. +*/ + +QString QLocale::toString(const QDate &date, const QString &format) const +{ + return d()->dateTimeToString(format, &date, 0, this); +} + +/*! + Returns a localized string representation of the given \a date according + to the specified \a format. +*/ + +QString QLocale::toString(const QDate &date, FormatType format) const +{ + if (!date.isValid()) + return QString(); + +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QVariant res = systemLocale()->query(format == LongFormat + ? QSystemLocale::DateToStringLong : QSystemLocale::DateToStringShort, + date); + if (!res.isNull()) + return res.toString(); + } +#endif + + QString format_str = dateFormat(format); + return toString(date, format_str); +} + +static bool timeFormatContainsAP(const QString &format) +{ + int i = 0; + while (i < format.size()) { + if (format.at(i).unicode() == '\'') { + qt_readEscapedFormatString(format, &i); + continue; + } + + if (format.at(i).toLower().unicode() == 'a') + return true; + + ++i; + } + return false; +} + +static QString timeZone() +{ +#if defined(Q_OS_WINCE) + TIME_ZONE_INFORMATION info; + DWORD res = GetTimeZoneInformation(&info); + if (res == TIME_ZONE_ID_UNKNOWN) + return QString(); + return QString::fromWCharArray(info.StandardName); +#elif defined(Q_OS_WIN) + _tzset(); +# if defined(_MSC_VER) && _MSC_VER >= 1400 + size_t returnSize = 0; + char timeZoneName[512]; + if (_get_tzname(&returnSize, timeZoneName, 512, 1)) + return QString(); + return QString::fromLocal8Bit(timeZoneName); +# else + return QString::fromLocal8Bit(_tzname[1]); +# endif +#elif defined(Q_OS_VXWORKS) + return QString(); +#else + tzset(); + return QString::fromLocal8Bit(tzname[1]); +#endif +} + +/*! + Returns a localized string representation of the given \a time according + to the specified \a format. + If \a format is an empty string, an empty string is returned. +*/ +QString QLocale::toString(const QTime &time, const QString &format) const +{ + return d()->dateTimeToString(format, 0, &time, this); +} + +/*! + \since 4.4 + + Returns a localized string representation of the given \a dateTime according + to the specified \a format. + If \a format is an empty string, an empty string is returned. +*/ + +QString QLocale::toString(const QDateTime &dateTime, const QString &format) const +{ + const QDate dt = dateTime.date(); + const QTime tm = dateTime.time(); + return d()->dateTimeToString(format, &dt, &tm, this); +} + +/*! + \since 4.4 + + Returns a localized string representation of the given \a dateTime according + to the specified \a format. +*/ + +QString QLocale::toString(const QDateTime &dateTime, FormatType format) const +{ + if (!dateTime.isValid()) + return QString(); + +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QVariant res = systemLocale()->query(format == LongFormat + ? QSystemLocale::DateTimeToStringLong + : QSystemLocale::DateTimeToStringShort, + dateTime); + if (!res.isNull()) + return res.toString(); + } +#endif + + const QString format_str = dateTimeFormat(format); + return toString(dateTime, format_str); +} + + +/*! + Returns a localized string representation of the given \a time in the + specified \a format. +*/ + +QString QLocale::toString(const QTime &time, FormatType format) const +{ + if (!time.isValid()) + return QString(); + +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QVariant res = systemLocale()->query(format == LongFormat + ? QSystemLocale::TimeToStringLong : QSystemLocale::TimeToStringShort, + time); + if (!res.isNull()) + return res.toString(); + } +#endif + + QString format_str = timeFormat(format); + return toString(time, format_str); +} + +/*! + \since 4.1 + + Returns the date format used for the current locale. + + If \a format is LongFormat the format will be a long version. + Otherwise it uses a shorter version. + + \sa QDate::toString(), QDate::fromString() +*/ + +QString QLocale::dateFormat(FormatType format) const +{ +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QVariant res = systemLocale()->query(format == LongFormat + ? QSystemLocale::DateFormatLong : QSystemLocale::DateFormatShort, + QVariant()); + if (!res.isNull()) + return res.toString(); + } +#endif + + quint32 idx, size; + switch (format) { + case LongFormat: + idx = d()->m_long_date_format_idx; + size = d()->m_long_date_format_size; + break; + default: + idx = d()->m_short_date_format_idx; + size = d()->m_short_date_format_size; + break; + } + return getLocaleData(date_format_data + idx, size); +} + +/*! + \since 4.1 + + Returns the time format used for the current locale. + + If \a format is LongFormat the format will be a long version. + Otherwise it uses a shorter version. + + \sa QTime::toString(), QTime::fromString() +*/ + +QString QLocale::timeFormat(FormatType format) const +{ +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QVariant res = systemLocale()->query(format == LongFormat + ? QSystemLocale::TimeFormatLong : QSystemLocale::TimeFormatShort, + QVariant()); + if (!res.isNull()) + return res.toString(); + } +#endif + + quint32 idx, size; + switch (format) { + case LongFormat: + idx = d()->m_long_time_format_idx; + size = d()->m_long_time_format_size; + break; + default: + idx = d()->m_short_time_format_idx; + size = d()->m_short_time_format_size; + break; + } + return getLocaleData(time_format_data + idx, size); +} + +/*! + \since 4.4 + + Returns the date time format used for the current locale. + + If \a format is ShortFormat the format will be a short version. + Otherwise it uses a longer version. + + \sa QDateTime::toString(), QDateTime::fromString() +*/ + +QString QLocale::dateTimeFormat(FormatType format) const +{ +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QVariant res = systemLocale()->query(format == LongFormat + ? QSystemLocale::DateTimeFormatLong + : QSystemLocale::DateTimeFormatShort, + QVariant()); + if (!res.isNull()) { + return res.toString(); + } + } +#endif + return dateFormat(format) + QLatin1Char(' ') + timeFormat(format); +} + +/*! + \since 4.4 + + Parses the time string given in \a string and returns the + time. The format of the time string is chosen according to the + \a format parameter (see timeFormat()). + + If the time could not be parsed, returns an invalid time. + + \sa timeFormat(), toDate(), toDateTime(), QTime::fromString() +*/ +#ifndef QT_NO_DATESTRING +QTime QLocale::toTime(const QString &string, FormatType format) const +{ + return toTime(string, timeFormat(format)); +} +#endif + +/*! + \since 4.4 + + Parses the date string given in \a string and returns the + date. The format of the date string is chosen according to the + \a format parameter (see dateFormat()). + + If the date could not be parsed, returns an invalid date. + + \sa dateFormat(), toTime(), toDateTime(), QDate::fromString() +*/ +#ifndef QT_NO_DATESTRING +QDate QLocale::toDate(const QString &string, FormatType format) const +{ + return toDate(string, dateFormat(format)); +} +#endif + +/*! + \since 4.4 + + Parses the date/time string given in \a string and returns the + time. The format of the date/time string is chosen according to the + \a format parameter (see dateTimeFormat()). + + If the string could not be parsed, returns an invalid QDateTime. + + \sa dateTimeFormat(), toTime(), toDate(), QDateTime::fromString() +*/ + +#ifndef QT_NO_DATESTRING +QDateTime QLocale::toDateTime(const QString &string, FormatType format) const +{ + return toDateTime(string, dateTimeFormat(format)); +} +#endif + +/*! + \since 4.4 + + Parses the time string given in \a string and returns the + time. See QTime::fromString() for information on what is a valid + format string. + + If the time could not be parsed, returns an invalid time. + + \sa timeFormat(), toDate(), toDateTime(), QTime::fromString() +*/ +#ifndef QT_NO_DATESTRING +QTime QLocale::toTime(const QString &string, const QString &format) const +{ + QTime time; +#ifndef QT_BOOTSTRAPPED + QDateTimeParser dt(QVariant::Time, QDateTimeParser::FromString); + dt.defaultLocale = *this; + if (dt.parseFormat(format)) + dt.fromString(string, 0, &time); +#else + Q_UNUSED(string); + Q_UNUSED(format); +#endif + return time; +} +#endif + +/*! + \since 4.4 + + Parses the date string given in \a string and returns the + date. See QDate::fromString() for information on the expressions + that can be used with this function. + + This function searches month names and the names of the days of + the week in the current locale. + + If the date could not be parsed, returns an invalid date. + + \sa dateFormat(), toTime(), toDateTime(), QDate::fromString() +*/ +#ifndef QT_NO_DATESTRING +QDate QLocale::toDate(const QString &string, const QString &format) const +{ + QDate date; +#ifndef QT_BOOTSTRAPPED + QDateTimeParser dt(QVariant::Date, QDateTimeParser::FromString); + dt.defaultLocale = *this; + if (dt.parseFormat(format)) + dt.fromString(string, &date, 0); +#else + Q_UNUSED(string); + Q_UNUSED(format); +#endif + return date; +} +#endif + +/*! + \since 4.4 + + Parses the date/time string given in \a string and returns the + time. See QDateTime::fromString() for information on the expressions + that can be used with this function. + + \note The month and day names used must be given in the user's local + language. + + If the string could not be parsed, returns an invalid QDateTime. + + \sa dateTimeFormat(), toTime(), toDate(), QDateTime::fromString() +*/ +#ifndef QT_NO_DATESTRING +QDateTime QLocale::toDateTime(const QString &string, const QString &format) const +{ +#ifndef QT_BOOTSTRAPPED + QTime time; + QDate date; + + QDateTimeParser dt(QVariant::DateTime, QDateTimeParser::FromString); + dt.defaultLocale = *this; + if (dt.parseFormat(format) && dt.fromString(string, &date, &time)) + return QDateTime(date, time); +#else + Q_UNUSED(string); + Q_UNUSED(format); +#endif + return QDateTime(QDate(), QTime(-1, -1, -1)); +} +#endif + + +/*! + \since 4.1 + + Returns the decimal point character of this locale. +*/ +QChar QLocale::decimalPoint() const +{ + return d()->decimal(); +} + +/*! + \since 4.1 + + Returns the group separator character of this locale. +*/ +QChar QLocale::groupSeparator() const +{ + return d()->group(); +} + +/*! + \since 4.1 + + Returns the percent character of this locale. +*/ +QChar QLocale::percent() const +{ + return d()->percent(); +} + +/*! + \since 4.1 + + Returns the zero digit character of this locale. +*/ +QChar QLocale::zeroDigit() const +{ + return d()->zero(); +} + +/*! + \since 4.1 + + Returns the negative sign character of this locale. +*/ +QChar QLocale::negativeSign() const +{ + return d()->minus(); +} + +/*! + \since 4.5 + + Returns the positive sign character of this locale. +*/ +QChar QLocale::positiveSign() const +{ + return d()->plus(); +} + +/*! + \since 4.1 + + Returns the exponential character of this locale. +*/ +QChar QLocale::exponential() const +{ + return d()->exponential(); +} + +static bool qIsUpper(char c) +{ + return c >= 'A' && c <= 'Z'; +} + +static char qToLower(char c) +{ + if (c >= 'A' && c <= 'Z') + return c - 'A' + 'a'; + else + return c; +} + +/*! + \overload + + \a f and \a prec have the same meaning as in QString::number(double, char, int). + + \sa toDouble() +*/ + +QString QLocale::toString(double i, char f, int prec) const +{ + QLocalePrivate::DoubleForm form = QLocalePrivate::DFDecimal; + uint flags = 0; + + if (qIsUpper(f)) + flags = QLocalePrivate::CapitalEorX; + f = qToLower(f); + + switch (f) { + case 'f': + form = QLocalePrivate::DFDecimal; + break; + case 'e': + form = QLocalePrivate::DFExponent; + break; + case 'g': + form = QLocalePrivate::DFSignificantDigits; + break; + default: + break; + } + + if (!(p.numberOptions & OmitGroupSeparator)) + flags |= QLocalePrivate::ThousandsGroup; + return d()->doubleToString(i, prec, form, -1, flags); +} + +/*! + \fn QLocale QLocale::c() + + Returns a QLocale object initialized to the "C" locale. + + \sa system() +*/ + +/*! + Returns a QLocale object initialized to the system locale. + + On Windows and Mac, this locale will use the decimal/grouping characters and date/time + formats specified in the system configuration panel. + + \sa c() +*/ + +QLocale QLocale::system() +{ + QLocale result(C); + result.p.index = localePrivateIndex(systemPrivate()); + return result; +} + + +/*! + \since 4.8 + + Returns a list of valid locale objects that match the given \a language, \a + script and \a country. + + Getting a list of all locales: + QList<QLocale> allLocales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, QLocale::AnyCountry); +*/ +QList<QLocale> QLocale::matchingLocales(QLocale::Language language, + QLocale::Script script, + QLocale::Country country) +{ + if (uint(language) > QLocale::LastLanguage || uint(script) > QLocale::LastScript || + uint(country) > QLocale::LastCountry) + return QList<QLocale>(); + + QList<QLocale> result; + const QLocalePrivate *d = locale_data; + if (language == QLocale::AnyLanguage && script == QLocale::AnyScript && country == QLocale::AnyCountry) + result.reserve(locale_data_size); + if (language != QLocale::C) + d += locale_index[language]; + while ( (d != locale_data + locale_data_size) + && (language == QLocale::AnyLanguage || d->m_language_id == uint(language))) { + QLocale locale(QLocale::C); + locale.p.index = localePrivateIndex(d); + result.append(locale); + ++d; + } + return result; +} + +/*! + \obsolete + \since 4.3 + + Returns the list of countries that have entires for \a language in Qt's locale + database. If the result is an empty list, then \a language is not represented in + Qt's locale database. + + \sa matchingLocales() +*/ +QList<QLocale::Country> QLocale::countriesForLanguage(Language language) +{ + QList<Country> result; + + unsigned language_id = language; + uint idx = locale_index[language_id]; + + if (language == C) { + result << AnyCountry; + return result; + } + + const QLocalePrivate *d = locale_data + idx; + + while (d->languageId() == language_id) { + result << static_cast<Country>(d->countryId()); + ++d; + } + + return result; +} + +/*! + \since 4.2 + + Returns the localized name of \a month, in the format specified + by \a type. + + \sa dayName(), standaloneMonthName() +*/ +QString QLocale::monthName(int month, FormatType type) const +{ + if (month < 1 || month > 12) + return QString(); + +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QVariant res = systemLocale()->query(type == LongFormat + ? QSystemLocale::MonthNameLong : QSystemLocale::MonthNameShort, + month); + if (!res.isNull()) + return res.toString(); + } +#endif + + quint32 idx, size; + switch (type) { + case QLocale::LongFormat: + idx = d()->m_long_month_names_idx; + size = d()->m_long_month_names_size; + break; + case QLocale::ShortFormat: + idx = d()->m_short_month_names_idx; + size = d()->m_short_month_names_size; + break; + case QLocale::NarrowFormat: + idx = d()->m_narrow_month_names_idx; + size = d()->m_narrow_month_names_size; + break; + default: + return QString(); + } + return getLocaleListData(months_data + idx, size, month - 1); +} + +/*! + \since 4.5 + + Returns the localized name of \a month that is used as a + standalone text, in the format specified by \a type. + + If the locale information doesn't specify the standalone month + name then return value is the same as in monthName(). + + \sa monthName(), standaloneDayName() +*/ +QString QLocale::standaloneMonthName(int month, FormatType type) const +{ + if (month < 1 || month > 12) + return QString(); + +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QVariant res = systemLocale()->query(type == LongFormat + ? QSystemLocale::MonthNameLong : QSystemLocale::MonthNameShort, + month); + if (!res.isNull()) + return res.toString(); + } +#endif + + quint32 idx, size; + switch (type) { + case QLocale::LongFormat: + idx = d()->m_standalone_long_month_names_idx; + size = d()->m_standalone_long_month_names_size; + break; + case QLocale::ShortFormat: + idx = d()->m_standalone_short_month_names_idx; + size = d()->m_standalone_short_month_names_size; + break; + case QLocale::NarrowFormat: + idx = d()->m_standalone_narrow_month_names_idx; + size = d()->m_standalone_narrow_month_names_size; + break; + default: + return QString(); + } + QString name = getLocaleListData(standalone_months_data + idx, size, month - 1); + if (name.isEmpty()) + return monthName(month, type); + return name; +} + +/*! + \since 4.2 + + Returns the localized name of the \a day (where 1 represents + Monday, 2 represents Tuesday and so on), in the format specified + by \a type. + + \sa monthName(), standaloneDayName() +*/ +QString QLocale::dayName(int day, FormatType type) const +{ + if (day < 1 || day > 7) + return QString(); + +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QVariant res = systemLocale()->query(type == LongFormat + ? QSystemLocale::DayNameLong : QSystemLocale::DayNameShort, + day); + if (!res.isNull()) + return res.toString(); + } +#endif + if (day == 7) + day = 0; + + quint32 idx, size; + switch (type) { + case QLocale::LongFormat: + idx = d()->m_long_day_names_idx; + size = d()->m_long_day_names_size; + break; + case QLocale::ShortFormat: + idx = d()->m_short_day_names_idx; + size = d()->m_short_day_names_size; + break; + case QLocale::NarrowFormat: + idx = d()->m_narrow_day_names_idx; + size = d()->m_narrow_day_names_size; + break; + default: + return QString(); + } + return getLocaleListData(days_data + idx, size, day); +} + +/*! + \since 4.5 + + Returns the localized name of the \a day (where 1 represents + Monday, 2 represents Tuesday and so on) that is used as a + standalone text, in the format specified by \a type. + + If the locale information does not specify the standalone day + name then return value is the same as in dayName(). + + \sa dayName(), standaloneMonthName() +*/ +QString QLocale::standaloneDayName(int day, FormatType type) const +{ + if (day < 1 || day > 7) + return QString(); + +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QVariant res = systemLocale()->query(type == LongFormat + ? QSystemLocale::DayNameLong : QSystemLocale::DayNameShort, + day); + if (!res.isNull()) + return res.toString(); + } +#endif + if (day == 7) + day = 0; + + quint32 idx, size; + switch (type) { + case QLocale::LongFormat: + idx = d()->m_standalone_long_day_names_idx; + size = d()->m_standalone_long_day_names_size; + break; + case QLocale::ShortFormat: + idx = d()->m_standalone_short_day_names_idx; + size = d()->m_standalone_short_day_names_size; + break; + case QLocale::NarrowFormat: + idx = d()->m_standalone_narrow_day_names_idx; + size = d()->m_standalone_narrow_day_names_size; + break; + default: + return QString(); + } + QString name = getLocaleListData(days_data + idx, size, day); + if (name.isEmpty()) + return dayName(day == 0 ? 7 : day, type); + return name; +} + +/*! + \since 4.8 + + Returns the first day of the week according to the current locale. +*/ +Qt::DayOfWeek QLocale::firstDayOfWeek() const +{ +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QVariant res = systemLocale()->query(QSystemLocale::FirstDayOfWeek, QVariant()); + if (!res.isNull()) + return static_cast<Qt::DayOfWeek>(res.toUInt()); + } +#endif + return static_cast<Qt::DayOfWeek>(d()->m_first_day_of_week); +} + +QLocale::MeasurementSystem QLocalePrivate::measurementSystem() const +{ + for (int i = 0; i < ImperialMeasurementSystemsCount; ++i) { + if (ImperialMeasurementSystems[i].languageId == m_language_id + && ImperialMeasurementSystems[i].countryId == m_country_id) { + return QLocale::ImperialSystem; + } + } + return QLocale::MetricSystem; +} + +/*! + \since 4.8 + + Returns a list of days that are considered weekdays according to the current locale. +*/ +QList<Qt::DayOfWeek> QLocale::weekdays() const +{ +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QVariant res = systemLocale()->query(QSystemLocale::Weekdays, QVariant()); + if (!res.isNull()) + return static_cast<QList<Qt::DayOfWeek> >(res.value<QList<Qt::DayOfWeek> >()); + } +#endif + QList<Qt::DayOfWeek> weekdays; + quint16 weekendStart = d()->m_weekend_start; + quint16 weekendEnd = d()->m_weekend_end; + for (int day = Qt::Monday; day <= Qt::Sunday; day++) { + if ((weekendEnd >= weekendStart && (day < weekendStart || day > weekendEnd)) || + (weekendEnd < weekendStart && (day > weekendEnd && day < weekendStart))) + weekdays << static_cast<Qt::DayOfWeek>(day); + } + return weekdays; +} + +/*! + \since 4.4 + + Returns the measurement system for the locale. +*/ +QLocale::MeasurementSystem QLocale::measurementSystem() const +{ +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QVariant res = systemLocale()->query(QSystemLocale::MeasurementSystem, QVariant()); + if (!res.isNull()) + return MeasurementSystem(res.toInt()); + } +#endif + + return d()->measurementSystem(); +} + +/*! + \since 4.7 + + Returns the text direction of the language. +*/ +Qt::LayoutDirection QLocale::textDirection() const +{ + Language lang = language(); + if (lang == QLocale::Arabic || + lang == QLocale::Hebrew || + lang == QLocale::Persian || + lang == QLocale::Urdu || + lang == QLocale::Syriac) + return Qt::RightToLeft; + + return Qt::LeftToRight; +} + + +/*! + \since 4.5 + + Returns the localized name of the "AM" suffix for times specified using + the conventions of the 12-hour clock. + + \sa pmText() +*/ +QString QLocale::amText() const +{ +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QVariant res = systemLocale()->query(QSystemLocale::AMText, QVariant()); + if (!res.isNull()) + return res.toString(); + } +#endif + return getLocaleData(am_data + d()->m_am_idx, d()->m_am_size); +} + +/*! + \since 4.5 + + Returns the localized name of the "PM" suffix for times specified using + the conventions of the 12-hour clock. + + \sa amText() +*/ +QString QLocale::pmText() const +{ +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QVariant res = systemLocale()->query(QSystemLocale::PMText, QVariant()); + if (!res.isNull()) + return res.toString(); + } +#endif + return getLocaleData(pm_data + d()->m_pm_idx, d()->m_pm_size); +} + + +QString QLocalePrivate::dateTimeToString(const QString &format, const QDate *date, const QTime *time, + const QLocale *q) const +{ + Q_ASSERT(date || time); + if ((date && !date->isValid()) || (time && !time->isValid())) + return QString(); + const bool format_am_pm = time && timeFormatContainsAP(format); + + enum { AM, PM } am_pm = AM; + int hour12 = time ? time->hour() : -1; + if (time) { + if (hour12 == 0) { + am_pm = AM; + hour12 = 12; + } else if (hour12 < 12) { + am_pm = AM; + } else if (hour12 == 12) { + am_pm = PM; + } else { + am_pm = PM; + hour12 -= 12; + } + } + + QString result; + + int i = 0; + while (i < format.size()) { + if (format.at(i).unicode() == '\'') { + result.append(qt_readEscapedFormatString(format, &i)); + continue; + } + + const QChar c = format.at(i); + int repeat = qt_repeatCount(format, i); + bool used = false; + if (date) { + switch (c.unicode()) { + case 'y': + used = true; + if (repeat >= 4) + repeat = 4; + else if (repeat >= 2) + repeat = 2; + + switch (repeat) { + case 4: + result.append(longLongToString(date->year())); + break; + case 2: + result.append(longLongToString(date->year() % 100, -1, 10, 2, + QLocalePrivate::ZeroPadded)); + break; + default: + repeat = 1; + result.append(c); + break; + } + break; + + case 'M': + used = true; + repeat = qMin(repeat, 4); + switch (repeat) { + case 1: + result.append(longLongToString(date->month())); + break; + case 2: + result.append(longLongToString(date->month(), -1, 10, 2, QLocalePrivate::ZeroPadded)); + break; + case 3: + result.append(q->monthName(date->month(), QLocale::ShortFormat)); + break; + case 4: + result.append(q->monthName(date->month(), QLocale::LongFormat)); + break; + } + break; + + case 'd': + used = true; + repeat = qMin(repeat, 4); + switch (repeat) { + case 1: + result.append(longLongToString(date->day())); + break; + case 2: + result.append(longLongToString(date->day(), -1, 10, 2, QLocalePrivate::ZeroPadded)); + break; + case 3: + result.append(q->dayName(date->dayOfWeek(), QLocale::ShortFormat)); + break; + case 4: + result.append(q->dayName(date->dayOfWeek(), QLocale::LongFormat)); + break; + } + break; + + default: + break; + } + } + if (!used && time) { + switch (c.unicode()) { + case 'h': { + used = true; + repeat = qMin(repeat, 2); + const int hour = format_am_pm ? hour12 : time->hour(); + + switch (repeat) { + case 1: + result.append(longLongToString(hour)); + break; + case 2: + result.append(longLongToString(hour, -1, 10, 2, QLocalePrivate::ZeroPadded)); + break; + } + break; + } + case 'H': + used = true; + repeat = qMin(repeat, 2); + switch (repeat) { + case 1: + result.append(longLongToString(time->hour())); + break; + case 2: + result.append(longLongToString(time->hour(), -1, 10, 2, QLocalePrivate::ZeroPadded)); + break; + } + break; + + case 'm': + used = true; + repeat = qMin(repeat, 2); + switch (repeat) { + case 1: + result.append(longLongToString(time->minute())); + break; + case 2: + result.append(longLongToString(time->minute(), -1, 10, 2, QLocalePrivate::ZeroPadded)); + break; + } + break; + + case 's': + used = true; + repeat = qMin(repeat, 2); + switch (repeat) { + case 1: + result.append(longLongToString(time->second())); + break; + case 2: + result.append(longLongToString(time->second(), -1, 10, 2, QLocalePrivate::ZeroPadded)); + break; + } + break; + + case 'a': + used = true; + if (i + 1 < format.length() && format.at(i + 1).unicode() == 'p') { + repeat = 2; + } else { + repeat = 1; + } + result.append(am_pm == AM ? q->amText().toLower() : q->pmText().toLower()); + break; + + case 'A': + used = true; + if (i + 1 < format.length() && format.at(i + 1).unicode() == 'P') { + repeat = 2; + } else { + repeat = 1; + } + result.append(am_pm == AM ? q->amText().toUpper() : q->pmText().toUpper()); + break; + + case 'z': + used = true; + if (repeat >= 3) { + repeat = 3; + } else { + repeat = 1; + } + switch (repeat) { + case 1: + result.append(longLongToString(time->msec())); + break; + case 3: + result.append(longLongToString(time->msec(), -1, 10, 3, QLocalePrivate::ZeroPadded)); + break; + } + break; + + case 't': + used = true; + repeat = 1; + result.append(timeZone()); + break; + default: + break; + } + } + if (!used) { + result.append(QString(repeat, c)); + } + i += repeat; + } + + return result; +} + +QString QLocalePrivate::doubleToString(double d, + int precision, + DoubleForm form, + int width, + unsigned flags) const +{ + return QLocalePrivate::doubleToString(zero(), plus(), minus(), exponential(), + group(), decimal(), + d, precision, form, width, flags); +} + +QString QLocalePrivate::doubleToString(const QChar _zero, const QChar plus, const QChar minus, + const QChar exponential, const QChar group, const QChar decimal, + double d, + int precision, + DoubleForm form, + int width, + unsigned flags) +{ + if (precision == -1) + precision = 6; + if (width == -1) + width = 0; + + bool negative = false; + bool special_number = false; // nan, +/-inf + QString num_str; + + // Detect special numbers (nan, +/-inf) + if (qt_is_inf(d)) { + num_str = QString::fromLatin1("inf"); + special_number = true; + negative = d < 0; + } else if (qt_is_nan(d)) { + num_str = QString::fromLatin1("nan"); + special_number = true; + } + + // Handle normal numbers + if (!special_number) { + int decpt, sign; + QString digits; + +#ifdef QT_QLOCALE_USES_FCVT + // NOT thread safe! + if (form == DFDecimal) { + digits = QLatin1String(fcvt(d, precision, &decpt, &sign)); + } else { + int pr = precision; + if (form == DFExponent) + ++pr; + else if (form == DFSignificantDigits && pr == 0) + pr = 1; + digits = QLatin1String(ecvt(d, pr, &decpt, &sign)); + + // Chop trailing zeros + if (digits.length() > 0) { + int last_nonzero_idx = digits.length() - 1; + while (last_nonzero_idx > 0 + && digits.unicode()[last_nonzero_idx] == QLatin1Char('0')) + --last_nonzero_idx; + digits.truncate(last_nonzero_idx + 1); + } + + } + +#else + int mode; + if (form == DFDecimal) + mode = 3; + else + mode = 2; + + /* This next bit is a bit quirky. In DFExponent form, the precision + is the number of digits after decpt. So that would suggest using + mode=3 for qdtoa. But qdtoa behaves strangely when mode=3 and + precision=0. So we get around this by using mode=2 and reasoning + that we want precision+1 significant digits, since the decimal + point in this mode is always after the first digit. */ + int pr = precision; + if (form == DFExponent) + ++pr; + + char *rve = 0; + char *buff = 0; + QT_TRY { + digits = QLatin1String(qdtoa(d, mode, pr, &decpt, &sign, &rve, &buff)); + } QT_CATCH(...) { + if (buff != 0) + free(buff); + QT_RETHROW; + } + if (buff != 0) + free(buff); +#endif // QT_QLOCALE_USES_FCVT + + if (_zero.unicode() != '0') { + ushort z = _zero.unicode() - '0'; + for (int i = 0; i < digits.length(); ++i) + reinterpret_cast<ushort *>(digits.data())[i] += z; + } + + bool always_show_decpt = (flags & Alternate || flags & ForcePoint); + switch (form) { + case DFExponent: { + num_str = exponentForm(_zero, decimal, exponential, group, plus, minus, + digits, decpt, precision, PMDecimalDigits, + always_show_decpt); + break; + } + case DFDecimal: { + num_str = decimalForm(_zero, decimal, group, + digits, decpt, precision, PMDecimalDigits, + always_show_decpt, flags & ThousandsGroup); + break; + } + case DFSignificantDigits: { + PrecisionMode mode = (flags & Alternate) ? + PMSignificantDigits : PMChopTrailingZeros; + + if (decpt != digits.length() && (decpt <= -4 || decpt > precision)) + num_str = exponentForm(_zero, decimal, exponential, group, plus, minus, + digits, decpt, precision, mode, + always_show_decpt); + else + num_str = decimalForm(_zero, decimal, group, + digits, decpt, precision, mode, + always_show_decpt, flags & ThousandsGroup); + break; + } + } + + negative = sign != 0 && !isZero(d); + } + + // pad with zeros. LeftAdjusted overrides this flag). Also, we don't + // pad special numbers + if (flags & QLocalePrivate::ZeroPadded + && !(flags & QLocalePrivate::LeftAdjusted) + && !special_number) { + int num_pad_chars = width - num_str.length(); + // leave space for the sign + if (negative + || flags & QLocalePrivate::AlwaysShowSign + || flags & QLocalePrivate::BlankBeforePositive) + --num_pad_chars; + + for (int i = 0; i < num_pad_chars; ++i) + num_str.prepend(_zero); + } + + // add sign + if (negative) + num_str.prepend(minus); + else if (flags & QLocalePrivate::AlwaysShowSign) + num_str.prepend(plus); + else if (flags & QLocalePrivate::BlankBeforePositive) + num_str.prepend(QLatin1Char(' ')); + + if (flags & QLocalePrivate::CapitalEorX) + num_str = num_str.toUpper(); + + return num_str; +} + +QString QLocalePrivate::longLongToString(qlonglong l, int precision, + int base, int width, + unsigned flags) const +{ + return QLocalePrivate::longLongToString(zero(), group(), plus(), minus(), + l, precision, base, width, flags); +} + +QString QLocalePrivate::longLongToString(const QChar zero, const QChar group, + const QChar plus, const QChar minus, + qlonglong l, int precision, + int base, int width, + unsigned flags) +{ + bool precision_not_specified = false; + if (precision == -1) { + precision_not_specified = true; + precision = 1; + } + + bool negative = l < 0; + if (base != 10) { + // these are not supported by sprintf for octal and hex + flags &= ~AlwaysShowSign; + flags &= ~BlankBeforePositive; + negative = false; // neither are negative numbers + } + + QString num_str; + if (base == 10) + num_str = qlltoa(l, base, zero); + else + num_str = qulltoa(l, base, zero); + + uint cnt_thousand_sep = 0; + if (flags & ThousandsGroup && base == 10) { + for (int i = num_str.length() - 3; i > 0; i -= 3) { + num_str.insert(i, group); + ++cnt_thousand_sep; + } + } + + for (int i = num_str.length()/* - cnt_thousand_sep*/; i < precision; ++i) + num_str.prepend(base == 10 ? zero : QChar::fromLatin1('0')); + + if ((flags & Alternate || flags & ShowBase) + && base == 8 + && (num_str.isEmpty() || num_str[0].unicode() != QLatin1Char('0'))) + num_str.prepend(QLatin1Char('0')); + + // LeftAdjusted overrides this flag ZeroPadded. sprintf only padds + // when precision is not specified in the format string + bool zero_padded = flags & ZeroPadded + && !(flags & LeftAdjusted) + && precision_not_specified; + + if (zero_padded) { + int num_pad_chars = width - num_str.length(); + + // leave space for the sign + if (negative + || flags & AlwaysShowSign + || flags & BlankBeforePositive) + --num_pad_chars; + + // leave space for optional '0x' in hex form + if (base == 16 && (flags & Alternate || flags & ShowBase)) + num_pad_chars -= 2; + // leave space for optional '0b' in binary form + else if (base == 2 && (flags & Alternate || flags & ShowBase)) + num_pad_chars -= 2; + + for (int i = 0; i < num_pad_chars; ++i) + num_str.prepend(base == 10 ? zero : QChar::fromLatin1('0')); + } + + if (flags & CapitalEorX) + num_str = num_str.toUpper(); + + if (base == 16 && (flags & Alternate || flags & ShowBase)) + num_str.prepend(QLatin1String(flags & UppercaseBase ? "0X" : "0x")); + if (base == 2 && (flags & Alternate || flags & ShowBase)) + num_str.prepend(QLatin1String(flags & UppercaseBase ? "0B" : "0b")); + + // add sign + if (negative) + num_str.prepend(minus); + else if (flags & AlwaysShowSign) + num_str.prepend(plus); + else if (flags & BlankBeforePositive) + num_str.prepend(QLatin1Char(' ')); + + return num_str; +} + +QString QLocalePrivate::unsLongLongToString(qulonglong l, int precision, + int base, int width, + unsigned flags) const +{ + return QLocalePrivate::unsLongLongToString(zero(), group(), plus(), + l, precision, base, width, flags); +} + +QString QLocalePrivate::unsLongLongToString(const QChar zero, const QChar group, + const QChar plus, + qulonglong l, int precision, + int base, int width, + unsigned flags) +{ + bool precision_not_specified = false; + if (precision == -1) { + precision_not_specified = true; + precision = 1; + } + + QString num_str = qulltoa(l, base, zero); + + uint cnt_thousand_sep = 0; + if (flags & ThousandsGroup && base == 10) { + for (int i = num_str.length() - 3; i > 0; i -=3) { + num_str.insert(i, group); + ++cnt_thousand_sep; + } + } + + for (int i = num_str.length()/* - cnt_thousand_sep*/; i < precision; ++i) + num_str.prepend(base == 10 ? zero : QChar::fromLatin1('0')); + + if ((flags & Alternate || flags & ShowBase) + && base == 8 + && (num_str.isEmpty() || num_str[0].unicode() != QLatin1Char('0'))) + num_str.prepend(QLatin1Char('0')); + + // LeftAdjusted overrides this flag ZeroPadded. sprintf only padds + // when precision is not specified in the format string + bool zero_padded = flags & ZeroPadded + && !(flags & LeftAdjusted) + && precision_not_specified; + + if (zero_padded) { + int num_pad_chars = width - num_str.length(); + + // leave space for optional '0x' in hex form + if (base == 16 && flags & Alternate) + num_pad_chars -= 2; + // leave space for optional '0b' in binary form + else if (base == 2 && flags & Alternate) + num_pad_chars -= 2; + + for (int i = 0; i < num_pad_chars; ++i) + num_str.prepend(base == 10 ? zero : QChar::fromLatin1('0')); + } + + if (flags & CapitalEorX) + num_str = num_str.toUpper(); + + if (base == 16 && (flags & Alternate || flags & ShowBase)) + num_str.prepend(QLatin1String(flags & UppercaseBase ? "0X" : "0x")); + else if (base == 2 && (flags & Alternate || flags & ShowBase)) + num_str.prepend(QLatin1String(flags & UppercaseBase ? "0B" : "0b")); + + // add sign + if (flags & AlwaysShowSign) + num_str.prepend(plus); + else if (flags & BlankBeforePositive) + num_str.prepend(QLatin1Char(' ')); + + return num_str; +} + +/* + Converts a number in locale to its representation in the C locale. + Only has to guarantee that a string that is a correct representation of + a number will be converted. If junk is passed in, junk will be passed + out and the error will be detected during the actual conversion to a + number. We can't detect junk here, since we don't even know the base + of the number. +*/ +bool QLocalePrivate::numberToCLocale(const QString &num, + GroupSeparatorMode group_sep_mode, + CharBuff *result) const +{ + const QChar *uc = num.unicode(); + int l = num.length(); + int idx = 0; + + // Skip whitespace + while (idx < l && uc[idx].isSpace()) + ++idx; + if (idx == l) + return false; + + const QChar _group = group(); + + while (idx < l) { + const QChar &in = uc[idx]; + + char out = digitToCLocale(in); + if (out == 0) { + if (in == list()) + out = ';'; + else if (in == percent()) + out = '%'; + // for handling base-x numbers + else if (in.unicode() >= 'A' && in.unicode() <= 'Z') + out = in.toLower().toLatin1(); + else if (in.unicode() >= 'a' && in.unicode() <= 'z') + out = in.toLatin1(); + else + break; + } + + result->append(out); + + ++idx; + } + + // Check trailing whitespace + for (; idx < l; ++idx) { + if (!uc[idx].isSpace()) + return false; + } + + result->append('\0'); + + // Check separators + if (group_sep_mode == ParseGroupSeparators + && !removeGroupSeparators(result)) + return false; + + + return true; +} + +bool QLocalePrivate::validateChars(const QString &str, NumberMode numMode, QByteArray *buff, + int decDigits) const +{ + buff->clear(); + buff->reserve(str.length()); + + const bool scientific = numMode == DoubleScientificMode; + bool lastWasE = false; + bool lastWasDigit = false; + int eCnt = 0; + int decPointCnt = 0; + bool dec = false; + int decDigitCnt = 0; + + for (int i = 0; i < str.length(); ++i) { + char c = digitToCLocale(str.at(i)); + + if (c >= '0' && c <= '9') { + if (numMode != IntegerMode) { + // If a double has too many digits after decpt, it shall be Invalid. + if (dec && decDigits != -1 && decDigits < ++decDigitCnt) + return false; + } + lastWasDigit = true; + } else { + switch (c) { + case '.': + if (numMode == IntegerMode) { + // If an integer has a decimal point, it shall be Invalid. + return false; + } else { + // If a double has more than one decimal point, it shall be Invalid. + if (++decPointCnt > 1) + return false; +#if 0 + // If a double with no decimal digits has a decimal point, it shall be + // Invalid. + if (decDigits == 0) + return false; +#endif // On second thoughts, it shall be Valid. + + dec = true; + } + break; + + case '+': + case '-': + if (scientific) { + // If a scientific has a sign that's not at the beginning or after + // an 'e', it shall be Invalid. + if (i != 0 && !lastWasE) + return false; + } else { + // If a non-scientific has a sign that's not at the beginning, + // it shall be Invalid. + if (i != 0) + return false; + } + break; + + case ',': + //it can only be placed after a digit which is before the decimal point + if (!lastWasDigit || decPointCnt > 0) + return false; + break; + + case 'e': + if (scientific) { + // If a scientific has more than one 'e', it shall be Invalid. + if (++eCnt > 1) + return false; + dec = false; + } else { + // If a non-scientific has an 'e', it shall be Invalid. + return false; + } + break; + + default: + // If it's not a valid digit, it shall be Invalid. + return false; + } + lastWasDigit = false; + } + + lastWasE = c == 'e'; + if (c != ',') + buff->append(c); + } + + return true; +} + +double QLocalePrivate::stringToDouble(const QString &number, bool *ok, + GroupSeparatorMode group_sep_mode) const +{ + CharBuff buff; + if (!numberToCLocale(group().unicode() == 0xa0 ? number.trimmed() : number, + group_sep_mode, &buff)) { + if (ok != 0) + *ok = false; + return 0.0; + } + return bytearrayToDouble(buff.constData(), ok); +} + +qlonglong QLocalePrivate::stringToLongLong(const QString &number, int base, + bool *ok, GroupSeparatorMode group_sep_mode) const +{ + CharBuff buff; + if (!numberToCLocale(group().unicode() == 0xa0 ? number.trimmed() : number, + group_sep_mode, &buff)) { + if (ok != 0) + *ok = false; + return 0; + } + + return bytearrayToLongLong(buff.constData(), base, ok); +} + +qulonglong QLocalePrivate::stringToUnsLongLong(const QString &number, int base, + bool *ok, GroupSeparatorMode group_sep_mode) const +{ + CharBuff buff; + if (!numberToCLocale(group().unicode() == 0xa0 ? number.trimmed() : number, + group_sep_mode, &buff)) { + if (ok != 0) + *ok = false; + return 0; + } + + return bytearrayToUnsLongLong(buff.constData(), base, ok); +} + + +double QLocalePrivate::bytearrayToDouble(const char *num, bool *ok, bool *overflow) +{ + if (ok != 0) + *ok = true; + if (overflow != 0) + *overflow = false; + + if (*num == '\0') { + if (ok != 0) + *ok = false; + return 0.0; + } + + if (qstrcmp(num, "nan") == 0) + return qt_snan(); + + if (qstrcmp(num, "+inf") == 0 || qstrcmp(num, "inf") == 0) + return qt_inf(); + + if (qstrcmp(num, "-inf") == 0) + return -qt_inf(); + + bool _ok; + const char *endptr; + double d = qstrtod(num, &endptr, &_ok); + + if (!_ok) { + // the only way strtod can fail with *endptr != '\0' on a non-empty + // input string is overflow + if (ok != 0) + *ok = false; + if (overflow != 0) + *overflow = *endptr != '\0'; + return 0.0; + } + + if (*endptr != '\0') { + // we stopped at a non-digit character after converting some digits + if (ok != 0) + *ok = false; + if (overflow != 0) + *overflow = false; + return 0.0; + } + + if (ok != 0) + *ok = true; + if (overflow != 0) + *overflow = false; + return d; +} + +qlonglong QLocalePrivate::bytearrayToLongLong(const char *num, int base, bool *ok, bool *overflow) +{ + bool _ok; + const char *endptr; + + if (*num == '\0') { + if (ok != 0) + *ok = false; + if (overflow != 0) + *overflow = false; + return 0; + } + + qlonglong l = qstrtoll(num, &endptr, base, &_ok); + + if (!_ok) { + if (ok != 0) + *ok = false; + if (overflow != 0) { + // the only way qstrtoll can fail with *endptr != '\0' on a non-empty + // input string is overflow + *overflow = *endptr != '\0'; + } + return 0; + } + + if (*endptr != '\0') { + // we stopped at a non-digit character after converting some digits + if (ok != 0) + *ok = false; + if (overflow != 0) + *overflow = false; + return 0; + } + + if (ok != 0) + *ok = true; + if (overflow != 0) + *overflow = false; + return l; +} + +qulonglong QLocalePrivate::bytearrayToUnsLongLong(const char *num, int base, bool *ok) +{ + bool _ok; + const char *endptr; + qulonglong l = qstrtoull(num, &endptr, base, &_ok); + + if (!_ok || *endptr != '\0') { + if (ok != 0) + *ok = false; + return 0; + } + + if (ok != 0) + *ok = true; + return l; +} + +/*! + \since 4.8 + + \enum QLocale::CurrencySymbolFormat + + Specifies the format of the currency symbol. + + \value CurrencyIsoCode a ISO-4217 code of the currency. + \value CurrencySymbol a currency symbol. + \value CurrencyDisplayName a user readable name of the currency. +*/ + +/*! + \since 4.8 + Returns a currency symbol according to the \a format. +*/ +QString QLocale::currencySymbol(QLocale::CurrencySymbolFormat format) const +{ +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QVariant res = systemLocale()->query(QSystemLocale::CurrencySymbol, format); + if (!res.isNull()) + return res.toString(); + } +#endif + quint32 idx, size; + switch (format) { + case CurrencySymbol: + idx = d()->m_currency_symbol_idx; + size = d()->m_currency_symbol_size; + return getLocaleData(currency_symbol_data + idx, size); + case CurrencyDisplayName: + idx = d()->m_currency_display_name_idx; + size = d()->m_currency_display_name_size; + return getLocaleListData(currency_display_name_data + idx, size, 0); + case CurrencyIsoCode: { + int len = 0; + const QLocalePrivate *d = this->d(); + for (; len < 3; ++len) + if (!d->m_currency_iso_code[len]) + break; + return len ? QString::fromLatin1(d->m_currency_iso_code, len) : QString(); + } + } + return QString(); +} + +/*! + \since 4.8 + + Returns a localized string representation of \a value as a currency. + If the \a symbol is provided it is used instead of the default currency symbol. + + \sa currencySymbol() +*/ +QString QLocale::toCurrencyString(qlonglong value, const QString &symbol) const +{ +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QSystemLocale::CurrencyToStringArgument arg(value, symbol); + QVariant res = systemLocale()->query(QSystemLocale::CurrencyToString, QVariant::fromValue(arg)); + if (!res.isNull()) + return res.toString(); + } +#endif + const QLocalePrivate *d = this->d(); + quint8 idx = d->m_currency_format_idx; + quint8 size = d->m_currency_format_size; + if (d->m_currency_negative_format_size && value < 0) { + idx = d->m_currency_negative_format_idx; + size = d->m_currency_negative_format_size; + value = -value; + } + QString str = d->longLongToString(value); + QString sym = symbol.isNull() ? currencySymbol() : symbol; + if (sym.isEmpty()) + sym = currencySymbol(QLocale::CurrencyIsoCode); + QString format = getLocaleData(currency_format_data + idx, size); + return format.arg(str, sym); +} + +/*! + \since 4.8 + \overload +*/ +QString QLocale::toCurrencyString(qulonglong value, const QString &symbol) const +{ +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QSystemLocale::CurrencyToStringArgument arg(value, symbol); + QVariant res = systemLocale()->query(QSystemLocale::CurrencyToString, QVariant::fromValue(arg)); + if (!res.isNull()) + return res.toString(); + } +#endif + const QLocalePrivate *d = this->d(); + quint8 idx = d->m_currency_format_idx; + quint8 size = d->m_currency_format_size; + QString str = d->unsLongLongToString(value); + QString sym = symbol.isNull() ? currencySymbol() : symbol; + if (sym.isEmpty()) + sym = currencySymbol(QLocale::CurrencyIsoCode); + QString format = getLocaleData(currency_format_data + idx, size); + return format.arg(str, sym); +} + +/*! + \since 4.8 + \overload +*/ +QString QLocale::toCurrencyString(double value, const QString &symbol) const +{ +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QSystemLocale::CurrencyToStringArgument arg(value, symbol); + QVariant res = systemLocale()->query(QSystemLocale::CurrencyToString, QVariant::fromValue(arg)); + if (!res.isNull()) + return res.toString(); + } +#endif + const QLocalePrivate *d = this->d(); + quint8 idx = d->m_currency_format_idx; + quint8 size = d->m_currency_format_size; + if (d->m_currency_negative_format_size && value < 0) { + idx = d->m_currency_negative_format_idx; + size = d->m_currency_negative_format_size; + value = -value; + } + QString str = d->doubleToString(value, d->m_currency_digits, + QLocalePrivate::DFDecimal); + QString sym = symbol.isNull() ? currencySymbol() : symbol; + if (sym.isEmpty()) + sym = currencySymbol(QLocale::CurrencyIsoCode); + QString format = getLocaleData(currency_format_data + idx, size); + return format.arg(str, sym); +} + +/*! + \since 4.8 + + Returns an ordered list of locale names for translation purposes in + preference order. + + The return value represents locale names that the user expects to see the + UI translation in. + + Most like you do not need to use this function directly, but just pass the + QLocale object to the QTranslator::load() function. + + The first item in the list is the most preferred one. + + \sa QTranslator, bcp47Name() +*/ +QStringList QLocale::uiLanguages() const +{ +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QVariant res = systemLocale()->query(QSystemLocale::UILanguages, QVariant()); + if (!res.isNull()) { + QStringList result = res.toStringList(); + if (!result.isEmpty()) + return result; + } + } +#endif + return QStringList(bcp47Name()); +} + +/*! + \since 4.8 + + Returns a native name of the language for the locale. For example + "Schwiizertüütsch" for Swiss-German locale. + + \sa nativeCountryName(), languageToString() +*/ +QString QLocale::nativeLanguageName() const +{ +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QVariant res = systemLocale()->query(QSystemLocale::NativeLanguageName, QVariant()); + if (!res.isNull()) + return res.toString(); + } +#endif + return getLocaleData(endonyms_data + d()->m_language_endonym_idx, d()->m_language_endonym_size); +} + +/*! + \since 4.8 + + Returns a native name of the country for the locale. For example + "España" for Spanish/Spain locale. + + \sa nativeLanguageName(), countryToString() +*/ +QString QLocale::nativeCountryName() const +{ +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QVariant res = systemLocale()->query(QSystemLocale::NativeCountryName, QVariant()); + if (!res.isNull()) + return res.toString(); + } +#endif + return getLocaleData(endonyms_data + d()->m_country_endonym_idx, d()->m_country_endonym_size); +} + +QT_END_NAMESPACE |