QwAnalysis
QwParameterFile.cc
Go to the documentation of this file.
1 /// @file QwParameterFile.cc
2 
3 #include "QwParameterFile.h"
4 
5 // System headers
6 #include <sstream>
7 #include <climits>
8 #include <algorithm>
9 #include <cctype>
10 
11 #ifndef BOOST_VERSION
12 #include "boost/version.hpp"
13 #endif
14 
15 // Qweak headers
16 #include "QwLog.h"
17 
18 // Initialize the list of search paths
19 std::vector<bfs::path> QwParameterFile::fSearchPaths;
20 
21 // Set current run number to zero
23 
24 // Set default comment, whitespace, section, module characters
25 const std::string QwParameterFile::kDefaultCommentChars = "#!;";
26 const std::string QwParameterFile::kDefaultWhitespaceChars = " \t\r";
27 const std::string QwParameterFile::kDefaultTokenSepChars = ", \t";
28 const std::string QwParameterFile::kDefaultSectionChars = "[]";
29 const std::string QwParameterFile::kDefaultModuleChars = "<>";
30 
31 /**
32  * Append a directory to the list of search paths
33  * @param searchdir Directory to be added
34  */
35 void QwParameterFile::AppendToSearchPath(const TString& searchdir)
36 {
37  bfs::path tmppath(searchdir.Data());
38  if( bfs::exists(tmppath) && bfs::is_directory(tmppath)) {
39  std::cout << tmppath.string()
40  << " is a directory; adding it to the search path\n";
41  fSearchPaths.push_back(tmppath);
42  } else if( bfs::exists(tmppath)) {
43  std::cout<<tmppath.string()<<" exists but is not a directory.\n";
44  } else {
45  std::cout<<tmppath.string()<<" doesn't exist.\n";
46  }
47 }
48 
49 /**
50  * Convert a string number value to an unsigned integer
51  * @param varvalue String with decimal or hexadecimal number
52  * @return Unsigned integer
53  */
54 UInt_t QwParameterFile::GetUInt(const TString& varvalue)
55 {
56  UInt_t value = 0;
57  if (varvalue.IsDigit()){
58  value = varvalue.Atoi();
59  } else if (varvalue.BeginsWith("0x") || varvalue.BeginsWith("0X")
60  || varvalue.BeginsWith("x") || varvalue.BeginsWith("X")
61  || varvalue.IsHex()){
62  //any whitespace ?
63  Int_t end = varvalue.Index(" ");
64  std::istringstream stream1;
65  if (end == -1){
66  stream1.str(varvalue.Data());
67  } else {
68  //make temporary string, removing whitespace
69  Int_t start = 0;
70  TString tmp;
71  //loop over all whitespace
72  while (end > -1) {
73  tmp += varvalue(start, end-start);
74  start = end+1;
75  end = varvalue.Index(" ", start);
76  }
77  //finally add part from last whitespace to end of string
78  end = varvalue.Length();
79  tmp += varvalue(start, end-start);
80  stream1.str(tmp.Data());
81  }
82  stream1 >> std::hex >> value;
83  }
84  return value;
85 }
86 
87 
88 /**
89  * Constructor
90  * @param stream String stream for reading
91  */
92 QwParameterFile::QwParameterFile(const std::stringstream& stream)
93 : fCommentChars(kDefaultCommentChars),
94  fWhitespaceChars(kDefaultWhitespaceChars),
95  fTokenSepChars(kDefaultTokenSepChars),
96  fSectionChars(kDefaultSectionChars),
97  fModuleChars(kDefaultModuleChars),
98  fFilename("stream"),
99  fBeGreedy(kFALSE)
100 {
101  fStream << stream.rdbuf();
102 }
103 
104 
105 /**
106  * Constructor
107  * @param name Name of the file to be opened
108  *
109  * If file starts with an explicit slash ('/'), it is assumed to be a full path.
110  */
111 QwParameterFile::QwParameterFile(const std::string& name)
112 : fCommentChars(kDefaultCommentChars),
113  fWhitespaceChars(kDefaultWhitespaceChars),
114  fTokenSepChars(kDefaultTokenSepChars),
115  fSectionChars(kDefaultSectionChars),
116  fModuleChars(kDefaultModuleChars),
117  fFilename(name),
118  fBeGreedy(kFALSE)
119 {
120  // Create a file from the name
121  bfs::path file(name);
122 
123  // Immediately try to open absolute paths and return
124  if (name.find("/") == 0) {
125  if (OpenFile(file) == false) {
126  QwWarning << "Could not open absolute path " << name << ". "
127  << "Parameter file will remain empty." << QwLog::endl;
128  SetEOF();
129  return;
130  }
131 
132  // Print file name of file that was used
133  QwMessage << "Parameter file: "
134  << QwColor(Qw::kGreen) << file.string()
136 
137  // Else, loop through search path and files
138  } else {
139 
140 #if BOOST_VERSION >= 104600
141  // Separate file in stem and extension
142  std::string file_stem = file.stem().string();
143  std::string file_ext = file.extension().string();
144 #elif BOOST_VERSION >= 103600
145  // Separate file in stem and extension
146  std::string file_stem = file.stem();
147  std::string file_ext = file.extension();
148 #else
149  // Separate file in stem and extension
150  std::string file_stem = bfs::basename(file);
151  std::string file_ext = bfs::extension(file);
152 #endif
153 
154  // Find the best match
155  Int_t best_score = 0;
156  bfs::path best_path;
157  for (size_t i = 0; i < fSearchPaths.size(); i++) {
158 
159  bfs::path path;
160  Int_t score = FindFile(fSearchPaths[i], file_stem, file_ext, path);
161  if (score > best_score) {
162  // Found file with better score
163  best_score = score;
164  best_path = path;
165  } else if (score == best_score) {
166  // Found file with identical score
167  QwWarning << "Equally likely parameter files encountered: " << best_path.string()
168  << " and " << path.string() << QwLog::endl;
169  QwMessage << "Analysis will use parameter file: " << best_path.string()
170  << QwLog::endl;
171  }
172  } // end of loop over search paths
173 
174  // File not found
175  if (best_score == 0) {
176  QwError << "Could not find any parameter file with name " << name << ". "
177  << "Parameter file will remain empty." << QwLog::endl;
178  SetEOF();
179  exit(-1);
180  return;
181  }
182 
183  // Found but unable to open
184  if (best_score > 0 && OpenFile(best_path) == false) {
185  QwError << "Could not open parameter file " << best_path.string() << ". "
186  << "Parameter file will remain empty." << QwLog::endl;
187  SetEOF();
188  exit(-1);
189  return;
190  }
191 
192  // Print file name of file that was used
193  QwMessage << "Parameter file: "
194  << QwColor(Qw::kGreen) << best_path.string()
196  }
197 }
198 
199 
200 /**
201  * Open a file at the specified location
202  * @param file Path to file to be opened
203  * @return False if the file could not be opened
204  */
205 bool QwParameterFile::OpenFile(const bfs::path& file)
206 {
207  Bool_t local_debug = false;
208 
209  Bool_t status = false;
210 
211  Bool_t check_whether_path_exists_and_is_a_regular_file = false;
212 
213  // Check whether path exists and is a regular file
214 #if BOOST_VERSION >= 103600
215  check_whether_path_exists_and_is_a_regular_file = bfs::exists(file) && bfs::is_regular_file(file);
216 #elif BOOST_VERSION >= 103400
217  check_whether_path_exists_and_is_a_regular_file = bfs::exists(file) && bfs::is_regular(file);
218 #else
219  check_whether_path_exists_and_is_a_regular_file = bfs::exists(file); /* pray */
220 #endif
221 
222  if (check_whether_path_exists_and_is_a_regular_file) {
223 
224  fBestParamFileNameAndPath = file.string();
225  this->SetParamFilename();
226 
227  // Connect stream (fFile) to file
228  fFile.open(file.string().c_str());
229  if (! fFile.good())
230  QwError << "QwParameterFile::OpenFile Unable to read parameter file "
231  << file.string() << QwLog::endl;
232  // Load into stream
233  fStream << fFile.rdbuf();
234  status = true;
235  if(local_debug) {
236  std::cout << "------before close------------" << std::endl;
237  std::cout << fStream.str() << std::endl;
238  }
239 
240  // fFile.clear();
241  // fFile.close(); // disconnet file
242  // this->Test();
243  } else {
244 
245  // File does not exist or is not a regular file
246  QwError << "QwParameterFile::OpenFile Unable to open parameter file "
247  << file.string() << QwLog::endl;
248  status = false;
249  }
250  if(local_debug) {
251  std::cout << "-------after close ----------" << std::endl;
252  std::cout << fStream.str() << std::endl;
253  }
254 
255  return status;
256 }
257 
258 
259 /**
260  * Find the file in a directory with highest-scoring run label
261  * @param directory Directory to search in
262  * @param file_stem File name stem to search for
263  * @param file_ext File name extensions to search for
264  * @param best_path (returns) Path to the highest-scoring file
265  * @return Score of file
266  */
268  const bfs::path& directory,
269  const std::string& file_stem,
270  const std::string& file_ext,
271  bfs::path& best_path)
272 {
273  // Return false if the directory does not exist
274  if (! bfs::exists(directory)) return false;
275 
276  // Default score indicates no match found
277  int best_score = -1;
278  int score = -1;
279  // Multiple overlapping open-ended ranges
280  int open_ended_latest_start = 0;
281  int open_ended_range_score = 0;
282 
283  // Loop over all files in the directory
284  // note: default iterator constructor yields past-the-end
285  bfs::directory_iterator end_iterator;
286  for (bfs::directory_iterator file_iterator(directory);
287  file_iterator != end_iterator;
288  file_iterator++) {
289 
290  // Match the stem and extension
291  // note: filename() returns only the file name, not the path
292 #if BOOST_VERSION >= 104600
293  std::string file_name = file_iterator->path().filename().string();
294 #elif BOOST_VERSION >= 103600
295  std::string file_name = file_iterator->filename();
296 #else
297  std::string file_name = file_iterator->leaf();
298 #endif
299  // stem
300  size_t pos_stem = file_name.find(file_stem);
301  if (pos_stem != 0) continue;
302  // extension (reverse find)
303  size_t pos_ext = file_name.rfind(file_ext);
304  if (pos_ext != file_name.length() - file_ext.length()) continue;
305 
306  // Scores (from low to high)
307  const int score_no_run_label = 1;
308  // Open run range:
309  // score increments each time a higher-starting range is found
310  // difference between min and max gives maximum number of open ranges
311  const int score_open_ended_run_range_min = 1000;
312  const int score_open_ended_run_range_max = 9000;
313  // Close run range:
314  // score decremented from max by size of run range, small range -> high score
315  // difference between min and max gives maximum number of runs in closed range
316  const int score_closed_run_range_min = 10000;
317  const int score_closed_run_range_max = 90000;
318  // Single run label will always have maximum score
319  const int score_single_run_label = INT_MAX;
320 
321  // Determine run label length
322  size_t label_length = pos_ext - file_stem.length();
323  // no run label
324  if (label_length == 0) {
325  score = score_no_run_label;
326  } else {
327  // run label starts after dot ('.') and that dot is included in the label length
328  if (file_name.at(pos_stem + file_stem.length()) == '.') {
329  std::string label = file_name.substr(pos_stem + file_stem.length() + 1, label_length - 1);
330  std::pair<int,int> range = ParseIntRange("-",label);
331  int run = fCurrentRunNumber;
332  if ((range.first <= run) && (run <= range.second)) {
333 
334  // run is in single-value range
335  if (range.first == range.second) {
336  score = score_single_run_label;
337 
338  // run is in double-value range
339  } else if (range.second < INT_MAX) {
340  int number_of_runs = abs(range.second - range.first);
341  score = score_closed_run_range_max - number_of_runs;
342  if (score < score_closed_run_range_min) {
343  score = score_closed_run_range_min;
344  QwError << "Too many runs in closed run range for " << file_stem << QwLog::endl;
345  QwWarning << "Range is from " << range.first << " to " << range.second << QwLog::endl;
346  }
347 
348  // run is in open-ended range
349  } else if (range.second == INT_MAX) {
350  // each matching open-ended range
351  if (range.first > open_ended_latest_start) {
352  open_ended_latest_start = range.first;
353  open_ended_range_score++;
354  score = score_open_ended_run_range_min + open_ended_range_score;
355  if (score > score_open_ended_run_range_max) {
356  score = score_open_ended_run_range_max;
357  QwError << "Too many open ended run ranges for " << file_stem << QwLog::endl;
358  }
359 
360  } else score = score_open_ended_run_range_min;
361  }
362  } else
363  // run not in range
364  score = -1;
365  } else
366  // run label does not start with a dot (i.e. partial match of stem)
367  score = -1;
368  }
369 
370  // Look for the match with highest score
371  if (score > best_score) {
372  best_path = *file_iterator;
373  best_score = score;
374  }
375  }
376  return best_score;
377 }
378 
379 
380 void QwParameterFile::TrimWhitespace(TString::EStripType head_tail)
381 {
382  // If the first bit is set, this routine removes leading spaces from the
383  // line. If the second bit is set, this routine removes trailing spaces
384  // from the line. The default behavior is to remove both.
385  TrimWhitespace(fLine, head_tail);
386 }
387 
389  const std::string& chars,
390  std::string& token,
391  TString::EStripType head_tail)
392 {
393  // If the first bit is set, this routine removes leading chars from the
394  // line. If the second bit is set, this routine removes trailing chars
395  // from the line. The default behavior is to remove both.
396  size_t mypos;
397  // Remove leading chars. If this first test returns "npos", it means
398  // this line is all chars, so get rid of it all.
399  // If we're not removing leading chars, lines which are all chars
400  // will not be removed.
401  mypos = token.find_first_not_of(chars);
402  if (head_tail & TString::kLeading) token.erase(0,mypos);
403  // Remove trailing spaces
404  mypos = token.find_last_not_of(chars);
405  mypos = token.find_first_of(chars,mypos);
406  if (mypos != std::string::npos && (head_tail & TString::kTrailing)){
407  token.erase(mypos);
408  }
409 }
410 
412  std::string &token,
413  TString::EStripType head_tail)
414 {
415  Trim(fWhitespaceChars,token,head_tail);
416 }
417 
418 void QwParameterFile::TrimComment(const char commentchar)
419 {
420  std::string commentchars = ""; // no std::string c'tor from single char
421  commentchars += commentchar; // so we have to use the operator+= overload
422  TrimComment(commentchars);
423 }
424 
425 void QwParameterFile::TrimComment(const std::string& commentchars)
426 {
427  // Remove everything after the comment character
428  size_t mypos = fLine.find_first_of(commentchars);
429  if (mypos != std::string::npos){
430  fLine.erase(mypos);
431  }
432 }
433 
435 {
436  // Trim section delimiter character on both sides
437  Trim(fSectionChars,fLine,TString::kBoth);
438 }
439 
441 {
442  // Trim module delimiter character on both sides
443  Trim(fModuleChars,fLine,TString::kBoth);
444 }
445 
446 
447 Bool_t QwParameterFile::HasValue(TString& vname)
448 {
449  Bool_t status=kFALSE;
450  TString vline;
451 
453  while (ReadNextLine()){
454  TrimWhitespace();
455  vline=(GetLine()).c_str();
456 
457  vline.ToLower();
458  TRegexp regexp(vline);
459  vname.ToLower();
460  if (vname.Contains(regexp)){
461  QwMessage <<" QwParameterFile::HasValue "<<vline<<" "<<vname<<QwLog::endl;
462  status=kTRUE;
463  break;
464  }
465  }
466 
467  return status;
468 }
469 
470 
472  const std::string& separatorchars,
473  TString &varname,
474  TString &varvalue)
475 {
476  std::string tmpvar, tmpval;
477  Bool_t status = HasVariablePair(separatorchars, tmpvar, tmpval);
478  if (status){
479  varname = tmpvar.c_str();
480  varvalue = tmpval.c_str();
481  }
482  return status;
483 }
484 
486  const std::string& separatorchars,
487  std::string &varname,
488  std::string &varvalue)
489 {
490  Bool_t status = kFALSE;
491  size_t equiv_pos1 = fLine.find_first_of(separatorchars);
492  if (equiv_pos1 != std::string::npos){
493  size_t equiv_pos2 = fLine.find_first_not_of(separatorchars,equiv_pos1);
494  if (equiv_pos2 != std::string::npos){
495  varname = fLine.substr(0,equiv_pos1);
496  varvalue = fLine.substr(equiv_pos2);
497  TrimWhitespace(varname, TString::kBoth);
498  TrimWhitespace(varvalue, TString::kBoth);
499  status = kTRUE;
500  }
501  }
502  return status;
503 }
504 
506  const std::string& separatorchars,
507  const TString& varname,
508  TString& varvalue)
509 {
510  std::string tmpval;
511  Bool_t status = FileHasVariablePair(separatorchars, varname.Data(), tmpval);
512  if (status) varvalue = tmpval.c_str();
513  return status;
514 }
515 
517  const std::string& separatorchars,
518  const std::string& varname,
519  std::string& varvalue)
520 {
522  while (ReadNextLine()) {
523  std::string this_varname;
524  if (HasVariablePair(separatorchars, this_varname, varvalue)) {
525  if (this_varname == varname) return kTRUE;
526  }
527  }
528  return false;
529 }
530 
531 
533 {
534  std::string secname;
535  return LineHasSectionHeader(secname);
536 }
537 
539 {
540  std::string secname_tmp = secname.Data();
541  Bool_t status = LineHasSectionHeader(secname_tmp);
542  secname = secname_tmp;
543  return status;
544 }
545 
546 Bool_t QwParameterFile::LineHasSectionHeader(std::string& secname)
547 {
548  TrimComment();
549  Bool_t status = kFALSE;
550  size_t equiv_pos1 = fLine.find_first_of('[');
551  if (equiv_pos1 != std::string::npos) {
552  size_t equiv_pos2 = fLine.find_first_of(']',equiv_pos1);
553  if (equiv_pos2 != std::string::npos && equiv_pos2 - equiv_pos1 > 1) {
554  secname = fLine.substr(equiv_pos1 + 1, equiv_pos2 - equiv_pos1 - 1);
555  TrimWhitespace(secname, TString::kBoth);
556  status = kTRUE;
557  }
558  }
559  return status;
560 }
561 
563 {
564  std::string secname;
565  return LineHasModuleHeader(secname);
566 }
567 
568 Bool_t QwParameterFile::LineHasModuleHeader(TString& secname)
569 {
570  std::string secname_tmp = secname.Data();
571  Bool_t status = LineHasModuleHeader(secname_tmp);
572  secname = secname_tmp;
573  return status;
574 }
575 
576 Bool_t QwParameterFile::LineHasModuleHeader(std::string& secname)
577 {
578  TrimComment();
579  Bool_t status = kFALSE;
580  size_t equiv_pos1 = fLine.find_first_of(fModuleChars[0]);
581  if (equiv_pos1 != std::string::npos) {
582  size_t equiv_pos2 = fLine.find_first_of(fModuleChars[1],equiv_pos1);
583  if (equiv_pos2 != std::string::npos && equiv_pos2 - equiv_pos1 > 1) {
584  secname = fLine.substr(equiv_pos1 + 1, equiv_pos2 - equiv_pos1 - 1);
585  TrimWhitespace(secname, TString::kBoth);
586  status = kTRUE;
587  }
588  }
589  return status;
590 }
591 
592 
593 Bool_t QwParameterFile::FileHasSectionHeader(const TString& secname)
594 {
596  while (ReadNextLine()) {
597  std::string this_secname;
598  if (LineHasSectionHeader(this_secname)) {
599  if (this_secname == secname) return kTRUE;
600  }
601  }
602  return false;
603 }
604 
605 Bool_t QwParameterFile::FileHasSectionHeader(const std::string& secname)
606 {
608  while (ReadNextLine()) {
609  std::string this_secname;
610  if (LineHasSectionHeader(this_secname)) {
611  if (this_secname == secname) return kTRUE;
612  }
613  }
614  return false;
615 }
616 
617 Bool_t QwParameterFile::FileHasModuleHeader(const TString& secname)
618 {
620  while (ReadNextLine()) {
621  std::string this_secname;
622  if (LineHasModuleHeader(this_secname)) {
623  if (this_secname == secname) return kTRUE;
624  }
625  }
626  return false;
627 }
628 
629 Bool_t QwParameterFile::FileHasModuleHeader(const std::string& secname)
630 {
632  while (ReadNextLine()) {
633  std::string this_secname;
634  if (LineHasModuleHeader(this_secname)) {
635  if (this_secname == secname) return kTRUE;
636  }
637  }
638  return false;
639 }
640 
641 /**
642  * Read from current position until next section header
643  * @return Pointer to the parameter stream until next section
644  */
646 {
647  std::string nextheader; // dummy
648  QwParameterFile* section = new QwParameterFile();
649  if (add_current_line) section->AddLine(GetLine()); // add current line
650  while (ReadNextLine() && ! LineHasSectionHeader(nextheader)) {
651  section->AddLine(GetLine());
652  }
653  return section;
654 }
655 
656 /**
657  * Read from current position until next module header
658  * @return Pointer to the parameter stream until next module
659  */
661 {
662  std::string nextheader; // dummy
663  QwParameterFile* section = new QwParameterFile();
664  if (add_current_line) section->AddLine(GetLine()); // add current line
665  while (ReadNextLine() && ! LineHasModuleHeader(nextheader)) {
666  section->AddLine(GetLine());
667  }
668  return section;
669 }
670 
671 Bool_t QwParameterFile::SkipSection(std::string secname)
672 {
673  // If the current line begins the section to be skipped,
674  // just keep reading until we get to the next section.
675  // Recurse, just in case the next section is the same
676  // section name.
677  Bool_t status = kTRUE;
678  std::string tmpname;
679  if (LineHasSectionHeader(tmpname)){
680  if (tmpname == secname){
681  QwDebug << "QwParameterFile::SkipSection: "
682  << "Begin skipping section " << tmpname << QwLog::endl;
683  while ((status=ReadNextLine()) && ! LineHasSectionHeader(tmpname)) {
684  // Do nothing for each line.
685  }
686  QwDebug << "QwParameterFile::SkipSection: "
687  << "Reached the end of the section."
688  << QwLog::endl;
689  if (status){
690  // Recurse, in case the next section has the same
691  // section name, but only if we found a new section
692  // header.
693  status = SkipSection(secname);
694  }
695  }
696  }
697  return status;
698 }
699 
700 
701 /**
702  * Read the lines until the first header
703  * @return Pointer to the parameter stream until first section
704  */
706 {
708  return ReadUntilNextSection();
709 }
710 
711 /**
712  * Read the lines of the next section
713  * @param secname Name of the next section (returns)
714  * @param keep_header Keep the header inside the section
715  * @return Pointer to the parameter stream of the next section
716  */
717 QwParameterFile* QwParameterFile::ReadNextSection(std::string &secname, const bool keep_header)
718 {
719  if (IsEOF()) return 0;
720  while (! LineHasSectionHeader(secname) && ReadNextLine()); // skip until header
721  return ReadUntilNextSection(keep_header);
722 }
723 
724 QwParameterFile* QwParameterFile::ReadNextSection(TString &secname, const bool keep_header)
725 {
726  if (IsEOF()) return 0;
727  while (! LineHasSectionHeader(secname) && ReadNextLine()); // skip until header
728  return ReadUntilNextSection(keep_header);
729 }
730 
731 
732 /**
733  * Read the lines until the first header
734  * @return Pointer to the parameter stream until first module
735  */
737 {
739  return ReadUntilNextModule();
740 }
741 
742 /**
743  * Read the lines of the next module
744  * @param secname Name of the next module (returns)
745  * @param keep_header Flag to keep header of module
746  * @return Pointer to the parameter stream of the next module
747  */
748 QwParameterFile* QwParameterFile::ReadNextModule(std::string &secname, const bool keep_header)
749 {
750  if (IsEOF()) return 0;
751  while (! LineHasModuleHeader(secname) && ReadNextLine()); // skip until header
752  return ReadUntilNextModule(keep_header);
753 }
754 
755 QwParameterFile* QwParameterFile::ReadNextModule(TString &secname, const bool keep_header)
756 {
757  if (IsEOF()) return 0;
758  while (! LineHasModuleHeader(secname) && ReadNextLine()); // skip until header
759  return ReadUntilNextModule(keep_header);
760 }
761 
762 std::string QwParameterFile::GetNextToken(const std::string& separatorchars)
763 {
764  std::string tmpstring = "";
765  if (fCurrentPos != std::string::npos){
766  size_t pos1 = fCurrentPos;
767  size_t pos2 = fLine.find_first_of(separatorchars.c_str(), pos1);
768  if (pos2 == std::string::npos){
769  fCurrentPos = pos2;
770  tmpstring = fLine.substr(pos1);
771  } else {
772  fCurrentPos = fLine.find_first_not_of(separatorchars.c_str(), pos2);
773  tmpstring = fLine.substr(pos1,pos2-pos1);
774  }
775  }
776  TrimWhitespace(tmpstring,TString::kBoth);
777  return tmpstring;
778 }
779 
780 std::ostream& operator<< (std::ostream& stream, const QwParameterFile& file)
781 {
782  /// \todo TODO (wdc) operator<< on QwParameterFile requires RewindToFileStart
783  std::string line;
784  stream << file.fStream.rdbuf();
785  return stream;
786 }
787 
788 
789 /** @brief Separate a separated range of integers into a pair of values
790  *
791  * @param separatorchars String with possible separator characters to consider.
792  * @param range String containing two integers separated by a separator character,
793  * or a single value.
794  * If the string begins with the separator character, the first value
795  * is taken as zero. If the string ends with the separator character,
796  * the second value is taken as kMaxInt.
797  *
798  * @return Pair of integers of the first and last values of the range.
799  * If the range contains a single value, the two integers will
800  * be identical.
801  */
802 std::pair<int,int> QwParameterFile::ParseIntRange(const std::string& separatorchars, const std::string& range)
803 {
804  std::pair<int,int> mypair;
805  size_t pos = range.find_first_of(separatorchars);
806  if (pos == std::string::npos) {
807  // Separator not found.
808  mypair.first = atoi(range.substr(0,range.length()).c_str());
809  mypair.second = mypair.first;
810  } else {
811  size_t end = range.length() - pos - 1;
812  if (pos == 0) {
813  // Separator is the first character
814  mypair.first = 0;
815  mypair.second = atoi(range.substr(pos+1, end).c_str());
816  } else if (pos == range.length() - 1) {
817  // Separator is the last character
818  mypair.first = atoi(range.substr(0,pos).c_str());
819  mypair.second = INT_MAX;
820  } else {
821  mypair.first = atoi(range.substr(0,pos).c_str());
822  mypair.second = atoi(range.substr(pos+1, end).c_str());
823  }
824  }
825 
826  // Check the values for common errors.
827  if (mypair.first < 0){
828  QwError << "The first value must not be negative!" << QwLog::endl;
829  return std::pair<int,int>(INT_MAX,INT_MAX);
830  } else if (mypair.first > mypair.second){
831  QwError << "The first value must not be larger than the second value"
832  << QwLog::endl;
833  return std::pair<int,int>(INT_MAX,INT_MAX);
834  }
835 
836  // Print the contents of the pair for debugging.
837  QwVerbose << "The range goes from " << mypair.first
838  << " to " << mypair.second << QwLog::endl;
839 
840  return mypair;
841 }
842 
843 
844 
846 {
847  Char_t delimiters[] = "/";
849  return;
850 };
851 
852 
853 TString QwParameterFile::LastString(TString in, char* delim)
854 {
855  TObjArray* all_strings = in.Tokenize(delim);
856  TObjString* last_string = (TObjString*) all_strings->Last();
857  return last_string->GetString();
858 };
859 
860 
862 {
863  TMacro *fParameterFile = new TMacro(fBestParamFileNameAndPath);
864  TString ms;
865  TList *list = fParameterFile->GetListOfLines();
866  for(Int_t i=0; i < list->GetSize(); i++) {
867  ms += list->At(i)->GetName();
868  ms += "\n";
869  }
870  delete fParameterFile;
871  fParameterFile = NULL;
872  return ms;
873 }
874 
875 
876 void QwParameterFile::AddBreakpointKeyword(std::string keyname){
877  std::transform(keyname.begin(), keyname.end(),
878  keyname.begin(), ::tolower);
879  fBreakpointWords.insert(keyname);
880 }
881 
882 Bool_t QwParameterFile::ReadNextLine_Greedy(std::string &varvalue)
883 {
884  // Keep reading until a non-comment, non-empty,
885  // non-keyword-value-pair line has been found.
886  Bool_t status;
887  std::string tmpname, tmpvalue;
888  while ((status = ReadNextLine_Single(varvalue))){
889  TrimComment();
890  TrimWhitespace();
891  if (LineIsEmpty()) continue;
892  if (HasVariablePair("=",tmpname,tmpvalue)){
893  std::transform(tmpname.begin(), tmpname.end(),
894  tmpname.begin(), ::tolower);
895  if (fBreakpointWords.count(tmpname)==1){
897  break;
898  } else {
899  fKeyValuePair[tmpname] = tmpvalue;
900  fHasNewPairs = kTRUE;
901  continue;
902  }
903  }
904  break;
905  }
906  return status;
907 }
static const double ms
Time units: base unit is ms.
Definition: QwUnits.h:72
#define QwMessage
Predefined log drain for regular messages.
Definition: QwLog.h:50
TString fBestParamFileName
static void AppendToSearchPath(const TString &searchdir)
Add a directory to the search path.
std::stringstream fStream
Bool_t LineHasModuleHeader()
std::ostream & operator<<(std::ostream &out, const QwColor &color)
Output stream operator which uses the enum-to-escape-code mapping.
Definition: QwColor.h:153
static const double in
Definition: QwUnits.h:66
TString GetParameterFileContents()
static UInt_t GetUInt(const TString &varvalue)
static const std::string kDefaultWhitespaceChars
Bool_t FileHasSectionHeader(const std::string &secname)
static const std::string kDefaultSectionChars
std::string GetNextToken()
Bool_t HasVariablePair(const std::string &separatorchars, std::string &varname, std::string &varvalue)
std::string fLine
#define QwVerbose
Predefined log drain for verbose messages.
Definition: QwLog.h:55
static const std::string kDefaultTokenSepChars
std::map< std::string, std::string > fKeyValuePair
QwParameterFile * ReadNextSection(std::string &secname, const bool keep_header=false)
TString LastString(TString in, char *delim)
QwParameterFile * ReadNextModule(std::string &secname, bool keep_header=false)
Bool_t HasValue(TString &vname)
Bool_t FileHasModuleHeader(const std::string &secname)
#define QwDebug
Predefined log drain for debugging output.
Definition: QwLog.h:60
A logfile class, based on an identical class in the Hermes analyzer.
size_t fCurrentPos
Internal line storage.
QwParameterFile * ReadUntilNextSection(const bool add_current_line=false)
Bool_t ReadNextLine_Single(std::string &varvalue)
std::string GetLine()
Bool_t ReadNextLine()
std::string fSectionChars
std::ifstream fFile
static UInt_t fCurrentRunNumber
static std::pair< int, int > ParseIntRange(const std::string &separatorchars, const std::string &range)
Parse a range of integers as #:# where either can be missing.
void AddBreakpointKeyword(std::string keyname)
int FindFile(const bfs::path &dir_path, const std::string &file_stem, const std::string &file_ext, bfs::path &path_found)
Find the first file in a directory that conforms to the run label.
Bool_t FileHasVariablePair(const std::string &separatorchars, const std::string &varname, std::string &varvalue)
static const std::string kDefaultCommentChars
A color changing class for the output stream.
Definition: QwColor.h:98
Bool_t LineHasSectionHeader()
QwParameterFile * ReadSectionPreamble()
Rewinds to the start and read until it finds next section header.
static std::ostream & endl(std::ostream &)
End of the line.
Definition: QwLog.cc:299
static std::vector< bfs::path > fSearchPaths
std::set< std::string > fBreakpointWords
bool OpenFile(const bfs::path &path_found)
Open a file.
void TrimWhitespace(TString::EStripType head_tail=TString::kBoth)
static const std::string kDefaultModuleChars
Bool_t ReadNextLine_Greedy(std::string &varvalue)
QwParameterFile * ReadModulePreamble()
Rewinds to the start and read until it finds next module header.
TString fBestParamFileNameAndPath
#define QwWarning
Predefined log drain for warnings.
Definition: QwLog.h:45
std::string fWhitespaceChars
void AddLine(const std::string &line)
QwParameterFile * ReadUntilNextModule(const bool add_current_line=false)
void Trim(const std::string &chars, std::string &token, TString::EStripType head_tail=TString::kBoth)
#define QwError
Predefined log drain for errors.
Definition: QwLog.h:40
Bool_t SkipSection(std::string secname)
Skips from the beginning of the section &#39;secname&#39; until the first section that does not have that nam...
std::string fModuleChars