diff --git a/src/ioc/db/dbScan.c b/src/ioc/db/dbScan.c index e56cd761d..04005b40c 100644 --- a/src/ioc/db/dbScan.c +++ b/src/ioc/db/dbScan.c @@ -161,8 +161,8 @@ long scanInit(void) startStopEvent = epicsEventMustCreate(epicsEventEmpty); scanCtl = ctlPause; - initOnce(); initPeriodic(); + initOnce(); initEvent(); buildScanLists(); for (i = 0; i < nPeriodic; i++) @@ -551,7 +551,8 @@ static void initOnce(void) cantProceed("initOnce: Ring buffer create failed\n"); } onceSem = epicsEventMustCreate(epicsEventEmpty); - onceTaskId = epicsThreadCreate("scanOnce", epicsThreadPriorityScanHigh, + onceTaskId = epicsThreadCreate("scanOnce", + epicsThreadPriorityScanLow + nPeriodic, epicsThreadGetStackSize(epicsThreadStackBig), onceTask, 0); epicsEventWait(startStopEvent); @@ -598,32 +599,29 @@ static void initPeriodic(void) periodic_scan_list *ppsl = dbCalloc(1, sizeof(periodic_scan_list)); const char *choice = pmenu->papChoiceValue[i + SCAN_1ST_PERIODIC]; double number; - char *end; - int c = 0; + char *unit; + int status = epicsParseDouble(choice, &number, &unit); ppsl->scan_list.lock = epicsMutexMustCreate(); ellInit(&ppsl->scan_list.list); - number = epicsStrtod(choice, &end); - while ((c = *end) && isspace(c)) - ++end; - if (number && - (!c || !strcmp(end, "second") || !strcmp(end, "seconds"))) { + if (status || number == 0) { + errlogPrintf("initPeriodic: Bad menuScan choice '%s'\n", choice); + ppsl->period = i; + } + else if (!*unit || !strcmp(unit, "second") || !strcmp(unit, "seconds")) { ppsl->period = number; } - else if (number && - (!strcmp(end, "minute") || !strcmp(end, "minutes"))) { + else if (!strcmp(unit, "minute") || !strcmp(unit, "minutes")) { ppsl->period = number * 60; } - else if (number && - (!strcmp(end, "hour") || !strcmp(end, "hours"))) { + else if (!strcmp(unit, "hour") || !strcmp(unit, "hours")) { ppsl->period = number * 60 * 60; } - else if (number && - (!strcmp(end, "Hz") || !strcmp(end, "Hertz"))) { + else if (!strcmp(unit, "Hz") || !strcmp(unit, "Hertz")) { ppsl->period = 1 / number; } else { - errlogPrintf("initPeriodic: Bad scan string '%s'\n", choice); + errlogPrintf("initPeriodic: Bad menuScan choice '%s'\n", choice); ppsl->period = i; } number = ppsl->period / quantum; diff --git a/src/libCom/misc/epicsStdlib.c b/src/libCom/misc/epicsStdlib.c index 6538948a2..2ddb521b3 100644 --- a/src/libCom/misc/epicsStdlib.c +++ b/src/libCom/misc/epicsStdlib.c @@ -24,7 +24,7 @@ /* These are the conversion primitives */ epicsShareFunc int -epicsParseLong(const char *str, long *to, int base) +epicsParseLong(const char *str, long *to, int base, char **units) { int c; char *endp; @@ -40,21 +40,22 @@ epicsParseLong(const char *str, long *to, int base) return S_stdlib_noConversion; if (errno == EINVAL) /* Not universally supported */ return S_stdlib_badBase; - - while ((c = *endp) && isspace(c)) - ++endp; - if (c) - return S_stdlib_extraneous; - 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 -epicsParseULong(const char *str, unsigned long *to, int base) +epicsParseULong(const char *str, unsigned long *to, int base, char **units) { int c; char *endp; @@ -70,21 +71,22 @@ epicsParseULong(const char *str, unsigned long *to, int base) return S_stdlib_noConversion; if (errno == EINVAL) /* Not universally supported */ return S_stdlib_badBase; - - while ((c = *endp) && isspace(c)) - ++endp; - if (c) - return S_stdlib_extraneous; - 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) +epicsParseDouble(const char *str, double *to, char **units) { int c; char *endp; @@ -95,18 +97,20 @@ epicsParseDouble(const char *str, double *to) errno = 0; value = epicsStrtod(str, &endp); + if (endp == str) return S_stdlib_noConversion; - - while ((c = *endp) && isspace(c)) - ++endp; - if (c) - return S_stdlib_extraneous; - if (errno == ERANGE) return (value == 0) ? S_stdlib_underflow : S_stdlib_overflow; + while ((c = *endp) && isspace(c)) + ++endp; + if (c && !units) + return S_stdlib_extraneous; + *to = value; + if (units) + *units = endp; return 0; } @@ -114,10 +118,10 @@ epicsParseDouble(const char *str, double *to) /* These call the primitives */ epicsShareFunc int -epicsParseInt8(const char *str, epicsInt8 *to, int base) +epicsParseInt8(const char *str, epicsInt8 *to, int base, char **units) { long value; - int status = epicsParseLong(str, &value, base); + int status = epicsParseLong(str, &value, base, units); if (status) return status; @@ -130,10 +134,10 @@ epicsParseInt8(const char *str, epicsInt8 *to, int base) } epicsShareFunc int -epicsParseUInt8(const char *str, epicsUInt8 *to, int base) +epicsParseUInt8(const char *str, epicsUInt8 *to, int base, char **units) { unsigned long value; - int status = epicsParseULong(str, &value, base); + int status = epicsParseULong(str, &value, base, units); if (status) return status; @@ -146,10 +150,10 @@ epicsParseUInt8(const char *str, epicsUInt8 *to, int base) } epicsShareFunc int -epicsParseInt16(const char *str, epicsInt16 *to, int base) +epicsParseInt16(const char *str, epicsInt16 *to, int base, char **units) { long value; - int status = epicsParseLong(str, &value, base); + int status = epicsParseLong(str, &value, base, units); if (status) return status; @@ -162,10 +166,10 @@ epicsParseInt16(const char *str, epicsInt16 *to, int base) } epicsShareFunc int -epicsParseUInt16(const char *str, epicsUInt16 *to, int base) +epicsParseUInt16(const char *str, epicsUInt16 *to, int base, char **units) { unsigned long value; - int status = epicsParseULong(str, &value, base); + int status = epicsParseULong(str, &value, base, units); if (status) return status; @@ -178,10 +182,10 @@ epicsParseUInt16(const char *str, epicsUInt16 *to, int base) } epicsShareFunc int -epicsParseInt32(const char *str, epicsInt32 *to, int base) +epicsParseInt32(const char *str, epicsInt32 *to, int base, char **units) { long value; - int status = epicsParseLong(str, &value, base); + int status = epicsParseLong(str, &value, base, units); if (status) return status; @@ -196,16 +200,16 @@ epicsParseInt32(const char *str, epicsInt32 *to, int base) } epicsShareFunc int -epicsParseUInt32(const char *str, epicsUInt32 *to, int base) +epicsParseUInt32(const char *str, epicsUInt32 *to, int base, char **units) { unsigned long value; - int status = epicsParseULong(str, &value, base); + int status = epicsParseULong(str, &value, base, units); if (status) return status; #if (ULONG_MAX > 0xffffffff) - if (value > 0xffffffffL) + if (value > 0xffffffffUL) return S_stdlib_overflow; #endif @@ -214,10 +218,10 @@ epicsParseUInt32(const char *str, epicsUInt32 *to, int base) } epicsShareFunc int -epicsParseFloat(const char *str, float *to) +epicsParseFloat(const char *str, float *to, char **units) { double value, abs; - int status = epicsParseDouble(str, &value); + int status = epicsParseDouble(str, &value, units); if (status) return status; diff --git a/src/libCom/misc/epicsStdlib.h b/src/libCom/misc/epicsStdlib.h index 81d31983f..fbdfec3f0 100644 --- a/src/libCom/misc/epicsStdlib.h +++ b/src/libCom/misc/epicsStdlib.h @@ -29,39 +29,39 @@ extern "C" { epicsShareFunc int - epicsParseLong(const char *str, long *to, int base); + epicsParseLong(const char *str, long *to, int base, char **units); epicsShareFunc int - epicsParseULong(const char *str, unsigned long *to, int base); + epicsParseULong(const char *str, unsigned long *to, int base, char **units); epicsShareFunc int - epicsParseDouble(const char *str, double *to); + epicsParseDouble(const char *str, double *to, char **units); epicsShareFunc int - epicsParseFloat(const char *str, float *to); + epicsParseFloat(const char *str, float *to, char **units); epicsShareFunc int - epicsParseInt8(const char *str, epicsInt8 *to, int base); + epicsParseInt8(const char *str, epicsInt8 *to, int base, char **units); epicsShareFunc int - epicsParseUInt8(const char *str, epicsUInt8 *to, int base); + epicsParseUInt8(const char *str, epicsUInt8 *to, int base, char **units); epicsShareFunc int - epicsParseInt16(const char *str, epicsInt16 *to, int base); + epicsParseInt16(const char *str, epicsInt16 *to, int base, char **units); epicsShareFunc int - epicsParseUInt16(const char *str, epicsUInt16 *to, int base); + epicsParseUInt16(const char *str, epicsUInt16 *to, int base, char **units); epicsShareFunc int - epicsParseInt32(const char *str, epicsInt32 *to, int base); + epicsParseInt32(const char *str, epicsInt32 *to, int base, char **units); epicsShareFunc int - epicsParseUInt32(const char *str, epicsUInt32 *to, int base); + epicsParseUInt32(const char *str, epicsUInt32 *to, int base, char **units); -#define epicsParseFloat32(str, to) epicsParseFloat(str, to) -#define epicsParseFloat64(str, to) epicsParseDouble(str, to) +#define epicsParseFloat32(str, to, units) epicsParseFloat(str, to, units) +#define epicsParseFloat64(str, to, units) epicsParseDouble(str, to, units) /* These macros return 1 if successful, 0 on failure. * This is analagous to the return value from sscanf() */ -#define epicsScanLong(str, to, base) !epicsParseLong(str, to, base) -#define epicsScanULong(str, to, base) !epicsParseULong(str, to, base) -#define epicsScanFloat(str, to) !epicsParseFloat(str, to) -#define epicsScanDouble(str, to) !epicsParseDouble(str, to) +#define epicsScanLong(str, to, base) !epicsParseLong(str, to, base, NULL) +#define epicsScanULong(str, to, base) !epicsParseULong(str, to, base, NULL) +#define epicsScanFloat(str, to) !epicsParseFloat(str, to, NULL) +#define epicsScanDouble(str, to) !epicsParseDouble(str, to, NULL) #ifdef __cplusplus } diff --git a/src/libCom/test/epicsStdlibTest.c b/src/libCom/test/epicsStdlibTest.c index 362df3aac..aa8d58f49 100644 --- a/src/libCom/test/epicsStdlibTest.c +++ b/src/libCom/test/epicsStdlibTest.c @@ -23,34 +23,34 @@ * so we can tell the user if our epicsStrtod() wrapper is unnecessary. */ int -parseStrtod(const char *str, double *to) +parseStrtod(const char *str, double *to, char **units) { int c; char *endp; - double dtmp; + double value; while ((c = *str) && isspace(c)) ++str; errno = 0; - dtmp = strtod(str, &endp); + value = strtod(str, &endp); + if (endp == str) return S_stdlib_noConversion; + if (errno == ERANGE) + return (value == 0) ? S_stdlib_underflow : S_stdlib_overflow; while ((c = *endp) && isspace(c)) ++endp; - if (c) + if (c && !units) return S_stdlib_extraneous; - if (dtmp == 0 && errno == ERANGE) - return S_stdlib_underflow; - if (fabs(dtmp) == HUGE_VAL && errno == ERANGE) - return S_stdlib_overflow; - - *to = dtmp; + *to = value; + if (units) + *units = endp; return 0; } -#define scanStrtod(str, to) !parseStrtod(str, to) +#define scanStrtod(str, to) !parseStrtod(str, to, NULL) MAIN(epicsStdlibTest) @@ -59,6 +59,7 @@ MAIN(epicsStdlibTest) long l; double d; float f; + char *endp; epicsInt8 i8; epicsUInt8 u8; epicsInt16 i16; @@ -66,33 +67,33 @@ MAIN(epicsStdlibTest) epicsInt32 i32; epicsUInt32 u32; - testPlan(135); + testPlan(143); - testOk(epicsParseLong("", &l, 0) == S_stdlib_noConversion, + testOk(epicsParseLong("", &l, 0, NULL) == S_stdlib_noConversion, "Long '' => noConversion"); - testOk(epicsParseULong("", &u, 0) == S_stdlib_noConversion, + testOk(epicsParseULong("", &u, 0, NULL) == S_stdlib_noConversion, "ULong '' => noConversion"); - testOk(epicsParseFloat("", &f) == S_stdlib_noConversion, + testOk(epicsParseFloat("", &f, NULL) == S_stdlib_noConversion, "Float '' => noConversion"); - testOk(epicsParseDouble("", &d) == S_stdlib_noConversion, + testOk(epicsParseDouble("", &d, NULL) == S_stdlib_noConversion, "Double '' => noConversion"); - testOk(epicsParseLong("\t \n", &l, 0) == S_stdlib_noConversion, + testOk(epicsParseLong("\t \n", &l, 0, NULL) == S_stdlib_noConversion, "Long '\\t 1\\n' => noConversion"); - testOk(epicsParseULong("\t \n", &u, 0) == S_stdlib_noConversion, + testOk(epicsParseULong("\t \n", &u, 0, NULL) == S_stdlib_noConversion, "ULong '\\t 1\\n' => noConversion"); - testOk(epicsParseFloat("\t \n", &f) == S_stdlib_noConversion, + testOk(epicsParseFloat("\t \n", &f, NULL) == S_stdlib_noConversion, "Float '\\t 1\\n' => noConversion"); - testOk(epicsParseDouble("\t \n", &d) == S_stdlib_noConversion, + testOk(epicsParseDouble("\t \n", &d, NULL) == S_stdlib_noConversion, "Double '\\t 1\\n' => noConversion"); - testOk(epicsParseLong("!", &l, 0) == S_stdlib_noConversion, + testOk(epicsParseLong("!", &l, 0, NULL) == S_stdlib_noConversion, "Long '!' => noConversion"); - testOk(epicsParseULong("!", &u, 0) == S_stdlib_noConversion, + testOk(epicsParseULong("!", &u, 0, NULL) == S_stdlib_noConversion, "ULong '!' => noConversion"); - testOk(epicsParseFloat("!", &f) == S_stdlib_noConversion, + testOk(epicsParseFloat("!", &f, NULL) == S_stdlib_noConversion, "Float '!' => noConversion"); - testOk(epicsParseDouble("!", &d) == S_stdlib_noConversion, + testOk(epicsParseDouble("!", &d, NULL) == S_stdlib_noConversion, "Double '!' => noConversion"); testOk(epicsScanLong("0", &l, 0) && l == 0, "Long '0'"); @@ -105,23 +106,41 @@ MAIN(epicsStdlibTest) 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(epicsParseLong("2!", &l, 0) == S_stdlib_extraneous, + testOk(epicsParseLong("2!", &l, 0, NULL) == S_stdlib_extraneous, "Long '2!' => extraneous"); - testOk(epicsParseULong("2!", &u, 0) == S_stdlib_extraneous, + testOk(epicsParseULong("2!", &u, 0, NULL) == S_stdlib_extraneous, "ULong '2!' => extraneous"); - testOk(epicsParseFloat("2!", &f) == S_stdlib_extraneous, + testOk(epicsParseFloat("2!", &f, NULL) == S_stdlib_extraneous, "Float '2!' => extraneous"); - testOk(epicsParseDouble("2!", &d) == S_stdlib_extraneous, + testOk(epicsParseDouble("2!", &d, NULL) == S_stdlib_extraneous, "Double '2!' => extraneous"); - testOk(epicsParseLong("3 !", &l, 0) == S_stdlib_extraneous, - "Long '3 !' => extraneous"); - testOk(epicsParseULong("3 !", &u, 0) == S_stdlib_extraneous, - "ULong '3 !' => extraneous"); - testOk(epicsParseFloat("3 !", &f) == S_stdlib_extraneous, - "Float '3 !' => extraneous"); - testOk(epicsParseDouble("3 !", &d) == S_stdlib_extraneous, - "Double '3 !' => extraneous"); + testOk(epicsParseLong("3 \n\t!", &l, 0, NULL) == S_stdlib_extraneous, + "Long '3 \\n\\t!' => extraneous"); + testOk(epicsParseULong("3 \n\t!", &u, 0, NULL) == S_stdlib_extraneous, + "ULong '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, + "Double '3 \\n\\t!' => extraneous"); + + testOk(!epicsParseLong("2!", &l, 0, &endp) && *endp == '!', + "Long '2!' => units='!'"); + testOk(!epicsParseULong("2!", &u, 0, &endp) && *endp == '!', + "ULong '2!' => units='!'"); + testOk(!epicsParseFloat("2!", &f, &endp) && *endp == '!', + "Float '2!' => units='!'"); + testOk(!epicsParseDouble("2!", &d, &endp) && *endp == '!', + "Double '2!' => units='!'"); + + testOk(!epicsParseLong("3 \n\t!", &l, 0, &endp) && *endp == '!', + "Long '3 \\n\\t!' => units='!'"); + testOk(!epicsParseULong("3 \n\t!", &u, 0, &endp) && *endp == '!', + "ULong '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 == '!', + "Double '3 \\n\\t!' => units='!'"); testOk(epicsScanLong("0x0", &l, 0) && l == 0, "Long '0x0'"); testOk(epicsScanULong("0x0", &u, 0) && u == 0, "ULong '0x0'"); @@ -153,9 +172,9 @@ MAIN(epicsStdlibTest) testOk(epicsScanFloat("0XF", &f) && f == 15, "Float '0XF'"); testOk(epicsScanDouble("0XF", &d) && d == 15, "Double '0XF'"); - testOk(epicsParseLong("0x0", &l, 10) == S_stdlib_extraneous, + testOk(epicsParseLong("0x0", &l, 10, NULL) == S_stdlib_extraneous, "Long '0x0' in base 10 => extraneous"); - testOk(epicsParseULong("0x0", &u, 10) == S_stdlib_extraneous, + testOk(epicsParseULong("0x0", &u, 10, NULL) == S_stdlib_extraneous, "ULong '0x0' in base 10 => extraneous"); testOk(epicsScanLong("0x10", &l, 0) && l == 0x10, "Long '0x10' in base 0"); @@ -188,43 +207,43 @@ MAIN(epicsStdlibTest) testOk(epicsScanDouble("-0x7fffffff", &d) && d == -0x7fffffff, "Double '-0x7fffffff'"); - testOk(!epicsParseInt8("0x7f", &i8, 0) && i8 == 0x7f, + testOk(!epicsParseInt8("0x7f", &i8, 0, NULL) && i8 == 0x7f, "Int8 '0x7f'"); - testOk(!epicsParseInt8("-0x80", &i8, 0) && i8 == -0x80, + testOk(!epicsParseInt8("-0x80", &i8, 0, NULL) && i8 == -0x80, "Int8 '-0x80'"); - testOk(!epicsParseUInt8("0xff", &u8, 0) && u8 == 0xff, + testOk(!epicsParseUInt8("0xff", &u8, 0, NULL) && u8 == 0xff, "UInt8 '0xff'"); - testOk(epicsParseInt8("0x80", &i8, 0) == S_stdlib_overflow, + testOk(epicsParseInt8("0x80", &i8, 0, NULL) == S_stdlib_overflow, "Int8 '0x80' => overflow"); - testOk(epicsParseInt8("-0x81", &i8, 0) == S_stdlib_overflow, + testOk(epicsParseInt8("-0x81", &i8, 0, NULL) == S_stdlib_overflow, "Int8 '-0x81' => overflow"); - testOk(epicsParseUInt8("0x100", &u8, 0) == S_stdlib_overflow, + testOk(epicsParseUInt8("0x100", &u8, 0, NULL) == S_stdlib_overflow, "UInt8 '0x100' => overflow"); - testOk(!epicsParseInt16("0x7fff", &i16, 0) && i16 == 0x7fff, + testOk(!epicsParseInt16("0x7fff", &i16, 0, NULL) && i16 == 0x7fff, "Int16 '0x7fff'"); - testOk(!epicsParseInt16("-0x8000", &i16, 0) && i16 == -0x8000, + testOk(!epicsParseInt16("-0x8000", &i16, 0, NULL) && i16 == -0x8000, "Int16 '-0x8000'"); - testOk(!epicsParseUInt16("0xffff", &u16, 0) && u16 == 0xffff, + testOk(!epicsParseUInt16("0xffff", &u16, 0, NULL) && u16 == 0xffff, "UInt16 '0xffff'"); - testOk(epicsParseInt16("0x8000", &i16, 0) == S_stdlib_overflow, + testOk(epicsParseInt16("0x8000", &i16, 0, NULL) == S_stdlib_overflow, "Int16 '0x8000' => overflow"); - testOk(epicsParseInt16("-0x8001", &i16, 0) == S_stdlib_overflow, + testOk(epicsParseInt16("-0x8001", &i16, 0, NULL) == S_stdlib_overflow, "Int16 '-0x8001' => overflow"); - testOk(epicsParseUInt16("0x10000", &u16, 0) == S_stdlib_overflow, + testOk(epicsParseUInt16("0x10000", &u16, 0, NULL) == S_stdlib_overflow, "UInt16 '0x10000' => overflow"); - testOk(!epicsParseInt32("0x7fffffff", &i32, 0) && i32 == 0x7fffffff, + testOk(!epicsParseInt32("0x7fffffff", &i32, 0, NULL) && i32 == 0x7fffffff, "Int32 '0x7fffffff'"); - testOk(!epicsParseInt32("-0x80000000", &i32, 0) && i32 == -0x80000000L, + testOk(!epicsParseInt32("-0x80000000", &i32, 0, NULL) && i32 == -0x80000000L, "Int32 '-0x80000000'"); - testOk(!epicsParseUInt32("0xffffffff", &u32, 0) && u32 == 0xffffffff, + testOk(!epicsParseUInt32("0xffffffff", &u32, 0, NULL) && u32 == 0xffffffff, "UInt32 '0xffffffff'"); - testOk(epicsParseInt32("0x80000000", &i32, 0) == S_stdlib_overflow, + testOk(epicsParseInt32("0x80000000", &i32, 0, NULL) == S_stdlib_overflow, "Int32 '0x80000000' => overflow"); - testOk(epicsParseInt32("-0x80000001", &i32, 0) == S_stdlib_overflow, + testOk(epicsParseInt32("-0x80000001", &i32, 0, NULL) == S_stdlib_overflow, "Int32 '-0x80000001' => overflow"); - testOk(epicsParseUInt32("0x100000000", &u32, 0) == S_stdlib_overflow, + testOk(epicsParseUInt32("0x100000000", &u32, 0, NULL) == S_stdlib_overflow, "UInt32 '0x100000000' => overflow"); testOk(epicsScanFloat(".1", &f) && fabs(f - 0.1) < 1e-7, @@ -262,9 +281,9 @@ MAIN(epicsStdlibTest) testOk(epicsScanDouble("1e-300", &d) && fabs(d - 1e-300) < 1e-306, "Double '1e-300'"); - testOk(epicsParseFloat("1e-40", &f) == S_stdlib_underflow, + testOk(epicsParseFloat("1e-40", &f, NULL) == S_stdlib_underflow, "Float '1e-40' => underflow"); - testOk(epicsParseDouble("1e-330", &d) == S_stdlib_underflow, + testOk(epicsParseDouble("1e-330", &d, NULL) == S_stdlib_underflow, "Double '1e-330' => underflow"); testOk(epicsScanFloat("1e30", &f) && fabs(f - 1e30) < 1e24, @@ -272,9 +291,9 @@ MAIN(epicsStdlibTest) testOk(epicsScanDouble("1e300", &d) && d == 1e300, "Double '1e300'"); - testOk(epicsParseFloat("1e40", &f) == S_stdlib_overflow, + testOk(epicsParseFloat("1e40", &f, NULL) == S_stdlib_overflow, "Float '1e40' => overflow"); - testOk(epicsParseDouble("1e310", &d) == S_stdlib_overflow, + testOk(epicsParseDouble("1e310", &d, NULL) == S_stdlib_overflow, "Double '1e330' => overflow"); testOk(epicsScanLong("2147483647", &l, 0) && l == 2147483647, @@ -352,20 +371,24 @@ MAIN(epicsStdlibTest) testDiag("Checking the native strtod(), only failures shown:"); - CHECK(parseStrtod("", &d) == S_stdlib_noConversion, + CHECK(parseStrtod("", &d, NULL) == S_stdlib_noConversion, " not ok - strtod('') => noConversion"); - CHECK(parseStrtod("\t \n", &d) == S_stdlib_noConversion, + CHECK(parseStrtod("\t \n", &d, NULL) == S_stdlib_noConversion, " not ok - strtod('\\t 1\\n') => noConversion"); - CHECK(parseStrtod("!", &d) == S_stdlib_noConversion, + CHECK(parseStrtod("!", &d, NULL) == S_stdlib_noConversion, " not ok - strtod('!') => noConversion"); CHECK(scanStrtod("0", &d) && d == 0, " not ok - strtod('0')"); CHECK(scanStrtod("\t 1\n", &d) && d == 1, " not ok - strtod('\\t 1\\n')"); - CHECK(parseStrtod("2!", &d) == S_stdlib_extraneous, + CHECK(parseStrtod("2!", &d, NULL) == S_stdlib_extraneous, " not ok - strtod('2!') => extraneous"); - CHECK(parseStrtod("3 !", &d) == S_stdlib_extraneous, + CHECK(parseStrtod("3 !", &d, NULL) == S_stdlib_extraneous, " not ok - strtod('3 !') => extraneous"); + CHECK(!parseStrtod("2!", &d, &endp) && *endp == '!', + " not ok - strtod('2!') => units='!'"); + CHECK(!parseStrtod("3 \n\t!", &d, &endp) && *endp == '!', + " not ok - strtod('3 \\n\\t!') => units='!'"); CHECK(scanStrtod("0x0", &d) && d == 0, " not ok - strtod('0x0')"); CHECK(scanStrtod("0x1", &d) && d == 1, @@ -396,7 +419,7 @@ MAIN(epicsStdlibTest) " not ok - strtod('-1e-1')"); CHECK(scanStrtod("1e-300", &d) && fabs(d - 1e-300) < 1e-306, " not ok - strtod('1e-300')"); - CHECK(parseStrtod("1e-400", &d) == S_stdlib_underflow, + CHECK(parseStrtod("1e-400", &d, NULL) == S_stdlib_underflow, " not ok - strtod('1e-400') => underflow"); CHECK(scanStrtod("4294967294", &d) && d == 4294967294.0, " not ok - strtod('4294967294')");