From 9471488796958517f80253bf7d72292029002a0c Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Wed, 27 Aug 2014 22:11:08 -0700
Subject: [PATCH 1/4] Add strtoll() and strtoull() for VxWorks
These are not yet provided even in VxWorks 6.9.
---
src/libCom/osi/Makefile | 2 +
src/libCom/osi/os/vxWorks/osdStrtod.h | 12 ++-
src/libCom/osi/os/vxWorks/strtoll.c | 139 ++++++++++++++++++++++++++
src/libCom/osi/os/vxWorks/strtoull.c | 116 +++++++++++++++++++++
4 files changed, 266 insertions(+), 3 deletions(-)
create mode 100644 src/libCom/osi/os/vxWorks/strtoll.c
create mode 100644 src/libCom/osi/os/vxWorks/strtoull.c
diff --git a/src/libCom/osi/Makefile b/src/libCom/osi/Makefile
index 96d4540f2..67eabde4d 100644
--- a/src/libCom/osi/Makefile
+++ b/src/libCom/osi/Makefile
@@ -130,6 +130,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
diff --git a/src/libCom/osi/os/vxWorks/osdStrtod.h b/src/libCom/osi/os/vxWorks/osdStrtod.h
index b5fda31c3..f2c5b68a9 100644
--- a/src/libCom/osi/os/vxWorks/osdStrtod.h
+++ b/src/libCom/osi/os/vxWorks/osdStrtod.h
@@ -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
diff --git a/src/libCom/osi/os/vxWorks/strtoll.c b/src/libCom/osi/os/vxWorks/strtoll.c
new file mode 100644
index 000000000..54e0a9522
--- /dev/null
+++ b/src/libCom/osi/os/vxWorks/strtoll.c
@@ -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
+#include
+#include
+#include
+
+#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);
+}
diff --git a/src/libCom/osi/os/vxWorks/strtoull.c b/src/libCom/osi/os/vxWorks/strtoull.c
new file mode 100644
index 000000000..197a45bcf
--- /dev/null
+++ b/src/libCom/osi/os/vxWorks/strtoull.c
@@ -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
+#include
+#include
+#include
+
+#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);
+}
From b0cdaddebcaaafc5f8ee39656d93ac92bc3fa748 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Wed, 27 Aug 2014 22:21:30 -0700
Subject: [PATCH 2/4] Added 64bit and long long epicsParse* functions
---
src/libCom/misc/epicsStdlib.c | 99 +++++++++++++++++++++++++++++++++++
src/libCom/misc/epicsStdlib.h | 9 ++++
2 files changed, 108 insertions(+)
diff --git a/src/libCom/misc/epicsStdlib.c b/src/libCom/misc/epicsStdlib.c
index faf6ca75c..b78931e26 100644
--- a/src/libCom/misc/epicsStdlib.c
+++ b/src/libCom/misc/epicsStdlib.c
@@ -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)
{
@@ -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 == 0x7fffffffffffffff)
+ 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 == 0xffffffffffffffff)
+ 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)
{
diff --git a/src/libCom/misc/epicsStdlib.h b/src/libCom/misc/epicsStdlib.h
index 03dace5b4..0245badbe 100644
--- a/src/libCom/misc/epicsStdlib.h
+++ b/src/libCom/misc/epicsStdlib.h
@@ -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)
From bdd495acae9ba085fb926c3c60c864012d9da8ec Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Wed, 27 Aug 2014 22:35:21 -0700
Subject: [PATCH 3/4] Document the 64-bit integer types and support routines.
---
documentation/RELEASE_NOTES.html | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
index 3db8233c0..1316350b4 100644
--- a/documentation/RELEASE_NOTES.html
+++ b/documentation/RELEASE_NOTES.html
@@ -15,6 +15,22 @@ EPICS Base 3.15.0.x releases are not intended for use in production systems.
Changes between 3.15.0.1 and 3.15.0.2
+Support routines for 64-bit integers
+
+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 functions for parsing strings into the relevent
+sized integer variables: epicsParseLLong(), epicsParseULLong(), epicsParseInt64()
+and epicsParseUInt64(). Use the first two for long long and unsigned long long
+integer types, and the second two for the epicsInt64 and epicsUInt64 types (the
+latter can map to the more common long and unsigned long types on some 64-bit
+architectures such as linux-x86_64).
+
+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.
+
Implement EPICS_CAS_INTF_ADDR_LIST in rsrv
The IOC server can now bind to a single IP address (and optional port number)
From 7629cf818ae872046bd1a1a7c38fb27af4593b14 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Wed, 27 Aug 2014 23:29:19 -0700
Subject: [PATCH 4/4] Add epicsScanLLong and epicsScanULLong macros and tests.
---
documentation/RELEASE_NOTES.html | 14 +++---
src/libCom/misc/epicsStdlib.h | 2 +
src/libCom/test/epicsStdlibTest.c | 82 ++++++++++++++++++++++++++++++-
3 files changed, 91 insertions(+), 7 deletions(-)
diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
index 1316350b4..57513b10d 100644
--- a/documentation/RELEASE_NOTES.html
+++ b/documentation/RELEASE_NOTES.html
@@ -20,12 +20,14 @@ EPICS Base 3.15.0.x releases are not intended for use in production systems.
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 functions for parsing strings into the relevent
-sized integer variables: epicsParseLLong(), epicsParseULLong(), epicsParseInt64()
-and epicsParseUInt64(). Use the first two for long long and unsigned long long
-integer types, and the second two for the epicsInt64 and epicsUInt64 types (the
-latter can map to the more common long and unsigned long types on some 64-bit
-architectures such as linux-x86_64).
+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.
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
diff --git a/src/libCom/misc/epicsStdlib.h b/src/libCom/misc/epicsStdlib.h
index 0245badbe..2d143cb39 100644
--- a/src/libCom/misc/epicsStdlib.h
+++ b/src/libCom/misc/epicsStdlib.h
@@ -72,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)
diff --git a/src/libCom/test/epicsStdlibTest.c b/src/libCom/test/epicsStdlibTest.c
index 4f71055b0..b8bce6ae3 100644
--- a/src/libCom/test/epicsStdlibTest.c
+++ b/src/libCom/test/epicsStdlibTest.c
@@ -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,