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