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