// @(#)root/star:$Name:  $:$Id: TDataSetIter.cxx,v 1.2 2000/09/05 09:18:42 brun Exp $
// Author: Valery Fine(fine@mail.cern.ch)   03/07/98
// Copyright (C) Valery Fine (Valeri Faine) 1998. All right reserved

#include <iostream.h>
#include <iomanip.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::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 (with no path) of the TDataSet
  // path        - path to start the search from (the current dataset "by default")
  // opt = "-i"  - case insensitive search
  //
  // 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;

  TDataSet *startset = 0;
  if (path && strlen(path)) startset = Find(path);
  else                      startset = fWorkingDataSet;
  if (!startset) return 0;

  TDataSet *set = startset;
  if ( !((opti && strcasecmp(set->GetName(),name) == 0 ) ||
          (strcmp(set->GetName(),name) == 0)) )
  {
    TDataSetIter next(startset,0);
    while ((set = next()))
       if ( (opti && strcasecmp(set->GetName(),name) == 0 ) ||
            (strcmp(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;

  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;
}

//______________________________________________________________________________
 Int_t TDataSetIter::Flag(const Char_t *path,UInt_t flag,EBitOpt reset)
{
  TDataSet *set = Find(path);
  if (set) set->SetBit(flag,reset);
  return 0;
}
//______________________________________________________________________________
 Int_t TDataSetIter::Flag(TDataSet *dataset,UInt_t flag,EBitOpt reset)
{
  if (dataset) dataset->SetBit(flag,reset);
  return 0;
}

//______________________________________________________________________________
 TDataSet *TDataSetIter::Ls(const Char_t *dirname,Option_t *opt) {
//
//   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 = 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) {
//
//   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= 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());
  //
}

//______________________________________________________________________________
 Int_t TDataSetIter::Rmdir(TDataSet *dataset,Option_t *)
{
//
//  Remove the TDataSet *dataset from the current dataset
//
  TDataSet *set = dataset;
  if (set) {
    delete set;
    if (set == fRootDataSet) fRootDataSet = 0;
    fWorkingDataSet = fRootDataSet;
  }
  return (Int_t)dataset;
}

//______________________________________________________________________________
 TDataSet *TDataSetIter::Next( 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 == 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 != 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)
{
////////////////////////////////////////////////////////////////////////////////
//                                                                            //
//           "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 = dataset->GetName();
     nextlen  = strlen(nextname);
     if (nextlen==len && !strncmp(name,nextname,len))
        return Find(name+len,dataset,mkdirflag);
   }

   tl = dataset->GetCollection();
   if (tl) {
     TIter next(tl);
     while ( (dsnext = NextDataSet(next)) )
     { //horisontal loop
        nextname = 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);
          fDepth--;
          if (ds)
             return ds;
        }

        if (!anywhere) continue;        // next horizontal
        ds = Find(name,dsnext,mkdirflag);
        if (ds)
             return ds;
     }                                  // end of while
   }

NOTFOUND:
   if (mkdirflag)
   {
     // create dir
     char buf[512];buf[0]=0; strncat(buf,name,len);
     ds = new TDataSet(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.