31 Bool_t TDirectory::fgAddDirectory = kTRUE;
33 const Int_t kMaxLen = 2048;
46 TDirectory::TDirectory() : TNamed()
49 std::atomic_flag_clear( &fSpinLock );
65 TDirectory::TDirectory(
const char *name,
const char *title, Option_t * , TDirectory* initMotherDir)
69 std::atomic_flag_clear( &fSpinLock );
71 if (!initMotherDir) initMotherDir = gDirectory;
73 if (strchr(name,
'/')) {
74 ::Error(
"TDirectory::TDirectory",
"directory name (%s) cannot contain a slash", name);
78 if (strlen(GetName()) == 0) {
79 ::Error(
"TDirectory::TDirectory",
"directory name cannot be \"\"");
84 BuildDirectory(initMotherDir ? initMotherDir->GetFile() :
nullptr, initMotherDir);
90 TDirectory::~TDirectory()
98 if (!fList->IsUsingRWLock())
99 Fatal(
"~TDirectory",
"In %s:%p the fList (%p) is not using the RWLock\n",
100 GetName(),
this,fList);
101 fList->Delete(
"slow");
105 TDirectory::CleanTargets();
107 TDirectory* mom = GetMotherDir();
114 Info(
"~TDirectory",
"dtor called for %s", GetName());
124 void TDirectory::TContext::CdNull()
126 gDirectory =
nullptr;
134 TDirectory::TContext::~TContext()
136 fActiveDestructor =
true;
140 (*fDirectory).UnregisterContext(
this);
151 fActiveDestructor =
false;
152 while(fDirectoryWait);
171 void TDirectory::AddDirectory(Bool_t add)
173 fgAddDirectory = add;
179 Bool_t TDirectory::AddDirectoryStatus()
181 return fgAddDirectory;
190 void TDirectory::Append(TObject *obj, Bool_t replace )
192 if (!obj || !fList)
return;
194 if (replace && obj->GetName() && obj->GetName()[0]) {
196 while (
nullptr != (old = GetList()->FindObject(obj->GetName()))) {
197 Warning(
"Append",
"Replacing existing %s: %s (Potential memory leak).",
198 obj->IsA()->GetName(),obj->GetName());
199 ROOT::DirAutoAdd_t func = old->IsA()->GetDirectoryAutoAdd();
209 obj->SetBit(kMustCleanup);
215 void TDirectory::Browse(TBrowser *b)
218 TObject *obj =
nullptr;
224 while ((obj = nextin())) {
225 b->Add(obj, obj->GetName());
237 void TDirectory::BuildDirectory(TFile* , TDirectory* motherDir)
239 fList =
new THashList(100,50);
246 if (motherDir && strlen(GetName()) != 0) motherDir->Append(
this);
252 void TDirectory::CleanTargets()
254 std::vector<TContext*> extraWait;
257 ROOT::Internal::TSpinLockGuard slg(fSpinLock);
260 const auto next = fContext->fNext;
261 const auto ctxt = fContext;
262 ctxt->fDirectoryWait =
true;
264 ctxt->fDirectory =
nullptr;
266 if (ctxt->fActiveDestructor) {
267 extraWait.push_back(fContext);
269 ctxt->fDirectoryWait =
false;
274 for(
auto &&context : extraWait) {
277 while(context->fActiveDestructor);
278 context->fDirectoryWait =
false;
281 if (gDirectory ==
this) {
282 TDirectory *cursav = GetMotherDir();
283 if (cursav && cursav !=
this) {
287 gDirectory =
nullptr;
300 static TBuffer* R__CreateBuffer()
302 typedef void (*tcling_callfunc_Wrapper_t)(
void*, int,
void**,
void*);
303 static tcling_callfunc_Wrapper_t creator =
nullptr;
305 R__LOCKGUARD(gROOTMutex);
306 TClass *c = TClass::GetClass(
"TBufferFile");
307 TMethod *m = c->GetMethodWithPrototype(
"TBufferFile",
"TBuffer::EMode,Int_t",kFALSE,ROOT::kExactMatch);
308 creator = (tcling_callfunc_Wrapper_t)( m->InterfaceMethod() );
310 TBuffer::EMode mode = TBuffer::kWrite;
312 void *args[] = { &mode, &size };
314 creator(0,2,args,&result);
328 TObject *TDirectory::CloneObject(
const TObject *obj, Bool_t autoadd )
331 char *pobj = (
char*)obj->IsA()->New();
333 Fatal(
"CloneObject",
"Failed to create new object");
337 Int_t baseOffset = obj->IsA()->GetBaseClassOffset(TObject::Class());
338 if (baseOffset==-1) {
342 Fatal(
"CloneObject",
"Incorrect detection of the inheritance from TObject for class %s.\n",
343 obj->IsA()->GetName());
345 TObject *newobj = (TObject*)(pobj+baseOffset);
350 TBuffer *buffer = R__CreateBuffer();
352 Fatal(
"CloneObject",
"Not able to create a TBuffer!");
355 buffer->MapObject(obj);
356 const_cast<TObject*
>(obj)->Streamer(*buffer);
359 buffer->SetReadMode();
361 buffer->SetBufferOffset(0);
362 buffer->MapObject(newobj);
363 newobj->Streamer(*buffer);
364 newobj->ResetBit(kIsReferenced);
365 newobj->ResetBit(kCanDelete);
369 ROOT::DirAutoAdd_t func = obj->IsA()->GetDirectoryAutoAdd();
380 TDirectory *&TDirectory::CurrentDirectory()
382 static TDirectory *currentDirectory =
nullptr;
384 return currentDirectory;
386 return *(TDirectory**)(*gThreadTsd)(¤tDirectory,ROOT::kDirectoryThreadSlot);
400 TDirectory *TDirectory::GetDirectory(
const char *apath,
401 Bool_t printError,
const char *funcname)
404 if (apath) nch = strlen(apath);
409 if (funcname==0 || strlen(funcname)==0) funcname =
"GetDirectory";
411 TDirectory *result =
this;
413 char *path =
new char[nch+1]; path[0] = 0;
414 if (nch) strlcpy(path,apath,nch+1);
415 char *s = (
char*)strrchr(path,
':');
418 R__LOCKGUARD(gROOTMutex);
419 TDirectory *f = (TDirectory *)gROOT->GetListOfFiles()->FindObject(path);
420 if (!f && !strcmp(gROOT->GetName(), path)) f = gROOT;
424 if (s && *(s+1)) result = f->GetDirectory(s+1,printError,funcname);
425 delete [] path;
return result;
427 if (printError) Error(funcname,
"No such file %s", path);
428 delete [] path;
return nullptr;
433 if (path[0] ==
'/') {
434 TDirectory *td = gROOT;
435 result = td->GetDirectory(path+1,printError,funcname);
436 delete [] path;
return result;
440 char *slash = (
char*)strchr(path,
'/');
442 if (!strcmp(path,
"..")) {
443 result = GetMotherDir();
444 delete [] path;
return result;
448 if (printError) Error(funcname,
"Unknown directory %s", path);
449 delete [] path;
return nullptr;
453 if (!obj->InheritsFrom(TDirectory::Class())) {
454 if (printError) Error(funcname,
"Object %s is not a directory", path);
455 delete [] path;
return nullptr;
457 delete [] path;
return (TDirectory*)obj;
460 TString subdir(path);
461 slash = (
char*)strchr(subdir.Data(),
'/');
464 if (!strcmp(subdir,
"..")) {
465 TDirectory* mom = GetMotherDir();
467 result = mom->GetDirectory(slash+1,printError,funcname);
468 delete [] path;
return result;
472 if (printError) Error(funcname,
"Unknown directory %s", subdir.Data());
473 delete [] path;
return nullptr;
477 if (!obj->InheritsFrom(TDirectory::Class())) {
478 if (printError) Error(funcname,
"Object %s is not a directory", subdir.Data());
479 delete [] path;
return nullptr;
481 result = ((TDirectory*)obj)->GetDirectory(slash+1,printError,funcname);
482 delete [] path;
return result;
497 Bool_t TDirectory::cd(
const char *path)
515 Bool_t TDirectory::cd1(
const char *apath)
518 if (apath) nch = strlen(apath);
524 TDirectory *where = GetDirectory(apath,kTRUE,
"cd");
541 Bool_t TDirectory::Cd(
const char *path)
554 Bool_t TDirectory::Cd1(
const char *apath)
558 if (apath) nch = strlen(apath);
559 if (!nch)
return kTRUE;
561 TDirectory *where = gDirectory->GetDirectory(apath,kTRUE,
"Cd");
572 void TDirectory::Clear(Option_t *)
574 if (fList) fList->Clear();
584 void TDirectory::Close(Option_t *option)
593 Bool_t nodelete = option ? (!strcmp(option,
"nodelete") ? kTRUE : kFALSE) : kFALSE;
596 Bool_t slow = option ? (!strcmp(option,
"slow") ? kTRUE : kFALSE) : kFALSE;
599 TObjLink *lnk = fList->FirstLink();
601 if (lnk->GetObject()->IsA() == TDirectory::Class()) {
614 if (slow) fList->Delete(
"slow");
615 else fList->Delete();
618 TDirectory::CleanTargets();
624 void TDirectory::DeleteAll(Option_t *)
626 fList->Delete(
"slow");
651 void TDirectory::Delete(
const char *namecycle)
654 Info(
"Delete",
"Call for this = %s namecycle = %s",
655 GetName(), (namecycle ? namecycle :
"null"));
657 TDirectory::TContext ctxt(
this);
660 DecodeNameCycle(namecycle, name, cycle, kMaxLen);
663 Int_t deletetree = 0;
664 if(strcmp(name,
"*") == 0) deleteall = 1;
665 if(strcmp(name,
"*T") == 0){ deleteall = 1; deletetree = 1;}
666 if(strcmp(name,
"T*") == 0){ deleteall = 1; deletetree = 1;}
667 if(namecycle==0 || !namecycle[0]){ deleteall = 1; deletetree = 1;}
668 TRegexp re(name,kTRUE);
674 if (cycle >= 9999 ) {
677 while ((idcur = (TNamed *) next())) {
679 s = idcur->GetName();
680 if (deleteall || s.Index(re) != kNPOS) {
682 if (idcur->IsA() == TDirectory::Class()) {
684 if (!deletetree && deleteall) deleteOK = 0;
688 fList->Remove(idcur);
692 ((TDirectory*) idcur)->ReadAll(
"dirs");
693 idcur->Delete(deletetree ?
"T*;*" :
"*");
707 void TDirectory::Draw(Option_t *option)
709 fList->R__FOR_EACH(TObject,Draw)(option);
715 TObject *TDirectory::FindObject(
const TObject *obj)
const
717 return fList->FindObject(obj);
723 TObject *TDirectory::FindObject(
const char *name)
const
725 return fList->FindObject(name);
735 TObject *TDirectory::FindObjectAny(
const char *aname)
const
738 TObject *obj = fList->FindObject(aname);
743 while( (obj = next()) ) {
744 if (obj->IsA()->InheritsFrom(TDirectory::Class())) {
745 TDirectory* subdir =
static_cast<TDirectory*
>(obj);
746 TObject *subobj = subdir->TDirectory::FindObjectAny(aname);
805 TObject *TDirectory::Get(
const char *namecycle)
810 DecodeNameCycle(namecycle, name, cycle, kMaxLen);
812 Int_t nch = strlen(name);
813 for (Int_t i = nch-1; i > 0; i--) {
814 if (name[i] ==
'/') {
816 TDirectory* dirToSearch=GetDirectory(name);
817 namobj = name + i + 1;
819 return dirToSearch ? dirToSearch->Get(namobj) :
nullptr;
825 TObject *idcur = fList->FindObject(namobj);
827 if (idcur==
this && strlen(namobj)!=0) {
832 }
else if (cycle == 9999) {
835 if (idcur->InheritsFrom(TCollection::Class()))
860 void *TDirectory::GetObjectUnchecked(
const char *namecycle)
862 return GetObjectChecked(namecycle,(TClass *)
nullptr);
868 void *TDirectory::GetObjectChecked(
const char *namecycle,
const char* classname)
870 return GetObjectChecked(namecycle, TClass::GetClass(classname));
897 void *TDirectory::GetObjectChecked(
const char *namecycle,
const TClass* expectedClass)
902 DecodeNameCycle(namecycle, name, cycle, kMaxLen);
904 Int_t nch = strlen(name);
905 for (Int_t i = nch-1; i > 0; i--) {
906 if (name[i] ==
'/') {
908 TDirectory* dirToSearch=GetDirectory(name);
909 namobj = name + i + 1;
912 return dirToSearch->GetObjectChecked(namobj, expectedClass);
921 if (!expectedClass || expectedClass->IsTObject()) {
922 TObject *objcur = fList->FindObject(namobj);
924 if (objcur==
this && strlen(namobj)!=0) {
929 }
else if (cycle == 9999) {
931 if (expectedClass && objcur->IsA()->GetBaseClassOffset(expectedClass) == -1)
return nullptr;
934 if (objcur->InheritsFrom(TCollection::Class()))
949 const char *TDirectory::GetPathStatic()
const
951 static char *path =
nullptr;
952 const int kMAXDEPTH = 128;
953 const TDirectory *d[kMAXDEPTH];
954 const TDirectory *cur =
this;
955 int depth = 0, len = 0;
958 len = strlen(cur->GetName()) + 1;
960 while (cur->fMother && depth < kMAXDEPTH) {
961 cur = (TDirectory *)cur->fMother;
963 len += strlen(cur->GetName()) + 1;
966 if (path)
delete [] path;
967 path =
new char[len+2];
969 for (
int i = depth-1; i >= 0; i--) {
971 strlcpy(path, d[i]->GetName(),len+2);
972 strlcat(path,
":",len+2);
973 if (i == 0) strlcat(path,
"/",len+2);
975 strlcat(path,
"/",len+2);
976 strlcat(path, d[i]->GetName(),len+2);
987 const char *TDirectory::GetPath()
const
989 FillFullPath(fPathBuffer);
992 fPathBuffer.Append(
"/");
994 return fPathBuffer.Data();
1000 void TDirectory::FillFullPath(TString& buf)
const
1002 TDirectory* mom = GetMotherDir();
1004 mom->FillFullPath(buf);
1041 TDirectory *TDirectory::mkdir(
const char *name,
const char *title, Bool_t returnExistingDirectory)
1043 if (returnExistingDirectory) {
1044 auto existingdir = GetDirectory(name);
1048 if (!name || !title || !name[0])
return nullptr;
1049 if (!title[0]) title = name;
1050 TDirectory *newdir =
nullptr;
1051 if (
const char *slash = strchr(name,
'/')) {
1052 Long_t size = Long_t(slash-name);
1053 char *workname =
new char[size+1];
1054 strncpy(workname, name, size);
1057 GetObject(workname,tmpdir);
1059 tmpdir = mkdir(workname,title);
1060 if (!tmpdir)
return nullptr;
1063 if (!tmpdir)
return nullptr;
1064 if (!newdir) newdir = tmpdir;
1065 tmpdir->mkdir(slash+1);
1069 TDirectory::TContext ctxt(
this);
1071 newdir =
new TDirectory(name, title,
"",
this);
1089 void TDirectory::ls(Option_t *option)
const
1091 TROOT::IndentLevel();
1092 TROOT::IncreaseDirLevel();
1094 TString opta = option;
1095 TString opt = opta.Strip(TString::kBoth);
1096 Bool_t memobj = kTRUE;
1098 if (opt.BeginsWith(
"-m")) {
1099 if (opt.Length() > 2)
1100 reg = opt(2,opt.Length());
1101 }
else if (opt.BeginsWith(
"-d")) {
1103 if (opt.Length() > 2)
1104 reg = opt(2,opt.Length());
1105 }
else if (!opt.IsNull())
1108 TRegexp re(reg, kTRUE);
1112 TIter nextobj(fList);
1113 while ((obj = (TObject *) nextobj())) {
1114 TString s = obj->GetName();
1115 if (s.Index(re) == kNPOS)
continue;
1119 TROOT::DecreaseDirLevel();
1125 void TDirectory::Paint(Option_t *option)
1127 fList->R__FOR_EACH(TObject,Paint)(option);
1133 void TDirectory::Print(Option_t *option)
const
1135 fList->R__FOR_EACH(TObject,Print)(option);
1141 void TDirectory::pwd()
const
1143 Printf(
"%s", GetPath());
1149 void TDirectory::RecursiveRemove(TObject *obj)
1151 fList->RecursiveRemove(obj);
1157 TObject *TDirectory::Remove(TObject* obj)
1161 p = fList->Remove(obj);
1172 void TDirectory::rmdir(
const char *name)
1174 if ((name==0) || (*name==0))
return;
1193 Int_t TDirectory::SaveObjectAs(
const TObject *obj,
const char *filename, Option_t *option)
const
1197 TString fname = filename;
1198 if (!filename || !filename[0]) {
1199 fname.Form(
"%s.root",obj->GetName());
1202 if (fname.Index(
".json") > 0) {
1203 cmd.Form(
"TBufferJSON::ExportToFile(\"%s\",(TObject*) %s, \"%s\");", fname.Data(), TString::LLtoa((Long_t)obj, 10).Data(), (option ? option :
""));
1204 nbytes = gROOT->ProcessLine(cmd);
1206 cmd.Form(
"TFile::Open(\"%s\",\"recreate\");",fname.Data());
1208 TDirectory *local = (TDirectory*)gROOT->ProcessLine(cmd);
1209 if (!local)
return 0;
1210 nbytes = obj->Write();
1213 TString opt(option);
1215 if (!opt.Contains(
"q")) {
1216 if (!gSystem->AccessPathName(fname.Data())) obj->Info(
"SaveAs",
"ROOT file %s has been created", fname.Data());
1229 void TDirectory::SetName(
const char* newname)
1231 TNamed::SetName(newname);
1237 void TDirectory::EncodeNameCycle(
char *buffer,
const char *name, Short_t cycle)
1240 strcpy(buffer, name);
1242 sprintf(buffer,
"%s;%d", name, cycle);
1250 void TDirectory::DecodeNameCycle(
const char *buffer,
char *name, Short_t &cycle,
1251 const size_t namesize)
1254 const char *ni = strchr(buffer,
';');
1262 len = strlen(buffer);
1267 if (len > namesize-1ul) len = namesize-1;
1269 ::Warning(
"TDirectory::DecodeNameCycle",
1270 "Using unsafe version: invoke this metod by specifying the buffer size");
1273 strncpy(name, buffer, len);
1278 else if (isdigit(*ni)) {
1279 long parsed = strtol(ni,
nullptr,10);
1280 if (parsed >= (
long) std::numeric_limits<Short_t>::max())
1283 cycle = (Short_t)parsed;
1291 void TDirectory::RegisterContext(TContext *ctxt) {
1292 ROOT::Internal::TSpinLockGuard slg(fSpinLock);
1295 TContext *current = fContext;
1296 while(current->fNext) {
1297 current = current->fNext;
1299 current->fNext = ctxt;
1300 ctxt->fPrevious = current;
1309 Int_t TDirectory::WriteTObject(
const TObject *obj,
const char *name, Option_t * , Int_t )
1311 const char *objname =
"no name specified";
1312 if (name) objname = name;
1313 else if (obj) objname = obj->GetName();
1314 Error(
"WriteTObject",
"The current directory (%s) is not associated with a file. The object (%s) has not been written.",GetName(),objname);
1321 void TDirectory::UnregisterContext(TContext *ctxt) {
1323 ROOT::Internal::TSpinLockGuard slg(fSpinLock);
1326 if (ctxt->fDirectory ==
nullptr)
1329 if (ctxt==fContext) {
1330 fContext = ctxt->fNext;
1331 if (fContext) fContext->fPrevious =
nullptr;
1332 ctxt->fPrevious = ctxt->fNext =
nullptr;
1334 TContext *next = ctxt->fNext;
1335 ctxt->fPrevious->fNext = next;
1336 if (next) next->fPrevious = ctxt->fPrevious;
1337 ctxt->fPrevious = ctxt->fNext =
nullptr;
1343 void TDirectory::Streamer(TBuffer &R__b)
1348 if (R__b.IsReading()) {
1349 Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
if (R__v) { }
1350 TNamed::Streamer(R__b);
1354 fUUID.Streamer(R__b);
1355 R__b.CheckByteCount(R__s, R__c, TDirectory::IsA());
1357 R__c = R__b.WriteVersion(TDirectory::IsA(), kTRUE);
1358 TNamed::Streamer(R__b);
1361 fUUID.Streamer(R__b);
1362 R__b.SetByteCount(R__c, kTRUE);