diff --git a/src/classes/PMsrHandler.cpp b/src/classes/PMsrHandler.cpp index 0d6326265..50c71a9dc 100644 --- a/src/classes/PMsrHandler.cpp +++ b/src/classes/PMsrHandler.cpp @@ -2874,15 +2874,13 @@ Bool_t PMsrHandler::HandleFitParameterEntry(PMsrLines &lines) param.fName = tokens[1].c_str(); // parameter value - if (PStringUtils::IsFloat(tokens[2])) - param.fValue = PStringUtils::ToDouble(tokens[2]); - else + param.fValue = PStringUtils::ToDouble(tokens[2], &ok); + if (!ok) error = true; - // parameter value - if (PStringUtils::IsFloat(tokens[3])) - param.fStep = PStringUtils::ToDouble(tokens[3]); - else + // parameter step + param.fStep = PStringUtils::ToDouble(tokens[3], &ok); + if (!ok) error = true; // 4 values, i.e. No Name Value Step @@ -2895,14 +2893,13 @@ Bool_t PMsrHandler::HandleFitParameterEntry(PMsrLines &lines) param.fNoOfParams = 5; // positive error - if (PStringUtils::IsFloat(tokens[4])) { + param.fPosError = PStringUtils::ToDouble(tokens[4], &ok); + if (ok) { param.fPosErrorPresent = true; - param.fPosError = PStringUtils::ToDouble(tokens[4]); + } else if (PStringUtils::IsEqualNoCase(tokens[4], "none")) { + param.fPosErrorPresent = false; } else { - if (PStringUtils::IsEqualNoCase(tokens[4], "none")) - param.fPosErrorPresent = false; - else - error = true; + error = true; } } @@ -2911,14 +2908,13 @@ Bool_t PMsrHandler::HandleFitParameterEntry(PMsrLines &lines) param.fNoOfParams = 7; // positive error - if (PStringUtils::IsFloat(tokens[4])) { + param.fPosError = PStringUtils::ToDouble(tokens[4], &ok); + if (ok) { param.fPosErrorPresent = true; - param.fPosError = PStringUtils::ToDouble(tokens[4]); + } else if (PStringUtils::IsEqualNoCase(tokens[4], "none")) { + param.fPosErrorPresent = false; } else { - if (PStringUtils::IsEqualNoCase(tokens[4], "none")) - param.fPosErrorPresent = false; - else - error = true; + error = true; } // lower boundary @@ -2926,8 +2922,8 @@ Bool_t PMsrHandler::HandleFitParameterEntry(PMsrLines &lines) if (PStringUtils::IsEqualNoCase(tokens[5], "none")) { // none param.fLowerBoundaryPresent = false; } else { // assuming that the lower boundary is a number - if (PStringUtils::IsFloat(tokens[5])) { - param.fLowerBoundary = PStringUtils::ToDouble(tokens[5]); + param.fLowerBoundary = PStringUtils::ToDouble(tokens[5], &ok); + if (ok) { param.fLowerBoundaryPresent = true; } else { error = true; @@ -2939,8 +2935,8 @@ Bool_t PMsrHandler::HandleFitParameterEntry(PMsrLines &lines) if (PStringUtils::IsEqualNoCase(tokens[6], "none")) { // none param.fUpperBoundaryPresent = false; } else { // assuming a number - if (PStringUtils::IsFloat(tokens[6])) { - param.fUpperBoundary = PStringUtils::ToDouble(tokens[6]); + param.fUpperBoundary = PStringUtils::ToDouble(tokens[6], &ok); + if (ok) { param.fUpperBoundaryPresent = true; } else { error = true; @@ -3125,11 +3121,10 @@ Bool_t PMsrHandler::HandleGlobalEntry(PMsrLines &lines) if (tokens.size() < 3) { error = true; } else { - if (PStringUtils::IsFloat(tokens[1])) { - dval = PStringUtils::ToDouble(tokens[1]); - if (dval <= 0.0) - error = true; - } + bool ok = false; + dval = PStringUtils::ToDouble(tokens[1], &ok); + if (!ok || dval <= 0.0) + error = true; if (!error) { global.SetRRFFreq(dval, tokens[2].c_str()); if (global.GetRRFFreq(tokens[2].c_str()) == RRF_FREQ_UNDEF) @@ -3152,12 +3147,12 @@ Bool_t PMsrHandler::HandleGlobalEntry(PMsrLines &lines) if (tokens.size() < 2) { error = true; } else { - if (PStringUtils::IsFloat(tokens[1])) { - dval = PStringUtils::ToDouble(tokens[1]); + bool ok = false; + dval = PStringUtils::ToDouble(tokens[1], &ok); + if (ok) global.SetRRFPhase(dval); - } else { + else error = true; - } } } else if (iter->fLine.BeginsWith("data", TString::kIgnoreCase)) { // data if (tokens.size() < 3) { @@ -3178,15 +3173,12 @@ Bool_t PMsrHandler::HandleGlobalEntry(PMsrLines &lines) error = true; } else { for (UInt_t i=1; i= 0.0) - global.SetT0Bin(dval); - else - error = true; - } else { + bool ok = false; + dval = PStringUtils::ToDouble(tokens[i], &ok); + if (ok && dval >= 0.0) + global.SetT0Bin(dval); + else error = true; - } } } } else if (iter->fLine.BeginsWith("addt0", TString::kIgnoreCase)) { // addt0 @@ -3194,15 +3186,12 @@ Bool_t PMsrHandler::HandleGlobalEntry(PMsrLines &lines) error = true; } else { for (UInt_t i=1; i= 0.0) - global.SetAddT0Bin(dval, addT0Counter, i-1); - else - error = true; - } else { + bool ok = false; + dval = PStringUtils::ToDouble(tokens[i], &ok); + if (ok && dval >= 0.0) + global.SetAddT0Bin(dval, addT0Counter, i-1); + else error = true; - } } } addT0Counter++; @@ -3241,8 +3230,10 @@ Bool_t PMsrHandler::HandleGlobalEntry(PMsrLines &lines) global.SetFitRangeInBins(true); } else { // fit given in time, i.e. fit , where , are given as doubles for (UInt_t i=1; i<3; i++) { - if (PStringUtils::IsFloat(tokens[i])) - global.SetFitRange(PStringUtils::ToDouble(tokens[i]), i-1); + bool ok = false; + const double range = PStringUtils::ToDouble(tokens[i], &ok); + if (ok) + global.SetFitRange(range, i-1); else error = true; } @@ -3641,8 +3632,10 @@ Bool_t PMsrHandler::HandleRunEntry(PMsrLines &lines) error = true; } else { for (UInt_t i=1; i= 0.0) - param.SetT0Bin(dval); - else - error = true; - } else { + bool ok = false; + dval = PStringUtils::ToDouble(tokens[i], &ok); + if (ok && dval >= 0.0) + param.SetT0Bin(dval); + else error = true; - } } } } @@ -3718,15 +3708,12 @@ Bool_t PMsrHandler::HandleRunEntry(PMsrLines &lines) error = true; } else { for (UInt_t i=1; i= 0.0) - param.SetAddT0Bin(dval, addT0Counter, i-1); - else - error = true; - } else { + bool ok = false; + dval = PStringUtils::ToDouble(tokens[i], &ok); + if (ok && dval >= 0.0) + param.SetAddT0Bin(dval, addT0Counter, i-1); + else error = true; - } } } @@ -3773,8 +3760,10 @@ Bool_t PMsrHandler::HandleRunEntry(PMsrLines &lines) param.SetFitRangeInBins(true); } else { // fit given in time, i.e. fit , where , are given as doubles for (UInt_t i=1; i<3; i++) { - if (PStringUtils::IsFloat(tokens[i])) - param.SetFitRange(PStringUtils::ToDouble(tokens[i]), i-1); + bool ok = false; + const double range = PStringUtils::ToDouble(tokens[i], &ok); + if (ok) + param.SetFitRange(range, i-1); else error = true; } @@ -4017,8 +4006,10 @@ Bool_t PMsrHandler::ParseFourierPhaseValueVector(PMsrFourierStructure &fourier, // convert all acceptable tokens for (UInt_t i=1; i1) { // make sure that no 'phase val, parX' mixture is present @@ -4440,9 +4431,9 @@ Bool_t PMsrHandler::HandleFourierEntry(PMsrLines &lines) continue; } else { for (UInt_t i=0; i<2; i++) { - if (PStringUtils::IsFloat(tokens[i+1])) { - fourier.fPlotRange[i] = PStringUtils::ToDouble(tokens[i+1]); - } else { + bool ok = false; + fourier.fPlotRange[i] = PStringUtils::ToDouble(tokens[i+1], &ok); + if (!ok) { error = true; continue; } @@ -4473,11 +4464,10 @@ Bool_t PMsrHandler::HandleFourierEntry(PMsrLines &lines) break; case 3: for (UInt_t i=0; i<2; i++) { - if (PStringUtils::IsFloat(tokens[i+1])) { - fourier.fRangeForPhaseCorrection[i] = PStringUtils::ToDouble(tokens[i+1]); - } else { + bool ok = false; + fourier.fRangeForPhaseCorrection[i] = PStringUtils::ToDouble(tokens[i+1], &ok); + if (!ok) error = true; - } } break; default: @@ -4640,28 +4630,33 @@ Bool_t PMsrHandler::HandlePlotEntry(PMsrLines &lines) } else { // handle t_min - if (PStringUtils::IsFloat(tokens[1])) - param.fTmin.push_back(PStringUtils::ToDouble(tokens[1])); + bool ok = false; + const double tmin = PStringUtils::ToDouble(tokens[1], &ok); + if (ok) + param.fTmin.push_back(tmin); else error = true; // handle t_max - if (PStringUtils::IsFloat(tokens[2])) - param.fTmax.push_back(PStringUtils::ToDouble(tokens[2])); + const double tmax = PStringUtils::ToDouble(tokens[2], &ok); + if (ok) + param.fTmax.push_back(tmax); else error = true; if (tokens.size() == 5) { // y-axis interval given as well // handle y_min - if (PStringUtils::IsFloat(tokens[3])) - param.fYmin.push_back(PStringUtils::ToDouble(tokens[3])); + const double ymin = PStringUtils::ToDouble(tokens[3], &ok); + if (ok) + param.fYmin.push_back(ymin); else error = true; // handle y_max - if (PStringUtils::IsFloat(tokens[4])) - param.fYmax.push_back(PStringUtils::ToDouble(tokens[4])); + const double ymax = PStringUtils::ToDouble(tokens[4], &ok); + if (ok) + param.fYmax.push_back(ymax); else error = true; } @@ -4681,14 +4676,17 @@ Bool_t PMsrHandler::HandlePlotEntry(PMsrLines &lines) for (UInt_t i=0; i(fParam.size()) < no) { - error = true; - } else { - // keep the parameter number in case parX was used - param.fRRFPhaseParamNo = no; - // get parameter value - param.fRRFPhase = fParam[no-1].fValue; - } + bool ok = false; + const double rrfPhase = PStringUtils::ToDouble(tokens[1], &ok); + if (ok) { + param.fRRFPhase = rrfPhase; + } else if (PStringUtils::BeginsWithNoCase(tokens[1], "par")) { // parameter value + Int_t no = 0; + if (FilterNumber(tokens[1].c_str(), "par", 0, no)) { + // check that the parameter is in range + if (static_cast(fParam.size()) < no) { + error = true; + } else { + // keep the parameter number in case parX was used + param.fRRFPhaseParamNo = no; + // get parameter value + param.fRRFPhase = fParam[no-1].fValue; } - } else { - error = true; } + } else { + error = true; } } } else if (iter1->fLine.Contains("rrf_packing", TString::kIgnoreCase)) { diff --git a/src/classes/PStringUtils.cpp b/src/classes/PStringUtils.cpp index 59c05cb88..45eaf89a7 100644 --- a/src/classes/PStringUtils.cpp +++ b/src/classes/PStringUtils.cpp @@ -28,6 +28,7 @@ ***************************************************************************/ #include +#include #include #include @@ -161,12 +162,29 @@ int PStringUtils::ToInt(const std::string &str, bool *ok) *

