diff options
author | Edward Welbourne <edward.welbourne@qt.io> | 2021-08-27 14:58:57 +0200 |
---|---|---|
committer | Edward Welbourne <edward.welbourne@qt.io> | 2021-08-30 17:46:00 +0200 |
commit | 5644af6f8a800a1516360a42ba4c1a8dc61fc516 (patch) | |
tree | 0fb11871c40c7f389f95bc227699fdcda8b7889a /src | |
parent | 522ca997d3baab1b88f454bbeea9f357d3969dff (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>
Diffstat (limited to 'src')
-rw-r--r-- | src/3rdparty/freebsd/0001-Patch-the-FreeBSD-strto-u-ll-functions-to-work-insid.patch | 158 | ||||
-rw-r--r-- | src/3rdparty/freebsd/LICENSE | 31 | ||||
-rw-r--r-- | src/3rdparty/freebsd/qt_attribution.json | 18 | ||||
-rw-r--r-- | src/3rdparty/freebsd/strtoll.c | 134 | ||||
-rw-r--r-- | src/3rdparty/freebsd/strtoull.c | 112 | ||||
-rw-r--r-- | src/corelib/text/qlocale_tools.cpp | 117 | ||||
-rw-r--r-- | src/corelib/text/qlocale_tools_p.h | 11 |
7 files changed, 88 insertions, 493 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 |