evtgen is hosted by Hepforge, IPPP Durham
EvtGen  2.0.0
Monte Carlo generator of particle decays, in particular the weak decays of heavy flavour particles such as B mesons.
EvtParserXml.cpp
Go to the documentation of this file.
1 
2 /***********************************************************************
3 * Copyright 1998-2020 CERN for the benefit of the EvtGen authors *
4 * *
5 * This file is part of EvtGen. *
6 * *
7 * EvtGen is free software: you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation, either version 3 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * EvtGen is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with EvtGen. If not, see <https://www.gnu.org/licenses/>. *
19 ***********************************************************************/
20 
22 
23 #include "EvtGenBase/EvtPatches.hh"
24 #include "EvtGenBase/EvtReport.hh"
25 
26 #include <fstream>
27 #include <sstream>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <vector>
31 using namespace std;
32 
33 bool EvtParserXml::open( std::string filename )
34 {
35  if ( !expandEnvVars( filename ) ) {
36  EvtGenReport( EVTGEN_ERROR, "EvtGen" )
37  << "Error while expanding environment variables in file name '"
38  << filename.c_str() << "'" << endl;
39  return false;
40  }
41 
42  _fin.open( filename.c_str() );
43  if ( !_fin ) {
44  EvtGenReport( EVTGEN_ERROR, "EvtGen" )
45  << "Could not open file '" << filename.c_str() << "'" << endl;
46  return false;
47  }
48 
49  return true;
50 }
51 
53 {
54  _fin.close();
55  return true;
56 }
57 
59 {
60  if ( !processTagTree() ) {
61  EvtGenReport( EVTGEN_ERROR, "EvtGen" )
62  << "Unexpected end tag " << _tagTitle << " found near line "
63  << _lineNo << endl;
64  EvtGenReport( EVTGEN_ERROR, "EvtGen" )
65  << "Will terminate execution!" << endl;
66  return false;
67  } //first process the previous tag to find out where we are in the tag tree
68 
69  while ( _line.find( "<" ) ==
70  std::string::npos ) { //add lines until we find start of a tag
71  std::string addLine;
72  if ( !std::getline( _fin, addLine ) )
73  return false;
74  _lineNo++;
75  _line += " ";
76  _line += addLine;
77  }
78 
79  unsigned int startTag;
80  unsigned int endTag;
81  unsigned int endTagTitle;
82 
83  startTag = _line.find( "<" );
84 
85  if ( _line[startTag + 1] ==
86  '?' ) { //XML header tag - ignore then read the next tag
87  while ( _line.find( "?>", startTag ) == std::string::npos ) {
88  std::string addLine;
89  if ( !std::getline( _fin, addLine ) )
90  return false;
91  _lineNo++;
92  _line += " ";
93  _line += addLine;
94  }
95  endTag = _line.find( "?>", startTag );
96  _line = _line.substr( endTag + 2 );
97  return readNextTag();
98  } else if ( _line[startTag + 1] ==
99  '!' ) { //XML comment tag - ignore then read the next tag
100  while ( _line.find( "-->", startTag ) == std::string::npos ) {
101  std::string addLine;
102  if ( !std::getline( _fin, addLine ) )
103  return false;
104  _lineNo++;
105  _line += " ";
106  _line += addLine;
107  }
108  endTag = _line.find( "-->", startTag );
109  _line = _line.substr( endTag + 3 );
110  _tagTitle = "";
111  _tag = "";
112  return readNextTag();
113  } else { //parsable
114 
115  while ( _line.find( ">", startTag ) ==
116  std::string::npos ) { //find end of a tag
117  std::string addLine;
118  if ( !std::getline( _fin, addLine ) )
119  return false;
120  _lineNo++;
121  _line += " ";
122  _line += addLine;
123  }
124  endTag = _line.find( ">", startTag );
125  _inLineTag = false;
126  if ( _line.find( "/>", startTag ) < endTag ) {
127  endTag--;
128  _inLineTag = true;
129  }
130 
131  if ( _line.find( " ", startTag ) != std::string::npos &&
132  _line.find( " ", startTag ) <
133  endTag ) { //find end of the first word in the tag
134  endTagTitle = _line.find( " ", startTag );
135  } else {
136  endTagTitle = endTag;
137  }
138 
139  _tagTitle = _line.substr( startTag + 1, endTagTitle - startTag - 1 );
140  _tag = _line.substr( startTag + 1, endTag - startTag - 1 );
141 
142  //now we have the tag lets remove it from the line
143  if ( _inLineTag ) {
144  _line = _line.substr( endTag + 2 );
145  } else {
146  _line = _line.substr( endTag + 1 );
147  }
148  return true;
149  }
150 }
151 
153 {
154  if ( _tagTree.empty() )
155  return "";
156  else
157  return _tagTree.back();
158 }
159 
160 std::string EvtParserXml::readAttribute( std::string attribute,
161  std::string defaultValue )
162 {
163  std::string whitespace = " \t\n\v\f\r";
164  for ( unsigned int i = 0; i < whitespace.size(); i++ ) {
165  //find any whitespace followed by the attribute name followed by an '='
166  std::string attName = whitespace[i] + attribute + "=";
167  if ( _tag.find( attName ) != std::string::npos ) {
168  int startAttri = _tag.find( attName );
169  int startQuote = _tag.find( "\"", startAttri + 1 );
170  int endQuote = _tag.find( "\"", startQuote + 1 );
171  return _tag.substr( startQuote + 1, endQuote - startQuote - 1 );
172  }
173  }
174  return defaultValue;
175 }
176 
177 bool EvtParserXml::readAttributeBool( std::string attribute, bool defaultValue )
178 {
179  std::string valStr = readAttribute( attribute );
180  if ( !defaultValue )
181  return ( valStr == "true" || valStr == "1" || valStr == "on" ||
182  valStr == "yes" );
183  else
184  return ( valStr != "false" && valStr != "0" && valStr != "off" &&
185  valStr != "no" );
186 }
187 
188 int EvtParserXml::readAttributeInt( std::string attribute, int defaultValue )
189 {
190  std::string valStr = readAttribute( attribute );
191  if ( valStr == "" )
192  return defaultValue;
193  std::istringstream valStream( valStr );
194  int retVal;
195  valStream >> retVal;
196  return retVal;
197 }
198 
199 double EvtParserXml::readAttributeDouble( std::string attribute,
200  double defaultValue )
201 {
202  std::string valStr = readAttribute( attribute );
203  if ( valStr == "" )
204  return defaultValue;
205  std::istringstream valStream( valStr );
206  double retVal;
207  valStream >> retVal;
208  return retVal;
209 }
210 
212 {
213  if ( _tagTitle == "" )
214  return true;
215  if ( _tagTitle[0] == '/' ) {
216  if ( _tagTitle.substr( 1 ) == _tagTree.back() ) {
217  _tagTree.pop_back();
218  } else {
219  return false;
220  }
221  } else if ( !_inLineTag ) {
222  _tagTree.push_back( _tagTitle );
223  }
224  return true;
225 }
226 
227 bool EvtParserXml::expandEnvVars( std::string& str )
228 {
229  while ( str.find( '$' ) != std::string::npos ) {
230  size_t varStart = str.find( '$' );
231  size_t varNameLength;
232  std::string varName;
233 
234  //if this is the last character then just remove the $
235  if ( varStart == str.length() - 1 ) {
236  str.erase( varStart );
237  return true;
238  }
239 
240  if ( str[varStart + 1] == '{' ) {
241  //deal with environment variables in {}s
242  size_t braceStart = varStart + 1;
243  size_t braceEnd = str.find( '}', braceStart );
244 
245  if ( braceEnd == std::string::npos ) {
246  EvtGenReport( EVTGEN_ERROR, "EvtGen" )
247  << "Incomplete environment variable found in text: " << str
248  << endl;
249  EvtGenReport( EVTGEN_ERROR, "EvtGen" )
250  << "Will terminate execution!" << endl;
251  return false;
252  }
253 
254  varName = str.substr( braceStart + 1, braceEnd - braceStart - 1 );
255  varNameLength = braceEnd - varStart;
256 
257  } else {
258  //deal with everything else
259  varNameLength = 0;
260 
261  while ( varNameLength + varStart + 1 < str.length() &&
262  isAlphaNum( str[varStart + varNameLength + 1] ) ) {
263  ++varNameLength;
264  }
265 
266  varName = str.substr( varStart + 1, varNameLength );
267  }
268 
269  char* envVar = getenv( varName.c_str() );
270 
271  if ( envVar )
272  str.replace( varStart, varNameLength + 1, envVar );
273  else {
274  EvtGenReport( EVTGEN_WARNING, "EvtGen" )
275  << "Undefined environment variable found in text: " << varName
276  << endl;
277  str.replace( varStart, varNameLength + 1, "" );
278  }
279  }
280  return true;
281 }
282 
284 {
285  if ( c >= '0' && c <= '9' )
286  return true;
287  if ( c >= 'A' && c <= 'Z' )
288  return true;
289  if ( c >= 'a' && c <= 'z' )
290  return true;
291  if ( c == '_' )
292  return true;
293  return false;
294 }
std::ostream & EvtGenReport(EvtGenSeverity severity, const char *facility=0)
Definition: EvtReport.cpp:33
bool processTagTree()
double readAttributeDouble(std::string attribute, double defaultValue=-1.)
bool open(std::string filename)
bool readAttributeBool(std::string attribute, bool defaultValue=false)
bool readNextTag()
std::string getParentTagTitle()
int readAttributeInt(std::string attribute, int defaultValue=-1)
bool isAlphaNum(char c)
bool expandEnvVars(std::string &str)
std::string readAttribute(std::string attribute, std::string defaultValue="")