Update strtoll and strtoull from upstream FreeBSD

There appears to be at least one fix, related to sign- or zero-extension
in the call to isspace(). So it's a good idea to update again. This also
brings the behavior to match strtoll and strtoull on Linux, including
the fact that strtoull will parse negative numbers. For that reason,
qstrtoll and qstrtoull are now wrappers that try and keep the behavior
that we used to have.

This update also changes the code from a 4-clause BSD license (bad) to a
3-clause BSD license (good).

Change-Id: I73b01b02ebd1551bf924599d52284ad25cc1def0
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
This commit is contained in:
Thiago Macieira 2014-02-04 14:14:23 -08:00
parent f43a624ab8
commit e1c99e15b6
3 changed files with 61 additions and 215 deletions

View File

@ -3127,11 +3127,14 @@ int qEnvironmentVariableIntValue(const char *varName, bool *ok) Q_DECL_NOEXCEPT
return 0; return 0;
} }
#endif #endif
const qlonglong value = qstrtoll(buffer, Q_NULLPTR, 0, ok); bool ok_ = true;
const qlonglong value = qstrtoll(buffer, Q_NULLPTR, 0, &ok_);
if (int(value) != value) { // this is the check in QByteArray::toInt(), keep it in sync if (int(value) != value) { // this is the check in QByteArray::toInt(), keep it in sync
if (ok) if (ok)
*ok = false; *ok = false;
return 0; return 0;
} else if (ok) {
*ok = ok_;
} }
return int(value); return int(value);
} }

View File

