Logo ROOT   6.08/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;
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  // 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  //The destructor of TObjArray takes the gROOTMutex lock so we want to
459  // delete the object after release the gInterpreterMutex lock
460  TObjArray *dirs = nullptr;
461  {
463  if (!fBasesLoaded) {
464  fBasesLoaded = new THashTable();
465  fBasesLoaded->SetOwner();
466  }
467  TString sbase = base;
468  if (sbase != "") {
469  sbase.ReplaceAll("::", "@@");
470  if (fBasesLoaded->FindObject(sbase))
471  return;
472  fBasesLoaded->Add(new TObjString(sbase));
473  }
474 
476 
477  TString plugindirs = gEnv->GetValue("Root.PluginPath", (char*)0);
478 #ifdef WIN32
479  dirs = plugindirs.Tokenize(";");
480 #else
481  dirs = plugindirs.Tokenize(":");
482 #endif
483  TString d;
484  for (Int_t i = 0; i < dirs->GetEntriesFast(); i++) {
485  d = ((TObjString*)dirs->At(i))->GetString();
486  // check if directory already scanned
487  Int_t skip = 0;
488  for (Int_t j = 0; j < i; j++) {
489  TString pd = ((TObjString*)dirs->At(j))->GetString();
490  if (pd == d) {
491  skip++;
492  break;
493  }
494  }
495  if (!skip) {
496  if (sbase != "") {
497  const char *p = gSystem->ConcatFileName(d, sbase);
498  LoadHandlerMacros(p);
499  delete [] p;
500  } else {
501  void *dirp = gSystem->OpenDirectory(d);
502  if (dirp) {
503  if (gDebug > 0)
504  Info("LoadHandlersFromPluginDirs", "%s", d.Data());
505  const char *f1;
506  while ((f1 = gSystem->GetDirEntry(dirp))) {
507  TString f = f1;
508  const char *p = gSystem->ConcatFileName(d, f);
509  LoadHandlerMacros(p);
510  fBasesLoaded->Add(new TObjString(f));
511  delete [] p;
512  }
513  }
514  gSystem->FreeDirectory(dirp);
515  }
516  }
517  }
519  }
520  delete dirs;
521 }
522 
523 ////////////////////////////////////////////////////////////////////////////////
524 /// Add plugin handler to the list of handlers. If there is already a
525 /// handler defined for the same base and regexp it will be replaced.
526 
527 void TPluginManager::AddHandler(const char *base, const char *regexp,
528  const char *className, const char *pluginName,
529  const char *ctor, const char *origin)
530 {
531  {
532  R__LOCKGUARD2(gPluginManagerMutex);
533  if (!fHandlers) {
534  fHandlers = new TList;
535  fHandlers->SetOwner();
536  }
537  }
538  // make sure there is no previous handler for the same case
539  RemoveHandler(base, regexp);
540 
541  if (TPH__IsReadingDirs())
542  origin = gInterpreter->GetCurrentMacroName();
543 
544  TPluginHandler *h = new TPluginHandler(base, regexp, className,
545  pluginName, ctor, origin);
546  {
547  R__LOCKGUARD2(gPluginManagerMutex);
548  fHandlers->Add(h);
549  }
550 }
551 
552 ////////////////////////////////////////////////////////////////////////////////
553 /// Remove handler for the specified base class and the specified
554 /// regexp. If regexp=0 remove all handlers for the specified base.
555 
556 void TPluginManager::RemoveHandler(const char *base, const char *regexp)
557 {
558  R__LOCKGUARD2(gPluginManagerMutex);
559  if (!fHandlers) return;
560 
561  TIter next(fHandlers);
562  TPluginHandler *h;
563 
564  while ((h = (TPluginHandler*) next())) {
565  if (h->fBase == base) {
566  if (!regexp || h->fRegexp == regexp) {
567  fHandlers->Remove(h);
568  delete h;
569  }
570  }
571  }
572 }
573 
574 ////////////////////////////////////////////////////////////////////////////////
575 /// Returns the handler if there exists a handler for the specified URI.
576 /// The uri can be 0 in which case the first matching plugin handler
577 /// will be returned. Returns 0 in case handler is not found.
578 
579 TPluginHandler *TPluginManager::FindHandler(const char *base, const char *uri)
580 {
581  LoadHandlersFromPluginDirs(base);
582 
583  R__LOCKGUARD2(gPluginManagerMutex);
584  TIter next(fHandlers);
585  TPluginHandler *h;
586 
587  while ((h = (TPluginHandler*) next())) {
588  if (h->CanHandle(base, uri)) {
589  if (gDebug > 0)
590  Info("FindHandler", "found plugin for %s", h->GetClass());
591  return h;
592  }
593  }
594 
595  if (gDebug > 2) {
596  if (uri)
597  Info("FindHandler", "did not find plugin for class %s and uri %s", base, uri);
598  else
599  Info("FindHandler", "did not find plugin for class %s", base);
600  }
601 
602  return 0;
603 }
604 
605 ////////////////////////////////////////////////////////////////////////////////
606 /// Print list of registered plugin handlers. If option is "a" print
607 /// also the ctor's that will be used.
608 
610 {
611  if (!fHandlers) return;
612 
613  TIter next(fHandlers);
614  TPluginHandler *h;
615  Int_t cnt = 0, cntmiss = 0;
616 
617  Printf("=====================================================================");
618  Printf("Base Regexp Class Plugin");
619  Printf("=====================================================================");
620 
621  while ((h = (TPluginHandler*) next())) {
622  cnt++;
623  h->Print(opt);
624  if (h->CheckPlugin() == -1)
625  cntmiss++;
626  }
627  Printf("=====================================================================");
628  Printf("%d plugin handlers registered", cnt);
629  Printf("[*] %d %s not available", cntmiss, cntmiss==1 ? "plugin" : "plugins");
630  Printf("=====================================================================\n");
631 }
632 
633 ////////////////////////////////////////////////////////////////////////////////
634 /// Write in the specified directory the plugin macros. If plugin is specified
635 /// and if it is a base class all macros for that base will be written. If it
636 /// is a plugin class name, only that one macro will be written. If plugin
637 /// is 0 all macros are written. Returns -1 if dir does not exist, 0 otherwise.
638 
639 Int_t TPluginManager::WritePluginMacros(const char *dir, const char *plugin) const
640 {
641  const_cast<TPluginManager*>(this)->LoadHandlersFromPluginDirs();
642 
643  if (!fHandlers) return 0;
644 
645  TString d;
646  if (!dir || !dir[0])
647  d = ".";
648  else
649  d = dir;
650 
652  Error("WritePluginMacros", "cannot write in directory %s", d.Data());
653  return -1;
654  }
655 
656  TString base;
657  Int_t idx = 0;
658 
659  TObjLink *lnk = fHandlers->FirstLink();
660  while (lnk) {
662  if (plugin && strcmp(plugin, h->fBase) && strcmp(plugin, h->fClass)) {
663  lnk = lnk->Next();
664  continue;
665  }
666  if (base != h->fBase) {
667  idx = 10;
668  base = h->fBase;
669  } else
670  idx += 10;
671  const char *dd = gSystem->ConcatFileName(d, h->fBase);
672  TString sdd = dd;
673  sdd.ReplaceAll("::", "@@");
674  delete [] dd;
676  if (gSystem->MakeDirectory(sdd) < 0) {
677  Error("WritePluginMacros", "cannot create directory %s", sdd.Data());
678  return -1;
679  }
680  }
681  TString fn;
682  fn.Form("P%03d_%s.C", idx, h->fClass.Data());
683  const char *fd = gSystem->ConcatFileName(sdd, fn);
684  FILE *f = fopen(fd, "w");
685  if (f) {
686  fprintf(f, "void P%03d_%s()\n{\n", idx, h->fClass.Data());
687  fprintf(f, " gPluginMgr->AddHandler(\"%s\", \"%s\", \"%s\",\n",
688  h->fBase.Data(), h->fRegexp.Data(), h->fClass.Data());
689  fprintf(f, " \"%s\", \"%s\");\n", h->fPlugin.Data(), h->fCtor.Data());
690 
691  // check for different regexps cases for the same base + class and
692  // put them all in the same macro
693  TObjLink *lnk2 = lnk->Next();
694  while (lnk2) {
695  TPluginHandler *h2 = (TPluginHandler *) lnk2->GetObject();
696  if (h->fBase != h2->fBase || h->fClass != h2->fClass)
697  break;
698 
699  fprintf(f, " gPluginMgr->AddHandler(\"%s\", \"%s\", \"%s\",\n",
700  h2->fBase.Data(), h2->fRegexp.Data(), h2->fClass.Data());
701  fprintf(f, " \"%s\", \"%s\");\n", h2->fPlugin.Data(), h2->fCtor.Data());
702 
703  lnk = lnk2;
704  lnk2 = lnk2->Next();
705  }
706  fprintf(f, "}\n");
707  fclose(f);
708  }
709  delete [] fd;
710  lnk = lnk->Next();
711  }
712  return 0;
713 }
714 
715 ////////////////////////////////////////////////////////////////////////////////
716 /// Write in the specified environment config file the plugin records. If
717 /// plugin is specified and if it is a base class all records for that
718 /// base will be written. If it is a plugin class name, only that one
719 /// record will be written. If plugin is 0 all macros are written.
720 /// If envFile is 0 or "" the records are written to stdout.
721 /// Returns -1 if envFile cannot be created or opened, 0 otherwise.
722 
723 Int_t TPluginManager::WritePluginRecords(const char *envFile, const char *plugin) const
724 {
725  const_cast<TPluginManager*>(this)->LoadHandlersFromPluginDirs();
726 
727  if (!fHandlers) return 0;
728 
729  FILE *fd;
730  if (!envFile || !envFile[0])
731  fd = stdout;
732  else
733  fd = fopen(envFile, "w+");
734 
735  if (!fd) {
736  Error("WritePluginRecords", "error opening file %s", envFile);
737  return -1;
738  }
739 
740  TString base, base2;
741  Int_t idx = 0;
742 
743  TObjLink *lnk = fHandlers->FirstLink();
744  while (lnk) {
746  if (plugin && strcmp(plugin, h->fBase) && strcmp(plugin, h->fClass)) {
747  lnk = lnk->Next();
748  continue;
749  }
750  if (base != h->fBase) {
751  idx = 1;
752  base = h->fBase;
753  base2 = base;
754  base2.ReplaceAll("::", "@@");
755  } else
756  idx += 1;
757 
758  if (idx == 1)
759  fprintf(fd, "Plugin.%s: %s %s %s \"%s\"\n", base2.Data(), h->fRegexp.Data(),
760  h->fClass.Data(), h->fPlugin.Data(), h->fCtor.Data());
761  else
762  fprintf(fd, "+Plugin.%s: %s %s %s \"%s\"\n", base2.Data(), h->fRegexp.Data(),
763  h->fClass.Data(), h->fPlugin.Data(), h->fCtor.Data());
764 
765  // check for different regexps cases for the same base + class and
766  // put them all in the same macro
767  TObjLink *lnk2 = lnk->Next();
768  while (lnk2) {
769  TPluginHandler *h2 = (TPluginHandler *) lnk2->GetObject();
770  if (h->fBase != h2->fBase || h->fClass != h2->fClass)
771  break;
772 
773  fprintf(fd, "+Plugin.%s: %s %s %s \"%s\"\n", base2.Data(), h2->fRegexp.Data(),
774  h2->fClass.Data(), h2->fPlugin.Data(), h2->fCtor.Data());
775 
776  lnk = lnk2;
777  lnk2 = lnk2->Next();
778  }
779  lnk = lnk->Next();
780  }
781 
782  if (envFile && envFile[0])
783  fclose(fd);
784 
785  return 0;
786 }
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:1266
Int_t CheckPlugin() const
Check if the plugin library for this handler exits.
An array of TObjects.
Definition: TObjArray.h:39
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:899
Collectable string class.
Definition: TObjString.h:32
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:4109
R__EXTERN TVirtualMutex * gInterpreterMutex
Definition: TInterpreter.h:46
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition: TString.h:635
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:822
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...
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:582
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:517
TObject * At(Int_t idx) const
Definition: TObjArray.h:167
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: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 EndsWith(const char *pat, ECaseCompare cmp=kExact) const
Return true if string ends with the specified string.
Definition: TString.cxx:2221
Long_t Property() const
Get property description word. For meaning of bits see EProperty.
Definition: TFunction.cxx:183
Bool_t CheckForExecPlugin(Int_t nargs)
Check that we can properly run ExecPlugin.
Method or function calling interface.
Definition: TMethodCall.h:41
A doubly linked list.
Definition: TList.h:47
void Print(Option_t *opt="") const
Print list of registered plugin handlers.
Definition: TEnv.h:91
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:549
SVector< double, 2 > v
Definition: Dict.h:5
THashList * GetTable() const
Definition: TEnv.h:144
virtual Int_t GetValue(const char *name, Int_t dflt)
Returns the integer value for a resource.
Definition: TEnv.cxx:496
Bool_t BeginsWith(const char *s, ECaseCompare cmp=kExact) const
Definition: TString.h:558
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition: TString.cxx:2322
Int_t GetEntriesFast() const
Definition: TObjArray.h:66
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:925
This class implements a plugin library manager.
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:81
TString & String()
Definition: TObjString.h:52
virtual void FreeDirectory(void *dirp)
Free a directory.
Definition: TSystem.cxx:840
#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
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:2241
#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:1959
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.
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition: TString.h:567
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:2893
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:5401
Bool_t IsNull() const
Definition: TString.h:387
Bool_t CanHandle(const char *base, const char *uri)
Check if regular expression appears in the URI, if so return kTRUE.
const Ssiz_t kNPOS
Definition: Rtypes.h:115
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: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
~TPluginHandler()
Cleanup plugin handler object.
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
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:886
const char * cnt
Definition: TXMLSetup.cxx:75
const char * Data() const
Definition: TString.h:349
const char * GetClass() const