Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TPluginManager.cxx
Go to the documentation of this file.
1// @(#)root/base:$Id$
2// Author: Fons Rademakers 26/1/2002
3
4/*************************************************************************
5 * Copyright (C) 1995-2002, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12/** \class TPluginManager
13\ingroup Base
14
15This class implements a plugin library manager.
16
17It keeps track of a list of plugin handlers. A plugin handler knows which plugin
18library to load to get a specific class that is used to extend the
19functionality of a specific base class and how to create an object
20of this class. For example, to extend the base class TFile to be
21able to read SQLite files one needs to load the plugin library
22libRSQLite.so which defines the TRSQLiteServer class. This loading
23should be triggered when a given URI contains a regular expression
24defined by the handler.
25
26Plugin handlers can be defined via macros in a list of plugin
27directories. With $ROOTSYS/etc/plugins the default top plugin
28directory specified in $ROOTSYS/etc/system.rootrc. Additional
29directories can be specified by adding them to the end of the list.
30Macros for identical plugin handlers in later directories will
31override previous ones (the inverse of normal search path behavior).
32The macros must have names like `<BaseClass>/PX0_<PluginClass>.C`,
33e.g. TSQLServer/P20_TMySQLServer.C, to allow easy sorting and grouping.
34If the BaseClass is in a namespace the directory must have the name
35NameSpace@@BaseClass as `:` is a reserved pathname character on some
36operating systems. Macros not beginning with 'P' and ending with ".C"
37are ignored. These macros typically look like:
38~~~ {.cpp}
39 void P10_TDCacheFile()
40 {
41 gPluginMgr->AddHandler("TFile", "^dcache", "TDCacheFile",
42 "DCache", "TDCacheFile(const char*,Option_t*)");
43 }
44~~~
45Plugin handlers can also be defined via resources in the .rootrc
46file. Although now deprecated this method still works for backward
47compatibility, e.g.:
48~~~ {.cpp}
49 Plugin.TSQLServer: ^mysql: TMySQLServer MySQL "<constructor>"
50 +Plugin.TSQLServer: ^pgsql: TPgSQLServer PgSQL "<constructor>"
51 Plugin.TVirtualFitter: * TFitter Minuit "TFitter(Int_t)"
52~~~
53Where the + in front of Plugin.TSQLServer says that it extends the
54existing definition of TSQLServer, useful when there is more than
55one plugin that can extend the same base class. The "<constructor>"
56should be the constructor or a static method that generates an
57instance of the specified class. Global methods should start with
58"::" in their name, like "::CreateFitter()".
59Instead of being a shared library a plugin can also be a CINT
60script, so instead of libDialog.so one can have Dialog.C.
61The * is a placeholder in case there is no need for a URI to
62differentiate between different plugins for the same base class.
63For the default plugins see $ROOTSYS/etc/system.rootrc.
64
65Plugin handlers can also be registered at run time, e.g.:
66~~~ {.cpp}
67 gPluginMgr->AddHandler("TSQLServer", "^sqlite:",
68 "TSQLiteServer", "RSQLite",
69 "TSQLiteServer(const char*,const char*,const char*)");
70~~~
71A list of currently defined handlers can be printed using:
72~~~ {.cpp}
73 gPluginMgr->Print(); // use option="a" to see ctors
74~~~
75The use of the plugin library manager removes all textual references
76to hard-coded class and library names and the resulting dependencies
77in the base classes. The plugin manager is used to extend a.o.
78TFile, TSQLServer, TGrid, etc. functionality.
79*/
80
81#include "TPluginManager.h"
82#include "TEnv.h"
83#include "TRegexp.h"
84#include "TROOT.h"
85#include "TSortedList.h"
86#include "THashList.h"
87#include "THashTable.h"
88#include "TClass.h"
89#include "TClassEdit.h"
90#include "TInterpreter.h"
91#include "TMethod.h"
92#include "TMethodArg.h"
93#include "TDataType.h"
94#include "TMethodCall.h"
95#include "TVirtualMutex.h"
96#include "TSystem.h"
97#include "TObjString.h"
98#include "TObjArray.h"
99#include "ThreadLocalStorage.h"
100
101#include <memory>
102#include <sstream>
103
104TPluginManager *gPluginMgr; // main plugin manager created in TROOT
105
106static bool &TPH__IsReadingDirs() {
107 TTHREAD_TLS(bool) readingDirs (false);
108 return readingDirs;
109}
110
112
113////////////////////////////////////////////////////////////////////////////////
114/// Create a plugin handler. Called by TPluginManager.
115
116TPluginHandler::TPluginHandler(const char *base, const char *regexp, const char *className, const char *pluginName,
117 const char *ctor, const char *origin)
118 : fBase(base),
119 fRegexp(regexp),
120 fClass(className),
121 fPlugin(pluginName),
122 fCtor(ctor),
123 fOrigin(origin),
124 fCallEnv(nullptr),
125 fMethod(nullptr),
126 fCanCall(0),
127 fIsMacro(kFALSE),
128 fIsGlobal(kFALSE),
129 fLoadStatus(-1)
130{
131 TString aclicMode, arguments, io;
132 TString fname = gSystem->SplitAclicMode(fPlugin, aclicMode, arguments, io);
133 Bool_t validMacro = kFALSE;
134 if (fname.EndsWith(".C") || fname.EndsWith(".cxx") || fname.EndsWith(".cpp") ||
135 fname.EndsWith(".cc"))
136 validMacro = kTRUE;
137
138 if (validMacro && gROOT->LoadMacro(fPlugin, nullptr, kTRUE) == 0)
139 fIsMacro = kTRUE;
140
141 if (fCtor.BeginsWith("::")) {
144 }
145}
146
147////////////////////////////////////////////////////////////////////////////////
148/// Cleanup plugin handler object.
149
151{
152 delete fCallEnv;
153}
154
155////////////////////////////////////////////////////////////////////////////////
156/// Check if regular expression appears in the URI, if so return kTRUE.
157/// If URI = 0 always return kTRUE.
158
159Bool_t TPluginHandler::CanHandle(const char *base, const char *uri)
160{
161 if (fBase != base)
162 return kFALSE;
163
164 if (!uri || fRegexp == "*")
165 return kTRUE;
166
167 Bool_t wildcard = kFALSE;
168 if (!fRegexp.MaybeRegexp())
169 wildcard = kTRUE;
170
171 TRegexp re(fRegexp, wildcard);
172 TString ruri = uri;
173
174 if (ruri.Index(re) != kNPOS)
175 return kTRUE;
176 return kFALSE;
177}
178
179////////////////////////////////////////////////////////////////////////////////
180/// Return true if the name of the iarg-th argument's type match `type_name`
181Bool_t TPluginHandler::CheckNameMatch(int iarg, const std::type_info& ti)
182{
183 int err = 0;
184 char* demangled_name = TClassEdit::DemangleTypeIdName(ti, err);
185 if (err) {
186 return false;
187 }
188 std::string norm_name;
189 TClassEdit::GetNormalizedName(norm_name, demangled_name);
190 free(demangled_name);
191 const TMethodArg *arg = static_cast<const TMethodArg *>(fMethod->GetListOfMethodArgs()->At(iarg));
192 return norm_name == arg->GetTypeNormalizedName();
193}
194
195////////////////////////////////////////////////////////////////////////////////
196/// Setup ctor or static method call environment.
197
199{
200 int setCanCall = -1;
201
202 // Use a exit_scope guard, to insure that fCanCall is set (to the value of
203 // result) as the last action of this function before returning.
204
205 // When the standard supports it, we should use std::exit_code
206 // See N4189 for example.
207 // auto guard = make_exit_scope( [...]() { ... } );
208 using exit_scope = std::shared_ptr<void*>;
209 exit_scope guard(nullptr,
210 [this,&setCanCall](void *) { this->fCanCall = setCanCall; } );
211
212 // check if class exists
214 if (!cl && !fIsGlobal) {
215 Error("SetupCallEnv", "class %s not found in plugin %s", fClass.Data(),
216 fPlugin.Data());
217 return;
218 }
219
220 // split method and prototype strings
221 TString method = fCtor(0, fCtor.Index("("));
222 TString proto = fCtor(fCtor.Index("(")+1, fCtor.Index(")")-fCtor.Index("(")-1);
223
224 if (fIsGlobal) {
225 cl = nullptr;
226 fMethod = gROOT->GetGlobalFunctionWithPrototype(method, proto, kFALSE);
227 } else {
228 fMethod = cl->GetMethodWithPrototype(method, proto);
229 }
230
231 if (!fMethod) {
232 if (fIsGlobal)
233 Error("SetupCallEnv", "global function %s not found", method.Data());
234 else
235 Error("SetupCallEnv", "method %s not found in class %s", method.Data(),
236 fClass.Data());
237 return;
238 }
239
240 if (!fIsGlobal && !(fMethod->Property() & kIsPublic)) {
241 Error("SetupCallEnv", "method %s is not public", method.Data());
242 return;
243 }
244
245 fCallEnv = new TMethodCall;
247
248 // cache argument types for fast comparison
249 fArgTupleTypeInfo.clear();
251
252 setCanCall = 1;
253
254 return;
255}
256
257
258////////////////////////////////////////////////////////////////////////////////
259/// Check if the plugin library for this handler exits. Returns 0
260/// when it exists and -1 in case the plugin does not exist.
261
263{
264 if (fIsMacro) {
265 if (TClass::GetClass(fClass)) return 0;
266 return gROOT->LoadMacro(fPlugin, nullptr, kTRUE);
267 } else
268 return gROOT->LoadClass(fClass, fPlugin, kTRUE);
269}
270
271////////////////////////////////////////////////////////////////////////////////
272/// Load the plugin library for this handler. Sets status to 0 on successful loading
273/// and -1 in case the library does not exist or in case of error.
275{
276 if (fIsMacro) {
278 fLoadStatus = 0;
279 else
280 fLoadStatus = gROOT->LoadMacro(fPlugin);
281 } else {
282 // first call also loads dependent libraries declared via the rootmap file
283 if (TClass::LoadClass(fClass, /* silent = */ kFALSE))
284 fLoadStatus = 0;
285 else
286 fLoadStatus = gROOT->LoadClass(fClass, fPlugin);
287 }
288}
289
290////////////////////////////////////////////////////////////////////////////////
291/// Load the plugin library for this handler. Returns 0 on successful loading
292/// and -1 in case the library does not exist or in case of error.
294{
295 // call once and cache the result to reduce lock contention
296 std::call_once(fLoadStatusFlag, &TPluginHandler::LoadPluginImpl, this);
297 return fLoadStatus;
298}
299
300////////////////////////////////////////////////////////////////////////////////
301/// Check that we can properly run ExecPlugin.
302
304{
305 if (fCtor.IsNull()) {
306 Error("ExecPlugin", "no ctor specified for this handler %s", fClass.Data());
307 return kFALSE;
308 }
309
310 if (fCanCall == 0) {
311 // Not initialized yet.
312 // SetupCallEnv is likely to require/take the interpreter lock.
313 // Grab it now to avoid dead-lock. In particular TPluginHandler::ExecPluginImpl
314 // takes the gInterpreterMutex and *then* call (indirectly) code that
315 // take the lock in fHandlers.
317
318 // Now check if another thread did not already do the work.
319 if (fCanCall == 0)
320 SetupCallEnv();
321 }
322
323 if (fCanCall == -1)
324 return kFALSE;
325
326 if (nargs < fMethod->GetNargs() - fMethod->GetNargsOpt() ||
327 nargs > fMethod->GetNargs()) {
328 Error("ExecPlugin", "nargs (%d) not consistent with expected number of arguments ([%d-%d])",
329 nargs, fMethod->GetNargs() - fMethod->GetNargsOpt(),
330 fMethod->GetNargs());
331 return kFALSE;
332 }
333
334 return kTRUE;
335}
336
337////////////////////////////////////////////////////////////////////////////////
338/// Print info about the plugin handler. If option is "a" print
339/// also the ctor's that will be used.
340
342{
343 const char *exist = "";
344 if (CheckPlugin() == -1)
345 exist = " [*]";
346
347 Printf("%-20s %-13s %-18s %s%s", fBase.Data(), fRegexp.Data(),
348 fClass.Data(), fPlugin.Data(), exist);
349 if (strchr(opt, 'a')) {
350 if (!exist[0]) {
351 TString lib = fPlugin;
352 if (!lib.BeginsWith("lib"))
353 lib = "lib" + lib;
354 char *path = gSystem->DynamicPathName(lib, kTRUE);
355 if (path) Printf(" [Lib: %s]", path);
356 delete [] path;
357 }
358 Printf(" [Ctor: %s]", fCtor.Data());
359 Printf(" [origin: %s]", fOrigin.Data());
360 }
361}
362
363
365
366////////////////////////////////////////////////////////////////////////////////
367/// Constructor
368TPluginManager::TPluginManager() : fHandlers(new TList()), fBasesLoaded(nullptr), fReadingDirs(kFALSE)
369{
372}
373
374////////////////////////////////////////////////////////////////////////////////
375/// Clean up the plugin manager.
376
378{
379 delete fHandlers;
380 delete fBasesLoaded;
381}
382
383////////////////////////////////////////////////////////////////////////////////
384/// Load plugin handlers specified in config file, like:
385/// ~~~ {.cpp}
386/// Plugin.TSQLServer: ^mysql: TMySQLServer MySQL "TMySQLServer(...)"
387/// +Plugin.TSQLServer: ^pgsql: TPgSQLServer PgSQL "TPgSQLServer(...)"
388/// ~~~
389/// The + allows the extension of an already defined resource (see TEnv).
390
392{
393 if (!env) return;
394
395 TIter next(env->GetTable());
396 TEnvRec *er;
397
398 while ((er = (TEnvRec*) next())) {
399 const char *s;
400 if ((s = strstr(er->GetName(), "Plugin."))) {
401 // use s, i.e. skip possible OS and application prefix to Plugin.
402 // so that GetValue() takes properly care of returning the value
403 // for the specified OS and/or application
404 const char *val = env->GetValue(s, (const char*)nullptr);
405 if (val) {
406 Int_t cnt = 0;
407 char *v = StrDup(val);
408 s += 7;
409 while (1) {
410 TString regexp = strtok(!cnt ? v : nullptr, "; "); // this method does not need to be reentrant
411 if (regexp.IsNull()) break;
412 TString clss = strtok(nullptr, "; ");
413 if (clss.IsNull()) break;
414 TString plugin = strtok(nullptr, "; ");
415 if (plugin.IsNull()) break;
416 TString ctor = strtok(nullptr, ";\"");
417 if (!ctor.Contains("("))
418 ctor = strtok(nullptr, ";\"");
419 AddHandler(s, regexp, clss, plugin, ctor, "TEnv");
420 cnt++;
421 }
422 delete [] v;
423 }
424 }
425 }
426}
427
428////////////////////////////////////////////////////////////////////////////////
429/// Load all plugin macros from the specified path/base directory.
430
432{
433 void *dirp = gSystem->OpenDirectory(path);
434 if (dirp) {
435 if (gDebug > 0)
436 Info("LoadHandlerMacros", "%s", path);
437 TSortedList macros;
438 macros.SetOwner();
439 const char *f1;
440 while ((f1 = gSystem->GetDirEntry(dirp))) {
441 TString f = f1;
442 if (f[0] == 'P' && f.EndsWith(".C")) {
443 const char *p = gSystem->ConcatFileName(path, f);
445 macros.Add(new TObjString(p));
446 }
447 delete [] p;
448 }
449 }
450 // load macros in alphabetical order
451 TIter next(&macros);
452 TObjString *s;
453 while ((s = (TObjString*)next())) {
454 if (gDebug > 1)
455 Info("LoadHandlerMacros", " plugin macro: %s", s->String().Data());
456 Longptr_t res;
457 if ((res = gROOT->Macro(s->String(), nullptr, kFALSE)) < 0) {
458 Error("LoadHandlerMacros", "pluging macro %s returned %ld",
459 s->String().Data(), res);
460 }
461 }
462 }
463 gSystem->FreeDirectory(dirp);
464}
465
466////////////////////////////////////////////////////////////////////////////////
467/// Load plugin handlers specified via macros in a list of plugin
468/// directories. The `$ROOTSYS/etc/plugins` is the default top plugin directory
469/// specified in `$ROOTSYS/etc/system.rootrc`. The macros must have names
470/// like `<BaseClass>/PX0_<PluginClass>.C`, e.g. //`TSQLServer/P20_TMySQLServer.C`,
471/// to allow easy sorting and grouping. If the BaseClass is in a namespace
472/// the directory must have the name NameSpace@@BaseClass as : is a reserved
473/// pathname character on some operating systems. Macros not beginning with
474/// 'P' and ending with ".C" are ignored. If base is specified only plugin
475/// macros for that base class are loaded. The macros typically
476/// should look like:
477/// ~~~ {.cpp}
478/// void P10_TDCacheFile()
479/// {
480/// gPluginMgr->AddHandler("TFile", "^dcache", "TDCacheFile",
481/// "DCache", "TDCacheFile(const char*,Option_t*,const char*,Int_t)");
482/// }
483/// ~~~
484/// In general these macros should not cause side effects, by changing global
485/// ROOT state via, e.g. gSystem calls, etc. However, in specific cases
486/// this might be useful, e.g. adding a library search path, adding a specific
487/// dependency, check on some OS or ROOT capability or downloading
488/// of the plugin.
489
491{
492 TString sbase = base;
493 if (sbase.Length())
494 sbase.ReplaceAll("::", "@@");
495
497
498 if (fBasesLoaded && fBasesLoaded->FindObject(sbase))
499 return;
500
502
503 // While waiting for the lock, another thread may
504 // have process the requested plugin.
505 if (fBasesLoaded && fBasesLoaded->FindObject(sbase))
506 return;
507
508 if (!fBasesLoaded) {
509 fBasesLoaded = new THashTable();
511 }
512 fBasesLoaded->Add(new TObjString(sbase));
513
515
516 TString plugindirs = gEnv->GetValue("Root.PluginPath", (char*)nullptr);
517 if (plugindirs.Length() == 0) {
518 plugindirs = "plugins";
520 }
521#ifdef WIN32
522 TObjArray *dirs = plugindirs.Tokenize(";");
523#else
524 TObjArray *dirs = plugindirs.Tokenize(":");
525#endif
526 TString d;
527 for (Int_t i = 0; i < dirs->GetEntriesFast(); i++) {
528 d = ((TObjString*)dirs->At(i))->GetString();
529 // check if directory already scanned
530 Int_t skip = 0;
531 for (Int_t j = 0; j < i; j++) {
532 TString pd = ((TObjString*)dirs->At(j))->GetString();
533 if (pd == d) {
534 skip++;
535 break;
536 }
537 }
538 if (!skip) {
539 if (sbase != "") {
540 const char *p = gSystem->ConcatFileName(d, sbase);
542 delete [] p;
543 } else {
544 void *dirp = gSystem->OpenDirectory(d);
545 if (dirp) {
546 if (gDebug > 0)
547 Info("LoadHandlersFromPluginDirs", "%s", d.Data());
548 const char *f1;
549 while ((f1 = gSystem->GetDirEntry(dirp))) {
550 TString f = f1;
551 const char *p = gSystem->ConcatFileName(d, f);
554 delete [] p;
555 }
556 }
557 gSystem->FreeDirectory(dirp);
558 }
559 }
560 }
562 delete dirs;
563}
564
565////////////////////////////////////////////////////////////////////////////////
566/// Add plugin handler to the list of handlers. If there is already a
567/// handler defined for the same base and regexp it will be replaced.
568
569void TPluginManager::AddHandler(const char *base, const char *regexp,
570 const char *className, const char *pluginName,
571 const char *ctor, const char *origin)
572{
573 // make sure there is no previous handler for the same case
574 RemoveHandler(base, regexp);
575
576 if (TPH__IsReadingDirs())
577 origin = gInterpreter->GetCurrentMacroName();
578
579 TPluginHandler *h = new TPluginHandler(base, regexp, className,
580 pluginName, ctor, origin);
581 fHandlers->Add(h);
582}
583
584////////////////////////////////////////////////////////////////////////////////
585/// Remove handler for the specified base class and the specified
586/// regexp. If regexp=0 remove all handlers for the specified base.
587
588void TPluginManager::RemoveHandler(const char *base, const char *regexp)
589{
590 TIter next(fHandlers);
592
593 while ((h = (TPluginHandler*) next())) {
594 if (h->fBase == base) {
595 if (!regexp || h->fRegexp == regexp) {
597 delete h;
598 }
599 }
600 }
601}
602
603////////////////////////////////////////////////////////////////////////////////
604/// Returns the handler if there exists a handler for the specified URI.
605/// The uri can be 0 in which case the first matching plugin handler
606/// will be returned. Returns 0 in case handler is not found.
607
608TPluginHandler *TPluginManager::FindHandler(const char *base, const char *uri)
609{
611
612 TIter next(fHandlers);
614
615 while ((h = (TPluginHandler*) next())) {
616 if (h->CanHandle(base, uri)) {
617 if (gDebug > 0)
618 Info("FindHandler", "found plugin for %s", h->GetClass());
619 return h;
620 }
621 }
622
623 if (gDebug > 2) {
624 if (uri)
625 Info("FindHandler", "did not find plugin for class %s and uri %s", base, uri);
626 else
627 Info("FindHandler", "did not find plugin for class %s", base);
628 }
629
630 return nullptr;
631}
632
633////////////////////////////////////////////////////////////////////////////////
634/// Print list of registered plugin handlers. If option is "a" print
635/// also the ctor's that will be used.
636
638{
639 TIter next(fHandlers);
641 Int_t cnt = 0, cntmiss = 0;
642
643 Printf("=====================================================================");
644 Printf("Base Regexp Class Plugin");
645 Printf("=====================================================================");
646
647 while ((h = (TPluginHandler*) next())) {
648 cnt++;
649 h->Print(opt);
650 if (h->CheckPlugin() == -1)
651 cntmiss++;
652 }
653 Printf("=====================================================================");
654 Printf("%d plugin handlers registered", cnt);
655 Printf("[*] %d %s not available", cntmiss, cntmiss==1 ? "plugin" : "plugins");
656 Printf("=====================================================================\n");
657}
658
659////////////////////////////////////////////////////////////////////////////////
660/// Write in the specified directory the plugin macros. If plugin is specified
661/// and if it is a base class all macros for that base will be written. If it
662/// is a plugin class name, only that one macro will be written. If plugin
663/// is 0 all macros are written. Returns -1 if dir does not exist, 0 otherwise.
664
665Int_t TPluginManager::WritePluginMacros(const char *dir, const char *plugin) const
666{
667 const_cast<TPluginManager*>(this)->LoadHandlersFromPluginDirs();
668
669 TString d;
670 if (!dir || !dir[0])
671 d = ".";
672 else
673 d = dir;
674
676 Error("WritePluginMacros", "cannot write in directory %s", d.Data());
677 return -1;
678 }
679
680 TString base;
681 Int_t idx = 0;
682
683 TObjLink *lnk = fHandlers->FirstLink();
684 while (lnk) {
686 if (plugin && strcmp(plugin, h->fBase) && strcmp(plugin, h->fClass)) {
687 lnk = lnk->Next();
688 continue;
689 }
690 if (base != h->fBase) {
691 idx = 10;
692 base = h->fBase;
693 } else
694 idx += 10;
695 const char *dd = gSystem->ConcatFileName(d, h->fBase);
696 TString sdd = dd;
697 sdd.ReplaceAll("::", "@@");
698 delete [] dd;
700 if (gSystem->MakeDirectory(sdd) < 0) {
701 Error("WritePluginMacros", "cannot create directory %s", sdd.Data());
702 return -1;
703 }
704 }
705 TString fn;
706 fn.Form("P%03d_%s.C", idx, h->fClass.Data());
707 const char *fd = gSystem->ConcatFileName(sdd, fn);
708 FILE *f = fopen(fd, "w");
709 if (f) {
710 fprintf(f, "void P%03d_%s()\n{\n", idx, h->fClass.Data());
711 fprintf(f, " gPluginMgr->AddHandler(\"%s\", \"%s\", \"%s\",\n",
712 h->fBase.Data(), h->fRegexp.Data(), h->fClass.Data());
713 fprintf(f, " \"%s\", \"%s\");\n", h->fPlugin.Data(), h->fCtor.Data());
714
715 // check for different regexps cases for the same base + class and
716 // put them all in the same macro
717 TObjLink *lnk2 = lnk->Next();
718 while (lnk2) {
719 TPluginHandler *h2 = (TPluginHandler *) lnk2->GetObject();
720 if (h->fBase != h2->fBase || h->fClass != h2->fClass)
721 break;
722
723 fprintf(f, " gPluginMgr->AddHandler(\"%s\", \"%s\", \"%s\",\n",
724 h2->fBase.Data(), h2->fRegexp.Data(), h2->fClass.Data());
725 fprintf(f, " \"%s\", \"%s\");\n", h2->fPlugin.Data(), h2->fCtor.Data());
726
727 lnk = lnk2;
728 lnk2 = lnk2->Next();
729 }
730 fprintf(f, "}\n");
731 fclose(f);
732 }
733 delete [] fd;
734 lnk = lnk->Next();
735 }
736 return 0;
737}
738
739////////////////////////////////////////////////////////////////////////////////
740/// Write in the specified environment config file the plugin records. If
741/// plugin is specified and if it is a base class all records for that
742/// base will be written. If it is a plugin class name, only that one
743/// record will be written. If plugin is 0 all macros are written.
744/// If envFile is 0 or "" the records are written to stdout.
745/// Returns -1 if envFile cannot be created or opened, 0 otherwise.
746
747Int_t TPluginManager::WritePluginRecords(const char *envFile, const char *plugin) const
748{
749 const_cast<TPluginManager*>(this)->LoadHandlersFromPluginDirs();
750
751 FILE *fd;
752 if (!envFile || !envFile[0])
753 fd = stdout;
754 else
755 fd = fopen(envFile, "w+");
756
757 if (!fd) {
758 Error("WritePluginRecords", "error opening file %s", envFile);
759 return -1;
760 }
761
762 TString base, base2;
763 Int_t idx = 0;
764
765 TObjLink *lnk = fHandlers->FirstLink();
766 while (lnk) {
768 if (plugin && strcmp(plugin, h->fBase) && strcmp(plugin, h->fClass)) {
769 lnk = lnk->Next();
770 continue;
771 }
772 if (base != h->fBase) {
773 idx = 1;
774 base = h->fBase;
775 base2 = base;
776 base2.ReplaceAll("::", "@@");
777 } else
778 idx += 1;
779
780 if (idx == 1)
781 fprintf(fd, "Plugin.%s: %s %s %s \"%s\"\n", base2.Data(), h->fRegexp.Data(),
782 h->fClass.Data(), h->fPlugin.Data(), h->fCtor.Data());
783 else
784 fprintf(fd, "+Plugin.%s: %s %s %s \"%s\"\n", base2.Data(), h->fRegexp.Data(),
785 h->fClass.Data(), h->fPlugin.Data(), h->fCtor.Data());
786
787 // check for different regexps cases for the same base + class and
788 // put them all in the same macro
789 TObjLink *lnk2 = lnk->Next();
790 while (lnk2) {
791 TPluginHandler *h2 = (TPluginHandler *) lnk2->GetObject();
792 if (h->fBase != h2->fBase || h->fClass != h2->fClass)
793 break;
794
795 fprintf(fd, "+Plugin.%s: %s %s %s \"%s\"\n", base2.Data(), h2->fRegexp.Data(),
796 h2->fClass.Data(), h2->fPlugin.Data(), h2->fCtor.Data());
797
798 lnk = lnk2;
799 lnk2 = lnk2->Next();
800 }
801 lnk = lnk->Next();
802 }
803
804 if (envFile && envFile[0])
805 fclose(fd);
806
807 return 0;
808}
Cppyy::TCppType_t fClass
#define d(i)
Definition RSha256.hxx:102
#define f(i)
Definition RSha256.hxx:104
#define h(i)
Definition RSha256.hxx:106
long Longptr_t
Definition RtypesCore.h:75
constexpr Bool_t kFALSE
Definition RtypesCore.h:94
constexpr Ssiz_t kNPOS
Definition RtypesCore.h:117
constexpr Bool_t kTRUE
Definition RtypesCore.h:93
const char Option_t
Definition RtypesCore.h:66
#define ClassImp(name)
Definition Rtypes.h:382
@ kIsPublic
Definition TDictionary.h:75
R__EXTERN TEnv * gEnv
Definition TEnv.h:170
winID h TVirtualViewer3D TVirtualGLPainter p
R__EXTERN TVirtualMutex * gInterpreterMutex
#define gInterpreter
static bool & TPH__IsReadingDirs()
TPluginManager * gPluginMgr
Int_t gDebug
Definition TROOT.cxx:597
#define gROOT
Definition TROOT.h:406
void Printf(const char *fmt,...)
Formats a string in a circular formatting buffer and prints the string.
Definition TString.cxx:2503
char * StrDup(const char *str)
Duplicate the string str.
Definition TString.cxx:2557
@ kReadPermission
Definition TSystem.h:45
@ kWritePermission
Definition TSystem.h:44
R__EXTERN TSystem * gSystem
Definition TSystem.h:561
#define R__LOCKGUARD(mutex)
#define R__WRITE_LOCKGUARD(mutex)
#define R__READ_LOCKGUARD(mutex)
const char * proto
Definition civetweb.c:17535
#define free
Definition civetweb.c:1539
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:81
static TClass * LoadClass(const char *requestedname, Bool_t silent)
Helper function used by TClass::GetClass().
Definition TClass.cxx:5830
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition TClass.cxx:3037
virtual bool UseRWLock(Bool_t enable=true)
Set this collection to use a RW lock upon access, making it thread safe.
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
Definition TEnv.h:86
const char * GetName() const override
Returns name of object.
Definition TEnv.h:109
The TEnv class reads config files, by default named .rootrc.
Definition TEnv.h:124
virtual Int_t GetValue(const char *name, Int_t dflt) const
Returns the integer value for a resource.
Definition TEnv.cxx:491
THashList * GetTable() const
Definition TEnv.h:140
Long_t Property() const override
Get property description word. For meaning of bits see EProperty.
Int_t GetNargsOpt() const
Number of function optional (default) arguments.
Int_t GetNargs() const
Number of function arguments.
TList * GetListOfMethodArgs()
Return list containing the TMethodArgs of a TFunction.
THashTable implements a hash table to store TObject's.
Definition THashTable.h:35
void Add(TObject *obj) override
Add object to the hash table.
TObject * FindObject(const char *name) const override
Find object using its name.
A doubly linked list.
Definition TList.h:38
void Add(TObject *obj) override
Definition TList.h:81
TObject * Remove(TObject *obj) override
Remove object from the list.
Definition TList.cxx:820
virtual TObjLink * FirstLink() const
Definition TList.h:102
TObject * At(Int_t idx) const override
Returns the object at position idx. Returns 0 if idx is out of range.
Definition TList.cxx:355
Each ROOT method (see TMethod) has a linked list of its arguments.
Definition TMethodArg.h:36
std::string GetTypeNormalizedName() const
Get the normalized name of the return type.
Method or function calling interface.
Definition TMethodCall.h:37
void Init(const TFunction *func)
Initialize the method invocation environment based on the TFunction object.
An array of TObjects.
Definition TObjArray.h:31
Int_t GetEntriesFast() const
Definition TObjArray.h:58
TObject * At(Int_t idx) const override
Definition TObjArray.h:164
Collectable string class.
Definition TObjString.h:28
TString & String()
Definition TObjString.h:48
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1005
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition TObject.cxx:979
bool CheckNameMatch(int iarg, const std::type_info &ti)
Return true if the name of the iarg-th argument's type match type_name
Int_t CheckPlugin() const
Check if the plugin library for this handler exits.
TFunction * fMethod
ctor method call environment
AtomicInt_t fCanCall
void Print(Option_t *opt="") const override
Print info about the plugin handler.
Bool_t CanHandle(const char *base, const char *uri)
Check if regular expression appears in the URI, if so return kTRUE.
~TPluginHandler()
Cleanup plugin handler object.
Bool_t CheckForExecPlugin(Int_t nargs)
Check that we can properly run ExecPlugin.
Bool_t fIsMacro
if 1 fCallEnv is ok, -1 fCallEnv is not ok, 0 fCallEnv not setup yet.
void SetupCallEnv()
Setup ctor or static method call environment.
void LoadPluginImpl()
Load the plugin library for this handler.
TMethodCall * fCallEnv
std::vector< std::string > fArgTupleTypeInfo
ctor method or global function
Int_t LoadPlugin()
Load the plugin library for this handler.
std::once_flag fLoadStatusFlag
This class implements a plugin library manager.
Int_t WritePluginMacros(const char *dir, const char *plugin=nullptr) const
Write in the specified directory the plugin macros.
void AddHandler(const char *base, const char *regexp, const char *className, const char *pluginName, const char *ctor=nullptr, const char *origin=nullptr)
Add plugin handler to the list of handlers.
void Print(Option_t *opt="") const override
Print list of registered plugin handlers.
~TPluginManager()
Clean up the plugin manager.
void RemoveHandler(const char *base, const char *regexp=nullptr)
Remove handler for the specified base class and the specified regexp.
void LoadHandlersFromEnv(TEnv *env)
Load plugin handlers specified in config file, like:
THashTable * fBasesLoaded
void LoadHandlerMacros(const char *path)
Load all plugin macros from the specified path/base directory.
Int_t WritePluginRecords(const char *envFile, const char *plugin=nullptr) const
Write in the specified environment config file the plugin records.
TPluginHandler * FindHandler(const char *base, const char *uri=nullptr)
Returns the handler if there exists a handler for the specified URI.
TPluginManager()
Constructor.
void LoadHandlersFromPluginDirs(const char *base=nullptr)
Load plugin handlers specified via macros in a list of plugin directories.
static const TString & GetEtcDir()
Get the sysconfig directory in the installation. Static utility function.
Definition TROOT.cxx:3056
Regular expression class.
Definition TRegexp.h:31
A sorted doubly linked list.
Definition TSortedList.h:28
void Add(TObject *obj) override
Add object in sorted list.
Basic string class.
Definition TString.h:139
Ssiz_t Length() const
Definition TString.h:417
Bool_t EndsWith(const char *pat, ECaseCompare cmp=kExact) const
Return true if string ends with the specified string.
Definition TString.cxx:2244
TSubString Strip(EStripType s=kTrailing, char c=' ') const
Return a substring of self stripped at beginning and/or end.
Definition TString.cxx:1163
const char * Data() const
Definition TString.h:376
Bool_t MaybeRegexp() const
Returns true if string contains one of the regexp characters "^$.[]*+?".
Definition TString.cxx:952
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition TString.h:704
@ kLeading
Definition TString.h:276
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
Definition TString.cxx:2264
Bool_t BeginsWith(const char *s, ECaseCompare cmp=kExact) const
Definition TString.h:623
Bool_t IsNull() const
Definition TString.h:414
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition TString.cxx:2356
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:632
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:651
virtual void FreeDirectory(void *dirp)
Free a directory.
Definition TSystem.cxx:845
virtual void * OpenDirectory(const char *name)
Open a directory. Returns 0 if directory does not exist.
Definition TSystem.cxx:836
virtual TString SplitAclicMode(const char *filename, TString &mode, TString &args, TString &io) const
This method split a filename of the form:
Definition TSystem.cxx:4258
virtual char * ConcatFileName(const char *dir, const char *name)
Concatenate a directory and a file name. User must delete returned string.
Definition TSystem.cxx:1071
virtual int MakeDirectory(const char *name)
Make a directory.
Definition TSystem.cxx:827
virtual const char * PrependPathName(const char *dir, TString &name)
Concatenate a directory and a file name.
Definition TSystem.cxx:1081
virtual Bool_t AccessPathName(const char *path, EAccessMode mode=kFileExists)
Returns FALSE if one can access a file using the specified access mode.
Definition TSystem.cxx:1296
virtual const char * GetDirEntry(void *dirp)
Get a directory entry. Returns 0 if no more entries.
Definition TSystem.cxx:853
char * DynamicPathName(const char *lib, Bool_t quiet=kFALSE)
Find a dynamic library called lib using the system search paths.
Definition TSystem.cxx:2020
TF1 * f1
Definition legend1.C:11
R__EXTERN TVirtualRWMutex * gCoreMutex
char * DemangleTypeIdName(const std::type_info &ti, int &errorCode)
Demangle in a portable way the type id name.
void GetNormalizedName(std::string &norm_name, std::string_view name)
Return the normalized name.