From ffedc2cb339a67d4ee411649eb067237b39e6d31 Mon Sep 17 00:00:00 2001 From: Thomas Fussell Date: Fri, 2 Oct 2015 10:02:54 -0400 Subject: [PATCH] literals should be long doubles to make float comparison exact --- source/cell.cpp | 225 ++++++++++++++------------------------------ tests/test_cell.hpp | 8 +- 2 files changed, 73 insertions(+), 160 deletions(-) diff --git a/source/cell.cpp b/source/cell.cpp index 5fdf41cb..3fe4bd54 100644 --- a/source/cell.cpp +++ b/source/cell.cpp @@ -17,91 +17,96 @@ namespace { -std::vector split_string(const std::string &string, char delim = ' ') +// return s after checking encoding, size, and illegal characters +std::string check_string(std::string s) { - std::stringstream ss(string); - std::string part; - std::vector parts; - while(std::getline(ss, part, delim)) + if (s.size() == 0) { - parts.push_back(part); + return s; } - return parts; + + // check encoding? + + if (s.size() > 32767) + { + s = s.substr(0, 32767); // max string length in Excel + } + + for (unsigned char c : s) + { + if (c <= 8 || c == 11 || c == 12 || (c >= 14 && c <= 31)) + { + throw "illegal characters"; + } + } + + return s; } -xlnt::value::type data_type_for_value(const std::string &value) +std::pair cast_numeric(const std::string &s) { - if(value.empty()) + const char *str = s.c_str(); + char *str_end = nullptr; + auto result = std::strtold(str, &str_end); + if (str_end != str + s.size()) return{ false, 0 }; + return{ true, result }; +} + +std::pair cast_percentage(const std::string &s) +{ + if (s.back() == '%') { - return xlnt::value::type::null; + auto number = cast_numeric(s.substr(0, s.size() - 1)); + + if (number.first) + { + return{ true, number.second / 100 }; + } } - if(value[0] == '0') + return { false, 0 }; +} + +std::pair cast_time(const std::string &s) +{ + xlnt::time result; + + try { - if(value.length() > 1) + auto last_colon = s.find_last_of(':'); + if (last_colon == std::string::npos) return { false, result }; + double seconds = std::stod(s.substr(last_colon + 1)); + result.second = static_cast(seconds); + result.microsecond = static_cast((seconds - static_cast(result.second)) * 1e6); + + auto first_colon = s.find_first_of(':'); + + if (first_colon == last_colon) { - if(value[1] == '.' || (value.length() > 2 && (value[1] == 'e' || value[1] == 'E'))) + auto decimal_pos = s.find('.'); + if (decimal_pos != std::string::npos) { - auto first_non_number = std::find_if(value.begin() + 2, value.end(), - [](char c) { return !std::isdigit(c, std::locale::classic()); }); - if(first_non_number == value.end()) - { - return xlnt::value::type::numeric; - } - } - auto split = split_string(value, ':'); - if(split.size() == 2 || split.size() == 3) - { - for(auto part : split) - { - try - { - std::stoi(part); - } - catch(std::invalid_argument) - { - return xlnt::value::type::string; - } - } - return xlnt::value::type::numeric; + result.minute = std::stoi(s.substr(0, first_colon)); } else { - return xlnt::value::type::string; + result.hour = std::stoi(s.substr(0, first_colon)); + result.minute = result.second; + result.second = 0; } } - return xlnt::value::type::numeric; - } - else if(value[0] == '#') - { - return xlnt::value::type::error; - } - else - { - char *p; - strtod(value.c_str(), &p); - if(*p != 0) - { - static const std::vector possible_booleans = {"TRUE", "true", "FALSE", "false"}; - if(std::find(possible_booleans.begin(), possible_booleans.end(), value) != possible_booleans.end()) - { - return xlnt::value::type::boolean; - } - if(value.back() == '%') - { - strtod(value.substr(0, value.length() - 1).c_str(), &p); - if(*p == 0) - { - return xlnt::value::type::numeric; - } - } - return xlnt::value::type::string; - } else { - return xlnt::value::type::numeric; + result.hour = std::stoi(s.substr(0, first_colon)); + result.minute = std::stoi(s.substr(first_colon + 1, last_colon - first_colon - 1)); } } + catch (std::invalid_argument) + { + return{ false, result }; + } + + return { true, result }; } } // namespace @@ -161,98 +166,6 @@ void cell::set_value(const value &v) d_->value_ = v; } -// return s after checking encoding, size, and illegal characters -std::string check_string(std::string s) -{ - if (s.size() == 0) - { - return s; - } - - // check encoding? - - if (s.size() > 32767) - { - s = s.substr(0, 32767); // max string length in Excel - } - - for (unsigned char c : s) - { - if (c <= 8 || c == 11 || c == 12 || (c >= 14 && c <= 31)) - { - throw "illegal characters"; - } - } - - return s; -} - -std::pair cast_numeric(const std::string &s) -{ - const char *str = s.c_str(); - char *str_end = nullptr; - auto result = std::strtold(str, &str_end); - if (str_end != str + s.size()) return{ false, 0 }; - return{ true, result }; -} - -std::pair cast_percentage(const std::string &s) -{ - if (s.back() == '%') - { - auto number = cast_numeric(s.substr(0, s.size() - 1)); - - if (number.first) - { - return{ true, number.second / 100 }; - } - } - - return { false, 0 }; -} - -std::pair cast_time(const std::string &s) -{ - time result; - - try - { - auto last_colon = s.find_last_of(':'); - if (last_colon == std::string::npos) return { false, result }; - double seconds = std::stod(s.substr(last_colon + 1)); - result.second = static_cast(seconds); - result.microsecond = static_cast((seconds - static_cast(result.second)) * 1e6); - - auto first_colon = s.find_first_of(':'); - - if (first_colon == last_colon) - { - auto decimal_pos = s.find('.'); - if (decimal_pos != std::string::npos) - { - result.minute = std::stoi(s.substr(0, first_colon)); - } - else - { - result.hour = std::stoi(s.substr(0, first_colon)); - result.minute = result.second; - result.second = 0; - } - } - else - { - result.hour = std::stoi(s.substr(0, first_colon)); - result.minute = std::stoi(s.substr(first_colon + 1, last_colon - first_colon - 1)); - } - } - catch (std::invalid_argument) - { - return{ false, result }; - } - - return { true, result }; -} - void cell::set_value(const std::string &s) { d_->is_date_ = false; diff --git a/tests/test_cell.hpp b/tests/test_cell.hpp index 52e30796..80dd489c 100644 --- a/tests/test_cell.hpp +++ b/tests/test_cell.hpp @@ -16,7 +16,7 @@ public: xlnt::cell cell(ws, "A1"); cell.set_value("4.2"); - TS_ASSERT(cell.get_value() == 4.2); + TS_ASSERT(cell.get_value() == 4.2L); cell.set_value("-42.000"); TS_ASSERT(cell.get_value() == -42); @@ -25,10 +25,10 @@ public: TS_ASSERT(cell.get_value() == 0); cell.set_value("0.9999"); - TS_ASSERT(cell.get_value() == 0.9999); + TS_ASSERT(cell.get_value() == 0.9999L); cell.set_value("99E-02"); - TS_ASSERT(cell.get_value() == 0.99); + TS_ASSERT(cell.get_value() == 0.99L); cell.set_value("4"); TS_ASSERT(cell.get_value() == 4); @@ -40,7 +40,7 @@ public: TS_ASSERT(cell.get_value() == 200); cell.set_value("3.1%"); - TS_ASSERT(cell.get_value() == 0.031); + TS_ASSERT(cell.get_value() == 0.031L); cell.set_value("03:40:16"); TS_ASSERT(cell.get_value() == xlnt::time(3, 40, 16));