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

source code of qtbase/src/corelib/text/qlocale.cpp