Logo ROOT   6.07/09
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;
148  fCtor = fCtor.Strip(TString::kLeading, ':');
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  R__LOCKGUARD2(gPluginManagerMutex);
284 
285  // Now check if another thread did not already do the work.
286  if (fCanCall == 0)
287  SetupCallEnv();
288  }
289 
290  if (fCanCall == -1)
291  return kFALSE;
292 
293  if (nargs < fMethod->GetNargs() - fMethod->GetNargsOpt() ||
294  nargs > fMethod->GetNargs()) {
295  Error("ExecPlugin", "nargs (%d) not consistent with expected number of arguments ([%d-%d])",
296  nargs, fMethod->GetNargs() - fMethod->GetNargsOpt(),
297  fMethod->GetNargs());
298  return kFALSE;
299  }
300 
301  return kTRUE;
302 }
303 
304 ////////////////////////////////////////////////////////////////////////////////
305 /// Print info about the plugin handler. If option is "a" print
306 /// also the ctor's that will be used.
307 
309 {
310  const char *exist = "";
311  if (CheckPlugin() == -1)
312  exist = " [*]";
313 
314  Printf("%-20s %-13s %-18s %s%s", fBase.Data(), fRegexp.Data(),
315  fClass.Data(), fPlugin.Data(), exist);
316  if (strchr(opt, 'a')) {
317  if (!exist[0]) {
318  TString lib = fPlugin;
319  if (!lib.BeginsWith("lib"))
320  lib = "lib" + lib;
321  char *path = gSystem->DynamicPathName(lib, kTRUE);
322  if (path) Printf(" [Lib: %s]", path);
323  delete [] path;
324  }
325  Printf(" [Ctor: %s]", fCtor.Data());
326  Printf(" [origin: %s]", fOrigin.Data());
327  }
328 }
329 
330 
332 
333 ////////////////////////////////////////////////////////////////////////////////
334 /// Clean up the plugin manager.
335 
337 {
338  delete fHandlers;
339  delete fBasesLoaded;
340 }
341 
342 ////////////////////////////////////////////////////////////////////////////////
343 /// Load plugin handlers specified in config file, like:
344 /// ~~~ {.cpp}
345 /// Plugin.TFile: ^rfio: TRFIOFile RFIO "TRFIOFile(...)"
346 /// Plugin.TSQLServer: ^mysql: TMySQLServer MySQL "TMySQLServer(...)"
347 /// +Plugin.TSQLServer: ^pgsql: TPgSQLServer PgSQL "TPgSQLServer(...)"
348 /// ~~~
349 /// The + allows the extension of an already defined resource (see TEnv).
350 
352 {
353  if (!env) return;
354 
355  TIter next(env->GetTable());
356  TEnvRec *er;
357 
358  while ((er = (TEnvRec*) next())) {
359  const char *s;
360  if ((s = strstr(er->GetName(), "Plugin."))) {
361  // use s, i.e. skip possible OS and application prefix to Plugin.
362  // so that GetValue() takes properly care of returning the value
363  // for the specified OS and/or application
364  const char *val = env->GetValue(s, (const char*)0);
365  if (val) {
366  Int_t cnt = 0;
367  char *v = StrDup(val);
368  s += 7;
369  while (1) {
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");
380  cnt++;
381  }
382  delete [] v;
383  }
384  }
385  }
386 }
387 
388 ////////////////////////////////////////////////////////////////////////////////
389 /// Load all plugin macros from the specified path/base directory.
390 
391 void TPluginManager::LoadHandlerMacros(const char *path)
392 {
393  void *dirp = gSystem->OpenDirectory(path);
394  if (dirp) {
395  if (gDebug > 0)
396  Info("LoadHandlerMacros", "%s", path);
397  TSortedList macros;
398  macros.SetOwner();
399  const char *f1;
400  while ((f1 = gSystem->GetDirEntry(dirp))) {
401  TString f = f1;
402  if (f[0] == 'P' && f.EndsWith(".C")) {
403  const char *p = gSystem->ConcatFileName(path, f);
405  macros.Add(new TObjString(p));
406  }
407  delete [] p;
408  }
409  }
410  // load macros in alphabetical order
411  TIter next(&macros);
412  TObjString *s;
413  while ((s = (TObjString*)next())) {
414  if (gDebug > 1)
415  Info("LoadHandlerMacros", " plugin macro: %s", s->String().Data());
416  Long_t res;
417  if ((res = gROOT->Macro(s->String(), 0, kFALSE)) < 0) {
418  Error("LoadHandlerMacros", "pluging macro %s returned %ld",
419  s->String().Data(), res);
420  }
421  }
422  }
423  gSystem->FreeDirectory(dirp);
424 }
425 
426 ////////////////////////////////////////////////////////////////////////////////
427 /// Load plugin handlers specified via macros in a list of plugin
428 /// directories. The `$ROOTSYS/etc/plugins` is the default top plugin directory
429 /// specified in `$ROOTSYS/etc/system.rootrc`. The macros must have names
430 /// like `<BaseClass>/PX0_<PluginClass>.C`, e.g.:
431 /// `TFile/P10_TRFIOFile.C`, `TSQLServer/P20_TMySQLServer.C`, etc.
432 /// to allow easy sorting and grouping. If the BaseClass is in a namespace
433 /// the directory must have the name NameSpace@@BaseClass as : is a reserved
434 /// pathname character on some operating systems. Macros not beginning with
435 /// 'P' and ending with ".C" are ignored. If base is specified only plugin
436 /// macros for that base class are loaded. The macros typically
437 /// should look like:
438 /// ~~~ {.cpp}
439 /// void P10_TDCacheFile()
440 /// {
441 /// gPluginMgr->AddHandler("TFile", "^dcache", "TDCacheFile",
442 /// "DCache", "TDCacheFile(const char*,Option_t*,const char*,Int_t)");
443 /// }
444 /// ~~~
445 /// In general these macros should not cause side effects, by changing global
446 /// ROOT state via, e.g. gSystem calls, etc. However, in specific cases
447 /// this might be useful, e.g. adding a library search path, adding a specific
448 /// dependency, check on some OS or ROOT capability or downloading
449 /// of the plugin.
450 
452 {
453  //The destructor of TObjArray takes the gROOTMutex lock so we want to
454  // delete the object after release the gInterpreterMutex lock
455  TObjArray *dirs = nullptr;
456  {
458  if (!fBasesLoaded) {
459  fBasesLoaded = new THashTable();
460  fBasesLoaded->SetOwner();
461  }
462  TString sbase = base;
463  if (sbase != "") {
464  sbase.ReplaceAll("::", "@@");
465  if (fBasesLoaded->FindObject(sbase))
466  return;
467  fBasesLoaded->Add(new TObjString(sbase));
468  }
469 
471 
472  TString plugindirs = gEnv->GetValue("Root.PluginPath", (char*)0);
473 #ifdef WIN32
474  dirs = plugindirs.Tokenize(";");
475 #else
476  dirs = plugindirs.Tokenize(":");
477 #endif
478  TString d;
479  for (Int_t i = 0; i < dirs->GetEntriesFast(); i++) {
480  d = ((TObjString*)dirs->At(i))->GetString();
481  // check if directory already scanned
482  Int_t skip = 0;
483  for (Int_t j = 0; j < i; j++) {
484  TString pd = ((TObjString*)dirs->At(j))->GetString();
485  if (pd == d) {
486  skip++;
487  break;
488  }
489  }
490  if (!skip) {
491  if (sbase != "") {
492  const char *p = gSystem->ConcatFileName(d, sbase);
493  LoadHandlerMacros(p);
494  delete [] p;
495  } else {
496  void *dirp = gSystem->OpenDirectory(d);
497  if (dirp) {
498  if (gDebug > 0)
499  Info("LoadHandlersFromPluginDirs", "%s", d.Data());
500  const char *f1;
501  while ((f1 = gSystem->GetDirEntry(dirp))) {
502  TString f = f1;
503  const char *p = gSystem->ConcatFileName(d, f);
504  LoadHandlerMacros(p);
505  fBasesLoaded->Add(new TObjString(f));
506  delete [] p;
507  }
508  }
509  gSystem->FreeDirectory(dirp);
510  }
511  }
512  }
514  }
515  delete dirs;
516 }
517 
518 ////////////////////////////////////////////////////////////////////////////////
519 /// Add plugin handler to the list of handlers. If there is already a
520 /// handler defined for the same base and regexp it will be replaced.
521 
522 void TPluginManager::AddHandler(const char *base, const char *regexp,
523  const char *className, const char *pluginName,
524  const char *ctor, const char *origin)
525 {
526  {
527  R__LOCKGUARD2(gPluginManagerMutex);
528  if (!fHandlers) {
529  fHandlers = new TList;
530  fHandlers->SetOwner();
531  }
532  }
533  // make sure there is no previous handler for the same case
534  RemoveHandler(base, regexp);
535 
536  if (TPH__IsReadingDirs())
537  origin = gInterpreter->GetCurrentMacroName();
538 
539  TPluginHandler *h = new TPluginHandler(base, regexp, className,
540  pluginName, ctor, origin);
541  {
542  R__LOCKGUARD2(gPluginManagerMutex);
543  fHandlers->Add(h);
544  }
545 }
546 
547 ////////////////////////////////////////////////////////////////////////////////
548 /// Remove handler for the specified base class and the specified
549 /// regexp. If regexp=0 remove all handlers for the specified base.
550 
551 void TPluginManager::RemoveHandler(const char *base, const char *regexp)
552 {
553  R__LOCKGUARD2(gPluginManagerMutex);
554  if (!fHandlers) return;
555 
556  TIter next(fHandlers);
557  TPluginHandler *h;
558 
559  while ((h = (TPluginHandler*) next())) {
560  if (h->fBase == base) {
561  if (!regexp || h->fRegexp == regexp) {
562  fHandlers->Remove(h);
563  delete h;
564  }
565  }
566  }
567 }
568 
569 ////////////////////////////////////////////////////////////////////////////////
570 /// Returns the handler if there exists a handler for the specified URI.
571 /// The uri can be 0 in which case the first matching plugin handler
572 /// will be returned. Returns 0 in case handler is not found.
573 
574 TPluginHandler *TPluginManager::FindHandler(const char *base, const char *uri)
575 {
576  LoadHandlersFromPluginDirs(base);
577 
578  R__LOCKGUARD2(gPluginManagerMutex);
579  TIter next(fHandlers);
580  TPluginHandler *h;
581 
582  while ((h = (TPluginHandler*) next())) {
583  if (h->CanHandle(base, uri)) {
584  if (gDebug > 0)
585  Info("FindHandler", "found plugin for %s", h->GetClass());
586  return h;
587  }
588  }
589 
590  if (gDebug > 2) {
591  if (uri)
592  Info("FindHandler", "did not find plugin for class %s and uri %s", base, uri);
593  else
594  Info("FindHandler", "did not find plugin for class %s", base);
595  }
596 
597  return 0;
598 }
599 
600 ////////////////////////////////////////////////////////////////////////////////
601 /// Print list of registered plugin handlers. If option is "a" print
602 /// also the ctor's that will be used.
603 
605 {
606  if (!fHandlers) return;
607 
608  TIter next(fHandlers);
609  TPluginHandler *h;
610  Int_t cnt = 0, cntmiss = 0;
611 
612  Printf("=====================================================================");
613  Printf("Base Regexp Class Plugin");
614  Printf("=====================================================================");
615 
616  while ((h = (TPluginHandler*) next())) {
617  cnt++;
618  h->Print(opt);
619  if (h->CheckPlugin() == -1)
620  cntmiss++;
621  }
622  Printf("=====================================================================");
623  Printf("%d plugin handlers registered", cnt);
624  Printf("[*] %d %s not available", cntmiss, cntmiss==1 ? "plugin" : "plugins");
625  Printf("=====================================================================\n");
626 }
627 
628 ////////////////////////////////////////////////////////////////////////////////
629 /// Write in the specified directory the plugin macros. If plugin is specified
630 /// and if it is a base class all macros for that base will be written. If it
631 /// is a plugin class name, only that one macro will be written. If plugin
632 /// is 0 all macros are written. Returns -1 if dir does not exist, 0 otherwise.
633 
634 Int_t TPluginManager::WritePluginMacros(const char *dir, const char *plugin) const
635 {
636  const_cast<TPluginManager*>(this)->LoadHandlersFromPluginDirs();
637 
638  if (!fHandlers) return 0;
639 
640  TString d;
641  if (!dir || !dir[0])
642  d = ".";
643  else
644  d = dir;
645 
647  Error("WritePluginMacros", "cannot write in directory %s", d.Data());
648  return -1;
649  }
650 
651  TString base;
652  Int_t idx = 0;
653 
654  TObjLink *lnk = fHandlers->FirstLink();
655  while (lnk) {
657  if (plugin && strcmp(plugin, h->fBase) && strcmp(plugin, h->fClass)) {
658  lnk = lnk->Next();
659  continue;
660  }
661  if (base != h->fBase) {
662  idx = 10;
663  base = h->fBase;
664  } else
665  idx += 10;
666  const char *dd = gSystem->ConcatFileName(d, h->fBase);
667  TString sdd = dd;
668  sdd.ReplaceAll("::", "@@");
669  delete [] dd;
671  if (gSystem->MakeDirectory(sdd) < 0) {
672  Error("WritePluginMacros", "cannot create directory %s", sdd.Data());
673  return -1;
674  }
675  }
676  TString fn;
677  fn.Form("P%03d_%s.C", idx, h->fClass.Data());
678  const char *fd = gSystem->ConcatFileName(sdd, fn);
679  FILE *f = fopen(fd, "w");
680  if (f) {
681  fprintf(f, "void P%03d_%s()\n{\n", idx, h->fClass.Data());
682  fprintf(f, " gPluginMgr->AddHandler(\"%s\", \"%s\", \"%s\",\n",
683  h->fBase.Data(), h->fRegexp.Data(), h->fClass.Data());
684  fprintf(f, " \"%s\", \"%s\");\n", h->fPlugin.Data(), h->fCtor.Data());
685 
686  // check for different regexps cases for the same base + class and
687  // put them all in the same macro
688  TObjLink *lnk2 = lnk->Next();
689  while (lnk2) {
690  TPluginHandler *h2 = (TPluginHandler *) lnk2->GetObject();
691  if (h->fBase != h2->fBase || h->fClass != h2->fClass)
692  break;
693 
694  fprintf(f, " gPluginMgr->AddHandler(\"%s\", \"%s\", \"%s\",\n",
695  h2->fBase.Data(), h2->fRegexp.Data(), h2->fClass.Data());
696  fprintf(f, " \"%s\", \"%s\");\n", h2->fPlugin.Data(), h2->fCtor.Data());
697 
698  lnk = lnk2;
699  lnk2 = lnk2->Next();
700  }
701  fprintf(f, "}\n");
702  fclose(f);
703  }
704  delete [] fd;
705  lnk = lnk->Next();
706  }
707  return 0;
708 }
709 
710 ////////////////////////////////////////////////////////////////////////////////
711 /// Write in the specified environment config file the plugin records. If
712 /// plugin is specified and if it is a base class all records for that
713 /// base will be written. If it is a plugin class name, only that one
714 /// record will be written. If plugin is 0 all macros are written.
715 /// If envFile is 0 or "" the records are written to stdout.
716 /// Returns -1 if envFile cannot be created or opened, 0 otherwise.
717 
718 Int_t TPluginManager::WritePluginRecords(const char *envFile, const char *plugin) const
719 {
720  const_cast<TPluginManager*>(this)->LoadHandlersFromPluginDirs();
721 
722  if (!fHandlers) return 0;
723 
724  FILE *fd;
725  if (!envFile || !envFile[0])
726  fd = stdout;
727  else
728  fd = fopen(envFile, "w+");
729 
730  if (!fd) {
731  Error("WritePluginRecords", "error opening file %s", envFile);
732  return -1;
733  }
734 
735  TString base, base2;
736  Int_t idx = 0;
737 
738  TObjLink *lnk = fHandlers->FirstLink();
739  while (lnk) {
741  if (plugin && strcmp(plugin, h->fBase) && strcmp(plugin, h->fClass)) {
742  lnk = lnk->Next();
743  continue;
744  }
745  if (base != h->fBase) {
746  idx = 1;
747  base = h->fBase;
748  base2 = base;
749  base2.ReplaceAll("::", "@@");
750  } else
751  idx += 1;
752 
753  if (idx == 1)
754  fprintf(fd, "Plugin.%s: %s %s %s \"%s\"\n", base2.Data(), h->fRegexp.Data(),
755  h->fClass.Data(), h->fPlugin.Data(), h->fCtor.Data());
756  else
757  fprintf(fd, "+Plugin.%s: %s %s %s \"%s\"\n", base2.Data(), h->fRegexp.Data(),
758  h->fClass.Data(), h->fPlugin.Data(), h->fCtor.Data());
759 
760  // check for different regexps cases for the same base + class and
761  // put them all in the same macro
762  TObjLink *lnk2 = lnk->Next();
763  while (lnk2) {
764  TPluginHandler *h2 = (TPluginHandler *) lnk2->GetObject();
765  if (h->fBase != h2->fBase || h->fClass != h2->fClass)
766  break;
767 
768  fprintf(fd, "+Plugin.%s: %s %s %s \"%s\"\n", base2.Data(), h2->fRegexp.Data(),
769  h2->fClass.Data(), h2->fPlugin.Data(), h2->fCtor.Data());
770 
771  lnk = lnk2;
772  lnk2 = lnk2->Next();
773  }
774  lnk = lnk->Next();
775  }
776 
777  if (envFile && envFile[0])
778  fclose(fd);
779 
780  return 0;
781 }
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:1265
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:4081
An array of TObjects.
Definition: TObjArray.h:39
void LoadHandlerMacros(const char *path)
Load all plugin macros from the specified path/base directory.
Bool_t MaybeRegexp() const
Returns true if string contains one of the regexp characters "^$.[]*+?".
Definition: TString.cxx:886
Collectable string class.
Definition: TObjString.h:32
const char Option_t
Definition: RtypesCore.h:62
R__EXTERN TVirtualMutex * gInterpreterMutex
Definition: TInterpreter.h:46
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition: TString.h:635
Int_t WritePluginRecords(const char *envFile, const char *plugin=0) const
Write in the specified environment config file the plugin records.
Int_t GetNargs() const
Number of function arguments.
Definition: TFunction.cxx:164
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 void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:899
virtual int MakeDirectory(const char *name)
Make a directory.
Definition: TSystem.cxx:822
void Print(Option_t *opt="") const
Print info about the plugin handler.
Regular expression class.
Definition: TRegexp.h:35
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:364
void LoadHandlersFromEnv(TEnv *env)
Load plugin handlers specified in config file, like: Plugin.TFile: ^rfio: TRFIOFile RFI...
Int_t LoadPlugin()
Load the plugin library for this handler.
The TEnv class reads config files, by default named .rootrc.
Definition: TEnv.h:128
Basic string class.
Definition: TString.h:137
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
const Bool_t kFALSE
Definition: Rtypes.h:92
#define gInterpreter
Definition: TInterpreter.h:515
Int_t GetEntriesFast() const
Definition: TObjArray.h:66
Bool_t BeginsWith(const char *s, ECaseCompare cmp=kExact) const
Definition: TString.h:558
const char * Data() const
Definition: TString.h:349
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:848
THashTable implements a hash table to store TObject&#39;s.
Definition: THashTable.h:39
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.
TMethodCall * fCallEnv
A sorted doubly linked list.
Definition: TSortedList.h:30
Bool_t CheckForExecPlugin(Int_t nargs)
Check that we can properly run ExecPlugin.
Method or function calling interface.
Definition: TMethodCall.h:41
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:925
A doubly linked list.
Definition: TList.h:47
Int_t GetNargsOpt() const
Number of function optional (default) arguments.
Definition: TFunction.cxx:174
Definition: TEnv.h:91
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.
Bool_t EndsWith(const char *pat, ECaseCompare cmp=kExact) const
Return true if string ends with the specified string.
Definition: TString.cxx:2221
R__EXTERN TSystem * gSystem
Definition: TSystem.h:549
SVector< double, 2 > v
Definition: Dict.h:5
virtual Int_t GetValue(const char *name, Int_t dflt)
Returns the integer value for a resource.
Definition: TEnv.cxx:496
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition: TString.cxx:2322
This class implements a plugin library manager.
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:81
Long_t Property() const
Get property description word. For meaning of bits see EProperty.
Definition: TFunction.cxx:183
Bool_t IsNull() const
Definition: TString.h:387
THashList * GetTable() const
Definition: TEnv.h:144
TString & String()
Definition: TObjString.h:52
virtual void FreeDirectory(void *dirp)
Free a directory.
Definition: TSystem.cxx:840
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
Definition: TString.cxx:2241
#define Printf
Definition: TGeoToOCC.h:18
char * StrDup(const char *str)
Duplicate the string str.
Definition: TString.cxx:2514
#define R__LOCKGUARD2(mutex)
AtomicInt_t fCanCall
ctor method or global function
long Long_t
Definition: RtypesCore.h:50
#define ClassImp(name)
Definition: Rtypes.h:279
double f(double x)
char * DynamicPathName(const char *lib, Bool_t quiet=kFALSE)
Find a dynamic library called lib using the system search paths.
Definition: TSystem.cxx:1958
R__EXTERN TEnv * gEnv
Definition: TEnv.h:174
Bool_t fIsMacro
if 1 fCallEnv is ok, -1 fCallEnv is not ok, 0 fCallEnv not setup yet.
static TVirtualMutex * gPluginManagerMutex
void Print(Option_t *opt="") const
Print list of registered plugin handlers.
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:2882
static TClass * LoadClass(const char *requestedname, Bool_t silent)
Helper function used by TClass::GetClass().
Definition: TClass.cxx:5389
Bool_t CanHandle(const char *base, const char *uri)
Check if regular expression appears in the URI, if so return kTRUE.
Int_t WritePluginMacros(const char *dir, const char *plugin=0) const
Write in the specified directory the plugin macros.
Int_t CheckPlugin() const
Check if the plugin library for this handler exits.
const Ssiz_t kNPOS
Definition: Rtypes.h:115
TPluginManager * gPluginMgr
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition: TString.h:567
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:831
const char * proto
Definition: civetweb.c:11652
R__EXTERN Int_t gDebug
Definition: Rtypes.h:128
void Add(TObject *obj)
Add object in sorted list.
Definition: TSortedList.cxx:27
TObject * At(Int_t idx) const
Definition: TObjArray.h:167
~TPluginHandler()
Cleanup plugin handler object.
const char * GetClass() const
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:582
TFunction * fMethod
ctor method call environment
const Bool_t kTRUE
Definition: Rtypes.h:91
virtual char * ConcatFileName(const char *dir, const char *name)
Concatenate a directory and a file name. User must delete returned string.
Definition: TSystem.cxx:1045
static char * skip(char **buf, const char *delimiters)
Definition: civetweb.c:2039
const char * cnt
Definition: TXMLSetup.cxx:75