From 7b7d3ac0d4a260f1138e7fc2e8769977362247de Mon Sep 17 00:00:00 2001 From: Ray Speth Date: Wed, 3 Apr 2013 23:10:18 +0000 Subject: [PATCH] Fixed locale-dependent processing of XML files Floating point values are read using a std::stringstream imbued with the "C" locale to avoid problems with using std::atof when the user's locale uses a character other than "." as the decimal separator. Patch provided by Phillip Berndt. Fixes Issue 153. --- src/base/ctml.cpp | 30 +++++++++++++++--------------- src/base/stringUtils.cpp | 22 ++++++++++++++++------ src/base/xml.cpp | 2 +- src/kinetics/importKinetics.cpp | 2 +- src/thermo/Elements.cpp | 6 +++--- src/thermo/HMWSoln_input.cpp | 12 ++++++------ src/thermo/PDSS_HKFT.cpp | 4 ++-- src/thermo/Phase.cpp | 6 +++--- src/transport/PecosTransport.cpp | 6 +++--- 9 files changed, 50 insertions(+), 40 deletions(-) diff --git a/src/base/ctml.cpp b/src/base/ctml.cpp index 33c86dcb5..0e418f793 100644 --- a/src/base/ctml.cpp +++ b/src/base/ctml.cpp @@ -633,7 +633,7 @@ void getFloats(const Cantera::XML_Node& node, std::map& v, std::string typ, title, units, vmin, vmax; for (int i = 0; i < n; i++) { const XML_Node& fi = *(f[i]); - x = atof(fi().c_str()); + x = fpValue(fi()); x0 = Undef; x1 = Undef; typ = fi["type"]; @@ -642,14 +642,14 @@ void getFloats(const Cantera::XML_Node& node, std::map& v, vmin = fi["min"]; vmax = fi["max"]; if (vmin != "") { - x0 = atof(vmin.c_str()); + x0 = fpValue(vmin); if (x < x0 - Tiny) { writelog("\nWarning: value "+fi()+" is below lower limit of " +vmin+".\n"); } } if (fi["max"] != "") { - x1 = atof(vmax.c_str()); + x1 = fpValue(vmax); if (x > x1 + Tiny) { writelog("\nWarning: value "+fi()+" is above upper limit of " +vmax+".\n"); @@ -744,21 +744,21 @@ doublereal getFloatCurrent(const Cantera::XML_Node& node, { doublereal x, x0, x1, fctr = 1.0; string units, vmin, vmax; - x = atof(node().c_str()); + x = fpValue(node()); x0 = Undef; x1 = Undef; units = node["units"]; vmin = node["min"]; vmax = node["max"]; if (vmin != "") { - x0 = atof(vmin.c_str()); + x0 = fpValue(vmin); if (x < x0 - Tiny) { writelog("\nWarning: value "+node()+" is below lower limit of " +vmin+".\n"); } } if (node["max"] != "") { - x1 = atof(vmax.c_str()); + x1 = fpValue(vmax); if (x > x1 + Tiny) { writelog("\nWarning: value "+node()+" is above upper limit of " +vmax+".\n"); @@ -1076,10 +1076,10 @@ size_t getFloatArray(const Cantera::XML_Node& node, std::vector & v, } if ((*readNode)["min"] != "") { - vmin = atofCheck((*readNode)["min"].c_str()); + vmin = fpValueCheck((*readNode)["min"]); } if ((*readNode)["max"] != "") { - vmax = atofCheck((*readNode)["max"].c_str()); + vmax = fpValueCheck((*readNode)["max"]); } doublereal vv; @@ -1089,7 +1089,7 @@ size_t getFloatArray(const Cantera::XML_Node& node, std::vector & v, if (icom != string::npos) { numstr = val.substr(0,icom); val = val.substr(icom+1,val.size()); - dtmp = atofCheck(numstr.c_str()); + dtmp = fpValueCheck(numstr); v.push_back(dtmp); } else { /* @@ -1101,7 +1101,7 @@ size_t getFloatArray(const Cantera::XML_Node& node, std::vector & v, * possibility in for backwards compatibility. */ if (!val.empty()) { - dtmp = atofCheck(val.c_str()); + dtmp = fpValueCheck(val); v.push_back(dtmp); } break; @@ -1152,10 +1152,10 @@ int getNamedFloatArray(const Cantera::XML_Node& parentNode, const std::string& } if ((*readNode)["min"] != "") { - vmin = atofCheck((*readNode)["min"].c_str()); + vmin = fpValueCheck((*readNode)["min"]); } if ((*readNode)["max"] != "") { - vmax = atofCheck((*readNode)["max"].c_str()); + vmax = fpValueCheck((*readNode)["max"]); } int expectedSize = 0; @@ -1176,7 +1176,7 @@ int getNamedFloatArray(const Cantera::XML_Node& parentNode, const std::string& if (icom != string::npos) { numstr = val.substr(0,icom); val = val.substr(icom+1,val.size()); - dtmp = atofCheck(numstr.c_str()); + dtmp = fpValueCheck(numstr); v.push_back(dtmp); } else { /* @@ -1189,7 +1189,7 @@ int getNamedFloatArray(const Cantera::XML_Node& parentNode, const std::string& */ int nlen = strlen(val.c_str()); if (nlen > 0) { - dtmp = atofCheck(val.c_str()); + dtmp = fpValueCheck(val); v.push_back(dtmp); } break; @@ -1425,7 +1425,7 @@ void getMatrixValues(const Cantera::XML_Node& node, throw CanteraError("getMatrixValues","Col not matched by string: " + key2); } - double dval = atofCheck(val.c_str()); + double dval = fpValueCheck(val); dval *= funit; /* * Finally, insert the value; diff --git a/src/base/stringUtils.cpp b/src/base/stringUtils.cpp index 34c80f9a6..6f3a5d2e7 100644 --- a/src/base/stringUtils.cpp +++ b/src/base/stringUtils.cpp @@ -214,7 +214,7 @@ compositionMap parseCompString(const std::string& ss, throw CanteraError("parseCompString", "unknown species " + name); } - x[name] = atof(num.c_str()); + x[name] = fpValue(num); } else { s = ""; } @@ -306,7 +306,11 @@ int intValue(const std::string& val) //================================================================================================ doublereal fpValue(const std::string& val) { - return std::atof(stripws(val).c_str()); + doublereal rval; + std::stringstream ss(val); + ss.imbue(std::locale("C")); + ss >> rval; + return rval; } //================================================================================================ doublereal fpValueCheck(const std::string& val) @@ -453,12 +457,12 @@ int stripLTWScstring(char str[]) //================================================================================================ // Translate a char string into a single double /* - * atofCheck is a wrapper around the C stdlib routine atof(). - * It does quite a bit more error checking than atof() or + * atofCheck is a wrapper around the C++ stdlib stringstream double parser. + * It does quite a bit more error checking than atofCheck() or * strtod(), and is quite a bit more restrictive. * * First it interprets both E, e, d, and D as exponents. - * atof() only interprets e or E as an exponent character. + * stringstreams only interpret e or E as an exponent character. * * It only accepts a string as well formed if it consists as a * single token. Multiple words will produce an error message @@ -470,6 +474,9 @@ int stripLTWScstring(char str[]) * * It does not accept hexadecimal numbers. * + * It does always use the C locale, regardless of any locale + * settings. + * * @param dptr pointer to the input c string * @return Returns the double * @@ -523,7 +530,10 @@ doublereal atofCheck(const char* const dptr) "Trouble processing string, " + hh); } } - doublereal rval = atof(eptr); + doublereal rval; + std::stringstream ss(eptr); + ss.imbue(std::locale("C")); + ss >> rval; free(eptr); return rval; } diff --git a/src/base/xml.cpp b/src/base/xml.cpp index 5d697be66..647e5a3e2 100644 --- a/src/base/xml.cpp +++ b/src/base/xml.cpp @@ -661,7 +661,7 @@ std::string XML_Node::operator()() const */ doublereal XML_Node::fp_value() const { - return atofCheck(m_value.c_str()); + return fpValueCheck(m_value); } // Return the value of an XML node as a single int diff --git a/src/kinetics/importKinetics.cpp b/src/kinetics/importKinetics.cpp index 261d1c525..69377bc43 100644 --- a/src/kinetics/importKinetics.cpp +++ b/src/kinetics/importKinetics.cpp @@ -236,7 +236,7 @@ bool getReagents(const XML_Node& rxn, Kinetics& kin, int rp, * specified species. */ spnum.push_back(isp); - stch = atof(val[n].c_str()); + stch = fpValue(val[n]); stoich.push_back(stch); ord = doublereal(stch); order.push_back(ord); diff --git a/src/thermo/Elements.cpp b/src/thermo/Elements.cpp index d631af7ab..2b90936c8 100644 --- a/src/thermo/Elements.cpp +++ b/src/thermo/Elements.cpp @@ -392,7 +392,7 @@ addElement(const std::string& symbol, doublereal weight) void Elements:: addElement(const XML_Node& e) { - doublereal weight = atof(e["atomicWt"].c_str()); + doublereal weight = fpValue(e["atomicWt"]); string symbol = e["name"]; addElement(symbol, weight); } @@ -467,7 +467,7 @@ addUniqueElement(const XML_Node& e) { doublereal weight = 0.0; if (e.hasAttrib("atomicWt")) { - weight = atof(stripws(e["atomicWt"]).c_str()); + weight = fpValue(stripws(e["atomicWt"])); } int anum = 0; if (e.hasAttrib("atomicNumber")) { @@ -478,7 +478,7 @@ addUniqueElement(const XML_Node& e) if (e.hasChild("entropy298")) { XML_Node& e298Node = e.child("entropy298"); if (e298Node.hasAttrib("value")) { - entropy298 = atofCheck(stripws(e298Node["value"]).c_str()); + entropy298 = fpValueCheck(stripws(e298Node["value"])); } } if (weight != 0.0) { diff --git a/src/thermo/HMWSoln_input.cpp b/src/thermo/HMWSoln_input.cpp index 48013bd4e..212fe8962 100644 --- a/src/thermo/HMWSoln_input.cpp +++ b/src/thermo/HMWSoln_input.cpp @@ -243,12 +243,12 @@ void HMWSoln::readXMLBinarySalt(XML_Node& BinSalt) if (nodeName == "alpha1") { stemp = xmlChild.value(); - m_Alpha1MX_ij[counter] = atofCheck(stemp.c_str()); + m_Alpha1MX_ij[counter] = fpValueCheck(stemp); } if (nodeName == "alpha2") { stemp = xmlChild.value(); - m_Alpha2MX_ij[counter] = atofCheck(stemp.c_str()); + m_Alpha2MX_ij[counter] = fpValueCheck(stemp); } } } @@ -475,7 +475,7 @@ void HMWSoln::readXMLPsiCommonCation(XML_Node& BinSalt) if (nodeName == "theta") { stemp = xmlChild.value(); double old = m_Theta_ij[counter]; - m_Theta_ij[counter] = atofCheck(stemp.c_str()); + m_Theta_ij[counter] = fpValueCheck(stemp); if (old != 0.0) { if (old != m_Theta_ij[counter]) { throw CanteraError("HMWSoln::readXMLPsiCommonCation", @@ -614,7 +614,7 @@ void HMWSoln::readXMLPsiCommonAnion(XML_Node& BinSalt) if (nodeName == "theta") { stemp = xmlChild.value(); double old = m_Theta_ij[counter]; - m_Theta_ij[counter] = atofCheck(stemp.c_str()); + m_Theta_ij[counter] = fpValueCheck(stemp); if (old != 0.0) { if (old != m_Theta_ij[counter]) { throw CanteraError("HMWSoln::readXMLPsiCommonAnion", @@ -1116,7 +1116,7 @@ void HMWSoln::constructPhaseXML(XML_Node& phaseNode, std::string id) stemp = scNode.attrib("TempReference"); formString = lowercase(stemp); if (formString != "") { - m_TempPitzerRef = atofCheck(formString.c_str()); + m_TempPitzerRef = fpValueCheck(formString); } else { m_TempPitzerRef = 273.15 + 25; } @@ -1230,7 +1230,7 @@ initThermoXML(XML_Node& phaseNode, const std::string& id_) stemp = scNode.attrib("TempReference"); formString = lowercase(stemp); if (formString != "") { - m_TempPitzerRef = atofCheck(formString.c_str()); + m_TempPitzerRef = fpValueCheck(formString); } else { m_TempPitzerRef = 273.15 + 25; } diff --git a/src/thermo/PDSS_HKFT.cpp b/src/thermo/PDSS_HKFT.cpp index a1cba00e3..f1f29cd75 100644 --- a/src/thermo/PDSS_HKFT.cpp +++ b/src/thermo/PDSS_HKFT.cpp @@ -632,12 +632,12 @@ void PDSS_HKFT::constructPDSSXML(VPStandardStateTP* tp, size_t spindex, std::string minTstring = (*hh)["Tmin"]; if (minTstring != "") { - m_minTemp = atofCheck(minTstring.c_str()); + m_minTemp = fpValueCheck(minTstring); } std::string maxTstring = (*hh)["Tmax"]; if (maxTstring != "") { - m_maxTemp = atofCheck(maxTstring.c_str()); + m_maxTemp = fpValueCheck(maxTstring); } if (hh->hasChild("DG0_f_Pr_Tr")) { diff --git a/src/thermo/Phase.cpp b/src/thermo/Phase.cpp index ce2136074..2f184b996 100644 --- a/src/thermo/Phase.cpp +++ b/src/thermo/Phase.cpp @@ -665,7 +665,7 @@ void Phase::addElement(const std::string& symbol, doublereal weight) void Phase::addElement(const XML_Node& e) { - doublereal weight = atof(e["atomicWt"].c_str()); + doublereal weight = fpValue(e["atomicWt"]); string symbol = e["name"]; addElement(symbol, weight); } @@ -721,7 +721,7 @@ void Phase::addUniqueElement(const XML_Node& e) { doublereal weight = 0.0; if (e.hasAttrib("atomicWt")) { - weight = atof(stripws(e["atomicWt"]).c_str()); + weight = fpValue(stripws(e["atomicWt"])); } int anum = 0; if (e.hasAttrib("atomicNumber")) { @@ -732,7 +732,7 @@ void Phase::addUniqueElement(const XML_Node& e) if (e.hasChild("entropy298")) { XML_Node& e298Node = e.child("entropy298"); if (e298Node.hasAttrib("value")) { - entropy298 = atofCheck(stripws(e298Node["value"]).c_str()); + entropy298 = fpValueCheck(stripws(e298Node["value"])); } } if (weight != 0.0) { diff --git a/src/transport/PecosTransport.cpp b/src/transport/PecosTransport.cpp index 63374f4c2..e1c83ce8e 100755 --- a/src/transport/PecosTransport.cpp +++ b/src/transport/PecosTransport.cpp @@ -667,9 +667,9 @@ void PecosTransport::read_blottner_transport_table() // this is the right species index if (sss.compare(ss1) == 0) { - a[k] = atof(ss2.c_str()); - b[k] = atof(ss3.c_str()); - c[k] = atof(ss4.c_str()); + a[k] = fpValue(ss2); + b[k] = fpValue(ss3); + c[k] = fpValue(ss4); // index i++;