Converts the leading part of the string to a double, mirroring * TString::Atof(). Returns 0.0 if no conversion is possible. * + *

Like ToInt(), conversion errors can be reported through the optional + * \a ok out-parameter: it is set to true when a value was parsed and to + * false otherwise (no number present, or the value is out of range). This + * lets callers distinguish a legitimate 0.0 from a failed conversion. + * strtod() (rather than std::from_chars) is used so that the accepted input + * set stays identical to TString::Atof() (leading whitespace is skipped, a + * leading '+' is honoured, trailing characters are ignored). A null \a ok + * preserves the historic fire-and-forget behaviour. + * * \param str string to be converted - * \return converted double value + * \param ok optional out-parameter signalling conversion success + * \return converted double value (0.0 on error) */ -double PStringUtils::ToDouble(const std::string &str) +double PStringUtils::ToDouble(const std::string &str, bool *ok) { - return std::strtod(str.c_str(), nullptr); + const char *begin = str.c_str(); + char *end = nullptr; + errno = 0; + const double value = std::strtod(begin, &end); + if (ok != nullptr) + *ok = (end != begin) && (errno != ERANGE); + + return value; } //-------------------------------------------------------------------------- diff --git a/src/include/PStringUtils.h b/src/include/PStringUtils.h index 3cc086c5a..c28aadc65 100644 --- a/src/include/PStringUtils.h +++ b/src/include/PStringUtils.h @@ -104,10 +104,15 @@ class PStringUtils *

Converts the leading part of the string to a double. * Mirrors TString::Atof(). Returns 0.0 if no conversion is possible. * + *

If \a ok is non-null it is set to true when a value was parsed and + * to false on error (no number, or value out of range), allowing callers + * to distinguish a legitimate 0.0 from a failed conversion. + * * @param str string to be converted - * @return converted double value + * @param ok optional out-parameter signalling conversion success + * @return converted double value (0.0 on error) */ - static double ToDouble(const std::string &str); + static double ToDouble(const std::string &str, bool *ok = nullptr); /** *

Case-insensitive full-string equality.