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