@ -1,6 +1,7 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2015 The Qt Company Ltd. ** Copyright (C) 2015 The Qt Company Ltd.
** Copyright (C) 2014 Intel Corporation
** Contact: http://www.qt.io/licensing/ ** Contact: http://www.qt.io/licensing/
** **
** This file is part of the QtCore module of the Qt Toolkit. ** This file is part of the QtCore module of the Qt Toolkit.
@ -36,6 +37,7 @@
#include "qstring.h" #include "qstring.h"
#include <ctype.h> #include <ctype.h>
#include <errno.h>
#include <float.h> #include <float.h>
#include <limits.h> #include <limits.h>
#include <math.h> #include <math.h>
@ -63,6 +65,55 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
#include "../../3rdparty/freebsd/strtoull.c"
#include "../../3rdparty/freebsd/strtoll.c"
unsigned long long
qstrtoull(const char * nptr, 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 == '-') {
*ok = false;
return 0;
}
*ok = true;
errno = 0;
char *endptr2 = 0;
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)) {
*ok = false;
return 0;
}
return result;
}
long long
qstrtoll(const char * nptr, const char **endptr, int base, bool *ok)
{
*ok = true;
errno = 0;
char *endptr2 = 0;
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)) {
*ok = false;
return 0;
}
return result;
}
static char *_qdtoa( NEEDS_VOLATILE double d, int mode, int ndigits, int *decpt, static char *_qdtoa( NEEDS_VOLATILE double d, int mode, int ndigits, int *decpt,
int *sign, char **rve, char **digits_str); int *sign, char **rve, char **digits_str);
@ -174,220 +225,6 @@ QString &exponentForm(QChar zero, QChar decimal, QChar exponential,
return digits; return digits;
} }
/*-
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgment:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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.
*/
// static char sccsid[] = "@(#)strtouq.c 8.1 (Berkeley) 6/4/93";
// "$FreeBSD: src/lib/libc/stdlib/strtoull.c,v 1.5.2.1 2001/03/02 09:45:20 obrien Exp $";
/*
* Convert a string to an unsigned long long integer.
*
* Ignores `locale' stuff. Assumes that the upper and lower case
* alphabets and digits are each contiguous.
*/
qulonglong qstrtoull(const char *nptr, const char **endptr, int base, bool *ok)
{
const char *s = nptr;
qulonglong acc;
unsigned char c;
qulonglong qbase, cutoff;
int any, cutlim;
if (ok != 0)
*ok = true;
/*
* See strtoq for comments as to the logic used.
*/
s = nptr;
do {
c = *s++;
} while (ascii_isspace(c));
if (c == '-') {
if (ok != 0)
*ok = false;
if (endptr != 0)
*endptr = s - 1;
return 0;
} else {
if (c == '+')
c = *s++;
}
if ((base == 0 || base == 16) &&
c == '0' && (*s == 'x' || *s == 'X')) {
c = s[1];
s += 2;
base = 16;
}
if (base == 0)
base = c == '0' ? 8 : 10;
qbase = unsigned(base);
cutoff = qulonglong(ULLONG_MAX) / qbase;
cutlim = qulonglong(ULLONG_MAX) % qbase;
for (acc = 0, any = 0;; c = *s++) {
if (!isascii(c))
break;
if (isdigit(c))
c -= '0';
else if (isalpha(c))
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
acc *= qbase;
acc += c;
}
}
if (any == 0) {
if (ok != 0)
*ok = false;
} else if (any < 0) {
acc = ULLONG_MAX;
if (ok != 0)
*ok = false;
}
if (endptr != 0)
*endptr = (any ? s - 1 : nptr);
return acc;
}
// "$FreeBSD: src/lib/libc/stdlib/strtoll.c,v 1.5.2.1 2001/03/02 09:45:20 obrien Exp $";
/*
* Convert a string to a long long integer.
*
* Ignores `locale' stuff. Assumes that the upper and lower case
* alphabets and digits are each contiguous.
*/
qlonglong qstrtoll(const char *nptr, const char **endptr, int base, bool *ok)
{
const char *s;
qulonglong acc;
unsigned char c;
qulonglong qbase, 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')) {
c = s[1];
s += 2;
base = 16;
}
if (base == 0)
base = c == '0' ? 8 : 10;
/*
* 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.
*/
qbase = unsigned(base);
cutoff = neg ? qulonglong(0-(LLONG_MIN + LLONG_MAX)) + LLONG_MAX : LLONG_MAX;
cutlim = cutoff % qbase;
cutoff /= qbase;
for (acc = 0, any = 0;; c = *s++) {
if (!isascii(c))
break;
if (isdigit(c))
c -= '0';
else if (isalpha(c))
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
acc *= qbase;
acc += c;
}
}
if (any < 0) {
acc = neg ? LLONG_MIN : LLONG_MAX;
if (ok != 0)
*ok = false;
} else if (neg) {
acc = (~acc) + 1;
}
if (endptr != 0)
*endptr = (any >= 0 ? s - 1 : nptr);
if (ok != 0)
*ok = any > 0;
return acc;
}
/* From: NetBSD: strtod.c,v 1.26 1998/02/03 18:44:21 perry Exp */ /* From: NetBSD: strtod.c,v 1.26 1998/02/03 18:44:21 perry Exp */
/* $FreeBSD: src/lib/libc/stdlib/netbsd_strtod.c,v 1.2.2.2 2001/03/02 17:14:15 tegge Exp $ */ /* $FreeBSD: src/lib/libc/stdlib/netbsd_strtod.c,v 1.2.2.2 2001/03/02 17:14:15 tegge Exp $ */

View File

@ -209,6 +209,12 @@ void tst_QIpAddress::invalidParseIp4_data()
// bad hex // bad hex
QTest::newRow("0x1g") << "0x1g"; QTest::newRow("0x1g") << "0x1g";
// negative numbers
QTest::newRow("-1") << "-1";
QTest::newRow("-1.1") << "-1.1";
QTest::newRow("1.-1") << "1.-1";
QTest::newRow("1.1.1.-1") << "1.1.1.-1";
// letters // letters
QTest::newRow("abc") << "abc"; QTest::newRow("abc") << "abc";
QTest::newRow("1.2.3a.4") << "1.2.3a.4"; QTest::newRow("1.2.3a.4") << "1.2.3a.4";