PStringUtils::ToDouble: signal conversion errors like ToInt
ToDouble() had the same shortcoming as ToInt(): wrapping strtod() with a nullptr endptr made a failed conversion indistinguishable from a legitimate 0.0. Add an optional `bool *ok` out-parameter that reports success. strtod() (with endptr + errno) is kept instead of std::from_chars so the accepted input set stays identical to TString::Atof() (leading whitespace skipped, leading '+' honoured, trailing characters ignored); ok is set false on a non-numeric string or an ERANGE overflow. The parameter defaults to nullptr, so existing call sites keep compiling unchanged. Convert the IsFloat-guarded ToDouble call sites in PMsrHandler to the single-parse ToDouble(token, &ok) form (replacing the IsFloat() guard + separate ToDouble() that parsed every token twice). All downstream >=0 / <=0 / range checks are preserved, and push_back sites only append on success so no spurious 0.0 is stored on error. Number-vs-keyword discriminators (pos.error/boundary "none", rrf_phase/fourier-phase parX) are restructured so the keyword branch is taken when ok is false. As a side effect this fixes a latent gap in the GLOBAL rrf_freq handler, where a non-numeric frequency previously slipped through with a stale value instead of raising an error. The IsFloat-guarded ToInt fit-range offsets (fgb/lgb) are intentionally left untouched, as there the guard type differs from the conversion. All 85 integration tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+123
-120
@@ -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<tokens.size(); i++) {
|
||||
if (PStringUtils::IsFloat(tokens[i])) {
|
||||
dval = PStringUtils::ToDouble(tokens[i]);
|
||||
if (dval >= 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<tokens.size(); i++) {
|
||||
if (PStringUtils::IsFloat(tokens[i])) {
|
||||
dval = PStringUtils::ToDouble(tokens[i]);
|
||||
if (dval >= 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 <start> <end>, where <start>, <end> 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<tokens.size(); i++) {
|
||||
if (PStringUtils::IsFloat(tokens[i]))
|
||||
param.SetBkgFix(PStringUtils::ToDouble(tokens[i]), i-1);
|
||||
bool ok = false;
|
||||
const double bkgFix = PStringUtils::ToDouble(tokens[i], &ok);
|
||||
if (ok)
|
||||
param.SetBkgFix(bkgFix, i-1);
|
||||
else
|
||||
error = true;
|
||||
}
|
||||
@@ -3696,15 +3689,12 @@ Bool_t PMsrHandler::HandleRunEntry(PMsrLines &lines)
|
||||
error = true;
|
||||
} else {
|
||||
for (UInt_t i=1; i<tokens.size(); i++) {
|
||||
if (PStringUtils::IsFloat(tokens[i])) {
|
||||
dval = PStringUtils::ToDouble(tokens[i]);
|
||||
if (dval >= 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<tokens.size(); i++) {
|
||||
if (PStringUtils::IsFloat(tokens[i])) {
|
||||
dval = PStringUtils::ToDouble(tokens[i]);
|
||||
if (dval >= 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 <start> <end>, where <start>, <end> 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;
|
||||
}
|
||||
@@ -4016,8 +4005,10 @@ Bool_t PMsrHandler::ParseFourierPhaseValueVector(PMsrFourierStructure &fourier,
|
||||
|
||||
// convert all acceptable tokens
|
||||
for (UInt_t i=1; i<tok.size(); i++) {
|
||||
if (PStringUtils::IsFloat(tok[i])) {
|
||||
fourier.fPhase.push_back(PStringUtils::ToDouble(tok[i]));
|
||||
bool ok = false;
|
||||
const double phase = PStringUtils::ToDouble(tok[i], &ok);
|
||||
if (ok) {
|
||||
fourier.fPhase.push_back(phase);
|
||||
} else {
|
||||
result = false;
|
||||
if (i>1) { // make sure that no 'phase val, parX' mixture is present
|
||||
@@ -4439,9 +4430,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;
|
||||
}
|
||||
@@ -4472,11 +4463,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:
|
||||
@@ -4639,28 +4629,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;
|
||||
}
|
||||
@@ -4680,14 +4675,17 @@ Bool_t PMsrHandler::HandlePlotEntry(PMsrLines &lines)
|
||||
for (UInt_t i=0; i<param.fRuns.size(); i++) {
|
||||
|
||||
// handle t_min
|
||||
if (PStringUtils::IsFloat(tokens[2*i+1]))
|
||||
param.fTmin.push_back(PStringUtils::ToDouble(tokens[2*i+1]));
|
||||
bool ok = false;
|
||||
const double tmin = PStringUtils::ToDouble(tokens[2*i+1], &ok);
|
||||
if (ok)
|
||||
param.fTmin.push_back(tmin);
|
||||
else
|
||||
error = true;
|
||||
|
||||
// handle t_max
|
||||
if (PStringUtils::IsFloat(tokens[2*i+2]))
|
||||
param.fTmax.push_back(PStringUtils::ToDouble(tokens[2*i+2]));
|
||||
const double tmax = PStringUtils::ToDouble(tokens[2*i+2], &ok);
|
||||
if (ok)
|
||||
param.fTmax.push_back(tmax);
|
||||
else
|
||||
error = true;
|
||||
}
|
||||
@@ -4696,14 +4694,17 @@ Bool_t PMsrHandler::HandlePlotEntry(PMsrLines &lines)
|
||||
if (tokens.size() == 2*param.fRuns.size() + 3) {
|
||||
|
||||
// handle y_min
|
||||
if (PStringUtils::IsFloat(tokens[2*param.fRuns.size()+1]))
|
||||
param.fYmin.push_back(PStringUtils::ToDouble(tokens[2*param.fRuns.size()+1]));
|
||||
bool ok = false;
|
||||
const double ymin = PStringUtils::ToDouble(tokens[2*param.fRuns.size()+1], &ok);
|
||||
if (ok)
|
||||
param.fYmin.push_back(ymin);
|
||||
else
|
||||
error = true;
|
||||
|
||||
// handle y_max
|
||||
if (PStringUtils::IsFloat(tokens[2*param.fRuns.size()+2]))
|
||||
param.fYmax.push_back(PStringUtils::ToDouble(tokens[2*param.fRuns.size()+2]));
|
||||
const double ymax = PStringUtils::ToDouble(tokens[2*param.fRuns.size()+2], &ok);
|
||||
if (ok)
|
||||
param.fYmax.push_back(ymax);
|
||||
else
|
||||
error = true;
|
||||
}
|
||||
@@ -4716,14 +4717,17 @@ Bool_t PMsrHandler::HandlePlotEntry(PMsrLines &lines)
|
||||
|
||||
if (tokens.size() == 3) { // i.e. use_fit_ranges ymin ymax
|
||||
// handle y_min
|
||||
if (PStringUtils::IsFloat(tokens[1]))
|
||||
param.fYmin.push_back(PStringUtils::ToDouble(tokens[1]));
|
||||
bool ok = false;
|
||||
const double ymin = PStringUtils::ToDouble(tokens[1], &ok);
|
||||
if (ok)
|
||||
param.fYmin.push_back(ymin);
|
||||
else
|
||||
error = true;
|
||||
|
||||
// handle y_max
|
||||
if (PStringUtils::IsFloat(tokens[2]))
|
||||
param.fYmax.push_back(PStringUtils::ToDouble(tokens[2]));
|
||||
const double ymax = PStringUtils::ToDouble(tokens[2], &ok);
|
||||
if (ok)
|
||||
param.fYmax.push_back(ymax);
|
||||
else
|
||||
error = true;
|
||||
}
|
||||
@@ -4760,11 +4764,10 @@ Bool_t PMsrHandler::HandlePlotEntry(PMsrLines &lines)
|
||||
error = true;
|
||||
} else {
|
||||
// get rrf frequency
|
||||
if (PStringUtils::IsFloat(tokens[1])) {
|
||||
param.fRRFFreq = PStringUtils::ToDouble(tokens[1]);
|
||||
} else {
|
||||
bool ok = false;
|
||||
param.fRRFFreq = PStringUtils::ToDouble(tokens[1], &ok);
|
||||
if (!ok)
|
||||
error = true;
|
||||
}
|
||||
// get unit
|
||||
if (PStringUtils::ContainsNoCase(tokens[2], "kHz"))
|
||||
param.fRRFUnit = RRF_UNIT_kHz;
|
||||
@@ -4787,25 +4790,25 @@ Bool_t PMsrHandler::HandlePlotEntry(PMsrLines &lines)
|
||||
error = true;
|
||||
} else {
|
||||
// get rrf phase
|
||||
if (PStringUtils::IsFloat(tokens[1])) {
|
||||
param.fRRFPhase = PStringUtils::ToDouble(tokens[1]);
|
||||
} 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<Int_t>(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<Int_t>(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)) {
|
||||
|
||||
Reference in New Issue
Block a user