ROOT  6.06/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 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 
330 
331 ////////////////////////////////////////////////////////////////////////////////
332 /// Clean up the plugin manager.
333 
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();
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 #ifdef WIN32
472  dirs = plugindirs.Tokenize(";");
473 #else
474  dirs = plugindirs.Tokenize(":");
475 #endif
476  TString d;
477  for (Int_t i = 0; i < dirs->GetEntriesFast(); i++) {
478  d = ((TObjString*)dirs->At(i))->GetString();
479  // check if directory already scanned
480  Int_t skip = 0;
481  for (Int_t j = 0; j < i; j++) {
482  TString pd = ((TObjString*)dirs->At(j))->GetString();
483  if (pd == d) {
484  skip++;
485  break;
486  }
487  }
488  if (!skip) {
489  if (sbase != "") {
490  const char *p = gSystem->ConcatFileName(d, sbase);
492  delete [] p;
493  } else {
494  void *dirp = gSystem->OpenDirectory(d);
495  if (dirp) {
496  if (gDebug > 0)
497  Info("LoadHandlersFromPluginDirs", "%s", d.Data());
498  const char *f1;
499  while ((f1 = gSystem->GetDirEntry(dirp))) {
500  TString f = f1;
501  const char *p = gSystem->ConcatFileName(d, f);
503  fBasesLoaded->Add(new TObjString(f));
504  delete [] p;
505  }
506  }
507  gSystem->FreeDirectory(dirp);
508  }
509  }
510  }
512  }
513  delete dirs;
514 }
515 
516 ////////////////////////////////////////////////////////////////////////////////
517 /// Add plugin handler to the list of handlers. If there is already a
518 /// handler defined for the same base and regexp it will be replaced.
519 
520 void TPluginManager::AddHandler(const char *base, const char *regexp,
521  const char *className, const char *pluginName,
522  const char *ctor, const char *origin)
523 {
524  {
525  R__LOCKGUARD2(gPluginManagerMutex);
526  if (!fHandlers) {
527  fHandlers = new TList;
528  fHandlers->SetOwner();
529  }
530  }
531  // make sure there is no previous handler for the same case
532  RemoveHandler(base, regexp);
533 
534  if (TPH__IsReadingDirs())
535  origin = gInterpreter->GetCurrentMacroName();
536 
537  TPluginHandler *h = new TPluginHandler(base, regexp, className,
538  pluginName, ctor, origin);
539  {
540  R__LOCKGUARD2(gPluginManagerMutex);
541  fHandlers->Add(h);
542  }
543 }
544 
545 ////////////////////////////////////////////////////////////////////////////////
546 /// Remove handler for the specified base class and the specified
547 /// regexp. If regexp=0 remove all handlers for the specified base.
548 
549 void TPluginManager::RemoveHandler(const char *base, const char *regexp)
550 {
551  R__LOCKGUARD2(gPluginManagerMutex);
552  if (!fHandlers) return;
553 
555  TPluginHandler *h;
556 
557  while ((h = (TPluginHandler*) next())) {
558  if (h->fBase == base) {
559  if (!regexp || h->fRegexp == regexp) {
560  fHandlers->Remove(h);
561  delete h;
562  }
563  }
564  }
565 }
566 
567 ////////////////////////////////////////////////////////////////////////////////
568 /// Returns the handler if there exists a handler for the specified URI.
569 /// The uri can be 0 in which case the first matching plugin handler
570 /// will be returned. Returns 0 in case handler is not found.
571 
572 TPluginHandler *TPluginManager::FindHandler(const char *base, const char *uri)
573 {
575 
576  R__LOCKGUARD2(gPluginManagerMutex);
578  TPluginHandler *h;
579 
580  while ((h = (TPluginHandler*) next())) {
581  if (h->CanHandle(base, uri)) {
582  if (gDebug > 0)
583  Info("FindHandler", "found plugin for %s", h->GetClass());
584  return h;
585  }
586  }
587 
588  if (gDebug > 2) {
589  if (uri)
590  Info("FindHandler", "did not find plugin for class %s and uri %s", base, uri);
591  else
592  Info("FindHandler", "did not find plugin for class %s", base);
593  }
594 
595  return 0;
596 }
597 
598 ////////////////////////////////////////////////////////////////////////////////
599 /// Print list of registered plugin handlers. If option is "a" print
600 /// also the ctor's that will be used.
601 
603 {
604  if (!fHandlers) return;
605 
607  TPluginHandler *h;
608  Int_t cnt = 0, cntmiss = 0;
609 
610  Printf("=====================================================================");
611  Printf("Base Regexp Class Plugin");
612  Printf("=====================================================================");
613 
614  while ((h = (TPluginHandler*) next())) {
615  cnt++;
616  h->Print(opt);
617  if (h->CheckPlugin() == -1)
618  cntmiss++;
619  }
620  Printf("=====================================================================");
621  Printf("%d plugin handlers registered", cnt);
622  Printf("[*] %d %s not available", cntmiss, cntmiss==1 ? "plugin" : "plugins");
623  Printf("=====================================================================\n");
624 }
625 
626 ////////////////////////////////////////////////////////////////////////////////
627 /// Write in the specified directory the plugin macros. If plugin is specified
628 /// and if it is a base class all macros for that base will be written. If it
629 /// is a plugin class name, only that one macro will be written. If plugin
630 /// is 0 all macros are written. Returns -1 if dir does not exist, 0 otherwise.
631 
632 Int_t TPluginManager::WritePluginMacros(const char *dir, const char *plugin) const
633 {
634  const_cast<TPluginManager*>(this)->LoadHandlersFromPluginDirs();
635 
636  if (!fHandlers) return 0;
637 
638  TString d;
639  if (!dir || !dir[0])
640  d = ".";
641  else
642  d = dir;
643 
645  Error("WritePluginMacros", "cannot write in directory %s", d.Data());
646  return -1;
647  }
648 
649  TString base;
650  Int_t idx = 0;
651 
652  TObjLink *lnk = fHandlers->FirstLink();
653  while (lnk) {
655  if (plugin && strcmp(plugin, h->fBase) && strcmp(plugin, h->fClass)) {
656  lnk = lnk->Next();
657  continue;
658  }
659  if (base != h->fBase) {
660  idx = 10;
661  base = h->fBase;
662  } else
663  idx += 10;
664  const char *dd = gSystem->ConcatFileName(d, h->fBase);
665  TString sdd = dd;
666  sdd.ReplaceAll("::", "@@");
667  delete [] dd;
669  if (gSystem->MakeDirectory(sdd) < 0) {
670  Error("WritePluginMacros", "cannot create directory %s", sdd.Data());
671  return -1;
672  }
673  }
674  TString fn;
675  fn.Form("P%03d_%s.C", idx, h->fClass.Data());
676  const char *fd = gSystem->ConcatFileName(sdd, fn);
677  FILE *f = fopen(fd, "w");
678  if (f) {
679  fprintf(f, "void P%03d_%s()\n{\n", idx, h->fClass.Data());
680  fprintf(f, " gPluginMgr->AddHandler(\"%s\", \"%s\", \"%s\",\n",
681  h->fBase.Data(), h->fRegexp.Data(), h->fClass.Data());
682  fprintf(f, " \"%s\", \"%s\");\n", h->fPlugin.Data(), h->fCtor.Data());
683 
684  // check for different regexps cases for the same base + class and
685  // put them all in the same macro
686  TObjLink *lnk2 = lnk->Next();
687  while (lnk2) {
688  TPluginHandler *h2 = (TPluginHandler *) lnk2->GetObject();
689  if (h->fBase != h2->fBase || h->fClass != h2->fClass)
690  break;
691 
692  fprintf(f, " gPluginMgr->AddHandler(\"%s\", \"%s\", \"%s\",\n",
693  h2->fBase.Data(), h2->fRegexp.Data(), h2->fClass.Data());
694  fprintf(f, " \"%s\", \"%s\");\n", h2->fPlugin.Data(), h2->fCtor.Data());
695 
696  lnk = lnk2;
697  lnk2 = lnk2->Next();
698  }
699  fprintf(f, "}\n");
700  fclose(f);
701  }
702  delete [] fd;
703  lnk = lnk->Next();
704  }
705  return 0;
706 }
707 
708 ////////////////////////////////////////////////////////////////////////////////
709 /// Write in the specified environment config file the plugin records. If
710 /// plugin is specified and if it is a base class all records for that
711 /// base will be written. If it is a plugin class name, only that one
712 /// record will be written. If plugin is 0 all macros are written.
713 /// If envFile is 0 or "" the records are written to stdout.
714 /// Returns -1 if envFile cannot be created or opened, 0 otherwise.
715 
716 Int_t TPluginManager::WritePluginRecords(const char *envFile, const char *plugin) const
717 {
718  const_cast<TPluginManager*>(this)->LoadHandlersFromPluginDirs();
719 
720  if (!fHandlers) return 0;
721 
722  FILE *fd;
723  if (!envFile || !envFile[0])
724  fd = stdout;
725  else
726  fd = fopen(envFile, "w+");
727 
728  if (!fd) {
729  Error("WritePluginRecords", "error opening file %s", envFile);
730  return -1;
731  }
732 
733  TString base, base2;
734  Int_t idx = 0;
735 
736  TObjLink *lnk = fHandlers->FirstLink();
737  while (lnk) {
739  if (plugin && strcmp(plugin, h->fBase) && strcmp(plugin, h->fClass)) {
740  lnk = lnk->Next();
741  continue;
742  }
743  if (base != h->fBase) {
744  idx = 1;
745  base = h->fBase;
746  base2 = base;
747  base2.ReplaceAll("::", "@@");
748  } else
749  idx += 1;
750 
751  if (idx == 1)
752  fprintf(fd, "Plugin.%s: %s %s %s \"%s\"\n", base2.Data(), h->fRegexp.Data(),
753  h->fClass.Data(), h->fPlugin.Data(), h->fCtor.Data());
754  else
755  fprintf(fd, "+Plugin.%s: %s %s %s \"%s\"\n", base2.Data(), h->fRegexp.Data(),
756  h->fClass.Data(), h->fPlugin.Data(), h->fCtor.Data());
757 
758  // check for different regexps cases for the same base + class and
759  // put them all in the same macro
760  TObjLink *lnk2 = lnk->Next();
761  while (lnk2) {
762  TPluginHandler *h2 = (TPluginHandler *) lnk2->GetObject();
763  if (h->fBase != h2->fBase || h->fClass != h2->fClass)
764  break;
765 
766  fprintf(fd, "+Plugin.%s: %s %s %s \"%s\"\n", base2.Data(), h2->fRegexp.Data(),
767  h2->fClass.Data(), h2->fPlugin.Data(), h2->fCtor.Data());
768 
769  lnk = lnk2;
770  lnk2 = lnk2->Next();
771  }
772  lnk = lnk->Next();
773  }
774 
775  if (envFile && envFile[0])
776  fclose(fd);
777 
778  return 0;
779 }
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:4071
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:885
ClassImp(TSeqCollection) Int_t TSeqCollection TIter next(this)
Return index of object in collection.
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.
THashTable * fBasesLoaded
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:892
virtual int MakeDirectory(const char *name)
Make a directory.
Definition: TSystem.cxx:821
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:340
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:502
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:847
THashTable implements a hash table to store TObject's.
Definition: THashTable.h:39
UChar_t mod R__LOCKGUARD2(gSrvAuthenticateMutex)
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
TClass * fClass
pointer to the foreign object
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:918
ClassImp(TPluginHandler) TPluginHandler
Create a plugin handler. Called by TPluginManager.
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:2220
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:494
virtual TObject * Remove(TObject *obj)
Remove object from the list.
Definition: TList.cxx:674
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition: TString.cxx:2321
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
virtual TObjLink * FirstLink() const
Definition: TList.h:101
THashList * GetTable() const
Definition: TEnv.h:144
TString & String()
Definition: TObjString.h:52
virtual void FreeDirectory(void *dirp)
Free a directory.
Definition: TSystem.cxx:839
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
Definition: TString.cxx:2240
#define Printf
Definition: TGeoToOCC.h:18
char * StrDup(const char *str)
Duplicate the string str.
Definition: TString.cxx:2513
AtomicInt_t fCanCall
ctor method or global function
long Long_t
Definition: RtypesCore.h:50
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.
void Add(TObject *obj)
Add object to the hash table.
Definition: THashTable.cxx:75
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:2881
static TClass * LoadClass(const char *requestedname, Bool_t silent)
Helper function used by TClass::GetClass().
Definition: TClass.cxx:5370
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.
virtual void Add(TObject *obj)
Definition: TList.h:81
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
TObject * FindObject(const char *name) const
Find object using its name.
Definition: THashTable.cxx:209
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)
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:1044
static char * skip(char **buf, const char *delimiters)
Definition: civetweb.c:1014
const char * cnt
Definition: TXMLSetup.cxx:75