Merged epicsInt64-library-support branch

This commit is contained in:
Andrew Johnson
2014-10-06 20:28:35 -05:00
8 changed files with 477 additions and 6 deletions

View File

@@ -15,6 +15,24 @@ EPICS Base 3.15.0.x releases are not intended for use in production systems.</p>
<h2 align="center">Changes between 3.15.0.1 and 3.15.0.2</h2>
<!-- Insert new items immediately below here ... -->
<h3>Support routines for 64-bit integers</h3>
<p>The libCom library now provides support for 64-bit integer types on all
supported architectures. The epicsTypes.h header file defines epicsInt64 and
epicsUInt64 type definitions for both C and C++ code. The epicsStdlib.h header
also declares the following for parsing strings into the relevent sized integer
variables: Functions epicsParseLLong(), epicsParseULLong() with related macros
epicsScanLLong() and epicsScanULLong(), and the functions epicsParseInt64()
and epicsParseUInt64(). Use the first two functions and the macros for long long
and unsigned long long integer types, and the last two functions for the
epicsInt64 and epicsUInt64 types. Note that the latter can map to the types long
and unsigned long on some 64-bit architectures such as linux-x86_64, not to the
two long long types.</p>
<p>This version does not provide the ability to define 64-bit record fields, the
use of the 64-bit types in the IOC database will come in a later release of
EPICS Base.</p>
<h3>Full support for loadable support modules</h3>
<p>Apparently later versions of Base 3.14 permitted support modules to be loaded

View File

