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