From b58c6bfe14d86a2094c240c24c37a6bb3fa62726 Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Wed, 23 Feb 2011 17:08:47 +0100 Subject: Split monolithic qlocale.cpp into platform-specific files This is just a refactoring change to split huge unreadable qlocale.cpp into multiple files. Reviewed-by: Zeno Albisser --- qmake/Makefile.unix | 14 +- qmake/Makefile.win32 | 2 + qmake/Makefile.win32-g++ | 8 + qmake/Makefile.win32-g++-sh | 8 + src/corelib/tools/qlocale.cpp | 8958 ++++++++--------------------------- src/corelib/tools/qlocale.h | 2 +- src/corelib/tools/qlocale.qdoc | 773 +++ src/corelib/tools/qlocale_mac.mm | 485 ++ src/corelib/tools/qlocale_p.h | 10 + src/corelib/tools/qlocale_tools.cpp | 2961 ++++++++++++ src/corelib/tools/qlocale_tools_p.h | 122 + src/corelib/tools/qlocale_unix.cpp | 256 + src/corelib/tools/qlocale_win.cpp | 757 +++ src/corelib/tools/tools.pri | 15 +- src/tools/bootstrap/bootstrap.pro | 6 + 15 files changed, 7353 insertions(+), 7024 deletions(-) create mode 100644 src/corelib/tools/qlocale.qdoc create mode 100644 src/corelib/tools/qlocale_mac.mm create mode 100644 src/corelib/tools/qlocale_tools.cpp create mode 100644 src/corelib/tools/qlocale_tools_p.h create mode 100644 src/corelib/tools/qlocale_unix.cpp create mode 100644 src/corelib/tools/qlocale_win.cpp diff --git a/qmake/Makefile.unix b/qmake/Makefile.unix index a24076e..5ac9c8c 100644 --- a/qmake/Makefile.unix +++ b/qmake/Makefile.unix @@ -21,7 +21,8 @@ QOBJS=qtextcodec.o qutfcodec.o qstring.o qtextstream.o qiodevice.o qmalloc.o qgl qfsfileengine_iterator.o qregexp.o qvector.o qbitarray.o qdir.o qdiriterator.o quuid.o qhash.o \ qfileinfo.o qdatetime.o qstringlist.o qabstractfileengine.o qtemporaryfile.o \ qmap.o qmetatype.o qsettings.o qsystemerror.o qlibraryinfo.o qvariant.o qvsnprintf.o \ - qlocale.o qlinkedlist.o qurl.o qnumeric.o qcryptographichash.o qxmlstream.o qxmlutils.o \ + qlocale.o qlocale_tools.o qlocale_unix.o qlinkedlist.o qurl.o qnumeric.o qcryptographichash.o \ + qxmlstream.o qxmlutils.o \ $(QTOBJS) @@ -57,7 +58,10 @@ DEPEND_SRC=project.cpp property.cpp meta.cpp main.cpp generators/makefile.cpp ge $(SOURCE_PATH)/src/corelib/io/qfileinfo.cpp $(SOURCE_PATH)/src/corelib/tools/qdatetime.cpp \ $(SOURCE_PATH)/src/corelib/tools/qstringlist.cpp $(SOURCE_PATH)/src/corelib/tools/qmap.cpp \ $(SOURCE_PATH)/src/corelib/global/qconfig.cpp $(SOURCE_PATH)/src/corelib/io/qurl.cpp \ - $(SOURCE_PATH)/src/corelib/tools/qlocale.cpp $(SOURCE_PATH)/src/corelib/tools/qlinkedlist.cpp \ + $(SOURCE_PATH)/src/corelib/tools/qlocale.cpp \ + $(SOURCE_PATH)/src/corelib/tools/qlocale_tools.cpp \ + $(SOURCE_PATH)/src/corelib/tools/qlocale_unix.cpp \ + $(SOURCE_PATH)/src/corelib/tools/qlinkedlist.cpp \ $(SOURCE_PATH)/src/corelib/tools/qhash.cpp $(SOURCE_PATH)/src/corelib/kernel/qcore_mac.cpp \ $(SOURCE_PATH)/src/corelib/io/qtemporaryfile.cpp $(SOURCE_PATH)/src/corelib/kernel/qmetatype.cpp \ $(SOURCE_PATH)/src/corelib/io/qsettings.cpp $(SOURCE_PATH)/src/corelib/kernel/qvariant.cpp \ @@ -156,6 +160,12 @@ qstring.o: $(SOURCE_PATH)/src/corelib/tools/qstring.cpp qlocale.o: $(SOURCE_PATH)/src/corelib/tools/qlocale.cpp $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qlocale.cpp +qlocale_tools.o: $(SOURCE_PATH)/src/corelib/tools/qlocale_tools.cpp + $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qlocale_tools.cpp + +qlocale_unix.o: $(SOURCE_PATH)/src/corelib/tools/qlocale_unix.cpp + $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qlocale_unix.cpp + qdatastream.o: $(SOURCE_PATH)/src/corelib/io/qdatastream.cpp $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qdatastream.cpp diff --git a/qmake/Makefile.win32 b/qmake/Makefile.win32 index 4d29537..0791eb4 100644 --- a/qmake/Makefile.win32 +++ b/qmake/Makefile.win32 @@ -97,6 +97,8 @@ QTOBJS= \ qlist.obj \ qlinkedlist.obj \ qlocale.obj \ + qlocale_tools.obj \ + qlocale_win.obj \ qmalloc.obj \ qmap.obj \ qregexp.obj \ diff --git a/qmake/Makefile.win32-g++ b/qmake/Makefile.win32-g++ index 59ac8c2..ee194f6 100644 --- a/qmake/Makefile.win32-g++ +++ b/qmake/Makefile.win32-g++ @@ -75,6 +75,8 @@ QTOBJS= \ qlist.o \ qlinkedlist.o \ qlocale.o \ + qlocale_tools.o \ + qlocale_win.o \ qmalloc.o \ qmap.o \ qregexp.o \ @@ -176,6 +178,12 @@ qstring.o: $(SOURCE_PATH)/src/corelib/tools/qstring.cpp qlocale.o: $(SOURCE_PATH)/src/corelib/tools/qlocale.cpp $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qlocale.cpp +qlocale_tools.o: $(SOURCE_PATH)/src/corelib/tools/qlocale_tools.cpp + $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qlocale_tools.cpp + +qlocale_win.o: $(SOURCE_PATH)/src/corelib/tools/qlocale_win.cpp + $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qlocale_win.cpp + quuid.o: $(SOURCE_PATH)/src/corelib/plugin/quuid.cpp $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/plugin/quuid.cpp diff --git a/qmake/Makefile.win32-g++-sh b/qmake/Makefile.win32-g++-sh index a84b3f6..52ad7a2 100644 --- a/qmake/Makefile.win32-g++-sh +++ b/qmake/Makefile.win32-g++-sh @@ -75,6 +75,8 @@ QTOBJS= \ qlist.o \ qlinkedlist.o \ qlocale.o \ + qlocale_tools.o \ + qlocale_win.o \ qmalloc.o \ qmap.o \ qregexp.o \ @@ -175,6 +177,12 @@ qstring.o: $(SOURCE_PATH)/src/corelib/tools/qstring.cpp qlocale.o: $(SOURCE_PATH)/src/corelib/tools/qlocale.cpp $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qlocale.cpp +qlocale_tools.o: $(SOURCE_PATH)/src/corelib/tools/qlocale_tools.cpp + $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qlocale_tools.cpp + +qlocale_win.o: $(SOURCE_PATH)/src/corelib/tools/qlocale_win.cpp + $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qlocale_win.cpp + quuid.o: $(SOURCE_PATH)/src/corelib/plugin/quuid.cpp $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/plugin/quuid.cpp diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index 61f7b7c..c8291d7 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -43,8 +43,8 @@ #ifndef QT_NO_SYSTEMLOCALE QT_BEGIN_NAMESPACE -class QSystemLocaleData; -static QSystemLocaleData *QSystemLocale_globalSystemLocale(); +class QSystemLocale; +static QSystemLocale *QSystemLocale_globalSystemLocale(); QT_END_NAMESPACE #endif @@ -54,6 +54,7 @@ QT_END_NAMESPACE #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" @@ -71,66 +72,8 @@ QT_END_NAMESPACE #include "private/qnumeric_p.h" #include "private/qsystemlibrary_p.h" -#include -#include -#include -#include -#include -#include -#include - -#if defined(__GLIBC__) && !defined(__UCLIBC__) -# include -#endif - -#if !defined(QT_QLOCALE_NEEDS_VOLATILE) -# if defined(Q_CC_GNU) -# if __GNUC__ == 4 -# define QT_QLOCALE_NEEDS_VOLATILE -# elif defined(Q_OS_WIN) -# define QT_QLOCALE_NEEDS_VOLATILE -# endif -# endif -#endif - -#if defined(QT_QLOCALE_NEEDS_VOLATILE) -# define NEEDS_VOLATILE volatile -#else -# define NEEDS_VOLATILE -#endif - -// Sizes as defined by the ISO C99 standard - fallback -#ifndef LLONG_MAX -# define LLONG_MAX Q_INT64_C(0x7fffffffffffffff) -#endif -#ifndef LLONG_MIN -# define LLONG_MIN (-LLONG_MAX - Q_INT64_C(1)) -#endif -#ifndef ULLONG_MAX -# define ULLONG_MAX Q_UINT64_C(0xffffffffffffffff) -#endif - -#define CONVERSION_BUFF_SIZE 255 - QT_BEGIN_NAMESPACE -#ifndef QT_QLOCALE_USES_FCVT -static char *_qdtoa( NEEDS_VOLATILE double d, int mode, int ndigits, int *decpt, - int *sign, char **rve, char **digits_str); -#endif -Q_CORE_EXPORT char *qdtoa(double d, int mode, int ndigits, int *decpt, - int *sign, char **rve, char **digits_str); -Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok); -static qlonglong qstrtoll(const char *nptr, const char **endptr, register int base, bool *ok); -static qulonglong qstrtoull(const char *nptr, const char **endptr, register int base, bool *ok); - -#if defined(Q_CC_MWERKS) && defined(Q_OS_WIN32) -inline bool isascii(int c) -{ - return (c >= 0 && c <=127); -} -#endif - #if defined(Q_OS_SYMBIAN) void qt_symbianUpdateSystemPrivate(); void qt_symbianInitSystemLocale(); @@ -138,47 +81,7 @@ void qt_symbianInitSystemLocale(); #ifndef QT_NO_SYSTEMLOCALE static QSystemLocale *_systemLocale = 0; - -struct QSystemLocaleData -{ - QSystemLocaleData() - : locale(true) - #if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) - ,lc_numeric(QLocale::C) - ,lc_time(QLocale::C) - ,lc_monetary(QLocale::C) - ,lc_messages(QLocale::C) - #endif - { -#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) - QByteArray all = qgetenv("LC_ALL"); - QByteArray numeric = all.isEmpty() ? qgetenv("LC_NUMERIC") : all; - QByteArray time = all.isEmpty() ? qgetenv("LC_TIME") : all; - QByteArray monetary = all.isEmpty() ? qgetenv("LC_MONETARY") : all; - QByteArray messages = all.isEmpty() ? qgetenv("LC_MESSAGES") : all; - QByteArray lang = qgetenv("LANG"); - if (numeric.isEmpty()) - numeric = lang; - if (monetary.isEmpty()) - monetary = lang; - if (messages.isEmpty()) - messages = lang; - lc_numeric = QLocale(QString::fromAscii(numeric)); - lc_time = QLocale(QString::fromAscii(time)); - lc_monetary = QLocale(QString::fromAscii(monetary)); - lc_messages = QLocale(QString::fromAscii(messages)); -#endif - } - QSystemLocale locale; -#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) - QLocale lc_numeric; - QLocale lc_time; - QLocale lc_monetary; - QLocale lc_messages; -#endif -}; - -Q_GLOBAL_STATIC(QSystemLocaleData, QSystemLocale_globalSystemLocale) +Q_GLOBAL_STATIC_WITH_ARGS(QSystemLocale, QSystemLocale_globalSystemLocale, (true)) static QLocalePrivate *system_lp = 0; Q_GLOBAL_STATIC(QLocalePrivate, globalLocalePrivate) #endif @@ -205,7 +108,7 @@ QLocale::MeasurementSystem QLocalePrivate::measurementSystem() const // Assumes that code is a // QChar code[3]; // If the code is two-digit the third digit must be 0 -static QLocale::Language codeToLanguage(const QChar *code) +QLocale::Language codeToLanguage(const QChar *code) { ushort uc1 = code[0].unicode(); ushort uc2 = code[1].unicode(); @@ -225,7 +128,7 @@ static QLocale::Language codeToLanguage(const QChar *code) // Assumes that code is a // QChar code[3]; -static QLocale::Country codeToCountry(const QChar *code) +QLocale::Country codeToCountry(const QChar *code) { ushort uc1 = code[0].unicode(); ushort uc2 = code[1].unicode(); @@ -240,7 +143,7 @@ static QLocale::Country codeToCountry(const QChar *code) return QLocale::AnyCountry; } -static QString languageToCode(QLocale::Language language) +QString languageToCode(QLocale::Language language) { if (language == QLocale::C) return QLatin1String("C"); @@ -257,7 +160,7 @@ static QString languageToCode(QLocale::Language language) return code; } -static QString countryToCode(QLocale::Country country) +QString countryToCode(QLocale::Country country) { if (country == QLocale::AnyCountry) return QString(); @@ -274,7 +177,7 @@ static QString countryToCode(QLocale::Country country) return code; } -static const QLocalePrivate *findLocale(QLocale::Language language, QLocale::Country country) +const QLocalePrivate *findLocale(QLocale::Language language, QLocale::Country country) { unsigned language_id = language; unsigned country_id = country; @@ -302,9 +205,9 @@ static const QLocalePrivate *findLocale(QLocale::Language language, QLocale::Cou return locale_data + idx; } -static bool splitLocaleName(const QString &name, - QChar *lang_begin, QChar *cntry_begin, - int *lang_len = 0, int *cntry_len = 0) +bool splitLocaleName(const QString &name, + QChar *lang_begin, QChar *cntry_begin, + int *lang_len, int *cntry_len) { for (int i = 0; i < 3; ++i) lang_begin[i] = 0; @@ -383,7 +286,7 @@ void getLangAndCountry(const QString &name, QLocale::Language &lang, QLocale::Co cntry = codeToCountry(cntry_code); } -static const QLocalePrivate *findLocale(const QString &name) +const QLocalePrivate *findLocale(const QString &name) { QLocale::Language lang; QLocale::Country cntry; @@ -391,7 +294,7 @@ static const QLocalePrivate *findLocale(const QString &name) return findLocale(lang, cntry); } -static QString readEscapedFormatString(const QString &format, int *idx) +QString readEscapedFormatString(const QString &format, int *idx) { int &i = *idx; @@ -425,7 +328,7 @@ static QString readEscapedFormatString(const QString &format, int *idx) return result; } -static int repeatCount(const QString &s, int i) +int repeatCount(const QString &s, int i) { QChar c = s.at(i); int j = i + 1; @@ -438,7589 +341,2614 @@ static const QLocalePrivate *default_lp = 0; static uint default_number_options = 0; #ifndef QT_NO_SYSTEMLOCALE -static QByteArray envVarLocale() -{ - static QByteArray lang = 0; -#ifdef Q_OS_UNIX - lang = qgetenv("LC_ALL"); - if (lang.isNull()) - lang = qgetenv("LC_NUMERIC"); - if (lang.isNull()) -#endif - lang = qgetenv("LANG"); - return lang; -} -#if defined(Q_OS_WIN) /****************************************************************************** -** Wrappers for Windows locale system functions +** Default system locale behavior */ -#ifndef MUI_LANGUAGE_NAME -#define MUI_LANGUAGE_NAME 0x8 -#endif - -static const char *winLangCodeToIsoName(int code); -static QString winIso639LangName(LCID id = LOCALE_USER_DEFAULT); -static QString winIso3116CtryName(LCID id = LOCALE_USER_DEFAULT); - -static QString getWinLocaleInfo(LCTYPE type) +/*! + Constructs a QSystemLocale object. The constructor will automatically + install this object as the system locale and remove any earlier installed + system locales. +*/ +QSystemLocale::QSystemLocale() { - LCID id = GetUserDefaultLCID(); - int cnt = GetLocaleInfo(id, type, 0, 0) * 2; - - if (cnt == 0) { - qWarning("QLocale: empty windows locale info (%d)", (int)type); - return QString(); - } - - QByteArray buff(cnt, 0); - - cnt = GetLocaleInfo(id, type, reinterpret_cast(buff.data()), buff.size() / 2); - - if (cnt == 0) { - qWarning("QLocale: empty windows locale info (%d)", (int)type); - return QString(); - } + delete _systemLocale; + _systemLocale = this; - return QString::fromWCharArray(reinterpret_cast(buff.data())); + if (system_lp) + system_lp->m_language_id = 0; } -QByteArray getWinLocaleName(LCID id = LOCALE_USER_DEFAULT) +/*! \internal */ +QSystemLocale::QSystemLocale(bool) +{ } + +/*! + Deletes the object. +*/ +QSystemLocale::~QSystemLocale() { - QByteArray result; - if (id == LOCALE_USER_DEFAULT) { - result = envVarLocale(); - QChar lang[3]; - QChar cntry[3]; - if ( result == "C" || (!result.isEmpty() - && splitLocaleName(QString::fromLocal8Bit(result), lang, cntry)) ) { - long id = 0; - bool ok = false; - id = qstrtoll(result.data(), 0, 0, &ok); - if ( !ok || id == 0 || id < INT_MIN || id > INT_MAX ) - return result; - else - return winLangCodeToIsoName( (int)id ); - } - } + if (_systemLocale == this) { + _systemLocale = 0; -#if defined(Q_OS_WINCE) - result = winLangCodeToIsoName(id != LOCALE_USER_DEFAULT ? id : GetUserDefaultLCID()); -#else - if (id == LOCALE_USER_DEFAULT) - id = GetUserDefaultLCID(); - QString resultuage = winIso639LangName(id); - QString country = winIso3116CtryName(id); - result = resultuage.toLatin1(); - if (!country.isEmpty()) { - result += '_'; - result += country.toLatin1(); + if (system_lp) + system_lp->m_language_id = 0; } -#endif - - return result; } -Q_CORE_EXPORT QLocale qt_localeFromLCID(LCID id) +static const QSystemLocale *systemLocale() { - return QLocale(QString::fromLatin1(getWinLocaleName(id))); + if (_systemLocale) + return _systemLocale; +#if defined(Q_OS_SYMBIAN) + qt_symbianInitSystemLocale(); +#endif + return QSystemLocale_globalSystemLocale(); } -static QString winToQtFormat(const QString &sys_fmt) +void QLocalePrivate::updateSystemPrivate() { - QString result; - int i = 0; + const QSystemLocale *sys_locale = systemLocale(); + if (!system_lp) + system_lp = globalLocalePrivate(); + *system_lp = *sys_locale->fallbackLocale().d(); - while (i < sys_fmt.size()) { - if (sys_fmt.at(i).unicode() == QLatin1Char('\'')) { - QString text = readEscapedFormatString(sys_fmt, &i); - if (text == QLatin1String("'")) - result += QLatin1String("''"); - else - result += QString(QLatin1Char('\'') + text + QLatin1Char('\'')); - continue; - } +#if defined(Q_OS_SYMBIAN) + qt_symbianUpdateSystemPrivate(); +#endif - QChar c = sys_fmt.at(i); - int repeat = repeatCount(sys_fmt, i); + QVariant res = sys_locale->query(QSystemLocale::LanguageId, QVariant()); + if (!res.isNull()) + system_lp->m_language_id = res.toInt(); + res = sys_locale->query(QSystemLocale::CountryId, QVariant()); + if (!res.isNull()) + system_lp->m_country_id = res.toInt(); - switch (c.unicode()) { - // Date - case 'y': - if (repeat > 5) - repeat = 5; - else if (repeat == 3) - repeat = 2; - switch (repeat) { - case 1: - result += QLatin1String("yy"); // "y" unsupported by Qt, use "yy" - break; - case 5: - result += QLatin1String("yyyy"); // "yyyyy" same as "yyyy" on Windows - break; - default: - result += QString(repeat, QLatin1Char('y')); - break; - } - break; - case 'g': - if (repeat > 2) - repeat = 2; - switch (repeat) { - case 2: - break; // no equivalent of "gg" in Qt - default: - result += QLatin1Char('g'); - break; - } - break; - case 't': - if (repeat > 2) - repeat = 2; - result += QLatin1String("AP"); // "t" unsupported, use "AP" - break; - default: - result += QString(repeat, c); - break; - } + res = sys_locale->query(QSystemLocale::DecimalPoint, QVariant()); + if (!res.isNull()) + system_lp->m_decimal = res.toString().at(0).unicode(); - i += repeat; - } + res = sys_locale->query(QSystemLocale::GroupSeparator, QVariant()); + if (!res.isNull()) + system_lp->m_group = res.toString().at(0).unicode(); - return result; -} + 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(); +} +#endif -static QString winDateToString(const QDate &date, DWORD flags) +static const QLocalePrivate *systemPrivate() { - SYSTEMTIME st; - memset(&st, 0, sizeof(SYSTEMTIME)); - st.wYear = date.year(); - st.wMonth = date.month(); - st.wDay = date.day(); - - LCID id = GetUserDefaultLCID(); +#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(); - wchar_t buf[255]; - if (GetDateFormat(id, flags, &st, 0, buf, 255)) - return QString::fromWCharArray(buf); + return system_lp; +#else + return locale_data; +#endif +} - return QString(); +static const QLocalePrivate *defaultPrivate() +{ + if (!default_lp) + default_lp = systemPrivate(); + return default_lp; } -static QString winTimeToString(const QTime &time) +static QString getLocaleListData(const ushort *data, int size, int index) { - SYSTEMTIME st; - memset(&st, 0, sizeof(SYSTEMTIME)); - st.wHour = time.hour(); - st.wMinute = time.minute(); - st.wSecond = time.second(); - st.wMilliseconds = 0; + 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(data), end-data); +} - DWORD flags = 0; - LCID id = GetUserDefaultLCID(); +static inline QString getLocaleData(const ushort *data, int size) +{ + return size ? QString::fromRawData(reinterpret_cast(data), size) : QString(); +} - wchar_t buf[255]; - if (GetTimeFormat(id, flags, &st, 0, buf, 255)) - return QString::fromWCharArray(buf); - return QString(); +#ifndef QT_NO_DATASTREAM +QDataStream &operator<<(QDataStream &ds, const QLocale &l) +{ + ds << l.name(); + return ds; } -static QString winDayName(int day, bool short_format) +QDataStream &operator>>(QDataStream &ds, QLocale &l) { - static const LCTYPE short_day_map[] - = { LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, - LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, - LOCALE_SABBREVDAYNAME6, LOCALE_SABBREVDAYNAME7 }; - - static const LCTYPE long_day_map[] - = { LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, - LOCALE_SDAYNAME3, LOCALE_SDAYNAME4, LOCALE_SDAYNAME5, - LOCALE_SDAYNAME6, LOCALE_SDAYNAME7 }; + QString s; + ds >> s; + l = QLocale(s); + return ds; +} +#endif // QT_NO_DATASTREAM - day -= 1; - LCTYPE type = short_format - ? short_day_map[day] : long_day_map[day]; - return getWinLocaleInfo(type); -} +static const int locale_data_size = sizeof(locale_data)/sizeof(QLocalePrivate) - 1; -static QString winMonthName(int month, bool short_format) +static const QLocalePrivate *dataPointerHelper(quint16 index) { - static const LCTYPE short_month_map[] - = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3, - LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6, - LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9, - LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 }; - - static const LCTYPE long_month_map[] - = { LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, - LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, - LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8, LOCALE_SMONTHNAME9, - LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12 }; - - month -= 1; - if (month < 0 || month > 11) - return QString(); +#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 - LCTYPE type = short_format ? short_month_map[month] : long_month_map[month]; - return getWinLocaleInfo(type); + return &locale_data[index]; } -static QLocale::MeasurementSystem winSystemMeasurementSystem() +static quint16 localePrivateIndex(const QLocalePrivate *p) { - LCID id = GetUserDefaultLCID(); - wchar_t output[2]; - - if (GetLocaleInfo(id, LOCALE_IMEASURE, output, 2)) { - QString iMeasure = QString::fromWCharArray(output); - if (iMeasure == QLatin1String("1")) { - return QLocale::ImperialSystem; - } - } +#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 QLocale::MetricSystem; + return index; } -static QString winSystemAMText() -{ - LCID id = GetUserDefaultLCID(); - wchar_t output[15]; // maximum length including terminating zero character for Win2003+ +/*! + Constructs a QLocale object with the specified \a name, + which has the format + "language[_-country][.codeset][@modifier]" or "C", where: - if (GetLocaleInfo(id, LOCALE_S1159, output, 15)) { - return QString::fromWCharArray(output); - } + \list + \i language is a lowercase, two-letter, ISO 639 language code, + \i territory is an uppercase, two-letter, ISO 3166 country code, + \i and codeset and modifier are ignored. + \endlist - return QString(); -} + The separator can be either underscore or a minus sign. -static QString winSystemPMText() -{ - LCID id = GetUserDefaultLCID(); - wchar_t output[15]; // maximum length including terminating zero character for Win2003+ + 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. - if (GetLocaleInfo(id, LOCALE_S2359, output, 15)) { - return QString::fromWCharArray(output); - } + The language and country codes are converted to their respective + \c Language and \c Country enums. After this conversion is + performed the constructor behaves exactly like QLocale(Country, + Language). - return QString(); -} + This constructor is much slower than QLocale(Country, Language). -static quint8 winSystemFirstDayOfWeek() + \sa name() +*/ + +QLocale::QLocale(const QString &name) + : v(0) { - LCID id = GetUserDefaultLCID(); - wchar_t output[4]; // maximum length including terminating zero character for Win2003+ + p.numberOptions = 0; + p.index = localePrivateIndex(findLocale(name)); +} - if (GetLocaleInfo(id, LOCALE_IFIRSTDAYOFWEEK, output, 4)) - return QString::fromWCharArray(output).toUInt()+1; +/*! + 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(). - return 1; -} + \sa setDefault() +*/ -QString winCurrencySymbol(QLocale::CurrencySymbolFormat format) +QLocale::QLocale() + : v(0) { - LCID lcid = GetUserDefaultLCID(); - wchar_t buf[13]; - switch (format) { - case QLocale::CurrencySymbol: - if (GetLocaleInfo(lcid, LOCALE_SCURRENCY, buf, 13)) - return QString::fromWCharArray(buf); - break; - case QLocale::CurrencyIsoCode: - if (GetLocaleInfo(lcid, LOCALE_SINTLSYMBOL, buf, 9)) - return QString::fromWCharArray(buf); - break; - case QLocale::CurrencyDisplayName: { - QVarLengthArray buf(64); - if (!GetLocaleInfo(lcid, LOCALE_SNATIVECURRNAME, buf.data(), buf.size())) { - if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) - break; - buf.resize(255); // should be large enough, right? - if (!GetLocaleInfo(lcid, LOCALE_SNATIVECURRNAME, buf.data(), buf.size())) - break; - } - return QString::fromWCharArray(buf.data()); - } - default: - break; - } - return QString(); + p.numberOptions = default_number_options; + p.index = localePrivateIndex(defaultPrivate()); } -static QString winFormatCurrency(const QVariant &in) -{ - QString value; - switch (in.type()) { - case QVariant::Int: - value = QLocalePrivate::longLongToString(QLatin1Char('0'), QLatin1Char(','), QLatin1Char('+'), QLatin1Char('-'), - in.toInt(), -1, 10, -1, QLocale::OmitGroupSeparator); - break; - case QVariant::UInt: - value = QLocalePrivate::unsLongLongToString(QLatin1Char('0'), QLatin1Char(','), QLatin1Char('+'), - in.toUInt(), -1, 10, -1, QLocale::OmitGroupSeparator); - break; - case QVariant::Double: - value = QLocalePrivate::doubleToString(QLatin1Char('0'), QLatin1Char('+'), QLatin1Char('-'), - QLatin1Char(' '), QLatin1Char(','), QLatin1Char('.'), - in.toDouble(), -1, QLocalePrivate::DFDecimal, -1, QLocale::OmitGroupSeparator); - break; - case QVariant::LongLong: - value = QLocalePrivate::longLongToString(QLatin1Char('0'), QLatin1Char(','), QLatin1Char('+'), QLatin1Char('-'), - in.toLongLong(), -1, 10, -1, QLocale::OmitGroupSeparator); - break; - case QVariant::ULongLong: - value = QLocalePrivate::unsLongLongToString(QLatin1Char('0'), QLatin1Char(','), QLatin1Char('+'), - in.toULongLong(), -1, 10, -1, QLocale::OmitGroupSeparator); - break; - default: - return QString(); - } +/*! + Constructs a QLocale object with the specified \a language and \a + country. - QVarLengthArray out(64); - LCID lcid = GetUserDefaultLCID(); - int ret = ::GetCurrencyFormat(lcid, 0, reinterpret_cast(value.utf16()), - NULL, out.data(), out.size()); - if (ret == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - ret = ::GetCurrencyFormat(lcid, 0, reinterpret_cast(value.utf16()), - NULL, out.data(), 0); - out.resize(ret); - ::GetCurrencyFormat(lcid, 0, reinterpret_cast(value.utf16()), - NULL, out.data(), out.size()); - } + \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 - return QString::fromWCharArray(out.data()); -} + The language and country that are actually used can be queried + using language() and country(). + + \sa setDefault() language() country() +*/ -QStringList winUILanguages() +QLocale::QLocale(Language language, Country country) + : v(0) { - if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA) { - typedef BOOL (*GetUserPreferredUILanguagesFunc) ( - DWORD dwFlags, - PULONG pulNumLanguages, - PWSTR pwszLanguagesBuffer, - PULONG pcchLanguagesBuffer); - static GetUserPreferredUILanguagesFunc GetUserPreferredUILanguages_ptr = 0; - if (!GetUserPreferredUILanguages_ptr) { - QSystemLibrary lib(QLatin1String("kernel32")); - if (lib.load()) - GetUserPreferredUILanguages_ptr = (GetUserPreferredUILanguagesFunc)lib.resolve("GetUserPreferredUILanguages"); - } - if (GetUserPreferredUILanguages_ptr) { - unsigned long cnt = 0; - QVarLengthArray buf(64); - unsigned long size = buf.size(); - if (!GetUserPreferredUILanguages_ptr(MUI_LANGUAGE_NAME, &cnt, buf.data(), &size)) { - size = 0; - if (GetLastError() == ERROR_INSUFFICIENT_BUFFER && - GetUserPreferredUILanguages_ptr(MUI_LANGUAGE_NAME, &cnt, NULL, &size)) { - buf.resize(size); - if (!GetUserPreferredUILanguages_ptr(MUI_LANGUAGE_NAME, &cnt, buf.data(), &size)) - return QStringList(); - } - } - QStringList result; - result.reserve(cnt); - const wchar_t *str = buf.constData(); - for (; cnt > 0; --cnt) { - QString s = QString::fromWCharArray(str); - if (s.isEmpty()) - break; // something is wrong - result.append(s); - str += s.size()+1; - } - return result; - } - } + const QLocalePrivate *d = findLocale(language, country); - // old Windows before Vista - return QStringList(QString::fromLatin1(winLangCodeToIsoName(GetUserDefaultUILanguage()))); + // 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.6 - Returns the fallback locale obtained from the system. - */ -QLocale QSystemLocale::fallbackLocale() const + Constructs a QLocale object as a copy of \a other. +*/ + +QLocale::QLocale(const QLocale &other) { - return QLocale(QString::fromLatin1(getWinLocaleName())); + v = other.v; } -QVariant QSystemLocale::query(QueryType type, QVariant in = QVariant()) const +const QLocalePrivate *QLocale::d() const { - LCTYPE locale_info = 0; - bool format_string = false; - - switch(type) { -// case Name: -// return getWinLocaleName(); - case DecimalPoint: - locale_info = LOCALE_SDECIMAL; - break; - case GroupSeparator: - locale_info = LOCALE_STHOUSAND; - break; - case NegativeSign: - locale_info = LOCALE_SNEGATIVESIGN; - break; - case PositiveSign: - locale_info = LOCALE_SPOSITIVESIGN; - break; - case DateFormatLong: - locale_info = LOCALE_SLONGDATE; - format_string = true; - break; - case DateFormatShort: - locale_info = LOCALE_SSHORTDATE; - format_string = true; - break; - case TimeFormatLong: - case TimeFormatShort: - locale_info = LOCALE_STIMEFORMAT; - format_string = true; - break; + return dataPointerHelper(p.index); +} - case DateTimeFormatLong: - case DateTimeFormatShort: - return QString(query(type == DateTimeFormatLong ? DateFormatLong : DateFormatShort).toString() - + QLatin1Char(' ') + query(type == DateTimeFormatLong ? TimeFormatLong : TimeFormatShort).toString()); - case DayNameLong: - case DayNameShort: - return winDayName(in.toInt(), (type == DayNameShort)); - case MonthNameLong: - case MonthNameShort: - return winMonthName(in.toInt(), (type == MonthNameShort)); - case DateToStringShort: - case DateToStringLong: - return winDateToString(in.toDate(), type == DateToStringShort ? DATE_SHORTDATE : DATE_LONGDATE); - case TimeToStringShort: - case TimeToStringLong: - return winTimeToString(in.toTime()); - case DateTimeToStringShort: - case DateTimeToStringLong: { - const QDateTime dt = in.toDateTime(); - return QString(winDateToString(dt.date(), type == DateTimeToStringShort ? DATE_SHORTDATE : DATE_LONGDATE) - + QLatin1Char(' ') + winTimeToString(dt.time())); } - - case ZeroDigit: - locale_info = LOCALE_SNATIVEDIGITS; - break; +/*! + Assigns \a other to this QLocale object and returns a reference + to this QLocale object. +*/ - case LanguageId: - case CountryId: { - QString locale = QString::fromLatin1(getWinLocaleName()); - QLocale::Language lang; - QLocale::Country cntry; - getLangAndCountry(locale, lang, cntry); - if (type == LanguageId) - return lang; - if (cntry == QLocale::AnyCountry) - return fallbackLocale().country(); - return cntry; - } +QLocale &QLocale::operator=(const QLocale &other) +{ + v = other.v; + return *this; +} - case MeasurementSystem: - return QVariant(static_cast(winSystemMeasurementSystem())); +/*! + \since 4.2 - case AMText: - return QVariant(winSystemAMText()); - case PMText: - return QVariant(winSystemPMText()); - case FirstDayOfWeek: - return QVariant(winSystemFirstDayOfWeek()); - case CurrencySymbol: - return QVariant(winCurrencySymbol(QLocale::CurrencySymbolFormat(in.toUInt()))); - case FormatCurrency: - return QVariant(winFormatCurrency(in)); - case UILanguages: - return QVariant(winUILanguages()); - default: - break; - } - if (locale_info) { - QString result = getWinLocaleInfo(locale_info); - if (format_string) - result = winToQtFormat(result); - if (!result.isEmpty()) - return result; - } - return QVariant(); + Sets the \a options related to number conversions for this + QLocale instance. +*/ +void QLocale::setNumberOptions(NumberOptions options) +{ + p.numberOptions = options; } -struct WindowsToISOListElt { - ushort windows_code; - char iso_name[6]; -}; - -/* NOTE: This array should be sorted by the first column! */ -static const WindowsToISOListElt windows_to_iso_list[] = { - { 0x0401, "ar_SA" }, - { 0x0402, "bg\0 " }, - { 0x0403, "ca\0 " }, - { 0x0404, "zh_TW" }, - { 0x0405, "cs\0 " }, - { 0x0406, "da\0 " }, - { 0x0407, "de\0 " }, - { 0x0408, "el\0 " }, - { 0x0409, "en_US" }, - { 0x040a, "es\0 " }, - { 0x040b, "fi\0 " }, - { 0x040c, "fr\0 " }, - { 0x040d, "he\0 " }, - { 0x040e, "hu\0 " }, - { 0x040f, "is\0 " }, - { 0x0410, "it\0 " }, - { 0x0411, "ja\0 " }, - { 0x0412, "ko\0 " }, - { 0x0413, "nl\0 " }, - { 0x0414, "no\0 " }, - { 0x0415, "pl\0 " }, - { 0x0416, "pt_BR" }, - { 0x0418, "ro\0 " }, - { 0x0419, "ru\0 " }, - { 0x041a, "hr\0 " }, - { 0x041c, "sq\0 " }, - { 0x041d, "sv\0 " }, - { 0x041e, "th\0 " }, - { 0x041f, "tr\0 " }, - { 0x0420, "ur\0 " }, - { 0x0421, "in\0 " }, - { 0x0422, "uk\0 " }, - { 0x0423, "be\0 " }, - { 0x0425, "et\0 " }, - { 0x0426, "lv\0 " }, - { 0x0427, "lt\0 " }, - { 0x0429, "fa\0 " }, - { 0x042a, "vi\0 " }, - { 0x042d, "eu\0 " }, - { 0x042f, "mk\0 " }, - { 0x0436, "af\0 " }, - { 0x0438, "fo\0 " }, - { 0x0439, "hi\0 " }, - { 0x043e, "ms\0 " }, - { 0x0458, "mt\0 " }, - { 0x0801, "ar_IQ" }, - { 0x0804, "zh_CN" }, - { 0x0807, "de_CH" }, - { 0x0809, "en_GB" }, - { 0x080a, "es_MX" }, - { 0x080c, "fr_BE" }, - { 0x0810, "it_CH" }, - { 0x0812, "ko\0 " }, - { 0x0813, "nl_BE" }, - { 0x0814, "no\0 " }, - { 0x0816, "pt\0 " }, - { 0x081a, "sr\0 " }, - { 0x081d, "sv_FI" }, - { 0x0c01, "ar_EG" }, - { 0x0c04, "zh_HK" }, - { 0x0c07, "de_AT" }, - { 0x0c09, "en_AU" }, - { 0x0c0a, "es\0 " }, - { 0x0c0c, "fr_CA" }, - { 0x0c1a, "sr\0 " }, - { 0x1001, "ar_LY" }, - { 0x1004, "zh_SG" }, - { 0x1007, "de_LU" }, - { 0x1009, "en_CA" }, - { 0x100a, "es_GT" }, - { 0x100c, "fr_CH" }, - { 0x1401, "ar_DZ" }, - { 0x1407, "de_LI" }, - { 0x1409, "en_NZ" }, - { 0x140a, "es_CR" }, - { 0x140c, "fr_LU" }, - { 0x1801, "ar_MA" }, - { 0x1809, "en_IE" }, - { 0x180a, "es_PA" }, - { 0x1c01, "ar_TN" }, - { 0x1c09, "en_ZA" }, - { 0x1c0a, "es_DO" }, - { 0x2001, "ar_OM" }, - { 0x2009, "en_JM" }, - { 0x200a, "es_VE" }, - { 0x2401, "ar_YE" }, - { 0x2409, "en\0 " }, - { 0x240a, "es_CO" }, - { 0x2801, "ar_SY" }, - { 0x2809, "en_BZ" }, - { 0x280a, "es_PE" }, - { 0x2c01, "ar_JO" }, - { 0x2c09, "en_TT" }, - { 0x2c0a, "es_AR" }, - { 0x3001, "ar_LB" }, - { 0x300a, "es_EC" }, - { 0x3401, "ar_KW" }, - { 0x340a, "es_CL" }, - { 0x3801, "ar_AE" }, - { 0x380a, "es_UY" }, - { 0x3c01, "ar_BH" }, - { 0x3c0a, "es_PY" }, - { 0x4001, "ar_QA" }, - { 0x400a, "es_BO" }, - { 0x440a, "es_SV" }, - { 0x480a, "es_HN" }, - { 0x4c0a, "es_NI" }, - { 0x500a, "es_PR" } -}; - -static const int windows_to_iso_count - = sizeof(windows_to_iso_list)/sizeof(WindowsToISOListElt); - -static const char *winLangCodeToIsoName(int code) -{ - int cmp = code - windows_to_iso_list[0].windows_code; - if (cmp < 0) - return 0; +/*! + \since 4.2 - if (cmp == 0) - return windows_to_iso_list[0].iso_name; + Returns the options related to number conversions for this + QLocale instance. - int begin = 0; - int end = windows_to_iso_count; + By default, no options are set for the standard locales. +*/ +QLocale::NumberOptions QLocale::numberOptions() const +{ + return static_cast(p.numberOptions); +} - while (end - begin > 1) { - uint mid = (begin + end)/2; +/*! + \since 4.8 - const WindowsToISOListElt *elt = windows_to_iso_list + mid; - int cmp = code - elt->windows_code; - if (cmp < 0) - end = mid; - else if (cmp > 0) - begin = mid; - else - return elt->iso_name; - } + Returns \a str quoted according to the current locale. - return 0; + If \a AlternateQuotation is used for \a QuoatationStyle + but the locale does not provide an alternate quotation, + we will fallback to the parent locale. +*/ +QString QLocale::quoteString(const QString &str, QuotationStyle qs) const +{ + return quoteString(&str, qs); } -static QString winIso639LangName(LCID id) -{ - QString result; +/*! + \since 4.8 - // Windows returns the wrong ISO639 for some languages, we need to detect them here using - // the language code - QString lang_code; - wchar_t out[256]; - if (GetLocaleInfo(id, LOCALE_ILANGUAGE, out, 255)) - lang_code = QString::fromWCharArray(out); - - if (!lang_code.isEmpty()) { - const char *endptr; - bool ok; - QByteArray latin1_lang_code = lang_code.toLatin1(); - int i = qstrtoull(latin1_lang_code, &endptr, 16, &ok); - if (ok && *endptr == '\0') { - switch (i) { - case 0x814: - result = QLatin1String("nn"); // Nynorsk - break; - default: - break; - } - } + \overload +*/ +QString QLocale::quoteString(const QStringRef &str, QuotationStyle qs) const +{ +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QVariant quotationBegin = systemLocale()->query(QSystemLocale::QuotationBegin, QVariant(qs)); + QVariant quotationEnd = systemLocale()->query(QSystemLocale::QuotationEnd, QVariant(qs)); + if (!quotationBegin.isNull() && !quotationEnd.isNull()) + return quotationBegin.toString() % str % quotationEnd.toString(); } +#endif - if (!result.isEmpty()) - return result; - - // not one of the problematic languages - do the usual lookup - if (GetLocaleInfo(id, LOCALE_SISO639LANGNAME , out, 255)) - result = QString::fromWCharArray(out); - - return result; + if (qs == 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); } -static QString winIso3116CtryName(LCID id) -{ - QString result; - - wchar_t out[256]; - if (GetLocaleInfo(id, LOCALE_SISO3166CTRYNAME, out, 255)) - result = QString::fromWCharArray(out); +/*! + \nonreentrant - return result; -} + 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. -#elif defined(Q_OS_MAC) -/****************************************************************************** -** Wrappers for Mac locale system functions + \sa system() c() */ -static QByteArray getMacLocaleName() +void QLocale::setDefault(const QLocale &locale) { - QByteArray result = envVarLocale(); - - QChar lang[3]; - QChar cntry[3]; - if (result.isEmpty() || result != "C" - && !splitLocaleName(QString::fromLocal8Bit(result), lang, cntry)) { - QCFType l = CFLocaleCopyCurrent(); - CFStringRef locale = CFLocaleGetIdentifier(l); - result = QCFString::toQString(locale).toUtf8(); - } - return result; + default_lp = locale.d(); + default_number_options = locale.numberOptions(); } -static QString macMonthName(int month, bool short_format) -{ - month -= 1; - if (month < 0 || month > 11) - return QString(); +/*! + Returns the language of this locale. - QCFType formatter - = CFDateFormatterCreate(0, QCFType(CFLocaleCopyCurrent()), - kCFDateFormatterNoStyle, kCFDateFormatterNoStyle); - QCFType values - = static_cast(CFDateFormatterCopyProperty(formatter, - short_format ? kCFDateFormatterShortMonthSymbols - : kCFDateFormatterMonthSymbols)); - if (values != 0) { - CFStringRef cfstring = static_cast(CFArrayGetValueAtIndex(values, month)); - return QCFString::toQString(cfstring); - } - return QString(); + \sa country(), languageToString(), name() +*/ +QLocale::Language QLocale::language() const +{ + return Language(d()->languageId()); } +/*! + Returns the country of this locale. -static QString macDayName(int day, bool short_format) + \sa language(), countryToString(), name() +*/ +QLocale::Country QLocale::country() const { - if (day < 1 || day > 7) - return QString(); - - QCFType formatter - = CFDateFormatterCreate(0, QCFType(CFLocaleCopyCurrent()), - kCFDateFormatterNoStyle, kCFDateFormatterNoStyle); - QCFType values = static_cast(CFDateFormatterCopyProperty(formatter, - short_format ? kCFDateFormatterShortWeekdaySymbols - : kCFDateFormatterWeekdaySymbols)); - if (values != 0) { - CFStringRef cfstring = static_cast(CFArrayGetValueAtIndex(values, day % 7)); - return QCFString::toQString(cfstring); - } - return QString(); + return Country(d()->countryId()); } -static QString macDateToString(const QDate &date, bool short_format) -{ - CFGregorianDate macGDate; - macGDate.year = date.year(); - macGDate.month = date.month(); - macGDate.day = date.day(); - macGDate.hour = 0; - macGDate.minute = 0; - macGDate.second = 0.0; - QCFType myDate - = CFDateCreate(0, CFGregorianDateGetAbsoluteTime(macGDate, - QCFType(CFTimeZoneCopyDefault()))); - QCFType mylocale = CFLocaleCopyCurrent(); - CFDateFormatterStyle style = short_format ? kCFDateFormatterShortStyle : kCFDateFormatterLongStyle; - QCFType myFormatter - = CFDateFormatterCreate(kCFAllocatorDefault, - mylocale, style, - kCFDateFormatterNoStyle); - return QCFString(CFDateFormatterCreateStringWithDate(0, myFormatter, myDate)); -} +/*! + 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-letter ISO 3166 country code. -static QString macTimeToString(const QTime &time, bool short_format) -{ - CFGregorianDate macGDate; - // Assume this is local time and the current date - QDate dt = QDate::currentDate(); - macGDate.year = dt.year(); - macGDate.month = dt.month(); - macGDate.day = dt.day(); - macGDate.hour = time.hour(); - macGDate.minute = time.minute(); - macGDate.second = time.second(); - QCFType myDate - = CFDateCreate(0, CFGregorianDateGetAbsoluteTime(macGDate, - QCFType(CFTimeZoneCopyDefault()))); - - QCFType mylocale = CFLocaleCopyCurrent(); - CFDateFormatterStyle style = short_format ? kCFDateFormatterShortStyle : kCFDateFormatterLongStyle; - QCFType myFormatter = CFDateFormatterCreate(kCFAllocatorDefault, - mylocale, - kCFDateFormatterNoStyle, - style); - return QCFString(CFDateFormatterCreateStringWithDate(0, myFormatter, myDate)); -} + \sa language(), country() +*/ -static QString macToQtFormat(const QString &sys_fmt) +QString QLocale::name() const { - QString result; - int i = 0; + Language l = language(); - while (i < sys_fmt.size()) { - if (sys_fmt.at(i).unicode() == '\'') { - QString text = readEscapedFormatString(sys_fmt, &i); - if (text == QLatin1String("'")) - result += QLatin1String("''"); - else - result += QLatin1Char('\'') + text + QLatin1Char('\''); - continue; - } + QString result = languageToCode(l); - QChar c = sys_fmt.at(i); - int repeat = repeatCount(sys_fmt, i); - - switch (c.unicode()) { - case 'G': // Qt doesn't support these :( - case 'Y': - case 'D': - case 'F': - case 'w': - case 'W': - case 'g': - break; + if (l == C) + return result; - case 'u': // extended year - use 'y' - if (repeat < 4) - result += QLatin1String("yy"); - else - result += QLatin1String("yyyy"); - break; - case 'S': // fractional second - if (repeat < 3) - result += QLatin1Char('z'); - else - result += QLatin1String("zzz"); - break; - case 'E': - if (repeat <= 3) - result += QLatin1String("ddd"); - else - result += QLatin1String("dddd"); - break; - case 'e': - if (repeat >= 2) - result += QLatin1String("dd"); - else - result += QLatin1Char('d'); - break; - case 'a': - result += QLatin1String("AP"); - break; - case 'k': - result += QString(repeat, QLatin1Char('H')); - break; - case 'K': - result += QString(repeat, QLatin1Char('h')); - break; - case 'z': - case 'Z': - case 'v': - result += QLatin1Char('t'); - break; - default: - result += QString(repeat, c); - break; - } + Country c = country(); + if (c == AnyCountry) + return result; - i += repeat; - } + result.append(QLatin1Char('_')); + result.append(countryToCode(c)); return result; } -QString getMacDateFormat(CFDateFormatterStyle style) -{ - QCFType l = CFLocaleCopyCurrent(); - QCFType formatter = CFDateFormatterCreate(kCFAllocatorDefault, - l, style, kCFDateFormatterNoStyle); - return macToQtFormat(QCFString::toQString(CFDateFormatterGetFormat(formatter))); -} +/*! + Returns a QString containing the name of \a language. -static QString getMacTimeFormat(CFDateFormatterStyle style) -{ - QCFType l = CFLocaleCopyCurrent(); - QCFType formatter = CFDateFormatterCreate(kCFAllocatorDefault, - l, kCFDateFormatterNoStyle, style); - return macToQtFormat(QCFString::toQString(CFDateFormatterGetFormat(formatter))); -} + \sa countryToString(), name() +*/ -static QString getCFLocaleValue(CFStringRef key) +QString QLocale::languageToString(Language language) { - QCFType locale = CFLocaleCopyCurrent(); - CFTypeRef value = CFLocaleGetValue(locale, key); - return QCFString::toQString(CFStringRef(static_cast(value))); + if (uint(language) > uint(QLocale::LastLanguage)) + return QLatin1String("Unknown"); + return QLatin1String(language_name_list + language_name_index[language]); } -static QLocale::MeasurementSystem macMeasurementSystem() -{ - QCFType locale = CFLocaleCopyCurrent(); - CFStringRef system = static_cast(CFLocaleGetValue(locale, kCFLocaleMeasurementSystem)); - if (QCFString::toQString(system) == QLatin1String("Metric")) { - return QLocale::MetricSystem; - } else { - return QLocale::ImperialSystem; - } -} +/*! + Returns a QString containing the name of \a country. -static quint8 macFirstDayOfWeek() -{ - QCFType calendar = CFCalendarCopyCurrent(); - quint8 day = static_cast(CFCalendarGetFirstWeekday(calendar))-1; - if (day == 0) - day = 7; - return day; -} + \sa country(), name() +*/ -static QString macCurrencySymbol(QLocale::CurrencySymbolFormat format) +QString QLocale::countryToString(Country country) { - QCFType locale = CFLocaleCopyCurrent(); - switch (format) { - case QLocale::CurrencyIsoCode: - return QCFString::toQString(static_cast(CFLocaleGetValue(locale, kCFLocaleCurrencyCode))); - case QLocale::CurrencySymbol: - return QCFString::toQString(static_cast(CFLocaleGetValue(locale, kCFLocaleCurrencySymbol))); - case QLocale::CurrencyDisplayName: { - CFStringRef code = static_cast(CFLocaleGetValue(locale, kCFLocaleCurrencyCode)); - QCFType value = CFLocaleCopyDisplayNameForPropertyValue(locale, kCFLocaleCurrencyCode, code); - return QCFString::toQString(value); - } - default: - break; - } - return QString(); + if (uint(country) > uint(QLocale::LastCountry)) + return QLatin1String("Unknown"); + return QLatin1String(country_name_list + country_name_index[country]); } -static QString macFormatCurrency(const QVariant &in) -{ - QCFType value; - switch (in.type()) { - case QVariant::Int: - case QVariant::UInt: { - int v = in.toInt(); - value = CFNumberCreate(NULL, kCFNumberIntType, &v); - break; - } - case QVariant::Double: { - double v = in.toInt(); - value = CFNumberCreate(NULL, kCFNumberDoubleType, &v); - break; - } - case QVariant::LongLong: - case QVariant::ULongLong: { - qint64 v = in.toLongLong(); - value = CFNumberCreate(NULL, kCFNumberLongLongType, &v); - break; - } - default: - return QString(); - } +/*! + 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. - QCFType locale = CFLocaleCopyCurrent(); - QCFType currencyFormatter = - CFNumberFormatterCreate(NULL, locale, kCFNumberFormatterCurrencyStyle); - QCFType result = CFNumberFormatterCreateStringWithNumber(NULL, currencyFormatter, value); - return QCFString::toQString(result); -} + If the conversion fails the function returns 0. -static QVariant macQuotationSymbol(QSystemLocale::QueryType type, const QVariant &in) -{ -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 - if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_6) - return QVariant(); + If \a ok is not 0, failure is reported by setting *ok to false, and + success by setting *ok to true. - QCFType locale = CFLocaleCopyCurrent(); - switch (type) { - case QSystemLocale::QuotationBegin: - if (in.toInt() == QLocale::StandardQuotation) - return QCFString::toQString(static_cast(CFLocaleGetValue(locale, kCFLocaleQuotationBeginDelimiterKey))); - else - return QCFString::toQString(static_cast(CFLocaleGetValue(locale, kCFLocaleAlternateQuotationBeginDelimiterKey))); - break; - case QSystemLocale::QuotationEnd: - if (in.toInt() == QLocale::StandardQuotation) - return QCFString::toQString(static_cast(CFLocaleGetValue(locale, kCFLocaleQuotationEndDelimiterKey))); - else - return QCFString::toQString(static_cast(CFLocaleGetValue(locale, kCFLocaleAlternateQuotationEndDelimiterKey))); - break; - default: - break; - } -#endif - return QVariant(); -} + This function ignores leading and trailing whitespace. + + \sa toUShort(), toString() +*/ -static void getMacPreferredLanguageAndCountry(QString *language, QString *country) +short QLocale::toShort(const QString &s, bool *ok, int base) const { - QCFType languages = (CFArrayRef)CFPreferencesCopyValue( - CFSTR("AppleLanguages"), - kCFPreferencesAnyApplication, - kCFPreferencesCurrentUser, - kCFPreferencesAnyHost); - if (languages && CFArrayGetCount(languages) > 0) { - QCFType locale = CFLocaleCreate(kCFAllocatorDefault, - CFStringRef(CFArrayGetValueAtIndex(languages, 0))); - if (language) - *language = QCFString::toQString(CFStringRef(CFLocaleGetValue(locale, kCFLocaleLanguageCode))); - if (country) - *country = QCFString::toQString(CFStringRef(CFLocaleGetValue(locale, kCFLocaleCountryCode))); + qlonglong i = toLongLong(s, ok, base); + if (i < SHRT_MIN || i > SHRT_MAX) { + if (ok != 0) + *ok = false; + return 0; } + return short(i); } -QLocale QSystemLocale::fallbackLocale() const -{ - return QLocale(QString::fromUtf8(getMacLocaleName().constData())); -} +/*! + 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. -QVariant QSystemLocale::query(QueryType type, QVariant in = QVariant()) const -{ - switch(type) { -// case Name: -// return getMacLocaleName(); - case DecimalPoint: { - QString value = getCFLocaleValue(kCFLocaleDecimalSeparator); - return value.isEmpty() ? QVariant() : value; - } - case GroupSeparator: { - QString value = getCFLocaleValue(kCFLocaleGroupingSeparator); - return value.isEmpty() ? QVariant() : value; - } - case DateFormatLong: - case DateFormatShort: - return getMacDateFormat(type == DateFormatShort - ? kCFDateFormatterShortStyle - : kCFDateFormatterLongStyle); - case TimeFormatLong: - case TimeFormatShort: - return getMacTimeFormat(type == TimeFormatShort - ? kCFDateFormatterShortStyle - : kCFDateFormatterLongStyle); - case DayNameLong: - case DayNameShort: - return macDayName(in.toInt(), (type == DayNameShort)); - case MonthNameLong: - case MonthNameShort: - return macMonthName(in.toInt(), (type == MonthNameShort)); - case DateToStringShort: - case DateToStringLong: - return macDateToString(in.toDate(), (type == DateToStringShort)); - case TimeToStringShort: - case TimeToStringLong: - return macTimeToString(in.toTime(), (type == TimeToStringShort)); - - case NegativeSign: - case PositiveSign: - case ZeroDigit: - break; - case LanguageId: - case CountryId: { - QString preferredLanguage; - QString preferredCountry(3, QChar()); // codeToCountry assumes QChar[3] - getMacPreferredLanguageAndCountry(&preferredLanguage, &preferredCountry); - QLocale::Language languageCode = (preferredLanguage.isEmpty() ? QLocale::C : codeToLanguage(preferredLanguage.data())); - QLocale::Country countryCode = (preferredCountry.isEmpty() ? QLocale::AnyCountry : codeToCountry(preferredCountry.data())); - const QLocalePrivate *d = findLocale(languageCode, countryCode); - if (type == LanguageId) - return (QLocale::Language)d->languageId(); - return (QLocale::Country)d->countryId(); - } + If the conversion fails the function returns 0. - case MeasurementSystem: - return QVariant(static_cast(macMeasurementSystem())); + If \a ok is not 0, failure is reported by setting *ok to false, and + success by setting *ok to true. - case AMText: - case PMText: - break; - case FirstDayOfWeek: - return QVariant(macFirstDayOfWeek()); - case CurrencySymbol: - return QVariant(macCurrencySymbol(QLocale::CurrencySymbolFormat(in.toUInt()))); - case FormatCurrency: - return macFormatCurrency(in); - case UILanguages: { - QCFType languages = (CFArrayRef)CFPreferencesCopyValue( - CFSTR("AppleLanguages"), - kCFPreferencesAnyApplication, - kCFPreferencesCurrentUser, - kCFPreferencesAnyHost); - const int cnt = CFArrayGetCount(languages); - QStringList result; - result.reserve(cnt); - for (int i = 0; i < cnt; ++i) { - const QString lang = QCFString::toQString( - static_cast(CFArrayGetValueAtIndex(languages, i))); - result.append(lang); - } - return QVariant(result); - } - case QuotationBegin: - case QuotationEnd: - return macQuotationSymbol(type,in); - default: - break; - } - return QVariant(); -} + This function ignores leading and trailing whitespace. -#elif defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) + \sa toShort(), toString() +*/ -static uint unixGetSystemMeasurementSystem() +ushort QLocale::toUShort(const QString &s, bool *ok, int base) const { - QString meas_locale = QString::fromLocal8Bit(qgetenv("LC_ALL")); - if (meas_locale.isEmpty()) { - meas_locale = QString::fromLocal8Bit(qgetenv("LC_MEASUREMENT")); - } - if (meas_locale.isEmpty()) { - meas_locale = QString::fromLocal8Bit(qgetenv("LANG")); - } - if (meas_locale.isEmpty()) { - meas_locale = QString::fromLocal8Bit("C"); - } - - if (meas_locale.compare(QString::fromLocal8Bit("Metric"), Qt::CaseInsensitive) == 0) - return 0; - if (meas_locale.compare(QString::fromLocal8Bit("Other"), Qt::CaseInsensitive) == 0) + qulonglong i = toULongLong(s, ok, base); + if (i > USHRT_MAX) { + if (ok != 0) + *ok = false; return 0; - - const QLocalePrivate* locale = findLocale(meas_locale); - return locale->measurementSystem(); + } + return ushort(i); } /*! - \internal + 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() */ -QLocale QSystemLocale::fallbackLocale() const + +int QLocale::toInt(const QString &s, bool *ok, int base) const { - return QLocale(QLatin1String(envVarLocale())); + qlonglong i = toLongLong(s, ok, base); + if (i < INT_MIN || i > INT_MAX) { + if (ok != 0) + *ok = false; + return 0; + } + return int(i); } /*! - \internal -*/ -QVariant QSystemLocale::query(QueryType type, QVariant in) const -{ - QSystemLocaleData *d = QSystemLocale_globalSystemLocale(); - const QLocale &lc_numeric = d->lc_numeric; - const QLocale &lc_time = d->lc_time; - const QLocale &lc_monetary = d->lc_monetary; + 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. - switch (type) { - case DecimalPoint: - return lc_numeric.decimalPoint(); - case GroupSeparator: - return lc_numeric.groupSeparator(); - case ZeroDigit: - return lc_numeric.zeroDigit(); - case NegativeSign: - return lc_numeric.negativeSign(); - case DateFormatLong: - return lc_time.dateFormat(QLocale::LongFormat); - case DateFormatShort: - return lc_time.dateFormat(QLocale::ShortFormat); - case TimeFormatLong: - return lc_time.timeFormat(QLocale::LongFormat); - case TimeFormatShort: - return lc_time.timeFormat(QLocale::ShortFormat); - case DayNameLong: - return lc_time.dayName(in.toInt(), QLocale::LongFormat); - case DayNameShort: - return lc_time.dayName(in.toInt(), QLocale::ShortFormat); - case MonthNameLong: - return lc_time.monthName(in.toInt(), QLocale::LongFormat); - case MonthNameShort: - return lc_time.monthName(in.toInt(), QLocale::ShortFormat); - case DateToStringLong: - return lc_time.toString(in.toDate(), QLocale::LongFormat); - case DateToStringShort: - return lc_time.toString(in.toDate(), QLocale::ShortFormat); - case TimeToStringLong: - return lc_time.toString(in.toTime(), QLocale::LongFormat); - case TimeToStringShort: - return lc_time.toString(in.toTime(), QLocale::ShortFormat); - case DateTimeFormatLong: - return lc_time.dateTimeFormat(QLocale::LongFormat); - case DateTimeFormatShort: - return lc_time.dateTimeFormat(QLocale::ShortFormat); - case DateTimeToStringLong: - return lc_time.toString(in.toDateTime(), QLocale::LongFormat); - case DateTimeToStringShort: - return lc_time.toString(in.toDateTime(), QLocale::ShortFormat); - case PositiveSign: - return lc_numeric.positiveSign(); - case AMText: - return lc_time.amText(); - case PMText: - return lc_time.pmText(); - case FirstDayOfWeek: - return lc_time.firstDayOfWeek(); - case CurrencySymbol: - return lc_monetary.currencySymbol(QLocale::CurrencySymbolFormat(in.toUInt())); - case FormatCurrency: { - switch (in.type()) { - case QVariant::Int: - return lc_monetary.toCurrencyString(in.toInt()); - case QVariant::UInt: - return lc_monetary.toCurrencyString(in.toUInt()); - case QVariant::Double: - return lc_monetary.toCurrencyString(in.toDouble()); - case QVariant::LongLong: - return lc_monetary.toCurrencyString(in.toLongLong()); - case QVariant::ULongLong: - return lc_monetary.toCurrencyString(in.toULongLong()); - default: - break; - } - return QString(); - } - case MeasurementSystem: - return QVariant(unixGetSystemMeasurementSystem()); - case UILanguages: { - QString languages = QString::fromLocal8Bit(qgetenv("LANGUAGE")); - if (!languages.isEmpty()) { - QStringList lst = languages.split(QLatin1Char(':')); - for (int i = 0; i < lst.size();) { - const QString &name = lst.at(i); - QChar lang[3]; - QChar cntry[3]; - if (name.isEmpty() || !splitLocaleName(name, lang, cntry)) - lst.removeAt(i); - else - ++i; - } - return lst; - } - QString name = QString::fromLocal8Bit(qgetenv("LC_ALL")); - if (name.isEmpty()) { - name = QString::fromLocal8Bit(qgetenv("LC_MESSAGES")); - if (name.isEmpty()) - name = QString::fromLocal8Bit(qgetenv("LANG")); - } - if (!name.isEmpty()) { - QChar lang[3]; - QChar cntry[3]; - int lang_len, cntry_len; - if (splitLocaleName(name, lang, cntry, &lang_len, &cntry_len)) - return QStringList(QString::fromRawData(lang, lang_len) % QLatin1Char('-') % QString::fromRawData(cntry, cntry_len)); - } - return QVariant(); - } - case QuotationBegin: - case QuotationEnd: - break; // TODO - default: - break; - } - return QVariant(); -} + If the conversion fails the function returns 0. -#elif !defined(Q_OS_SYMBIAN) + If \a ok is not 0, failure is reported by setting *ok to false, and + success by setting *ok to true. -/*! - \since 4.6 + This function ignores leading and trailing whitespace. - Returns a fallback locale, that will get used for everything that - is not explicitly overridden by the system locale. + \sa toInt(), toString() */ -QLocale QSystemLocale::fallbackLocale() const + +uint QLocale::toUInt(const QString &s, bool *ok, int base) const { - return QLocale(QLatin1String(envVarLocale())); + qulonglong i = toULongLong(s, ok, base); + if (i > UINT_MAX) { + if (ok != 0) + *ok = false; + return 0; + } + return uint(i); } /*! - Performs a query of the given \a type in the system locale for - customized values or conversion. If the method returns a null - QVariant, the conversion of the fallbackLocale() will be used. + 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. - \a in is unused for some of the query types. + 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 QSystemLocale::QueryType + \sa toInt(), toULongLong(), toDouble(), toString() */ -QVariant QSystemLocale::query(QueryType /* type */, QVariant /* in */) const + + +qlonglong QLocale::toLongLong(const QString &s, bool *ok, int base) const { - return QVariant(); -} + QLocalePrivate::GroupSeparatorMode mode + = p.numberOptions & RejectGroupSeparator + ? QLocalePrivate::FailOnGroupSeparators + : QLocalePrivate::ParseGroupSeparators; -#endif + return d()->stringToLongLong(s, base, ok, mode); +} -/****************************************************************************** -** Default system locale behavior -*/ +// ### Qt5: make the return type for toULongLong() qulonglong. /*! - \class QSystemLocale - \brief The QSystemLocale class can be used to finetune the system locale - of the user. - \since 4.2 - - \ingroup i18n + 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. - \warning This class is only useful in very rare cases. Usually QLocale offers - all the functionality required for application development. + If the conversion fails the function returns 0. - QSystemLocale allows to override the values provided by the system - locale (QLocale::system()). + If \a ok is not 0, failure is reported by setting *ok to false, and + success by setting *ok to true. - \sa QLocale -*/ + This function ignores leading and trailing whitespace. -/*! - \enum QSystemLocale::QueryType - - Specifies the type of information queried by query(). For each value - the type of information to return from the query() method is listed. - - \value LanguageId a uint specifying the language. - \value CountryId a uint specifying the country. - \value DecimalPoint a QString specifying the decimal point. - \value GroupSeparator a QString specifying the group separator. - \value ZeroDigit a QString specifying the zero digit. - \value NegativeSign a QString specifying the minus sign. - \value PositiveSign a QString specifying the plus sign. - \value DateFormatLong a QString specifying the long date format - \value DateFormatShort a QString specifying the short date format - \value TimeFormatLong a QString specifying the long time format - \value TimeFormatShort a QString specifying the short time format - \value DayNameLong a QString specifying the name of a weekday. the in variant contains an integer between 1 and 7 (Monday - Sunday) - \value DayNameShort a QString specifying the short name of a weekday. the in variant contains an integer between 1 and 7 (Monday - Sunday) - \value MonthNameLong a QString specifying the name of a month. the in variant contains an integer between 1 and 12 - \value MonthNameShort a QString specifying the short name of a month. the in variant contains an integer between 1 and 12 - \value DateToStringLong converts the QDate stored in the in variant to a QString using the long date format - \value DateToStringShort converts the QDate stored in the in variant to a QString using the short date format - \value TimeToStringLong converts the QTime stored in the in variant to a QString using the long time format - \value TimeToStringShort converts the QTime stored in the in variant to a QString using the short time format - \value DateTimeFormatLong a QString specifying the long date time format - \value DateTimeFormatShort a QString specifying the short date time format - \value DateTimeToStringLong converts the QDateTime in the in variant to a QString using the long datetime format - \value DateTimeToStringShort converts the QDateTime in the in variant to a QString using the short datetime format - \value MeasurementSystem a QLocale::MeasurementSystem enum specifying the measurement system - \value AMText a string that represents the system AM designator associated with a 12-hour clock. - \value PMText a string that represents the system PM designator associated with a 12-hour clock. - \value FirstDayOfWeek a Qt::DayOfWeek enum specifiying the first day of the week - \value CurrencySymbol a string that represents a currency in a format QLocale::CurrencyFormat. - \value FormatCurrency a localized string representation of a number with a currency symbol. - \value UILanguages a list of strings representing locale names that could be used for UI translation. - \value QuotationBegin a QString specifying the start of a quotation. the in variant contains a QLocale::QuotationStyle - \value QuotationEnd a QString specifying the end of a quotation. the in variant contains a QLocale::QuotationStyle + \sa toLongLong(), toInt(), toDouble(), toString() */ -/*! - Constructs a QSystemLocale object. The constructor will automatically - install this object as the system locale and remove any earlier installed - system locales. -*/ -QSystemLocale::QSystemLocale() +qlonglong QLocale::toULongLong(const QString &s, bool *ok, int base) const { - delete _systemLocale; - _systemLocale = this; + QLocalePrivate::GroupSeparatorMode mode + = p.numberOptions & RejectGroupSeparator + ? QLocalePrivate::FailOnGroupSeparators + : QLocalePrivate::ParseGroupSeparators; - if (system_lp) - system_lp->m_language_id = 0; + return d()->stringToUnsLongLong(s, base, ok, mode); } -/*! \internal */ -QSystemLocale::QSystemLocale(bool) -{ } - /*! - Deletes the object. + 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() */ -QSystemLocale::~QSystemLocale() -{ - if (_systemLocale == this) { - _systemLocale = 0; - if (system_lp) - system_lp->m_language_id = 0; - } -} +#define QT_MAX_FLOAT 3.4028234663852886e+38 -static const QSystemLocale *systemLocale() +float QLocale::toFloat(const QString &s, bool *ok) const { - if (_systemLocale) - return _systemLocale; -#if defined(Q_OS_SYMBIAN) - qt_symbianInitSystemLocale(); -#endif - return &QSystemLocale_globalSystemLocale()->locale; + 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); } -void QLocalePrivate::updateSystemPrivate() -{ - const QSystemLocale *sys_locale = systemLocale(); - if (!system_lp) - system_lp = globalLocalePrivate(); - *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(); - res = sys_locale->query(QSystemLocale::CountryId, QVariant()); - if (!res.isNull()) - system_lp->m_country_id = res.toInt(); - - res = sys_locale->query(QSystemLocale::DecimalPoint, QVariant()); - if (!res.isNull()) - system_lp->m_decimal = res.toString().at(0).unicode(); +/*! + Returns the double represented by the localized string \a s, or + 0.0 if the conversion failed. - res = sys_locale->query(QSystemLocale::GroupSeparator, QVariant()); - if (!res.isNull()) - system_lp->m_group = res.toString().at(0).unicode(); + If \a ok is not 0, reports failure by setting + *ok to false and success by setting *ok to true. - res = sys_locale->query(QSystemLocale::ZeroDigit, QVariant()); - if (!res.isNull()) - system_lp->m_zero = res.toString().at(0).unicode(); + Unlike QString::toDouble(), this function does not fall back to + the "C" locale if the string cannot be interpreted in this + locale. - res = sys_locale->query(QSystemLocale::NegativeSign, QVariant()); - if (!res.isNull()) - system_lp->m_minus = res.toString().at(0).unicode(); + \snippet doc/src/snippets/code/src_corelib_tools_qlocale.cpp 3 - res = sys_locale->query(QSystemLocale::PositiveSign, QVariant()); - if (!res.isNull()) - system_lp->m_plus = res.toString().at(0).unicode(); -} -#endif + Notice that the last conversion returns 1234.0, because '.' is the + thousands group separator in the German locale. -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(); + This function ignores leading and trailing whitespace. - return system_lp; -#else - return locale_data; -#endif -} + \sa toFloat(), toInt(), toString() +*/ -static const QLocalePrivate *defaultPrivate() +double QLocale::toDouble(const QString &s, bool *ok) const { - if (!default_lp) - default_lp = systemPrivate(); - return default_lp; -} + QLocalePrivate::GroupSeparatorMode mode + = p.numberOptions & RejectGroupSeparator + ? QLocalePrivate::FailOnGroupSeparators + : QLocalePrivate::ParseGroupSeparators; -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(data), end-data); + return d()->stringToDouble(s, ok, mode); } -static inline QString getLocaleData(const ushort *data, int size) -{ - return size ? QString::fromRawData(reinterpret_cast(data), size) : QString(); -} +/*! + Returns a localized string representation of \a i. + \sa toLongLong() +*/ -#ifndef QT_NO_DATASTREAM -QDataStream &operator<<(QDataStream &ds, const QLocale &l) +QString QLocale::toString(qlonglong i) const { - ds << l.name(); - return ds; -} + int flags = p.numberOptions & OmitGroupSeparator + ? 0 + : QLocalePrivate::ThousandsGroup; -QDataStream &operator>>(QDataStream &ds, QLocale &l) -{ - QString s; - ds >> s; - l = QLocale(s); - return ds; + return d()->longLongToString(i, -1, 10, -1, flags); } -#endif // QT_NO_DATASTREAM - /*! - \class QLocale - \brief The QLocale class converts between numbers and their - string representations in various languages. - - \reentrant - \ingroup i18n - \ingroup string-processing - \ingroup shared - - - QLocale is initialized with a language/country pair in its - constructor and offers number-to-string and string-to-number - conversion functions similar to those in QString. - - Example: - - \snippet doc/src/snippets/code/src_corelib_tools_qlocale.cpp 0 - - QLocale supports the concept of a default locale, which is - determined from the system's locale settings at application - startup. The default locale can be changed by calling the - static member setDefault(). Setting the default locale has the - following effects: - - \list - \i If a QLocale object is constructed with the default constructor, - it will use the default locale's settings. - \i QString::toInt(), QString::toDouble(), etc., interpret the - string according to the default locale. If this fails, it - falls back on the "C" locale. - \i QString::arg() uses the default locale to format a number when - its position specifier in the format string contains an 'L', - e.g. "%L1". - \endlist - - The following example illustrates how to use QLocale directly: - - \snippet doc/src/snippets/code/src_corelib_tools_qlocale.cpp 1 - - When a language/country pair is specified in the constructor, one - of three things can happen: - - \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 - - Use language() and country() to determine the actual language and - country values used. - - An alternative method for constructing a QLocale object is by - specifying the locale name. - - \snippet doc/src/snippets/code/src_corelib_tools_qlocale.cpp 2 - - This constructor converts the locale name to a language/country - pair; it does not use the system locale database. - - QLocale's data is based on Common Locale Data Repository v1.8.1. - - The double-to-string and string-to-double conversion functions are - covered by the following licenses: - - \legalese - Copyright (c) 1991 by AT&T. - - Permission to use, copy, modify, and distribute this software for any - purpose without fee is hereby granted, provided that this entire notice - is included in all copies of any software which is or includes a copy - or modification of this software and in all copies of the supporting - documentation for such software. + \overload - THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR AT&T MAKES ANY - REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + \sa toULongLong() +*/ - This product includes software developed by the University of - California, Berkeley and its contributors. +QString QLocale::toString(qulonglong i) const +{ + int flags = p.numberOptions & OmitGroupSeparator + ? 0 + : QLocalePrivate::ThousandsGroup; - \sa QString::arg(), QString::toInt(), QString::toDouble() -*/ + return d()->unsLongLongToString(i, -1, 10, -1, flags); +} /*! - \enum QLocale::Language - - This enumerated type is used to specify a language. - - \value C The "C" locale is identical in behavior to English/UnitedStates. - \value Abkhazian - \value Afan - \value Afar - \value Afrikaans - \value Albanian - \value Amharic - \value Arabic - \value Armenian - \value Assamese - \value Aymara - \value Azerbaijani - \value Bashkir - \value Basque - \value Bengali - \value Bhutani - \value Bihari - \value Bislama - \value Bosnian - \value Breton - \value Bulgarian - \value Burmese - \value Byelorussian - \value Cambodian - \value Catalan - \value Chinese - \value Cornish - \value Corsican - \value Croatian - \value Czech - \value Danish - \value Divehi - \value Dutch - \value English - \value Esperanto - \value Estonian - \value Faroese - \value FijiLanguage - \value Finnish - \value French - \value Frisian - \value Gaelic - \value Galician - \value Georgian - \value German - \value Greek - \value Greenlandic - \value Guarani - \value Gujarati - \value Hausa - \value Hebrew - \value Hindi - \value Hungarian - \value Icelandic - \value Indonesian - \value Interlingua - \value Interlingue - \value Inuktitut - \value Inupiak - \value Irish - \value Italian - \value Japanese - \value Javanese - \value Kannada - \value Kashmiri - \value Kazakh - \value Kinyarwanda - \value Kirghiz - \value Korean - \value Kurdish - \value Kurundi - \value Laothian - \value Latin - \value Latvian - \value Lingala - \value Lithuanian - \value Macedonian - \value Malagasy - \value Malay - \value Malayalam - \value Maltese - \value Manx - \value Maori - \value Marathi - \value Moldavian - \value Mongolian - \value NauruLanguage - \value Nepali - \value Norwegian - \value NorwegianBokmal - \value Nynorsk Obsolete, please use NorwegianNynorsk - \value NorwegianNynorsk - \value Occitan - \value Oriya - \value Pashto - \value Persian - \value Polish - \value Portuguese - \value Punjabi - \value Quechua - \value RhaetoRomance - \value Romanian - \value Russian - \value Samoan - \value Sangho - \value Sanskrit - \value Serbian - \value SerboCroatian - \value Sesotho - \value Setswana - \value Shona - \value Sindhi - \value Singhalese - \value Siswati - \value Slovak - \value Slovenian - \value Somali - \value Spanish - \value Sundanese - \value Swahili - \value Swedish - \value Tagalog - \value Tajik - \value Tamil - \value Tatar - \value Telugu - \value Thai - \value Tibetan - \value Tigrinya - \value TongaLanguage - \value Tsonga - \value Turkish - \value Turkmen - \value Twi - \value Uigur - \value Ukrainian - \value Urdu - \value Uzbek - \value Vietnamese - \value Volapuk - \value Welsh - \value Wolof - \value Xhosa - \value Yiddish - \value Yoruba - \value Zhuang - \value Zulu - \value Bosnian - \value Divehi - \value Manx - \value Cornish - \value Akan - \value Konkani - \value Ga - \value Igbo - \value Kamba - \value Syriac - \value Blin - \value Geez - \value Koro - \value Sidamo - \value Atsam - \value Tigre - \value Jju - \value Friulian - \value Venda - \value Ewe - \value Walamo - \value Hawaiian - \value Tyap - \value Chewa - \value Filipino - \value SwissGerman - \value SichuanYi - \value Kpelle - \value LowGerman - \value SouthNdebele - \value NorthernSotho - \value NorthernSami - \value Taroko - \value Gusii - \value Taita - \value Fulah - \value Kikuyu - \value Samburu - \value Sena - \value NorthNdebele - \value Rombo - \value Tachelhit - \value Kabyle - \value Nyankole - \value Bena - \value Vunjo - \value Bambara - \value Embu - \value Cherokee - \value Morisyen - \value Makonde - \value Langi - \value Ganda - \value Bemba - \value Kabuverdianu - \value Meru - \value Kalenjin - \value Nama - \value Machame - \value Colognian - \value Masai - \value Soga - \value Luyia - \value Asu - \value Teso - \value Saho - \value KoyraChiini - \value Rwa - \value Luo - \value Chiga - \value CentralMoroccoTamazight - \value KoyraboroSenni - \value Shambala - \omitvalue LastLanguage - - \sa language() + 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. */ -/*! - \enum QLocale::Country - - This enumerated type is used to specify a country. - - \value AnyCountry - \value Afghanistan - \value Albania - \value Algeria - \value AmericanSamoa - \value Andorra - \value Angola - \value Anguilla - \value Antarctica - \value AntiguaAndBarbuda - \value Argentina - \value Armenia - \value Aruba - \value Australia - \value Austria - \value Azerbaijan - \value Bahamas - \value Bahrain - \value Bangladesh - \value Barbados - \value Belarus - \value Belgium - \value Belize - \value Benin - \value Bermuda - \value Bhutan - \value Bolivia - \value BosniaAndHerzegowina - \value Botswana - \value BouvetIsland - \value Brazil - \value BritishIndianOceanTerritory - \value BruneiDarussalam - \value Bulgaria - \value BurkinaFaso - \value Burundi - \value Cambodia - \value Cameroon - \value Canada - \value CapeVerde - \value CaymanIslands - \value CentralAfricanRepublic - \value Chad - \value Chile - \value China - \value ChristmasIsland - \value CocosIslands - \value Colombia - \value Comoros - \value DemocraticRepublicOfCongo - \value PeoplesRepublicOfCongo - \value CookIslands - \value CostaRica - \value IvoryCoast - \value Croatia - \value Cuba - \value Cyprus - \value CzechRepublic - \value Denmark - \value Djibouti - \value Dominica - \value DominicanRepublic - \value EastTimor - \value Ecuador - \value Egypt - \value ElSalvador - \value EquatorialGuinea - \value Eritrea - \value Estonia - \value Ethiopia - \value FalklandIslands - \value FaroeIslands - \value FijiCountry - \value Finland - \value France - \value MetropolitanFrance - \value FrenchGuiana - \value FrenchPolynesia - \value FrenchSouthernTerritories - \value Gabon - \value Gambia - \value Georgia - \value Germany - \value Ghana - \value Gibraltar - \value Greece - \value Greenland - \value Grenada - \value Guadeloupe - \value Guam - \value Guatemala - \value Guinea - \value GuineaBissau - \value Guyana - \value Haiti - \value HeardAndMcDonaldIslands - \value Honduras - \value HongKong - \value Hungary - \value Iceland - \value India - \value Indonesia - \value Iran - \value Iraq - \value Ireland - \value Israel - \value Italy - \value Jamaica - \value Japan - \value Jordan - \value Kazakhstan - \value Kenya - \value Kiribati - \value DemocraticRepublicOfKorea - \value RepublicOfKorea - \value Kuwait - \value Kyrgyzstan - \value Lao - \value Latvia - \value Lebanon - \value Lesotho - \value Liberia - \value LibyanArabJamahiriya - \value Liechtenstein - \value Lithuania - \value Luxembourg - \value Macau - \value Macedonia - \value Madagascar - \value Malawi - \value Malaysia - \value Maldives - \value Mali - \value Malta - \value MarshallIslands - \value Martinique - \value Mauritania - \value Mauritius - \value Mayotte - \value Mexico - \value Micronesia - \value Moldova - \value Monaco - \value Mongolia - \value Montserrat - \value Morocco - \value Mozambique - \value Myanmar - \value Namibia - \value NauruCountry - \value Nepal - \value Netherlands - \value NetherlandsAntilles - \value NewCaledonia - \value NewZealand - \value Nicaragua - \value Niger - \value Nigeria - \value Niue - \value NorfolkIsland - \value NorthernMarianaIslands - \value Norway - \value Oman - \value Pakistan - \value Palau - \value PalestinianTerritory - \value Panama - \value PapuaNewGuinea - \value Paraguay - \value Peru - \value Philippines - \value Pitcairn - \value Poland - \value Portugal - \value PuertoRico - \value Qatar - \value Reunion - \value Romania - \value RussianFederation - \value Rwanda - \value SaintKittsAndNevis - \value StLucia - \value StVincentAndTheGrenadines - \value Samoa - \value SanMarino - \value SaoTomeAndPrincipe - \value SaudiArabia - \value Senegal - \value SerbiaAndMontenegro - \value Seychelles - \value SierraLeone - \value Singapore - \value Slovakia - \value Slovenia - \value SolomonIslands - \value Somalia - \value SouthAfrica - \value SouthGeorgiaAndTheSouthSandwichIslands - \value Spain - \value SriLanka - \value StHelena - \value StPierreAndMiquelon - \value Sudan - \value Suriname - \value SvalbardAndJanMayenIslands - \value Swaziland - \value Sweden - \value Switzerland - \value SyrianArabRepublic - \value Taiwan - \value Tajikistan - \value Tanzania - \value Thailand - \value Togo - \value Tokelau - \value TongaCountry - \value TrinidadAndTobago - \value Tunisia - \value Turkey - \value Turkmenistan - \value TurksAndCaicosIslands - \value Tuvalu - \value Uganda - \value Ukraine - \value UnitedArabEmirates - \value UnitedKingdom - \value UnitedStates - \value UnitedStatesMinorOutlyingIslands - \value Uruguay - \value Uzbekistan - \value Vanuatu - \value VaticanCityState - \value Venezuela - \value VietNam - \value BritishVirginIslands - \value USVirginIslands - \value WallisAndFutunaIslands - \value WesternSahara - \value Yemen - \value Yugoslavia - \value Zambia - \value Zimbabwe - \value SerbiaAndMontenegro - \value Montenegro - \value Serbia - \value SaintBarthelemy - \value SaintMartin - \value LatinAmericaAndTheCaribbean - \omitvalue LastCountry - - \sa country() -*/ +QString QLocale::toString(const QDate &date, const QString &format) const +{ + return d()->dateTimeToString(format, &date, 0, this); +} /*! - \enum QLocale::FormatType - - This enum describes the types of format that can be used when - converting QDate and QTime objects to strings. - - \value LongFormat The long version of day and month names; for - example, returning "January" as a month name. - - \value ShortFormat The short version of day and month names; for - example, returning "Jan" as a month name. - - \value NarrowFormat A special version of day and month names for - use when space is limited; for example, returning "J" as a month - name. Note that the narrow format might contain the same text for - different months and days or it can even be an empty string if the - locale doesn't support narrow names, so you should avoid using it - for date formatting. Also, for the system locale this format is - the same as ShortFormat. + Returns a localized string representation of the given \a date according + to the specified \a format. */ -/*! - \enum QLocale::NumberOption - - This enum defines a set of options for number-to-string and string-to-number - conversions. They can be retrieved with numberOptions() and set with - setNumberOptions(). - - \value OmitGroupSeparator If this option is set, the number-to-string functions - will not insert group separators in their return values. The default - is to insert group separators. - \value RejectGroupSeparator If this option is set, the string-to-number functions - will fail if they encounter group separators in their input. The default - is to accept numbers containing correctly placed group separators. +QString QLocale::toString(const QDate &date, FormatType format) const +{ + if (!date.isValid()) + return QString(); - \sa setNumberOptions() numberOptions() -*/ +#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 -/*! - \enum QLocale::MeasurementSystem + QString format_str = dateFormat(format); + return toString(date, format_str); +} - This enum defines which units are used for measurement. +static bool timeFormatContainsAP(const QString &format) +{ + int i = 0; + while (i < format.size()) { + if (format.at(i).unicode() == '\'') { + readEscapedFormatString(format, &i); + continue; + } - \value MetricSystem This value indicates metric units, such as meters, - centimeters and millimeters. - \value ImperialSystem This value indicates imperial units, such as inches and - miles. There are several distinct imperial systems in the world; this - value stands for the official United States imperial units. + if (format.at(i).toLower().unicode() == 'a') + return true; - \since 4.4 -*/ + ++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 +} /*! - \fn bool QLocale::operator==(const QLocale &other) const - - Returns true if the QLocale object is the same as the \a other - locale specified; otherwise returns false. + 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); +} /*! - \fn bool QLocale::operator!=(const QLocale &other) const + \since 4.4 - Returns true if the QLocale object is not the same as the \a other - locale specified; otherwise returns false. + 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. */ -/*! - \enum QLocale::QuotationStyle - - This enum defines a set of possible styles for locale specific quotation. - - \value StandardQuotation If this option is set, the standard quotation marks - will be used to quote strings. - \value AlternateQuotation If this option is set, the alternate quotation marks - will be used to quote strings. +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.8 +/*! + \since 4.4 - \sa quoteString() + Returns a localized string representation of the given \a dateTime according + to the specified \a format. */ -static const int locale_data_size = sizeof(locale_data)/sizeof(QLocalePrivate) - 1; - -static const QLocalePrivate *dataPointerHelper(quint16 index) +QString QLocale::toString(const QDateTime &dateTime, FormatType format) const { + if (!dateTime.isValid()) + return QString(); + #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); + if (d() == systemPrivate()) { + QVariant res = systemLocale()->query(format == LongFormat + ? QSystemLocale::DateTimeToStringLong + : QSystemLocale::DateTimeToStringShort, + dateTime); + if (!res.isNull()) + return res.toString(); + } #endif - return &locale_data[index]; + const QString format_str = dateTimeFormat(format); + return toString(dateTime, format_str); } -static quint16 localePrivateIndex(const QLocalePrivate *p) + +/*! + 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 - 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; + if (d() == systemPrivate()) { + QVariant res = systemLocale()->query(format == LongFormat + ? QSystemLocale::TimeToStringLong : QSystemLocale::TimeToStringShort, + time); + if (!res.isNull()) + return res.toString(); + } #endif - return index; + QString format_str = timeFormat(format); + return toString(time, format_str); } /*! - Constructs a QLocale object with the specified \a name, - which has the format - "language[_-country][.codeset][@modifier]" or "C", where: - - \list - \i language is a lowercase, two-letter, ISO 639 language code, - \i territory is an uppercase, two-letter, ISO 3166 country code, - \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. + \since 4.1 - The language and country codes are converted to their respective - \c Language and \c Country enums. After this conversion is - performed the constructor behaves exactly like QLocale(Country, - Language). + Returns the date format used for the current locale. - This constructor is much slower than QLocale(Country, Language). + If \a format is LongFormat the format will be a long version. + Otherwise it uses a shorter version. - \sa name() + \sa QDate::toString(), QDate::fromString() */ -QLocale::QLocale(const QString &name) - : v(0) +QString QLocale::dateFormat(FormatType format) const { - 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() -*/ +#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 -QLocale::QLocale() - : v(0) -{ - p.numberOptions = default_number_options; - p.index = localePrivateIndex(defaultPrivate()); + 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); } /*! - Constructs a QLocale object with the specified \a language and \a - country. + \since 4.1 - \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 + Returns the time format used for the current locale. - The language and country that are actually used can be queried - using language() and country(). + If \a format is LongFormat the format will be a long version. + Otherwise it uses a shorter version. - \sa setDefault() language() country() + \sa QTime::toString(), QTime::fromString() */ -QLocale::QLocale(Language language, Country country) - : v(0) +QString QLocale::timeFormat(FormatType format) const { - const QLocalePrivate *d = findLocale(language, country); +#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 - // 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); + 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); } /*! - Constructs a QLocale object as a copy of \a other. -*/ + \since 4.4 -QLocale::QLocale(const QLocale &other) -{ - v = other.v; -} + Returns the date time format used for the current locale. -const QLocalePrivate *QLocale::d() const -{ - return dataPointerHelper(p.index); -} + If \a format is ShortFormat the format will be a short version. + Otherwise it uses a longer version. -/*! - Assigns \a other to this QLocale object and returns a reference - to this QLocale object. + \sa QDateTime::toString(), QDateTime::fromString() */ -QLocale &QLocale::operator=(const QLocale &other) +QString QLocale::dateTimeFormat(FormatType format) const { - v = other.v; - return *this; +#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.2 + \since 4.4 - Sets the \a options related to number conversions for this - QLocale instance. + 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() */ -void QLocale::setNumberOptions(NumberOptions options) +#ifndef QT_NO_DATESTRING +QTime QLocale::toTime(const QString &string, FormatType format) const { - p.numberOptions = options; + return toTime(string, timeFormat(format)); } +#endif /*! - \since 4.2 + \since 4.4 - Returns the options related to number conversions for this - QLocale instance. + 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()). - By default, no options are set for the standard locales. + If the date could not be parsed, returns an invalid date. + + \sa dateFormat(), toTime(), toDateTime(), QDate::fromString() */ -QLocale::NumberOptions QLocale::numberOptions() const +#ifndef QT_NO_DATESTRING +QDate QLocale::toDate(const QString &string, FormatType format) const { - return static_cast(p.numberOptions); + return toDate(string, dateFormat(format)); } +#endif /*! - \since 4.8 + \since 4.4 - Returns \a str quoted according to the current locale. + 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 \a AlternateQuotation is used for \a QuoatationStyle - but the locale does not provide an alternate quotation, - we will fallback to the parent locale. + If the string could not be parsed, returns an invalid QDateTime. + + \sa dateTimeFormat(), toTime(), toDate(), QDateTime::fromString() */ -QString QLocale::quoteString(const QString &str, QuotationStyle qs) const -{ - return quoteString(&str, qs); +#ifndef QT_NO_DATESTRING +QDateTime QLocale::toDateTime(const QString &string, FormatType format) const +{ + return toDateTime(string, dateTimeFormat(format)); } +#endif /*! - \since 4.8 + \since 4.4 - \overload -*/ -QString QLocale::quoteString(const QStringRef &str, QuotationStyle qs) const -{ -#ifndef QT_NO_SYSTEMLOCALE - if (d() == systemPrivate()) { - QVariant quotationBegin = systemLocale()->query(QSystemLocale::QuotationBegin, QVariant(qs)); - QVariant quotationEnd = systemLocale()->query(QSystemLocale::QuotationEnd, QVariant(qs)); - if (!quotationBegin.isNull() && !quotationEnd.isNull()) - return quotationBegin.toString() % str % quotationEnd.toString(); - } -#endif + 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 (qs == 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); + 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 /*! - \nonreentrant + \since 4.4 - 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. + 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. - \warning In a multithreaded application, the default locale - should be set at application startup, before any non-GUI threads - are created. + This function searches month names and the names of the days of + the week in the current locale. - \sa system() c() -*/ + If the date could not be parsed, returns an invalid date. -void QLocale::setDefault(const QLocale &locale) + \sa dateFormat(), toTime(), toDateTime(), QDate::fromString() +*/ +#ifndef QT_NO_DATESTRING +QDate QLocale::toDate(const QString &string, const QString &format) const { - default_lp = locale.d(); - default_number_options = locale.numberOptions(); + 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 /*! - Returns the language of this locale. + \since 4.4 - \sa country(), languageToString(), name() + 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() */ -QLocale::Language QLocale::language() const +#ifndef QT_NO_DATESTRING +QDateTime QLocale::toDateTime(const QString &string, const QString &format) const { - return Language(d()->languageId()); +#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 + /*! - Returns the country of this locale. + \since 4.1 - \sa language(), countryToString(), name() + Returns the decimal point character of this locale. */ -QLocale::Country QLocale::country() const +QChar QLocale::decimalPoint() const { - return Country(d()->countryId()); + return d()->decimal(); } /*! - 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-letter ISO 3166 country code. + \since 4.1 - \sa language(), country() + Returns the group separator character of this locale. */ - -QString QLocale::name() const +QChar QLocale::groupSeparator() const { - Language l = language(); - - QString result = languageToCode(l); - - if (l == C) - return result; - - Country c = country(); - if (c == AnyCountry) - return result; - - result.append(QLatin1Char('_')); - result.append(countryToCode(c)); - - return result; + return d()->group(); } /*! - Returns a QString containing the name of \a language. + \since 4.1 - \sa countryToString(), name() + Returns the percent character of this locale. */ - -QString QLocale::languageToString(Language language) +QChar QLocale::percent() const { - if (uint(language) > uint(QLocale::LastLanguage)) - return QLatin1String("Unknown"); - return QLatin1String(language_name_list + language_name_index[language]); + return d()->percent(); } /*! - Returns a QString containing the name of \a country. + \since 4.1 - \sa country(), name() + Returns the zero digit character of this locale. */ - -QString QLocale::countryToString(Country country) +QChar QLocale::zeroDigit() const { - if (uint(country) > uint(QLocale::LastCountry)) - return QLatin1String("Unknown"); - return QLatin1String(country_name_list + country_name_index[country]); + return d()->zero(); } /*! - 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. + \since 4.1 - \sa toUShort(), toString() + Returns the negative sign character of this locale. */ - -short QLocale::toShort(const QString &s, bool *ok, int base) const +QChar QLocale::negativeSign() const { - qlonglong i = toLongLong(s, ok, base); - if (i < SHRT_MIN || i > SHRT_MAX) { - if (ok != 0) - *ok = false; - return 0; - } - return short(i); + return d()->minus(); } /*! - 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. + \since 4.5 - \sa toShort(), toString() + Returns the positive sign character of this locale. */ - -ushort QLocale::toUShort(const QString &s, bool *ok, int base) const +QChar QLocale::positiveSign() const { - qulonglong i = toULongLong(s, ok, base); - if (i > USHRT_MAX) { - if (ok != 0) - *ok = false; - return 0; - } - return ushort(i); + return d()->plus(); } /*! - 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. + \since 4.1 - \sa toUInt(), toString() + Returns the exponential character of this locale. */ +QChar QLocale::exponential() const +{ + return d()->exponential(); +} -int QLocale::toInt(const QString &s, bool *ok, int base) const +static bool qIsUpper(char c) { - qlonglong i = toLongLong(s, ok, base); - if (i < INT_MIN || i > INT_MAX) { - if (ok != 0) - *ok = false; - return 0; - } - return int(i); + return c >= 'A' && c <= 'Z'; +} + +static char qToLower(char c) +{ + if (c >= 'A' && c <= 'Z') + return c - 'A' + 'a'; + else + return c; } /*! - 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. + \overload - If the conversion fails the function returns 0. + \a f and \a prec have the same meaning as in QString::number(double, char, int). - 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() + \sa toDouble() */ -uint QLocale::toUInt(const QString &s, bool *ok, int base) const +QString QLocale::toString(double i, char f, int prec) 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() -*/ + QLocalePrivate::DoubleForm form = QLocalePrivate::DFDecimal; + uint flags = 0; + if (qIsUpper(f)) + flags = QLocalePrivate::CapitalEorX; + f = qToLower(f); -qlonglong QLocale::toLongLong(const QString &s, bool *ok, int base) const -{ - QLocalePrivate::GroupSeparatorMode mode - = p.numberOptions & RejectGroupSeparator - ? QLocalePrivate::FailOnGroupSeparators - : QLocalePrivate::ParseGroupSeparators; + switch (f) { + case 'f': + form = QLocalePrivate::DFDecimal; + break; + case 'e': + form = QLocalePrivate::DFExponent; + break; + case 'g': + form = QLocalePrivate::DFSignificantDigits; + break; + default: + break; + } - return d()->stringToLongLong(s, base, ok, mode); + if (!(p.numberOptions & OmitGroupSeparator)) + flags |= QLocalePrivate::ThousandsGroup; + return d()->doubleToString(i, prec, form, -1, flags); } -// ### 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. + \fn QLocale QLocale::c() - This function ignores leading and trailing whitespace. + Returns a QLocale object initialized to the "C" locale. - \sa toLongLong(), toInt(), toDouble(), toString() + \sa system() */ -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. + Returns a QLocale object initialized to the system locale. - This function ignores leading and trailing whitespace. + On Windows and Mac, this locale will use the decimal/grouping characters and date/time + formats specified in the system configuration panel. - \sa toDouble(), toInt(), toString() + \sa c() */ -#define QT_MAX_FLOAT 3.4028234663852886e+38 - -float QLocale::toFloat(const QString &s, bool *ok) const +QLocale QLocale::system() { - 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); + QLocale result(C); + result.p.index = localePrivateIndex(systemPrivate()); + return result; } /*! - 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. + \since 4.3 - \sa toFloat(), toInt(), toString() + 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. */ - -double QLocale::toDouble(const QString &s, bool *ok) const +QList QLocale::countriesForLanguage(Language language) { - QLocalePrivate::GroupSeparatorMode mode - = p.numberOptions & RejectGroupSeparator - ? QLocalePrivate::FailOnGroupSeparators - : QLocalePrivate::ParseGroupSeparators; + QList result; - return d()->stringToDouble(s, ok, mode); -} + unsigned language_id = language; + uint idx = locale_index[language_id]; -/*! - Returns a localized string representation of \a i. + if (language == C) { + result << AnyCountry; + return result; + } - \sa toLongLong() -*/ + const QLocalePrivate *d = locale_data + idx; -QString QLocale::toString(qlonglong i) const -{ - int flags = p.numberOptions & OmitGroupSeparator - ? 0 - : QLocalePrivate::ThousandsGroup; + while (d->languageId() == language_id) { + result << static_cast(d->countryId()); + ++d; + } - return d()->longLongToString(i, -1, 10, -1, flags); + return result; } /*! - \overload + \since 4.2 - \sa toULongLong() -*/ + Returns the localized name of \a month, in the format specified + by \a type. -QString QLocale::toString(qulonglong i) const + \sa dayName(), standaloneMonthName() +*/ +QString QLocale::monthName(int month, FormatType type) const { - int flags = p.numberOptions & OmitGroupSeparator - ? 0 - : QLocalePrivate::ThousandsGroup; + if (month < 1 || month > 12) + return QString(); - return d()->unsLongLongToString(i, -1, 10, -1, flags); +#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); } /*! - 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. -*/ + \since 4.5 -QString QLocale::toString(const QDate &date, const QString &format) const -{ - return d()->dateTimeToString(format, &date, 0, this); -} + Returns the localized name of \a month that is used as a + standalone text, in the format specified by \a type. -/*! - Returns a localized string representation of the given \a date according - to the specified \a format. -*/ + If the locale information doesn't specify the standalone month + name then return value is the same as in monthName(). -QString QLocale::toString(const QDate &date, FormatType format) const + \sa monthName(), standaloneDayName() +*/ +QString QLocale::standaloneMonthName(int month, FormatType type) const { - if (!date.isValid()) + if (month < 1 || month > 12) return QString(); #ifndef QT_NO_SYSTEMLOCALE if (d() == systemPrivate()) { - QVariant res = systemLocale()->query(format == LongFormat - ? QSystemLocale::DateToStringLong : QSystemLocale::DateToStringShort, - date); + QVariant res = systemLocale()->query(type == LongFormat + ? QSystemLocale::MonthNameLong : QSystemLocale::MonthNameShort, + month); 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() == '\'') { - 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)) + 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(); - 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); + } + QString name = getLocaleListData(standalone_months_data + idx, size, month - 1); + if (name.isEmpty()) + return monthName(month, type); + return name; } /*! - \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.2 -/*! - \since 4.4 + 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. - Returns a localized string representation of the given \a dateTime according - to the specified \a format. + \sa monthName(), standaloneDayName() */ - -QString QLocale::toString(const QDateTime &dateTime, FormatType format) const +QString QLocale::dayName(int day, FormatType type) const { - if (!dateTime.isValid()) + if (day < 1 || day > 7) return QString(); #ifndef QT_NO_SYSTEMLOCALE if (d() == systemPrivate()) { - QVariant res = systemLocale()->query(format == LongFormat - ? QSystemLocale::DateTimeToStringLong - : QSystemLocale::DateTimeToStringShort, - dateTime); + QVariant res = systemLocale()->query(type == LongFormat + ? QSystemLocale::DayNameLong : QSystemLocale::DayNameShort, + day); if (!res.isNull()) return res.toString(); } #endif + if (day == 7) + day = 0; - 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()) + 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(); - -#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); + return getLocaleListData(days_data + idx, size, day); } /*! - \since 4.1 + \since 4.5 - Returns the date format used for the current locale. + 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 \a format is LongFormat the format will be a long version. - Otherwise it uses a shorter version. + If the locale information does not specify the standalone day + name then return value is the same as in dayName(). - \sa QDate::toString(), QDate::fromString() + \sa dayName(), standaloneMonthName() */ - -QString QLocale::dateFormat(FormatType format) const +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(format == LongFormat - ? QSystemLocale::DateFormatLong : QSystemLocale::DateFormatShort, - QVariant()); + 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 (format) { - case LongFormat: - idx = d()->m_long_date_format_idx; - size = d()->m_long_date_format_size; + switch (type) { + case QLocale::LongFormat: + idx = d()->m_standalone_long_day_names_idx; + size = d()->m_standalone_long_day_names_size; break; - default: - idx = d()->m_short_date_format_idx; - size = d()->m_short_date_format_size; + 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(); } - return getLocaleData(date_format_data + idx, size); + QString name = getLocaleListData(days_data + idx, size, day); + if (name.isEmpty()) + return dayName(day == 0 ? 7 : day, type); + return name; } /*! - \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. + \since 4.8 - \sa QTime::toString(), QTime::fromString() + Returns the first day of the week according to the current locale. */ - -QString QLocale::timeFormat(FormatType format) const +Qt::DayOfWeek QLocale::firstDayOfWeek() const { #ifndef QT_NO_SYSTEMLOCALE if (d() == systemPrivate()) { - QVariant res = systemLocale()->query(format == LongFormat - ? QSystemLocale::TimeFormatLong : QSystemLocale::TimeFormatShort, - QVariant()); + QVariant res = systemLocale()->query(QSystemLocale::FirstDayOfWeek, QVariant()); if (!res.isNull()) - return res.toString(); + return static_cast(res.toUInt()); } #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); + return static_cast(d()->m_first_day_of_week); } /*! \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() + Returns the measurement system for the locale. */ - -QString QLocale::dateTimeFormat(FormatType format) const +QLocale::MeasurementSystem QLocale::measurementSystem() const { + MeasurementSystem meas = MetricSystem; + bool found = false; + #ifndef QT_NO_SYSTEMLOCALE if (d() == systemPrivate()) { - QVariant res = systemLocale()->query(format == LongFormat - ? QSystemLocale::DateTimeFormatLong - : QSystemLocale::DateTimeFormatShort, - QVariant()); + QVariant res = systemLocale()->query(QSystemLocale::MeasurementSystem, QVariant()); if (!res.isNull()) { - return res.toString(); + meas = MeasurementSystem(res.toInt()); + found = true; } } #endif - return dateFormat(format) + QLatin1Char(' ') + timeFormat(format); + + if (!found) { + meas = d()->measurementSystem(); + found = true; + } + + return meas; } /*! - \since 4.4 + \since 4.7 - 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() + Returns the text direction of the language. */ -#ifndef QT_NO_DATESTRING -QTime QLocale::toTime(const QString &string, FormatType format) const +Qt::LayoutDirection QLocale::textDirection() 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. + Language lang = language(); + if (lang == QLocale::Arabic || + lang == QLocale::Hebrew || + lang == QLocale::Persian || + lang == QLocale::Urdu || + lang == QLocale::Syriac) + return Qt::RightToLeft; - \sa dateFormat(), toTime(), toDateTime(), QDate::fromString() -*/ -#ifndef QT_NO_DATESTRING -QDate QLocale::toDate(const QString &string, FormatType format) const -{ - return toDate(string, dateFormat(format)); + return Qt::LeftToRight; } -#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. + \since 4.5 - If the time could not be parsed, returns an invalid time. + Returns the localized name of the "AM" suffix for times specified using + the conventions of the 12-hour clock. - \sa timeFormat(), toDate(), toDateTime(), QTime::fromString() + \sa pmText() */ -#ifndef QT_NO_DATESTRING -QTime QLocale::toTime(const QString &string, const QString &format) const +QString QLocale::amText() 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); +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QVariant res = systemLocale()->query(QSystemLocale::AMText, QVariant()); + if (!res.isNull()) + return res.toString(); + } #endif - return time; + return getLocaleData(am_data + d()->m_am_idx, d()->m_am_size); } -#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. + \since 4.5 - If the date could not be parsed, returns an invalid date. + Returns the localized name of the "PM" suffix for times specified using + the conventions of the 12-hour clock. - \sa dateFormat(), toTime(), toDateTime(), QDate::fromString() + \sa amText() */ -#ifndef QT_NO_DATESTRING -QDate QLocale::toDate(const QString &string, const QString &format) const +QString QLocale::pmText() 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); +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QVariant res = systemLocale()->query(QSystemLocale::PMText, QVariant()); + if (!res.isNull()) + return res.toString(); + } #endif - return date; + return getLocaleData(pm_data + d()->m_pm_idx, d()->m_pm_size); } -#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 +QString QLocalePrivate::dateTimeToString(const QString &format, const QDate *date, const QTime *time, + const QLocale *q) const { -#ifndef QT_BOOTSTRAPPED - QTime time; - QDate date; + Q_ASSERT(date || time); + if ((date && !date->isValid()) || (time && !time->isValid())) + return QString(); + const bool format_am_pm = time && timeFormatContainsAP(format); - 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 + 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; -/*! - \since 4.1 + int i = 0; + while (i < format.size()) { + if (format.at(i).unicode() == '\'') { + result.append(readEscapedFormatString(format, &i)); + continue; + } - Returns the decimal point character of this locale. -*/ -QChar QLocale::decimalPoint() const -{ - return d()->decimal(); -} + const QChar c = format.at(i); + int repeat = 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; -/*! - \since 4.1 + 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; - Returns the group separator character of this locale. -*/ -QChar QLocale::groupSeparator() const -{ - return d()->group(); -} + 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; -/*! - \since 4.1 + 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; - Returns the percent character of this locale. -*/ -QChar QLocale::percent() const -{ - return d()->percent(); -} - -/*! - \since 4.1 + 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(); - Returns the zero digit character of this locale. -*/ -QChar QLocale::zeroDigit() const -{ - return d()->zero(); -} + 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; -/*! - \since 4.1 + 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; - Returns the negative sign character of this locale. -*/ -QChar QLocale::negativeSign() const -{ - return d()->minus(); -} + 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; -/*! - \since 4.5 + 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 ? QLatin1String("am") : QLatin1String("pm")); + break; - Returns the positive sign character of this locale. -*/ -QChar QLocale::positiveSign() const -{ - return d()->plus(); -} + 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 ? QLatin1String("AM") : QLatin1String("PM")); + break; -/*! - \since 4.1 + 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; - Returns the exponential character of this locale. -*/ -QChar QLocale::exponential() const -{ - return d()->exponential(); -} + case 't': + used = true; + repeat = 1; + result.append(timeZone()); + break; + default: + break; + } + } + if (!used) { + result.append(QString(repeat, c)); + } + i += repeat; + } -static bool qIsUpper(char c) -{ - return c >= 'A' && c <= 'Z'; + return result; } -static char qToLower(char c) +QString QLocalePrivate::doubleToString(double d, + int precision, + DoubleForm form, + int width, + unsigned flags) const { - if (c >= 'A' && c <= 'Z') - return c - 'A' + 'a'; - else - return c; + return QLocalePrivate::doubleToString(zero(), plus(), minus(), exponential(), + group(), decimal(), + d, precision, form, width, flags); } -/*! - \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 +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) { - QLocalePrivate::DoubleForm form = QLocalePrivate::DFDecimal; - uint flags = 0; + if (precision == -1) + precision = 6; + if (width == -1) + width = 0; - if (qIsUpper(f)) - flags = QLocalePrivate::CapitalEorX; - f = qToLower(f); + bool negative = false; + bool special_number = false; // nan, +/-inf + QString num_str; - switch (f) { - case 'f': - form = QLocalePrivate::DFDecimal; - break; - case 'e': - form = QLocalePrivate::DFExponent; - break; - case 'g': - form = QLocalePrivate::DFSignificantDigits; - break; - default: - break; + // 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; } - 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. + // Handle normal numbers + if (!special_number) { + int decpt, sign; + QString digits; - \sa system() -*/ +#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)); -/*! - Returns a QLocale object initialized to the system locale. + // 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); + } - On Windows and Mac, this locale will use the decimal/grouping characters and date/time - formats specified in the system configuration panel. + } - \sa c() -*/ +#else + int mode; + if (form == DFDecimal) + mode = 3; + else + mode = 2; -QLocale QLocale::system() -{ - QLocale result(C); - result.p.index = localePrivateIndex(systemPrivate()); - return result; -} - -/*! - \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. -*/ -QList QLocale::countriesForLanguage(Language language) -{ - QList 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(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(res.toUInt()); - } -#endif - return static_cast(d()->m_first_day_of_week); -} - -/*! - \since 4.4 - - Returns the measurement system for the locale. -*/ -QLocale::MeasurementSystem QLocale::measurementSystem() const -{ - MeasurementSystem meas = MetricSystem; - bool found = false; - -#ifndef QT_NO_SYSTEMLOCALE - if (d() == systemPrivate()) { - QVariant res = systemLocale()->query(QSystemLocale::MeasurementSystem, QVariant()); - if (!res.isNull()) { - meas = MeasurementSystem(res.toInt()); - found = true; - } - } -#endif - - if (!found) { - meas = d()->measurementSystem(); - found = true; - } - - return meas; -} - -/*! - \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); -} - - -/*! -\fn QString QLocale::toString(short i) const - -\overload - -\sa toShort() -*/ - -/*! -\fn QString QLocale::toString(ushort i) const - -\overload - -\sa toUShort() -*/ - -/*! -\fn QString QLocale::toString(int i) const - -\overload - -\sa toInt() -*/ - -/*! -\fn QString QLocale::toString(uint i) const - -\overload - -\sa toUInt() -*/ - -/* -\fn QString QLocale::toString(long i) const - -\overload - -\sa toLong() -*/ - -/* -\fn QString QLocale::toString(ulong i) const - -\overload - -\sa toULong() -*/ - -/*! -\fn QString QLocale::toString(float i, char f = 'g', int prec = 6) const - -\overload - -\a f and \a prec have the same meaning as in QString::number(double, char, int). - -\sa toDouble() -*/ - - -static QString qulltoa(qulonglong l, int base, const QChar _zero) -{ - ushort buff[65]; // length of MAX_ULLONG in base 2 - ushort *p = buff + 65; - - if (base != 10 || _zero.unicode() == '0') { - while (l != 0) { - int c = l % base; - - --p; - - if (c < 10) - *p = '0' + c; - else - *p = c - 10 + 'a'; - - l /= base; - } - } - else { - while (l != 0) { - int c = l % base; - - *(--p) = _zero.unicode() + c; - - l /= base; - } - } - - return QString(reinterpret_cast(p), 65 - (p - buff)); -} - -static QString qlltoa(qlonglong l, int base, const QChar zero) -{ - return qulltoa(l < 0 ? -l : l, base, zero); -} - -enum PrecisionMode { - PMDecimalDigits = 0x01, - PMSignificantDigits = 0x02, - PMChopTrailingZeros = 0x03 -}; - -static QString &decimalForm(QChar zero, QChar decimal, QChar group, - QString &digits, int decpt, uint precision, - PrecisionMode pm, - bool always_show_decpt, - bool thousands_group) -{ - if (decpt < 0) { - for (int i = 0; i < -decpt; ++i) - digits.prepend(zero); - decpt = 0; - } - else if (decpt > digits.length()) { - for (int i = digits.length(); i < decpt; ++i) - digits.append(zero); - } - - if (pm == PMDecimalDigits) { - uint decimal_digits = digits.length() - decpt; - for (uint i = decimal_digits; i < precision; ++i) - digits.append(zero); - } - else if (pm == PMSignificantDigits) { - for (uint i = digits.length(); i < precision; ++i) - digits.append(zero); - } - else { // pm == PMChopTrailingZeros - } - - if (always_show_decpt || decpt < digits.length()) - digits.insert(decpt, decimal); - - if (thousands_group) { - for (int i = decpt - 3; i > 0; i -= 3) - digits.insert(i, group); - } - - if (decpt == 0) - digits.prepend(zero); - - return digits; -} - -static QString &exponentForm(QChar zero, QChar decimal, QChar exponential, - QChar group, QChar plus, QChar minus, - QString &digits, int decpt, uint precision, - PrecisionMode pm, - bool always_show_decpt) -{ - int exp = decpt - 1; - - if (pm == PMDecimalDigits) { - for (uint i = digits.length(); i < precision + 1; ++i) - digits.append(zero); - } - else if (pm == PMSignificantDigits) { - for (uint i = digits.length(); i < precision; ++i) - digits.append(zero); - } - else { // pm == PMChopTrailingZeros - } - - if (always_show_decpt || digits.length() > 1) - digits.insert(1, decimal); - - digits.append(exponential); - digits.append(QLocalePrivate::longLongToString(zero, group, plus, minus, - exp, 2, 10, -1, QLocalePrivate::AlwaysShowSign)); - - return digits; -} - -static bool isZero(double d) -{ - uchar *ch = (uchar *)&d; -#ifdef QT_ARMFPA - return !(ch[3] & 0x7F || ch[2] || ch[1] || ch[0] || ch[7] || ch[6] || ch[5] || ch[4]); -#else - if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { - return !(ch[0] & 0x7F || ch[1] || ch[2] || ch[3] || ch[4] || ch[5] || ch[6] || ch[7]); - } else { - return !(ch[7] & 0x7F || ch[6] || ch[5] || ch[4] || ch[3] || ch[2] || ch[1] || ch[0]); - } -#endif -} - -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(readEscapedFormatString(format, &i)); - continue; - } - - const QChar c = format.at(i); - int repeat = 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 ? QLatin1String("am") : QLatin1String("pm")); - 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 ? QLatin1String("AM") : QLatin1String("PM")); - 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(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; -} - -// Removes thousand-group separators in "C" locale. -static bool removeGroupSeparators(QLocalePrivate::CharBuff *num) -{ - int group_cnt = 0; // counts number of group chars - int decpt_idx = -1; - - char *data = num->data(); - int l = qstrlen(data); - - // Find the decimal point and check if there are any group chars - int i = 0; - for (; i < l; ++i) { - char c = data[i]; - - if (c == ',') { - if (i == 0 || data[i - 1] < '0' || data[i - 1] > '9') - return false; - if (i == l - 1 || data[i + 1] < '0' || data[i + 1] > '9') - return false; - ++group_cnt; - } - else if (c == '.') { - // Fail if more than one decimal points - if (decpt_idx != -1) - return false; - decpt_idx = i; - } else if (c == 'e' || c == 'E') { - // an 'e' or 'E' - if we have not encountered a decimal - // point, this is where it "is". - if (decpt_idx == -1) - decpt_idx = i; - } - } - - // If no group chars, we're done - if (group_cnt == 0) - return true; - - // No decimal point means that it "is" at the end of the string - if (decpt_idx == -1) - decpt_idx = l; - - i = 0; - while (i < l && group_cnt > 0) { - char c = data[i]; - - if (c == ',') { - // Don't allow group chars after the decimal point - if (i > decpt_idx) - return false; - - // Check that it is placed correctly relative to the decpt - if ((decpt_idx - i) % 4 != 0) - return false; - - // Remove it - memmove(data + i, data + i + 1, l - i - 1); - data[--l] = '\0'; - - --group_cnt; - --decpt_idx; - } else { - // Check that we are not missing a separator - if (i < decpt_idx - && (decpt_idx - i) % 4 == 0 - && !(i == 0 && c == '-')) // check for negative sign at start of string - return false; - ++i; - } - } - - return true; -} - -/* - 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); + /* 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; - 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'; + 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; } - 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::CurrencyFormat - - Specifies the format of the currency symbol. + if (buff != 0) + free(buff); +#endif // QT_QLOCALE_USES_FCVT - \value CurrencyIsoCode a ISO-4217 code of the currency. - \value CurrencySymbol a currency symbol. - \value CurrencyDisplayName a user readable name of the currency. -*/ + if (_zero.unicode() != '0') { + ushort z = _zero.unicode() - '0'; + for (int i = 0; i < digits.length(); ++i) + reinterpret_cast(digits.data())[i] += z; + } -/*! - \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]) + 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; - return len ? QString::fromLatin1(d->m_currency_iso_code, len) : QString(); - } - } - return QString(); -} - -/*! - \fn QString QLocale::toCurrencyString(short) const - \since 4.8 - \overload -*/ - -/*! - \fn QString QLocale::toCurrencyString(ushort) const - \since 4.8 - \overload -*/ - -/*! - \fn QString QLocale::toCurrencyString(int) const - \since 4.8 - \overload -*/ - -/*! - \fn QString QLocale::toCurrencyString(uint) const - \since 4.8 - \overload -*/ -/*! - \fn QString QLocale::toCurrencyString(float) const - \since 4.8 - \overload -*/ - -/*! - \since 4.8 - - Returns a localized string representation of \a value as a currency. -*/ -QString QLocale::toCurrencyString(qlonglong value) const -{ -#ifndef QT_NO_SYSTEMLOCALE - if (d() == systemPrivate()) { - QVariant res = systemLocale()->query(QSystemLocale::FormatCurrency, value); - 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 symbol = currencySymbol(); - if (symbol.isEmpty()) - symbol = currencySymbol(QLocale::CurrencyIsoCode); - QString format = getLocaleData(currency_format_data + idx, size); - return format.arg(str, symbol); -} - -/*! - \since 4.8 - \overload -*/ -QString QLocale::toCurrencyString(qulonglong value) const -{ -#ifndef QT_NO_SYSTEMLOCALE - if (d() == systemPrivate()) { - QVariant res = systemLocale()->query(QSystemLocale::FormatCurrency, value); - 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 symbol = currencySymbol(); - if (symbol.isEmpty()) - symbol = currencySymbol(QLocale::CurrencyIsoCode); - QString format = getLocaleData(currency_format_data + idx, size); - return format.arg(str, symbol); -} - -QString QLocale::toCurrencyString(double value) const -{ -#ifndef QT_NO_SYSTEMLOCALE - if (d() == systemPrivate()) { - QVariant res = systemLocale()->query(QSystemLocale::FormatCurrency, value); - 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 symbol = currencySymbol(); - if (symbol.isEmpty()) - symbol = currencySymbol(QLocale::CurrencyIsoCode); - QString format = getLocaleData(currency_format_data + idx, size); - return format.arg(str, symbol); -} - -/*! - \since 4.8 - - Returns a sorted list of locale names that could be used for translation - of messages presented to the user. + } + 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; - \sa QTranslator -*/ -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; + 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; + } } - } -#endif - return QStringList(name()); -} - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgment: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -// static char sccsid[] = "@(#)strtouq.c 8.1 (Berkeley) 6/4/93"; -// "$FreeBSD: src/lib/libc/stdlib/strtoull.c,v 1.5.2.1 2001/03/02 09:45:20 obrien Exp $"; -/* - * Convert a string to an unsigned long long integer. - * - * Ignores `locale' stuff. Assumes that the upper and lower case - * alphabets and digits are each contiguous. - */ -static qulonglong qstrtoull(const char *nptr, const char **endptr, register int base, bool *ok) -{ - register const char *s = nptr; - register qulonglong acc; - register unsigned char c; - register qulonglong qbase, cutoff; - register int any, cutlim; + negative = sign != 0 && !isZero(d); + } - if (ok != 0) - *ok = true; + // 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; - /* - * See strtoq for comments as to the logic used. - */ - s = nptr; - do { - c = *s++; - } while (isspace(c)); - if (c == '-') { - if (ok != 0) - *ok = false; - if (endptr != 0) - *endptr = s - 1; - return 0; - } else { - if (c == '+') - c = *s++; - } - if ((base == 0 || base == 16) && - c == '0' && (*s == 'x' || *s == 'X')) { - c = s[1]; - s += 2; - base = 16; - } - if (base == 0) - base = c == '0' ? 8 : 10; - qbase = unsigned(base); - cutoff = qulonglong(ULLONG_MAX) / qbase; - cutlim = qulonglong(ULLONG_MAX) % qbase; - for (acc = 0, any = 0;; c = *s++) { - if (!isascii(c)) - break; - if (isdigit(c)) - c -= '0'; - else if (isalpha(c)) - c -= isupper(c) ? 'A' - 10 : 'a' - 10; - else - break; - if (c >= base) - break; - if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) - any = -1; - else { - any = 1; - acc *= qbase; - acc += c; - } - } - if (any == 0) { - if (ok != 0) - *ok = false; - } else if (any < 0) { - acc = ULLONG_MAX; - if (ok != 0) - *ok = false; + for (int i = 0; i < num_pad_chars; ++i) + num_str.prepend(_zero); } - if (endptr != 0) - *endptr = (any ? s - 1 : nptr); - return acc; -} + // 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(' ')); -// "$FreeBSD: src/lib/libc/stdlib/strtoll.c,v 1.5.2.1 2001/03/02 09:45:20 obrien Exp $"; + if (flags & QLocalePrivate::CapitalEorX) + num_str = num_str.toUpper(); + return num_str; +} -/* - * Convert a string to a long long integer. - * - * Ignores `locale' stuff. Assumes that the upper and lower case - * alphabets and digits are each contiguous. - */ -static qlonglong qstrtoll(const char *nptr, const char **endptr, register int base, bool *ok) +QString QLocalePrivate::longLongToString(qlonglong l, int precision, + int base, int width, + unsigned flags) const { - register const char *s; - register qulonglong acc; - register unsigned char c; - register qulonglong qbase, cutoff; - register int neg, any, cutlim; - - /* - * Skip white space and pick up leading +/- sign if any. - * If base is 0, allow 0x for hex and 0 for octal, else - * assume decimal; if base is already 16, allow 0x. - */ - s = nptr; - do { - c = *s++; - } while (isspace(c)); - if (c == '-') { - neg = 1; - c = *s++; - } else { - neg = 0; - if (c == '+') - c = *s++; - } - if ((base == 0 || base == 16) && - c == '0' && (*s == 'x' || *s == 'X')) { - c = s[1]; - s += 2; - base = 16; - } - if (base == 0) - base = c == '0' ? 8 : 10; - - /* - * Compute the cutoff value between legal numbers and illegal - * numbers. That is the largest legal value, divided by the - * base. An input number that is greater than this value, if - * followed by a legal input character, is too big. One that - * is equal to this value may be valid or not; the limit - * between valid and invalid numbers is then based on the last - * digit. For instance, if the range for quads is - * [-9223372036854775808..9223372036854775807] and the input base - * is 10, cutoff will be set to 922337203685477580 and cutlim to - * either 7 (neg==0) or 8 (neg==1), meaning that if we have - * accumulated a value > 922337203685477580, or equal but the - * next digit is > 7 (or 8), the number is too big, and we will - * return a range error. - * - * Set any if any `digits' consumed; make it negative to indicate - * overflow. - */ - qbase = unsigned(base); - cutoff = neg ? qulonglong(0-(LLONG_MIN + LLONG_MAX)) + LLONG_MAX : LLONG_MAX; - cutlim = cutoff % qbase; - cutoff /= qbase; - for (acc = 0, any = 0;; c = *s++) { - if (!isascii(c)) - break; - if (isdigit(c)) - c -= '0'; - else if (isalpha(c)) - c -= isupper(c) ? 'A' - 10 : 'a' - 10; - else - break; - if (c >= base) - break; - if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) - any = -1; - else { - any = 1; - acc *= qbase; - acc += c; - } - } - if (any < 0) { - acc = neg ? LLONG_MIN : LLONG_MAX; - if (ok != 0) - *ok = false; - } else if (neg) { - acc = (~acc) + 1; - } - if (endptr != 0) - *endptr = (any >= 0 ? s - 1 : nptr); - - if (ok != 0) - *ok = any > 0; - - return acc; + return QLocalePrivate::longLongToString(zero(), group(), plus(), minus(), + l, precision, base, width, flags); } -#ifndef QT_QLOCALE_USES_FCVT - -/* From: NetBSD: strtod.c,v 1.26 1998/02/03 18:44:21 perry Exp */ -/* $FreeBSD: src/lib/libc/stdlib/netbsd_strtod.c,v 1.2.2.2 2001/03/02 17:14:15 tegge Exp $ */ - -/* Please send bug reports to - David M. Gay - AT&T Bell Laboratories, Room 2C-463 - 600 Mountain Avenue - Murray Hill, NJ 07974-2070 - U.S.A. - dmg@research.att.com or research!dmg - */ - -/* strtod for IEEE-, VAX-, and IBM-arithmetic machines. - * - * This strtod returns a nearest machine number to the input decimal - * string (or sets errno to ERANGE). With IEEE arithmetic, ties are - * broken by the IEEE round-even rule. Otherwise ties are broken by - * biased rounding (add half and chop). - * - * Inspired loosely by William D. Clinger's paper "How to Read Floating - * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101]. - * - * Modifications: - * - * 1. We only require IEEE, IBM, or VAX double-precision - * arithmetic (not IEEE double-extended). - * 2. We get by with floating-point arithmetic in a case that - * Clinger missed -- when we're computing d * 10^n - * for a small integer d and the integer n is not too - * much larger than 22 (the maximum integer k for which - * we can represent 10^k exactly), we may be able to - * compute (d*10^k) * 10^(e-k) with just one roundoff. - * 3. Rather than a bit-at-a-time adjustment of the binary - * result in the hard case, we use floating-point - * arithmetic to determine the adjustment to within - * one bit; only in really hard cases do we need to - * compute a second residual. - * 4. Because of 3., we don't need a large table of powers of 10 - * for ten-to-e (just some small tables, e.g. of 10^k - * for 0 <= k <= 22). - */ - -/* - * #define IEEE_LITTLE_ENDIAN for IEEE-arithmetic machines where the least - * significant byte has the lowest address. - * #define IEEE_BIG_ENDIAN for IEEE-arithmetic machines where the most - * significant byte has the lowest address. - * #define Long int on machines with 32-bit ints and 64-bit longs. - * #define Sudden_Underflow for IEEE-format machines without gradual - * underflow (i.e., that flush to zero on underflow). - * #define IBM for IBM mainframe-style floating-point arithmetic. - * #define VAX for VAX-style floating-point arithmetic. - * #define Unsigned_Shifts if >> does treats its left operand as unsigned. - * #define No_leftright to omit left-right logic in fast floating-point - * computation of dtoa. - * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3. - * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines - * that use extended-precision instructions to compute rounded - * products and quotients) with IBM. - * #define ROUND_BIASED for IEEE-format with biased rounding. - * #define Inaccurate_Divide for IEEE-format with correctly rounded - * products but inaccurate quotients, e.g., for Intel i860. - * #define Just_16 to store 16 bits per 32-bit Long when doing high-precision - * integer arithmetic. Whether this speeds things up or slows things - * down depends on the machine and the number being converted. - * #define KR_headers for old-style C function headers. - * #define Bad_float_h if your system lacks a float.h or if it does not - * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP, - * FLT_RADIX, FLT_ROUNDS, and DBL_MAX. - * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n) - * if memory is available and otherwise does something you deem - * appropriate. If MALLOC is undefined, malloc will be invoked - * directly -- and assumed always to succeed. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: strtod.c,v 1.26 1998/02/03 18:44:21 perry Exp $"); -#endif /* LIBC_SCCS and not lint */ - -/* -#if defined(__m68k__) || defined(__sparc__) || defined(__i386__) || \ - defined(__mips__) || defined(__ns32k__) || defined(__alpha__) || \ - defined(__powerpc__) || defined(Q_OS_WIN) || defined(Q_OS_DARWIN) || defined(Q_OS_MAC) || \ - defined(mips) || defined(Q_OS_AIX) || defined(Q_OS_SOLARIS) -# define IEEE_BIG_OR_LITTLE_ENDIAN 1 -#endif -*/ - -// *All* of our architectures have IEEE arithmetic, don't they? -#define IEEE_BIG_OR_LITTLE_ENDIAN 1 +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; + } -#ifdef __arm32__ -/* - * Although the CPU is little endian the FP has different - * byte and word endianness. The byte order is still little endian - * but the word order is big endian. - */ -#define IEEE_BIG_OR_LITTLE_ENDIAN -#endif + 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 + } -#ifdef vax -#define VAX -#endif + QString num_str; + if (base == 10) + num_str = qlltoa(l, base, zero); + else + num_str = qulltoa(l, base, zero); -#define Long qint32 -#define ULong quint32 + 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; + } + } -#define MALLOC malloc + for (int i = num_str.length()/* - cnt_thousand_sep*/; i < precision; ++i) + num_str.prepend(base == 10 ? zero : QChar::fromLatin1('0')); -#ifdef BSD_QDTOA_DEBUG -QT_BEGIN_INCLUDE_NAMESPACE -#include -QT_END_INCLUDE_NAMESPACE + if ((flags & Alternate || flags & ShowBase) + && base == 8 + && (num_str.isEmpty() || num_str[0].unicode() != QLatin1Char('0'))) + num_str.prepend(QLatin1Char('0')); -#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);} -#endif + // 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; -#ifdef Unsigned_Shifts -#define Sign_Extend(a,b) if (b < 0) a |= 0xffff0000; -#else -#define Sign_Extend(a,b) /*no-op*/ -#endif + if (zero_padded) { + int num_pad_chars = width - num_str.length(); -#if (defined(IEEE_BIG_OR_LITTLE_ENDIAN) + defined(VAX) + defined(IBM)) != 1 -#error Exactly one of IEEE_BIG_OR_LITTLE_ENDIAN, VAX, or IBM should be defined. -#endif + // leave space for the sign + if (negative + || flags & AlwaysShowSign + || flags & BlankBeforePositive) + --num_pad_chars; -static inline ULong _getWord0(const NEEDS_VOLATILE double x) -{ - const NEEDS_VOLATILE uchar *ptr = reinterpret_cast(&x); - if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { - return (ptr[0]<<24) + (ptr[1]<<16) + (ptr[2]<<8) + ptr[3]; - } else { - return (ptr[7]<<24) + (ptr[6]<<16) + (ptr[5]<<8) + ptr[4]; - } -} + // 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; -static inline void _setWord0(NEEDS_VOLATILE double *x, ULong l) -{ - NEEDS_VOLATILE uchar *ptr = reinterpret_cast(x); - if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { - ptr[0] = uchar(l>>24); - ptr[1] = uchar(l>>16); - ptr[2] = uchar(l>>8); - ptr[3] = uchar(l); - } else { - ptr[7] = uchar(l>>24); - ptr[6] = uchar(l>>16); - ptr[5] = uchar(l>>8); - ptr[4] = uchar(l); + for (int i = 0; i < num_pad_chars; ++i) + num_str.prepend(base == 10 ? zero : QChar::fromLatin1('0')); } -} -static inline ULong _getWord1(const NEEDS_VOLATILE double x) -{ - const NEEDS_VOLATILE uchar *ptr = reinterpret_cast(&x); - if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { - return (ptr[4]<<24) + (ptr[5]<<16) + (ptr[6]<<8) + ptr[7]; - } else { - return (ptr[3]<<24) + (ptr[2]<<16) + (ptr[1]<<8) + ptr[0]; - } -} -static inline void _setWord1(NEEDS_VOLATILE double *x, ULong l) -{ - NEEDS_VOLATILE uchar *ptr = reinterpret_cast(x); - if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { - ptr[4] = uchar(l>>24); - ptr[5] = uchar(l>>16); - ptr[6] = uchar(l>>8); - ptr[7] = uchar(l); - } else { - ptr[3] = uchar(l>>24); - ptr[2] = uchar(l>>16); - ptr[1] = uchar(l>>8); - ptr[0] = uchar(l); - } -} + if (flags & CapitalEorX) + num_str = num_str.toUpper(); -static inline ULong getWord0(const NEEDS_VOLATILE double x) -{ -#ifdef QT_ARMFPA - return _getWord1(x); -#else - return _getWord0(x); -#endif -} + 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")); -static inline void setWord0(NEEDS_VOLATILE double *x, ULong l) -{ -#ifdef QT_ARMFPA - _setWord1(x, l); -#else - _setWord0(x, l); -#endif -} + // add sign + if (negative) + num_str.prepend(minus); + else if (flags & AlwaysShowSign) + num_str.prepend(plus); + else if (flags & BlankBeforePositive) + num_str.prepend(QLatin1Char(' ')); -static inline ULong getWord1(const NEEDS_VOLATILE double x) -{ -#ifdef QT_ARMFPA - return _getWord0(x); -#else - return _getWord1(x); -#endif + return num_str; } -static inline void setWord1(NEEDS_VOLATILE double *x, ULong l) +QString QLocalePrivate::unsLongLongToString(qulonglong l, int precision, + int base, int width, + unsigned flags) const { -#ifdef QT_ARMFPA - _setWord0(x, l); -#else - _setWord1(x, l); -#endif + return QLocalePrivate::unsLongLongToString(zero(), group(), plus(), + l, precision, base, width, flags); } -static inline void Storeinc(ULong *&a, const ULong &b, const ULong &c) +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; + } - *a = (ushort(b) << 16) | ushort(c); - ++a; -} - -/* #define P DBL_MANT_DIG */ -/* Ten_pmax = floor(P*log(2)/log(5)) */ -/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */ -/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */ -/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */ - -#if defined(IEEE_BIG_OR_LITTLE_ENDIAN) -#define Exp_shift 20 -#define Exp_shift1 20 -#define Exp_msk1 0x100000 -#define Exp_msk11 0x100000 -#define Exp_mask 0x7ff00000 -#define P 53 -#define Bias 1023 -#define IEEE_Arith -#define Emin (-1022) -#define Exp_1 0x3ff00000 -#define Exp_11 0x3ff00000 -#define Ebits 11 -#define Frac_mask 0xfffff -#define Frac_mask1 0xfffff -#define Ten_pmax 22 -#define Bletch 0x10 -#define Bndry_mask 0xfffff -#define Bndry_mask1 0xfffff -#if defined(LSB) && defined(Q_OS_VXWORKS) -#undef LSB -#endif -#define LSB 1 -#define Sign_bit 0x80000000 -#define Log2P 1 -#define Tiny0 0 -#define Tiny1 1 -#define Quick_max 14 -#define Int_max 14 -#define Infinite(x) (getWord0(x) == 0x7ff00000) /* sufficient test for here */ -#else -#undef Sudden_Underflow -#define Sudden_Underflow -#ifdef IBM -#define Exp_shift 24 -#define Exp_shift1 24 -#define Exp_msk1 0x1000000 -#define Exp_msk11 0x1000000 -#define Exp_mask 0x7f000000 -#define P 14 -#define Bias 65 -#define Exp_1 0x41000000 -#define Exp_11 0x41000000 -#define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */ -#define Frac_mask 0xffffff -#define Frac_mask1 0xffffff -#define Bletch 4 -#define Ten_pmax 22 -#define Bndry_mask 0xefffff -#define Bndry_mask1 0xffffff -#define LSB 1 -#define Sign_bit 0x80000000 -#define Log2P 4 -#define Tiny0 0x100000 -#define Tiny1 0 -#define Quick_max 14 -#define Int_max 15 -#else /* VAX */ -#define Exp_shift 23 -#define Exp_shift1 7 -#define Exp_msk1 0x80 -#define Exp_msk11 0x800000 -#define Exp_mask 0x7f80 -#define P 56 -#define Bias 129 -#define Exp_1 0x40800000 -#define Exp_11 0x4080 -#define Ebits 8 -#define Frac_mask 0x7fffff -#define Frac_mask1 0xffff007f -#define Ten_pmax 24 -#define Bletch 2 -#define Bndry_mask 0xffff007f -#define Bndry_mask1 0xffff007f -#define LSB 0x10000 -#define Sign_bit 0x8000 -#define Log2P 1 -#define Tiny0 0x80 -#define Tiny1 0 -#define Quick_max 15 -#define Int_max 15 -#endif -#endif - -#ifndef IEEE_Arith -#define ROUND_BIASED -#endif - -#ifdef RND_PRODQUOT -#define rounded_product(a,b) a = rnd_prod(a, b) -#define rounded_quotient(a,b) a = rnd_quot(a, b) -extern double rnd_prod(double, double), rnd_quot(double, double); -#else -#define rounded_product(a,b) a *= b -#define rounded_quotient(a,b) a /= b -#endif - -#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) -#define Big1 0xffffffff - -#ifndef Just_16 -/* When Pack_32 is not defined, we store 16 bits per 32-bit Long. - * This makes some inner loops simpler and sometimes saves work - * during multiplications, but it often seems to make things slightly - * slower. Hence the default is now to store 32 bits per Long. - */ -#ifndef Pack_32 -#define Pack_32 -#endif -#endif + QString num_str = qulltoa(l, base, zero); -#define Kmax 15 + 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; + } + } -struct -Bigint { - struct Bigint *next; - int k, maxwds, sign, wds; - ULong x[1]; -}; + for (int i = num_str.length()/* - cnt_thousand_sep*/; i < precision; ++i) + num_str.prepend(base == 10 ? zero : QChar::fromLatin1('0')); - typedef struct Bigint Bigint; + if ((flags & Alternate || flags & ShowBase) + && base == 8 + && (num_str.isEmpty() || num_str[0].unicode() != QLatin1Char('0'))) + num_str.prepend(QLatin1Char('0')); -static Bigint *Balloc(int k) -{ - int x; - Bigint *rv; - - x = 1 << k; - rv = static_cast(MALLOC(sizeof(Bigint) + (x-1)*sizeof(Long))); - Q_CHECK_PTR(rv); - rv->k = k; - rv->maxwds = x; - rv->sign = rv->wds = 0; - return rv; -} + // 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; -static void Bfree(Bigint *v) -{ - free(v); -} + if (zero_padded) { + int num_pad_chars = width - num_str.length(); -#define Bcopy(x,y) memcpy(reinterpret_cast(&x->sign), reinterpret_cast(&y->sign), \ -y->wds*sizeof(Long) + 2*sizeof(int)) + // 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; -/* multiply by m and add a */ -static Bigint *multadd(Bigint *b, int m, int a) -{ - int i, wds; - ULong *x, y; -#ifdef Pack_32 - ULong xi, z; -#endif - Bigint *b1; - - wds = b->wds; - x = b->x; - i = 0; - do { -#ifdef Pack_32 - xi = *x; - y = (xi & 0xffff) * m + a; - z = (xi >> 16) * m + (y >> 16); - a = (z >> 16); - *x++ = (z << 16) + (y & 0xffff); -#else - y = *x * m + a; - a = (y >> 16); - *x++ = y & 0xffff; -#endif - } - while(++i < wds); - if (a) { - if (wds >= b->maxwds) { - b1 = Balloc(b->k+1); - Bcopy(b1, b); - Bfree(b); - b = b1; - } - b->x[wds++] = a; - b->wds = wds; + for (int i = 0; i < num_pad_chars; ++i) + num_str.prepend(base == 10 ? zero : QChar::fromLatin1('0')); } - return b; -} -static Bigint *s2b(const char *s, int nd0, int nd, ULong y9) -{ - Bigint *b; - int i, k; - Long x, y; - - x = (nd + 8) / 9; - for(k = 0, y = 1; x > y; y <<= 1, k++) ; -#ifdef Pack_32 - b = Balloc(k); - b->x[0] = y9; - b->wds = 1; -#else - b = Balloc(k+1); - b->x[0] = y9 & 0xffff; - b->wds = (b->x[1] = y9 >> 16) ? 2 : 1; -#endif + if (flags & CapitalEorX) + num_str = num_str.toUpper(); - i = 9; - if (9 < nd0) { - s += 9; - do b = multadd(b, 10, *s++ - '0'); - while(++i < nd0); - s++; - } - else - s += 10; - for(; i < nd; i++) - b = multadd(b, 10, *s++ - '0'); - return b; -} + 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")); -static int hi0bits(ULong x) -{ - int k = 0; + // add sign + if (flags & AlwaysShowSign) + num_str.prepend(plus); + else if (flags & BlankBeforePositive) + num_str.prepend(QLatin1Char(' ')); - if (!(x & 0xffff0000)) { - k = 16; - x <<= 16; - } - if (!(x & 0xff000000)) { - k += 8; - x <<= 8; - } - if (!(x & 0xf0000000)) { - k += 4; - x <<= 4; - } - if (!(x & 0xc0000000)) { - k += 2; - x <<= 2; - } - if (!(x & 0x80000000)) { - k++; - if (!(x & 0x40000000)) - return 32; - } - return k; + return num_str; } -static int lo0bits(ULong *y) +/* + 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 { - int k; - ULong x = *y; - - if (x & 7) { - if (x & 1) - return 0; - if (x & 2) { - *y = x >> 1; - return 1; - } - *y = x >> 2; - return 2; - } - k = 0; - if (!(x & 0xffff)) { - k = 16; - x >>= 16; - } - if (!(x & 0xff)) { - k += 8; - x >>= 8; - } - if (!(x & 0xf)) { - k += 4; - x >>= 4; - } - if (!(x & 0x3)) { - k += 2; - x >>= 2; - } - if (!(x & 1)) { - k++; - x >>= 1; - if (!x & 1) - return 32; - } - *y = x; - return k; -} + const QChar *uc = num.unicode(); + int l = num.length(); + int idx = 0; -static Bigint *i2b(int i) -{ - Bigint *b; + // Skip whitespace + while (idx < l && uc[idx].isSpace()) + ++idx; + if (idx == l) + return false; - b = Balloc(1); - b->x[0] = i; - b->wds = 1; - return b; -} + const QChar _group = group(); -static Bigint *mult(Bigint *a, Bigint *b) -{ - Bigint *c; - int k, wa, wb, wc; - ULong carry, y, z; - ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0; -#ifdef Pack_32 - ULong z2; -#endif + while (idx < l) { + const QChar &in = uc[idx]; - if (a->wds < b->wds) { - c = a; - a = b; - b = c; - } - k = a->k; - wa = a->wds; - wb = b->wds; - wc = wa + wb; - if (wc > a->maxwds) - k++; - c = Balloc(k); - for(x = c->x, xa = x + wc; x < xa; x++) - *x = 0; - xa = a->x; - xae = xa + wa; - xb = b->x; - xbe = xb + wb; - xc0 = c->x; -#ifdef Pack_32 - for(; xb < xbe; xb++, xc0++) { - if ((y = *xb & 0xffff) != 0) { - x = xa; - xc = xc0; - carry = 0; - do { - z = (*x & 0xffff) * y + (*xc & 0xffff) + carry; - carry = z >> 16; - z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; - carry = z2 >> 16; - Storeinc(xc, z2, z); - } - while(x < xae); - *xc = carry; - } - if ((y = *xb >> 16) != 0) { - x = xa; - xc = xc0; - carry = 0; - z2 = *xc; - do { - z = (*x & 0xffff) * y + (*xc >> 16) + carry; - carry = z >> 16; - Storeinc(xc, z, z2); - z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; - carry = z2 >> 16; - } - while(x < xae); - *xc = z2; - } - } -#else - for(; xb < xbe; xc0++) { - if (y = *xb++) { - x = xa; - xc = xc0; - carry = 0; - do { - z = *x++ * y + *xc + carry; - carry = z >> 16; - *xc++ = z & 0xffff; - } - while(x < xae); - *xc = carry; + 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; } - } -#endif - for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ; - c->wds = wc; - return c; -} -static Bigint *p5s; + result->append(out); -struct p5s_deleter -{ - ~p5s_deleter() - { - while (p5s) { - Bigint *next = p5s->next; - Bfree(p5s); - p5s = next; - } + ++idx; } -}; -static Bigint *pow5mult(Bigint *b, int k) -{ - Bigint *b1, *p5, *p51; - int i; - static const int p05[3] = { 5, 25, 125 }; - - if ((i = k & 3) != 0) -#if defined(Q_OS_IRIX) && defined(Q_CC_GNU) - { - // work around a bug on 64 bit IRIX gcc - int *p = (int *) p05; - b = multadd(b, p[i-1], 0); + // Check trailing whitespace + for (; idx < l; ++idx) { + if (!uc[idx].isSpace()) + return false; } -#else - b = multadd(b, p05[i-1], 0); -#endif - if (!(k >>= 2)) - return b; - if (!(p5 = p5s)) { - /* first time */ - static p5s_deleter deleter; - p5 = p5s = i2b(625); - p5->next = 0; - } - for(;;) { - if (k & 1) { - b1 = mult(b, p5); - Bfree(b); - b = b1; - } - if (!(k >>= 1)) - break; - if (!(p51 = p5->next)) { - p51 = p5->next = mult(p5,p5); - p51->next = 0; - } - p5 = p51; - } - return b; -} + result->append('\0'); -static Bigint *lshift(Bigint *b, int k) -{ - int i, k1, n, n1; - Bigint *b1; - ULong *x, *x1, *xe, z; + // Check separators + if (group_sep_mode == ParseGroupSeparators + && !removeGroupSeparators(result)) + return false; -#ifdef Pack_32 - n = k >> 5; -#else - n = k >> 4; -#endif - k1 = b->k; - n1 = n + b->wds + 1; - for(i = b->maxwds; n1 > i; i <<= 1) - k1++; - b1 = Balloc(k1); - x1 = b1->x; - for(i = 0; i < n; i++) - *x1++ = 0; - x = b->x; - xe = x + b->wds; -#ifdef Pack_32 - if (k &= 0x1f) { - k1 = 32 - k; - z = 0; - do { - *x1++ = *x << k | z; - z = *x++ >> k1; - } - while(x < xe); - if ((*x1 = z) != 0) - ++n1; - } -#else - if (k &= 0xf) { - k1 = 16 - k; - z = 0; - do { - *x1++ = *x << k & 0xffff | z; - z = *x++ >> k1; - } - while(x < xe); - if (*x1 = z) - ++n1; - } -#endif - else do - *x1++ = *x++; - while(x < xe); - b1->wds = n1 - 1; - Bfree(b); - return b1; -} -static int cmp(Bigint *a, Bigint *b) -{ - ULong *xa, *xa0, *xb, *xb0; - int i, j; - - i = a->wds; - j = b->wds; -#ifdef BSD_QDTOA_DEBUG - if (i > 1 && !a->x[i-1]) - Bug("cmp called with a->x[a->wds-1] == 0"); - if (j > 1 && !b->x[j-1]) - Bug("cmp called with b->x[b->wds-1] == 0"); -#endif - if (i -= j) - return i; - xa0 = a->x; - xa = xa0 + j; - xb0 = b->x; - xb = xb0 + j; - for(;;) { - if (*--xa != *--xb) - return *xa < *xb ? -1 : 1; - if (xa <= xa0) - break; - } - return 0; + return true; } -static Bigint *diff(Bigint *a, Bigint *b) +bool QLocalePrivate::validateChars(const QString &str, NumberMode numMode, QByteArray *buff, + int decDigits) const { - Bigint *c; - int i, wa, wb; - Long borrow, y; /* We need signed shifts here. */ - ULong *xa, *xae, *xb, *xbe, *xc; -#ifdef Pack_32 - Long z; -#endif + buff->clear(); + buff->reserve(str.length()); - i = cmp(a,b); - if (!i) { - c = Balloc(0); - c->wds = 1; - c->x[0] = 0; - return c; - } - if (i < 0) { - c = a; - a = b; - b = c; - i = 1; - } - else - i = 0; - c = Balloc(a->k); - c->sign = i; - wa = a->wds; - xa = a->x; - xae = xa + wa; - wb = b->wds; - xb = b->x; - xbe = xb + wb; - xc = c->x; - borrow = 0; -#ifdef Pack_32 - do { - y = (*xa & 0xffff) - (*xb & 0xffff) + borrow; - borrow = y >> 16; - Sign_Extend(borrow, y); - z = (*xa++ >> 16) - (*xb++ >> 16) + borrow; - borrow = z >> 16; - Sign_Extend(borrow, z); - Storeinc(xc, z, y); - } - while(xb < xbe); - while(xa < xae) { - y = (*xa & 0xffff) + borrow; - borrow = y >> 16; - Sign_Extend(borrow, y); - z = (*xa++ >> 16) + borrow; - borrow = z >> 16; - Sign_Extend(borrow, z); - Storeinc(xc, z, y); - } -#else - do { - y = *xa++ - *xb++ + borrow; - borrow = y >> 16; - Sign_Extend(borrow, y); - *xc++ = y & 0xffff; - } - while(xb < xbe); - while(xa < xae) { - y = *xa++ + borrow; - borrow = y >> 16; - Sign_Extend(borrow, y); - *xc++ = y & 0xffff; - } -#endif - while(!*--xc) - wa--; - c->wds = wa; - return c; -} + const bool scientific = numMode == DoubleScientificMode; + bool lastWasE = false; + bool lastWasDigit = false; + int eCnt = 0; + int decPointCnt = 0; + bool dec = false; + int decDigitCnt = 0; -static double ulp(double x) -{ - Long L; - double a; + for (int i = 0; i < str.length(); ++i) { + char c = digitToCLocale(str.at(i)); - L = (getWord0(x) & Exp_mask) - (P-1)*Exp_msk1; -#ifndef Sudden_Underflow - if (L > 0) { -#endif -#ifdef IBM - L |= Exp_msk1 >> 4; -#endif - setWord0(&a, L); - setWord1(&a, 0); -#ifndef Sudden_Underflow - } - else { - L = -L >> Exp_shift; - if (L < Exp_shift) { - setWord0(&a, 0x80000 >> L); - setWord1(&a, 0); - } - else { - setWord0(&a, 0); - L -= Exp_shift; - setWord1(&a, L >= 31 ? 1U : 1U << (31 - L)); - } - } -#endif - return a; -} + 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. -static double b2d(Bigint *a, int *e) -{ - ULong *xa, *xa0, w, y, z; - int k; - double d; - - xa0 = a->x; - xa = xa0 + a->wds; - y = *--xa; -#ifdef BSD_QDTOA_DEBUG - if (!y) Bug("zero y in b2d"); -#endif - k = hi0bits(y); - *e = 32 - k; -#ifdef Pack_32 - if (k < Ebits) { - setWord0(&d, Exp_1 | y >> (Ebits - k)); - w = xa > xa0 ? *--xa : 0; - setWord1(&d, y << ((32-Ebits) + k) | w >> (Ebits - k)); - goto ret_d; - } - z = xa > xa0 ? *--xa : 0; - if (k -= Ebits) { - setWord0(&d, Exp_1 | y << k | z >> (32 - k)); - y = xa > xa0 ? *--xa : 0; - setWord1(&d, z << k | y >> (32 - k)); - } - else { - setWord0(&d, Exp_1 | y); - setWord1(&d, z); - } -#else - if (k < Ebits + 16) { - z = xa > xa0 ? *--xa : 0; - setWord0(&d, Exp_1 | y << k - Ebits | z >> Ebits + 16 - k); - w = xa > xa0 ? *--xa : 0; - y = xa > xa0 ? *--xa : 0; - setWord1(&d, z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k); - goto ret_d; - } - z = xa > xa0 ? *--xa : 0; - w = xa > xa0 ? *--xa : 0; - k -= Ebits + 16; - setWord0(&d, Exp_1 | y << k + 16 | z << k | w >> 16 - k); - y = xa > xa0 ? *--xa : 0; - setWord1(&d, w << k + 16 | y << k); -#endif - ret_d: - return d; -} + dec = true; + } + break; -static Bigint *d2b(double d, int *e, int *bits) -{ - Bigint *b; - int de, i, k; - ULong *x, y, z; + 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; -#ifdef Pack_32 - b = Balloc(1); -#else - b = Balloc(2); -#endif - x = b->x; - - z = getWord0(d) & Frac_mask; - setWord0(&d, getWord0(d) & 0x7fffffff); /* clear sign bit, which we ignore */ -#ifdef Sudden_Underflow - de = (int)(getWord0(d) >> Exp_shift); -#ifndef IBM - z |= Exp_msk11; -#endif -#else - if ((de = int(getWord0(d) >> Exp_shift)) != 0) - z |= Exp_msk1; -#endif -#ifdef Pack_32 - if ((y = getWord1(d)) != 0) { - if ((k = lo0bits(&y)) != 0) { - x[0] = y | z << (32 - k); - z >>= k; - } - else - x[0] = y; - i = b->wds = (x[1] = z) ? 2 : 1; - } - else { -#ifdef BSD_QDTOA_DEBUG - if (!z) - Bug("Zero passed to d2b"); -#endif - k = lo0bits(&z); - x[0] = z; - i = b->wds = 1; - k += 32; - } -#else - if (y = getWord1(d)) { - if (k = lo0bits(&y)) - if (k >= 16) { - x[0] = y | z << 32 - k & 0xffff; - x[1] = z >> k - 16 & 0xffff; - x[2] = z >> k; - i = 2; - } - else { - x[0] = y & 0xffff; - x[1] = y >> 16 | z << 16 - k & 0xffff; - x[2] = z >> k & 0xffff; - x[3] = z >> k+16; - i = 3; + 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; } - else { - x[0] = y & 0xffff; - x[1] = y >> 16; - x[2] = z & 0xffff; - x[3] = z >> 16; - i = 3; - } - } - else { -#ifdef BSD_QDTOA_DEBUG - if (!z) - Bug("Zero passed to d2b"); -#endif - k = lo0bits(&z); - if (k >= 16) { - x[0] = z; - i = 0; - } - else { - x[0] = z & 0xffff; - x[1] = z >> 16; - i = 1; + lastWasDigit = false; } - k += 32; - } - while(!x[i]) - --i; - b->wds = i + 1; -#endif -#ifndef Sudden_Underflow - if (de) { -#endif -#ifdef IBM - *e = (de - Bias - (P-1) << 2) + k; - *bits = 4*P + 8 - k - hi0bits(getWord0(d) & Frac_mask); -#else - *e = de - Bias - (P-1) + k; - *bits = P - k; -#endif -#ifndef Sudden_Underflow - } - else { - *e = de - Bias - (P-1) + 1 + k; -#ifdef Pack_32 - *bits = 32*i - hi0bits(x[i-1]); -#else - *bits = (i+2)*16 - hi0bits(x[i]); -#endif + + lastWasE = c == 'e'; + if (c != ',') + buff->append(c); } -#endif - return b; + + return true; } -static double ratio(Bigint *a, Bigint *b) +double QLocalePrivate::stringToDouble(const QString &number, bool *ok, + GroupSeparatorMode group_sep_mode) const { - double da, db; - int k, ka, kb; - - da = b2d(a, &ka); - db = b2d(b, &kb); -#ifdef Pack_32 - k = ka - kb + 32*(a->wds - b->wds); -#else - k = ka - kb + 16*(a->wds - b->wds); -#endif -#ifdef IBM - if (k > 0) { - setWord0(&da, getWord0(da) + (k >> 2)*Exp_msk1); - if (k &= 3) - da *= 1 << k; - } - else { - k = -k; - setWord0(&db, getWord0(db) + (k >> 2)*Exp_msk1); - if (k &= 3) - db *= 1 << k; - } -#else - if (k > 0) - setWord0(&da, getWord0(da) + k*Exp_msk1); - else { - k = -k; - setWord0(&db, getWord0(db) + k*Exp_msk1); + CharBuff buff; + if (!numberToCLocale(group().unicode() == 0xa0 ? number.trimmed() : number, + group_sep_mode, &buff)) { + if (ok != 0) + *ok = false; + return 0.0; } -#endif - return da / db; + return bytearrayToDouble(buff.constData(), ok); } -static const double tens[] = { - 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, - 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, - 1e20, 1e21, 1e22 -#ifdef VAX - , 1e23, 1e24 -#endif -}; +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; + } -#ifdef IEEE_Arith -static const double bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; -static const double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, 1e-256 }; -#define n_bigtens 5 -#else -#ifdef IBM -static const double bigtens[] = { 1e16, 1e32, 1e64 }; -static const double tinytens[] = { 1e-16, 1e-32, 1e-64 }; -#define n_bigtens 3 -#else -static const double bigtens[] = { 1e16, 1e32 }; -static const double tinytens[] = { 1e-16, 1e-32 }; -#define n_bigtens 2 -#endif -#endif + return bytearrayToLongLong(buff.constData(), base, ok); +} -/* - The pre-release gcc3.3 shipped with SuSE 8.2 has a bug which causes - the comparison 1e-100 == 0.0 to return true. As a workaround, we - compare it to a global variable containing 0.0, which produces - correct assembler output. +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); +} - ### consider detecting the broken compilers and using the static - ### double for these, and use a #define for all working compilers -*/ -static double g_double_zero = 0.0; -Q_CORE_EXPORT double qstrtod(const char *s00, const char **se, bool *ok) +double QLocalePrivate::bytearrayToDouble(const char *num, bool *ok, bool *overflow) { - int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign, - e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign; - const char *s, *s0, *s1; - double aadj, aadj1, adj, rv, rv0; - Long L; - ULong y, z; - Bigint *bb1, *bd0; - Bigint *bb = NULL, *bd = NULL, *bs = NULL, *delta = NULL;/* pacify gcc */ - - /* - #ifndef KR_headers - const char decimal_point = localeconv()->decimal_point[0]; - #else - const char decimal_point = '.'; - #endif */ if (ok != 0) *ok = true; + if (overflow != 0) + *overflow = false; - const char decimal_point = '.'; - - sign = nz0 = nz = 0; - rv = 0.; - + if (*num == '\0') { + if (ok != 0) + *ok = false; + return 0.0; + } - for(s = s00; isspace(uchar(*s)); s++) - ; + if (qstrcmp(num, "nan") == 0) + return qt_snan(); - if (*s == '-') { - sign = 1; - s++; - } else if (*s == '+') { - s++; - } + if (qstrcmp(num, "+inf") == 0 || qstrcmp(num, "inf") == 0) + return qt_inf(); - if (*s == '\0') { - s = s00; - goto ret; - } + if (qstrcmp(num, "-inf") == 0) + return -qt_inf(); - if (*s == '0') { - nz0 = 1; - while(*++s == '0') ; - if (!*s) - goto ret; - } - s0 = s; - y = z = 0; - for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) - if (nd < 9) - y = 10*y + c - '0'; - else if (nd < 16) - z = 10*z + c - '0'; - nd0 = nd; - if (c == decimal_point) { - c = *++s; - if (!nd) { - for(; c == '0'; c = *++s) - nz++; - if (c > '0' && c <= '9') { - s0 = s; - nf += nz; - nz = 0; - goto have_dig; - } - goto dig_done; - } - for(; c >= '0' && c <= '9'; c = *++s) { - have_dig: - nz++; - if (c -= '0') { - nf += nz; - for(i = 1; i < nz; i++) - if (nd++ < 9) - y *= 10; - else if (nd <= DBL_DIG + 1) - z *= 10; - if (nd++ < 9) - y = 10*y + c; - else if (nd <= DBL_DIG + 1) - z = 10*z + c; - nz = 0; - } - } - } - dig_done: - e = 0; - if (c == 'e' || c == 'E') { - if (!nd && !nz && !nz0) { - s = s00; - goto ret; - } - s00 = s; - esign = 0; - switch(c = *++s) { - case '-': - esign = 1; - case '+': - c = *++s; - } - if (c >= '0' && c <= '9') { - while(c == '0') - c = *++s; - if (c > '0' && c <= '9') { - L = c - '0'; - s1 = s; - while((c = *++s) >= '0' && c <= '9') - L = 10*L + c - '0'; - if (s - s1 > 8 || L > 19999) - /* Avoid confusion from exponents - * so large that e might overflow. - */ - e = 19999; /* safe for 16 bit ints */ - else - e = int(L); - if (esign) - e = -e; - } - else - e = 0; - } - else - s = s00; - } - if (!nd) { - if (!nz && !nz0) - s = s00; - goto ret; - } - e1 = e -= nf; - - /* Now we have nd0 digits, starting at s0, followed by a - * decimal point, followed by nd-nd0 digits. The number we're - * after is the integer represented by those digits times - * 10**e */ - - if (!nd0) - nd0 = nd; - k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; - rv = y; - if (k > 9) -#if defined(Q_OS_IRIX) && defined(Q_CC_GNU) - { - // work around a bug on 64 bit IRIX gcc - double *t = (double *) tens; - rv = t[k - 9] * rv + z; - } -#else - rv = tens[k - 9] * rv + z; -#endif + bool _ok; + const char *endptr; + double d = qstrtod(num, &endptr, &_ok); - bd0 = 0; - if (nd <= DBL_DIG -#ifndef RND_PRODQUOT - && FLT_ROUNDS == 1 -#endif - ) { - if (!e) - goto ret; - if (e > 0) { - if (e <= Ten_pmax) { -#ifdef VAX - goto vax_ovfl_check; -#else - /* rv = */ rounded_product(rv, tens[e]); - goto ret; -#endif - } - i = DBL_DIG - nd; - if (e <= Ten_pmax + i) { - /* A fancier test would sometimes let us do - * this for larger i values. - */ - e -= i; - rv *= tens[i]; -#ifdef VAX - /* VAX exponent range is so narrow we must - * worry about overflow here... - */ - vax_ovfl_check: - setWord0(&rv, getWord0(rv) - P*Exp_msk1); - /* rv = */ rounded_product(rv, tens[e]); - if ((getWord0(rv) & Exp_mask) - > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) - goto ovfl; - setWord0(&rv, getWord0(rv) + P*Exp_msk1); -#else - /* rv = */ rounded_product(rv, tens[e]); -#endif - goto ret; - } - } -#ifndef Inaccurate_Divide - else if (e >= -Ten_pmax) { - /* rv = */ rounded_quotient(rv, tens[-e]); - goto ret; - } -#endif + 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; } - e1 += nd - k; - - /* Get starting approximation = rv * 10**e1 */ - - if (e1 > 0) { - if ((i = e1 & 15) != 0) - rv *= tens[i]; - if (e1 &= ~15) { - if (e1 > DBL_MAX_10_EXP) { - ovfl: - // errno = ERANGE; - if (ok != 0) - *ok = false; -#ifdef __STDC__ - rv = HUGE_VAL; -#else - /* Can't trust HUGE_VAL */ -#ifdef IEEE_Arith - setWord0(&rv, Exp_mask); - setWord1(&rv, 0); -#else - setWord0(&rv, Big0); - setWord1(&rv, Big1); -#endif -#endif - if (bd0) - goto retfree; - goto ret; - } - if (e1 >>= 4) { - for(j = 0; e1 > 1; j++, e1 >>= 1) - if (e1 & 1) - rv *= bigtens[j]; - /* The last multiplication could overflow. */ - setWord0(&rv, getWord0(rv) - P*Exp_msk1); - rv *= bigtens[j]; - if ((z = getWord0(rv) & Exp_mask) - > Exp_msk1*(DBL_MAX_EXP+Bias-P)) - goto ovfl; - if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) { - /* set to largest number */ - /* (Can't trust DBL_MAX) */ - setWord0(&rv, Big0); - setWord1(&rv, Big1); - } - else - setWord0(&rv, getWord0(rv) + P*Exp_msk1); - } - } - } - else if (e1 < 0) { - e1 = -e1; - if ((i = e1 & 15) != 0) - rv /= tens[i]; - if (e1 &= ~15) { - e1 >>= 4; - if (e1 >= 1 << n_bigtens) - goto undfl; - for(j = 0; e1 > 1; j++, e1 >>= 1) - if (e1 & 1) - rv *= tinytens[j]; - /* The last multiplication could underflow. */ - rv0 = rv; - rv *= tinytens[j]; - if (rv == g_double_zero) - { - rv = 2.*rv0; - rv *= tinytens[j]; - if (rv == g_double_zero) - { - undfl: - rv = 0.; - // errno = ERANGE; - if (ok != 0) - *ok = false; - if (bd0) - goto retfree; - goto ret; - } - setWord0(&rv, Tiny0); - setWord1(&rv, Tiny1); - /* The refinement below will clean - * this approximation up. - */ - } - } + 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; } - /* Now the hard part -- adjusting rv to the correct value.*/ - - /* Put digits into bd: true value = bd * 10^e */ + if (ok != 0) + *ok = true; + if (overflow != 0) + *overflow = false; + return d; +} - bd0 = s2b(s0, nd0, nd, y); +qlonglong QLocalePrivate::bytearrayToLongLong(const char *num, int base, bool *ok, bool *overflow) +{ + bool _ok; + const char *endptr; - for(;;) { - bd = Balloc(bd0->k); - Bcopy(bd, bd0); - bb = d2b(rv, &bbe, &bbbits); /* rv = bb * 2^bbe */ - bs = i2b(1); + if (*num == '\0') { + if (ok != 0) + *ok = false; + if (overflow != 0) + *overflow = false; + return 0; + } - if (e >= 0) { - bb2 = bb5 = 0; - bd2 = bd5 = e; - } - else { - bb2 = bb5 = -e; - bd2 = bd5 = 0; - } - if (bbe >= 0) - bb2 += bbe; - else - bd2 -= bbe; - bs2 = bb2; -#ifdef Sudden_Underflow -#ifdef IBM - j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3); -#else - j = P + 1 - bbbits; -#endif -#else - i = bbe + bbbits - 1; /* logb(rv) */ - if (i < Emin) /* denormal */ - j = bbe + (P-Emin); - else - j = P + 1 - bbbits; -#endif - bb2 += j; - bd2 += j; - i = bb2 < bd2 ? bb2 : bd2; - if (i > bs2) - i = bs2; - if (i > 0) { - bb2 -= i; - bd2 -= i; - bs2 -= i; - } - if (bb5 > 0) { - bs = pow5mult(bs, bb5); - bb1 = mult(bs, bb); - Bfree(bb); - bb = bb1; - } - if (bb2 > 0) - bb = lshift(bb, bb2); - if (bd5 > 0) - bd = pow5mult(bd, bd5); - if (bd2 > 0) - bd = lshift(bd, bd2); - if (bs2 > 0) - bs = lshift(bs, bs2); - delta = diff(bb, bd); - dsign = delta->sign; - delta->sign = 0; - i = cmp(delta, bs); - if (i < 0) { - /* Error is less than half an ulp -- check for - * special case of mantissa a power of two. - */ - if (dsign || getWord1(rv) || getWord0(rv) & Bndry_mask) - break; - delta = lshift(delta,Log2P); - if (cmp(delta, bs) > 0) - goto drop_down; - break; - } - if (i == 0) { - /* exactly half-way between */ - if (dsign) { - if ((getWord0(rv) & Bndry_mask1) == Bndry_mask1 - && getWord1(rv) == 0xffffffff) { - /*boundary case -- increment exponent*/ - setWord0(&rv, (getWord0(rv) & Exp_mask) - + Exp_msk1 -#ifdef IBM - | Exp_msk1 >> 4 -#endif - ); - setWord1(&rv, 0); - break; - } - } - else if (!(getWord0(rv) & Bndry_mask) && !getWord1(rv)) { - drop_down: - /* boundary case -- decrement exponent */ -#ifdef Sudden_Underflow - L = getWord0(rv) & Exp_mask; -#ifdef IBM - if (L < Exp_msk1) -#else - if (L <= Exp_msk1) -#endif - goto undfl; - L -= Exp_msk1; -#else - L = (getWord0(rv) & Exp_mask) - Exp_msk1; -#endif - setWord0(&rv, L | Bndry_mask1); - setWord1(&rv, 0xffffffff); -#ifdef IBM - goto cont; -#else - break; -#endif - } -#ifndef ROUND_BIASED - if (!(getWord1(rv) & LSB)) - break; -#endif - if (dsign) - rv += ulp(rv); -#ifndef ROUND_BIASED - else { - rv -= ulp(rv); -#ifndef Sudden_Underflow - if (rv == g_double_zero) - goto undfl; -#endif - } -#endif - break; - } - if ((aadj = ratio(delta, bs)) <= 2.) { - if (dsign) - aadj = aadj1 = 1.; - else if (getWord1(rv) || getWord0(rv) & Bndry_mask) { -#ifndef Sudden_Underflow - if (getWord1(rv) == Tiny1 && !getWord0(rv)) - goto undfl; -#endif - aadj = 1.; - aadj1 = -1.; - } - else { - /* special case -- power of FLT_RADIX to be */ - /* rounded down... */ + qlonglong l = qstrtoll(num, &endptr, base, &_ok); - if (aadj < 2./FLT_RADIX) - aadj = 1./FLT_RADIX; - else - aadj *= 0.5; - aadj1 = -aadj; - } - } - else { - aadj *= 0.5; - aadj1 = dsign ? aadj : -aadj; -#ifdef Check_FLT_ROUNDS - switch(FLT_ROUNDS) { - case 2: /* towards +infinity */ - aadj1 -= 0.5; - break; - case 0: /* towards 0 */ - case 3: /* towards -infinity */ - aadj1 += 0.5; - } -#else - if (FLT_ROUNDS == 0) - aadj1 += 0.5; -#endif - } - y = getWord0(rv) & Exp_mask; - - /* Check for overflow */ - - if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) { - rv0 = rv; - setWord0(&rv, getWord0(rv) - P*Exp_msk1); - adj = aadj1 * ulp(rv); - rv += adj; - if ((getWord0(rv) & Exp_mask) >= - Exp_msk1*(DBL_MAX_EXP+Bias-P)) { - if (getWord0(rv0) == Big0 && getWord1(rv0) == Big1) - goto ovfl; - setWord0(&rv, Big0); - setWord1(&rv, Big1); - goto cont; - } - else - setWord0(&rv, getWord0(rv) + P*Exp_msk1); - } - else { -#ifdef Sudden_Underflow - if ((getWord0(rv) & Exp_mask) <= P*Exp_msk1) { - rv0 = rv; - setWord0(&rv, getWord0(rv) + P*Exp_msk1); - adj = aadj1 * ulp(rv); - rv += adj; -#ifdef IBM - if ((getWord0(rv) & Exp_mask) < P*Exp_msk1) -#else - if ((getWord0(rv) & Exp_mask) <= P*Exp_msk1) -#endif - { - if (getWord0(rv0) == Tiny0 - && getWord1(rv0) == Tiny1) - goto undfl; - setWord0(&rv, Tiny0); - setWord1(&rv, Tiny1); - goto cont; - } - else - setWord0(&rv, getWord0(rv) - P*Exp_msk1); - } - else { - adj = aadj1 * ulp(rv); - rv += adj; - } -#else - /* Compute adj so that the IEEE rounding rules will - * correctly round rv + adj in some half-way cases. - * If rv * ulp(rv) is denormalized (i.e., - * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid - * trouble from bits lost to denormalization; - * example: 1.2e-307 . - */ - if (y <= (P-1)*Exp_msk1 && aadj >= 1.) { - aadj1 = int(aadj + 0.5); - if (!dsign) - aadj1 = -aadj1; - } - adj = aadj1 * ulp(rv); - rv += adj; -#endif - } - z = getWord0(rv) & Exp_mask; - if (y == z) { - /* Can we stop now? */ - L = Long(aadj); - aadj -= L; - /* The tolerances below are conservative. */ - if (dsign || getWord1(rv) || getWord0(rv) & Bndry_mask) { - if (aadj < .4999999 || aadj > .5000001) - break; - } - else if (aadj < .4999999/FLT_RADIX) - break; + 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'; } - cont: - Bfree(bb); - Bfree(bd); - Bfree(bs); - Bfree(delta); + return 0; } - retfree: - Bfree(bb); - Bfree(bd); - Bfree(bs); - Bfree(bd0); - Bfree(delta); - ret: - if (se) - *se = s; - return sign ? -rv : rv; -} - -static int quorem(Bigint *b, Bigint *S) -{ - int n; - Long borrow, y; - ULong carry, q, ys; - ULong *bx, *bxe, *sx, *sxe; -#ifdef Pack_32 - Long z; - ULong si, zs; -#endif - n = S->wds; -#ifdef BSD_QDTOA_DEBUG - /*debug*/ if (b->wds > n) - /*debug*/ Bug("oversize b in quorem"); -#endif - if (b->wds < n) + 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; - sx = S->x; - sxe = sx + --n; - bx = b->x; - bxe = bx + n; - q = *bxe / (*sxe + 1); /* ensure q <= true quotient */ -#ifdef BSD_QDTOA_DEBUG - /*debug*/ if (q > 9) - /*debug*/ Bug("oversized quotient in quorem"); -#endif - if (q) { - borrow = 0; - carry = 0; - do { -#ifdef Pack_32 - si = *sx++; - ys = (si & 0xffff) * q + carry; - zs = (si >> 16) * q + (ys >> 16); - carry = zs >> 16; - y = (*bx & 0xffff) - (ys & 0xffff) + borrow; - borrow = y >> 16; - Sign_Extend(borrow, y); - z = (*bx >> 16) - (zs & 0xffff) + borrow; - borrow = z >> 16; - Sign_Extend(borrow, z); - Storeinc(bx, z, y); -#else - ys = *sx++ * q + carry; - carry = ys >> 16; - y = *bx - (ys & 0xffff) + borrow; - borrow = y >> 16; - Sign_Extend(borrow, y); - *bx++ = y & 0xffff; -#endif - } - while(sx <= sxe); - if (!*bxe) { - bx = b->x; - while(--bxe > bx && !*bxe) - --n; - b->wds = n; - } - } - if (cmp(b, S) >= 0) { - q++; - borrow = 0; - carry = 0; - bx = b->x; - sx = S->x; - do { -#ifdef Pack_32 - si = *sx++; - ys = (si & 0xffff) + carry; - zs = (si >> 16) + (ys >> 16); - carry = zs >> 16; - y = (*bx & 0xffff) - (ys & 0xffff) + borrow; - borrow = y >> 16; - Sign_Extend(borrow, y); - z = (*bx >> 16) - (zs & 0xffff) + borrow; - borrow = z >> 16; - Sign_Extend(borrow, z); - Storeinc(bx, z, y); -#else - ys = *sx++ + carry; - carry = ys >> 16; - y = *bx - (ys & 0xffff) + borrow; - borrow = y >> 16; - Sign_Extend(borrow, y); - *bx++ = y & 0xffff; -#endif - } - while(sx <= sxe); - bx = b->x; - bxe = bx + n; - if (!*bxe) { - while(--bxe > bx && !*bxe) - --n; - b->wds = n; - } } - return q; + + if (ok != 0) + *ok = true; + if (overflow != 0) + *overflow = false; + return l; } -/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. - * - * Inspired by "How to Print Floating-Point Numbers Accurately" by - * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 92-101]. - * - * Modifications: - * 1. Rather than iterating, we use a simple numeric overestimate - * to determine k = floor(log10(d)). We scale relevant - * quantities using O(log2(k)) rather than O(k) multiplications. - * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't - * try to generate digits strictly left to right. Instead, we - * compute with fewer bits and propagate the carry if necessary - * when rounding the final digit up. This is often faster. - * 3. Under the assumption that input will be rounded nearest, - * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22. - * That is, we allow equality in stopping tests when the - * round-nearest rule will give the same floating-point value - * as would satisfaction of the stopping test with strict - * inequality. - * 4. We remove common factors of powers of 2 from relevant - * quantities. - * 5. When converting floating-point integers less than 1e16, - * we use floating-point arithmetic rather than resorting - * to multiple-precision integers. - * 6. When asked to produce fewer than 15 digits, we first try - * to get by with floating-point arithmetic; we resort to - * multiple-precision integer arithmetic only if we cannot - * guarantee that the floating-point calculation has given - * the correctly rounded result. For k requested digits and - * "uniformly" distributed input, the probability is - * something like 10^(k-15) that we must resort to the Long - * calculation. - */ - - -/* This actually sometimes returns a pointer to a string literal - cast to a char*. Do NOT try to modify the return value. */ - -Q_CORE_EXPORT char *qdtoa ( double d, int mode, int ndigits, int *decpt, int *sign, char **rve, char **resultp) +qulonglong QLocalePrivate::bytearrayToUnsLongLong(const char *num, int base, bool *ok) { - // Some values of the floating-point control word can cause _qdtoa to crash with an underflow. - // We set a safe value here. -#ifdef Q_OS_WIN - _clear87(); - unsigned int oldbits = _control87(0, 0); -#ifndef MCW_EM -# ifdef _MCW_EM -# define MCW_EM _MCW_EM -# else -# define MCW_EM 0x0008001F -# endif -#endif - _control87(MCW_EM, MCW_EM); -#endif - -#if defined(__GLIBC__) && !defined(__UCLIBC__) - fenv_t envp; - feholdexcept(&envp); -#endif - - char *s = _qdtoa(d, mode, ndigits, decpt, sign, rve, resultp); - -#ifdef Q_OS_WIN - _clear87(); -#ifndef _M_X64 - _control87(oldbits, 0xFFFFF); -#else - _control87(oldbits, _MCW_EM|_MCW_DN|_MCW_RC); -#endif //_M_X64 -#endif //Q_OS_WIN + bool _ok; + const char *endptr; + qulonglong l = qstrtoull(num, &endptr, base, &_ok); -#if defined(__GLIBC__) && !defined(__UCLIBC__) - fesetenv(&envp); -#endif + if (!_ok || *endptr != '\0') { + if (ok != 0) + *ok = false; + return 0; + } - return s; + if (ok != 0) + *ok = true; + return l; } -static char *_qdtoa( NEEDS_VOLATILE double d, int mode, int ndigits, int *decpt, int *sign, char **rve, char **resultp) -{ - /* - Arguments ndigits, decpt, sign are similar to those - of ecvt and fcvt; trailing zeros are suppressed from - the returned string. If not null, *rve is set to point - to the end of the return value. If d is +-Infinity or NaN, - then *decpt is set to 9999. - - mode: - 0 ==> shortest string that yields d when read in - and rounded to nearest. - 1 ==> like 0, but with Steele & White stopping rule; - e.g. with IEEE P754 arithmetic , mode 0 gives - 1e23 whereas mode 1 gives 9.999999999999999e22. - 2 ==> max(1,ndigits) significant digits. This gives a - return value similar to that of ecvt, except - that trailing zeros are suppressed. - 3 ==> through ndigits past the decimal point. This - gives a return value similar to that from fcvt, - except that trailing zeros are suppressed, and - ndigits can be negative. - 4-9 should give the same return values as 2-3, i.e., - 4 <= mode <= 9 ==> same return as mode - 2 + (mode & 1). These modes are mainly for - debugging; often they run slower but sometimes - faster than modes 2-3. - 4,5,8,9 ==> left-to-right digit generation. - 6-9 ==> don't try fast floating-point estimate - (if applicable). - - Values of mode other than 0-9 are treated as mode 0. - - Sufficient space is allocated to the return value - to hold the suppressed trailing zeros. - */ - - int bbits, b2, b5, be, dig, i, ieps, ilim0, - j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, - try_quick; - int ilim = 0, ilim1 = 0, spec_case = 0; /* pacify gcc */ - Long L; -#ifndef Sudden_Underflow - int denorm; - ULong x; -#endif - Bigint *b, *b1, *delta, *mhi, *S; - Bigint *mlo = NULL; /* pacify gcc */ - double d2; - double ds, eps; - char *s, *s0; - - if (getWord0(d) & Sign_bit) { - /* set sign for everything, including 0's and NaNs */ - *sign = 1; - setWord0(&d, getWord0(d) & ~Sign_bit); /* clear sign bit */ - } - else - *sign = 0; +/*! + \since 4.8 -#if defined(IEEE_Arith) + defined(VAX) -#ifdef IEEE_Arith - if ((getWord0(d) & Exp_mask) == Exp_mask) -#else - if (getWord0(d) == 0x8000) -#endif - { - /* Infinity or NaN */ - *decpt = 9999; - s = -#ifdef IEEE_Arith - !getWord1(d) && !(getWord0(d) & 0xfffff) ? const_cast("Infinity") : -#endif - const_cast("NaN"); - if (rve) - *rve = -#ifdef IEEE_Arith - s[3] ? s + 8 : -#endif - s + 3; - return s; - } -#endif -#ifdef IBM - d += 0; /* normalize */ -#endif - if (d == g_double_zero) - { - *decpt = 1; - s = const_cast("0"); - if (rve) - *rve = s + 1; - return s; - } + \enum QLocale::CurrencyFormat - b = d2b(d, &be, &bbits); -#ifdef Sudden_Underflow - i = (int)(getWord0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); -#else - if ((i = int(getWord0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1))) != 0) { -#endif - d2 = d; - setWord0(&d2, getWord0(d2) & Frac_mask1); - setWord0(&d2, getWord0(d2) | Exp_11); -#ifdef IBM - if (j = 11 - hi0bits(getWord0(d2) & Frac_mask)) - d2 /= 1 << j; -#endif + Specifies the format of the currency symbol. - /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 - * log10(x) = log(x) / log(10) - * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) - * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2) - * - * This suggests computing an approximation k to log10(d) by - * - * k = (i - Bias)*0.301029995663981 - * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); - * - * We want k to be too large rather than too small. - * The error in the first-order Taylor series approximation - * is in our favor, so we just round up the constant enough - * to compensate for any error in the multiplication of - * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, - * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, - * adding 1e-13 to the constant term more than suffices. - * Hence we adjust the constant term to 0.1760912590558. - * (We could get a more accurate k by invoking log10, - * but this is probably not worthwhile.) - */ - - i -= Bias; -#ifdef IBM - i <<= 2; - i += j; -#endif -#ifndef Sudden_Underflow - denorm = 0; - } - else { - /* d is denormalized */ - - i = bbits + be + (Bias + (P-1) - 1); - x = i > 32 ? getWord0(d) << (64 - i) | getWord1(d) >> (i - 32) - : getWord1(d) << (32 - i); - d2 = x; - setWord0(&d2, getWord0(d2) - 31*Exp_msk1); /* adjust exponent */ - i -= (Bias + (P-1) - 1) + 1; - denorm = 1; + \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 - ds = (d2-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; - k = int(ds); - if (ds < 0. && ds != k) - k--; /* want k = floor(ds) */ - k_check = 1; - if (k >= 0 && k <= Ten_pmax) { - if (d < tens[k]) - k--; - k_check = 0; - } - j = bbits - i - 1; - if (j >= 0) { - b2 = 0; - s2 = j; - } - else { - b2 = -j; - s2 = 0; - } - if (k >= 0) { - b5 = 0; - s5 = k; - s2 += k; - } - else { - b2 -= k; - b5 = -k; - s5 = 0; - } - if (mode < 0 || mode > 9) - mode = 0; - try_quick = 1; - if (mode > 5) { - mode -= 4; - try_quick = 0; - } - leftright = 1; - switch(mode) { - case 0: - case 1: - ilim = ilim1 = -1; - i = 18; - ndigits = 0; - break; - case 2: - leftright = 0; - /* no break */ - case 4: - if (ndigits <= 0) - ndigits = 1; - ilim = ilim1 = i = ndigits; - break; - case 3: - leftright = 0; - /* no break */ - case 5: - i = ndigits + k + 1; - ilim = i; - ilim1 = i - 1; - if (i <= 0) - i = 1; - } - QT_TRY { - *resultp = static_cast(malloc(i + 1)); - Q_CHECK_PTR(*resultp); - } QT_CATCH(...) { - Bfree(b); - QT_RETHROW; + 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(); } - s = s0 = *resultp; - - if (ilim >= 0 && ilim <= Quick_max && try_quick) { - - /* Try to get by with floating-point arithmetic. */ - - i = 0; - d2 = d; - k0 = k; - ilim0 = ilim; - ieps = 2; /* conservative */ - if (k > 0) { - ds = tens[k&0xf]; - j = k >> 4; - if (j & Bletch) { - /* prevent overflows */ - j &= Bletch - 1; - d /= bigtens[n_bigtens-1]; - ieps++; - } - for(; j; j >>= 1, i++) - if (j & 1) { - ieps++; - ds *= bigtens[i]; - } - d /= ds; - } - else if ((j1 = -k) != 0) { - d *= tens[j1 & 0xf]; - for(j = j1 >> 4; j; j >>= 1, i++) - if (j & 1) { - ieps++; - d *= bigtens[i]; - } - } - if (k_check && d < 1. && ilim > 0) { - if (ilim1 <= 0) - goto fast_failed; - ilim = ilim1; - k--; - d *= 10.; - ieps++; - } - eps = ieps*d + 7.; - setWord0(&eps, getWord0(eps) - (P-1)*Exp_msk1); - if (ilim == 0) { - S = mhi = 0; - d -= 5.; - if (d > eps) - goto one_digit; - if (d < -eps) - goto no_digits; - goto fast_failed; - } -#ifndef No_leftright - if (leftright) { - /* Use Steele & White method of only - * generating digits needed. - */ - eps = 0.5/tens[ilim-1] - eps; - for(i = 0;;) { - L = Long(d); - d -= L; - *s++ = '0' + int(L); - if (d < eps) - goto ret1; - if (1. - d < eps) - goto bump_up; - if (++i >= ilim) - break; - eps *= 10.; - d *= 10.; - } - } - else { -#endif - /* Generate ilim digits, then fix them up. */ -#if defined(Q_OS_IRIX) && defined(Q_CC_GNU) - // work around a bug on 64 bit IRIX gcc - double *t = (double *) tens; - eps *= t[ilim-1]; -#else - eps *= tens[ilim-1]; -#endif - for(i = 1;; i++, d *= 10.) { - L = Long(d); - d -= L; - *s++ = '0' + int(L); - if (i == ilim) { - if (d > 0.5 + eps) - goto bump_up; - else if (d < 0.5 - eps) { - while(*--s == '0') {} - s++; - goto ret1; - } - break; - } - } -#ifndef No_leftright - } -#endif - fast_failed: - s = s0; - d = d2; - k = k0; - ilim = ilim0; } + return QString(); +} - /* Do we have a "small" integer? */ +/*! + \fn QString QLocale::toCurrencyString(short) const + \since 4.8 + \overload +*/ - if (be >= 0 && k <= Int_max) { - /* Yes. */ - ds = tens[k]; - if (ndigits < 0 && ilim <= 0) { - S = mhi = 0; - if (ilim < 0 || d <= 5*ds) - goto no_digits; - goto one_digit; - } - for(i = 1;; i++) { - L = Long(d / ds); - d -= L*ds; -#ifdef Check_FLT_ROUNDS - /* If FLT_ROUNDS == 2, L will usually be high by 1 */ - if (d < 0) { - L--; - d += ds; - } -#endif - *s++ = '0' + int(L); - if (i == ilim) { - d += d; - if (d > ds || (d == ds && L & 1)) { - bump_up: - while(*--s == '9') - if (s == s0) { - k++; - *s = '0'; - break; - } - ++*s++; - } - break; - } - if ((d *= 10.) == g_double_zero) - break; - } - goto ret1; - } +/*! + \fn QString QLocale::toCurrencyString(ushort) const + \since 4.8 + \overload +*/ - m2 = b2; - m5 = b5; - mhi = mlo = 0; - if (leftright) { - if (mode < 2) { - i = -#ifndef Sudden_Underflow - denorm ? be + (Bias + (P-1) - 1 + 1) : -#endif -#ifdef IBM - 1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3); -#else - 1 + P - bbits; -#endif - } - else { - j = ilim - 1; - if (m5 >= j) - m5 -= j; - else { - s5 += j -= m5; - b5 += j; - m5 = 0; - } - if ((i = ilim) < 0) { - m2 -= i; - i = 0; - } - } - b2 += i; - s2 += i; - mhi = i2b(1); - } - if (m2 > 0 && s2 > 0) { - i = m2 < s2 ? m2 : s2; - b2 -= i; - m2 -= i; - s2 -= i; - } - if (b5 > 0) { - if (leftright) { - if (m5 > 0) { - mhi = pow5mult(mhi, m5); - b1 = mult(mhi, b); - Bfree(b); - b = b1; - } - if ((j = b5 - m5) != 0) - b = pow5mult(b, j); - } - else - b = pow5mult(b, b5); - } - S = i2b(1); - if (s5 > 0) - S = pow5mult(S, s5); +/*! + \fn QString QLocale::toCurrencyString(int) const + \since 4.8 + \overload +*/ + +/*! + \fn QString QLocale::toCurrencyString(uint) const + \since 4.8 + \overload +*/ +/*! + \fn QString QLocale::toCurrencyString(float) const + \since 4.8 + \overload +*/ - /* Check for special case that d is a normalized power of 2. */ +/*! + \since 4.8 - if (mode < 2) { - if (!getWord1(d) && !(getWord0(d) & Bndry_mask) -#ifndef Sudden_Underflow - && getWord0(d) & Exp_mask -#endif - ) { - /* The special case */ - b2 += Log2P; - s2 += Log2P; - spec_case = 1; - } - else - spec_case = 0; + Returns a localized string representation of \a value as a currency. +*/ +QString QLocale::toCurrencyString(qlonglong value) const +{ +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QVariant res = systemLocale()->query(QSystemLocale::FormatCurrency, value); + if (!res.isNull()) + return res.toString(); } - - /* Arrange for convenient computation of quotients: - * shift left if necessary so divisor has 4 leading 0 bits. - * - * Perhaps we should just compute leading 28 bits of S once - * and for all and pass them and a shift to quorem, so it - * can do shifts and ors to compute the numerator for q. - */ -#ifdef Pack_32 - if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f) != 0) - i = 32 - i; -#else - if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf) - i = 16 - i; #endif - if (i > 4) { - i -= 4; - b2 += i; - m2 += i; - s2 += i; - } - else if (i < 4) { - i += 28; - b2 += i; - m2 += i; - s2 += i; - } - if (b2 > 0) - b = lshift(b, b2); - if (s2 > 0) - S = lshift(S, s2); - if (k_check) { - if (cmp(b,S) < 0) { - k--; - b = multadd(b, 10, 0); /* we botched the k estimate */ - if (leftright) - mhi = multadd(mhi, 10, 0); - ilim = ilim1; - } - } - if (ilim <= 0 && mode > 2) { - if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) { - /* no digits, fcvt style */ - no_digits: - k = -1 - ndigits; - goto ret; - } - one_digit: - *s++ = '1'; - k++; - goto ret; + 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; } - if (leftright) { - if (m2 > 0) - mhi = lshift(mhi, m2); - - /* Compute mlo -- check for special case - * that d is a normalized power of 2. - */ - - mlo = mhi; - if (spec_case) { - mhi = Balloc(mhi->k); - Bcopy(mhi, mlo); - mhi = lshift(mhi, Log2P); - } + QString str = d->longLongToString(value); + QString symbol = currencySymbol(); + if (symbol.isEmpty()) + symbol = currencySymbol(QLocale::CurrencyIsoCode); + QString format = getLocaleData(currency_format_data + idx, size); + return format.arg(str, symbol); +} - for(i = 1;;i++) { - dig = quorem(b,S) + '0'; - /* Do we yet have the shortest decimal string - * that will round to d? - */ - j = cmp(b, mlo); - delta = diff(S, mhi); - j1 = delta->sign ? 1 : cmp(b, delta); - Bfree(delta); -#ifndef ROUND_BIASED - if (j1 == 0 && !mode && !(getWord1(d) & 1)) { - if (dig == '9') - goto round_9_up; - if (j > 0) - dig++; - *s++ = dig; - goto ret; - } -#endif - if (j < 0 || (j == 0 && !mode -#ifndef ROUND_BIASED - && !(getWord1(d) & 1) -#endif - )) { - if (j1 > 0) { - b = lshift(b, 1); - j1 = cmp(b, S); - if ((j1 > 0 || (j1 == 0 && dig & 1)) - && dig++ == '9') - goto round_9_up; - } - *s++ = dig; - goto ret; - } - if (j1 > 0) { - if (dig == '9') { /* possible if i == 1 */ - round_9_up: - *s++ = '9'; - goto roundoff; - } - *s++ = dig + 1; - goto ret; - } - *s++ = dig; - if (i == ilim) - break; - b = multadd(b, 10, 0); - if (mlo == mhi) - mlo = mhi = multadd(mhi, 10, 0); - else { - mlo = multadd(mlo, 10, 0); - mhi = multadd(mhi, 10, 0); - } - } +/*! + \since 4.8 + \overload +*/ +QString QLocale::toCurrencyString(qulonglong value) const +{ +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QVariant res = systemLocale()->query(QSystemLocale::FormatCurrency, value); + if (!res.isNull()) + return res.toString(); } - else - for(i = 1;; i++) { - *s++ = dig = quorem(b,S) + '0'; - if (i >= ilim) - break; - b = multadd(b, 10, 0); - } +#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 symbol = currencySymbol(); + if (symbol.isEmpty()) + symbol = currencySymbol(QLocale::CurrencyIsoCode); + QString format = getLocaleData(currency_format_data + idx, size); + return format.arg(str, symbol); +} - /* Round off last digit */ - - b = lshift(b, 1); - j = cmp(b, S); - if (j > 0 || (j == 0 && dig & 1)) { - roundoff: - while(*--s == '9') - if (s == s0) { - k++; - *s++ = '1'; - goto ret; - } - ++*s++; - } - else { - while(*--s == '0') {} - s++; - } - ret: - Bfree(S); - if (mhi) { - if (mlo && mlo != mhi) - Bfree(mlo); - Bfree(mhi); +QString QLocale::toCurrencyString(double value) const +{ +#ifndef QT_NO_SYSTEMLOCALE + if (d() == systemPrivate()) { + QVariant res = systemLocale()->query(QSystemLocale::FormatCurrency, value); + if (!res.isNull()) + return res.toString(); } - ret1: - Bfree(b); - if (s == s0) { /* don't return empty string */ - *s++ = '0'; - k = 0; +#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; } - *s = 0; - *decpt = k + 1; - if (rve) - *rve = s; - return s0; + QString str = d->doubleToString(value, d->m_currency_digits, + QLocalePrivate::DFDecimal); + QString symbol = currencySymbol(); + if (symbol.isEmpty()) + symbol = currencySymbol(QLocale::CurrencyIsoCode); + QString format = getLocaleData(currency_format_data + idx, size); + return format.arg(str, symbol); } -#else -// NOT thread safe! - -#include - -Q_CORE_EXPORT char *qdtoa( double d, int mode, int ndigits, int *decpt, int *sign, char **rve, char **resultp) -{ - if(rve) - *rve = 0; - char *res; - if (mode == 0) - ndigits = 80; +/*! + \since 4.8 - if (mode == 3) - res = fcvt(d, ndigits, decpt, sign); - else - res = ecvt(d, ndigits, decpt, sign); - - int n = qstrlen(res); - if (mode == 0) { // remove trailing 0's - const int stop = qMax(1, *decpt); - int i; - for (i = n-1; i >= stop; --i) { - if (res[i] != '0') - break; - } - n = i + 1; - } - *resultp = static_cast(malloc(n + 1)); - Q_CHECK_PTR(resultp); - qstrncpy(*resultp, res, n + 1); - return *resultp; -} + Returns a sorted list of locale names that could be used for translation + of messages presented to the user. -Q_CORE_EXPORT double qstrtod(const char *s00, const char **se, bool *ok) + \sa QTranslator +*/ +QStringList QLocale::uiLanguages() const { - errno = 0; - double ret = strtod((char*)s00, (char**)se); - if (ok) { - if((ret == 0.0l && errno == ERANGE) - || ret == HUGE_VAL || ret == -HUGE_VAL) - *ok = false; - else - *ok = true; // the result will be that we don't report underflow in this case +#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; + } } - return ret; +#endif + return QStringList(name()); } -#endif // QT_QLOCALE_USES_FCVT QT_END_NAMESPACE diff --git a/src/corelib/tools/qlocale.h b/src/corelib/tools/qlocale.h index e62e2d9..18c6db3 100644 --- a/src/corelib/tools/qlocale.h +++ b/src/corelib/tools/qlocale.h @@ -107,7 +107,7 @@ public: private: QSystemLocale(bool); - friend class QSystemLocaleData; + friend QSystemLocale *QSystemLocale_globalSystemLocale(); }; #endif diff --git a/src/corelib/tools/qlocale.qdoc b/src/corelib/tools/qlocale.qdoc new file mode 100644 index 0000000..3231951 --- /dev/null +++ b/src/corelib/tools/qlocale.qdoc @@ -0,0 +1,773 @@ + +/*! + \class QLocale + \brief The QLocale class converts between numbers and their + string representations in various languages. + + \reentrant + \ingroup i18n + \ingroup string-processing + \ingroup shared + + + QLocale is initialized with a language/country pair in its + constructor and offers number-to-string and string-to-number + conversion functions similar to those in QString. + + Example: + + \snippet doc/src/snippets/code/src_corelib_tools_qlocale.cpp 0 + + QLocale supports the concept of a default locale, which is + determined from the system's locale settings at application + startup. The default locale can be changed by calling the + static member setDefault(). Setting the default locale has the + following effects: + + \list + \i If a QLocale object is constructed with the default constructor, + it will use the default locale's settings. + \i QString::toInt(), QString::toDouble(), etc., interpret the + string according to the default locale. If this fails, it + falls back on the "C" locale. + \i QString::arg() uses the default locale to format a number when + its position specifier in the format string contains an 'L', + e.g. "%L1". + \endlist + + The following example illustrates how to use QLocale directly: + + \snippet doc/src/snippets/code/src_corelib_tools_qlocale.cpp 1 + + When a language/country pair is specified in the constructor, one + of three things can happen: + + \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 + + Use language() and country() to determine the actual language and + country values used. + + An alternative method for constructing a QLocale object is by + specifying the locale name. + + \snippet doc/src/snippets/code/src_corelib_tools_qlocale.cpp 2 + + This constructor converts the locale name to a language/country + pair; it does not use the system locale database. + + QLocale's data is based on Common Locale Data Repository v1.8.1. + + The double-to-string and string-to-double conversion functions are + covered by the following licenses: + + \legalese + Copyright (c) 1991 by AT&T. + + Permission to use, copy, modify, and distribute this software for any + purpose without fee is hereby granted, provided that this entire notice + is included in all copies of any software which is or includes a copy + or modification of this software and in all copies of the supporting + documentation for such software. + + THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED + WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR AT&T MAKES ANY + REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY + OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + + This product includes software developed by the University of + California, Berkeley and its contributors. + + \sa QString::arg(), QString::toInt(), QString::toDouble() +*/ + +/*! + \enum QLocale::Language + + This enumerated type is used to specify a language. + + \value C The "C" locale is identical in behavior to English/UnitedStates. + \value Abkhazian + \value Afan + \value Afar + \value Afrikaans + \value Albanian + \value Amharic + \value Arabic + \value Armenian + \value Assamese + \value Aymara + \value Azerbaijani + \value Bashkir + \value Basque + \value Bengali + \value Bhutani + \value Bihari + \value Bislama + \value Bosnian + \value Breton + \value Bulgarian + \value Burmese + \value Byelorussian + \value Cambodian + \value Catalan + \value Chinese + \value Cornish + \value Corsican + \value Croatian + \value Czech + \value Danish + \value Divehi + \value Dutch + \value English + \value Esperanto + \value Estonian + \value Faroese + \value FijiLanguage + \value Finnish + \value French + \value Frisian + \value Gaelic + \value Galician + \value Georgian + \value German + \value Greek + \value Greenlandic + \value Guarani + \value Gujarati + \value Hausa + \value Hebrew + \value Hindi + \value Hungarian + \value Icelandic + \value Indonesian + \value Interlingua + \value Interlingue + \value Inuktitut + \value Inupiak + \value Irish + \value Italian + \value Japanese + \value Javanese + \value Kannada + \value Kashmiri + \value Kazakh + \value Kinyarwanda + \value Kirghiz + \value Korean + \value Kurdish + \value Kurundi + \value Laothian + \value Latin + \value Latvian + \value Lingala + \value Lithuanian + \value Macedonian + \value Malagasy + \value Malay + \value Malayalam + \value Maltese + \value Manx + \value Maori + \value Marathi + \value Moldavian + \value Mongolian + \value NauruLanguage + \value Nepali + \value Norwegian + \value NorwegianBokmal + \value Nynorsk Obsolete, please use NorwegianNynorsk + \value NorwegianNynorsk + \value Occitan + \value Oriya + \value Pashto + \value Persian + \value Polish + \value Portuguese + \value Punjabi + \value Quechua + \value RhaetoRomance + \value Romanian + \value Russian + \value Samoan + \value Sangho + \value Sanskrit + \value Serbian + \value SerboCroatian + \value Sesotho + \value Setswana + \value Shona + \value Sindhi + \value Singhalese + \value Siswati + \value Slovak + \value Slovenian + \value Somali + \value Spanish + \value Sundanese + \value Swahili + \value Swedish + \value Tagalog + \value Tajik + \value Tamil + \value Tatar + \value Telugu + \value Thai + \value Tibetan + \value Tigrinya + \value TongaLanguage + \value Tsonga + \value Turkish + \value Turkmen + \value Twi + \value Uigur + \value Ukrainian + \value Urdu + \value Uzbek + \value Vietnamese + \value Volapuk + \value Welsh + \value Wolof + \value Xhosa + \value Yiddish + \value Yoruba + \value Zhuang + \value Zulu + \value Bosnian + \value Divehi + \value Manx + \value Cornish + \value Akan + \value Konkani + \value Ga + \value Igbo + \value Kamba + \value Syriac + \value Blin + \value Geez + \value Koro + \value Sidamo + \value Atsam + \value Tigre + \value Jju + \value Friulian + \value Venda + \value Ewe + \value Walamo + \value Hawaiian + \value Tyap + \value Chewa + \value Filipino + \value SwissGerman + \value SichuanYi + \value Kpelle + \value LowGerman + \value SouthNdebele + \value NorthernSotho + \value NorthernSami + \value Taroko + \value Gusii + \value Taita + \value Fulah + \value Kikuyu + \value Samburu + \value Sena + \value NorthNdebele + \value Rombo + \value Tachelhit + \value Kabyle + \value Nyankole + \value Bena + \value Vunjo + \value Bambara + \value Embu + \value Cherokee + \value Morisyen + \value Makonde + \value Langi + \value Ganda + \value Bemba + \value Kabuverdianu + \value Meru + \value Kalenjin + \value Nama + \value Machame + \value Colognian + \value Masai + \value Soga + \value Luyia + \value Asu + \value Teso + \value Saho + \value KoyraChiini + \value Rwa + \value Luo + \value Chiga + \value CentralMoroccoTamazight + \value KoyraboroSenni + \value Shambala + \omitvalue LastLanguage + + \sa language() +*/ + +/*! + \enum QLocale::Country + + This enumerated type is used to specify a country. + + \value AnyCountry + \value Afghanistan + \value Albania + \value Algeria + \value AmericanSamoa + \value Andorra + \value Angola + \value Anguilla + \value Antarctica + \value AntiguaAndBarbuda + \value Argentina + \value Armenia + \value Aruba + \value Australia + \value Austria + \value Azerbaijan + \value Bahamas + \value Bahrain + \value Bangladesh + \value Barbados + \value Belarus + \value Belgium + \value Belize + \value Benin + \value Bermuda + \value Bhutan + \value Bolivia + \value BosniaAndHerzegowina + \value Botswana + \value BouvetIsland + \value Brazil + \value BritishIndianOceanTerritory + \value BruneiDarussalam + \value Bulgaria + \value BurkinaFaso + \value Burundi + \value Cambodia + \value Cameroon + \value Canada + \value CapeVerde + \value CaymanIslands + \value CentralAfricanRepublic + \value Chad + \value Chile + \value China + \value ChristmasIsland + \value CocosIslands + \value Colombia + \value Comoros + \value DemocraticRepublicOfCongo + \value PeoplesRepublicOfCongo + \value CookIslands + \value CostaRica + \value IvoryCoast + \value Croatia + \value Cuba + \value Cyprus + \value CzechRepublic + \value Denmark + \value Djibouti + \value Dominica + \value DominicanRepublic + \value EastTimor + \value Ecuador + \value Egypt + \value ElSalvador + \value EquatorialGuinea + \value Eritrea + \value Estonia + \value Ethiopia + \value FalklandIslands + \value FaroeIslands + \value FijiCountry + \value Finland + \value France + \value MetropolitanFrance + \value FrenchGuiana + \value FrenchPolynesia + \value FrenchSouthernTerritories + \value Gabon + \value Gambia + \value Georgia + \value Germany + \value Ghana + \value Gibraltar + \value Greece + \value Greenland + \value Grenada + \value Guadeloupe + \value Guam + \value Guatemala + \value Guinea + \value GuineaBissau + \value Guyana + \value Haiti + \value HeardAndMcDonaldIslands + \value Honduras + \value HongKong + \value Hungary + \value Iceland + \value India + \value Indonesia + \value Iran + \value Iraq + \value Ireland + \value Israel + \value Italy + \value Jamaica + \value Japan + \value Jordan + \value Kazakhstan + \value Kenya + \value Kiribati + \value DemocraticRepublicOfKorea + \value RepublicOfKorea + \value Kuwait + \value Kyrgyzstan + \value Lao + \value Latvia + \value Lebanon + \value Lesotho + \value Liberia + \value LibyanArabJamahiriya + \value Liechtenstein + \value Lithuania + \value Luxembourg + \value Macau + \value Macedonia + \value Madagascar + \value Malawi + \value Malaysia + \value Maldives + \value Mali + \value Malta + \value MarshallIslands + \value Martinique + \value Mauritania + \value Mauritius + \value Mayotte + \value Mexico + \value Micronesia + \value Moldova + \value Monaco + \value Mongolia + \value Montserrat + \value Morocco + \value Mozambique + \value Myanmar + \value Namibia + \value NauruCountry + \value Nepal + \value Netherlands + \value NetherlandsAntilles + \value NewCaledonia + \value NewZealand + \value Nicaragua + \value Niger + \value Nigeria + \value Niue + \value NorfolkIsland + \value NorthernMarianaIslands + \value Norway + \value Oman + \value Pakistan + \value Palau + \value PalestinianTerritory + \value Panama + \value PapuaNewGuinea + \value Paraguay + \value Peru + \value Philippines + \value Pitcairn + \value Poland + \value Portugal + \value PuertoRico + \value Qatar + \value Reunion + \value Romania + \value RussianFederation + \value Rwanda + \value SaintKittsAndNevis + \value StLucia + \value StVincentAndTheGrenadines + \value Samoa + \value SanMarino + \value SaoTomeAndPrincipe + \value SaudiArabia + \value Senegal + \value SerbiaAndMontenegro + \value Seychelles + \value SierraLeone + \value Singapore + \value Slovakia + \value Slovenia + \value SolomonIslands + \value Somalia + \value SouthAfrica + \value SouthGeorgiaAndTheSouthSandwichIslands + \value Spain + \value SriLanka + \value StHelena + \value StPierreAndMiquelon + \value Sudan + \value Suriname + \value SvalbardAndJanMayenIslands + \value Swaziland + \value Sweden + \value Switzerland + \value SyrianArabRepublic + \value Taiwan + \value Tajikistan + \value Tanzania + \value Thailand + \value Togo + \value Tokelau + \value TongaCountry + \value TrinidadAndTobago + \value Tunisia + \value Turkey + \value Turkmenistan + \value TurksAndCaicosIslands + \value Tuvalu + \value Uganda + \value Ukraine + \value UnitedArabEmirates + \value UnitedKingdom + \value UnitedStates + \value UnitedStatesMinorOutlyingIslands + \value Uruguay + \value Uzbekistan + \value Vanuatu + \value VaticanCityState + \value Venezuela + \value VietNam + \value BritishVirginIslands + \value USVirginIslands + \value WallisAndFutunaIslands + \value WesternSahara + \value Yemen + \value Yugoslavia + \value Zambia + \value Zimbabwe + \value SerbiaAndMontenegro + \value Montenegro + \value Serbia + \value SaintBarthelemy + \value SaintMartin + \value LatinAmericaAndTheCaribbean + \omitvalue LastCountry + + \sa country() +*/ + +/*! + \enum QLocale::FormatType + + This enum describes the types of format that can be used when + converting QDate and QTime objects to strings. + + \value LongFormat The long version of day and month names; for + example, returning "January" as a month name. + + \value ShortFormat The short version of day and month names; for + example, returning "Jan" as a month name. + + \value NarrowFormat A special version of day and month names for + use when space is limited; for example, returning "J" as a month + name. Note that the narrow format might contain the same text for + different months and days or it can even be an empty string if the + locale doesn't support narrow names, so you should avoid using it + for date formatting. Also, for the system locale this format is + the same as ShortFormat. +*/ + +/*! + \enum QLocale::NumberOption + + This enum defines a set of options for number-to-string and string-to-number + conversions. They can be retrieved with numberOptions() and set with + setNumberOptions(). + + \value OmitGroupSeparator If this option is set, the number-to-string functions + will not insert group separators in their return values. The default + is to insert group separators. + \value RejectGroupSeparator If this option is set, the string-to-number functions + will fail if they encounter group separators in their input. The default + is to accept numbers containing correctly placed group separators. + + \sa setNumberOptions() numberOptions() +*/ + +/*! + \enum QLocale::MeasurementSystem + + This enum defines which units are used for measurement. + + \value MetricSystem This value indicates metric units, such as meters, + centimeters and millimeters. + \value ImperialSystem This value indicates imperial units, such as inches and + miles. There are several distinct imperial systems in the world; this + value stands for the official United States imperial units. + + \since 4.4 +*/ + + +/*! + \fn bool QLocale::operator==(const QLocale &other) const + + Returns true if the QLocale object is the same as the \a other + locale specified; otherwise returns false. +*/ + +/*! + \fn bool QLocale::operator!=(const QLocale &other) const + + Returns true if the QLocale object is not the same as the \a other + locale specified; otherwise returns false. +*/ + +/*! + \enum QLocale::QuotationStyle + + This enum defines a set of possible styles for locale specific quotation. + + \value StandardQuotation If this option is set, the standard quotation marks + will be used to quote strings. + \value AlternateQuotation If this option is set, the alternate quotation marks + will be used to quote strings. + + \since 4.8 + + \sa quoteString() +*/ + +/*! + \class QSystemLocale + \brief The QSystemLocale class can be used to finetune the system locale + of the user. + \since 4.2 + + \ingroup i18n + + \warning This class is only useful in very rare cases. Usually QLocale offers + all the functionality required for application development. + + QSystemLocale allows to override the values provided by the system + locale (QLocale::system()). + + \sa QLocale +*/ + +/*! + \enum QSystemLocale::QueryType + + Specifies the type of information queried by query(). For each value + the type of information to return from the query() method is listed. + + \value LanguageId a uint specifying the language. + \value CountryId a uint specifying the country. + \value DecimalPoint a QString specifying the decimal point. + \value GroupSeparator a QString specifying the group separator. + \value ZeroDigit a QString specifying the zero digit. + \value NegativeSign a QString specifying the minus sign. + \value PositiveSign a QString specifying the plus sign. + \value DateFormatLong a QString specifying the long date format + \value DateFormatShort a QString specifying the short date format + \value TimeFormatLong a QString specifying the long time format + \value TimeFormatShort a QString specifying the short time format + \value DayNameLong a QString specifying the name of a weekday. the in variant contains an integer between 1 and 7 (Monday - Sunday) + \value DayNameShort a QString specifying the short name of a weekday. the in variant contains an integer between 1 and 7 (Monday - Sunday) + \value MonthNameLong a QString specifying the name of a month. the in variant contains an integer between 1 and 12 + \value MonthNameShort a QString specifying the short name of a month. the in variant contains an integer between 1 and 12 + \value DateToStringLong converts the QDate stored in the in variant to a QString using the long date format + \value DateToStringShort converts the QDate stored in the in variant to a QString using the short date format + \value TimeToStringLong converts the QTime stored in the in variant to a QString using the long time format + \value TimeToStringShort converts the QTime stored in the in variant to a QString using the short time format + \value DateTimeFormatLong a QString specifying the long date time format + \value DateTimeFormatShort a QString specifying the short date time format + \value DateTimeToStringLong converts the QDateTime in the in variant to a QString using the long datetime format + \value DateTimeToStringShort converts the QDateTime in the in variant to a QString using the short datetime format + \value MeasurementSystem a QLocale::MeasurementSystem enum specifying the measurement system + \value AMText a string that represents the system AM designator associated with a 12-hour clock. + \value PMText a string that represents the system PM designator associated with a 12-hour clock. + \value FirstDayOfWeek a Qt::DayOfWeek enum specifiying the first day of the week + \value CurrencySymbol a string that represents a currency in a format QLocale::CurrencyFormat. + \value FormatCurrency a localized string representation of a number with a currency symbol. + \value UILanguages a list of strings representing locale names that could be used for UI translation. + \value QuotationBegin a QString specifying the start of a quotation. the in variant contains a QLocale::QuotationStyle + \value QuotationEnd a QString specifying the end of a quotation. the in variant contains a QLocale::QuotationStyle +*/ + +/*! +\fn QString QLocale::toString(short i) const + +\overload + +\sa toShort() +*/ + +/*! +\fn QString QLocale::toString(ushort i) const + +\overload + +\sa toUShort() +*/ + +/*! +\fn QString QLocale::toString(int i) const + +\overload + +\sa toInt() +*/ + +/*! +\fn QString QLocale::toString(uint i) const + +\overload + +\sa toUInt() +*/ + +/* +\fn QString QLocale::toString(long i) const + +\overload + +\sa toLong() +*/ + +/* +\fn QString QLocale::toString(ulong i) const + +\overload + +\sa toULong() +*/ + +/*! +\fn QString QLocale::toString(float i, char f = 'g', int prec = 6) const + +\overload + +\a f and \a prec have the same meaning as in QString::number(double, char, int). + +\sa toDouble() +*/ diff --git a/src/corelib/tools/qlocale_mac.mm b/src/corelib/tools/qlocale_mac.mm new file mode 100644 index 0000000..cdbf93d --- /dev/null +++ b/src/corelib/tools/qlocale_mac.mm @@ -0,0 +1,485 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "qlocale_p.h" + +#include "qstringlist.h" +#include "qvariant.h" +#include "qdatetime.h" + +#if !defined(QWS) && defined(Q_OS_MAC) +# include "private/qcore_mac_p.h" +# include +#endif + +QT_BEGIN_NAMESPACE + +/****************************************************************************** +** Wrappers for Mac locale system functions +*/ + +static QByteArray envVarLocale() +{ + static QByteArray lang = 0; +#ifdef Q_OS_UNIX + lang = qgetenv("LC_ALL"); + if (lang.isNull()) + lang = qgetenv("LC_NUMERIC"); + if (lang.isNull()) +#endif + lang = qgetenv("LANG"); + return lang; +} + +static QByteArray getMacLocaleName() +{ + QByteArray result = envVarLocale(); + + QChar lang[3]; + QChar cntry[3]; + if (result.isEmpty() || result != "C" + && !splitLocaleName(QString::fromLocal8Bit(result), lang, cntry)) { + QCFType l = CFLocaleCopyCurrent(); + CFStringRef locale = CFLocaleGetIdentifier(l); + result = QCFString::toQString(locale).toUtf8(); + } + return result; +} + +static QString macMonthName(int month, bool short_format) +{ + month -= 1; + if (month < 0 || month > 11) + return QString(); + + QCFType formatter + = CFDateFormatterCreate(0, QCFType(CFLocaleCopyCurrent()), + kCFDateFormatterNoStyle, kCFDateFormatterNoStyle); + QCFType values + = static_cast(CFDateFormatterCopyProperty(formatter, + short_format ? kCFDateFormatterShortMonthSymbols + : kCFDateFormatterMonthSymbols)); + if (values != 0) { + CFStringRef cfstring = static_cast(CFArrayGetValueAtIndex(values, month)); + return QCFString::toQString(cfstring); + } + return QString(); +} + +static QString macDayName(int day, bool short_format) +{ + if (day < 1 || day > 7) + return QString(); + + QCFType formatter + = CFDateFormatterCreate(0, QCFType(CFLocaleCopyCurrent()), + kCFDateFormatterNoStyle, kCFDateFormatterNoStyle); + QCFType values = static_cast(CFDateFormatterCopyProperty(formatter, + short_format ? kCFDateFormatterShortWeekdaySymbols + : kCFDateFormatterWeekdaySymbols)); + if (values != 0) { + CFStringRef cfstring = static_cast(CFArrayGetValueAtIndex(values, day % 7)); + return QCFString::toQString(cfstring); + } + return QString(); +} + +static QString macDateToString(const QDate &date, bool short_format) +{ + CFGregorianDate macGDate; + macGDate.year = date.year(); + macGDate.month = date.month(); + macGDate.day = date.day(); + macGDate.hour = 0; + macGDate.minute = 0; + macGDate.second = 0.0; + QCFType myDate + = CFDateCreate(0, CFGregorianDateGetAbsoluteTime(macGDate, + QCFType(CFTimeZoneCopyDefault()))); + QCFType mylocale = CFLocaleCopyCurrent(); + CFDateFormatterStyle style = short_format ? kCFDateFormatterShortStyle : kCFDateFormatterLongStyle; + QCFType myFormatter + = CFDateFormatterCreate(kCFAllocatorDefault, + mylocale, style, + kCFDateFormatterNoStyle); + return QCFString(CFDateFormatterCreateStringWithDate(0, myFormatter, myDate)); +} + +static QString macTimeToString(const QTime &time, bool short_format) +{ + CFGregorianDate macGDate; + // Assume this is local time and the current date + QDate dt = QDate::currentDate(); + macGDate.year = dt.year(); + macGDate.month = dt.month(); + macGDate.day = dt.day(); + macGDate.hour = time.hour(); + macGDate.minute = time.minute(); + macGDate.second = time.second(); + QCFType myDate + = CFDateCreate(0, CFGregorianDateGetAbsoluteTime(macGDate, + QCFType(CFTimeZoneCopyDefault()))); + + QCFType mylocale = CFLocaleCopyCurrent(); + CFDateFormatterStyle style = short_format ? kCFDateFormatterShortStyle : kCFDateFormatterLongStyle; + QCFType myFormatter = CFDateFormatterCreate(kCFAllocatorDefault, + mylocale, + kCFDateFormatterNoStyle, + style); + return QCFString(CFDateFormatterCreateStringWithDate(0, myFormatter, myDate)); +} + +static QString macToQtFormat(const QString &sys_fmt) +{ + QString result; + int i = 0; + + while (i < sys_fmt.size()) { + if (sys_fmt.at(i).unicode() == '\'') { + QString text = readEscapedFormatString(sys_fmt, &i); + if (text == QLatin1String("'")) + result += QLatin1String("''"); + else + result += QLatin1Char('\'') + text + QLatin1Char('\''); + continue; + } + + QChar c = sys_fmt.at(i); + int repeat = repeatCount(sys_fmt, i); + + switch (c.unicode()) { + case 'G': // Qt doesn't support these :( + case 'Y': + case 'D': + case 'F': + case 'w': + case 'W': + case 'g': + break; + + case 'u': // extended year - use 'y' + if (repeat < 4) + result += QLatin1String("yy"); + else + result += QLatin1String("yyyy"); + break; + case 'S': // fractional second + if (repeat < 3) + result += QLatin1Char('z'); + else + result += QLatin1String("zzz"); + break; + case 'E': + if (repeat <= 3) + result += QLatin1String("ddd"); + else + result += QLatin1String("dddd"); + break; + case 'e': + if (repeat >= 2) + result += QLatin1String("dd"); + else + result += QLatin1Char('d'); + break; + case 'a': + result += QLatin1String("AP"); + break; + case 'k': + result += QString(repeat, QLatin1Char('H')); + break; + case 'K': + result += QString(repeat, QLatin1Char('h')); + break; + case 'z': + case 'Z': + case 'v': + result += QLatin1Char('t'); + break; + default: + result += QString(repeat, c); + break; + } + + i += repeat; + } + + return result; +} + +QString getMacDateFormat(CFDateFormatterStyle style) +{ + QCFType l = CFLocaleCopyCurrent(); + QCFType formatter = CFDateFormatterCreate(kCFAllocatorDefault, + l, style, kCFDateFormatterNoStyle); + return macToQtFormat(QCFString::toQString(CFDateFormatterGetFormat(formatter))); +} + +static QString getMacTimeFormat(CFDateFormatterStyle style) +{ + QCFType l = CFLocaleCopyCurrent(); + QCFType formatter = CFDateFormatterCreate(kCFAllocatorDefault, + l, kCFDateFormatterNoStyle, style); + return macToQtFormat(QCFString::toQString(CFDateFormatterGetFormat(formatter))); +} + +static QString getCFLocaleValue(CFStringRef key) +{ + QCFType locale = CFLocaleCopyCurrent(); + CFTypeRef value = CFLocaleGetValue(locale, key); + return QCFString::toQString(CFStringRef(static_cast(value))); +} + +static QLocale::MeasurementSystem macMeasurementSystem() +{ + QCFType locale = CFLocaleCopyCurrent(); + CFStringRef system = static_cast(CFLocaleGetValue(locale, kCFLocaleMeasurementSystem)); + if (QCFString::toQString(system) == QLatin1String("Metric")) { + return QLocale::MetricSystem; + } else { + return QLocale::ImperialSystem; + } +} + + +static quint8 macFirstDayOfWeek() +{ + QCFType calendar = CFCalendarCopyCurrent(); + quint8 day = static_cast(CFCalendarGetFirstWeekday(calendar))-1; + if (day == 0) + day = 7; + return day; +} + +static QString macCurrencySymbol(QLocale::CurrencySymbolFormat format) +{ + QCFType locale = CFLocaleCopyCurrent(); + switch (format) { + case QLocale::CurrencyIsoCode: + return QCFString::toQString(static_cast(CFLocaleGetValue(locale, kCFLocaleCurrencyCode))); + case QLocale::CurrencySymbol: + return QCFString::toQString(static_cast(CFLocaleGetValue(locale, kCFLocaleCurrencySymbol))); + case QLocale::CurrencyDisplayName: { + CFStringRef code = static_cast(CFLocaleGetValue(locale, kCFLocaleCurrencyCode)); + QCFType value = CFLocaleCopyDisplayNameForPropertyValue(locale, kCFLocaleCurrencyCode, code); + return QCFString::toQString(value); + } + default: + break; + } + return QString(); +} + +static QString macFormatCurrency(const QVariant &in) +{ + QCFType value; + switch (in.type()) { + case QVariant::Int: + case QVariant::UInt: { + int v = in.toInt(); + value = CFNumberCreate(NULL, kCFNumberIntType, &v); + break; + } + case QVariant::Double: { + double v = in.toInt(); + value = CFNumberCreate(NULL, kCFNumberDoubleType, &v); + break; + } + case QVariant::LongLong: + case QVariant::ULongLong: { + qint64 v = in.toLongLong(); + value = CFNumberCreate(NULL, kCFNumberLongLongType, &v); + break; + } + default: + return QString(); + } + + QCFType locale = CFLocaleCopyCurrent(); + QCFType currencyFormatter = + CFNumberFormatterCreate(NULL, locale, kCFNumberFormatterCurrencyStyle); + QCFType result = CFNumberFormatterCreateStringWithNumber(NULL, currencyFormatter, value); + return QCFString::toQString(result); +} + +static QVariant macQuotationSymbol(QSystemLocale::QueryType type, const QVariant &in) +{ +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 + if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_6) + return QVariant(); + + QCFType locale = CFLocaleCopyCurrent(); + switch (type) { + case QSystemLocale::QuotationBegin: + if (in.toInt() == QLocale::StandardQuotation) + return QCFString::toQString(static_cast(CFLocaleGetValue(locale, kCFLocaleQuotationBeginDelimiterKey))); + else + return QCFString::toQString(static_cast(CFLocaleGetValue(locale, kCFLocaleAlternateQuotationBeginDelimiterKey))); + break; + case QSystemLocale::QuotationEnd: + if (in.toInt() == QLocale::StandardQuotation) + return QCFString::toQString(static_cast(CFLocaleGetValue(locale, kCFLocaleQuotationEndDelimiterKey))); + else + return QCFString::toQString(static_cast(CFLocaleGetValue(locale, kCFLocaleAlternateQuotationEndDelimiterKey))); + break; + default: + break; + } +#endif + return QVariant(); +} + +static void getMacPreferredLanguageAndCountry(QString *language, QString *country) +{ + QCFType languages = (CFArrayRef)CFPreferencesCopyValue( + CFSTR("AppleLanguages"), + kCFPreferencesAnyApplication, + kCFPreferencesCurrentUser, + kCFPreferencesAnyHost); + if (languages && CFArrayGetCount(languages) > 0) { + QCFType locale = CFLocaleCreate(kCFAllocatorDefault, + CFStringRef(CFArrayGetValueAtIndex(languages, 0))); + if (language) + *language = QCFString::toQString(CFStringRef(CFLocaleGetValue(locale, kCFLocaleLanguageCode))); + if (country) + *country = QCFString::toQString(CFStringRef(CFLocaleGetValue(locale, kCFLocaleCountryCode))); + } +} + +#ifndef QT_NO_SYSTEMLOCALE + +QLocale QSystemLocale::fallbackLocale() const +{ + return QLocale(QString::fromUtf8(getMacLocaleName().constData())); +} + +QVariant QSystemLocale::query(QueryType type, QVariant in = QVariant()) const +{ + switch(type) { +// case Name: +// return getMacLocaleName(); + case DecimalPoint: { + QString value = getCFLocaleValue(kCFLocaleDecimalSeparator); + return value.isEmpty() ? QVariant() : value; + } + case GroupSeparator: { + QString value = getCFLocaleValue(kCFLocaleGroupingSeparator); + return value.isEmpty() ? QVariant() : value; + } + case DateFormatLong: + case DateFormatShort: + return getMacDateFormat(type == DateFormatShort + ? kCFDateFormatterShortStyle + : kCFDateFormatterLongStyle); + case TimeFormatLong: + case TimeFormatShort: + return getMacTimeFormat(type == TimeFormatShort + ? kCFDateFormatterShortStyle + : kCFDateFormatterLongStyle); + case DayNameLong: + case DayNameShort: + return macDayName(in.toInt(), (type == DayNameShort)); + case MonthNameLong: + case MonthNameShort: + return macMonthName(in.toInt(), (type == MonthNameShort)); + case DateToStringShort: + case DateToStringLong: + return macDateToString(in.toDate(), (type == DateToStringShort)); + case TimeToStringShort: + case TimeToStringLong: + return macTimeToString(in.toTime(), (type == TimeToStringShort)); + + case NegativeSign: + case PositiveSign: + case ZeroDigit: + break; + case LanguageId: + case CountryId: { + QString preferredLanguage; + QString preferredCountry(3, QChar()); // codeToCountry assumes QChar[3] + getMacPreferredLanguageAndCountry(&preferredLanguage, &preferredCountry); + QLocale::Language languageCode = (preferredLanguage.isEmpty() ? QLocale::C : codeToLanguage(preferredLanguage.data())); + QLocale::Country countryCode = (preferredCountry.isEmpty() ? QLocale::AnyCountry : codeToCountry(preferredCountry.data())); + const QLocalePrivate *d = findLocale(languageCode, countryCode); + if (type == LanguageId) + return (QLocale::Language)d->languageId(); + return (QLocale::Country)d->countryId(); + } + + case MeasurementSystem: + return QVariant(static_cast(macMeasurementSystem())); + + case AMText: + case PMText: + break; + case FirstDayOfWeek: + return QVariant(macFirstDayOfWeek()); + case CurrencySymbol: + return QVariant(macCurrencySymbol(QLocale::CurrencySymbolFormat(in.toUInt()))); + case FormatCurrency: + return macFormatCurrency(in); + case UILanguages: { + QCFType languages = (CFArrayRef)CFPreferencesCopyValue( + CFSTR("AppleLanguages"), + kCFPreferencesAnyApplication, + kCFPreferencesCurrentUser, + kCFPreferencesAnyHost); + const int cnt = CFArrayGetCount(languages); + QStringList result; + result.reserve(cnt); + for (int i = 0; i < cnt; ++i) { + const QString lang = QCFString::toQString( + static_cast(CFArrayGetValueAtIndex(languages, i))); + result.append(lang); + } + return QVariant(result); + } + case QuotationBegin: + case QuotationEnd: + return macQuotationSymbol(type,in); + default: + break; + } + return QVariant(); +} + +#endif // QT_NO_SYSTEMLOCALE + +QT_END_NAMESPACE diff --git a/src/corelib/tools/qlocale_p.h b/src/corelib/tools/qlocale_p.h index 1d286ab..748f654 100644 --- a/src/corelib/tools/qlocale_p.h +++ b/src/corelib/tools/qlocale_p.h @@ -245,6 +245,16 @@ private: }; #endif +const QLocalePrivate *findLocale(QLocale::Language language, QLocale::Country country); +const QLocalePrivate *findLocale(const QString &name); +QString readEscapedFormatString(const QString &format, int *idx); +bool splitLocaleName(const QString &name, QChar *lang_begin, QChar *cntry_begin, + int *lang_len = 0, int *cntry_len = 0); +int repeatCount(const QString &s, int i); +QLocale::Language codeToLanguage(const QChar *code); +QLocale::Country codeToCountry(const QChar *code); +void getLangAndCountry(const QString &name, QLocale::Language &lang, QLocale::Country &cntry); + QT_END_NAMESPACE #endif // QLOCALE_P_H diff --git a/src/corelib/tools/qlocale_tools.cpp b/src/corelib/tools/qlocale_tools.cpp new file mode 100644 index 0000000..17d8b2a --- /dev/null +++ b/src/corelib/tools/qlocale_tools.cpp @@ -0,0 +1,2961 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "qlocale_tools_p.h" +#include "qlocale_p.h" +#include "qstring.h" + +#include +#include +#include +#include +#include +#include + +#if defined(Q_OS_LINUX) && !defined(__UCLIBC__) +# include +#endif + +// Sizes as defined by the ISO C99 standard - fallback +#ifndef LLONG_MAX +# define LLONG_MAX Q_INT64_C(0x7fffffffffffffff) +#endif +#ifndef LLONG_MIN +# define LLONG_MIN (-LLONG_MAX - Q_INT64_C(1)) +#endif +#ifndef ULLONG_MAX +# define ULLONG_MAX Q_UINT64_C(0xffffffffffffffff) +#endif + +QT_BEGIN_NAMESPACE + +#ifndef QT_QLOCALE_USES_FCVT +static char *_qdtoa( NEEDS_VOLATILE double d, int mode, int ndigits, int *decpt, + int *sign, char **rve, char **digits_str); +#endif + +QString qulltoa(qulonglong l, int base, const QChar _zero) +{ + ushort buff[65]; // length of MAX_ULLONG in base 2 + ushort *p = buff + 65; + + if (base != 10 || _zero.unicode() == '0') { + while (l != 0) { + int c = l % base; + + --p; + + if (c < 10) + *p = '0' + c; + else + *p = c - 10 + 'a'; + + l /= base; + } + } + else { + while (l != 0) { + int c = l % base; + + *(--p) = _zero.unicode() + c; + + l /= base; + } + } + + return QString(reinterpret_cast(p), 65 - (p - buff)); +} + +QString qlltoa(qlonglong l, int base, const QChar zero) +{ + return qulltoa(l < 0 ? -l : l, base, zero); +} + +QString &decimalForm(QChar zero, QChar decimal, QChar group, + QString &digits, int decpt, uint precision, + PrecisionMode pm, + bool always_show_decpt, + bool thousands_group) +{ + if (decpt < 0) { + for (int i = 0; i < -decpt; ++i) + digits.prepend(zero); + decpt = 0; + } + else if (decpt > digits.length()) { + for (int i = digits.length(); i < decpt; ++i) + digits.append(zero); + } + + if (pm == PMDecimalDigits) { + uint decimal_digits = digits.length() - decpt; + for (uint i = decimal_digits; i < precision; ++i) + digits.append(zero); + } + else if (pm == PMSignificantDigits) { + for (uint i = digits.length(); i < precision; ++i) + digits.append(zero); + } + else { // pm == PMChopTrailingZeros + } + + if (always_show_decpt || decpt < digits.length()) + digits.insert(decpt, decimal); + + if (thousands_group) { + for (int i = decpt - 3; i > 0; i -= 3) + digits.insert(i, group); + } + + if (decpt == 0) + digits.prepend(zero); + + return digits; +} + +QString &exponentForm(QChar zero, QChar decimal, QChar exponential, + QChar group, QChar plus, QChar minus, + QString &digits, int decpt, uint precision, + PrecisionMode pm, + bool always_show_decpt) +{ + int exp = decpt - 1; + + if (pm == PMDecimalDigits) { + for (uint i = digits.length(); i < precision + 1; ++i) + digits.append(zero); + } + else if (pm == PMSignificantDigits) { + for (uint i = digits.length(); i < precision; ++i) + digits.append(zero); + } + else { // pm == PMChopTrailingZeros + } + + if (always_show_decpt || digits.length() > 1) + digits.insert(1, decimal); + + digits.append(exponential); + digits.append(QLocalePrivate::longLongToString(zero, group, plus, minus, + exp, 2, 10, -1, QLocalePrivate::AlwaysShowSign)); + + return digits; +} + +// Removes thousand-group separators in "C" locale. +bool removeGroupSeparators(QLocalePrivate::CharBuff *num) +{ + int group_cnt = 0; // counts number of group chars + int decpt_idx = -1; + + char *data = num->data(); + int l = qstrlen(data); + + // Find the decimal point and check if there are any group chars + int i = 0; + for (; i < l; ++i) { + char c = data[i]; + + if (c == ',') { + if (i == 0 || data[i - 1] < '0' || data[i - 1] > '9') + return false; + if (i == l - 1 || data[i + 1] < '0' || data[i + 1] > '9') + return false; + ++group_cnt; + } + else if (c == '.') { + // Fail if more than one decimal points + if (decpt_idx != -1) + return false; + decpt_idx = i; + } else if (c == 'e' || c == 'E') { + // an 'e' or 'E' - if we have not encountered a decimal + // point, this is where it "is". + if (decpt_idx == -1) + decpt_idx = i; + } + } + + // If no group chars, we're done + if (group_cnt == 0) + return true; + + // No decimal point means that it "is" at the end of the string + if (decpt_idx == -1) + decpt_idx = l; + + i = 0; + while (i < l && group_cnt > 0) { + char c = data[i]; + + if (c == ',') { + // Don't allow group chars after the decimal point + if (i > decpt_idx) + return false; + + // Check that it is placed correctly relative to the decpt + if ((decpt_idx - i) % 4 != 0) + return false; + + // Remove it + memmove(data + i, data + i + 1, l - i - 1); + data[--l] = '\0'; + + --group_cnt; + --decpt_idx; + } else { + // Check that we are not missing a separator + if (i < decpt_idx + && (decpt_idx - i) % 4 == 0 + && !(i == 0 && c == '-')) // check for negative sign at start of string + return false; + ++i; + } + } + + return true; +} + +#if defined(Q_CC_MWERKS) && defined(Q_OS_WIN32) +inline bool isascii(int c) +{ + return (c >= 0 && c <=127); +} +#endif + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgment: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +// static char sccsid[] = "@(#)strtouq.c 8.1 (Berkeley) 6/4/93"; +// "$FreeBSD: src/lib/libc/stdlib/strtoull.c,v 1.5.2.1 2001/03/02 09:45:20 obrien Exp $"; + +/* + * Convert a string to an unsigned long long integer. + * + * Ignores `locale' stuff. Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +qulonglong qstrtoull(const char *nptr, const char **endptr, register int base, bool *ok) +{ + register const char *s = nptr; + register qulonglong acc; + register unsigned char c; + register qulonglong qbase, cutoff; + register int any, cutlim; + + if (ok != 0) + *ok = true; + + /* + * See strtoq for comments as to the logic used. + */ + s = nptr; + do { + c = *s++; + } while (isspace(c)); + if (c == '-') { + if (ok != 0) + *ok = false; + if (endptr != 0) + *endptr = s - 1; + return 0; + } else { + if (c == '+') + c = *s++; + } + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + qbase = unsigned(base); + cutoff = qulonglong(ULLONG_MAX) / qbase; + cutlim = qulonglong(ULLONG_MAX) % qbase; + for (acc = 0, any = 0;; c = *s++) { + if (!isascii(c)) + break; + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= qbase; + acc += c; + } + } + if (any == 0) { + if (ok != 0) + *ok = false; + } else if (any < 0) { + acc = ULLONG_MAX; + if (ok != 0) + *ok = false; + } + if (endptr != 0) + *endptr = (any ? s - 1 : nptr); + return acc; +} + + +// "$FreeBSD: src/lib/libc/stdlib/strtoll.c,v 1.5.2.1 2001/03/02 09:45:20 obrien Exp $"; + + +/* + * Convert a string to a long long integer. + * + * Ignores `locale' stuff. Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +qlonglong qstrtoll(const char *nptr, const char **endptr, register int base, bool *ok) +{ + register const char *s; + register qulonglong acc; + register unsigned char c; + register qulonglong qbase, cutoff; + register int neg, any, cutlim; + + /* + * Skip white space and pick up leading +/- sign if any. + * If base is 0, allow 0x for hex and 0 for octal, else + * assume decimal; if base is already 16, allow 0x. + */ + s = nptr; + do { + c = *s++; + } while (isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else { + neg = 0; + if (c == '+') + c = *s++; + } + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + + /* + * Compute the cutoff value between legal numbers and illegal + * numbers. That is the largest legal value, divided by the + * base. An input number that is greater than this value, if + * followed by a legal input character, is too big. One that + * is equal to this value may be valid or not; the limit + * between valid and invalid numbers is then based on the last + * digit. For instance, if the range for quads is + * [-9223372036854775808..9223372036854775807] and the input base + * is 10, cutoff will be set to 922337203685477580 and cutlim to + * either 7 (neg==0) or 8 (neg==1), meaning that if we have + * accumulated a value > 922337203685477580, or equal but the + * next digit is > 7 (or 8), the number is too big, and we will + * return a range error. + * + * Set any if any `digits' consumed; make it negative to indicate + * overflow. + */ + qbase = unsigned(base); + cutoff = neg ? qulonglong(0-(LLONG_MIN + LLONG_MAX)) + LLONG_MAX : LLONG_MAX; + cutlim = cutoff % qbase; + cutoff /= qbase; + for (acc = 0, any = 0;; c = *s++) { + if (!isascii(c)) + break; + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= qbase; + acc += c; + } + } + if (any < 0) { + acc = neg ? LLONG_MIN : LLONG_MAX; + if (ok != 0) + *ok = false; + } else if (neg) { + acc = (~acc) + 1; + } + if (endptr != 0) + *endptr = (any >= 0 ? s - 1 : nptr); + + if (ok != 0) + *ok = any > 0; + + return acc; +} + +#ifndef QT_QLOCALE_USES_FCVT + +/* From: NetBSD: strtod.c,v 1.26 1998/02/03 18:44:21 perry Exp */ +/* $FreeBSD: src/lib/libc/stdlib/netbsd_strtod.c,v 1.2.2.2 2001/03/02 17:14:15 tegge Exp $ */ + +/* Please send bug reports to + David M. Gay + AT&T Bell Laboratories, Room 2C-463 + 600 Mountain Avenue + Murray Hill, NJ 07974-2070 + U.S.A. + dmg@research.att.com or research!dmg + */ + +/* strtod for IEEE-, VAX-, and IBM-arithmetic machines. + * + * This strtod returns a nearest machine number to the input decimal + * string (or sets errno to ERANGE). With IEEE arithmetic, ties are + * broken by the IEEE round-even rule. Otherwise ties are broken by + * biased rounding (add half and chop). + * + * Inspired loosely by William D. Clinger's paper "How to Read Floating + * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101]. + * + * Modifications: + * + * 1. We only require IEEE, IBM, or VAX double-precision + * arithmetic (not IEEE double-extended). + * 2. We get by with floating-point arithmetic in a case that + * Clinger missed -- when we're computing d * 10^n + * for a small integer d and the integer n is not too + * much larger than 22 (the maximum integer k for which + * we can represent 10^k exactly), we may be able to + * compute (d*10^k) * 10^(e-k) with just one roundoff. + * 3. Rather than a bit-at-a-time adjustment of the binary + * result in the hard case, we use floating-point + * arithmetic to determine the adjustment to within + * one bit; only in really hard cases do we need to + * compute a second residual. + * 4. Because of 3., we don't need a large table of powers of 10 + * for ten-to-e (just some small tables, e.g. of 10^k + * for 0 <= k <= 22). + */ + +/* + * #define IEEE_LITTLE_ENDIAN for IEEE-arithmetic machines where the least + * significant byte has the lowest address. + * #define IEEE_BIG_ENDIAN for IEEE-arithmetic machines where the most + * significant byte has the lowest address. + * #define Long int on machines with 32-bit ints and 64-bit longs. + * #define Sudden_Underflow for IEEE-format machines without gradual + * underflow (i.e., that flush to zero on underflow). + * #define IBM for IBM mainframe-style floating-point arithmetic. + * #define VAX for VAX-style floating-point arithmetic. + * #define Unsigned_Shifts if >> does treats its left operand as unsigned. + * #define No_leftright to omit left-right logic in fast floating-point + * computation of dtoa. + * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3. + * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines + * that use extended-precision instructions to compute rounded + * products and quotients) with IBM. + * #define ROUND_BIASED for IEEE-format with biased rounding. + * #define Inaccurate_Divide for IEEE-format with correctly rounded + * products but inaccurate quotients, e.g., for Intel i860. + * #define Just_16 to store 16 bits per 32-bit Long when doing high-precision + * integer arithmetic. Whether this speeds things up or slows things + * down depends on the machine and the number being converted. + * #define KR_headers for old-style C function headers. + * #define Bad_float_h if your system lacks a float.h or if it does not + * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP, + * FLT_RADIX, FLT_ROUNDS, and DBL_MAX. + * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n) + * if memory is available and otherwise does something you deem + * appropriate. If MALLOC is undefined, malloc will be invoked + * directly -- and assumed always to succeed. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: strtod.c,v 1.26 1998/02/03 18:44:21 perry Exp $"); +#endif /* LIBC_SCCS and not lint */ + +/* +#if defined(__m68k__) || defined(__sparc__) || defined(__i386__) || \ + defined(__mips__) || defined(__ns32k__) || defined(__alpha__) || \ + defined(__powerpc__) || defined(Q_OS_WIN) || defined(Q_OS_DARWIN) || defined(Q_OS_MAC) || \ + defined(mips) || defined(Q_OS_AIX) || defined(Q_OS_SOLARIS) +# define IEEE_BIG_OR_LITTLE_ENDIAN 1 +#endif +*/ + +// *All* of our architectures have IEEE arithmetic, don't they? +#define IEEE_BIG_OR_LITTLE_ENDIAN 1 + +#ifdef __arm32__ +/* + * Although the CPU is little endian the FP has different + * byte and word endianness. The byte order is still little endian + * but the word order is big endian. + */ +#define IEEE_BIG_OR_LITTLE_ENDIAN +#endif + +#ifdef vax +#define VAX +#endif + +#define Long qint32 +#define ULong quint32 + +#define MALLOC malloc + +#ifdef BSD_QDTOA_DEBUG +QT_BEGIN_INCLUDE_NAMESPACE +#include +QT_END_INCLUDE_NAMESPACE + +#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);} +#endif + +#ifdef Unsigned_Shifts +#define Sign_Extend(a,b) if (b < 0) a |= 0xffff0000; +#else +#define Sign_Extend(a,b) /*no-op*/ +#endif + +#if (defined(IEEE_BIG_OR_LITTLE_ENDIAN) + defined(VAX) + defined(IBM)) != 1 +#error Exactly one of IEEE_BIG_OR_LITTLE_ENDIAN, VAX, or IBM should be defined. +#endif + +static inline ULong _getWord0(const NEEDS_VOLATILE double x) +{ + const NEEDS_VOLATILE uchar *ptr = reinterpret_cast(&x); + if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { + return (ptr[0]<<24) + (ptr[1]<<16) + (ptr[2]<<8) + ptr[3]; + } else { + return (ptr[7]<<24) + (ptr[6]<<16) + (ptr[5]<<8) + ptr[4]; + } +} + +static inline void _setWord0(NEEDS_VOLATILE double *x, ULong l) +{ + NEEDS_VOLATILE uchar *ptr = reinterpret_cast(x); + if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { + ptr[0] = uchar(l>>24); + ptr[1] = uchar(l>>16); + ptr[2] = uchar(l>>8); + ptr[3] = uchar(l); + } else { + ptr[7] = uchar(l>>24); + ptr[6] = uchar(l>>16); + ptr[5] = uchar(l>>8); + ptr[4] = uchar(l); + } +} + +static inline ULong _getWord1(const NEEDS_VOLATILE double x) +{ + const NEEDS_VOLATILE uchar *ptr = reinterpret_cast(&x); + if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { + return (ptr[4]<<24) + (ptr[5]<<16) + (ptr[6]<<8) + ptr[7]; + } else { + return (ptr[3]<<24) + (ptr[2]<<16) + (ptr[1]<<8) + ptr[0]; + } +} +static inline void _setWord1(NEEDS_VOLATILE double *x, ULong l) +{ + NEEDS_VOLATILE uchar *ptr = reinterpret_cast(x); + if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { + ptr[4] = uchar(l>>24); + ptr[5] = uchar(l>>16); + ptr[6] = uchar(l>>8); + ptr[7] = uchar(l); + } else { + ptr[3] = uchar(l>>24); + ptr[2] = uchar(l>>16); + ptr[1] = uchar(l>>8); + ptr[0] = uchar(l); + } +} + +static inline ULong getWord0(const NEEDS_VOLATILE double x) +{ +#ifdef QT_ARMFPA + return _getWord1(x); +#else + return _getWord0(x); +#endif +} + +static inline void setWord0(NEEDS_VOLATILE double *x, ULong l) +{ +#ifdef QT_ARMFPA + _setWord1(x, l); +#else + _setWord0(x, l); +#endif +} + +static inline ULong getWord1(const NEEDS_VOLATILE double x) +{ +#ifdef QT_ARMFPA + return _getWord0(x); +#else + return _getWord1(x); +#endif +} + +static inline void setWord1(NEEDS_VOLATILE double *x, ULong l) +{ +#ifdef QT_ARMFPA + _setWord0(x, l); +#else + _setWord1(x, l); +#endif +} + +static inline void Storeinc(ULong *&a, const ULong &b, const ULong &c) +{ + + *a = (ushort(b) << 16) | ushort(c); + ++a; +} + +/* #define P DBL_MANT_DIG */ +/* Ten_pmax = floor(P*log(2)/log(5)) */ +/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */ +/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */ +/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */ + +#if defined(IEEE_BIG_OR_LITTLE_ENDIAN) +#define Exp_shift 20 +#define Exp_shift1 20 +#define Exp_msk1 0x100000 +#define Exp_msk11 0x100000 +#define Exp_mask 0x7ff00000 +#define P 53 +#define Bias 1023 +#define IEEE_Arith +#define Emin (-1022) +#define Exp_1 0x3ff00000 +#define Exp_11 0x3ff00000 +#define Ebits 11 +#define Frac_mask 0xfffff +#define Frac_mask1 0xfffff +#define Ten_pmax 22 +#define Bletch 0x10 +#define Bndry_mask 0xfffff +#define Bndry_mask1 0xfffff +#if defined(LSB) && defined(Q_OS_VXWORKS) +#undef LSB +#endif +#define LSB 1 +#define Sign_bit 0x80000000 +#define Log2P 1 +#define Tiny0 0 +#define Tiny1 1 +#define Quick_max 14 +#define Int_max 14 +#define Infinite(x) (getWord0(x) == 0x7ff00000) /* sufficient test for here */ +#else +#undef Sudden_Underflow +#define Sudden_Underflow +#ifdef IBM +#define Exp_shift 24 +#define Exp_shift1 24 +#define Exp_msk1 0x1000000 +#define Exp_msk11 0x1000000 +#define Exp_mask 0x7f000000 +#define P 14 +#define Bias 65 +#define Exp_1 0x41000000 +#define Exp_11 0x41000000 +#define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */ +#define Frac_mask 0xffffff +#define Frac_mask1 0xffffff +#define Bletch 4 +#define Ten_pmax 22 +#define Bndry_mask 0xefffff +#define Bndry_mask1 0xffffff +#define LSB 1 +#define Sign_bit 0x80000000 +#define Log2P 4 +#define Tiny0 0x100000 +#define Tiny1 0 +#define Quick_max 14 +#define Int_max 15 +#else /* VAX */ +#define Exp_shift 23 +#define Exp_shift1 7 +#define Exp_msk1 0x80 +#define Exp_msk11 0x800000 +#define Exp_mask 0x7f80 +#define P 56 +#define Bias 129 +#define Exp_1 0x40800000 +#define Exp_11 0x4080 +#define Ebits 8 +#define Frac_mask 0x7fffff +#define Frac_mask1 0xffff007f +#define Ten_pmax 24 +#define Bletch 2 +#define Bndry_mask 0xffff007f +#define Bndry_mask1 0xffff007f +#define LSB 0x10000 +#define Sign_bit 0x8000 +#define Log2P 1 +#define Tiny0 0x80 +#define Tiny1 0 +#define Quick_max 15 +#define Int_max 15 +#endif +#endif + +#ifndef IEEE_Arith +#define ROUND_BIASED +#endif + +#ifdef RND_PRODQUOT +#define rounded_product(a,b) a = rnd_prod(a, b) +#define rounded_quotient(a,b) a = rnd_quot(a, b) +extern double rnd_prod(double, double), rnd_quot(double, double); +#else +#define rounded_product(a,b) a *= b +#define rounded_quotient(a,b) a /= b +#endif + +#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) +#define Big1 0xffffffff + +#ifndef Just_16 +/* When Pack_32 is not defined, we store 16 bits per 32-bit Long. + * This makes some inner loops simpler and sometimes saves work + * during multiplications, but it often seems to make things slightly + * slower. Hence the default is now to store 32 bits per Long. + */ +#ifndef Pack_32 +#define Pack_32 +#endif +#endif + +#define Kmax 15 + +struct +Bigint { + struct Bigint *next; + int k, maxwds, sign, wds; + ULong x[1]; +}; + + typedef struct Bigint Bigint; + +static Bigint *Balloc(int k) +{ + int x; + Bigint *rv; + + x = 1 << k; + rv = static_cast(MALLOC(sizeof(Bigint) + (x-1)*sizeof(Long))); + Q_CHECK_PTR(rv); + rv->k = k; + rv->maxwds = x; + rv->sign = rv->wds = 0; + return rv; +} + +static void Bfree(Bigint *v) +{ + free(v); +} + +#define Bcopy(x,y) memcpy(reinterpret_cast(&x->sign), reinterpret_cast(&y->sign), \ +y->wds*sizeof(Long) + 2*sizeof(int)) + +/* multiply by m and add a */ +static Bigint *multadd(Bigint *b, int m, int a) +{ + int i, wds; + ULong *x, y; +#ifdef Pack_32 + ULong xi, z; +#endif + Bigint *b1; + + wds = b->wds; + x = b->x; + i = 0; + do { +#ifdef Pack_32 + xi = *x; + y = (xi & 0xffff) * m + a; + z = (xi >> 16) * m + (y >> 16); + a = (z >> 16); + *x++ = (z << 16) + (y & 0xffff); +#else + y = *x * m + a; + a = (y >> 16); + *x++ = y & 0xffff; +#endif + } + while(++i < wds); + if (a) { + if (wds >= b->maxwds) { + b1 = Balloc(b->k+1); + Bcopy(b1, b); + Bfree(b); + b = b1; + } + b->x[wds++] = a; + b->wds = wds; + } + return b; +} + +static Bigint *s2b(const char *s, int nd0, int nd, ULong y9) +{ + Bigint *b; + int i, k; + Long x, y; + + x = (nd + 8) / 9; + for(k = 0, y = 1; x > y; y <<= 1, k++) ; +#ifdef Pack_32 + b = Balloc(k); + b->x[0] = y9; + b->wds = 1; +#else + b = Balloc(k+1); + b->x[0] = y9 & 0xffff; + b->wds = (b->x[1] = y9 >> 16) ? 2 : 1; +#endif + + i = 9; + if (9 < nd0) { + s += 9; + do b = multadd(b, 10, *s++ - '0'); + while(++i < nd0); + s++; + } + else + s += 10; + for(; i < nd; i++) + b = multadd(b, 10, *s++ - '0'); + return b; +} + +static int hi0bits(ULong x) +{ + int k = 0; + + if (!(x & 0xffff0000)) { + k = 16; + x <<= 16; + } + if (!(x & 0xff000000)) { + k += 8; + x <<= 8; + } + if (!(x & 0xf0000000)) { + k += 4; + x <<= 4; + } + if (!(x & 0xc0000000)) { + k += 2; + x <<= 2; + } + if (!(x & 0x80000000)) { + k++; + if (!(x & 0x40000000)) + return 32; + } + return k; +} + +static int lo0bits(ULong *y) +{ + int k; + ULong x = *y; + + if (x & 7) { + if (x & 1) + return 0; + if (x & 2) { + *y = x >> 1; + return 1; + } + *y = x >> 2; + return 2; + } + k = 0; + if (!(x & 0xffff)) { + k = 16; + x >>= 16; + } + if (!(x & 0xff)) { + k += 8; + x >>= 8; + } + if (!(x & 0xf)) { + k += 4; + x >>= 4; + } + if (!(x & 0x3)) { + k += 2; + x >>= 2; + } + if (!(x & 1)) { + k++; + x >>= 1; + if (!x & 1) + return 32; + } + *y = x; + return k; +} + +static Bigint *i2b(int i) +{ + Bigint *b; + + b = Balloc(1); + b->x[0] = i; + b->wds = 1; + return b; +} + +static Bigint *mult(Bigint *a, Bigint *b) +{ + Bigint *c; + int k, wa, wb, wc; + ULong carry, y, z; + ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0; +#ifdef Pack_32 + ULong z2; +#endif + + if (a->wds < b->wds) { + c = a; + a = b; + b = c; + } + k = a->k; + wa = a->wds; + wb = b->wds; + wc = wa + wb; + if (wc > a->maxwds) + k++; + c = Balloc(k); + for(x = c->x, xa = x + wc; x < xa; x++) + *x = 0; + xa = a->x; + xae = xa + wa; + xb = b->x; + xbe = xb + wb; + xc0 = c->x; +#ifdef Pack_32 + for(; xb < xbe; xb++, xc0++) { + if ((y = *xb & 0xffff) != 0) { + x = xa; + xc = xc0; + carry = 0; + do { + z = (*x & 0xffff) * y + (*xc & 0xffff) + carry; + carry = z >> 16; + z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; + carry = z2 >> 16; + Storeinc(xc, z2, z); + } + while(x < xae); + *xc = carry; + } + if ((y = *xb >> 16) != 0) { + x = xa; + xc = xc0; + carry = 0; + z2 = *xc; + do { + z = (*x & 0xffff) * y + (*xc >> 16) + carry; + carry = z >> 16; + Storeinc(xc, z, z2); + z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; + carry = z2 >> 16; + } + while(x < xae); + *xc = z2; + } + } +#else + for(; xb < xbe; xc0++) { + if (y = *xb++) { + x = xa; + xc = xc0; + carry = 0; + do { + z = *x++ * y + *xc + carry; + carry = z >> 16; + *xc++ = z & 0xffff; + } + while(x < xae); + *xc = carry; + } + } +#endif + for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ; + c->wds = wc; + return c; +} + +static Bigint *p5s; + +struct p5s_deleter +{ + ~p5s_deleter() + { + while (p5s) { + Bigint *next = p5s->next; + Bfree(p5s); + p5s = next; + } + } +}; + +static Bigint *pow5mult(Bigint *b, int k) +{ + Bigint *b1, *p5, *p51; + int i; + static const int p05[3] = { 5, 25, 125 }; + + if ((i = k & 3) != 0) +#if defined(Q_OS_IRIX) && defined(Q_CC_GNU) + { + // work around a bug on 64 bit IRIX gcc + int *p = (int *) p05; + b = multadd(b, p[i-1], 0); + } +#else + b = multadd(b, p05[i-1], 0); +#endif + + if (!(k >>= 2)) + return b; + if (!(p5 = p5s)) { + /* first time */ + static p5s_deleter deleter; + p5 = p5s = i2b(625); + p5->next = 0; + } + for(;;) { + if (k & 1) { + b1 = mult(b, p5); + Bfree(b); + b = b1; + } + if (!(k >>= 1)) + break; + if (!(p51 = p5->next)) { + p51 = p5->next = mult(p5,p5); + p51->next = 0; + } + p5 = p51; + } + return b; +} + +static Bigint *lshift(Bigint *b, int k) +{ + int i, k1, n, n1; + Bigint *b1; + ULong *x, *x1, *xe, z; + +#ifdef Pack_32 + n = k >> 5; +#else + n = k >> 4; +#endif + k1 = b->k; + n1 = n + b->wds + 1; + for(i = b->maxwds; n1 > i; i <<= 1) + k1++; + b1 = Balloc(k1); + x1 = b1->x; + for(i = 0; i < n; i++) + *x1++ = 0; + x = b->x; + xe = x + b->wds; +#ifdef Pack_32 + if (k &= 0x1f) { + k1 = 32 - k; + z = 0; + do { + *x1++ = *x << k | z; + z = *x++ >> k1; + } + while(x < xe); + if ((*x1 = z) != 0) + ++n1; + } +#else + if (k &= 0xf) { + k1 = 16 - k; + z = 0; + do { + *x1++ = *x << k & 0xffff | z; + z = *x++ >> k1; + } + while(x < xe); + if (*x1 = z) + ++n1; + } +#endif + else do + *x1++ = *x++; + while(x < xe); + b1->wds = n1 - 1; + Bfree(b); + return b1; +} + +static int cmp(Bigint *a, Bigint *b) +{ + ULong *xa, *xa0, *xb, *xb0; + int i, j; + + i = a->wds; + j = b->wds; +#ifdef BSD_QDTOA_DEBUG + if (i > 1 && !a->x[i-1]) + Bug("cmp called with a->x[a->wds-1] == 0"); + if (j > 1 && !b->x[j-1]) + Bug("cmp called with b->x[b->wds-1] == 0"); +#endif + if (i -= j) + return i; + xa0 = a->x; + xa = xa0 + j; + xb0 = b->x; + xb = xb0 + j; + for(;;) { + if (*--xa != *--xb) + return *xa < *xb ? -1 : 1; + if (xa <= xa0) + break; + } + return 0; +} + +static Bigint *diff(Bigint *a, Bigint *b) +{ + Bigint *c; + int i, wa, wb; + Long borrow, y; /* We need signed shifts here. */ + ULong *xa, *xae, *xb, *xbe, *xc; +#ifdef Pack_32 + Long z; +#endif + + i = cmp(a,b); + if (!i) { + c = Balloc(0); + c->wds = 1; + c->x[0] = 0; + return c; + } + if (i < 0) { + c = a; + a = b; + b = c; + i = 1; + } + else + i = 0; + c = Balloc(a->k); + c->sign = i; + wa = a->wds; + xa = a->x; + xae = xa + wa; + wb = b->wds; + xb = b->x; + xbe = xb + wb; + xc = c->x; + borrow = 0; +#ifdef Pack_32 + do { + y = (*xa & 0xffff) - (*xb & 0xffff) + borrow; + borrow = y >> 16; + Sign_Extend(borrow, y); + z = (*xa++ >> 16) - (*xb++ >> 16) + borrow; + borrow = z >> 16; + Sign_Extend(borrow, z); + Storeinc(xc, z, y); + } + while(xb < xbe); + while(xa < xae) { + y = (*xa & 0xffff) + borrow; + borrow = y >> 16; + Sign_Extend(borrow, y); + z = (*xa++ >> 16) + borrow; + borrow = z >> 16; + Sign_Extend(borrow, z); + Storeinc(xc, z, y); + } +#else + do { + y = *xa++ - *xb++ + borrow; + borrow = y >> 16; + Sign_Extend(borrow, y); + *xc++ = y & 0xffff; + } + while(xb < xbe); + while(xa < xae) { + y = *xa++ + borrow; + borrow = y >> 16; + Sign_Extend(borrow, y); + *xc++ = y & 0xffff; + } +#endif + while(!*--xc) + wa--; + c->wds = wa; + return c; +} + +static double ulp(double x) +{ + Long L; + double a; + + L = (getWord0(x) & Exp_mask) - (P-1)*Exp_msk1; +#ifndef Sudden_Underflow + if (L > 0) { +#endif +#ifdef IBM + L |= Exp_msk1 >> 4; +#endif + setWord0(&a, L); + setWord1(&a, 0); +#ifndef Sudden_Underflow + } + else { + L = -L >> Exp_shift; + if (L < Exp_shift) { + setWord0(&a, 0x80000 >> L); + setWord1(&a, 0); + } + else { + setWord0(&a, 0); + L -= Exp_shift; + setWord1(&a, L >= 31 ? 1U : 1U << (31 - L)); + } + } +#endif + return a; +} + +static double b2d(Bigint *a, int *e) +{ + ULong *xa, *xa0, w, y, z; + int k; + double d; + + xa0 = a->x; + xa = xa0 + a->wds; + y = *--xa; +#ifdef BSD_QDTOA_DEBUG + if (!y) Bug("zero y in b2d"); +#endif + k = hi0bits(y); + *e = 32 - k; +#ifdef Pack_32 + if (k < Ebits) { + setWord0(&d, Exp_1 | y >> (Ebits - k)); + w = xa > xa0 ? *--xa : 0; + setWord1(&d, y << ((32-Ebits) + k) | w >> (Ebits - k)); + goto ret_d; + } + z = xa > xa0 ? *--xa : 0; + if (k -= Ebits) { + setWord0(&d, Exp_1 | y << k | z >> (32 - k)); + y = xa > xa0 ? *--xa : 0; + setWord1(&d, z << k | y >> (32 - k)); + } + else { + setWord0(&d, Exp_1 | y); + setWord1(&d, z); + } +#else + if (k < Ebits + 16) { + z = xa > xa0 ? *--xa : 0; + setWord0(&d, Exp_1 | y << k - Ebits | z >> Ebits + 16 - k); + w = xa > xa0 ? *--xa : 0; + y = xa > xa0 ? *--xa : 0; + setWord1(&d, z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k); + goto ret_d; + } + z = xa > xa0 ? *--xa : 0; + w = xa > xa0 ? *--xa : 0; + k -= Ebits + 16; + setWord0(&d, Exp_1 | y << k + 16 | z << k | w >> 16 - k); + y = xa > xa0 ? *--xa : 0; + setWord1(&d, w << k + 16 | y << k); +#endif + ret_d: + return d; +} + +static Bigint *d2b(double d, int *e, int *bits) +{ + Bigint *b; + int de, i, k; + ULong *x, y, z; + +#ifdef Pack_32 + b = Balloc(1); +#else + b = Balloc(2); +#endif + x = b->x; + + z = getWord0(d) & Frac_mask; + setWord0(&d, getWord0(d) & 0x7fffffff); /* clear sign bit, which we ignore */ +#ifdef Sudden_Underflow + de = (int)(getWord0(d) >> Exp_shift); +#ifndef IBM + z |= Exp_msk11; +#endif +#else + if ((de = int(getWord0(d) >> Exp_shift)) != 0) + z |= Exp_msk1; +#endif +#ifdef Pack_32 + if ((y = getWord1(d)) != 0) { + if ((k = lo0bits(&y)) != 0) { + x[0] = y | z << (32 - k); + z >>= k; + } + else + x[0] = y; + i = b->wds = (x[1] = z) ? 2 : 1; + } + else { +#ifdef BSD_QDTOA_DEBUG + if (!z) + Bug("Zero passed to d2b"); +#endif + k = lo0bits(&z); + x[0] = z; + i = b->wds = 1; + k += 32; + } +#else + if (y = getWord1(d)) { + if (k = lo0bits(&y)) + if (k >= 16) { + x[0] = y | z << 32 - k & 0xffff; + x[1] = z >> k - 16 & 0xffff; + x[2] = z >> k; + i = 2; + } + else { + x[0] = y & 0xffff; + x[1] = y >> 16 | z << 16 - k & 0xffff; + x[2] = z >> k & 0xffff; + x[3] = z >> k+16; + i = 3; + } + else { + x[0] = y & 0xffff; + x[1] = y >> 16; + x[2] = z & 0xffff; + x[3] = z >> 16; + i = 3; + } + } + else { +#ifdef BSD_QDTOA_DEBUG + if (!z) + Bug("Zero passed to d2b"); +#endif + k = lo0bits(&z); + if (k >= 16) { + x[0] = z; + i = 0; + } + else { + x[0] = z & 0xffff; + x[1] = z >> 16; + i = 1; + } + k += 32; + } + while(!x[i]) + --i; + b->wds = i + 1; +#endif +#ifndef Sudden_Underflow + if (de) { +#endif +#ifdef IBM + *e = (de - Bias - (P-1) << 2) + k; + *bits = 4*P + 8 - k - hi0bits(getWord0(d) & Frac_mask); +#else + *e = de - Bias - (P-1) + k; + *bits = P - k; +#endif +#ifndef Sudden_Underflow + } + else { + *e = de - Bias - (P-1) + 1 + k; +#ifdef Pack_32 + *bits = 32*i - hi0bits(x[i-1]); +#else + *bits = (i+2)*16 - hi0bits(x[i]); +#endif + } +#endif + return b; +} + +static double ratio(Bigint *a, Bigint *b) +{ + double da, db; + int k, ka, kb; + + da = b2d(a, &ka); + db = b2d(b, &kb); +#ifdef Pack_32 + k = ka - kb + 32*(a->wds - b->wds); +#else + k = ka - kb + 16*(a->wds - b->wds); +#endif +#ifdef IBM + if (k > 0) { + setWord0(&da, getWord0(da) + (k >> 2)*Exp_msk1); + if (k &= 3) + da *= 1 << k; + } + else { + k = -k; + setWord0(&db, getWord0(db) + (k >> 2)*Exp_msk1); + if (k &= 3) + db *= 1 << k; + } +#else + if (k > 0) + setWord0(&da, getWord0(da) + k*Exp_msk1); + else { + k = -k; + setWord0(&db, getWord0(db) + k*Exp_msk1); + } +#endif + return da / db; +} + +static const double tens[] = { + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, + 1e20, 1e21, 1e22 +#ifdef VAX + , 1e23, 1e24 +#endif +}; + +#ifdef IEEE_Arith +static const double bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; +static const double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, 1e-256 }; +#define n_bigtens 5 +#else +#ifdef IBM +static const double bigtens[] = { 1e16, 1e32, 1e64 }; +static const double tinytens[] = { 1e-16, 1e-32, 1e-64 }; +#define n_bigtens 3 +#else +static const double bigtens[] = { 1e16, 1e32 }; +static const double tinytens[] = { 1e-16, 1e-32 }; +#define n_bigtens 2 +#endif +#endif + +/* + The pre-release gcc3.3 shipped with SuSE 8.2 has a bug which causes + the comparison 1e-100 == 0.0 to return true. As a workaround, we + compare it to a global variable containing 0.0, which produces + correct assembler output. + + ### consider detecting the broken compilers and using the static + ### double for these, and use a #define for all working compilers +*/ +static double g_double_zero = 0.0; + +Q_CORE_EXPORT double qstrtod(const char *s00, const char **se, bool *ok) +{ + int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign, + e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign; + const char *s, *s0, *s1; + double aadj, aadj1, adj, rv, rv0; + Long L; + ULong y, z; + Bigint *bb1, *bd0; + Bigint *bb = NULL, *bd = NULL, *bs = NULL, *delta = NULL;/* pacify gcc */ + + /* + #ifndef KR_headers + const char decimal_point = localeconv()->decimal_point[0]; + #else + const char decimal_point = '.'; + #endif */ + if (ok != 0) + *ok = true; + + const char decimal_point = '.'; + + sign = nz0 = nz = 0; + rv = 0.; + + + for(s = s00; isspace(uchar(*s)); s++) + ; + + if (*s == '-') { + sign = 1; + s++; + } else if (*s == '+') { + s++; + } + + if (*s == '\0') { + s = s00; + goto ret; + } + + if (*s == '0') { + nz0 = 1; + while(*++s == '0') ; + if (!*s) + goto ret; + } + s0 = s; + y = z = 0; + for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) + if (nd < 9) + y = 10*y + c - '0'; + else if (nd < 16) + z = 10*z + c - '0'; + nd0 = nd; + if (c == decimal_point) { + c = *++s; + if (!nd) { + for(; c == '0'; c = *++s) + nz++; + if (c > '0' && c <= '9') { + s0 = s; + nf += nz; + nz = 0; + goto have_dig; + } + goto dig_done; + } + for(; c >= '0' && c <= '9'; c = *++s) { + have_dig: + nz++; + if (c -= '0') { + nf += nz; + for(i = 1; i < nz; i++) + if (nd++ < 9) + y *= 10; + else if (nd <= DBL_DIG + 1) + z *= 10; + if (nd++ < 9) + y = 10*y + c; + else if (nd <= DBL_DIG + 1) + z = 10*z + c; + nz = 0; + } + } + } + dig_done: + e = 0; + if (c == 'e' || c == 'E') { + if (!nd && !nz && !nz0) { + s = s00; + goto ret; + } + s00 = s; + esign = 0; + switch(c = *++s) { + case '-': + esign = 1; + case '+': + c = *++s; + } + if (c >= '0' && c <= '9') { + while(c == '0') + c = *++s; + if (c > '0' && c <= '9') { + L = c - '0'; + s1 = s; + while((c = *++s) >= '0' && c <= '9') + L = 10*L + c - '0'; + if (s - s1 > 8 || L > 19999) + /* Avoid confusion from exponents + * so large that e might overflow. + */ + e = 19999; /* safe for 16 bit ints */ + else + e = int(L); + if (esign) + e = -e; + } + else + e = 0; + } + else + s = s00; + } + if (!nd) { + if (!nz && !nz0) + s = s00; + goto ret; + } + e1 = e -= nf; + + /* Now we have nd0 digits, starting at s0, followed by a + * decimal point, followed by nd-nd0 digits. The number we're + * after is the integer represented by those digits times + * 10**e */ + + if (!nd0) + nd0 = nd; + k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; + rv = y; + if (k > 9) +#if defined(Q_OS_IRIX) && defined(Q_CC_GNU) + { + // work around a bug on 64 bit IRIX gcc + double *t = (double *) tens; + rv = t[k - 9] * rv + z; + } +#else + rv = tens[k - 9] * rv + z; +#endif + + bd0 = 0; + if (nd <= DBL_DIG +#ifndef RND_PRODQUOT + && FLT_ROUNDS == 1 +#endif + ) { + if (!e) + goto ret; + if (e > 0) { + if (e <= Ten_pmax) { +#ifdef VAX + goto vax_ovfl_check; +#else + /* rv = */ rounded_product(rv, tens[e]); + goto ret; +#endif + } + i = DBL_DIG - nd; + if (e <= Ten_pmax + i) { + /* A fancier test would sometimes let us do + * this for larger i values. + */ + e -= i; + rv *= tens[i]; +#ifdef VAX + /* VAX exponent range is so narrow we must + * worry about overflow here... + */ + vax_ovfl_check: + setWord0(&rv, getWord0(rv) - P*Exp_msk1); + /* rv = */ rounded_product(rv, tens[e]); + if ((getWord0(rv) & Exp_mask) + > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) + goto ovfl; + setWord0(&rv, getWord0(rv) + P*Exp_msk1); +#else + /* rv = */ rounded_product(rv, tens[e]); +#endif + goto ret; + } + } +#ifndef Inaccurate_Divide + else if (e >= -Ten_pmax) { + /* rv = */ rounded_quotient(rv, tens[-e]); + goto ret; + } +#endif + } + e1 += nd - k; + + /* Get starting approximation = rv * 10**e1 */ + + if (e1 > 0) { + if ((i = e1 & 15) != 0) + rv *= tens[i]; + if (e1 &= ~15) { + if (e1 > DBL_MAX_10_EXP) { + ovfl: + // errno = ERANGE; + if (ok != 0) + *ok = false; +#ifdef __STDC__ + rv = HUGE_VAL; +#else + /* Can't trust HUGE_VAL */ +#ifdef IEEE_Arith + setWord0(&rv, Exp_mask); + setWord1(&rv, 0); +#else + setWord0(&rv, Big0); + setWord1(&rv, Big1); +#endif +#endif + if (bd0) + goto retfree; + goto ret; + } + if (e1 >>= 4) { + for(j = 0; e1 > 1; j++, e1 >>= 1) + if (e1 & 1) + rv *= bigtens[j]; + /* The last multiplication could overflow. */ + setWord0(&rv, getWord0(rv) - P*Exp_msk1); + rv *= bigtens[j]; + if ((z = getWord0(rv) & Exp_mask) + > Exp_msk1*(DBL_MAX_EXP+Bias-P)) + goto ovfl; + if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) { + /* set to largest number */ + /* (Can't trust DBL_MAX) */ + setWord0(&rv, Big0); + setWord1(&rv, Big1); + } + else + setWord0(&rv, getWord0(rv) + P*Exp_msk1); + } + + } + } + else if (e1 < 0) { + e1 = -e1; + if ((i = e1 & 15) != 0) + rv /= tens[i]; + if (e1 &= ~15) { + e1 >>= 4; + if (e1 >= 1 << n_bigtens) + goto undfl; + for(j = 0; e1 > 1; j++, e1 >>= 1) + if (e1 & 1) + rv *= tinytens[j]; + /* The last multiplication could underflow. */ + rv0 = rv; + rv *= tinytens[j]; + if (rv == g_double_zero) + { + rv = 2.*rv0; + rv *= tinytens[j]; + if (rv == g_double_zero) + { + undfl: + rv = 0.; + // errno = ERANGE; + if (ok != 0) + *ok = false; + if (bd0) + goto retfree; + goto ret; + } + setWord0(&rv, Tiny0); + setWord1(&rv, Tiny1); + /* The refinement below will clean + * this approximation up. + */ + } + } + } + + /* Now the hard part -- adjusting rv to the correct value.*/ + + /* Put digits into bd: true value = bd * 10^e */ + + bd0 = s2b(s0, nd0, nd, y); + + for(;;) { + bd = Balloc(bd0->k); + Bcopy(bd, bd0); + bb = d2b(rv, &bbe, &bbbits); /* rv = bb * 2^bbe */ + bs = i2b(1); + + if (e >= 0) { + bb2 = bb5 = 0; + bd2 = bd5 = e; + } + else { + bb2 = bb5 = -e; + bd2 = bd5 = 0; + } + if (bbe >= 0) + bb2 += bbe; + else + bd2 -= bbe; + bs2 = bb2; +#ifdef Sudden_Underflow +#ifdef IBM + j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3); +#else + j = P + 1 - bbbits; +#endif +#else + i = bbe + bbbits - 1; /* logb(rv) */ + if (i < Emin) /* denormal */ + j = bbe + (P-Emin); + else + j = P + 1 - bbbits; +#endif + bb2 += j; + bd2 += j; + i = bb2 < bd2 ? bb2 : bd2; + if (i > bs2) + i = bs2; + if (i > 0) { + bb2 -= i; + bd2 -= i; + bs2 -= i; + } + if (bb5 > 0) { + bs = pow5mult(bs, bb5); + bb1 = mult(bs, bb); + Bfree(bb); + bb = bb1; + } + if (bb2 > 0) + bb = lshift(bb, bb2); + if (bd5 > 0) + bd = pow5mult(bd, bd5); + if (bd2 > 0) + bd = lshift(bd, bd2); + if (bs2 > 0) + bs = lshift(bs, bs2); + delta = diff(bb, bd); + dsign = delta->sign; + delta->sign = 0; + i = cmp(delta, bs); + if (i < 0) { + /* Error is less than half an ulp -- check for + * special case of mantissa a power of two. + */ + if (dsign || getWord1(rv) || getWord0(rv) & Bndry_mask) + break; + delta = lshift(delta,Log2P); + if (cmp(delta, bs) > 0) + goto drop_down; + break; + } + if (i == 0) { + /* exactly half-way between */ + if (dsign) { + if ((getWord0(rv) & Bndry_mask1) == Bndry_mask1 + && getWord1(rv) == 0xffffffff) { + /*boundary case -- increment exponent*/ + setWord0(&rv, (getWord0(rv) & Exp_mask) + + Exp_msk1 +#ifdef IBM + | Exp_msk1 >> 4 +#endif + ); + setWord1(&rv, 0); + break; + } + } + else if (!(getWord0(rv) & Bndry_mask) && !getWord1(rv)) { + drop_down: + /* boundary case -- decrement exponent */ +#ifdef Sudden_Underflow + L = getWord0(rv) & Exp_mask; +#ifdef IBM + if (L < Exp_msk1) +#else + if (L <= Exp_msk1) +#endif + goto undfl; + L -= Exp_msk1; +#else + L = (getWord0(rv) & Exp_mask) - Exp_msk1; +#endif + setWord0(&rv, L | Bndry_mask1); + setWord1(&rv, 0xffffffff); +#ifdef IBM + goto cont; +#else + break; +#endif + } +#ifndef ROUND_BIASED + if (!(getWord1(rv) & LSB)) + break; +#endif + if (dsign) + rv += ulp(rv); +#ifndef ROUND_BIASED + else { + rv -= ulp(rv); +#ifndef Sudden_Underflow + if (rv == g_double_zero) + goto undfl; +#endif + } +#endif + break; + } + if ((aadj = ratio(delta, bs)) <= 2.) { + if (dsign) + aadj = aadj1 = 1.; + else if (getWord1(rv) || getWord0(rv) & Bndry_mask) { +#ifndef Sudden_Underflow + if (getWord1(rv) == Tiny1 && !getWord0(rv)) + goto undfl; +#endif + aadj = 1.; + aadj1 = -1.; + } + else { + /* special case -- power of FLT_RADIX to be */ + /* rounded down... */ + + if (aadj < 2./FLT_RADIX) + aadj = 1./FLT_RADIX; + else + aadj *= 0.5; + aadj1 = -aadj; + } + } + else { + aadj *= 0.5; + aadj1 = dsign ? aadj : -aadj; +#ifdef Check_FLT_ROUNDS + switch(FLT_ROUNDS) { + case 2: /* towards +infinity */ + aadj1 -= 0.5; + break; + case 0: /* towards 0 */ + case 3: /* towards -infinity */ + aadj1 += 0.5; + } +#else + if (FLT_ROUNDS == 0) + aadj1 += 0.5; +#endif + } + y = getWord0(rv) & Exp_mask; + + /* Check for overflow */ + + if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) { + rv0 = rv; + setWord0(&rv, getWord0(rv) - P*Exp_msk1); + adj = aadj1 * ulp(rv); + rv += adj; + if ((getWord0(rv) & Exp_mask) >= + Exp_msk1*(DBL_MAX_EXP+Bias-P)) { + if (getWord0(rv0) == Big0 && getWord1(rv0) == Big1) + goto ovfl; + setWord0(&rv, Big0); + setWord1(&rv, Big1); + goto cont; + } + else + setWord0(&rv, getWord0(rv) + P*Exp_msk1); + } + else { +#ifdef Sudden_Underflow + if ((getWord0(rv) & Exp_mask) <= P*Exp_msk1) { + rv0 = rv; + setWord0(&rv, getWord0(rv) + P*Exp_msk1); + adj = aadj1 * ulp(rv); + rv += adj; +#ifdef IBM + if ((getWord0(rv) & Exp_mask) < P*Exp_msk1) +#else + if ((getWord0(rv) & Exp_mask) <= P*Exp_msk1) +#endif + { + if (getWord0(rv0) == Tiny0 + && getWord1(rv0) == Tiny1) + goto undfl; + setWord0(&rv, Tiny0); + setWord1(&rv, Tiny1); + goto cont; + } + else + setWord0(&rv, getWord0(rv) - P*Exp_msk1); + } + else { + adj = aadj1 * ulp(rv); + rv += adj; + } +#else + /* Compute adj so that the IEEE rounding rules will + * correctly round rv + adj in some half-way cases. + * If rv * ulp(rv) is denormalized (i.e., + * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid + * trouble from bits lost to denormalization; + * example: 1.2e-307 . + */ + if (y <= (P-1)*Exp_msk1 && aadj >= 1.) { + aadj1 = int(aadj + 0.5); + if (!dsign) + aadj1 = -aadj1; + } + adj = aadj1 * ulp(rv); + rv += adj; +#endif + } + z = getWord0(rv) & Exp_mask; + if (y == z) { + /* Can we stop now? */ + L = Long(aadj); + aadj -= L; + /* The tolerances below are conservative. */ + if (dsign || getWord1(rv) || getWord0(rv) & Bndry_mask) { + if (aadj < .4999999 || aadj > .5000001) + break; + } + else if (aadj < .4999999/FLT_RADIX) + break; + } + cont: + Bfree(bb); + Bfree(bd); + Bfree(bs); + Bfree(delta); + } + retfree: + Bfree(bb); + Bfree(bd); + Bfree(bs); + Bfree(bd0); + Bfree(delta); + ret: + if (se) + *se = s; + return sign ? -rv : rv; +} + +static int quorem(Bigint *b, Bigint *S) +{ + int n; + Long borrow, y; + ULong carry, q, ys; + ULong *bx, *bxe, *sx, *sxe; +#ifdef Pack_32 + Long z; + ULong si, zs; +#endif + + n = S->wds; +#ifdef BSD_QDTOA_DEBUG + /*debug*/ if (b->wds > n) + /*debug*/ Bug("oversize b in quorem"); +#endif + if (b->wds < n) + return 0; + sx = S->x; + sxe = sx + --n; + bx = b->x; + bxe = bx + n; + q = *bxe / (*sxe + 1); /* ensure q <= true quotient */ +#ifdef BSD_QDTOA_DEBUG + /*debug*/ if (q > 9) + /*debug*/ Bug("oversized quotient in quorem"); +#endif + if (q) { + borrow = 0; + carry = 0; + do { +#ifdef Pack_32 + si = *sx++; + ys = (si & 0xffff) * q + carry; + zs = (si >> 16) * q + (ys >> 16); + carry = zs >> 16; + y = (*bx & 0xffff) - (ys & 0xffff) + borrow; + borrow = y >> 16; + Sign_Extend(borrow, y); + z = (*bx >> 16) - (zs & 0xffff) + borrow; + borrow = z >> 16; + Sign_Extend(borrow, z); + Storeinc(bx, z, y); +#else + ys = *sx++ * q + carry; + carry = ys >> 16; + y = *bx - (ys & 0xffff) + borrow; + borrow = y >> 16; + Sign_Extend(borrow, y); + *bx++ = y & 0xffff; +#endif + } + while(sx <= sxe); + if (!*bxe) { + bx = b->x; + while(--bxe > bx && !*bxe) + --n; + b->wds = n; + } + } + if (cmp(b, S) >= 0) { + q++; + borrow = 0; + carry = 0; + bx = b->x; + sx = S->x; + do { +#ifdef Pack_32 + si = *sx++; + ys = (si & 0xffff) + carry; + zs = (si >> 16) + (ys >> 16); + carry = zs >> 16; + y = (*bx & 0xffff) - (ys & 0xffff) + borrow; + borrow = y >> 16; + Sign_Extend(borrow, y); + z = (*bx >> 16) - (zs & 0xffff) + borrow; + borrow = z >> 16; + Sign_Extend(borrow, z); + Storeinc(bx, z, y); +#else + ys = *sx++ + carry; + carry = ys >> 16; + y = *bx - (ys & 0xffff) + borrow; + borrow = y >> 16; + Sign_Extend(borrow, y); + *bx++ = y & 0xffff; +#endif + } + while(sx <= sxe); + bx = b->x; + bxe = bx + n; + if (!*bxe) { + while(--bxe > bx && !*bxe) + --n; + b->wds = n; + } + } + return q; +} + +/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. + * + * Inspired by "How to Print Floating-Point Numbers Accurately" by + * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 92-101]. + * + * Modifications: + * 1. Rather than iterating, we use a simple numeric overestimate + * to determine k = floor(log10(d)). We scale relevant + * quantities using O(log2(k)) rather than O(k) multiplications. + * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't + * try to generate digits strictly left to right. Instead, we + * compute with fewer bits and propagate the carry if necessary + * when rounding the final digit up. This is often faster. + * 3. Under the assumption that input will be rounded nearest, + * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22. + * That is, we allow equality in stopping tests when the + * round-nearest rule will give the same floating-point value + * as would satisfaction of the stopping test with strict + * inequality. + * 4. We remove common factors of powers of 2 from relevant + * quantities. + * 5. When converting floating-point integers less than 1e16, + * we use floating-point arithmetic rather than resorting + * to multiple-precision integers. + * 6. When asked to produce fewer than 15 digits, we first try + * to get by with floating-point arithmetic; we resort to + * multiple-precision integer arithmetic only if we cannot + * guarantee that the floating-point calculation has given + * the correctly rounded result. For k requested digits and + * "uniformly" distributed input, the probability is + * something like 10^(k-15) that we must resort to the Long + * calculation. + */ + + +/* This actually sometimes returns a pointer to a string literal + cast to a char*. Do NOT try to modify the return value. */ + +Q_CORE_EXPORT char *qdtoa ( double d, int mode, int ndigits, int *decpt, int *sign, char **rve, char **resultp) +{ + // Some values of the floating-point control word can cause _qdtoa to crash with an underflow. + // We set a safe value here. +#ifdef Q_OS_WIN + _clear87(); + unsigned int oldbits = _control87(0, 0); +#ifndef MCW_EM +# ifdef _MCW_EM +# define MCW_EM _MCW_EM +# else +# define MCW_EM 0x0008001F +# endif +#endif + _control87(MCW_EM, MCW_EM); +#endif + +#if defined(Q_OS_LINUX) && !defined(__UCLIBC__) + fenv_t envp; + feholdexcept(&envp); +#endif + + char *s = _qdtoa(d, mode, ndigits, decpt, sign, rve, resultp); + +#ifdef Q_OS_WIN + _clear87(); +#ifndef _M_X64 + _control87(oldbits, 0xFFFFF); +#else + _control87(oldbits, _MCW_EM|_MCW_DN|_MCW_RC); +#endif //_M_X64 +#endif //Q_OS_WIN + +#if defined(Q_OS_LINUX) && !defined(__UCLIBC__) + fesetenv(&envp); +#endif + + return s; +} + +static char *_qdtoa( NEEDS_VOLATILE double d, int mode, int ndigits, int *decpt, int *sign, char **rve, char **resultp) +{ + /* + Arguments ndigits, decpt, sign are similar to those + of ecvt and fcvt; trailing zeros are suppressed from + the returned string. If not null, *rve is set to point + to the end of the return value. If d is +-Infinity or NaN, + then *decpt is set to 9999. + + mode: + 0 ==> shortest string that yields d when read in + and rounded to nearest. + 1 ==> like 0, but with Steele & White stopping rule; + e.g. with IEEE P754 arithmetic , mode 0 gives + 1e23 whereas mode 1 gives 9.999999999999999e22. + 2 ==> max(1,ndigits) significant digits. This gives a + return value similar to that of ecvt, except + that trailing zeros are suppressed. + 3 ==> through ndigits past the decimal point. This + gives a return value similar to that from fcvt, + except that trailing zeros are suppressed, and + ndigits can be negative. + 4-9 should give the same return values as 2-3, i.e., + 4 <= mode <= 9 ==> same return as mode + 2 + (mode & 1). These modes are mainly for + debugging; often they run slower but sometimes + faster than modes 2-3. + 4,5,8,9 ==> left-to-right digit generation. + 6-9 ==> don't try fast floating-point estimate + (if applicable). + + Values of mode other than 0-9 are treated as mode 0. + + Sufficient space is allocated to the return value + to hold the suppressed trailing zeros. + */ + + int bbits, b2, b5, be, dig, i, ieps, ilim0, + j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, + try_quick; + int ilim = 0, ilim1 = 0, spec_case = 0; /* pacify gcc */ + Long L; +#ifndef Sudden_Underflow + int denorm; + ULong x; +#endif + Bigint *b, *b1, *delta, *mhi, *S; + Bigint *mlo = NULL; /* pacify gcc */ + double d2; + double ds, eps; + char *s, *s0; + + if (getWord0(d) & Sign_bit) { + /* set sign for everything, including 0's and NaNs */ + *sign = 1; + setWord0(&d, getWord0(d) & ~Sign_bit); /* clear sign bit */ + } + else + *sign = 0; + +#if defined(IEEE_Arith) + defined(VAX) +#ifdef IEEE_Arith + if ((getWord0(d) & Exp_mask) == Exp_mask) +#else + if (getWord0(d) == 0x8000) +#endif + { + /* Infinity or NaN */ + *decpt = 9999; + s = +#ifdef IEEE_Arith + !getWord1(d) && !(getWord0(d) & 0xfffff) ? const_cast("Infinity") : +#endif + const_cast("NaN"); + if (rve) + *rve = +#ifdef IEEE_Arith + s[3] ? s + 8 : +#endif + s + 3; + return s; + } +#endif +#ifdef IBM + d += 0; /* normalize */ +#endif + if (d == g_double_zero) + { + *decpt = 1; + s = const_cast("0"); + if (rve) + *rve = s + 1; + return s; + } + + b = d2b(d, &be, &bbits); +#ifdef Sudden_Underflow + i = (int)(getWord0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); +#else + if ((i = int(getWord0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1))) != 0) { +#endif + d2 = d; + setWord0(&d2, getWord0(d2) & Frac_mask1); + setWord0(&d2, getWord0(d2) | Exp_11); +#ifdef IBM + if (j = 11 - hi0bits(getWord0(d2) & Frac_mask)) + d2 /= 1 << j; +#endif + + /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 + * log10(x) = log(x) / log(10) + * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) + * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2) + * + * This suggests computing an approximation k to log10(d) by + * + * k = (i - Bias)*0.301029995663981 + * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); + * + * We want k to be too large rather than too small. + * The error in the first-order Taylor series approximation + * is in our favor, so we just round up the constant enough + * to compensate for any error in the multiplication of + * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, + * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, + * adding 1e-13 to the constant term more than suffices. + * Hence we adjust the constant term to 0.1760912590558. + * (We could get a more accurate k by invoking log10, + * but this is probably not worthwhile.) + */ + + i -= Bias; +#ifdef IBM + i <<= 2; + i += j; +#endif +#ifndef Sudden_Underflow + denorm = 0; + } + else { + /* d is denormalized */ + + i = bbits + be + (Bias + (P-1) - 1); + x = i > 32 ? getWord0(d) << (64 - i) | getWord1(d) >> (i - 32) + : getWord1(d) << (32 - i); + d2 = x; + setWord0(&d2, getWord0(d2) - 31*Exp_msk1); /* adjust exponent */ + i -= (Bias + (P-1) - 1) + 1; + denorm = 1; + } +#endif + ds = (d2-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; + k = int(ds); + if (ds < 0. && ds != k) + k--; /* want k = floor(ds) */ + k_check = 1; + if (k >= 0 && k <= Ten_pmax) { + if (d < tens[k]) + k--; + k_check = 0; + } + j = bbits - i - 1; + if (j >= 0) { + b2 = 0; + s2 = j; + } + else { + b2 = -j; + s2 = 0; + } + if (k >= 0) { + b5 = 0; + s5 = k; + s2 += k; + } + else { + b2 -= k; + b5 = -k; + s5 = 0; + } + if (mode < 0 || mode > 9) + mode = 0; + try_quick = 1; + if (mode > 5) { + mode -= 4; + try_quick = 0; + } + leftright = 1; + switch(mode) { + case 0: + case 1: + ilim = ilim1 = -1; + i = 18; + ndigits = 0; + break; + case 2: + leftright = 0; + /* no break */ + case 4: + if (ndigits <= 0) + ndigits = 1; + ilim = ilim1 = i = ndigits; + break; + case 3: + leftright = 0; + /* no break */ + case 5: + i = ndigits + k + 1; + ilim = i; + ilim1 = i - 1; + if (i <= 0) + i = 1; + } + QT_TRY { + *resultp = static_cast(malloc(i + 1)); + Q_CHECK_PTR(*resultp); + } QT_CATCH(...) { + Bfree(b); + QT_RETHROW; + } + s = s0 = *resultp; + + if (ilim >= 0 && ilim <= Quick_max && try_quick) { + + /* Try to get by with floating-point arithmetic. */ + + i = 0; + d2 = d; + k0 = k; + ilim0 = ilim; + ieps = 2; /* conservative */ + if (k > 0) { + ds = tens[k&0xf]; + j = k >> 4; + if (j & Bletch) { + /* prevent overflows */ + j &= Bletch - 1; + d /= bigtens[n_bigtens-1]; + ieps++; + } + for(; j; j >>= 1, i++) + if (j & 1) { + ieps++; + ds *= bigtens[i]; + } + d /= ds; + } + else if ((j1 = -k) != 0) { + d *= tens[j1 & 0xf]; + for(j = j1 >> 4; j; j >>= 1, i++) + if (j & 1) { + ieps++; + d *= bigtens[i]; + } + } + if (k_check && d < 1. && ilim > 0) { + if (ilim1 <= 0) + goto fast_failed; + ilim = ilim1; + k--; + d *= 10.; + ieps++; + } + eps = ieps*d + 7.; + setWord0(&eps, getWord0(eps) - (P-1)*Exp_msk1); + if (ilim == 0) { + S = mhi = 0; + d -= 5.; + if (d > eps) + goto one_digit; + if (d < -eps) + goto no_digits; + goto fast_failed; + } +#ifndef No_leftright + if (leftright) { + /* Use Steele & White method of only + * generating digits needed. + */ + eps = 0.5/tens[ilim-1] - eps; + for(i = 0;;) { + L = Long(d); + d -= L; + *s++ = '0' + int(L); + if (d < eps) + goto ret1; + if (1. - d < eps) + goto bump_up; + if (++i >= ilim) + break; + eps *= 10.; + d *= 10.; + } + } + else { +#endif + /* Generate ilim digits, then fix them up. */ +#if defined(Q_OS_IRIX) && defined(Q_CC_GNU) + // work around a bug on 64 bit IRIX gcc + double *t = (double *) tens; + eps *= t[ilim-1]; +#else + eps *= tens[ilim-1]; +#endif + for(i = 1;; i++, d *= 10.) { + L = Long(d); + d -= L; + *s++ = '0' + int(L); + if (i == ilim) { + if (d > 0.5 + eps) + goto bump_up; + else if (d < 0.5 - eps) { + while(*--s == '0') {} + s++; + goto ret1; + } + break; + } + } +#ifndef No_leftright + } +#endif + fast_failed: + s = s0; + d = d2; + k = k0; + ilim = ilim0; + } + + /* Do we have a "small" integer? */ + + if (be >= 0 && k <= Int_max) { + /* Yes. */ + ds = tens[k]; + if (ndigits < 0 && ilim <= 0) { + S = mhi = 0; + if (ilim < 0 || d <= 5*ds) + goto no_digits; + goto one_digit; + } + for(i = 1;; i++) { + L = Long(d / ds); + d -= L*ds; +#ifdef Check_FLT_ROUNDS + /* If FLT_ROUNDS == 2, L will usually be high by 1 */ + if (d < 0) { + L--; + d += ds; + } +#endif + *s++ = '0' + int(L); + if (i == ilim) { + d += d; + if (d > ds || (d == ds && L & 1)) { + bump_up: + while(*--s == '9') + if (s == s0) { + k++; + *s = '0'; + break; + } + ++*s++; + } + break; + } + if ((d *= 10.) == g_double_zero) + break; + } + goto ret1; + } + + m2 = b2; + m5 = b5; + mhi = mlo = 0; + if (leftright) { + if (mode < 2) { + i = +#ifndef Sudden_Underflow + denorm ? be + (Bias + (P-1) - 1 + 1) : +#endif +#ifdef IBM + 1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3); +#else + 1 + P - bbits; +#endif + } + else { + j = ilim - 1; + if (m5 >= j) + m5 -= j; + else { + s5 += j -= m5; + b5 += j; + m5 = 0; + } + if ((i = ilim) < 0) { + m2 -= i; + i = 0; + } + } + b2 += i; + s2 += i; + mhi = i2b(1); + } + if (m2 > 0 && s2 > 0) { + i = m2 < s2 ? m2 : s2; + b2 -= i; + m2 -= i; + s2 -= i; + } + if (b5 > 0) { + if (leftright) { + if (m5 > 0) { + mhi = pow5mult(mhi, m5); + b1 = mult(mhi, b); + Bfree(b); + b = b1; + } + if ((j = b5 - m5) != 0) + b = pow5mult(b, j); + } + else + b = pow5mult(b, b5); + } + S = i2b(1); + if (s5 > 0) + S = pow5mult(S, s5); + + /* Check for special case that d is a normalized power of 2. */ + + if (mode < 2) { + if (!getWord1(d) && !(getWord0(d) & Bndry_mask) +#ifndef Sudden_Underflow + && getWord0(d) & Exp_mask +#endif + ) { + /* The special case */ + b2 += Log2P; + s2 += Log2P; + spec_case = 1; + } + else + spec_case = 0; + } + + /* Arrange for convenient computation of quotients: + * shift left if necessary so divisor has 4 leading 0 bits. + * + * Perhaps we should just compute leading 28 bits of S once + * and for all and pass them and a shift to quorem, so it + * can do shifts and ors to compute the numerator for q. + */ +#ifdef Pack_32 + if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f) != 0) + i = 32 - i; +#else + if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf) + i = 16 - i; +#endif + if (i > 4) { + i -= 4; + b2 += i; + m2 += i; + s2 += i; + } + else if (i < 4) { + i += 28; + b2 += i; + m2 += i; + s2 += i; + } + if (b2 > 0) + b = lshift(b, b2); + if (s2 > 0) + S = lshift(S, s2); + if (k_check) { + if (cmp(b,S) < 0) { + k--; + b = multadd(b, 10, 0); /* we botched the k estimate */ + if (leftright) + mhi = multadd(mhi, 10, 0); + ilim = ilim1; + } + } + if (ilim <= 0 && mode > 2) { + if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) { + /* no digits, fcvt style */ + no_digits: + k = -1 - ndigits; + goto ret; + } + one_digit: + *s++ = '1'; + k++; + goto ret; + } + if (leftright) { + if (m2 > 0) + mhi = lshift(mhi, m2); + + /* Compute mlo -- check for special case + * that d is a normalized power of 2. + */ + + mlo = mhi; + if (spec_case) { + mhi = Balloc(mhi->k); + Bcopy(mhi, mlo); + mhi = lshift(mhi, Log2P); + } + + for(i = 1;;i++) { + dig = quorem(b,S) + '0'; + /* Do we yet have the shortest decimal string + * that will round to d? + */ + j = cmp(b, mlo); + delta = diff(S, mhi); + j1 = delta->sign ? 1 : cmp(b, delta); + Bfree(delta); +#ifndef ROUND_BIASED + if (j1 == 0 && !mode && !(getWord1(d) & 1)) { + if (dig == '9') + goto round_9_up; + if (j > 0) + dig++; + *s++ = dig; + goto ret; + } +#endif + if (j < 0 || (j == 0 && !mode +#ifndef ROUND_BIASED + && !(getWord1(d) & 1) +#endif + )) { + if (j1 > 0) { + b = lshift(b, 1); + j1 = cmp(b, S); + if ((j1 > 0 || (j1 == 0 && dig & 1)) + && dig++ == '9') + goto round_9_up; + } + *s++ = dig; + goto ret; + } + if (j1 > 0) { + if (dig == '9') { /* possible if i == 1 */ + round_9_up: + *s++ = '9'; + goto roundoff; + } + *s++ = dig + 1; + goto ret; + } + *s++ = dig; + if (i == ilim) + break; + b = multadd(b, 10, 0); + if (mlo == mhi) + mlo = mhi = multadd(mhi, 10, 0); + else { + mlo = multadd(mlo, 10, 0); + mhi = multadd(mhi, 10, 0); + } + } + } + else + for(i = 1;; i++) { + *s++ = dig = quorem(b,S) + '0'; + if (i >= ilim) + break; + b = multadd(b, 10, 0); + } + + /* Round off last digit */ + + b = lshift(b, 1); + j = cmp(b, S); + if (j > 0 || (j == 0 && dig & 1)) { + roundoff: + while(*--s == '9') + if (s == s0) { + k++; + *s++ = '1'; + goto ret; + } + ++*s++; + } + else { + while(*--s == '0') {} + s++; + } + ret: + Bfree(S); + if (mhi) { + if (mlo && mlo != mhi) + Bfree(mlo); + Bfree(mhi); + } + ret1: + Bfree(b); + if (s == s0) { /* don't return empty string */ + *s++ = '0'; + k = 0; + } + *s = 0; + *decpt = k + 1; + if (rve) + *rve = s; + return s0; +} +#else +// NOT thread safe! + +#include + +Q_CORE_EXPORT char *qdtoa( double d, int mode, int ndigits, int *decpt, int *sign, char **rve, char **resultp) +{ + if(rve) + *rve = 0; + + char *res; + if (mode == 0) + ndigits = 80; + + if (mode == 3) + res = fcvt(d, ndigits, decpt, sign); + else + res = ecvt(d, ndigits, decpt, sign); + + int n = qstrlen(res); + if (mode == 0) { // remove trailing 0's + const int stop = qMax(1, *decpt); + int i; + for (i = n-1; i >= stop; --i) { + if (res[i] != '0') + break; + } + n = i + 1; + } + *resultp = static_cast(malloc(n + 1)); + Q_CHECK_PTR(resultp); + qstrncpy(*resultp, res, n + 1); + return *resultp; +} + +Q_CORE_EXPORT double qstrtod(const char *s00, const char **se, bool *ok) +{ + double ret = strtod((char*)s00, (char**)se); + if (ok) { + if((ret == 0.0l && errno == ERANGE) + || ret == HUGE_VAL || ret == -HUGE_VAL) + *ok = false; + else + *ok = true; // the result will be that we don't report underflow in this case + } + return ret; +} + +#endif // QT_QLOCALE_USES_FCVT + +QT_END_NAMESPACE diff --git a/src/corelib/tools/qlocale_tools_p.h b/src/corelib/tools/qlocale_tools_p.h new file mode 100644 index 0000000..07631d5 --- /dev/null +++ b/src/corelib/tools/qlocale_tools_p.h @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef QLOCALE_TOOLS_P_H +#define QLOCALE_TOOLS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of internal files. This header file may change from version to version +// without notice, or even be removed. +// +// We mean it. +// + +#include "qlocale_p.h" +#include "qstring.h" + +#if !defined(QT_QLOCALE_NEEDS_VOLATILE) +# if defined(Q_CC_GNU) +# if __GNUC__ == 4 +# define QT_QLOCALE_NEEDS_VOLATILE +# elif defined(Q_OS_WIN) +# define QT_QLOCALE_NEEDS_VOLATILE +# endif +# endif +#endif + +#if defined(QT_QLOCALE_NEEDS_VOLATILE) +# define NEEDS_VOLATILE volatile +#else +# define NEEDS_VOLATILE +#endif + +QT_BEGIN_NAMESPACE + +QString qulltoa(qulonglong l, int base, const QChar _zero); +QString qlltoa(qlonglong l, int base, const QChar zero); + +enum PrecisionMode { + PMDecimalDigits = 0x01, + PMSignificantDigits = 0x02, + PMChopTrailingZeros = 0x03 +}; + +QString &decimalForm(QChar zero, QChar decimal, QChar group, + QString &digits, int decpt, uint precision, + PrecisionMode pm, + bool always_show_decpt, + bool thousands_group); +QString &exponentForm(QChar zero, QChar decimal, QChar exponential, + QChar group, QChar plus, QChar minus, + QString &digits, int decpt, uint precision, + PrecisionMode pm, + bool always_show_decpt); + +inline bool isZero(double d) +{ + uchar *ch = (uchar *)&d; +#ifdef QT_ARMFPA + return !(ch[3] & 0x7F || ch[2] || ch[1] || ch[0] || ch[7] || ch[6] || ch[5] || ch[4]); +#else + if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { + return !(ch[0] & 0x7F || ch[1] || ch[2] || ch[3] || ch[4] || ch[5] || ch[6] || ch[7]); + } else { + return !(ch[7] & 0x7F || ch[6] || ch[5] || ch[4] || ch[3] || ch[2] || ch[1] || ch[0]); + } +#endif +} + +// Removes thousand-group separators in "C" locale. +bool removeGroupSeparators(QLocalePrivate::CharBuff *num); + +Q_CORE_EXPORT char *qdtoa(double d, int mode, int ndigits, int *decpt, + int *sign, char **rve, char **digits_str); +Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok); +qlonglong qstrtoll(const char *nptr, const char **endptr, register int base, bool *ok); +qulonglong qstrtoull(const char *nptr, const char **endptr, register int base, bool *ok); + +QT_END_NAMESPACE + +#endif diff --git a/src/corelib/tools/qlocale_unix.cpp b/src/corelib/tools/qlocale_unix.cpp new file mode 100644 index 0000000..7d43726 --- /dev/null +++ b/src/corelib/tools/qlocale_unix.cpp @@ -0,0 +1,256 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "qlocale_p.h" + +#include "qdatetime.h" +#include "qstringlist.h" +#include "qvariant.h" + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_SYSTEMLOCALE +struct QSystemLocaleData +{ + QSystemLocaleData() + : lc_numeric(QLocale::C) + ,lc_time(QLocale::C) + ,lc_monetary(QLocale::C) + ,lc_messages(QLocale::C) + { + QByteArray all = qgetenv("LC_ALL"); + QByteArray numeric = all.isEmpty() ? qgetenv("LC_NUMERIC") : all; + QByteArray time = all.isEmpty() ? qgetenv("LC_TIME") : all; + QByteArray monetary = all.isEmpty() ? qgetenv("LC_MONETARY") : all; + QByteArray messages = all.isEmpty() ? qgetenv("LC_MESSAGES") : all; + QByteArray lang = qgetenv("LANG"); + if (numeric.isEmpty()) + numeric = lang; + if (monetary.isEmpty()) + monetary = lang; + if (messages.isEmpty()) + messages = lang; + lc_numeric = QLocale(QString::fromAscii(numeric)); + lc_time = QLocale(QString::fromAscii(time)); + lc_monetary = QLocale(QString::fromAscii(monetary)); + lc_messages = QLocale(QString::fromAscii(messages)); + } + + QLocale lc_numeric; + QLocale lc_time; + QLocale lc_monetary; + QLocale lc_messages; +}; +Q_GLOBAL_STATIC(QSystemLocaleData, qSystemLocaleData) +#endif + + +static uint unixGetSystemMeasurementSystem() +{ + QString meas_locale = QString::fromLocal8Bit(qgetenv("LC_ALL")); + if (meas_locale.isEmpty()) { + meas_locale = QString::fromLocal8Bit(qgetenv("LC_MEASUREMENT")); + } + if (meas_locale.isEmpty()) { + meas_locale = QString::fromLocal8Bit(qgetenv("LANG")); + } + if (meas_locale.isEmpty()) { + meas_locale = QString::fromLocal8Bit("C"); + } + + if (meas_locale.compare(QString::fromLocal8Bit("Metric"), Qt::CaseInsensitive) == 0) + return 0; + if (meas_locale.compare(QString::fromLocal8Bit("Other"), Qt::CaseInsensitive) == 0) + return 0; + + const QLocalePrivate* locale = findLocale(meas_locale); + return locale->measurementSystem(); +} + +static QByteArray envVarLocale() +{ + static QByteArray lang = 0; +#ifdef Q_OS_UNIX + lang = qgetenv("LC_ALL"); + if (lang.isNull()) + lang = qgetenv("LC_NUMERIC"); + if (lang.isNull()) +#endif + lang = qgetenv("LANG"); + return lang; +} + +#ifndef QT_NO_SYSTEMLOCALE +/*! + \internal +*/ +QLocale QSystemLocale::fallbackLocale() const +{ + return QLocale(QLatin1String(envVarLocale())); +} + +/*! + \internal +*/ +QVariant QSystemLocale::query(QueryType type, QVariant in) const +{ + QSystemLocaleData *d = qSystemLocaleData(); + const QLocale &lc_numeric = d->lc_numeric; + const QLocale &lc_time = d->lc_time; + const QLocale &lc_monetary = d->lc_monetary; + + switch (type) { + case DecimalPoint: + return lc_numeric.decimalPoint(); + case GroupSeparator: + return lc_numeric.groupSeparator(); + case ZeroDigit: + return lc_numeric.zeroDigit(); + case NegativeSign: + return lc_numeric.negativeSign(); + case DateFormatLong: + return lc_time.dateFormat(QLocale::LongFormat); + case DateFormatShort: + return lc_time.dateFormat(QLocale::ShortFormat); + case TimeFormatLong: + return lc_time.timeFormat(QLocale::LongFormat); + case TimeFormatShort: + return lc_time.timeFormat(QLocale::ShortFormat); + case DayNameLong: + return lc_time.dayName(in.toInt(), QLocale::LongFormat); + case DayNameShort: + return lc_time.dayName(in.toInt(), QLocale::ShortFormat); + case MonthNameLong: + return lc_time.monthName(in.toInt(), QLocale::LongFormat); + case MonthNameShort: + return lc_time.monthName(in.toInt(), QLocale::ShortFormat); + case DateToStringLong: + return lc_time.toString(in.toDate(), QLocale::LongFormat); + case DateToStringShort: + return lc_time.toString(in.toDate(), QLocale::ShortFormat); + case TimeToStringLong: + return lc_time.toString(in.toTime(), QLocale::LongFormat); + case TimeToStringShort: + return lc_time.toString(in.toTime(), QLocale::ShortFormat); + case DateTimeFormatLong: + return lc_time.dateTimeFormat(QLocale::LongFormat); + case DateTimeFormatShort: + return lc_time.dateTimeFormat(QLocale::ShortFormat); + case DateTimeToStringLong: + return lc_time.toString(in.toDateTime(), QLocale::LongFormat); + case DateTimeToStringShort: + return lc_time.toString(in.toDateTime(), QLocale::ShortFormat); + case PositiveSign: + return lc_numeric.positiveSign(); + case AMText: + return lc_time.amText(); + case PMText: + return lc_time.pmText(); + case FirstDayOfWeek: + return lc_time.firstDayOfWeek(); + case CurrencySymbol: + return lc_monetary.currencySymbol(QLocale::CurrencySymbolFormat(in.toUInt())); + case FormatCurrency: { + switch (in.type()) { + case QVariant::Int: + return lc_monetary.toCurrencyString(in.toInt()); + case QVariant::UInt: + return lc_monetary.toCurrencyString(in.toUInt()); + case QVariant::Double: + return lc_monetary.toCurrencyString(in.toDouble()); + case QVariant::LongLong: + return lc_monetary.toCurrencyString(in.toLongLong()); + case QVariant::ULongLong: + return lc_monetary.toCurrencyString(in.toULongLong()); + default: + break; + } + return QString(); + } + case MeasurementSystem: + return QVariant(unixGetSystemMeasurementSystem()); + case UILanguages: { + QString languages = QString::fromLocal8Bit(qgetenv("LANGUAGE")); + if (!languages.isEmpty()) { + QStringList lst = languages.split(QLatin1Char(':')); + for (int i = 0; i < lst.size();) { + const QString &name = lst.at(i); + QChar lang[3]; + QChar cntry[3]; + if (name.isEmpty() || !splitLocaleName(name, lang, cntry)) + lst.removeAt(i); + else + ++i; + } + return lst; + } + QString name = QString::fromLocal8Bit(qgetenv("LC_ALL")); + if (name.isEmpty()) { + name = QString::fromLocal8Bit(qgetenv("LC_MESSAGES")); + if (name.isEmpty()) + name = QString::fromLocal8Bit(qgetenv("LANG")); + } + if (!name.isEmpty()) { + QChar lang[3]; + QChar cntry[3]; + int lang_len, cntry_len; + if (splitLocaleName(name, lang, cntry, &lang_len, &cntry_len)) + return QStringList(QString::fromRawData(lang, lang_len) % QLatin1Char('-') % QString::fromRawData(cntry, cntry_len)); + } + return QVariant(); + } + case QuotationBegin: + case QuotationEnd: + break; // TODO + default: + break; + } + return QVariant(); +} +#endif // QT_NO_SYSTEMLOCALE + +QString timeZone() +{ + tzset(); + return QString::fromLocal8Bit(tzname[1]); +} + +QT_END_NAMESPACE diff --git a/src/corelib/tools/qlocale_win.cpp b/src/corelib/tools/qlocale_win.cpp new file mode 100644 index 0000000..3605e44 --- /dev/null +++ b/src/corelib/tools/qlocale_win.cpp @@ -0,0 +1,757 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "qlocale_p.h" +#include "qlocale_tools_p.h" + +#include "qstringlist.h" +#include "qvariant.h" +#include "qdatetime.h" + +#include "private/qsystemlibrary_p.h" + +#if defined(Q_WS_WIN) +# include "qt_windows.h" +# include +#endif + +QT_BEGIN_NAMESPACE + +#ifndef MUI_LANGUAGE_NAME +#define MUI_LANGUAGE_NAME 0x8 +#endif + +static const char *winLangCodeToIsoName(int code); +static QString winIso639LangName(LCID id = LOCALE_USER_DEFAULT); +static QString winIso3116CtryName(LCID id = LOCALE_USER_DEFAULT); + +static QString getWinLocaleInfo(LCTYPE type) +{ + LCID id = GetUserDefaultLCID(); + int cnt = GetLocaleInfo(id, type, 0, 0) * 2; + + if (cnt == 0) { + qWarning("QLocale: empty windows locale info (%d)", (int)type); + return QString(); + } + + QByteArray buff(cnt, 0); + + cnt = GetLocaleInfo(id, type, reinterpret_cast(buff.data()), buff.size() / 2); + + if (cnt == 0) { + qWarning("QLocale: empty windows locale info (%d)", (int)type); + return QString(); + } + + return QString::fromWCharArray(reinterpret_cast(buff.data())); +} + +static QByteArray envVarLocale() +{ + static QByteArray lang = qgetenv("LANG"); + return lang; +} + +QByteArray getWinLocaleName(LCID id = LOCALE_USER_DEFAULT) +{ + QByteArray result; + if (id == LOCALE_USER_DEFAULT) { + result = envVarLocale(); + QChar lang[3]; + QChar cntry[3]; + if ( result == "C" || (!result.isEmpty() + && splitLocaleName(QString::fromLocal8Bit(result), lang, cntry)) ) { + long id = 0; + bool ok = false; + id = qstrtoll(result.data(), 0, 0, &ok); + if ( !ok || id == 0 || id < INT_MIN || id > INT_MAX ) + return result; + else + return winLangCodeToIsoName( (int)id ); + } + } + +#if defined(Q_OS_WINCE) + result = winLangCodeToIsoName(id != LOCALE_USER_DEFAULT ? id : GetUserDefaultLCID()); +#else + if (id == LOCALE_USER_DEFAULT) + id = GetUserDefaultLCID(); + QString resultuage = winIso639LangName(id); + QString country = winIso3116CtryName(id); + result = resultuage.toLatin1(); + if (!country.isEmpty()) { + result += '_'; + result += country.toLatin1(); + } +#endif + + return result; +} + +Q_CORE_EXPORT QLocale qt_localeFromLCID(LCID id) +{ + return QLocale(QString::fromLatin1(getWinLocaleName(id))); +} + +static QString winToQtFormat(const QString &sys_fmt) +{ + QString result; + int i = 0; + + while (i < sys_fmt.size()) { + if (sys_fmt.at(i).unicode() == QLatin1Char('\'')) { + QString text = readEscapedFormatString(sys_fmt, &i); + if (text == QLatin1String("'")) + result += QLatin1String("''"); + else + result += QString(QLatin1Char('\'') + text + QLatin1Char('\'')); + continue; + } + + QChar c = sys_fmt.at(i); + int repeat = repeatCount(sys_fmt, i); + + switch (c.unicode()) { + // Date + case 'y': + if (repeat > 5) + repeat = 5; + else if (repeat == 3) + repeat = 2; + switch (repeat) { + case 1: + result += QLatin1String("yy"); // "y" unsupported by Qt, use "yy" + break; + case 5: + result += QLatin1String("yyyy"); // "yyyyy" same as "yyyy" on Windows + break; + default: + result += QString(repeat, QLatin1Char('y')); + break; + } + break; + case 'g': + if (repeat > 2) + repeat = 2; + switch (repeat) { + case 2: + break; // no equivalent of "gg" in Qt + default: + result += QLatin1Char('g'); + break; + } + break; + case 't': + if (repeat > 2) + repeat = 2; + result += QLatin1String("AP"); // "t" unsupported, use "AP" + break; + default: + result += QString(repeat, c); + break; + } + + i += repeat; + } + + return result; +} + + + +static QString winDateToString(const QDate &date, DWORD flags) +{ + SYSTEMTIME st; + memset(&st, 0, sizeof(SYSTEMTIME)); + st.wYear = date.year(); + st.wMonth = date.month(); + st.wDay = date.day(); + + LCID id = GetUserDefaultLCID(); + + wchar_t buf[255]; + if (GetDateFormat(id, flags, &st, 0, buf, 255)) + return QString::fromWCharArray(buf); + + return QString(); +} + +static QString winTimeToString(const QTime &time) +{ + SYSTEMTIME st; + memset(&st, 0, sizeof(SYSTEMTIME)); + st.wHour = time.hour(); + st.wMinute = time.minute(); + st.wSecond = time.second(); + st.wMilliseconds = 0; + + DWORD flags = 0; + LCID id = GetUserDefaultLCID(); + + wchar_t buf[255]; + if (GetTimeFormat(id, flags, &st, 0, buf, 255)) + return QString::fromWCharArray(buf); + + return QString(); +} + +static QString winDayName(int day, bool short_format) +{ + static const LCTYPE short_day_map[] + = { LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, + LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, + LOCALE_SABBREVDAYNAME6, LOCALE_SABBREVDAYNAME7 }; + + static const LCTYPE long_day_map[] + = { LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, + LOCALE_SDAYNAME3, LOCALE_SDAYNAME4, LOCALE_SDAYNAME5, + LOCALE_SDAYNAME6, LOCALE_SDAYNAME7 }; + + day -= 1; + + LCTYPE type = short_format + ? short_day_map[day] : long_day_map[day]; + return getWinLocaleInfo(type); +} + +static QString winMonthName(int month, bool short_format) +{ + static const LCTYPE short_month_map[] + = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3, + LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6, + LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9, + LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 }; + + static const LCTYPE long_month_map[] + = { LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, + LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, + LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8, LOCALE_SMONTHNAME9, + LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12 }; + + month -= 1; + if (month < 0 || month > 11) + return QString(); + + LCTYPE type = short_format ? short_month_map[month] : long_month_map[month]; + return getWinLocaleInfo(type); +} + +static QLocale::MeasurementSystem winSystemMeasurementSystem() +{ + LCID id = GetUserDefaultLCID(); + wchar_t output[2]; + + if (GetLocaleInfo(id, LOCALE_IMEASURE, output, 2)) { + QString iMeasure = QString::fromWCharArray(output); + if (iMeasure == QLatin1String("1")) { + return QLocale::ImperialSystem; + } + } + + return QLocale::MetricSystem; +} + +static QString winSystemAMText() +{ + LCID id = GetUserDefaultLCID(); + wchar_t output[15]; // maximum length including terminating zero character for Win2003+ + + if (GetLocaleInfo(id, LOCALE_S1159, output, 15)) { + return QString::fromWCharArray(output); + } + + return QString(); +} + +static QString winSystemPMText() +{ + LCID id = GetUserDefaultLCID(); + wchar_t output[15]; // maximum length including terminating zero character for Win2003+ + + if (GetLocaleInfo(id, LOCALE_S2359, output, 15)) { + return QString::fromWCharArray(output); + } + + return QString(); +} + +static quint8 winSystemFirstDayOfWeek() +{ + LCID id = GetUserDefaultLCID(); + wchar_t output[4]; // maximum length including terminating zero character for Win2003+ + + if (GetLocaleInfo(id, LOCALE_IFIRSTDAYOFWEEK, output, 4)) + return QString::fromWCharArray(output).toUInt()+1; + + return 1; +} + +QString winCurrencySymbol(QLocale::CurrencySymbolFormat format) +{ + LCID lcid = GetUserDefaultLCID(); + wchar_t buf[13]; + switch (format) { + case QLocale::CurrencySymbol: + if (GetLocaleInfo(lcid, LOCALE_SCURRENCY, buf, 13)) + return QString::fromWCharArray(buf); + break; + case QLocale::CurrencyIsoCode: + if (GetLocaleInfo(lcid, LOCALE_SINTLSYMBOL, buf, 9)) + return QString::fromWCharArray(buf); + break; + case QLocale::CurrencyDisplayName: { + QVarLengthArray buf(64); + if (!GetLocaleInfo(lcid, LOCALE_SNATIVECURRNAME, buf.data(), buf.size())) { + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) + break; + buf.resize(255); // should be large enough, right? + if (!GetLocaleInfo(lcid, LOCALE_SNATIVECURRNAME, buf.data(), buf.size())) + break; + } + return QString::fromWCharArray(buf.data()); + } + default: + break; + } + return QString(); +} + +static QString winFormatCurrency(const QVariant &in) +{ + QString value; + switch (in.type()) { + case QVariant::Int: + value = QLocalePrivate::longLongToString(QLatin1Char('0'), QLatin1Char(','), QLatin1Char('+'), QLatin1Char('-'), + in.toInt(), -1, 10, -1, QLocale::OmitGroupSeparator); + break; + case QVariant::UInt: + value = QLocalePrivate::unsLongLongToString(QLatin1Char('0'), QLatin1Char(','), QLatin1Char('+'), + in.toUInt(), -1, 10, -1, QLocale::OmitGroupSeparator); + break; + case QVariant::Double: + value = QLocalePrivate::doubleToString(QLatin1Char('0'), QLatin1Char('+'), QLatin1Char('-'), + QLatin1Char(' '), QLatin1Char(','), QLatin1Char('.'), + in.toDouble(), -1, QLocalePrivate::DFDecimal, -1, QLocale::OmitGroupSeparator); + break; + case QVariant::LongLong: + value = QLocalePrivate::longLongToString(QLatin1Char('0'), QLatin1Char(','), QLatin1Char('+'), QLatin1Char('-'), + in.toLongLong(), -1, 10, -1, QLocale::OmitGroupSeparator); + break; + case QVariant::ULongLong: + value = QLocalePrivate::unsLongLongToString(QLatin1Char('0'), QLatin1Char(','), QLatin1Char('+'), + in.toULongLong(), -1, 10, -1, QLocale::OmitGroupSeparator); + break; + default: + return QString(); + } + + QVarLengthArray out(64); + LCID lcid = GetUserDefaultLCID(); + int ret = ::GetCurrencyFormat(lcid, 0, reinterpret_cast(value.utf16()), + NULL, out.data(), out.size()); + if (ret == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + ret = ::GetCurrencyFormat(lcid, 0, reinterpret_cast(value.utf16()), + NULL, out.data(), 0); + out.resize(ret); + ::GetCurrencyFormat(lcid, 0, reinterpret_cast(value.utf16()), + NULL, out.data(), out.size()); + } + + return QString::fromWCharArray(out.data()); +} + +QStringList winUILanguages() +{ + if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA) { + typedef BOOL (*GetUserPreferredUILanguagesFunc) ( + DWORD dwFlags, + PULONG pulNumLanguages, + PWSTR pwszLanguagesBuffer, + PULONG pcchLanguagesBuffer); + static GetUserPreferredUILanguagesFunc GetUserPreferredUILanguages_ptr = 0; + if (!GetUserPreferredUILanguages_ptr) { + QSystemLibrary lib(QLatin1String("kernel32")); + if (lib.load()) + GetUserPreferredUILanguages_ptr = (GetUserPreferredUILanguagesFunc)lib.resolve("GetUserPreferredUILanguages"); + } + if (GetUserPreferredUILanguages_ptr) { + unsigned long cnt = 0; + QVarLengthArray buf(64); + unsigned long size = buf.size(); + if (!GetUserPreferredUILanguages_ptr(MUI_LANGUAGE_NAME, &cnt, buf.data(), &size)) { + size = 0; + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER && + GetUserPreferredUILanguages_ptr(MUI_LANGUAGE_NAME, &cnt, NULL, &size)) { + buf.resize(size); + if (!GetUserPreferredUILanguages_ptr(MUI_LANGUAGE_NAME, &cnt, buf.data(), &size)) + return QStringList(); + } + } + QStringList result; + result.reserve(cnt); + const wchar_t *str = buf.constData(); + for (; cnt > 0; --cnt) { + QString s = QString::fromWCharArray(str); + if (s.isEmpty()) + break; // something is wrong + result.append(s); + str += s.size()+1; + } + return result; + } + } + + // old Windows before Vista + return QStringList(QString::fromLatin1(winLangCodeToIsoName(GetUserDefaultUILanguage()))); +} + +#ifndef QT_NO_SYSTEMLOCALE + +/*! + \since 4.6 + Returns the fallback locale obtained from the system. + */ +QLocale QSystemLocale::fallbackLocale() const +{ + return QLocale(QString::fromLatin1(getWinLocaleName())); +} + +QVariant QSystemLocale::query(QueryType type, QVariant in = QVariant()) const +{ + LCTYPE locale_info = 0; + bool format_string = false; + + switch(type) { +// case Name: +// return getWinLocaleName(); + case DecimalPoint: + locale_info = LOCALE_SDECIMAL; + break; + case GroupSeparator: + locale_info = LOCALE_STHOUSAND; + break; + case NegativeSign: + locale_info = LOCALE_SNEGATIVESIGN; + break; + case PositiveSign: + locale_info = LOCALE_SPOSITIVESIGN; + break; + case DateFormatLong: + locale_info = LOCALE_SLONGDATE; + format_string = true; + break; + case DateFormatShort: + locale_info = LOCALE_SSHORTDATE; + format_string = true; + break; + case TimeFormatLong: + case TimeFormatShort: + locale_info = LOCALE_STIMEFORMAT; + format_string = true; + break; + + case DateTimeFormatLong: + case DateTimeFormatShort: + return QString(query(type == DateTimeFormatLong ? DateFormatLong : DateFormatShort).toString() + + QLatin1Char(' ') + query(type == DateTimeFormatLong ? TimeFormatLong : TimeFormatShort).toString()); + case DayNameLong: + case DayNameShort: + return winDayName(in.toInt(), (type == DayNameShort)); + case MonthNameLong: + case MonthNameShort: + return winMonthName(in.toInt(), (type == MonthNameShort)); + case DateToStringShort: + case DateToStringLong: + return winDateToString(in.toDate(), type == DateToStringShort ? DATE_SHORTDATE : DATE_LONGDATE); + case TimeToStringShort: + case TimeToStringLong: + return winTimeToString(in.toTime()); + case DateTimeToStringShort: + case DateTimeToStringLong: { + const QDateTime dt = in.toDateTime(); + return QString(winDateToString(dt.date(), type == DateTimeToStringShort ? DATE_SHORTDATE : DATE_LONGDATE) + + QLatin1Char(' ') + winTimeToString(dt.time())); } + + case ZeroDigit: + locale_info = LOCALE_SNATIVEDIGITS; + break; + + case LanguageId: + case CountryId: { + QString locale = QString::fromLatin1(getWinLocaleName()); + QLocale::Language lang; + QLocale::Country cntry; + getLangAndCountry(locale, lang, cntry); + if (type == LanguageId) + return lang; + if (cntry == QLocale::AnyCountry) + return fallbackLocale().country(); + return cntry; + } + + case MeasurementSystem: + return QVariant(static_cast(winSystemMeasurementSystem())); + + case AMText: + return QVariant(winSystemAMText()); + case PMText: + return QVariant(winSystemPMText()); + case FirstDayOfWeek: + return QVariant(winSystemFirstDayOfWeek()); + case CurrencySymbol: + return QVariant(winCurrencySymbol(QLocale::CurrencySymbolFormat(in.toUInt()))); + case FormatCurrency: + return QVariant(winFormatCurrency(in)); + case UILanguages: + return QVariant(winUILanguages()); + default: + break; + } + if (locale_info) { + QString result = getWinLocaleInfo(locale_info); + if (format_string) + result = winToQtFormat(result); + if (!result.isEmpty()) + return result; + } + return QVariant(); +} +#endif // QT_NO_SYSTEMLOCALE + +struct WindowsToISOListElt { + ushort windows_code; + char iso_name[6]; +}; + +/* NOTE: This array should be sorted by the first column! */ +static const WindowsToISOListElt windows_to_iso_list[] = { + { 0x0401, "ar_SA" }, + { 0x0402, "bg\0 " }, + { 0x0403, "ca\0 " }, + { 0x0404, "zh_TW" }, + { 0x0405, "cs\0 " }, + { 0x0406, "da\0 " }, + { 0x0407, "de\0 " }, + { 0x0408, "el\0 " }, + { 0x0409, "en_US" }, + { 0x040a, "es\0 " }, + { 0x040b, "fi\0 " }, + { 0x040c, "fr\0 " }, + { 0x040d, "he\0 " }, + { 0x040e, "hu\0 " }, + { 0x040f, "is\0 " }, + { 0x0410, "it\0 " }, + { 0x0411, "ja\0 " }, + { 0x0412, "ko\0 " }, + { 0x0413, "nl\0 " }, + { 0x0414, "no\0 " }, + { 0x0415, "pl\0 " }, + { 0x0416, "pt_BR" }, + { 0x0418, "ro\0 " }, + { 0x0419, "ru\0 " }, + { 0x041a, "hr\0 " }, + { 0x041c, "sq\0 " }, + { 0x041d, "sv\0 " }, + { 0x041e, "th\0 " }, + { 0x041f, "tr\0 " }, + { 0x0420, "ur\0 " }, + { 0x0421, "in\0 " }, + { 0x0422, "uk\0 " }, + { 0x0423, "be\0 " }, + { 0x0425, "et\0 " }, + { 0x0426, "lv\0 " }, + { 0x0427, "lt\0 " }, + { 0x0429, "fa\0 " }, + { 0x042a, "vi\0 " }, + { 0x042d, "eu\0 " }, + { 0x042f, "mk\0 " }, + { 0x0436, "af\0 " }, + { 0x0438, "fo\0 " }, + { 0x0439, "hi\0 " }, + { 0x043e, "ms\0 " }, + { 0x0458, "mt\0 " }, + { 0x0801, "ar_IQ" }, + { 0x0804, "zh_CN" }, + { 0x0807, "de_CH" }, + { 0x0809, "en_GB" }, + { 0x080a, "es_MX" }, + { 0x080c, "fr_BE" }, + { 0x0810, "it_CH" }, + { 0x0812, "ko\0 " }, + { 0x0813, "nl_BE" }, + { 0x0814, "no\0 " }, + { 0x0816, "pt\0 " }, + { 0x081a, "sr\0 " }, + { 0x081d, "sv_FI" }, + { 0x0c01, "ar_EG" }, + { 0x0c04, "zh_HK" }, + { 0x0c07, "de_AT" }, + { 0x0c09, "en_AU" }, + { 0x0c0a, "es\0 " }, + { 0x0c0c, "fr_CA" }, + { 0x0c1a, "sr\0 " }, + { 0x1001, "ar_LY" }, + { 0x1004, "zh_SG" }, + { 0x1007, "de_LU" }, + { 0x1009, "en_CA" }, + { 0x100a, "es_GT" }, + { 0x100c, "fr_CH" }, + { 0x1401, "ar_DZ" }, + { 0x1407, "de_LI" }, + { 0x1409, "en_NZ" }, + { 0x140a, "es_CR" }, + { 0x140c, "fr_LU" }, + { 0x1801, "ar_MA" }, + { 0x1809, "en_IE" }, + { 0x180a, "es_PA" }, + { 0x1c01, "ar_TN" }, + { 0x1c09, "en_ZA" }, + { 0x1c0a, "es_DO" }, + { 0x2001, "ar_OM" }, + { 0x2009, "en_JM" }, + { 0x200a, "es_VE" }, + { 0x2401, "ar_YE" }, + { 0x2409, "en\0 " }, + { 0x240a, "es_CO" }, + { 0x2801, "ar_SY" }, + { 0x2809, "en_BZ" }, + { 0x280a, "es_PE" }, + { 0x2c01, "ar_JO" }, + { 0x2c09, "en_TT" }, + { 0x2c0a, "es_AR" }, + { 0x3001, "ar_LB" }, + { 0x300a, "es_EC" }, + { 0x3401, "ar_KW" }, + { 0x340a, "es_CL" }, + { 0x3801, "ar_AE" }, + { 0x380a, "es_UY" }, + { 0x3c01, "ar_BH" }, + { 0x3c0a, "es_PY" }, + { 0x4001, "ar_QA" }, + { 0x400a, "es_BO" }, + { 0x440a, "es_SV" }, + { 0x480a, "es_HN" }, + { 0x4c0a, "es_NI" }, + { 0x500a, "es_PR" } +}; + +static const int windows_to_iso_count + = sizeof(windows_to_iso_list)/sizeof(WindowsToISOListElt); + +static const char *winLangCodeToIsoName(int code) +{ + int cmp = code - windows_to_iso_list[0].windows_code; + if (cmp < 0) + return 0; + + if (cmp == 0) + return windows_to_iso_list[0].iso_name; + + int begin = 0; + int end = windows_to_iso_count; + + while (end - begin > 1) { + uint mid = (begin + end)/2; + + const WindowsToISOListElt *elt = windows_to_iso_list + mid; + int cmp = code - elt->windows_code; + if (cmp < 0) + end = mid; + else if (cmp > 0) + begin = mid; + else + return elt->iso_name; + } + + return 0; + +} + +static QString winIso639LangName(LCID id) +{ + QString result; + + // Windows returns the wrong ISO639 for some languages, we need to detect them here using + // the language code + QString lang_code; + wchar_t out[256]; + if (GetLocaleInfo(id, LOCALE_ILANGUAGE, out, 255)) + lang_code = QString::fromWCharArray(out); + + if (!lang_code.isEmpty()) { + const char *endptr; + bool ok; + QByteArray latin1_lang_code = lang_code.toLatin1(); + int i = qstrtoull(latin1_lang_code, &endptr, 16, &ok); + if (ok && *endptr == '\0') { + switch (i) { + case 0x814: + result = QLatin1String("nn"); // Nynorsk + break; + default: + break; + } + } + } + + if (!result.isEmpty()) + return result; + + // not one of the problematic languages - do the usual lookup + if (GetLocaleInfo(id, LOCALE_SISO639LANGNAME , out, 255)) + result = QString::fromWCharArray(out); + + return result; +} + +static QString winIso3116CtryName(LCID id) +{ + QString result; + + wchar_t out[256]; + if (GetLocaleInfo(id, LOCALE_SISO3166CTRYNAME, out, 255)) + result = QString::fromWCharArray(out); + + return result; +} + +QT_END_NAMESPACE diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index 9d564a1..586a917 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -19,6 +19,7 @@ HEADERS += \ tools/qlist.h \ tools/qlocale.h \ tools/qlocale_p.h \ + tools/qlocale_tools_p.h \ tools/qlocale_data_p.h \ tools/qmap.h \ tools/qmargins.h \ @@ -64,6 +65,7 @@ SOURCES += \ tools/qlinkedlist.cpp \ tools/qlist.cpp \ tools/qlocale.cpp \ + tools/qlocale_tools.cpp \ tools/qpoint.cpp \ tools/qmap.cpp \ tools/qmargins.cpp \ @@ -82,12 +84,13 @@ SOURCES += \ tools/qvector.cpp \ tools/qvsnprintf.cpp -symbian:SOURCES+=tools/qlocale_symbian.cpp - -!nacl:mac:SOURCES += tools/qelapsedtimer_mac.cpp -else:symbian:SOURCES += tools/qelapsedtimer_symbian.cpp -else:unix:SOURCES += tools/qelapsedtimer_unix.cpp -else:win32:SOURCES += tools/qelapsedtimer_win.cpp +!nacl:mac: { + SOURCES += tools/qelapsedtimer_mac.cpp + OBJECTIVE_SOURCES += tools/qlocale_mac.mm +} +else:symbian:SOURCES += tools/qelapsedtimer_symbian.cpp tools/qlocale_symbian.cpp +else:unix:SOURCES += tools/qelapsedtimer_unix.cpp tools/qlocale_unix.cpp +else:win32:SOURCES += tools/qelapsedtimer_win.cpp tools/qlocale_win.cpp else:SOURCES += tools/qelapsedtimer_generic.cpp contains(QT_CONFIG, zlib):include($$PWD/../../3rdparty/zlib.pri) diff --git a/src/tools/bootstrap/bootstrap.pro b/src/tools/bootstrap/bootstrap.pro index 9e5845c..50ae2cf 100644 --- a/src/tools/bootstrap/bootstrap.pro +++ b/src/tools/bootstrap/bootstrap.pro @@ -77,6 +77,7 @@ SOURCES += \ ../../corelib/tools/qhash.cpp \ ../../corelib/tools/qlist.cpp \ ../../corelib/tools/qlocale.cpp \ + ../../corelib/tools/qlocale_tools.cpp \ ../../corelib/tools/qmap.cpp \ ../../corelib/tools/qregexp.cpp \ ../../corelib/tools/qstring.cpp \ @@ -97,6 +98,11 @@ win32:SOURCES += ../../corelib/io/qfilesystemengine_win.cpp \ ../../corelib/io/qfsfileengine_win.cpp \ ../../corelib/plugin/qsystemlibrary.cpp \ +mac: OBJECTIVE_SOURCES += ../../corelib/tools/qlocale_mac.mm +else:symbian:SOURCES += ../../corelib/tools/qlocale_symbian.cpp +else:unix:SOURCES += ../../corelib/tools/qlocale_unix.cpp +else:win32:SOURCES += ../../corelib/tools/qlocale_win.cpp + macx: { QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.4 #enables weak linking for 10.4 (exported) SOURCES += ../../corelib/io/qfilesystemengine_mac.cpp -- cgit v0.12