Hall A ROOT/C++ Analyzer (podd)
Loading...
Searching...
No Matches
MultiFileRun.cxx
Go to the documentation of this file.
1//*-- Author : Ole Hansen 02-Nov-21
2
4//
5// Podd::MultiFileRun
6//
8
9#include "MultiFileRun.h"
10#include "THaCodaFile.h"
11#include "THaPrintOption.h"
12#include "CodaDecoder.h"
13#include "TRegexp.h"
14#include "TSystem.h"
15#include "Helper.h"
16#include <utility>
17#include <algorithm>
18#include <iostream>
19#include <cassert>
20#include <set>
21
22using namespace std;
23using namespace Decoder;
24
25#if __cplusplus >= 201402L
26# define MKCODAFILE make_unique<Decoder::THaCodaFile>()
27#else
28# define MKCODAFILE unique_ptr<Decoder::THaCodaFile>(new Decoder::THaCodaFile)
29#endif
30
31namespace Podd {
32
33//__________________________________________________________________________
34static TString GetDirName(const char *pathname)
35{
36#if ROOT_VERSION_CODE < ROOT_VERSION(6,22,0)
37 // This code taken from ROOT 6.22's TSystem.cxx
38 if( !pathname || !strchr(pathname, '/') )
39 return ".";
40
41 auto pathlen = strlen(pathname);
42
43 const char* r = pathname + pathlen - 1;
44 // First skip the trailing '/'
45 while( (r > pathname) && (*r == '/') )
46 --r;
47 // Then find the next non slash
48 while( (r > pathname) && (*r != '/') )
49 --r;
50
51 // Then skip duplicate slashes
52 // Note the 'r>buf' is a strict comparison to allows '/topdir' to return '/'
53 while( (r > pathname) && (*r == '/') )
54 --r;
55 // If all was cut away, we encountered a rel. path like 'subdir/'
56 // and ended up at '.'.
57 if( (r == pathname) && (*r != '/') )
58 return ".";
59
60 return TString(pathname, r + 1 - pathname); // NOLINT(modernize-return-braced-init-list)
61#else
62 return gSystem->GetDirName(pathname);
63#endif
64}
65
66//_____________________________________________________________________________
67static inline TString JoinPath( const TString& base, const TString& to_join )
68{
69 if( base.IsNull() )
70 return to_join;
71 return base + (base.EndsWith("/") ? "" : "/") + to_join;
72}
73
74//_____________________________________________________________________________
75static inline string JoinPath( const string& base, const string& to_join )
76{
77 if( base.empty() )
78 return to_join;
79 return base + (base[base.length()-1] == '/' ? "" : "/") + to_join;
80}
81
82//_____________________________________________________________________________
83MultiFileRun::MultiFileRun( const char* filenamePattern,
84 const char* description, bool is_regex )
85 : THaRun("", description)
86 , fFirstSegment{0}
87 , fFirstStream{0}
88 , fMaxSegments{0}
89 , fMaxStreams{0}
90 , fFlags{0}
91 , fNameIsRegexp{is_regex}
92 , fLastUsedStream{-1}
93 , fNActive{0}
94 , fNevRead{0}
95{
96 fCodaData.reset(); // Not used
97
98 if( filenamePattern && *filenamePattern )
99 fFileList.emplace_back(filenamePattern);
100
101 // Expand environment variables and leading "~" in file name pattern
102 auto expand_name = [this]( string& f) { ExpandFileName(f); };
103 for_each(ALL(fFileList), expand_name);
104
106}
107
108//_____________________________________________________________________________
109MultiFileRun::MultiFileRun( std::vector<std::string> pathList,
110 const char* filenamePattern, const char* description,
111 bool is_regex )
112 : MultiFileRun(std::move(pathList),
113 vector<string>{(filenamePattern ? filenamePattern : "")},
114 description, is_regex)
115{}
116
117//_____________________________________________________________________________
118MultiFileRun::MultiFileRun( vector<string> pathList, vector<string> fileList,
119 const char* description, bool is_regex )
120 : THaRun("", description)
121 , fFileList{std::move(fileList)}
122 , fPathList{std::move(pathList)}
123 , fFirstSegment{0}
124 , fFirstStream{0}
125 , fMaxSegments{0}
126 , fMaxStreams{0}
127 , fFlags{0}
128 , fNameIsRegexp{is_regex}
129 , fLastUsedStream{-1}
130 , fNActive{0}
131 , fNevRead{0}
132{
133 fCodaData.reset(); // Not used
134
135 // Expand environment variables and leading "~" in file paths
136 auto expand_name = [this]( string& f) { ExpandFileName(f); };
137 for_each(ALL(fFileList), expand_name);
138 for_each(ALL(fPathList), expand_name);
139
141
143}
144
145//_____________________________________________________________________________
147 : THaRun(rhs)
148 , fFileList{rhs.fFileList}
149 , fPathList{rhs.fPathList}
150 , fStreams{rhs.fStreams}
151 , fFirstSegment{rhs.fFirstSegment}
152 , fFirstStream{rhs.fFirstStream}
153 , fMaxSegments{rhs.fMaxSegments}
154 , fMaxStreams{rhs.fMaxStreams}
155 , fFlags{rhs.fFlags}
156 , fNameIsRegexp{rhs.fNameIsRegexp}
157 , fLastUsedStream{-1}
158 , fNActive{0}
159 , fNevRead{0}
160{
161 fCodaData.reset(); // Not used. THaRun copy c'tor sets it
162}
163
164//_____________________________________________________________________________
166{
167 // Assignment operator
168
169 if( this != &rhs ) {
171
172 fCodaData.reset(); // Not used. THaRun::operator= sets it
173 fLastUsedStream = -1;
174 fNActive = 0;
175 fNevRead = 0;
176 try {
177 const auto& mfr = dynamic_cast<const MultiFileRun&>(rhs);
178 fFileList = mfr.fFileList;
179 fPathList = mfr.fPathList;
180 fStreams = mfr.fStreams;
181 fFirstSegment = mfr.fFirstSegment;
182 fFirstStream = mfr.fFirstStream;
183 fMaxSegments = mfr.fMaxSegments;
184 fMaxStreams = mfr.fMaxStreams;
185 fFlags = mfr.fFlags;
186 fNameIsRegexp = mfr.fNameIsRegexp;
187 }
188 catch( const std::bad_cast& ) {
189 // Assigning from a different class. Not a good idea, but anyway.
190 fFileList.assign(1, string{fFilename.Data()});
191 fPathList.clear();
194 fFlags = 0;
195 fNameIsRegexp = false;
196 }
197 }
198 return *this;
199}
200
201
202//_____________________________________________________________________________
204{
205 THaPrintOption sopt(opt);
206 sopt.ToUpper();
207 bool doing_init = (sopt.Contains("INIT"));
208
209 // If initializing, keep explicitly set parameters
210 if( !doing_init ) {
213 }
214 // Clear the base classes. This calls our Close(), which resets fNActive etc.
215 THaRun::Clear(opt);
216
217 fLastUsedStream = -1;
218 fNActive = 0;
219 fNevRead = 0;
220 fStreams.clear();
221}
222
223//_____________________________________________________________________________
225{
226 if( !IsOpen() )
227 return READ_OK;
228
229 fOpened = false;
230 fNActive = 0;
231 fNevRead = 0;
232
233 Int_t err = CODA_OK;
234 for( auto& stream: fStreams ) {
235 Int_t st = stream.Close();
236 if( st != CODA_OK )
237 err = st;
238 }
239 return ReturnCode(err);
240}
241
242//_____________________________________________________________________________
244{
245 // Compare this MultiFileRun object to another run. Returns 0 when equal,
246 // -1 when 'this' is smaller and +1 when bigger (like strcmp).
247 // Used by ROOT containers.
248
249 if (this == obj) return 0;
250 const auto* rhs = dynamic_cast<const THaRunBase*>(obj);
251 if( !rhs ) return -1;
252 // Compare run numbers
253 if( *this < *rhs ) return -1;
254 else if( *rhs < *this ) return 1;
255 const auto* mfr = dynamic_cast<const MultiFileRun*>(rhs);
256 if( !mfr ) return 1;
257 if( fStreams > mfr->fStreams ) return 1;
258 if( fStreams < mfr->fStreams ) return -1;
259 return 0;
260}
261
262//_____________________________________________________________________________
264{
265 // fDataVersion is either 0 if we're uninitialized or set in BuildInputList.
266 return fDataVersion;
267}
268
269//_____________________________________________________________________________
271{
272 if( fCodaData ) {
273 // This is set only during ReadInitInfo when prescanning a separate file
274 assert(fCodaData->isOpen());
275 return fCodaData->getEvBuffer();
276 }
277
278 if( !IsOpen() ) {
279 cerr << "Not open" << endl;
280 return nullptr;
281 }
282 if( fNevRead == 0 ) {
283 cerr << "No events read" << endl;
284 return nullptr;
285 }
286
287 assert(!fStreams.empty());
288 if( fStreams.empty() )
289 return nullptr;
290 const auto& curstr = fStreams[fLastUsedStream];
291 assert(curstr.fActive);
292 if( !curstr.fActive ) {
293 // The stream has seen EOF and so the buffer contains no valid data
294 cerr << "At EOF" << endl;
295 return nullptr;
296 }
297 return curstr.GetEvBuffer();
298}
299
300//_____________________________________________________________________________
302{
303 assert(!fStreams.empty());
304 if( fStreams.empty() )
305 return 0;
306 const auto& curstr = fStreams[fLastUsedStream];
307 assert(curstr.fActive);
308 if( !curstr.fActive )
309 return 0;
310 return curstr.fEvNum;
311}
312
313//_____________________________________________________________________________
315{
316 return fOpened;
317}
318
319//_____________________________________________________________________________
320static Int_t CheckSetFileDataVersion( const string& path,
321 Int_t ver, Int_t& data_ver )
322{
323 Int_t err = CODA_OK;
324 if( ver > 0 ) { // got a valid version from file
325 if( data_ver == 0 ) { // not yet set
326 data_ver = ver;
327 } else if( ver != data_ver ) {
328 // all input files must the same format
329 cerr << "Inconsistent CODA version " << ver << " for file "
330 << path << ", expected " << data_ver << endl;
331 err = CODA_ERROR;
332 }
333 //else already set and agrees
334 } else {
335 // error getting format
336 cerr << "Error getting CODA version from file " << path << endl;
337 err = CODA_ERROR;
338 }
339 return err;
340}
341
342//_____________________________________________________________________________
343// If there are multiple input streams and/or files, check for consistency
344// of file naming (assumed to be representative of the run number) and
345// each file's CODA version
347{
348 Int_t err = CODA_OK, file_data_version = 0;
349 TString stem;
350 for( auto& stream: fStreams ) {
351 assert(!stream.fFiles.empty());
352 for( const auto& file: stream.fFiles ) {
353 // Since CODA does not currently store the run number in each file
354 // segment, we have to rely on filename heuristics to guess whether the
355 // user is trying to do something unwise, like mixing different runs.
356 if( stem.IsNull() )
357 stem = file.fStem;
358 else if( file.fStem != stem ) {
359 cerr << "Warning: Inconsistent file naming: \"" << file.fStem
360 << "\" vs. \"" << stem << ". Are these the same runs?" << endl;
361 }
362 assert(stream.fCodaData); // else bad stream constructor
363 Int_t ret = stream.fCodaData->codaOpen(file.fPath.c_str());
364 if( ret != CODA_OK ) {
365 cerr << "Error " << ret << " opening CODA file " << file.fPath << endl;
366 } else {
368 file.fPath, stream.fCodaData->getCodaVersion(), file_data_version);
369 }
370 if( ret != CODA_OK )
371 err = ret;
372 stream.Close();
373 }
374 }
375 if( err == CODA_OK ) {
376 assert(file_data_version > 0);
377 if( fDataVersion == 0 )
378 fDataVersion = file_data_version;
379
380 } else {
381 cerr << "One or more files had errors" << endl;
382 }
383 return ReturnCode(err);
384}
385
386//_____________________________________________________________________________
387// Extract segment and stream number of 'file' and add the file path to
388// the list of files for the corresponding stream
390{
391 Int_t seg = -1, str = -1;
392 TString stem;
393 if( StdFindSegmentNumber(file, stem, seg, str)
394 && (seg == -1 || seg >= fFirstSegment)
395 && (str == -1 || str >= fFirstStream) ) {
396 TString path = (dir != ".") ? JoinPath(dir, file) : file;
397 auto it = find_if(ALL(fStreams), [str]( const StreamInfo& ifo ) {
398 return ifo.fID == str;
399 });
400 if( it == fStreams.end() ) {
401 fStreams.emplace_back(str);
402 it = std::prev(fStreams.end());
403 }
404 auto& files = it->fFiles;
405 auto jt = find_if(ALL(files), [seg]( const FileInfo& fi ) {
406 return fi.fSegment == seg;
407 });
408 if( jt == files.end() )
409 files.emplace_back(path.Data(), stem.Data(), seg);
410 else {
411 if( jt->fStem == stem ) {
412 cerr << "Warning: Duplicate segment number: "
413 << jt->fPath << " : " << path << endl
414 << "Ignoring apparently identical file " << path << endl;
415 } else {
416 cerr << "Error: Duplicate segment number: "
417 << jt->fPath << " : " << path << endl
418 << "Files seem different, check your filename pattern." << endl;
419 return READ_ERROR;
420 }
421 }
422 return READ_EOF; // indicates file has been found
423 }
424 return READ_OK;
425}
426
427//_____________________________________________________________________________
428// Sort streams by number. Sort files of each stream by segment number.
429// Limit number of streams and files to fMaxStreams and fMaxSegments, resp.
431{
432 sort(ALL(fStreams));
433
434 if( fMaxStreams > 0 && fStreams.size() > fMaxStreams ) {
435 fStreams.resize(fMaxStreams);
436 }
437
438 // Sort each stream's files by segment number
439 size_t nfiles = 0;
440 for( auto& stream: fStreams ) {
441 auto& files = stream.fFiles;
442 sort(ALL(files));
443 if( fMaxSegments > 0 && files.size() > fMaxSegments )
444 files.resize(fMaxSegments);
445 nfiles += files.size();
446 }
447 cout << "MultiFileRun: " << nfiles << " file";
448 if( nfiles != 1 ) cout << 's';
449 cout << " in " << fStreams.size() << " stream";
450 if( fStreams.size() != 1 ) cout << 's';
451 cout << endl;
452}
453
454//_____________________________________________________________________________
455static vector<TString> SplitPath( const TString& path )
456{
457 vector<TString> vs;
458 TString dirn = path;
459 while( dirn != "/" && dirn != "." ) {
460 vs.emplace_back(gSystem->BaseName(dirn));
461 dirn = GetDirName(dirn);
462 }
463 vs.emplace_back(dirn); // top directory
464 reverse(ALL(vs));
465 return vs;
466}
467
468//_____________________________________________________________________________
469static bool item_is_dir( const TString& itempath )
470{
471 FileStat_t buf;
472 Int_t ret = gSystem->GetPathInfo(itempath, buf);
473 if( ret != 0 || !R_ISDIR(buf.fMode) )
474 return false;
475 if( gSystem->AccessPathName(itempath, kReadPermission) ||
477 cerr << "Warning: Directory " << itempath
478 << " is not accessible. Check permissions." << endl;
479 return false;
480 }
481 return true;
482}
483
484//_____________________________________________________________________________
485static bool item_is_not_dir( const TString& itempath )
486{
487 FileStat_t buf;
488 Int_t ret = gSystem->GetPathInfo(itempath, buf);
489 return ( ret == 0 && !R_ISDIR(buf.fMode) );
490}
491
492//_____________________________________________________________________________
493static bool item_exists( const TString& itempath )
494{
495 FileStat_t buf;
496 Int_t ret = gSystem->GetPathInfo(itempath, buf);
497 return ( ret == 0 );
498}
499
500//_____________________________________________________________________________
501bool MultiFileRun::HasWildcards( const TString& str ) const
502{
503 // Return true if 'path' should be interpreted as a regular expression.
504 // This searches for the first occurrence of a character that will be treated
505 // specially, so that 'path' needs to be "compiled" by TRegexp.
506
507 // TODO this is hard to test (too many possible cases) and so this function
508 // may still be buggy for edge cases.
509
510 string spath = str.Data();
511 if( !fNameIsRegexp ) {
512 // ROOT's TRegexp with wildcard = true supports shell-style wildcards
513 // including character ranges like '[a-z]', but also '[a-z]+'.
514 return spath.find_first_of("?*[") != string::npos;
515 }
516 // Handle full (= non-wildcard) regular expressions.
517 // These characters immediately give away the string as a regexp:
518 auto is_regex_char = []( string::value_type c ) {
519 return (c == '.' || c == '[' ||
520 c == '*' || c == '+' || c == '?');
521 };
522 string::size_type pos = 0;
523 while( true ) {
524 pos = spath.find_first_of("^$.[*+?\\", pos);
525 if( pos == string::npos )
526 return false;
527 auto c = spath[pos];
528 if( is_regex_char(c) )
529 return true;
530 // ROOT TRegexp treats '^' and '$' as normal characters except at the start
531 // and end of the expression, respectively. So, except at those positions,
532 // these characters alone do not make 'path' a regexp. (They make path an
533 // invalid directory name, but that is checked elsewhere.)
534 if( (c == '^' && pos == 0) || (c == '$' && pos + 1 == spath.length()) )
535 return true;
536 // A '\' requires regex treatment only if it precedes one of the special
537 // regex characters. Otherwise, C-string interpretation applies, e.g. "\t"
538 if( c == '\\' && pos + 1 < spath.length()
539 && is_regex_char(spath[pos + 1]) )
540 return true;
541 ++pos;
542 }
543}
544
545//_____________________________________________________________________________
547 const TString& dir, const TRegexp& match_re, const action_t& action )
548{
549 auto* dirp = gSystem->OpenDirectory(dir);
550 assert( dirp ); // else item_is_dir() faulty
551 if( !dirp ) {
552 cerr << "Directory " << dir << " unexpectedly cannot be opened." << endl;
553 return READ_ERROR;
554 }
555 Int_t ret = READ_OK;
557 bool found_exact = false;
558 while( const char* entry = gSystem->GetDirEntry(dirp) ) {
559 if( strcmp(entry, ".") == 0 || strcmp(entry, "..") == 0 )
560 continue;
561 Ssiz_t len = 0;
562 TString item = entry;
563 if( match_re.Index(item, &len) == 0 && len == item.Length() ) {
564 ret = action(dir, item);
565 if( ret == READ_EOF ) {
566 // Don't quit if file was found since there may be more matches
567 found_exact = true;
568 continue;
569 }
570 if( ret != READ_OK )
571 goto exit;
572 }
573 }
574 if( found_exact )
575 ret = READ_EOF;
576 exit:
578 gSystem->FreeDirectory(dirp);
579 return ret;
580}
581
582//_____________________________________________________________________________
583Int_t MultiFileRun::ScanForFilename( const path_t& path, bool regex_mode,
584 const action_t& action )
585{
586 const TString& dir = path.first;
587 const TString& file = path.second;
588 if( HasWildcards(file) ) {
589 TRegexp file_re(file, !regex_mode);
590 if( file_re.Status() != TRegexp::kOK ) {
591 cerr << "Bad filename pattern \"" << file << "\", err = "
592 << file_re.Status() << endl;
593 return READ_ERROR;
594 }
595 return ForEachMatchItemInDir(dir, file_re, action);
596
597 } else {
598 return action(dir, file);
599 }
600}
601
602//_____________________________________________________________________________
603Int_t MultiFileRun::ScanForSubdirs // NOLINT(misc-no-recursion)
604 ( const TString& curdir, const std::vector<TString>& splitpath, Int_t level,
605 bool regex_mode, const action_t& action )
606{
607 auto do_directory = [this, level, &splitpath, &action] // NOLINT(misc-no-recursion)
608 ( const TString& curpath, const TString& subdir ) -> Int_t
609 {
610 auto itempath = JoinPath(curpath, subdir);
611 if( item_is_dir(itempath) ) {
612 return DescendInto(itempath, splitpath, level + 1, action);
613 } else if( !TestBit(kResolvingWildcard) ) {
614 cerr << itempath << " is not a directory" << endl;
615 }
616 return READ_OK;
617 };
618
619 const auto& subdir = splitpath[level];
620 if( HasWildcards(subdir) ) {
621 TRegexp subdir_re(subdir, !regex_mode);
622 if( subdir_re.Status() != TRegexp::kOK ) {
623 cerr << "Bad directory pattern \"" << subdir << "\", err = "
624 << subdir_re.Status() << endl;
625 return READ_ERROR;
626 }
627 return ForEachMatchItemInDir(curdir, subdir_re, do_directory);
628 } else {
629 return do_directory(curdir, subdir);
630 }
631}
632
633//_____________________________________________________________________________
634Int_t MultiFileRun::DescendInto // NOLINT(misc-no-recursion)
635 ( const TString& curpath, const std::vector<TString>& splitpath, Int_t level,
636 const action_t& action )
637{
638 if( level+1 >= SSIZE(splitpath) ) {
639 // Base case: Lowest directory level. Look for the filename pattern.
640 return ScanForFilename({curpath, splitpath[level]}, fNameIsRegexp, action);
641 }
642 return ScanForSubdirs(curpath, splitpath, level, fNameIsRegexp, action);
643}
644
645//_____________________________________________________________________________
647 const action_t& action )
648{
649 // Make a vector of directory path components
650 auto splitpath = SplitPath(path.first);
651 // The last element is the file name
652 splitpath.push_back(path.second);
653 assert(!splitpath.empty());
654 const auto topdir = splitpath[0];
655 if( item_is_dir(topdir) ) {
656 Int_t ret = DescendInto(topdir, splitpath, 1, action);
657 if( ret != READ_OK )
658 return ret;
659 }
660 return READ_OK;
661}
662
663//_____________________________________________________________________________
665 const action_t& action )
666{
667 if( item_is_dir(path.first) ) {
668 return ScanForFilename(path, fNameIsRegexp, action);
669 }
670 return READ_OK;
671}
672
673//_____________________________________________________________________________
674void MultiFileRun::AssembleFilePaths( vector<path_t>& candidates,
675 const vector<string>& file_list )
676{
677 candidates.clear();
678 // Sort file names and remove duplicates
679// Changed my mind on this. Let the user decide the order.
680// std::sort(ALL(file_list));
681// auto last = std::unique(ALL(file_list));
682// file_list.erase(last, file_list.end());
683
684 // Add any file names that are absolute paths to the beginning of the list
685 // of path candidates. Usually this is just a single entry if the class was
686 // constructed with the basic constructor taking a single filename pattern.
687 for( const auto& file: file_list ) {
688 if( file.empty() || file.front() != '/' )
689 continue;
690 candidates.emplace_back(GetDirName(file.c_str()),
691 gSystem->BaseName(file.c_str()));
692 }
693
694 // If the path list is empty, make a temporary dummy entry so the loop
695 // below actually runs and records the filenames with relative paths.
696 bool temp_pathlist = false;
697 if( fPathList.empty() ) {
698 temp_pathlist = true;
699 fPathList.emplace_back("");
700 }
701
702 // Add all combinations of paths and file names to the list of candidates.
703 // Maintain the order of the path list as given by the user, so that can put
704 // fast/likely locations first, for example.
705 for( const auto& dir: fPathList ) {
706 for( const auto& file: file_list ) {
707 if( file.empty() || file.front() == '/' )
708 continue;
709 TString fullpath = JoinPath(dir, file);
710 path_t cand_path{GetDirName(fullpath),
711 gSystem->BaseName(fullpath)};
712 // Disregard exact duplicates, however they may have gotten here.
713 // Wildcards may still lead to duplicates; those will be caught later.
714 if( std::find(ALL(candidates), cand_path) == candidates.end() )
715 candidates.emplace_back(std::move(cand_path));
716 }
717 }
718
719 if( temp_pathlist )
720 fPathList.clear();
721}
722
723//_____________________________________________________________________________
724// Build a list of unique directory/filename pairs to search
725void MultiFileRun::AssembleFilePaths( vector<path_t>& candidates )
726{
727 AssembleFilePaths(candidates, fFileList);
728}
729
730//_____________________________________________________________________________
731// Build the list of input files
733{
734 vector<path_t> candidates;
735 AssembleFilePaths(candidates);
736
737 // Action to perform for a matching file
738 auto add_file = [this]( const TString& curpath, const TString& file ) -> Int_t
739 {
740 auto itempath = JoinPath(curpath, file);
741 if( item_exists(itempath) ) {
742 if( item_is_not_dir(itempath) ) {
743 return AddFile(file, curpath);
744 } else {
745 cerr << itempath << " is a directory. Expected file." << endl;
746 }
747 }
748 return READ_OK;
749 };
750
751 // Cache for non-wildcard names already found
752 set<TString> files_found;
753 for( const auto& path: candidates ) {
754 if( files_found.find(path.second) != files_found.end() )
755 // Skip already-found non-wildcard files names. This avoids "duplicate
756 // segment" warnings in case several search paths lead to the same file.
757 continue;
758 Int_t ret;
759 if( HasWildcards(path.first) ) {
760 // Traverse directory tree, resolving wildcard/regexp in directory names
761 ret = BuildInputListFromWildcardDir(path, add_file);
762 } else {
763 // If the directory path contains no wildcards/regexp, simply scan
764 // that directory directly
765 ret = BuildInputListFromTopDir(path, add_file);
766 }
767 if( ret == READ_EOF ) {
768 if( !HasWildcards(path.second)
770 files_found.insert(path.second);
771 continue;
772 }
773 if( ret != READ_OK )
774 return ret;
775 }
776 if( fStreams.empty() ) {
777 cerr << "MultiFileRun::Open: no matching files found" << endl;
778 return READ_ERROR;
779 }
780 files_found.clear();
781 candidates.clear();
782
783 SortStreams();
784
786
787 return ret;
788}
789
790//_____________________________________________________________________________
792{
793 // Prepare for reading multiple files (segments, streams)
794
795 if( IsOpen() )
796 return READ_OK;
797
798 if( fFileList.empty() ) {
799 cerr << "CODA file name not set. Cannot open the run." << endl;
800 return READ_FATAL; // filename not set
801 }
802 // Find existing files matching the given pattern
803 if( fStreams.empty() && !FindSegmentNumber() ) {
804 return READ_FATAL;
805 }
806
807 // Now actually open the file(s). Streams will be read in parallel,
808 // and so one file of each stream is opened simultaneously.
809 for( auto& stream: fStreams ) {
810 stream.fVersion = fDataVersion;
811#ifndef NDEBUG
812 Int_t ret =
813#endif
814 stream.Open();
815 assert(ret == CODA_OK); // else checks in BuildInputList faulty
816 }
817 fLastUsedStream = 0;
819 fFilename = fStreams[fLastUsedStream].GetFilename();
820 fNActive = static_cast<Int_t>(fStreams.size());
821 fOpened = true;
822 return READ_OK;
823}
824
825//_____________________________________________________________________________
826Int_t MultiFileRun::ReadEvent() // NOLINT(misc-no-recursion)
827{
828 if( fCodaData ) {
829 // This is set only during ReadInitInfo when prescanning a separate file
830 assert(fCodaData->isOpen());
831 return ReturnCode(fCodaData->codaRead());
832 }
833
834 if( !IsOpen() ) {
835 cerr << "Not open" << endl;
836 return READ_ERROR;
837 }
838 if( fNActive <= 0 )
839 return READ_EOF;
840
841 // If multiple streams are being read, find the smallest event number of
842 // all open streams so that GetEvBuffer knows what to return next
844#ifndef NDEBUG
845 Bool_t success =
846#endif
848 assert(success);
849 fFilename = fStreams[fLastUsedStream].GetFilename();
850
851 auto& curstr = fStreams[fLastUsedStream];
852 Int_t st = curstr.Read();
853 if( st == CODA_EOF ) { // no more data
854 curstr.fActive = false;
855 if( --fNActive > 0 )
856 return ReadEvent(); // advance to next active stream
857 assert(fNActive == 0);
858 }
859 if( st != CODA_OK )
860 return ReturnCode(st);
861
862 ++fNevRead;
863 return st;
864}
865
866//_____________________________________________________________________________
867// Check which of the currently active streams has the lowest physics event
868// number and return its index. If multiple streams match, match the one with
869// the lowest stream number.
871{
872 assert(fNActive >= 1);
874 auto sz = SSIZE(fStreams);
875 if( fNActive > 1 ) {
876 Int_t minidx = -1;
877 UInt_t minev = kMaxUInt;
878 for( Int_t i = 0; i < sz; ++i ) {
879 const auto& stream = fStreams[i];
880 if( stream.fActive && stream.fEvNum < minev ) {
881 minidx = i;
882 minev = stream.fEvNum;
883 }
884 }
885 assert(minidx != -1);
886 ret = minidx;
887 } else {
888#ifndef NDEBUG
889 bool found = false;
890#endif
891 for( int i = 0; i < sz; ++i ) {
892 if( fStreams[i].fActive ) {
893 ret = i;
894#ifndef NDEBUG
895 assert(!found); // else fNActive incorrect
896 found = true;
897#else
898 break;
899#endif
900 }
901 }
902#ifndef NDEBUG
903 assert(found); // else fNActive incorrect
904#endif
905 }
906 return ret;
907}
908
909//_____________________________________________________________________________
910// Find a file matching the name pattern returned by GetInitInfoFile().
911// The file must exist on disk and have at least read permissions.
912// - First, in the same directory as the continuation segment.
913// - Then, look in the directories in fPathList
914// Returns an empty string if no matching file can be found.
916{
917 // Full path of the file that should contain the init info
918 TString initinfo_file = GetInitInfoFileName(fname);
919 // Check current directory
920 if( !gSystem->AccessPathName(initinfo_file, kReadPermission) )
921 return initinfo_file;
922
923 string base = gSystem->BaseName(initinfo_file);
924 assert(!HasWildcards(base));
925 vector<string> file_list;
926 bool have_empty = false;
927 for( const auto& file: fFileList ) {
928 string fdir = GetDirName(file.c_str()).Data();
929 if( fdir == '.' ) {
930 have_empty = true;
931 continue;
932 }
933 file_list.push_back(JoinPath(fdir,base));
934 }
935 if( file_list.empty() || have_empty )
936 file_list.push_back(base);
937
938 // Search the locations in the path list , including directory components
939 // in the file list.
940 // Simplified version of BuildInputList for a single, non-wildcard file name
941 vector<path_t> candidates;
942 AssembleFilePaths( candidates, file_list);
943
944 // Action to perform for a matching file
945 auto set_filename = [&initinfo_file]( const TString& curpath,
946 const TString& file ) -> Int_t
947 {
948 auto itempath = JoinPath(curpath, file);
949 if( item_exists(itempath) ) {
950 if( item_is_not_dir(itempath) ) {
951 initinfo_file = itempath;
952 return READ_EOF;
953 } else {
954 cerr << itempath << " is a directory. Expected file." << endl;
955 }
956 }
957 return READ_OK;
958 };
959
960 initinfo_file.Clear();
961 for( const auto& path: candidates ) {
962 Int_t ret;
963 if( HasWildcards(path.first) ) {
964 // Traverse directory tree, resolving wildcard/regexp in directory names
965 ret = BuildInputListFromWildcardDir(path, set_filename);
966 } else {
967 // If the directory path contains no wildcards/regexp, simply scan
968 // that directory directly
969 ret = BuildInputListFromTopDir(path, set_filename);
970 }
971 if( ret == READ_EOF ) {
972 // Found a file suitable to provide init info
973 assert(!initinfo_file.IsNull());
974 break;
975 }
976 if( ret != READ_OK )
977 break;
978 }
979 return initinfo_file;
980}
981
982//_____________________________________________________________________________
984{
985 THaPrintOption sopt(opt);
986 sopt.ToUpper();
987 if( sopt.Contains("NAMEDESC") ) {
988 auto files = GetFiles();
989 cout << "\"file://"
990 << ( !files.empty() ? files[0].c_str() : "(not set)" ) << "\"";
991 if( files.size() > 1 )
992 cout << " etc. (" << files.size() << " files)";
993 if( strcmp(GetTitle(), "") != 0 )
994 cout << " \"" << GetTitle() << "\"";
995 return;
996 }
997 THaCodaRun::Print(opt); // NOLINT(bugprone-parent-virtual-call)
998 if( !fPathList.empty() ) {
999 cout << "Search path";
1000 if( fPathList.size() > 1 )
1001 cout << "s:" << endl;
1002 else
1003 cout << ":";
1004 for( const auto& path: fPathList ) {
1005 cout << " " << path << endl;
1006 }
1007 }
1008 PrintFileInfo();
1009 if( fFirstSegment != 0 )
1010 cout << "First segment: " << fFirstSegment << endl;
1011 if( fMaxSegments != 0 )
1012 cout << "Max segments: " << fMaxSegments << endl;
1013 if( fFirstStream != 0 )
1014 cout << "First stream: " << fFirstStream << endl;
1015 if( fMaxStreams != 0 )
1016 cout << "Max streams: " << fMaxStreams << endl;
1018}
1019
1020//_____________________________________________________________________________
1022{
1023 if( !fFileList.empty() ) {
1024 cout << "File name";
1025 if( fFileList.size() > 1 )
1026 cout << "s";
1027 if( any_of(ALL(fFileList),
1028 [this]( const string& f ) { return HasWildcards(f); }) )
1029 cout << (fNameIsRegexp ? " (regexp): " : " (wildcards): ");
1030 else
1031 cout << ": ";
1032 if( fFileList.size() > 1 )
1033 cout << endl;
1034 for( const auto& file: fFileList ) {
1035 cout << " " << file << endl;
1036 }
1037 }
1038}
1039
1040//_____________________________________________________________________________
1042{
1043 for( const auto& stream: fStreams ) {
1044 if( stream.fID >= 0 )
1045 cout << "Stream " << stream.fID;
1046 else
1047 cout << "Default stream";
1048 cout << ": " << endl;
1049 for( const auto& file: stream.fFiles ) {
1050 cout << " " << file.fPath << endl;
1051 }
1052 }
1053}
1054
1055//_____________________________________________________________________________
1057{
1058 fLastUsedStream = -1;
1059 fStreams.clear();
1060 fIsInit = false;
1061}
1062
1063//_____________________________________________________________________________
1065{
1066 // Set the file name pattern for the input file(s).
1067 // This sets to list of files to one entry.
1068 // If the name changes, the existing input, if any, will be closed.
1069 // Return -1 if illegal name, 1 if name not changed, 0 otherwise.
1070
1071 static const char* const here = "MultiFileRun::SetFilename";
1072
1073 if( !name || !*name ) {
1074 Error( here, "Illegal file name." );
1075 return -1;
1076 }
1077
1078 if( fFileList.size() == 1 && fFileList[0] == name )
1079 return 1;
1080
1081 Close();
1082
1083 string str{name};
1084 try {
1085 ExpandFileName(str);
1086 }
1087 catch( std::invalid_argument& e ) {
1088 cerr << e.what() << endl;
1089 return -1;
1090 }
1091 fFileList.assign(1, str);
1092
1093 // Assume we have to reinitialize. A new file name generally means a new
1094 // run date, run number, etc.
1095 ClearStreams();
1096
1098
1099 return 0;
1100}
1101
1102//_____________________________________________________________________________
1103bool MultiFileRun::SetFileList( vector<std::string> filelist )
1104{
1105 if( fFileList == filelist )
1106 return true;
1107 auto expand_name = [this]( string& f) { ExpandFileName(f); };
1108 try {
1109 for_each(ALL(filelist), expand_name);
1110 }
1111 catch( std::invalid_argument& e ) {
1112 cerr << e.what() << endl;
1113 return true;
1114 }
1115 Close();
1116 fFileList = std::move(filelist);
1117 ClearStreams();
1119 return false;
1120}
1121
1122//_____________________________________________________________________________
1123bool MultiFileRun::SetPathList( vector<std::string> pathlist )
1124{
1125 if( fPathList == pathlist )
1126 return true;
1127 auto expand_name = [this]( string& f) { ExpandFileName(f); };
1128 try {
1129 for_each(ALL(pathlist), expand_name);
1130 }
1131 catch( std::invalid_argument& e ) {
1132 cerr << e.what() << endl;
1133 return true;
1134 }
1135 Close();
1136 fPathList = std::move(pathlist);
1137 ClearStreams();
1138 return false;
1139}
1140
1141//_____________________________________________________________________________
1143{
1144 if( n < 0 ) n = 0;
1145 fFirstSegment = n;
1146 ClearStreams();
1147}
1148
1149//_____________________________________________________________________________
1151{
1152 if( n < 0 ) n = 0;
1153 fFirstStream = n;
1154 ClearStreams();
1155}
1156
1157//_____________________________________________________________________________
1159{
1160 if( n < 0 ) n = 0;
1161 fMaxSegments = n;
1162 ClearStreams();
1163}
1164
1165//_____________________________________________________________________________
1167{
1168 if( n < 0 ) n = 0;
1169 fMaxStreams = n;
1170 ClearStreams();
1171}
1172
1173//_____________________________________________________________________________
1174// Set fSegment and fStream to those of the current input.
1175// The value of -1 for either variable means that this info is not specified
1176// (i.e. the filename has no stream or segment number).
1177//
1178// If necessary, this function builds the list of input files.
1179//
1180// Returns true if successful, false otherwise.
1182{
1183 if( fStreams.empty() ) {
1184 Int_t ret = BuildInputList();
1185 if( ret != READ_OK || fStreams.empty() )
1186 return false;
1187 fLastUsedStream = 0;
1188 }
1189 assert(fLastUsedStream >= 0 && fLastUsedStream < SSIZE(fStreams));
1190 const auto& curstr = fStreams[fLastUsedStream];
1191 assert(curstr.fFileIndex < SSIZE(curstr.fFiles));
1192 fSegment = curstr.fFiles[curstr.fFileIndex].fSegment;
1193 fStream = curstr.fID;
1194 return true;
1195}
1196
1197//_____________________________________________________________________________
1199{
1200 bool found = false;
1201 for( const auto& file: fFileList ) {
1202 if( file.length() > 0 && file.front() == '/' && !fPathList.empty() ) {
1203 cerr << "MultiFileRun: Warning: file name " << file
1204 << " is an absolute path, but path list also specified. "
1205 "Will ignore path list for this file." << endl;
1206 found = true;
1207 }
1208 }
1209 return found;
1210}
1211
1212//_____________________________________________________________________________
1213void MultiFileRun::ExpandFileName( string& str ) const
1214{
1215 TString path = str;
1216 if( fNameIsRegexp && path.EndsWith("$") )
1217 path.Chop();
1218
1219 if( gSystem->ExpandPathName(path) ) {
1220 string s = "MultiFileRun: Undefined environment variable in path \"";
1221 s.append(str).append("\"");
1222 throw std::invalid_argument(s);
1223 }
1224 str = path.Data();
1225}
1226
1227//_____________________________________________________________________________
1229{
1230 size_t nfiles = 0;
1231 for( const auto& stream: fStreams ) {
1232 nfiles += stream.fFiles.size();
1233 }
1234 return nfiles;
1235}
1236
1237//_____________________________________________________________________________
1239{
1240 return fStreams.size();
1241}
1242
1243//_____________________________________________________________________________
1245{
1246 Int_t minseg = kMaxInt;
1247 for( const auto& stream: fStreams ) {
1248 for( const auto& file: stream.fFiles ) {
1249 if( file.fSegment < minseg )
1250 minseg = file.fSegment;
1251 }
1252 }
1253 return minseg;
1254}
1255
1256//_____________________________________________________________________________
1258{
1259 Int_t maxseg = kMinInt;
1260 for( const auto& stream: fStreams ) {
1261 for( const auto& file: stream.fFiles ) {
1262 if( file.fSegment > maxseg )
1263 maxseg = file.fSegment;
1264 }
1265 }
1266 return maxseg;
1267}
1268
1269//_____________________________________________________________________________
1271{
1272 Int_t minstr = kMaxInt;
1273 for( const auto& stream: fStreams ) {
1274 if( stream.fID < minstr )
1275 minstr = stream.fID;
1276 }
1277 return minstr;
1278}
1279
1280//_____________________________________________________________________________
1282{
1283 Int_t maxstr = kMinInt;
1284 for( const auto& stream: fStreams ) {
1285 if( stream.fID > maxstr )
1286 maxstr = stream.fID;
1287 }
1288 return maxstr;
1289}
1290
1291//_____________________________________________________________________________
1292vector<string> MultiFileRun::GetFiles() const
1293{
1294 vector<string> files;
1295 for( const auto& stream: fStreams ) {
1296 for( const auto& file: stream.fFiles ) {
1297 files.push_back(file.fPath);
1298 }
1299 }
1300 return files;
1301}
1302
1303//_____________________________________________________________________________
1304MultiFileRun::FileInfo::FileInfo( std::string path, std::string stem, Int_t seg )
1305 : fPath{std::move(path)}
1306 , fStem{std::move(stem)}
1307 , fSegment{seg}
1308{}
1309
1310//_____________________________________________________________________________
1313 , fID{-1}
1314 , fVersion{0}
1315 , fFileIndex{0}
1316 , fEvNum{0}
1317 , fActive{false}
1318{}
1319
1320//_____________________________________________________________________________
1323 , fID{id}
1324 , fVersion{0}
1325 , fFileIndex{0}
1326 , fEvNum{0}
1327 , fActive{false}
1328{}
1329
1330//_____________________________________________________________________________
1333 , fFiles{rhs.fFiles}
1334 , fID{rhs.fID}
1335 , fVersion{rhs.fVersion}
1336 , fFileIndex{rhs.fFileIndex}
1337 , fEvNum{rhs.fEvNum}
1338 , fActive{rhs.fActive}
1339{}
1340
1341//_____________________________________________________________________________
1344{
1345 if( this != &rhs ) {
1347 fFiles = rhs.fFiles;
1348 fID = rhs.fID;
1349 fVersion = rhs.fVersion;
1350 fFileIndex = rhs.fFileIndex;
1351 fEvNum = rhs.fEvNum;
1352 fActive = rhs.fActive;
1353 }
1354 return *this;
1355}
1356
1357//_____________________________________________________________________________
1359{
1360 assert(fCodaData);
1361 if( fCodaData->isOpen() )
1362 return CODA_OK;
1363 fFileIndex = 0;
1364 fActive = true;
1365 return OpenCurrent();
1366}
1367
1368//_____________________________________________________________________________
1370{
1371 assert(fCodaData);
1372 if( fCodaData->isOpen() )
1373 fCodaData->codaClose();
1374 auto& fn = fFiles[fFileIndex].fPath;
1375 return fCodaData->codaOpen(fn.c_str());
1376}
1377
1378//_____________________________________________________________________________
1380{
1381 assert(fCodaData);
1382 if( !fCodaData->isOpen() ) {
1383 cerr << "Not open" << endl;
1384 return CODA_ERROR;
1385 }
1386 if( !fActive )
1387 return CODA_EOF;
1388
1389 Int_t st = CODA_OK;
1390 while( IsGood() ) {
1391 st = fCodaData->codaRead();
1392 if( st == CODA_OK ) {
1393 st = FetchEventNumber();
1394 break;
1395 }
1396 if( st == CODA_EOF ) {
1397 if( ++fFileIndex >= SSIZE(fFiles) ) {
1398 fCodaData->codaClose();
1399 return CODA_EOF;
1400 }
1401 cout << "MultiFileRun::Read: Switching to next segment idx = "
1402 << fFileIndex << ", file = \"" << fFiles[fFileIndex].fPath << "\""
1403 << endl;
1404 st = OpenCurrent();
1405 }
1406 }
1407 return st;
1408}
1409
1410//_____________________________________________________________________________
1412{
1413 assert(fCodaData);
1414 fEvNum = 0;
1415 fFileIndex = 0;
1416 fActive = false;
1417 return fCodaData->codaClose();
1418}
1419
1420//_____________________________________________________________________________
1422{
1423 assert(fCodaData);
1424 return fCodaData->isGood();
1425}
1426
1427//_____________________________________________________________________________
1429{
1430 assert(fCodaData);
1431 assert(fActive);
1432 if( !fCodaData || !fActive )
1433 return nullptr; // if not active, the buffer does not contain valid data
1434 return fCodaData->getEvBuffer();
1435}
1436
1437//_____________________________________________________________________________
1438// Extract even number from CODA 2 format data.
1439// 'evbuf' must hold a physics event.
1440static Int_t GetEvNumV2( const UInt_t* evbuf, UInt_t& num )
1441{
1442 auto evlen = evbuf[0] + 1;
1443 if( evlen < 5 ) {
1444 cerr << "Physics event too short, len = " << evlen << ", need >= 5"
1445 << endl;
1446 return CODA_ERROR;
1447 }
1448 if( evbuf[4] <= num )
1449 cerr << "MultiFileRun::FetchEventNumber: Warning: unexpected "
1450 << "event number change " << num << " -> " << evbuf[4]
1451 << endl;
1452 num = evbuf[4];
1453
1454 return CODA_OK;
1455}
1456
1457//_____________________________________________________________________________
1458// Extract even number from CODA 3 format data.
1459// 'evbuf' must hold a physics event.
1460static Int_t GetEvNumV3( const UInt_t* evbuf, UInt_t& num )
1461{
1462 auto block_size = evbuf[1] & 0xff;
1463 if( block_size == 0 ) {
1464 cerr << "CODA 3 format error: Physics event with block size 0" << endl;
1465 return CODA_ERROR;
1466 }
1467 // The physics event number that we're after is stored in the trigger bank
1468 CodaDecoder::TBOBJ tbank;
1469 try {
1470 tbank.Fill(evbuf + 2, block_size,
1471 /* The TSROC number does not matter as we are not using
1472 its data */21);
1473 }
1474 catch( const CodaDecoder::coda_format_error& e ) {
1475 cerr << "CODA 3 format error: " << e.what() << endl;
1476 return CODA_ERROR;
1477 }
1478 if( tbank.evtNum <= num )
1479 cerr << "MultiFileRun::FetchEventNumber: Warning: unexpected "
1480 << "event number change " << num << " -> " << tbank.evtNum
1481 << endl;
1482 num = tbank.evtNum;
1483
1484 return CODA_OK;
1485}
1486
1487//_____________________________________________________________________________
1488// Test if the current event is a physics event. If so, extract its event
1489// number. This requires some CODA-specific low-level decoding.
1491{
1492 assert(fCodaData && fCodaData->isOpen());
1493 auto buflen = fCodaData->getBuffSize();
1494 if( buflen == 0 ) {
1495 cerr << "Invalid event buffer size = 0" << endl;
1496 return CODA_ERROR;
1497 }
1498 const auto* evbuf = fCodaData->getEvBuffer();
1499 auto evlen = evbuf[0] + 1;
1500 if( evlen > buflen ) {
1501 cerr << "Invalid event length " << evlen
1502 << " > buffer size " << buflen << endl;
1503 return CODA_ERROR;
1504 }
1505 if( evlen < 2 ) {
1506 cerr << "Event too short, len = " << evlen << ", need >= 2" << endl;
1507 return CODA_ERROR;
1508 }
1509 auto tag = evbuf[1] >> 16;
1510 if( fVersion == 2 ) {
1511 auto evtyp = tag;
1512 if( evtyp <= MAX_PHYS_EVTYPE ) {
1513 Int_t ret = GetEvNumV2(evbuf, fEvNum);
1514 if( ret )
1515 return ret;
1516 }
1517 }
1518 else if( fVersion == 3 ) {
1519 auto evtyp = CodaDecoder::InterpretBankTag(tag);
1520 if( evtyp == 1 ) { // CODA 3 physics event
1521 Int_t ret = GetEvNumV3(evbuf, fEvNum);
1522 if( ret )
1523 return ret;
1524 }
1525 }
1526 else {
1527 cerr << "Unsupported CODA version " << fVersion << endl;
1528 return CODA_ERROR;
1529 }
1530 return CODA_OK;
1531}
1532
1533//_____________________________________________________________________________
1535{
1536 static const string nullstr;
1537 if( fFiles.empty() )
1538 return nullstr;
1539 assert(fFileIndex >= 0 && fFileIndex < SSIZE(fFiles));
1540 return fFiles[fFileIndex].fPath;
1541}
1542
1543//_____________________________________________________________________________
1544
1545} //namespace Podd
1546
int Int_t
unsigned int UInt_t
unsigned int fFlags
#define MKCODAFILE
Int_t fVersion
std::string fPath
Definition MultiFileRun.h:5
Bool_t IsGood() const
std::vector< FileInfo > fFiles
Coda data (file)
Int_t OpenCurrent()
Stream has not yet reached EOF.
std::string fStem
Definition MultiFileRun.h:6
UInt_t fEvNum
Index of currently open file.
Int_t fFileIndex
Int_t fSegment
Definition MultiFileRun.h:7
Bool_t fActive
Number of most recent physics event.
Int_t FetchEventNumber()
Int_t fID
ROOT::R::TRInterface & r
#define f(i)
#define c(i)
#define e(i)
bool Bool_t
const Int_t kMinInt
const Int_t kMaxInt
const UInt_t kMaxUInt
int Ssiz_t
const char Option_t
#define TESTBIT(n, i)
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize id
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t UChar_t len
char name[80]
#define CODA_ERROR
Definition THaCodaData.h:30
#define CODA_EOF
Definition THaCodaData.h:29
#define CODA_OK
Definition THaCodaData.h:28
static const char *const here
Definition THaVar.cxx:64
kExecutePermission
kReadPermission
Bool_t R_ISDIR(Int_t mode)
R__EXTERN TSystem * gSystem
uint32_t Fill(const uint32_t *evbuffer, uint32_t blkSize, uint32_t tsroc)
static UInt_t InterpretBankTag(UInt_t tag)
virtual Bool_t IsOpen() const
void AssembleFilePaths(std::vector< path_t > &candidates)
Int_t ForEachMatchItemInDir(const TString &dir, const TRegexp &match_re, const action_t &action)
virtual Int_t Close()
std::pair< TString, TString > path_t
void PrintStreamInfo() const
virtual Int_t FindNextStream() const
Int_t GetLastSegment() const
virtual UInt_t GetEvNum() const
bool SetPathList(std::vector< std::string > pathlist)
UInt_t GetNStreams() const
void SetFirstSegment(Int_t n)
virtual void Clear(Option_t *opt="")
void SetMaxStreams(Int_t n)
std::vector< std::string > GetFiles() const
UInt_t fNevRead
Number of active streams.
MultiFileRun(const char *filenamePattern="", const char *description="", bool is_regex=false)
virtual Int_t BuildInputList()
Number of events read.
virtual Int_t ReadEvent()
virtual Int_t Open()
void PrintFileInfo() const
Int_t ScanForFilename(const path_t &path, bool regex_mode, const action_t &action)
Int_t BuildInputListFromWildcardDir(const path_t &path, const action_t &action)
std::vector< std::string > fFileList
void SetMaxSegments(Int_t n)
virtual void Print(Option_t *opt="") const
virtual Int_t GetDataVersion()
std::vector< StreamInfo > fStreams
std::function< Int_t(const TString &, const TString &)> action_t
bool SetFileList(std::vector< std::string > filelist)
Int_t ScanForSubdirs(const TString &curdir, const std::vector< TString > &splitpath, Int_t level, bool regex_mode, const action_t &action)
Int_t AddFile(const TString &file, const TString &dir)
Int_t GetLastStream() const
Int_t GetStartStream() const
Int_t BuildInputListFromTopDir(const path_t &path, const action_t &action)
bool HasWildcards(const TString &str) const
virtual Int_t SetFilename(const char *name)
virtual const UInt_t * GetEvBuffer() const
std::vector< std::string > fPathList
Int_t GetStartSegment() const
virtual Bool_t FindSegmentNumber()
void SetFirstStream(Int_t n)
virtual Int_t Compare(const TObject *obj) const
Int_t DescendInto(const TString &curpath, const std::vector< TString > &splitpath, Int_t level, const action_t &action)
MultiFileRun & operator=(const THaRunBase &rhs)
UInt_t GetNFiles() const
void ExpandFileName(std::string &str) const
Int_t fNActive
Index of last stream that was read.
virtual TString FindInitInfoFile(const TString &fname)
std::unique_ptr< Decoder::THaCodaData > fCodaData
Definition THaCodaRun.h:35
static Int_t ReturnCode(Int_t coda_retcode)
Bool_t Contains(const std::string &token) const
Bool_t fIsInit
Definition THaRunBase.h:98
Bool_t fOpened
Definition THaRunBase.h:99
Int_t fDataVersion
Definition THaRunBase.h:106
Int_t fStream
Definition THaRun.h:40
virtual TString GetInitInfoFileName(TString fname)
Definition THaRun.cxx:277
TString fFilename
Definition THaRun.h:37
virtual void Clear(Option_t *opt="")
Definition THaRun.cxx:124
static Bool_t StdFindSegmentNumber(const TString &filename, TString &stem, Int_t &segment, Int_t &stream)
Definition THaRun.cxx:442
Int_t fSegment
Definition THaRun.h:39
virtual THaRun & operator=(const THaRunBase &rhs)
Definition THaRun.cxx:93
const char * GetTitle() const override
void Print(Option_t *option="") const override
void SetBit(UInt_t f)
virtual void Error(const char *method, const char *msgfmt,...) const
void ResetBit(UInt_t f)
EStatVal Status()
Ssiz_t Index(const TString &str, Ssiz_t *len, Ssiz_t start=0) const
Ssiz_t Length() const
Bool_t EndsWith(const char *pat, ECaseCompare cmp=kExact) const
void Clear()
const char * Data() const
TString & Chop()
Bool_t IsNull() const
virtual void FreeDirectory(void *dirp)
virtual void * OpenDirectory(const char *name)
virtual int GetPathInfo(const char *path, FileStat_t &buf)
virtual Bool_t AccessPathName(const char *path, EAccessMode mode=kFileExists)
virtual const char * GetDirEntry(void *dirp)
virtual const char * BaseName(const char *pathname)
virtual char * ExpandPathName(const char *path)
virtual TString GetDirName(const char *pathname)
const Int_t n
static const UInt_t MAX_PHYS_EVTYPE
Definition Decoder.h:38
static vector< TString > SplitPath(const TString &path)
static bool item_exists(const TString &itempath)
static bool item_is_not_dir(const TString &itempath)
static TString JoinPath(const TString &base, const TString &to_join)
static bool item_is_dir(const TString &itempath)
static Int_t GetEvNumV2(const UInt_t *evbuf, UInt_t &num)
static TString GetDirName(const char *pathname)
static Int_t CheckSetFileDataVersion(const string &path, Int_t ver, Int_t &data_ver)
static Int_t GetEvNumV3(const UInt_t *evbuf, UInt_t &num)
STL namespace.
const std::string & GetFilename() const
Bool_t fActive
Number of most recent physics event.
Int_t OpenCurrent()
Stream has not yet reached EOF.
StreamInfo & operator=(const StreamInfo &rhs)
UInt_t fEvNum
Index of currently open file.
std::vector< FileInfo > fFiles
Coda data (file)
const UInt_t * GetEvBuffer() const
ClassImp(TPyArg)