103 TPluginManager *gPluginMgr;
105 static TVirtualMutex *gPluginManagerMutex;
107 static bool &TPH__IsReadingDirs() {
108 TTHREAD_TLS(
bool) readingDirs (false);
112 ClassImp(TPluginHandler);
117 TPluginHandler::TPluginHandler(const
char *base, const
char *regexp,
118 const
char *className, const
char *pluginName,
119 const
char *ctor, const
char *origin):
132 TString aclicMode, arguments, io;
133 TString fname = gSystem->SplitAclicMode(fPlugin, aclicMode, arguments, io);
134 Bool_t validMacro = kFALSE;
135 if (fname.EndsWith(
".C") || fname.EndsWith(
".cxx") || fname.EndsWith(
".cpp") ||
136 fname.EndsWith(
".cc"))
139 if (validMacro && gROOT->LoadMacro(fPlugin, 0, kTRUE) == 0)
142 if (fCtor.BeginsWith(
"::")) {
144 fCtor = fCtor.Strip(TString::kLeading,
':');
151 TPluginHandler::~TPluginHandler()
160 Bool_t TPluginHandler::CanHandle(
const char *base,
const char *uri)
165 if (!uri || fRegexp ==
"*")
168 Bool_t wildcard = kFALSE;
169 if (!fRegexp.MaybeRegexp())
172 TRegexp re(fRegexp, wildcard);
175 if (ruri.Index(re) != kNPOS)
183 void TPluginHandler::SetupCallEnv()
193 using exit_scope = std::shared_ptr<void*>;
194 exit_scope guard(
nullptr,
195 [
this,&setCanCall](
void *) { this->fCanCall = setCanCall; } );
198 TClass *cl = TClass::GetClass(fClass);
199 if (!cl && !fIsGlobal) {
200 Error(
"SetupCallEnv",
"class %s not found in plugin %s", fClass.Data(),
206 TString method = fCtor(0, fCtor.Index(
"("));
207 TString proto = fCtor(fCtor.Index(
"(")+1, fCtor.Index(
")")-fCtor.Index(
"(")-1);
211 fMethod = gROOT->GetGlobalFunctionWithPrototype(method, proto, kFALSE);
213 fMethod = cl->GetMethodWithPrototype(method, proto);
218 Error(
"SetupCallEnv",
"global function %s not found", method.Data());
220 Error(
"SetupCallEnv",
"method %s not found in class %s", method.Data(),
225 if (!fIsGlobal && !(fMethod->Property() & kIsPublic)) {
226 Error(
"SetupCallEnv",
"method %s is not public", method.Data());
230 fCallEnv =
new TMethodCall;
231 fCallEnv->Init(fMethod);
242 Int_t TPluginHandler::CheckPlugin()
const
245 if (TClass::GetClass(fClass))
return 0;
246 return gROOT->LoadMacro(fPlugin, 0, kTRUE);
248 return gROOT->LoadClass(fClass, fPlugin, kTRUE);
255 Int_t TPluginHandler::LoadPlugin()
258 if (TClass::GetClass(fClass))
return 0;
259 return gROOT->LoadMacro(fPlugin);
262 if (TClass::LoadClass(fClass, kFALSE))
return 0;
263 return gROOT->LoadClass(fClass, fPlugin);
270 Bool_t TPluginHandler::CheckForExecPlugin(Int_t nargs)
272 if (fCtor.IsNull()) {
273 Error(
"ExecPlugin",
"no ctor specified for this handler %s", fClass.Data());
283 R__LOCKGUARD(gInterpreterMutex);
284 R__LOCKGUARD2(gPluginManagerMutex);
294 if (nargs < fMethod->GetNargs() - fMethod->GetNargsOpt() ||
295 nargs > fMethod->GetNargs()) {
296 Error(
"ExecPlugin",
"nargs (%d) not consistent with expected number of arguments ([%d-%d])",
297 nargs, fMethod->GetNargs() - fMethod->GetNargsOpt(),
298 fMethod->GetNargs());
309 void TPluginHandler::Print(Option_t *opt)
const
311 const char *exist =
"";
312 if (CheckPlugin() == -1)
315 Printf(
"%-20s %-13s %-18s %s%s", fBase.Data(), fRegexp.Data(),
316 fClass.Data(), fPlugin.Data(), exist);
317 if (strchr(opt,
'a')) {
319 TString lib = fPlugin;
320 if (!lib.BeginsWith(
"lib"))
322 char *path = gSystem->DynamicPathName(lib, kTRUE);
323 if (path) Printf(
" [Lib: %s]", path);
326 Printf(
" [Ctor: %s]", fCtor.Data());
327 Printf(
" [origin: %s]", fOrigin.Data());
332 ClassImp(TPluginManager);
337 TPluginManager::~TPluginManager()
351 void TPluginManager::LoadHandlersFromEnv(TEnv *env)
355 TIter next(env->GetTable());
358 while ((er = (TEnvRec*) next())) {
360 if ((s = strstr(er->GetName(),
"Plugin."))) {
364 const char *val = env->GetValue(s, (
const char*)0);
367 char *v = StrDup(val);
370 TString regexp = strtok(!cnt ? v : 0,
"; ");
371 if (regexp.IsNull())
break;
372 TString clss = strtok(0,
"; ");
373 if (clss.IsNull())
break;
374 TString plugin = strtok(0,
"; ");
375 if (plugin.IsNull())
break;
376 TString ctor = strtok(0,
";\"");
377 if (!ctor.Contains(
"("))
378 ctor = strtok(0,
";\"");
379 AddHandler(s, regexp, clss, plugin, ctor,
"TEnv");
391 void TPluginManager::LoadHandlerMacros(
const char *path)
393 void *dirp = gSystem->OpenDirectory(path);
396 Info(
"LoadHandlerMacros",
"%s", path);
400 while ((f1 = gSystem->GetDirEntry(dirp))) {
402 if (f[0] ==
'P' && f.EndsWith(
".C")) {
403 const char *p = gSystem->ConcatFileName(path, f);
404 if (!gSystem->AccessPathName(p, kReadPermission)) {
405 macros.Add(
new TObjString(p));
413 while ((s = (TObjString*)next())) {
415 Info(
"LoadHandlerMacros",
" plugin macro: %s", s->String().Data());
417 if ((res = gROOT->Macro(s->String(), 0, kFALSE)) < 0) {
418 Error(
"LoadHandlerMacros",
"pluging macro %s returned %ld",
419 s->String().Data(), res);
423 gSystem->FreeDirectory(dirp);
450 void TPluginManager::LoadHandlersFromPluginDirs(
const char *base)
452 TString sbase = base;
454 sbase.ReplaceAll(
"::",
"@@");
456 R__READ_LOCKGUARD(ROOT::gCoreMutex);
458 if (fBasesLoaded && fBasesLoaded->FindObject(sbase))
461 R__WRITE_LOCKGUARD(ROOT::gCoreMutex);
465 if (fBasesLoaded && fBasesLoaded->FindObject(sbase))
469 fBasesLoaded =
new THashTable();
470 fBasesLoaded->SetOwner();
472 fBasesLoaded->Add(
new TObjString(sbase));
474 TPH__IsReadingDirs() = kTRUE;
476 TString plugindirs = gEnv->GetValue(
"Root.PluginPath", (
char*)0);
477 if (plugindirs.Length() == 0) {
478 plugindirs =
"plugins";
479 gSystem->PrependPathName(TROOT::GetEtcDir(), plugindirs);
482 TObjArray *dirs = plugindirs.Tokenize(
";");
484 TObjArray *dirs = plugindirs.Tokenize(
":");
487 for (Int_t i = 0; i < dirs->GetEntriesFast(); i++) {
488 d = ((TObjString*)dirs->At(i))->GetString();
491 for (Int_t j = 0; j < i; j++) {
492 TString pd = ((TObjString*)dirs->At(j))->GetString();
500 const char *p = gSystem->ConcatFileName(d, sbase);
501 LoadHandlerMacros(p);
504 void *dirp = gSystem->OpenDirectory(d);
507 Info(
"LoadHandlersFromPluginDirs",
"%s", d.Data());
509 while ((f1 = gSystem->GetDirEntry(dirp))) {
511 const char *p = gSystem->ConcatFileName(d, f);
512 LoadHandlerMacros(p);
513 fBasesLoaded->Add(
new TObjString(f));
517 gSystem->FreeDirectory(dirp);
521 TPH__IsReadingDirs() = kFALSE;
529 void TPluginManager::AddHandler(
const char *base,
const char *regexp,
530 const char *className,
const char *pluginName,
531 const char *ctor,
const char *origin)
534 R__LOCKGUARD2(gPluginManagerMutex);
536 fHandlers =
new TList;
537 fHandlers->SetOwner();
541 RemoveHandler(base, regexp);
543 if (TPH__IsReadingDirs())
544 origin = gInterpreter->GetCurrentMacroName();
546 TPluginHandler *h =
new TPluginHandler(base, regexp, className,
547 pluginName, ctor, origin);
549 R__LOCKGUARD2(gPluginManagerMutex);
558 void TPluginManager::RemoveHandler(
const char *base,
const char *regexp)
560 R__LOCKGUARD2(gPluginManagerMutex);
561 if (!fHandlers)
return;
563 TIter next(fHandlers);
566 while ((h = (TPluginHandler*) next())) {
567 if (h->fBase == base) {
568 if (!regexp || h->fRegexp == regexp) {
569 fHandlers->Remove(h);
581 TPluginHandler *TPluginManager::FindHandler(
const char *base,
const char *uri)
583 LoadHandlersFromPluginDirs(base);
585 R__LOCKGUARD2(gPluginManagerMutex);
586 TIter next(fHandlers);
589 while ((h = (TPluginHandler*) next())) {
590 if (h->CanHandle(base, uri)) {
592 Info(
"FindHandler",
"found plugin for %s", h->GetClass());
599 Info(
"FindHandler",
"did not find plugin for class %s and uri %s", base, uri);
601 Info(
"FindHandler",
"did not find plugin for class %s", base);
611 void TPluginManager::Print(Option_t *opt)
const
613 if (!fHandlers)
return;
615 TIter next(fHandlers);
617 Int_t cnt = 0, cntmiss = 0;
619 Printf(
"=====================================================================");
620 Printf(
"Base Regexp Class Plugin");
621 Printf(
"=====================================================================");
623 while ((h = (TPluginHandler*) next())) {
626 if (h->CheckPlugin() == -1)
629 Printf(
"=====================================================================");
630 Printf(
"%d plugin handlers registered", cnt);
631 Printf(
"[*] %d %s not available", cntmiss, cntmiss==1 ?
"plugin" :
"plugins");
632 Printf(
"=====================================================================\n");
641 Int_t TPluginManager::WritePluginMacros(
const char *dir,
const char *plugin)
const
643 const_cast<TPluginManager*
>(
this)->LoadHandlersFromPluginDirs();
645 if (!fHandlers)
return 0;
653 if (gSystem->AccessPathName(d, kWritePermission)) {
654 Error(
"WritePluginMacros",
"cannot write in directory %s", d.Data());
661 TObjLink *lnk = fHandlers->FirstLink();
663 TPluginHandler *h = (TPluginHandler *) lnk->GetObject();
664 if (plugin && strcmp(plugin, h->fBase) && strcmp(plugin, h->fClass)) {
668 if (base != h->fBase) {
673 const char *dd = gSystem->ConcatFileName(d, h->fBase);
675 sdd.ReplaceAll(
"::",
"@@");
677 if (gSystem->AccessPathName(sdd, kWritePermission)) {
678 if (gSystem->MakeDirectory(sdd) < 0) {
679 Error(
"WritePluginMacros",
"cannot create directory %s", sdd.Data());
684 fn.Form(
"P%03d_%s.C", idx, h->fClass.Data());
685 const char *fd = gSystem->ConcatFileName(sdd, fn);
686 FILE *f = fopen(fd,
"w");
688 fprintf(f,
"void P%03d_%s()\n{\n", idx, h->fClass.Data());
689 fprintf(f,
" gPluginMgr->AddHandler(\"%s\", \"%s\", \"%s\",\n",
690 h->fBase.Data(), h->fRegexp.Data(), h->fClass.Data());
691 fprintf(f,
" \"%s\", \"%s\");\n", h->fPlugin.Data(), h->fCtor.Data());
695 TObjLink *lnk2 = lnk->Next();
697 TPluginHandler *h2 = (TPluginHandler *) lnk2->GetObject();
698 if (h->fBase != h2->fBase || h->fClass != h2->fClass)
701 fprintf(f,
" gPluginMgr->AddHandler(\"%s\", \"%s\", \"%s\",\n",
702 h2->fBase.Data(), h2->fRegexp.Data(), h2->fClass.Data());
703 fprintf(f,
" \"%s\", \"%s\");\n", h2->fPlugin.Data(), h2->fCtor.Data());
725 Int_t TPluginManager::WritePluginRecords(
const char *envFile,
const char *plugin)
const
727 const_cast<TPluginManager*
>(
this)->LoadHandlersFromPluginDirs();
729 if (!fHandlers)
return 0;
732 if (!envFile || !envFile[0])
735 fd = fopen(envFile,
"w+");
738 Error(
"WritePluginRecords",
"error opening file %s", envFile);
745 TObjLink *lnk = fHandlers->FirstLink();
747 TPluginHandler *h = (TPluginHandler *) lnk->GetObject();
748 if (plugin && strcmp(plugin, h->fBase) && strcmp(plugin, h->fClass)) {
752 if (base != h->fBase) {
756 base2.ReplaceAll(
"::",
"@@");
761 fprintf(fd,
"Plugin.%s: %s %s %s \"%s\"\n", base2.Data(), h->fRegexp.Data(),
762 h->fClass.Data(), h->fPlugin.Data(), h->fCtor.Data());
764 fprintf(fd,
"+Plugin.%s: %s %s %s \"%s\"\n", base2.Data(), h->fRegexp.Data(),
765 h->fClass.Data(), h->fPlugin.Data(), h->fCtor.Data());
769 TObjLink *lnk2 = lnk->Next();
771 TPluginHandler *h2 = (TPluginHandler *) lnk2->GetObject();
772 if (h->fBase != h2->fBase || h->fClass != h2->fClass)
775 fprintf(fd,
"+Plugin.%s: %s %s %s \"%s\"\n", base2.Data(), h2->fRegexp.Data(),
776 h2->fClass.Data(), h2->fPlugin.Data(), h2->fCtor.Data());
784 if (envFile && envFile[0])