diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index df024bc7b..baec0d6ff 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -15,6 +15,24 @@ 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 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 +EPICS Base.

+

Full support for loadable support modules

Apparently later versions of Base 3.14 permitted support modules to be loaded diff --git a/src/libCom/misc/epicsStdlib.c b/src/libCom/misc/epicsStdlib.c index e61269a1f..ea719c4eb 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) { @@ -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) { diff --git a/src/libCom/misc/epicsStdlib.h b/src/libCom/misc/epicsStdlib.h index 03dace5b4..2d143cb39 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) @@ -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) diff --git a/src/libCom/osi/Makefile b/src/libCom/osi/Makefile index 600af56e0..fb38abc1f 100644 --- a/src/libCom/osi/Makefile +++ b/src/libCom/osi/Makefile @@ -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 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); +} 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,