1 /****************************************************************************
2 **
3 ** Copyright (C) 2020 The Qt Company Ltd.
4 ** Copyright (C) 2019 Intel Corporation.
5 ** Contact: https://www.qt.io/licensing/
6 **
7 ** This file is part of the QtCore module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see https://www.qt.io/terms-conditions. For further
16 ** information use the contact form at https://www.qt.io/contact-us.
17 **
18 ** GNU Lesser General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU Lesser
20 ** General Public License version 3 as published by the Free Software
21 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
22 ** packaging of this file. Please review the following information to
23 ** ensure the GNU Lesser General Public License version 3 requirements
24 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25 **
26 ** GNU General Public License Usage
27 ** Alternatively, this file may be used under the terms of the GNU
28 ** General Public License version 2.0 or (at your option) the GNU General
29 ** Public license version 3 or any later version approved by the KDE Free
30 ** Qt Foundation. The licenses are as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32 ** included in the packaging of this file. Please review the following
33 ** information to ensure the GNU General Public License requirements will
34 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35 ** https://www.gnu.org/licenses/gpl-3.0.html.
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40 
41 #include "qglobal.h"
42 
43 #if !defined(QWS) && defined(Q_OS_MAC)
44 #   include "private/qcore_mac_p.h"
45 #   include <CoreFoundation/CoreFoundation.h>
46 #endif
47 
48 #include "qplatformdefs.h"
49 
50 #include "qdatastream.h"
51 #include "qdebug.h"
52 #include "qhashfunctions.h"
53 #include "qstring.h"
54 #include "qlocale.h"
55 #include "qlocale_p.h"
56 #include "qlocale_tools_p.h"
57 #if QT_CONFIG(datetimeparser)
58 #include "private/qdatetimeparser_p.h"
59 #endif
60 #include "qnamespace.h"
61 #include "qdatetime.h"
62 #include "qstringlist.h"
63 #include "qvariant.h"
64 #include "qstringbuilder.h"
65 #include "private/qnumeric_p.h"
66 #include <cmath>
67 #ifndef QT_NO_SYSTEMLOCALE
68 #   include "qmutex.h"
69 #endif
70 #ifdef Q_OS_WIN
71 #   include <qt_windows.h>
72 #   include <time.h>
73 #endif
74 
75 #include "private/qcalendarbackend_p.h"
76 #include "private/qgregoriancalendar_p.h"
77 #include "qcalendar.h"
78 
79 QT_BEGIN_NAMESPACE
80 
81 #ifndef QT_NO_SYSTEMLOCALE
82 static QSystemLocale *_systemLocale = nullptr;
83 class QSystemLocaleSingleton: public QSystemLocale
84 {
85 public:
QSystemLocaleSingleton()86     QSystemLocaleSingleton() : QSystemLocale(true) {}
87 };
88 
89 Q_GLOBAL_STATIC(QSystemLocaleSingleton, QSystemLocale_globalSystemLocale)
90 static QLocaleData globalLocaleData;
91 #endif
92 
93 /******************************************************************************
94 ** Helpers for accessing Qt locale database
95 */
96 
97 QT_BEGIN_INCLUDE_NAMESPACE
98 #include "qlocale_data_p.h"
99 QT_END_INCLUDE_NAMESPACE
100 
codeToLanguage(QStringView code)101 QLocale::Language QLocalePrivate::codeToLanguage(QStringView code) noexcept
102 {
103     const auto len = code.size();
104     if (len != 2 && len != 3)
105         return QLocale::C;
106     ushort uc1 = code[0].toLower().unicode();
107     ushort uc2 = code[1].toLower().unicode();
108     ushort uc3 = len > 2 ? code[2].toLower().unicode() : 0;
109 
110     const unsigned char *c = language_code_list;
111     for (; *c != 0; c += 3) {
112         if (uc1 == c[0] && uc2 == c[1] && uc3 == c[2])
113             return QLocale::Language((c - language_code_list)/3);
114     }
115 
116     if (uc3 == 0) {
117         // legacy codes
118         if (uc1 == 'n' && uc2 == 'o') // no -> nb
119             return QLocale::NorwegianBokmal;
120         if (uc1 == 't' && uc2 == 'l') // tl -> fil
121             return QLocale::Filipino;
122         if (uc1 == 's' && uc2 == 'h') // sh -> sr[_Latn]
123             return QLocale::Serbian;
124         if (uc1 == 'm' && uc2 == 'o') // mo -> ro
125             return QLocale::Romanian;
126         // Android uses the following deprecated codes
127         if (uc1 == 'i' && uc2 == 'w') // iw -> he
128             return QLocale::Hebrew;
129         if (uc1 == 'i' && uc2 == 'n') // in -> id
130             return QLocale::Indonesian;
131         if (uc1 == 'j' && uc2 == 'i') // ji -> yi
132             return QLocale::Yiddish;
133     }
134     return QLocale::C;
135 }
136 
codeToScript(QStringView code)137 QLocale::Script QLocalePrivate::codeToScript(QStringView code) noexcept
138 {
139     const auto len = code.size();
140     if (len != 4)
141         return QLocale::AnyScript;
142 
143     // script is titlecased in our data
144     unsigned char c0 = code[0].toUpper().toLatin1();
145     unsigned char c1 = code[1].toLower().toLatin1();
146     unsigned char c2 = code[2].toLower().toLatin1();
147     unsigned char c3 = code[3].toLower().toLatin1();
148 
149     const unsigned char *c = script_code_list;
150     for (int i = 0; i < QLocale::LastScript; ++i, c += 4) {
151         if (c0 == c[0] && c1 == c[1] && c2 == c[2] && c3 == c[3])
152             return QLocale::Script(i);
153     }
154     return QLocale::AnyScript;
155 }
156 
codeToCountry(QStringView code)157 QLocale::Country QLocalePrivate::codeToCountry(QStringView code) noexcept
158 {
159     const auto len = code.size();
160     if (len != 2 && len != 3)
161         return QLocale::AnyCountry;
162 
163     ushort uc1 = code[0].toUpper().unicode();
164     ushort uc2 = code[1].toUpper().unicode();
165     ushort uc3 = len > 2 ? code[2].toUpper().unicode() : 0;
166 
167     const unsigned char *c = country_code_list;
168     for (; *c != 0; c += 3) {
169         if (uc1 == c[0] && uc2 == c[1] && uc3 == c[2])
170             return QLocale::Country((c - country_code_list)/3);
171     }
172 
173     return QLocale::AnyCountry;
174 }
175 
languageToCode(QLocale::Language language)176 QLatin1String QLocalePrivate::languageToCode(QLocale::Language language)
177 {
178     if (language == QLocale::AnyLanguage)
179         return QLatin1String();
180     if (language == QLocale::C)
181         return QLatin1String("C");
182 
183     const unsigned char *c = language_code_list + 3*(uint(language));
184 
185     return QLatin1String(reinterpret_cast<const char*>(c), c[2] == 0 ? 2 : 3);
186 
187 }
188 
scriptToCode(QLocale::Script script)189 QLatin1String QLocalePrivate::scriptToCode(QLocale::Script script)
190 {
191     if (script == QLocale::AnyScript || script > QLocale::LastScript)
192         return QLatin1String();
193     const unsigned char *c = script_code_list + 4*(uint(script));
194     return QLatin1String(reinterpret_cast<const char *>(c), 4);
195 }
196 
countryToCode(QLocale::Country country)197 QLatin1String QLocalePrivate::countryToCode(QLocale::Country country)
198 {
199     if (country == QLocale::AnyCountry)
200         return QLatin1String();
201 
202     const unsigned char *c = country_code_list + 3*(uint(country));
203 
204     return QLatin1String(reinterpret_cast<const char*>(c), c[2] == 0 ? 2 : 3);
205 }
206 
207 // http://www.unicode.org/reports/tr35/#Likely_Subtags
addLikelySubtags(QLocaleId & localeId)208 static bool addLikelySubtags(QLocaleId &localeId)
209 {
210     // ### optimize with bsearch
211     const int likely_subtags_count = sizeof(likely_subtags) / sizeof(likely_subtags[0]);
212     const QLocaleId *p = likely_subtags;
213     const QLocaleId *const e = p + likely_subtags_count;
214     for ( ; p < e; p += 2) {
215         if (localeId == p[0]) {
216             localeId = p[1];
217             return true;
218         }
219     }
220     return false;
221 }
222 
withLikelySubtagsAdded() const223 QLocaleId QLocaleId::withLikelySubtagsAdded() const
224 {
225     // language_script_region
226     if (language_id || script_id || country_id) {
227         QLocaleId id = QLocaleId::fromIds(language_id, script_id, country_id);
228         if (addLikelySubtags(id))
229             return id;
230     }
231     // language_region
232     if (script_id) {
233         QLocaleId id = QLocaleId::fromIds(language_id, 0, country_id);
234         if (addLikelySubtags(id)) {
235             id.script_id = script_id;
236             return id;
237         }
238     }
239     // language_script
240     if (country_id) {
241         QLocaleId id = QLocaleId::fromIds(language_id, script_id, 0);
242         if (addLikelySubtags(id)) {
243             id.country_id = country_id;
244             return id;
245         }
246     }
247     // language
248     if (script_id && country_id) {
249         QLocaleId id = QLocaleId::fromIds(language_id, 0, 0);
250         if (addLikelySubtags(id)) {
251             id.script_id = script_id;
252             id.country_id = country_id;
253             return id;
254         }
255     }
256     // und_script
257     if (language_id) {
258         QLocaleId id = QLocaleId::fromIds(0, script_id, 0);
259         if (addLikelySubtags(id)) {
260             id.language_id = language_id;
261             return id;
262         }
263     }
264     return *this;
265 }
266 
withLikelySubtagsRemoved() const267 QLocaleId QLocaleId::withLikelySubtagsRemoved() const
268 {
269     QLocaleId max = withLikelySubtagsAdded();
270     // language
271     {
272         QLocaleId id = QLocaleId::fromIds(language_id, 0, 0);
273         if (id.withLikelySubtagsAdded() == max)
274             return id;
275     }
276     // language_region
277     if (country_id) {
278         QLocaleId id = QLocaleId::fromIds(language_id, 0, country_id);
279         if (id.withLikelySubtagsAdded() == max)
280             return id;
281     }
282     // language_script
283     if (script_id) {
284         QLocaleId id = QLocaleId::fromIds(language_id, script_id, 0);
285         if (id.withLikelySubtagsAdded() == max)
286             return id;
287     }
288     return max;
289 }
290 
name(char separator) const291 QByteArray QLocaleId::name(char separator) const
292 {
293     if (language_id == QLocale::AnyLanguage)
294         return QByteArray();
295     if (language_id == QLocale::C)
296         return QByteArrayLiteral("C");
297 
298     const unsigned char *lang = language_code_list + 3 * language_id;
299     const unsigned char *script =
300             (script_id != QLocale::AnyScript ? script_code_list + 4 * script_id : nullptr);
301     const unsigned char *country =
302             (country_id != QLocale::AnyCountry ? country_code_list + 3 * country_id : nullptr);
303     char len = (lang[2] != 0 ? 3 : 2) + (script ? 4 + 1 : 0)
304         + (country ? (country[2] != 0 ? 3 : 2) + 1 : 0);
305     QByteArray name(len, Qt::Uninitialized);
306     char *uc = name.data();
307     *uc++ = lang[0];
308     *uc++ = lang[1];
309     if (lang[2] != 0)
310         *uc++ = lang[2];
311     if (script) {
312         *uc++ = separator;
313         *uc++ = script[0];
314         *uc++ = script[1];
315         *uc++ = script[2];
316         *uc++ = script[3];
317     }
318     if (country) {
319         *uc++ = separator;
320         *uc++ = country[0];
321         *uc++ = country[1];
322         if (country[2] != 0)
323             *uc++ = country[2];
324     }
325     return name;
326 }
327 
bcp47Name(char separator) const328 QByteArray QLocalePrivate::bcp47Name(char separator) const
329 {
330     if (m_data->m_language_id == QLocale::AnyLanguage)
331         return QByteArray();
332     if (m_data->m_language_id == QLocale::C)
333         return QByteArrayLiteral("en");
334 
335     QLocaleId localeId = QLocaleId::fromIds(m_data->m_language_id, m_data->m_script_id,
336                                             m_data->m_country_id);
337     return localeId.withLikelySubtagsRemoved().name(separator);
338 }
339 
340 /*!
341   \internal
342  */
rawName(char separator) const343 QByteArray QLocalePrivate::rawName(char separator) const
344 {
345     QByteArrayList parts;
346     if (m_data->m_language_id != QLocale::AnyLanguage)
347         parts.append(languageCode().latin1());
348     if (m_data->m_script_id != QLocale::AnyScript)
349         parts.append(scriptCode().latin1());
350     if (m_data->m_country_id != QLocale::AnyCountry)
351         parts.append(countryCode().latin1());
352 
353     return parts.join(separator);
354 }
355 
findLocaleDataById(const QLocaleId & localeId)356 static const QLocaleData *findLocaleDataById(const QLocaleId &localeId)
357 {
358     const uint idx = locale_index[localeId.language_id];
359 
360     const QLocaleData *data = locale_data + idx;
361 
362     // If there are no locales for specified language (so we we've got the
363     // default language, which has no associated script or country), give up:
364     if (localeId.language_id && idx == 0)
365         return data;
366 
367     Q_ASSERT(localeId.language_id
368              ? data->m_language_id == localeId.language_id
369              : data->m_language_id);
370 
371     if (localeId.script_id == QLocale::AnyScript && localeId.country_id == QLocale::AnyCountry)
372         return data;
373 
374     if (localeId.script_id == QLocale::AnyScript) {
375         do {
376             if (data->m_country_id == localeId.country_id)
377                 return data;
378             ++data;
379         } while (localeId.language_id
380                  ? data->m_language_id == localeId.language_id
381                  : data->m_language_id);
382     } else if (localeId.country_id == QLocale::AnyCountry) {
383         do {
384             if (data->m_script_id == localeId.script_id)
385                 return data;
386             ++data;
387         } while (localeId.language_id
388                  ? data->m_language_id == localeId.language_id
389                  : data->m_language_id);;
390     } else {
391         do {
392             if (data->m_script_id == localeId.script_id
393                 && data->m_country_id == localeId.country_id) {
394                 return data;
395             }
396             ++data;
397         } while (localeId.language_id
398                  ? data->m_language_id == localeId.language_id
399                  : data->m_language_id);;
400     }
401 
402     return nullptr;
403 }
404 
findLocaleData(QLocale::Language language,QLocale::Script script,QLocale::Country country)405 const QLocaleData *QLocaleData::findLocaleData(QLocale::Language language, QLocale::Script script,
406                                                QLocale::Country country)
407 {
408     QLocaleId localeId = QLocaleId::fromIds(language, script, country);
409     QLocaleId likelyId = localeId.withLikelySubtagsAdded();
410 
411     const uint idx = locale_index[likelyId.language_id];
412 
413     // Try a straight match with the likely data:
414     if (const QLocaleData *const data = findLocaleDataById(likelyId))
415         return data;
416     QList<QLocaleId> tried;
417     tried.push_back(likelyId);
418 
419     // No match; try again with raw data:
420     if (!tried.contains(localeId)) {
421         if (const QLocaleData *const data = findLocaleDataById(localeId))
422             return data;
423         tried.push_back(localeId);
424     }
425 
426     // No match; try again with likely country
427     if (country != QLocale::AnyCountry
428         && (language != QLocale::AnyLanguage || script != QLocale::AnyScript)) {
429         localeId = QLocaleId::fromIds(language, script, QLocale::AnyCountry);
430         likelyId = localeId.withLikelySubtagsAdded();
431         if (!tried.contains(likelyId)) {
432             if (const QLocaleData *const data = findLocaleDataById(likelyId))
433                 return data;
434             tried.push_back(likelyId);
435         }
436 
437         // No match; try again with any country
438         if (!tried.contains(localeId)) {
439             if (const QLocaleData *const data = findLocaleDataById(localeId))
440                 return data;
441             tried.push_back(localeId);
442         }
443     }
444 
445     // No match; try again with likely script
446     if (script != QLocale::AnyScript
447         && (language != QLocale::AnyLanguage || country != QLocale::AnyCountry)) {
448         localeId = QLocaleId::fromIds(language, QLocale::AnyScript, country);
449         likelyId = localeId.withLikelySubtagsAdded();
450         if (!tried.contains(likelyId)) {
451             if (const QLocaleData *const data = findLocaleDataById(likelyId))
452                 return data;
453             tried.push_back(likelyId);
454         }
455 
456         // No match; try again with any script
457         if (!tried.contains(localeId)) {
458             if (const QLocaleData *const data = findLocaleDataById(localeId))
459                 return data;
460             tried.push_back(localeId);
461         }
462     }
463 
464     // No match; return data at original index
465     return locale_data + idx;
466 }
467 
findLocaleOffset(QLocale::Language language,QLocale::Script script,QLocale::Country country)468 uint QLocaleData::findLocaleOffset(QLocale::Language language, QLocale::Script script,
469                                    QLocale::Country country)
470 {
471     return findLocaleData(language, script, country) - locale_data;
472 }
473 
parse_locale_tag(const QString & input,int & i,QString * result,const QString & separators)474 static bool parse_locale_tag(const QString &input, int &i, QString *result,
475                              const QString &separators)
476 {
477     *result = QString(8, Qt::Uninitialized); // worst case according to BCP47
478     QChar *pch = result->data();
479     const QChar *uc = input.data() + i;
480     const int l = input.length();
481     int size = 0;
482     for (; i < l && size < 8; ++i, ++size) {
483         if (separators.contains(*uc))
484             break;
485         if (! ((uc->unicode() >= 'a' && uc->unicode() <= 'z') ||
486                (uc->unicode() >= 'A' && uc->unicode() <= 'Z') ||
487                (uc->unicode() >= '0' && uc->unicode() <= '9')) ) // latin only
488             return false;
489         *pch++ = *uc++;
490     }
491     result->truncate(size);
492     return true;
493 }
494 
qt_splitLocaleName(const QString & name,QString & lang,QString & script,QString & cntry)495 bool qt_splitLocaleName(const QString &name, QString &lang, QString &script, QString &cntry)
496 {
497     const int length = name.length();
498 
499     lang = script = cntry = QString();
500 
501     const QString separators = QStringLiteral("_-.@");
502     enum ParserState { NoState, LangState, ScriptState, CountryState };
503     ParserState state = LangState;
504     for (int i = 0; i < length && state != NoState; ) {
505         QString value;
506         if (!parse_locale_tag(name, i, &value, separators) ||value.isEmpty())
507             break;
508         QChar sep = i < length ? name.at(i) : QChar();
509         switch (state) {
510         case LangState:
511             if (!sep.isNull() && !separators.contains(sep)) {
512                 state = NoState;
513                 break;
514             }
515             lang = value;
516             if (i == length) {
517                 // just language was specified
518                 state = NoState;
519                 break;
520             }
521             state = ScriptState;
522             break;
523         case ScriptState: {
524             QString scripts = QString::fromLatin1((const char *)script_code_list,
525                                                   sizeof(script_code_list) - 1);
526             if (value.length() == 4 && scripts.indexOf(value) % 4 == 0) {
527                 // script name is always 4 characters
528                 script = value;
529                 state = CountryState;
530             } else {
531                 // it wasn't a script, maybe it is a country then?
532                 cntry = value;
533                 state = NoState;
534             }
535             break;
536         }
537         case CountryState:
538             cntry = value;
539             state = NoState;
540             break;
541         case NoState:
542             // shouldn't happen
543             qWarning("QLocale: This should never happen");
544             break;
545         }
546         ++i;
547     }
548     return lang.length() == 2 || lang.length() == 3;
549 }
550 
getLangAndCountry(const QString & name,QLocale::Language & lang,QLocale::Script & script,QLocale::Country & cntry)551 void QLocalePrivate::getLangAndCountry(const QString &name, QLocale::Language &lang,
552                                        QLocale::Script &script, QLocale::Country &cntry)
553 {
554     lang = QLocale::C;
555     script = QLocale::AnyScript;
556     cntry = QLocale::AnyCountry;
557 
558     QString lang_code;
559     QString script_code;
560     QString cntry_code;
561     if (!qt_splitLocaleName(name, lang_code, script_code, cntry_code))
562         return;
563 
564     lang = QLocalePrivate::codeToLanguage(lang_code);
565     if (lang == QLocale::C)
566         return;
567     script = QLocalePrivate::codeToScript(script_code);
568     cntry = QLocalePrivate::codeToCountry(cntry_code);
569 }
570 
findLocaleData(const QString & name)571 static const QLocaleData *findLocaleData(const QString &name)
572 {
573     QLocale::Language lang;
574     QLocale::Script script;
575     QLocale::Country cntry;
576     QLocalePrivate::getLangAndCountry(name, lang, script, cntry);
577 
578     return QLocaleData::findLocaleData(lang, script, cntry);
579 }
580 
findLocaleOffset(const QString & name)581 static uint findLocaleOffset(const QString &name)
582 {
583     QLocale::Language lang;
584     QLocale::Script script;
585     QLocale::Country cntry;
586     QLocalePrivate::getLangAndCountry(name, lang, script, cntry);
587 
588     return QLocaleData::findLocaleOffset(lang, script, cntry);
589 }
590 
qt_readEscapedFormatString(QStringView format,int * idx)591 QString qt_readEscapedFormatString(QStringView format, int *idx)
592 {
593     int &i = *idx;
594 
595     Q_ASSERT(format.at(i) == QLatin1Char('\''));
596     ++i;
597     if (i == format.size())
598         return QString();
599     if (format.at(i).unicode() == '\'') { // "''" outside of a quoted stirng
600         ++i;
601         return QLatin1String("'");
602     }
603 
604     QString result;
605 
606     while (i < format.size()) {
607         if (format.at(i).unicode() == '\'') {
608             if (format.mid(i + 1).startsWith(QLatin1Char('\''))) {
609                 // "''" inside a quoted string
610                 result.append(QLatin1Char('\''));
611                 i += 2;
612             } else {
613                 break;
614             }
615         } else {
616             result.append(format.at(i++));
617         }
618     }
619     if (i < format.size())
620         ++i;
621 
622     return result;
623 }
624 
625 /*!
626     \internal
627 
628     Counts the number of identical leading characters in \a s.
629 
630     If \a s is empty, returns 0.
631 
632     Otherwise, returns the number of consecutive \c{s.front()}
633     characters at the start of \a s.
634 
635     \code
636     qt_repeatCount(u"a");   // == 1
637     qt_repeatCount(u"ab");  // == 1
638     qt_repeatCount(u"aab"); // == 2
639     \endcode
640 */
qt_repeatCount(QStringView s)641 int qt_repeatCount(QStringView s)
642 {
643     if (s.isEmpty())
644         return 0;
645     const QChar c = s.front();
646     qsizetype j = 1;
647     while (j < s.size() && s.at(j) == c)
648         ++j;
649     return int(j);
650 }
651 
652 static const QLocaleData *default_data = nullptr;
653 
654 static const QLocaleData *const c_data = locale_data;
c_private()655 static QLocalePrivate *c_private()
656 {
657     static QLocalePrivate c_locale{
658             c_data, Q_BASIC_ATOMIC_INITIALIZER(1), 0, QLocale::OmitGroupSeparator };
659     return &c_locale;
660 }
661 
662 static const QLocaleData *systemData();
663 static QLocale::NumberOptions system_number_options = QLocale::DefaultNumberOptions;
664 Q_GLOBAL_STATIC_WITH_ARGS(QExplicitlySharedDataPointer<QLocalePrivate>, systemLocalePrivate,
665                           (QLocalePrivate::create(systemData(), system_number_options)))
666 
667 #ifndef QT_NO_SYSTEMLOCALE
668 /******************************************************************************
669 ** Default system locale behavior
670 */
671 
672 /*!
673   Constructs a QSystemLocale object.
674 
675   The constructor will automatically install this object as the system locale,
676   if there's not one active.  It also resets the flag that'll prompt
677   QLocale::system() to re-initialize its data, so that instantiating a
678   QSystemLocale transiently (doesn't install the transient as system locale if
679   there was one already and) triggers an update to the system locale's data.
680 */
QSystemLocale()681 QSystemLocale::QSystemLocale()
682 {
683     if (!_systemLocale)
684         _systemLocale = this;
685 
686     globalLocaleData.m_language_id = 0;
687 }
688 
689 /*!
690     \internal
691 */
QSystemLocale(bool)692 QSystemLocale::QSystemLocale(bool)
693 { }
694 
695 /*!
696   Deletes the object.
697 */
~QSystemLocale()698 QSystemLocale::~QSystemLocale()
699 {
700     if (_systemLocale == this) {
701         _systemLocale = nullptr;
702 
703         globalLocaleData.m_language_id = 0;
704     }
705 }
706 
systemLocale()707 static const QSystemLocale *systemLocale()
708 {
709     if (_systemLocale)
710         return _systemLocale;
711     return QSystemLocale_globalSystemLocale();
712 }
713 
updateSystemPrivate()714 static void updateSystemPrivate()
715 {
716     // This function is NOT thread-safe!
717     // It *should not* be called by anything but systemData()
718     // It *is* called before {system,default}LocalePrivate exist.
719     const QSystemLocale *sys_locale = systemLocale();
720 
721     // tell the object that the system locale has changed.
722     sys_locale->query(QSystemLocale::LocaleChanged, QVariant());
723 
724     // Populate global with fallback as basis:
725     globalLocaleData = *sys_locale->fallbackUiLocaleData();
726     system_number_options = QLocale::DefaultNumberOptions;
727 
728     QVariant res = sys_locale->query(QSystemLocale::LanguageId, QVariant());
729     if (!res.isNull()) {
730         globalLocaleData.m_language_id = res.toInt();
731         globalLocaleData.m_script_id = QLocale::AnyScript; // default for compatibility
732         if (globalLocaleData.m_language_id == QLocale::C)
733             system_number_options = QLocale::OmitGroupSeparator;
734     }
735     res = sys_locale->query(QSystemLocale::CountryId, QVariant());
736     if (!res.isNull()) {
737         globalLocaleData.m_country_id = res.toInt();
738         globalLocaleData.m_script_id = QLocale::AnyScript; // default for compatibility
739     }
740     res = sys_locale->query(QSystemLocale::ScriptId, QVariant());
741     if (!res.isNull())
742         globalLocaleData.m_script_id = res.toInt();
743 
744     res = sys_locale->query(QSystemLocale::DecimalPoint, QVariant());
745     if (!res.isNull() && !res.toString().isEmpty())
746         globalLocaleData.m_decimal = res.toString().at(0).unicode();
747 
748     // System may supply empty group separator to say we should omit grouping;
749     // and it makes no sense to use the same separator for decimal and grouping
750     // (which might happen by system supplying, as decimal, what CLDR has given
751     // us for grouping; or the other way round). Assume, at least, that each of
752     // system and CLDR has decimal != group, all the same.
753     res = sys_locale->query(QSystemLocale::GroupSeparator, QVariant());
754     if (res.isNull()) {
755         // The case where system over-rides decimal but not group, and its
756         // decimal clashes with CLDR's group.
757         if (globalLocaleData.m_group == globalLocaleData.m_decimal)
758             system_number_options |= QLocale::OmitGroupSeparator;
759     } else if (res.toString().isEmpty()) {
760         system_number_options |= QLocale::OmitGroupSeparator;
761     } else {
762         const ushort group = res.toString().at(0).unicode();
763         if (group != globalLocaleData.m_decimal)
764             globalLocaleData.m_group = group;
765     }
766 
767     res = sys_locale->query(QSystemLocale::ZeroDigit, QVariant());
768     if (!res.isNull() && !res.toString().isEmpty())
769         globalLocaleData.m_zero = res.toString().at(0).unicode();
770 
771     res = sys_locale->query(QSystemLocale::NegativeSign, QVariant());
772     if (!res.isNull() && !res.toString().isEmpty())
773         globalLocaleData.m_minus = res.toString().at(0).unicode();
774 
775     res = sys_locale->query(QSystemLocale::PositiveSign, QVariant());
776     if (!res.isNull() && !res.toString().isEmpty())
777         globalLocaleData.m_plus = res.toString().at(0).unicode();
778 
779     if (systemLocalePrivate.exists())
780         systemLocalePrivate->data()->m_numberOptions = system_number_options;
781     // else: system_number_options will be passed to create() when constructing.
782 }
783 #endif // !QT_NO_SYSTEMLOCALE
784 
systemData()785 static const QLocaleData *systemData()
786 {
787 #ifndef QT_NO_SYSTEMLOCALE
788     /*
789       Copy over the information from the fallback locale and modify.
790 
791       This modifies (cross-thread) global state, so take care to only call it in
792       one thread.
793     */
794     {
795         static QBasicMutex systemDataMutex;
796         systemDataMutex.lock();
797         if (globalLocaleData.m_language_id == 0)
798             updateSystemPrivate();
799         systemDataMutex.unlock();
800     }
801 
802     return &globalLocaleData;
803 #else
804     return locale_data;
805 #endif
806 }
807 
defaultData()808 static const QLocaleData *defaultData()
809 {
810     if (!default_data)
811         default_data = systemData();
812     return default_data;
813 }
814 
c()815 const QLocaleData *QLocaleData::c()
816 {
817     Q_ASSERT(locale_index[QLocale::C] == 0);
818     return c_data;
819 }
820 
getLocaleData(const ushort * data,int size)821 static inline QString getLocaleData(const ushort *data, int size)
822 {
823     return size > 0 ? QString::fromRawData(reinterpret_cast<const QChar *>(data), size) : QString();
824 }
825 
getLocaleListData(const ushort * data,int size,int index)826 static QString getLocaleListData(const ushort *data, int size, int index)
827 {
828     static const ushort separator = ';';
829     while (index && size > 0) {
830         while (*data != separator)
831             ++data, --size;
832         --index;
833         ++data;
834         --size;
835     }
836     const ushort *end = data;
837     while (size > 0 && *end != separator)
838         ++end, --size;
839     return getLocaleData(data, end - data);
840 }
841 
842 
843 #ifndef QT_NO_DATASTREAM
operator <<(QDataStream & ds,const QLocale & l)844 QDataStream &operator<<(QDataStream &ds, const QLocale &l)
845 {
846     ds << l.name();
847     return ds;
848 }
849 
operator >>(QDataStream & ds,QLocale & l)850 QDataStream &operator>>(QDataStream &ds, QLocale &l)
851 {
852     QString s;
853     ds >> s;
854     l = QLocale(s);
855     return ds;
856 }
857 #endif // QT_NO_DATASTREAM
858 
859 
860 static const int locale_data_size = sizeof(locale_data)/sizeof(QLocaleData) - 1;
861 
862 Q_GLOBAL_STATIC_WITH_ARGS(QSharedDataPointer<QLocalePrivate>, defaultLocalePrivate,
863                           (QLocalePrivate::create(defaultData())))
864 
localePrivateByName(const QString & name)865 static QLocalePrivate *localePrivateByName(const QString &name)
866 {
867     if (name == QLatin1String("C"))
868         return c_private();
869     // TODO: Remove this version, and use offset everywhere
870     const QLocaleData *data = findLocaleData(name);
871     return QLocalePrivate::create(data, findLocaleOffset(name),
872                                   data->m_language_id == QLocale::C
873                                   ? QLocale::OmitGroupSeparator : QLocale::DefaultNumberOptions);
874 }
875 
findLocalePrivate(QLocale::Language language,QLocale::Script script,QLocale::Country country)876 static QLocalePrivate *findLocalePrivate(QLocale::Language language, QLocale::Script script,
877                                          QLocale::Country country)
878 {
879     if (language == QLocale::C)
880         return c_private();
881 
882     // TODO: Remove pointer, use index instead
883     const QLocaleData *data = QLocaleData::findLocaleData(language, script, country);
884     const uint offset = QLocaleData::findLocaleOffset(language, script, country);
885 
886     QLocale::NumberOptions numberOptions = QLocale::DefaultNumberOptions;
887 
888     // If not found, should default to system
889     if (data->m_language_id == QLocale::C) {
890         if (defaultLocalePrivate.exists())
891             numberOptions = defaultLocalePrivate->data()->m_numberOptions;
892         data = defaultData();
893     }
894     return QLocalePrivate::create(data, offset, numberOptions);
895 }
896 
897 
898 /*!
899  \internal
900 */
QLocale(QLocalePrivate & dd)901 QLocale::QLocale(QLocalePrivate &dd)
902     : d(&dd)
903 {}
904 
905 
906 /*!
907     Constructs a QLocale object with the specified \a name,
908     which has the format
909     "language[_script][_country][.codeset][@modifier]" or "C", where:
910 
911     \list
912     \li language is a lowercase, two-letter, ISO 639 language code (also some
913         three-letter codes),
914     \li script is a titlecase, four-letter, ISO 15924 script code,
915     \li country is an uppercase, two-letter, ISO 3166 country code
916         (also "419" as defined by United Nations),
917     \li and codeset and modifier are ignored.
918     \endlist
919 
920     The separator can be either underscore or a minus sign.
921 
922     If the string violates the locale format, or language is not
923     a valid ISO 639 code, the "C" locale is used instead. If country
924     is not present, or is not a valid ISO 3166 code, the most
925     appropriate country is chosen for the specified language.
926 
927     The language, script and country codes are converted to their respective
928     \c Language, \c Script and \c Country enums. After this conversion is
929     performed, the constructor behaves exactly like QLocale(Country, Script,
930     Language).
931 
932     This constructor is much slower than QLocale(Country, Script, Language).
933 
934     \sa bcp47Name()
935 */
936 
QLocale(const QString & name)937 QLocale::QLocale(const QString &name)
938     : d(localePrivateByName(name))
939 {
940 }
941 
942 /*!
943     Constructs a QLocale object initialized with the default locale. If
944     no default locale was set using setDefault(), this locale will
945     be the same as the one returned by system().
946 
947     \sa setDefault()
948 */
949 
QLocale()950 QLocale::QLocale()
951     : d(*defaultLocalePrivate)
952 {
953     // Make sure system data is up to date
954     systemData();
955 }
956 
957 /*!
958     Constructs a QLocale object with the specified \a language and \a
959     country.
960 
961     \list
962     \li If the language/country pair is found in the database, it is used.
963     \li If the language is found but the country is not, or if the country
964        is \c AnyCountry, the language is used with the most
965        appropriate available country (for example, Germany for German),
966     \li If neither the language nor the country are found, QLocale
967        defaults to the default locale (see setDefault()).
968     \endlist
969 
970     The language and country that are actually used can be queried
971     using language() and country().
972 
973     \sa setDefault(), language(), country()
974 */
975 
QLocale(Language language,Country country)976 QLocale::QLocale(Language language, Country country)
977     : d(findLocalePrivate(language, QLocale::AnyScript, country))
978 {
979 }
980 
981 /*!
982     \since 4.8
983 
984     Constructs a QLocale object with the specified \a language, \a script and
985     \a country.
986 
987     \list
988     \li If the language/script/country is found in the database, it is used.
989     \li If both \a script is AnyScript and \a country is AnyCountry, the
990        language is used with the most appropriate available script and country
991        (for example, Germany for German),
992     \li If either \a script is AnyScript or \a country is AnyCountry, the
993        language is used with the first locale that matches the given \a script
994        and \a country.
995     \li If neither the language nor the country are found, QLocale
996        defaults to the default locale (see setDefault()).
997     \endlist
998 
999     The language, script and country that are actually used can be queried
1000     using language(), script() and country().
1001 
1002     \sa setDefault(), language(), script(), country()
1003 */
1004 
QLocale(Language language,Script script,Country country)1005 QLocale::QLocale(Language language, Script script, Country country)
1006     : d(findLocalePrivate(language, script, country))
1007 {
1008 }
1009 
1010 /*!
1011     Constructs a QLocale object as a copy of \a other.
1012 */
1013 
QLocale(const QLocale & other)1014 QLocale::QLocale(const QLocale &other)
1015 {
1016     d = other.d;
1017 }
1018 
1019 /*!
1020     Destructor
1021 */
1022 
~QLocale()1023 QLocale::~QLocale()
1024 {
1025 }
1026 
1027 /*!
1028     Assigns \a other to this QLocale object and returns a reference
1029     to this QLocale object.
1030 */
1031 
operator =(const QLocale & other)1032 QLocale &QLocale::operator=(const QLocale &other)
1033 {
1034     d = other.d;
1035     return *this;
1036 }
1037 
operator ==(const QLocale & other) const1038 bool QLocale::operator==(const QLocale &other) const
1039 {
1040     return d->m_data == other.d->m_data && d->m_numberOptions == other.d->m_numberOptions;
1041 }
1042 
operator !=(const QLocale & other) const1043 bool QLocale::operator!=(const QLocale &other) const
1044 {
1045     return d->m_data != other.d->m_data || d->m_numberOptions != other.d->m_numberOptions;
1046 }
1047 
1048 /*!
1049     \fn void QLocale::swap(QLocale &other)
1050     \since 5.6
1051 
1052     Swaps locale \a other with this locale. This operation is very fast and
1053     never fails.
1054 */
1055 
1056 /*!
1057     \since 5.6
1058     \relates QLocale
1059 
1060     Returns the hash value for \a key, using
1061     \a seed to seed the calculation.
1062 */
qHash(const QLocale & key,uint seed)1063 uint qHash(const QLocale &key, uint seed) noexcept
1064 {
1065     QtPrivate::QHashCombine hash;
1066     seed = hash(seed, key.d->m_data);
1067     seed = hash(seed, key.d->m_numberOptions);
1068     return seed;
1069 }
1070 
1071 /*!
1072     \since 4.2
1073 
1074     Sets the \a options related to number conversions for this
1075     QLocale instance.
1076 
1077     \sa numberOptions()
1078 */
setNumberOptions(NumberOptions options)1079 void QLocale::setNumberOptions(NumberOptions options)
1080 {
1081     d->m_numberOptions = options;
1082 }
1083 
1084 /*!
1085     \since 4.2
1086 
1087     Returns the options related to number conversions for this
1088     QLocale instance.
1089 
1090     By default, no options are set for the standard locales, except
1091     for the "C" locale, which has OmitGroupSeparator set by default.
1092 
1093     \sa setNumberOptions(), toString(), groupSeparator()
1094 */
numberOptions() const1095 QLocale::NumberOptions QLocale::numberOptions() const
1096 {
1097     return static_cast<NumberOptions>(d->m_numberOptions);
1098 }
1099 
1100 /*!
1101     \since 4.8
1102 
1103     Returns \a str quoted according to the current locale using the given
1104     quotation \a style.
1105 */
quoteString(const QString & str,QuotationStyle style) const1106 QString QLocale::quoteString(const QString &str, QuotationStyle style) const
1107 {
1108     return quoteString(QStringRef(&str), style);
1109 }
1110 
1111 /*!
1112     \since 4.8
1113 
1114     \overload
1115 */
quoteString(const QStringRef & str,QuotationStyle style) const1116 QString QLocale::quoteString(const QStringRef &str, QuotationStyle style) const
1117 {
1118 #ifndef QT_NO_SYSTEMLOCALE
1119     if (d->m_data == systemData()) {
1120         QVariant res;
1121         if (style == QLocale::AlternateQuotation)
1122             res = systemLocale()->query(QSystemLocale::StringToAlternateQuotation,
1123                                         QVariant::fromValue(str));
1124         if (res.isNull() || style == QLocale::StandardQuotation)
1125             res = systemLocale()->query(QSystemLocale::StringToStandardQuotation,
1126                                         QVariant::fromValue(str));
1127         if (!res.isNull())
1128             return res.toString();
1129     }
1130 #endif
1131 
1132     if (style == QLocale::StandardQuotation)
1133         return QChar(d->m_data->m_quotation_start) % str % QChar(d->m_data->m_quotation_end);
1134 
1135     return QChar(d->m_data->m_alternate_quotation_start)
1136         % str % QChar(d->m_data->m_alternate_quotation_end);
1137 }
1138 
1139 /*!
1140     \since 4.8
1141 
1142     Returns a string that represents a join of a given \a list of strings with
1143     a separator defined by the locale.
1144 */
createSeparatedList(const QStringList & list) const1145 QString QLocale::createSeparatedList(const QStringList &list) const
1146 {
1147 #ifndef QT_NO_SYSTEMLOCALE
1148     if (d->m_data == systemData()) {
1149         QVariant res =
1150             systemLocale()->query(QSystemLocale::ListToSeparatedString, QVariant::fromValue(list));
1151 
1152         if (!res.isNull())
1153             return res.toString();
1154     }
1155 #endif
1156 
1157     const int size = list.size();
1158     if (size == 1) {
1159         return list.at(0);
1160     } else if (size == 2) {
1161         QString format = getLocaleData(
1162             list_pattern_part_data + d->m_data->m_list_pattern_part_two_idx,
1163             d->m_data->m_list_pattern_part_two_size);
1164         return format.arg(list.at(0), list.at(1));
1165     } else if (size > 2) {
1166         QString formatStart = getLocaleData(
1167             list_pattern_part_data + d->m_data->m_list_pattern_part_start_idx,
1168             d->m_data->m_list_pattern_part_start_size);
1169         QString formatMid = getLocaleData(
1170             list_pattern_part_data + d->m_data->m_list_pattern_part_mid_idx,
1171             d->m_data->m_list_pattern_part_mid_size);
1172         QString formatEnd = getLocaleData(
1173             list_pattern_part_data + d->m_data->m_list_pattern_part_end_idx,
1174             d->m_data->m_list_pattern_part_end_size);
1175         QString result = formatStart.arg(list.at(0), list.at(1));
1176         for (int i = 2; i < size - 1; ++i)
1177             result = formatMid.arg(result, list.at(i));
1178         result = formatEnd.arg(result, list.at(size - 1));
1179         return result;
1180     }
1181 
1182     return QString();
1183 }
1184 
1185 /*!
1186     \nonreentrant
1187 
1188     Sets the global default locale to \a locale. These
1189     values are used when a QLocale object is constructed with
1190     no arguments. If this function is not called, the system's
1191     locale is used.
1192 
1193     \warning In a multithreaded application, the default locale
1194     should be set at application startup, before any non-GUI threads
1195     are created.
1196 
1197     \sa system(), c()
1198 */
1199 
setDefault(const QLocale & locale)1200 void QLocale::setDefault(const QLocale &locale)
1201 {
1202     default_data = locale.d->m_data;
1203 
1204     if (defaultLocalePrivate.isDestroyed())
1205         return; // avoid crash on exit
1206     if (!defaultLocalePrivate.exists()) {
1207         // Force it to exist; see QTBUG-83016
1208         QLocale ignoreme;
1209         Q_ASSERT(defaultLocalePrivate.exists());
1210     }
1211 
1212     // update the cached private
1213     *defaultLocalePrivate = locale.d;
1214 }
1215 
1216 /*!
1217     Returns the language of this locale.
1218 
1219     \sa script(), country(), languageToString(), bcp47Name()
1220 */
language() const1221 QLocale::Language QLocale::language() const
1222 {
1223     return Language(d->languageId());
1224 }
1225 
1226 /*!
1227     \since 4.8
1228 
1229     Returns the script of this locale.
1230 
1231     \sa language(), country(), languageToString(), scriptToString(), bcp47Name()
1232 */
script() const1233 QLocale::Script QLocale::script() const
1234 {
1235     return Script(d->m_data->m_script_id);
1236 }
1237 
1238 /*!
1239     Returns the country of this locale.
1240 
1241     \sa language(), script(), countryToString(), bcp47Name()
1242 */
country() const1243 QLocale::Country QLocale::country() const
1244 {
1245     return Country(d->countryId());
1246 }
1247 
1248 /*!
1249     Returns the language and country of this locale as a
1250     string of the form "language_country", where
1251     language is a lowercase, two-letter ISO 639 language code,
1252     and country is an uppercase, two- or three-letter ISO 3166 country code.
1253 
1254     Note that even if QLocale object was constructed with an explicit script,
1255     name() will not contain it for compatibility reasons. Use bcp47Name() instead
1256     if you need a full locale name.
1257 
1258     \sa QLocale(), language(), script(), country(), bcp47Name()
1259 */
1260 
name() const1261 QString QLocale::name() const
1262 {
1263     Language l = language();
1264     if (l == C)
1265         return d->languageCode();
1266 
1267     Country c = country();
1268     if (c == AnyCountry)
1269         return d->languageCode();
1270 
1271     return d->languageCode() + QLatin1Char('_') + d->countryCode();
1272 }
1273 
toIntegral_helper(const QLocaleData * d,QStringView str,bool * ok,QLocale::NumberOptions mode,qlonglong)1274 static qlonglong toIntegral_helper(const QLocaleData *d, QStringView str, bool *ok,
1275                                    QLocale::NumberOptions mode, qlonglong)
1276 {
1277     return d->stringToLongLong(str, 10, ok, mode);
1278 }
1279 
toIntegral_helper(const QLocaleData * d,QStringView str,bool * ok,QLocale::NumberOptions mode,qulonglong)1280 static qulonglong toIntegral_helper(const QLocaleData *d, QStringView str, bool *ok,
1281                                     QLocale::NumberOptions mode, qulonglong)
1282 {
1283     return d->stringToUnsLongLong(str, 10, ok, mode);
1284 }
1285 
1286 template <typename T> static inline
toIntegral_helper(const QLocalePrivate * d,QStringView str,bool * ok)1287 T toIntegral_helper(const QLocalePrivate *d, QStringView str, bool *ok)
1288 {
1289     using Int64 =
1290         typename std::conditional<std::is_unsigned<T>::value, qulonglong, qlonglong>::type;
1291 
1292     // we select the right overload by the last, unused parameter
1293     Int64 val = toIntegral_helper(d->m_data, str, ok, d->m_numberOptions, Int64());
1294     if (T(val) != val) {
1295         if (ok != nullptr)
1296             *ok = false;
1297         val = 0;
1298     }
1299     return T(val);
1300 }
1301 
1302 
1303 /*!
1304     \since 4.8
1305 
1306     Returns the dash-separated language, script and country (and possibly other
1307     BCP47 fields) of this locale as a string.
1308 
1309     Unlike the uiLanguages() the returned value of the bcp47Name() represents
1310     the locale name of the QLocale data but not the language the user-interface
1311     should be in.
1312 
1313     This function tries to conform the locale name to BCP47.
1314 
1315     \sa language(), country(), script(), uiLanguages()
1316 */
bcp47Name() const1317 QString QLocale::bcp47Name() const
1318 {
1319     return QString::fromLatin1(d->bcp47Name());
1320 }
1321 
1322 /*!
1323     Returns a QString containing the name of \a language.
1324 
1325     \sa countryToString(), scriptToString(), bcp47Name()
1326 */
1327 
languageToString(Language language)1328 QString QLocale::languageToString(Language language)
1329 {
1330     if (uint(language) > uint(QLocale::LastLanguage))
1331         return QLatin1String("Unknown");
1332     return QLatin1String(language_name_list + language_name_index[language]);
1333 }
1334 
1335 /*!
1336     Returns a QString containing the name of \a country.
1337 
1338     \sa languageToString(), scriptToString(), country(), bcp47Name()
1339 */
1340 
countryToString(Country country)1341 QString QLocale::countryToString(Country country)
1342 {
1343     if (uint(country) > uint(QLocale::LastCountry))
1344         return QLatin1String("Unknown");
1345     return QLatin1String(country_name_list + country_name_index[country]);
1346 }
1347 
1348 /*!
1349     \since 4.8
1350 
1351     Returns a QString containing the name of \a script.
1352 
1353     \sa languageToString(), countryToString(), script(), bcp47Name()
1354 */
scriptToString(QLocale::Script script)1355 QString QLocale::scriptToString(QLocale::Script script)
1356 {
1357     if (uint(script) > uint(QLocale::LastScript))
1358         return QLatin1String("Unknown");
1359     return QLatin1String(script_name_list + script_name_index[script]);
1360 }
1361 
1362 #if QT_STRINGVIEW_LEVEL < 2
1363 /*!
1364     Returns the short int represented by the localized string \a s.
1365 
1366     If the conversion fails the function returns 0.
1367 
1368     If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1369     to \c false, and success by setting *\a{ok} to \c true.
1370 
1371     This function ignores leading and trailing whitespace.
1372 
1373     \sa toUShort(), toString()
1374 */
1375 
toShort(const QString & s,bool * ok) const1376 short QLocale::toShort(const QString &s, bool *ok) const
1377 {
1378     return toIntegral_helper<short>(d, s, ok);
1379 }
1380 
1381 /*!
1382     Returns the unsigned short int represented by the localized string \a s.
1383 
1384     If the conversion fails the function returns 0.
1385 
1386     If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1387     to \c false, and success by setting *\a{ok} to \c true.
1388 
1389     This function ignores leading and trailing whitespace.
1390 
1391     \sa toShort(), toString()
1392 */
1393 
toUShort(const QString & s,bool * ok) const1394 ushort QLocale::toUShort(const QString &s, bool *ok) const
1395 {
1396     return toIntegral_helper<ushort>(d, s, ok);
1397 }
1398 
1399 /*!
1400     Returns the int represented by the localized string \a s.
1401 
1402     If the conversion fails the function returns 0.
1403 
1404     If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1405     to \c false, and success by setting *\a{ok} to \c true.
1406 
1407     This function ignores leading and trailing whitespace.
1408 
1409     \sa toUInt(), toString()
1410 */
1411 
toInt(const QString & s,bool * ok) const1412 int QLocale::toInt(const QString &s, bool *ok) const
1413 {
1414     return toIntegral_helper<int>(d, s, ok);
1415 }
1416 
1417 /*!
1418     Returns the unsigned int represented by the localized string \a s.
1419 
1420     If the conversion fails the function returns 0.
1421 
1422     If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1423     to \c false, and success by setting *\a{ok} to \c true.
1424 
1425     This function ignores leading and trailing whitespace.
1426 
1427     \sa toInt(), toString()
1428 */
1429 
toUInt(const QString & s,bool * ok) const1430 uint QLocale::toUInt(const QString &s, bool *ok) const
1431 {
1432     return toIntegral_helper<uint>(d, s, ok);
1433 }
1434 
1435 /*!
1436  Returns the long int represented by the localized string \a s.
1437 
1438  If the conversion fails the function returns 0.
1439 
1440  If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1441  to \c false, and success by setting *\a{ok} to \c true.
1442 
1443  This function ignores leading and trailing whitespace.
1444 
1445  \sa toInt(), toULong(), toDouble(), toString()
1446 
1447  \since 5.13
1448  */
1449 
1450 
toLong(const QString & s,bool * ok) const1451 long QLocale::toLong(const QString &s, bool *ok) const
1452 {
1453     return toIntegral_helper<long>(d, s, ok);
1454 }
1455 
1456 /*!
1457  Returns the unsigned long int represented by the localized
1458  string \a s.
1459 
1460  If the conversion fails the function returns 0.
1461 
1462  If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1463  to \c false, and success by setting *\a{ok} to \c true.
1464 
1465  This function ignores leading and trailing whitespace.
1466 
1467  \sa toLong(), toInt(), toDouble(), toString()
1468 
1469  \since 5.13
1470 */
1471 
toULong(const QString & s,bool * ok) const1472 ulong QLocale::toULong(const QString &s, bool *ok) const
1473 {
1474     return toIntegral_helper<ulong>(d, s, ok);
1475 }
1476 
1477 /*!
1478     Returns the long long int represented by the localized string \a s.
1479 
1480     If the conversion fails the function returns 0.
1481 
1482     If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1483     to \c false, and success by setting *\a{ok} to \c true.
1484 
1485     This function ignores leading and trailing whitespace.
1486 
1487     \sa toInt(), toULongLong(), toDouble(), toString()
1488 */
1489 
1490 
toLongLong(const QString & s,bool * ok) const1491 qlonglong QLocale::toLongLong(const QString &s, bool *ok) const
1492 {
1493     return toIntegral_helper<qlonglong>(d, s, ok);
1494 }
1495 
1496 /*!
1497     Returns the unsigned long long int represented by the localized
1498     string \a s.
1499 
1500     If the conversion fails the function returns 0.
1501 
1502     If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1503     to \c false, and success by setting *\a{ok} to \c true.
1504 
1505     This function ignores leading and trailing whitespace.
1506 
1507     \sa toLongLong(), toInt(), toDouble(), toString()
1508 */
1509 
toULongLong(const QString & s,bool * ok) const1510 qulonglong QLocale::toULongLong(const QString &s, bool *ok) const
1511 {
1512     return toIntegral_helper<qulonglong>(d, s, ok);
1513 }
1514 
1515 /*!
1516     Returns the float represented by the localized string \a s.
1517 
1518     Returns an infinity if the conversion overflows or 0.0 if the
1519     conversion fails for any other reason (e.g. underflow).
1520 
1521     If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1522     to \c false, and success by setting *\a{ok} to \c true.
1523 
1524     This function does not fall back to the 'C' locale if the string
1525     cannot be interpreted in this locale.
1526 
1527     This function ignores leading and trailing whitespace.
1528 
1529     \sa toDouble(), toInt(), toString()
1530 */
1531 
toFloat(const QString & s,bool * ok) const1532 float QLocale::toFloat(const QString &s, bool *ok) const
1533 {
1534     return QLocaleData::convertDoubleToFloat(toDouble(s, ok), ok);
1535 }
1536 
1537 /*!
1538     Returns the double represented by the localized string \a s.
1539 
1540     Returns an infinity if the conversion overflows or 0.0 if the
1541     conversion fails for any other reason (e.g. underflow).
1542 
1543     If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1544     to \c false, and success by setting *\a{ok} to \c true.
1545 
1546     This function does not fall back to the 'C' locale if the string
1547     cannot be interpreted in this locale.
1548 
1549     \snippet code/src_corelib_tools_qlocale.cpp 3
1550 
1551     Notice that the last conversion returns 1234.0, because '.' is the
1552     thousands group separator in the German locale.
1553 
1554     This function ignores leading and trailing whitespace.
1555 
1556     \sa toFloat(), toInt(), toString()
1557 */
1558 
toDouble(const QString & s,bool * ok) const1559 double QLocale::toDouble(const QString &s, bool *ok) const
1560 {
1561     return d->m_data->stringToDouble(s, ok, d->m_numberOptions);
1562 }
1563 
1564 /*!
1565     Returns the short int represented by the localized string \a s.
1566 
1567     If the conversion fails the function returns 0.
1568 
1569     If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1570     to \c false, and success by setting *\a{ok} to \c true.
1571 
1572     This function ignores leading and trailing whitespace.
1573 
1574     \sa toUShort(), toString()
1575 
1576     \since 5.1
1577 */
1578 
toShort(const QStringRef & s,bool * ok) const1579 short QLocale::toShort(const QStringRef &s, bool *ok) const
1580 {
1581     return toIntegral_helper<short>(d, s, ok);
1582 }
1583 
1584 /*!
1585     Returns the unsigned short int represented by the localized string \a s.
1586 
1587     If the conversion fails the function returns 0.
1588 
1589     If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1590     to \c false, and success by setting *\a{ok} to \c true.
1591 
1592     This function ignores leading and trailing whitespace.
1593 
1594     \sa toShort(), toString()
1595 
1596     \since 5.1
1597 */
1598 
toUShort(const QStringRef & s,bool * ok) const1599 ushort QLocale::toUShort(const QStringRef &s, bool *ok) const
1600 {
1601     return toIntegral_helper<ushort>(d, s, ok);
1602 }
1603 
1604 /*!
1605     Returns the int represented by the localized string \a s.
1606 
1607     If the conversion fails the function returns 0.
1608 
1609     If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1610     to \c false, and success by setting *\a{ok} to \c true.
1611 
1612     This function ignores leading and trailing whitespace.
1613 
1614     \sa toUInt(), toString()
1615 
1616     \since 5.1
1617 */
1618 
toInt(const QStringRef & s,bool * ok) const1619 int QLocale::toInt(const QStringRef &s, bool *ok) const
1620 {
1621     return toIntegral_helper<int>(d, s, ok);
1622 }
1623 
1624 /*!
1625     Returns the unsigned int represented by the localized string \a s.
1626 
1627     If the conversion fails the function returns 0.
1628 
1629     If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1630     to \c false, and success by setting *\a{ok} to \c true.
1631 
1632     This function ignores leading and trailing whitespace.
1633 
1634     \sa toInt(), toString()
1635 
1636     \since 5.1
1637 */
1638 
toUInt(const QStringRef & s,bool * ok) const1639 uint QLocale::toUInt(const QStringRef &s, bool *ok) const
1640 {
1641     return toIntegral_helper<uint>(d, s, ok);
1642 }
1643 
1644 /*!
1645  Returns the long int represented by the localized string \a s.
1646 
1647  If the conversion fails the function returns 0.
1648 
1649  If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1650  to \c false, and success by setting *\a{ok} to \c true.
1651 
1652  This function ignores leading and trailing whitespace.
1653 
1654  \sa toInt(), toULong(), toDouble(), toString()
1655 
1656  \since 5.13
1657  */
1658 
1659 
toLong(const QStringRef & s,bool * ok) const1660 long QLocale::toLong(const QStringRef &s, bool *ok) const
1661 {
1662     return toIntegral_helper<long>(d, s, ok);
1663 }
1664 
1665 /*!
1666  Returns the unsigned long int represented by the localized
1667  string \a s.
1668 
1669  If the conversion fails the function returns 0.
1670 
1671  If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1672  to \c false, and success by setting *\a{ok} to \c true.
1673 
1674  This function ignores leading and trailing whitespace.
1675 
1676  \sa toLong(), toInt(), toDouble(), toString()
1677 
1678  \since 5.13
1679  */
1680 
toULong(const QStringRef & s,bool * ok) const1681 ulong QLocale::toULong(const QStringRef &s, bool *ok) const
1682 {
1683     return toIntegral_helper<ulong>(d, s, ok);
1684 }
1685 
1686 /*!
1687     Returns the long long int represented by the localized string \a s.
1688 
1689     If the conversion fails the function returns 0.
1690 
1691     If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1692     to \c false, and success by setting *\a{ok} to \c true.
1693 
1694     This function ignores leading and trailing whitespace.
1695 
1696     \sa toInt(), toULongLong(), toDouble(), toString()
1697 
1698     \since 5.1
1699 */
1700 
1701 
toLongLong(const QStringRef & s,bool * ok) const1702 qlonglong QLocale::toLongLong(const QStringRef &s, bool *ok) const
1703 {
1704     return toIntegral_helper<qlonglong>(d, s, ok);
1705 }
1706 
1707 /*!
1708     Returns the unsigned long long int represented by the localized
1709     string \a s.
1710 
1711     If the conversion fails the function returns 0.
1712 
1713     If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1714     to \c false, and success by setting *\a{ok} to \c true.
1715 
1716     This function ignores leading and trailing whitespace.
1717 
1718     \sa toLongLong(), toInt(), toDouble(), toString()
1719 
1720     \since 5.1
1721 */
1722 
toULongLong(const QStringRef & s,bool * ok) const1723 qulonglong QLocale::toULongLong(const QStringRef &s, bool *ok) const
1724 {
1725     return toIntegral_helper<qulonglong>(d, s, ok);
1726 }
1727 
1728 /*!
1729     Returns the float represented by the localized string \a s.
1730 
1731     Returns an infinity if the conversion overflows or 0.0 if the
1732     conversion fails for any other reason (e.g. underflow).
1733 
1734     If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1735     to \c false, and success by setting *\a{ok} to \c true.
1736 
1737     This function does not fall back to the 'C' locale if the string
1738     cannot be interpreted in this locale.
1739 
1740     This function ignores leading and trailing whitespace.
1741 
1742     \sa toDouble(), toInt(), toString()
1743 
1744     \since 5.1
1745 */
1746 
toFloat(const QStringRef & s,bool * ok) const1747 float QLocale::toFloat(const QStringRef &s, bool *ok) const
1748 {
1749     return QLocaleData::convertDoubleToFloat(toDouble(s, ok), ok);
1750 }
1751 
1752 /*!
1753     Returns the double represented by the localized string \a s.
1754 
1755     Returns an infinity if the conversion overflows or 0.0 if the
1756     conversion fails for any other reason (e.g. underflow).
1757 
1758     If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1759     to \c false, and success by setting *\a{ok} to \c true.
1760 
1761     This function does not fall back to the 'C' locale if the string
1762     cannot be interpreted in this locale.
1763 
1764     \snippet code/src_corelib_tools_qlocale.cpp 3
1765 
1766     Notice that the last conversion returns 1234.0, because '.' is the
1767     thousands group separator in the German locale.
1768 
1769     This function ignores leading and trailing whitespace.
1770 
1771     \sa toFloat(), toInt(), toString()
1772 
1773     \since 5.1
1774 */
1775 
toDouble(const QStringRef & s,bool * ok) const1776 double QLocale::toDouble(const QStringRef &s, bool *ok) const
1777 {
1778     return d->m_data->stringToDouble(s, ok, d->m_numberOptions);
1779 }
1780 #endif // QT_STRINGVIEW_LEVEL < 2
1781 
1782 /*!
1783     Returns the short int represented by the localized string \a s.
1784 
1785     If the conversion fails, the function returns 0.
1786 
1787     If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1788     to \c false, and success by setting *\a{ok} to \c true.
1789 
1790     This function ignores leading and trailing whitespace.
1791 
1792     \sa toUShort(), toString()
1793 
1794     \since 5.10
1795 */
1796 
toShort(QStringView s,bool * ok) const1797 short QLocale::toShort(QStringView s, bool *ok) const
1798 {
1799     return toIntegral_helper<short>(d, s, ok);
1800 }
1801 
1802 /*!
1803     Returns the unsigned short int represented by the localized string \a s.
1804 
1805     If the conversion fails, the function returns 0.
1806 
1807     If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1808     to \c false, and success by setting *\a{ok} to \c true.
1809 
1810     This function ignores leading and trailing whitespace.
1811 
1812     \sa toShort(), toString()
1813 
1814     \since 5.10
1815 */
1816 
toUShort(QStringView s,bool * ok) const1817 ushort QLocale::toUShort(QStringView s, bool *ok) const
1818 {
1819     return toIntegral_helper<ushort>(d, s, ok);
1820 }
1821 
1822 /*!
1823     Returns the int represented by the localized string \a s.
1824 
1825     If the conversion fails, the function returns 0.
1826 
1827     If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1828     to \c false, and success by setting *\a{ok} to \c true.
1829 
1830     This function ignores leading and trailing whitespace.
1831 
1832     \sa toUInt(), toString()
1833 
1834     \since 5.10
1835 */
1836 
toInt(QStringView s,bool * ok) const1837 int QLocale::toInt(QStringView s, bool *ok) const
1838 {
1839     return toIntegral_helper<int>(d, s, ok);
1840 }
1841 
1842 /*!
1843     Returns the unsigned int represented by the localized string \a s.
1844 
1845     If the conversion fails, the function returns 0.
1846 
1847     If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1848     to \c false, and success by setting *\a{ok} to \c true.
1849 
1850     This function ignores leading and trailing whitespace.
1851 
1852     \sa toInt(), toString()
1853 
1854     \since 5.10
1855 */
1856 
toUInt(QStringView s,bool * ok) const1857 uint QLocale::toUInt(QStringView s, bool *ok) const
1858 {
1859     return toIntegral_helper<uint>(d, s, ok);
1860 }
1861 
1862 /*!
1863  Returns the long int represented by the localized string \a s.
1864 
1865  If the conversion fails the function returns 0.
1866 
1867  If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1868  to \c false, and success by setting *\a{ok} to \c true.
1869 
1870  This function ignores leading and trailing whitespace.
1871 
1872  \sa toInt(), toULong(), toDouble(), toString()
1873 
1874  \since 5.13
1875  */
1876 
1877 
toLong(QStringView s,bool * ok) const1878 long QLocale::toLong(QStringView s, bool *ok) const
1879 {
1880     return toIntegral_helper<long>(d, s, ok);
1881 }
1882 
1883 /*!
1884  Returns the unsigned long int represented by the localized
1885  string \a s.
1886 
1887  If the conversion fails the function returns 0.
1888 
1889  If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1890  to \c false, and success by setting *\a{ok} to \c true.
1891 
1892  This function ignores leading and trailing whitespace.
1893 
1894  \sa toLong(), toInt(), toDouble(), toString()
1895 
1896  \since 5.13
1897  */
1898 
toULong(QStringView s,bool * ok) const1899 ulong QLocale::toULong(QStringView s, bool *ok) const
1900 {
1901     return toIntegral_helper<ulong>(d, s, ok);
1902 }
1903 
1904 /*!
1905     Returns the long long int represented by the localized string \a s.
1906 
1907     If the conversion fails, the function returns 0.
1908 
1909     If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1910     to \c false, and success by setting *\a{ok} to \c true.
1911 
1912     This function ignores leading and trailing whitespace.
1913 
1914     \sa toInt(), toULongLong(), toDouble(), toString()
1915 
1916     \since 5.10
1917 */
1918 
1919 
toLongLong(QStringView s,bool * ok) const1920 qlonglong QLocale::toLongLong(QStringView s, bool *ok) const
1921 {
1922     return toIntegral_helper<qlonglong>(d, s, ok);
1923 }
1924 
1925 /*!
1926     Returns the unsigned long long int represented by the localized
1927     string \a s.
1928 
1929     If the conversion fails, the function returns 0.
1930 
1931     If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1932     to \c false, and success by setting *\a{ok} to \c true.
1933 
1934     This function ignores leading and trailing whitespace.
1935 
1936     \sa toLongLong(), toInt(), toDouble(), toString()
1937 
1938     \since 5.10
1939 */
1940 
toULongLong(QStringView s,bool * ok) const1941 qulonglong QLocale::toULongLong(QStringView s, bool *ok) const
1942 {
1943     return toIntegral_helper<qulonglong>(d, s, ok);
1944 }
1945 
1946 /*!
1947     Returns the float represented by the localized string \a s.
1948 
1949     Returns an infinity if the conversion overflows or 0.0 if the
1950     conversion fails for any other reason (e.g. underflow).
1951 
1952     If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1953     to \c false, and success by setting *\a{ok} to \c true.
1954 
1955     This function ignores leading and trailing whitespace.
1956 
1957     \sa toDouble(), toInt(), toString()
1958 
1959     \since 5.10
1960 */
1961 
toFloat(QStringView s,bool * ok) const1962 float QLocale::toFloat(QStringView s, bool *ok) const
1963 {
1964     return QLocaleData::convertDoubleToFloat(toDouble(s, ok), ok);
1965 }
1966 
1967 /*!
1968     Returns the double represented by the localized string \a s.
1969 
1970     Returns an infinity if the conversion overflows or 0.0 if the
1971     conversion fails for any other reason (e.g. underflow).
1972 
1973     If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1974     to \c false, and success by setting *\a{ok} to \c true.
1975 
1976     Unlike QString::toDouble(), this function does not fall back to
1977     the "C" locale if the string cannot be interpreted in this
1978     locale.
1979 
1980     \snippet code/src_corelib_tools_qlocale.cpp 3-qstringview
1981 
1982     Notice that the last conversion returns 1234.0, because '.' is the
1983     thousands group separator in the German locale.
1984 
1985     This function ignores leading and trailing whitespace.
1986 
1987     \sa toFloat(), toInt(), toString()
1988 
1989     \since 5.10
1990 */
1991 
toDouble(QStringView s,bool * ok) const1992 double QLocale::toDouble(QStringView s, bool *ok) const
1993 {
1994     return d->m_data->stringToDouble(s, ok, d->m_numberOptions);
1995 }
1996 
1997 /*!
1998     Returns a localized string representation of \a i.
1999 
2000     \sa toLongLong(), numberOptions(), zeroDigit(), positiveSign()
2001 */
2002 
toString(qlonglong i) const2003 QString QLocale::toString(qlonglong i) const
2004 {
2005     int flags = d->m_numberOptions & OmitGroupSeparator
2006                     ? 0
2007                     : (d->m_data->m_country_id == Country::India)
2008                       ? QLocaleData::IndianNumberGrouping : QLocaleData::ThousandsGroup;
2009 
2010     return d->m_data->longLongToString(i, -1, 10, -1, flags);
2011 }
2012 
2013 /*!
2014     \overload
2015 
2016     \sa toULongLong(), numberOptions(), zeroDigit(), positiveSign()
2017 */
2018 
toString(qulonglong i) const2019 QString QLocale::toString(qulonglong i) const
2020 {
2021     int flags = d->m_numberOptions & OmitGroupSeparator
2022                     ? 0
2023                     : (d->m_data->m_country_id == Country::India)
2024                       ? QLocaleData::IndianNumberGrouping : QLocaleData::ThousandsGroup;
2025 
2026     return d->m_data->unsLongLongToString(i, -1, 10, -1, flags);
2027 }
2028 
2029 #if QT_STRINGVIEW_LEVEL < 2
2030 /*!
2031     Returns a localized string representation of the given \a date in the
2032     specified \a format.
2033     If \a format is an empty string, an empty string is returned.
2034 
2035     \sa QDate::toString()
2036 */
2037 
toString(const QDate & date,const QString & format) const2038 QString QLocale::toString(const QDate &date, const QString &format) const
2039 {
2040     return QCalendar().dateTimeToString(format, QDateTime(), date, QTime(), *this);
2041 }
2042 #endif
2043 
2044 /*!
2045     \since 5.14
2046 
2047     Returns a localized string representation of the given \a date in the
2048     specified \a format, optionally for a specified calendar \a cal.
2049     If \a format is an empty string, an empty string is returned.
2050 
2051     \sa QDate::toString()
2052 */
toString(const QDate & date,QStringView format,QCalendar cal) const2053 QString QLocale::toString(const QDate &date, QStringView format, QCalendar cal) const
2054 {
2055     return cal.dateTimeToString(format, QDateTime(), date, QTime(), *this);
2056 }
2057 
2058 /*!
2059     \since 5.10
2060     \overload
2061 */
toString(const QDate & date,QStringView format) const2062 QString QLocale::toString(const QDate &date, QStringView format) const
2063 {
2064     return QCalendar().dateTimeToString(format, QDateTime(), date, QTime(), *this);
2065 }
2066 
2067 /*!
2068     \since 5.14
2069 
2070     Returns a localized string representation of the given \a date according
2071     to the specified \a format (see dateFormat()), optionally for a specified
2072     calendar \a cal.
2073 
2074     \note Some locales may use formats that limit the range of years they can
2075     represent.
2076 */
toString(const QDate & date,FormatType format,QCalendar cal) const2077 QString QLocale::toString(const QDate &date, FormatType format, QCalendar cal) const
2078 {
2079     if (!date.isValid())
2080         return QString();
2081 
2082 #ifndef QT_NO_SYSTEMLOCALE
2083     if (cal.isGregorian() && d->m_data == systemData()) {
2084         QVariant res = systemLocale()->query(format == LongFormat
2085                                              ? QSystemLocale::DateToStringLong
2086                                              : QSystemLocale::DateToStringShort,
2087                                              date);
2088         if (!res.isNull())
2089             return res.toString();
2090     }
2091 #endif
2092 
2093     QString format_str = dateFormat(format);
2094     return toString(date, format_str, cal);
2095 }
2096 
2097 /*!
2098     \since 4.5
2099     \overload
2100 */
toString(const QDate & date,FormatType format) const2101 QString QLocale::toString(const QDate &date, FormatType format) const
2102 {
2103     if (!date.isValid())
2104         return QString();
2105 
2106 #ifndef QT_NO_SYSTEMLOCALE
2107     if (d->m_data == systemData()) {
2108         QVariant res = systemLocale()->query(format == LongFormat
2109                                              ? QSystemLocale::DateToStringLong
2110                                              : QSystemLocale::DateToStringShort,
2111                                              date);
2112         if (!res.isNull())
2113             return res.toString();
2114     }
2115 #endif
2116 
2117     QString format_str = dateFormat(format);
2118     return toString(date, format_str);
2119 }
2120 
timeFormatContainsAP(QStringView format)2121 static bool timeFormatContainsAP(QStringView format)
2122 {
2123     int i = 0;
2124     while (i < format.size()) {
2125         if (format.at(i).unicode() == '\'') {
2126             qt_readEscapedFormatString(format, &i);
2127             continue;
2128         }
2129 
2130         if (format.at(i).toLower().unicode() == 'a')
2131             return true;
2132 
2133         ++i;
2134     }
2135     return false;
2136 }
2137 
2138 #if QT_STRINGVIEW_LEVEL < 2
2139 /*!
2140     Returns a localized string representation of the given \a time according
2141     to the specified \a format.
2142     If \a format is an empty string, an empty string is returned.
2143 
2144     \sa QTime::toString()
2145 */
toString(const QTime & time,const QString & format) const2146 QString QLocale::toString(const QTime &time, const QString &format) const
2147 {
2148     return QCalendar().dateTimeToString(format, QDateTime(), QDate(), time, *this);
2149 }
2150 #endif
2151 
2152 /*!
2153     \since 4.5
2154 
2155     Returns a localized string representation of the given \a time according
2156     to the specified \a format.
2157     If \a format is an empty string, an empty string is returned.
2158 
2159     \sa QTime::toString()
2160 */
toString(const QTime & time,QStringView format) const2161 QString QLocale::toString(const QTime &time, QStringView format) const
2162 {
2163     return QCalendar().dateTimeToString(format, QDateTime(), QDate(), time, *this);
2164 }
2165 
2166 #if QT_STRINGVIEW_LEVEL < 2
2167 /*!
2168     \since 4.4
2169 
2170     Returns a localized string representation of the given \a dateTime according
2171     to the specified \a format.
2172     If \a format is an empty string, an empty string is returned.
2173 
2174     \sa QDateTime::toString(), QDate::toString(), QTime::toString()
2175 */
2176 
toString(const QDateTime & dateTime,const QString & format) const2177 QString QLocale::toString(const QDateTime &dateTime, const QString &format) const
2178 {
2179     return QCalendar().dateTimeToString(format, dateTime, QDate(), QTime(), *this);
2180 }
2181 #endif
2182 
2183 /*!
2184     \since 5.14
2185 
2186     Returns a localized string representation of the given \a dateTime according
2187     to the specified \a format, optionally for a specified calendar \a cal.
2188     If \a format is an empty string, an empty string is returned.
2189 
2190     \sa QDateTime::toString(), QDate::toString(), QTime::toString()
2191 */
toString(const QDateTime & dateTime,QStringView format,QCalendar cal) const2192 QString QLocale::toString(const QDateTime &dateTime, QStringView format, QCalendar cal) const
2193 {
2194     return cal.dateTimeToString(format, dateTime, QDate(), QTime(), *this);
2195 }
2196 
2197 /*!
2198     \since 5.10
2199     \overload
2200 */
toString(const QDateTime & dateTime,QStringView format) const2201 QString QLocale::toString(const QDateTime &dateTime, QStringView format) const
2202 {
2203     return QCalendar().dateTimeToString(format, dateTime, QDate(), QTime(), *this);
2204 }
2205 
2206 /*!
2207     \since 5.14
2208 
2209     Returns a localized string representation of the given \a dateTime according
2210     to the specified \a format (see dateTimeFormat()), optionally for a
2211     specified calendar \a cal.
2212 
2213     \note Some locales may use formats that limit the range of years they can
2214     represent.
2215 */
toString(const QDateTime & dateTime,FormatType format,QCalendar cal) const2216 QString QLocale::toString(const QDateTime &dateTime, FormatType format, QCalendar cal) const
2217 {
2218     if (!dateTime.isValid())
2219         return QString();
2220 
2221 #ifndef QT_NO_SYSTEMLOCALE
2222     if (cal.isGregorian() && d->m_data == systemData()) {
2223         QVariant res = systemLocale()->query(format == LongFormat
2224                                              ? QSystemLocale::DateTimeToStringLong
2225                                              : QSystemLocale::DateTimeToStringShort,
2226                                              dateTime);
2227         if (!res.isNull())
2228             return res.toString();
2229     }
2230 #endif
2231 
2232     const QString format_str = dateTimeFormat(format);
2233     return toString(dateTime, format_str, cal);
2234 }
2235 
2236 /*!
2237     \since 4.4
2238     \overload
2239 */
toString(const QDateTime & dateTime,FormatType format) const2240 QString QLocale::toString(const QDateTime &dateTime, FormatType format) const
2241 {
2242     if (!dateTime.isValid())
2243         return QString();
2244 
2245 #ifndef QT_NO_SYSTEMLOCALE
2246     if (d->m_data == systemData()) {
2247         QVariant res = systemLocale()->query(format == LongFormat
2248                                              ? QSystemLocale::DateTimeToStringLong
2249                                              : QSystemLocale::DateTimeToStringShort,
2250                                              dateTime);
2251         if (!res.isNull())
2252             return res.toString();
2253     }
2254 #endif
2255 
2256     const QString format_str = dateTimeFormat(format);
2257     return toString(dateTime, format_str);
2258 }
2259 
2260 
2261 /*!
2262     Returns a localized string representation of the given \a time in the
2263     specified \a format (see timeFormat()).
2264 */
2265 
toString(const QTime & time,FormatType format) const2266 QString QLocale::toString(const QTime &time, FormatType format) const
2267 {
2268     if (!time.isValid())
2269         return QString();
2270 
2271 #ifndef QT_NO_SYSTEMLOCALE
2272     if (d->m_data == systemData()) {
2273         QVariant res = systemLocale()->query(format == LongFormat
2274                                              ? QSystemLocale::TimeToStringLong
2275                                              : QSystemLocale::TimeToStringShort,
2276                                              time);
2277         if (!res.isNull())
2278             return res.toString();
2279     }
2280 #endif
2281 
2282     QString format_str = timeFormat(format);
2283     return toString(time, format_str);
2284 }
2285 
2286 /*!
2287     \since 4.1
2288 
2289     Returns the date format used for the current locale.
2290 
2291     If \a format is LongFormat, the format will be elaborate, otherwise it will be short.
2292     For example, LongFormat for the \c{en_US} locale is \c{dddd, MMMM d, yyyy},
2293     ShortFormat is \c{M/d/yy}.
2294 
2295     \sa QDate::toString(), QDate::fromString()
2296 */
2297 
dateFormat(FormatType format) const2298 QString QLocale::dateFormat(FormatType format) const
2299 {
2300 #ifndef QT_NO_SYSTEMLOCALE
2301     if (d->m_data == systemData()) {
2302         QVariant res = systemLocale()->query(format == LongFormat
2303                                              ? QSystemLocale::DateFormatLong
2304                                              : QSystemLocale::DateFormatShort,
2305                                              QVariant());
2306         if (!res.isNull())
2307             return res.toString();
2308     }
2309 #endif
2310 
2311     quint32 idx, size;
2312     switch (format) {
2313     case LongFormat:
2314         idx = d->m_data->m_long_date_format_idx;
2315         size = d->m_data->m_long_date_format_size;
2316         break;
2317     default:
2318         idx = d->m_data->m_short_date_format_idx;
2319         size = d->m_data->m_short_date_format_size;
2320         break;
2321     }
2322     return getLocaleData(date_format_data + idx, size);
2323 }
2324 
2325 /*!
2326     \since 4.1
2327 
2328     Returns the time format used for the current locale.
2329 
2330     If \a format is LongFormat, the format will be elaborate, otherwise it will be short.
2331     For example, LongFormat for the \c{en_US} locale is \c{h:mm:ss AP t},
2332     ShortFormat is \c{h:mm AP}.
2333 
2334     \sa QTime::toString(), QTime::fromString()
2335 */
2336 
timeFormat(FormatType format) const2337 QString QLocale::timeFormat(FormatType format) const
2338 {
2339 #ifndef QT_NO_SYSTEMLOCALE
2340     if (d->m_data == systemData()) {
2341         QVariant res = systemLocale()->query(format == LongFormat
2342                                              ? QSystemLocale::TimeFormatLong
2343                                              : QSystemLocale::TimeFormatShort,
2344                                              QVariant());
2345         if (!res.isNull())
2346             return res.toString();
2347     }
2348 #endif
2349 
2350     quint32 idx, size;
2351     switch (format) {
2352     case LongFormat:
2353         idx = d->m_data->m_long_time_format_idx;
2354         size = d->m_data->m_long_time_format_size;
2355         break;
2356     default:
2357         idx = d->m_data->m_short_time_format_idx;
2358         size = d->m_data->m_short_time_format_size;
2359         break;
2360     }
2361     return getLocaleData(time_format_data + idx, size);
2362 }
2363 
2364 /*!
2365     \since 4.4
2366 
2367     Returns the date time format used for the current locale.
2368 
2369     If \a format is LongFormat, the format will be elaborate, otherwise it will be short.
2370     For example, LongFormat for the \c{en_US} locale is \c{dddd, MMMM d, yyyy h:mm:ss AP t},
2371     ShortFormat is \c{M/d/yy h:mm AP}.
2372 
2373     \sa QDateTime::toString(), QDateTime::fromString()
2374 */
2375 
dateTimeFormat(FormatType format) const2376 QString QLocale::dateTimeFormat(FormatType format) const
2377 {
2378 #ifndef QT_NO_SYSTEMLOCALE
2379     if (d->m_data == systemData()) {
2380         QVariant res = systemLocale()->query(format == LongFormat
2381                                              ? QSystemLocale::DateTimeFormatLong
2382                                              : QSystemLocale::DateTimeFormatShort,
2383                                              QVariant());
2384         if (!res.isNull()) {
2385             return res.toString();
2386         }
2387     }
2388 #endif
2389     return dateFormat(format) + QLatin1Char(' ') + timeFormat(format);
2390 }
2391 
2392 #if QT_CONFIG(datestring)
2393 /*!
2394     \since 4.4
2395 
2396     Parses the time string given in \a string and returns the
2397     time. The format of the time string is chosen according to the
2398     \a format parameter (see timeFormat()).
2399 
2400     If the time could not be parsed, returns an invalid time.
2401 
2402     \sa timeFormat(), toDate(), toDateTime(), QTime::fromString()
2403 */
toTime(const QString & string,FormatType format) const2404 QTime QLocale::toTime(const QString &string, FormatType format) const
2405 {
2406     return toTime(string, timeFormat(format));
2407 }
2408 
2409 #if QT_DEPRECATED_SINCE(5, 15)
2410 /*!
2411     \since 5.14
2412     \overload
2413     \deprecated
2414 */
toTime(const QString & string,FormatType format,QCalendar cal) const2415 QTime QLocale::toTime(const QString &string, FormatType format, QCalendar cal) const
2416 {
2417 QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
2418     return toTime(string, timeFormat(format), cal);
2419 QT_WARNING_POP
2420 }
2421 #endif
2422 
2423 /*!
2424     \since 4.4
2425 
2426     Parses the date string given in \a string and returns the
2427     date. The format of the date string is chosen according to the
2428     \a format parameter (see dateFormat()).
2429 
2430     If the date could not be parsed, returns an invalid date.
2431 
2432     \sa dateFormat(), toTime(), toDateTime(), QDate::fromString()
2433 */
toDate(const QString & string,FormatType format) const2434 QDate QLocale::toDate(const QString &string, FormatType format) const
2435 {
2436     return toDate(string, dateFormat(format));
2437 }
2438 
2439 /*!
2440     \since 5.14
2441     \overload
2442 */
toDate(const QString & string,FormatType format,QCalendar cal) const2443 QDate QLocale::toDate(const QString &string, FormatType format, QCalendar cal) const
2444 {
2445     return toDate(string, dateFormat(format), cal);
2446 }
2447 
2448 /*!
2449     \since 4.4
2450 
2451     Parses the date/time string given in \a string and returns the
2452     time. The format of the date/time string is chosen according to the
2453     \a format parameter (see dateTimeFormat()).
2454 
2455     If the string could not be parsed, returns an invalid QDateTime.
2456 
2457     \sa dateTimeFormat(), toTime(), toDate(), QDateTime::fromString()
2458 */
toDateTime(const QString & string,FormatType format) const2459 QDateTime QLocale::toDateTime(const QString &string, FormatType format) const
2460 {
2461     return toDateTime(string, dateTimeFormat(format));
2462 }
2463 
2464 /*!
2465     \since 5.14
2466     \overload
2467 */
toDateTime(const QString & string,FormatType format,QCalendar cal) const2468 QDateTime QLocale::toDateTime(const QString &string, FormatType format, QCalendar cal) const
2469 {
2470     return toDateTime(string, dateTimeFormat(format), cal);
2471 }
2472 
2473 /*!
2474     \since 4.4
2475 
2476     Parses the time string given in \a string and returns the
2477     time. See QTime::fromString() for information on what is a valid
2478     format string.
2479 
2480     If the time could not be parsed, returns an invalid time.
2481 
2482     \sa timeFormat(), toDate(), toDateTime(), QTime::fromString()
2483 */
toTime(const QString & string,const QString & format) const2484 QTime QLocale::toTime(const QString &string, const QString &format) const
2485 {
2486     QTime time;
2487 #if QT_CONFIG(datetimeparser)
2488     QDateTimeParser dt(QMetaType::QTime, QDateTimeParser::FromString, QCalendar());
2489     dt.setDefaultLocale(*this);
2490     if (dt.parseFormat(format))
2491         dt.fromString(string, nullptr, &time);
2492 #else
2493     Q_UNUSED(string);
2494     Q_UNUSED(format);
2495 #endif
2496     return time;
2497 }
2498 
2499 #if QT_DEPRECATED_SINCE(5, 15)
2500 /*!
2501     \since 5.14
2502     \overload
2503     \deprecated
2504 */
toTime(const QString & string,const QString & format,QCalendar cal) const2505 QTime QLocale::toTime(const QString &string, const QString &format, QCalendar cal) const
2506 {
2507     QTime time;
2508 #if QT_CONFIG(datetimeparser)
2509     QDateTimeParser dt(QMetaType::QTime, QDateTimeParser::FromString, cal);
2510     dt.setDefaultLocale(*this);
2511     if (dt.parseFormat(format))
2512         dt.fromString(string, nullptr, &time);
2513 #else
2514     Q_UNUSED(cal);
2515     Q_UNUSED(string);
2516     Q_UNUSED(format);
2517 #endif
2518     return time;
2519 }
2520 #endif
2521 
2522 /*!
2523     \since 4.4
2524 
2525     Parses the date string given in \a string and returns the
2526     date. See QDate::fromString() for information on the expressions
2527     that can be used with this function.
2528 
2529     This function searches month names and the names of the days of
2530     the week in the current locale.
2531 
2532     If the date could not be parsed, returns an invalid date.
2533 
2534     \sa dateFormat(), toTime(), toDateTime(), QDate::fromString()
2535 */
toDate(const QString & string,const QString & format) const2536 QDate QLocale::toDate(const QString &string, const QString &format) const
2537 {
2538     return toDate(string, format, QCalendar());
2539 }
2540 
2541 /*!
2542     \since 5.14
2543     \overload
2544 */
toDate(const QString & string,const QString & format,QCalendar cal) const2545 QDate QLocale::toDate(const QString &string, const QString &format, QCalendar cal) const
2546 {
2547     QDate date;
2548 #if QT_CONFIG(datetimeparser)
2549     QDateTimeParser dt(QMetaType::QDate, QDateTimeParser::FromString, cal);
2550     dt.setDefaultLocale(*this);
2551     if (dt.parseFormat(format))
2552         dt.fromString(string, &date, nullptr);
2553 #else
2554     Q_UNUSED(string);
2555     Q_UNUSED(format);
2556     Q_UNUSED(cal);
2557 #endif
2558     return date;
2559 }
2560 
2561 /*!
2562     \since 4.4
2563 
2564     Parses the date/time string given in \a string and returns the
2565     time.  See QDateTime::fromString() for information on the expressions
2566     that can be used with this function.
2567 
2568     \note The month and day names used must be given in the user's local
2569     language.
2570 
2571     If the string could not be parsed, returns an invalid QDateTime.  If the
2572     string can be parsed and represents an invalid date-time (e.g. in a gap
2573     skipped by a time-zone transition), an invalid QDateTime is returned, whose
2574     toMSecsSinceEpoch() represents a near-by date-time that is valid. Passing
2575     that to fromMSecsSinceEpoch() will produce a valid date-time that isn't
2576     faithfully represented by the string parsed.
2577 
2578     \sa dateTimeFormat(), toTime(), toDate(), QDateTime::fromString()
2579 */
toDateTime(const QString & string,const QString & format) const2580 QDateTime QLocale::toDateTime(const QString &string, const QString &format) const
2581 {
2582     return toDateTime(string, format, QCalendar());
2583 }
2584 
2585 /*!
2586     \since 5.14
2587     \overload
2588 */
toDateTime(const QString & string,const QString & format,QCalendar cal) const2589 QDateTime QLocale::toDateTime(const QString &string, const QString &format, QCalendar cal) const
2590 {
2591 #if QT_CONFIG(datetimeparser)
2592     QDateTime datetime;
2593 
2594     QDateTimeParser dt(QMetaType::QDateTime, QDateTimeParser::FromString, cal);
2595     dt.setDefaultLocale(*this);
2596     if (dt.parseFormat(format) && (dt.fromString(string, &datetime) || !datetime.isValid()))
2597         return datetime;
2598 #else
2599     Q_UNUSED(string);
2600     Q_UNUSED(format);
2601     Q_UNUSED(cal);
2602 #endif
2603     return QDateTime();
2604 }
2605 #endif // datestring
2606 
2607 /*!
2608     \since 4.1
2609 
2610     Returns the decimal point character of this locale.
2611 
2612     \note This function shall change to return a QString instead of QChar in
2613     Qt6. Callers are encouraged to exploit the QString(QChar) constructor to
2614     convert early in preparation for this.
2615 
2616     \sa groupSeparator(), toString()
2617 */
decimalPoint() const2618 QChar QLocale::decimalPoint() const
2619 {
2620     return d->decimal();
2621 }
2622 
2623 /*!
2624     \since 4.1
2625 
2626     Returns the group separator character of this locale.
2627 
2628     \note This function shall change to return a QString instead of QChar in
2629     Qt6. Callers are encouraged to exploit the QString(QChar) constructor to
2630     convert early in preparation for this.
2631 
2632     \sa decimalPoint(), toString()
2633 */
groupSeparator() const2634 QChar QLocale::groupSeparator() const
2635 {
2636     return d->group();
2637 }
2638 
2639 /*!
2640     \since 4.1
2641 
2642     Returns the percent character of this locale.
2643 
2644     \note This function shall change to return a QString instead of QChar in
2645     Qt6. Callers are encouraged to exploit the QString(QChar) constructor to
2646     convert early in preparation for this.
2647 
2648     \sa toString()
2649 */
percent() const2650 QChar QLocale::percent() const
2651 {
2652     return d->percent();
2653 }
2654 
2655 /*!
2656     \since 4.1
2657 
2658     Returns the zero digit character of this locale.
2659 
2660     \note This function shall change to return a QString instead of QChar in
2661     Qt6. Callers are encouraged to exploit the QString(QChar) constructor to
2662     convert early in preparation for this.
2663 
2664     \sa toString()
2665 */
zeroDigit() const2666 QChar QLocale::zeroDigit() const
2667 {
2668     return d->zero();
2669 }
2670 
2671 /*!
2672     \since 4.1
2673 
2674     Returns the negative sign character of this locale.
2675 
2676     \note This function shall change to return a QString instead of QChar in
2677     Qt6. Callers are encouraged to exploit the QString(QChar) constructor to
2678     convert early in preparation for this.
2679 
2680     \sa positiveSign(), toString()
2681 */
negativeSign() const2682 QChar QLocale::negativeSign() const
2683 {
2684     return d->minus();
2685 }
2686 
2687 /*!
2688     \since 4.5
2689 
2690     Returns the positive sign character of this locale.
2691 
2692     \note This function shall change to return a QString instead of QChar in
2693     Qt6. Callers are encouraged to exploit the QString(QChar) constructor to
2694     convert early in preparation for this.
2695 
2696     \sa negativeSign(), toString()
2697 */
positiveSign() const2698 QChar QLocale::positiveSign() const
2699 {
2700     return d->plus();
2701 }
2702 
2703 /*!
2704     \since 4.1
2705 
2706     Returns the exponential character of this locale, used to separate exponent
2707     from mantissa in some floating-point numeric representations.
2708 
2709     \note This function shall change to return a QString instead of QChar in
2710     Qt6. Callers are encouraged to exploit the QString(QChar) constructor to
2711     convert early in preparation for this.
2712 
2713     \sa toString(double, char, int)
2714 */
exponential() const2715 QChar QLocale::exponential() const
2716 {
2717     return d->exponential();
2718 }
2719 
qIsUpper(char c)2720 static bool qIsUpper(char c)
2721 {
2722     return c >= 'A' && c <= 'Z';
2723 }
2724 
qToLower(char c)2725 static char qToLower(char c)
2726 {
2727     if (c >= 'A' && c <= 'Z')
2728         return c - 'A' + 'a';
2729     else
2730         return c;
2731 }
2732 
2733 /*!
2734     \overload
2735 
2736     \a f and \a prec have the same meaning as in QString::number(double, char, int).
2737 
2738     \sa toDouble(), numberOptions(), exponential(), decimalPoint(), zeroDigit(), positiveSign(), percent()
2739 */
2740 
toString(double i,char f,int prec) const2741 QString QLocale::toString(double i, char f, int prec) const
2742 {
2743     QLocaleData::DoubleForm form = QLocaleData::DFDecimal;
2744     uint flags = 0;
2745 
2746     if (qIsUpper(f))
2747         flags = QLocaleData::CapitalEorX;
2748     f = qToLower(f);
2749 
2750     switch (f) {
2751         case 'f':
2752             form = QLocaleData::DFDecimal;
2753             break;
2754         case 'e':
2755             form = QLocaleData::DFExponent;
2756             break;
2757         case 'g':
2758             form = QLocaleData::DFSignificantDigits;
2759             break;
2760         default:
2761             break;
2762     }
2763 
2764     if (!(d->m_numberOptions & OmitGroupSeparator))
2765         flags |= QLocaleData::ThousandsGroup;
2766     if (!(d->m_numberOptions & OmitLeadingZeroInExponent))
2767         flags |= QLocaleData::ZeroPadExponent;
2768     if (d->m_numberOptions & IncludeTrailingZeroesAfterDot)
2769         flags |= QLocaleData::AddTrailingZeroes;
2770     return d->m_data->doubleToString(i, prec, form, -1, flags);
2771 }
2772 
2773 /*!
2774     \fn QLocale QLocale::c()
2775 
2776     Returns a QLocale object initialized to the "C" locale.
2777 
2778     This locale is based on en_US but with various quirks of its own, such as
2779     simplified number formatting and its own date formatting. It implements the
2780     POSIX standards that describe the behavior of standard library functions of
2781     the "C" programming language.
2782 
2783     Among other things, this means its collation order is based on the ASCII
2784     values of letters, so that (for case-sensitive sorting) all upper-case
2785     letters sort before any lower-case one (rather than each letter's upper- and
2786     lower-case forms sorting adjacent to one another, before the next letter's
2787     two forms).
2788 
2789     \sa system()
2790 */
2791 
2792 /*!
2793     Returns a QLocale object initialized to the system locale.
2794 
2795     On Windows and Mac, this locale will use the decimal/grouping characters and
2796     date/time formats specified in the system configuration panel.
2797 
2798     \sa c()
2799 */
2800 
system()2801 QLocale QLocale::system()
2802 {
2803     QT_PREPEND_NAMESPACE(systemData)(); // trigger updating of the system data if necessary
2804     if (systemLocalePrivate.isDestroyed())
2805         return QLocale(QLocale::C);
2806     return QLocale(*systemLocalePrivate->data());
2807 }
2808 
2809 
2810 /*!
2811     \since 4.8
2812 
2813     Returns a list of valid locale objects that match the given \a language, \a
2814     script and \a country.
2815 
2816     Getting a list of all locales:
2817     QList<QLocale> allLocales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript,
2818                                                          QLocale::AnyCountry);
2819 
2820     Getting a list of locales suitable for Russia:
2821     QList<QLocale> locales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript,
2822                                                       QLocale::Russia);
2823 */
matchingLocales(QLocale::Language language,QLocale::Script script,QLocale::Country country)2824 QList<QLocale> QLocale::matchingLocales(QLocale::Language language,
2825                                         QLocale::Script script,
2826                                         QLocale::Country country)
2827 {
2828     if (uint(language) > QLocale::LastLanguage || uint(script) > QLocale::LastScript ||
2829             uint(country) > QLocale::LastCountry)
2830         return QList<QLocale>();
2831 
2832     if (language == QLocale::C)
2833         return QList<QLocale>() << QLocale(QLocale::C);
2834 
2835     QList<QLocale> result;
2836     if (language == QLocale::AnyLanguage && script == QLocale::AnyScript
2837         && country == QLocale::AnyCountry) {
2838         result.reserve(locale_data_size);
2839     }
2840     const QLocaleData *data = locale_data + locale_index[language];
2841     while ( (data != locale_data + locale_data_size)
2842             && (language == QLocale::AnyLanguage || data->m_language_id == uint(language))) {
2843         if ((script == QLocale::AnyScript || data->m_script_id == uint(script))
2844             && (country == QLocale::AnyCountry || data->m_country_id == uint(country))) {
2845             result.append(QLocale(*(data->m_language_id == C ? c_private()
2846                                     : QLocalePrivate::create(data))));
2847         }
2848         ++data;
2849     }
2850     return result;
2851 }
2852 
2853 /*!
2854     \obsolete
2855     \since 4.3
2856 
2857     Returns the list of countries that have entries for \a language in Qt's locale
2858     database. If the result is an empty list, then \a language is not represented in
2859     Qt's locale database.
2860 
2861     \sa matchingLocales()
2862 */
countriesForLanguage(Language language)2863 QList<QLocale::Country> QLocale::countriesForLanguage(Language language)
2864 {
2865     QList<Country> result;
2866     if (language == C) {
2867         result << AnyCountry;
2868         return result;
2869     }
2870 
2871     unsigned language_id = language;
2872     const QLocaleData *data = locale_data + locale_index[language_id];
2873     while (data->m_language_id == language_id) {
2874         const QLocale::Country country = static_cast<Country>(data->m_country_id);
2875         if (!result.contains(country))
2876             result.append(country);
2877         ++data;
2878     }
2879 
2880     return result;
2881 }
2882 
2883 /*!
2884     \since 4.2
2885 
2886     Returns the localized name of \a month, in the format specified
2887     by \a type.
2888 
2889     For example, if the locale is \c en_US and \a month is 1,
2890     \l LongFormat will return \c January. \l ShortFormat \c Jan,
2891     and \l NarrowFormat \c J.
2892 
2893     \sa dayName(), standaloneMonthName()
2894 */
monthName(int month,FormatType type) const2895 QString QLocale::monthName(int month, FormatType type) const
2896 {
2897     return QCalendar().monthName(*this, month, QCalendar::Unspecified, type);
2898 }
2899 
2900 /*!
2901     \since 4.5
2902 
2903     Returns the localized name of \a month that is used as a
2904     standalone text, in the format specified by \a type.
2905 
2906     If the locale information doesn't specify the standalone month
2907     name then return value is the same as in monthName().
2908 
2909     \sa monthName(), standaloneDayName()
2910 */
standaloneMonthName(int month,FormatType type) const2911 QString QLocale::standaloneMonthName(int month, FormatType type) const
2912 {
2913     return QCalendar().standaloneMonthName(*this, month, QCalendar::Unspecified, type);
2914 }
2915 
2916 /*!
2917     \since 4.2
2918 
2919     Returns the localized name of the \a day (where 1 represents
2920     Monday, 2 represents Tuesday and so on), in the format specified
2921     by \a type.
2922 
2923     For example, if the locale is \c en_US and \a day is 1,
2924     \l LongFormat will return \c Monday, \l ShortFormat \c Mon,
2925     and \l NarrowFormat \c M.
2926 
2927     \sa monthName(), standaloneDayName()
2928 */
dayName(int day,FormatType type) const2929 QString QLocale::dayName(int day, FormatType type) const
2930 {
2931     return QCalendar().weekDayName(*this, day, type);
2932 }
2933 
2934 /*!
2935     \since 4.5
2936 
2937     Returns the localized name of the \a day (where 1 represents
2938     Monday, 2 represents Tuesday and so on) that is used as a
2939     standalone text, in the format specified by \a type.
2940 
2941     If the locale information does not specify the standalone day
2942     name then return value is the same as in dayName().
2943 
2944     \sa dayName(), standaloneMonthName()
2945 */
standaloneDayName(int day,FormatType type) const2946 QString QLocale::standaloneDayName(int day, FormatType type) const
2947 {
2948     return QCalendar().standaloneWeekDayName(*this, day, type);
2949 }
2950 
2951 // Calendar look-up of month and day names:
2952 
2953 /*!
2954   \internal
2955  */
2956 
rawMonthName(const QCalendarLocale & localeData,const ushort * monthsData,int month,QLocale::FormatType type)2957 static QString rawMonthName(const QCalendarLocale &localeData,
2958                             const ushort *monthsData, int month,
2959                             QLocale::FormatType type)
2960 {
2961     quint32 idx, size;
2962     switch (type) {
2963     case QLocale::LongFormat:
2964        idx = localeData.m_long.index;
2965        size = localeData.m_long.size;
2966        break;
2967     case QLocale::ShortFormat:
2968        idx = localeData.m_short.index;
2969        size = localeData.m_short.size;
2970        break;
2971     case QLocale::NarrowFormat:
2972        idx = localeData.m_narrow.index;
2973        size = localeData.m_narrow.size;
2974        break;
2975     default:
2976        return QString();
2977     }
2978     return getLocaleListData(monthsData + idx, size, month - 1);
2979 }
2980 
2981 /*!
2982   \internal
2983  */
2984 
rawStandaloneMonthName(const QCalendarLocale & localeData,const ushort * monthsData,int month,QLocale::FormatType type)2985 static QString rawStandaloneMonthName(const QCalendarLocale &localeData,
2986                                       const ushort *monthsData, int month,
2987                                       QLocale::FormatType type)
2988 {
2989     quint32 idx, size;
2990     switch (type) {
2991     case QLocale::LongFormat:
2992         idx = localeData.m_standalone_long.index;
2993         size = localeData.m_standalone_long.size;
2994         break;
2995     case QLocale::ShortFormat:
2996         idx = localeData.m_standalone_short.index;
2997         size = localeData.m_standalone_short.size;
2998         break;
2999     case QLocale::NarrowFormat:
3000         idx = localeData.m_standalone_narrow.index;
3001         size = localeData.m_standalone_narrow.size;
3002         break;
3003     default:
3004         return QString();
3005     }
3006     QString name = getLocaleListData(monthsData + idx, size, month - 1);
3007     return name.isEmpty() ? rawMonthName(localeData, monthsData, month, type) : name;
3008 }
3009 
3010 /*!
3011   \internal
3012  */
3013 
rawWeekDayName(const QLocaleData * data,const int day,QLocale::FormatType type)3014 static QString rawWeekDayName(const QLocaleData *data, const int day,
3015                               QLocale::FormatType type)
3016 {
3017     quint32 idx, size;
3018     switch (type) {
3019     case QLocale::LongFormat:
3020         idx = data->m_long_day_names_idx;
3021         size = data->m_long_day_names_size;
3022         break;
3023     case QLocale::ShortFormat:
3024         idx = data->m_short_day_names_idx;
3025         size = data->m_short_day_names_size;
3026         break;
3027     case QLocale::NarrowFormat:
3028         idx = data->m_narrow_day_names_idx;
3029         size = data->m_narrow_day_names_size;
3030         break;
3031     default:
3032         return QString();
3033     }
3034     return getLocaleListData(days_data + idx, size, day == 7 ? 0 : day);
3035 }
3036 
3037 /*!
3038   \internal
3039  */
3040 
rawStandaloneWeekDayName(const QLocaleData * data,const int day,QLocale::FormatType type)3041 static QString rawStandaloneWeekDayName(const QLocaleData *data, const int day,
3042                                         QLocale::FormatType type)
3043 {
3044     quint32 idx, size;
3045     switch (type) {
3046     case QLocale::LongFormat:
3047         idx = data->m_standalone_long_day_names_idx;
3048         size = data->m_standalone_long_day_names_size;
3049         break;
3050     case QLocale::ShortFormat:
3051         idx = data->m_standalone_short_day_names_idx;
3052         size = data->m_standalone_short_day_names_size;
3053         break;
3054     case QLocale::NarrowFormat:
3055         idx = data->m_standalone_narrow_day_names_idx;
3056         size = data->m_standalone_narrow_day_names_size;
3057         break;
3058     default:
3059         return QString();
3060     }
3061     QString name = getLocaleListData(days_data + idx, size, day == 7 ? 0 : day);
3062     if (name.isEmpty())
3063         return rawWeekDayName(data, day, type);
3064     return name;
3065 }
3066 
3067 // Refugees from qcalendar.cpp that need functions above:
3068 
monthName(const QLocale & locale,int month,int,QLocale::FormatType format) const3069 QString QCalendarBackend::monthName(const QLocale &locale, int month, int,
3070                                     QLocale::FormatType format) const
3071 {
3072     Q_ASSERT(month >= 1 && month <= maximumMonthsInYear());
3073     return rawMonthName(localeMonthIndexData()[locale.d->m_data_offset],
3074                         localeMonthData(), month, format);
3075 }
3076 
monthName(const QLocale & locale,int month,int year,QLocale::FormatType format) const3077 QString QGregorianCalendar::monthName(const QLocale &locale, int month, int year,
3078                                       QLocale::FormatType format) const
3079 {
3080 #ifndef QT_NO_SYSTEMLOCALE
3081     if (locale.d->m_data == systemData()) {
3082         Q_ASSERT(month >= 1 && month <= 12);
3083         QVariant res = systemLocale()->query(format == QLocale::LongFormat
3084                                              ? QSystemLocale::MonthNameLong
3085                                              : QSystemLocale::MonthNameShort,
3086                                              month);
3087         if (!res.isNull())
3088             return res.toString();
3089     }
3090 #endif
3091 
3092     return QCalendarBackend::monthName(locale, month, year, format);
3093 }
3094 
standaloneMonthName(const QLocale & locale,int month,int,QLocale::FormatType format) const3095 QString QCalendarBackend::standaloneMonthName(const QLocale &locale, int month, int,
3096                                               QLocale::FormatType format) const
3097 {
3098     Q_ASSERT(month >= 1 && month <= maximumMonthsInYear());
3099     return rawStandaloneMonthName(localeMonthIndexData()[locale.d->m_data_offset],
3100                                   localeMonthData(), month, format);
3101 }
3102 
standaloneMonthName(const QLocale & locale,int month,int year,QLocale::FormatType format) const3103 QString QGregorianCalendar::standaloneMonthName(const QLocale &locale, int month, int year,
3104                                                 QLocale::FormatType format) const
3105 {
3106 #ifndef QT_NO_SYSTEMLOCALE
3107     if (locale.d->m_data == systemData()) {
3108         Q_ASSERT(month >= 1 && month <= 12);
3109         QVariant res = systemLocale()->query(format == QLocale::LongFormat
3110                                              ? QSystemLocale::StandaloneMonthNameLong
3111                                              : QSystemLocale::StandaloneMonthNameShort,
3112                                              month);
3113         if (!res.isNull())
3114             return res.toString();
3115     }
3116 #endif
3117 
3118     return QCalendarBackend::standaloneMonthName(locale, month, year, format);
3119 }
3120 
3121 // Most calendars share the common week-day naming, modulo locale.
3122 // Calendars that don't must override these methods.
weekDayName(const QLocale & locale,int day,QLocale::FormatType format) const3123 QString QCalendarBackend::weekDayName(const QLocale &locale, int day,
3124                                       QLocale::FormatType format) const
3125 {
3126     if (day < 1 || day > 7)
3127         return QString();
3128 
3129 #ifndef QT_NO_SYSTEMLOCALE
3130     if (locale.d->m_data == systemData()) {
3131         QVariant res = systemLocale()->query(format == QLocale::LongFormat
3132                                              ? QSystemLocale::DayNameLong
3133                                              : QSystemLocale::DayNameShort,
3134                                              day);
3135         if (!res.isNull())
3136             return res.toString();
3137     }
3138 #endif
3139 
3140     return rawWeekDayName(locale.d->m_data, day, format);
3141 }
3142 
standaloneWeekDayName(const QLocale & locale,int day,QLocale::FormatType format) const3143 QString QCalendarBackend::standaloneWeekDayName(const QLocale &locale, int day,
3144                                                 QLocale::FormatType format) const
3145 {
3146     if (day < 1 || day > 7)
3147         return QString();
3148 
3149 #ifndef QT_NO_SYSTEMLOCALE
3150     if (locale.d->m_data == systemData()) {
3151         QVariant res = systemLocale()->query(format == QLocale::LongFormat
3152                                              ? QSystemLocale::DayNameLong
3153                                              : QSystemLocale::DayNameShort,
3154                                              day);
3155         if (!res.isNull())
3156             return res.toString();
3157     }
3158 #endif
3159 
3160     return rawStandaloneWeekDayName(locale.d->m_data, day, format);
3161 }
3162 
3163 // End of this block of qcalendar.cpp refugees.  (One more follows.)
3164 
3165 /*!
3166     \since 4.8
3167 
3168     Returns the first day of the week according to the current locale.
3169 */
firstDayOfWeek() const3170 Qt::DayOfWeek QLocale::firstDayOfWeek() const
3171 {
3172 #ifndef QT_NO_SYSTEMLOCALE
3173     if (d->m_data == systemData()) {
3174         QVariant res = systemLocale()->query(QSystemLocale::FirstDayOfWeek, QVariant());
3175         if (!res.isNull())
3176             return static_cast<Qt::DayOfWeek>(res.toUInt());
3177     }
3178 #endif
3179     return static_cast<Qt::DayOfWeek>(d->m_data->m_first_day_of_week);
3180 }
3181 
measurementSystem() const3182 QLocale::MeasurementSystem QLocalePrivate::measurementSystem() const
3183 {
3184     for (int i = 0; i < ImperialMeasurementSystemsCount; ++i) {
3185         if (ImperialMeasurementSystems[i].languageId == m_data->m_language_id
3186             && ImperialMeasurementSystems[i].countryId == m_data->m_country_id) {
3187             return ImperialMeasurementSystems[i].system;
3188         }
3189     }
3190     return QLocale::MetricSystem;
3191 }
3192 
3193 /*!
3194     \since 4.8
3195 
3196     Returns a list of days that are considered weekdays according to the current locale.
3197 */
weekdays() const3198 QList<Qt::DayOfWeek> QLocale::weekdays() const
3199 {
3200 #ifndef QT_NO_SYSTEMLOCALE
3201     if (d->m_data == systemData()) {
3202         QVariant res = systemLocale()->query(QSystemLocale::Weekdays, QVariant());
3203         if (!res.isNull())
3204             return static_cast<QList<Qt::DayOfWeek> >(qvariant_cast<QList<Qt::DayOfWeek> >(res));
3205     }
3206 #endif
3207     QList<Qt::DayOfWeek> weekdays;
3208     quint16 weekendStart = d->m_data->m_weekend_start;
3209     quint16 weekendEnd = d->m_data->m_weekend_end;
3210     for (int day = Qt::Monday; day <= Qt::Sunday; day++) {
3211         if ((weekendEnd >= weekendStart && (day < weekendStart || day > weekendEnd)) ||
3212             (weekendEnd < weekendStart && (day > weekendEnd && day < weekendStart)))
3213                 weekdays << static_cast<Qt::DayOfWeek>(day);
3214     }
3215     return weekdays;
3216 }
3217 
3218 /*!
3219     \since 4.4
3220 
3221     Returns the measurement system for the locale.
3222 */
measurementSystem() const3223 QLocale::MeasurementSystem QLocale::measurementSystem() const
3224 {
3225 #ifndef QT_NO_SYSTEMLOCALE
3226     if (d->m_data == systemData()) {
3227         QVariant res = systemLocale()->query(QSystemLocale::MeasurementSystem, QVariant());
3228         if (!res.isNull())
3229             return MeasurementSystem(res.toInt());
3230     }
3231 #endif
3232 
3233     return d->measurementSystem();
3234 }
3235 
3236 /*!
3237   \since 4.7
3238 
3239   Returns the text direction of the language.
3240 */
textDirection() const3241 Qt::LayoutDirection QLocale::textDirection() const
3242 {
3243     switch (script()) {
3244     case QLocale::AdlamScript:
3245     case QLocale::ArabicScript:
3246     case QLocale::AvestanScript:
3247     case QLocale::CypriotScript:
3248     case QLocale::HatranScript:
3249     case QLocale::HebrewScript:
3250     case QLocale::ImperialAramaicScript:
3251     case QLocale::InscriptionalPahlaviScript:
3252     case QLocale::InscriptionalParthianScript:
3253     case QLocale::KharoshthiScript:
3254     case QLocale::LydianScript:
3255     case QLocale::MandaeanScript:
3256     case QLocale::ManichaeanScript:
3257     case QLocale::MendeKikakuiScript:
3258     case QLocale::MeroiticCursiveScript:
3259     case QLocale::MeroiticScript:
3260     case QLocale::NabataeanScript:
3261     case QLocale::NkoScript:
3262     case QLocale::OldHungarianScript:
3263     case QLocale::OldNorthArabianScript:
3264     case QLocale::OldSouthArabianScript:
3265     case QLocale::OrkhonScript:
3266     case QLocale::PalmyreneScript:
3267     case QLocale::PhoenicianScript:
3268     case QLocale::PsalterPahlaviScript:
3269     case QLocale::SamaritanScript:
3270     case QLocale::SyriacScript:
3271     case QLocale::ThaanaScript:
3272         return Qt::RightToLeft;
3273     default:
3274         break;
3275     }
3276     return Qt::LeftToRight;
3277 }
3278 
3279 /*!
3280   \since 4.8
3281 
3282   Returns an uppercase copy of \a str.
3283 
3284   If Qt Core is using the ICU libraries, they will be used to perform
3285   the transformation according to the rules of the current locale.
3286   Otherwise the conversion may be done in a platform-dependent manner,
3287   with QString::toUpper() as a generic fallback.
3288 
3289   \sa QString::toUpper()
3290 */
toUpper(const QString & str) const3291 QString QLocale::toUpper(const QString &str) const
3292 {
3293 #if QT_CONFIG(icu)
3294     bool ok = true;
3295     QString result = QIcu::toUpper(d->bcp47Name('_'), str, &ok);
3296     if (ok)
3297         return result;
3298     // else fall through and use Qt's toUpper
3299 #endif
3300     return str.toUpper();
3301 }
3302 
3303 /*!
3304   \since 4.8
3305 
3306   Returns a lowercase copy of \a str.
3307 
3308   If Qt Core is using the ICU libraries, they will be used to perform
3309   the transformation according to the rules of the current locale.
3310   Otherwise the conversion may be done in a platform-dependent manner,
3311   with QString::toLower() as a generic fallback.
3312 
3313   \sa QString::toLower()
3314 */
toLower(const QString & str) const3315 QString QLocale::toLower(const QString &str) const
3316 {
3317 #if QT_CONFIG(icu)
3318     bool ok = true;
3319     const QString result = QIcu::toLower(d->bcp47Name('_'), str, &ok);
3320     if (ok)
3321         return result;
3322     // else fall through and use Qt's toUpper
3323 #endif
3324     return str.toLower();
3325 }
3326 
3327 
3328 /*!
3329     \since 4.5
3330 
3331     Returns the localized name of the "AM" suffix for times specified using
3332     the conventions of the 12-hour clock.
3333 
3334     \sa pmText()
3335 */
amText() const3336 QString QLocale::amText() const
3337 {
3338 #ifndef QT_NO_SYSTEMLOCALE
3339     if (d->m_data == systemData()) {
3340         QVariant res = systemLocale()->query(QSystemLocale::AMText, QVariant());
3341         if (!res.isNull())
3342             return res.toString();
3343     }
3344 #endif
3345     return getLocaleData(am_data + d->m_data->m_am_idx, d->m_data->m_am_size);
3346 }
3347 
3348 /*!
3349     \since 4.5
3350 
3351     Returns the localized name of the "PM" suffix for times specified using
3352     the conventions of the 12-hour clock.
3353 
3354     \sa amText()
3355 */
pmText() const3356 QString QLocale::pmText() const
3357 {
3358 #ifndef QT_NO_SYSTEMLOCALE
3359     if (d->m_data == systemData()) {
3360         QVariant res = systemLocale()->query(QSystemLocale::PMText, QVariant());
3361         if (!res.isNull())
3362             return res.toString();
3363     }
3364 #endif
3365     return getLocaleData(pm_data + d->m_data->m_pm_idx, d->m_data->m_pm_size);
3366 }
3367 
3368 // Another intrusion from QCalendar, using some of the tools above:
3369 
dateTimeToString(QStringView format,const QDateTime & datetime,const QDate & dateOnly,const QTime & timeOnly,const QLocale & locale) const3370 QString QCalendarBackend::dateTimeToString(QStringView format, const QDateTime &datetime,
3371                                            const QDate &dateOnly, const QTime &timeOnly,
3372                                            const QLocale &locale) const
3373 {
3374     QDate date;
3375     QTime time;
3376     bool formatDate = false;
3377     bool formatTime = false;
3378     if (datetime.isValid()) {
3379         date = datetime.date();
3380         time = datetime.time();
3381         formatDate = true;
3382         formatTime = true;
3383     } else if (dateOnly.isValid()) {
3384         date = dateOnly;
3385         formatDate = true;
3386     } else if (timeOnly.isValid()) {
3387         time = timeOnly;
3388         formatTime = true;
3389     } else {
3390         return QString();
3391     }
3392 
3393     QString result;
3394     int year = 0, month = 0, day = 0;
3395     if (formatDate) {
3396         const auto parts = julianDayToDate(date.toJulianDay());
3397         if (!parts.isValid())
3398             return QString();
3399         year = parts.year;
3400         month = parts.month;
3401         day = parts.day;
3402     }
3403 
3404     int i = 0;
3405     while (i < format.size()) {
3406         if (format.at(i).unicode() == '\'') {
3407             result.append(qt_readEscapedFormatString(format, &i));
3408             continue;
3409         }
3410 
3411         const QChar c = format.at(i);
3412         int repeat = qt_repeatCount(format.mid(i));
3413         bool used = false;
3414         if (formatDate) {
3415             switch (c.unicode()) {
3416             case 'y':
3417                 used = true;
3418                 if (repeat >= 4)
3419                     repeat = 4;
3420                 else if (repeat >= 2)
3421                     repeat = 2;
3422 
3423                 switch (repeat) {
3424                 case 4: {
3425                     const int len = (year < 0) ? 5 : 4;
3426                     result.append(locale.d->m_data->longLongToString(year, -1, 10, len,
3427                                                                      QLocaleData::ZeroPadded));
3428                     break;
3429                 }
3430                 case 2:
3431                     result.append(locale.d->m_data->longLongToString(year % 100, -1, 10, 2,
3432                                                                      QLocaleData::ZeroPadded));
3433                     break;
3434                 default:
3435                     repeat = 1;
3436                     result.append(c);
3437                     break;
3438                 }
3439                 break;
3440 
3441             case 'M':
3442                 used = true;
3443                 repeat = qMin(repeat, 4);
3444                 switch (repeat) {
3445                 case 1:
3446                     result.append(locale.d->m_data->longLongToString(month));
3447                     break;
3448                 case 2:
3449                     result.append(locale.d->m_data->longLongToString(month, -1, 10, 2,
3450                                                                      QLocaleData::ZeroPadded));
3451                     break;
3452                 case 3:
3453                     result.append(monthName(locale, month, year, QLocale::ShortFormat));
3454                     break;
3455                 case 4:
3456                     result.append(monthName(locale, month, year, QLocale::LongFormat));
3457                     break;
3458                 }
3459                 break;
3460 
3461             case 'd':
3462                 used = true;
3463                 repeat = qMin(repeat, 4);
3464                 switch (repeat) {
3465                 case 1:
3466                     result.append(locale.d->m_data->longLongToString(day));
3467                     break;
3468                 case 2:
3469                     result.append(locale.d->m_data->longLongToString(day, -1, 10, 2,
3470                                                                      QLocaleData::ZeroPadded));
3471                     break;
3472                 case 3:
3473                     result.append(locale.dayName(
3474                                       dayOfWeek(date.toJulianDay()), QLocale::ShortFormat));
3475                     break;
3476                 case 4:
3477                     result.append(locale.dayName(
3478                                       dayOfWeek(date.toJulianDay()), QLocale::LongFormat));
3479                     break;
3480                 }
3481                 break;
3482 
3483             default:
3484                 break;
3485             }
3486         }
3487         if (!used && formatTime) {
3488             switch (c.unicode()) {
3489             case 'h': {
3490                 used = true;
3491                 repeat = qMin(repeat, 2);
3492                 int hour = time.hour();
3493                 if (timeFormatContainsAP(format)) {
3494                     if (hour > 12)
3495                         hour -= 12;
3496                     else if (hour == 0)
3497                         hour = 12;
3498                 }
3499 
3500                 switch (repeat) {
3501                 case 1:
3502                     result.append(locale.d->m_data->longLongToString(hour));
3503                     break;
3504                 case 2:
3505                     result.append(locale.d->m_data->longLongToString(hour, -1, 10, 2,
3506                                                                      QLocaleData::ZeroPadded));
3507                     break;
3508                 }
3509                 break;
3510             }
3511             case 'H':
3512                 used = true;
3513                 repeat = qMin(repeat, 2);
3514                 switch (repeat) {
3515                 case 1:
3516                     result.append(locale.d->m_data->longLongToString(time.hour()));
3517                     break;
3518                 case 2:
3519                     result.append(locale.d->m_data->longLongToString(time.hour(), -1, 10, 2,
3520                                                                      QLocaleData::ZeroPadded));
3521                     break;
3522                 }
3523                 break;
3524 
3525             case 'm':
3526                 used = true;
3527                 repeat = qMin(repeat, 2);
3528                 switch (repeat) {
3529                 case 1:
3530                     result.append(locale.d->m_data->longLongToString(time.minute()));
3531                     break;
3532                 case 2:
3533                     result.append(locale.d->m_data->longLongToString(time.minute(), -1, 10, 2,
3534                                                                      QLocaleData::ZeroPadded));
3535                     break;
3536                 }
3537                 break;
3538 
3539             case 's':
3540                 used = true;
3541                 repeat = qMin(repeat, 2);
3542                 switch (repeat) {
3543                 case 1:
3544                     result.append(locale.d->m_data->longLongToString(time.second()));
3545                     break;
3546                 case 2:
3547                     result.append(locale.d->m_data->longLongToString(time.second(), -1, 10, 2,
3548                                                                      QLocaleData::ZeroPadded));
3549                     break;
3550                 }
3551                 break;
3552 
3553             case 'a':
3554                 used = true;
3555                 repeat = format.mid(i + 1).startsWith(QLatin1Char('p')) ? 2 : 1;
3556                 result.append(time.hour() < 12 ? locale.amText().toLower()
3557                                                : locale.pmText().toLower());
3558                 break;
3559 
3560             case 'A':
3561                 used = true;
3562                 repeat = format.mid(i + 1).startsWith(QLatin1Char('P')) ? 2 : 1;
3563                 result.append(time.hour() < 12 ? locale.amText().toUpper()
3564                                                 : locale.pmText().toUpper());
3565                 break;
3566 
3567             case 'z':
3568                 used = true;
3569                 repeat = (repeat >= 3) ? 3 : 1;
3570 
3571                 // note: the millisecond component is treated like the decimal part of the seconds
3572                 // so ms == 2 is always printed as "002", but ms == 200 can be either "2" or "200"
3573                 result.append(locale.d->m_data->longLongToString(time.msec(), -1, 10, 3,
3574                                                                  QLocaleData::ZeroPadded));
3575                 if (repeat == 1) {
3576                     if (result.endsWith(locale.d->zero()))
3577                         result.chop(1);
3578                     if (result.endsWith(locale.d->zero()))
3579                         result.chop(1);
3580                 }
3581                 break;
3582 
3583             case 't':
3584                 used = true;
3585                 repeat = 1;
3586                 // If we have a QDateTime use the time spec otherwise use the current system tzname
3587                 result.append(formatDate ? datetime.timeZoneAbbreviation()
3588                                          : QDateTime::currentDateTime().timeZoneAbbreviation());
3589                 break;
3590 
3591             default:
3592                 break;
3593             }
3594         }
3595         if (!used)
3596             result.append(QString(repeat, c));
3597         i += repeat;
3598     }
3599 
3600     return result;
3601 }
3602 
3603 // End of QCalendar intrustions
3604 
doubleToString(double d,int precision,DoubleForm form,int width,unsigned flags) const3605 QString QLocaleData::doubleToString(double d, int precision, DoubleForm form,
3606                                     int width, unsigned flags) const
3607 {
3608     return doubleToString(m_zero, m_plus, m_minus, m_exponential, m_group, m_decimal,
3609                           d, precision, form, width, flags);
3610 }
3611 
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)3612 QString QLocaleData::doubleToString(const QChar _zero, const QChar plus, const QChar minus,
3613                                     const QChar exponential, const QChar group, const QChar decimal,
3614                                     double d, int precision, DoubleForm form, int width,
3615                                     unsigned flags)
3616 {
3617     if (precision != QLocale::FloatingPointShortest && precision < 0)
3618         precision = 6;
3619     if (width < 0)
3620         width = 0;
3621 
3622     bool negative = false;
3623     QString num_str;
3624 
3625     int decpt;
3626     int bufSize = 1;
3627     if (precision == QLocale::FloatingPointShortest)
3628         bufSize += DoubleMaxSignificant;
3629     else if (form == DFDecimal) // optimize for numbers between -512k and 512k
3630         bufSize += ((d > (1 << 19) || d < -(1 << 19)) ? DoubleMaxDigitsBeforeDecimal : 6) +
3631                 precision;
3632     else // Add extra digit due to different interpretations of precision. Also, "nan" has to fit.
3633         bufSize += qMax(2, precision) + 1;
3634 
3635     QVarLengthArray<char> buf(bufSize);
3636     int length;
3637 
3638     qt_doubleToAscii(d, form, precision, buf.data(), bufSize, negative, length, decpt);
3639 
3640     if (qstrncmp(buf.data(), "inf", 3) == 0 || qstrncmp(buf.data(), "nan", 3) == 0) {
3641         num_str = QString::fromLatin1(buf.data(), length);
3642     } else { // Handle normal numbers
3643         QString digits = QString::fromLatin1(buf.data(), length);
3644 
3645         if (_zero.unicode() != '0') {
3646             ushort z = _zero.unicode() - '0';
3647             for (int i = 0; i < digits.length(); ++i)
3648                 reinterpret_cast<ushort *>(digits.data())[i] += z;
3649         }
3650 
3651         bool always_show_decpt = (flags & ForcePoint);
3652         switch (form) {
3653             case DFExponent: {
3654                 num_str = exponentForm(_zero, decimal, exponential, group, plus, minus,
3655                                        digits, decpt, precision, PMDecimalDigits,
3656                                        always_show_decpt, flags & ZeroPadExponent);
3657                 break;
3658             }
3659             case DFDecimal: {
3660                 num_str = decimalForm(_zero, decimal, group,
3661                                       digits, decpt, precision, PMDecimalDigits,
3662                                       always_show_decpt, flags & ThousandsGroup);
3663                 break;
3664             }
3665             case DFSignificantDigits: {
3666                 PrecisionMode mode = (flags & AddTrailingZeroes) ?
3667                             PMSignificantDigits : PMChopTrailingZeros;
3668 
3669                 int cutoff = precision < 0 ? 6 : precision;
3670                 // Find out which representation is shorter
3671                 if (precision == QLocale::FloatingPointShortest && decpt > 0) {
3672                     cutoff = digits.length() + 4; // 'e', '+'/'-', one digit exponent
3673                     if (decpt <= 10) {
3674                         ++cutoff;
3675                     } else {
3676                         cutoff += decpt > 100 ? 2 : 1;
3677                     }
3678                     if (!always_show_decpt && digits.length() > decpt)
3679                         ++cutoff; // decpt shown in exponent form, but not in decimal form
3680                 }
3681 
3682                 if (decpt != digits.length() && (decpt <= -4 || decpt > cutoff))
3683                     num_str = exponentForm(_zero, decimal, exponential, group, plus, minus,
3684                                            digits, decpt, precision, mode,
3685                                            always_show_decpt, flags & ZeroPadExponent);
3686                 else
3687                     num_str = decimalForm(_zero, decimal, group,
3688                                           digits, decpt, precision, mode,
3689                                           always_show_decpt, flags & ThousandsGroup);
3690                 break;
3691             }
3692         }
3693 
3694         if (isZero(d))
3695             negative = false;
3696 
3697         // pad with zeros. LeftAdjusted overrides this flag). Also, we don't
3698         // pad special numbers
3699         if (flags & QLocaleData::ZeroPadded && !(flags & QLocaleData::LeftAdjusted)) {
3700             int num_pad_chars = width - num_str.length();
3701             // leave space for the sign
3702             if (negative
3703                     || flags & QLocaleData::AlwaysShowSign
3704                     || flags & QLocaleData::BlankBeforePositive)
3705                 --num_pad_chars;
3706 
3707             for (int i = 0; i < num_pad_chars; ++i)
3708                 num_str.prepend(_zero);
3709         }
3710     }
3711 
3712     // add sign
3713     if (negative)
3714         num_str.prepend(minus);
3715     else if (flags & QLocaleData::AlwaysShowSign)
3716         num_str.prepend(plus);
3717     else if (flags & QLocaleData::BlankBeforePositive)
3718         num_str.prepend(QLatin1Char(' '));
3719 
3720     if (flags & QLocaleData::CapitalEorX)
3721         num_str = std::move(num_str).toUpper();
3722 
3723     return num_str;
3724 }
3725 
longLongToString(qlonglong l,int precision,int base,int width,unsigned flags) const3726 QString QLocaleData::longLongToString(qlonglong l, int precision,
3727                                             int base, int width,
3728                                             unsigned flags) const
3729 {
3730     return longLongToString(m_zero, m_group, m_plus, m_minus,
3731                                             l, precision, base, width, flags);
3732 }
3733 
longLongToString(const QChar zero,const QChar group,const QChar plus,const QChar minus,qlonglong l,int precision,int base,int width,unsigned flags)3734 QString QLocaleData::longLongToString(const QChar zero, const QChar group,
3735                                          const QChar plus, const QChar minus,
3736                                          qlonglong l, int precision,
3737                                          int base, int width,
3738                                          unsigned flags)
3739 {
3740     bool precision_not_specified = false;
3741     if (precision == -1) {
3742         precision_not_specified = true;
3743         precision = 1;
3744     }
3745 
3746     bool negative = l < 0;
3747     if (base != 10) {
3748         // these are not supported by sprintf for octal and hex
3749         flags &= ~AlwaysShowSign;
3750         flags &= ~BlankBeforePositive;
3751         negative = false; // neither are negative numbers
3752     }
3753 
3754 QT_WARNING_PUSH
3755     /* "unary minus operator applied to unsigned type, result still unsigned" */
3756 QT_WARNING_DISABLE_MSVC(4146)
3757     /*
3758       Negating std::numeric_limits<qlonglong>::min() hits undefined behavior, so
3759       taking an absolute value has to cast to unsigned to change sign.
3760      */
3761     QString num_str = qulltoa(negative ? -qulonglong(l) : qulonglong(l), base, zero);
3762 QT_WARNING_POP
3763 
3764     uint cnt_thousand_sep = 0;
3765     if (base == 10){
3766         if (flags & ThousandsGroup) {
3767             for (int i = num_str.length() - 3; i > 0; i -= 3) {
3768                 num_str.insert(i, group);
3769                 ++cnt_thousand_sep;
3770             }
3771         } else if (flags & IndianNumberGrouping) {
3772             if (num_str.length() > 3)
3773                 num_str.insert(num_str.length() - 3 , group);
3774             for (int i = num_str.length() - 6; i > 0; i -= 2) {
3775                 num_str.insert(i, group);
3776                 ++cnt_thousand_sep;
3777             }
3778         }
3779     }
3780 
3781     for (int i = num_str.length()/* - cnt_thousand_sep*/; i < precision; ++i)
3782         num_str.prepend(base == 10 ? zero : QChar::fromLatin1('0'));
3783 
3784     if ((flags & ShowBase)
3785             && base == 8
3786             && (num_str.isEmpty() || num_str[0].unicode() != QLatin1Char('0')))
3787         num_str.prepend(QLatin1Char('0'));
3788 
3789     // LeftAdjusted overrides this flag ZeroPadded. sprintf only padds
3790     // when precision is not specified in the format string
3791     bool zero_padded = flags & ZeroPadded
3792                         && !(flags & LeftAdjusted)
3793                         && precision_not_specified;
3794 
3795     if (zero_padded) {
3796         int num_pad_chars = width - num_str.length();
3797 
3798         // leave space for the sign
3799         if (negative
3800                 || flags & AlwaysShowSign
3801                 || flags & BlankBeforePositive)
3802             --num_pad_chars;
3803 
3804         // leave space for optional '0x' in hex form
3805         if (base == 16 && (flags & ShowBase))
3806             num_pad_chars -= 2;
3807         // leave space for optional '0b' in binary form
3808         else if (base == 2 && (flags & ShowBase))
3809             num_pad_chars -= 2;
3810 
3811         for (int i = 0; i < num_pad_chars; ++i)
3812             num_str.prepend(base == 10 ? zero : QChar::fromLatin1('0'));
3813     }
3814 
3815     if (flags & CapitalEorX)
3816         num_str = std::move(num_str).toUpper();
3817 
3818     if (base == 16 && (flags & ShowBase))
3819         num_str.prepend(QLatin1String(flags & UppercaseBase ? "0X" : "0x"));
3820     if (base == 2 && (flags & ShowBase))
3821         num_str.prepend(QLatin1String(flags & UppercaseBase ? "0B" : "0b"));
3822 
3823     // add sign
3824     if (negative)
3825         num_str.prepend(minus);
3826     else if (flags & AlwaysShowSign)
3827         num_str.prepend(plus);
3828     else if (flags & BlankBeforePositive)
3829         num_str.prepend(QLatin1Char(' '));
3830 
3831     return num_str;
3832 }
3833 
unsLongLongToString(qulonglong l,int precision,int base,int width,unsigned flags) const3834 QString QLocaleData::unsLongLongToString(qulonglong l, int precision,
3835                                             int base, int width,
3836                                             unsigned flags) const
3837 {
3838     return unsLongLongToString(m_zero, m_group, m_plus,
3839                                                l, precision, base, width, flags);
3840 }
3841 
unsLongLongToString(const QChar zero,const QChar group,const QChar plus,qulonglong l,int precision,int base,int width,unsigned flags)3842 QString QLocaleData::unsLongLongToString(const QChar zero, const QChar group,
3843                                             const QChar plus,
3844                                             qulonglong l, int precision,
3845                                             int base, int width,
3846                                             unsigned flags)
3847 {
3848     const QChar resultZero = base == 10 ? zero : QChar(QLatin1Char('0'));
3849     QString num_str = l ? qulltoa(l, base, zero) : QString(resultZero);
3850 
3851     bool precision_not_specified = false;
3852     if (precision == -1) {
3853         if (flags == NoFlags)
3854             return num_str; // fast-path: nothing below applies, so we're done.
3855 
3856         precision_not_specified = true;
3857         precision = 1;
3858     }
3859 
3860     uint cnt_thousand_sep = 0;
3861     if (base == 10) {
3862         if (flags & ThousandsGroup) {
3863             for (int i = num_str.length() - 3; i > 0; i -=3) {
3864                 num_str.insert(i, group);
3865                 ++cnt_thousand_sep;
3866             }
3867         } else if (flags & IndianNumberGrouping) {
3868             if (num_str.length() > 3)
3869                 num_str.insert(num_str.length() - 3 , group);
3870             for (int i = num_str.length() - 6; i > 0; i -= 2) {
3871                 num_str.insert(i, group);
3872                 ++cnt_thousand_sep;
3873             }
3874         }
3875     }
3876 
3877     const int zeroPadding = precision - num_str.length()/* + cnt_thousand_sep*/;
3878     if (zeroPadding > 0)
3879         num_str.prepend(QString(zeroPadding, resultZero));
3880 
3881     if ((flags & ShowBase)
3882             && base == 8
3883             && (num_str.isEmpty() || num_str.at(0).unicode() != QLatin1Char('0')))
3884         num_str.prepend(QLatin1Char('0'));
3885 
3886     // LeftAdjusted overrides this flag ZeroPadded. sprintf only padds
3887     // when precision is not specified in the format string
3888     bool zero_padded = flags & ZeroPadded
3889                         && !(flags & LeftAdjusted)
3890                         && precision_not_specified;
3891 
3892     if (zero_padded) {
3893         int num_pad_chars = width - num_str.length();
3894 
3895         // leave space for optional '0x' in hex form
3896         if (base == 16 && flags & ShowBase)
3897             num_pad_chars -= 2;
3898         // leave space for optional '0b' in binary form
3899         else if (base == 2 && flags & ShowBase)
3900             num_pad_chars -= 2;
3901 
3902         if (num_pad_chars > 0)
3903             num_str.prepend(QString(num_pad_chars, resultZero));
3904     }
3905 
3906     if (flags & CapitalEorX)
3907         num_str = std::move(num_str).toUpper();
3908 
3909     if (base == 16 && flags & ShowBase)
3910         num_str.prepend(QLatin1String(flags & UppercaseBase ? "0X" : "0x"));
3911     else if (base == 2 && flags & ShowBase)
3912         num_str.prepend(QLatin1String(flags & UppercaseBase ? "0B" : "0b"));
3913 
3914     // add sign
3915     if (flags & AlwaysShowSign)
3916         num_str.prepend(plus);
3917     else if (flags & BlankBeforePositive)
3918         num_str.prepend(QLatin1Char(' '));
3919 
3920     return num_str;
3921 }
3922 
3923 /*
3924     Converts a number in locale to its representation in the C locale.
3925     Only has to guarantee that a string that is a correct representation of
3926     a number will be converted. If junk is passed in, junk will be passed
3927     out and the error will be detected during the actual conversion to a
3928     number. We can't detect junk here, since we don't even know the base
3929     of the number.
3930 */
numberToCLocale(QStringView s,QLocale::NumberOptions number_options,CharBuff * result) const3931 bool QLocaleData::numberToCLocale(QStringView s, QLocale::NumberOptions number_options,
3932                                   CharBuff *result) const
3933 {
3934     const QChar *uc = s.data();
3935     auto l = s.size();
3936     decltype(l) idx = 0;
3937 
3938     // Skip whitespace
3939     while (idx < l && uc[idx].isSpace())
3940         ++idx;
3941     if (idx == l)
3942         return false;
3943 
3944     // Check trailing whitespace
3945     for (; idx < l; --l) {
3946         if (!uc[l - 1].isSpace())
3947             break;
3948     }
3949 
3950     int group_cnt = 0; // counts number of group chars
3951     int decpt_idx = -1;
3952     int last_separator_idx = -1;
3953     int start_of_digits_idx = -1;
3954     int exponent_idx = -1;
3955 
3956     while (idx < l) {
3957         const QChar in = uc[idx];
3958 
3959         char out = digitToCLocale(in);
3960         if (out == 0) {
3961             if (in == m_list)
3962                 out = ';';
3963             else if (in == m_percent)
3964                 out = '%';
3965             // for handling base-x numbers
3966             else if (in.unicode() >= 'A' && in.unicode() <= 'Z')
3967                 out = in.toLower().toLatin1();
3968             else if (in.unicode() >= 'a' && in.unicode() <= 'z')
3969                 out = in.toLatin1();
3970             else
3971                 break;
3972         } else if (out == '.') {
3973             // Fail if more than one decimal point or point after e
3974             if (decpt_idx != -1 || exponent_idx != -1)
3975                 return false;
3976             decpt_idx = idx;
3977         } else if (out == 'e' || out == 'E') {
3978             exponent_idx = idx;
3979         }
3980 
3981         if (number_options & QLocale::RejectLeadingZeroInExponent) {
3982             if (exponent_idx != -1 && out == '0' && idx < l - 1) {
3983                 // After the exponent there can only be '+', '-' or digits.
3984                 // If we find a '0' directly after some non-digit, then that is a leading zero.
3985                 if (result->last() < '0' || result->last() > '9')
3986                     return false;
3987             }
3988         }
3989 
3990         if (number_options & QLocale::RejectTrailingZeroesAfterDot) {
3991             // If we've seen a decimal point and the last character after the exponent is 0, then
3992             // that is a trailing zero.
3993             if (decpt_idx >= 0 && idx == exponent_idx && result->last() == '0')
3994                     return false;
3995         }
3996 
3997         if (!(number_options & QLocale::RejectGroupSeparator)) {
3998             if (start_of_digits_idx == -1 && out >= '0' && out <= '9') {
3999                 start_of_digits_idx = idx;
4000             } else if (out == ',') {
4001                 // Don't allow group chars after the decimal point or exponent
4002                 if (decpt_idx != -1 || exponent_idx != -1)
4003                     return false;
4004 
4005                 // check distance from the last separator or from the beginning of the digits
4006                 // ### FIXME: Some locales allow other groupings!
4007                 // See https://en.wikipedia.org/wiki/Thousands_separator
4008                 if (m_country_id == QLocale::India) {
4009                     if (last_separator_idx != -1 && idx - last_separator_idx != 3)
4010                         return false;
4011                 } else if (last_separator_idx != -1 && idx - last_separator_idx != 4)
4012                     return false;
4013                 if (last_separator_idx == -1
4014                     && (start_of_digits_idx == -1 || idx - start_of_digits_idx > 3)) {
4015                     return false;
4016                 }
4017 
4018                 last_separator_idx = idx;
4019                 ++group_cnt;
4020 
4021                 // don't add the group separator
4022                 ++idx;
4023                 continue;
4024             } else if (out == '.' || out == 'e' || out == 'E') {
4025                 // check distance from the last separator
4026                 // ### FIXME: Some locales allow other groupings!
4027                 // See https://en.wikipedia.org/wiki/Thousands_separator
4028                 if (last_separator_idx != -1 && idx - last_separator_idx != 4)
4029                     return false;
4030 
4031                 // stop processing separators
4032                 last_separator_idx = -1;
4033             }
4034         }
4035 
4036         result->append(out);
4037 
4038         ++idx;
4039     }
4040 
4041     if (!(number_options & QLocale::RejectGroupSeparator)) {
4042         // group separator post-processing
4043         // did we end in a separator?
4044         if (last_separator_idx + 1 == idx)
4045             return false;
4046         // were there enough digits since the last separator?
4047         if (last_separator_idx != -1 && idx - last_separator_idx != 4)
4048             return false;
4049     }
4050 
4051     if (number_options & QLocale::RejectTrailingZeroesAfterDot) {
4052         // In decimal form, the last character can be a trailing zero if we've seen a decpt.
4053         if (decpt_idx != -1 && exponent_idx == -1 && result->last() == '0')
4054             return false;
4055     }
4056 
4057     result->append('\0');
4058     return idx == l;
4059 }
4060 
validateChars(QStringView str,NumberMode numMode,QByteArray * buff,int decDigits,QLocale::NumberOptions number_options) const4061 bool QLocaleData::validateChars(QStringView str, NumberMode numMode, QByteArray *buff,
4062                                 int decDigits, QLocale::NumberOptions number_options) const
4063 {
4064     buff->clear();
4065     buff->reserve(str.length());
4066 
4067     const bool scientific = numMode == DoubleScientificMode;
4068     bool lastWasE = false;
4069     bool lastWasDigit = false;
4070     int eCnt = 0;
4071     int decPointCnt = 0;
4072     bool dec = false;
4073     int decDigitCnt = 0;
4074 
4075     for (qsizetype i = 0; i < str.size(); ++i) {
4076         char c = digitToCLocale(str.at(i));
4077 
4078         if (c >= '0' && c <= '9') {
4079             if (numMode != IntegerMode) {
4080                 // If a double has too many digits after decpt, it shall be Invalid.
4081                 if (dec && decDigits != -1 && decDigits < ++decDigitCnt)
4082                     return false;
4083             }
4084 
4085             // The only non-digit character after the 'e' can be '+' or '-'.
4086             // If a zero is directly after that, then the exponent is zero-padded.
4087             if ((number_options & QLocale::RejectLeadingZeroInExponent)
4088                 && c == '0' && eCnt > 0 && !lastWasDigit) {
4089                 return false;
4090             }
4091 
4092             lastWasDigit = true;
4093         } else {
4094             switch (c) {
4095                 case '.':
4096                     if (numMode == IntegerMode) {
4097                         // If an integer has a decimal point, it shall be Invalid.
4098                         return false;
4099                     } else {
4100                         // If a double has more than one decimal point, it shall be Invalid.
4101                         if (++decPointCnt > 1)
4102                             return false;
4103 #if 0
4104                         // If a double with no decimal digits has a decimal point, it shall be
4105                         // Invalid.
4106                         if (decDigits == 0)
4107                             return false;
4108 #endif                  // On second thoughts, it shall be Valid.
4109 
4110                         dec = true;
4111                     }
4112                     break;
4113 
4114                 case '+':
4115                 case '-':
4116                     if (scientific) {
4117                         // If a scientific has a sign that's not at the beginning or after
4118                         // an 'e', it shall be Invalid.
4119                         if (i != 0 && !lastWasE)
4120                             return false;
4121                     } else {
4122                         // If a non-scientific has a sign that's not at the beginning,
4123                         // it shall be Invalid.
4124                         if (i != 0)
4125                             return false;
4126                     }
4127                     break;
4128 
4129                 case ',':
4130                     //it can only be placed after a digit which is before the decimal point
4131                     if ((number_options & QLocale::RejectGroupSeparator) || !lastWasDigit ||
4132                             decPointCnt > 0)
4133                         return false;
4134                     break;
4135 
4136                 case 'e':
4137                     if (scientific) {
4138                         // If a scientific has more than one 'e', it shall be Invalid.
4139                         if (++eCnt > 1)
4140                             return false;
4141                         dec = false;
4142                     } else {
4143                         // If a non-scientific has an 'e', it shall be Invalid.
4144                         return false;
4145                     }
4146                     break;
4147 
4148                 default:
4149                     // If it's not a valid digit, it shall be Invalid.
4150                     return false;
4151             }
4152             lastWasDigit = false;
4153         }
4154 
4155         lastWasE = c == 'e';
4156         if (c != ',')
4157             buff->append(c);
4158     }
4159 
4160     return true;
4161 }
4162 
stringToDouble(QStringView str,bool * ok,QLocale::NumberOptions number_options) const4163 double QLocaleData::stringToDouble(QStringView str, bool *ok,
4164                                    QLocale::NumberOptions number_options) const
4165 {
4166     CharBuff buff;
4167     if (!numberToCLocale(str, number_options, &buff)) {
4168         if (ok != nullptr)
4169             *ok = false;
4170         return 0.0;
4171     }
4172     int processed = 0;
4173     bool nonNullOk = false;
4174     double d = qt_asciiToDouble(buff.constData(), buff.length() - 1, nonNullOk, processed);
4175     if (ok != nullptr)
4176         *ok = nonNullOk;
4177     return d;
4178 }
4179 
stringToLongLong(QStringView str,int base,bool * ok,QLocale::NumberOptions number_options) const4180 qlonglong QLocaleData::stringToLongLong(QStringView str, int base, bool *ok,
4181                                         QLocale::NumberOptions number_options) const
4182 {
4183     CharBuff buff;
4184     if (!numberToCLocale(str, number_options, &buff)) {
4185         if (ok != nullptr)
4186             *ok = false;
4187         return 0;
4188     }
4189 
4190     return bytearrayToLongLong(buff.constData(), base, ok);
4191 }
4192 
stringToUnsLongLong(QStringView str,int base,bool * ok,QLocale::NumberOptions number_options) const4193 qulonglong QLocaleData::stringToUnsLongLong(QStringView str, int base, bool *ok,
4194                                             QLocale::NumberOptions number_options) const
4195 {
4196     CharBuff buff;
4197     if (!numberToCLocale(str, number_options, &buff)) {
4198         if (ok != nullptr)
4199             *ok = false;
4200         return 0;
4201     }
4202 
4203     return bytearrayToUnsLongLong(buff.constData(), base, ok);
4204 }
4205 
bytearrayToLongLong(const char * num,int base,bool * ok)4206 qlonglong QLocaleData::bytearrayToLongLong(const char *num, int base, bool *ok)
4207 {
4208     bool _ok;
4209     const char *endptr;
4210 
4211     if (*num == '\0') {
4212         if (ok != nullptr)
4213             *ok = false;
4214         return 0;
4215     }
4216 
4217     qlonglong l = qstrtoll(num, &endptr, base, &_ok);
4218 
4219     if (!_ok) {
4220         if (ok != nullptr)
4221             *ok = false;
4222         return 0;
4223     }
4224 
4225     if (*endptr != '\0') {
4226         while (ascii_isspace(*endptr))
4227             ++endptr;
4228     }
4229 
4230     if (*endptr != '\0') {
4231         // we stopped at a non-digit character after converting some digits
4232         if (ok != nullptr)
4233             *ok = false;
4234         return 0;
4235     }
4236 
4237     if (ok != nullptr)
4238         *ok = true;
4239     return l;
4240 }
4241 
bytearrayToUnsLongLong(const char * num,int base,bool * ok)4242 qulonglong QLocaleData::bytearrayToUnsLongLong(const char *num, int base, bool *ok)
4243 {
4244     bool _ok;
4245     const char *endptr;
4246     qulonglong l = qstrtoull(num, &endptr, base, &_ok);
4247 
4248     if (!_ok) {
4249         if (ok != nullptr)
4250             *ok = false;
4251         return 0;
4252     }
4253 
4254     if (*endptr != '\0') {
4255         while (ascii_isspace(*endptr))
4256             ++endptr;
4257     }
4258 
4259     if (*endptr != '\0') {
4260         if (ok != nullptr)
4261             *ok = false;
4262         return 0;
4263     }
4264 
4265     if (ok != nullptr)
4266         *ok = true;
4267     return l;
4268 }
4269 
4270 /*!
4271     \since 4.8
4272 
4273     \enum QLocale::CurrencySymbolFormat
4274 
4275     Specifies the format of the currency symbol.
4276 
4277     \value CurrencyIsoCode a ISO-4217 code of the currency.
4278     \value CurrencySymbol a currency symbol.
4279     \value CurrencyDisplayName a user readable name of the currency.
4280 */
4281 
4282 /*!
4283     \since 4.8
4284     Returns a currency symbol according to the \a format.
4285 */
currencySymbol(QLocale::CurrencySymbolFormat format) const4286 QString QLocale::currencySymbol(QLocale::CurrencySymbolFormat format) const
4287 {
4288 #ifndef QT_NO_SYSTEMLOCALE
4289     if (d->m_data == systemData()) {
4290         QVariant res = systemLocale()->query(QSystemLocale::CurrencySymbol, format);
4291         if (!res.isNull())
4292             return res.toString();
4293     }
4294 #endif
4295     quint32 idx, size;
4296     switch (format) {
4297     case CurrencySymbol:
4298         idx = d->m_data->m_currency_symbol_idx;
4299         size = d->m_data->m_currency_symbol_size;
4300         return getLocaleData(currency_symbol_data + idx, size);
4301     case CurrencyDisplayName:
4302         idx = d->m_data->m_currency_display_name_idx;
4303         size = d->m_data->m_currency_display_name_size;
4304         return getLocaleListData(currency_display_name_data + idx, size, 0);
4305     case CurrencyIsoCode: {
4306         int len = 0;
4307         const QLocaleData *data = this->d->m_data;
4308         for (; len < 3; ++len)
4309             if (!data->m_currency_iso_code[len])
4310                 break;
4311         return len ? QString::fromLatin1(data->m_currency_iso_code, len) : QString();
4312     }
4313     }
4314     return QString();
4315 }
4316 
4317 /*!
4318     \since 4.8
4319 
4320     Returns a localized string representation of \a value as a currency.
4321     If the \a symbol is provided it is used instead of the default currency symbol.
4322 
4323     \sa currencySymbol()
4324 */
toCurrencyString(qlonglong value,const QString & symbol) const4325 QString QLocale::toCurrencyString(qlonglong value, const QString &symbol) const
4326 {
4327 #ifndef QT_NO_SYSTEMLOCALE
4328     if (d->m_data == systemData()) {
4329         QSystemLocale::CurrencyToStringArgument arg(value, symbol);
4330         QVariant res =
4331             systemLocale()->query(QSystemLocale::CurrencyToString, QVariant::fromValue(arg));
4332         if (!res.isNull())
4333             return res.toString();
4334     }
4335 #endif
4336     const QLocalePrivate *d = this->d;
4337     quint8 idx = d->m_data->m_currency_format_idx;
4338     quint8 size = d->m_data->m_currency_format_size;
4339     if (d->m_data->m_currency_negative_format_size && value < 0) {
4340         idx = d->m_data->m_currency_negative_format_idx;
4341         size = d->m_data->m_currency_negative_format_size;
4342         value = -value;
4343     }
4344     QString str = toString(value);
4345     QString sym = symbol.isNull() ? currencySymbol() : symbol;
4346     if (sym.isEmpty())
4347         sym = currencySymbol(QLocale::CurrencyIsoCode);
4348     QString format = getLocaleData(currency_format_data + idx, size);
4349     return format.arg(str, sym);
4350 }
4351 
4352 /*!
4353     \since 4.8
4354     \overload
4355 */
toCurrencyString(qulonglong value,const QString & symbol) const4356 QString QLocale::toCurrencyString(qulonglong value, const QString &symbol) const
4357 {
4358 #ifndef QT_NO_SYSTEMLOCALE
4359     if (d->m_data == systemData()) {
4360         QSystemLocale::CurrencyToStringArgument arg(value, symbol);
4361         QVariant res =
4362             systemLocale()->query(QSystemLocale::CurrencyToString, QVariant::fromValue(arg));
4363         if (!res.isNull())
4364             return res.toString();
4365     }
4366 #endif
4367     const QLocaleData *data = this->d->m_data;
4368     quint8 idx = data->m_currency_format_idx;
4369     quint8 size = data->m_currency_format_size;
4370     QString str = toString(value);
4371     QString sym = symbol.isNull() ? currencySymbol() : symbol;
4372     if (sym.isEmpty())
4373         sym = currencySymbol(QLocale::CurrencyIsoCode);
4374     QString format = getLocaleData(currency_format_data + idx, size);
4375     return format.arg(str, sym);
4376 }
4377 
4378 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
4379 /*!
4380     \since 4.8
4381     \overload
4382 */
toCurrencyString(double value,const QString & symbol) const4383 QString QLocale::toCurrencyString(double value, const QString &symbol) const
4384 {
4385     return toCurrencyString(value, symbol, d->m_data->m_currency_digits);
4386 }
4387 #endif
4388 
4389 /*!
4390     \since 5.7
4391     \overload toCurrencyString()
4392 
4393     Returns a localized string representation of \a value as a currency.
4394     If the \a symbol is provided it is used instead of the default currency symbol.
4395     If the \a precision is provided it is used to set the precision of the currency value.
4396 
4397     \sa currencySymbol()
4398  */
toCurrencyString(double value,const QString & symbol,int precision) const4399 QString QLocale::toCurrencyString(double value, const QString &symbol, int precision) const
4400 {
4401 #ifndef QT_NO_SYSTEMLOCALE
4402     if (d->m_data == systemData()) {
4403         QSystemLocale::CurrencyToStringArgument arg(value, symbol);
4404         QVariant res =
4405             systemLocale()->query(QSystemLocale::CurrencyToString, QVariant::fromValue(arg));
4406         if (!res.isNull())
4407             return res.toString();
4408     }
4409 #endif
4410     const QLocaleData *data = this->d->m_data;
4411     quint8 idx = data->m_currency_format_idx;
4412     quint8 size = data->m_currency_format_size;
4413     if (data->m_currency_negative_format_size && value < 0) {
4414         idx = data->m_currency_negative_format_idx;
4415         size = data->m_currency_negative_format_size;
4416         value = -value;
4417     }
4418     QString str = toString(value, 'f', precision == -1 ? d->m_data->m_currency_digits : precision);
4419     QString sym = symbol.isNull() ? currencySymbol() : symbol;
4420     if (sym.isEmpty())
4421         sym = currencySymbol(QLocale::CurrencyIsoCode);
4422     QString format = getLocaleData(currency_format_data + idx, size);
4423     return format.arg(str, sym);
4424 }
4425 
4426 /*!
4427   \fn QString QLocale::toCurrencyString(float i, const QString &symbol) const
4428   \fn QString QLocale::toCurrencyString(float i, const QString &symbol, int precision) const
4429   \overload toCurrencyString()
4430 */
4431 
4432 /*!
4433     \since 5.10
4434 
4435     \enum QLocale::DataSizeFormat
4436 
4437     Specifies the format for representation of data quantities.
4438 
4439     \omitvalue DataSizeBase1000
4440     \omitvalue DataSizeSIQuantifiers
4441     \value DataSizeIecFormat            format using base 1024 and IEC prefixes: KiB, MiB, GiB, ...
4442     \value DataSizeTraditionalFormat    format using base 1024 and SI prefixes: kB, MB, GB, ...
4443     \value DataSizeSIFormat             format using base 1000 and SI prefixes: kB, MB, GB, ...
4444 
4445     \sa formattedDataSize()
4446 */
4447 
4448 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
4449 /*!
4450     \obsolete
4451 
4452     Use the const version instead.
4453 */
formattedDataSize(qint64 bytes,int precision,DataSizeFormats format)4454 QString QLocale::formattedDataSize(qint64 bytes, int precision, DataSizeFormats format)
4455 {
4456     const auto *that = this;
4457     return that->formattedDataSize(bytes, precision, format);
4458 }
4459 #endif
4460 
4461 /*!
4462     \since 5.10
4463 
4464     Converts a size in bytes to a human-readable localized string, comprising a
4465     number and a quantified unit. The quantifier is chosen such that the number
4466     is at least one, and as small as possible. For example if \a bytes is
4467     16384, \a precision is 2, and \a format is \l DataSizeIecFormat (the
4468     default), this function returns "16.00 KiB"; for 1330409069609 bytes it
4469     returns "1.21 GiB"; and so on. If \a format is \l DataSizeIecFormat or
4470     \l DataSizeTraditionalFormat, the given number of bytes is divided by a
4471     power of 1024, with result less than 1024; for \l DataSizeSIFormat, it is
4472     divided by a power of 1000, with result less than 1000.
4473     \c DataSizeIecFormat uses the new IEC standard quantifiers Ki, Mi and so on,
4474     whereas \c DataSizeSIFormat uses the older SI quantifiers k, M, etc., and
4475     \c DataSizeTraditionalFormat abuses them.
4476 */
formattedDataSize(qint64 bytes,int precision,DataSizeFormats format) const4477 QString QLocale::formattedDataSize(qint64 bytes, int precision, DataSizeFormats format) const
4478 {
4479     int power, base = 1000;
4480     if (!bytes) {
4481         power = 0;
4482     } else if (format & DataSizeBase1000) {
4483         power = int(std::log10(qAbs(bytes)) / 3);
4484     } else { // Compute log2(bytes) / 10:
4485         power = int((63 - qCountLeadingZeroBits(quint64(qAbs(bytes)))) / 10);
4486         base = 1024;
4487     }
4488     // Only go to doubles if we'll be using a quantifier:
4489     const QString number = power
4490         ? toString(bytes / std::pow(double(base), power), 'f', qMin(precision, 3 * power))
4491         : toString(bytes);
4492 
4493     // We don't support sizes in units larger than exbibytes because
4494     // the number of bytes would not fit into qint64.
4495     Q_ASSERT(power <= 6 && power >= 0);
4496     QString unit;
4497     if (power > 0) {
4498         quint16 index, size;
4499         if (format & DataSizeSIQuantifiers) {
4500             index = d->m_data->m_byte_si_quantified_idx;
4501             size = d->m_data->m_byte_si_quantified_size;
4502         } else {
4503             index = d->m_data->m_byte_iec_quantified_idx;
4504             size = d->m_data->m_byte_iec_quantified_size;
4505         }
4506         unit = getLocaleListData(byte_unit_data + index, size, power - 1);
4507     } else {
4508         unit = getLocaleData(byte_unit_data + d->m_data->m_byte_idx, d->m_data->m_byte_size);
4509     }
4510 
4511     return number + QLatin1Char(' ') + unit;
4512 }
4513 
4514 /*!
4515     \since 4.8
4516 
4517     Returns an ordered list of locale names for translation purposes in
4518     preference order (like "en-Latn-US", "en-US", "en").
4519 
4520     The return value represents locale names that the user expects to see the
4521     UI translation in.
4522 
4523     Most like you do not need to use this function directly, but just pass the
4524     QLocale object to the QTranslator::load() function.
4525 
4526     The first item in the list is the most preferred one.
4527 
4528     \sa QTranslator, bcp47Name()
4529 */
uiLanguages() const4530 QStringList QLocale::uiLanguages() const
4531 {
4532     QStringList uiLanguages;
4533     QVector<QLocale> locales;
4534 #ifndef QT_NO_SYSTEMLOCALE
4535     if (d->m_data == systemData()) {
4536         QVariant res = systemLocale()->query(QSystemLocale::UILanguages, QVariant());
4537         if (!res.isNull()) {
4538             uiLanguages = res.toStringList();
4539             // ... but we need to include likely-adjusted forms of each of those, too:
4540             for (const auto &entry : qAsConst(uiLanguages))
4541                 locales.append(QLocale(entry));
4542         }
4543         if (locales.isEmpty())
4544             locales.append(systemLocale()->fallbackUiLocale());
4545     } else
4546 #endif
4547     {
4548         locales.append(*this);
4549     }
4550     for (int i = locales.size(); i-- > 0; ) {
4551         const QLocale &locale = locales.at(i);
4552         int j;
4553         QByteArray prior;
4554         if (i < uiLanguages.size()) {
4555             // Adding likely-adjusted forms to system locale's list.
4556             // Name the locale is derived from:
4557             const QString &name = uiLanguages.at(i);
4558             prior = name.toLatin1();
4559             // Don't try to likely-adjust if construction's likely-adjustments
4560             // were so drastic the result doesn't match the prior name:
4561             if (locale.name() != name && locale.d->rawName() != prior)
4562                 continue;
4563             // Insert just after prior:
4564             j = i + 1;
4565         } else {
4566             // Plain locale, not system locale; just append.
4567             j = uiLanguages.size();
4568         }
4569         const auto data = locale.d->m_data;
4570 
4571         QLocaleId id
4572             = QLocaleId::fromIds(data->m_language_id, data->m_script_id, data->m_country_id);
4573         const QLocaleId max = id.withLikelySubtagsAdded();
4574         const QLocaleId min = max.withLikelySubtagsRemoved();
4575         id.script_id = 0; // For re-use as script-less variant.
4576 
4577         // Include version with all likely sub-tags (last) if distinct from the rest:
4578         if (max != min && max != id && max.name() != prior)
4579             uiLanguages.insert(j, QString::fromLatin1(max.name()));
4580 
4581         // Include scriptless version if likely-equivalent and distinct:
4582         if (data->m_script_id && id != min && id.name() != prior
4583             && id.withLikelySubtagsAdded() == max) {
4584             uiLanguages.insert(j, QString::fromLatin1(id.name()));
4585         }
4586 
4587         // Include minimal version (first) unless it's what our locale is derived from:
4588         if (min.name() != prior)
4589             uiLanguages.insert(j, QString::fromLatin1(min.name()));
4590     }
4591     return uiLanguages;
4592 }
4593 
4594 /*!
4595   \since 5.13
4596 
4597   Returns the locale to use for collation.
4598 
4599   The result is usually this locale; however, the system locale (which is
4600   commonly the default locale) will return the system collation locale.
4601   The result is suitable for passing to QCollator's constructor.
4602 
4603   \sa QCollator
4604 */
collation() const4605 QLocale QLocale::collation() const
4606 {
4607 #ifndef QT_NO_SYSTEMLOCALE
4608     if (d->m_data == systemData()) {
4609         QString res = systemLocale()->query(QSystemLocale::Collation, QVariant()).toString();
4610         if (!res.isEmpty())
4611             return QLocale(res);
4612     }
4613 #endif
4614     return *this;
4615 }
4616 
4617 /*!
4618     \since 4.8
4619 
4620     Returns a native name of the language for the locale. For example
4621     "Schwiizertüütsch" for Swiss-German locale.
4622 
4623     \sa nativeCountryName(), languageToString()
4624 */
nativeLanguageName() const4625 QString QLocale::nativeLanguageName() const
4626 {
4627 #ifndef QT_NO_SYSTEMLOCALE
4628     if (d->m_data == systemData()) {
4629         QVariant res = systemLocale()->query(QSystemLocale::NativeLanguageName, QVariant());
4630         if (!res.isNull())
4631             return res.toString();
4632     }
4633 #endif
4634     return getLocaleData(endonyms_data + d->m_data->m_language_endonym_idx,
4635                          d->m_data->m_language_endonym_size);
4636 }
4637 
4638 /*!
4639     \since 4.8
4640 
4641     Returns a native name of the country for the locale. For example
4642     "España" for Spanish/Spain locale.
4643 
4644     \sa nativeLanguageName(), countryToString()
4645 */
nativeCountryName() const4646 QString QLocale::nativeCountryName() const
4647 {
4648 #ifndef QT_NO_SYSTEMLOCALE
4649     if (d->m_data == systemData()) {
4650         QVariant res = systemLocale()->query(QSystemLocale::NativeCountryName, QVariant());
4651         if (!res.isNull())
4652             return res.toString();
4653     }
4654 #endif
4655     return getLocaleData(endonyms_data + d->m_data->m_country_endonym_idx,
4656                          d->m_data->m_country_endonym_size);
4657 }
4658 
4659 #ifndef QT_NO_DEBUG_STREAM
operator <<(QDebug dbg,const QLocale & l)4660 QDebug operator<<(QDebug dbg, const QLocale &l)
4661 {
4662     QDebugStateSaver saver(dbg);
4663     dbg.nospace().noquote()
4664         << "QLocale(" << QLocale::languageToString(l.language())
4665         << ", " << QLocale::scriptToString(l.script())
4666         << ", " << QLocale::countryToString(l.country()) << ')';
4667     return dbg;
4668 }
4669 #endif
4670 QT_END_NAMESPACE
4671 
4672 #ifndef QT_NO_QOBJECT
4673 #include "moc_qlocale.cpp"
4674 #endif
4675