Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qlocale.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// Copyright (C) 2021 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:critical reason:data-parser
5
6#include "qglobal.h"
7
8#if defined(Q_CC_GNU_ONLY) && Q_CC_GNU >= 1000
9/* gcc has complained about storing a pointer to a static QLocalePrivate in a
10 QSharedDataPointer, whose destructor would free the non-heap object if the
11 refcount ever got down to zero. The static instances this happens to are
12 instantiated with a refcount of 1 that never gets decremented so as long as
13 QSharedDataPointer keeps its incref()s and decref()s balanced it'll never get
14 down to zero - but the clever compiler isn't quite smart enough to figure
15 that out.
16*/
17QT_WARNING_DISABLE_GCC("-Wfree-nonheap-object") // false positive tracking
18#endif
19
20#if defined(Q_OS_MACOS)
21# include "private/qcore_mac_p.h"
22# include <CoreFoundation/CoreFoundation.h>
23#endif
24
25#include "qplatformdefs.h"
26
27#include "qcalendar.h"
28#include "qdatastream.h"
29#include "qdebug.h"
30#include "private/qduplicatetracker_p.h"
31#include "qhashfunctions.h"
32#include "qstring.h"
34#include "qlocale.h"
35#include "qlocale_p.h"
37#include <private/qtools_p.h>
38#if QT_CONFIG(datetimeparser)
39#include "private/qdatetimeparser_p.h"
40#endif
41#include "qnamespace.h"
42#include "qdatetime.h"
43#include "qstringlist.h"
44#include "qvariant.h"
46#include "qstringbuilder.h"
47#if QT_CONFIG(timezone)
48# include "qtimezone.h"
49#endif
50#include "private/qnumeric_p.h"
51#include "private/qtools_p.h"
52#include <cmath>
53#ifndef QT_NO_SYSTEMLOCALE
54# include "qmutex.h"
55#endif
56#ifdef Q_OS_WIN
57# include <qt_windows.h>
58# include <time.h>
59#endif
60
61#include "private/qcalendarbackend_p.h"
62#include "private/qgregoriancalendar_p.h"
63#if QT_CONFIG(timezone) && QT_CONFIG(timezone_locale) && !QT_CONFIG(icu)
64# include "private/qtimezonelocale_p.h"
65#endif
66#if QT_CONFIG(datestring)
67# include "private/qttemporalpattern_p.h"
68#endif
69
70#include <q20iterator.h>
71
73
74constexpr int QLocale::DefaultTwoDigitBaseYear;
75
76QT_IMPL_METATYPE_EXTERN_TAGGED(QList<Qt::DayOfWeek>, QList_Qt__DayOfWeek)
77#ifndef QT_NO_SYSTEMLOCALE
78QT_IMPL_METATYPE_EXTERN_TAGGED(QSystemLocale::CurrencyToStringArgument,
79 QSystemLocale__CurrencyToStringArgument)
80#endif
81
82using namespace Qt::StringLiterals;
83using namespace QtMiscUtils;
84
85#ifndef QT_NO_SYSTEMLOCALE
86Q_CONSTINIT static QSystemLocale *_systemLocale = nullptr;
87Q_CONSTINIT static QLocaleData systemLocaleData = {};
88#endif
89
90static_assert(ascii_isspace(' '));
91static_assert(ascii_isspace('\t'));
92static_assert(ascii_isspace('\n'));
93static_assert(ascii_isspace('\v'));
94static_assert(ascii_isspace('\f'));
95static_assert(ascii_isspace('\r'));
96static_assert(!ascii_isspace('\0'));
97static_assert(!ascii_isspace('\a'));
98static_assert(!ascii_isspace('a'));
99static_assert(!ascii_isspace('\177'));
100static_assert(!ascii_isspace(uchar('\200')));
101static_assert(!ascii_isspace(uchar('\xA0'))); // NBSP (is a space but Latin 1, not ASCII)
102static_assert(!ascii_isspace(uchar('\377')));
103
104/******************************************************************************
105** Helpers for accessing Qt locale database
106*/
107
108QT_BEGIN_INCLUDE_NAMESPACE
109#include "qlocale_data_p.h"
110QT_END_INCLUDE_NAMESPACE
111
112QLocale::Language QLocalePrivate::codeToLanguage(QStringView code,
113 QLocale::LanguageCodeTypes codeTypes) noexcept
114{
115 const auto len = code.size();
116 if (len != 2 && len != 3)
117 return QLocale::AnyLanguage;
118
119 const char16_t uc1 = code[0].toLower().unicode();
120 const char16_t uc2 = code[1].toLower().unicode();
121 const char16_t uc3 = len > 2 ? code[2].toLower().unicode() : 0;
122
123 // All language codes are ASCII.
124 if (uc1 > 0x7F || uc2 > 0x7F || uc3 > 0x7F)
125 return QLocale::AnyLanguage;
126
127 const AlphaCode codeBuf = { char(uc1), char(uc2), char(uc3) };
128
129 auto searchCode = [codeBuf](auto f) {
130 return std::find_if(languageCodeList.begin(), languageCodeList.end(),
131 [=](LanguageCodeEntry i) { return f(i) == codeBuf; });
132 };
133
134 if (codeTypes.testFlag(QLocale::ISO639Part1) && uc3 == 0) {
135 auto i = searchCode([](LanguageCodeEntry i) { return i.part1; });
136 if (i != languageCodeList.end())
137 return QLocale::Language(std::distance(languageCodeList.begin(), i));
138 }
139
140 if (uc3 != 0) {
141 if (codeTypes.testFlag(QLocale::ISO639Part2B)) {
142 auto i = searchCode([](LanguageCodeEntry i) { return i.part2B; });
143 if (i != languageCodeList.end())
144 return QLocale::Language(std::distance(languageCodeList.begin(), i));
145 }
146
147 // Optimization: Part 2T code if present is always the same as Part 3 code.
148 // This is asserted in iso639_3.LanguageCodeData.
149 if (codeTypes.testFlag(QLocale::ISO639Part2T)
150 && !codeTypes.testFlag(QLocale::ISO639Part3)) {
151 auto i = searchCode([](LanguageCodeEntry i) { return i.part2T; });
152 if (i != languageCodeList.end())
153 return QLocale::Language(std::distance(languageCodeList.begin(), i));
154 }
155
156 if (codeTypes.testFlag(QLocale::ISO639Part3)) {
157 auto i = searchCode([](LanguageCodeEntry i) { return i.part3; });
158 if (i != languageCodeList.end())
159 return QLocale::Language(std::distance(languageCodeList.begin(), i));
160 }
161 }
162
163 if (codeTypes.testFlag(QLocale::LegacyLanguageCode) && uc3 == 0) {
164 constexpr struct LegacyCodes {
165 AlphaCode code;
166 QLocale::Language language;
167 } legacyCodes[] = {
168 { {'n', 'o'}, QLocale::NorwegianBokmal }, // no -> nb
169 { {'t', 'l'}, QLocale::Filipino }, // tl -> fil
170 { {'s', 'h'}, QLocale::Serbian }, // sh -> sr[_Latn]
171 { {'m', 'o'}, QLocale::Romanian }, // mo -> ro
172 // Android uses the following deprecated codes:
173 { {'i', 'w'}, QLocale::Hebrew }, // iw -> he
174 { {'i', 'n'}, QLocale::Indonesian }, // in -> id
175 { {'j', 'i'}, QLocale::Yiddish }, // ji -> yi
176 };
177 // We don't need binary search for seven entries (and they're not
178 // sorted), so search linearly:
179 for (const auto &e : legacyCodes) {
180 if (codeBuf == e.code)
181 return e.language;
182 }
183 }
184 return QLocale::AnyLanguage;
185}
186
187static qsizetype scriptIndex(QStringView code, Qt::CaseSensitivity cs) noexcept
188{
189 if (code.size() != 4)
190 return -1;
191
192 // Scripts are titlecased in script_code_list.
193 const bool fixCase = cs == Qt::CaseInsensitive;
194 const unsigned char c0 = (fixCase ? code[0].toUpper() : code[0]).toLatin1();
195 const unsigned char c1 = (fixCase ? code[1].toLower() : code[1]).toLatin1();
196 const unsigned char c2 = (fixCase ? code[2].toLower() : code[2]).toLatin1();
197 const unsigned char c3 = (fixCase ? code[3].toLower() : code[3]).toLatin1();
198 // Any outside the Latin1 repertoire aren't ASCII => will not match.
199 if (!c0 || !c1 || !c2 || !c3)
200 return -1;
201
202 constexpr qsizetype NumScripts = QLocale::LastScript + 1;
203 static_assert(sizeof(script_code_list) == 4 * NumScripts + 1); // +1 for an extra NUL
204 const unsigned char *c = script_code_list;
205 for (qsizetype i = 0; i < NumScripts; ++i, c += 4) {
206 if (c0 == c[0] && c1 == c[1] && c2 == c[2] && c3 == c[3])
207 return i;
208 }
209 return -1;
210}
211
212QLocale::Script QLocalePrivate::codeToScript(QStringView code) noexcept
213{
214 qsizetype index = scriptIndex(code, Qt::CaseInsensitive);
215 return index < 0 ? QLocale::AnyScript : QLocale::Script(index);
216}
217
218QLocale::Territory QLocalePrivate::codeToTerritory(QStringView code) noexcept
219{
220 const auto len = code.size();
221 if (len != 2 && len != 3)
222 return QLocale::AnyTerritory;
223
224 char16_t uc1 = code[0].toUpper().unicode();
225 char16_t uc2 = code[1].toUpper().unicode();
226 char16_t uc3 = len > 2 ? code[2].toUpper().unicode() : 0;
227
228 const unsigned char *c = territory_code_list;
229 for (; *c != 0; c += 3) {
230 if (uc1 == c[0] && uc2 == c[1] && uc3 == c[2])
231 return QLocale::Territory((c - territory_code_list)/3);
232 }
233
234 return QLocale::AnyTerritory;
235}
236
237std::array<char, 4> QLocalePrivate::languageToCode(QLocale::Language language,
238 QLocale::LanguageCodeTypes codeTypes)
239{
240 if (language == QLocale::AnyLanguage || language > QLocale::LastLanguage)
241 return {};
242 if (language == QLocale::C)
243 return {'C'};
244
245 const LanguageCodeEntry &i = languageCodeList[language];
246
247 if (codeTypes.testFlag(QLocale::ISO639Part1) && i.part1.isValid())
248 return i.part1.decode();
249
250 if (codeTypes.testFlag(QLocale::ISO639Part2B) && i.part2B.isValid())
251 return i.part2B.decode();
252
253 if (codeTypes.testFlag(QLocale::ISO639Part2T) && i.part2T.isValid())
254 return i.part2T.decode();
255
256 if (codeTypes.testFlag(QLocale::ISO639Part3))
257 return i.part3.decode();
258
259 return {};
260}
261
262QLatin1StringView QLocalePrivate::scriptToCode(QLocale::Script script)
263{
264 if (script == QLocale::AnyScript || script > QLocale::LastScript)
265 return {};
266 const unsigned char *c = script_code_list + 4 * script;
267 return {reinterpret_cast<const char *>(c), 4};
268}
269
270QLatin1StringView QLocalePrivate::territoryToCode(QLocale::Territory territory)
271{
272 if (territory == QLocale::AnyTerritory || territory > QLocale::LastTerritory)
273 return {};
274
275 const unsigned char *c = territory_code_list + 3 * territory;
276 return {reinterpret_cast<const char*>(c), c[2] == 0 ? 2 : 3};
277}
278
279namespace {
280struct LikelyPair
281{
282 QLocaleId key; // Search key.
283 QLocaleId value = QLocaleId { 0, 0, 0 };
284};
285
286bool operator<(LikelyPair lhs, LikelyPair rhs)
287{
288 // Must match the comparison LocaleDataWriter.likelySubtags() uses when
289 // sorting, see qtbase/util/locale_database.qlocalexml2cpp.py
290 const auto compare = [](int lhs, int rhs) {
291 // 0 sorts after all other values; lhs and rhs are passed ushort values.
292 const int huge = 0x10000;
293 return (lhs ? lhs : huge) - (rhs ? rhs : huge);
294 };
295 const auto &left = lhs.key;
296 const auto &right = rhs.key;
297 // Comparison order: language, region, script:
298 if (int cmp = compare(left.language_id, right.language_id))
299 return cmp < 0;
300 if (int cmp = compare(left.territory_id, right.territory_id))
301 return cmp < 0;
302 return compare(left.script_id, right.script_id) < 0;
303}
304} // anonymous namespace
305
306/*!
307 \internal
308 Fill in blank fields of a locale ID.
309
310 An ID in which some fields are zero stands for any locale that agrees with
311 it in its non-zero fields. CLDR's likely-subtag data is meant to help us
312 chose which candidate to prefer. (Note, however, that CLDR does have some
313 cases where it maps an ID to a "best match" for which CLDR does not provide
314 data, even though there are locales for which CLDR does provide data that do
315 match the given ID. It's telling us, unhelpfully but truthfully, what
316 locale would (most likely) be meant by (someone using) the combination
317 requested, even when that locale isn't yet supported.) It may also map an
318 obsolete or generic tag to a modern or more specific replacement, possibly
319 filling in some of the other fields in the process (presently only for
320 countries). Note that some fields of the result may remain blank, but there
321 is no more specific recommendation available.
322
323 For the formal specification, see
324 https://www.unicode.org/reports/tr35/#Likely_Subtags
325
326 \note We also search und_script_region and und_region; they're not mentioned
327 in the spec, but the examples clearly presume them and CLDR does provide
328 such likely matches.
329*/
331{
332 /* Each pattern that appears in a comments below, language_script_region and
333 similar, indicates which of this's fields (even if blank) are being
334 attended to in a given search; for fields left out of the pattern, the
335 search uses 0 regardless of whether this has specified the field.
336
337 If a key matches what we're searching for (possibly with a wildcard in
338 the key matching a non-wildcard in our search), the tags from this that
339 are specified in the key are replaced by the match (even if different);
340 but the other tags of this replace what's in the match (even when the
341 match does specify a value).
342
343 Keep QLocaleXmlReader.__fillLikely() in sync with this, to ensure
344 locale-appropriate time-zone naming works correctly.
345 */
346 static_assert(std::size(likely_subtags) % 2 == 0);
347 auto *pairs = reinterpret_cast<const LikelyPair *>(likely_subtags);
348 auto *const afterPairs = pairs + std::size(likely_subtags) / 2;
349 LikelyPair sought { *this };
350 // Our array is sorted in the order that puts all candidate matches in the
351 // order we would want them; ones we should prefer appear before the others.
352 if (language_id) {
353 // language_script_region, language_region, language_script, language:
354 pairs = std::lower_bound(pairs, afterPairs, sought);
355 // Single language's block isn't long enough to warrant more binary
356 // chopping within it - just traverse it all:
357 for (; pairs < afterPairs && pairs->key.language_id == language_id; ++pairs) {
358 const QLocaleId &key = pairs->key;
360 continue;
361 if (key.script_id && key.script_id != script_id)
362 continue;
363 QLocaleId value = pairs->value;
364 if (territory_id && !key.territory_id)
366 if (script_id && !key.script_id)
367 value.script_id = script_id;
368 return value;
369 }
370 }
371 // und_script_region or und_region (in that order):
372 if (territory_id) {
373 sought.key = QLocaleId { 0, script_id, territory_id };
374 pairs = std::lower_bound(pairs, afterPairs, sought);
375 // Again, individual und_?_region block isn't long enough to make binary
376 // chop a win:
377 for (; pairs < afterPairs && pairs->key.territory_id == territory_id; ++pairs) {
378 const QLocaleId &key = pairs->key;
379 Q_ASSERT(!key.language_id);
380 if (key.script_id && key.script_id != script_id)
381 continue;
382 QLocaleId value = pairs->value;
383 if (language_id)
385 if (script_id && !key.script_id)
386 value.script_id = script_id;
387 return value;
388 }
389 }
390 // und_script:
391 if (script_id) {
392 sought.key = QLocaleId { 0, script_id, 0 };
393 pairs = std::lower_bound(pairs, afterPairs, sought);
394 if (pairs < afterPairs && pairs->key.script_id == script_id) {
395 Q_ASSERT(!pairs->key.language_id && !pairs->key.territory_id);
396 QLocaleId value = pairs->value;
397 if (language_id)
399 if (territory_id)
401 return value;
402 }
403 }
404 // Finally, fall back to the match-all rule (if there is one):
405 pairs = afterPairs - 1; // All other keys are < match-all.
406 if (pairs->key.matchesAll()) {
407 QLocaleId value = pairs->value;
408 if (language_id)
410 if (territory_id)
412 if (script_id)
413 value.script_id = script_id;
414 return value;
415 }
416 return *this;
417}
418
420{
422 // language
423 {
424 QLocaleId id { language_id, 0, 0 };
426 return id;
427 }
428 // language_region
429 if (territory_id) {
432 return id;
433 }
434 // language_script
435 if (script_id) {
438 return id;
439 }
440 return max;
441}
442
443QByteArray QLocaleId::name(char separator) const
444{
445 if (language_id == QLocale::AnyLanguage)
446 return QByteArray();
447 if (language_id == QLocale::C)
448 return QByteArrayLiteral("C");
449 Q_ASSERT(language_id <= QLocale::LastLanguage);
450 Q_ASSERT(script_id <= QLocale::LastScript);
451 Q_ASSERT(territory_id <= QLocale::LastTerritory);
452
453 const LanguageCodeEntry &language = languageCodeList[language_id];
454 AlphaCode lang;
455 qsizetype langLen;
456
457 if (language.part1.isValid()) {
458 lang = language.part1;
459 langLen = 2;
460 } else {
461 lang = language.part2B.isValid() ? language.part2B : language.part3;
462 langLen = 3;
463 }
464
465 const unsigned char *script =
466 (script_id != QLocale::AnyScript ? script_code_list + 4 * script_id : nullptr);
467 const unsigned char *country =
468 (territory_id != QLocale::AnyTerritory
469 ? territory_code_list + 3 * territory_id : nullptr);
470 qsizetype len = langLen + (script ? 4 + 1 : 0) + (country ? (country[2] != 0 ? 3 : 2) + 1 : 0);
471 QByteArray name(len, Qt::Uninitialized);
472 char *uc = name.data();
473
474 auto langArray = lang.decode();
475
476 *uc++ = langArray[0];
477 *uc++ = langArray[1];
478 if (langLen > 2)
479 *uc++ = langArray[2];
480
481 if (script) {
482 *uc++ = separator;
483 *uc++ = script[0];
484 *uc++ = script[1];
485 *uc++ = script[2];
486 *uc++ = script[3];
487 }
488 if (country) {
489 *uc++ = separator;
490 *uc++ = country[0];
491 *uc++ = country[1];
492 if (country[2] != 0)
493 *uc++ = country[2];
494 }
495 return name;
496}
497
498QByteArray QLocalePrivate::bcp47Name(char separator) const
499{
500 if (m_data->m_language_id == QLocale::AnyLanguage)
501 return QByteArray();
502 if (m_data->m_language_id == QLocale::C)
503 return QByteArrayView("en") % separator % QByteArrayView("POSIX");
504
505 return m_data->id().withLikelySubtagsRemoved().name(separator);
506}
507
508static qsizetype findLocaleIndexById(QLocaleId localeId) noexcept
509{
510 qsizetype idx = locale_index[localeId.language_id];
511 // If there are no locales for specified language (so we we've got the
512 // default language, which has no associated script or country), give up:
513 if (localeId.language_id && idx == 0)
514 return idx;
515
516 Q_ASSERT(localeId.acceptLanguage(locale_data[idx].m_language_id));
517
518 do {
519 if (localeId.acceptScriptTerritory(locale_data[idx].id()))
520 return idx;
521 ++idx;
522 } while (localeId.acceptLanguage(locale_data[idx].m_language_id));
523
524 return -1;
525}
526
527static constexpr qsizetype locale_data_size = q20::ssize(locale_data) - 1; // trailing guard
528bool QLocaleData::allLocaleDataRows(bool (*check)(qsizetype, const QLocaleData &))
529{
530 for (qsizetype index = 0; index < locale_data_size; ++index) {
531 if (!(*check)(index, locale_data[index]))
532 return false;
533 }
534 return true;
535}
536
537// Internal: to enable tst_qlocaledata to access locales
538const QLocaleData *QLocaleData::dataForLocaleIndex(qsizetype index)
539{
540 Q_PRE(index >= 0);
541 Q_PRE(index < locale_data_size);
542 return locale_data + index;
543}
544
545#if QT_CONFIG(timezone) && QT_CONFIG(timezone_locale) && !QT_CONFIG(icu)
546namespace QtTimeZoneLocale {
547
548// Indices of locales obtained from the given by likely subtag fall-backs.
549QList<qsizetype> fallbackLocalesFor(qsizetype index)
550{
551 // Should match QLocaleXmlReader.pruneZoneNaming()'s fallbacks() helper,
552 // aside from the special-case kludge for C -> en_US.
553 Q_ASSERT(index < locale_data_size);
554 QList<qsizetype> result = {index};
555 QLocaleId id = locale_data[index].id();
556 if (id.language_id == QLocale::C) {
557 id = { QLocale::English, QLocale::LatinScript, QLocale::UnitedStates };
558 qsizetype it = findLocaleIndexById(id);
559 Q_ASSERT_X(it != -1, Q_FUNC_INFO, "Missing en_Latn_US from locale data");
560 Q_ASSERT_X(it != index, // equivalent to !result.contains(it)
561 Q_FUNC_INFO, "en_Latn_US != C");
562 result << it;
563 }
564
565 const QLocaleId base = id;
566 QLocaleId likely = id.withLikelySubtagsAdded();
567 if (likely != base) {
568 qsizetype it = findLocaleIndexById(likely);
569 if (it != -1 && !result.contains(it))
570 result << it;
571 }
572 if (id.territory_id) {
573 id.territory_id = 0;
574 likely = id.withLikelySubtagsAdded();
575 if (likely != base) {
576 qsizetype it = findLocaleIndexById(likely);
577 if (it != -1 && !result.contains(it))
578 result << it;
579 }
580 }
581 if (id.script_id) {
582 id.script_id = 0;
583 likely = id.withLikelySubtagsAdded();
584 if (likely != base) {
585 qsizetype it = findLocaleIndexById(likely);
586 if (it != -1 && !result.contains(it))
587 result << it;
588 }
589 }
590 return result;
591}
592
593} // QtTimeZoneLocale
594#endif // timezone_locale && !icu
595
596qsizetype QLocaleData::findLocaleIndex(QLocaleId lid) noexcept
597{
598 QLocaleId localeId = lid;
599 QLocaleId likelyId = localeId.withLikelySubtagsAdded();
600 const ushort fallback = likelyId.language_id;
601
602 // Try a straight match with the likely data:
603 qsizetype index = findLocaleIndexById(likelyId);
604 if (index >= 0)
605 return index;
606 QVarLengthArray<QLocaleId, 6> tried;
607 tried.push_back(likelyId);
608
609#define CheckCandidate(id) do {
610 if (!tried.contains(id)) {
611 index = findLocaleIndexById(id);
612 if (index >= 0)
613 return index;
614 tried.push_back(id);
615 }
616 } while (false) // end CheckCandidate
617
618 // No match; try again with raw data:
619 CheckCandidate(localeId);
620
621 // No match; try again with likely country for language_script
622 if (lid.territory_id && (lid.language_id || lid.script_id)) {
623 localeId.territory_id = 0;
624 likelyId = localeId.withLikelySubtagsAdded();
625 CheckCandidate(likelyId);
626
627 // No match; try again with any country
628 CheckCandidate(localeId);
629 }
630
631 // No match; try again with likely script for language_region
632 if (lid.script_id && (lid.language_id || lid.territory_id)) {
633 localeId = QLocaleId { lid.language_id, 0, lid.territory_id };
634 likelyId = localeId.withLikelySubtagsAdded();
635 CheckCandidate(likelyId);
636
637 // No match; try again with any script
638 CheckCandidate(localeId);
639 }
640#undef CheckCandidate
641
642 // No match; return base index for initial likely language:
643 return locale_index[fallback];
644}
645
646static QStringView findTag(QStringView name) noexcept
647{
648 const std::u16string_view v(name.utf16(), size_t(name.size()));
649 const auto i = v.find_first_of(u"_-.@");
650 if (i == std::string_view::npos)
651 return name;
652 return name.first(qsizetype(i));
653}
654
655static bool validTag(QStringView tag)
656{
657 // Is tag is a non-empty sequence of ASCII letters and/or digits ?
658 for (QChar uc : tag) {
659 const char16_t ch = uc.unicode();
660 if (!isAsciiLetterOrNumber(ch))
661 return false;
662 }
663 return tag.size() > 0;
664}
665
666bool qt_splitLocaleName(QStringView name,
667 QStringView *lang, QStringView *script, QStringView *land) noexcept
668{
669 // Assume each of lang, script and land is nullptr or points to an empty QStringView.
670 enum ParserState { NoState, LangState, ScriptState, CountryState };
671 ParserState state = LangState;
672 while (name.size() && state != NoState) {
673 const QStringView tag = findTag(name);
674 if (!validTag(tag))
675 break;
676 name = name.sliced(tag.size());
677 const bool sep = name.size() > 0;
678 if (sep) // tag wasn't all that remained; there was a separator
679 name = name.sliced(1);
680
681 switch (state) {
682 case LangState:
683 if (tag.size() != 2 && tag.size() != 3)
684 return false;
685 if (lang)
686 *lang = tag;
687 state = sep ? ScriptState : NoState;
688 break;
689 case ScriptState:
690 if (scriptIndex(tag, Qt::CaseSensitive) >= 0) {
691 if (script)
692 *script = tag;
693 state = sep ? CountryState : NoState;
694 break;
695 }
696 // It wasn't a script, assume it's a country.
697 Q_FALLTHROUGH();
698 case CountryState:
699 if (land)
700 *land = tag;
701 state = NoState;
702 break;
703 case NoState: // Precluded by loop condition !
704 Q_UNREACHABLE();
705 break;
706 }
707 }
708 return state != LangState;
709}
710
711QLocaleId QLocaleId::fromName(QStringView name) noexcept
712{
713 QStringView lang;
714 QStringView script;
715 QStringView land;
716 if (!qt_splitLocaleName(name, &lang, &script, &land))
717 return { QLocale::C, 0, 0 };
718
719 // POSIX is a variant, but looks like a territory.
720 if (land.compare("POSIX", Qt::CaseInsensitive) == 0)
721 return { QLocale::C, 0, 0 };
722
723 QLocale::Language langId = QLocalePrivate::codeToLanguage(lang);
724 if (langId == QLocale::AnyLanguage)
725 return { QLocale::C, 0, 0 };
726 return { langId, QLocalePrivate::codeToScript(script), QLocalePrivate::codeToTerritory(land) };
727}
728
729QString qt_readEscapedFormatString(QStringView format, qsizetype *idx)
730{
731 qsizetype &i = *idx;
732
733 Q_ASSERT(format.at(i) == u'\'');
734 ++i;
735 if (i == format.size())
736 return QString();
737 if (format.at(i).unicode() == '\'') { // "''" outside of a quoted string
738 ++i;
739 return "'"_L1;
740 }
741
742 QString result;
743
744 while (i < format.size()) {
745 if (format.at(i).unicode() == '\'') {
746 if (format.mid(i + 1).startsWith(u'\'')) {
747 // "''" inside a quoted string
748 result.append(u'\'');
749 i += 2;
750 } else {
751 break;
752 }
753 } else {
754 result.append(format.at(i++));
755 }
756 }
757 if (i < format.size())
758 ++i;
759
760 return result;
761}
762
763Q_CONSTINIT static const QLocaleData *default_data = nullptr;
764Q_CONSTINIT QBasicAtomicInt QLocalePrivate::s_generation = Q_BASIC_ATOMIC_INITIALIZER(0);
765
766static QLocalePrivate *c_private() noexcept
767{
768 Q_CONSTINIT static QLocalePrivate c_locale(locale_data, 0, QLocale::OmitGroupSeparator, 1);
769 return &c_locale;
770}
771
772static constexpr QLocale::NumberOptions defaultNumberOptions(QLocale::Language forLanguage)
773{
774 return forLanguage == QLocale::C ? QLocale::OmitGroupSeparator : QLocale::DefaultNumberOptions;
775}
776
777static constexpr QLocale::NumberOptions defaultNumberOptions(quint16 forLanguage)
778{
779 return defaultNumberOptions(QLocale::Language(forLanguage));
780}
781
782#ifndef QT_NO_SYSTEMLOCALE
783/******************************************************************************
784** Default system locale behavior
785*/
786
787/*!
788 \internal
789 Constructs a QSystemLocale object.
790
791 The constructor will automatically install this object as the system locale.
792 It and the destructor maintain a stack of system locales, with the
793 most-recently-created instance (that hasn't yet been deleted) used as the
794 system locale. This is only intended as a way to let a platform plugin
795 install its own system locale, overriding what might otherwise be provided
796 for its class of platform (as Android does, differing from Linux), and to
797 let tests transiently override the system or plugin-supplied one. As such,
798 there should not be diverse threads creating and destroying QSystemLocale
799 instances concurrently, so no attempt is made at thread-safety in managing
800 the stack.
801
802 This constructor also resets the flag that'll prompt QLocale::system() to
803 re-initialize its data, so that instantiating a QSystemLocale (even
804 transiently) triggers a refresh of the system locale's data. This is
805 exploited by some test code.
806*/
807QSystemLocale::QSystemLocale() : next(_systemLocale)
808{
809 _systemLocale = this;
810
811 systemLocaleData.m_language_id = 0;
812}
813
814/*!
815 \internal
816 Deletes the object.
817*/
818QSystemLocale::~QSystemLocale()
819{
820 if (_systemLocale == this) {
821 _systemLocale = next;
822
823 // Change to system locale => force refresh.
824 systemLocaleData.m_language_id = 0;
825 } else {
826 for (QSystemLocale *p = _systemLocale; p; p = p->next) {
827 if (p->next == this)
828 p->next = next;
829 }
830 }
831}
832
834{
835 if (_systemLocale)
836 return _systemLocale;
837
838 // As this is only ever instantiated with _systemLocale null, it is
839 // necessarily the ->next-most in any chain that may subsequently develop;
840 // and it won't be destructed until exit()-time.
841 static QSystemLocale globalInstance;
842 return &globalInstance;
843}
844
846{
847 // This function is NOT thread-safe!
848 // It *should not* be called by anything but systemData()
849 // It *is* called before {system,default}LocalePrivate exist.
850 const QSystemLocale *sys_locale = systemLocale();
851
852 // tell the object that the system locale has changed.
853 sys_locale->query(QSystemLocale::LocaleChanged);
854
855 // Populate system locale with fallback as basis
856 systemLocaleData = locale_data[sys_locale->fallbackLocaleIndex()];
857
858 QVariant res = sys_locale->query(QSystemLocale::LanguageId);
859 if (!res.isNull()) {
860 systemLocaleData.m_language_id = res.toInt();
861 systemLocaleData.m_script_id = QLocale::AnyScript; // default for compatibility
862 }
863 res = sys_locale->query(QSystemLocale::TerritoryId);
864 if (!res.isNull()) {
865 systemLocaleData.m_territory_id = res.toInt();
866 systemLocaleData.m_script_id = QLocale::AnyScript; // default for compatibility
867 }
868 res = sys_locale->query(QSystemLocale::ScriptId);
869 if (!res.isNull())
870 systemLocaleData.m_script_id = res.toInt();
871
872 // Should we replace Any values based on likely sub-tags ?
873
874 // If system locale is default locale, update the default collator's generation:
875 if (default_data == &systemLocaleData)
876 QLocalePrivate::s_generation.fetchAndAddRelaxed(1);
877}
878#endif // !QT_NO_SYSTEMLOCALE
879
880static const QLocaleData *systemData(qsizetype *sysIndex = nullptr)
881{
882#ifndef QT_NO_SYSTEMLOCALE
883 /*
884 Copy over the information from the fallback locale and modify.
885
886 If sysIndex is passed, it should be the m_index of the system locale's
887 QLocalePrivate, which we'll update if it needs it.
888
889 This modifies (cross-thread) global state, so is mutex-protected.
890 */
891 {
892 Q_CONSTINIT static QLocaleId sysId;
893 bool updated = false;
894
895 Q_CONSTINIT static QBasicMutex systemDataMutex;
896 systemDataMutex.lock();
897 if (systemLocaleData.m_language_id == 0) {
898 updateSystemPrivate();
899 updated = true;
900 }
901 // Initialization of system private has *sysIndex == -1 to hit this.
902 if (sysIndex && (updated || *sysIndex < 0)) {
903 const QLocaleId nowId = systemLocaleData.id();
904 if (sysId != nowId || *sysIndex < 0) {
905 // This look-up may be expensive:
906 *sysIndex = QLocaleData::findLocaleIndex(nowId);
907 sysId = nowId;
908 }
909 }
910 systemDataMutex.unlock();
911 }
912
913 return &systemLocaleData;
914#else
915 Q_UNUSED(sysIndex);
916 return locale_data;
917#endif
918}
919
921{
922 if (!default_data)
923 default_data = systemData();
924 return default_data;
925}
926
928{
929 const QLocaleData *const data = defaultData();
930#ifndef QT_NO_SYSTEMLOCALE
931 if (data == &systemLocaleData) {
932 // Work out a suitable index matching the system data, for use when
933 // accessing calendar data, when not fetched from system.
934 return QLocaleData::findLocaleIndex(data->id());
935 }
936#endif
937
938 using QtPrivate::q_points_into_range;
939 Q_ASSERT(q_points_into_range(data, locale_data));
940 return data - locale_data;
941}
942
943const QLocaleData *QLocaleData::c() noexcept
944{
945 Q_ASSERT(locale_index[QLocale::C] == 0);
946 return locale_data;
947}
948
949#ifndef QT_NO_DATASTREAM
950QDataStream &operator<<(QDataStream &ds, const QLocale &l)
951{
952 ds << l.name();
953 return ds;
954}
955
956QDataStream &operator>>(QDataStream &ds, QLocale &l)
957{
958 QString s;
959 ds >> s;
960 l = QLocale(s);
961 return ds;
962}
963#endif // QT_NO_DATASTREAM
964
965Q_GLOBAL_STATIC(QSharedDataPointer<QLocalePrivate>, defaultLocalePrivate,
966 new QLocalePrivate(defaultData(), defaultIndex(),
967 defaultNumberOptions(defaultData()->m_language_id)))
968
969static QLocalePrivate *localePrivateByName(QStringView name)
970{
971 if (name == u"C")
972 return c_private();
973 const qsizetype index = QLocaleData::findLocaleIndex(QLocaleId::fromName(name));
974 return new QLocalePrivate(QLocaleData::dataForLocaleIndex(index), index,
975 defaultNumberOptions(locale_data[index].m_language_id));
976}
977
978static QLocalePrivate *findLocalePrivate(QLocale::Language language, QLocale::Script script,
979 QLocale::Territory territory)
980{
981 if (language == QLocale::C)
982 return c_private();
983
984 qsizetype index = QLocaleData::findLocaleIndex(QLocaleId { language, script, territory });
985 const QLocaleData *data = QLocaleData::dataForLocaleIndex(index);
986
987 QLocale::NumberOptions numberOptions = QLocale::DefaultNumberOptions;
988
989 // If not found, should use default locale:
990 if (data->m_language_id == QLocale::C) {
991 if (defaultLocalePrivate.exists())
992 numberOptions = defaultLocalePrivate->data()->m_numberOptions;
993 data = defaultData();
994 index = defaultIndex();
995 }
996 return new QLocalePrivate(data, index, numberOptions);
997}
998
999bool comparesEqual(const QLocale &loc, QLocale::Language lang)
1000{
1001 // Keep in sync with findLocalePrivate()!
1002 auto compareWithPrivate = [&loc](const QLocaleData *data, QLocale::NumberOptions opts)
1003 {
1004 return loc.d->m_data == data && loc.d->m_numberOptions == opts;
1005 };
1006
1007 if (lang == QLocale::C)
1008 return compareWithPrivate(c_private()->m_data, c_private()->m_numberOptions);
1009
1010 qsizetype index = QLocaleData::findLocaleIndex(QLocaleId { lang });
1011 const QLocaleData *data = QLocaleData::dataForLocaleIndex(index);
1012
1013 QLocale::NumberOptions numberOptions = QLocale::DefaultNumberOptions;
1014
1015 // If not found, should use default locale:
1016 if (data->m_language_id == QLocale::C) {
1017 if (defaultLocalePrivate.exists())
1018 numberOptions = defaultLocalePrivate->data()->m_numberOptions;
1019 data = defaultData();
1020 }
1021 return compareWithPrivate(data, numberOptions);
1022}
1023
1024static std::optional<QString>
1025systemLocaleString(const QLocaleData *that, QSystemLocale::QueryType type)
1026{
1027#ifndef QT_NO_SYSTEMLOCALE
1028 if (that != &systemLocaleData)
1029 return std::nullopt;
1030
1031 QVariant v = systemLocale()->query(type);
1032 if (v.metaType() != QMetaType::fromType<QString>())
1033 return std::nullopt;
1034
1035 return v.toString();
1036#else
1037 Q_UNUSED(that)
1038 Q_UNUSED(type)
1039 return std::nullopt;
1040#endif
1041}
1042
1043static QString localeString(const QLocaleData *that, QSystemLocale::QueryType type,
1044 QLocaleData::DataRange range)
1045{
1046 if (auto opt = systemLocaleString(that, type))
1047 return *opt;
1048 return range.getData(single_character_data);
1049}
1050
1052{
1053 return localeString(this, QSystemLocale::DecimalPoint, decimalSeparator());
1054}
1055
1057{
1058 return localeString(this, QSystemLocale::GroupSeparator, groupDelim());
1059}
1060
1061QString QLocaleData::percentSign() const
1062{
1063 return percent().getData(single_character_data);
1064}
1065
1067{
1068 return listDelimit().getData(single_character_data);
1069}
1070
1071QString QLocaleData::zeroDigit() const
1072{
1073 return localeString(this, QSystemLocale::ZeroDigit, zero());
1074}
1075
1076char32_t QLocaleData::zeroUcs() const
1077{
1078#ifndef QT_NO_SYSTEMLOCALE
1079 if (this == &systemLocaleData) {
1080 const auto text = systemLocale()->query(QSystemLocale::ZeroDigit).toString();
1081 if (!text.isEmpty()) {
1082 if (text.size() == 1 && !text.at(0).isSurrogate())
1083 return text.at(0).unicode();
1084 if (text.size() == 2 && text.at(0).isHighSurrogate())
1085 return QChar::surrogateToUcs4(text.at(0), text.at(1));
1086 }
1087 }
1088#endif
1090}
1091
1093{
1094 return localeString(this, QSystemLocale::NegativeSign, minus());
1095}
1096
1098{
1099 return localeString(this, QSystemLocale::PositiveSign, plus());
1100}
1101
1103{
1104 return exponential().getData(single_character_data);
1105}
1106
1108{
1109#ifndef QT_NO_SYSTEMLOCALE
1110 if (this == &systemLocaleData) {
1111 QVariant queryResult = systemLocale()->query(QSystemLocale::Grouping);
1112 if (!queryResult.isNull()) {
1113 QLocaleData::GroupSizes sysGroupSizes =
1114 queryResult.value<QLocaleData::GroupSizes>();
1115 if (sysGroupSizes.first <= 0)
1116 sysGroupSizes.first = m_grouping_first;
1117 if (sysGroupSizes.higher <= 0)
1118 sysGroupSizes.higher = m_grouping_higher;
1119 if (sysGroupSizes.least <= 0)
1120 sysGroupSizes.least = m_grouping_least;
1121 return sysGroupSizes;
1122 }
1123 }
1124#endif
1125 return { m_grouping_first,
1126 m_grouping_higher,
1127 m_grouping_least };
1128}
1129
1130/*!
1131 \internal
1132*/
1133QLocale::QLocale(QLocalePrivate &dd)
1134 // If this ever becomes explicitly noexcept(false),
1135 // adjust QLocale::c() to not use this ctor anymore.
1136 : d(&dd)
1137{}
1138
1139/*!
1140 \variable QLocale::DefaultTwoDigitBaseYear
1141 \since 6.7
1142
1143 \brief The default start year of the century within which a format taking
1144 a two-digit year will select. The value of the constant is \c {1900}.
1145
1146 Some locales use, particularly for ShortFormat, only the last two digits of
1147 the year. Proir to 6.7 the year 1900 was always used as a base year for
1148 such cases. Now various QLocale and QDate functions have the overloads that
1149 allow callers to specify the base year, and this constant is used as its
1150 default value.
1151
1152 \sa toDate(), toDateTime(), QDate::fromString(), QDateTime::fromString()
1153*/
1154
1155/*!
1156 \since 6.3
1157
1158 Constructs a QLocale object with the specified \a name.
1159
1160 The name has the format "language[_script][_territory][.codeset][@modifier]"
1161 or "C", where:
1162
1163 \list
1164 \li language is a lowercase, two-letter, ISO 639 language code (some
1165 three-letter codes are also recognized),
1166 \li script is a capitalized, four-letter, ISO 15924 script code,
1167 \li territory is an uppercase, two-letter, ISO 3166 territory code
1168 (some numeric codes are also recognized), and
1169 \li codeset and modifier are ignored.
1170 \endlist
1171
1172 The separator can be either underscore \c{'_'} (U+005F, "low line") or a
1173 dash \c{'-'} (U+002D, "hyphen-minus"). If QLocale has no data for the
1174 specified combination of language, script, and territory, then it uses the
1175 most suitable match it can find instead. If the string violates the locale
1176 format, or no suitable data can be found for the specified keys, the "C"
1177 locale is used instead.
1178
1179 This constructor is much slower than QLocale(Language, Script, Territory) or
1180 QLocale(Language, Territory).
1181
1182 \sa bcp47Name(), {Matching combinations of language, script and territory}
1183*/
1184QLocale::QLocale(QStringView name)
1185 : d(localePrivateByName(name))
1186{
1187}
1188
1189/*!
1190 \fn QLocale::QLocale(const QString &name)
1191 \overload
1192*/
1193
1194/*!
1195 Constructs a QLocale object initialized with the default locale.
1196
1197 If no default locale was set using setDefault(), this locale will be the
1198 same as the one returned by system().
1199
1200 \sa setDefault(), system()
1201*/
1202
1203QLocale::QLocale()
1204 : d(c_private())
1205{
1206 if (!defaultLocalePrivate.isDestroyed()) {
1207 // Make sure system data is up to date:
1208 systemData();
1209 d = *defaultLocalePrivate;
1210 }
1211}
1212
1213/*!
1214 Constructs a QLocale object for the specified \a language and \a territory.
1215
1216 If there is more than one script in use for this combination, a likely
1217 script will be selected. If QLocale has no data for the specified \a
1218 language, the default locale is used. If QLocale has no data for the
1219 specified combination of \a language and \a territory, an alternative
1220 territory may be used instead.
1221
1222 \sa setDefault(), {Matching combinations of language, script and territory}
1223*/
1224
1225QLocale::QLocale(Language language, Territory territory)
1226 : d(findLocalePrivate(language, AnyScript, territory))
1227{
1228}
1229
1230/*!
1231 \since 4.8
1232
1233 Constructs a QLocale object for the specified \a language, \a script and \a
1234 territory.
1235
1236 If QLocale does not have data for the given combination, it will find data
1237 for as good a match as it can. It falls back on the default locale if
1238
1239 \list
1240 \li \a language is \c AnyLanguage and no language can be inferred from \a
1241 script and \a territory
1242 \li QLocale has no data for the language, either given as \a language or
1243 inferred as above.
1244 \endlist
1245
1246 \sa setDefault(), {Matching combinations of language, script and territory}
1247*/
1248
1249QLocale::QLocale(Language language, Script script, Territory territory)
1250 : d(findLocalePrivate(language, script, territory))
1251{
1252}
1253
1254/*!
1255 Constructs a QLocale object as a copy of \a other.
1256*/
1257
1258QLocale::QLocale(const QLocale &other) noexcept = default;
1259
1260/*!
1261 Destructor
1262*/
1263
1264QLocale::~QLocale()
1265{
1266}
1267
1268/*!
1269 Assigns \a other to this QLocale object and returns a reference
1270 to this QLocale object.
1271*/
1272
1273QLocale &QLocale::operator=(const QLocale &other) noexcept = default;
1274
1275/*!
1276 \internal
1277 Equality comparison.
1278*/
1279
1280bool QLocale::equals(const QLocale &other) const noexcept
1281{
1282 return d->m_data == other.d->m_data && d->m_numberOptions == other.d->m_numberOptions;
1283}
1284
1285/*!
1286 \fn void QLocale::swap(QLocale &other)
1287 \since 5.6
1288 \memberswap{locale}
1289*/
1290
1291/*!
1292 \since 5.6
1293 \qhashold{QLocale}
1294*/
1295size_t qHash(const QLocale &key, size_t seed) noexcept
1296{
1297 return qHashMulti(seed, key.d->m_data, key.d->m_numberOptions);
1298}
1299
1300/*!
1301 \since 4.2
1302
1303 Sets the \a options related to number conversions for this QLocale instance.
1304
1305 \sa numberOptions(), FloatingPointPrecisionOption
1306*/
1307void QLocale::setNumberOptions(NumberOptions options)
1308{
1309 d->m_numberOptions = options;
1310}
1311
1312/*!
1313 \since 4.2
1314
1315 Returns the options related to number conversions for this QLocale instance.
1316
1317 By default, no options are set for the standard locales, except for the "C"
1318 locale, which has OmitGroupSeparator set by default.
1319
1320 \sa setNumberOptions(), toString(), groupSeparator(), FloatingPointPrecisionOption
1321*/
1322QLocale::NumberOptions QLocale::numberOptions() const
1323{
1324 return d->m_numberOptions;
1325}
1326
1327/*!
1328 \fn QString QLocale::quoteString(const QString &str, QuotationStyle style) const
1329
1330 \since 4.8
1331
1332 Returns \a str quoted according to the current locale using the given
1333 quotation \a style.
1334*/
1335
1336/*!
1337 \since 6.0
1338
1339 \overload
1340*/
1341QString QLocale::quoteString(QStringView str, QuotationStyle style) const
1342{
1343#ifndef QT_NO_SYSTEMLOCALE
1344 if (d->m_data == &systemLocaleData) {
1345 QVariant res;
1346 if (style == AlternateQuotation)
1347 res = systemLocale()->query(QSystemLocale::StringToAlternateQuotation,
1348 QVariant::fromValue(str));
1349 if (res.isNull() || style == StandardQuotation)
1350 res = systemLocale()->query(QSystemLocale::StringToStandardQuotation,
1351 QVariant::fromValue(str));
1352 if (!res.isNull())
1353 return res.toString();
1354 }
1355#endif
1356
1357 QLocaleData::DataRange start, end;
1358 if (style == StandardQuotation) {
1359 start = d->m_data->quoteStart();
1360 end = d->m_data->quoteEnd();
1361 } else {
1362 start = d->m_data->quoteStartAlternate();
1363 end = d->m_data->quoteEndAlternate();
1364 }
1365
1366 return start.viewData(single_character_data) % str % end.viewData(single_character_data);
1367}
1368
1369/*!
1370 \since 4.8
1371
1372 Returns a string that represents a join of a given \a list of strings with
1373 a separator defined by the locale.
1374*/
1375QString QLocale::createSeparatedList(const QStringList &list) const
1376{
1377 // May be empty if list is empty or sole entry is empty.
1378#ifndef QT_NO_SYSTEMLOCALE
1379 if (d->m_data == &systemLocaleData) {
1380 QVariant res =
1381 systemLocale()->query(QSystemLocale::ListToSeparatedString, QVariant::fromValue(list));
1382
1383 if (!res.isNull())
1384 return res.toString();
1385 }
1386#endif
1387
1388 const qsizetype size = list.size();
1389 if (size < 1)
1390 return QString();
1391
1392 if (size == 1)
1393 return list.at(0);
1394
1395 if (size == 2)
1396 return d->m_data->pairListPattern().getData(
1397 list_pattern_part_data).arg(list.at(0), list.at(1));
1398
1399 QStringView formatStart = d->m_data->startListPattern().viewData(list_pattern_part_data);
1400 QStringView formatMid = d->m_data->midListPattern().viewData(list_pattern_part_data);
1401 QStringView formatEnd = d->m_data->endListPattern().viewData(list_pattern_part_data);
1402 QString result = formatStart.arg(list.at(0), list.at(1));
1403 for (qsizetype i = 2; i < size - 1; ++i)
1404 result = formatMid.arg(result, list.at(i));
1405 result = formatEnd.arg(result, list.at(size - 1));
1406 return result;
1407}
1408
1409/*!
1410 \nonreentrant
1411
1412 Sets the global default locale to \a locale.
1413
1414 This locale is used when a QLocale object is constructed with no
1415 arguments. If this function is not called, the system's locale is used.
1416
1417 \warning In a multithreaded application, the default locale should be set at
1418 application startup, before any non-GUI threads are created.
1419
1420 \sa system(), c()
1421*/
1422
1423void QLocale::setDefault(const QLocale &locale)
1424{
1425 default_data = locale.d->m_data;
1426
1427 if (defaultLocalePrivate.isDestroyed())
1428 return; // avoid crash on exit
1429 if (!defaultLocalePrivate.exists()) {
1430 // Force it to exist; see QTBUG-83016
1431 [[maybe_unused]] QLocale ignoreme;
1432 Q_ASSERT(defaultLocalePrivate.exists());
1433 }
1434
1435 // update the cached private
1436 *defaultLocalePrivate = locale.d;
1437 QLocalePrivate::s_generation.fetchAndAddRelaxed(1);
1438}
1439
1440/*!
1441 Returns the language of this locale.
1442
1443 \sa script(), territory(), languageToString(), bcp47Name()
1444*/
1445QLocale::Language QLocale::language() const
1446{
1447 return Language(d->languageId());
1448}
1449
1450/*!
1451 \since 4.8
1452
1453 Returns the script of this locale.
1454
1455 \sa language(), territory(), languageToString(), scriptToString(), bcp47Name()
1456*/
1457QLocale::Script QLocale::script() const
1458{
1459 return Script(d->m_data->m_script_id);
1460}
1461
1462/*!
1463 \since 6.2
1464
1465 Returns the territory of this locale.
1466
1467 \sa language(), script(), territoryToString(), bcp47Name()
1468*/
1469QLocale::Territory QLocale::territory() const
1470{
1471 return Territory(d->territoryId());
1472}
1473
1474#if QT_DEPRECATED_SINCE(6, 6)
1475/*!
1476 \deprecated [6.6] Use \l territory() instead.
1477
1478 Returns the territory of this locale.
1479
1480 \sa language(), script(), territoryToString(), bcp47Name()
1481*/
1482QLocale::Country QLocale::country() const
1483{
1484 return territory();
1485}
1486#endif
1487
1488/*!
1489 \since 6.7
1490 \enum QLocale::TagSeparator
1491
1492 Indicate how to combine the parts that make up a locale identifier.
1493
1494 A locale identifier may be made up of several tags, indicating language,
1495 script and territory (plus, potentially, other details), joined together to
1496 form the identifier. Various standards and conventional forms use either a
1497 dash (the Unicode HYPHEN-MINUS, U+002D) or an underscore (LOW LINE, U+005F).
1498 Different clients of QLocale may thus need one or the other.
1499
1500 \value Dash Use \c{'-'}, the dash or hyphen character.
1501 \value Underscore Use \c{'_'}, the underscore character.
1502
1503 \note Although dash and underscore are the only separators used in public
1504 standards (as at 2023), it is possible to cast any \l
1505 {https://en.cppreference.com/w/cpp/language/ascii} {ASCII} character to this
1506 type if a non-standard ASCII separator is needed. Casting a non-ASCII
1507 character (with decimal value above 127) is not supported: such values are
1508 reserved for future use as enum members if some public standard ever uses a
1509 non-ASCII separator. It is, of course, possible to use QString::replace() to
1510 replace the separator used by a function taking a parameter of this type
1511 with an arbitrary Unicode character or string.
1512*/
1513
1514Q_DECL_COLD_FUNCTION static void badSeparatorWarning(const char *method, char sep)
1515{
1516 qWarning("QLocale::%s(): Using non-ASCII separator '%c' (%02x) is unsupported",
1517 method, sep, uint(uchar(sep)));
1518}
1519
1520/*!
1521 \brief The short name of this locale.
1522
1523 Returns the language and territory of this locale as a string of the form
1524 "language_territory", where language is a lowercase, two-letter ISO 639
1525 language code, and territory is an uppercase, two- or three-letter ISO 3166
1526 territory code. If the locale has no specified territory, only the language
1527 name is returned. Since Qt 6.7 an optional \a separator parameter can be
1528 supplied to override the default underscore character separating the two
1529 tags.
1530
1531 Even if the QLocale object was constructed with an explicit script, name()
1532 will not contain it for compatibility reasons. Use \l bcp47Name() instead if
1533 you need a full locale name, or construct the string you want to identify a
1534 locale by from those returned by passing its \l language() to \l
1535 languageToCode() and similar for the script and territory.
1536
1537 \sa QLocale(), language(), script(), territory(), bcp47Name(), uiLanguages()
1538*/
1539
1540QString QLocale::name(TagSeparator separator) const
1541{
1542 const char sep = char(separator);
1543 if (uchar(sep) > 0x7f) {
1544 badSeparatorWarning("name", sep);
1545 return {};
1546 }
1547 const auto code = d->languageCode();
1548 QLatin1StringView view{code.data()};
1549
1550 Language l = language();
1551 if (l == C)
1552 return view;
1553
1554 Territory c = territory();
1555 if (c == AnyTerritory)
1556 return view;
1557
1558 return view + QLatin1Char(sep) + d->territoryCode();
1559}
1560
1561template <typename T> static inline
1562T toIntegral_helper(const QLocalePrivate *d, QStringView str, bool *ok)
1563{
1564 constexpr bool isUnsigned = std::is_unsigned_v<T>;
1565 using Int64 = typename std::conditional_t<isUnsigned, quint64, qint64>;
1566
1567 QSimpleParsedNumber<Int64> r{};
1568 if constexpr (isUnsigned)
1569 r = d->m_data->stringToUnsLongLong(str, 10, d->m_numberOptions);
1570 else
1571 r = d->m_data->stringToLongLong(str, 10, d->m_numberOptions);
1572
1573 if (ok)
1574 *ok = r.ok();
1575
1576 Int64 val = r.result;
1577 if (T(val) != val) {
1578 if (ok != nullptr)
1579 *ok = false;
1580 val = 0;
1581 }
1582 return T(val);
1583}
1584
1585
1586/*!
1587 \since 4.8
1588
1589 \brief Returns the BCP47 field names joined with dashes.
1590
1591 This combines as many of language, script and territory (and possibly other
1592 BCP47 fields) for this locale as are needed to uniquely specify it. Note
1593 that fields may be omitted if the Unicode consortium's \l {Matching
1594 combinations of language, script and territory}{Likely Subtag Rules} imply
1595 the omitted fields when given those retained. See \l name() for how to
1596 construct a string from individual fields, if some other format is needed.
1597
1598 Unlike uiLanguages(), the value returned by bcp47Name() represents the
1599 locale name of the QLocale data; this need not be the language the
1600 user-interface should be in.
1601
1602 This function tries to conform the locale name to the IETF Best Common
1603 Practice 47, defined by RFC 5646. Since Qt 6.7, it supports an optional \a
1604 separator parameter which can be used to override the BCP47-specified use of
1605 a hyphen to separate the tags. For use in IETF-defined protocols, however,
1606 the default, QLocale::TagSeparator::Dash, should be retained.
1607
1608 \sa name(), language(), territory(), script(), uiLanguages()
1609*/
1610QString QLocale::bcp47Name(TagSeparator separator) const
1611{
1612 const char sep = char(separator);
1613 if (uchar(sep) > 0x7f) {
1614 badSeparatorWarning("bcp47Name", sep);
1615 return {};
1616 }
1617 return QString::fromLatin1(d->bcp47Name(sep));
1618}
1619
1620/*!
1621 Returns the two- or three-letter language code for \a language, as defined
1622 in the ISO 639 standards.
1623
1624 If specified, \a codeTypes selects which set of codes to consider. The first
1625 code from the set that is defined for \a language is returned. Otherwise,
1626 all ISO-639 codes are considered. The codes are considered in the following
1627 order: \c ISO639Part1, \c ISO639Part2B, \c ISO639Part2T, \c ISO639Part3.
1628 \c LegacyLanguageCode is ignored by this function.
1629
1630 \note For \c{QLocale::C} the function returns \c{"C"}.
1631 For \c QLocale::AnyLanguage an empty string is returned.
1632 If the language has no code in any selected code set, an empty string
1633 is returned.
1634
1635 \since 6.3
1636 \sa codeToLanguage(), language(), name(), bcp47Name(), territoryToCode(), scriptToCode()
1637*/
1638QString QLocale::languageToCode(Language language, LanguageCodeTypes codeTypes)
1639{
1640 const auto code = QLocalePrivate::languageToCode(language, codeTypes);
1641 return QLatin1StringView{code.data()};
1642}
1643
1644/*!
1645 Returns the QLocale::Language enum corresponding to the two- or three-letter
1646 \a languageCode, as defined in the ISO 639 standards.
1647
1648 If specified, \a codeTypes selects which set of codes to consider for
1649 conversion. By default all codes known to Qt are considered. The codes are
1650 matched in the following order: \c ISO639Part1, \c ISO639Part2B,
1651 \c ISO639Part2T, \c ISO639Part3, \c LegacyLanguageCode.
1652
1653 If the code is invalid or not known \c QLocale::AnyLanguage is returned.
1654
1655 \since 6.3
1656 \sa languageToCode(), codeToTerritory(), codeToScript()
1657*/
1658QLocale::Language QLocale::codeToLanguage(QStringView languageCode,
1659 LanguageCodeTypes codeTypes) noexcept
1660{
1661 return QLocalePrivate::codeToLanguage(languageCode, codeTypes);
1662}
1663
1664/*!
1665 \since 6.2
1666
1667 Returns the two-letter territory code for \a territory, as defined
1668 in the ISO 3166 standard.
1669
1670 \note For \c{QLocale::AnyTerritory} an empty string is returned.
1671
1672 \sa codeToTerritory(), territory(), name(), bcp47Name(), languageToCode(), scriptToCode()
1673*/
1674QString QLocale::territoryToCode(QLocale::Territory territory)
1675{
1676 return QLocalePrivate::territoryToCode(territory);
1677}
1678
1679/*!
1680 \since 6.2
1681
1682 Returns the QLocale::Territory enum corresponding to the two-letter or
1683 three-digit \a territoryCode, as defined in the ISO 3166 standard.
1684
1685 If the code is invalid or not known QLocale::AnyTerritory is returned.
1686
1687 \sa territoryToCode(), codeToLanguage(), codeToScript()
1688*/
1689QLocale::Territory QLocale::codeToTerritory(QStringView territoryCode) noexcept
1690{
1691 return QLocalePrivate::codeToTerritory(territoryCode);
1692}
1693
1694#if QT_DEPRECATED_SINCE(6, 6)
1695/*!
1696 \deprecated [6.6] Use \l territoryToCode() instead.
1697
1698 Returns the two-letter territory code for \a country, as defined
1699 in the ISO 3166 standard.
1700
1701 \note For \c{QLocale::AnyTerritory} or \c{QLocale::AnyCountry} an empty string is returned.
1702
1703 \sa codeToTerritory(), territory(), name(), bcp47Name(), languageToCode(), scriptToCode()
1704*/
1705QString QLocale::countryToCode(Country country)
1706{
1707 return territoryToCode(country);
1708}
1709
1710/*!
1711 Returns the QLocale::Territory enum corresponding to the two-letter or
1712 three-digit \a countryCode, as defined in the ISO 3166 standard.
1713
1714 If the code is invalid or not known QLocale::AnyTerritory is returned.
1715
1716 \deprecated [6.6] Use codeToTerritory(QStringView) instead.
1717 \since 6.1
1718 \sa territoryToCode(), codeToLanguage(), codeToScript()
1719*/
1720QLocale::Country QLocale::codeToCountry(QStringView countryCode) noexcept
1721{
1722 return QLocalePrivate::codeToTerritory(countryCode);
1723}
1724#endif
1725
1726/*!
1727 Returns the four-letter script code for \a script, as defined in the
1728 ISO 15924 standard.
1729
1730 \note For \c{QLocale::AnyScript} an empty string is returned.
1731
1732 \since 6.1
1733 \sa script(), name(), bcp47Name(), languageToCode(), territoryToCode()
1734*/
1735QString QLocale::scriptToCode(Script script)
1736{
1737 return QLocalePrivate::scriptToCode(script);
1738}
1739
1740/*!
1741 Returns the QLocale::Script enum corresponding to the four-letter script
1742 \a scriptCode, as defined in the ISO 15924 standard.
1743
1744 If the code is invalid or not known QLocale::AnyScript is returned.
1745
1746 \since 6.1
1747 \sa scriptToCode(), codeToLanguage(), codeToTerritory()
1748*/
1749QLocale::Script QLocale::codeToScript(QStringView scriptCode) noexcept
1750{
1751 return QLocalePrivate::codeToScript(scriptCode);
1752}
1753
1754/*!
1755 Returns a QString containing the name of \a language.
1756
1757 \sa territoryToString(), scriptToString(), bcp47Name()
1758*/
1759
1760QString QLocale::languageToString(Language language)
1761{
1762 if (language > LastLanguage)
1763 return "Unknown"_L1;
1764 return QString::fromUtf8(language_name_list + language_name_index[language]);
1765}
1766
1767/*!
1768 \since 6.2
1769
1770 Returns a QString containing the name of \a territory.
1771
1772 \sa languageToString(), scriptToString(), territory(), bcp47Name()
1773*/
1774QString QLocale::territoryToString(Territory territory)
1775{
1776 if (territory > LastTerritory)
1777 return "Unknown"_L1;
1778 return QString::fromUtf8(territory_name_list + territory_name_index[territory]);
1779}
1780
1781#if QT_DEPRECATED_SINCE(6, 6)
1782/*!
1783 \deprecated [6.6] Use \l territoryToString() instead.
1784
1785 Returns a QString containing the name of \a country.
1786
1787 \sa languageToString(), scriptToString(), territory(), bcp47Name()
1788*/
1789QString QLocale::countryToString(Country country)
1790{
1791 return territoryToString(country);
1792}
1793#endif
1794
1795/*!
1796 \since 4.8
1797
1798 Returns a QString containing the name of \a script.
1799
1800 \sa languageToString(), territoryToString(), script(), bcp47Name()
1801*/
1802QString QLocale::scriptToString(Script script)
1803{
1804 if (script > LastScript)
1805 return "Unknown"_L1;
1806 return QString::fromUtf8(script_name_list + script_name_index[script]);
1807}
1808
1809/*!
1810 \fn short QLocale::toShort(const QString &s, bool *ok) const
1811
1812 Returns the short int represented by the localized string \a s.
1813
1814 If the conversion fails the function returns 0.
1815
1816 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1817 to \c false, and success by setting *\a{ok} to \c true.
1818
1819 This function ignores leading and trailing whitespace.
1820
1821 \sa toUShort(), toString()
1822*/
1823
1824/*!
1825 \fn ushort QLocale::toUShort(const QString &s, bool *ok) const
1826
1827 Returns the unsigned short 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 toShort(), toString()
1837*/
1838
1839/*!
1840 \fn int QLocale::toInt(const QString &s, bool *ok) const
1841 Returns the int represented by the localized string \a s.
1842
1843 If the conversion fails the function returns 0.
1844
1845 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1846 to \c false, and success by setting *\a{ok} to \c true.
1847
1848 This function ignores leading and trailing whitespace.
1849
1850 \sa toUInt(), toString()
1851*/
1852
1853/*!
1854 \fn uint QLocale::toUInt(const QString &s, bool *ok) const
1855 Returns the unsigned int represented by the localized string \a s.
1856
1857 If the conversion fails the function returns 0.
1858
1859 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1860 to \c false, and success by setting *\a{ok} to \c true.
1861
1862 This function ignores leading and trailing whitespace.
1863
1864 \sa toInt(), toString()
1865*/
1866
1867/*!
1868 \since 5.13
1869 \fn long QLocale::toLong(const QString &s, bool *ok) const
1870
1871 Returns the long int represented by the localized string \a s.
1872
1873 If the conversion fails the function returns 0.
1874
1875 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1876 to \c false, and success by setting *\a{ok} to \c true.
1877
1878 This function ignores leading and trailing whitespace.
1879
1880 \sa toInt(), toULong(), toDouble(), toString()
1881*/
1882
1883/*!
1884 \since 5.13
1885 \fn ulong QLocale::toULong(const QString &s, bool *ok) const
1886
1887 Returns the unsigned long int represented by the localized
1888 string \a s.
1889
1890 If the conversion fails the function returns 0.
1891
1892 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1893 to \c false, and success by setting *\a{ok} to \c true.
1894
1895 This function ignores leading and trailing whitespace.
1896
1897 \sa toLong(), toInt(), toDouble(), toString()
1898*/
1899
1900/*!
1901 \fn qlonglong QLocale::toLongLong(const QString &s, bool *ok) const
1902 Returns the long long int represented by the localized string \a s.
1903
1904 If the conversion fails the function returns 0.
1905
1906 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1907 to \c false, and success by setting *\a{ok} to \c true.
1908
1909 This function ignores leading and trailing whitespace.
1910
1911 \sa toInt(), toULongLong(), toDouble(), toString()
1912*/
1913
1914/*!
1915 \fn qulonglong QLocale::toULongLong(const QString &s, bool *ok) const
1916
1917 Returns the unsigned long long int represented by the localized
1918 string \a s.
1919
1920 If the conversion fails the function returns 0.
1921
1922 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1923 to \c false, and success by setting *\a{ok} to \c true.
1924
1925 This function ignores leading and trailing whitespace.
1926
1927 \sa toLongLong(), toInt(), toDouble(), toString()
1928*/
1929
1930/*!
1931 \fn float QLocale::toFloat(const QString &s, bool *ok) const
1932
1933 Returns the float represented by the localized string \a s.
1934
1935 Returns an infinity if the conversion overflows or 0.0 if the
1936 conversion fails for any other reason (e.g. underflow).
1937
1938 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1939 to \c false, and success by setting *\a{ok} to \c true.
1940
1941 This function ignores leading and trailing whitespace.
1942
1943 \sa toDouble(), toInt(), toString()
1944*/
1945
1946/*!
1947 \fn double QLocale::toDouble(const QString &s, bool *ok) const
1948 Returns the double represented by the localized string \a s.
1949
1950 Returns an infinity if the conversion overflows or 0.0 if the
1951 conversion fails for any other reason (e.g. underflow).
1952
1953 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1954 to \c false, and success by setting *\a{ok} to \c true.
1955
1956 \snippet code/src_corelib_text_qlocale.cpp 3
1957
1958 Notice that the last conversion returns 1234.0, because '.' is the
1959 thousands group separator in the German locale.
1960
1961 This function ignores leading and trailing whitespace.
1962
1963 \sa toFloat(), toInt(), toString()
1964*/
1965
1966/*!
1967 Returns the short int represented by the localized string \a s.
1968
1969 If the conversion fails, the function returns 0.
1970
1971 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1972 to \c false, and success by setting *\a{ok} to \c true.
1973
1974 This function ignores leading and trailing whitespace.
1975
1976 \sa toUShort(), toString()
1977
1978 \since 5.10
1979*/
1980
1981short QLocale::toShort(QStringView s, bool *ok) const
1982{
1983 return toIntegral_helper<short>(d, s, ok);
1984}
1985
1986/*!
1987 Returns the unsigned short int represented by the localized string \a s.
1988
1989 If the conversion fails, the function returns 0.
1990
1991 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1992 to \c false, and success by setting *\a{ok} to \c true.
1993
1994 This function ignores leading and trailing whitespace.
1995
1996 \sa toShort(), toString()
1997
1998 \since 5.10
1999*/
2000
2001ushort QLocale::toUShort(QStringView s, bool *ok) const
2002{
2003 return toIntegral_helper<ushort>(d, s, ok);
2004}
2005
2006/*!
2007 Returns the int represented by the localized string \a s.
2008
2009 If the conversion fails, the function returns 0.
2010
2011 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
2012 to \c false, and success by setting *\a{ok} to \c true.
2013
2014 This function ignores leading and trailing whitespace.
2015
2016 \sa toUInt(), toString()
2017
2018 \since 5.10
2019*/
2020
2021int QLocale::toInt(QStringView s, bool *ok) const
2022{
2023 return toIntegral_helper<int>(d, s, ok);
2024}
2025
2026/*!
2027 Returns the unsigned int represented by the localized string \a s.
2028
2029 If the conversion fails, the function returns 0.
2030
2031 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
2032 to \c false, and success by setting *\a{ok} to \c true.
2033
2034 This function ignores leading and trailing whitespace.
2035
2036 \sa toInt(), toString()
2037
2038 \since 5.10
2039*/
2040
2041uint QLocale::toUInt(QStringView s, bool *ok) const
2042{
2043 return toIntegral_helper<uint>(d, s, ok);
2044}
2045
2046/*!
2047 \since 5.13
2048 Returns the long int represented by the localized string \a s.
2049
2050 If the conversion fails the function returns 0.
2051
2052 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
2053 to \c false, and success by setting *\a{ok} to \c true.
2054
2055 This function ignores leading and trailing whitespace.
2056
2057 \sa toInt(), toULong(), toDouble(), toString()
2058*/
2059
2060long QLocale::toLong(QStringView s, bool *ok) const
2061{
2062 return toIntegral_helper<long>(d, s, ok);
2063}
2064
2065/*!
2066 \since 5.13
2067 Returns the unsigned long int represented by the localized
2068 string \a s.
2069
2070 If the conversion fails the function returns 0.
2071
2072 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
2073 to \c false, and success by setting *\a{ok} to \c true.
2074
2075 This function ignores leading and trailing whitespace.
2076
2077 \sa toLong(), toInt(), toDouble(), toString()
2078*/
2079
2080ulong QLocale::toULong(QStringView s, bool *ok) const
2081{
2082 return toIntegral_helper<ulong>(d, s, ok);
2083}
2084
2085/*!
2086 Returns the long long int represented by the localized string \a s.
2087
2088 If the conversion fails, the function returns 0.
2089
2090 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
2091 to \c false, and success by setting *\a{ok} to \c true.
2092
2093 This function ignores leading and trailing whitespace.
2094
2095 \sa toInt(), toULongLong(), toDouble(), toString()
2096
2097 \since 5.10
2098*/
2099
2100
2101qlonglong QLocale::toLongLong(QStringView s, bool *ok) const
2102{
2103 return toIntegral_helper<qlonglong>(d, s, ok);
2104}
2105
2106/*!
2107 Returns the unsigned long long int represented by the localized
2108 string \a s.
2109
2110 If the conversion fails, the function returns 0.
2111
2112 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
2113 to \c false, and success by setting *\a{ok} to \c true.
2114
2115 This function ignores leading and trailing whitespace.
2116
2117 \sa toLongLong(), toInt(), toDouble(), toString()
2118
2119 \since 5.10
2120*/
2121
2122qulonglong QLocale::toULongLong(QStringView s, bool *ok) const
2123{
2124 return toIntegral_helper<qulonglong>(d, s, ok);
2125}
2126
2127/*!
2128 Returns the float represented by the localized string \a s.
2129
2130 Returns an infinity if the conversion overflows or 0.0 if the
2131 conversion fails for any other reason (e.g. underflow).
2132
2133 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
2134 to \c false, and success by setting *\a{ok} to \c true.
2135
2136 This function ignores leading and trailing whitespace.
2137
2138 \sa toDouble(), toInt(), toString()
2139
2140 \since 5.10
2141*/
2142
2143float QLocale::toFloat(QStringView s, bool *ok) const
2144{
2145 return QLocaleData::convertDoubleToFloat(toDouble(s, ok), ok);
2146}
2147
2148/*!
2149 Returns the double represented by the localized string \a s.
2150
2151 Returns an infinity if the conversion overflows or 0.0 if the
2152 conversion fails for any other reason (e.g. underflow).
2153
2154 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
2155 to \c false, and success by setting *\a{ok} to \c true.
2156
2157 \snippet code/src_corelib_text_qlocale.cpp 3-qstringview
2158
2159 Notice that the last conversion returns 1234.0, because '.' is the
2160 thousands group separator in the German locale.
2161
2162 This function ignores leading and trailing whitespace.
2163
2164 \sa toFloat(), toInt(), toString()
2165
2166 \since 5.10
2167*/
2168
2169double QLocale::toDouble(QStringView s, bool *ok) const
2170{
2171 return d->m_data->stringToDouble(s, ok, d->m_numberOptions);
2172}
2173
2174/*!
2175 Returns a localized string representation of \a i.
2176
2177 \sa toLongLong(), numberOptions(), zeroDigit(), positiveSign()
2178*/
2179
2180QString QLocale::toString(qlonglong i) const
2181{
2182 int flags = (d->m_numberOptions & OmitGroupSeparator
2183 ? 0 : QLocaleData::GroupDigits);
2184
2185 return d->m_data->longLongToString(i, -1, 10, -1, flags);
2186}
2187
2188/*!
2189 \overload
2190
2191 \sa toULongLong(), numberOptions(), zeroDigit(), positiveSign()
2192*/
2193
2194QString QLocale::toString(qulonglong i) const
2195{
2196 int flags = (d->m_numberOptions & OmitGroupSeparator
2197 ? 0 : QLocaleData::GroupDigits);
2198
2199 return d->m_data->unsLongLongToString(i, -1, 10, -1, flags);
2200}
2201// ### Incorrect way of calculating the width, will be fixed soon.
2202static qsizetype stringWidth(QStringView text)
2203{
2204 QStringIterator counter(text);
2205 qsizetype count = 0;
2206 while (counter.hasNext()) {
2207 ++count;
2208 [[maybe_unused]] auto ch = counter.next();
2209 }
2210 return count;
2211}
2212
2213static unsigned calculateFlags(int fieldWidth, char32_t fillChar,
2214 const QLocale &locale)
2215{
2216 unsigned flags = QLocaleData::NoFlags;
2217 if (!(locale.numberOptions() & QLocale::OmitGroupSeparator))
2218 flags |= QLocaleData::GroupDigits;
2219 if (fieldWidth < 0)
2221 else if (fillChar == U'0')
2222 flags |= QLocaleData::ZeroPadded;
2223
2224 return flags;
2225}
2226
2227static QString calculateFiller(qsizetype padding,
2228 char32_t fillChar,
2229 [[maybe_unused]] qsizetype fieldWidth,
2230 const QLocaleData *localeData)
2231{
2232 QString filler;
2233 if (fillChar == U'0') {
2234 Q_ASSERT(fieldWidth < 0);
2235 filler = localeData->zeroDigit();
2236 } else {
2237 filler = QString(QChar::fromUcs4(fillChar));
2238 }
2239 // ### size is not width
2240 if (padding > 1)
2241 filler = filler.repeated(padding);
2242 return filler;
2243}
2244
2245/*!
2246 \fn QString QLocale::toString(short number, int fieldWidth, char32_t fillChar) const
2247 \fn QString QLocale::toString(int number, int fieldWidth, char32_t fillChar) const
2248 \fn QString QLocale::toString(long number, int fieldWidth, char32_t fillChar) const
2249 \include qlocale.cpp tostring-with-padding
2250 \include qlocale.cpp tostring-signed-padding
2251*/
2252/*!
2253//! [tostring-with-padding]
2254 Returns a string representation of the given \a number.
2255
2256 The string's length shall be at least the absolute value of \a fieldWidth,
2257 using \a fillChar as padding if the \a number has fewer digits. If
2258 \a fillChar is \c{'0'} the zero digit of this locale is used as padding.
2259 If \a fieldWidth is negative the string starts with its representation
2260 of \a number and, if shorter, is padded to length \c{-fieldWidth} with
2261 the given \a fillChar. For positive fieldWidth, the padding appears before
2262 the representation of \a number.
2263//! [tostring-with-padding]
2264//! [tostring-signed-padding]
2265 When the \a number is negative and \a fieldWidth is positive, if
2266 \a fillChar is a \c{'0'} the padding is inserted between this locale's
2267 minus sign and the start of the number's digits.
2268 \overload toString()
2269//! [tostring-signed-padding]
2270 */
2271QString QLocale::toString(qlonglong number, int fieldWidth, char32_t fillChar) const
2272{
2273 int absFieldWidth = qAbs(fieldWidth);
2274 int width = (fillChar == U'0') ? absFieldWidth : -1;
2275 unsigned flags = calculateFlags(fieldWidth, fillChar, *this);
2276
2277 QString result = d->m_data->longLongToString(number, -1, 10, width, flags);
2278 qsizetype padding = absFieldWidth - stringWidth(result);
2279
2280 if (padding > 0) {
2281 QString filler = calculateFiller(padding, fillChar, fieldWidth, d->m_data);
2282 if (fieldWidth < 0)
2283 result.append(filler);
2284 else
2285 result.prepend(filler);
2286 }
2287 return result;
2288}
2289
2290/*!
2291 \fn QString QLocale::toString(ushort number, int fieldWidth, char32_t fillChar) const
2292 \fn QString QLocale::toString(uint number, int fieldWidth, char32_t fillChar) const
2293 \fn QString QLocale::toString(ulong number, int fieldWidth, char32_t fillChar) const
2294 \include qlocale.cpp tostring-with-padding
2295 \overload toString()
2296 */
2297/*!
2298 \include qlocale.cpp tostring-with-padding
2299 \overload toString()
2300 */
2301QString QLocale::toString(qulonglong number, int fieldWidth, char32_t fillChar) const
2302{
2303 int absFieldWidth = qAbs(fieldWidth);
2304 int width = (fillChar == U'0') ? absFieldWidth : -1;
2305 unsigned flags = calculateFlags(fieldWidth, fillChar, *this);
2306
2307 QString result = d->m_data->unsLongLongToString(number, -1, 10, width, flags);
2308 qsizetype padding = absFieldWidth - stringWidth(result);
2309
2310 if (padding > 0) {
2311 QString filler = calculateFiller(padding, fillChar, fieldWidth, d->m_data);
2312 if (fieldWidth < 0)
2313 result.append(filler);
2314 else
2315 result.prepend(filler);
2316 }
2317 return result;
2318}
2319
2320/*!
2321 \overload
2322*/
2323
2324QString QLocale::toString(QDate date, const QString &format) const
2325{
2326 return toString(date, qToStringViewIgnoringNull(format));
2327}
2328
2329/*!
2330 \overload
2331 Returns a localized string representation of the given \a time according
2332 to the specified \a format (see QTime::toString()).
2333
2334 If \a format is an empty string, an empty string is returned.
2335
2336 \sa dateFormat(), QTime::toString()
2337*/
2338
2339QString QLocale::toString(QTime time, const QString &format) const
2340{
2341 return toString(time, qToStringViewIgnoringNull(format));
2342}
2343
2344/*!
2345 \since 4.4
2346 \fn QString QLocale::toString(const QDateTime &dateTime, const QString &format) const
2347 \overload
2348*/
2349
2350/*!
2351 \since 5.14
2352 \overload
2353
2354 Returns a localized string representation of the given \a date in the
2355 specified \a format (see QDate::toString()), optionally for a specified
2356 calendar \a cal.
2357
2358 If \a format is an empty string, an empty string is returned.
2359
2360 \sa dateFormat(), QDate::toString()
2361*/
2362QString QLocale::toString(QDate date, QStringView format, QCalendar cal) const
2363{
2364 return cal.dateTimeToString(format, QDateTime(), date, QTime(), *this);
2365}
2366
2367/*!
2368 \since 5.10
2369 \overload
2370*/
2371QString QLocale::toString(QDate date, QStringView format) const
2372{
2373 return QCalendar().dateTimeToString(format, QDateTime(), date, QTime(), *this);
2374}
2375
2376/*!
2377 \since 5.14
2378
2379 Returns a localized string representation of the given \a date according to
2380 the specified \a format (see dateFormat()), optionally for a specified
2381 calendar \a cal.
2382
2383 \note Some locales may use formats that limit the range of years they can
2384 represent. Some locales' use of two-digit years may lead to ambiguity.
2385*/
2386QString QLocale::toString(QDate date, FormatType format, QCalendar cal) const
2387{
2388 if (!date.isValid())
2389 return QString();
2390
2391#ifndef QT_NO_SYSTEMLOCALE
2392 if (cal.isGregorian() && d->m_data == &systemLocaleData) {
2393 QVariant res = systemLocale()->query(format == LongFormat
2394 ? QSystemLocale::DateToStringLong
2395 : QSystemLocale::DateToStringShort,
2396 date);
2397 if (!res.isNull())
2398 return res.toString();
2399 }
2400#endif
2401
2402 QString format_str = dateFormat(format);
2403 return toString(date, format_str, cal);
2404}
2405
2406/*!
2407 \since 4.5
2408 \overload
2409*/
2410QString QLocale::toString(QDate date, FormatType format) const
2411{
2412 if (!date.isValid())
2413 return QString();
2414
2415#ifndef QT_NO_SYSTEMLOCALE
2416 if (d->m_data == &systemLocaleData) {
2417 QVariant res = systemLocale()->query(format == LongFormat
2418 ? QSystemLocale::DateToStringLong
2419 : QSystemLocale::DateToStringShort,
2420 date);
2421 if (!res.isNull())
2422 return res.toString();
2423 }
2424#endif
2425
2426 QString format_str = dateFormat(format);
2427 return toString(date, format_str);
2428}
2429
2430static bool timeFormatContainsAP(QStringView format)
2431{
2432 qsizetype i = 0;
2433 while (i < format.size()) {
2434 if (format.at(i).unicode() == '\'') {
2435 qt_readEscapedFormatString(format, &i);
2436 continue;
2437 }
2438
2439 if (format.at(i).toLower().unicode() == 'a')
2440 return true;
2441
2442 ++i;
2443 }
2444 return false;
2445}
2446
2447/*!
2448 \since 4.5
2449 \overload
2450*/
2451QString QLocale::toString(QTime time, QStringView format) const
2452{
2453 return QCalendar().dateTimeToString(format, QDateTime(), QDate(), time, *this);
2454}
2455
2456/*!
2457 \since 5.14
2458
2459 Returns a localized string representation of the given \a dateTime according
2460 to the specified \a format (see QDateTime::toString()), optionally for a
2461 specified calendar \a cal.
2462
2463 If \a format is an empty string, an empty string is returned.
2464
2465 \sa QDateTime::toString(), QDate::toString(), QTime::toString()
2466*/
2467QString QLocale::toString(const QDateTime &dateTime, QStringView format, QCalendar cal) const
2468{
2469 return cal.dateTimeToString(format, dateTime, QDate(), QTime(), *this);
2470}
2471
2472/*!
2473 \since 5.10
2474 \overload
2475*/
2476QString QLocale::toString(const QDateTime &dateTime, QStringView format) const
2477{
2478 return QCalendar().dateTimeToString(format, dateTime, QDate(), QTime(), *this);
2479}
2480
2481/*!
2482 \since 5.14
2483
2484 Returns a localized string representation of the given \a dateTime according
2485 to the specified \a format (see dateTimeFormat()), optionally for a
2486 specified calendar \a cal.
2487
2488 \note Some locales may use formats that limit the range of years they can
2489 represent. Some locales' use of two-digit years may lead to ambiguity.
2490*/
2491QString QLocale::toString(const QDateTime &dateTime, FormatType format, QCalendar cal) const
2492{
2493 if (!dateTime.isValid())
2494 return QString();
2495
2496#ifndef QT_NO_SYSTEMLOCALE
2497 if (cal.isGregorian() && d->m_data == &systemLocaleData) {
2498 QVariant res = systemLocale()->query(format == LongFormat
2499 ? QSystemLocale::DateTimeToStringLong
2500 : QSystemLocale::DateTimeToStringShort,
2501 dateTime);
2502 if (!res.isNull())
2503 return res.toString();
2504 }
2505#endif
2506
2507 const QString format_str = dateTimeFormat(format);
2508 return toString(dateTime, format_str, cal);
2509}
2510
2511/*!
2512 \since 4.4
2513 \overload
2514*/
2515QString QLocale::toString(const QDateTime &dateTime, FormatType format) const
2516{
2517 if (!dateTime.isValid())
2518 return QString();
2519
2520#ifndef QT_NO_SYSTEMLOCALE
2521 if (d->m_data == &systemLocaleData) {
2522 QVariant res = systemLocale()->query(format == LongFormat
2523 ? QSystemLocale::DateTimeToStringLong
2524 : QSystemLocale::DateTimeToStringShort,
2525 dateTime);
2526 if (!res.isNull())
2527 return res.toString();
2528 }
2529#endif
2530
2531 const QString format_str = dateTimeFormat(format);
2532 return toString(dateTime, format_str);
2533}
2534
2535
2536/*!
2537 Returns a localized string representation of the given \a time in the
2538 specified \a format (see timeFormat()).
2539*/
2540
2541QString QLocale::toString(QTime time, FormatType format) const
2542{
2543 if (!time.isValid())
2544 return QString();
2545
2546#ifndef QT_NO_SYSTEMLOCALE
2547 if (d->m_data == &systemLocaleData) {
2548 QVariant res = systemLocale()->query(format == LongFormat
2549 ? QSystemLocale::TimeToStringLong
2550 : QSystemLocale::TimeToStringShort,
2551 time);
2552 if (!res.isNull())
2553 return res.toString();
2554 }
2555#endif
2556
2557 QString format_str = timeFormat(format);
2558 return toString(time, format_str);
2559}
2560
2561/*!
2562 \since 4.1
2563
2564 Returns the date format used for the current locale.
2565
2566 If \a format is LongFormat, the format will be elaborate, otherwise it will be short.
2567 For example, LongFormat for the \c{en_US} locale is \c{dddd, MMMM d, yyyy},
2568 ShortFormat is \c{M/d/yy}.
2569
2570 \sa QDate::toString(), QDate::fromString()
2571*/
2572
2573QString QLocale::dateFormat(FormatType format) const
2574{
2575#ifndef QT_NO_SYSTEMLOCALE
2576 if (d->m_data == &systemLocaleData) {
2577 QVariant res = systemLocale()->query(format == LongFormat
2578 ? QSystemLocale::DateFormatLong
2579 : QSystemLocale::DateFormatShort,
2580 QVariant());
2581 if (!res.isNull())
2582 return res.toString();
2583 }
2584#endif
2585
2586 return (format == LongFormat
2587 ? d->m_data->longDateFormat()
2588 : d->m_data->shortDateFormat()
2589 ).getData(date_format_data);
2590}
2591
2592/*!
2593 \since 4.1
2594
2595 Returns the time format used for the current locale.
2596
2597 If \a format is LongFormat, the format will be elaborate, otherwise it will be short.
2598 For example, LongFormat for the \c{en_US} locale is \c{h:mm:ss AP t},
2599 ShortFormat is \c{h:mm AP}.
2600
2601 \sa QTime::toString(), QTime::fromString()
2602*/
2603
2604QString QLocale::timeFormat(FormatType format) const
2605{
2606#ifndef QT_NO_SYSTEMLOCALE
2607 if (d->m_data == &systemLocaleData) {
2608 QVariant res = systemLocale()->query(format == LongFormat
2609 ? QSystemLocale::TimeFormatLong
2610 : QSystemLocale::TimeFormatShort,
2611 QVariant());
2612 if (!res.isNull())
2613 return res.toString();
2614 }
2615#endif
2616
2617 return (format == LongFormat
2618 ? d->m_data->longTimeFormat()
2619 : d->m_data->shortTimeFormat()
2620 ).getData(time_format_data);
2621}
2622
2623/*!
2624 \since 4.4
2625
2626 Returns the date time format used for the current locale.
2627
2628 If \a format is LongFormat, the format will be elaborate, otherwise it will be short.
2629 For example, LongFormat for the \c{en_US} locale is \c{dddd, MMMM d, yyyy h:mm:ss AP t},
2630 ShortFormat is \c{M/d/yy h:mm AP}.
2631
2632 \sa QDateTime::toString(), QDateTime::fromString()
2633*/
2634
2635QString QLocale::dateTimeFormat(FormatType format) const
2636{
2637#ifndef QT_NO_SYSTEMLOCALE
2638 if (d->m_data == &systemLocaleData) {
2639 QVariant res = systemLocale()->query(format == LongFormat
2640 ? QSystemLocale::DateTimeFormatLong
2641 : QSystemLocale::DateTimeFormatShort,
2642 QVariant());
2643 if (!res.isNull()) {
2644 return res.toString();
2645 }
2646 }
2647#endif
2648 return dateFormat(format) + u' ' + timeFormat(format);
2649}
2650
2651#if QT_CONFIG(datestring)
2652/*!
2653 \since 4.4
2654
2655 Reads \a string as a time in a locale-specific \a format.
2656
2657 Parses \a string and returns the time it represents. The format of the time
2658 string is chosen according to the \a format parameter (see timeFormat()).
2659
2660 \note Any am/pm indicators used must match \l amText() or \l pmText(),
2661 ignoring case.
2662
2663 If the time could not be parsed, returns an invalid time.
2664
2665 \sa timeFormat(), toDate(), toDateTime(), QTime::fromString()
2666*/
2667QTime QLocale::toTime(const QString &string, FormatType format) const
2668{
2669 return toTime(string, timeFormat(format));
2670}
2671
2672/*!
2673 \since 4.4
2674
2675 Reads \a string as a date in a locale-specific \a format.
2676
2677 Parses \a string and returns the date it represents. The format of the date
2678 string is chosen according to the \a format parameter (see dateFormat()).
2679
2680//! [base-year-for-short]
2681 Some locales use, particularly for ShortFormat, only the last two digits of
2682 the year. In such a case, the 100 years starting at \a baseYear are the
2683 candidates first considered. Prior to 6.7 there was no \a baseYear parameter
2684 and 1900 was always used. This is the default for \a baseYear, selecting a
2685 year from then to 1999. In some cases, other fields may lead to the next or
2686 previous century being selected, to get a result consistent with all fields
2687 given. See \l QDate::fromString() for details.
2688//! [base-year-for-short]
2689
2690 \note Month and day names, where used, must be given in the locale's
2691 language.
2692
2693 If the date could not be parsed, returns an invalid date.
2694
2695 \sa dateFormat(), toTime(), toDateTime(), QDate::fromString()
2696*/
2697QDate QLocale::toDate(const QString &string, FormatType format, int baseYear) const
2698{
2699 return toDate(string, dateFormat(format), baseYear);
2700}
2701
2702/*!
2703 \since 5.14
2704 \overload
2705*/
2706QDate QLocale::toDate(const QString &string, FormatType format, QCalendar cal, int baseYear) const
2707{
2708 return toDate(string, dateFormat(format), cal, baseYear);
2709}
2710
2711/*!
2712 \since 4.4
2713
2714 Reads \a string as a date-time in a locale-specific \a format.
2715
2716 Parses \a string and returns the date-time it represents. The format of the
2717 date string is chosen according to the \a format parameter (see
2718 dateFormat()).
2719
2720 \include qlocale.cpp base-year-for-short
2721
2722 \note Month and day names, where used, must be given in the locale's
2723 language. Any am/pm indicators used must match \l amText() or \l pmText(),
2724 ignoring case.
2725
2726 If the string could not be parsed, returns an invalid QDateTime.
2727
2728 \sa dateTimeFormat(), toTime(), toDate(), QDateTime::fromString()
2729*/
2730QDateTime QLocale::toDateTime(const QString &string, FormatType format, int baseYear) const
2731{
2732 return toDateTime(string, dateTimeFormat(format), baseYear);
2733}
2734
2735/*!
2736 \since 5.14
2737 \overload
2738*/
2739QDateTime QLocale::toDateTime(const QString &string, FormatType format, QCalendar cal,
2740 int baseYear) const
2741{
2742 return toDateTime(string, dateTimeFormat(format), cal, baseYear);
2743}
2744
2745/*!
2746 \since 4.4
2747
2748 Reads \a string as a time in the given \a format.
2749
2750 Parses \a string and returns the time it represents. See QTime::fromString()
2751 for the interpretation of \a format.
2752
2753 \note Any am/pm indicators used must match \l amText() or \l pmText(),
2754 ignoring case.
2755
2756 If the time could not be parsed, returns an invalid time.
2757
2758 \sa timeFormat(), toDate(), toDateTime(), QTime::fromString()
2759*/
2760QTime QLocale::toTime(const QString &string, const QString &format) const
2761{
2762#if QT_CONFIG(datetimeparser)
2763 QTimePattern pattern = QTimePattern::fromQtFormat(format);
2764 pattern.setLocale(*this);
2765 if (auto match = pattern.parse(string, QTime(0, 0)); match.size == string.size())
2766 return std::move(match.payload);
2767#else
2768 Q_UNUSED(string);
2769 Q_UNUSED(format);
2770#endif
2771 return {};
2772}
2773
2774/*!
2775 \since 4.4
2776
2777 Reads \a string as a date in the given \a format.
2778
2779 Parses \a string and returns the date it represents. See QDate::fromString()
2780 for the interpretation of \a format.
2781
2782//! [base-year-for-two-digit]
2783 When \a format only specifies the last two digits of a year, the 100 years
2784 starting at \a baseYear are the candidates first considered. Prior to 6.7
2785 there was no \a baseYear parameter and 1900 was always used. This is the
2786 default for \a baseYear, selecting a year from then to 1999. In some cases,
2787 other fields may lead to the next or previous century being selected, to get
2788 a result consistent with all fields given. See \l QDate::fromString() for
2789 details.
2790//! [base-year-for-two-digit]
2791
2792 \note Month and day names, where used, must be given in the locale's
2793 language.
2794
2795 If the date could not be parsed, returns an invalid date.
2796
2797 \sa dateFormat(), toTime(), toDateTime(), QDate::fromString()
2798*/
2799QDate QLocale::toDate(const QString &string, const QString &format, int baseYear) const
2800{
2801 return toDate(string, format, QCalendar(), baseYear);
2802}
2803
2804/*!
2805 \since 5.14
2806 \overload
2807*/
2808QDate QLocale::toDate(const QString &string, const QString &format, QCalendar cal, int baseYear) const
2809{
2810#if QT_CONFIG(datetimeparser)
2811 QDatePattern pattern = QDatePattern::fromQtFormat(format);
2812 pattern.setLocale(*this);
2813 pattern.setCalendar(cal);
2814 pattern.setBaseYear(baseYear);
2815 if (auto match = pattern.parse(string, QDate(baseYear, 1, 1, cal));
2816 match.size == string.size()) {
2817 return std::move(match.payload);
2818 }
2819#else
2820 Q_UNUSED(string);
2821 Q_UNUSED(format);
2822 Q_UNUSED(cal);
2823 Q_UNUSED(baseYear);
2824#endif
2825 return {};
2826}
2827
2828/*!
2829 \since 4.4
2830
2831 Reads \a string as a date-time in the given \a format.
2832
2833 Parses \a string and returns the date-time it represents. See
2834 QDateTime::fromString() for the interpretation of \a format.
2835
2836 \include qlocale.cpp base-year-for-two-digit
2837
2838 \note Month and day names, where used, must be given in the locale's
2839 language. Any am/pm indicators used must match \l amText() or \l pmText(),
2840 ignoring case.
2841
2842 If the string could not be parsed, returns an invalid QDateTime. If the
2843 string can be parsed and represents an invalid date-time (e.g. in a gap
2844 skipped by a time-zone transition), the returned QDateTime represents a
2845 near-by datetime that is valid (typically differing from it by the width of
2846 the gap in valid datetimes, e.g. the hour skipped by a transition). Passing
2847 that to fromMSecsSinceEpoch() will produce a valid date-time that isn't
2848 faithfully represented by the string parsed.
2849
2850 \sa dateTimeFormat(), toTime(), toDate(), QDateTime::fromString()
2851*/
2852QDateTime QLocale::toDateTime(const QString &string, const QString &format, int baseYear) const
2853{
2854 return toDateTime(string, format, QCalendar(), baseYear);
2855}
2856
2857/*!
2858 \since 5.14
2859 \overload
2860*/
2861QDateTime QLocale::toDateTime(const QString &string, const QString &format, QCalendar cal,
2862 int baseYear) const
2863{
2864#if QT_CONFIG(datetimeparser)
2865 QDateTimePattern pattern = QDateTimePattern::fromQtFormat(format);
2866 pattern.setLocale(*this);
2867 pattern.setCalendar(cal);
2868 pattern.setBaseYear(baseYear);
2869 if (auto match = pattern.parse(string, QDate(baseYear, 1, 1, cal).startOfDay());
2870 match.size == string.size()) {
2871 return std::move(match.payload);
2872 }
2873#else
2874 Q_UNUSED(string);
2875 Q_UNUSED(format);
2876 Q_UNUSED(cal);
2877 Q_UNUSED(baseYear);
2878#endif
2879 return {};
2880}
2881#endif // datestring
2882
2883/*!
2884 \since 4.1
2885
2886 Returns the fractional part separator for this locale.
2887
2888 This is the token that separates the whole number part from the fracional
2889 part in the representation of a number which has a fractional part. This is
2890 commonly called the "decimal point character" - even though, in many
2891 locales, it is not a "point" (or similar dot). It is (since Qt 6.0) returned
2892 as a string in case some locale needs more than one UTF-16 code-point to
2893 represent its separator.
2894
2895 \sa groupSeparator(), toString()
2896*/
2897QString QLocale::decimalPoint() const
2898{
2899 return d->m_data->decimalPoint();
2900}
2901
2902/*!
2903 \since 4.1
2904
2905 Returns the digit-grouping separator for this locale.
2906
2907 This is a token used to break up long sequences of digits, in the
2908 representation of a number, to make it easier to read. In some locales it
2909 may be empty, indicating that digits should not be broken up into groups in
2910 this way. In others it may be a spacing character. It is (since Qt 6.0)
2911 returned as a string in case some locale needs more than one UTF-16
2912 code-point to represent its separator.
2913
2914 \sa decimalPoint(), toString()
2915*/
2916QString QLocale::groupSeparator() const
2917{
2918 return d->m_data->groupSeparator();
2919}
2920
2921/*!
2922 \since 4.1
2923
2924 Returns the percent marker of this locale.
2925
2926 This is a token presumed to be appended to a number to indicate a
2927 percentage. It is (since Qt 6.0) returned as a string because, in some
2928 locales, it is not a single character - for example, because it includes a
2929 text-direction-control character.
2930
2931 \sa toString()
2932*/
2933QString QLocale::percent() const
2934{
2935 return d->m_data->percentSign();
2936}
2937
2938/*!
2939 \since 4.1
2940
2941 Returns the zero digit character of this locale.
2942
2943 This is a single Unicode character but may be encoded as a surrogate pair,
2944 so is (since Qt 6.0) returned as a string. In most locales, other digits
2945 follow it in Unicode ordering - however, some number systems, notably those
2946 using U+3007 as zero, do not have contiguous digits. Use toString() to
2947 obtain suitable representations of numbers, rather than trying to construct
2948 them from this zero digit.
2949
2950 \sa toString()
2951*/
2952QString QLocale::zeroDigit() const
2953{
2954 return d->m_data->zeroDigit();
2955}
2956
2957/*!
2958 \since 4.1
2959
2960 Returns the negative sign indicator of this locale.
2961
2962 This is a token presumed to be used as a prefix to a number to indicate that
2963 it is negative. It is (since Qt 6.0) returned as a string because, in some
2964 locales, it is not a single character - for example, because it includes a
2965 text-direction-control character.
2966
2967 \sa positiveSign(), toString()
2968*/
2969QString QLocale::negativeSign() const
2970{
2971 return d->m_data->negativeSign();
2972}
2973
2974/*!
2975 \since 4.5
2976
2977 Returns the positive sign indicator of this locale.
2978
2979 This is a token presumed to be used as a prefix to a number to indicate that
2980 it is positive. It is (since Qt 6.0) returned as a string because, in some
2981 locales, it is not a single character - for example, because it includes a
2982 text-direction-control character.
2983
2984 \sa negativeSign(), toString()
2985*/
2986QString QLocale::positiveSign() const
2987{
2988 return d->m_data->positiveSign();
2989}
2990
2991/*!
2992 \since 4.1
2993
2994 Returns the exponent separator for this locale.
2995
2996 This is a token used to separate mantissa from exponent in some
2997 floating-point numeric representations. It is (since Qt 6.0) returned as a
2998 string because, in some locales, it is not a single character - for example,
2999 it may consist of a multiplication sign and a representation of the "ten to
3000 the power" operator.
3001
3002 \sa toString(double, char, int)
3003*/
3004QString QLocale::exponential() const
3005{
3006 return d->m_data->exponentSeparator();
3007}
3008
3009/*!
3010 \overload
3011 Returns a string representing the floating-point number \a f.
3012
3013 The form of the representation is controlled by the \a format and \a
3014 precision parameters.
3015
3016 The \a format defaults to \c{'g'}. It can be any of the following:
3017
3018 \table
3019 \header \li Format \li Meaning \li Meaning of \a precision
3020 \row \li \c 'e' \li format as [-]9.9e[+|-]999 \li number of digits \e after the decimal point
3021 \row \li \c 'E' \li format as [-]9.9E[+|-]999 \li "
3022 \row \li \c 'f' \li format as [-]9.9 \li "
3023 \row \li \c 'F' \li same as \c 'f' except for INF and NAN (see below) \li "
3024 \row \li \c 'g' \li use \c 'e' or \c 'f' format, whichever is more concise \li maximum number of significant digits (trailing zeroes are omitted)
3025 \row \li \c 'G' \li use \c 'E' or \c 'F' format, whichever is more concise \li "
3026 \endtable
3027
3028 The special \a precision value QLocale::FloatingPointShortest selects the
3029 shortest representation that, when read as a number, gets back the original floating-point
3030 value. Aside from that, any negative \a precision is ignored in favor of the
3031 default, 6.
3032
3033 For the \c 'e', \c 'f' and \c 'g' formats, positive infinity is represented
3034 as "inf", negative infinity as "-inf" and floating-point NaN (not-a-number)
3035 values are represented as "nan". For the \c 'E', \c 'F' and \c 'G' formats,
3036 "INF" and "NAN" are used instead. This does not vary with locale.
3037
3038 \sa toDouble(), numberOptions(), exponential(), decimalPoint(), zeroDigit(),
3039 positiveSign(), percent(), toCurrencyString(), formattedDataSize(),
3040 QLocale::FloatingPointPrecisionOption
3041*/
3042
3043QString QLocale::toString(double f, char format, int precision) const
3044{
3045 QLocaleData::DoubleForm form = QLocaleData::DFDecimal;
3046 uint flags = isAsciiUpper(format) ? QLocaleData::CapitalEorX : 0;
3047
3048 switch (QtMiscUtils::toAsciiLower(format)) {
3049 case 'f':
3050 form = QLocaleData::DFDecimal;
3051 break;
3052 case 'e':
3053 form = QLocaleData::DFExponent;
3054 break;
3055 case 'g':
3056 form = QLocaleData::DFSignificantDigits;
3057 break;
3058 default:
3059 break;
3060 }
3061
3062 if (!(d->m_numberOptions & OmitGroupSeparator))
3063 flags |= QLocaleData::GroupDigits;
3064 if (!(d->m_numberOptions & OmitLeadingZeroInExponent))
3065 flags |= QLocaleData::ZeroPadExponent;
3066 if (d->m_numberOptions & IncludeTrailingZeroesAfterDot)
3067 flags |= QLocaleData::AddTrailingZeroes;
3068 return d->m_data->doubleToString(f, precision, form, -1, flags);
3069}
3070
3071/*!
3072 Returns a QLocale object initialized to the "C" locale.
3073
3074 This locale is based on en_US but with various quirks of its own, such as
3075 simplified number formatting and its own date formatting. It implements the
3076 POSIX standards that describe the behavior of standard library functions of
3077 the "C" programming language.
3078
3079 Among other things, this means its collation order is based on the ASCII
3080 values of letters, so that (for case-sensitive sorting) all upper-case
3081 letters sort before any lower-case one (rather than each letter's upper- and
3082 lower-case forms sorting adjacent to one another, before the next letter's
3083 two forms).
3084
3085 \sa system()
3086*/
3087QLocale QLocale::c() noexcept
3088{
3089 return QLocale(*c_private());
3090}
3091
3092/*!
3093 Returns a QLocale object initialized to the system locale.
3094
3095 The system locale may use system-specific sources for locale data, where
3096 available, otherwise falling back on QLocale's built-in database entry for
3097 the language, script and territory the system reports.
3098
3099 For example, on Windows and Mac, this locale will use the decimal/grouping
3100 characters and date/time formats specified in the system configuration
3101 panel.
3102
3103 \sa c()
3104*/
3105
3106QLocale QLocale::system()
3107{
3108 constexpr auto sysData = []() {
3109 // Same return as systemData(), but leave the setup to the actual call to it.
3110#ifdef QT_NO_SYSTEMLOCALE
3111 return locale_data;
3112#else
3113 return &systemLocaleData;
3114#endif
3115 };
3116 Q_CONSTINIT static QLocalePrivate locale(sysData(), -1, DefaultNumberOptions, 1);
3117 // Calling systemData() ensures system data is up to date; we also need it
3118 // to ensure that locale's index stays up to date:
3119 systemData(&locale.m_index);
3120 Q_ASSERT(locale.m_index >= 0 && locale.m_index < locale_data_size);
3121 locale.m_numberOptions = defaultNumberOptions(locale.m_data->m_language_id);
3122
3123 return QLocale(locale);
3124}
3125
3126/*!
3127 Returns a list of valid locale objects that match the given \a language, \a
3128 script and \a territory.
3129
3130 Getting a list of all locales:
3131 QList<QLocale> allLocales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript,
3132 QLocale::AnyTerritory);
3133
3134 Getting a list of locales suitable for Russia:
3135 QList<QLocale> locales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript,
3136 QLocale::Russia);
3137*/
3138QList<QLocale> QLocale::matchingLocales(Language language, Script script, Territory territory)
3139{
3140 QList<QLocale> result;
3141
3142 const QLocaleId filter { language, script, territory };
3143 if (!filter.isValid())
3144 return result;
3145
3146 if (language == C) {
3147 result.emplace_back(C);
3148 return result;
3149 }
3150
3151 if (filter.matchesAll())
3152 result.reserve(locale_data_size);
3153
3154 quint16 index = locale_index[language];
3155 // There may be no matches, for some languages (e.g. Abkhazian at CLDR v39).
3156 while (index < locale_data_size
3157 && filter.acceptLanguage(locale_data[index].m_language_id)) {
3158 const QLocaleId id = locale_data[index].id();
3159 if (filter.acceptScriptTerritory(id)) {
3160 result.append(QLocale(*(id.language_id == C ? c_private()
3161 : new QLocalePrivate(locale_data + index, index))));
3162 }
3163 ++index;
3164 }
3165
3166 // Add current system locale, if it matches
3167 const auto syslocaledata = systemData();
3168
3169 if (filter.acceptLanguage(syslocaledata->m_language_id)) {
3170 const QLocaleId id = syslocaledata->id();
3171 if (filter.acceptScriptTerritory(id))
3172 result.append(system());
3173 }
3174
3175 return result;
3176}
3177
3178#if QT_DEPRECATED_SINCE(6, 6)
3179/*!
3180 \deprecated [6.6] Use \l matchingLocales() instead and consult the \l territory() of each.
3181 \since 4.3
3182
3183 Returns the list of countries that have entries for \a language in Qt's locale
3184 database. If the result is an empty list, then \a language is not represented in
3185 Qt's locale database.
3186
3187 \sa matchingLocales()
3188*/
3189QList<QLocale::Country> QLocale::countriesForLanguage(Language language)
3190{
3191 const auto locales = matchingLocales(language, AnyScript, AnyCountry);
3192 QList<Country> result;
3193 result.reserve(locales.size());
3194 for (const auto &locale : locales)
3195 result.append(locale.territory());
3196 return result;
3197}
3198#endif
3199
3200/*!
3201 \since 4.2
3202
3203 Returns the localized name of \a month, in the format specified
3204 by \a type.
3205
3206 For example, if the locale is \c en_US and \a month is 1,
3207 \l LongFormat will return \c January. \l ShortFormat \c Jan,
3208 and \l NarrowFormat \c J.
3209
3210 \sa dayName(), standaloneMonthName()
3211*/
3212QString QLocale::monthName(int month, FormatType type) const
3213{
3214 return QCalendar().monthName(*this, month, QCalendar::Unspecified, type);
3215}
3216
3217/*!
3218 \since 4.5
3219
3220 Returns the localized name of \a month that is used as a
3221 standalone text, in the format specified by \a type.
3222
3223 If the locale information doesn't specify the standalone month
3224 name then return value is the same as in monthName().
3225
3226 \sa monthName(), standaloneDayName()
3227*/
3228QString QLocale::standaloneMonthName(int month, FormatType type) const
3229{
3230 return QCalendar().standaloneMonthName(*this, month, QCalendar::Unspecified, type);
3231}
3232
3233/*!
3234 \since 4.2
3235
3236 Returns the localized name of the \a day (where 1 represents
3237 Monday, 2 represents Tuesday and so on), in the format specified
3238 by \a type.
3239
3240 For example, if the locale is \c en_US and \a day is 1,
3241 \l LongFormat will return \c Monday, \l ShortFormat \c Mon,
3242 and \l NarrowFormat \c M.
3243
3244 \sa monthName(), standaloneDayName()
3245*/
3246QString QLocale::dayName(int day, FormatType type) const
3247{
3248 return QCalendar().weekDayName(*this, day, type);
3249}
3250
3251/*!
3252 \since 4.5
3253
3254 Returns the localized name of the \a day (where 1 represents
3255 Monday, 2 represents Tuesday and so on) that is used as a
3256 standalone text, in the format specified by \a type.
3257
3258 If the locale information does not specify the standalone day
3259 name then return value is the same as in dayName().
3260
3261 \sa dayName(), standaloneMonthName()
3262*/
3263QString QLocale::standaloneDayName(int day, FormatType type) const
3264{
3265 return QCalendar().standaloneWeekDayName(*this, day, type);
3266}
3267
3268// Calendar look-up of month and day names:
3269
3270// Get locale-specific month name data:
3272 const QCalendarLocale *table)
3273{
3274 // Only used in assertions
3275 [[maybe_unused]] const auto sameLocale = [](const QLocaleData &locale,
3276 const QCalendarLocale &cal) {
3277 return locale.m_language_id == cal.m_language_id
3278 && locale.m_script_id == cal.m_script_id
3279 && locale.m_territory_id == cal.m_territory_id;
3280 };
3281 const QCalendarLocale &monthly = table[loc->m_index];
3282#ifdef QT_NO_SYSTEMLOCALE
3283 [[maybe_unused]] constexpr bool isSys = false;
3284#else // Can't have preprocessor directives in a macro's parameter list, so use local.
3285 [[maybe_unused]] const bool isSys = loc->m_data == &systemLocaleData;
3286#endif
3287 Q_ASSERT(loc->m_data == &locale_data[loc->m_index] || isSys);
3288 // Compare monthly to locale_data[] entry, as the m_index used with
3289 // systemLocaleData is a best fit, not necessarily an exact match.
3290 Q_ASSERT(sameLocale(locale_data[loc->m_index], monthly));
3291 return monthly;
3292}
3293
3294/*!
3295 \internal
3296 */
3297
3298static QString rawMonthName(const QCalendarLocale &localeData,
3299 const char16_t *monthsData, int month,
3300 QLocale::FormatType type)
3301{
3302 const QLocaleData::DataRange range = localeData.monthName(type);
3303 return range.getListEntry(monthsData, month - 1);
3304}
3305
3306/*!
3307 \internal
3308 */
3309
3310static QString rawStandaloneMonthName(const QCalendarLocale &localeData,
3311 const char16_t *monthsData, int month,
3312 QLocale::FormatType type)
3313{
3314 const QLocaleData::DataRange range = localeData.standaloneMonthName(type);
3315 if (QString name = range.getListEntry(monthsData, month - 1); !name.isEmpty())
3316 return name;
3317 return rawMonthName(localeData, monthsData, month, type);
3318}
3319
3320/*!
3321 \internal
3322 */
3323
3324static QString rawWeekDayName(const QLocaleData *data, const int day,
3325 QLocale::FormatType type)
3326{
3327 QLocaleData::DataRange range;
3328 switch (type) {
3329 case QLocale::LongFormat:
3330 range = data->longDayNames();
3331 break;
3332 case QLocale::ShortFormat:
3333 range = data->shortDayNames();
3334 break;
3335 case QLocale::NarrowFormat:
3336 range = data->narrowDayNames();
3337 break;
3338 default:
3339 return QString();
3340 }
3341 return range.getListEntry(days_data, day == 7 ? 0 : day);
3342}
3343
3344/*!
3345 \internal
3346 */
3347
3348static QString rawStandaloneWeekDayName(const QLocaleData *data, const int day,
3349 QLocale::FormatType type)
3350{
3351 QLocaleData::DataRange range;
3352 switch (type) {
3353 case QLocale::LongFormat:
3354 range =data->longDayNamesStandalone();
3355 break;
3356 case QLocale::ShortFormat:
3357 range = data->shortDayNamesStandalone();
3358 break;
3359 case QLocale::NarrowFormat:
3360 range = data->narrowDayNamesStandalone();
3361 break;
3362 default:
3363 return QString();
3364 }
3365 QString name = range.getListEntry(days_data, day == 7 ? 0 : day);
3366 if (name.isEmpty())
3367 return rawWeekDayName(data, day, type);
3368 return name;
3369}
3370
3371// Refugees from qcalendar.cpp that need functions above:
3372
3373QString QCalendarBackend::monthName(const QLocale &locale, int month, int,
3374 QLocale::FormatType format) const
3375{
3376 Q_ASSERT(month >= 1 && month <= maximumMonthsInYear());
3377 return rawMonthName(getMonthDataFor(locale.d, localeMonthIndexData()),
3378 localeMonthData(), month, format);
3379}
3380
3381QString QRomanCalendar::monthName(const QLocale &locale, int month, int year,
3382 QLocale::FormatType format) const
3383{
3384#ifndef QT_NO_SYSTEMLOCALE
3385 if (locale.d->m_data == &systemLocaleData) {
3386 Q_ASSERT(month >= 1 && month <= 12);
3387 QSystemLocale::QueryType queryType = QSystemLocale::MonthNameLong;
3388 switch (format) {
3389 case QLocale::LongFormat:
3390 queryType = QSystemLocale::MonthNameLong;
3391 break;
3392 case QLocale::ShortFormat:
3393 queryType = QSystemLocale::MonthNameShort;
3394 break;
3395 case QLocale::NarrowFormat:
3396 queryType = QSystemLocale::MonthNameNarrow;
3397 break;
3398 }
3399 QVariant res = systemLocale()->query(queryType, month);
3400 if (!res.isNull())
3401 return res.toString();
3402 }
3403#endif
3404
3405 return QCalendarBackend::monthName(locale, month, year, format);
3406}
3407
3408QString QCalendarBackend::standaloneMonthName(const QLocale &locale, int month, int,
3409 QLocale::FormatType format) const
3410{
3411 Q_ASSERT(month >= 1 && month <= maximumMonthsInYear());
3412 return rawStandaloneMonthName(getMonthDataFor(locale.d, localeMonthIndexData()),
3413 localeMonthData(), month, format);
3414}
3415
3416QString QRomanCalendar::standaloneMonthName(const QLocale &locale, int month, int year,
3417 QLocale::FormatType format) const
3418{
3419#ifndef QT_NO_SYSTEMLOCALE
3420 if (locale.d->m_data == &systemLocaleData) {
3421 Q_ASSERT(month >= 1 && month <= 12);
3422 QSystemLocale::QueryType queryType = QSystemLocale::StandaloneMonthNameLong;
3423 switch (format) {
3424 case QLocale::LongFormat:
3425 queryType = QSystemLocale::StandaloneMonthNameLong;
3426 break;
3427 case QLocale::ShortFormat:
3428 queryType = QSystemLocale::StandaloneMonthNameShort;
3429 break;
3430 case QLocale::NarrowFormat:
3431 queryType = QSystemLocale::StandaloneMonthNameNarrow;
3432 break;
3433 }
3434 QVariant res = systemLocale()->query(queryType, month);
3435 if (!res.isNull())
3436 return res.toString();
3437 }
3438#endif
3439
3440 return QCalendarBackend::standaloneMonthName(locale, month, year, format);
3441}
3442
3443// Most calendars share the common week-day naming, modulo locale.
3444// Calendars that don't must override these methods.
3445QString QCalendarBackend::weekDayName(const QLocale &locale, int day,
3446 QLocale::FormatType format) const
3447{
3448 if (day < 1 || day > 7)
3449 return QString();
3450
3451#ifndef QT_NO_SYSTEMLOCALE
3452 if (locale.d->m_data == &systemLocaleData) {
3453 QSystemLocale::QueryType queryType = QSystemLocale::DayNameLong;
3454 switch (format) {
3455 case QLocale::LongFormat:
3456 queryType = QSystemLocale::DayNameLong;
3457 break;
3458 case QLocale::ShortFormat:
3459 queryType = QSystemLocale::DayNameShort;
3460 break;
3461 case QLocale::NarrowFormat:
3462 queryType = QSystemLocale::DayNameNarrow;
3463 break;
3464 }
3465 QVariant res = systemLocale()->query(queryType, day);
3466 if (!res.isNull())
3467 return res.toString();
3468 }
3469#endif
3470
3471 return rawWeekDayName(locale.d->m_data, day, format);
3472}
3473
3474QString QCalendarBackend::standaloneWeekDayName(const QLocale &locale, int day,
3475 QLocale::FormatType format) const
3476{
3477 if (day < 1 || day > 7)
3478 return QString();
3479
3480#ifndef QT_NO_SYSTEMLOCALE
3481 if (locale.d->m_data == &systemLocaleData) {
3482 QSystemLocale::QueryType queryType = QSystemLocale::StandaloneDayNameLong;
3483 switch (format) {
3484 case QLocale::LongFormat:
3485 queryType = QSystemLocale::StandaloneDayNameLong;
3486 break;
3487 case QLocale::ShortFormat:
3488 queryType = QSystemLocale::StandaloneDayNameShort;
3489 break;
3490 case QLocale::NarrowFormat:
3491 queryType = QSystemLocale::StandaloneDayNameNarrow;
3492 break;
3493 }
3494 QVariant res = systemLocale()->query(queryType, day);
3495 if (!res.isNull())
3496 return res.toString();
3497 }
3498#endif
3499
3500 return rawStandaloneWeekDayName(locale.d->m_data, day, format);
3501}
3502
3503// End of this block of qcalendar.cpp refugees. (One more follows.)
3504
3505/*!
3506 \since 4.8
3507
3508 Returns the first day of the week according to the current locale.
3509*/
3510Qt::DayOfWeek QLocale::firstDayOfWeek() const
3511{
3512#ifndef QT_NO_SYSTEMLOCALE
3513 if (d->m_data == &systemLocaleData) {
3514 const auto res = systemLocale()->query(QSystemLocale::FirstDayOfWeek);
3515 if (!res.isNull())
3516 return static_cast<Qt::DayOfWeek>(res.toUInt());
3517 }
3518#endif
3519 return static_cast<Qt::DayOfWeek>(d->m_data->m_first_day_of_week);
3520}
3521
3523{
3524 /* Unicode CLDR's information about measurement systems doesn't say which to
3525 use by default in each locale. Even if it did, adding another entry in
3526 every locale's row of locale_data[] would take up much more memory than
3527 the small table below.
3528 */
3529 struct TerritoryLanguage
3530 {
3531 quint16 languageId;
3532 quint16 territoryId;
3533 QLocale::MeasurementSystem system;
3534 };
3535 // TODO: research how realistic and/or complete this is:
3536 constexpr TerritoryLanguage ImperialMeasurementSystems[] = {
3537 { QLocale::English, QLocale::UnitedStates, QLocale::ImperialUSSystem },
3538 { QLocale::English, QLocale::UnitedStatesMinorOutlyingIslands, QLocale::ImperialUSSystem },
3539 { QLocale::Spanish, QLocale::UnitedStates, QLocale::ImperialUSSystem },
3540 { QLocale::Hawaiian, QLocale::UnitedStates, QLocale::ImperialUSSystem },
3541 { QLocale::English, QLocale::UnitedKingdom, QLocale::ImperialUKSystem }
3542 };
3543
3544 for (const auto &system : ImperialMeasurementSystems) {
3545 if (system.languageId == m_data->m_language_id
3546 && system.territoryId == m_data->m_territory_id) {
3547 return system.system;
3548 }
3549 }
3550 return QLocale::MetricSystem;
3551}
3552
3553/*!
3554 \since 4.8
3555
3556 Returns a list of days that are considered weekdays according to the current locale.
3557*/
3558QList<Qt::DayOfWeek> QLocale::weekdays() const
3559{
3560#ifndef QT_NO_SYSTEMLOCALE
3561 if (d->m_data == &systemLocaleData) {
3562 auto res
3563 = qvariant_cast<QList<Qt::DayOfWeek> >(systemLocale()->query(QSystemLocale::Weekdays));
3564 if (!res.isEmpty())
3565 return res;
3566 }
3567#endif
3568 QList<Qt::DayOfWeek> weekdays;
3569 quint16 weekendStart = d->m_data->m_weekend_start;
3570 quint16 weekendEnd = d->m_data->m_weekend_end;
3571 for (int day = Qt::Monday; day <= Qt::Sunday; day++) {
3572 if ((weekendEnd >= weekendStart && (day < weekendStart || day > weekendEnd)) ||
3573 (weekendEnd < weekendStart && (day > weekendEnd && day < weekendStart)))
3574 weekdays << static_cast<Qt::DayOfWeek>(day);
3575 }
3576 return weekdays;
3577}
3578
3579/*!
3580 \since 4.4
3581
3582 Returns the measurement system for the locale.
3583*/
3584QLocale::MeasurementSystem QLocale::measurementSystem() const
3585{
3586#ifndef QT_NO_SYSTEMLOCALE
3587 if (d->m_data == &systemLocaleData) {
3588 const auto res = systemLocale()->query(QSystemLocale::MeasurementSystem);
3589 if (!res.isNull())
3590 return MeasurementSystem(res.toInt());
3591 }
3592#endif
3593
3594 return d->measurementSystem();
3595}
3596
3597/*!
3598 \since 4.7
3599
3600 Returns the text direction of the language.
3601*/
3602Qt::LayoutDirection QLocale::textDirection() const
3603{
3604 switch (script()) {
3605 case AdlamScript:
3606 case ArabicScript:
3607 case AvestanScript:
3608 case CypriotScript:
3609 case HatranScript:
3610 case HebrewScript:
3611 case ImperialAramaicScript:
3612 case InscriptionalPahlaviScript:
3613 case InscriptionalParthianScript:
3614 case KharoshthiScript:
3615 case LydianScript:
3616 case MandaeanScript:
3617 case ManichaeanScript:
3618 case MendeKikakuiScript:
3619 case MeroiticCursiveScript:
3620 case MeroiticScript:
3621 case NabataeanScript:
3622 case NkoScript:
3623 case OldHungarianScript:
3624 case OldNorthArabianScript:
3625 case OldSouthArabianScript:
3626 case OrkhonScript:
3627 case PalmyreneScript:
3628 case PhoenicianScript:
3629 case PsalterPahlaviScript:
3630 case SamaritanScript:
3631 case SyriacScript:
3632 case ThaanaScript:
3633 return Qt::RightToLeft;
3634 default:
3635 break;
3636 }
3637 return Qt::LeftToRight;
3638}
3639
3640/*!
3641 \since 4.8
3642
3643 Returns an uppercase copy of \a str.
3644
3645 If Qt Core is using the ICU libraries, they will be used to perform
3646 the transformation according to the rules of the current locale.
3647 Otherwise the conversion may be done in a platform-dependent manner,
3648 with QString::toUpper() as a generic fallback.
3649
3650 \note In some cases the uppercase form of a string may be longer than the
3651 original.
3652
3653 \sa QString::toUpper()
3654*/
3655QString QLocale::toUpper(const QString &str) const
3656{
3657#if !defined(QT_BOOTSTRAPPED) && (QT_CONFIG(icu) || defined(Q_OS_WIN) || defined(Q_OS_APPLE))
3658 bool ok = true;
3659 QString result = d->toUpper(str, &ok);
3660 if (ok)
3661 return result;
3662 // else fall through and use Qt's toUpper
3663#endif
3664 return str.toUpper();
3665}
3666
3667/*!
3668 \since 4.8
3669
3670 Returns a lowercase copy of \a str.
3671
3672 If Qt Core is using the ICU libraries, they will be used to perform
3673 the transformation according to the rules of the current locale.
3674 Otherwise the conversion may be done in a platform-dependent manner,
3675 with QString::toLower() as a generic fallback.
3676
3677 \sa QString::toLower()
3678*/
3679QString QLocale::toLower(const QString &str) const
3680{
3681#if !defined(QT_BOOTSTRAPPED) && (QT_CONFIG(icu) || defined(Q_OS_WIN) || defined(Q_OS_APPLE))
3682 bool ok = true;
3683 const QString result = d->toLower(str, &ok);
3684 if (ok)
3685 return result;
3686 // else fall through and use Qt's toLower
3687#endif
3688 return str.toLower();
3689}
3690
3691
3692/*!
3693 \since 4.5
3694
3695 Returns the localized name of the "AM" suffix for times specified using
3696 the conventions of the 12-hour clock.
3697
3698 \sa pmText()
3699*/
3700QString QLocale::amText() const
3701{
3702#ifndef QT_NO_SYSTEMLOCALE
3703 if (d->m_data == &systemLocaleData) {
3704 auto res = systemLocale()->query(QSystemLocale::AMText).toString();
3705 if (!res.isEmpty())
3706 return res;
3707 }
3708#endif
3709 return d->m_data->anteMeridiem().getData(am_data);
3710}
3711
3712/*!
3713 \since 4.5
3714
3715 Returns the localized name of the "PM" suffix for times specified using
3716 the conventions of the 12-hour clock.
3717
3718 \sa amText()
3719*/
3720QString QLocale::pmText() const
3721{
3722#ifndef QT_NO_SYSTEMLOCALE
3723 if (d->m_data == &systemLocaleData) {
3724 auto res = systemLocale()->query(QSystemLocale::PMText).toString();
3725 if (!res.isEmpty())
3726 return res;
3727 }
3728#endif
3729 return d->m_data->postMeridiem().getData(pm_data);
3730}
3731
3732// For the benefit of QCalendar, below.
3733static QString offsetFromAbbreviation(QString &&text)
3734{
3735 QStringView tail{text};
3736 // May need to strip a prefix:
3737 if (tail.startsWith("UTC"_L1) || tail.startsWith("GMT"_L1))
3738 tail = tail.sliced(3);
3739 // TODO: there may be a locale-specific alternative prefix.
3740 // Hard to know without zone-name L10n details, though.
3741 return (tail.isEmpty() // The Qt::UTC case omits the zero offset:
3742 ? u"+00:00"_s
3743 // Whole-hour offsets may lack the zero minutes:
3744 : (tail.size() <= 3
3745 ? tail + ":00"_L1
3746 : std::move(text).right(tail.size())));
3747}
3748
3749// For the benefit of QCalendar, below, when not provided by QTZL.
3750#if !QT_CONFIG(datestring)
3751// No need for temporal data serialization and parsing code.
3752#elif QT_CONFIG(icu) || !(QT_CONFIG(timezone) && QT_CONFIG(timezone_locale))
3753namespace QtTimeZoneLocale {
3754
3755// TODO: is there a way to get this non-kludgily from ICU ?
3756// If so, that version goes in QTZL.cpp's relevant #if-ery branch.
3757QString zoneOffsetFormat([[maybe_unused]] const QLocale &locale,
3758 qsizetype,
3759 QtTemporalPattern::TemporalFieldFlags,
3760 const QDateTime &when,
3761 int offsetSeconds)
3762{
3763 // Only the non-ICU TZ-locale code uses the prefix forms, so this tacitly
3764 // assumes flags: Numeric | Abbreviated | NeedNoUtcPrefix | ZeroPad.
3765 QString text =
3766#if QT_CONFIG(timezone)
3767 locale != QLocale::system()
3768 ? when.timeRepresentation().displayName(when, QTimeZone::OffsetName, locale)
3769 :
3770#endif
3771 when.toOffsetFromUtc(offsetSeconds).timeZoneAbbreviation();
3772
3773 if (!text.isEmpty())
3774 text = offsetFromAbbreviation(std::move(text));
3775 // else: no suitable representation of the zone.
3776 return text;
3777}
3778
3779} // QtTimeZoneLocale
3780#endif // ICU or no TZ L10n
3781
3782// Another intrusion from QCalendar, using some of the tools above:
3783QString QCalendarBackend::dateTimeToString(QStringView format, const QDateTime &datetime,
3784 QDate dateOnly, QTime timeOnly,
3785 const QLocale &locale) const
3786{
3787 QDate date;
3788 QTime time;
3789 bool formatDate = false;
3790 bool formatTime = false;
3791 if (datetime.isValid()) {
3792 date = datetime.date();
3793 time = datetime.time();
3794 formatDate = true;
3795 formatTime = true;
3796 } else if (dateOnly.isValid()) {
3797 date = dateOnly;
3798 formatDate = true;
3799 } else if (timeOnly.isValid()) {
3800 time = timeOnly;
3801 formatTime = true;
3802 } else {
3803 return QString();
3804 }
3805
3806 QString result;
3807 int year = 0, month = 0, day = 0;
3808 if (formatDate) {
3809 const auto parts = julianDayToDate(date.toJulianDay());
3810 if (!parts.isValid())
3811 return QString();
3812 year = parts.year;
3813 month = parts.month;
3814 day = parts.day;
3815 }
3816
3817 auto appendToResult = [&](int t, int repeat) {
3818 auto data = locale.d->m_data;
3819 if (repeat > 1)
3820 result.append(data->longLongToString(t, -1, 10, repeat, QLocaleData::ZeroPadded));
3821 else
3822 result.append(data->longLongToString(t));
3823 };
3824
3825 auto formatType = [](int repeat) {
3826 return repeat == 3 ? QLocale::ShortFormat : QLocale::LongFormat;
3827 };
3828
3829 qsizetype i = 0;
3830 while (i < format.size()) {
3831 if (format.at(i).unicode() == '\'') {
3832 result.append(qt_readEscapedFormatString(format, &i));
3833 continue;
3834 }
3835
3836 const QChar c = format.at(i);
3837 qsizetype rep = qt_repeatCount(format.mid(i));
3838 Q_ASSERT(rep < std::numeric_limits<int>::max());
3839 int repeat = int(rep);
3840 bool used = false;
3841 if (formatDate) {
3842 switch (c.unicode()) {
3843 case 'y':
3844 used = true;
3845 if (repeat >= 4)
3846 repeat = 4;
3847 else if (repeat >= 2)
3848 repeat = 2;
3849
3850 switch (repeat) {
3851 case 4:
3852 // Years with more than four digits must have a sign:
3853 if (year > 9999)
3854 result.append(locale.positiveSign());
3855 appendToResult(year, (year < 0) ? 5 : 4);
3856 break;
3857 case 2:
3858 appendToResult(year % 100, 2);
3859 break;
3860 default:
3861 repeat = 1;
3862 result.append(c);
3863 break;
3864 }
3865 break;
3866
3867 case 'M':
3868 used = true;
3869 repeat = qMin(repeat, 4);
3870 if (repeat <= 2)
3871 appendToResult(month, repeat);
3872 else
3873 result.append(monthName(locale, month, year, formatType(repeat)));
3874 break;
3875
3876 case 'd':
3877 used = true;
3878 repeat = qMin(repeat, 4);
3879 if (repeat <= 2)
3880 appendToResult(day, repeat);
3881 else
3882 result.append(
3883 locale.dayName(dayOfWeek(date.toJulianDay()), formatType(repeat)));
3884 break;
3885
3886 default:
3887 break;
3888 }
3889 }
3890 if (!used && formatTime) {
3891 switch (c.unicode()) {
3892 case 'h': {
3893 used = true;
3894 repeat = qMin(repeat, 2);
3895 int hour = time.hour();
3896 if (timeFormatContainsAP(format)) {
3897 if (hour > 12)
3898 hour -= 12;
3899 else if (hour == 0)
3900 hour = 12;
3901 }
3902 appendToResult(hour, repeat);
3903 break;
3904 }
3905 case 'H':
3906 used = true;
3907 repeat = qMin(repeat, 2);
3908 appendToResult(time.hour(), repeat);
3909 break;
3910
3911 case 'm':
3912 used = true;
3913 repeat = qMin(repeat, 2);
3914 appendToResult(time.minute(), repeat);
3915 break;
3916
3917 case 's':
3918 used = true;
3919 repeat = qMin(repeat, 2);
3920 appendToResult(time.second(), repeat);
3921 break;
3922
3923 case 'A':
3924 case 'a': {
3925 QString text = time.hour() < 12 ? locale.amText() : locale.pmText();
3926 used = true;
3927 repeat = 1;
3928 if (format.mid(i + 1).startsWith(u'p', Qt::CaseInsensitive))
3929 ++repeat;
3930 if (c.unicode() == 'A' && (repeat == 1 || format.at(i + 1).unicode() == 'P'))
3931 text = std::move(text).toUpper();
3932 else if (c.unicode() == 'a' && (repeat == 1 || format.at(i + 1).unicode() == 'p'))
3933 text = std::move(text).toLower();
3934 // else 'Ap' or 'aP' => use CLDR text verbatim, preserving case
3935 result.append(text);
3936 break;
3937 }
3938
3939 case 'z':
3940 used = true;
3941 repeat = qMin(repeat, 3);
3942
3943 // note: the millisecond component is treated like the decimal part of the seconds
3944 // so ms == 2 is always printed as "002", but ms == 200 can be either "2" or "200"
3945 appendToResult(time.msec(), 3);
3946 if (repeat != 3) {
3947 const QString zero = locale.zeroDigit();
3948 if (result.endsWith(zero))
3949 result.chop(zero.size());
3950 if (result.endsWith(zero))
3951 result.chop(zero.size());
3952 }
3953 break;
3954
3955 case 't': {
3956#if QT_CONFIG(datestring)
3957 // Feature check should really apply to the whole function, but
3958 // this portion of it depends on internals entangled with the
3959 // feature.
3960 enum AbbrType { Long, Offset, Short };
3961 const auto tzAbbr = [locale](const QDateTime &when, AbbrType type) {
3962 QString text;
3963 if (type == Offset) {
3964 using Flag = QtTemporalPattern::TemporalFieldFlag;
3965 constexpr auto noPrefixOffset = Flag::Numeric | Flag::Abbreviated
3966 | Flag::NeedNoUtcPrefix | Flag::ZeroPad;
3967 text = QtTimeZoneLocale::zoneOffsetFormat(locale, locale.d->m_index,
3968 noPrefixOffset,
3969 when, when.offsetFromUtc());
3970 // When using timezone_locale data, this should always succeed:
3971 if (!text.isEmpty())
3972 return text;
3973 }
3974# if QT_CONFIG(timezone)
3975 if (type != Short || locale != QLocale::system()) {
3976 QTimeZone::NameType mode =
3977 type == Short ? QTimeZone::ShortName
3978 : type == Long ? QTimeZone::LongName : QTimeZone::OffsetName;
3979 text = when.timeRepresentation().displayName(when, mode, locale);
3980 if (!text.isEmpty())
3981 return text;
3982 // else fall back to an unlocalized one if we can find one.
3983 }
3984 if (type == Long) {
3985 // If no long name found, use IANA ID:
3986 text = QString::fromLatin1(when.timeZone().id());
3987 if (!text.isEmpty())
3988 return text;
3989 }
3990 // else: prefer QDateTime's abbreviation, for backwards-compatibility.
3991# endif // else, make do with non-localized abbreviation:
3992 // Absent timezone_locale data, Offset might still reach here:
3993 if (type == Offset) // Our prior failure might not have tried this:
3994 text = when.toOffsetFromUtc(when.offsetFromUtc()).timeZoneAbbreviation();
3995 if (text.isEmpty()) // Notably including type != Offset
3996 text = when.timeZoneAbbreviation();
3997 if (type == Offset)
3998 text = offsetFromAbbreviation(std::move(text));
3999 return text;
4000 };
4001
4002 used = true;
4003 repeat = qMin(repeat, 4);
4004 // If we don't have a date-time, use the current system time:
4005 const QDateTime when = formatDate ? datetime : QDateTime::currentDateTime();
4006 QString text;
4007 switch (repeat) {
4008 case 4:
4009 text = tzAbbr(when, Long);
4010 break;
4011 case 3: // ±hh:mm
4012 case 2: // ±hhmm (we'll remove the ':' at the end)
4013 text = tzAbbr(when, Offset);
4014 if (repeat == 2)
4015 text.remove(u':');
4016 break;
4017 default:
4018 text = tzAbbr(when, Short);
4019 // UTC-offset zones only include minutes if non-zero.
4020 if (text.startsWith("UTC"_L1) && text.size() == 6)
4021 text += ":00"_L1;
4022 break;
4023 }
4024 if (!text.isEmpty())
4025 result.append(text);
4026#endif // datestring
4027 break;
4028 }
4029
4030 default:
4031 break;
4032 }
4033 }
4034 if (!used)
4035 result.resize(result.size() + repeat, c);
4036 i += repeat;
4037 }
4038
4039 return result;
4040}
4041// End of QCalendar intrustions
4042
4043QString QLocaleData::doubleToString(double d, int precision, DoubleForm form,
4044 int width, unsigned flags) const
4045{
4046 // Although the special handling of F.P.Shortest below is limited to
4047 // DFSignificantDigits, the double-conversion library does treat it
4048 // specially for the other forms, shedding trailing zeros for DFDecimal and
4049 // using the shortest mantissa that faithfully represents the value for
4050 // DFExponent.
4051 if (precision != QLocale::FloatingPointShortest && precision < 0)
4052 precision = 6;
4053 if (width < 0)
4054 width = 0;
4055
4056 int decpt;
4057 qsizetype bufSize = 1;
4058 if (precision == QLocale::FloatingPointShortest)
4059 bufSize += std::numeric_limits<double>::max_digits10;
4060 else if (form == DFDecimal && qt_is_finite(d))
4061 bufSize += wholePartSpace(qAbs(d)) + precision;
4062 else // Add extra digit due to different interpretations of precision.
4063 bufSize += qMax(2, precision) + 1; // Must also be big enough for "nan" or "inf"
4064
4065 QVarLengthArray<char> buf(bufSize);
4066 int length;
4067 bool negative = false;
4068 qt_doubleToAscii(d, form, precision, buf.data(), bufSize, negative, length, decpt);
4069
4070 const QString prefix = signPrefix(negative && !qIsNull(d), flags);
4071 QString numStr;
4072
4073 if (length == 3
4074 && (qstrncmp(buf.data(), "inf", 3) == 0 || qstrncmp(buf.data(), "nan", 3) == 0)) {
4075 numStr = QString::fromLatin1(buf.data(), length);
4076 } else { // Handle finite values
4077 const QString zero = zeroDigit();
4078 QString digits = QString::fromLatin1(buf.data(), length);
4079
4080 if (zero == u"0") {
4081 // No need to convert digits.
4082 Q_ASSERT(std::all_of(buf.cbegin(), buf.cbegin() + length, isAsciiDigit));
4083 // That check is taken care of in unicodeForDigits, below.
4084 } else if (zero.size() == 2 && zero.at(0).isHighSurrogate()) {
4085 const char32_t zeroUcs4 = QChar::surrogateToUcs4(zero.at(0), zero.at(1));
4086 QString converted;
4087 converted.reserve(2 * digits.size());
4088 for (QChar ch : std::as_const(digits)) {
4089 const char32_t digit = unicodeForDigit(ch.unicode() - '0', zeroUcs4);
4090 Q_ASSERT(QChar::requiresSurrogates(digit));
4091 converted.append(QChar::highSurrogate(digit));
4092 converted.append(QChar::lowSurrogate(digit));
4093 }
4094 digits = std::move(converted);
4095 } else {
4096 Q_ASSERT(zero.size() == 1);
4097 Q_ASSERT(!zero.at(0).isSurrogate());
4098 char16_t z = zero.at(0).unicode();
4099 char16_t *const value = reinterpret_cast<char16_t *>(digits.data());
4100 for (qsizetype i = 0; i < digits.size(); ++i)
4101 value[i] = unicodeForDigit(value[i] - '0', z);
4102 }
4103
4104 const bool mustMarkDecimal = flags & ForcePoint;
4105 const bool groupDigits = flags & GroupDigits;
4106 const int minExponentDigits = flags & ZeroPadExponent ? 2 : 1;
4107 switch (form) {
4108 case DFExponent:
4109 numStr = exponentForm(std::move(digits), decpt, precision, PMDecimalDigits,
4110 mustMarkDecimal, minExponentDigits);
4111 break;
4112 case DFDecimal:
4113 numStr = decimalForm(std::move(digits), decpt, precision, PMDecimalDigits,
4114 mustMarkDecimal, groupDigits);
4115 break;
4116 case DFSignificantDigits: {
4117 PrecisionMode mode
4118 = (flags & AddTrailingZeroes) ? PMSignificantDigits : PMChopTrailingZeros;
4119
4120 /* POSIX specifies sprintf() to follow fprintf(), whose 'g/G' format
4121 says; with P = 6 if precision unspecified else 1 if precision is
4122 0 else precision; when 'e/E' would have exponent X, use:
4123 * 'f/F' if P > X >= -4, with precision P-1-X
4124 * 'e/E' otherwise, with precision P-1
4125 Helpfully, we already have mapped precision < 0 to 6 - except for
4126 F.P.Shortest mode, which is its own story - and those of our
4127 callers with unspecified precision either used 6 or -1 for it.
4128 */
4129 bool useDecimal;
4130 if (precision == QLocale::FloatingPointShortest) {
4131 // Find out which representation is shorter.
4132 // Set bias to everything added to exponent form but not
4133 // decimal, minus the converse.
4134
4135 const QLocaleData::GroupSizes grouping = groupSizes();
4136 // Exponent adds separator, sign and digits:
4137 int bias = 2 + minExponentDigits;
4138 // Decimal form may get grouping separators inserted:
4139 if (groupDigits && decpt >= grouping.first + grouping.least)
4140 bias -= (decpt - grouping.least) / grouping.higher + 1;
4141 // X = decpt - 1 needs two digits if decpt > 10:
4142 if (decpt > 10 && minExponentDigits == 1)
4143 ++bias;
4144 // Assume digitCount < 95, so we can ignore the 3-digit
4145 // exponent case (we'll set useDecimal false anyway).
4146
4147 const qsizetype digitCount = digits.size() / zero.size();
4148 if (!mustMarkDecimal) {
4149 // Decimal separator is skipped if at end; adjust if
4150 // that happens for only one form:
4151 if (digitCount <= decpt && digitCount > 1)
4152 ++bias; // decimal but not exponent
4153 else if (digitCount == 1 && decpt <= 0)
4154 --bias; // exponent but not decimal
4155 }
4156 // When 0 < decpt <= digitCount, the forms have equal digit
4157 // counts, plus things bias has taken into account; otherwise
4158 // decimal form's digit count is right-padded with zeros to
4159 // decpt, when decpt is positive, otherwise it's left-padded
4160 // with 1 - decpt zeros.
4161 useDecimal = (decpt <= 0 ? 1 - decpt <= bias
4162 : decpt <= digitCount ? 0 <= bias : decpt <= digitCount + bias);
4163 } else {
4164 // X == decpt - 1, POSIX's P; -4 <= X < P iff -4 < decpt <= P
4165 Q_ASSERT(precision >= 0);
4166 useDecimal = decpt > -4 && decpt <= (precision ? precision : 1);
4167 }
4168
4169 numStr = useDecimal
4170 ? decimalForm(std::move(digits), decpt, precision, mode,
4171 mustMarkDecimal, groupDigits)
4172 : exponentForm(std::move(digits), decpt, precision, mode,
4173 mustMarkDecimal, minExponentDigits);
4174 break;
4175 }
4176 }
4177
4178 // Pad with zeros. LeftAdjusted overrides ZeroPadded.
4179 if (flags & ZeroPadded && !(flags & LeftAdjusted)) {
4180 for (qsizetype i = numStr.size() / zero.size() + prefix.size(); i < width; ++i)
4181 numStr.prepend(zero);
4182 }
4183 }
4184
4185 return prefix + (flags & CapitalEorX
4186 ? std::move(numStr).toUpper()
4187 : std::move(numStr).toLower());
4188}
4189
4190QString QLocaleData::decimalForm(QString &&digits, int decpt, int precision,
4191 PrecisionMode pm, bool mustMarkDecimal,
4192 bool groupDigits) const
4193{
4194 const QString zero = zeroDigit();
4195 const auto digitWidth = zero.size();
4196 Q_ASSERT(digitWidth == 1 || digitWidth == 2);
4197 Q_ASSERT(digits.size() % digitWidth == 0);
4198
4199 // Separator needs to go at index decpt: so add zeros before or after the
4200 // given digits, if they don't reach that position already:
4201 if (decpt < 0) {
4202 for (; decpt < 0; ++decpt)
4203 digits.prepend(zero);
4204 } else {
4205 for (qsizetype i = digits.size() / digitWidth; i < decpt; ++i)
4206 digits.append(zero);
4207 }
4208
4209 switch (pm) {
4210 case PMDecimalDigits:
4211 for (qsizetype i = digits.size() / digitWidth - decpt; i < precision; ++i)
4212 digits.append(zero);
4213 break;
4214 case PMSignificantDigits:
4215 for (qsizetype i = digits.size() / digitWidth; i < precision; ++i)
4216 digits.append(zero);
4217 break;
4218 case PMChopTrailingZeros:
4219 Q_ASSERT(digits.size() / digitWidth <= qMax(decpt, 1) || !digits.endsWith(zero));
4220 break;
4221 }
4222
4223 if (mustMarkDecimal || decpt < digits.size() / digitWidth)
4224 digits.insert(decpt * digitWidth, decimalPoint());
4225
4226 if (groupDigits) {
4227 const QLocaleData::GroupSizes grouping = groupSizes();
4228 const QString group = groupSeparator();
4229 qsizetype i = decpt - grouping.least;
4230 if (i >= grouping.first) {
4231 digits.insert(i * digitWidth, group);
4232 while ((i -= grouping.higher) > 0)
4233 digits.insert(i * digitWidth, group);
4234 }
4235 }
4236
4237 if (decpt == 0)
4238 digits.prepend(zero);
4239
4240 return std::move(digits);
4241}
4242
4243QString QLocaleData::exponentForm(QString &&digits, int decpt, int precision,
4244 PrecisionMode pm, bool mustMarkDecimal,
4245 int minExponentDigits) const
4246{
4247 const QString zero = zeroDigit();
4248 const auto digitWidth = zero.size();
4249 Q_ASSERT(digitWidth == 1 || digitWidth == 2);
4250 Q_ASSERT(digits.size() % digitWidth == 0);
4251
4252 switch (pm) {
4253 case PMDecimalDigits:
4254 for (qsizetype i = digits.size() / digitWidth; i < precision + 1; ++i)
4255 digits.append(zero);
4256 break;
4257 case PMSignificantDigits:
4258 for (qsizetype i = digits.size() / digitWidth; i < precision; ++i)
4259 digits.append(zero);
4260 break;
4261 case PMChopTrailingZeros:
4262 Q_ASSERT(digits.size() / digitWidth <= 1 || !digits.endsWith(zero));
4263 break;
4264 }
4265
4266 if (mustMarkDecimal || digits.size() > digitWidth)
4267 digits.insert(digitWidth, decimalPoint());
4268
4269 digits.append(exponentSeparator());
4270 digits.append(longLongToString(decpt - 1, minExponentDigits, 10, -1, AlwaysShowSign));
4271
4272 return std::move(digits);
4273}
4274
4275QString QLocaleData::signPrefix(bool negative, unsigned flags) const
4276{
4277 if (negative)
4278 return negativeSign();
4279 if (flags & AlwaysShowSign)
4280 return positiveSign();
4281 if (flags & BlankBeforePositive)
4282 return u" "_s;
4283 return {};
4284}
4285
4286QString QLocaleData::longLongToString(qlonglong n, int precision,
4287 int base, int width, unsigned flags) const
4288{
4289 bool negative = n < 0;
4290
4291 /*
4292 Negating std::numeric_limits<qlonglong>::min() hits undefined behavior, so
4293 taking an absolute value has to take a slight detour.
4294 */
4295 QString numStr = qulltoa(negative ? 1u + qulonglong(-(n + 1)) : qulonglong(n),
4296 base, zeroDigit());
4297
4298 return applyIntegerFormatting(std::move(numStr), negative, precision, base, width, flags);
4299}
4300
4301QString QLocaleData::unsLongLongToString(qulonglong l, int precision,
4302 int base, int width, unsigned flags) const
4303{
4304 return applyIntegerFormatting(qulltoa(l, base, zeroDigit()),
4305 false, precision, base, width, flags);
4306}
4307
4308QString QLocaleData::applyIntegerFormatting(QString &&numStr, bool negative, int precision,
4309 int base, int width, unsigned flags) const
4310{
4311 const QString zero = base == 10 ? zeroDigit() : QStringLiteral("0");
4312 const auto digitWidth = zero.size();
4313 const auto digitCount = numStr.size() / digitWidth;
4314
4315 const auto basePrefix = [&] () -> QStringView {
4316 if (flags & ShowBase) {
4317 const bool upper = flags & UppercaseBase;
4318 if (base == 16)
4319 return upper ? u"0X" : u"0x";
4320 if (base == 2)
4321 return upper ? u"0B" : u"0b";
4322 if (base == 8 && !numStr.startsWith(zero))
4323 return zero;
4324 }
4325 return {};
4326 }();
4327
4328 const QString prefix = signPrefix(negative, flags) + basePrefix;
4329 // Count how much of width we've used up. Each digit counts as one
4330 qsizetype usedWidth = digitCount + prefix.size();
4331
4332 if (base == 10 && flags & GroupDigits) {
4333 const QLocaleData::GroupSizes grouping = groupSizes();
4334 const QString group = groupSeparator();
4335 qsizetype i = digitCount - grouping.least;
4336 if (i >= grouping.first) {
4337 numStr.insert(i * digitWidth, group);
4338 ++usedWidth;
4339 while ((i -= grouping.higher) > 0) {
4340 numStr.insert(i * digitWidth, group);
4341 ++usedWidth;
4342 }
4343 }
4344 // TODO: should we group any zero-padding we add later ?
4345 }
4346
4347 const bool noPrecision = precision == -1;
4348 if (noPrecision)
4349 precision = 1;
4350
4351 for (qsizetype i = numStr.size(); i < precision; ++i) {
4352 numStr.prepend(zero);
4353 usedWidth++;
4354 }
4355
4356 // LeftAdjusted overrides ZeroPadded; and sprintf() only pads when
4357 // precision is not specified in the format string.
4358 if (noPrecision && flags & ZeroPadded && !(flags & LeftAdjusted)) {
4359 for (qsizetype i = usedWidth; i < width; ++i)
4360 numStr.prepend(zero);
4361 }
4362
4363 QString result(flags & CapitalEorX ? std::move(numStr).toUpper() : std::move(numStr));
4364 if (prefix.size())
4365 result.prepend(prefix);
4366 return result;
4367}
4368
4370 : grouping(data->groupSizes()), isC(data == c())
4371 // Note: actually test pointer equality to c(), not language == C, as
4372 // system locale might be configured as C with tweaks.
4373{
4374 if (isC)
4375 return;
4376 setZero(data->zero().viewData(single_character_data));
4377 group = data->groupDelim().viewData(single_character_data);
4378 // Note: minus, plus and exponent might not actually be single characters.
4379 minus = data->minus().viewData(single_character_data);
4380 plus = data->plus().viewData(single_character_data);
4381 if (mode != IntegerMode)
4382 decimal = data->decimalSeparator().viewData(single_character_data);
4383 if (mode == DoubleScientificMode) {
4384 exponent = data->exponential().viewData(single_character_data);
4385 // exponentCyrillic means "apply the Cyrrilic-specific exponent hack"
4386 exponentCyrillic = data->m_script_id == QLocale::CyrillicScript;
4387 }
4388#ifndef QT_NO_SYSTEMLOCALE
4389 if (data == &systemLocaleData) {
4390 const auto getString = [sys = systemLocale()](QSystemLocale::QueryType query) {
4391 return sys->query(query).toString();
4392 };
4393 if (mode != IntegerMode) {
4394 sysDecimal = getString(QSystemLocale::DecimalPoint);
4395 if (sysDecimal.size())
4396 decimal = QStringView{sysDecimal};
4397 }
4398 sysGroup = getString(QSystemLocale::GroupSeparator);
4399 if (sysGroup.size())
4400 group = QStringView{sysGroup};
4401 sysMinus = getString(QSystemLocale::NegativeSign);
4402 if (sysMinus.size())
4403 minus = QStringView{sysMinus};
4404 sysPlus = getString(QSystemLocale::PositiveSign);
4405 if (sysPlus.size())
4406 plus = QStringView{sysPlus};
4407 setZero(getString(QSystemLocale::ZeroDigit));
4408 }
4409#endif
4410}
4411
4412namespace {
4413// A bit like QStringIterator but rather specialized ... and some of the tokens
4414// it recognizes aren't single Unicode code-points (but it does map each to a
4415// single character).
4416class NumericTokenizer
4417{
4418 // TODO: use deterministic finite-state-automata.
4419 // TODO QTBUG-95460: CLDR has Inf/NaN representations per locale.
4420 static constexpr char lettersInfNaN[] = "afin"; // Letters of Inf, NaN
4421 static constexpr auto matchInfNaN = QtPrivate::makeCharacterSetMatch<lettersInfNaN>();
4422 const QStringView m_text;
4423 const QLocaleData::NumericData m_guide;
4424 qsizetype m_index;
4425 const QLocaleData::NumberMode m_mode;
4426 static_assert('+' + 1 == ',' && ',' + 1 == '-' && '-' + 1 == '.');
4427 char lastMark; // C locale accepts '+' through lastMark.
4428public:
4429 NumericTokenizer(QStringView text, QLocaleData::NumericData &&guide,
4430 QLocaleData::NumberMode mode, qsizetype from = 0)
4431 : m_text(text), m_guide(guide), m_index(from), m_mode(mode),
4432 lastMark(mode == QLocaleData::IntegerMode ? '-' : '.')
4433 {
4434 Q_ASSERT(m_guide.isValid(mode));
4435 }
4436 bool done() const { return !(m_index < m_text.size()); }
4437 qsizetype index() const { return m_index; }
4438 int digitValue(char32_t digit) const { return m_guide.digitValue(digit); }
4439 bool isInfNanChar(char ch) const { return matchInfNaN.matches(ch); }
4440 char nextToken();
4441 bool fractionGroupClash() const
4442 {
4443 // If the user's hand-configuration of the system makes group and
4444 // fractional part separators coincide, we have some kludges to apply,
4445 // though we can skip them in integer mode.
4446 return Q_UNLIKELY(m_mode != QLocaleData::IntegerMode && m_guide.fractionalIsGroup());
4447 }
4448 const QLocaleData::GroupSizes &groupSizes() { return m_guide.groupSizes(); }
4449};
4450
4451char NumericTokenizer::nextToken()
4452{
4453 // As long as caller stops iterating on a zero return, those don't need to
4454 // keep m_index correctly updated.
4455 Q_ASSERT(!done());
4456 do {
4457 // Mauls non-letters above 'Z' but we don't care:
4458 const auto asciiLower = [](unsigned char c) { return c >= 'A' ? c | 0x20 : c; };
4459 const QStringView tail = m_text.sliced(m_index);
4460 const QChar ch = tail.front();
4461 if (ch == u'\u2212') {
4462 // Special case: match the "proper" minus sign, for all locales.
4463 ++m_index;
4464 return '-';
4465 }
4466 if (m_guide.isC) {
4467 // "Conversion" to C locale is just a filter:
4468 if (Q_LIKELY(ch.unicode() < 256)) {
4469 unsigned char ascii = asciiLower(ch.toLatin1());
4470 if (Q_LIKELY(isAsciiDigit(ascii) || ('+' <= ascii && ascii <= lastMark)
4471 // No caller presently (6.5) passes DoubleStandardMode,
4472 // so !IntegerMode implies scientific, for now.
4473 || (m_mode != QLocaleData::IntegerMode && isInfNanChar(ascii))
4474 || (m_mode == QLocaleData::DoubleScientificMode && ascii == 'e'))) {
4475 ++m_index;
4476 return ascii;
4477 }
4478 }
4479 return 0;
4480 }
4481 if (ch.unicode() < 256) {
4482 // Accept the C locale's digits and signs in all locales:
4483 char ascii = asciiLower(ch.toLatin1());
4484 if (isAsciiDigit(ascii) || ascii == '-' || ascii == '+'
4485 // Also its Inf and NaN letters:
4486 || (m_mode != QLocaleData::IntegerMode && isInfNanChar(ascii))) {
4487 ++m_index;
4488 return ascii;
4489 }
4490 }
4491
4492 // Other locales may be trickier:
4493 if (tail.startsWith(m_guide.minus)) {
4494 m_index += m_guide.minus.size();
4495 return '-';
4496 }
4497 if (tail.startsWith(m_guide.plus)) {
4498 m_index += m_guide.plus.size();
4499 return '+';
4500 }
4501 if (!m_guide.group.isEmpty() && tail.startsWith(m_guide.group)) {
4502 m_index += m_guide.group.size();
4503 // When group and decimal coincide, and a fractional part is not
4504 // unexpected, treat the last as a fractional part separator (and leave
4505 // the caller to special-case the situations where that causes a
4506 // parse-fail that we can dodge by not reading it that way).
4507 if (fractionGroupClash() && tail.indexOf(m_guide.decimal, m_guide.group.size()) == -1)
4508 return '.';
4509 return ',';
4510 }
4511 if (m_mode != QLocaleData::IntegerMode && tail.startsWith(m_guide.decimal)) {
4512 m_index += m_guide.decimal.size();
4513 return '.';
4514 }
4516 && tail.startsWith(m_guide.exponent, Qt::CaseInsensitive)) {
4517 m_index += m_guide.exponent.size();
4518 return 'e';
4519 }
4520
4521 // Must match qlocale_tools.h's unicodeForDigit()
4522 if (m_guide.zeroLen == 1) {
4523 if (!ch.isSurrogate()) {
4524 if (const int gap = digitValue(char32_t(ch.unicode())); gap >= 0) {
4525 ++m_index;
4526 return '0' + gap;
4527 }
4528 } else if (ch.isHighSurrogate() && tail.size() > 1 && tail.at(1).isLowSurrogate()) {
4529 return 0;
4530 }
4531 // There remain one or two things a non-surrogate might be ...
4532 } else if (ch.isHighSurrogate()) {
4533 // None of the corner cases below matches a surrogate, so return
4534 // early if we don't have a digit.
4535 if (tail.size() > 1) {
4536 if (const QChar low = tail.at(1); low.isLowSurrogate()) {
4537 if (const int gap = digitValue(QChar::surrogateToUcs4(ch, low)); gap >= 0) {
4538 m_index += 2;
4539 return '0' + gap;
4540 }
4541 }
4542 }
4543 return 0;
4544 }
4545
4546 // All cases where tail starts with properly-matched surrogate pair
4547 // have been handled by this point.
4548 Q_ASSERT(!(ch.isHighSurrogate() && tail.size() > 1 && tail.at(1).isLowSurrogate()));
4549
4550 // Weird corner cases (code above assumes these match no surrogates):
4551 switch (ch.unicode()) {
4552 // Skip over inivisble marks commonly found in numeric forms:
4553 case 0x061C: // Arabic Letter Mark (before signs in standard Arabic)
4554 case 0x200E: // Left-to-Right marker
4555 case 0x200F: // Right-to-Left marker
4556 ++m_index;
4557 continue;
4558
4559 case u' ':
4560 // Some locales use a non-breaking space (U+00A0) or its thin
4561 // version (U+202f) for grouping. These look like spaces, so people
4562 // (and thus some of our tests) use a regular space instead and
4563 // complain if it doesn't work.
4564 // Should this be extended generally to any case where group is a space ?
4565 if (m_guide.group == u"\u00a0" || m_guide.group == u"\u202f") {
4566 ++m_index;
4567 return ',';
4568 }
4569 break;
4570
4571 // Case-insensitive match:
4572 case u'E':
4573 case u'e':
4574 case u'\u0415': // Cyrillic E
4575 case u'\u0435': // Cyrillic e
4576 // Cyrillic E is used by Ukrainian as exponent; but others writing
4577 // Cyrillic may well use that; and Ukrainians might well use E.
4578 // All other Cyrillic locales (officially) use plain ASCII E.
4579 if (m_guide.exponentCyrillic) { // Only true in scientific float mode.
4580 ++m_index;
4581 return 'e';
4582 }
4583 break;
4584 }
4585
4586 break;
4587 } while (!done());
4588 return 0;
4589}
4590} // namespace with no name
4591
4592/*!
4593 \internal
4594 \since 6.12
4595 \class QLocaleData::DigitSequence
4596 \brief Descriptor for a digit sequence within a text.
4597
4598 Packages the ASCII equivalent (optional sign and) digit sequence, along with
4599 a description of which parts come from where in the original text.
4600
4601 Supports construction or assignment by moving or copying. Modifying its
4602 members, other than by assigning a newly constructed value or a result of
4603 taking a subsequence, may lead to undefined behaviour.
4604
4605 \sa sliced(), first(), last()
4606*/
4607// Exists for the benefit of date-time parsing, but could be used for anything
4608// else that doesn't do fractional parts, exponents or digit-grouping.
4609
4610/*!
4611 \fn qsizetype QLocaleData::DigitSequence::size()
4612
4613 Returns the number of ASCII characters describing the digit sequence.
4614
4615 This is the number of digits plus, if present, one for the sign. It is the
4616 number of characters \l transcribeTo() will transcribe. For the number of
4617 digits found, use \c {digits.size()}. Note that this may be less than the
4618 length of the text parsed, for example when the digits are surrogate pairs
4619 or the sign includes special Unicode markers, such as those for text
4620 direction.
4621
4622 \sa isEmpty()
4623*/
4624
4625/*!
4626 \fn void QLocaleData::DigitSequence::transcribeTo(CharBuff *buff)
4627
4628 Transcribes the ASCII form of this digit sequence to \a buff.
4629
4630 \sa size()
4631*/
4632
4633/*!
4634 \since 6.12
4635 \enum QLocaleData::DigitSequence::Option
4636
4637 Options to modify how digit sequences are parsed.
4638
4639 \value Default The null option value.
4640 \value AllowSign A leading sign character may be present.
4641
4642 In the numeric fields of a date, only a year field ever has a sign, all
4643 others use ungrouped digits. Zero-padding on the left of day and month
4644 fields is common (and it may also appear in year fields). The hour field of
4645 a zone-offset may also have a sign. Otherwise all numeric time fields are
4646 similar to numeric month and day fields.
4647
4648 In numeric fields of a time, the least-significant given (be it hour, minute
4649 or second) may have a fractional part in some formats. The handling of this
4650 is left for the caller to take care of. Likewise, the caller is expected to
4651 deal with leading and trailing space appropriately.
4652*/
4653
4654/*!
4655 \fn bool QLocaleData::DigitSequence::isEmpty() const
4656
4657 Returns true precisely if this digit sequence represents nothing.
4658
4659 This arises when the constructor found no digits and (when allowed) not even
4660 a sign. It may also result from extracting an empty subsequence of a digit
4661 sequence that was originally parsed. It is equivalent to \l
4662 {QLocaleData::DigitSequence::}{size()} == 0. To test whether any digits were
4663 found, use \c {digits.isEmpty()}, which may be true even though \c
4664 {isEmpty()} is false. That arises when only a sign was found (making
4665 \c{size() == 1}).
4666
4667 \sa size()
4668*/
4669
4670/*!
4671 \fn bool QLocaleData::DigitSequence::hasSign() const
4672
4673 Returns true precisely if the digit sequence parsed includes a leading sign.
4674 It is equivalent to \c{sign != '\0'}.
4675*/
4676
4677/*!
4678 \fn QStringView QLocaleData::DigitSequence::used(QStringView text, qsizetype from) const
4679 \fn QStringView QLocaleData::DigitSequence::used(QStringView text) const
4680
4681 Returns the slice of \a text described by this digit sequence.
4682
4683 The given \a text should be the one passed to the constructor either of this
4684 digit sequence or of one from which it was obtained by some combination of
4685 \l first(), \l sliced() and \l last(). In the directly-constructed case, or
4686 in the case of (optionally repeatedly) applying only \l first(), \a from may
4687 be passed: it should be the like-named offset passed to the original
4688 constructor, or 0 if no offset was passed. In that case, the whole text
4689 parsed for this digit sequence (alibeit possibly a prefix of the text
4690 originally parsed) is returned. Otherwise, \a from should be omitted and
4691 this function returns the text described by just the digits of this
4692 sequence, omitting (even when relevant) the sign.
4693
4694 \sa {QLocaleData::DigitSequence::}{DigitSequence()}
4695*/
4696
4697/*!
4698 \fn QLocaleData::DigitSequence QLocaleData::DigitSequence::first(qsizetype count) const
4699
4700 Returns a DigitSequence describing a prefix of this.
4701
4702 The result describes the first \a count ASCII characters to which the
4703 sequence corresponds and their positions within the parsed text. The value
4704 of \a count must not be negative or exceed \c size().
4705*/
4706
4707/*!
4708 \fn QLocaleData::DigitSequence QLocaleData::DigitSequence::last(qsizetype count) const
4709
4710 Returns a DigitSequence describing a tail of this.
4711
4712 The result describes the last \a count ASCII characters to which the
4713 sequence corresponds. The value of \a count must not be negative or exceed
4714 \c size(). The result is equivalent to \c{sliced(size() - count)}.
4715*/
4716
4717/*!
4718 \fn QLocaleData::DigitSequence QLocaleData::DigitSequence::sliced(qsizetype from) const
4719
4720 Returns a DigitSequence describing a tail of this.
4721
4722 This skips over the text to which the first \a from ASCII characters of the
4723 sequence correspond, to describe the remainder and their positions within
4724 the parsed text. The value of \a from must not be negative or exceed \c
4725 size().
4726*/
4727
4728/*!
4729 \overload
4730 \fn QLocaleData::DigitSequence QLocaleData::DigitSequence::sliced(qsizetype from, qsizetype count) const
4731
4732 Returns a DigitSequence describing a subsequence of this.
4733
4734 This skips over the portion of the text to which first \a from ASCII
4735 characters correspond and describes the portion described by the next \a
4736 count ASCII characters. The value of \a from must not be negative or exceed
4737 \c size(). The value of \a count must not be negative or exceed \c{size() -
4738 from}. The result is equivalent to \c{sliced(from).first(count)}.
4739*/
4740
4741/*!
4742 Scan \a text for an initial sequence of digits.
4743
4744 The given \a numeric provides data relevant to number-parsing, including
4745 what constitute digits. Options in \a flags control whether a leading sign
4746 may be included. If \a from is passed, the scan starts at this index in \a
4747 text, otherwise from the start.
4748
4749 The resulting \l {QLocaleData::}{DigitSequence} contains the parsed digit
4750 sequence, \c digits, describes the positions of digits within \a text, by \c
4751 digitStart and \c digitWidth, and (where allowed) reports any sign.
4752
4753 When \c digits is empty, \c digitStart is the end of the text parsed: this
4754 is either where the sign ended, when \c hasSign(), or the value of \c from
4755 passed to the constructor. Otherwise, each \c{digits[i]} represents
4756 \c{text.sliced(digitStart + i * digitWidth, digitWidth)} and the whole text
4757 parsed is \c{text.first(digitStart + digits.size() *
4758 digitWidth).sliced(from)}. Either way, if \c hasSign(), it represents
4759 \c{text.first(endIndex()).sliced(from)}.
4760
4761 \sa {QLocaleData::DigitSequence::}{used()}
4762*/
4763QLocaleData::DigitSequence::DigitSequence(QStringView text, NumericData &&numeric,
4764 Options flags, qsizetype from)
4765 : digitStart(from), digitWidth(numeric.zeroWidth())
4766{
4767 NumericTokenizer tokens(text, std::move(numeric), IntegerMode, from);
4768 if (tokens.done())
4769 return;
4770 char currentToken = tokens.nextToken();
4771 if (!currentToken)
4772 return;
4773
4774 // Handle any leading sign:
4775 if (currentToken == '+' || currentToken == '-') {
4776 if (!flags.testFlag(Option::AllowSign))
4777 return;
4778 digitStart = tokens.index();
4779 sign = currentToken;
4780 currentToken = '\0';
4781 }
4782
4783 // Iterate what remains:
4784 while (currentToken || !tokens.done()) {
4785 if (!currentToken)
4786 currentToken = tokens.nextToken();
4787 if (!currentToken)
4788 return;
4789
4790 if (currentToken < '0' || currentToken > '9')
4791 return; // What we got was not a digit in our locale.
4792
4793 // We have a digit.
4794 digits.push_back(currentToken);
4795 currentToken = '\0';
4796 }
4797}
4798
4799/*!
4800 \internal
4801 QLocaleData::DigitSequence QLocaleData::digitSequence(QStringView text, QLocaleData::DigitSequence::Options, qsizetype from)
4802 \brief Returns a DigitSequence describing some portion of \a text starting at \a from.
4803
4804 As for the \l{QLocaleData::}{DigitSequence} constructor, supplying the
4805 \l{QLocaleData::}{NumericData} for this QLocaleData instance and the
4806 IntegerMode as the relevant argument to it.
4807*/
4808
4809/*
4810 Converts a number in locale representation to the C locale equivalent.
4811
4812 Only has to guarantee that a string that is a correct representation of a
4813 number will be converted. Checks signs, separators and digits appear in all
4814 the places they should, and nowhere else.
4815
4816 Returns true precisely if the number appears to be well-formed, modulo
4817 things a parser for C Locale strings (without digit-grouping separators;
4818 they're stripped) will catch. When it returns true, it records (and
4819 '\0'-terminates) the C locale representation in *result.
4820
4821 Note: only QString integer-parsing methods have a base parameter (hence need
4822 to cope with letters as possible digits); but these are now all routed via
4823 byteArrayToU?LongLong(), so no longer come via here. The QLocale
4824 number-parsers only work in decimal, so don't have to cope with any digits
4825 other than 0 through 9.
4826*/
4827bool QLocaleData::numberToCLocale(QStringView s, QLocale::NumberOptions number_options,
4828 NumberMode mode, CharBuff *result) const
4829{
4830 s = s.trimmed();
4831 if (s.size() < 1)
4832 return false;
4833 NumericTokenizer tokens(s, NumericData(this, mode), mode);
4834
4835 // Reflects order constraints on possible parts of a number:
4836 enum { Whole, Grouped, Fraction, Exponent, Name } stage = Whole;
4837 // Grouped is just Whole with some digit-grouping separators in it.
4838 // Name is Inf or NaN; excludes all others (so none can be after it).
4839
4840 // Fractional part *or* whole-number part can be empty, but not both, unless
4841 // we have Name. Exponent must have some digits in it.
4842 bool wantDigits = true;
4843
4844 // Digit-grouping details (all modes):
4845 bool needHigherGroup = false; // Set when first group is too short to be the only one
4846 qsizetype digitsInGroup = 0;
4847 const QLocaleData::GroupSizes &grouping = tokens.groupSizes();
4848 const auto badLeastGroup = [&]() {
4849 // In principle we could object to a complete absence of grouping, when
4850 // digitsInGroup >= qMax(grouping.first, grouping.least), unless the
4851 // locale itself would omit them. However, when merely not rejecting
4852 // grouping separators, we have historically accepted ungrouped digits,
4853 // so objecting now would break existing code.
4854 if (stage == Grouped) {
4855 Q_ASSERT(!number_options.testFlag(QLocale::RejectGroupSeparator));
4856 // First group was invalid if it was short and we've not seen a separator since:
4857 if (needHigherGroup)
4858 return true;
4859 // Were there enough digits since the last group separator?
4860 if (digitsInGroup != grouping.least)
4861 return true;
4862 }
4863 return false;
4864 };
4865
4866 char last = '\0';
4867 while (!tokens.done()) {
4868 char out = tokens.nextToken();
4869 if (out == 0)
4870 return false;
4871
4872 // Note that out can only be '.', 'e' or an inf/NaN character if the
4873 // mode allows it (else nextToken() would return 0 instead), so we don't
4874 // need to check mode.
4875 if (out == '.') {
4876 if (stage > Grouped) // Too late to start a fractional part.
4877 return false;
4878
4879 if (tokens.fractionGroupClash() && badLeastGroup()
4880 && digitsInGroup == grouping.higher) {
4881 // Reinterpret '.' as ',' (as they're indistinguishable) to
4882 // interpret the recent digits as a group, with the least to
4883 // follow (hopefully of a suitable length):
4884 out = ',';
4885 stage = Grouped;
4886 needHigherGroup = false;
4887 digitsInGroup = 0;
4888 } else {
4889 // That's the end of the integral part - check size of last group:
4890 if (badLeastGroup())
4891 return false;
4892 stage = Fraction;
4893 }
4894 } else if (out == 'e') {
4895 if (wantDigits || stage == Name || stage > Fraction)
4896 return false;
4897
4898 if (stage < Fraction) {
4899 // The 'e' ends the whole-number part, so check its last group:
4900 if (badLeastGroup())
4901 return false;
4902 } else if (number_options.testFlag(QLocale::RejectTrailingZeroesAfterDot)) {
4903 // In a fractional part, a 0 just before the exponent is trailing:
4904 if (last == '0')
4905 return false;
4906 }
4907 stage = Exponent;
4908 wantDigits = true; // We need some in the exponent
4909 } else if (out == ',') {
4910 // (If tokens.fractionGroupClash(), a comma only comes out of
4911 // nextToken() if there's a later separator, since the last is
4912 // always treated as dot. So if we have a comma here, treating it as
4913 // a dot wouldn't save the parse: the later dot-or-comma would make
4914 // the text malformed.)
4915 if (number_options.testFlag(QLocale::RejectGroupSeparator))
4916 return false;
4917
4918 switch (stage) {
4919 case Whole:
4920 // Check size of most significant group
4921 if (digitsInGroup == 0
4922 || digitsInGroup > qMax(grouping.first, grouping.higher)) {
4923 return false;
4924 }
4925 Q_ASSERT(!needHigherGroup);
4926 // First group is only allowed fewer than grouping.first digits
4927 // if it's followed by a grouping.higher group, i.e. there's a
4928 // later group separator:
4929 if (grouping.first > digitsInGroup)
4930 needHigherGroup = true;
4931 stage = Grouped;
4932 break;
4933 case Grouped:
4934 // Check size of group between two separators:
4935 if (digitsInGroup != grouping.higher)
4936 return false;
4937 needHigherGroup = false; // We just found it, if needed.
4938 break;
4939 // Only allow group chars within the whole-number part:
4940 case Fraction:
4941 case Exponent:
4942 case Name:
4943 return false;
4944 }
4945 digitsInGroup = 0;
4946 } else if (isAsciiDigit(out)) {
4947 if (stage == Name)
4948 return false;
4949 if (out == '0' && number_options.testFlag(QLocale::RejectLeadingZeroInExponent)
4950 && stage > Fraction && !tokens.done() && !isAsciiDigit(last)) {
4951 // After the exponent there can only be '+', '-' or digits. If
4952 // we find a '0' directly after some non-digit, then that is a
4953 // leading zero, acceptable only if it is the whole exponent.
4954 return false;
4955 }
4956 wantDigits = false;
4957 ++digitsInGroup;
4958 } else if (stage == Whole && tokens.isInfNanChar(out)) {
4959 if (!wantDigits) // Mixed digits with Inf/NaN
4960 return false;
4961 wantDigits = false;
4962 stage = Name;
4963 }
4964 // else: nothing special to do.
4965
4966 last = out;
4967 if (out != ',') // Leave group separators out of the result.
4968 result->append(out);
4969 }
4970 if (wantDigits)
4971 return false;
4972
4973 if (!number_options.testFlag(QLocale::RejectGroupSeparator)) {
4974 // If this is the end of the whole-part, check least significant group:
4975 if (stage < Fraction && badLeastGroup())
4976 return false;
4977 }
4978
4979 if (number_options.testFlag(QLocale::RejectTrailingZeroesAfterDot) && stage == Fraction) {
4980 // In the fractional part, a final zero is trailing:
4981 if (last == '0')
4982 return false;
4983 }
4984
4985 return true;
4986}
4987
4989QLocaleData::validateChars(QStringView str, NumberMode numMode, int decDigits,
4990 QLocale::NumberOptions number_options) const
4991{
4992 ParsingResult result;
4993 result.buff.reserve(str.size());
4994
4995 enum { Whole, Fractional, Exponent } state = Whole;
4996 const bool scientific = numMode == DoubleScientificMode;
4997 NumericTokenizer tokens(str, NumericData(this, numMode), numMode);
4998 char last = '\0';
4999
5000 while (!tokens.done()) {
5001 char c = tokens.nextToken();
5002
5003 if (isAsciiDigit(c)) {
5004 switch (state) {
5005 case Whole:
5006 // Nothing special to do (unless we want to check grouping sizes).
5007 break;
5008 case Fractional:
5009 // If a double has too many digits in its fractional part it is Invalid.
5010 if (decDigits-- == 0)
5011 return {};
5012 break;
5013 case Exponent:
5014 if (!isAsciiDigit(last)) {
5015 // This is the first digit in the exponent (there may have beena '+'
5016 // or '-' in before). If it's a zero, the exponent is zero-padded.
5017 if (c == '0' && (number_options & QLocale::RejectLeadingZeroInExponent))
5018 return {};
5019 }
5020 break;
5021 }
5022
5023 } else {
5024 switch (c) {
5025 case '.':
5026 // If an integer has a decimal point, it is Invalid.
5027 // A double can only have one, at the end of its whole-number part.
5028 if (numMode == IntegerMode || state != Whole)
5029 return {};
5030 // Even when decDigits is 0, we do allow the decimal point to be
5031 // present - just as long as no digits follow it.
5032
5033 state = Fractional;
5034 break;
5035
5036 case '+':
5037 case '-':
5038 // A sign can only appear at the start or after the e of scientific:
5039 if (last != '\0' && !(scientific && last == 'e'))
5040 return {};
5041 break;
5042
5043 case ',':
5044 // Grouping is only allowed after a digit in the whole-number portion:
5045 if ((number_options & QLocale::RejectGroupSeparator) || state != Whole
5046 || !isAsciiDigit(last)) {
5047 return {};
5048 }
5049 // We could check grouping sizes are correct, but fixup()s are
5050 // probably better off correcting any misplacement instead.
5051 break;
5052
5053 case 'e':
5054 // Only one e is allowed and only in scientific:
5055 if (!scientific || state == Exponent)
5056 return {};
5057 state = Exponent;
5058 break;
5059
5060 default:
5061 // Nothing else can validly appear in a number.
5062 // NumericTokenizer allows letters of "inf" and "nan", but
5063 // validators don't accept those values.
5064 // For anything else, tokens.nextToken() must have returned 0.
5065 Q_ASSERT(!c || c == 'a' || c == 'f' || c == 'i' || c == 'n');
5066 return {};
5067 }
5068 }
5069
5070 last = c;
5071 if (c != ',') // Skip grouping
5072 result.buff.append(c);
5073 }
5074
5076
5077 // Intermediate if it ends with any character that requires a digit after
5078 // it to be valid e.g. group separator, sign, or exponent
5079 if (last == ',' || last == '-' || last == '+' || last == 'e')
5081
5082 return result;
5083}
5084
5085double QLocaleData::stringToDouble(QStringView str, bool *ok,
5086 QLocale::NumberOptions number_options) const
5087{
5088 CharBuff buff;
5089 if (!numberToCLocale(str, number_options, DoubleScientificMode, &buff)) {
5090 if (ok != nullptr)
5091 *ok = false;
5092 return 0.0;
5093 }
5094 auto r = qt_asciiToDouble(buff.constData(), buff.size());
5095 if (ok != nullptr)
5096 *ok = r.ok();
5097 return r.result;
5098}
5099
5101QLocaleData::stringToLongLong(QStringView str, int base,
5102 QLocale::NumberOptions number_options) const
5103{
5104 CharBuff buff;
5105 if (!numberToCLocale(str, number_options, IntegerMode, &buff))
5106 return {};
5107
5108 return bytearrayToLongLong(QByteArrayView(buff), base);
5109}
5110
5112QLocaleData::stringToUnsLongLong(QStringView str, int base,
5113 QLocale::NumberOptions number_options) const
5114{
5115 CharBuff buff;
5116 if (!numberToCLocale(str, number_options, IntegerMode, &buff))
5117 return {};
5118
5119 return bytearrayToUnsLongLong(QByteArrayView(buff), base);
5120}
5121
5122static bool checkParsed(QByteArrayView num, qsizetype used)
5123{
5124 if (used <= 0)
5125 return false;
5126
5127 const qsizetype len = num.size();
5128 if (used < len && num[used] != '\0') {
5129 while (used < len && ascii_isspace(num[used]))
5130 ++used;
5131 }
5132
5133 if (used < len && num[used] != '\0')
5134 // we stopped at a non-digit character after converting some digits
5135 return false;
5136
5137 return true;
5138}
5139
5140QSimpleParsedNumber<qint64> QLocaleData::bytearrayToLongLong(QByteArrayView num, int base)
5141{
5142 auto r = qstrntoll(num.data(), num.size(), base);
5143 if (!checkParsed(num, r.used))
5144 return {};
5145 return r;
5146}
5147
5148QSimpleParsedNumber<quint64> QLocaleData::bytearrayToUnsLongLong(QByteArrayView num, int base)
5149{
5150 auto r = qstrntoull(num.data(), num.size(), base);
5151 if (!checkParsed(num, r.used))
5152 return {};
5153 return r;
5154}
5155
5156/*!
5157 \since 4.8
5158
5159 \enum QLocale::CurrencySymbolFormat
5160
5161 Specifies the format of the currency symbol.
5162
5163 \value CurrencyIsoCode a ISO-4217 code of the currency.
5164 \value CurrencySymbol a currency symbol.
5165 \value CurrencyDisplayName a user readable name of the currency.
5166*/
5167
5168/*!
5169 \since 4.8
5170 Returns a currency symbol according to the \a format.
5171*/
5172QString QLocale::currencySymbol(CurrencySymbolFormat format) const
5173{
5174#ifndef QT_NO_SYSTEMLOCALE
5175 if (d->m_data == &systemLocaleData) {
5176 auto res = systemLocale()->query(QSystemLocale::CurrencySymbol, format).toString();
5177 if (!res.isEmpty())
5178 return res;
5179 }
5180#endif
5181 switch (format) {
5182 case CurrencySymbol:
5183 return d->m_data->currencySymbol().getData(currency_symbol_data);
5184 case CurrencyDisplayName:
5185 return d->m_data->currencyDisplayName().getData(currency_display_name_data);
5186 case CurrencyIsoCode: {
5187 const char *code = d->m_data->m_currency_iso_code;
5188 if (auto len = qstrnlen(code, 3))
5189 return QString::fromLatin1(code, qsizetype(len));
5190 break;
5191 }
5192 }
5193 return QString();
5194}
5195
5196/*!
5197 \since 4.8
5198
5199 Returns a localized string representation of \a value as a currency.
5200 If the \a symbol is provided it is used instead of the default currency symbol.
5201
5202 \sa currencySymbol()
5203*/
5204QString QLocale::toCurrencyString(qlonglong value, const QString &symbol) const
5205{
5206#ifndef QT_NO_SYSTEMLOCALE
5207 if (d->m_data == &systemLocaleData) {
5208 QSystemLocale::CurrencyToStringArgument arg(value, symbol);
5209 auto res = systemLocale()->query(QSystemLocale::CurrencyToString,
5210 QVariant::fromValue(arg)).toString();
5211 if (!res.isEmpty())
5212 return res;
5213 }
5214#endif
5215 QLocaleData::DataRange range = d->m_data->currencyFormatNegative();
5216 if (!range.size || value >= 0)
5217 range = d->m_data->currencyFormat();
5218 else
5219 value = -value;
5220 QString str = toString(value);
5221 QString sym = symbol.isNull() ? currencySymbol() : symbol;
5222 if (sym.isEmpty())
5223 sym = currencySymbol(CurrencyIsoCode);
5224 return range.viewData(currency_format_data).arg(str, sym);
5225}
5226
5227/*!
5228 \since 4.8
5229 \overload
5230*/
5231QString QLocale::toCurrencyString(qulonglong value, const QString &symbol) const
5232{
5233#ifndef QT_NO_SYSTEMLOCALE
5234 if (d->m_data == &systemLocaleData) {
5235 QSystemLocale::CurrencyToStringArgument arg(value, symbol);
5236 auto res = systemLocale()->query(QSystemLocale::CurrencyToString,
5237 QVariant::fromValue(arg)).toString();
5238 if (!res.isEmpty())
5239 return res;
5240 }
5241#endif
5242 QString str = toString(value);
5243 QString sym = symbol.isNull() ? currencySymbol() : symbol;
5244 if (sym.isEmpty())
5245 sym = currencySymbol(CurrencyIsoCode);
5246 return d->m_data->currencyFormat().getData(currency_format_data).arg(str, sym);
5247}
5248
5249/*!
5250 \since 5.7
5251 \overload toCurrencyString()
5252
5253 Returns a localized string representation of \a value as a currency.
5254 If the \a symbol is provided it is used instead of the default currency symbol.
5255 If the \a precision is provided it is used to set the precision of the currency value.
5256
5257 \sa currencySymbol()
5258 */
5259QString QLocale::toCurrencyString(double value, const QString &symbol, int precision) const
5260{
5261#ifndef QT_NO_SYSTEMLOCALE
5262 if (d->m_data == &systemLocaleData) {
5263 QSystemLocale::CurrencyToStringArgument arg(value, symbol);
5264 auto res = systemLocale()->query(QSystemLocale::CurrencyToString,
5265 QVariant::fromValue(arg)).toString();
5266 if (!res.isEmpty())
5267 return res;
5268 }
5269#endif
5270 QLocaleData::DataRange range = d->m_data->currencyFormatNegative();
5271 if (!range.size || value >= 0)
5272 range = d->m_data->currencyFormat();
5273 else
5274 value = -value;
5275 QString str = toString(value, 'f', precision == -1 ? d->m_data->m_currency_digits : precision);
5276 QString sym = symbol.isNull() ? currencySymbol() : symbol;
5277 if (sym.isEmpty())
5278 sym = currencySymbol(CurrencyIsoCode);
5279 return range.viewData(currency_format_data).arg(str, sym);
5280}
5281
5282/*!
5283 \fn QString QLocale::toCurrencyString(float i, const QString &symbol, int precision) const
5284 \overload toCurrencyString()
5285*/
5286
5287/*!
5288 \since 5.10
5289
5290 \enum QLocale::DataSizeFormat
5291
5292 Specifies the format for representation of data quantities.
5293
5294 \omitvalue DataSizeBase1000
5295 \omitvalue DataSizeSIQuantifiers
5296 \value DataSizeIecFormat format using base 1024 and IEC prefixes: KiB, MiB, GiB, ...
5297 \value DataSizeTraditionalFormat format using base 1024 and SI prefixes: kB, MB, GB, ...
5298 \value DataSizeSIFormat format using base 1000 and SI prefixes: kB, MB, GB, ...
5299
5300 \sa formattedDataSize()
5301*/
5302
5303/*!
5304 \since 5.10
5305
5306 Converts a size in bytes to a human-readable localized string, comprising a
5307 number and a quantified unit. The quantifier is chosen such that the number
5308 is at least one, and as small as possible. For example if \a bytes is
5309 16384, \a precision is 2, and \a format is \l DataSizeIecFormat (the
5310 default), this function returns "16.00 KiB"; for 1330409069609 bytes it
5311 returns "1.21 GiB"; and so on. If \a format is \l DataSizeIecFormat or
5312 \l DataSizeTraditionalFormat, the given number of bytes is divided by a
5313 power of 1024, with result less than 1024; for \l DataSizeSIFormat, it is
5314 divided by a power of 1000, with result less than 1000.
5315 \c DataSizeIecFormat uses the new IEC standard quantifiers Ki, Mi and so on,
5316 whereas \c DataSizeSIFormat uses the older SI quantifiers k, M, etc., and
5317 \c DataSizeTraditionalFormat abuses them.
5318*/
5319QString QLocale::formattedDataSize(qint64 bytes, int precision, DataSizeFormats format) const
5320{
5321 int power, base = 1000;
5322 if (!bytes) {
5323 power = 0;
5324 } else if (format & DataSizeBase1000) {
5325 constexpr auto log10_1000 = 3; // std::log10(1000U)
5326 power = int(std::log10(QtPrivate::qUnsignedAbs(bytes))) / log10_1000;
5327 } else {
5328 constexpr auto log2_1024 = 10; // QtPrivate::log2i(1024U);
5329 power = QtPrivate::log2i(QtPrivate::qUnsignedAbs(bytes)) / log2_1024;
5330 base = 1024;
5331 }
5332 // Only go to doubles if we'll be using a quantifier:
5333 const QString number = power
5334 ? toString(bytes / std::pow(double(base), power), 'f', qMin(precision, 3 * power))
5335 : toString(bytes);
5336
5337 // We don't support sizes in units larger than exbibytes because
5338 // the number of bytes would not fit into qint64.
5339 Q_ASSERT(power <= 6 && power >= 0);
5340 QStringView unit;
5341 if (power > 0) {
5342 QLocaleData::DataRange range = (format & DataSizeSIQuantifiers)
5343 ? d->m_data->byteAmountSI() : d->m_data->byteAmountIEC();
5344 unit = range.viewListEntry(byte_unit_data, power - 1);
5345 } else {
5346 unit = d->m_data->byteCount().viewData(byte_unit_data);
5347 }
5348
5349 return number + u' ' + unit;
5350}
5351
5352/*!
5353 \since 4.8
5354 \brief List of locale names for use in selecting translations
5355
5356 Each entry in the returned list is the name of a locale suitable to the
5357 user's preferences for what to translate the UI into. Where a name in the
5358 list is composed of several tags, they are joined as indicated by \a
5359 separator. Prior to Qt 6.7 a dash was used as separator.
5360
5361 For example, using the default separator QLocale::TagSeparator::Dash, if the
5362 user has configured their system to use English as used in the USA, the list
5363 would be "en-Latn-US", "en-US", "en-Latn", "en". The order of entries is the
5364 order in which to check for translations; earlier items in the list are to
5365 be preferred over later ones. If your translation files (or other resources
5366 specific to locale) use underscores, rather than dashes, to separate locale
5367 tags, pass QLocale::TagSeparator::Underscore as \a separator.
5368
5369 Returns a list of locale names. This may include multiple languages,
5370 especially for the system locale when multiple UI translation languages are
5371 configured. The order of entries is significant. For example, for the system
5372 locale, it reflects user preferences.
5373
5374 Prior to Qt 6.9, the list only contained explicitly configured locales and
5375 their equivalents. This led some callers to add truncations (such as from
5376 'en-Latn-DE' to 'en') as fallbacks. This could sometimes result in
5377 inappropriate choices, especially if these were tried before later entries
5378 that would be more appropriate fallbacks.
5379
5380 Starting from Qt 6.9, reasonable truncations are included in the returned
5381 list \e after all entries equivalent to the explicitly specified
5382 locales. This change allows for more accurate fallback options without
5383 callers needing to do any truncation.
5384
5385 Users can explicitly include preferred fallback locales (such as en-US) in
5386 their system configuration to control the order of preference. You are
5387 advised to rely on the order of entries in uiLanguages() rather than using
5388 custom fallback methods.
5389
5390 Most likely you do not need to use this function directly, but just pass the
5391 QLocale object to the QTranslator::load() function.
5392
5393 \sa QTranslator, bcp47Name()
5394*/
5395QStringList QLocale::uiLanguages(TagSeparator separator) const
5396{
5397 const char sep = char(separator);
5398 QStringList uiLanguages;
5399 if (uchar(sep) > 0x7f) {
5400 badSeparatorWarning("uiLanguages", sep);
5401 return uiLanguages;
5402 }
5403 QList<QLocaleId> localeIds;
5404#ifdef QT_NO_SYSTEMLOCALE
5405 constexpr bool isSystem = false;
5406#else
5407 const bool isSystem = d->m_data == &systemLocaleData;
5408 if (isSystem) {
5409 uiLanguages = systemLocale()->query(QSystemLocale::UILanguages).toStringList();
5410 if (separator != TagSeparator::Dash) {
5411 // Map from default separator, Dash, used by backends:
5412 const QChar join = QLatin1Char(sep);
5413 uiLanguages.replaceInStrings(u"-", QStringView(&join, 1));
5414 }
5415 // ... but we need to include likely-adjusted forms of each of those, too.
5416 // For now, collect up locale Ids representing the entries, for later processing:
5417 for (const auto &entry : std::as_const(uiLanguages))
5418 localeIds.append(QLocaleId::fromName(entry));
5419 if (localeIds.isEmpty())
5420 localeIds.append(systemLocale()->fallbackLocale().d->m_data->id());
5421 /* Note: Darwin allows entirely independent choice of locale and of
5422 preferred languages, so it's possible the locale implied by
5423 LanguageId, ScriptId and TerritoryId is absent from the UILanguages
5424 list and that this faithfully reflects the user's wishes. None the
5425 less, we include it (if it isn't C) in the list below, after the last
5426 with the same language and script or (if none has) at the end, in
5427 case there is no better option available. (See, QTBUG-104930.)
5428 */
5429 const QString name = QString::fromLatin1(d->m_data->id().name(sep)); // Raw name
5430 if (!name.isEmpty() && language() != C && !uiLanguages.contains(name)) {
5431 // That uses contains(name) as a cheap pre-test, but there may be an
5432 // entry that matches this on purging likely subtags.
5433 const QLocaleId id = d->m_data->id();
5434 const QLocaleId max = id.withLikelySubtagsAdded();
5435 const QLocaleId mine = max.withLikelySubtagsRemoved();
5436 // Default to putting at the end:
5437 qsizetype lastAlike = uiLanguages.size() - 1;
5438 bool seen = false;
5439 for (qsizetype i = 0; !seen && i < uiLanguages.size(); ++i) {
5440 const auto its = QLocaleId::fromName(uiLanguages.at(i)).withLikelySubtagsAdded();
5441 seen = its.withLikelySubtagsRemoved() == mine;
5442 if (!seen && its.language_id == max.language_id && its.script_id == max.script_id)
5443 lastAlike = i;
5444 }
5445 if (!seen) {
5446 localeIds.insert(lastAlike + 1, id);
5447 uiLanguages.insert(lastAlike + 1, QString::fromLatin1(id.name(sep)));
5448 }
5449 }
5450 } else
5451#endif
5452 {
5453 localeIds.append(d->m_data->id());
5454 }
5455
5456 for (qsizetype i = localeIds.size(); i-- > 0; ) {
5457 const QLocaleId id = localeIds.at(i);
5458 Q_ASSERT(id.language_id);
5459 if (id.language_id == C) {
5460 if (!uiLanguages.contains(u"C"_s))
5461 uiLanguages.append(u"C"_s);
5462 // Attempt no likely sub-tag amendments to C.
5463 continue;
5464 }
5465
5466 qsizetype j;
5467 const QByteArray prior = id.name(sep);
5468 bool faithful = true; // prior matches uiLanguages.at(j - 1)
5469 if (isSystem && i < uiLanguages.size()) {
5470 // Adding likely-adjusted forms to system locale's list.
5471 faithful = uiLanguages.at(i) == QLatin1StringView(prior);
5472 Q_ASSERT(faithful
5473 // A legacy code may get mapped to an ID with a different name:
5474 || QLocaleId::fromName(uiLanguages.at(i)).name(sep) == prior);
5475 // Insert just after the entry we're supplementing:
5476 j = i + 1;
5477 } else {
5478 // Plain locale or empty system uiLanguages; just append.
5479 if (!uiLanguages.contains(QLatin1StringView(prior)))
5480 uiLanguages.append(QString::fromLatin1(prior));
5481 j = uiLanguages.size();
5482 }
5483
5484 const QLocaleId max = id.withLikelySubtagsAdded();
5485 Q_ASSERT(max.language_id);
5486 Q_ASSERT(max.language_id == id.language_id);
5487 // We can't say the same for script or territory, though.
5488
5489 // We have various candidates to consider.
5490 const auto addIfEquivalent = [&j, &uiLanguages, max, sep, &prior, faithful](QLocaleId cid) {
5491 if (cid.withLikelySubtagsAdded() == max) {
5492 if (const QByteArray name = cid.name(sep); name != prior)
5493 uiLanguages.insert(j, QString::fromLatin1(name));
5494 else if (faithful) // Later candidates are more specific, so go before.
5495 --j;
5496 }
5497 };
5498 // language
5499 addIfEquivalent({ max.language_id, 0, 0 });
5500 // language-script
5501 if (max.script_id)
5502 addIfEquivalent({ max.language_id, max.script_id, 0 });
5503 if (id.script_id && id.script_id != max.script_id)
5504 addIfEquivalent({ id.language_id, id.script_id, 0 });
5505 // language-territory
5506 if (max.territory_id)
5507 addIfEquivalent({ max.language_id, 0, max.territory_id });
5508 if (id.territory_id && id.territory_id != max.territory_id)
5509 addIfEquivalent({ id.language_id, 0, id.territory_id });
5510 // full
5511 if (max.territory_id && max.script_id)
5512 addIfEquivalent(max);
5513 if (max.territory_id && id.script_id && id.script_id != max.script_id)
5514 addIfEquivalent({ id.language_id, id.script_id, max.territory_id });
5515 if (max.script_id && id.territory_id && id.territory_id != max.territory_id)
5516 addIfEquivalent({ id.language_id, max.script_id, id.territory_id });
5517 if (id.territory_id && id.territory_id != max.territory_id
5518 && id.script_id && id.script_id != max.script_id) {
5519 addIfEquivalent(id);
5520 }
5521 }
5522
5523 // Second pass: deduplicate.
5524 // Can't use QStringList::removeDuplicates() here, because we still need
5525 // the QDuplicateTracker, later.
5526 QDuplicateTracker<QString> known(uiLanguages.size());
5527 uiLanguages.removeIf([&](const QString &s) { return known.hasSeen(s); });
5528
5529 // Third pass: add truncations, when not already present.
5530 // Cubic in list length, but hopefully that's at most a dozen or so.
5531 const QLatin1Char cut(sep);
5532 const auto hasPrefix = [cut](auto name, QStringView stem) {
5533 // A prefix only counts if it's either full or followed by a separator.
5534 return name.startsWith(stem)
5535 && (name.size() == stem.size() || name.at(stem.size()) == cut);
5536 };
5537 // As we now forward-traverse the list, we need to keep track of the
5538 // positions just after (a) the block of things added above that are
5539 // equivalent to the current entry and (b) the block of truncations (if any)
5540 // added just after this block. All truncations of entries in (a) belong at
5541 // the end of (b); once i advances to the end of (a) it must jump to just
5542 // after (b). The more specific entries in (a) may well have truncations
5543 // that can also arise from less specific ones later in (a); for the
5544 // purposes of determining whether such truncations go at the end of (b) or
5545 // the end of the list, we thus need to ignore these matches.
5546 qsizetype afterEquivs = 0;
5547 qsizetype afterTruncs = 0;
5548 // From here onwards, we only have the truncations we're adding, whose
5549 // truncations should all have been included already.
5550 // If advancing i brings us to the end of block (a), jump to the end of (b):
5551 for (qsizetype i = 0; i < uiLanguages.size(); ++i >= afterEquivs && (i = afterTruncs)) {
5552 const QString entry = uiLanguages.at(i);
5553 const QLocaleId max = QLocaleId::fromName(entry).withLikelySubtagsAdded();
5554 // Keep track of our two blocks:
5555 if (i >= afterEquivs) {
5556 Q_ASSERT(i >= afterTruncs); // i.e. we just skipped past the end of a block
5557 afterEquivs = i + 1;
5558 // Advance past equivalents of entry:
5559 while (afterEquivs < uiLanguages.size()
5560 && QLocaleId::fromName(uiLanguages.at(afterEquivs))
5561 .withLikelySubtagsAdded() == max) {
5562 ++afterEquivs;
5563 }
5564 // We'll add any truncations starting there:
5565 afterTruncs = afterEquivs;
5566 }
5567 if (hasPrefix(entry, u"C") || hasPrefix(entry, u"und"))
5568 continue;
5569 qsizetype stopAt = uiLanguages.size();
5570 qsizetype at = entry.size(); // if 0, calls lastIndexOf(cut, -1), which is in-contract
5571 while ((at = entry.lastIndexOf(cut, at - 1)) > 0) {
5572 QString prefix = entry.first(at);
5573 // Don't test with hasSeen() as we might defer adding to later, when
5574 // we'll need known to see the later entry's offering of this prefix
5575 // as a new entry.
5576 bool found = known.contains(prefix);
5577 /* By default we append but if no later entry has this as a prefix
5578 and the locale it implies would use the same script as entry, put
5579 it after the block of consecutive equivalents of which entry is a
5580 part instead. Thus [en-NL, nl-NL, en-GB] will append en but
5581 [en-NL, en-GB, nl-NL] will put it before nl-NL, for example. We
5582 require a script match so we don't pick translations that the
5583 user cannot read, despite knowing the language. (Ideally that
5584 would be a constraint the caller can opt into / out of. See
5585 QTBUG-112765.)
5586 */
5587 bool justAfter
5588 = (QLocaleId::fromName(prefix).withLikelySubtagsAdded().script_id == max.script_id);
5589 for (qsizetype j = afterTruncs; !found && j < stopAt; ++j) {
5590 QString later = uiLanguages.at(j);
5591 if (!later.startsWith(prefix)) {
5592 const QByteArray laterFull =
5593 QLocaleId::fromName(later.replace(cut, u'-')
5594 ).withLikelySubtagsAdded().name(sep);
5595 // When prefix matches a later entry's max, it belongs later.
5596 if (hasPrefix(QLatin1StringView(laterFull), prefix))
5597 justAfter = false;
5598 continue;
5599 }
5600 // The duplicate tracker would already have spotted if equal:
5601 Q_ASSERT(later.size() > prefix.size());
5602 if (later.at(prefix.size()) == cut) {
5603 justAfter = false;
5604 // Prefix match. Shall produce the same prefix, but possibly
5605 // after prefixes of other entries in the list. If later has
5606 // a longer prefix not yet in the list, we want that before
5607 // this shorter prefix, so leave this for later, otherwise,
5608 // we include this prefix right away.
5609 QStringView head{later};
5610 for (qsizetype as = head.lastIndexOf(cut);
5611 !found && as > prefix.size(); as = head.lastIndexOf(cut)) {
5612 head = head.first(as);
5613 bool seen = false;
5614 for (qsizetype k = j + 1; !seen && k < uiLanguages.size(); ++k)
5615 seen = uiLanguages.at(k) == head;
5616 if (!seen)
5617 found = true;
5618 }
5619 }
5620 }
5621 if (found) // Don't duplicate.
5622 continue; // Some shorter truncations may still be missing.
5623 // Now we're committed to adding it, get it into known:
5624 (void) known.hasSeen(prefix);
5625 if (justAfter) {
5626 uiLanguages.insert(afterTruncs++, std::move(prefix));
5627 ++stopAt; // All later entries have moved one step later.
5628 } else {
5629 uiLanguages.append(std::move(prefix));
5630 }
5631 }
5632 }
5633
5634 return uiLanguages;
5635}
5636
5637/*!
5638 \since 5.13
5639
5640 Returns the locale to use for collation.
5641
5642 The result is usually this locale; however, the system locale (which is
5643 commonly the default locale) will return the system collation locale.
5644 The result is suitable for passing to QCollator's constructor.
5645
5646 \sa QCollator
5647*/
5648QLocale QLocale::collation() const
5649{
5650#ifndef QT_NO_SYSTEMLOCALE
5651 if (d->m_data == &systemLocaleData) {
5652 const auto res = systemLocale()->query(QSystemLocale::Collation).toString();
5653 if (!res.isEmpty())
5654 return QLocale(res);
5655 }
5656#endif
5657 return *this;
5658}
5659
5660/*!
5661 \since 4.8
5662
5663 Returns a native name of the language for the locale. For example
5664 "Schweizer Hochdeutsch" for the Swiss-German locale.
5665
5666 \sa nativeTerritoryName(), languageToString()
5667*/
5668QString QLocale::nativeLanguageName() const
5669{
5670#ifndef QT_NO_SYSTEMLOCALE
5671 if (d->m_data == &systemLocaleData) {
5672 auto res = systemLocale()->query(QSystemLocale::NativeLanguageName).toString();
5673 if (!res.isEmpty())
5674 return res;
5675 }
5676#endif
5677 return d->m_data->endonymLanguage().getData(endonyms_data);
5678}
5679
5680/*!
5681 \since 6.2
5682
5683 Returns a native name of the territory for the locale. For example
5684 "España" for Spanish/Spain locale.
5685
5686 \sa nativeLanguageName(), territoryToString()
5687*/
5688QString QLocale::nativeTerritoryName() const
5689{
5690#ifndef QT_NO_SYSTEMLOCALE
5691 if (d->m_data == &systemLocaleData) {
5692 auto res = systemLocale()->query(QSystemLocale::NativeTerritoryName).toString();
5693 if (!res.isEmpty())
5694 return res;
5695 }
5696#endif
5697 return d->m_data->endonymTerritory().getData(endonyms_data);
5698}
5699
5700#if QT_DEPRECATED_SINCE(6, 6)
5701/*!
5702 \deprecated [6.6] Use \l nativeTerritoryName() instead.
5703 \since 4.8
5704
5705 Returns a native name of the territory for the locale. For example
5706 "España" for Spanish/Spain locale.
5707
5708 \sa nativeLanguageName(), territoryToString()
5709*/
5710QString QLocale::nativeCountryName() const
5711{
5712 return nativeTerritoryName();
5713}
5714#endif
5715
5716#ifndef QT_NO_DEBUG_STREAM
5717QDebug operator<<(QDebug dbg, const QLocale &l)
5718{
5719 QDebugStateSaver saver(dbg);
5720 const bool isSys = l == QLocale::system();
5721 dbg.nospace().noquote()
5722 << (isSys ? "QLocale::system()/* " : "QLocale(")
5723 << QLocale::languageToString(l.language()) << ", "
5724 << QLocale::scriptToString(l.script()) << ", "
5725 << QLocale::territoryToString(l.territory()) << (isSys ? " */" : ")");
5726 return dbg;
5727}
5728#endif
5729QT_END_NAMESPACE
5730
5731#ifndef QT_NO_QOBJECT
5732#include "moc_qlocale.cpp"
5733#endif
const QLocaleData *const m_data
Definition qlocale_p.h:715
QLocale::MeasurementSystem measurementSystem() const
Definition qlocale.cpp:3522
QByteArray bcp47Name(char separator='-') const
Definition qlocale.cpp:498
char32_t next(char32_t invalidAs=QChar::ReplacementCharacter)
bool hasNext() const
Combined button and popup list for selecting options.
Definition qcompare.h:111
CaseSensitivity
@ CaseInsensitive
@ CaseSensitive
Q_GLOBAL_STATIC(DefaultRoleNames, qDefaultRoleNames, { { Qt::DisplayRole, "display" }, { Qt::DecorationRole, "decoration" }, { Qt::EditRole, "edit" }, { Qt::ToolTipRole, "toolTip" }, { Qt::StatusTipRole, "statusTip" }, { Qt::WhatsThisRole, "whatsThis" }, }) const QHash< int
static unsigned calculateFlags(int fieldWidth, char32_t fillChar, const QLocale &locale)
Definition qlocale.cpp:2213
static QString calculateFiller(qsizetype padding, char32_t fillChar, qsizetype fieldWidth, const QLocaleData *localeData)
Definition qlocale.cpp:2227
QDebug operator<<(QDebug dbg, const QLocale &l)
Definition qlocale.cpp:5717
static QLocalePrivate * findLocalePrivate(QLocale::Language language, QLocale::Script script, QLocale::Territory territory)
Definition qlocale.cpp:978
static std::optional< QString > systemLocaleString(const QLocaleData *that, QSystemLocale::QueryType type)
Definition qlocale.cpp:1025
static const QSystemLocale * systemLocale()
Definition qlocale.cpp:833
static bool checkParsed(QByteArrayView num, qsizetype used)
Definition qlocale.cpp:5122
static QString rawWeekDayName(const QLocaleData *data, const int day, QLocale::FormatType type)
Definition qlocale.cpp:3324
QDataStream & operator>>(QDataStream &ds, QLocale &l)
Definition qlocale.cpp:956
#define CheckCandidate(id)
static Q_DECL_COLD_FUNCTION void badSeparatorWarning(const char *method, char sep)
Definition qlocale.cpp:1514
static QString rawStandaloneWeekDayName(const QLocaleData *data, const int day, QLocale::FormatType type)
Definition qlocale.cpp:3348
static constexpr QLocale::NumberOptions defaultNumberOptions(QLocale::Language forLanguage)
Definition qlocale.cpp:772
static QStringView findTag(QStringView name) noexcept
Definition qlocale.cpp:646
static bool validTag(QStringView tag)
Definition qlocale.cpp:655
static qsizetype scriptIndex(QStringView code, Qt::CaseSensitivity cs) noexcept
Definition qlocale.cpp:187
static const QCalendarLocale & getMonthDataFor(const QLocalePrivate *loc, const QCalendarLocale *table)
Definition qlocale.cpp:3271
static T toIntegral_helper(const QLocalePrivate *d, QStringView str, bool *ok)
Definition qlocale.cpp:1562
static bool timeFormatContainsAP(QStringView format)
Definition qlocale.cpp:2430
size_t qHash(const QLocale &key, size_t seed) noexcept
Definition qlocale.cpp:1295
bool comparesEqual(const QLocale &loc, QLocale::Language lang)
Definition qlocale.cpp:999
static qsizetype findLocaleIndexById(QLocaleId localeId) noexcept
Definition qlocale.cpp:508
static constexpr qsizetype locale_data_size
Definition qlocale.cpp:527
static void updateSystemPrivate()
Definition qlocale.cpp:845
static QString rawMonthName(const QCalendarLocale &localeData, const char16_t *monthsData, int month, QLocale::FormatType type)
Definition qlocale.cpp:3298
static qsizetype stringWidth(QStringView text)
Definition qlocale.cpp:2202
static QLocalePrivate * c_private() noexcept
Definition qlocale.cpp:766
static const QLocaleData * defaultData()
Definition qlocale.cpp:920
static QString rawStandaloneMonthName(const QCalendarLocale &localeData, const char16_t *monthsData, int month, QLocale::FormatType type)
Definition qlocale.cpp:3310
static QString localeString(const QLocaleData *that, QSystemLocale::QueryType type, QLocaleData::DataRange range)
Definition qlocale.cpp:1043
static const QLocaleData * systemData(qsizetype *sysIndex=nullptr)
Definition qlocale.cpp:880
static QString offsetFromAbbreviation(QString &&text)
Definition qlocale.cpp:3733
static qsizetype defaultIndex()
Definition qlocale.cpp:927
static constexpr char16_t single_character_data[]
static constexpr char16_t days_data[]
static constexpr QLocaleData locale_data[]
static constexpr QLocaleId likely_subtags[]
static constexpr unsigned char territory_code_list[]
static constexpr unsigned char script_code_list[]
bool qt_splitLocaleName(QStringView name, QStringView *lang=nullptr, QStringView *script=nullptr, QStringView *cntry=nullptr) noexcept
Definition qlocale.cpp:666
QString qt_readEscapedFormatString(QStringView format, qsizetype *idx)
Definition qlocale.cpp:729
#define QStringLiteral(str)
Definition qstring.h:1860
char32_t ucsFirst(const char16_t *table) const
Definition qlocale_p.h:588
Descriptor for a digit sequence within a text.
Definition qlocale_p.h:453
const GroupSizes grouping
Definition qlocale_p.h:371
QString positiveSign() const
Definition qlocale.cpp:1097
QString groupSeparator() const
Definition qlocale.cpp:1056
QSimpleParsedNumber< qint64 > stringToLongLong(QStringView str, int base, QLocale::NumberOptions options) const
Definition qlocale.cpp:5101
Q_AUTOTEST_EXPORT char32_t zeroUcs() const
Definition qlocale.cpp:1076
QString zeroDigit() const
Definition qlocale.cpp:1071
bool numberToCLocale(QStringView s, QLocale::NumberOptions number_options, NumberMode mode, CharBuff *result) const
Returns a DigitSequence describing some portion of text starting at from.
Definition qlocale.cpp:4827
QString decimalPoint() const
Definition qlocale.cpp:1051
QString doubleToString(double d, int precision=-1, DoubleForm form=DFSignificantDigits, int width=-1, unsigned flags=NoFlags) const
Definition qlocale.cpp:4043
QLocaleId id() const
Definition qlocale_p.h:551
QString listSeparator() const
Definition qlocale.cpp:1066
QString percentSign() const
Definition qlocale.cpp:1061
@ AddTrailingZeroes
Definition qlocale_p.h:267
double stringToDouble(QStringView str, bool *ok, QLocale::NumberOptions options) const
Definition qlocale.cpp:5085
QString longLongToString(qint64 l, int precision=-1, int base=10, int width=-1, unsigned flags=NoFlags) const
Definition qlocale.cpp:4286
@ DoubleScientificMode
Definition qlocale_p.h:281
@ DFSignificantDigits
Definition qlocale_p.h:261
QString exponentSeparator() const
Definition qlocale.cpp:1102
QString negativeSign() const
Definition qlocale.cpp:1092
QSimpleParsedNumber< quint64 > stringToUnsLongLong(QStringView str, int base, QLocale::NumberOptions options) const
Definition qlocale.cpp:5112
QString unsLongLongToString(quint64 l, int precision=-1, int base=10, int width=-1, unsigned flags=NoFlags) const
Definition qlocale.cpp:4301
QLocaleId withLikelySubtagsAdded() const noexcept
Definition qlocale.cpp:330
QLocaleId withLikelySubtagsRemoved() const noexcept
Definition qlocale.cpp:419
ushort script_id
Definition qlocale_p.h:242
bool operator==(QLocaleId other) const noexcept
Definition qlocale_p.h:211
ushort territory_id
Definition qlocale_p.h:242
ushort language_id
Definition qlocale_p.h:242