// @(#)root/star:$Name: $:$Id: TDataSetIter.cxx,v 1.3 2003/01/27 20:41:36 brun Exp $
// Author: Valery Fine(fine@mail.cern.ch) 03/07/98
// Copyright (C) Valery Fine (Valeri Faine) 1998. All right reserved
#include "Riosfwd.h"
#include "Riostream.h"
#include "TDataSetIter.h"
#include "TBrowser.h"
#include "TSystem.h"
#ifndef WIN32
# ifndef HASSTRCASE
# define HASSTRCASE
# endif
#endif
#ifndef HASSTRCASE
# define strcasecmp(arg1,arg2) stricmp(arg1,arg2)
#endif
TDataSet *TDataSetIter::fNullDataSet = (TDataSet *)(-1);
ClassImp(TDataSetIter)
//////////////////////////////////////////////////////////////////////////
// //
// TDataSetIter //
// //
// TDataSetIter is a class iterator to navigate TDataSet objects //
// via 4 internal pointers : //
// //
// 1. fRootDataSet - "root" dataset //
// 2. fWorkingDataSet - Working dataset //
// 3. fDataSet - the last selected TDataSet //
// 4. fNext - TIter for the the list of the "root" dataset //
// //
//////////////////////////////////////////////////////////////////////////
//______________________________________________________________________________
TDataSetIter::TDataSetIter(TDataSet *link, Bool_t dir)
{
fWorkingDataSet= fRootDataSet =link;
fMaxDepth = fDepth =1;
fDataSet= fNullDataSet ;
fNext = link ? new TIter(link->GetCollection() ,dir):0;
}
//______________________________________________________________________________
TDataSetIter::TDataSetIter(TDataSet *link, Int_t depth, Bool_t dir)
{
fRootDataSet = fWorkingDataSet = link;
fMaxDepth = depth;
fDepth = 1;
fDataSet = fNullDataSet;
fNext = (link)? new TIter(link->GetCollection() ,dir):0;
// Create a DataSet iterator to pass all nodes of the
// "depth" levels
// of TDataSet *link
if (fMaxDepth != 1) {
fNextSet[0] = fNext;
if (fMaxDepth > 100) fMaxDepth = 100;
fDepth = 0;
}
}
//______________________________________________________________________________
TDataSetIter::~TDataSetIter()
{
if (fMaxDepth != 1) {
Int_t level = fDepth;
if (level) level--;
for (Int_t i = level;i>=0;i--) {
TIter *s = fNextSet[i];
if (s) delete s;
}
}
else
SafeDelete(fNext);
fDepth = 0;
}
//______________________________________________________________________________
TDataSet *TDataSetIter::Add(TDataSet *set, TDataSet *dataset)
{
///////////////////////////////////////////////////////////////////////////////
// //
// Add - adds the set to the dataset defined with the second parameters //
// //
// TDataSet dataset != 0 - Add the set to the TDataSet *dataset //
// //
// = 0 - (by default) to the current TDataSet defined //
// with fWorkingDataSet data member //
// //
// returns the pointer to set is success or ZERO poiner //
// ======= //
// //
// Note: If this TDataSetIter is empty (i.e. Cwd() returns 0), the "set" //
// becomes the "root" dataset of this iterator // //
///////////////////////////////////////////////////////////////////////////////
if (!set) return 0;
TDataSet *s = dataset;
if (!s) s = Cwd();
if (s) {
s->Add(set);
s = set;
}
else {
// make the coming dataset the current one for the iterator
s = set;
fRootDataSet = s;
fWorkingDataSet = s;
if (fNext) {
Error("Add","TDataSetIter.has been corrupted ;-!");
delete fNext;
fNext = 0;
}
fNext = new TIter(s->GetCollection() );
}
return s;
}
//______________________________________________________________________________
TDataSet *TDataSetIter::Add(TDataSet *dataset, const Char_t *path)
{
///////////////////////////////////////////////////////////////////////////////
// //
// Add //
// //
// Char_t path != 0 - Add a TDataSet dataset to the TDataSet dataset //
// defined with "path" //
// = 0 - (by default) to the current TDataSet defined //
// with fWorkingDataSet data member //
// //
// returns the dataset is success or ZERO pointer //
// ======= //
// //
///////////////////////////////////////////////////////////////////////////////
if (!dataset) return 0;
TDataSet *set = 0;
if (path && strlen(path)) set = Find(path);
return Add(dataset,set);
}
//______________________________________________________________________________
TDataSet *TDataSetIter::Cd(const Char_t *dirname){
/////////////////////////////////////////////////////////////////////
// //
// TDataSet *TDataSetIter::Cd(const Char_t *dirname) //
// //
// Change the current working directory to dirname //
// //
// Returns the pointer to the new "working" TDataSet //
// ======= 0, if the new directory doesn't exist. //
// //
// Remark: The name = ".." has a special meaning. //
// ------ TDataSetIter::Cd("..") returns the parent set //
// But one still can not use ".." as a legal part //
// of the full path //
/////////////////////////////////////////////////////////////////////
TDataSet *set = 0;
if (strcmp(dirname,".."))
set = Find(dirname);
else
set = fWorkingDataSet->GetParent();
if (set) fWorkingDataSet = set;
return set;
}
//______________________________________________________________________________
TDataSet *TDataSetIter::Cd(TDataSet *ds)
{
/////////////////////////////////////////////////////////////////////
// //
// TDataSet *TDataSetIter::Cd(const TDataSet *ds) //
// //
// Make: Cwd() = ds; //
// Look for the first occurence of the "ds" pointer for the current//
// TDataSet in respect of the Cwd() if any //
// //
// Change the current working directory to ds if present //
// //
// Returns the pointer to the new "working" TDataSet (i.e. ds) //
// ======= 0, if the new directory doesn't exist. //
// //
/////////////////////////////////////////////////////////////////////
TDataSet *nextSet = 0;
if (Cwd()) {
TDataSetIter next(Cwd(),0);
while ( (nextSet = next()) )
if (ds == nextSet) {fWorkingDataSet = ds; break;}
}
return nextSet;
}
//______________________________________________________________________________
TDataSet *TDataSetIter::Dir(Char_t *dirname)
{
//
// Print the names of the TDataSet objects for the datatset named with "dirname"
// apart of TDataSet::Ls() this method prints one level only
//
TDataSet *set = (TDataSet *)fWorkingDataSet;
if (dirname) set = Find(dirname);
if (set) set->ls();
return set;
}
//______________________________________________________________________________
Int_t TDataSetIter::Du() const {
// summarize dataset usage by Herb Ward proposal
if (!fWorkingDataSet) return 0;
TDataSetIter next(fWorkingDataSet,0);
TDataSet *nextset = 0;
Int_t count = 0;
while((nextset = (count) ? next():fWorkingDataSet)) {
count++;
if (nextset->IsFolder()) cout << endl;
TString path = nextset->Path();
cout << setw(2) << next.GetDepth() << ". ";
cout << path << setw(TMath::Max(Int_t(60-strlen(path.Data())),Int_t(0))) << "...";
const Char_t *type = nextset->IsFolder() ? "directory" : "table" ;
cout << setw(10) << type;
cout << " : " << setw(10) << nextset->GetTitle();
cout << endl;
}
return count;
}
//______________________________________________________________________________
TDataSet *TDataSetIter::FindByName(const Char_t *name,const Char_t *path,Option_t *opt)
{ return FindDataSet(name,path,opt);}
//______________________________________________________________________________
TDataSet *TDataSetIter::FindByTitle(const Char_t *title,const Char_t *path,Option_t *opt)
{
TString optt = "-t";
optt += opt;
return FindDataSet(title,path,optt.Data());
}
//______________________________________________________________________________
TDataSet *TDataSetIter::FindDataSet(const Char_t *name,const Char_t *path,Option_t *opt)
{
//
// FindDataSet looks for the object with the name supplied across dataset.
//
// name - the "base" name title (with no path) of the TDataSet (see: opt = -t)
// path - path to start the search from (the current dataset "by default")
// opt = "-i" - case insensitive search
// "-t" - first <name> parameter defines the object "title" rather the object "name"
//
// Note: If the name provided is not unique
// the first found is returned.
//
if (!name || strlen(name) == 0) return 0;
if (strchr(name,'/')) {
Error("FindDataSet","The name of the object <%s> can not contain any "/"",name);
return 0;
}
Bool_t opti = opt ? strcasecmp(opt,"-i") == 0 : kFALSE;
Bool_t optt = opt ? strcasecmp(opt,"-t") == 0 : kFALSE;
TDataSet *startset = 0;
if (path && strlen(path)) startset = Find(path);
else startset = fWorkingDataSet;
if (!startset) return 0;
TDataSet *set = startset;
if ( !((opti && strcasecmp( optt ? set->GetTitle() : set->GetName(),name) == 0 ) ||
(strcmp(optt ? set->GetTitle() : set->GetName(),name) == 0)) )
{
TDataSetIter next(startset,0);
while ((set = next()))
if ( (opti && strcasecmp(optt ? set->GetTitle() : set->GetName(),name) == 0 ) ||
(strcmp(optt ? set->GetTitle() : set->GetName(),name) == 0) ) break;
}
return set;
}
//______________________________________________________________________________
TDataSet *TDataSetIter::FindDataSet(TDataSet *set,const Char_t *path,Option_t *opt)
{
//
// Check whether the object does belong the TDataSet defined with "path"
// opt = "-l" - check the "reference" links only
// "-s" - check the "structural" links only
// = "by default" - checks all links
//
if (!set) return 0;
if (opt) {/* no used */}
TDataSet *startset = 0;
if (path) startset = Find(path);
else startset = fWorkingDataSet;
if (!startset) return 0;
TDataSetIter next(startset);
TDataSet *nextSet = 0;
while ( (nextSet = next()) )
if (set == nextSet) break;
return nextSet;
}
//______________________________________________________________________________
TObject *TDataSetIter::FindObject(const Char_t *name) const
{
// This method is not recommended.
// It is done to back TObject::FindObject method only.
// One is recommnened to use FindByName method instead.
return ((TDataSetIter *)this)->FindByName(name);
}
//______________________________________________________________________________
TObject *TDataSetIter::FindObject(const TObject *dataset) const
{
// This method is not recommended.
// It is done to back TObject::FindObject method only.
// One is recommended to use FindByName method instead.
return ((TDataSetIter *)this)->FindByPointer((TDataSet *)dataset);
}
//______________________________________________________________________________
TDataSet *TDataSetIter::FindByPointer(TDataSet *set,const Char_t *path,Option_t *)
{
//
// Check whether the object does belong the TDataSet defined with "path"
// opt = "-l" - check the "reference" links only
// "-s" - check the "structural" links only
// = "by default" - checks all links
//
if (!set) return 0;
TDataSet *startset = 0;
if (path && path[0]) startset = Find(path);
else startset = fWorkingDataSet;
if (!startset) return 0;
TDataSetIter next(startset);
TDataSet *nextSet = 0;
while ( (nextSet = next()) )
if (set == nextSet) break;
return nextSet;
}
//______________________________________________________________________________
Int_t TDataSetIter::Flag(const Char_t *path,UInt_t flag,TDataSet::EBitOpt reset)
{
TDataSet *set = Find(path);
if (set) set->SetBit(flag,reset);
return 0;
}
//______________________________________________________________________________
Int_t TDataSetIter::Flag(TDataSet *dataset,UInt_t flag,TDataSet::EBitOpt reset)
{
if (dataset) dataset->SetBit(flag,reset);
return 0;
}
//______________________________________________________________________________
TDataSet *TDataSetIter::Ls(const Char_t *dirname,Option_t *opt) const {
//
// Ls(const Char_t *dirname,Option_t)
//
// Prints the list of the TDataSet defined with dirname
//
// dirname = 0 - prints the current dataset
// dirname[0] = '/' - print TDataSet defined with dirname
// dirname[0] != '/' - prints DataSet with respect of the current class
//
TDataSet *set= 0;
if (dirname && strlen(dirname)) set = ((TDataSetIter*)this)->Find(dirname);
if (!set && dirname==0) set=Cwd();
if (set) set->ls(opt);
return set;
}
//______________________________________________________________________________
TDataSet *TDataSetIter::Ls(const Char_t *dirname,Int_t depth) const {
//
// Ls(const Char_t *dirname,Int_t depth)
//
// Prints the list of the TDataSet defined with dirname
// Returns the dataset defined by "path" or Cwd();
//
// dirname = 0 - prints the current dataset
// dirname[0] = '/' - print TDataSet defined with dirname
// dirname[0] != '/' - prints DataSet with respect of the current class
//
// depth = 0 - print all level of the TDataSet defined with dirname
// > 0 - print depth levels at most of the dirname TDataSet
//
TDataSet *set= fWorkingDataSet;
if (dirname && strlen(dirname)) set= ((TDataSetIter*)this)->Find(dirname);
if (set) set->ls(depth);
return set;
}
//______________________________________________________________________________
TDataSet *TDataSetIter::Mkdir(const Char_t *dirname)
{
TDataSet *set = 0;
set = Find(dirname,0,kTRUE);
if (!fNext) Reset(); // Create a new iterator
// If this dataset is first one then make it the root and working
if (!fRootDataSet ) fRootDataSet = set;
if (!fWorkingDataSet) fWorkingDataSet = fRootDataSet;
return set;
}
//______________________________________________________________________________
void TDataSetIter::Notify(TDataSet *)
{
//
// Notify(TDataSet *dataset)
//
// This dummy method is called when TDataSetIter::Find dives in "dataset"
// to look for thew next level of the dataset's
// printf("void TDataSetIter::Notify(TDataSet *) level: %d %sn",fDepth,ds->GetName());
//
}
//______________________________________________________________________________
TDataSet *TDataSetIter::Rmdir(TDataSet *dataset,Option_t *)
{
//
// Remove the TDataSet *dataset from the current dataset
// If the current dataset is the deleted dataset the its parent
// becomes the "current dataset" or 0 if this dataset has no parent.
//
// returns: the "current dataset" pointer
//
//
TDataSet *set = dataset;
if (set) {
if (set == fWorkingDataSet) {
fWorkingDataSet = set->GetParent();
}
if (set == fRootDataSet) {
fRootDataSet = 0;
}
delete set;
}
return Cwd();
}
//______________________________________________________________________________
TDataSet *TDataSetIter::Next( TDataSet::EDataSetPass mode)
{
////////////////////////////////////////////////////////////////////////////////
//
// returns the pointer the "next" TDataSet object
// = 0 if all objects have been returned.
//
// mode = kContinue - default normal mode
// kPrune - stop passing of the current branch but continue with the next one if any
// kUp - break passing, return to the previous level, then continue
// all other - are treated as "kContinue"
//
////////////////////////////////////////////////////////////////////////////////
if (fMaxDepth==1) fDataSet = fNext ? NextDataSet(*fNext) :0;
else {
// Check the whether the next level does exist
if (fDepth==0) fDepth = 1;
if (fDataSet && fDataSet != fNullDataSet &&
(fDepth < fMaxDepth || fMaxDepth ==0) && mode == TDataSet::kContinue )
{
// create the next level iterator, go deeper
TSeqCollection *list = fDataSet->GetCollection();
// Look for the next level
if (list && list->GetSize() ) {
fDepth++;
if (fDepth >= 100) {
Error("Next()"
," too many (%d) nested levels of your TDataSet has been detected",fDepth);
return 0;
}
fNextSet[fDepth-1] = new TIter(list);
}
}
// Pick the next object of the current level
TIter *next = fNextSet[fDepth-1];
if (next) {
fDataSet = 0;
if (mode != TDataSet::kUp) fDataSet = NextDataSet(*next);
// Go upstair if the current one has been escaped
if (!fDataSet) {
// go backwards direction
while (!fDataSet && fDepth > 1) {
fDepth--;
delete next;
next = fNextSet[fDepth-1];
TDataSet *set = NextDataSet(*next);
if (set)
fDataSet = set;
}
}
}
}
return (TDataSet *)fDataSet;
}
//______________________________________________________________________________
TDataSet *TDataSetIter::NextDataSet(TIter &next){
TDataSet *ds = (TDataSet *)next();
if (ds) Notify(ds);
return ds;
}
//______________________________________________________________________________
TDataSet *TDataSetIter::NextDataSet(Int_t nDataSet)
{
// Pick the next object of the level provided
TIter *next = fNextSet[nDataSet];
if (next) return NextDataSet(*next);
return 0;
}
//______________________________________________________________________________
TDataSet *TDataSetIter::FindByPath(const Char_t *path, TDataSet *rootset,Bool_t mkdir)
{ return Find(path,rootset,mkdir);}
//______________________________________________________________________________
TDataSet *TDataSetIter::Find(const Char_t *path, TDataSet *rootset,
Bool_t mkdirflag,Bool_t titleFlag)
{
////////////////////////////////////////////////////////////////////////////////
// //
// titleFlag = kFALSE; use object name as key (by default) //
// kTRUE; use object title as key and ignore mkdirFlag //
// //
// "path" ::= <relative path> | <absolute path> | <empty> //
// //
// "relative path" ::= <dataset name> | <dataset name>/<dataset name> //
// //
// "absolute path" ::= /<relative path> //
// "empty" ::= zero pointer | pointer to zero length string //
// //
// "relative path": the search is done against of fWorkingDataSet data mem //
// "absolute path": the search is done against of fRootDataSet data mem //
// "empty path" : no search is done just next TDataSet is returned if any //
// //
// Remark: This version can not treat any "special name" like "..", ".", etc //
// ------ //
////////////////////////////////////////////////////////////////////////////////
TDataSet *dataset=0,*dsnext=0,*ds=0;
Int_t len=0,nextlen=0,yes=0,anywhere=0,rootdir=0;
const Char_t *name=0,*nextname=0;
TSeqCollection *tl=0;
name = path;
if (!name) return rootset;
dataset = rootset;
if (!dataset) {// Starting point
rootdir = 1999;
dataset = (path[0]=='/') ? fRootDataSet:fWorkingDataSet;}
if (name[0] == '/') name++;
if (!strncmp(name,".*/",3)) {anywhere=1998; name +=3;}
len = strcspn(name," /");
if (!len) return dataset;
if (!dataset) goto NOTFOUND;
// Check name of root directory
if (rootdir)
{
nextname = titleFlag ? dataset->GetTitle() : dataset->GetName();
nextlen = strlen(nextname);
if (nextlen==len && !strncmp(name,nextname,len))
return Find(name+len,dataset,mkdirflag,titleFlag);
}
tl = dataset->GetCollection();
if (tl) {
TIter next(tl);
while ( (dsnext = NextDataSet(next)) )
{ //horisontal loop
nextname = titleFlag ? dataset->GetTitle() : dsnext->GetName();
if (!nextname) continue;
yes = name[0]=='*'; // wildcard test
if (!yes) { // real test
nextlen = strlen(nextname);
yes = (len == nextlen);
if (yes)
yes = !strncmp(name,nextname,len);
}
if (yes)
{//go down
if (fDepth == 0) fDepth = 1;
Notify(dsnext);
fDepth++;
ds = Find(name+len,dsnext,mkdirflag,titleFlag);
fDepth--;
if (ds)
return ds;
}
if (!anywhere) continue; // next horizontal
ds = Find(name,dsnext,mkdirflag,titleFlag);
if (ds)
return ds;
} // end of while
}
NOTFOUND:
if (mkdirflag && !titleFlag)
{
// create dir the same type as the type of the fRootDataSet if present
// Create TDataSet by default.
char buf[512];buf[0]=0; strncat(buf,name,len);
if (!fRootDataSet)
ds = new TDataSet(buf);
else {
ds = fRootDataSet->Instance();
ds->SetName(buf);
}
if (!fRootDataSet) fRootDataSet = ds;
if (!fWorkingDataSet) fWorkingDataSet = ds;
if (dataset)
dataset->Add(ds);
else {
dataset = ds;
name +=len;
}
return Find(name,dataset,mkdirflag);
}
return 0;
}
//______________________________________________________________________________
void TDataSetIter::Reset(TDataSet *l, int depth)
{
//
// TDataSet *l != 0 means the new start pointer
// depth != 0 means the new value for the depth
// otherwise the privious one is used;
//
fDataSet = fNullDataSet;
if (fMaxDepth != 1) {
// clean all interators
Int_t level = fDepth;
if (level) level--;
for (int i = level;i>=0;i--) {
TIter *s = fNextSet[i];
if (s) delete s;
}
fNext = 0; // this iterator has been deleted in the loop above
}
fDepth = 0;
if (l) {
fRootDataSet = l;
fWorkingDataSet = l;
SafeDelete(fNext);
if (fRootDataSet->GetCollection() )
fNext = new TIter(fRootDataSet->GetCollection() );
}
else {
fWorkingDataSet = fRootDataSet;
if (fNext)
fNext->Reset();
else if (fRootDataSet && fRootDataSet->GetCollection() )
fNext = new TIter(fRootDataSet->GetCollection() );
}
// set the new value of the maximum depth to bypass
if (depth) fMaxDepth = depth;
}
//______________________________________________________________________________
TDataSet *TDataSetIter::Shunt(TDataSet *set, TDataSet *dataset)
{
///////////////////////////////////////////////////////////////////////////////
// //
// Shunt - moves the set to the dataset defined with the second parameters //
// //
// TDataSet dataset != 0 - Add the set to the TDataSet *dataset //
// //
// = 0 - (by default) to the current TDataSet defined //
// with fWorkingDataSet data member //
// //
// returns the pointer to set if successful or ZERO pointer //
// ======= //
// //
// Note: If this TDataSetIter is empty (i.e. Cwd() returns 0), the "set" //
// becomes the "root" dataset of this iterator // //
///////////////////////////////////////////////////////////////////////////////
if (!set) return 0;
TDataSet *s = dataset;
if (!s) s = Cwd();
if (s) {
s->Shunt(set);
s = set;
}
else {
// make the coming dataset the current one for the iterator
s = set;
fRootDataSet = s;
fWorkingDataSet = s;
if (fNext) {
Error("Shunt","TDataSetIter.has been corrupted ;-!");
delete fNext;
fNext = 0;
}
fNext = new TIter(s->GetCollection() );
}
return s;
}
//______________________________________________________________________________
TDataSet *TDataSetIter::Shunt(TDataSet *dataset, const Char_t *path)
{
///////////////////////////////////////////////////////////////////////////////
// //
// Shunt //
// //
// Char_t path != 0 - Move a TDataSet dataset from its parent to //
// the TDataSet dataset //
// defined with "path" //
// = 0 - (by default) to the current TDataSet defined //
// with fWorkingDataSet data member //
// //
// returns the dataset is success or ZERO pointer //
// ======= //
// //
///////////////////////////////////////////////////////////////////////////////
if (!dataset) return 0;
TDataSet *set = 0;
if (path && strlen(path)) set = Find(path);
return Shunt(dataset,set);
}
//______________________________________________________________________________
TDataSet *TDataSetIter::operator[](const Char_t *path)
{
//
// operator [] returns the pointer to the TDataSet if it does contain
// any data (TTable for example)
//
// Input:
// path = The path to the dataset to find
//
// Output:
// pointer to the dataset if it found and
// its TDataSet::HasData() method returns non-zero
// (see for example TTable::HasData() )
TDataSet *dataSet = Find(path);
if (dataSet && dataSet->HasData()) return dataSet;
return 0;
}
ROOT page - Class index - Top of the page
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.