summaryrefslogtreecommitdiffstats
path: root/src/corelib/text
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 /src/corelib/text
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>
Diffstat (limited to 'src/corelib/text')
-rw-r--r--src/corelib/text/qlocale_tools.cpp117
-rw-r--r--src/corelib/text/qlocale_tools_p.h11
2 files changed, 88 insertions, 40 deletions
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