summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEdward Welbourne <edward.welbourne@qt.io>2021-08-27 14:58:57 +0200
committerEdward Welbourne <edward.welbourne@qt.io>2021-08-30 17:46:00 +0200
commit5644af6f8a800a1516360a42ba4c1a8dc61fc516 (patch)
tree0fb11871c40c7f389f95bc227699fdcda8b7889a
parent522ca997d3baab1b88f454bbeea9f357d3969dff (diff)
Replace FreeBSD's strtou?ll() with std::from_chars()-based strntou?ll()
Remove third-party code in favor of STL. Implement (for now) strtou?ll() as inlines on strntou?ll() calling strlen() for the size parameter. (This is not entirely safe, as a string lacking '\0'-termination but with at least some non-matching text after the numeric portion would formerly be parsed just fine, but would now produce a crash. However, strtou?ll() are internal and callers should be ensuring '\0'-termination.) Task-number: QTBUG-74286 Change-Id: I0c8ca7d4f6110367e93b4c0164854a82c5a545e1 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
-rw-r--r--src/3rdparty/freebsd/0001-Patch-the-FreeBSD-strto-u-ll-functions-to-work-insid.patch158
-rw-r--r--src/3rdparty/freebsd/LICENSE31
-rw-r--r--src/3rdparty/freebsd/qt_attribution.json18
-rw-r--r--src/3rdparty/freebsd/strtoll.c134
-rw-r--r--src/3rdparty/freebsd/strtoull.c112
-rw-r--r--src/corelib/text/qlocale_tools.cpp117
-rw-r--r--src/corelib/text/qlocale_tools_p.h11
-rw-r--r--tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp199
-rw-r--r--tests/auto/corelib/text/qlocale/tst_qlocale.cpp3
-rw-r--r--tests/auto/corelib/text/qstring/tst_qstring.cpp76
10 files changed, 346 insertions, 513 deletions
diff --git a/src/3rdparty/freebsd/0001-Patch-the-FreeBSD-strto-u-ll-functions-to-work-insid.patch b/src/3rdparty/freebsd/0001-Patch-the-FreeBSD-strto-u-ll-functions-to-work-insid.patch
deleted file mode 100644
index 8fd012e4b1..0000000000
--- a/src/3rdparty/freebsd/0001-Patch-the-FreeBSD-strto-u-ll-functions-to-work-insid.patch
+++ /dev/null
@@ -1,158 +0,0 @@
-From 81a2d1a38becdeed2cd8b963e190aedf197e39c6 Mon Sep 17 00:00:00 2001
-From: Thiago Macieira <thiago.macieira@intel.com>
-Date: Thu, 2 Oct 2014 22:03:19 -0700
-Subject: [PATCH 1/1] Patch the FreeBSD strto(u)ll functions to work inside
- QtCore
-
-Changes:
- - remove the #includes and the SCCSID
- - rename from strtoxx_l to qt_strtoxx (merging the two functions)
- - remove __restrict
- - remove the locale_t parameter and use ascii_isspace instead of isspace_l
- - fix compilation with -Wcast-qual (requires C++)
-
- src/3rdparty/freebsd/strtoll.c | 27 +++------------------------
- src/3rdparty/freebsd/strtoull.c | 27 +++------------------------
- 2 files changed, 6 insertions(+), 48 deletions(-)
-
-diff --git a/src/3rdparty/freebsd/strtoll.c b/src/3rdparty/freebsd/strtoll.c
-index c87aefb1cd..89da83425d 100644
---- a/src/3rdparty/freebsd/strtoll.c
-+++ b/src/3rdparty/freebsd/strtoll.c
-@@ -1,6 +1,4 @@
- /*-
-- * SPDX-License-Identifier: BSD-3-Clause
-- *
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
-@@ -34,18 +32,6 @@
- * SUCH DAMAGE.
- */
-
--#if defined(LIBC_SCCS) && !defined(lint)
--static char sccsid[] = "@(#)strtoq.c 8.1 (Berkeley) 6/4/93";
--#endif /* LIBC_SCCS and not lint */
--#include <sys/cdefs.h>
--__FBSDID("$FreeBSD$");
--
--#include <limits.h>
--#include <errno.h>
--#include <ctype.h>
--#include <stdlib.h>
--#include "xlocale_private.h"
--
- /*
- * Convert a string to a long long integer.
- *
-@@ -53,15 +39,13 @@ __FBSDID("$FreeBSD$");
- * alphabets and digits are each contiguous.
- */
- long long
--strtoll_l(const char * __restrict nptr, char ** __restrict endptr, int base,
-- locale_t locale)
-+qt_strtoll(const char * nptr, char **endptr, int base)
- {
- const char *s;
- unsigned long long acc;
- char c;
- unsigned long long cutoff;
- int neg, any, cutlim;
-- FIX_LOCALE(locale);
-
- /*
- * Skip white space and pick up leading +/- sign if any.
-@@ -71,7 +55,7 @@ strtoll_l(const char * __restrict nptr, char ** __restrict endptr, int base,
- s = nptr;
- do {
- c = *s++;
-- } while (isspace_l((unsigned char)c, locale));
-+ } while (ascii_isspace(c));
- if (c == '-') {
- neg = 1;
- c = *s++;
-@@ -145,11 +129,6 @@ noconv:
- } else if (neg)
- acc = -acc;
- if (endptr != NULL)
-- *endptr = (char *)(any ? s - 1 : nptr);
-+ *endptr = const_cast<char *>(any ? s - 1 : nptr);
- return (acc);
- }
--long long
--strtoll(const char * __restrict nptr, char ** __restrict endptr, int base)
--{
-- return strtoll_l(nptr, endptr, base, __get_locale());
--}
-diff --git a/src/3rdparty/freebsd/strtoull.c b/src/3rdparty/freebsd/strtoull.c
-index 58a9b23b56..cf151691ad 100644
---- a/src/3rdparty/freebsd/strtoull.c
-+++ b/src/3rdparty/freebsd/strtoull.c
-@@ -1,6 +1,4 @@
- /*-
-- * SPDX-License-Identifier: BSD-3-Clause
-- *
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
-@@ -34,18 +32,6 @@
- * SUCH DAMAGE.
- */
-
--#if defined(LIBC_SCCS) && !defined(lint)
--static char sccsid[] = "@(#)strtouq.c 8.1 (Berkeley) 6/4/93";
--#endif /* LIBC_SCCS and not lint */
--#include <sys/cdefs.h>
--__FBSDID("$FreeBSD$");
--
--#include <limits.h>
--#include <errno.h>
--#include <ctype.h>
--#include <stdlib.h>
--#include "xlocale_private.h"
--
- /*
- * Convert a string to an unsigned long long integer.
- *
-@@ -53,15 +39,13 @@ __FBSDID("$FreeBSD$");
- * alphabets and digits are each contiguous.
- */
- unsigned long long
--strtoull_l(const char * __restrict nptr, char ** __restrict endptr, int base,
-- locale_t locale)
-+qt_strtoull(const char * nptr, char **endptr, int base)
- {
- const char *s;
- unsigned long long acc;
- char c;
- unsigned long long cutoff;
- int neg, any, cutlim;
-- FIX_LOCALE(locale);
-
- /*
- * See strtoq for comments as to the logic used.
-@@ -69,7 +53,7 @@ strtoull_l(const char * __restrict nptr, char ** __restrict endptr, int base,
- s = nptr;
- do {
- c = *s++;
-- } while (isspace_l((unsigned char)c, locale));
-+ } while (ascii_isspace(c));
- if (c == '-') {
- neg = 1;
- c = *s++;
-@@ -123,11 +107,6 @@ noconv:
- } else if (neg)
- acc = -acc;
- if (endptr != NULL)
-- *endptr = (char *)(any ? s - 1 : nptr);
-+ *endptr = const_cast<char *>(any ? s - 1 : nptr);
- return (acc);
- }
--unsigned long long
--strtoull(const char * __restrict nptr, char ** __restrict endptr, int base)
--{
-- return strtoull_l(nptr, endptr, base, __get_locale());
--}
---
-2.25.1
-
diff --git a/src/3rdparty/freebsd/LICENSE b/src/3rdparty/freebsd/LICENSE
deleted file mode 100644
index 5bb30318eb..0000000000
--- a/src/3rdparty/freebsd/LICENSE
+++ /dev/null
@@ -1,31 +0,0 @@
-Copyright (c) 1992, 1993
- The Regents of the University of California. All rights reserved.
-
-Copyright (c) 2011 The FreeBSD Foundation
-All rights reserved.
-Portions of this software were developed by David Chisnall
-under sponsorship from the FreeBSD Foundation.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-3. Neither the name of the University nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
diff --git a/src/3rdparty/freebsd/qt_attribution.json b/src/3rdparty/freebsd/qt_attribution.json
deleted file mode 100644
index 644880a90d..0000000000
--- a/src/3rdparty/freebsd/qt_attribution.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "Id": "freebsd",
- "Name": "FreeBSD strtoll and strtoull",
- "QDocModule": "qtcore",
- "QtUsage": "Used in Qt Core.",
- "Files": "strtoll.c strtoull.c",
-
- "Description": "strtoll() and strtoull() are functions for converting a string to (unsigned) long long integer.",
- "Homepage": "https://github.com/freebsd/freebsd/",
- "DownloadLocation": "https://github.com/freebsd/freebsd/tree/master/lib/libc/stdlib",
- "Version": "upstream has complicated with std locales; do not update",
- "Version": "18b29f3fb8abee5d57ed8f4a44f806bec7e0eeff",
- "License": "BSD 3-clause \"New\" or \"Revised\" License",
- "LicenseId": "BSD-3-Clause",
- "LicenseFile": "LICENSE",
- "Copyright": "Copyright (c) 1992, 1993 The Regents of the University of California.
-Copyright (c) 2011 The FreeBSD Foundation"
-}
diff --git a/src/3rdparty/freebsd/strtoll.c b/src/3rdparty/freebsd/strtoll.c
deleted file mode 100644
index 89da83425d..0000000000
--- a/src/3rdparty/freebsd/strtoll.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Copyright (c) 2011 The FreeBSD Foundation
- * All rights reserved.
- * Portions of this software were developed by David Chisnall
- * under sponsorship from the FreeBSD Foundation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * Convert a string to a long long integer.
- *
- * Assumes that the upper and lower case
- * alphabets and digits are each contiguous.
- */
-long long
-qt_strtoll(const char * nptr, char **endptr, int base)
-{
- const char *s;
- unsigned long long acc;
- char c;
- unsigned long long cutoff;
- int neg, any, cutlim;
-
- /*
- * Skip white space and pick up leading +/- sign if any.
- * If base is 0, allow 0x for hex and 0 for octal, else
- * assume decimal; if base is already 16, allow 0x.
- */
- s = nptr;
- do {
- c = *s++;
- } while (ascii_isspace(c));
- if (c == '-') {
- neg = 1;
- c = *s++;
- } else {
- neg = 0;
- if (c == '+')
- c = *s++;
- }
- if ((base == 0 || base == 16) &&
- c == '0' && (*s == 'x' || *s == 'X') &&
- ((s[1] >= '0' && s[1] <= '9') ||
- (s[1] >= 'A' && s[1] <= 'F') ||
- (s[1] >= 'a' && s[1] <= 'f'))) {
- c = s[1];
- s += 2;
- base = 16;
- }
- if (base == 0)
- base = c == '0' ? 8 : 10;
- acc = any = 0;
- if (base < 2 || base > 36)
- goto noconv;
-
- /*
- * Compute the cutoff value between legal numbers and illegal
- * numbers. That is the largest legal value, divided by the
- * base. An input number that is greater than this value, if
- * followed by a legal input character, is too big. One that
- * is equal to this value may be valid or not; the limit
- * between valid and invalid numbers is then based on the last
- * digit. For instance, if the range for quads is
- * [-9223372036854775808..9223372036854775807] and the input base
- * is 10, cutoff will be set to 922337203685477580 and cutlim to
- * either 7 (neg==0) or 8 (neg==1), meaning that if we have
- * accumulated a value > 922337203685477580, or equal but the
- * next digit is > 7 (or 8), the number is too big, and we will
- * return a range error.
- *
- * Set 'any' if any `digits' consumed; make it negative to indicate
- * overflow.
- */
- cutoff = neg ? (unsigned long long)-(LLONG_MIN + LLONG_MAX) + LLONG_MAX
- : LLONG_MAX;
- cutlim = cutoff % base;
- cutoff /= base;
- for ( ; ; c = *s++) {
- if (c >= '0' && c <= '9')
- c -= '0';
- else if (c >= 'A' && c <= 'Z')
- c -= 'A' - 10;
- else if (c >= 'a' && c <= 'z')
- c -= 'a' - 10;
- else
- break;
- if (c >= base)
- break;
- if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
- any = -1;
- else {
- any = 1;
- acc *= base;
- acc += c;
- }
- }
- if (any < 0) {
- acc = neg ? LLONG_MIN : LLONG_MAX;
- errno = ERANGE;
- } else if (!any) {
-noconv:
- errno = EINVAL;
- } else if (neg)
- acc = -acc;
- if (endptr != NULL)
- *endptr = const_cast<char *>(any ? s - 1 : nptr);
- return (acc);
-}
diff --git a/src/3rdparty/freebsd/strtoull.c b/src/3rdparty/freebsd/strtoull.c
deleted file mode 100644
index cf151691ad..0000000000
--- a/src/3rdparty/freebsd/strtoull.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Copyright (c) 2011 The FreeBSD Foundation
- * All rights reserved.
- * Portions of this software were developed by David Chisnall
- * under sponsorship from the FreeBSD Foundation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * Convert a string to an unsigned long long integer.
- *
- * Assumes that the upper and lower case
- * alphabets and digits are each contiguous.
- */
-unsigned long long
-qt_strtoull(const char * nptr, char **endptr, int base)
-{
- const char *s;
- unsigned long long acc;
- char c;
- unsigned long long cutoff;
- int neg, any, cutlim;
-
- /*
- * See strtoq for comments as to the logic used.
- */
- s = nptr;
- do {
- c = *s++;
- } while (ascii_isspace(c));
- if (c == '-') {
- neg = 1;
- c = *s++;
- } else {
- neg = 0;
- if (c == '+')
- c = *s++;
- }
- if ((base == 0 || base == 16) &&
- c == '0' && (*s == 'x' || *s == 'X') &&
- ((s[1] >= '0' && s[1] <= '9') ||
- (s[1] >= 'A' && s[1] <= 'F') ||
- (s[1] >= 'a' && s[1] <= 'f'))) {
- c = s[1];
- s += 2;
- base = 16;
- }
- if (base == 0)
- base = c == '0' ? 8 : 10;
- acc = any = 0;
- if (base < 2 || base > 36)
- goto noconv;
-
- cutoff = ULLONG_MAX / base;
- cutlim = ULLONG_MAX % base;
- for ( ; ; c = *s++) {
- if (c >= '0' && c <= '9')
- c -= '0';
- else if (c >= 'A' && c <= 'Z')
- c -= 'A' - 10;
- else if (c >= 'a' && c <= 'z')
- c -= 'a' - 10;
- else
- break;
- if (c >= base)
- break;
- if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
- any = -1;
- else {
- any = 1;
- acc *= base;
- acc += c;
- }
- }
- if (any < 0) {
- acc = ULLONG_MAX;
- errno = ERANGE;
- } else if (!any) {
-noconv:
- errno = EINVAL;
- } else if (neg)
- acc = -acc;
- if (endptr != NULL)
- *endptr = const_cast<char *>(any ? s - 1 : nptr);
- return (acc);
-}
diff --git a/src/corelib/text/qlocale_tools.cpp b/src/corelib/text/qlocale_tools.cpp
index 15933c3644..c144dba938 100644
--- a/src/corelib/text/qlocale_tools.cpp
+++ b/src/corelib/text/qlocale_tools.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Copyright (C) 2016 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
@@ -54,6 +54,7 @@
#include <time.h>
#include <limits>
+#include <charconv>
#if defined(Q_OS_LINUX) && !defined(__UCLIBC__)
# include <fenv.h>
@@ -72,13 +73,6 @@
QT_BEGIN_NAMESPACE
-QT_WARNING_PUSH
- /* "unary minus operator applied to unsigned type, result still unsigned" */
-QT_WARNING_DISABLE_MSVC(4146)
-#include "../../3rdparty/freebsd/strtoull.c"
-#include "../../3rdparty/freebsd/strtoll.c"
-QT_WARNING_POP
-
QT_CLOCALE_HOLDER
void qt_doubleToAscii(double d, QLocaleData::DoubleForm form, int precision, char *buf, int bufSize,
@@ -416,50 +410,99 @@ double qt_asciiToDouble(const char *num, qsizetype numLen, bool &ok, int &proces
return d;
}
+/* Detect base if 0 and, if base is hex, skip over 0x prefix */
+static auto scanPrefix(const char *p, const char *stop, int base)
+{
+ if (p < stop && *p >= '0' && *p <= '9') {
+ if (*p == '0') {
+ const char *x = p + 1;
+ if (x < stop && (*x == 'x' || *x == 'X')) {
+ if (base == 0)
+ base = 16;
+ if (base == 16)
+ p += 2;
+ } else if (base == 0) {
+ base = 8;
+ }
+ } else if (base == 0) {
+ base = 10;
+ }
+ Q_ASSERT(base);
+ }
+ struct R
+ {
+ const char *next;
+ int base;
+ };
+ return R{p, base};
+}
+
unsigned long long
-qstrtoull(const char * nptr, const char **endptr, int base, bool *ok)
+qstrntoull(const char *begin, qsizetype size, const char **endptr, int base, bool *ok)
{
- // strtoull accepts negative numbers. We don't.
- // Use a different variable so we pass the original nptr to strtoul
- // (we need that so endptr may be nptr in case of failure)
- const char *begin = nptr;
- while (ascii_isspace(*begin))
- ++begin;
- if (*begin == '-') {
+ const char *p = begin, *const stop = begin + size;
+ while (p < stop && ascii_isspace(*p))
+ ++p;
+ unsigned long long result = 0;
+ if (p >= stop || *p == '-') {
*ok = false;
- return 0;
+ if (endptr)
+ *endptr = begin;
+ return result;
}
-
- *ok = true;
- errno = 0;
- char *endptr2 = nullptr;
- unsigned long long result = qt_strtoull(nptr, &endptr2, base);
- if (endptr)
- *endptr = endptr2;
- if ((result == 0 || result == std::numeric_limits<unsigned long long>::max())
- && (errno || endptr2 == nptr)) {
+ const auto prefix = scanPrefix(*p == '+' ? p + 1 : p, stop, base);
+ if (!prefix.base || prefix.next >= stop) {
+ if (endptr)
+ *endptr = begin;
*ok = false;
return 0;
}
+
+ const auto res = std::from_chars(prefix.next, stop, result, prefix.base);
+ *ok = res.ec == std::errc{};
+ if (endptr)
+ *endptr = res.ptr == prefix.next ? begin : res.ptr;
return result;
}
long long
-qstrtoll(const char * nptr, const char **endptr, int base, bool *ok)
+qstrntoll(const char *begin, qsizetype size, const char **endptr, int base, bool *ok)
{
- *ok = true;
- errno = 0;
- char *endptr2 = nullptr;
- long long result = qt_strtoll(nptr, &endptr2, base);
- if (endptr)
- *endptr = endptr2;
- if ((result == 0 || result == std::numeric_limits<long long>::min()
- || result == std::numeric_limits<long long>::max())
- && (errno || nptr == endptr2)) {
+ const char *p = begin, *const stop = begin + size;
+ while (p < stop && ascii_isspace(*p))
+ ++p;
+ // Frustratingly, std::from_chars() doesn't cope with a 0x prefix that might
+ // be between the sign and digits, so we have to handle that for it, which
+ // means we can't use its ability to read LLONG_MIN directly; see below.
+ const bool negate = p < stop && *p == '-';
+ if (negate || (p < stop && *p == '+'))
+ ++p;
+
+ const auto prefix = scanPrefix(p, stop, base);
+ if (!prefix.base || prefix.next >= stop) {
+ if (endptr)
+ *endptr = begin;
*ok = false;
return 0;
}
- return result;
+
+ long long result = 0;
+ auto res = std::from_chars(prefix.next, stop, result, prefix.base);
+ *ok = res.ec == std::errc{};
+ if (negate && res.ec == std::errc::result_out_of_range) {
+ // Maybe LLONG_MIN:
+ unsigned long long check = 0;
+ res = std::from_chars(prefix.next, stop, check, prefix.base);
+ if (res.ec == std::errc{} && check + std::numeric_limits<long long>::min() == 0) {
+ *ok = true;
+ if (endptr)
+ *endptr = res.ptr;
+ return std::numeric_limits<long long>::min();
+ }
+ }
+ if (endptr)
+ *endptr = res.ptr == prefix.next ? begin : res.ptr;
+ return negate && *ok ? -result : result;
}
template <typename Char>
diff --git a/src/corelib/text/qlocale_tools_p.h b/src/corelib/text/qlocale_tools_p.h
index b6ffff8224..27d849ea7a 100644
--- a/src/corelib/text/qlocale_tools_p.h
+++ b/src/corelib/text/qlocale_tools_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2020 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -117,8 +117,13 @@ inline double qstrtod(const char *s00, char const **se, bool *ok)
return qstrntod(s00, len, se, ok);
}
-qlonglong qstrtoll(const char *nptr, const char **endptr, int base, bool *ok);
-qulonglong qstrtoull(const char *nptr, const char **endptr, int base, bool *ok);
+qlonglong qstrntoll(const char *nptr, qsizetype size, const char **endptr, int base, bool *ok);
+qulonglong qstrntoull(const char *nptr, qsizetype size, const char **endptr, int base, bool *ok);
+
+inline qlonglong qstrtoll(const char *nptr, const char **endptr, int base, bool *ok)
+{ return qstrntoll(nptr, strlen(nptr), endptr, base, ok); }
+inline qulonglong qstrtoull(const char *nptr, const char **endptr, int base, bool *ok)
+{ return qstrntoull(nptr, strlen(nptr), endptr, base, ok); }
QT_END_NAMESPACE
diff --git a/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp b/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp
index 3b7e0efb00..ff04eca14d 100644
--- a/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp
+++ b/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp
@@ -36,6 +36,7 @@
#include <private/qtools_p.h>
#include "../shared/test_number_shared.h"
+#include <limits>
class tst_QByteArray : public QObject
{
@@ -1674,6 +1675,20 @@ void tst_QByteArray::toULong()
QCOMPARE(b, ok);
}
+static QByteArray decNext(QByteArray &&big)
+{
+ // Increments a decimal digit-string (ignoring sign, so decrements if
+ // negative); only intended for taking a boundary value just out of range,
+ // so big is never a string of only 9s (that'd be one less than a power of
+ // ten, which cannot be a power of two, as odd, or one less than one, as the
+ // power of ten isn't a power of two).
+ int i = big.size() - 1;
+ while (big.at(i) == '9')
+ big[i--] = '0';
+ big[i] += 1;
+ return big;
+}
+
void tst_QByteArray::toLongLong_data()
{
QTest::addColumn<QByteArray>("str");
@@ -1689,10 +1704,14 @@ void tst_QByteArray::toLongLong_data()
<< 7679359922672374856LL << true;
QTest::newRow("in range dec neg") << QByteArray("-7679359922672374856") << 10
<< -7679359922672374856LL << true;
- QTest::newRow("in range hex") << QByteArray("6A929129A5421448") << 16 << 0x6A929129A5421448LL
- << true;
- QTest::newRow("in range hex neg") << QByteArray("-6A929129A5421448") << 16
- << -0x6A929129A5421448LL << true;
+ QTest::newRow("in range hex")
+ << QByteArray("6A929129A5421448") << 16 << 0x6A929129A5421448LL << true;
+ QTest::newRow("in range hex prefix")
+ << QByteArray("0x6A929129A5421448") << 16 << 0x6A929129A5421448LL << true;
+ QTest::newRow("in range hex neg")
+ << QByteArray("-6A929129A5421448") << 16 << -0x6A929129A5421448LL << true;
+ QTest::newRow("in range hex prefix neg")
+ << QByteArray("-0x6A929129A5421448") << 16 << -0x6A929129A5421448LL << true;
QTest::newRow("Fibonacci's last int64") << QByteArray("7540113804746346429") << 10
<< 7540113804746346429LL << true;
@@ -1700,6 +1719,8 @@ void tst_QByteArray::toLongLong_data()
<< 0xABCFFFFFFF123LL << true;
QTest::newRow("trailing spaces") << QByteArray("9876543210\t\r \n") << 10
<< 9876543210LL << true;
+ QTest::newRow("space after plus") << QByteArray("+ 12") << 10 << 0LL << false;
+ QTest::newRow("space after minus") << QByteArray("- 12") << 10 << 0LL << false;
QTest::newRow("leading junk") << QByteArray("q12345") << 10 << 0LL << false;
QTest::newRow("trailing junk") << QByteArray("abc12345t") << 16 << 0LL << false;
@@ -1716,13 +1737,86 @@ void tst_QByteArray::toLongLong_data()
QTest::newRow("base 3") << QByteArray("12012") << 3 << 140LL << true;
QTest::newRow("neg base 3") << QByteArray("-201") << 3 << -19LL << true;
- QTest::newRow("max dec") << QByteArray("9223372036854775807") << 10 << 9223372036854775807LL
- << true;
- QTest::newRow("mix hex") << QByteArray("-7FFFFFFFFFFFFFFF") << 16 << -0x7FFFFFFFFFFFFFFFLL
- << true;
-
- QTest::newRow("max + 1 dec") << QByteArray("9223372036854775808") << 10 << 0LL << false;
- QTest::newRow("min - 1 hex") << QByteArray("-8000000000000001") << 16 << 0LL << false;
+ // Boundary values, first in every base:
+ using LL = std::numeric_limits<qlonglong>;
+ for (int b = 0; b <= 36; ++b) {
+ if (b == 1) // bases 0 and 2 through 36 are allowed
+ ++b;
+ QTest::addRow("max base %d", b)
+ << QByteArray::number(LL::max(), b ? b : 10) << b << LL::max() << true;
+ QTest::addRow("min base %d", b)
+ << QByteArray::number(LL::min(), b ? b : 10) << b << LL::min() << true;
+ }
+ // Check leading zeros don't hit any buffer-too-big problems:
+ QTest::newRow("many-0 max dec")
+ << (QByteArray(512, '0') + QByteArray::number(LL::max())) << 10 << LL::max() << true;
+
+ // Special bases (and let's include some leading space, too !), first decimal:
+ QTest::newRow("max dec, base 0") << QByteArray::number(LL::max()) << 0 << LL::max() << true;
+ QTest::newRow("max space dec")
+ << ("\t\r\n\f\v " + QByteArray::number(LL::max())) << 10 << LL::max() << true;
+ QTest::newRow("max space dec, base 0")
+ << ("\t\r\n\f\v " + QByteArray::number(LL::max())) << 0 << LL::max() << true;
+ QTest::newRow("min dec, base 0") << QByteArray::number(LL::min()) << 0 << LL::min() << true;
+ QTest::newRow("min space dec")
+ << ("\t\r\n\f\v " + QByteArray::number(LL::min())) << 10 << LL::min() << true;
+ QTest::newRow("min space dec, base 0")
+ << ("\t\r\n\f\v " + QByteArray::number(LL::min())) << 0 << LL::min() << true;
+
+ // Hex with prefix:
+ QTest::newRow("max 0x base 0")
+ << ("0x" + QByteArray::number(LL::max(), 16)) << 0 << LL::max() << true;
+ QTest::newRow("max +0x base 0")
+ << ("+0x" + QByteArray::number(LL::max(), 16)) << 0 << LL::max() << true;
+ QTest::newRow("max space 0x base 0")
+ << ("\t\r\n\f\v 0x" + QByteArray::number(LL::max(), 16)) << 0 << LL::max() << true;
+ QTest::newRow("max space +0x base 0")
+ << ("\t\r\n\f\v +0x" + QByteArray::number(LL::max(), 16)) << 0 << LL::max() << true;
+ QByteArray big = QByteArray::number(LL::min(), 16);
+ big.insert(1, "0x"); // after sign
+ QTest::newRow("min hex prefix") << big << 16 << LL::min() << true;
+ QTest::newRow("min 0x base 0") << big << 0 << LL::min() << true;
+ big.prepend("\t\r\n\f\v ");
+ QTest::newRow("min space hex prefix") << big << 16 << LL::min() << true;
+ QTest::newRow("min space 0x base 0") << big << 0 << LL::min() << true;
+
+ // Octal with prefix:
+ QTest::newRow("max octal base 0")
+ << ('0' + QByteArray::number(LL::max(), 8)) << 0 << LL::max() << true;
+ QTest::newRow("max +octal base 0")
+ << ("+0" + QByteArray::number(LL::max(), 8)) << 0 << LL::max() << true;
+ QTest::newRow("max space octal base 0")
+ << ("\t\r\n\f\v 0" + QByteArray::number(LL::max(), 8)) << 0 << LL::max() << true;
+ QTest::newRow("max space +octal base 0")
+ << ("\t\r\n\f\v +0" + QByteArray::number(LL::max(), 8)) << 0 << LL::max() << true;
+ big = QByteArray::number(LL::min(), 8);
+ big.insert(1, '0'); // after sign
+ QTest::newRow("min octal prefix") << big << 8 << LL::min() << true;
+ QTest::newRow("min octal base 0") << big << 0 << LL::min() << true;
+ big.prepend("\t\r\n\f\v ");
+ QTest::newRow("min space octal prefix") << big << 8 << LL::min() << true;
+ QTest::newRow("min space octal base 0") << big << 0 << LL::min() << true;
+
+ // Values *just* out of range:
+ QTest::newRow("max + 1 dec") << decNext(QByteArray::number(LL::max())) << 10 << 0LL << false;
+ QTest::newRow("max + 1 dec base 0")
+ << decNext(QByteArray::number(LL::max())) << 0 << 0LL << false;
+ QTest::newRow("min - 1 dec") << decNext(QByteArray::number(LL::min())) << 10 << 0LL << false;
+ QTest::newRow("min - 1 dec base 0")
+ << decNext(QByteArray::number(LL::min())) << 0 << 0LL << false;
+ // For hex and octal, we know the last digit of min is 0 and skipping its sign gets max+1:
+ big = QByteArray::number(LL::min(), 8);
+ QTest::newRow("max + 1 oct") << big.sliced(1) << 8 << 0LL << false;
+ big[big.size() - 1] = '1';
+ QTest::newRow("min - 1 oct") << big << 8 << 0LL << false;
+ big.insert(1, '0'); // after minus sign
+ QTest::newRow("min - 1 octal base 0") << big << 0 << 0LL << false;
+ big = QByteArray::number(LL::min(), 16);
+ QTest::newRow("max + 1 hex") << big.sliced(1) << 16 << 0LL << false;
+ big[big.size() - 1] = '1';
+ QTest::newRow("min - 1 hex") << big << 16 << 0LL << false;
+ big.insert(1, "0x"); // after minus sign
+ QTest::newRow("min - 1, 0x base 0") << big << 0 << 0LL << false;
}
void tst_QByteArray::toLongLong()
@@ -1749,14 +1843,81 @@ void tst_QByteArray::toULongLong_data()
QTest::addColumn<qulonglong>("result");
QTest::addColumn<bool>("ok");
- QTest::newRow("null") << QByteArray() << 10 << (qulonglong)0 << false;
- QTest::newRow("empty") << QByteArray("") << 10 << (qulonglong)0 << false;
- QTest::newRow("out of base bound") << QByteArray("c") << 10 << (qulonglong)0 << false;
-
- QTest::newRow("leading spaces") << QByteArray(" \n\r\t100") << 10 << qulonglong(100) << true;
- QTest::newRow("trailing spaces") << QByteArray("100 \n\r\t") << 10 << qulonglong(100) << true;
- QTest::newRow("leading junk") << QByteArray("x100") << 10 << qulonglong(0) << false;
- QTest::newRow("trailing junk") << QByteArray("100x") << 10 << qulonglong(0) << false;
+ QTest::newRow("null") << QByteArray() << 10 << 0ULL << false;
+ QTest::newRow("empty") << QByteArray("") << 10 << 0ULL << false;
+ QTest::newRow("out of base bound") << QByteArray("c") << 10 << 0ULL << false;
+
+ QTest::newRow("in range dec")
+ << QByteArray("7679359922672374856") << 10 << 7679359922672374856ULL << true;
+ QTest::newRow("in range hex")
+ << QByteArray("6A929129A5421448") << 16 << 0x6A929129A5421448ULL << true;
+ QTest::newRow("in range hex prefix")
+ << QByteArray("0x6A929129A5421448") << 16 << 0x6A929129A5421448ULL << true;
+
+ QTest::newRow("leading spaces") << QByteArray(" \n\r\t100") << 10 << 100ULL << true;
+ QTest::newRow("trailing spaces") << QByteArray("100 \n\r\t") << 10 << 100ULL << true;
+ QTest::newRow("leading plus") << QByteArray("+100") << 10 << 100ULL << true;
+ QTest::newRow("space after plus") << QByteArray("+ 12") << 10 << 0ULL << false;
+ QTest::newRow("leading minus") << QByteArray("-100") << 10 << 0ULL << false;
+ QTest::newRow("leading junk") << QByteArray("x100") << 10 << 0ULL << false;
+ QTest::newRow("trailing junk") << QByteArray("100x") << 10 << 0ULL << false;
+
+ QTest::newRow("dec, base 0") << QByteArray("9876543210") << 0 << 9876543210ULL << true;
+ QTest::newRow("hex, base 0") << QByteArray("0x9876543210") << 0 << 0x9876543210ULL << true;
+ QTest::newRow("oct, base 0") << QByteArray("07654321234567") << 0 << 07654321234567ULL << true;
+ QTest::newRow("base 3") << QByteArray("12012") << 3 << 140ULL << true;
+
+ // Boundary values, first in every base:
+ using ULL = std::numeric_limits<qulonglong>;
+ for (int b = 0; b <= 36; ++b) {
+ if (b == 1) // bases 0 and 2 through 36 are allowed
+ ++b;
+ QTest::addRow("max base %d", b)
+ << QByteArray::number(ULL::max(), b ? b : 10) << b << ULL::max() << true;
+ }
+ // Check leading zeros don't hit any buffer-too-big problems:
+ QTest::newRow("many-0 max dec")
+ << (QByteArray(512, '0') + QByteArray::number(ULL::max())) << 10 << ULL::max() << true;
+
+ // Special bases (and let's include some leading space, too !), first decimal:
+ QTest::newRow("max dec, base 0") << QByteArray::number(ULL::max()) << 0 << ULL::max() << true;
+ QTest::newRow("max space dec")
+ << ("\t\r\n\f\v " + QByteArray::number(ULL::max())) << 10 << ULL::max() << true;
+ QTest::newRow("max space dec, base 0")
+ << ("\t\r\n\f\v " + QByteArray::number(ULL::max())) << 0 << ULL::max() << true;
+
+ // Hex with prefix:
+ QTest::newRow("max 0x base 0")
+ << ("0x" + QByteArray::number(ULL::max(), 16)) << 0 << ULL::max() << true;
+ QTest::newRow("max +0x base 0")
+ << ("+0x" + QByteArray::number(ULL::max(), 16)) << 0 << ULL::max() << true;
+ QTest::newRow("max space 0x base 0")
+ << ("\t\r\n\f\v 0x" + QByteArray::number(ULL::max(), 16)) << 0 << ULL::max() << true;
+ QTest::newRow("max space +0x base 0")
+ << ("\t\r\n\f\v +0x" + QByteArray::number(ULL::max(), 16)) << 0 << ULL::max() << true;
+
+ // Octal with prefix:
+ QTest::newRow("max octal base 0")
+ << ('0' + QByteArray::number(ULL::max(), 8)) << 0 << ULL::max() << true;
+ QTest::newRow("max +octal base 0")
+ << ("+0" + QByteArray::number(ULL::max(), 8)) << 0 << ULL::max() << true;
+ QTest::newRow("max space octal base 0")
+ << ("\t\r\n\f\v 0" + QByteArray::number(ULL::max(), 8)) << 0 << ULL::max() << true;
+ QTest::newRow("max space +octal base 0")
+ << ("\t\r\n\f\v +0" + QByteArray::number(ULL::max(), 8)) << 0 << ULL::max() << true;
+
+ // Values *just* out of range:
+ QTest::newRow("max + 1 dec") << decNext(QByteArray::number(ULL::max())) << 10 << 0ULL << false;
+ QTest::newRow("max + 1 dec base 0")
+ << decNext(QByteArray::number(ULL::max())) << 0 << 0ULL << false;
+ auto big = QByteArray::number(ULL::max(), 8).replace('7', '0');
+ // Number of bits is a power of two, so not a multiple of three; so (only)
+ // first digit of max wasn't 7:
+ big[0] += 1;
+ QTest::newRow("max + 1 oct") << big << 8 << 0ULL << false;
+ // Number of bits is a multiple of four, so every digit of max is 'f'.
+ big = '1' + QByteArray::number(ULL::max(), 16).replace('f', '0');
+ QTest::newRow("max + 1 hex") << big << 16 << 0ULL << false;
}
void tst_QByteArray::toULongLong()
diff --git a/tests/auto/corelib/text/qlocale/tst_qlocale.cpp b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp
index 89cb46163a..631ca9ff0a 100644
--- a/tests/auto/corelib/text/qlocale/tst_qlocale.cpp
+++ b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp
@@ -1319,6 +1319,9 @@ void tst_QLocale::long_long_conversion_data()
QTest::newRow("C 12345,67") << QString("C") << "12345,67" << false << (qlonglong) 0;
QTest::newRow("C 123456,7") << QString("C") << "123456,7" << false << (qlonglong) 0;
QTest::newRow("C 1,234,567") << QString("C") << "1,234,567" << true << (qlonglong) 1234567;
+ using LL = std::numeric_limits<qlonglong>;
+ QTest::newRow("C LLONG_MIN") << QString("C") << QString::number(LL::min()) << true << LL::min();
+ QTest::newRow("C LLONG_MAX") << QString("C") << QString::number(LL::max()) << true << LL::max();
QTest::newRow("de_DE 1") << QString("de_DE") << "1" << true << (qlonglong) 1;
QTest::newRow("de_DE 1.") << QString("de_DE") << "1." << false << (qlonglong) 0;
diff --git a/tests/auto/corelib/text/qstring/tst_qstring.cpp b/tests/auto/corelib/text/qstring/tst_qstring.cpp
index c2a7b93c7d..a377834025 100644
--- a/tests/auto/corelib/text/qstring/tst_qstring.cpp
+++ b/tests/auto/corelib/text/qstring/tst_qstring.cpp
@@ -3897,7 +3897,7 @@ void tst_QString::toLong()
void tst_QString::toULongLong()
{
QString str;
- bool ok;
+ bool ok = true;
QCOMPARE(str.toULongLong(), Q_UINT64_C(0));
QCOMPARE(str.toULongLong(&ok), Q_UINT64_C(0));
@@ -3917,6 +3917,15 @@ void tst_QString::toULongLong()
QCOMPARE( str.toULongLong( 0 ), Q_UINT64_C(0) );
QCOMPARE( str.toULongLong( &ok ), Q_UINT64_C(0) );
QVERIFY( !ok );
+
+ // Check limits round-trip in every base:
+ using ULL = std::numeric_limits<qulonglong>;
+ for (int b = 0; b <= 36; ++b) {
+ if (b == 1) // 0 and 2 through 36 are valid bases
+ ++b;
+ QCOMPARE(QString::number(ULL::max(), b ? b : 10).toULongLong(&ok, b), ULL::max());
+ QVERIFY(ok);
+ }
}
void tst_QString::toLongLong()
@@ -3969,6 +3978,71 @@ void tst_QString::toLongLong()
}
}
}
+
+ // Check bounds.
+ // First in every base, with no prefix:
+ using LL = std::numeric_limits<qlonglong>;
+ for (int b = 0; b <= 36; ++b) {
+ if (b == 1) // 0 and 2 through 36 are valid bases
+ ++b;
+ QCOMPARE(QString::number(LL::max(), b ? b : 10).toLongLong(&ok, b), LL::max());
+ QVERIFY(ok);
+ QCOMPARE(QString::number(LL::min(), b ? b : 10).toLongLong(&ok, b), LL::min());
+ QVERIFY(ok);
+ }
+
+ // Then in base 16 or 0 with 0x prefix:
+ auto big = QString::number(LL::min(), 16);
+ big.insert(1, u"0x"); // after the minus sign
+ big.prepend(u"\t\r\n\f\v ");
+ QCOMPARE(big.toLongLong(&ok, 16), LL::min());
+ QVERIFY(ok);
+ QCOMPARE(big.toLongLong(&ok, 0), LL::min());
+ QVERIFY(ok);
+ big = QString::number(LL::max(), 16);
+ big.prepend(u"\t\r\n\f\v 0x");
+ QCOMPARE(big.toLongLong(&ok, 16), LL::max());
+ QVERIFY(ok);
+ QCOMPARE(big.toLongLong(&ok, 0), LL::max());
+ QVERIFY(ok);
+ big.insert(6, u'+');
+ QCOMPARE(big.toLongLong(&ok, 16), LL::max());
+ QVERIFY(ok);
+ QCOMPARE(big.toLongLong(&ok, 0), LL::max());
+ QVERIFY(ok);
+
+ // Next octal:
+ big = QString::number(LL::min(), 8);
+ big.insert(1, u'0'); // after the minus sign
+ big.prepend(u"\t\r\n\f\v ");
+ QCOMPARE(big.toLongLong(&ok, 8), LL::min());
+ QVERIFY(ok);
+ QCOMPARE(big.toLongLong(&ok, 0), LL::min());
+ QVERIFY(ok);
+ big = QString::number(LL::max(), 8);
+ big.prepend(u"\t\r\n\f\v 0");
+ QCOMPARE(big.toLongLong(&ok, 8), LL::max());
+ QVERIFY(ok);
+ QCOMPARE(big.toLongLong(&ok, 0), LL::max());
+ QVERIFY(ok);
+ big.insert(6, u'+');
+ QCOMPARE(big.toLongLong(&ok, 8), LL::max());
+ QVERIFY(ok);
+ QCOMPARE(big.toLongLong(&ok, 0), LL::max());
+ QVERIFY(ok);
+
+ // Finally decimal for base 0:
+ big = QString::number(LL::min(), 10);
+ big.prepend(u"\t\r\n\f\v ");
+ QCOMPARE(big.toLongLong(&ok, 0), LL::min());
+ QVERIFY(ok);
+ big = QString::number(LL::max(), 10);
+ big.prepend(u"\t\r\n\f\v ");
+ QCOMPARE(big.toLongLong(&ok, 0), LL::max());
+ QVERIFY(ok);
+ big.insert(6, u'+');
+ QCOMPARE(big.toLongLong(&ok, 0), LL::max());
+ QVERIFY(ok);
}
////////////////////////////////////////////////////////////////////////////