Change the epicsParse APIs to return a units pointer.

This lets us use epicsParseDouble() for scan rate parsing.

Ensure the scanOnce thread is a higher priority than the fastest
periodic scan thread, irrespective of how many threads there are.
This commit is contained in:
Andrew Johnson
2012-06-29 14:41:35 -05:00
parent 4eb31d7edc
commit fb61234431
4 changed files with 159 additions and 134 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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
}

View File

@@ -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')");