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#include "qlocale_tools_p.h"
42#include "qdoublescanprint_p.h"
43#include "qlocale_p.h"
44#include "qstring.h"
45
46#include <private/qnumeric_p.h>
47
48#include <ctype.h>
49#include <errno.h>
50#include <float.h>
51#include <limits.h>
52#include <math.h>
53#include <stdlib.h>
54#include <time.h>
55
56#if defined(Q_OS_LINUX) && !defined(__UCLIBC__)
57# include <fenv.h>
58#endif
59
60// Sizes as defined by the ISO C99 standard - fallback
61#ifndef LLONG_MAX
62# define LLONG_MAX Q_INT64_C(0x7fffffffffffffff)
63#endif
64#ifndef LLONG_MIN
65# define LLONG_MIN (-LLONG_MAX - Q_INT64_C(1))
66#endif
67#ifndef ULLONG_MAX
68# define ULLONG_MAX Q_UINT64_C(0xffffffffffffffff)
69#endif
70
71QT_BEGIN_NAMESPACE
72
73QT_WARNING_PUSH
74 /* "unary minus operator applied to unsigned type, result still unsigned" */
75QT_WARNING_DISABLE_MSVC(4146)
76#include "../../3rdparty/freebsd/strtoull.c"
77#include "../../3rdparty/freebsd/strtoll.c"
78QT_WARNING_POP
79
80QT_CLOCALE_HOLDER
81
82void qt_doubleToAscii(double d, QLocaleData::DoubleForm form, int precision, char *buf, int bufSize,
83 bool &sign, int &length, int &decpt)
84{
85 if (bufSize == 0) {
86 decpt = 0;
87 sign = d < 0;
88 length = 0;
89 return;
90 }
91
92 // Detect special numbers (nan, +/-inf)
93 // We cannot use the high-level API of libdouble-conversion as we need to apply locale-specific
94 // formatting, such as decimal points, thousands-separators, etc. Because of this, we have to
95 // check for infinity and NaN before calling DoubleToAscii.
96 if (qt_is_inf(d)) {
97 sign = d < 0;
98 if (bufSize >= 3) {
99 buf[0] = 'i';
100 buf[1] = 'n';
101 buf[2] = 'f';
102 length = 3;
103 } else {
104 length = 0;
105 }
106 return;
107 } else if (qt_is_nan(d)) {
108 if (bufSize >= 3) {
109 buf[0] = 'n';
110 buf[1] = 'a';
111 buf[2] = 'n';
112 length = 3;
113 } else {
114 length = 0;
115 }
116 return;
117 }
118
119 if (form == QLocaleData::DFSignificantDigits && precision == 0)
120 precision = 1; // 0 significant digits is silently converted to 1
121
122#if !defined(QT_NO_DOUBLECONVERSION) && !defined(QT_BOOTSTRAPPED)
123 // one digit before the decimal dot, counts as significant digit for DoubleToStringConverter
124 if (form == QLocaleData::DFExponent && precision >= 0)
125 ++precision;
126
127 double_conversion::DoubleToStringConverter::DtoaMode mode;
128 if (precision == QLocale::FloatingPointShortest) {
129 mode = double_conversion::DoubleToStringConverter::SHORTEST;
130 } else if (form == QLocaleData::DFSignificantDigits || form == QLocaleData::DFExponent) {
131 mode = double_conversion::DoubleToStringConverter::PRECISION;
132 } else {
133 mode = double_conversion::DoubleToStringConverter::FIXED;
134 }
135 double_conversion::DoubleToStringConverter::DoubleToAscii(v: d, mode, requested_digits: precision, buffer: buf, buffer_length: bufSize,
136 sign: &sign, length: &length, point: &decpt);
137#else // QT_NO_DOUBLECONVERSION || QT_BOOTSTRAPPED
138
139 // Cut the precision at 999, to fit it into the format string. We can't get more than 17
140 // significant digits, so anything after that is mostly noise. You do get closer to the "middle"
141 // of the range covered by the given double with more digits, so to a degree it does make sense
142 // to honor higher precisions. We define that at more than 999 digits that is not the case.
143 if (precision > 999)
144 precision = 999;
145 else if (precision == QLocale::FloatingPointShortest)
146 precision = QLocaleData::DoubleMaxSignificant; // "shortest" mode not supported by snprintf
147
148 if (isZero(d)) {
149 // Negative zero is expected as simple "0", not "-0". We cannot do d < 0, though.
150 sign = false;
151 buf[0] = '0';
152 length = 1;
153 decpt = 1;
154 return;
155 } else if (d < 0) {
156 sign = true;
157 d = -d;
158 } else {
159 sign = false;
160 }
161
162 const int formatLength = 7; // '%', '.', 3 digits precision, 'f', '\0'
163 char format[formatLength];
164 format[formatLength - 1] = '\0';
165 format[0] = '%';
166 format[1] = '.';
167 format[2] = char((precision / 100) % 10) + '0';
168 format[3] = char((precision / 10) % 10) + '0';
169 format[4] = char(precision % 10) + '0';
170 int extraChars;
171 switch (form) {
172 case QLocaleData::DFDecimal:
173 format[formatLength - 2] = 'f';
174 // <anything> '.' <precision> '\0' - optimize for numbers smaller than 512k
175 extraChars = (d > (1 << 19) ? QLocaleData::DoubleMaxDigitsBeforeDecimal : 6) + 2;
176 break;
177 case QLocaleData::DFExponent:
178 format[formatLength - 2] = 'e';
179 // '.', 'e', '-', <exponent> '\0'
180 extraChars = 7;
181 break;
182 case QLocaleData::DFSignificantDigits:
183 format[formatLength - 2] = 'g';
184
185 // either the same as in the 'e' case, or '.' and '\0'
186 // precision covers part before '.'
187 extraChars = 7;
188 break;
189 default:
190 Q_UNREACHABLE();
191 }
192
193 QVarLengthArray<char> target(precision + extraChars);
194
195 length = qDoubleSnprintf(target.data(), target.size(), QT_CLOCALE, format, d);
196 int firstSignificant = 0;
197 int decptInTarget = length;
198
199 // Find the first significant digit (not 0), and note any '.' we encounter.
200 // There is no '-' at the front of target because we made sure d > 0 above.
201 while (firstSignificant < length) {
202 if (target[firstSignificant] == '.')
203 decptInTarget = firstSignificant;
204 else if (target[firstSignificant] != '0')
205 break;
206 ++firstSignificant;
207 }
208
209 // If no '.' found so far, search the rest of the target buffer for it.
210 if (decptInTarget == length)
211 decptInTarget = std::find(target.data() + firstSignificant, target.data() + length, '.') -
212 target.data();
213
214 int eSign = length;
215 if (form != QLocaleData::DFDecimal) {
216 // In 'e' or 'g' form, look for the 'e'.
217 eSign = std::find(target.data() + firstSignificant, target.data() + length, 'e') -
218 target.data();
219
220 if (eSign < length) {
221 // If 'e' is found, the final decimal point is determined by the number after 'e'.
222 // Mind that the final decimal point, decpt, is the offset of the decimal point from the
223 // start of the resulting string in buf. It may be negative or larger than bufSize, in
224 // which case the missing digits are zeroes. In the 'e' case decptInTarget is always 1,
225 // as variants of snprintf always generate numbers with one digit before the '.' then.
226 // This is why the final decimal point is offset by 1, relative to the number after 'e'.
227 bool ok;
228 const char *endptr;
229 decpt = qstrtoll(target.data() + eSign + 1, &endptr, 10, &ok) + 1;
230 Q_ASSERT(ok);
231 Q_ASSERT(endptr - target.data() <= length);
232 } else {
233 // No 'e' found, so it's the 'f' form. Variants of snprintf generate numbers with
234 // potentially multiple digits before the '.', but without decimal exponent then. So we
235 // get the final decimal point from the position of the '.'. The '.' itself takes up one
236 // character. We adjust by 1 below if that gets in the way.
237 decpt = decptInTarget - firstSignificant;
238 }
239 } else {
240 // In 'f' form, there can not be an 'e', so it's enough to look for the '.'
241 // (and possibly adjust by 1 below)
242 decpt = decptInTarget - firstSignificant;
243 }
244
245 // Move the actual digits from the snprintf target to the actual buffer.
246 if (decptInTarget > firstSignificant) {
247 // First move the digits before the '.', if any
248 int lengthBeforeDecpt = decptInTarget - firstSignificant;
249 memcpy(buf, target.data() + firstSignificant, qMin(lengthBeforeDecpt, bufSize));
250 if (eSign > decptInTarget && lengthBeforeDecpt < bufSize) {
251 // Then move any remaining digits, until 'e'
252 memcpy(buf + lengthBeforeDecpt, target.data() + decptInTarget + 1,
253 qMin(eSign - decptInTarget - 1, bufSize - lengthBeforeDecpt));
254 // The final length of the output is the distance between the first significant digit
255 // and 'e' minus 1, for the '.', except if the buffer is smaller.
256 length = qMin(eSign - firstSignificant - 1, bufSize);
257 } else {
258 // 'e' was before the decpt or things didn't fit. Don't subtract the '.' from the length.
259 length = qMin(eSign - firstSignificant, bufSize);
260 }
261 } else {
262 if (eSign > firstSignificant) {
263 // If there are any significant digits at all, they are all after the '.' now.
264 // Just copy them straight away.
265 memcpy(buf, target.data() + firstSignificant, qMin(eSign - firstSignificant, bufSize));
266
267 // The decimal point was before the first significant digit, so we were one off above.
268 // Consider 0.1 - buf will be just '1', and decpt should be 0. But
269 // "decptInTarget - firstSignificant" will yield -1.
270 ++decpt;
271 length = qMin(eSign - firstSignificant, bufSize);
272 } else {
273 // No significant digits means the number is just 0.
274 buf[0] = '0';
275 length = 1;
276 decpt = 1;
277 }
278 }
279#endif // QT_NO_DOUBLECONVERSION || QT_BOOTSTRAPPED
280 while (length > 1 && buf[length - 1] == '0') // drop trailing zeroes
281 --length;
282}
283
284double qt_asciiToDouble(const char *num, int numLen, bool &ok, int &processed,
285 StrayCharacterMode strayCharMode)
286{
287 auto string_equals = [](const char *needle, const char *haystack, qsizetype haystackLen) {
288 qsizetype needleLen = strlen(s: needle);
289 return needleLen == haystackLen && memcmp(s1: needle, s2: haystack, n: haystackLen) == 0;
290 };
291
292 if (*num == '\0') {
293 ok = false;
294 processed = 0;
295 return 0.0;
296 }
297
298 ok = true;
299
300 // We have to catch NaN before because we need NaN as marker for "garbage" in the
301 // libdouble-conversion case and, in contrast to libdouble-conversion or sscanf, we don't allow
302 // "-nan" or "+nan"
303 if (string_equals("nan", num, numLen)) {
304 processed = 3;
305 return qt_qnan();
306 } else if (string_equals("+nan", num, numLen) || string_equals("-nan", num, numLen)) {
307 processed = 0;
308 ok = false;
309 return 0.0;
310 }
311
312 // Infinity values are implementation defined in the sscanf case. In the libdouble-conversion
313 // case we need infinity as overflow marker.
314 if (string_equals("+inf", num, numLen)) {
315 processed = 4;
316 return qt_inf();
317 } else if (string_equals("inf", num, numLen)) {
318 processed = 3;
319 return qt_inf();
320 } else if (string_equals("-inf", num, numLen)) {
321 processed = 4;
322 return -qt_inf();
323 }
324
325 double d = 0.0;
326#if !defined(QT_NO_DOUBLECONVERSION) && !defined(QT_BOOTSTRAPPED)
327 int conv_flags = double_conversion::StringToDoubleConverter::NO_FLAGS;
328 if (strayCharMode == TrailingJunkAllowed) {
329 conv_flags = double_conversion::StringToDoubleConverter::ALLOW_TRAILING_JUNK;
330 } else if (strayCharMode == WhitespacesAllowed) {
331 conv_flags = double_conversion::StringToDoubleConverter::ALLOW_LEADING_SPACES
332 | double_conversion::StringToDoubleConverter::ALLOW_TRAILING_SPACES;
333 }
334 double_conversion::StringToDoubleConverter conv(conv_flags, 0.0, qt_qnan(), nullptr, nullptr);
335 d = conv.StringToDouble(buffer: num, length: numLen, processed_characters_count: &processed);
336
337 if (!qIsFinite(d)) {
338 ok = false;
339 if (qIsNaN(d)) {
340 // Garbage found. We don't accept it and return 0.
341 processed = 0;
342 return 0.0;
343 } else {
344 // Overflow. That's not OK, but we still return infinity.
345 return d;
346 }
347 }
348#else
349 // need to ensure that our input is null-terminated for sscanf
350 // (this is a QVarLengthArray<char, 128> but this code here is too low-level for QVLA)
351 char reasonableBuffer[128];
352 char *buffer;
353 if (numLen < qsizetype(sizeof(reasonableBuffer)) - 1)
354 buffer = reasonableBuffer;
355 else
356 buffer = static_cast<char *>(malloc(numLen + 1));
357 memcpy(buffer, num, numLen);
358 buffer[numLen] = '\0';
359
360 if (qDoubleSscanf(buffer, QT_CLOCALE, "%lf%n", &d, &processed) < 1)
361 processed = 0;
362
363 if (buffer != reasonableBuffer)
364 free(buffer);
365
366 if ((strayCharMode == TrailingJunkProhibited && processed != numLen) || qIsNaN(d)) {
367 // Implementation defined nan symbol or garbage found. We don't accept it.
368 processed = 0;
369 ok = false;
370 return 0.0;
371 }
372
373 if (!qIsFinite(d)) {
374 // Overflow. Check for implementation-defined infinity symbols and reject them.
375 // We assume that any infinity symbol has to contain a character that cannot be part of a
376 // "normal" number (that is 0-9, ., -, +, e).
377 ok = false;
378 for (int i = 0; i < processed; ++i) {
379 char c = num[i];
380 if ((c < '0' || c > '9') && c != '.' && c != '-' && c != '+' && c != 'e' && c != 'E') {
381 // Garbage found
382 processed = 0;
383 return 0.0;
384 }
385 }
386 return d;
387 }
388#endif // !defined(QT_NO_DOUBLECONVERSION) && !defined(QT_BOOTSTRAPPED)
389
390 // Otherwise we would have gotten NaN or sorted it out above.
391 Q_ASSERT(strayCharMode == TrailingJunkAllowed || processed == numLen);
392
393 // Check if underflow has occurred.
394 if (isZero(d)) {
395 for (int i = 0; i < processed; ++i) {
396 if (num[i] >= '1' && num[i] <= '9') {
397 // if a digit before any 'e' is not 0, then a non-zero number was intended.
398 ok = false;
399 return 0.0;
400 } else if (num[i] == 'e' || num[i] == 'E') {
401 break;
402 }
403 }
404 }
405 return d;
406}
407
408unsigned long long
409qstrtoull(const char * nptr, const char **endptr, int base, bool *ok)
410{
411 // strtoull accepts negative numbers. We don't.
412 // Use a different variable so we pass the original nptr to strtoul
413 // (we need that so endptr may be nptr in case of failure)
414 const char *begin = nptr;
415 while (ascii_isspace(c: *begin))
416 ++begin;
417 if (*begin == '-') {
418 *ok = false;
419 return 0;
420 }
421
422 *ok = true;
423 errno = 0;
424 char *endptr2 = nullptr;
425 unsigned long long result = qt_strtoull(nptr, endptr: &endptr2, base);
426 if (endptr)
427 *endptr = endptr2;
428 if ((result == 0 || result == std::numeric_limits<unsigned long long>::max())
429 && (errno || endptr2 == nptr)) {
430 *ok = false;
431 return 0;
432 }
433 return result;
434}
435
436long long
437qstrtoll(const char * nptr, const char **endptr, int base, bool *ok)
438{
439 *ok = true;
440 errno = 0;
441 char *endptr2 = nullptr;
442 long long result = qt_strtoll(nptr, endptr: &endptr2, base);
443 if (endptr)
444 *endptr = endptr2;
445 if ((result == 0 || result == std::numeric_limits<long long>::min()
446 || result == std::numeric_limits<long long>::max())
447 && (errno || nptr == endptr2)) {
448 *ok = false;
449 return 0;
450 }
451 return result;
452}
453
454QString qulltoa(qulonglong l, int base, const QChar _zero)
455{
456 ushort buff[65]; // length of MAX_ULLONG in base 2
457 ushort *p = buff + 65;
458
459 if (base != 10 || _zero.unicode() == '0') {
460 while (l != 0) {
461 int c = l % base;
462
463 --p;
464
465 if (c < 10)
466 *p = '0' + c;
467 else
468 *p = c - 10 + 'a';
469
470 l /= base;
471 }
472 }
473 else {
474 while (l != 0) {
475 int c = l % base;
476
477 *(--p) = _zero.unicode() + c;
478
479 l /= base;
480 }
481 }
482
483 return QString(reinterpret_cast<QChar *>(p), 65 - (p - buff));
484}
485
486QString &decimalForm(QChar zero, QChar decimal, QChar group,
487 QString &digits, int decpt, int precision,
488 PrecisionMode pm,
489 bool always_show_decpt,
490 bool thousands_group)
491{
492 if (decpt < 0) {
493 for (int i = 0; i < -decpt; ++i)
494 digits.prepend(c: zero);
495 decpt = 0;
496 }
497 else if (decpt > digits.length()) {
498 for (int i = digits.length(); i < decpt; ++i)
499 digits.append(c: zero);
500 }
501
502 if (pm == PMDecimalDigits) {
503 uint decimal_digits = digits.length() - decpt;
504 for (int i = decimal_digits; i < precision; ++i)
505 digits.append(c: zero);
506 }
507 else if (pm == PMSignificantDigits) {
508 for (int i = digits.length(); i < precision; ++i)
509 digits.append(c: zero);
510 }
511 else { // pm == PMChopTrailingZeros
512 }
513
514 if (always_show_decpt || decpt < digits.length())
515 digits.insert(i: decpt, c: decimal);
516
517 if (thousands_group) {
518 for (int i = decpt - 3; i > 0; i -= 3)
519 digits.insert(i, c: group);
520 }
521
522 if (decpt == 0)
523 digits.prepend(c: zero);
524
525 return digits;
526}
527
528QString &exponentForm(QChar zero, QChar decimal, QChar exponential,
529 QChar group, QChar plus, QChar minus,
530 QString &digits, int decpt, int precision,
531 PrecisionMode pm,
532 bool always_show_decpt,
533 bool leading_zero_in_exponent)
534{
535 int exp = decpt - 1;
536
537 if (pm == PMDecimalDigits) {
538 for (int i = digits.length(); i < precision + 1; ++i)
539 digits.append(c: zero);
540 }
541 else if (pm == PMSignificantDigits) {
542 for (int i = digits.length(); i < precision; ++i)
543 digits.append(c: zero);
544 }
545 else { // pm == PMChopTrailingZeros
546 }
547
548 if (always_show_decpt || digits.length() > 1)
549 digits.insert(i: 1, c: decimal);
550
551 digits.append(c: exponential);
552 digits.append(s: QLocaleData::longLongToString(zero, group, plus, minus,
553 l: exp, precision: leading_zero_in_exponent ? 2 : 1, base: 10, width: -1, flags: QLocaleData::AlwaysShowSign));
554
555 return digits;
556}
557
558double qstrtod(const char *s00, const char **se, bool *ok)
559{
560 const int len = static_cast<int>(strlen(s: s00));
561 Q_ASSERT(len >= 0);
562 return qstrntod(s00, len, se, ok);
563}
564
565/*!
566 \internal
567
568 Converts the initial portion of the string pointed to by \a s00 to a double, using the 'C' locale.
569 */
570double qstrntod(const char *s00, int len, const char **se, bool *ok)
571{
572 int processed = 0;
573 bool nonNullOk = false;
574 double d = qt_asciiToDouble(num: s00, numLen: len, ok&: nonNullOk, processed, strayCharMode: TrailingJunkAllowed);
575 if (se)
576 *se = s00 + processed;
577 if (ok)
578 *ok = nonNullOk;
579 return d;
580}
581
582QString qdtoa(qreal d, int *decpt, int *sign)
583{
584 bool nonNullSign = false;
585 int nonNullDecpt = 0;
586 int length = 0;
587
588 // Some versions of libdouble-conversion like an extra digit, probably for '\0'
589 char result[QLocaleData::DoubleMaxSignificant + 1];
590 qt_doubleToAscii(d, form: QLocaleData::DFSignificantDigits, precision: QLocale::FloatingPointShortest, buf: result,
591 bufSize: QLocaleData::DoubleMaxSignificant + 1, sign&: nonNullSign, length, decpt&: nonNullDecpt);
592
593 if (sign)
594 *sign = nonNullSign ? 1 : 0;
595 if (decpt)
596 *decpt = nonNullDecpt;
597
598 return QLatin1String(result, length);
599}
600
601QT_END_NAMESPACE
602

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