TDirectory.cxx

Go to the documentation of this file.
00001 // @(#)root/base:$Id: TDirectory.cxx 37531 2010-12-10 20:38:06Z pcanal $
00002 // Author: Rene Brun   28/11/94
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 #include "Riostream.h"
00013 #include "Strlen.h"
00014 #include "TDirectory.h"
00015 #include "TClassTable.h"
00016 #include "TInterpreter.h"
00017 #include "THashList.h"
00018 #include "TBrowser.h"
00019 #include "TROOT.h"
00020 #include "TError.h"
00021 #include "TClass.h"
00022 #include "TRegexp.h"
00023 #include "TSystem.h"
00024 #include "TVirtualMutex.h"
00025 
00026 TDirectory    *gDirectory;      //Pointer to current directory in memory
00027 Bool_t TDirectory::fgAddDirectory = kTRUE;
00028 
00029 const Int_t  kMaxLen = 2048;
00030 
00031 //______________________________________________________________________________
00032 //Begin_Html
00033 /*
00034 <img src="gif/tdirectory_classtree.gif">
00035 */
00036 //End_Html
00037 
00038 ClassImp(TDirectory)
00039 
00040 //______________________________________________________________________________
00041 //
00042 
00043 //______________________________________________________________________________
00044    TDirectory::TDirectory() : TNamed(), fMother(0),fList(0),fContext(0)
00045 {
00046 //*-*-*-*-*-*-*-*-*-*-*-*Directory default constructor-*-*-*-*-*-*-*-*-*-*-*-*
00047 //*-*                    =============================
00048 }
00049 
00050 //______________________________________________________________________________
00051 TDirectory::TDirectory(const char *name, const char *title, Option_t * /*classname*/, TDirectory* initMotherDir)
00052    : TNamed(name, title), fMother(0), fList(0),fContext(0)
00053 {
00054 //*-*-*-*-*-*-*-*-*-*-*-* Create a new Directory *-*-*-*-*-*-*-*-*-*-*-*-*-*
00055 //*-*                     ======================
00056 //  A new directory with name,title is created in the current directory
00057 //  The directory header information is immediately saved in the file
00058 //  A new key is added in the parent directory
00059 //
00060 //  When this constructor is called from a class directly derived
00061 //  from TDirectory, the third argument classname MUST be specified.
00062 //  In this case, classname must be the name of the derived class.
00063 //
00064 //  Note that the directory name cannot contain slashes.
00065 //
00066    if (initMotherDir==0) initMotherDir = gDirectory;
00067 
00068    if (strchr(name,'/')) {
00069       ::Error("TDirectory::TDirectory","directory name (%s) cannot contain a slash", name);
00070       gDirectory = 0;
00071       return;
00072    }
00073    if (strlen(GetName()) == 0) {
00074       ::Error("TDirectory::TDirectory","directory name cannot be \"\"");
00075       gDirectory = 0;
00076       return;
00077    }
00078 
00079    Build(initMotherDir ? initMotherDir->GetFile() : 0, initMotherDir);
00080 
00081    R__LOCKGUARD2(gROOTMutex);
00082 }
00083 
00084 //______________________________________________________________________________
00085 TDirectory::TDirectory(const TDirectory &directory) : TNamed(directory)
00086 {
00087    // Copy constructor.
00088    directory.Copy(*this);
00089 }
00090 
00091 //______________________________________________________________________________
00092 TDirectory::~TDirectory()
00093 {
00094    // -- Destructor.
00095 
00096    if (!gROOT) {
00097       delete fList;
00098       return; //when called by TROOT destructor
00099    }
00100 
00101    if (fList) {
00102       fList->Delete("slow");
00103       SafeDelete(fList);
00104    }
00105 
00106    CleanTargets();
00107 
00108    TDirectory* mom = GetMotherDir();
00109 
00110    if (mom) {
00111       mom->Remove(this);
00112    }
00113 
00114    if (gDebug) {
00115       Info("~TDirectory", "dtor called for %s", GetName());
00116    }
00117 }
00118 
00119 //______________________________________________________________________________
00120 void TDirectory::AddDirectory(Bool_t add)
00121 {
00122 // Sets the flag controlling the automatic add objects like histograms, TGraph2D, etc
00123 // in memory
00124 //
00125 // By default (fAddDirectory = kTRUE), these objects are automatically added
00126 // to the list of objects in memory.
00127 // Note that in the classes like TH1, TGraph2D supporting this facility,
00128 // one object can be removed from its support directory
00129 // by calling object->SetDirectory(0) or object->SetDirectory(dir) to add it
00130 // to the list of objects in the directory dir.
00131 //
00132 //  NOTE that this is a static function. To call it, use;
00133 //     TDirectory::AddDirectory
00134 
00135    fgAddDirectory = add;
00136 }
00137 
00138 //______________________________________________________________________________
00139 Bool_t TDirectory::AddDirectoryStatus()
00140 {
00141    //static function: see TDirectory::AddDirectory for more comments
00142    return fgAddDirectory;
00143 }
00144 
00145 //______________________________________________________________________________
00146 void TDirectory::Append(TObject *obj, Bool_t replace /* = kFALSE */)
00147 {
00148    // Append object to this directory.
00149    //
00150    // If replace is true:
00151    //   remove any existing objects with the same same (if the name is not ""
00152 
00153    if (obj == 0 || fList == 0) return;
00154 
00155    if (replace && obj->GetName() && obj->GetName()[0]) {
00156       TObject *old;
00157       while (0!=(old = GetList()->FindObject(obj->GetName()))) {
00158          Warning("Append","Replacing existing %s: %s (Potential memory leak).",
00159                  obj->IsA()->GetName(),obj->GetName());
00160          ROOT::DirAutoAdd_t func = old->IsA()->GetDirectoryAutoAdd();
00161          if (func) {
00162             func(old,0);
00163          } else {
00164             Remove(old);
00165          }
00166       }
00167    }
00168 
00169    fList->Add(obj);
00170    obj->SetBit(kMustCleanup);
00171 }
00172 
00173 //______________________________________________________________________________
00174 void TDirectory::Browse(TBrowser *b)
00175 {
00176    // Browse the content of the directory.
00177 
00178    if (b) {
00179       TObject *obj = 0;
00180       TIter nextin(fList);
00181 
00182       cd();
00183 
00184       //Add objects that are only in memory
00185       while ((obj = nextin())) {
00186          b->Add(obj, obj->GetName());
00187       }
00188    }
00189 }
00190 
00191 //______________________________________________________________________________
00192 void TDirectory::Build(TFile* /*motherFile*/, TDirectory* motherDir)
00193 {
00194 //*-*-*-*-*-*-*-*-*-*-*-*Initialise directory to defaults*-*-*-*-*-*-*-*-*-*
00195 //*-*                    ================================
00196 
00197    // If directory is created via default ctor (when dir is read from file)
00198    // don't add it here to the directory since its name is not yet known.
00199    // It will be added to the directory in TKey::ReadObj().
00200 
00201    if (motherDir && strlen(GetName()) != 0) motherDir->Append(this);
00202 
00203    fList       = new THashList(100,50);
00204    fMother     = motherDir;
00205    SetBit(kCanDelete);
00206 }
00207 
00208 //______________________________________________________________________________
00209 void TDirectory::CleanTargets()
00210 {
00211    // Clean the pointers to this object (gDirectory, TContext, etc.)
00212 
00213    while (fContext) {
00214       fContext->fDirectory = 0;
00215       fContext = fContext->fNext;
00216    }
00217 
00218    if (gDirectory == this) {
00219       TDirectory *cursav = GetMotherDir();
00220       if (cursav && cursav != this) {
00221          cursav->cd();
00222       } else {
00223          if (this == gROOT) {
00224             gDirectory = 0;
00225          } else {
00226             gROOT->cd();
00227          }
00228       }
00229    }
00230 }
00231 
00232 //______________________________________________________________________________
00233 TObject *TDirectory::CloneObject(const TObject *obj, Bool_t autoadd /* = kTRUE */)
00234 {
00235    // Clone an object.
00236    // This function is called when the directory is not a TDirectoryFile.
00237    // This version has to load the I/O package, hence via CINT
00238    // 
00239    // If autoadd is true and if the object class has a
00240    // DirectoryAutoAdd function, it will be called at the end of the
00241    // function with the parameter gDirector.  This usually means that
00242    // the object will be appended to the current ROOT directory.
00243 
00244    // if no default ctor return immediately (error issued by New())
00245    char *pobj = (char*)obj->IsA()->New();
00246    if (!pobj) return 0;
00247    
00248    Int_t baseOffset = obj->IsA()->GetBaseClassOffset(TObject::Class());
00249    if (baseOffset==-1) {
00250       // cl does not inherit from TObject.
00251       // Since this is not supported in this function, the only reason we could reach this code
00252       // is because something is screwed up in the ROOT code.
00253       Fatal("CloneObject","Incorrect detection of the inheritance from TObject for class %s.\n",
00254             obj->IsA()->GetName());
00255    }
00256    TObject *newobj = (TObject*)(pobj+baseOffset);
00257 
00258    //create a buffer where the object will be streamed
00259    //We are forced to go via the I/O package (ie TBufferFile).
00260    //Invoking TBufferFile via CINT will automatically load the I/O library
00261    TBuffer *buffer = (TBuffer*)gROOT->ProcessLine(Form("new TBufferFile(%d,10000);",TBuffer::kWrite));
00262    if (!buffer) return 0;
00263    buffer->MapObject(obj);  //register obj in map to handle self reference
00264    const_cast<TObject*>(obj)->Streamer(*buffer);
00265 
00266    // read new object from buffer
00267    buffer->SetReadMode();
00268    buffer->ResetMap();
00269    buffer->SetBufferOffset(0);
00270    buffer->MapObject(newobj);  //register obj in map to handle self reference
00271    newobj->Streamer(*buffer);
00272    newobj->ResetBit(kIsReferenced);
00273    newobj->ResetBit(kCanDelete);
00274 
00275    delete buffer;
00276    if (autoadd) {
00277       ROOT::DirAutoAdd_t func = obj->IsA()->GetDirectoryAutoAdd();
00278       if (func) {
00279          func(newobj,this);
00280       }
00281    }
00282    return newobj;
00283 }
00284 
00285 
00286 //______________________________________________________________________________
00287 TDirectory *TDirectory::GetDirectory(const char *apath,
00288                                      Bool_t printError, const char *funcname)
00289 {
00290    // Find a directory using apath.
00291    // It apath is null or empty, returns "this" directory.
00292    // Otherwie use apath to find a directory.
00293    // The absolute path syntax is:
00294    //    file.root:/dir1/dir2
00295    // where file.root is the file and /dir1/dir2 the desired subdirectory
00296    // in the file. Relative syntax is relative to "this" directory. E.g:
00297    // ../aa.
00298    // Returns 0 in case path does not exist.
00299    // If printError is true, use Error with 'funcname' to issue an error message.
00300 
00301    Int_t nch = 0;
00302    if (apath) nch = strlen(apath);
00303    if (!nch) {
00304       return this;
00305    }
00306 
00307    if (funcname==0 || strlen(funcname)==0) funcname = "GetDirectory";
00308 
00309    TDirectory *result = this;
00310 
00311    char *path = new char[nch+1]; path[0] = 0;
00312    if (nch) strlcpy(path,apath,nch+1);
00313    char *s = (char*)strrchr(path, ':');
00314    if (s) {
00315       *s = '\0';
00316       R__LOCKGUARD2(gROOTMutex);
00317       TDirectory *f = (TDirectory *)gROOT->GetListOfFiles()->FindObject(path);
00318       if (!f && !strcmp(gROOT->GetName(), path)) f = gROOT;
00319       if (s) *s = ':';
00320       if (f) {
00321          result = f;
00322          if (s && *(s+1)) result = f->GetDirectory(s+1,printError,funcname);
00323          delete [] path; return result;
00324       } else {
00325          if (printError) Error(funcname, "No such file %s", path);
00326          delete [] path; return 0;
00327       }
00328    }
00329 
00330    // path starts with a slash (assumes current file)
00331    if (path[0] == '/') {
00332       TDirectory *td = gROOT;
00333       result = td->GetDirectory(path+1,printError,funcname);
00334       delete [] path; return result;
00335    }
00336 
00337    TObject *obj;
00338    char *slash = (char*)strchr(path,'/');
00339    if (!slash) {                     // we are at the lowest level
00340       if (!strcmp(path, "..")) {
00341          result = GetMotherDir();
00342          delete [] path; return result;
00343       }
00344       obj = Get(path);
00345       if (!obj) {
00346          if (printError) Error(funcname,"Unknown directory %s", path);
00347          delete [] path; return 0;
00348       }
00349 
00350       //Check return object is a directory
00351       if (!obj->InheritsFrom(TDirectory::Class())) {
00352          if (printError) Error(funcname,"Object %s is not a directory", path);
00353          delete [] path; return 0;
00354       }
00355       delete [] path; return (TDirectory*)obj;
00356    }
00357 
00358    TString subdir(path);
00359    slash = (char*)strchr(subdir.Data(),'/');
00360    *slash = 0;
00361    //Get object with path from current directory/file
00362    if (!strcmp(subdir, "..")) {
00363       TDirectory* mom = GetMotherDir();
00364       if (mom)
00365          result = mom->GetDirectory(slash+1,printError,funcname);
00366       delete [] path; return result;
00367    }
00368    obj = Get(subdir);
00369    if (!obj) {
00370       if (printError) Error(funcname,"Unknown directory %s", subdir.Data());
00371       delete [] path; return 0;
00372    }
00373 
00374    //Check return object is a directory
00375    if (!obj->InheritsFrom(TDirectory::Class())) {
00376       if (printError) Error(funcname,"Object %s is not a directory", subdir.Data());
00377       delete [] path; return 0;
00378    }
00379    result = ((TDirectory*)obj)->GetDirectory(slash+1,printError,funcname);
00380    delete [] path; return result;
00381 }
00382 
00383 //______________________________________________________________________________
00384 Bool_t TDirectory::cd(const char *path)
00385 {
00386    // Change current directory to "this" directory . Using path one can
00387    // change the current directory to "path". The absolute path syntax is:
00388    // file.root:/dir1/dir2
00389    // where file.root is the file and /dir1/dir2 the desired subdirectory
00390    // in the file. Relative syntax is relative to "this" directory. E.g:
00391    // ../aa. Returns kTRUE in case of success.
00392 
00393    return cd1(path);
00394 }
00395 
00396 //______________________________________________________________________________
00397 Bool_t TDirectory::cd1(const char *apath)
00398 {
00399    // Change current directory to "this" directory . Using path one can
00400    // change the current directory to "path". The absolute path syntax is:
00401    // file.root:/dir1/dir2
00402    // where file.root is the file and /dir1/dir2 the desired subdirectory
00403    // in the file. Relative syntax is relative to "this" directory. E.g:
00404    // ../aa. Returns kFALSE in case path does not exist.
00405 
00406    Int_t nch = 0;
00407    if (apath) nch = strlen(apath);
00408    if (!nch) {
00409       gDirectory = this;
00410       return kTRUE;
00411    }
00412 
00413    TDirectory *where = GetDirectory(apath,kTRUE,"cd");
00414    if (where) {
00415       where->cd();
00416       return kTRUE;
00417    }
00418    return kFALSE;
00419 }
00420 
00421 //______________________________________________________________________________
00422 Bool_t TDirectory::Cd(const char *path)
00423 {
00424    // Change current directory to "path". The absolute path syntax is:
00425    // file.root:/dir1/dir2
00426    // where file.root is the file and /dir1/dir2 the desired subdirectory
00427    // in the file. Relative syntax is relative to the current directory
00428    // gDirectory, e.g.: ../aa. Returns kTRUE in case of success.
00429 
00430    return Cd1(path);
00431 }
00432 
00433 //______________________________________________________________________________
00434 Bool_t TDirectory::Cd1(const char *apath)
00435 {
00436    // Change current directory to "path". The path syntax is:
00437    // file.root:/dir1/dir2
00438    // where file.root is the file and /dir1/dir2 the desired subdirectory
00439    // in the file. Returns kFALSE in case path does not exist.
00440 
00441    // null path is always true (i.e. stay in the current directory)
00442    Int_t nch = 0;
00443    if (apath) nch = strlen(apath);
00444    if (!nch) return kTRUE;
00445 
00446    TDirectory *where = gDirectory->GetDirectory(apath,kTRUE,"Cd");
00447    if (where) {
00448       where->cd();
00449       return kTRUE;
00450    }
00451    return kFALSE;
00452 }
00453 
00454 //______________________________________________________________________________
00455 void TDirectory::Clear(Option_t *)
00456 {
00457 //*-*-*-*Delete all objects from a Directory list-*-*-*-*-*
00458 //*-*    =======================================
00459 
00460    if (fList) fList->Clear();
00461 
00462 }
00463 
00464 //______________________________________________________________________________
00465 void TDirectory::Close(Option_t *)
00466 {
00467    // -- Delete all objects from memory and directory structure itself.
00468 
00469    if (!fList) {
00470       return;
00471    }
00472 
00473    // Save the directory key list and header
00474    Save();
00475 
00476    Bool_t fast = kTRUE;
00477    TObjLink *lnk = fList->FirstLink();
00478    while (lnk) {
00479       if (lnk->GetObject()->IsA() == TDirectory::Class()) {fast = kFALSE;break;}
00480       lnk = lnk->Next();
00481    }
00482    // Delete objects from directory list, this in turn, recursively closes all
00483    // sub-directories (that were allocated on the heap)
00484    // if this dir contains subdirs, we must use the slow option for Delete!
00485    // we must avoid "slow" as much as possible, in particular Delete("slow")
00486    // with a large number of objects (eg >10^5) would take for ever.
00487    if (fast) fList->Delete();
00488    else      fList->Delete("slow");
00489 
00490    CleanTargets();
00491 }
00492 
00493 //______________________________________________________________________________
00494 void TDirectory::DeleteAll(Option_t *)
00495 {
00496    // -- Delete all objects from memory.
00497 
00498    fList->Delete("slow");
00499 }
00500 
00501 //______________________________________________________________________________
00502 void TDirectory::Delete(const char *namecycle)
00503 {
00504 //*-*-*-*-*-*-*-* Delete Objects or/and keys in a directory *-*-*-*-*-*-*-*
00505 //*-*             =========================================
00506 //   namecycle has the format name;cycle
00507 //   namecycle = "" same as namecycle ="T*"
00508 //   name  = * means all
00509 //   cycle = * means all cycles (memory and keys)
00510 //   cycle = "" or cycle = 9999 ==> apply to a memory object
00511 //   When name=* use T* to delete subdirectories also
00512 //
00513 //   To delete one directory, you must specify the directory cycle,
00514 //      eg.  file.Delete("dir1;1");
00515 //
00516 //   examples:
00517 //     foo   : delete object named foo in memory
00518 //     foo*  : delete all objects with a name starting with foo
00519 //     foo;1 : delete cycle 1 of foo on file
00520 //     foo;* : delete all cycles of foo on file and also from memory
00521 //     *;2   : delete all objects on file having the cycle 2
00522 //     *;*   : delete all objects from memory and file
00523 //    T*;*   : delete all objects from memory and file and all subdirectories
00524 //
00525 
00526    if (gDebug)
00527      Info("Delete","Call for this = %s namecycle = %s",
00528                GetName(), (namecycle ? namecycle : "null"));
00529 
00530    TDirectory::TContext ctxt(gDirectory, this);
00531    Short_t  cycle;
00532    char     name[kMaxLen];
00533    DecodeNameCycle(namecycle, name, cycle);
00534 
00535    Int_t deleteall    = 0;
00536    Int_t deletetree   = 0;
00537    if(strcmp(name,"*") == 0)   deleteall = 1;
00538    if(strcmp(name,"*T") == 0){ deleteall = 1; deletetree = 1;}
00539    if(strcmp(name,"T*") == 0){ deleteall = 1; deletetree = 1;}
00540    if(namecycle==0 || strlen(namecycle) == 0){ deleteall = 1; deletetree = 1;}
00541    TRegexp re(name,kTRUE);
00542    TString s;
00543    Int_t deleteOK = 0;
00544 
00545 //*-*---------------------Case of Object in memory---------------------
00546 //                        ========================
00547    if (cycle >= 9999 ) {
00548       TNamed *idcur;
00549       TIter   next(fList);
00550       while ((idcur = (TNamed *) next())) {
00551          deleteOK = 0;
00552          s = idcur->GetName();
00553          if (deleteall || s.Index(re) != kNPOS) {
00554             deleteOK = 1;
00555             if (idcur->IsA() == TDirectory::Class()) {
00556                deleteOK = 2;
00557                if (!deletetree && deleteall) deleteOK = 0;
00558             }
00559          }
00560          if (deleteOK != 0) {
00561             fList->Remove(idcur);
00562             if (deleteOK==2) {
00563                // read subdirectories to correctly delete them
00564                if (deletetree)
00565                   ((TDirectory*) idcur)->ReadAll("dirs");
00566                idcur->Delete(deletetree ? "T*;*" : "*");
00567                delete idcur;
00568             } else
00569                idcur->Delete(name);
00570          }
00571       }
00572    }
00573 }
00574 
00575 //______________________________________________________________________________
00576 void TDirectory::Draw(Option_t *option)
00577 {
00578 //*-*-*-*-*-*-*-*-*-*-*-*Fill Graphics Structure and Paint*-*-*-*-*-*-*-*-*-*
00579 //*-*                    =================================
00580 // Loop on all objects (memory or file) and all subdirectories
00581 //
00582 
00583    fList->R__FOR_EACH(TObject,Draw)(option);
00584 }
00585 
00586 //______________________________________________________________________________
00587 TObject *TDirectory::FindObject(const TObject *obj) const
00588 {
00589    // Find object in the list of memory objects.
00590 
00591    return fList->FindObject(obj);
00592 }
00593 
00594 //______________________________________________________________________________
00595 TObject *TDirectory::FindObject(const char *name) const
00596 {
00597    // Find object by name in the list of memory objects.
00598 
00599    return fList->FindObject(name);
00600 }
00601 
00602 //______________________________________________________________________________
00603 TObject *TDirectory::FindObjectAny(const char *aname) const
00604 {
00605    // Find object by name in the list of memory objects of the current
00606    // directory or its sub-directories.
00607    // After this call the current directory is not changed.
00608    // To automatically set the current directory where the object is found,
00609    // use FindKeyAny(aname)->ReadObj().
00610 
00611    //object may be already in the list of objects in memory
00612    TObject *obj =  fList->FindObject(aname);
00613    if (obj) return obj;
00614    
00615    //try with subdirectories
00616    TIter next(fList);
00617    while( (obj = next()) ) {
00618       if (obj->IsA()->InheritsFrom(TDirectory::Class())) {
00619          TDirectory* subdir = static_cast<TDirectory*>(obj);
00620          TObject *subobj = subdir->TDirectory::FindObjectAny(aname); // Explicitly recurse into _this_ exact function.
00621          if (subobj) {
00622             return subobj;
00623          }
00624       }
00625    }
00626    return 0;
00627 }
00628 
00629 //______________________________________________________________________________
00630 TObject *TDirectory::Get(const char *namecycle)
00631 {
00632 //  return pointer to object identified by namecycle
00633 //
00634 //   namecycle has the format name;cycle
00635 //   name  = * is illegal, cycle = * is illegal
00636 //   cycle = "" or cycle = 9999 ==> apply to a memory object
00637 //
00638 //   examples:
00639 //     foo   : get object named foo in memory
00640 //             if object is not in memory, try with highest cycle from file
00641 //     foo;1 : get cycle 1 of foo on file
00642 //
00643 //  The retrieved object should in principle derive from TObject.
00644 //  If not, the function TDirectory::GetObject should be called.
00645 //  However, this function will still work for a non-TObject, providing that
00646 //  the calling application cast the return type to the correct type (which
00647 //  is the actual type of the object).
00648 //
00649 //  NOTE:
00650 //  The method GetObject offer better protection and avoid the need
00651 //  for any cast:
00652 //      MyClass *obj;
00653 //      directory->GetObject("some object",obj);
00654 //      if (obj) { ... the object exist and inherits from MyClass ... }
00655 //
00656 //  VERY IMPORTANT NOTE:
00657 //  In case the class of this object derives from TObject but not
00658 //  as a first inheritance, one must use dynamic_cast<>().
00659 //  Example 1: Normal case:
00660 //      class MyClass : public TObject, public AnotherClass
00661 //   then on return, one can do:
00662 //      MyClass *obj = (MyClass*)directory->Get("some object of MyClass");
00663 //
00664 //  Example 2: Special case:
00665 //      class MyClass : public AnotherClass, public TObject
00666 //  then on return, one must do:
00667 //      MyClass *obj = dynamic_cast<MyClass*>(directory->Get("some object of MyClass"));
00668 //
00669 //  Of course, dynamic_cast<> can also be used in the example 1.
00670 //
00671 
00672    Short_t  cycle;
00673    char     name[kMaxLen];
00674 
00675    DecodeNameCycle(namecycle, name, cycle);
00676    char *namobj = name;
00677    Int_t nch = strlen(name);
00678    for (Int_t i = nch-1; i > 0; i--) {
00679       if (name[i] == '/') {
00680          name[i] = 0;
00681          TDirectory* dirToSearch=GetDirectory(name);
00682          namobj = name + i + 1;
00683          name[i] = '/';
00684          return dirToSearch?dirToSearch->Get(namobj):0;
00685       }
00686    }
00687 
00688 //*-*---------------------Case of Object in memory---------------------
00689 //                        ========================
00690    TObject *idcur = fList->FindObject(namobj);
00691    if (idcur) {
00692       if (idcur==this && strlen(namobj)!=0) {
00693          // The object has the same name has the directory and
00694          // that's what we picked-up!  We just need to ignore
00695          // it ...
00696          idcur = 0;
00697       } else if (cycle == 9999) {
00698          return idcur;
00699       } else {
00700          if (idcur->InheritsFrom(TCollection::Class()))
00701             idcur->Delete();  // delete also list elements
00702          delete idcur;
00703          idcur = 0;
00704       }
00705    }
00706    return idcur;
00707 }
00708 
00709 //______________________________________________________________________________
00710 void *TDirectory::GetObjectUnchecked(const char *namecycle)
00711 {
00712 // return pointer to object identified by namecycle.
00713 // The returned object may or may not derive from TObject.
00714 //
00715 //   namecycle has the format name;cycle
00716 //   name  = * is illegal, cycle = * is illegal
00717 //   cycle = "" or cycle = 9999 ==> apply to a memory object
00718 //
00719 //  VERY IMPORTANT NOTE:
00720 //  The calling application must cast the returned object to
00721 //  the final type, e.g.
00722 //      MyClass *obj = (MyClass*)directory->GetObject("some object of MyClass");
00723 
00724    return GetObjectChecked(namecycle,(TClass*)0);
00725 }
00726 
00727 //_________________________________________________________________________________
00728 void *TDirectory::GetObjectChecked(const char *namecycle, const char* classname)
00729 {
00730 // See documentation of TDirectory::GetObjectCheck(const char *namecycle, const TClass *cl)
00731 
00732    return GetObjectChecked(namecycle,TClass::GetClass(classname));
00733 }
00734 
00735 
00736 //____________________________________________________________________________
00737 void *TDirectory::GetObjectChecked(const char *namecycle, const TClass* expectedClass)
00738 {
00739 // return pointer to object identified by namecycle if and only if the actual
00740 // object is a type suitable to be stored as a pointer to a "expectedClass"
00741 // If expectedClass is null, no check is performed.
00742 //
00743 //   namecycle has the format name;cycle
00744 //   name  = * is illegal, cycle = * is illegal
00745 //   cycle = "" or cycle = 9999 ==> apply to a memory object
00746 //
00747 //  VERY IMPORTANT NOTE:
00748 //  The calling application must cast the returned pointer to
00749 //  the type described by the 2 arguments (i.e. cl):
00750 //      MyClass *obj = (MyClass*)directory->GetObjectChecked("some object of MyClass","MyClass"));
00751 //
00752 //  Note: We recommend using the method TDirectory::GetObject:
00753 //      MyClass *obj = 0;
00754 //      directory->GetObject("some object inheriting from MyClass",obj);
00755 //      if (obj) { ... we found what we are looking for ... }
00756 
00757    Short_t  cycle;
00758    char     name[kMaxLen];
00759 
00760    DecodeNameCycle(namecycle, name, cycle);
00761    char *namobj = name;
00762    Int_t nch = strlen(name);
00763    for (Int_t i = nch-1; i > 0; i--) {
00764       if (name[i] == '/') {
00765          name[i] = 0;
00766          TDirectory* dirToSearch=GetDirectory(name);
00767          namobj = name + i + 1;
00768          name[i] = '/';
00769          if (dirToSearch) {
00770             return dirToSearch->GetObjectChecked(namobj, expectedClass);
00771          } else {
00772             return 0;
00773          }
00774       }
00775    }
00776 
00777 //*-*---------------------Case of Object in memory---------------------
00778 //                        ========================
00779    if (expectedClass==0 || expectedClass->InheritsFrom(TObject::Class())) {
00780       TObject *objcur = fList->FindObject(namobj);
00781       if (objcur) {
00782          if (objcur==this && strlen(namobj)!=0) {
00783             // The object has the same name has the directory and
00784             // that's what we picked-up!  We just need to ignore
00785             // it ...
00786             objcur = 0;
00787          } else if (cycle == 9999) {
00788             // Check type
00789             if (expectedClass && objcur->IsA()->GetBaseClassOffset(expectedClass) == -1) return 0;
00790             else return objcur;
00791          } else {
00792             if (objcur->InheritsFrom(TCollection::Class()))
00793                objcur->Delete();  // delete also list elements
00794             delete objcur;
00795             objcur = 0;
00796          }
00797       }
00798    }
00799 
00800    return 0;
00801 }
00802 
00803 //______________________________________________________________________________
00804 const char *TDirectory::GetPathStatic() const
00805 {
00806    // Returns the full path of the directory. E.g. file:/dir1/dir2.
00807    // The returned path will be re-used by the next call to GetPath().
00808 
00809    static char *path = 0;
00810    const int kMAXDEPTH = 128;
00811    const TDirectory *d[kMAXDEPTH];
00812    const TDirectory *cur = this;
00813    int depth = 0, len = 0;
00814 
00815    d[depth++] = cur;
00816    len = strlen(cur->GetName()) + 1;  // +1 for the /
00817 
00818    while (cur->fMother && depth < kMAXDEPTH) {
00819       cur = (TDirectory *)cur->fMother;
00820       d[depth++] = cur;
00821       len += strlen(cur->GetName()) + 1;
00822    }
00823 
00824    if (path) delete [] path;
00825    path = new char[len+2];
00826 
00827    for (int i = depth-1; i >= 0; i--) {
00828       if (i == depth-1) {    // file or TROOT name
00829          strlcpy(path, d[i]->GetName(),len+2);
00830          strlcat(path, ":",len+2);
00831          if (i == 0) strlcat(path, "/",len+2);
00832       } else {
00833          strlcat(path, "/",len+2);
00834          strlcat(path, d[i]->GetName(),len+2);
00835       }
00836    }
00837 
00838    return path;
00839 }
00840 
00841 //______________________________________________________________________________
00842 const char *TDirectory::GetPath() const
00843 {
00844    // Returns the full path of the directory. E.g. file:/dir1/dir2.
00845    // The returned path will be re-used by the next call to GetPath().
00846 
00847    //
00848    TString* buf = &(const_cast<TDirectory*>(this)->fPathBuffer);
00849 
00850    FillFullPath(*buf);
00851    if (GetMotherDir()==0) // case of file
00852       buf->Append("/");
00853 
00854    return buf->Data();
00855 }
00856 
00857 //______________________________________________________________________________
00858 void TDirectory::FillFullPath(TString& buf) const
00859 {
00860    // recursive method to fill full path for directory
00861 
00862    TDirectory* mom = GetMotherDir();
00863    if (mom!=0) {
00864       mom->FillFullPath(buf);
00865       buf += "/";
00866       buf += GetName();
00867    } else {
00868       buf = GetName();
00869       buf +=":";
00870    }
00871 }
00872 
00873 //______________________________________________________________________________
00874 TDirectory *TDirectory::mkdir(const char *name, const char *title)
00875 {
00876    // Create a sub-directory and return a pointer to the created directory.
00877    // Returns 0 in case of error.
00878    // Returns 0 if a directory with the same name already exists.
00879    // Note that the directory name may be of the form "a/b/c" to create a hierarchy of directories.
00880    // In this case, the function returns the pointer to the "a" directory if the operation is successful.
00881    
00882    if (!name || !title || !strlen(name)) return 0;
00883    if (!strlen(title)) title = name;
00884    TDirectory *newdir = 0;
00885    if (const char *slash = strchr(name,'/')) {
00886       Long_t size = Long_t(slash-name);
00887       char *workname = new char[size+1];
00888       strncpy(workname, name, size);
00889       workname[size] = 0;
00890       TDirectory *tmpdir = mkdir(workname,title);
00891       if (!tmpdir) return 0;
00892       if (!newdir) newdir = tmpdir;
00893       tmpdir->mkdir(slash+1);
00894       delete[] workname;
00895       return newdir;
00896    }
00897 
00898    TDirectory::TContext ctxt(this);
00899 
00900    newdir = new TDirectory(name, title, "", this);
00901 
00902    return newdir;
00903 }
00904 
00905 //______________________________________________________________________________
00906 void TDirectory::ls(Option_t *option) const
00907 {
00908    // List Directory contents.
00909    //
00910    //  Indentation is used to identify the directory tree
00911    //  Subdirectories are listed first, then objects in memory.
00912    //
00913    //  The option can has the following format:
00914    //     [<regexp>]
00915    //  The <regexp> will be used to match the name of the objects.
00916    //  By default memory and disk objects are listed.
00917    //
00918 
00919    TROOT::IndentLevel();
00920    TROOT::IncreaseDirLevel();
00921 
00922    TString opta = option;
00923    TString opt  = opta.Strip(TString::kBoth);
00924    Bool_t memobj  = kTRUE;
00925    Bool_t diskobj = kTRUE;
00926    TString reg = "*";
00927    if (opt.BeginsWith("-m")) {
00928       diskobj = kFALSE;
00929       if (opt.Length() > 2)
00930          reg = opt(2,opt.Length());
00931    } else if (opt.BeginsWith("-d")) {
00932       memobj  = kFALSE;
00933       if (opt.Length() > 2)
00934          reg = opt(2,opt.Length());
00935    } else if (!opt.IsNull())
00936       reg = opt;
00937 
00938    TRegexp re(reg, kTRUE);
00939 
00940    if (memobj) {
00941       TObject *obj;
00942       TIter nextobj(fList);
00943       while ((obj = (TObject *) nextobj())) {
00944          TString s = obj->GetName();
00945          if (s.Index(re) == kNPOS) continue;
00946          obj->ls(option);            //*-* Loop on all the objects in memory
00947       }
00948    }
00949    TROOT::DecreaseDirLevel();
00950 }
00951 
00952 //______________________________________________________________________________
00953 void TDirectory::Paint(Option_t *option)
00954 {
00955    // Paint all objects in the directory.
00956 
00957    fList->R__FOR_EACH(TObject,Paint)(option);
00958 }
00959 
00960 //______________________________________________________________________________
00961 void TDirectory::Print(Option_t *option) const
00962 {
00963    // Print all objects in the directory.
00964 
00965    fList->R__FOR_EACH(TObject,Print)(option);
00966 }
00967 
00968 //______________________________________________________________________________
00969 void TDirectory::pwd() const
00970 {
00971    // Print the path of the directory.
00972 
00973    Printf("%s", GetPath());
00974 }
00975 
00976 //______________________________________________________________________________
00977 void TDirectory::RecursiveRemove(TObject *obj)
00978 {
00979    // Recursively remove object from a Directory.
00980 
00981    fList->RecursiveRemove(obj);
00982 }
00983  
00984 //______________________________________________________________________________
00985 TObject *TDirectory::Remove(TObject* obj)
00986 {
00987    // Remove an object from the in-memory list.
00988 
00989    TObject *p = 0;
00990    if (fList) {
00991       p = fList->Remove(obj);
00992    }
00993    return p;
00994 }
00995 
00996 //______________________________________________________________________________
00997 void TDirectory::rmdir(const char *name)
00998 {
00999    // Removes subdirectory from the directory
01000    // When directory is deleted, all keys in all subdirectories will be
01001    // read first and deleted from file (if exists)
01002    // Equivalent call is Delete("name;*");
01003 
01004    if ((name==0) || (*name==0)) return;
01005 
01006    TString mask(name);
01007    mask+=";*";
01008    Delete(mask);
01009 }
01010 
01011 //______________________________________________________________________________
01012 Int_t TDirectory::SaveObjectAs(const TObject *obj, const char *filename, Option_t *option) const
01013 {
01014    // Save object in filename,
01015    // if filename is 0 or "", a file with "objectname.root" is created.
01016    // The name of the key is the object name.
01017    // If the operation is successful, it returns the number of bytes written to the file
01018    // otherwise it returns 0.
01019    // By default a message is printed. Use option "q" to not print the message.
01020 
01021    if (!obj) return 0;
01022    if (!gDirectory) return 0;
01023    TDirectory *dirsav = gDirectory;
01024    TString fname = filename;
01025    if (!filename || strlen(filename) == 0) {
01026       fname = Form("%s.root",obj->GetName());
01027    }
01028    const char *cmd = Form("TFile::Open(\"%s\",\"recreate\");",fname.Data());
01029    TDirectory *local = (TDirectory*)gROOT->ProcessLine(cmd);
01030    if (!local) return 0;
01031    Int_t nbytes = obj->Write();
01032    delete local;
01033    if (dirsav) dirsav->cd();
01034    TString opt = option;
01035    opt.ToLower();
01036    if (!opt.Contains("q")) {
01037       if (!gSystem->AccessPathName(fname.Data())) obj->Info("SaveAs", "ROOT file %s has been created", fname.Data());
01038    }
01039    return nbytes;
01040 }
01041 
01042 //______________________________________________________________________________
01043 void TDirectory::SetName(const char* newname)
01044 {
01045    // Set the name for directory
01046    // If the directory name is changed after the directory was written once,
01047    // ROOT currently would NOT change the name of correspondent key in the
01048    // mother directory.
01049    // DO NOT use this method to 'rename a directory'.
01050    // Renaming a directory is currently NOT supported.
01051 
01052    TNamed::SetName(newname);
01053 }
01054 
01055 //______________________________________________________________________________
01056 void TDirectory::EncodeNameCycle(char *buffer, const char *name, Short_t cycle)
01057 {
01058    // Encode the name and cycle into buffer like: "aap;2".
01059 
01060    if (cycle == 9999)
01061       strcpy(buffer, name);
01062    else
01063       sprintf(buffer, "%s;%d", name, cycle);
01064 }
01065 
01066 //______________________________________________________________________________
01067 void TDirectory::DecodeNameCycle(const char *buffer, char *name, Short_t &cycle)
01068 {
01069    // Decode a namecycle "aap;2" into name "aap" and cycle "2".
01070 
01071    cycle     = 9999;
01072    Int_t nch = buffer ? strlen(buffer) : 0;
01073    for (Int_t i = 0; i < nch; i++) {
01074       if (buffer[i] != ';')
01075          name[i] = buffer[i];
01076       else {
01077          name[i] = 0;
01078          if (i < nch-1 )
01079             if (buffer[i+1] == '*') {
01080                cycle = 10000;
01081                return;
01082             }
01083          sscanf(buffer+i+1, "%hd", &cycle);
01084          return;
01085       }
01086    }
01087    name[nch] = 0;
01088 }
01089 
01090 //______________________________________________________________________________
01091 void TDirectory::RegisterContext(TContext *ctxt) {
01092    // Register a TContext pointing to this TDirectory object
01093 
01094    R__LOCKGUARD2(gROOTMutex);
01095    if (fContext) {
01096       TContext *current = fContext;
01097       while(current->fNext) {
01098          current = current->fNext;
01099       }
01100       current->fNext = ctxt;
01101       ctxt->fPrevious = current;
01102    } else {
01103       fContext = ctxt;
01104    }
01105 }
01106 
01107 //______________________________________________________________________________
01108 Int_t TDirectory::WriteTObject(const TObject *obj, const char *name, Option_t * /*option*/, Int_t /*bufsize*/)
01109 {
01110    // See TDirectoryFile::WriteTObject for details
01111 
01112    const char *objname = "no name specified";
01113    if (name) objname = name;
01114    else if (obj) objname = obj->GetName();
01115    Error("WriteTObject","The current directory (%s) is not associated with a file. The object (%s) has not been written.",GetName(),objname);
01116    return 0;
01117 }
01118 
01119 //______________________________________________________________________________
01120 void TDirectory::UnregisterContext(TContext *ctxt) {
01121    // UnRegister a TContext pointing to this TDirectory object
01122 
01123    R__LOCKGUARD2(gROOTMutex);
01124    if (ctxt==fContext) {
01125       fContext = ctxt->fNext;
01126       if (fContext) fContext->fPrevious = 0;
01127       ctxt->fPrevious = ctxt->fNext = 0;
01128    } else {
01129       TContext *next = ctxt->fNext;
01130       ctxt->fPrevious->fNext = next;
01131       if (next) next->fPrevious = ctxt->fPrevious;
01132       ctxt->fPrevious = ctxt->fNext = 0;
01133    }
01134 }
01135 
01136 //______________________________________________________________________________
01137 void TDirectory::TContext::CdNull()
01138 {
01139    // Set the current directory to null.
01140    // This is called from the TContext destructor.  Since the destructor is
01141    // inline, we do not want to have it directly use a global variable.
01142 
01143    gDirectory = 0;
01144 }

Generated on Tue Jul 5 14:11:19 2011 for ROOT_528-00b_version by  doxygen 1.5.1