@@ -85,6 +85,68 @@ epicsParseULong(const char *str, unsigned long *to, int base, char **units)
return 0;
}
epicsShareFunc int
epicsParseLLong(const char *str, long long *to, int base, char **units)
{
int c;
char *endp;
long long value;
while ((c = *str) && isspace(c))
++str;
errno = 0;
value = strtoll(str, &endp, base);
if (endp == str)
return S_stdlib_noConversion;
if (errno == EINVAL) /* Not universally supported */
return S_stdlib_badBase;
if (errno == ERANGE)
return S_stdlib_overflow;
while ((c = *endp) && isspace(c))
++endp;
if (c && !units)
return S_stdlib_extraneous;
*to = value;
if (units)
*units = endp;
return 0;
}
epicsShareFunc int
epicsParseULLong(const char *str, unsigned long long *to, int base, char **units)
{
int c;
char *endp;
unsigned long long value;
while ((c = *str) && isspace(c))
++str;
errno = 0;
value = strtoull(str, &endp, base);
if (endp == str)
return S_stdlib_noConversion;
if (errno == EINVAL) /* Not universally supported */
return S_stdlib_badBase;
if (errno == ERANGE)
return S_stdlib_overflow;
while ((c = *endp) && isspace(c))
++endp;
if (c && !units)
return S_stdlib_extraneous;
*to = value;
if (units)
*units = endp;
return 0;
}
epicsShareFunc int
epicsParseDouble(const char *str, double *to, char **units)
{
@@ -190,7 +252,7 @@ epicsParseInt32(const char *str, epicsInt32 *to, int base, char **units)
if (status)
return status;
#if (LONG_MAX > 0x7fffffff)
#if (LONG_MAX > 0x7fffffffLL)
if (value < -0x80000000L || value > 0x7fffffffL)
return S_stdlib_overflow;
#endif
@@ -208,7 +270,7 @@ epicsParseUInt32(const char *str, epicsUInt32 *to, int base, char **units)
if (status)
return status;
#if (ULONG_MAX > 0xffffffff)
#if (ULONG_MAX > 0xffffffffULL)
if (value > 0xffffffffUL && value <= ~0xffffffffUL)
return S_stdlib_overflow;
#endif
@@ -217,6 +279,43 @@ epicsParseUInt32(const char *str, epicsUInt32 *to, int base, char **units)
return 0;
}
epicsShareFunc int
epicsParseInt64(const char *str, epicsInt64 *to, int base, char **units)
{
#if (LONG_MAX == 0x7fffffffffffffffLL)
long value;
int status = epicsParseLong(str, &value, base, units);
#else
long long value;
int status = epicsParseLLong(str, &value, base, units);
#endif
if (status)
return status;
*to = value;
return 0;
}
epicsShareFunc int
epicsParseUInt64(const char *str, epicsUInt64 *to, int base, char **units)
{
#if (ULONG_MAX == 0xffffffffffffffffULL)
unsigned long value;
int status = epicsParseULong(str, &value, base, units);
#else
unsigned long long value;
int status = epicsParseULLong(str, &value, base, units);
#endif
if (status)
return status;
*to = value;
return 0;
}
epicsShareFunc int
epicsParseFloat(const char *str, float *to, char **units)
{

View File

@@ -35,6 +35,10 @@ epicsShareFunc int
epicsParseLong(const char *str, long *to, int base, char **units);
epicsShareFunc int
epicsParseULong(const char *str, unsigned long *to, int base, char **units);
epicsShareFunc int
epicsParseLLong(const char *str, long long *to, int base, char **units);
epicsShareFunc int
epicsParseULLong(const char *str, unsigned long long *to, int base, char **units);
epicsShareFunc int
epicsParseDouble(const char *str, double *to, char **units);
@@ -55,6 +59,11 @@ epicsShareFunc int
epicsShareFunc int
epicsParseUInt32(const char *str, epicsUInt32 *to, int base, char **units);
epicsShareFunc int
epicsParseInt64(const char *str, epicsInt64 *to, int base, char **units);
epicsShareFunc int
epicsParseUInt64(const char *str, epicsUInt64 *to, int base, char **units);
#define epicsParseFloat32(str, to, units) epicsParseFloat(str, to, units)
#define epicsParseFloat64(str, to, units) epicsParseDouble(str, to, units)
@@ -63,6 +72,8 @@ epicsShareFunc int
*/
#define epicsScanLong(str, to, base) !epicsParseLong(str, to, base, NULL)
#define epicsScanULong(str, to, base) !epicsParseULong(str, to, base, NULL)
#define epicsScanLLong(str, to, base) !epicsParseLLong(str, to, base, NULL)
#define epicsScanULLong(str, to, base) !epicsParseULLong(str, to, base, NULL)
#define epicsScanFloat(str, to) !epicsParseFloat(str, to, NULL)
#define epicsScanDouble(str, to) !epicsParseDouble(str, to, NULL)

View File

@@ -133,6 +133,8 @@ INC_vxWorks += task_params.h
Com_SRCS_vxWorks += epicsDynLink.c
Com_SRCS_vxWorks += veclist.c
Com_SRCS_vxWorks += logMsgToErrlog.cpp
Com_SRCS_vxWorks += strtoll.c
Com_SRCS_vxWorks += strtoull.c
#This forces the vxWorks compatibility stuff to be loaded
OBJS_vxWorks = vxComLibrary

View File

@@ -1,12 +1,11 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Saskatchewan
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* This header fragment is intended to be included as part of epicsString.h
* This header is included as part of epicsString.h and epicsStdlib.h
*/
#ifdef __cplusplus
@@ -18,6 +17,13 @@ extern "C" {
*/
epicsShareFunc double epicsStrtod(const char *str, char **endp);
/*
* VxWorks doesn't provide these routines, so for now we do
*/
long long int strtoll(const char *nptr, char **endptr, int base);
unsigned long long int strtoull(const char *nptr, char **endptr, int base);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,139 @@
/*-
* 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.
* 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.
*/
#include <limits.h>
#include <errno.h>
#include <ctype.h>
#include <stdlib.h>
#ifndef LLONG_MAX
#define LLONG_MAX 0x7FFFFFFFFFFFFFFFLL
#define LLONG_MIN (-0x7FFFFFFFFFFFFFFFLL - 1)
#endif
/*
* Convert a string to a long long integer.
*
* Assumes that the upper and lower case
* alphabets and digits are each contiguous.
*/
long long
strtoll(const char * __restrict nptr, char ** __restrict 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 (isspace((unsigned char)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 = (char *)(any ? s - 1 : nptr);
return (acc);
}

View File

@@ -0,0 +1,116 @@
/*-
* 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.
* 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.
*/
#include <limits.h>
#include <errno.h>
#include <ctype.h>
#include <stdlib.h>
#ifndef ULLONG_MAX
#define ULLONG_MAX 0xFFFFFFFFFFFFFFFFULL
#endif
/*
* 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
strtoull(const char * __restrict nptr, char ** __restrict 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 (isspace((unsigned char)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 = (char *)(any ? s - 1 : nptr);
return (acc);
}

View File

@@ -58,6 +58,8 @@ MAIN(epicsStdlibTest)
{
unsigned long u;
long l;
unsigned long long ull;
long long ll;
double d;
float f;
char *endp;
@@ -67,13 +69,19 @@ MAIN(epicsStdlibTest)
epicsUInt16 u16;
epicsInt32 i32;
epicsUInt32 u32;
epicsInt64 i64;
epicsUInt64 u64;
testPlan(153);
testPlan(199);
testOk(epicsParseLong("", &l, 0, NULL) == S_stdlib_noConversion,
"Long '' => noConversion");
testOk(epicsParseULong("", &u, 0, NULL) == S_stdlib_noConversion,
"ULong '' => noConversion");
testOk(epicsParseLLong("", &ll, 0, NULL) == S_stdlib_noConversion,
"LLong '' => noConversion");
testOk(epicsParseULLong("", &ull, 0, NULL) == S_stdlib_noConversion,
"ULLong '' => noConversion");
testOk(epicsParseFloat("", &f, NULL) == S_stdlib_noConversion,
"Float '' => noConversion");
testOk(epicsParseDouble("", &d, NULL) == S_stdlib_noConversion,
@@ -83,6 +91,10 @@ MAIN(epicsStdlibTest)
"Long '\\t 1\\n' => noConversion");
testOk(epicsParseULong("\t \n", &u, 0, NULL) == S_stdlib_noConversion,
"ULong '\\t 1\\n' => noConversion");
testOk(epicsParseLLong("\t \n", &ll, 0, NULL) == S_stdlib_noConversion,
"LLong '\\t 1\\n' => noConversion");
testOk(epicsParseULLong("\t \n", &ull, 0, NULL) == S_stdlib_noConversion,
"ULLong '\\t 1\\n' => noConversion");
testOk(epicsParseFloat("\t \n", &f, NULL) == S_stdlib_noConversion,
"Float '\\t 1\\n' => noConversion");
testOk(epicsParseDouble("\t \n", &d, NULL) == S_stdlib_noConversion,
@@ -92,6 +104,10 @@ MAIN(epicsStdlibTest)
"Long '!' => noConversion");
testOk(epicsParseULong("!", &u, 0, NULL) == S_stdlib_noConversion,
"ULong '!' => noConversion");
testOk(epicsParseLLong("!", &ll, 0, NULL) == S_stdlib_noConversion,
"LLong '!' => noConversion");
testOk(epicsParseULLong("!", &ull, 0, NULL) == S_stdlib_noConversion,
"ULLong '!' => noConversion");
testOk(epicsParseFloat("!", &f, NULL) == S_stdlib_noConversion,
"Float '!' => noConversion");
testOk(epicsParseDouble("!", &d, NULL) == S_stdlib_noConversion,
@@ -99,16 +115,22 @@ MAIN(epicsStdlibTest)
testOk(epicsScanLong("0", &l, 0) && l == 0, "Long '0'");
testOk(epicsScanULong("0", &u, 0) && u == 0, "ULong '0'");
testOk(epicsScanLLong("0", &ll, 0) && ll == 0, "LLong '0'");
testOk(epicsScanULLong("0", &ull, 0) && ull == 0, "ULLong '0'");
testOk(epicsScanFloat("0", &f) && f == 0, "Float '0'");
testOk(epicsScanDouble("0", &d) && d == 0, "Double '0'");
testOk(epicsScanLong("\t 1\n", &l, 0) && l == 1, "Long '\\t 1\\n'");
testOk(epicsScanULong("\t 1\n", &u, 0) && u == 1, "ULong '\\t 1\\n'");
testOk(epicsScanLLong("\t 1\n", &ll, 0) && ll == 1, "LLong '\\t 1\\n'");
testOk(epicsScanULLong("\t 1\n", &ull, 0) && ull == 1, "ULLong '\\t 1\\n'");
testOk(epicsScanFloat("\t 1\n", &f) && f == 1, "Float '\\t 1\\n'");
testOk(epicsScanDouble("\t 1\n", &d) && d == 1, "Double '\\t 1\\n'");
testOk(epicsScanLong("-1", &l, 0) && l == -1, "Long '-1'");
testOk(epicsScanULong("-1", &u, 0) && u + 1 == 0, "ULong '-1'");
testOk(epicsScanLLong("-1", &ll, 0) && ll == -1, "LLong '-1'");
testOk(epicsScanULLong("-1", &ull, 0) && ull + 1 == 0, "ULLong '-1'");
testOk(epicsScanFloat("-1", &f) && f == -1, "Float '-1'");
testOk(epicsScanDouble("-1", &d) && d == -1, "Double '-1'");
@@ -116,6 +138,10 @@ MAIN(epicsStdlibTest)
"Long '2!' => extraneous");
testOk(epicsParseULong("2!", &u, 0, NULL) == S_stdlib_extraneous,
"ULong '2!' => extraneous");
testOk(epicsParseLLong("2!", &ll, 0, NULL) == S_stdlib_extraneous,
"LLong '2!' => extraneous");
testOk(epicsParseULLong("2!", &ull, 0, NULL) == S_stdlib_extraneous,
"ULLong '2!' => extraneous");
testOk(epicsParseFloat("2!", &f, NULL) == S_stdlib_extraneous,
"Float '2!' => extraneous");
testOk(epicsParseDouble("2!", &d, NULL) == S_stdlib_extraneous,
@@ -125,6 +151,10 @@ MAIN(epicsStdlibTest)
"Long '3 \\n\\t!' => extraneous");
testOk(epicsParseULong("3 \n\t!", &u, 0, NULL) == S_stdlib_extraneous,
"ULong '3 \\n\\t!' => extraneous");
testOk(epicsParseLLong("3 \n\t!", &ll, 0, NULL) == S_stdlib_extraneous,
"LLong '3 \\n\\t!' => extraneous");
testOk(epicsParseULLong("3 \n\t!", &ull, 0, NULL) == S_stdlib_extraneous,
"ULLong '3 \\n\\t!' => extraneous");
testOk(epicsParseFloat("3 \n\t!", &f, NULL) == S_stdlib_extraneous,
"Float '3 \\n\\t!' => extraneous");
testOk(epicsParseDouble("3 \n\t!", &d, NULL) == S_stdlib_extraneous,
@@ -134,6 +164,10 @@ MAIN(epicsStdlibTest)
"Long '2!' => units='!'");
testOk(!epicsParseULong("2!", &u, 0, &endp) && *endp == '!',
"ULong '2!' => units='!'");
testOk(!epicsParseLLong("2!", &ll, 0, &endp) && *endp == '!',
"LLong '2!' => units='!'");
testOk(!epicsParseULLong("2!", &ull, 0, &endp) && *endp == '!',
"ULLong '2!' => units='!'");
testOk(!epicsParseFloat("2!", &f, &endp) && *endp == '!',
"Float '2!' => units='!'");
testOk(!epicsParseDouble("2!", &d, &endp) && *endp == '!',
@@ -143,6 +177,10 @@ MAIN(epicsStdlibTest)
"Long '3 \\n\\t!' => units='!'");
testOk(!epicsParseULong("3 \n\t!", &u, 0, &endp) && *endp == '!',
"ULong '3 \\n\\t!' => units='!'");
testOk(!epicsParseLLong("3 \n\t!", &ll, 0, &endp) && *endp == '!',
"LLong '3 \\n\\t!' => units='!'");
testOk(!epicsParseULLong("3 \n\t!", &ull, 0, &endp) && *endp == '!',
"ULLong '3 \\n\\t!' => units='!'");
testOk(!epicsParseFloat("3 \n\t!", &f, &endp) && *endp == '!',
"Float '3 \\n\\t!' => units='!'");
testOk(!epicsParseDouble("3 \n\t!", &d, &endp) && *endp == '!',
@@ -150,31 +188,43 @@ MAIN(epicsStdlibTest)
testOk(epicsScanLong("0x0", &l, 0) && l == 0, "Long '0x0'");
testOk(epicsScanULong("0x0", &u, 0) && u == 0, "ULong '0x0'");
testOk(epicsScanLLong("0x0", &ll, 0) && ll == 0, "LLong '0x0'");
testOk(epicsScanULLong("0x0", &ull, 0) && ull == 0, "ULLong '0x0'");
testOk(epicsScanFloat("0x0", &f) && f == 0, "Float '0x0'");
testOk(epicsScanDouble("0x0", &d) && d == 0, "Double '0x0'");
testOk(epicsScanLong("0x1", &l, 0) && l == 1, "Long '0x1'");
testOk(epicsScanULong("0x1", &u, 0) && u == 1, "ULong '0x1'");
testOk(epicsScanLLong("0x1", &ll, 0) && ll == 1, "LLong '0x1'");
testOk(epicsScanULLong("0x1", &ull, 0) && ull == 1, "ULLong '0x1'");
testOk(epicsScanFloat("0x1", &f) && f == 1, "Float '0x1'");
testOk(epicsScanDouble("0x1", &d) && d == 1, "Double '0x1'");
testOk(epicsScanLong("+0x1", &l, 0) && l == 1, "Long '+0x1'");
testOk(epicsScanULong("+0x1", &u, 0) && u == 1, "ULong '+0x1'");
testOk(epicsScanLLong("+0x1", &ll, 0) && ll == 1, "LLong '+0x1'");
testOk(epicsScanULLong("+0x1", &ull, 0) && ull == 1, "ULLong '+0x1'");
testOk(epicsScanFloat("+0x1", &f) && f == 1, "Float '+0x1'");
testOk(epicsScanDouble("+0x1", &d) && d == 1, "Double '+0x1'");
testOk(epicsScanLong("-0x1", &l, 0) && l == -1, "Long '-0x1'");
testOk(epicsScanULong("-0x1", &u, 0) && u == -1, "ULong '-0x1'");
testOk(epicsScanLLong("-0x1", &ll, 0) && ll == -1, "LLong '-0x1'");
testOk(epicsScanULLong("-0x1", &ull, 0) && ull == -1, "ULLong '-0x1'");
testOk(epicsScanFloat("-0x1", &f) && f == -1, "Float '-0x1'");
testOk(epicsScanDouble("-0x1", &d) && d == -1, "Double '-0x1'");
testOk(epicsScanLong("0xf", &l, 0) && l == 15, "Long '0xf'");
testOk(epicsScanULong("0xf", &u, 0) && u == 15, "ULong '0xf'");
testOk(epicsScanLLong("0xf", &ll, 0) && ll == 15, "LLong '0xf'");
testOk(epicsScanULLong("0xf", &ull, 0) && ull == 15, "ULLong '0xf'");
testOk(epicsScanFloat("0xf", &f) && f == 15, "Float '0xf'");
testOk(epicsScanDouble("0xf", &d) && d == 15, "Double '0xf'");
testOk(epicsScanLong("0XF", &l, 0) && l == 15, "Long '0XF'");
testOk(epicsScanULong("0XF", &u, 0) && u == 15, "ULong '0XF'");
testOk(epicsScanLLong("0XF", &ll, 0) && ll == 15, "LLong '0XF'");
testOk(epicsScanULLong("0XF", &ull, 0) && ull == 15, "ULLong '0XF'");
testOk(epicsScanFloat("0XF", &f) && f == 15, "Float '0XF'");
testOk(epicsScanDouble("0XF", &d) && d == 15, "Double '0XF'");
@@ -182,6 +232,11 @@ MAIN(epicsStdlibTest)
"Long '0x0' in base 10 => extraneous");
testOk(epicsParseULong("0x0", &u, 10, NULL) == S_stdlib_extraneous,
"ULong '0x0' in base 10 => extraneous");
testOk(epicsParseLLong("0x0", &ll, 10, NULL) == S_stdlib_extraneous,
"LLong '0x0' in base 10 => extraneous");
testOk(epicsParseULLong("0x0", &ull, 10, NULL) == S_stdlib_extraneous,
"ULLong '0x0' in base 10 => extraneous");
testOk(epicsScanLong("0x10", &l, 0) && l == 0x10,
"Long '0x10' in base 0");
testOk(epicsScanULong("0x10", &u, 0) && u == 0x10,
@@ -199,6 +254,10 @@ MAIN(epicsStdlibTest)
"Long '0x7fffffff'");
testOk(epicsScanULong("0xffffffff", &u, 0) && u == 0xffffffff,
"ULong '0xffffffff'");
testOk(epicsScanLLong("0x7fffffffffffffff", &ll, 0) &&
ll == 0x7fffffffffffffff, "LLong '0x7fffffffffffffff'");
testOk(epicsScanULLong("0xffffffffffffffff", &ull, 0) &&
ull == 0xffffffffffffffff, "ULLong '0xffffffffffffffff'");
testOk(epicsScanFloat("0xffffff", &f) && f == 0xffffff,
"Float '0xffffff'");
testOk(epicsScanDouble("0xffffffff", &d) && d == 0xffffffff,
@@ -208,6 +267,10 @@ MAIN(epicsStdlibTest)
"Long '-0x7fffffff'");
testOk(epicsScanULong("-0x7fffffff", &u, 0) && u == -0x7fffffff,
"ULong '-0x7fffffff'");
testOk(epicsScanLLong("-0x7fffffffffffffff", &ll, 0)
&& ll == -0x7fffffffffffffff, "LLong '-0x7fffffffffffffff'");
testOk(epicsScanULLong("-0x7fffffffffffffff", &ull, 0) &&
ull == -0x7fffffffffffffff, "ULLong '-0x7fffffffffffffff'");
testOk(epicsScanFloat("-0xffffff", &f) && f == -0xffffff,
"Float '-0xffffff'");
testOk(epicsScanDouble("-0x7fffffff", &d) && d == -0x7fffffff,
@@ -264,6 +327,23 @@ MAIN(epicsStdlibTest)
testOk(epicsParseUInt32("-0x100000000", &u32, 0, NULL) == S_stdlib_overflow,
"UInt32 '-0x100000000' => overflow");
testOk(!epicsParseInt64("0x7fffffffffffffff", &i64, 0, NULL) &&
i64 == 0x7fffffffffffffff, "Int64 '0x7fffffffffffffff'");
testOk(!epicsParseInt64("-0x8000000000000000", &i64, 0, NULL) &&
i64 == -0x8000000000000000L, "Int64 '-0x8000000000000000'");
testOk(!epicsParseUInt64("0xffffffffffffffff", &u64, 0, NULL) &&
u64 == 0xffffffffffffffff, "UInt64 '0xffffffffffffffff'");
testOk(!epicsParseUInt64("-1", &u64, 0, NULL) && u64 == 0xffffffffffffffffU,
"UInt64 '-1'");
testOk(epicsParseInt64("0x8000000000000000", &i64, 0, NULL) == S_stdlib_overflow,
"Int64 '0x8000000000000000' => overflow");
testOk(epicsParseInt64("-0x8000000000000001", &i64, 0, NULL) == S_stdlib_overflow,
"Int64 '-0x8000000000000001' => overflow");
testOk(epicsParseUInt64("0x10000000000000000", &u64, 0, NULL) == S_stdlib_overflow,
"UInt64 '0x10000000000000000' => overflow");
testOk(epicsParseUInt64("-0x10000000000000000", &u64, 0, NULL) == S_stdlib_overflow,
"UInt64 '-0x10000000000000000' => overflow");
testOk(epicsScanFloat(".1", &f) && fabs(f - 0.1) < 1e-7,
"Float '.1'");
testOk(epicsScanDouble(".1", &d) && fabs(d - 0.1) < 1e-15,