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