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 Returns a localized string representation of the given \a date in the
2322 specified \a format.
2323 If \a format is an empty string, an empty string is returned.
2324
2325 \sa QDate::toString()
2326*/
2327
2328QString QLocale::toString(QDate date, const QString &format) const
2329{
2330 return toString(date, qToStringViewIgnoringNull(format));
2331}
2332
2333/*!
2334 Returns a localized string representation of the given \a time according
2335 to the specified \a format.
2336 If \a format is an empty string, an empty string is returned.
2337
2338 \sa QTime::toString()
2339*/
2340
2341QString QLocale::toString(QTime time, const QString &format) const
2342{
2343 return toString(time, qToStringViewIgnoringNull(format));
2344}
2345
2346/*!
2347 \since 4.4
2348 \fn QString QLocale::toString(const QDateTime &dateTime, const QString &format) const
2349
2350 Returns a localized string representation of the given \a dateTime according
2351 to the specified \a format.
2352 If \a format is an empty string, an empty string is returned.
2353
2354 \sa QDateTime::toString(), QDate::toString(), QTime::toString()
2355*/
2356
2357/*!
2358 \since 5.14
2359
2360 Returns a localized string representation of the given \a date in the
2361 specified \a format, optionally for a specified calendar \a cal.
2362 If \a format is an empty string, an empty string is returned.
2363
2364 \sa QDate::toString()
2365*/
2366QString QLocale::toString(QDate date, QStringView format, QCalendar cal) const
2367{
2368 return cal.dateTimeToString(format, QDateTime(), date, QTime(), *this);
2369}
2370
2371/*!
2372 \since 5.10
2373 \overload
2374*/
2375QString QLocale::toString(QDate date, QStringView format) const
2376{
2377 return QCalendar().dateTimeToString(format, QDateTime(), date, QTime(), *this);
2378}
2379
2380/*!
2381 \since 5.14
2382
2383 Returns a localized string representation of the given \a date according
2384 to the specified \a format (see dateFormat()), optionally for a specified
2385 calendar \a cal.
2386
2387 \note Some locales may use formats that limit the range of years they can
2388 represent.
2389*/
2390QString QLocale::toString(QDate date, FormatType format, QCalendar cal) const
2391{
2392 if (!date.isValid())
2393 return QString();
2394
2395#ifndef QT_NO_SYSTEMLOCALE
2396 if (cal.isGregorian() && d->m_data == &systemLocaleData) {
2397 QVariant res = systemLocale()->query(format == LongFormat
2398 ? QSystemLocale::DateToStringLong
2399 : QSystemLocale::DateToStringShort,
2400 date);
2401 if (!res.isNull())
2402 return res.toString();
2403 }
2404#endif
2405
2406 QString format_str = dateFormat(format);
2407 return toString(date, format_str, cal);
2408}
2409
2410/*!
2411 \since 4.5
2412 \overload
2413*/
2414QString QLocale::toString(QDate date, FormatType format) const
2415{
2416 if (!date.isValid())
2417 return QString();
2418
2419#ifndef QT_NO_SYSTEMLOCALE
2420 if (d->m_data == &systemLocaleData) {
2421 QVariant res = systemLocale()->query(format == LongFormat
2422 ? QSystemLocale::DateToStringLong
2423 : QSystemLocale::DateToStringShort,
2424 date);
2425 if (!res.isNull())
2426 return res.toString();
2427 }
2428#endif
2429
2430 QString format_str = dateFormat(format);
2431 return toString(date, format_str);
2432}
2433
2434static bool timeFormatContainsAP(QStringView format)
2435{
2436 qsizetype i = 0;
2437 while (i < format.size()) {
2438 if (format.at(i).unicode() == '\'') {
2439 qt_readEscapedFormatString(format, &i);
2440 continue;
2441 }
2442
2443 if (format.at(i).toLower().unicode() == 'a')
2444 return true;
2445
2446 ++i;
2447 }
2448 return false;
2449}
2450
2451/*!
2452 \since 4.5
2453
2454 Returns a localized string representation of the given \a time according
2455 to the specified \a format.
2456 If \a format is an empty string, an empty string is returned.
2457
2458 \sa QTime::toString()
2459*/
2460QString QLocale::toString(QTime time, QStringView format) const
2461{
2462 return QCalendar().dateTimeToString(format, QDateTime(), QDate(), time, *this);
2463}
2464
2465/*!
2466 \since 5.14
2467
2468 Returns a localized string representation of the given \a dateTime according
2469 to the specified \a format, optionally for a specified calendar \a cal.
2470 If \a format is an empty string, an empty string is returned.
2471
2472 \sa QDateTime::toString(), QDate::toString(), QTime::toString()
2473*/
2474QString QLocale::toString(const QDateTime &dateTime, QStringView format, QCalendar cal) const
2475{
2476 return cal.dateTimeToString(format, dateTime, QDate(), QTime(), *this);
2477}
2478
2479/*!
2480 \since 5.10
2481 \overload
2482*/
2483QString QLocale::toString(const QDateTime &dateTime, QStringView format) const
2484{
2485 return QCalendar().dateTimeToString(format, dateTime, QDate(), QTime(), *this);
2486}
2487
2488/*!
2489 \since 5.14
2490
2491 Returns a localized string representation of the given \a dateTime according
2492 to the specified \a format (see dateTimeFormat()), optionally for a
2493 specified calendar \a cal.
2494
2495 \note Some locales may use formats that limit the range of years they can
2496 represent.
2497*/
2498QString QLocale::toString(const QDateTime &dateTime, FormatType format, QCalendar cal) const
2499{
2500 if (!dateTime.isValid())
2501 return QString();
2502
2503#ifndef QT_NO_SYSTEMLOCALE
2504 if (cal.isGregorian() && d->m_data == &systemLocaleData) {
2505 QVariant res = systemLocale()->query(format == LongFormat
2506 ? QSystemLocale::DateTimeToStringLong
2507 : QSystemLocale::DateTimeToStringShort,
2508 dateTime);
2509 if (!res.isNull())
2510 return res.toString();
2511 }
2512#endif
2513
2514 const QString format_str = dateTimeFormat(format);
2515 return toString(dateTime, format_str, cal);
2516}
2517
2518/*!
2519 \since 4.4
2520 \overload
2521*/
2522QString QLocale::toString(const QDateTime &dateTime, FormatType format) const
2523{
2524 if (!dateTime.isValid())
2525 return QString();
2526
2527#ifndef QT_NO_SYSTEMLOCALE
2528 if (d->m_data == &systemLocaleData) {
2529 QVariant res = systemLocale()->query(format == LongFormat
2530 ? QSystemLocale::DateTimeToStringLong
2531 : QSystemLocale::DateTimeToStringShort,
2532 dateTime);
2533 if (!res.isNull())
2534 return res.toString();
2535 }
2536#endif
2537
2538 const QString format_str = dateTimeFormat(format);
2539 return toString(dateTime, format_str);
2540}
2541
2542
2543/*!
2544 Returns a localized string representation of the given \a time in the
2545 specified \a format (see timeFormat()).
2546*/
2547
2548QString QLocale::toString(QTime time, FormatType format) const
2549{
2550 if (!time.isValid())
2551 return QString();
2552
2553#ifndef QT_NO_SYSTEMLOCALE
2554 if (d->m_data == &systemLocaleData) {
2555 QVariant res = systemLocale()->query(format == LongFormat
2556 ? QSystemLocale::TimeToStringLong
2557 : QSystemLocale::TimeToStringShort,
2558 time);
2559 if (!res.isNull())
2560 return res.toString();
2561 }
2562#endif
2563
2564 QString format_str = timeFormat(format);
2565 return toString(time, format_str);
2566}
2567
2568/*!
2569 \since 4.1
2570
2571 Returns the date format used for the current locale.
2572
2573 If \a format is LongFormat, the format will be elaborate, otherwise it will be short.
2574 For example, LongFormat for the \c{en_US} locale is \c{dddd, MMMM d, yyyy},
2575 ShortFormat is \c{M/d/yy}.
2576
2577 \sa QDate::toString(), QDate::fromString()
2578*/
2579
2580QString QLocale::dateFormat(FormatType format) const
2581{
2582#ifndef QT_NO_SYSTEMLOCALE
2583 if (d->m_data == &systemLocaleData) {
2584 QVariant res = systemLocale()->query(format == LongFormat
2585 ? QSystemLocale::DateFormatLong
2586 : QSystemLocale::DateFormatShort,
2587 QVariant());
2588 if (!res.isNull())
2589 return res.toString();
2590 }
2591#endif
2592
2593 return (format == LongFormat
2594 ? d->m_data->longDateFormat()
2595 : d->m_data->shortDateFormat()
2596 ).getData(date_format_data);
2597}
2598
2599/*!
2600 \since 4.1
2601
2602 Returns the time format used for the current locale.
2603
2604 If \a format is LongFormat, the format will be elaborate, otherwise it will be short.
2605 For example, LongFormat for the \c{en_US} locale is \c{h:mm:ss AP t},
2606 ShortFormat is \c{h:mm AP}.
2607
2608 \sa QTime::toString(), QTime::fromString()
2609*/
2610
2611QString QLocale::timeFormat(FormatType format) const
2612{
2613#ifndef QT_NO_SYSTEMLOCALE
2614 if (d->m_data == &systemLocaleData) {
2615 QVariant res = systemLocale()->query(format == LongFormat
2616 ? QSystemLocale::TimeFormatLong
2617 : QSystemLocale::TimeFormatShort,
2618 QVariant());
2619 if (!res.isNull())
2620 return res.toString();
2621 }
2622#endif
2623
2624 return (format == LongFormat
2625 ? d->m_data->longTimeFormat()
2626 : d->m_data->shortTimeFormat()
2627 ).getData(time_format_data);
2628}
2629
2630/*!
2631 \since 4.4
2632
2633 Returns the date time format used for the current locale.
2634
2635 If \a format is LongFormat, the format will be elaborate, otherwise it will be short.
2636 For example, LongFormat for the \c{en_US} locale is \c{dddd, MMMM d, yyyy h:mm:ss AP t},
2637 ShortFormat is \c{M/d/yy h:mm AP}.
2638
2639 \sa QDateTime::toString(), QDateTime::fromString()
2640*/
2641
2642QString QLocale::dateTimeFormat(FormatType format) const
2643{
2644#ifndef QT_NO_SYSTEMLOCALE
2645 if (d->m_data == &systemLocaleData) {
2646 QVariant res = systemLocale()->query(format == LongFormat
2647 ? QSystemLocale::DateTimeFormatLong
2648 : QSystemLocale::DateTimeFormatShort,
2649 QVariant());
2650 if (!res.isNull()) {
2651 return res.toString();
2652 }
2653 }
2654#endif
2655 return dateFormat(format) + u' ' + timeFormat(format);
2656}
2657
2658#if QT_CONFIG(datestring)
2659/*!
2660 \since 4.4
2661
2662 Reads \a string as a time in a locale-specific \a format.
2663
2664 Parses \a string and returns the time it represents. The format of the time
2665 string is chosen according to the \a format parameter (see timeFormat()).
2666
2667 \note Any am/pm indicators used must match \l amText() or \l pmText(),
2668 ignoring case.
2669
2670 If the time could not be parsed, returns an invalid time.
2671
2672 \sa timeFormat(), toDate(), toDateTime(), QTime::fromString()
2673*/
2674QTime QLocale::toTime(const QString &string, FormatType format) const
2675{
2676 return toTime(string, timeFormat(format));
2677}
2678
2679/*!
2680 \since 4.4
2681
2682 Reads \a string as a date in a locale-specific \a format.
2683
2684 Parses \a string and returns the date it represents. The format of the date
2685 string is chosen according to the \a format parameter (see dateFormat()).
2686
2687//! [base-year-for-short]
2688 Some locales use, particularly for ShortFormat, only the last two digits of
2689 the year. In such a case, the 100 years starting at \a baseYear are the
2690 candidates first considered. Prior to 6.7 there was no \a baseYear parameter
2691 and 1900 was always used. This is the default for \a baseYear, selecting a
2692 year from then to 1999. In some cases, other fields may lead to the next or
2693 previous century being selected, to get a result consistent with all fields
2694 given. See \l QDate::fromString() for details.
2695//! [base-year-for-short]
2696
2697 \note Month and day names, where used, must be given in the locale's
2698 language.
2699
2700 If the date could not be parsed, returns an invalid date.
2701
2702 \sa dateFormat(), toTime(), toDateTime(), QDate::fromString()
2703*/
2704QDate QLocale::toDate(const QString &string, FormatType format, int baseYear) const
2705{
2706 return toDate(string, dateFormat(format), baseYear);
2707}
2708
2709/*!
2710 \since 5.14
2711 \overload
2712*/
2713QDate QLocale::toDate(const QString &string, FormatType format, QCalendar cal, int baseYear) const
2714{
2715 return toDate(string, dateFormat(format), cal, baseYear);
2716}
2717
2718/*!
2719 \since 4.4
2720
2721 Reads \a string as a date-time in a locale-specific \a format.
2722
2723 Parses \a string and returns the date-time it represents. The format of the
2724 date string is chosen according to the \a format parameter (see
2725 dateFormat()).
2726
2727 \include qlocale.cpp base-year-for-short
2728
2729 \note Month and day names, where used, must be given in the locale's
2730 language. Any am/pm indicators used must match \l amText() or \l pmText(),
2731 ignoring case.
2732
2733 If the string could not be parsed, returns an invalid QDateTime.
2734
2735 \sa dateTimeFormat(), toTime(), toDate(), QDateTime::fromString()
2736*/
2737QDateTime QLocale::toDateTime(const QString &string, FormatType format, int baseYear) const
2738{
2739 return toDateTime(string, dateTimeFormat(format), baseYear);
2740}
2741
2742/*!
2743 \since 5.14
2744 \overload
2745*/
2746QDateTime QLocale::toDateTime(const QString &string, FormatType format, QCalendar cal,
2747 int baseYear) const
2748{
2749 return toDateTime(string, dateTimeFormat(format), cal, baseYear);
2750}
2751
2752/*!
2753 \since 4.4
2754
2755 Reads \a string as a time in the given \a format.
2756
2757 Parses \a string and returns the time it represents. See QTime::fromString()
2758 for the interpretation of \a format.
2759
2760 \note Any am/pm indicators used must match \l amText() or \l pmText(),
2761 ignoring case.
2762
2763 If the time could not be parsed, returns an invalid time.
2764
2765 \sa timeFormat(), toDate(), toDateTime(), QTime::fromString()
2766*/
2767QTime QLocale::toTime(const QString &string, const QString &format) const
2768{
2769#if QT_CONFIG(datetimeparser)
2770 QTimePattern pattern = QTimePattern::fromQtFormat(format);
2771 pattern.setLocale(*this);
2772 if (auto match = pattern.parse(string, QTime(0, 0)); match.size == string.size())
2773 return std::move(match.payload);
2774#else
2775 Q_UNUSED(string);
2776 Q_UNUSED(format);
2777#endif
2778 return {};
2779}
2780
2781/*!
2782 \since 4.4
2783
2784 Reads \a string as a date in the given \a format.
2785
2786 Parses \a string and returns the date it represents. See QDate::fromString()
2787 for the interpretation of \a format.
2788
2789//! [base-year-for-two-digit]
2790 When \a format only specifies the last two digits of a year, the 100 years
2791 starting at \a baseYear are the candidates first considered. Prior to 6.7
2792 there was no \a baseYear parameter and 1900 was always used. This is the
2793 default for \a baseYear, selecting a year from then to 1999. In some cases,
2794 other fields may lead to the next or previous century being selected, to get
2795 a result consistent with all fields given. See \l QDate::fromString() for
2796 details.
2797//! [base-year-for-two-digit]
2798
2799 \note Month and day names, where used, must be given in the locale's
2800 language.
2801
2802 If the date could not be parsed, returns an invalid date.
2803
2804 \sa dateFormat(), toTime(), toDateTime(), QDate::fromString()
2805*/
2806QDate QLocale::toDate(const QString &string, const QString &format, int baseYear) const
2807{
2808 return toDate(string, format, QCalendar(), baseYear);
2809}
2810
2811/*!
2812 \since 5.14
2813 \overload
2814*/
2815QDate QLocale::toDate(const QString &string, const QString &format, QCalendar cal, int baseYear) const
2816{
2817#if QT_CONFIG(datetimeparser)
2818 QDatePattern pattern = QDatePattern::fromQtFormat(format);
2819 pattern.setLocale(*this);
2820 pattern.setCalendar(cal);
2821 pattern.setBaseYear(baseYear);
2822 if (auto match = pattern.parse(string, QDate(baseYear, 1, 1, cal));
2823 match.size == string.size()) {
2824 return std::move(match.payload);
2825 }
2826#else
2827 Q_UNUSED(string);
2828 Q_UNUSED(format);
2829 Q_UNUSED(cal);
2830 Q_UNUSED(baseYear);
2831#endif
2832 return {};
2833}
2834
2835/*!
2836 \since 4.4
2837
2838 Reads \a string as a date-time in the given \a format.
2839
2840 Parses \a string and returns the date-time it represents. See
2841 QDateTime::fromString() for the interpretation of \a format.
2842
2843 \include qlocale.cpp base-year-for-two-digit
2844
2845 \note Month and day names, where used, must be given in the locale's
2846 language. Any am/pm indicators used must match \l amText() or \l pmText(),
2847 ignoring case.
2848
2849 If the string could not be parsed, returns an invalid QDateTime. If the
2850 string can be parsed and represents an invalid date-time (e.g. in a gap
2851 skipped by a time-zone transition), the returned QDateTime represents a
2852 near-by datetime that is valid (typically differing from it by the width of
2853 the gap in valid datetimes, e.g. the hour skipped by a transition). Passing
2854 that to fromMSecsSinceEpoch() will produce a valid date-time that isn't
2855 faithfully represented by the string parsed.
2856
2857 \sa dateTimeFormat(), toTime(), toDate(), QDateTime::fromString()
2858*/
2859QDateTime QLocale::toDateTime(const QString &string, const QString &format, int baseYear) const
2860{
2861 return toDateTime(string, format, QCalendar(), baseYear);
2862}
2863
2864/*!
2865 \since 5.14
2866 \overload
2867*/
2868QDateTime QLocale::toDateTime(const QString &string, const QString &format, QCalendar cal,
2869 int baseYear) const
2870{
2871#if QT_CONFIG(datetimeparser)
2872 QDateTimePattern pattern = QDateTimePattern::fromQtFormat(format);
2873 pattern.setLocale(*this);
2874 pattern.setCalendar(cal);
2875 pattern.setBaseYear(baseYear);
2876 if (auto match = pattern.parse(string, QDate(baseYear, 1, 1, cal).startOfDay());
2877 match.size == string.size()) {
2878 return std::move(match.payload);
2879 }
2880#else
2881 Q_UNUSED(string);
2882 Q_UNUSED(format);
2883 Q_UNUSED(cal);
2884 Q_UNUSED(baseYear);
2885#endif
2886 return {};
2887}
2888#endif // datestring
2889
2890/*!
2891 \since 4.1
2892
2893 Returns the fractional part separator for this locale.
2894
2895 This is the token that separates the whole number part from the fracional
2896 part in the representation of a number which has a fractional part. This is
2897 commonly called the "decimal point character" - even though, in many
2898 locales, it is not a "point" (or similar dot). It is (since Qt 6.0) returned
2899 as a string in case some locale needs more than one UTF-16 code-point to
2900 represent its separator.
2901
2902 \sa groupSeparator(), toString()
2903*/
2904QString QLocale::decimalPoint() const
2905{
2906 return d->m_data->decimalPoint();
2907}
2908
2909/*!
2910 \since 4.1
2911
2912 Returns the digit-grouping separator for this locale.
2913
2914 This is a token used to break up long sequences of digits, in the
2915 representation of a number, to make it easier to read. In some locales it
2916 may be empty, indicating that digits should not be broken up into groups in
2917 this way. In others it may be a spacing character. It is (since Qt 6.0)
2918 returned as a string in case some locale needs more than one UTF-16
2919 code-point to represent its separator.
2920
2921 \sa decimalPoint(), toString()
2922*/
2923QString QLocale::groupSeparator() const
2924{
2925 return d->m_data->groupSeparator();
2926}
2927
2928/*!
2929 \since 4.1
2930
2931 Returns the percent marker of this locale.
2932
2933 This is a token presumed to be appended to a number to indicate a
2934 percentage. It is (since Qt 6.0) returned as a string because, in some
2935 locales, it is not a single character - for example, because it includes a
2936 text-direction-control character.
2937
2938 \sa toString()
2939*/
2940QString QLocale::percent() const
2941{
2942 return d->m_data->percentSign();
2943}
2944
2945/*!
2946 \since 4.1
2947
2948 Returns the zero digit character of this locale.
2949
2950 This is a single Unicode character but may be encoded as a surrogate pair,
2951 so is (since Qt 6.0) returned as a string. In most locales, other digits
2952 follow it in Unicode ordering - however, some number systems, notably those
2953 using U+3007 as zero, do not have contiguous digits. Use toString() to
2954 obtain suitable representations of numbers, rather than trying to construct
2955 them from this zero digit.
2956
2957 \sa toString()
2958*/
2959QString QLocale::zeroDigit() const
2960{
2961 return d->m_data->zeroDigit();
2962}
2963
2964/*!
2965 \since 4.1
2966
2967 Returns the negative sign indicator of this locale.
2968
2969 This is a token presumed to be used as a prefix to a number to indicate that
2970 it is negative. It is (since Qt 6.0) returned as a string because, in some
2971 locales, it is not a single character - for example, because it includes a
2972 text-direction-control character.
2973
2974 \sa positiveSign(), toString()
2975*/
2976QString QLocale::negativeSign() const
2977{
2978 return d->m_data->negativeSign();
2979}
2980
2981/*!
2982 \since 4.5
2983
2984 Returns the positive sign indicator of this locale.
2985
2986 This is a token presumed to be used as a prefix to a number to indicate that
2987 it is positive. It is (since Qt 6.0) returned as a string because, in some
2988 locales, it is not a single character - for example, because it includes a
2989 text-direction-control character.
2990
2991 \sa negativeSign(), toString()
2992*/
2993QString QLocale::positiveSign() const
2994{
2995 return d->m_data->positiveSign();
2996}
2997
2998/*!
2999 \since 4.1
3000
3001 Returns the exponent separator for this locale.
3002
3003 This is a token used to separate mantissa from exponent in some
3004 floating-point numeric representations. It is (since Qt 6.0) returned as a
3005 string because, in some locales, it is not a single character - for example,
3006 it may consist of a multiplication sign and a representation of the "ten to
3007 the power" operator.
3008
3009 \sa toString(double, char, int)
3010*/
3011QString QLocale::exponential() const
3012{
3013 return d->m_data->exponentSeparator();
3014}
3015
3016/*!
3017 \overload
3018 Returns a string representing the floating-point number \a f.
3019
3020 The form of the representation is controlled by the \a format and \a
3021 precision parameters.
3022
3023 The \a format defaults to \c{'g'}. It can be any of the following:
3024
3025 \table
3026 \header \li Format \li Meaning \li Meaning of \a precision
3027 \row \li \c 'e' \li format as [-]9.9e[+|-]999 \li number of digits \e after the decimal point
3028 \row \li \c 'E' \li format as [-]9.9E[+|-]999 \li "
3029 \row \li \c 'f' \li format as [-]9.9 \li "
3030 \row \li \c 'F' \li same as \c 'f' except for INF and NAN (see below) \li "
3031 \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)
3032 \row \li \c 'G' \li use \c 'E' or \c 'F' format, whichever is more concise \li "
3033 \endtable
3034
3035 The special \a precision value QLocale::FloatingPointShortest selects the
3036 shortest representation that, when read as a number, gets back the original floating-point
3037 value. Aside from that, any negative \a precision is ignored in favor of the
3038 default, 6.
3039
3040 For the \c 'e', \c 'f' and \c 'g' formats, positive infinity is represented
3041 as "inf", negative infinity as "-inf" and floating-point NaN (not-a-number)
3042 values are represented as "nan". For the \c 'E', \c 'F' and \c 'G' formats,
3043 "INF" and "NAN" are used instead. This does not vary with locale.
3044
3045 \sa toDouble(), numberOptions(), exponential(), decimalPoint(), zeroDigit(),
3046 positiveSign(), percent(), toCurrencyString(), formattedDataSize(),
3047 QLocale::FloatingPointPrecisionOption
3048*/
3049
3050QString QLocale::toString(double f, char format, int precision) const
3051{
3052 QLocaleData::DoubleForm form = QLocaleData::DFDecimal;
3053 uint flags = isAsciiUpper(format) ? QLocaleData::CapitalEorX : 0;
3054
3055 switch (QtMiscUtils::toAsciiLower(format)) {
3056 case 'f':
3057 form = QLocaleData::DFDecimal;
3058 break;
3059 case 'e':
3060 form = QLocaleData::DFExponent;
3061 break;
3062 case 'g':
3063 form = QLocaleData::DFSignificantDigits;
3064 break;
3065 default:
3066 break;
3067 }
3068
3069 if (!(d->m_numberOptions & OmitGroupSeparator))
3070 flags |= QLocaleData::GroupDigits;
3071 if (!(d->m_numberOptions & OmitLeadingZeroInExponent))
3072 flags |= QLocaleData::ZeroPadExponent;
3073 if (d->m_numberOptions & IncludeTrailingZeroesAfterDot)
3074 flags |= QLocaleData::AddTrailingZeroes;
3075 return d->m_data->doubleToString(f, precision, form, -1, flags);
3076}
3077
3078/*!
3079 Returns a QLocale object initialized to the "C" locale.
3080
3081 This locale is based on en_US but with various quirks of its own, such as
3082 simplified number formatting and its own date formatting. It implements the
3083 POSIX standards that describe the behavior of standard library functions of
3084 the "C" programming language.
3085
3086 Among other things, this means its collation order is based on the ASCII
3087 values of letters, so that (for case-sensitive sorting) all upper-case
3088 letters sort before any lower-case one (rather than each letter's upper- and
3089 lower-case forms sorting adjacent to one another, before the next letter's
3090 two forms).
3091
3092 \sa system()
3093*/
3094QLocale QLocale::c() noexcept
3095{
3096 return QLocale(*c_private());
3097}
3098
3099/*!
3100 Returns a QLocale object initialized to the system locale.
3101
3102 The system locale may use system-specific sources for locale data, where
3103 available, otherwise falling back on QLocale's built-in database entry for
3104 the language, script and territory the system reports.
3105
3106 For example, on Windows and Mac, this locale will use the decimal/grouping
3107 characters and date/time formats specified in the system configuration
3108 panel.
3109
3110 \sa c()
3111*/
3112
3113QLocale QLocale::system()
3114{
3115 constexpr auto sysData = []() {
3116 // Same return as systemData(), but leave the setup to the actual call to it.
3117#ifdef QT_NO_SYSTEMLOCALE
3118 return locale_data;
3119#else
3120 return &systemLocaleData;
3121#endif
3122 };
3123 Q_CONSTINIT static QLocalePrivate locale(sysData(), -1, DefaultNumberOptions, 1);
3124 // Calling systemData() ensures system data is up to date; we also need it
3125 // to ensure that locale's index stays up to date:
3126 systemData(&locale.m_index);
3127 Q_ASSERT(locale.m_index >= 0 && locale.m_index < locale_data_size);
3128 locale.m_numberOptions = defaultNumberOptions(locale.m_data->m_language_id);
3129
3130 return QLocale(locale);
3131}
3132
3133/*!
3134 Returns a list of valid locale objects that match the given \a language, \a
3135 script and \a territory.
3136
3137 Getting a list of all locales:
3138 QList<QLocale> allLocales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript,
3139 QLocale::AnyTerritory);
3140
3141 Getting a list of locales suitable for Russia:
3142 QList<QLocale> locales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript,
3143 QLocale::Russia);
3144*/
3145QList<QLocale> QLocale::matchingLocales(Language language, Script script, Territory territory)
3146{
3147 QList<QLocale> result;
3148
3149 const QLocaleId filter { language, script, territory };
3150 if (!filter.isValid())
3151 return result;
3152
3153 if (language == C) {
3154 result.emplace_back(C);
3155 return result;
3156 }
3157
3158 if (filter.matchesAll())
3159 result.reserve(locale_data_size);
3160
3161 quint16 index = locale_index[language];
3162 // There may be no matches, for some languages (e.g. Abkhazian at CLDR v39).
3163 while (index < locale_data_size
3164 && filter.acceptLanguage(locale_data[index].m_language_id)) {
3165 const QLocaleId id = locale_data[index].id();
3166 if (filter.acceptScriptTerritory(id)) {
3167 result.append(QLocale(*(id.language_id == C ? c_private()
3168 : new QLocalePrivate(locale_data + index, index))));
3169 }
3170 ++index;
3171 }
3172
3173 // Add current system locale, if it matches
3174 const auto syslocaledata = systemData();
3175
3176 if (filter.acceptLanguage(syslocaledata->m_language_id)) {
3177 const QLocaleId id = syslocaledata->id();
3178 if (filter.acceptScriptTerritory(id))
3179 result.append(system());
3180 }
3181
3182 return result;
3183}
3184
3185#if QT_DEPRECATED_SINCE(6, 6)
3186/*!
3187 \deprecated [6.6] Use \l matchingLocales() instead and consult the \l territory() of each.
3188 \since 4.3
3189
3190 Returns the list of countries that have entries for \a language in Qt's locale
3191 database. If the result is an empty list, then \a language is not represented in
3192 Qt's locale database.
3193
3194 \sa matchingLocales()
3195*/
3196QList<QLocale::Country> QLocale::countriesForLanguage(Language language)
3197{
3198 const auto locales = matchingLocales(language, AnyScript, AnyCountry);
3199 QList<Country> result;
3200 result.reserve(locales.size());
3201 for (const auto &locale : locales)
3202 result.append(locale.territory());
3203 return result;
3204}
3205#endif
3206
3207/*!
3208 \since 4.2
3209
3210 Returns the localized name of \a month, in the format specified
3211 by \a type.
3212
3213 For example, if the locale is \c en_US and \a month is 1,
3214 \l LongFormat will return \c January. \l ShortFormat \c Jan,
3215 and \l NarrowFormat \c J.
3216
3217 \sa dayName(), standaloneMonthName()
3218*/
3219QString QLocale::monthName(int month, FormatType type) const
3220{
3221 return QCalendar().monthName(*this, month, QCalendar::Unspecified, type);
3222}
3223
3224/*!
3225 \since 4.5
3226
3227 Returns the localized name of \a month that is used as a
3228 standalone text, in the format specified by \a type.
3229
3230 If the locale information doesn't specify the standalone month
3231 name then return value is the same as in monthName().
3232
3233 \sa monthName(), standaloneDayName()
3234*/
3235QString QLocale::standaloneMonthName(int month, FormatType type) const
3236{
3237 return QCalendar().standaloneMonthName(*this, month, QCalendar::Unspecified, type);
3238}
3239
3240/*!
3241 \since 4.2
3242
3243 Returns the localized name of the \a day (where 1 represents
3244 Monday, 2 represents Tuesday and so on), in the format specified
3245 by \a type.
3246
3247 For example, if the locale is \c en_US and \a day is 1,
3248 \l LongFormat will return \c Monday, \l ShortFormat \c Mon,
3249 and \l NarrowFormat \c M.
3250
3251 \sa monthName(), standaloneDayName()
3252*/
3253QString QLocale::dayName(int day, FormatType type) const
3254{
3255 return QCalendar().weekDayName(*this, day, type);
3256}
3257
3258/*!
3259 \since 4.5
3260
3261 Returns the localized name of the \a day (where 1 represents
3262 Monday, 2 represents Tuesday and so on) that is used as a
3263 standalone text, in the format specified by \a type.
3264
3265 If the locale information does not specify the standalone day
3266 name then return value is the same as in dayName().
3267
3268 \sa dayName(), standaloneMonthName()
3269*/
3270QString QLocale::standaloneDayName(int day, FormatType type) const
3271{
3272 return QCalendar().standaloneWeekDayName(*this, day, type);
3273}
3274
3275// Calendar look-up of month and day names:
3276
3277// Get locale-specific month name data:
3279 const QCalendarLocale *table)
3280{
3281 // Only used in assertions
3282 [[maybe_unused]] const auto sameLocale = [](const QLocaleData &locale,
3283 const QCalendarLocale &cal) {
3284 return locale.m_language_id == cal.m_language_id
3285 && locale.m_script_id == cal.m_script_id
3286 && locale.m_territory_id == cal.m_territory_id;
3287 };
3288 const QCalendarLocale &monthly = table[loc->m_index];
3289#ifdef QT_NO_SYSTEMLOCALE
3290 [[maybe_unused]] constexpr bool isSys = false;
3291#else // Can't have preprocessor directives in a macro's parameter list, so use local.
3292 [[maybe_unused]] const bool isSys = loc->m_data == &systemLocaleData;
3293#endif
3294 Q_ASSERT(loc->m_data == &locale_data[loc->m_index] || isSys);
3295 // Compare monthly to locale_data[] entry, as the m_index used with
3296 // systemLocaleData is a best fit, not necessarily an exact match.
3297 Q_ASSERT(sameLocale(locale_data[loc->m_index], monthly));
3298 return monthly;
3299}
3300
3301/*!
3302 \internal
3303 */
3304
3305static QString rawMonthName(const QCalendarLocale &localeData,
3306 const char16_t *monthsData, int month,
3307 QLocale::FormatType type)
3308{
3309 const QLocaleData::DataRange range = localeData.monthName(type);
3310 return range.getListEntry(monthsData, month - 1);
3311}
3312
3313/*!
3314 \internal
3315 */
3316
3317static QString rawStandaloneMonthName(const QCalendarLocale &localeData,
3318 const char16_t *monthsData, int month,
3319 QLocale::FormatType type)
3320{
3321 const QLocaleData::DataRange range = localeData.standaloneMonthName(type);
3322 if (QString name = range.getListEntry(monthsData, month - 1); !name.isEmpty())
3323 return name;
3324 return rawMonthName(localeData, monthsData, month, type);
3325}
3326
3327/*!
3328 \internal
3329 */
3330
3331static QString rawWeekDayName(const QLocaleData *data, const int day,
3332 QLocale::FormatType type)
3333{
3334 QLocaleData::DataRange range;
3335 switch (type) {
3336 case QLocale::LongFormat:
3337 range = data->longDayNames();
3338 break;
3339 case QLocale::ShortFormat:
3340 range = data->shortDayNames();
3341 break;
3342 case QLocale::NarrowFormat:
3343 range = data->narrowDayNames();
3344 break;
3345 default:
3346 return QString();
3347 }
3348 return range.getListEntry(days_data, day == 7 ? 0 : day);
3349}
3350
3351/*!
3352 \internal
3353 */
3354
3355static QString rawStandaloneWeekDayName(const QLocaleData *data, const int day,
3356 QLocale::FormatType type)
3357{
3358 QLocaleData::DataRange range;
3359 switch (type) {
3360 case QLocale::LongFormat:
3361 range =data->longDayNamesStandalone();
3362 break;
3363 case QLocale::ShortFormat:
3364 range = data->shortDayNamesStandalone();
3365 break;
3366 case QLocale::NarrowFormat:
3367 range = data->narrowDayNamesStandalone();
3368 break;
3369 default:
3370 return QString();
3371 }
3372 QString name = range.getListEntry(days_data, day == 7 ? 0 : day);
3373 if (name.isEmpty())
3374 return rawWeekDayName(data, day, type);
3375 return name;
3376}
3377
3378// Refugees from qcalendar.cpp that need functions above:
3379
3380QString QCalendarBackend::monthName(const QLocale &locale, int month, int,
3381 QLocale::FormatType format) const
3382{
3383 Q_ASSERT(month >= 1 && month <= maximumMonthsInYear());
3384 return rawMonthName(getMonthDataFor(locale.d, localeMonthIndexData()),
3385 localeMonthData(), month, format);
3386}
3387
3388QString QRomanCalendar::monthName(const QLocale &locale, int month, int year,
3389 QLocale::FormatType format) const
3390{
3391#ifndef QT_NO_SYSTEMLOCALE
3392 if (locale.d->m_data == &systemLocaleData) {
3393 Q_ASSERT(month >= 1 && month <= 12);
3394 QSystemLocale::QueryType queryType = QSystemLocale::MonthNameLong;
3395 switch (format) {
3396 case QLocale::LongFormat:
3397 queryType = QSystemLocale::MonthNameLong;
3398 break;
3399 case QLocale::ShortFormat:
3400 queryType = QSystemLocale::MonthNameShort;
3401 break;
3402 case QLocale::NarrowFormat:
3403 queryType = QSystemLocale::MonthNameNarrow;
3404 break;
3405 }
3406 QVariant res = systemLocale()->query(queryType, month);
3407 if (!res.isNull())
3408 return res.toString();
3409 }
3410#endif
3411
3412 return QCalendarBackend::monthName(locale, month, year, format);
3413}
3414
3415QString QCalendarBackend::standaloneMonthName(const QLocale &locale, int month, int,
3416 QLocale::FormatType format) const
3417{
3418 Q_ASSERT(month >= 1 && month <= maximumMonthsInYear());
3419 return rawStandaloneMonthName(getMonthDataFor(locale.d, localeMonthIndexData()),
3420 localeMonthData(), month, format);
3421}
3422
3423QString QRomanCalendar::standaloneMonthName(const QLocale &locale, int month, int year,
3424 QLocale::FormatType format) const
3425{
3426#ifndef QT_NO_SYSTEMLOCALE
3427 if (locale.d->m_data == &systemLocaleData) {
3428 Q_ASSERT(month >= 1 && month <= 12);
3429 QSystemLocale::QueryType queryType = QSystemLocale::StandaloneMonthNameLong;
3430 switch (format) {
3431 case QLocale::LongFormat:
3432 queryType = QSystemLocale::StandaloneMonthNameLong;
3433 break;
3434 case QLocale::ShortFormat:
3435 queryType = QSystemLocale::StandaloneMonthNameShort;
3436 break;
3437 case QLocale::NarrowFormat:
3438 queryType = QSystemLocale::StandaloneMonthNameNarrow;
3439 break;
3440 }
3441 QVariant res = systemLocale()->query(queryType, month);
3442 if (!res.isNull())
3443 return res.toString();
3444 }
3445#endif
3446
3447 return QCalendarBackend::standaloneMonthName(locale, month, year, format);
3448}
3449
3450// Most calendars share the common week-day naming, modulo locale.
3451// Calendars that don't must override these methods.
3452QString QCalendarBackend::weekDayName(const QLocale &locale, int day,
3453 QLocale::FormatType format) const
3454{
3455 if (day < 1 || day > 7)
3456 return QString();
3457
3458#ifndef QT_NO_SYSTEMLOCALE
3459 if (locale.d->m_data == &systemLocaleData) {
3460 QSystemLocale::QueryType queryType = QSystemLocale::DayNameLong;
3461 switch (format) {
3462 case QLocale::LongFormat:
3463 queryType = QSystemLocale::DayNameLong;
3464 break;
3465 case QLocale::ShortFormat:
3466 queryType = QSystemLocale::DayNameShort;
3467 break;
3468 case QLocale::NarrowFormat:
3469 queryType = QSystemLocale::DayNameNarrow;
3470 break;
3471 }
3472 QVariant res = systemLocale()->query(queryType, day);
3473 if (!res.isNull())
3474 return res.toString();
3475 }
3476#endif
3477
3478 return rawWeekDayName(locale.d->m_data, day, format);
3479}
3480
3481QString QCalendarBackend::standaloneWeekDayName(const QLocale &locale, int day,
3482 QLocale::FormatType format) const
3483{
3484 if (day < 1 || day > 7)
3485 return QString();
3486
3487#ifndef QT_NO_SYSTEMLOCALE
3488 if (locale.d->m_data == &systemLocaleData) {
3489 QSystemLocale::QueryType queryType = QSystemLocale::StandaloneDayNameLong;
3490 switch (format) {
3491 case QLocale::LongFormat:
3492 queryType = QSystemLocale::StandaloneDayNameLong;
3493 break;
3494 case QLocale::ShortFormat:
3495 queryType = QSystemLocale::StandaloneDayNameShort;
3496 break;
3497 case QLocale::NarrowFormat:
3498 queryType = QSystemLocale::StandaloneDayNameNarrow;
3499 break;
3500 }
3501 QVariant res = systemLocale()->query(queryType, day);
3502 if (!res.isNull())
3503 return res.toString();
3504 }
3505#endif
3506
3507 return rawStandaloneWeekDayName(locale.d->m_data, day, format);
3508}
3509
3510// End of this block of qcalendar.cpp refugees. (One more follows.)
3511
3512/*!
3513 \since 4.8
3514
3515 Returns the first day of the week according to the current locale.
3516*/
3517Qt::DayOfWeek QLocale::firstDayOfWeek() const
3518{
3519#ifndef QT_NO_SYSTEMLOCALE
3520 if (d->m_data == &systemLocaleData) {
3521 const auto res = systemLocale()->query(QSystemLocale::FirstDayOfWeek);
3522 if (!res.isNull())
3523 return static_cast<Qt::DayOfWeek>(res.toUInt());
3524 }
3525#endif
3526 return static_cast<Qt::DayOfWeek>(d->m_data->m_first_day_of_week);
3527}
3528
3530{
3531 /* Unicode CLDR's information about measurement systems doesn't say which to
3532 use by default in each locale. Even if it did, adding another entry in
3533 every locale's row of locale_data[] would take up much more memory than
3534 the small table below.
3535 */
3536 struct TerritoryLanguage
3537 {
3538 quint16 languageId;
3539 quint16 territoryId;
3540 QLocale::MeasurementSystem system;
3541 };
3542 // TODO: research how realistic and/or complete this is:
3543 constexpr TerritoryLanguage ImperialMeasurementSystems[] = {
3544 { QLocale::English, QLocale::UnitedStates, QLocale::ImperialUSSystem },
3545 { QLocale::English, QLocale::UnitedStatesMinorOutlyingIslands, QLocale::ImperialUSSystem },
3546 { QLocale::Spanish, QLocale::UnitedStates, QLocale::ImperialUSSystem },
3547 { QLocale::Hawaiian, QLocale::UnitedStates, QLocale::ImperialUSSystem },
3548 { QLocale::English, QLocale::UnitedKingdom, QLocale::ImperialUKSystem }
3549 };
3550
3551 for (const auto &system : ImperialMeasurementSystems) {
3552 if (system.languageId == m_data->m_language_id
3553 && system.territoryId == m_data->m_territory_id) {
3554 return system.system;
3555 }
3556 }
3557 return QLocale::MetricSystem;
3558}
3559
3560/*!
3561 \since 4.8
3562
3563 Returns a list of days that are considered weekdays according to the current locale.
3564*/
3565QList<Qt::DayOfWeek> QLocale::weekdays() const
3566{
3567#ifndef QT_NO_SYSTEMLOCALE
3568 if (d->m_data == &systemLocaleData) {
3569 auto res
3570 = qvariant_cast<QList<Qt::DayOfWeek> >(systemLocale()->query(QSystemLocale::Weekdays));
3571 if (!res.isEmpty())
3572 return res;
3573 }
3574#endif
3575 QList<Qt::DayOfWeek> weekdays;
3576 quint16 weekendStart = d->m_data->m_weekend_start;
3577 quint16 weekendEnd = d->m_data->m_weekend_end;
3578 for (int day = Qt::Monday; day <= Qt::Sunday; day++) {
3579 if ((weekendEnd >= weekendStart && (day < weekendStart || day > weekendEnd)) ||
3580 (weekendEnd < weekendStart && (day > weekendEnd && day < weekendStart)))
3581 weekdays << static_cast<Qt::DayOfWeek>(day);
3582 }
3583 return weekdays;
3584}
3585
3586/*!
3587 \since 4.4
3588
3589 Returns the measurement system for the locale.
3590*/
3591QLocale::MeasurementSystem QLocale::measurementSystem() const
3592{
3593#ifndef QT_NO_SYSTEMLOCALE
3594 if (d->m_data == &systemLocaleData) {
3595 const auto res = systemLocale()->query(QSystemLocale::MeasurementSystem);
3596 if (!res.isNull())
3597 return MeasurementSystem(res.toInt());
3598 }
3599#endif
3600
3601 return d->measurementSystem();
3602}
3603
3604/*!
3605 \since 4.7
3606
3607 Returns the text direction of the language.
3608*/
3609Qt::LayoutDirection QLocale::textDirection() const
3610{
3611 switch (script()) {
3612 case AdlamScript:
3613 case ArabicScript:
3614 case AvestanScript:
3615 case CypriotScript:
3616 case HatranScript:
3617 case HebrewScript:
3618 case ImperialAramaicScript:
3619 case InscriptionalPahlaviScript:
3620 case InscriptionalParthianScript:
3621 case KharoshthiScript:
3622 case LydianScript:
3623 case MandaeanScript:
3624 case ManichaeanScript:
3625 case MendeKikakuiScript:
3626 case MeroiticCursiveScript:
3627 case MeroiticScript:
3628 case NabataeanScript:
3629 case NkoScript:
3630 case OldHungarianScript:
3631 case OldNorthArabianScript:
3632 case OldSouthArabianScript:
3633 case OrkhonScript:
3634 case PalmyreneScript:
3635 case PhoenicianScript:
3636 case PsalterPahlaviScript:
3637 case SamaritanScript:
3638 case SyriacScript:
3639 case ThaanaScript:
3640 return Qt::RightToLeft;
3641 default:
3642 break;
3643 }
3644 return Qt::LeftToRight;
3645}
3646
3647/*!
3648 \since 4.8
3649
3650 Returns an uppercase copy of \a str.
3651
3652 If Qt Core is using the ICU libraries, they will be used to perform
3653 the transformation according to the rules of the current locale.
3654 Otherwise the conversion may be done in a platform-dependent manner,
3655 with QString::toUpper() as a generic fallback.
3656
3657 \note In some cases the uppercase form of a string may be longer than the
3658 original.
3659
3660 \sa QString::toUpper()
3661*/
3662QString QLocale::toUpper(const QString &str) const
3663{
3664#if !defined(QT_BOOTSTRAPPED) && (QT_CONFIG(icu) || defined(Q_OS_WIN) || defined(Q_OS_APPLE))
3665 bool ok = true;
3666 QString result = d->toUpper(str, &ok);
3667 if (ok)
3668 return result;
3669 // else fall through and use Qt's toUpper
3670#endif
3671 return str.toUpper();
3672}
3673
3674/*!
3675 \since 4.8
3676
3677 Returns a lowercase copy of \a str.
3678
3679 If Qt Core is using the ICU libraries, they will be used to perform
3680 the transformation according to the rules of the current locale.
3681 Otherwise the conversion may be done in a platform-dependent manner,
3682 with QString::toLower() as a generic fallback.
3683
3684 \sa QString::toLower()
3685*/
3686QString QLocale::toLower(const QString &str) const
3687{
3688#if !defined(QT_BOOTSTRAPPED) && (QT_CONFIG(icu) || defined(Q_OS_WIN) || defined(Q_OS_APPLE))
3689 bool ok = true;
3690 const QString result = d->toLower(str, &ok);
3691 if (ok)
3692 return result;
3693 // else fall through and use Qt's toLower
3694#endif
3695 return str.toLower();
3696}
3697
3698
3699/*!
3700 \since 4.5
3701
3702 Returns the localized name of the "AM" suffix for times specified using
3703 the conventions of the 12-hour clock.
3704
3705 \sa pmText()
3706*/
3707QString QLocale::amText() const
3708{
3709#ifndef QT_NO_SYSTEMLOCALE
3710 if (d->m_data == &systemLocaleData) {
3711 auto res = systemLocale()->query(QSystemLocale::AMText).toString();
3712 if (!res.isEmpty())
3713 return res;
3714 }
3715#endif
3716 return d->m_data->anteMeridiem().getData(am_data);
3717}
3718
3719/*!
3720 \since 4.5
3721
3722 Returns the localized name of the "PM" suffix for times specified using
3723 the conventions of the 12-hour clock.
3724
3725 \sa amText()
3726*/
3727QString QLocale::pmText() const
3728{
3729#ifndef QT_NO_SYSTEMLOCALE
3730 if (d->m_data == &systemLocaleData) {
3731 auto res = systemLocale()->query(QSystemLocale::PMText).toString();
3732 if (!res.isEmpty())
3733 return res;
3734 }
3735#endif
3736 return d->m_data->postMeridiem().getData(pm_data);
3737}
3738
3739// For the benefit of QCalendar, below.
3740static QString offsetFromAbbreviation(QString &&text)
3741{
3742 QStringView tail{text};
3743 // May need to strip a prefix:
3744 if (tail.startsWith("UTC"_L1) || tail.startsWith("GMT"_L1))
3745 tail = tail.sliced(3);
3746 // TODO: there may be a locale-specific alternative prefix.
3747 // Hard to know without zone-name L10n details, though.
3748 return (tail.isEmpty() // The Qt::UTC case omits the zero offset:
3749 ? u"+00:00"_s
3750 // Whole-hour offsets may lack the zero minutes:
3751 : (tail.size() <= 3
3752 ? tail + ":00"_L1
3753 : std::move(text).right(tail.size())));
3754}
3755
3756// For the benefit of QCalendar, below, when not provided by QTZL.
3757#if !QT_CONFIG(datestring)
3758// No need for temporal data serialization and parsing code.
3759#elif QT_CONFIG(icu) || !(QT_CONFIG(timezone) && QT_CONFIG(timezone_locale))
3760namespace QtTimeZoneLocale {
3761
3762// TODO: is there a way to get this non-kludgily from ICU ?
3763// If so, that version goes in QTZL.cpp's relevant #if-ery branch.
3764QString zoneOffsetFormat([[maybe_unused]] const QLocale &locale,
3765 qsizetype,
3766 QtTemporalPattern::TemporalFieldFlags,
3767 const QDateTime &when,
3768 int offsetSeconds)
3769{
3770 // Only the non-ICU TZ-locale code uses the prefix forms, so this tacitly
3771 // assumes flags: Numeric | Abbreviated | NeedNoUtcPrefix | ZeroPad.
3772 QString text =
3773#if QT_CONFIG(timezone)
3774 locale != QLocale::system()
3775 ? when.timeRepresentation().displayName(when, QTimeZone::OffsetName, locale)
3776 :
3777#endif
3778 when.toOffsetFromUtc(offsetSeconds).timeZoneAbbreviation();
3779
3780 if (!text.isEmpty())
3781 text = offsetFromAbbreviation(std::move(text));
3782 // else: no suitable representation of the zone.
3783 return text;
3784}
3785
3786} // QtTimeZoneLocale
3787#endif // ICU or no TZ L10n
3788
3789// Another intrusion from QCalendar, using some of the tools above:
3790QString QCalendarBackend::dateTimeToString(QStringView format, const QDateTime &datetime,
3791 QDate dateOnly, QTime timeOnly,
3792 const QLocale &locale) const
3793{
3794 QDate date;
3795 QTime time;
3796 bool formatDate = false;
3797 bool formatTime = false;
3798 if (datetime.isValid()) {
3799 date = datetime.date();
3800 time = datetime.time();
3801 formatDate = true;
3802 formatTime = true;
3803 } else if (dateOnly.isValid()) {
3804 date = dateOnly;
3805 formatDate = true;
3806 } else if (timeOnly.isValid()) {
3807 time = timeOnly;
3808 formatTime = true;
3809 } else {
3810 return QString();
3811 }
3812
3813 QString result;
3814 int year = 0, month = 0, day = 0;
3815 if (formatDate) {
3816 const auto parts = julianDayToDate(date.toJulianDay());
3817 if (!parts.isValid())
3818 return QString();
3819 year = parts.year;
3820 month = parts.month;
3821 day = parts.day;
3822 }
3823
3824 auto appendToResult = [&](int t, int repeat) {
3825 auto data = locale.d->m_data;
3826 if (repeat > 1)
3827 result.append(data->longLongToString(t, -1, 10, repeat, QLocaleData::ZeroPadded));
3828 else
3829 result.append(data->longLongToString(t));
3830 };
3831
3832 auto formatType = [](int repeat) {
3833 return repeat == 3 ? QLocale::ShortFormat : QLocale::LongFormat;
3834 };
3835
3836 qsizetype i = 0;
3837 while (i < format.size()) {
3838 if (format.at(i).unicode() == '\'') {
3839 result.append(qt_readEscapedFormatString(format, &i));
3840 continue;
3841 }
3842
3843 const QChar c = format.at(i);
3844 qsizetype rep = qt_repeatCount(format.mid(i));
3845 Q_ASSERT(rep < std::numeric_limits<int>::max());
3846 int repeat = int(rep);
3847 bool used = false;
3848 if (formatDate) {
3849 switch (c.unicode()) {
3850 case 'y':
3851 used = true;
3852 if (repeat >= 4)
3853 repeat = 4;
3854 else if (repeat >= 2)
3855 repeat = 2;
3856
3857 switch (repeat) {
3858 case 4:
3859 // Years with more than four digits must have a sign:
3860 if (year > 9999)
3861 result.append(locale.positiveSign());
3862 appendToResult(year, (year < 0) ? 5 : 4);
3863 break;
3864 case 2:
3865 appendToResult(year % 100, 2);
3866 break;
3867 default:
3868 repeat = 1;
3869 result.append(c);
3870 break;
3871 }
3872 break;
3873
3874 case 'M':
3875 used = true;
3876 repeat = qMin(repeat, 4);
3877 if (repeat <= 2)
3878 appendToResult(month, repeat);
3879 else
3880 result.append(monthName(locale, month, year, formatType(repeat)));
3881 break;
3882
3883 case 'd':
3884 used = true;
3885 repeat = qMin(repeat, 4);
3886 if (repeat <= 2)
3887 appendToResult(day, repeat);
3888 else
3889 result.append(
3890 locale.dayName(dayOfWeek(date.toJulianDay()), formatType(repeat)));
3891 break;
3892
3893 default:
3894 break;
3895 }
3896 }
3897 if (!used && formatTime) {
3898 switch (c.unicode()) {
3899 case 'h': {
3900 used = true;
3901 repeat = qMin(repeat, 2);
3902 int hour = time.hour();
3903 if (timeFormatContainsAP(format)) {
3904 if (hour > 12)
3905 hour -= 12;
3906 else if (hour == 0)
3907 hour = 12;
3908 }
3909 appendToResult(hour, repeat);
3910 break;
3911 }
3912 case 'H':
3913 used = true;
3914 repeat = qMin(repeat, 2);
3915 appendToResult(time.hour(), repeat);
3916 break;
3917
3918 case 'm':
3919 used = true;
3920 repeat = qMin(repeat, 2);
3921 appendToResult(time.minute(), repeat);
3922 break;
3923
3924 case 's':
3925 used = true;
3926 repeat = qMin(repeat, 2);
3927 appendToResult(time.second(), repeat);
3928 break;
3929
3930 case 'A':
3931 case 'a': {
3932 QString text = time.hour() < 12 ? locale.amText() : locale.pmText();
3933 used = true;
3934 repeat = 1;
3935 if (format.mid(i + 1).startsWith(u'p', Qt::CaseInsensitive))
3936 ++repeat;
3937 if (c.unicode() == 'A' && (repeat == 1 || format.at(i + 1).unicode() == 'P'))
3938 text = std::move(text).toUpper();
3939 else if (c.unicode() == 'a' && (repeat == 1 || format.at(i + 1).unicode() == 'p'))
3940 text = std::move(text).toLower();
3941 // else 'Ap' or 'aP' => use CLDR text verbatim, preserving case
3942 result.append(text);
3943 break;
3944 }
3945
3946 case 'z':
3947 used = true;
3948 repeat = qMin(repeat, 3);
3949
3950 // note: the millisecond component is treated like the decimal part of the seconds
3951 // so ms == 2 is always printed as "002", but ms == 200 can be either "2" or "200"
3952 appendToResult(time.msec(), 3);
3953 if (repeat != 3) {
3954 const QString zero = locale.zeroDigit();
3955 if (result.endsWith(zero))
3956 result.chop(zero.size());
3957 if (result.endsWith(zero))
3958 result.chop(zero.size());
3959 }
3960 break;
3961
3962 case 't': {
3963#if QT_CONFIG(datestring)
3964 // Feature check should really apply to the whole function, but
3965 // this portion of it depends on internals entangled with the
3966 // feature.
3967 enum AbbrType { Long, Offset, Short };
3968 const auto tzAbbr = [locale](const QDateTime &when, AbbrType type) {
3969 QString text;
3970 if (type == Offset) {
3971 using Flag = QtTemporalPattern::TemporalFieldFlag;
3972 constexpr auto noPrefixOffset = Flag::Numeric | Flag::Abbreviated
3973 | Flag::NeedNoUtcPrefix | Flag::ZeroPad;
3974 text = QtTimeZoneLocale::zoneOffsetFormat(locale, locale.d->m_index,
3975 noPrefixOffset,
3976 when, when.offsetFromUtc());
3977 // When using timezone_locale data, this should always succeed:
3978 if (!text.isEmpty())
3979 return text;
3980 }
3981# if QT_CONFIG(timezone)
3982 if (type != Short || locale != QLocale::system()) {
3983 QTimeZone::NameType mode =
3984 type == Short ? QTimeZone::ShortName
3985 : type == Long ? QTimeZone::LongName : QTimeZone::OffsetName;
3986 text = when.timeRepresentation().displayName(when, mode, locale);
3987 if (!text.isEmpty())
3988 return text;
3989 // else fall back to an unlocalized one if we can find one.
3990 }
3991 if (type == Long) {
3992 // If no long name found, use IANA ID:
3993 text = QString::fromLatin1(when.timeZone().id());
3994 if (!text.isEmpty())
3995 return text;
3996 }
3997 // else: prefer QDateTime's abbreviation, for backwards-compatibility.
3998# endif // else, make do with non-localized abbreviation:
3999 // Absent timezone_locale data, Offset might still reach here:
4000 if (type == Offset) // Our prior failure might not have tried this:
4001 text = when.toOffsetFromUtc(when.offsetFromUtc()).timeZoneAbbreviation();
4002 if (text.isEmpty()) // Notably including type != Offset
4003 text = when.timeZoneAbbreviation();
4004 if (type == Offset)
4005 text = offsetFromAbbreviation(std::move(text));
4006 return text;
4007 };
4008
4009 used = true;
4010 repeat = qMin(repeat, 4);
4011 // If we don't have a date-time, use the current system time:
4012 const QDateTime when = formatDate ? datetime : QDateTime::currentDateTime();
4013 QString text;
4014 switch (repeat) {
4015 case 4:
4016 text = tzAbbr(when, Long);
4017 break;
4018 case 3: // ±hh:mm
4019 case 2: // ±hhmm (we'll remove the ':' at the end)
4020 text = tzAbbr(when, Offset);
4021 if (repeat == 2)
4022 text.remove(u':');
4023 break;
4024 default:
4025 text = tzAbbr(when, Short);
4026 // UTC-offset zones only include minutes if non-zero.
4027 if (text.startsWith("UTC"_L1) && text.size() == 6)
4028 text += ":00"_L1;
4029 break;
4030 }
4031 if (!text.isEmpty())
4032 result.append(text);
4033#endif // datestring
4034 break;
4035 }
4036
4037 default:
4038 break;
4039 }
4040 }
4041 if (!used)
4042 result.resize(result.size() + repeat, c);
4043 i += repeat;
4044 }
4045
4046 return result;
4047}
4048// End of QCalendar intrustions
4049
4050QString QLocaleData::doubleToString(double d, int precision, DoubleForm form,
4051 int width, unsigned flags) const
4052{
4053 // Although the special handling of F.P.Shortest below is limited to
4054 // DFSignificantDigits, the double-conversion library does treat it
4055 // specially for the other forms, shedding trailing zeros for DFDecimal and
4056 // using the shortest mantissa that faithfully represents the value for
4057 // DFExponent.
4058 if (precision != QLocale::FloatingPointShortest && precision < 0)
4059 precision = 6;
4060 if (width < 0)
4061 width = 0;
4062
4063 int decpt;
4064 qsizetype bufSize = 1;
4065 if (precision == QLocale::FloatingPointShortest)
4066 bufSize += std::numeric_limits<double>::max_digits10;
4067 else if (form == DFDecimal && qt_is_finite(d))
4068 bufSize += wholePartSpace(qAbs(d)) + precision;
4069 else // Add extra digit due to different interpretations of precision.
4070 bufSize += qMax(2, precision) + 1; // Must also be big enough for "nan" or "inf"
4071
4072 QVarLengthArray<char> buf(bufSize);
4073 int length;
4074 bool negative = false;
4075 qt_doubleToAscii(d, form, precision, buf.data(), bufSize, negative, length, decpt);
4076
4077 const QString prefix = signPrefix(negative && !qIsNull(d), flags);
4078 QString numStr;
4079
4080 if (length == 3
4081 && (qstrncmp(buf.data(), "inf", 3) == 0 || qstrncmp(buf.data(), "nan", 3) == 0)) {
4082 numStr = QString::fromLatin1(buf.data(), length);
4083 } else { // Handle finite values
4084 const QString zero = zeroDigit();
4085 QString digits = QString::fromLatin1(buf.data(), length);
4086
4087 if (zero == u"0") {
4088 // No need to convert digits.
4089 Q_ASSERT(std::all_of(buf.cbegin(), buf.cbegin() + length, isAsciiDigit));
4090 // That check is taken care of in unicodeForDigits, below.
4091 } else if (zero.size() == 2 && zero.at(0).isHighSurrogate()) {
4092 const char32_t zeroUcs4 = QChar::surrogateToUcs4(zero.at(0), zero.at(1));
4093 QString converted;
4094 converted.reserve(2 * digits.size());
4095 for (QChar ch : std::as_const(digits)) {
4096 const char32_t digit = unicodeForDigit(ch.unicode() - '0', zeroUcs4);
4097 Q_ASSERT(QChar::requiresSurrogates(digit));
4098 converted.append(QChar::highSurrogate(digit));
4099 converted.append(QChar::lowSurrogate(digit));
4100 }
4101 digits = std::move(converted);
4102 } else {
4103 Q_ASSERT(zero.size() == 1);
4104 Q_ASSERT(!zero.at(0).isSurrogate());
4105 char16_t z = zero.at(0).unicode();
4106 char16_t *const value = reinterpret_cast<char16_t *>(digits.data());
4107 for (qsizetype i = 0; i < digits.size(); ++i)
4108 value[i] = unicodeForDigit(value[i] - '0', z);
4109 }
4110
4111 const bool mustMarkDecimal = flags & ForcePoint;
4112 const bool groupDigits = flags & GroupDigits;
4113 const int minExponentDigits = flags & ZeroPadExponent ? 2 : 1;
4114 switch (form) {
4115 case DFExponent:
4116 numStr = exponentForm(std::move(digits), decpt, precision, PMDecimalDigits,
4117 mustMarkDecimal, minExponentDigits);
4118 break;
4119 case DFDecimal:
4120 numStr = decimalForm(std::move(digits), decpt, precision, PMDecimalDigits,
4121 mustMarkDecimal, groupDigits);
4122 break;
4123 case DFSignificantDigits: {
4124 PrecisionMode mode
4125 = (flags & AddTrailingZeroes) ? PMSignificantDigits : PMChopTrailingZeros;
4126
4127 /* POSIX specifies sprintf() to follow fprintf(), whose 'g/G' format
4128 says; with P = 6 if precision unspecified else 1 if precision is
4129 0 else precision; when 'e/E' would have exponent X, use:
4130 * 'f/F' if P > X >= -4, with precision P-1-X
4131 * 'e/E' otherwise, with precision P-1
4132 Helpfully, we already have mapped precision < 0 to 6 - except for
4133 F.P.Shortest mode, which is its own story - and those of our
4134 callers with unspecified precision either used 6 or -1 for it.
4135 */
4136 bool useDecimal;
4137 if (precision == QLocale::FloatingPointShortest) {
4138 // Find out which representation is shorter.
4139 // Set bias to everything added to exponent form but not
4140 // decimal, minus the converse.
4141
4142 const QLocaleData::GroupSizes grouping = groupSizes();
4143 // Exponent adds separator, sign and digits:
4144 int bias = 2 + minExponentDigits;
4145 // Decimal form may get grouping separators inserted:
4146 if (groupDigits && decpt >= grouping.first + grouping.least)
4147 bias -= (decpt - grouping.least) / grouping.higher + 1;
4148 // X = decpt - 1 needs two digits if decpt > 10:
4149 if (decpt > 10 && minExponentDigits == 1)
4150 ++bias;
4151 // Assume digitCount < 95, so we can ignore the 3-digit
4152 // exponent case (we'll set useDecimal false anyway).
4153
4154 const qsizetype digitCount = digits.size() / zero.size();
4155 if (!mustMarkDecimal) {
4156 // Decimal separator is skipped if at end; adjust if
4157 // that happens for only one form:
4158 if (digitCount <= decpt && digitCount > 1)
4159 ++bias; // decimal but not exponent
4160 else if (digitCount == 1 && decpt <= 0)
4161 --bias; // exponent but not decimal
4162 }
4163 // When 0 < decpt <= digitCount, the forms have equal digit
4164 // counts, plus things bias has taken into account; otherwise
4165 // decimal form's digit count is right-padded with zeros to
4166 // decpt, when decpt is positive, otherwise it's left-padded
4167 // with 1 - decpt zeros.
4168 useDecimal = (decpt <= 0 ? 1 - decpt <= bias
4169 : decpt <= digitCount ? 0 <= bias : decpt <= digitCount + bias);
4170 } else {
4171 // X == decpt - 1, POSIX's P; -4 <= X < P iff -4 < decpt <= P
4172 Q_ASSERT(precision >= 0);
4173 useDecimal = decpt > -4 && decpt <= (precision ? precision : 1);
4174 }
4175
4176 numStr = useDecimal
4177 ? decimalForm(std::move(digits), decpt, precision, mode,
4178 mustMarkDecimal, groupDigits)
4179 : exponentForm(std::move(digits), decpt, precision, mode,
4180 mustMarkDecimal, minExponentDigits);
4181 break;
4182 }
4183 }
4184
4185 // Pad with zeros. LeftAdjusted overrides ZeroPadded.
4186 if (flags & ZeroPadded && !(flags & LeftAdjusted)) {
4187 for (qsizetype i = numStr.size() / zero.size() + prefix.size(); i < width; ++i)
4188 numStr.prepend(zero);
4189 }
4190 }
4191
4192 return prefix + (flags & CapitalEorX
4193 ? std::move(numStr).toUpper()
4194 : std::move(numStr).toLower());
4195}
4196
4197QString QLocaleData::decimalForm(QString &&digits, int decpt, int precision,
4198 PrecisionMode pm, bool mustMarkDecimal,
4199 bool groupDigits) const
4200{
4201 const QString zero = zeroDigit();
4202 const auto digitWidth = zero.size();
4203 Q_ASSERT(digitWidth == 1 || digitWidth == 2);
4204 Q_ASSERT(digits.size() % digitWidth == 0);
4205
4206 // Separator needs to go at index decpt: so add zeros before or after the
4207 // given digits, if they don't reach that position already:
4208 if (decpt < 0) {
4209 for (; decpt < 0; ++decpt)
4210 digits.prepend(zero);
4211 } else {
4212 for (qsizetype i = digits.size() / digitWidth; i < decpt; ++i)
4213 digits.append(zero);
4214 }
4215
4216 switch (pm) {
4217 case PMDecimalDigits:
4218 for (qsizetype i = digits.size() / digitWidth - decpt; i < precision; ++i)
4219 digits.append(zero);
4220 break;
4221 case PMSignificantDigits:
4222 for (qsizetype i = digits.size() / digitWidth; i < precision; ++i)
4223 digits.append(zero);
4224 break;
4225 case PMChopTrailingZeros:
4226 Q_ASSERT(digits.size() / digitWidth <= qMax(decpt, 1) || !digits.endsWith(zero));
4227 break;
4228 }
4229
4230 if (mustMarkDecimal || decpt < digits.size() / digitWidth)
4231 digits.insert(decpt * digitWidth, decimalPoint());
4232
4233 if (groupDigits) {
4234 const QLocaleData::GroupSizes grouping = groupSizes();
4235 const QString group = groupSeparator();
4236 qsizetype i = decpt - grouping.least;
4237 if (i >= grouping.first) {
4238 digits.insert(i * digitWidth, group);
4239 while ((i -= grouping.higher) > 0)
4240 digits.insert(i * digitWidth, group);
4241 }
4242 }
4243
4244 if (decpt == 0)
4245 digits.prepend(zero);
4246
4247 return std::move(digits);
4248}
4249
4250QString QLocaleData::exponentForm(QString &&digits, int decpt, int precision,
4251 PrecisionMode pm, bool mustMarkDecimal,
4252 int minExponentDigits) const
4253{
4254 const QString zero = zeroDigit();
4255 const auto digitWidth = zero.size();
4256 Q_ASSERT(digitWidth == 1 || digitWidth == 2);
4257 Q_ASSERT(digits.size() % digitWidth == 0);
4258
4259 switch (pm) {
4260 case PMDecimalDigits:
4261 for (qsizetype i = digits.size() / digitWidth; i < precision + 1; ++i)
4262 digits.append(zero);
4263 break;
4264 case PMSignificantDigits:
4265 for (qsizetype i = digits.size() / digitWidth; i < precision; ++i)
4266 digits.append(zero);
4267 break;
4268 case PMChopTrailingZeros:
4269 Q_ASSERT(digits.size() / digitWidth <= 1 || !digits.endsWith(zero));
4270 break;
4271 }
4272
4273 if (mustMarkDecimal || digits.size() > digitWidth)
4274 digits.insert(digitWidth, decimalPoint());
4275
4276 digits.append(exponentSeparator());
4277 digits.append(longLongToString(decpt - 1, minExponentDigits, 10, -1, AlwaysShowSign));
4278
4279 return std::move(digits);
4280}
4281
4282QString QLocaleData::signPrefix(bool negative, unsigned flags) const
4283{
4284 if (negative)
4285 return negativeSign();
4286 if (flags & AlwaysShowSign)
4287 return positiveSign();
4288 if (flags & BlankBeforePositive)
4289 return u" "_s;
4290 return {};
4291}
4292
4293QString QLocaleData::longLongToString(qlonglong n, int precision,
4294 int base, int width, unsigned flags) const
4295{
4296 bool negative = n < 0;
4297
4298 /*
4299 Negating std::numeric_limits<qlonglong>::min() hits undefined behavior, so
4300 taking an absolute value has to take a slight detour.
4301 */
4302 QString numStr = qulltoa(negative ? 1u + qulonglong(-(n + 1)) : qulonglong(n),
4303 base, zeroDigit());
4304
4305 return applyIntegerFormatting(std::move(numStr), negative, precision, base, width, flags);
4306}
4307
4308QString QLocaleData::unsLongLongToString(qulonglong l, int precision,
4309 int base, int width, unsigned flags) const
4310{
4311 return applyIntegerFormatting(qulltoa(l, base, zeroDigit()),
4312 false, precision, base, width, flags);
4313}
4314
4315QString QLocaleData::applyIntegerFormatting(QString &&numStr, bool negative, int precision,
4316 int base, int width, unsigned flags) const
4317{
4318 const QString zero = base == 10 ? zeroDigit() : QStringLiteral("0");
4319 const auto digitWidth = zero.size();
4320 const auto digitCount = numStr.size() / digitWidth;
4321
4322 const auto basePrefix = [&] () -> QStringView {
4323 if (flags & ShowBase) {
4324 const bool upper = flags & UppercaseBase;
4325 if (base == 16)
4326 return upper ? u"0X" : u"0x";
4327 if (base == 2)
4328 return upper ? u"0B" : u"0b";
4329 if (base == 8 && !numStr.startsWith(zero))
4330 return zero;
4331 }
4332 return {};
4333 }();
4334
4335 const QString prefix = signPrefix(negative, flags) + basePrefix;
4336 // Count how much of width we've used up. Each digit counts as one
4337 qsizetype usedWidth = digitCount + prefix.size();
4338
4339 if (base == 10 && flags & GroupDigits) {
4340 const QLocaleData::GroupSizes grouping = groupSizes();
4341 const QString group = groupSeparator();
4342 qsizetype i = digitCount - grouping.least;
4343 if (i >= grouping.first) {
4344 numStr.insert(i * digitWidth, group);
4345 ++usedWidth;
4346 while ((i -= grouping.higher) > 0) {
4347 numStr.insert(i * digitWidth, group);
4348 ++usedWidth;
4349 }
4350 }
4351 // TODO: should we group any zero-padding we add later ?
4352 }
4353
4354 const bool noPrecision = precision == -1;
4355 if (noPrecision)
4356 precision = 1;
4357
4358 for (qsizetype i = numStr.size(); i < precision; ++i) {
4359 numStr.prepend(zero);
4360 usedWidth++;
4361 }
4362
4363 // LeftAdjusted overrides ZeroPadded; and sprintf() only pads when
4364 // precision is not specified in the format string.
4365 if (noPrecision && flags & ZeroPadded && !(flags & LeftAdjusted)) {
4366 for (qsizetype i = usedWidth; i < width; ++i)
4367 numStr.prepend(zero);
4368 }
4369
4370 QString result(flags & CapitalEorX ? std::move(numStr).toUpper() : std::move(numStr));
4371 if (prefix.size())
4372 result.prepend(prefix);
4373 return result;
4374}
4375
4377 : grouping(data->groupSizes()), isC(data == c())
4378 // Note: actually test pointer equality to c(), not language == C, as
4379 // system locale might be configured as C with tweaks.
4380{
4381 if (isC)
4382 return;
4383 setZero(data->zero().viewData(single_character_data));
4384 group = data->groupDelim().viewData(single_character_data);
4385 // Note: minus, plus and exponent might not actually be single characters.
4386 minus = data->minus().viewData(single_character_data);
4387 plus = data->plus().viewData(single_character_data);
4388 if (mode != IntegerMode)
4389 decimal = data->decimalSeparator().viewData(single_character_data);
4390 if (mode == DoubleScientificMode) {
4391 exponent = data->exponential().viewData(single_character_data);
4392 // exponentCyrillic means "apply the Cyrrilic-specific exponent hack"
4393 exponentCyrillic = data->m_script_id == QLocale::CyrillicScript;
4394 }
4395#ifndef QT_NO_SYSTEMLOCALE
4396 if (data == &systemLocaleData) {
4397 const auto getString = [sys = systemLocale()](QSystemLocale::QueryType query) {
4398 return sys->query(query).toString();
4399 };
4400 if (mode != IntegerMode) {
4401 sysDecimal = getString(QSystemLocale::DecimalPoint);
4402 if (sysDecimal.size())
4403 decimal = QStringView{sysDecimal};
4404 }
4405 sysGroup = getString(QSystemLocale::GroupSeparator);
4406 if (sysGroup.size())
4407 group = QStringView{sysGroup};
4408 sysMinus = getString(QSystemLocale::NegativeSign);
4409 if (sysMinus.size())
4410 minus = QStringView{sysMinus};
4411 sysPlus = getString(QSystemLocale::PositiveSign);
4412 if (sysPlus.size())
4413 plus = QStringView{sysPlus};
4414 setZero(getString(QSystemLocale::ZeroDigit));
4415 }
4416#endif
4417}
4418
4419namespace {
4420// A bit like QStringIterator but rather specialized ... and some of the tokens
4421// it recognizes aren't single Unicode code-points (but it does map each to a
4422// single character).
4423class NumericTokenizer
4424{
4425 // TODO: use deterministic finite-state-automata.
4426 // TODO QTBUG-95460: CLDR has Inf/NaN representations per locale.
4427 static constexpr char lettersInfNaN[] = "afin"; // Letters of Inf, NaN
4428 static constexpr auto matchInfNaN = QtPrivate::makeCharacterSetMatch<lettersInfNaN>();
4429 const QStringView m_text;
4430 const QLocaleData::NumericData m_guide;
4431 qsizetype m_index;
4432 const QLocaleData::NumberMode m_mode;
4433 static_assert('+' + 1 == ',' && ',' + 1 == '-' && '-' + 1 == '.');
4434 char lastMark; // C locale accepts '+' through lastMark.
4435public:
4436 NumericTokenizer(QStringView text, QLocaleData::NumericData &&guide,
4437 QLocaleData::NumberMode mode, qsizetype from = 0)
4438 : m_text(text), m_guide(guide), m_index(from), m_mode(mode),
4439 lastMark(mode == QLocaleData::IntegerMode ? '-' : '.')
4440 {
4441 Q_ASSERT(m_guide.isValid(mode));
4442 }
4443 bool done() const { return !(m_index < m_text.size()); }
4444 qsizetype index() const { return m_index; }
4445 int digitValue(char32_t digit) const { return m_guide.digitValue(digit); }
4446 bool isInfNanChar(char ch) const { return matchInfNaN.matches(ch); }
4447 char nextToken();
4448 bool fractionGroupClash() const
4449 {
4450 // If the user's hand-configuration of the system makes group and
4451 // fractional part separators coincide, we have some kludges to apply,
4452 // though we can skip them in integer mode.
4453 return Q_UNLIKELY(m_mode != QLocaleData::IntegerMode && m_guide.fractionalIsGroup());
4454 }
4455 const QLocaleData::GroupSizes &groupSizes() { return m_guide.groupSizes(); }
4456};
4457
4458char NumericTokenizer::nextToken()
4459{
4460 // As long as caller stops iterating on a zero return, those don't need to
4461 // keep m_index correctly updated.
4462 Q_ASSERT(!done());
4463 do {
4464 // Mauls non-letters above 'Z' but we don't care:
4465 const auto asciiLower = [](unsigned char c) { return c >= 'A' ? c | 0x20 : c; };
4466 const QStringView tail = m_text.sliced(m_index);
4467 const QChar ch = tail.front();
4468 if (ch == u'\u2212') {
4469 // Special case: match the "proper" minus sign, for all locales.
4470 ++m_index;
4471 return '-';
4472 }
4473 if (m_guide.isC) {
4474 // "Conversion" to C locale is just a filter:
4475 if (Q_LIKELY(ch.unicode() < 256)) {
4476 unsigned char ascii = asciiLower(ch.toLatin1());
4477 if (Q_LIKELY(isAsciiDigit(ascii) || ('+' <= ascii && ascii <= lastMark)
4478 // No caller presently (6.5) passes DoubleStandardMode,
4479 // so !IntegerMode implies scientific, for now.
4480 || (m_mode != QLocaleData::IntegerMode && isInfNanChar(ascii))
4481 || (m_mode == QLocaleData::DoubleScientificMode && ascii == 'e'))) {
4482 ++m_index;
4483 return ascii;
4484 }
4485 }
4486 return 0;
4487 }
4488 if (ch.unicode() < 256) {
4489 // Accept the C locale's digits and signs in all locales:
4490 char ascii = asciiLower(ch.toLatin1());
4491 if (isAsciiDigit(ascii) || ascii == '-' || ascii == '+'
4492 // Also its Inf and NaN letters:
4493 || (m_mode != QLocaleData::IntegerMode && isInfNanChar(ascii))) {
4494 ++m_index;
4495 return ascii;
4496 }
4497 }
4498
4499 // Other locales may be trickier:
4500 if (tail.startsWith(m_guide.minus)) {
4501 m_index += m_guide.minus.size();
4502 return '-';
4503 }
4504 if (tail.startsWith(m_guide.plus)) {
4505 m_index += m_guide.plus.size();
4506 return '+';
4507 }
4508 if (!m_guide.group.isEmpty() && tail.startsWith(m_guide.group)) {
4509 m_index += m_guide.group.size();
4510 // When group and decimal coincide, and a fractional part is not
4511 // unexpected, treat the last as a fractional part separator (and leave
4512 // the caller to special-case the situations where that causes a
4513 // parse-fail that we can dodge by not reading it that way).
4514 if (fractionGroupClash() && tail.indexOf(m_guide.decimal, m_guide.group.size()) == -1)
4515 return '.';
4516 return ',';
4517 }
4518 if (m_mode != QLocaleData::IntegerMode && tail.startsWith(m_guide.decimal)) {
4519 m_index += m_guide.decimal.size();
4520 return '.';
4521 }
4523 && tail.startsWith(m_guide.exponent, Qt::CaseInsensitive)) {
4524 m_index += m_guide.exponent.size();
4525 return 'e';
4526 }
4527
4528 // Must match qlocale_tools.h's unicodeForDigit()
4529 if (m_guide.zeroLen == 1) {
4530 if (!ch.isSurrogate()) {
4531 if (const int gap = digitValue(char32_t(ch.unicode())); gap >= 0) {
4532 ++m_index;
4533 return '0' + gap;
4534 }
4535 } else if (ch.isHighSurrogate() && tail.size() > 1 && tail.at(1).isLowSurrogate()) {
4536 return 0;
4537 }
4538 // There remain one or two things a non-surrogate might be ...
4539 } else if (ch.isHighSurrogate()) {
4540 // None of the corner cases below matches a surrogate, so return
4541 // early if we don't have a digit.
4542 if (tail.size() > 1) {
4543 if (const QChar low = tail.at(1); low.isLowSurrogate()) {
4544 if (const int gap = digitValue(QChar::surrogateToUcs4(ch, low)); gap >= 0) {
4545 m_index += 2;
4546 return '0' + gap;
4547 }
4548 }
4549 }
4550 return 0;
4551 }
4552
4553 // All cases where tail starts with properly-matched surrogate pair
4554 // have been handled by this point.
4555 Q_ASSERT(!(ch.isHighSurrogate() && tail.size() > 1 && tail.at(1).isLowSurrogate()));
4556
4557 // Weird corner cases (code above assumes these match no surrogates):
4558 switch (ch.unicode()) {
4559 // Skip over inivisble marks commonly found in numeric forms:
4560 case 0x061C: // Arabic Letter Mark (before signs in standard Arabic)
4561 case 0x200E: // Left-to-Right marker
4562 case 0x200F: // Right-to-Left marker
4563 ++m_index;
4564 continue;
4565
4566 case u' ':
4567 // Some locales use a non-breaking space (U+00A0) or its thin
4568 // version (U+202f) for grouping. These look like spaces, so people
4569 // (and thus some of our tests) use a regular space instead and
4570 // complain if it doesn't work.
4571 // Should this be extended generally to any case where group is a space ?
4572 if (m_guide.group == u"\u00a0" || m_guide.group == u"\u202f") {
4573 ++m_index;
4574 return ',';
4575 }
4576 break;
4577
4578 // Case-insensitive match:
4579 case u'E':
4580 case u'e':
4581 case u'\u0415': // Cyrillic E
4582 case u'\u0435': // Cyrillic e
4583 // Cyrillic E is used by Ukrainian as exponent; but others writing
4584 // Cyrillic may well use that; and Ukrainians might well use E.
4585 // All other Cyrillic locales (officially) use plain ASCII E.
4586 if (m_guide.exponentCyrillic) { // Only true in scientific float mode.
4587 ++m_index;
4588 return 'e';
4589 }
4590 break;
4591 }
4592
4593 break;
4594 } while (!done());
4595 return 0;
4596}
4597} // namespace with no name
4598
4599/*!
4600 \internal
4601 \since 6.12
4602 \class QLocaleData::DigitSequence
4603 \brief Descriptor for a digit sequence within a text.
4604
4605 Packages the ASCII equivalent (optional sign and) digit sequence, along with
4606 a description of which parts come from where in the original text.
4607
4608 Supports construction or assignment by moving or copying. Modifying its
4609 members, other than by assigning a newly constructed value or a result of
4610 taking a subsequence, may lead to undefined behaviour.
4611
4612 \sa sliced(), first(), last()
4613*/
4614// Exists for the benefit of date-time parsing, but could be used for anything
4615// else that doesn't do fractional parts, exponents or digit-grouping.
4616
4617/*!
4618 \fn qsizetype QLocaleData::DigitSequence::size()
4619
4620 Returns the number of ASCII characters describing the digit sequence.
4621
4622 This is the number of digits plus, if present, one for the sign. It is the
4623 number of characters \l transcribeTo() will transcribe. For the number of
4624 digits found, use \c {digits.size()}. Note that this may be less than the
4625 length of the text parsed, for example when the digits are surrogate pairs
4626 or the sign includes special Unicode markers, such as those for text
4627 direction.
4628
4629 \sa isEmpty()
4630*/
4631
4632/*!
4633 \fn void QLocaleData::DigitSequence::transcribeTo(CharBuff *buff)
4634
4635 Transcribes the ASCII form of this digit sequence to \a buff.
4636
4637 \sa size()
4638*/
4639
4640/*!
4641 \since 6.12
4642 \enum QLocaleData::DigitSequence::Option
4643
4644 Options to modify how digit sequences are parsed.
4645
4646 \value Default The null option value.
4647 \value AllowSign A leading sign character may be present.
4648
4649 In the numeric fields of a date, only a year field ever has a sign, all
4650 others use ungrouped digits. Zero-padding on the left of day and month
4651 fields is common (and it may also appear in year fields). The hour field of
4652 a zone-offset may also have a sign. Otherwise all numeric time fields are
4653 similar to numeric month and day fields.
4654
4655 In numeric fields of a time, the least-significant given (be it hour, minute
4656 or second) may have a fractional part in some formats. The handling of this
4657 is left for the caller to take care of. Likewise, the caller is expected to
4658 deal with leading and trailing space appropriately.
4659*/
4660
4661/*!
4662 \fn bool QLocaleData::DigitSequence::isEmpty() const
4663
4664 Returns true precisely if this digit sequence represents nothing.
4665
4666 This arises when the constructor found no digits and (when allowed) not even
4667 a sign. It may also result from extracting an empty subsequence of a digit
4668 sequence that was originally parsed. It is equivalent to \l
4669 {QLocaleData::DigitSequence::}{size()} == 0. To test whether any digits were
4670 found, use \c {digits.isEmpty()}, which may be true even though \c
4671 {isEmpty()} is false. That arises when only a sign was found (making
4672 \c{size() == 1}).
4673
4674 \sa size()
4675*/
4676
4677/*!
4678 \fn bool QLocaleData::DigitSequence::hasSign() const
4679
4680 Returns true precisely if the digit sequence parsed includes a leading sign.
4681 It is equivalent to \c{sign != '\0'}.
4682*/
4683
4684/*!
4685 \fn QStringView QLocaleData::DigitSequence::used(QStringView text, qsizetype from) const
4686 \fn QStringView QLocaleData::DigitSequence::used(QStringView text) const
4687
4688 Returns the slice of \a text described by this digit sequence.
4689
4690 The given \a text should be the one passed to the constructor either of this
4691 digit sequence or of one from which it was obtained by some combination of
4692 \l first(), \l sliced() and \l last(). In the directly-constructed case, or
4693 in the case of (optionally repeatedly) applying only \l first(), \a from may
4694 be passed: it should be the like-named offset passed to the original
4695 constructor, or 0 if no offset was passed. In that case, the whole text
4696 parsed for this digit sequence (alibeit possibly a prefix of the text
4697 originally parsed) is returned. Otherwise, \a from should be omitted and
4698 this function returns the text described by just the digits of this
4699 sequence, omitting (even when relevant) the sign.
4700
4701 \sa {QLocaleData::DigitSequence::}{DigitSequence()}
4702*/
4703
4704/*!
4705 \fn QLocaleData::DigitSequence QLocaleData::DigitSequence::first(qsizetype count) const
4706
4707 Returns a DigitSequence describing a prefix of this.
4708
4709 The result describes the first \a count ASCII characters to which the
4710 sequence corresponds and their positions within the parsed text. The value
4711 of \a count must not be negative or exceed \c size().
4712*/
4713
4714/*!
4715 \fn QLocaleData::DigitSequence QLocaleData::DigitSequence::last(qsizetype count) const
4716
4717 Returns a DigitSequence describing a tail of this.
4718
4719 The result describes the last \a count ASCII characters to which the
4720 sequence corresponds. The value of \a count must not be negative or exceed
4721 \c size(). The result is equivalent to \c{sliced(size() - count)}.
4722*/
4723
4724/*!
4725 \fn QLocaleData::DigitSequence QLocaleData::DigitSequence::sliced(qsizetype from) const
4726
4727 Returns a DigitSequence describing a tail of this.
4728
4729 This skips over the text to which the first \a from ASCII characters of the
4730 sequence correspond, to describe the remainder and their positions within
4731 the parsed text. The value of \a from must not be negative or exceed \c
4732 size().
4733*/
4734
4735/*!
4736 \overload
4737 \fn QLocaleData::DigitSequence QLocaleData::DigitSequence::sliced(qsizetype from, qsizetype count) const
4738
4739 Returns a DigitSequence describing a subsequence of this.
4740
4741 This skips over the portion of the text to which first \a from ASCII
4742 characters correspond and describes the portion described by the next \a
4743 count ASCII characters. The value of \a from must not be negative or exceed
4744 \c size(). The value of \a count must not be negative or exceed \c{size() -
4745 from}. The result is equivalent to \c{sliced(from).first(count)}.
4746*/
4747
4748/*!
4749 Scan \a text for an initial sequence of digits.
4750
4751 The given \a numeric provides data relevant to number-parsing, including
4752 what constitute digits. Options in \a flags control whether a leading sign
4753 may be included. If \a from is passed, the scan starts at this index in \a
4754 text, otherwise from the start.
4755
4756 The resulting \l {QLocaleData::}{DigitSequence} contains the parsed digit
4757 sequence, \c digits, describes the positions of digits within \a text, by \c
4758 digitStart and \c digitWidth, and (where allowed) reports any sign.
4759
4760 When \c digits is empty, \c digitStart is the end of the text parsed: this
4761 is either where the sign ended, when \c hasSign(), or the value of \c from
4762 passed to the constructor. Otherwise, each \c{digits[i]} represents
4763 \c{text.sliced(digitStart + i * digitWidth, digitWidth)} and the whole text
4764 parsed is \c{text.first(digitStart + digits.size() *
4765 digitWidth).sliced(from)}. Either way, if \c hasSign(), it represents
4766 \c{text.first(endIndex()).sliced(from)}.
4767
4768 \sa {QLocaleData::DigitSequence::}{used()}
4769*/
4770QLocaleData::DigitSequence::DigitSequence(QStringView text, NumericData &&numeric,
4771 Options flags, qsizetype from)
4772 : digitStart(from), digitWidth(numeric.zeroWidth())
4773{
4774 NumericTokenizer tokens(text, std::move(numeric), IntegerMode, from);
4775 if (tokens.done())
4776 return;
4777 char currentToken = tokens.nextToken();
4778 if (!currentToken)
4779 return;
4780
4781 // Handle any leading sign:
4782 if (currentToken == '+' || currentToken == '-') {
4783 if (!flags.testFlag(Option::AllowSign))
4784 return;
4785 digitStart = tokens.index();
4786 sign = currentToken;
4787 currentToken = '\0';
4788 }
4789
4790 // Iterate what remains:
4791 while (currentToken || !tokens.done()) {
4792 if (!currentToken)
4793 currentToken = tokens.nextToken();
4794 if (!currentToken)
4795 return;
4796
4797 if (currentToken < '0' || currentToken > '9')
4798 return; // What we got was not a digit in our locale.
4799
4800 // We have a digit.
4801 digits.push_back(currentToken);
4802 currentToken = '\0';
4803 }
4804}
4805
4806/*!
4807 \internal
4808 QLocaleData::DigitSequence QLocaleData::digitSequence(QStringView text, QLocaleData::DigitSequence::Options, qsizetype from)
4809 \brief Returns a DigitSequence describing some portion of \a text starting at \a from.
4810
4811 As for the \l{QLocaleData::}{DigitSequence} constructor, supplying the
4812 \l{QLocaleData::}{NumericData} for this QLocaleData instance and the
4813 IntegerMode as the relevant argument to it.
4814*/
4815
4816/*
4817 Converts a number in locale representation to the C locale equivalent.
4818
4819 Only has to guarantee that a string that is a correct representation of a
4820 number will be converted. Checks signs, separators and digits appear in all
4821 the places they should, and nowhere else.
4822
4823 Returns true precisely if the number appears to be well-formed, modulo
4824 things a parser for C Locale strings (without digit-grouping separators;
4825 they're stripped) will catch. When it returns true, it records (and
4826 '\0'-terminates) the C locale representation in *result.
4827
4828 Note: only QString integer-parsing methods have a base parameter (hence need
4829 to cope with letters as possible digits); but these are now all routed via
4830 byteArrayToU?LongLong(), so no longer come via here. The QLocale
4831 number-parsers only work in decimal, so don't have to cope with any digits
4832 other than 0 through 9.
4833*/
4834bool QLocaleData::numberToCLocale(QStringView s, QLocale::NumberOptions number_options,
4835 NumberMode mode, CharBuff *result) const
4836{
4837 s = s.trimmed();
4838 if (s.size() < 1)
4839 return false;
4840 NumericTokenizer tokens(s, NumericData(this, mode), mode);
4841
4842 // Reflects order constraints on possible parts of a number:
4843 enum { Whole, Grouped, Fraction, Exponent, Name } stage = Whole;
4844 // Grouped is just Whole with some digit-grouping separators in it.
4845 // Name is Inf or NaN; excludes all others (so none can be after it).
4846
4847 // Fractional part *or* whole-number part can be empty, but not both, unless
4848 // we have Name. Exponent must have some digits in it.
4849 bool wantDigits = true;
4850
4851 // Digit-grouping details (all modes):
4852 bool needHigherGroup = false; // Set when first group is too short to be the only one
4853 qsizetype digitsInGroup = 0;
4854 const QLocaleData::GroupSizes &grouping = tokens.groupSizes();
4855 const auto badLeastGroup = [&]() {
4856 // In principle we could object to a complete absence of grouping, when
4857 // digitsInGroup >= qMax(grouping.first, grouping.least), unless the
4858 // locale itself would omit them. However, when merely not rejecting
4859 // grouping separators, we have historically accepted ungrouped digits,
4860 // so objecting now would break existing code.
4861 if (stage == Grouped) {
4862 Q_ASSERT(!number_options.testFlag(QLocale::RejectGroupSeparator));
4863 // First group was invalid if it was short and we've not seen a separator since:
4864 if (needHigherGroup)
4865 return true;
4866 // Were there enough digits since the last group separator?
4867 if (digitsInGroup != grouping.least)
4868 return true;
4869 }
4870 return false;
4871 };
4872
4873 char last = '\0';
4874 while (!tokens.done()) {
4875 char out = tokens.nextToken();
4876 if (out == 0)
4877 return false;
4878
4879 // Note that out can only be '.', 'e' or an inf/NaN character if the
4880 // mode allows it (else nextToken() would return 0 instead), so we don't
4881 // need to check mode.
4882 if (out == '.') {
4883 if (stage > Grouped) // Too late to start a fractional part.
4884 return false;
4885
4886 if (tokens.fractionGroupClash() && badLeastGroup()
4887 && digitsInGroup == grouping.higher) {
4888 // Reinterpret '.' as ',' (as they're indistinguishable) to
4889 // interpret the recent digits as a group, with the least to
4890 // follow (hopefully of a suitable length):
4891 out = ',';
4892 stage = Grouped;
4893 needHigherGroup = false;
4894 digitsInGroup = 0;
4895 } else {
4896 // That's the end of the integral part - check size of last group:
4897 if (badLeastGroup())
4898 return false;
4899 stage = Fraction;
4900 }
4901 } else if (out == 'e') {
4902 if (wantDigits || stage == Name || stage > Fraction)
4903 return false;
4904
4905 if (stage < Fraction) {
4906 // The 'e' ends the whole-number part, so check its last group:
4907 if (badLeastGroup())
4908 return false;
4909 } else if (number_options.testFlag(QLocale::RejectTrailingZeroesAfterDot)) {
4910 // In a fractional part, a 0 just before the exponent is trailing:
4911 if (last == '0')
4912 return false;
4913 }
4914 stage = Exponent;
4915 wantDigits = true; // We need some in the exponent
4916 } else if (out == ',') {
4917 // (If tokens.fractionGroupClash(), a comma only comes out of
4918 // nextToken() if there's a later separator, since the last is
4919 // always treated as dot. So if we have a comma here, treating it as
4920 // a dot wouldn't save the parse: the later dot-or-comma would make
4921 // the text malformed.)
4922 if (number_options.testFlag(QLocale::RejectGroupSeparator))
4923 return false;
4924
4925 switch (stage) {
4926 case Whole:
4927 // Check size of most significant group
4928 if (digitsInGroup == 0
4929 || digitsInGroup > qMax(grouping.first, grouping.higher)) {
4930 return false;
4931 }
4932 Q_ASSERT(!needHigherGroup);
4933 // First group is only allowed fewer than grouping.first digits
4934 // if it's followed by a grouping.higher group, i.e. there's a
4935 // later group separator:
4936 if (grouping.first > digitsInGroup)
4937 needHigherGroup = true;
4938 stage = Grouped;
4939 break;
4940 case Grouped:
4941 // Check size of group between two separators:
4942 if (digitsInGroup != grouping.higher)
4943 return false;
4944 needHigherGroup = false; // We just found it, if needed.
4945 break;
4946 // Only allow group chars within the whole-number part:
4947 case Fraction:
4948 case Exponent:
4949 case Name:
4950 return false;
4951 }
4952 digitsInGroup = 0;
4953 } else if (isAsciiDigit(out)) {
4954 if (stage == Name)
4955 return false;
4956 if (out == '0' && number_options.testFlag(QLocale::RejectLeadingZeroInExponent)
4957 && stage > Fraction && !tokens.done() && !isAsciiDigit(last)) {
4958 // After the exponent there can only be '+', '-' or digits. If
4959 // we find a '0' directly after some non-digit, then that is a
4960 // leading zero, acceptable only if it is the whole exponent.
4961 return false;
4962 }
4963 wantDigits = false;
4964 ++digitsInGroup;
4965 } else if (stage == Whole && tokens.isInfNanChar(out)) {
4966 if (!wantDigits) // Mixed digits with Inf/NaN
4967 return false;
4968 wantDigits = false;
4969 stage = Name;
4970 }
4971 // else: nothing special to do.
4972
4973 last = out;
4974 if (out != ',') // Leave group separators out of the result.
4975 result->append(out);
4976 }
4977 if (wantDigits)
4978 return false;
4979
4980 if (!number_options.testFlag(QLocale::RejectGroupSeparator)) {
4981 // If this is the end of the whole-part, check least significant group:
4982 if (stage < Fraction && badLeastGroup())
4983 return false;
4984 }
4985
4986 if (number_options.testFlag(QLocale::RejectTrailingZeroesAfterDot) && stage == Fraction) {
4987 // In the fractional part, a final zero is trailing:
4988 if (last == '0')
4989 return false;
4990 }
4991
4992 return true;
4993}
4994
4996QLocaleData::validateChars(QStringView str, NumberMode numMode, int decDigits,
4997 QLocale::NumberOptions number_options) const
4998{
4999 ParsingResult result;
5000 result.buff.reserve(str.size());
5001
5002 enum { Whole, Fractional, Exponent } state = Whole;
5003 const bool scientific = numMode == DoubleScientificMode;
5004 NumericTokenizer tokens(str, NumericData(this, numMode), numMode);
5005 char last = '\0';
5006
5007 while (!tokens.done()) {
5008 char c = tokens.nextToken();
5009
5010 if (isAsciiDigit(c)) {
5011 switch (state) {
5012 case Whole:
5013 // Nothing special to do (unless we want to check grouping sizes).
5014 break;
5015 case Fractional:
5016 // If a double has too many digits in its fractional part it is Invalid.
5017 if (decDigits-- == 0)
5018 return {};
5019 break;
5020 case Exponent:
5021 if (!isAsciiDigit(last)) {
5022 // This is the first digit in the exponent (there may have beena '+'
5023 // or '-' in before). If it's a zero, the exponent is zero-padded.
5024 if (c == '0' && (number_options & QLocale::RejectLeadingZeroInExponent))
5025 return {};
5026 }
5027 break;
5028 }
5029
5030 } else {
5031 switch (c) {
5032 case '.':
5033 // If an integer has a decimal point, it is Invalid.
5034 // A double can only have one, at the end of its whole-number part.
5035 if (numMode == IntegerMode || state != Whole)
5036 return {};
5037 // Even when decDigits is 0, we do allow the decimal point to be
5038 // present - just as long as no digits follow it.
5039
5040 state = Fractional;
5041 break;
5042
5043 case '+':
5044 case '-':
5045 // A sign can only appear at the start or after the e of scientific:
5046 if (last != '\0' && !(scientific && last == 'e'))
5047 return {};
5048 break;
5049
5050 case ',':
5051 // Grouping is only allowed after a digit in the whole-number portion:
5052 if ((number_options & QLocale::RejectGroupSeparator) || state != Whole
5053 || !isAsciiDigit(last)) {
5054 return {};
5055 }
5056 // We could check grouping sizes are correct, but fixup()s are
5057 // probably better off correcting any misplacement instead.
5058 break;
5059
5060 case 'e':
5061 // Only one e is allowed and only in scientific:
5062 if (!scientific || state == Exponent)
5063 return {};
5064 state = Exponent;
5065 break;
5066
5067 default:
5068 // Nothing else can validly appear in a number.
5069 // NumericTokenizer allows letters of "inf" and "nan", but
5070 // validators don't accept those values.
5071 // For anything else, tokens.nextToken() must have returned 0.
5072 Q_ASSERT(!c || c == 'a' || c == 'f' || c == 'i' || c == 'n');
5073 return {};
5074 }
5075 }
5076
5077 last = c;
5078 if (c != ',') // Skip grouping
5079 result.buff.append(c);
5080 }
5081
5083
5084 // Intermediate if it ends with any character that requires a digit after
5085 // it to be valid e.g. group separator, sign, or exponent
5086 if (last == ',' || last == '-' || last == '+' || last == 'e')
5088
5089 return result;
5090}
5091
5092double QLocaleData::stringToDouble(QStringView str, bool *ok,
5093 QLocale::NumberOptions number_options) const
5094{
5095 CharBuff buff;
5096 if (!numberToCLocale(str, number_options, DoubleScientificMode, &buff)) {
5097 if (ok != nullptr)
5098 *ok = false;
5099 return 0.0;
5100 }
5101 auto r = qt_asciiToDouble(buff.constData(), buff.size());
5102 if (ok != nullptr)
5103 *ok = r.ok();
5104 return r.result;
5105}
5106
5108QLocaleData::stringToLongLong(QStringView str, int base,
5109 QLocale::NumberOptions number_options) const
5110{
5111 CharBuff buff;
5112 if (!numberToCLocale(str, number_options, IntegerMode, &buff))
5113 return {};
5114
5115 return bytearrayToLongLong(QByteArrayView(buff), base);
5116}
5117
5119QLocaleData::stringToUnsLongLong(QStringView str, int base,
5120 QLocale::NumberOptions number_options) const
5121{
5122 CharBuff buff;
5123 if (!numberToCLocale(str, number_options, IntegerMode, &buff))
5124 return {};
5125
5126 return bytearrayToUnsLongLong(QByteArrayView(buff), base);
5127}
5128
5129static bool checkParsed(QByteArrayView num, qsizetype used)
5130{
5131 if (used <= 0)
5132 return false;
5133
5134 const qsizetype len = num.size();
5135 if (used < len && num[used] != '\0') {
5136 while (used < len && ascii_isspace(num[used]))
5137 ++used;
5138 }
5139
5140 if (used < len && num[used] != '\0')
5141 // we stopped at a non-digit character after converting some digits
5142 return false;
5143
5144 return true;
5145}
5146
5147QSimpleParsedNumber<qint64> QLocaleData::bytearrayToLongLong(QByteArrayView num, int base)
5148{
5149 auto r = qstrntoll(num.data(), num.size(), base);
5150 if (!checkParsed(num, r.used))
5151 return {};
5152 return r;
5153}
5154
5155QSimpleParsedNumber<quint64> QLocaleData::bytearrayToUnsLongLong(QByteArrayView num, int base)
5156{
5157 auto r = qstrntoull(num.data(), num.size(), base);
5158 if (!checkParsed(num, r.used))
5159 return {};
5160 return r;
5161}
5162
5163/*!
5164 \since 4.8
5165
5166 \enum QLocale::CurrencySymbolFormat
5167
5168 Specifies the format of the currency symbol.
5169
5170 \value CurrencyIsoCode a ISO-4217 code of the currency.
5171 \value CurrencySymbol a currency symbol.
5172 \value CurrencyDisplayName a user readable name of the currency.
5173*/
5174
5175/*!
5176 \since 4.8
5177 Returns a currency symbol according to the \a format.
5178*/
5179QString QLocale::currencySymbol(CurrencySymbolFormat format) const
5180{
5181#ifndef QT_NO_SYSTEMLOCALE
5182 if (d->m_data == &systemLocaleData) {
5183 auto res = systemLocale()->query(QSystemLocale::CurrencySymbol, format).toString();
5184 if (!res.isEmpty())
5185 return res;
5186 }
5187#endif
5188 switch (format) {
5189 case CurrencySymbol:
5190 return d->m_data->currencySymbol().getData(currency_symbol_data);
5191 case CurrencyDisplayName:
5192 return d->m_data->currencyDisplayName().getData(currency_display_name_data);
5193 case CurrencyIsoCode: {
5194 const char *code = d->m_data->m_currency_iso_code;
5195 if (auto len = qstrnlen(code, 3))
5196 return QString::fromLatin1(code, qsizetype(len));
5197 break;
5198 }
5199 }
5200 return QString();
5201}
5202
5203/*!
5204 \since 4.8
5205
5206 Returns a localized string representation of \a value as a currency.
5207 If the \a symbol is provided it is used instead of the default currency symbol.
5208
5209 \sa currencySymbol()
5210*/
5211QString QLocale::toCurrencyString(qlonglong value, const QString &symbol) const
5212{
5213#ifndef QT_NO_SYSTEMLOCALE
5214 if (d->m_data == &systemLocaleData) {
5215 QSystemLocale::CurrencyToStringArgument arg(value, symbol);
5216 auto res = systemLocale()->query(QSystemLocale::CurrencyToString,
5217 QVariant::fromValue(arg)).toString();
5218 if (!res.isEmpty())
5219 return res;
5220 }
5221#endif
5222 QLocaleData::DataRange range = d->m_data->currencyFormatNegative();
5223 if (!range.size || value >= 0)
5224 range = d->m_data->currencyFormat();
5225 else
5226 value = -value;
5227 QString str = toString(value);
5228 QString sym = symbol.isNull() ? currencySymbol() : symbol;
5229 if (sym.isEmpty())
5230 sym = currencySymbol(CurrencyIsoCode);
5231 return range.viewData(currency_format_data).arg(str, sym);
5232}
5233
5234/*!
5235 \since 4.8
5236 \overload
5237*/
5238QString QLocale::toCurrencyString(qulonglong value, const QString &symbol) const
5239{
5240#ifndef QT_NO_SYSTEMLOCALE
5241 if (d->m_data == &systemLocaleData) {
5242 QSystemLocale::CurrencyToStringArgument arg(value, symbol);
5243 auto res = systemLocale()->query(QSystemLocale::CurrencyToString,
5244 QVariant::fromValue(arg)).toString();
5245 if (!res.isEmpty())
5246 return res;
5247 }
5248#endif
5249 QString str = toString(value);
5250 QString sym = symbol.isNull() ? currencySymbol() : symbol;
5251 if (sym.isEmpty())
5252 sym = currencySymbol(CurrencyIsoCode);
5253 return d->m_data->currencyFormat().getData(currency_format_data).arg(str, sym);
5254}
5255
5256/*!
5257 \since 5.7
5258 \overload toCurrencyString()
5259
5260 Returns a localized string representation of \a value as a currency.
5261 If the \a symbol is provided it is used instead of the default currency symbol.
5262 If the \a precision is provided it is used to set the precision of the currency value.
5263
5264 \sa currencySymbol()
5265 */
5266QString QLocale::toCurrencyString(double value, const QString &symbol, int precision) const
5267{
5268#ifndef QT_NO_SYSTEMLOCALE
5269 if (d->m_data == &systemLocaleData) {
5270 QSystemLocale::CurrencyToStringArgument arg(value, symbol);
5271 auto res = systemLocale()->query(QSystemLocale::CurrencyToString,
5272 QVariant::fromValue(arg)).toString();
5273 if (!res.isEmpty())
5274 return res;
5275 }
5276#endif
5277 QLocaleData::DataRange range = d->m_data->currencyFormatNegative();
5278 if (!range.size || value >= 0)
5279 range = d->m_data->currencyFormat();
5280 else
5281 value = -value;
5282 QString str = toString(value, 'f', precision == -1 ? d->m_data->m_currency_digits : precision);
5283 QString sym = symbol.isNull() ? currencySymbol() : symbol;
5284 if (sym.isEmpty())
5285 sym = currencySymbol(CurrencyIsoCode);
5286 return range.viewData(currency_format_data).arg(str, sym);
5287}
5288
5289/*!
5290 \fn QString QLocale::toCurrencyString(float i, const QString &symbol, int precision) const
5291 \overload toCurrencyString()
5292*/
5293
5294/*!
5295 \since 5.10
5296
5297 \enum QLocale::DataSizeFormat
5298
5299 Specifies the format for representation of data quantities.
5300
5301 \omitvalue DataSizeBase1000
5302 \omitvalue DataSizeSIQuantifiers
5303 \value DataSizeIecFormat format using base 1024 and IEC prefixes: KiB, MiB, GiB, ...
5304 \value DataSizeTraditionalFormat format using base 1024 and SI prefixes: kB, MB, GB, ...
5305 \value DataSizeSIFormat format using base 1000 and SI prefixes: kB, MB, GB, ...
5306
5307 \sa formattedDataSize()
5308*/
5309
5310/*!
5311 \since 5.10
5312
5313 Converts a size in bytes to a human-readable localized string, comprising a
5314 number and a quantified unit. The quantifier is chosen such that the number
5315 is at least one, and as small as possible. For example if \a bytes is
5316 16384, \a precision is 2, and \a format is \l DataSizeIecFormat (the
5317 default), this function returns "16.00 KiB"; for 1330409069609 bytes it
5318 returns "1.21 GiB"; and so on. If \a format is \l DataSizeIecFormat or
5319 \l DataSizeTraditionalFormat, the given number of bytes is divided by a
5320 power of 1024, with result less than 1024; for \l DataSizeSIFormat, it is
5321 divided by a power of 1000, with result less than 1000.
5322 \c DataSizeIecFormat uses the new IEC standard quantifiers Ki, Mi and so on,
5323 whereas \c DataSizeSIFormat uses the older SI quantifiers k, M, etc., and
5324 \c DataSizeTraditionalFormat abuses them.
5325*/
5326QString QLocale::formattedDataSize(qint64 bytes, int precision, DataSizeFormats format) const
5327{
5328 int power, base = 1000;
5329 if (!bytes) {
5330 power = 0;
5331 } else if (format & DataSizeBase1000) {
5332 constexpr auto log10_1000 = 3; // std::log10(1000U)
5333 power = int(std::log10(QtPrivate::qUnsignedAbs(bytes))) / log10_1000;
5334 } else {
5335 constexpr auto log2_1024 = 10; // QtPrivate::log2i(1024U);
5336 power = QtPrivate::log2i(QtPrivate::qUnsignedAbs(bytes)) / log2_1024;
5337 base = 1024;
5338 }
5339 // Only go to doubles if we'll be using a quantifier:
5340 const QString number = power
5341 ? toString(bytes / std::pow(double(base), power), 'f', qMin(precision, 3 * power))
5342 : toString(bytes);
5343
5344 // We don't support sizes in units larger than exbibytes because
5345 // the number of bytes would not fit into qint64.
5346 Q_ASSERT(power <= 6 && power >= 0);
5347 QStringView unit;
5348 if (power > 0) {
5349 QLocaleData::DataRange range = (format & DataSizeSIQuantifiers)
5350 ? d->m_data->byteAmountSI() : d->m_data->byteAmountIEC();
5351 unit = range.viewListEntry(byte_unit_data, power - 1);
5352 } else {
5353 unit = d->m_data->byteCount().viewData(byte_unit_data);
5354 }
5355
5356 return number + u' ' + unit;
5357}
5358
5359/*!
5360 \since 4.8
5361 \brief List of locale names for use in selecting translations
5362
5363 Each entry in the returned list is the name of a locale suitable to the
5364 user's preferences for what to translate the UI into. Where a name in the
5365 list is composed of several tags, they are joined as indicated by \a
5366 separator. Prior to Qt 6.7 a dash was used as separator.
5367
5368 For example, using the default separator QLocale::TagSeparator::Dash, if the
5369 user has configured their system to use English as used in the USA, the list
5370 would be "en-Latn-US", "en-US", "en-Latn", "en". The order of entries is the
5371 order in which to check for translations; earlier items in the list are to
5372 be preferred over later ones. If your translation files (or other resources
5373 specific to locale) use underscores, rather than dashes, to separate locale
5374 tags, pass QLocale::TagSeparator::Underscore as \a separator.
5375
5376 Returns a list of locale names. This may include multiple languages,
5377 especially for the system locale when multiple UI translation languages are
5378 configured. The order of entries is significant. For example, for the system
5379 locale, it reflects user preferences.
5380
5381 Prior to Qt 6.9, the list only contained explicitly configured locales and
5382 their equivalents. This led some callers to add truncations (such as from
5383 'en-Latn-DE' to 'en') as fallbacks. This could sometimes result in
5384 inappropriate choices, especially if these were tried before later entries
5385 that would be more appropriate fallbacks.
5386
5387 Starting from Qt 6.9, reasonable truncations are included in the returned
5388 list \e after all entries equivalent to the explicitly specified
5389 locales. This change allows for more accurate fallback options without
5390 callers needing to do any truncation.
5391
5392 Users can explicitly include preferred fallback locales (such as en-US) in
5393 their system configuration to control the order of preference. You are
5394 advised to rely on the order of entries in uiLanguages() rather than using
5395 custom fallback methods.
5396
5397 Most likely you do not need to use this function directly, but just pass the
5398 QLocale object to the QTranslator::load() function.
5399
5400 \sa QTranslator, bcp47Name()
5401*/
5402QStringList QLocale::uiLanguages(TagSeparator separator) const
5403{
5404 const char sep = char(separator);
5405 QStringList uiLanguages;
5406 if (uchar(sep) > 0x7f) {
5407 badSeparatorWarning("uiLanguages", sep);
5408 return uiLanguages;
5409 }
5410 QList<QLocaleId> localeIds;
5411#ifdef QT_NO_SYSTEMLOCALE
5412 constexpr bool isSystem = false;
5413#else
5414 const bool isSystem = d->m_data == &systemLocaleData;
5415 if (isSystem) {
5416 uiLanguages = systemLocale()->query(QSystemLocale::UILanguages).toStringList();
5417 if (separator != TagSeparator::Dash) {
5418 // Map from default separator, Dash, used by backends:
5419 const QChar join = QLatin1Char(sep);
5420 uiLanguages.replaceInStrings(u"-", QStringView(&join, 1));
5421 }
5422 // ... but we need to include likely-adjusted forms of each of those, too.
5423 // For now, collect up locale Ids representing the entries, for later processing:
5424 for (const auto &entry : std::as_const(uiLanguages))
5425 localeIds.append(QLocaleId::fromName(entry));
5426 if (localeIds.isEmpty())
5427 localeIds.append(systemLocale()->fallbackLocale().d->m_data->id());
5428 /* Note: Darwin allows entirely independent choice of locale and of
5429 preferred languages, so it's possible the locale implied by
5430 LanguageId, ScriptId and TerritoryId is absent from the UILanguages
5431 list and that this faithfully reflects the user's wishes. None the
5432 less, we include it (if it isn't C) in the list below, after the last
5433 with the same language and script or (if none has) at the end, in
5434 case there is no better option available. (See, QTBUG-104930.)
5435 */
5436 const QString name = QString::fromLatin1(d->m_data->id().name(sep)); // Raw name
5437 if (!name.isEmpty() && language() != C && !uiLanguages.contains(name)) {
5438 // That uses contains(name) as a cheap pre-test, but there may be an
5439 // entry that matches this on purging likely subtags.
5440 const QLocaleId id = d->m_data->id();
5441 const QLocaleId max = id.withLikelySubtagsAdded();
5442 const QLocaleId mine = max.withLikelySubtagsRemoved();
5443 // Default to putting at the end:
5444 qsizetype lastAlike = uiLanguages.size() - 1;
5445 bool seen = false;
5446 for (qsizetype i = 0; !seen && i < uiLanguages.size(); ++i) {
5447 const auto its = QLocaleId::fromName(uiLanguages.at(i)).withLikelySubtagsAdded();
5448 seen = its.withLikelySubtagsRemoved() == mine;
5449 if (!seen && its.language_id == max.language_id && its.script_id == max.script_id)
5450 lastAlike = i;
5451 }
5452 if (!seen) {
5453 localeIds.insert(lastAlike + 1, id);
5454 uiLanguages.insert(lastAlike + 1, QString::fromLatin1(id.name(sep)));
5455 }
5456 }
5457 } else
5458#endif
5459 {
5460 localeIds.append(d->m_data->id());
5461 }
5462
5463 for (qsizetype i = localeIds.size(); i-- > 0; ) {
5464 const QLocaleId id = localeIds.at(i);
5465 Q_ASSERT(id.language_id);
5466 if (id.language_id == C) {
5467 if (!uiLanguages.contains(u"C"_s))
5468 uiLanguages.append(u"C"_s);
5469 // Attempt no likely sub-tag amendments to C.
5470 continue;
5471 }
5472
5473 qsizetype j;
5474 const QByteArray prior = id.name(sep);
5475 bool faithful = true; // prior matches uiLanguages.at(j - 1)
5476 if (isSystem && i < uiLanguages.size()) {
5477 // Adding likely-adjusted forms to system locale's list.
5478 faithful = uiLanguages.at(i) == QLatin1StringView(prior);
5479 Q_ASSERT(faithful
5480 // A legacy code may get mapped to an ID with a different name:
5481 || QLocaleId::fromName(uiLanguages.at(i)).name(sep) == prior);
5482 // Insert just after the entry we're supplementing:
5483 j = i + 1;
5484 } else {
5485 // Plain locale or empty system uiLanguages; just append.
5486 if (!uiLanguages.contains(QLatin1StringView(prior)))
5487 uiLanguages.append(QString::fromLatin1(prior));
5488 j = uiLanguages.size();
5489 }
5490
5491 const QLocaleId max = id.withLikelySubtagsAdded();
5492 Q_ASSERT(max.language_id);
5493 Q_ASSERT(max.language_id == id.language_id);
5494 // We can't say the same for script or territory, though.
5495
5496 // We have various candidates to consider.
5497 const auto addIfEquivalent = [&j, &uiLanguages, max, sep, &prior, faithful](QLocaleId cid) {
5498 if (cid.withLikelySubtagsAdded() == max) {
5499 if (const QByteArray name = cid.name(sep); name != prior)
5500 uiLanguages.insert(j, QString::fromLatin1(name));
5501 else if (faithful) // Later candidates are more specific, so go before.
5502 --j;
5503 }
5504 };
5505 // language
5506 addIfEquivalent({ max.language_id, 0, 0 });
5507 // language-script
5508 if (max.script_id)
5509 addIfEquivalent({ max.language_id, max.script_id, 0 });
5510 if (id.script_id && id.script_id != max.script_id)
5511 addIfEquivalent({ id.language_id, id.script_id, 0 });
5512 // language-territory
5513 if (max.territory_id)
5514 addIfEquivalent({ max.language_id, 0, max.territory_id });
5515 if (id.territory_id && id.territory_id != max.territory_id)
5516 addIfEquivalent({ id.language_id, 0, id.territory_id });
5517 // full
5518 if (max.territory_id && max.script_id)
5519 addIfEquivalent(max);
5520 if (max.territory_id && id.script_id && id.script_id != max.script_id)
5521 addIfEquivalent({ id.language_id, id.script_id, max.territory_id });
5522 if (max.script_id && id.territory_id && id.territory_id != max.territory_id)
5523 addIfEquivalent({ id.language_id, max.script_id, id.territory_id });
5524 if (id.territory_id && id.territory_id != max.territory_id
5525 && id.script_id && id.script_id != max.script_id) {
5526 addIfEquivalent(id);
5527 }
5528 }
5529
5530 // Second pass: deduplicate.
5531 // Can't use QStringList::removeDuplicates() here, because we still need
5532 // the QDuplicateTracker, later.
5533 QDuplicateTracker<QString> known(uiLanguages.size());
5534 uiLanguages.removeIf([&](const QString &s) { return known.hasSeen(s); });
5535
5536 // Third pass: add truncations, when not already present.
5537 // Cubic in list length, but hopefully that's at most a dozen or so.
5538 const QLatin1Char cut(sep);
5539 const auto hasPrefix = [cut](auto name, QStringView stem) {
5540 // A prefix only counts if it's either full or followed by a separator.
5541 return name.startsWith(stem)
5542 && (name.size() == stem.size() || name.at(stem.size()) == cut);
5543 };
5544 // As we now forward-traverse the list, we need to keep track of the
5545 // positions just after (a) the block of things added above that are
5546 // equivalent to the current entry and (b) the block of truncations (if any)
5547 // added just after this block. All truncations of entries in (a) belong at
5548 // the end of (b); once i advances to the end of (a) it must jump to just
5549 // after (b). The more specific entries in (a) may well have truncations
5550 // that can also arise from less specific ones later in (a); for the
5551 // purposes of determining whether such truncations go at the end of (b) or
5552 // the end of the list, we thus need to ignore these matches.
5553 qsizetype afterEquivs = 0;
5554 qsizetype afterTruncs = 0;
5555 // From here onwards, we only have the truncations we're adding, whose
5556 // truncations should all have been included already.
5557 // If advancing i brings us to the end of block (a), jump to the end of (b):
5558 for (qsizetype i = 0; i < uiLanguages.size(); ++i >= afterEquivs && (i = afterTruncs)) {
5559 const QString entry = uiLanguages.at(i);
5560 const QLocaleId max = QLocaleId::fromName(entry).withLikelySubtagsAdded();
5561 // Keep track of our two blocks:
5562 if (i >= afterEquivs) {
5563 Q_ASSERT(i >= afterTruncs); // i.e. we just skipped past the end of a block
5564 afterEquivs = i + 1;
5565 // Advance past equivalents of entry:
5566 while (afterEquivs < uiLanguages.size()
5567 && QLocaleId::fromName(uiLanguages.at(afterEquivs))
5568 .withLikelySubtagsAdded() == max) {
5569 ++afterEquivs;
5570 }
5571 // We'll add any truncations starting there:
5572 afterTruncs = afterEquivs;
5573 }
5574 if (hasPrefix(entry, u"C") || hasPrefix(entry, u"und"))
5575 continue;
5576 qsizetype stopAt = uiLanguages.size();
5577 qsizetype at = entry.size(); // if 0, calls lastIndexOf(cut, -1), which is in-contract
5578 while ((at = entry.lastIndexOf(cut, at - 1)) > 0) {
5579 QString prefix = entry.first(at);
5580 // Don't test with hasSeen() as we might defer adding to later, when
5581 // we'll need known to see the later entry's offering of this prefix
5582 // as a new entry.
5583 bool found = known.contains(prefix);
5584 /* By default we append but if no later entry has this as a prefix
5585 and the locale it implies would use the same script as entry, put
5586 it after the block of consecutive equivalents of which entry is a
5587 part instead. Thus [en-NL, nl-NL, en-GB] will append en but
5588 [en-NL, en-GB, nl-NL] will put it before nl-NL, for example. We
5589 require a script match so we don't pick translations that the
5590 user cannot read, despite knowing the language. (Ideally that
5591 would be a constraint the caller can opt into / out of. See
5592 QTBUG-112765.)
5593 */
5594 bool justAfter
5595 = (QLocaleId::fromName(prefix).withLikelySubtagsAdded().script_id == max.script_id);
5596 for (qsizetype j = afterTruncs; !found && j < stopAt; ++j) {
5597 QString later = uiLanguages.at(j);
5598 if (!later.startsWith(prefix)) {
5599 const QByteArray laterFull =
5600 QLocaleId::fromName(later.replace(cut, u'-')
5601 ).withLikelySubtagsAdded().name(sep);
5602 // When prefix matches a later entry's max, it belongs later.
5603 if (hasPrefix(QLatin1StringView(laterFull), prefix))
5604 justAfter = false;
5605 continue;
5606 }
5607 // The duplicate tracker would already have spotted if equal:
5608 Q_ASSERT(later.size() > prefix.size());
5609 if (later.at(prefix.size()) == cut) {
5610 justAfter = false;
5611 // Prefix match. Shall produce the same prefix, but possibly
5612 // after prefixes of other entries in the list. If later has
5613 // a longer prefix not yet in the list, we want that before
5614 // this shorter prefix, so leave this for later, otherwise,
5615 // we include this prefix right away.
5616 QStringView head{later};
5617 for (qsizetype as = head.lastIndexOf(cut);
5618 !found && as > prefix.size(); as = head.lastIndexOf(cut)) {
5619 head = head.first(as);
5620 bool seen = false;
5621 for (qsizetype k = j + 1; !seen && k < uiLanguages.size(); ++k)
5622 seen = uiLanguages.at(k) == head;
5623 if (!seen)
5624 found = true;
5625 }
5626 }
5627 }
5628 if (found) // Don't duplicate.
5629 continue; // Some shorter truncations may still be missing.
5630 // Now we're committed to adding it, get it into known:
5631 (void) known.hasSeen(prefix);
5632 if (justAfter) {
5633 uiLanguages.insert(afterTruncs++, std::move(prefix));
5634 ++stopAt; // All later entries have moved one step later.
5635 } else {
5636 uiLanguages.append(std::move(prefix));
5637 }
5638 }
5639 }
5640
5641 return uiLanguages;
5642}
5643
5644/*!
5645 \since 5.13
5646
5647 Returns the locale to use for collation.
5648
5649 The result is usually this locale; however, the system locale (which is
5650 commonly the default locale) will return the system collation locale.
5651 The result is suitable for passing to QCollator's constructor.
5652
5653 \sa QCollator
5654*/
5655QLocale QLocale::collation() const
5656{
5657#ifndef QT_NO_SYSTEMLOCALE
5658 if (d->m_data == &systemLocaleData) {
5659 const auto res = systemLocale()->query(QSystemLocale::Collation).toString();
5660 if (!res.isEmpty())
5661 return QLocale(res);
5662 }
5663#endif
5664 return *this;
5665}
5666
5667/*!
5668 \since 4.8
5669
5670 Returns a native name of the language for the locale. For example
5671 "Schweizer Hochdeutsch" for the Swiss-German locale.
5672
5673 \sa nativeTerritoryName(), languageToString()
5674*/
5675QString QLocale::nativeLanguageName() const
5676{
5677#ifndef QT_NO_SYSTEMLOCALE
5678 if (d->m_data == &systemLocaleData) {
5679 auto res = systemLocale()->query(QSystemLocale::NativeLanguageName).toString();
5680 if (!res.isEmpty())
5681 return res;
5682 }
5683#endif
5684 return d->m_data->endonymLanguage().getData(endonyms_data);
5685}
5686
5687/*!
5688 \since 6.2
5689
5690 Returns a native name of the territory for the locale. For example
5691 "España" for Spanish/Spain locale.
5692
5693 \sa nativeLanguageName(), territoryToString()
5694*/
5695QString QLocale::nativeTerritoryName() const
5696{
5697#ifndef QT_NO_SYSTEMLOCALE
5698 if (d->m_data == &systemLocaleData) {
5699 auto res = systemLocale()->query(QSystemLocale::NativeTerritoryName).toString();
5700 if (!res.isEmpty())
5701 return res;
5702 }
5703#endif
5704 return d->m_data->endonymTerritory().getData(endonyms_data);
5705}
5706
5707#if QT_DEPRECATED_SINCE(6, 6)
5708/*!
5709 \deprecated [6.6] Use \l nativeTerritoryName() instead.
5710 \since 4.8
5711
5712 Returns a native name of the territory for the locale. For example
5713 "España" for Spanish/Spain locale.
5714
5715 \sa nativeLanguageName(), territoryToString()
5716*/
5717QString QLocale::nativeCountryName() const
5718{
5719 return nativeTerritoryName();
5720}
5721#endif
5722
5723#ifndef QT_NO_DEBUG_STREAM
5724QDebug operator<<(QDebug dbg, const QLocale &l)
5725{
5726 QDebugStateSaver saver(dbg);
5727 const bool isSys = l == QLocale::system();
5728 dbg.nospace().noquote()
5729 << (isSys ? "QLocale::system()/* " : "QLocale(")
5730 << QLocale::languageToString(l.language()) << ", "
5731 << QLocale::scriptToString(l.script()) << ", "
5732 << QLocale::territoryToString(l.territory()) << (isSys ? " */" : ")");
5733 return dbg;
5734}
5735#endif
5736QT_END_NAMESPACE
5737
5738#ifndef QT_NO_QOBJECT
5739#include "moc_qlocale.cpp"
5740#endif
const QLocaleData *const m_data
Definition qlocale_p.h:715
QLocale::MeasurementSystem measurementSystem() const
Definition qlocale.cpp:3529
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:5724
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:5129
static QString rawWeekDayName(const QLocaleData *data, const int day, QLocale::FormatType type)
Definition qlocale.cpp:3331
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:3355
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:3278
static T toIntegral_helper(const QLocalePrivate *d, QStringView str, bool *ok)
Definition qlocale.cpp:1562
static bool timeFormatContainsAP(QStringView format)
Definition qlocale.cpp:2434
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:3305
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:3317
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:3740
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:1847
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:5108
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:4834
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:4050
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:5092
QString longLongToString(qint64 l, int precision=-1, int base=10, int width=-1, unsigned flags=NoFlags) const
Definition qlocale.cpp:4293
@ 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:5119
QString unsLongLongToString(quint64 l, int precision=-1, int base=10, int width=-1, unsigned flags=NoFlags) const
Definition qlocale.cpp:4308
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