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.
This commit is contained in:
Ray Speth 2013-04-03 23:10:18 +00:00
parent 00a4e04ce0
commit 7b7d3ac0d4
9 changed files with 50 additions and 40 deletions

View file

@ -633,7 +633,7 @@ void getFloats(const Cantera::XML_Node& node, std::map<std::string, double>& 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<std::string, double>& 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<doublereal> & 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<doublereal> & 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<doublereal> & 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;

View file

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

View file

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

View file

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

View file

@ -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) {

View file

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

View file

@ -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")) {

View file

@ -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) {

View file

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