diff --git a/pvDataApp/misc/parseToPOD.cpp b/pvDataApp/misc/parseToPOD.cpp index e947c69..9ec4178 100644 --- a/pvDataApp/misc/parseToPOD.cpp +++ b/pvDataApp/misc/parseToPOD.cpp @@ -420,6 +420,16 @@ void handleParseError(int err) namespace epics { namespace pvData { namespace detail { +void parseToPOD(const std::string & in, boolean *out) +{ + if(epicsStrCaseCmp(in.c_str(),"true")==0) + *out = 1; + else if(epicsStrCaseCmp(in.c_str(),"false")==0) + *out = 0; + else + throw std::runtime_error("parseToPOD: String no match true/false"); +} + #define INTFN(T, S) \ void parseToPOD(const std::string& in, T *out) { \ epics ## S temp; \ @@ -428,9 +438,8 @@ void parseToPOD(const std::string& in, T *out) { \ else *out = temp; \ } -INTFN(char, Int8); -INTFN(int8_t, Int8); -INTFN(uint8_t, UInt8); +INTFN(int8, Int8); +INTFN(uint8, UInt8); INTFN(int16_t, Int16); INTFN(uint16_t, UInt16); INTFN(int32_t, Int32); diff --git a/pvDataApp/misc/typeCast.cpp b/pvDataApp/misc/typeCast.cpp index 6b5ba2a..9b6e190 100644 --- a/pvDataApp/misc/typeCast.cpp +++ b/pvDataApp/misc/typeCast.cpp @@ -44,7 +44,7 @@ typedef void (*convertfn)(size_t, void*, const void*); static convertfn converters[pvString+1][pvString+1] = { // to pvBoolean - { &noconvert, + { ©V, &noconvert, &noconvert, &noconvert, @@ -55,7 +55,7 @@ static convertfn converters[pvString+1][pvString+1] = &noconvert, &noconvert, &noconvert, - &noconvert + &castVTyped, }, // to pvByte {&noconvert, @@ -198,7 +198,7 @@ static convertfn converters[pvString+1][pvString+1] = &castVTyped, }, // to pvString - {&noconvert, + {&castVTyped, &castVTyped, &castVTyped, &castVTyped, diff --git a/pvDataApp/misc/typeCast.h b/pvDataApp/misc/typeCast.h index 0717d0c..6719dcb 100644 --- a/pvDataApp/misc/typeCast.h +++ b/pvDataApp/misc/typeCast.h @@ -23,9 +23,9 @@ typedef std::string String; namespace detail { // parseToPOD wraps the epicsParse*() functions in one name // and throws exceptions - void parseToPOD(const std::string&, char *out); - void parseToPOD(const std::string&, int8_t *out); - void parseToPOD(const std::string&, uint8_t *out); + void parseToPOD(const std::string&, boolean *out); + void parseToPOD(const std::string&, int8 *out); + void parseToPOD(const std::string&, uint8 *out); void parseToPOD(const std::string&, int16_t *out); void parseToPOD(const std::string&, uint16_t *out); void parseToPOD(const std::string&, int32_t *out); @@ -43,6 +43,27 @@ namespace detail { template<> struct cast_arg { typedef const String& arg; }; + // Handle mangling of type/value when printing + template + struct print_convolute { + static FORCE_INLINE T op(const T& i) { return i; } + }; + // trick std::ostream into treating char's as numbers + // by promoting char to int + template<> + struct print_convolute { + static FORCE_INLINE signed int op(int8 i) { return i; } + }; + template<> + struct print_convolute { + static FORCE_INLINE unsigned int op(uint8 i) { return i; } + }; + // Turn boolean into a string + template<> + struct print_convolute { + static FORCE_INLINE String op(boolean i) { return i ? "true" : "false"; } + }; + // trick std::ostream into treating char's as numbers // by promoting char to int template @@ -75,9 +96,8 @@ namespace detail { template struct cast_helper::type> { static String op(FROM from) { - typedef typename print_cast::type ptype; std::ostringstream strm; - strm << (ptype)from; + strm << print_convolute::op(from); if(strm.fail()) throw std::runtime_error("Cast to string failed"); return strm.str(); diff --git a/testApp/misc/testTypeCast.cpp b/testApp/misc/testTypeCast.cpp index dc74d60..2fd5cf3 100644 --- a/testApp/misc/testTypeCast.cpp +++ b/testApp/misc/testTypeCast.cpp @@ -114,7 +114,7 @@ namespace { MAIN(testTypeCast) { - testPlan(110); + testPlan(122); try { @@ -313,7 +313,6 @@ try { TEST2(String, "1", int8_t, 1); TEST2(String, "-1", int8_t, -1); TEST2(String, "1", uint8_t, 1); - TEST2(String, "-1", char, -1); TEST2(String, "127", int32_t, std::numeric_limits::max()); TEST2(String, "-128", int32_t, std::numeric_limits::min()); @@ -337,6 +336,18 @@ try { TEST(double, 1.1e100, String, "1.1E+100"); + // any non-zero value is true + TEST(String, "true", epics::pvData::boolean, 100); + + TEST2(String, "true", epics::pvData::boolean, 1); + TEST2(String, "false", epics::pvData::boolean, 0); + + // Case insensitive + TEST(epics::pvData::boolean, 1, String, "True"); + TEST(epics::pvData::boolean, 0, String, "False"); + TEST(epics::pvData::boolean, 1, String, "TRUE"); + TEST(epics::pvData::boolean, 0, String, "FALSE"); + testDiag("String Parsing"); TEST(int32_t, 15, String, "0xf"); @@ -372,9 +383,15 @@ try { FAIL(int8_t, String, "1000"); FAIL(int8_t, String, "-1000"); -; + FAIL(double, String, "1e+10000000"); + FAIL(epics::pvData::boolean, String, "hello"); + FAIL(epics::pvData::boolean, String, "1"); + FAIL(epics::pvData::boolean, String, "0"); + FAIL(epics::pvData::boolean, String, "T"); + FAIL(epics::pvData::boolean, String, "F"); + testDiag("Floating point overflows"); TEST(float, FLT_MAX, double, 1e300);