libCom: Add routines for parsing strings into epicsTypes
Adds new routines for converting numeric strings into the standard epicsInt8, epicsUInt8, epicsInt16, epicsUInt16, epicsInt32 and epicsUInt32 types, along with Long, ULong, Double and Float. These all provide error checking and detection of extraneous characters. The epicsScanDouble and epicsScanFloat routines originally in epicsStdlib.h are replaced by macros that call the epicsParse routine, and this also provides epicsScanLong and epicsScanULong to match. A test file is added to ensure conversions work properly and report appropriate errors. This file also checks the native strtod() routine if not used to check whether the epicsStrtod() code is required on this platform.
This commit is contained in:
@@ -0,0 +1,440 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* epicsStdlibTest.c
|
||||
*
|
||||
* Author Andrew Johnson
|
||||
*/
|
||||
|
||||
#include <float.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "epicsStdlib.h"
|
||||
#include "epicsMath.h"
|
||||
#include "epicsUnitTest.h"
|
||||
#include "testMain.h"
|
||||
|
||||
/* Implement the epicsParseDouble() API for checking the native stdtod()
|
||||
* so we can tell the user if our epicsStrtod() wrapper is unnecessary.
|
||||
*/
|
||||
int
|
||||
parseStrtod(const char *str, double *to)
|
||||
{
|
||||
int c;
|
||||
char *endp;
|
||||
double dtmp;
|
||||
|
||||
while ((c = *str) && isspace(c))
|
||||
++str;
|
||||
|
||||
errno = 0;
|
||||
dtmp = strtod(str, &endp);
|
||||
if (endp == str)
|
||||
return S_stdlib_noConversion;
|
||||
|
||||
while ((c = *endp) && isspace(c))
|
||||
++endp;
|
||||
if (c)
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
#define scanStrtod(str, to) !parseStrtod(str, to)
|
||||
|
||||
|
||||
MAIN(epicsStdlibTest)
|
||||
{
|
||||
unsigned long u;
|
||||
long l;
|
||||
double d;
|
||||
float f;
|
||||
epicsInt8 i8;
|
||||
epicsUInt8 u8;
|
||||
epicsInt16 i16;
|
||||
epicsUInt16 u16;
|
||||
epicsInt32 i32;
|
||||
epicsUInt32 u32;
|
||||
|
||||
testPlan(135);
|
||||
|
||||
testOk(epicsParseLong("", &l, 0) == S_stdlib_noConversion,
|
||||
"Long '' => noConversion");
|
||||
testOk(epicsParseULong("", &u, 0) == S_stdlib_noConversion,
|
||||
"ULong '' => noConversion");
|
||||
testOk(epicsParseFloat("", &f) == S_stdlib_noConversion,
|
||||
"Float '' => noConversion");
|
||||
testOk(epicsParseDouble("", &d) == S_stdlib_noConversion,
|
||||
"Double '' => noConversion");
|
||||
|
||||
testOk(epicsParseLong("\t \n", &l, 0) == S_stdlib_noConversion,
|
||||
"Long '\\t 1\\n' => noConversion");
|
||||
testOk(epicsParseULong("\t \n", &u, 0) == S_stdlib_noConversion,
|
||||
"ULong '\\t 1\\n' => noConversion");
|
||||
testOk(epicsParseFloat("\t \n", &f) == S_stdlib_noConversion,
|
||||
"Float '\\t 1\\n' => noConversion");
|
||||
testOk(epicsParseDouble("\t \n", &d) == S_stdlib_noConversion,
|
||||
"Double '\\t 1\\n' => noConversion");
|
||||
|
||||
testOk(epicsParseLong("!", &l, 0) == S_stdlib_noConversion,
|
||||
"Long '!' => noConversion");
|
||||
testOk(epicsParseULong("!", &u, 0) == S_stdlib_noConversion,
|
||||
"ULong '!' => noConversion");
|
||||
testOk(epicsParseFloat("!", &f) == S_stdlib_noConversion,
|
||||
"Float '!' => noConversion");
|
||||
testOk(epicsParseDouble("!", &d) == S_stdlib_noConversion,
|
||||
"Double '!' => noConversion");
|
||||
|
||||
testOk(epicsScanLong("0", &l, 0) && l == 0, "Long '0'");
|
||||
testOk(epicsScanULong("0", &u, 0) && u == 0, "ULong '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(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,
|
||||
"Long '2!' => extraneous");
|
||||
testOk(epicsParseULong("2!", &u, 0) == S_stdlib_extraneous,
|
||||
"ULong '2!' => extraneous");
|
||||
testOk(epicsParseFloat("2!", &f) == S_stdlib_extraneous,
|
||||
"Float '2!' => extraneous");
|
||||
testOk(epicsParseDouble("2!", &d) == 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(epicsScanLong("0x0", &l, 0) && l == 0, "Long '0x0'");
|
||||
testOk(epicsScanULong("0x0", &u, 0) && u == 0, "ULong '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(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(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(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(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(epicsScanFloat("0XF", &f) && f == 15, "Float '0XF'");
|
||||
testOk(epicsScanDouble("0XF", &d) && d == 15, "Double '0XF'");
|
||||
|
||||
testOk(epicsParseLong("0x0", &l, 10) == S_stdlib_extraneous,
|
||||
"Long '0x0' in base 10 => extraneous");
|
||||
testOk(epicsParseULong("0x0", &u, 10) == S_stdlib_extraneous,
|
||||
"ULong '0x0' in base 10 => extraneous");
|
||||
testOk(epicsScanLong("0x10", &l, 0) && l == 0x10,
|
||||
"Long '0x10' in base 0");
|
||||
testOk(epicsScanULong("0x10", &u, 0) && u == 0x10,
|
||||
"ULong '0x10' in base 0");
|
||||
testOk(epicsScanLong("0x10", &l, 16) && l == 0x10,
|
||||
"Long '0x10' in base 16");
|
||||
testOk(epicsScanULong("0x10", &u, 16) && u == 0x10,
|
||||
"ULong '0x10' in base 16");
|
||||
testOk(epicsScanLong("10", &l, 16) && l == 0x10,
|
||||
"Long '10' in base 16");
|
||||
testOk(epicsScanULong("10", &u, 16) && u == 0x10,
|
||||
"ULong '10' in base 16");
|
||||
|
||||
testOk(epicsScanLong("0x7fffffff", &l, 0) && l == 0x7fffffff,
|
||||
"Long '0x7fffffff'");
|
||||
testOk(epicsScanULong("0xffffffff", &u, 0) && u == 0xffffffff,
|
||||
"ULong '0xffffffff'");
|
||||
testOk(epicsScanFloat("0xffffff", &f) && f == 0xffffff,
|
||||
"Float '0xffffff'");
|
||||
testOk(epicsScanDouble("0xffffffff", &d) && d == 0xffffffff,
|
||||
"Double '0xffffffff'");
|
||||
|
||||
testOk(epicsScanLong("-0x7fffffff", &l, 0) && l == -0x7fffffff,
|
||||
"Long '-0x7fffffff'");
|
||||
testOk(epicsScanULong("-0x7fffffff", &u, 0) && u == -0x7fffffff,
|
||||
"ULong '-0x7fffffff'");
|
||||
testOk(epicsScanFloat("-0xffffff", &f) && f == -0xffffff,
|
||||
"Float '-0xffffff'");
|
||||
testOk(epicsScanDouble("-0x7fffffff", &d) && d == -0x7fffffff,
|
||||
"Double '-0x7fffffff'");
|
||||
|
||||
testOk(!epicsParseInt8("0x7f", &i8, 0) && i8 == 0x7f,
|
||||
"Int8 '0x7f'");
|
||||
testOk(!epicsParseInt8("-0x80", &i8, 0) && i8 == -0x80,
|
||||
"Int8 '-0x80'");
|
||||
testOk(!epicsParseUInt8("0xff", &u8, 0) && u8 == 0xff,
|
||||
"UInt8 '0xff'");
|
||||
testOk(epicsParseInt8("0x80", &i8, 0) == S_stdlib_overflow,
|
||||
"Int8 '0x80' => overflow");
|
||||
testOk(epicsParseInt8("-0x81", &i8, 0) == S_stdlib_overflow,
|
||||
"Int8 '-0x81' => overflow");
|
||||
testOk(epicsParseUInt8("0x100", &u8, 0) == S_stdlib_overflow,
|
||||
"UInt8 '0x100' => overflow");
|
||||
|
||||
testOk(!epicsParseInt16("0x7fff", &i16, 0) && i16 == 0x7fff,
|
||||
"Int16 '0x7fff'");
|
||||
testOk(!epicsParseInt16("-0x8000", &i16, 0) && i16 == -0x8000,
|
||||
"Int16 '-0x8000'");
|
||||
testOk(!epicsParseUInt16("0xffff", &u16, 0) && u16 == 0xffff,
|
||||
"UInt16 '0xffff'");
|
||||
testOk(epicsParseInt16("0x8000", &i16, 0) == S_stdlib_overflow,
|
||||
"Int16 '0x8000' => overflow");
|
||||
testOk(epicsParseInt16("-0x8001", &i16, 0) == S_stdlib_overflow,
|
||||
"Int16 '-0x8001' => overflow");
|
||||
testOk(epicsParseUInt16("0x10000", &u16, 0) == S_stdlib_overflow,
|
||||
"UInt16 '0x10000' => overflow");
|
||||
|
||||
testOk(!epicsParseInt32("0x7fffffff", &i32, 0) && i32 == 0x7fffffff,
|
||||
"Int32 '0x7fffffff'");
|
||||
testOk(!epicsParseInt32("-0x80000000", &i32, 0) && i32 == -0x80000000L,
|
||||
"Int32 '-0x80000000'");
|
||||
testOk(!epicsParseUInt32("0xffffffff", &u32, 0) && u32 == 0xffffffff,
|
||||
"UInt32 '0xffffffff'");
|
||||
testOk(epicsParseInt32("0x80000000", &i32, 0) == S_stdlib_overflow,
|
||||
"Int32 '0x80000000' => overflow");
|
||||
testOk(epicsParseInt32("-0x80000001", &i32, 0) == S_stdlib_overflow,
|
||||
"Int32 '-0x80000001' => overflow");
|
||||
testOk(epicsParseUInt32("0x100000000", &u32, 0) == S_stdlib_overflow,
|
||||
"UInt32 '0x100000000' => overflow");
|
||||
|
||||
testOk(epicsScanFloat(".1", &f) && fabs(f - 0.1) < 1e-7,
|
||||
"Float '.1'");
|
||||
testOk(epicsScanDouble(".1", &d) && fabs(d - 0.1) < 1e-15,
|
||||
"Double '.1'");
|
||||
|
||||
testOk(epicsScanFloat("0.1", &f) && fabs(f - 0.1) < 1e-7,
|
||||
"Float '0.1'");
|
||||
testOk(epicsScanDouble("0.1", &d) && fabs(d - 0.1) < 1e-15,
|
||||
"Double '0.1'");
|
||||
|
||||
testOk(epicsScanFloat("1e-1", &f) && fabs(f - 1e-1) < 1e-7,
|
||||
"Float '1e-1'");
|
||||
testOk(epicsScanDouble("1e-1", &d) && fabs(d - 1e-1) < 1e-15,
|
||||
"Double '1e-1'");
|
||||
|
||||
testOk(epicsScanFloat("-.1", &f) && fabs(f + 0.1) < 1e-7,
|
||||
"Float '-.1'");
|
||||
testOk(epicsScanDouble("-.1", &d) && fabs(d + 0.1) < 1e-15,
|
||||
"Double '-.1'");
|
||||
|
||||
testOk(epicsScanFloat("-0.1", &f) && fabs(f + 0.1) < 1e-7,
|
||||
"Float '-0.1'");
|
||||
testOk(epicsScanDouble("-0.1", &d) && fabs(d + 0.1) < 1e-15,
|
||||
"Double '-0.1'");
|
||||
|
||||
testOk(epicsScanFloat("-1e-1", &f) && fabs(f + 1e-1) < 1e-7,
|
||||
"Float '-1e-1'");
|
||||
testOk(epicsScanDouble("-1e-1", &d) && fabs(d + 1e-1) < 1e-15,
|
||||
"Double '-1e-1'");
|
||||
|
||||
testOk(epicsScanFloat("1e-30", &f) && fabs(f - 1e-30) < 1e-36,
|
||||
"Float '1e-30'");
|
||||
testOk(epicsScanDouble("1e-300", &d) && fabs(d - 1e-300) < 1e-306,
|
||||
"Double '1e-300'");
|
||||
|
||||
testOk(epicsParseFloat("1e-40", &f) == S_stdlib_underflow,
|
||||
"Float '1e-40' => underflow");
|
||||
testOk(epicsParseDouble("1e-330", &d) == S_stdlib_underflow,
|
||||
"Double '1e-330' => underflow");
|
||||
|
||||
testOk(epicsScanFloat("1e30", &f) && fabs(f - 1e30) < 1e24,
|
||||
"Float '1e30'");
|
||||
testOk(epicsScanDouble("1e300", &d) && d == 1e300,
|
||||
"Double '1e300'");
|
||||
|
||||
testOk(epicsParseFloat("1e40", &f) == S_stdlib_overflow,
|
||||
"Float '1e40' => overflow");
|
||||
testOk(epicsParseDouble("1e310", &d) == S_stdlib_overflow,
|
||||
"Double '1e330' => overflow");
|
||||
|
||||
testOk(epicsScanLong("2147483647", &l, 0) && l == 2147483647,
|
||||
"Long '2147483647'");
|
||||
testOk(epicsScanLong("-2147483647", &l, 0) && l == -2147483647,
|
||||
"Long '-2147483647'");
|
||||
testOk(epicsScanULong("4294967295", &u, 0) && u == 4294967295u,
|
||||
"ULong '4294967295'");
|
||||
testOk(epicsScanFloat("16777214", &f) && f == 16777214.0,
|
||||
"Float '16777214'");
|
||||
testOk(epicsScanFloat("16777215", &f) && f == 16777215.0,
|
||||
"Float '16777215'");
|
||||
testOk(epicsScanFloat("-16777215", &f) && f == -16777215.0,
|
||||
"Float '-16777215'");
|
||||
testOk(epicsScanFloat("-16777216", &f) && f == -16777216.0,
|
||||
"Float '-16777216'");
|
||||
testOk(epicsScanDouble("4294967294", &d) && d == 4294967294.0,
|
||||
"Double '4294967294'");
|
||||
testOk(epicsScanDouble("4294967295", &d) && d == 4294967295.0,
|
||||
"Double '4294967295'");
|
||||
testOk(epicsScanDouble("-4294967295", &d) && d == -4294967295.0,
|
||||
"Double '-4294967295'");
|
||||
testOk(epicsScanDouble("-4294967296", &d) && d == -4294967296.0,
|
||||
"Double '-4294967296'");
|
||||
|
||||
testOk(epicsScanFloat("NAN", &f) && isnan(f), "Float 'NAN'");
|
||||
testOk(epicsScanDouble("NAN", &d) && isnan(d), "Double 'NAN'");
|
||||
testOk(epicsScanFloat("Nan", &f) && isnan(f), "Float 'Nan'");
|
||||
testOk(epicsScanDouble("Nan", &d) && isnan(d), "Double 'Nan'");
|
||||
testOk(epicsScanFloat("nan()", &f) && isnan(f), "Float 'nan()'");
|
||||
testOk(epicsScanDouble("nan()", &d) && isnan(d), "Double 'nan()'");
|
||||
|
||||
testOk(epicsScanFloat("INF", &f) && f == epicsINF,
|
||||
"Float 'INF'");
|
||||
testOk(epicsScanDouble("INF", &d) && d == epicsINF,
|
||||
"Double 'INF'");
|
||||
testOk(epicsScanFloat("Infinity", &f) && f == epicsINF,
|
||||
"Float 'Infinity'");
|
||||
testOk(epicsScanDouble("Infinity", &d) && d == epicsINF,
|
||||
"Double 'Infinity'");
|
||||
|
||||
testOk(epicsScanFloat("+INF", &f) && f == epicsINF,
|
||||
"Float '+INF'");
|
||||
testOk(epicsScanDouble("+INF", &d) && d == epicsINF,
|
||||
"Double '+INF'");
|
||||
testOk(epicsScanFloat("+Infinity", &f) && f == epicsINF,
|
||||
"Float '+Infinity'");
|
||||
testOk(epicsScanDouble("+Infinity", &d) && d == epicsINF,
|
||||
"Double '+Infinity'");
|
||||
|
||||
testOk(epicsScanFloat("-INF", &f) && f == -epicsINF,
|
||||
"Float '-INF'");
|
||||
testOk(epicsScanDouble("-INF", &d) && d == -epicsINF,
|
||||
"Double '-INF'");
|
||||
testOk(epicsScanFloat("-Infinity", &f) && f == -epicsINF,
|
||||
"Float '-Infinity'");
|
||||
testOk(epicsScanDouble("-Infinity", &d) && d == -epicsINF,
|
||||
"Double '-Infinity'");
|
||||
|
||||
#ifdef epicsStrtod
|
||||
#define CHECK_STRTOD epicsStrtod != strtod
|
||||
if (epicsStrtod == strtod)
|
||||
testDiag("This target defines epicsStrtod as strtod");
|
||||
else
|
||||
testDiag("This target defines its own epicsStrtod macro");
|
||||
#else
|
||||
#define CHECK_STRTOD 1
|
||||
testDiag("This target compiles epicsStrtod()");
|
||||
#endif
|
||||
|
||||
if (CHECK_STRTOD) {
|
||||
int pass = 0, fail = 0;
|
||||
|
||||
#define CHECK(ok, msg) if (ok) pass++; else fail++, testDiag(msg)
|
||||
|
||||
testDiag("Checking the native strtod(), only failures shown:");
|
||||
|
||||
CHECK(parseStrtod("", &d) == S_stdlib_noConversion,
|
||||
" not ok - strtod('') => noConversion");
|
||||
CHECK(parseStrtod("\t \n", &d) == S_stdlib_noConversion,
|
||||
" not ok - strtod('\\t 1\\n') => noConversion");
|
||||
CHECK(parseStrtod("!", &d) == 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,
|
||||
" not ok - strtod('2!') => extraneous");
|
||||
CHECK(parseStrtod("3 !", &d) == S_stdlib_extraneous,
|
||||
" not ok - strtod('3 !') => extraneous");
|
||||
CHECK(scanStrtod("0x0", &d) && d == 0,
|
||||
" not ok - strtod('0x0')");
|
||||
CHECK(scanStrtod("0x1", &d) && d == 1,
|
||||
" not ok - strtod('0x1')");
|
||||
CHECK(scanStrtod("+0x1", &d) && d == 1,
|
||||
" not ok - strtod('+0x1')");
|
||||
CHECK(scanStrtod("-0x1", &d) && d == -1,
|
||||
" not ok - strtod('-0x1')");
|
||||
CHECK(scanStrtod("0xf", &d) && d == 15,
|
||||
" not ok - strtod('0xf')");
|
||||
CHECK(scanStrtod("0XF", &d) && d == 15,
|
||||
" not ok - strtod('0XF')");
|
||||
CHECK(scanStrtod("0xffffffff", &d) && d == 0xffffffff,
|
||||
" not ok - strtod('0xffffffff')");
|
||||
CHECK(scanStrtod("-0x7fffffff", &d) && d == -0x7fffffffl,
|
||||
" not ok - strtod('-0x7fffffff')");
|
||||
CHECK(scanStrtod(".1", &d) && fabs(d - 0.1) < 1e-15,
|
||||
" not ok - strtod('.1')");
|
||||
CHECK(scanStrtod("0.1", &d) && fabs(d - 0.1) < 1e-15,
|
||||
" not ok - strtod('0.1')");
|
||||
CHECK(scanStrtod("1e-1", &d) && fabs(d - 1e-1) < 1e-15,
|
||||
" not ok - strtod('1e-1')");
|
||||
CHECK(scanStrtod("-.1", &d) && fabs(d + 0.1) < 1e-15,
|
||||
" not ok - strtod('-.1')");
|
||||
CHECK(scanStrtod("-0.1", &d) && fabs(d + 0.1) < 1e-15,
|
||||
" not ok - strtod('-0.1')");
|
||||
CHECK(scanStrtod("-1e-1", &d) && fabs(d + 1e-1) < 1e-15,
|
||||
" 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,
|
||||
" not ok - strtod('1e-400') => underflow");
|
||||
CHECK(scanStrtod("4294967294", &d) && d == 4294967294.0,
|
||||
" not ok - strtod('4294967294')");
|
||||
CHECK(scanStrtod("4294967295", &d) && d == 4294967295.0,
|
||||
" not ok - strtod('4294967295')");
|
||||
CHECK(scanStrtod("-4294967295", &d) && d == -4294967295.0,
|
||||
" not ok - strtod('-4294967295')");
|
||||
CHECK(scanStrtod("-4294967296", &d) && d == -4294967296.0,
|
||||
" not ok - strtod('-4294967296')");
|
||||
CHECK(scanStrtod("NAN", &d) && isnan(d),
|
||||
" not ok - strtod('NAN')");
|
||||
CHECK(scanStrtod("Nan", &d) && isnan(d),
|
||||
" not ok - strtod('Nan')");
|
||||
CHECK(scanStrtod("nan()", &d) && isnan(d),
|
||||
" not ok - strtod('nan()')");
|
||||
CHECK(scanStrtod("INF", &d) && d == epicsINF,
|
||||
" not ok - strtod('INF')");
|
||||
CHECK(scanStrtod("Infinity", &d) && d == epicsINF,
|
||||
" not ok - strtod('Infinity')");
|
||||
CHECK(scanStrtod("+INF", &d) && d == epicsINF,
|
||||
" not ok - strtod('+INF')");
|
||||
CHECK(scanStrtod("+Infinity", &d) && d == epicsINF,
|
||||
" not ok - strtod('+Infinity')");
|
||||
CHECK(scanStrtod("-INF", &d) && d == -epicsINF,
|
||||
" not ok - strtod('-INF')");
|
||||
CHECK(scanStrtod("-Infinity", &d) && d == -epicsINF,
|
||||
" not ok - strtod('-Infinity')");
|
||||
|
||||
if (fail)
|
||||
testDiag("The native strtod() passed %d and failed %d tests",
|
||||
pass, fail);
|
||||
else {
|
||||
testDiag("The native strtod() passed all %d tests", pass);
|
||||
#ifndef epicsStrtod
|
||||
testDiag("The compiled epicsStrtod() should not be needed");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return testDone();
|
||||
}
|
||||
Reference in New Issue
Block a user