AnalysisSettings.cxx
1 #include "AnalysisSettings.h"
2 #include <fstream>
3 #include "TObjString.h"
4 #include "TString.h"
5 #include "TObjArray.h"
6 #include "TRegexp.h"
7 #include "TClass.h"
8 #include "TDataMember.h"
9 #include "TMethodCall.h"
10 #include <cstdlib>
11 #include <stdexcept>
12 
13 
14 const char* default_filename = "AcclaimSettings.conf";
15 
16 Acclaim::AnalysisSettings::AnalysisSettings(const char* fName) : fileName(fName) {
17 
18  parseSettingsFile();
19 }
20 
21 
22 void Acclaim::AnalysisSettings::write(TFile* f) const{
23 
24  if(!f){
25  std::cerr << "Error in " << __PRETTY_FUNCTION__
26  << ", got NULL pointer to TFile. Cannot save AnalysisSettings." << std::endl;
27  return;
28  }
29 
30  if(!f->IsWritable()){
31  std::cerr << "Error in " << __PRETTY_FUNCTION__ << ", TFile " << f->GetName()
32  << " is not writable. Cannot save AnalysisSettings." << std::endl;
33  return;
34  }
35 
36  if(!f->IsOpen()){
37  std::cerr << "Error in " << __PRETTY_FUNCTION__ << ", TFile " << f->GetName()
38  << " is not open. Cannot save AnalysisSettings." << std::endl;
39  return;
40  }
41 
42  f->cd();
43 
44  TObjArray* tokens = fileName.Tokenize("/");
45  TString shortFileName = ((TObjString*) tokens->Last())->GetString();
46 
47  TNamed* tn = new TNamed(shortFileName, parsedFileCopy);
48  tn->Write();
49  delete tn;
50 
51 }
52 
53 
54 void Acclaim::AnalysisSettings::print() const{
55  // For debugging
56  std::cout << __PRETTY_FUNCTION__ << std::endl;
57 
58  SectionMap_t::const_iterator sit = sectionMap.begin();
59  for(; sit!= sectionMap.end(); ++sit){
60  VariableMap_t* vm = sit->second;
61  std::cout << "[" << sit->first << "]" << std::endl;
62 
63  VariableMap_t::iterator vit = vm->begin();
64  for(; vit!=vm->end(); ++vit){
65  std::cout << vit->first << "=" << vit->second << std::endl;
66  }
67 
68  std::cout << std::endl;
69  }
70 }
71 
72 
73 
74 
75 void Acclaim::AnalysisSettings::apply(TObject* obj) const {
76 
77  if(obj==NULL){
78  std::cerr << "Warning in " << __PRETTY_FUNCTION__ << ", got NULL TObject pointer. Doing nothing." << std::endl;
79  return;
80  }
81 
82  TString className = obj->ClassName();
83 
84  SectionMap_t::const_iterator sit = sectionMap.find(className);
85  if(sit==sectionMap.end()){
86  std::cerr << "Fatal error in " << __PRETTY_FUNCTION__ << ", found no settings for " << className
87  << "." << std::endl;
88  throw std::runtime_error("Missing settings");
89  }
90 
91  VariableMap_t* varMap = sit->second;
92  TClass* cl = obj->IsA();
93 
94  VariableMap_t::iterator vit = varMap->begin();
95  for(; vit!= varMap->end(); ++vit){
96  TDataMember *dm = cl->GetDataMember(vit->first);
97 
98  if(!dm){
99  std::cerr << "Error in " << __PRETTY_FUNCTION__ << ", unable to find data member for "
100  << className << "." << vit->first << "." << std::endl;
101  throw std::runtime_error("Missing data member");
102  }
103  else{
104  TMethodCall *sm = dm->SetterMethod(cl);
105  if(!sm){
106  std::cerr << "Error in " << __PRETTY_FUNCTION__ << ", unable to find setter method for "
107  << className << "." << vit->first << ". Skipping this setting." << std::endl;
108  throw std::runtime_error("Missing Setter function");
109  }
110  else{
111  sm->Execute(obj, vit->second);
112  }
113  }
114  }
115 }
116 
117 
118 
119 Bool_t Acclaim::AnalysisSettings::stringIsKeyValuePair(const TString& commentStrippedLine, TString& key, TString& value) const{
120  key = "";
121  value = "";
122 
123  Bool_t isKeyValuePair = false;
124 
125  TObjArray* tokens = commentStrippedLine.Tokenize("=");
126  int nTokens = tokens->GetEntries();
127 
128  // If there are two tokens, then there was one delimeter so we're good
129  if(nTokens == 2){
130  key = ((TObjString*) tokens->At(0))->GetString();
131  key.Strip().String(); // should strip trailing whitespace
132  value = ((TObjString*) tokens->At(1))->GetString();
133  value.Strip().String(); // should strip trailing whitespace
134  isKeyValuePair = true;
135  }
136  delete tokens;
137  return isKeyValuePair;
138 }
139 
140 
141 Bool_t Acclaim::AnalysisSettings::stringIsAlphaNumeric(const TString& str) const{
142  // really this should be "stringIsNotWhiteSpace", but that's hard to figure out how to do
143  TRegexp reggie("[a-zA-Z0-9]");
144  Ssiz_t len = str.Length();
145 
146  Bool_t isAlphaNumeric = reggie.Index(str, &len) != -1;
147  return isAlphaNumeric;
148 }
149 
150 
151 
152 Bool_t Acclaim::AnalysisSettings::stringIsSection(const TString& commentStrippedLine, TString& secName) const{
153 
154  secName = "";
155  Bool_t isSection = false;
156  Ssiz_t len = commentStrippedLine.Length();
157 
158  if(len > 0){
159  TString firstChar = TString(commentStrippedLine(0,1));
160  if(firstChar.Contains("[") && commentStrippedLine.Contains("]")){
161 
162  TObjArray* tokens = TString(commentStrippedLine(1, len)).Tokenize("]");
163  int nTokens = tokens->GetEntries();
164  TString secNameMaybe = ((TObjString*) tokens->At(0))->GetString();
165 
166  if(nTokens<=2){
167  Bool_t trailingGood = true;
168  if(nTokens==2){
169  TString trailing = ((TObjString*) tokens->At(1))->GetString();
170  if(stringIsAlphaNumeric(trailing)){
171  trailingGood = false;
172  }
173  }
174  if(trailingGood){
175  secName = secNameMaybe;
176  isSection = true;
177  }
178  }
179  delete tokens;
180  }
181  }
182  return isSection;
183 }
184 
185 
186 Acclaim::AnalysisSettings::VariableMap_t* Acclaim::AnalysisSettings::handleSection(const TString& section){
187 
188  // std::cout << "I found a section: " << section << std::endl;
189 
190  SectionMap_t::iterator it = sectionMap.find(section);
191  VariableMap_t* variableMap = NULL;
192  if(it!=sectionMap.end()){
193  variableMap = it->second;
194  }
195  else{
196  variableMap = new VariableMap_t();
197  sectionMap[section] = variableMap;
198  }
199  return variableMap;
200 }
201 
202 
203 void Acclaim::AnalysisSettings::handleKeyValue(VariableMap_t* variableMap, const TString& key, const TString& value){
204 
205  if(variableMap==NULL){
206  std::cerr << "Error in " << __PRETTY_FUNCTION__ << " found variable " << key << " with value " << value << " but has no section! Variables must have a section. Skipping this entry." << std::endl;
207  return;
208  }
209 
210  VariableMap_t::iterator it = variableMap->find(key);
211  if(it!=variableMap->end()){
212  // something funky going on here...
213  TString sectionName;
214  SectionMap_t::iterator it2 = sectionMap.begin();
215  for(; it2 != sectionMap.end(); ++it2){
216  if(variableMap==it2->second){
217  sectionName = it2->first;
218  break;
219  }
220  }
221  std::cerr << "Warning in " << __PRETTY_FUNCTION__ << ", while parsing section " << sectionName \
222  << "I found a duplicate entry for " << key << std::endl;
223  std::cerr << "The original value is " << it->second << ", the duplicated value is " << value << std::endl;
224  std::cerr << "Ignoring the second value." << std::endl;
225  }
226  else{
227  (*variableMap)[key] = value;
228  }
229 }
230 
231 
232 Bool_t Acclaim::AnalysisSettings::tryFile(const char* fName){
233  Bool_t openedFile = false;
234 
235  TString n(fName);
236  if(n.Length() > 0 && n[n.Length()-1] == '/'){
237  std::cerr << "Info in " << __PRETTY_FUNCTION__ << ", interpreting forward slash terminated input as directory, appending " << default_filename << std::endl;
238  n += TString::Format("%s", default_filename);
239  }
240 
241  std::cout << "Info in " << __PRETTY_FUNCTION__ << ", trying "<< n.Data() << std::endl;
242 
243  std::ifstream a(n.Data());
244  if(a.is_open()){
245  openedFile = true;
246  fileName = n.Data();
247  }
248  return openedFile;
249 }
250 
251 void Acclaim::AnalysisSettings::findFile(){
252 
253  if(fileName.Length()!=0){
254  // try to open current file name
255  if(tryFile(fileName)){
256  return;
257  }
258  }
259 
260  // that didn't work so try a couple more things ...
261 
262  // default file name in the present working directory
263  const char* fName = default_filename;
264  if(tryFile(fName)){
265  fileName = TString(fName);
266  return;
267  }
268 
269  const char* anitaUtilInstallDir = getenv("ANITA_UTIL_INSTALL_DIR");
270  if(!anitaUtilInstallDir){
271  // you've got some major issues...
272  std::cerr << "Error in " << __PRETTY_FUNCTION__ << ", ANITA_UTIL_INSTALL_DIR not set." << std::endl;
273  }
274 
275  TString fName2 = TString::Format("%s/share/Acclaim/%s", anitaUtilInstallDir, default_filename);
276  if(tryFile(fName2.Data())){
277  fileName = TString(fName2);
278  return;
279  }
280 
281  // if you get here, then there's some problems...
282  std::cerr << "Error in " << __PRETTY_FUNCTION__ << ", couldn't find any settings files! Giving up." << std::endl;
283  exit(1);
284 }
285 
286 
287 
288 void Acclaim::AnalysisSettings::parseSettingsFile(){
289 
290  findFile();
291  std::cout << "After Acclaim::AnalysisSettings::findFile(), fileName = " << fileName << std::endl;
292 
293  std::ifstream settingsFile(fileName);
294 
295  if(!settingsFile.is_open()){
296  // if you get here, then there's some problems...
297  std::cerr << "Error in " << __PRETTY_FUNCTION__ << ", couldn't find settings file " << fileName
298  << ". Giving up." << std::endl;
299  throw "Acclaim::AnalysisSettings Error";
300  }
301  else{
302  int lineNum = 1;
303 
304  VariableMap_t* varMap = NULL;
305 
306  while(!settingsFile.eof()){
307 
308  std::string thisLine;
309  std::getline(settingsFile, thisLine);
310 
311  parsedFileCopy.Append(thisLine);
312  parsedFileCopy.Append("\n");
313 
314  // First cut out the comment, which is all characters after the first #, including the #
315  std::size_t found = thisLine.find("#");
316 
317  // Here we switch to TString because of its lovely tokenization methods
318  TString thisLineCommentsRemoved(thisLine.substr(0, found));
319 
320  TString section;
321  Bool_t isSection = stringIsSection(thisLineCommentsRemoved, section);
322 
323  if(isSection){
324  varMap = handleSection(section);
325  }
326  else{
327  TString key, value;
328  Bool_t isKeyValuePair = stringIsKeyValuePair(thisLineCommentsRemoved, key, value);
329  if(isKeyValuePair){
330  handleKeyValue(varMap, key, value);
331  }
332  else{
333  Bool_t isAlphaNumeric = stringIsAlphaNumeric(thisLineCommentsRemoved);
334  if(isAlphaNumeric){
335  std::cerr << "Warning in " << __PRETTY_FUNCTION__
336  << ". I couldn't parse line " << lineNum
337  << " in " << fileName << ". It said: " << std::endl;
338  std::cerr << thisLine << std::endl;
339  }
340  else{
341  // then I think it was whitespace...
342  }
343  }
344  }
345 
346  lineNum++;
347  }
348 
349  }
350 }
351 
352 
353 
354 
372 Bool_t Acclaim::AnalysisSettings::getSetting(const char* settingName, TString& settingVal) const{
373 
374  TString setting = settingName;
375 
376  for(SectionMap_t::const_iterator it=sectionMap.begin(); it!= sectionMap.end(); ++it){
377 
378  int secLen = it->first.Length();
379  if(secLen <= setting.Length() && setting(0, secLen)==it->first){
380 
381  std::cout << "Setting " << setting << ", found a match with section " << it->first << std::endl;
382 
383  // string the class identifier
384  setting.Replace(0, secLen, "");
385 
386  // let's allow :: or -> or . as member identifiers
387  Bool_t goodMemberIdentifier = false;
388 
389  if(setting(0, 2)=="::" || setting(0, 2) == "->"){
390  setting.Replace(0, 2, "");
391  goodMemberIdentifier = true;
392  }
393  else if(setting(0, 1)=="."){
394  setting.Replace(0, 1, "");
395  goodMemberIdentifier = true;
396  }
397  std::cout << "Now reduced to " << setting << std::endl;
398 
399  if(goodMemberIdentifier){
400 
401  const VariableMap_t* vars = it->second;
402 
403  VariableMap_t::const_iterator it2 = vars->find(setting);
404  if(it2 != vars->end()){ // found it!
405  settingVal = it2->second;
406  return true;
407  }
408  else{
409  std::cerr << "Error in " << __PRETTY_FUNCTION__ << ", couldn't find variable "
410  << setting << " in config file section " << it->first << std::endl;
411  return false;
412  }
413  }
414  else{
415  std::cerr << "Error in " << __PRETTY_FUNCTION__ << ", malformed member identifer! Acceptable formats are:" << std::endl;
416  std::cerr << " Acclaim::Class::member" << std::endl;
417  std::cerr << " Acclaim::Class->member" << std::endl;
418  std::cerr << " Acclaim::Class.member" << std::endl;
419  return false;
420  }
421  }
422  }
423 
424  std::cerr << "Error in " << __PRETTY_FUNCTION__ << ", unable to find a class to match input " << setting << std::endl;
425 
426  return false;
427 }
428 
429 
430 
431 
441 Bool_t Acclaim::AnalysisSettings::getSetting(const char* settingName, Bool_t& settingVal) const{
442  Int_t boolAsInt;
443  Bool_t foundSetting = getSetting(settingName, boolAsInt);
444  if(foundSetting){
445  settingVal = settingVal = boolAsInt;
446  }
447  return foundSetting;
448 }
449 
450 
460 Bool_t Acclaim::AnalysisSettings::getSetting(const char* settingName, Int_t& settingVal) const{
461  TString valAsString;
462  Bool_t foundSetting = getSetting(settingName, valAsString);
463  if(foundSetting){
464  settingVal = atoi(valAsString.Data());
465  }
466  return foundSetting;
467 }
468 
478 Bool_t Acclaim::AnalysisSettings::getSetting(const char* settingName, Double_t& settingVal) const{
479  TString valAsString;
480  Bool_t foundSetting = getSetting(settingName, valAsString);
481  if(foundSetting){
482  settingVal = atof(valAsString.Data());
483  }
484  return foundSetting;
485 }
Bool_t getSetting(const char *settingName, Bool_t &settingVal) const