1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Copyright (C) 2016 Intel Corporation.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the QtCore module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or (at your option) the GNU General
29** Public license version 3 or any later version approved by the KDE Free
30** Qt Foundation. The licenses are as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32** included in the packaging of this file. Please review the following
33** information to ensure the GNU General Public License requirements will
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35** https://www.gnu.org/licenses/gpl-3.0.html.
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#ifndef QLOCALE_P_H
42#define QLOCALE_P_H
43
44//
45// W A R N I N G
46// -------------
47//
48// This file is not part of the Qt API. It exists for the convenience
49// of internal files. This header file may change from version to version
50// without notice, or even be removed.
51//
52// We mean it.
53//
54
55#include <QtCore/private/qglobal_p.h>
56#include "QtCore/qstring.h"
57#include "QtCore/qvarlengtharray.h"
58#include "QtCore/qvariant.h"
59#include "QtCore/qnumeric.h"
60
61#include "qlocale.h"
62
63#include <limits>
64#include <cmath>
65
66QT_BEGIN_NAMESPACE
67
68#ifndef QT_NO_SYSTEMLOCALE
69struct QLocaleData;
70class Q_CORE_EXPORT QSystemLocale
71{
72public:
73 QSystemLocale();
74 virtual ~QSystemLocale();
75
76 struct CurrencyToStringArgument
77 {
78 CurrencyToStringArgument() { }
79 CurrencyToStringArgument(const QVariant &v, const QString &s)
80 : value(v), symbol(s) { }
81 QVariant value;
82 QString symbol;
83 };
84
85 enum QueryType {
86 LanguageId, // uint
87 CountryId, // uint
88 DecimalPoint, // QString
89 GroupSeparator, // QString
90 ZeroDigit, // QString
91 NegativeSign, // QString
92 DateFormatLong, // QString
93 DateFormatShort, // QString
94 TimeFormatLong, // QString
95 TimeFormatShort, // QString
96 DayNameLong, // QString, in: int
97 DayNameShort, // QString, in: int
98 MonthNameLong, // QString, in: int
99 MonthNameShort, // QString, in: int
100 DateToStringLong, // QString, in: QDate
101 DateToStringShort, // QString in: QDate
102 TimeToStringLong, // QString in: QTime
103 TimeToStringShort, // QString in: QTime
104 DateTimeFormatLong, // QString
105 DateTimeFormatShort, // QString
106 DateTimeToStringLong, // QString in: QDateTime
107 DateTimeToStringShort, // QString in: QDateTime
108 MeasurementSystem, // uint
109 PositiveSign, // QString
110 AMText, // QString
111 PMText, // QString
112 FirstDayOfWeek, // Qt::DayOfWeek
113 Weekdays, // QList<Qt::DayOfWeek>
114 CurrencySymbol, // QString in: CurrencyToStringArgument
115 CurrencyToString, // QString in: qlonglong, qulonglong or double
116 Collation, // QString
117 UILanguages, // QStringList
118 StringToStandardQuotation, // QString in: QStringRef to quote
119 StringToAlternateQuotation, // QString in: QStringRef to quote
120 ScriptId, // uint
121 ListToSeparatedString, // QString
122 LocaleChanged, // system locale changed
123 NativeLanguageName, // QString
124 NativeCountryName, // QString
125 StandaloneMonthNameLong, // QString, in: int
126 StandaloneMonthNameShort // QString, in: int
127 };
128 virtual QVariant query(QueryType type, QVariant in) const;
129 virtual QLocale fallbackUiLocale() const;
130
131 inline const QLocaleData *fallbackUiLocaleData() const;
132private:
133 QSystemLocale(bool);
134 friend class QSystemLocaleSingleton;
135};
136Q_DECLARE_TYPEINFO(QSystemLocale::QueryType, Q_PRIMITIVE_TYPE);
137Q_DECLARE_TYPEINFO(QSystemLocale::CurrencyToStringArgument, Q_MOVABLE_TYPE);
138#endif
139
140#if QT_CONFIG(icu)
141namespace QIcu {
142 QString toUpper(const QByteArray &localeId, const QString &str, bool *ok);
143 QString toLower(const QByteArray &localeId, const QString &str, bool *ok);
144}
145#endif
146
147
148struct QLocaleId
149{
150 // bypass constructors
151 static inline QLocaleId fromIds(ushort language, ushort script, ushort country)
152 {
153 const QLocaleId localeId = { language, script, country };
154 return localeId;
155 }
156
157 inline bool operator==(QLocaleId other) const
158 { return language_id == other.language_id && script_id == other.script_id && country_id == other.country_id; }
159 inline bool operator!=(QLocaleId other) const
160 { return !operator==(other); }
161
162 QLocaleId withLikelySubtagsAdded() const;
163 QLocaleId withLikelySubtagsRemoved() const;
164
165 QByteArray name(char separator = '-') const;
166
167 ushort language_id, script_id, country_id;
168};
169Q_DECLARE_TYPEINFO(QLocaleId, Q_PRIMITIVE_TYPE);
170
171struct QLocaleData
172{
173public:
174 static const QLocaleData *findLocaleData(QLocale::Language language,
175 QLocale::Script script,
176 QLocale::Country country);
177 static const QLocaleData *c();
178
179 // Maximum number of significant digits needed to represent a double.
180 // We cannot use std::numeric_limits here without constexpr.
181 static const int DoubleMantissaBits = 53;
182 static const int Log10_2_100000 = 30103; // log10(2) * 100000
183 // same as C++11 std::numeric_limits<T>::max_digits10
184 static const int DoubleMaxSignificant = (DoubleMantissaBits * Log10_2_100000) / 100000 + 2;
185
186 // Maximum number of digits before decimal point to represent a double
187 // Same as std::numeric_limits<double>::max_exponent10 + 1
188 static const int DoubleMaxDigitsBeforeDecimal = 309;
189
190 enum DoubleForm {
191 DFExponent = 0,
192 DFDecimal,
193 DFSignificantDigits,
194 _DFMax = DFSignificantDigits
195 };
196
197 enum Flags {
198 NoFlags = 0,
199 AddTrailingZeroes = 0x01,
200 ZeroPadded = 0x02,
201 LeftAdjusted = 0x04,
202 BlankBeforePositive = 0x08,
203 AlwaysShowSign = 0x10,
204 ThousandsGroup = 0x20,
205 CapitalEorX = 0x40,
206
207 ShowBase = 0x80,
208 UppercaseBase = 0x100,
209 ZeroPadExponent = 0x200,
210 ForcePoint = 0x400
211 };
212
213 enum NumberMode { IntegerMode, DoubleStandardMode, DoubleScientificMode };
214
215 typedef QVarLengthArray<char, 256> CharBuff;
216
217 static QString doubleToString(const QChar zero, const QChar plus,
218 const QChar minus, const QChar exponent,
219 const QChar group, const QChar decimal,
220 double d, int precision,
221 DoubleForm form,
222 int width, unsigned flags);
223 static QString longLongToString(const QChar zero, const QChar group,
224 const QChar plus, const QChar minus,
225 qint64 l, int precision, int base,
226 int width, unsigned flags);
227 static QString unsLongLongToString(const QChar zero, const QChar group,
228 const QChar plus,
229 quint64 l, int precision,
230 int base, int width,
231 unsigned flags);
232
233 QString doubleToString(double d,
234 int precision = -1,
235 DoubleForm form = DFSignificantDigits,
236 int width = -1,
237 unsigned flags = NoFlags) const;
238 QString longLongToString(qint64 l, int precision = -1,
239 int base = 10,
240 int width = -1,
241 unsigned flags = NoFlags) const;
242 QString unsLongLongToString(quint64 l, int precision = -1,
243 int base = 10,
244 int width = -1,
245 unsigned flags = NoFlags) const;
246
247 // this function is meant to be called with the result of stringToDouble or bytearrayToDouble
248 static float convertDoubleToFloat(double d, bool *ok)
249 {
250 if (qIsInf(d))
251 return float(d);
252 if (std::fabs(d) > std::numeric_limits<float>::max()) {
253 if (ok)
254 *ok = false;
255 const float huge = std::numeric_limits<float>::infinity();
256 return d < 0 ? -huge : huge;
257 }
258 if (d != 0 && float(d) == 0) {
259 // Values that underflow double already failed. Match them:
260 if (ok)
261 *ok = false;
262 return 0;
263 }
264 return float(d);
265 }
266
267 double stringToDouble(QStringView str, bool *ok, QLocale::NumberOptions options) const;
268 qint64 stringToLongLong(QStringView str, int base, bool *ok, QLocale::NumberOptions options) const;
269 quint64 stringToUnsLongLong(QStringView str, int base, bool *ok, QLocale::NumberOptions options) const;
270
271 static double bytearrayToDouble(const char *num, bool *ok);
272 // this function is used in QIntValidator (QtGui)
273 Q_CORE_EXPORT static qint64 bytearrayToLongLong(const char *num, int base, bool *ok);
274 static quint64 bytearrayToUnsLongLong(const char *num, int base, bool *ok);
275
276 bool numberToCLocale(QStringView s, QLocale::NumberOptions number_options,
277 CharBuff *result) const;
278 inline char digitToCLocale(QChar c) const;
279
280 // this function is used in QIntValidator (QtGui)
281 Q_CORE_EXPORT bool validateChars(QStringView str, NumberMode numMode, QByteArray *buff, int decDigits = -1,
282 QLocale::NumberOptions number_options = QLocale::DefaultNumberOptions) const;
283
284public:
285 quint16 m_language_id, m_script_id, m_country_id;
286
287 // FIXME QTBUG-69324: not all unicode code-points map to single-token UTF-16 :-(
288 char16_t m_decimal, m_group, m_list, m_percent, m_zero, m_minus, m_plus, m_exponential;
289 char16_t m_quotation_start, m_quotation_end;
290 char16_t m_alternate_quotation_start, m_alternate_quotation_end;
291
292 quint16 m_list_pattern_part_start_idx, m_list_pattern_part_start_size;
293 quint16 m_list_pattern_part_mid_idx, m_list_pattern_part_mid_size;
294 quint16 m_list_pattern_part_end_idx, m_list_pattern_part_end_size;
295 quint16 m_list_pattern_part_two_idx, m_list_pattern_part_two_size;
296 quint16 m_short_date_format_idx, m_short_date_format_size;
297 quint16 m_long_date_format_idx, m_long_date_format_size;
298 quint16 m_short_time_format_idx, m_short_time_format_size;
299 quint16 m_long_time_format_idx, m_long_time_format_size;
300 quint16 m_standalone_short_month_names_idx, m_standalone_short_month_names_size;
301 quint16 m_standalone_long_month_names_idx, m_standalone_long_month_names_size;
302 quint16 m_standalone_narrow_month_names_idx, m_standalone_narrow_month_names_size;
303 quint16 m_short_month_names_idx, m_short_month_names_size;
304 quint16 m_long_month_names_idx, m_long_month_names_size;
305 quint16 m_narrow_month_names_idx, m_narrow_month_names_size;
306 quint16 m_standalone_short_day_names_idx, m_standalone_short_day_names_size;
307 quint16 m_standalone_long_day_names_idx, m_standalone_long_day_names_size;
308 quint16 m_standalone_narrow_day_names_idx, m_standalone_narrow_day_names_size;
309 quint16 m_short_day_names_idx, m_short_day_names_size;
310 quint16 m_long_day_names_idx, m_long_day_names_size;
311 quint16 m_narrow_day_names_idx, m_narrow_day_names_size;
312 quint16 m_am_idx, m_am_size;
313 quint16 m_pm_idx, m_pm_size;
314 quint16 m_byte_idx, m_byte_size;
315 quint16 m_byte_si_quantified_idx, m_byte_si_quantified_size;
316 quint16 m_byte_iec_quantified_idx, m_byte_iec_quantified_size;
317 char m_currency_iso_code[3];
318 quint16 m_currency_symbol_idx, m_currency_symbol_size;
319 quint16 m_currency_display_name_idx, m_currency_display_name_size;
320 quint8 m_currency_format_idx, m_currency_format_size;
321 quint8 m_currency_negative_format_idx, m_currency_negative_format_size;
322 quint16 m_language_endonym_idx, m_language_endonym_size;
323 quint16 m_country_endonym_idx, m_country_endonym_size;
324 quint16 m_currency_digits : 2;
325 quint16 m_currency_rounding : 3;
326 quint16 m_first_day_of_week : 3;
327 quint16 m_weekend_start : 3;
328 quint16 m_weekend_end : 3;
329};
330
331class Q_CORE_EXPORT QLocalePrivate
332{
333public:
334 static QLocalePrivate *create(
335 const QLocaleData *data,
336 QLocale::NumberOptions numberOptions = QLocale::DefaultNumberOptions)
337 {
338 QLocalePrivate *retval = new QLocalePrivate;
339 retval->m_data = data;
340 retval->ref.storeRelaxed(0);
341 retval->m_numberOptions = numberOptions;
342 return retval;
343 }
344
345 static QLocalePrivate *get(QLocale &l) { return l.d; }
346 static const QLocalePrivate *get(const QLocale &l) { return l.d; }
347
348 QChar decimal() const { return QChar(m_data->m_decimal); }
349 QChar group() const { return QChar(m_data->m_group); }
350 QChar list() const { return QChar(m_data->m_list); }
351 QChar percent() const { return QChar(m_data->m_percent); }
352 QChar zero() const { return QChar(m_data->m_zero); }
353 QChar plus() const { return QChar(m_data->m_plus); }
354 QChar minus() const { return QChar(m_data->m_minus); }
355 QChar exponential() const { return QChar(m_data->m_exponential); }
356
357 quint16 languageId() const { return m_data->m_language_id; }
358 quint16 countryId() const { return m_data->m_country_id; }
359
360 QByteArray bcp47Name(char separator = '-') const;
361
362 inline QLatin1String languageCode() const { return languageToCode(QLocale::Language(m_data->m_language_id)); }
363 inline QLatin1String scriptCode() const { return scriptToCode(QLocale::Script(m_data->m_script_id)); }
364 inline QLatin1String countryCode() const { return countryToCode(QLocale::Country(m_data->m_country_id)); }
365
366 static QLatin1String languageToCode(QLocale::Language language);
367 static QLatin1String scriptToCode(QLocale::Script script);
368 static QLatin1String countryToCode(QLocale::Country country);
369 static QLocale::Language codeToLanguage(QStringView code) noexcept;
370 static QLocale::Script codeToScript(QStringView code) noexcept;
371 static QLocale::Country codeToCountry(QStringView code) noexcept;
372 static void getLangAndCountry(const QString &name, QLocale::Language &lang,
373 QLocale::Script &script, QLocale::Country &cntry);
374
375 QLocale::MeasurementSystem measurementSystem() const;
376
377 QString dateTimeToString(QStringView format, const QDateTime &datetime,
378 const QDate &dateOnly, const QTime &timeOnly,
379 const QLocale *q) const;
380
381 const QLocaleData *m_data;
382 QBasicAtomicInt ref;
383 QLocale::NumberOptions m_numberOptions;
384};
385
386#ifndef QT_NO_SYSTEMLOCALE
387const QLocaleData *QSystemLocale::fallbackUiLocaleData() const { return fallbackUiLocale().d->m_data; }
388#endif
389
390template <>
391inline QLocalePrivate *QSharedDataPointer<QLocalePrivate>::clone()
392{
393 // cannot use QLocalePrivate's copy constructor
394 // since it is deleted in C++11
395 return QLocalePrivate::create(d->m_data, d->m_numberOptions);
396}
397
398inline char QLocaleData::digitToCLocale(QChar in) const
399{
400 const ushort tenUnicode = m_zero + 10;
401
402 if (in.unicode() >= m_zero && in.unicode() < tenUnicode)
403 return '0' + in.unicode() - m_zero;
404
405 if (in.unicode() >= '0' && in.unicode() <= '9')
406 return in.toLatin1();
407
408 if (in == m_plus || in == QLatin1Char('+'))
409 return '+';
410
411 if (in == m_minus || in == QLatin1Char('-') || in == QChar(0x2212))
412 return '-';
413
414 if (in == m_decimal)
415 return '.';
416
417 if (in == m_group)
418 return ',';
419
420 if (in == m_exponential || in == QChar(QChar::toUpper(m_exponential)))
421 return 'e';
422
423 // In several languages group() is a non-breaking space (U+00A0) or its thin
424 // version (U+202f), which look like spaces. People (and thus some of our
425 // tests) use a regular space instead and complain if it doesn't work.
426 if ((m_group == 0xA0 || m_group == 0x202f) && in.unicode() == ' ')
427 return ',';
428
429 return 0;
430}
431
432QString qt_readEscapedFormatString(QStringView format, int *idx);
433bool qt_splitLocaleName(const QString &name, QString &lang, QString &script, QString &cntry);
434int qt_repeatCount(QStringView s);
435
436enum { AsciiSpaceMask = (1u << (' ' - 1)) |
437 (1u << ('\t' - 1)) | // 9: HT - horizontal tab
438 (1u << ('\n' - 1)) | // 10: LF - line feed
439 (1u << ('\v' - 1)) | // 11: VT - vertical tab
440 (1u << ('\f' - 1)) | // 12: FF - form feed
441 (1u << ('\r' - 1)) }; // 13: CR - carriage return
442Q_DECL_CONSTEXPR inline bool ascii_isspace(uchar c)
443{
444 return c >= 1u && c <= 32u && (AsciiSpaceMask >> uint(c - 1)) & 1u;
445}
446
447#if defined(Q_COMPILER_CONSTEXPR)
448Q_STATIC_ASSERT(ascii_isspace(' '));
449Q_STATIC_ASSERT(ascii_isspace('\t'));
450Q_STATIC_ASSERT(ascii_isspace('\n'));
451Q_STATIC_ASSERT(ascii_isspace('\v'));
452Q_STATIC_ASSERT(ascii_isspace('\f'));
453Q_STATIC_ASSERT(ascii_isspace('\r'));
454Q_STATIC_ASSERT(!ascii_isspace('\0'));
455Q_STATIC_ASSERT(!ascii_isspace('\a'));
456Q_STATIC_ASSERT(!ascii_isspace('a'));
457Q_STATIC_ASSERT(!ascii_isspace('\177'));
458Q_STATIC_ASSERT(!ascii_isspace(uchar('\200')));
459Q_STATIC_ASSERT(!ascii_isspace(uchar('\xA0')));
460Q_STATIC_ASSERT(!ascii_isspace(uchar('\377')));
461#endif
462
463QT_END_NAMESPACE
464
465Q_DECLARE_METATYPE(QStringRef)
466Q_DECLARE_METATYPE(QList<Qt::DayOfWeek>)
467#ifndef QT_NO_SYSTEMLOCALE
468Q_DECLARE_METATYPE(QSystemLocale::CurrencyToStringArgument)
469#endif
470
471#endif // QLOCALE_P_H
472