00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084 #include "TPluginManager.h"
00085 #include "Varargs.h"
00086 #include "TEnv.h"
00087 #include "TRegexp.h"
00088 #include "TROOT.h"
00089 #include "TSortedList.h"
00090 #include "THashList.h"
00091 #include "THashTable.h"
00092 #include "Varargs.h"
00093 #include "TClass.h"
00094 #include "TInterpreter.h"
00095 #include "TMethod.h"
00096 #include "TMethodArg.h"
00097 #include "TDataType.h"
00098 #include "TMethodCall.h"
00099 #include "TVirtualMutex.h"
00100 #include "TSystem.h"
00101 #include "TObjString.h"
00102
00103
00104 TPluginManager *gPluginMgr;
00105
00106
00107 ClassImp(TPluginHandler)
00108
00109
00110 TPluginHandler::TPluginHandler(const char *base, const char *regexp,
00111 const char *className, const char *pluginName,
00112 const char *ctor, const char *origin):
00113 fBase(base),
00114 fRegexp(regexp),
00115 fClass(className),
00116 fPlugin(pluginName),
00117 fCtor(ctor),
00118 fOrigin(origin),
00119 fCallEnv(0),
00120 fMethod(0),
00121 fCanCall(0),
00122 fIsMacro(kFALSE),
00123 fIsGlobal(kFALSE)
00124 {
00125
00126
00127 if (fPlugin.EndsWith(".C") && gROOT->LoadMacro(fPlugin, 0, kTRUE) == 0)
00128 fIsMacro = kTRUE;
00129
00130 if (fCtor.Contains("::")) {
00131 fIsGlobal = kTRUE;
00132 fCtor = fCtor.Strip(TString::kLeading, ':');
00133 }
00134 }
00135
00136
00137 TPluginHandler::~TPluginHandler()
00138 {
00139
00140
00141 delete fCallEnv;
00142 }
00143
00144
00145 Bool_t TPluginHandler::CanHandle(const char *base, const char *uri)
00146 {
00147
00148
00149
00150 if (fBase != base)
00151 return kFALSE;
00152
00153 if (!uri || fRegexp == "*")
00154 return kTRUE;
00155
00156 Bool_t wildcard = kFALSE;
00157 if (!fRegexp.MaybeRegexp())
00158 wildcard = kTRUE;
00159
00160 TRegexp re(fRegexp, wildcard);
00161 TString ruri = uri;
00162
00163 if (ruri.Index(re) != kNPOS)
00164 return kTRUE;
00165 return kFALSE;
00166 }
00167
00168
00169 void TPluginHandler::SetupCallEnv()
00170 {
00171
00172
00173 fCanCall = -1;
00174
00175
00176 TClass *cl = TClass::GetClass(fClass);
00177 if (!cl && !fIsGlobal) {
00178 Error("SetupCallEnv", "class %s not found in plugin %s", fClass.Data(),
00179 fPlugin.Data());
00180 return;
00181 }
00182
00183
00184 TString method = fCtor(0, fCtor.Index("("));
00185 TString proto = fCtor(fCtor.Index("(")+1, fCtor.Index(")")-fCtor.Index("(")-1);
00186
00187 if (fIsGlobal) {
00188 cl = 0;
00189 fMethod = gROOT->GetGlobalFunctionWithPrototype(method, proto, kTRUE);
00190 } else {
00191 fMethod = cl->GetMethodWithPrototype(method, proto);
00192 }
00193
00194 if (!fMethod) {
00195 if (fIsGlobal)
00196 Error("SetupCallEnv", "global function %s not found", method.Data());
00197 else
00198 Error("SetupCallEnv", "method %s not found in class %s", method.Data(),
00199 fClass.Data());
00200 return;
00201 }
00202
00203 if (!fIsGlobal && !(fMethod->Property() & kIsPublic)) {
00204 Error("SetupCallEnv", "method %s is not public", method.Data());
00205 return;
00206 }
00207
00208 fCallEnv = new TMethodCall;
00209 fCallEnv->InitWithPrototype(cl, method, proto);
00210
00211 fCanCall = 1;
00212
00213 return;
00214 }
00215
00216
00217 Int_t TPluginHandler::CheckPlugin() const
00218 {
00219
00220
00221
00222 if (fIsMacro) {
00223 if (TClass::GetClass(fClass)) return 0;
00224 return gROOT->LoadMacro(fPlugin, 0, kTRUE);
00225 } else
00226 return gROOT->LoadClass(fClass, fPlugin, kTRUE);
00227 }
00228
00229
00230 Int_t TPluginHandler::LoadPlugin()
00231 {
00232
00233
00234
00235 if (fIsMacro) {
00236 if (TClass::GetClass(fClass)) return 0;
00237 return gROOT->LoadMacro(fPlugin);
00238 } else {
00239
00240 if (gROOT->LoadClass(fClass)) return 0;
00241 return gROOT->LoadClass(fClass, fPlugin);
00242 }
00243 }
00244
00245
00246 Long_t TPluginHandler::ExecPlugin(Int_t va_(nargs), ...)
00247 {
00248
00249
00250
00251
00252
00253
00254 if (fCtor.IsNull()) {
00255 Error("ExecPlugin", "no ctor specified for this handler %s", fClass.Data());
00256 return 0;
00257 }
00258
00259 if (!fCallEnv && !fCanCall)
00260 SetupCallEnv();
00261
00262 if (fCanCall == -1)
00263 return 0;
00264
00265 if (nargs < fMethod->GetNargs() - fMethod->GetNargsOpt() ||
00266 nargs > fMethod->GetNargs()) {
00267 Error("ExecPlugin", "nargs (%d) not consistent with expected number of arguments ([%d-%d])",
00268 nargs, fMethod->GetNargs() - fMethod->GetNargsOpt(),
00269 fMethod->GetNargs());
00270 return 0;
00271 }
00272
00273 R__LOCKGUARD2(gCINTMutex);
00274
00275 fCallEnv->ResetParam();
00276
00277 if (nargs > 0) {
00278 TIter next(fMethod->GetListOfMethodArgs());
00279 TMethodArg *arg;
00280
00281 va_list ap;
00282 va_start(ap, va_(nargs));
00283
00284 for (int i = 0; i < nargs; i++) {
00285 arg = (TMethodArg*) next();
00286 TString type = arg->GetFullTypeName();
00287 TDataType *dt = gROOT->GetType(type);
00288 if (dt)
00289 type = dt->GetFullTypeName();
00290 if (arg->Property() & (kIsPointer | kIsArray | kIsReference))
00291 fCallEnv->SetParam((Long_t) va_arg(ap, void*));
00292 else if (type == "bool")
00293 fCallEnv->SetParam((Long_t) va_arg(ap, int));
00294 else if (type == "char" || type == "unsigned char")
00295 fCallEnv->SetParam((Long_t) va_arg(ap, int));
00296 else if (type == "short" || type == "unsigned short")
00297 fCallEnv->SetParam((Long_t) va_arg(ap, int));
00298 else if (type == "int" || type == "unsigned int")
00299 fCallEnv->SetParam((Long_t) va_arg(ap, int));
00300 else if (type == "long" || type == "unsigned long")
00301 fCallEnv->SetParam((Long_t) va_arg(ap, long));
00302 else if (type == "long long")
00303 fCallEnv->SetParam((Long64_t) va_arg(ap, Long64_t));
00304 else if (type == "unsigned long long")
00305 fCallEnv->SetParam((ULong64_t) va_arg(ap, ULong64_t));
00306 else if (type == "float")
00307 fCallEnv->SetParam((Double_t) va_arg(ap, double));
00308 else if (type == "double")
00309 fCallEnv->SetParam((Double_t) va_arg(ap, double));
00310 }
00311
00312 va_end(ap);
00313 }
00314
00315 Long_t ret;
00316 fCallEnv->Execute(ret);
00317
00318 return ret;
00319 }
00320
00321
00322 void TPluginHandler::Print(Option_t *opt) const
00323 {
00324
00325
00326
00327 const char *exist = "";
00328 if (CheckPlugin() == -1)
00329 exist = " [*]";
00330
00331 Printf("%-20s %-13s %-18s %s%s", fBase.Data(), fRegexp.Data(),
00332 fClass.Data(), fPlugin.Data(), exist);
00333 if (strchr(opt, 'a')) {
00334 if (strlen(exist) == 0) {
00335 TString lib = fPlugin;
00336 if (!lib.BeginsWith("lib"))
00337 lib = "lib" + lib;
00338 char *path = gSystem->DynamicPathName(lib, kTRUE);
00339 if (path) Printf(" [Lib: %s]", path);
00340 delete [] path;
00341 }
00342 Printf(" [Ctor: %s]", fCtor.Data());
00343 Printf(" [origin: %s]", fOrigin.Data());
00344 }
00345 }
00346
00347
00348 ClassImp(TPluginManager)
00349
00350
00351 TPluginManager::~TPluginManager()
00352 {
00353
00354
00355 delete fHandlers;
00356 delete fBasesLoaded;
00357 }
00358
00359
00360 void TPluginManager::LoadHandlersFromEnv(TEnv *env)
00361 {
00362
00363
00364
00365
00366
00367
00368 if (!env) return;
00369
00370 TIter next(env->GetTable());
00371 TEnvRec *er;
00372
00373 while ((er = (TEnvRec*) next())) {
00374 const char *s;
00375 if ((s = strstr(er->GetName(), "Plugin."))) {
00376
00377
00378
00379 const char *val = env->GetValue(s, (const char*)0);
00380 if (val) {
00381 Int_t cnt = 0;
00382 char *v = StrDup(val);
00383 s += 7;
00384 while (1) {
00385 TString regexp = strtok(!cnt ? v : 0, "; ");
00386 if (regexp.IsNull()) break;
00387 TString clss = strtok(0, "; ");
00388 if (clss.IsNull()) break;
00389 TString plugin = strtok(0, "; ");
00390 if (plugin.IsNull()) break;
00391 TString ctor = strtok(0, ";\"");
00392 if (!ctor.Contains("("))
00393 ctor = strtok(0, ";\"");
00394 AddHandler(s, regexp, clss, plugin, ctor, "TEnv");
00395 cnt++;
00396 }
00397 delete [] v;
00398 }
00399 }
00400 }
00401 }
00402
00403
00404 void TPluginManager::LoadHandlerMacros(const char *path)
00405 {
00406
00407
00408 void *dirp = gSystem->OpenDirectory(path);
00409 if (dirp) {
00410 if (gDebug > 0)
00411 Info("LoadHandlerMacros", "%s", path);
00412 TSortedList macros;
00413 macros.SetOwner();
00414 const char *f1;
00415 while ((f1 = gSystem->GetDirEntry(dirp))) {
00416 TString f = f1;
00417 if (f[0] == 'P' && f.EndsWith(".C")) {
00418 const char *p = gSystem->ConcatFileName(path, f);
00419 if (!gSystem->AccessPathName(p, kReadPermission)) {
00420 macros.Add(new TObjString(p));
00421 }
00422 delete [] p;
00423 }
00424 }
00425
00426 TIter next(¯os);
00427 TObjString *s;
00428 while ((s = (TObjString*)next())) {
00429 if (gDebug > 1)
00430 Info("LoadHandlerMacros", " plugin macro: %s", s->String().Data());
00431 Long_t res;
00432 if ((res = gROOT->Macro(s->String(), 0, kFALSE)) < 0) {
00433 Error("LoadHandlerMacros", "pluging macro %s returned %ld",
00434 s->String().Data(), res);
00435 }
00436 }
00437 }
00438 gSystem->FreeDirectory(dirp);
00439 }
00440
00441
00442 void TPluginManager::LoadHandlersFromPluginDirs(const char *base)
00443 {
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466 if (!fBasesLoaded) {
00467 fBasesLoaded = new THashTable();
00468 fBasesLoaded->SetOwner();
00469 }
00470 TString sbase = base;
00471 if (sbase != "") {
00472 sbase.ReplaceAll("::", "@@");
00473 if (fBasesLoaded->FindObject(sbase))
00474 return;
00475 fBasesLoaded->Add(new TObjString(sbase));
00476 }
00477
00478 fReadingDirs = kTRUE;
00479
00480 TString plugindirs = gEnv->GetValue("Root.PluginPath", (char*)0);
00481 #ifdef WIN32
00482 TObjArray *dirs = plugindirs.Tokenize(";");
00483 #else
00484 TObjArray *dirs = plugindirs.Tokenize(":");
00485 #endif
00486 TString d;
00487 for (Int_t i = 0; i < dirs->GetEntriesFast(); i++) {
00488 d = ((TObjString*)dirs->At(i))->GetString();
00489
00490 Int_t skip = 0;
00491 for (Int_t j = 0; j < i; j++) {
00492 TString pd = ((TObjString*)dirs->At(j))->GetString();
00493 if (pd == d) {
00494 skip++;
00495 break;
00496 }
00497 }
00498 if (!skip) {
00499 if (sbase != "") {
00500 const char *p = gSystem->ConcatFileName(d, sbase);
00501 LoadHandlerMacros(p);
00502 delete [] p;
00503 } else {
00504 void *dirp = gSystem->OpenDirectory(d);
00505 if (dirp) {
00506 if (gDebug > 0)
00507 Info("LoadHandlersFromPluginDirs", "%s", d.Data());
00508 const char *f1;
00509 while ((f1 = gSystem->GetDirEntry(dirp))) {
00510 TString f = f1;
00511 const char *p = gSystem->ConcatFileName(d, f);
00512 LoadHandlerMacros(p);
00513 fBasesLoaded->Add(new TObjString(f));
00514 delete [] p;
00515 }
00516 }
00517 gSystem->FreeDirectory(dirp);
00518 }
00519 }
00520 }
00521
00522 delete dirs;
00523 fReadingDirs = kFALSE;
00524 }
00525
00526
00527 void TPluginManager::AddHandler(const char *base, const char *regexp,
00528 const char *className, const char *pluginName,
00529 const char *ctor, const char *origin)
00530 {
00531
00532
00533
00534 if (!fHandlers) {
00535 fHandlers = new TList;
00536 fHandlers->SetOwner();
00537 }
00538
00539
00540 RemoveHandler(base, regexp);
00541
00542 if (fReadingDirs)
00543 origin = gInterpreter->GetCurrentMacroName();
00544
00545 TPluginHandler *h = new TPluginHandler(base, regexp, className,
00546 pluginName, ctor, origin);
00547 fHandlers->Add(h);
00548 }
00549
00550
00551 void TPluginManager::RemoveHandler(const char *base, const char *regexp)
00552 {
00553
00554
00555
00556 if (!fHandlers) return;
00557
00558 TIter next(fHandlers);
00559 TPluginHandler *h;
00560
00561 while ((h = (TPluginHandler*) next())) {
00562 if (h->fBase == base) {
00563 if (!regexp || h->fRegexp == regexp) {
00564 fHandlers->Remove(h);
00565 delete h;
00566 }
00567 }
00568 }
00569 }
00570
00571
00572 TPluginHandler *TPluginManager::FindHandler(const char *base, const char *uri)
00573 {
00574
00575
00576
00577
00578 LoadHandlersFromPluginDirs(base);
00579
00580 TIter next(fHandlers);
00581 TPluginHandler *h;
00582
00583 while ((h = (TPluginHandler*) next())) {
00584 if (h->CanHandle(base, uri)) {
00585 if (gDebug > 0)
00586 Info("FindHandler", "found plugin for %s", h->GetClass());
00587 return h;
00588 }
00589 }
00590
00591 if (gDebug > 2) {
00592 if (uri)
00593 Info("FindHandler", "did not find plugin for class %s and uri %s", base, uri);
00594 else
00595 Info("FindHandler", "did not find plugin for class %s", base);
00596 }
00597
00598 return 0;
00599 }
00600
00601
00602 void TPluginManager::Print(Option_t *opt) const
00603 {
00604
00605
00606
00607 if (!fHandlers) return;
00608
00609 TIter next(fHandlers);
00610 TPluginHandler *h;
00611 Int_t cnt = 0, cntmiss = 0;
00612
00613 Printf("=====================================================================");
00614 Printf("Base Regexp Class Plugin");
00615 Printf("=====================================================================");
00616
00617 while ((h = (TPluginHandler*) next())) {
00618 cnt++;
00619 h->Print(opt);
00620 if (h->CheckPlugin() == -1)
00621 cntmiss++;
00622 }
00623 Printf("=====================================================================");
00624 Printf("%d plugin handlers registered", cnt);
00625 Printf("[*] %d %s not available", cntmiss, cntmiss==1 ? "plugin" : "plugins");
00626 Printf("=====================================================================\n");
00627 }
00628
00629
00630 Int_t TPluginManager::WritePluginMacros(const char *dir, const char *plugin) const
00631 {
00632
00633
00634
00635
00636
00637 const_cast<TPluginManager*>(this)->LoadHandlersFromPluginDirs();
00638
00639 if (!fHandlers) return 0;
00640
00641 TString d;
00642 if (!dir || !dir[0])
00643 d = ".";
00644 else
00645 d = dir;
00646
00647 if (gSystem->AccessPathName(d, kWritePermission)) {
00648 Error("WritePluginMacros", "cannot write in directory %s", d.Data());
00649 return -1;
00650 }
00651
00652 TString base;
00653 Int_t idx = 0;
00654
00655 TObjLink *lnk = fHandlers->FirstLink();
00656 while (lnk) {
00657 TPluginHandler *h = (TPluginHandler *) lnk->GetObject();
00658 if (plugin && strcmp(plugin, h->fBase) && strcmp(plugin, h->fClass)) {
00659 lnk = lnk->Next();
00660 continue;
00661 }
00662 if (base != h->fBase) {
00663 idx = 10;
00664 base = h->fBase;
00665 } else
00666 idx += 10;
00667 const char *dd = gSystem->ConcatFileName(d, h->fBase);
00668 TString sdd = dd;
00669 sdd.ReplaceAll("::", "@@");
00670 delete [] dd;
00671 if (gSystem->AccessPathName(sdd, kWritePermission)) {
00672 if (gSystem->MakeDirectory(sdd) < 0) {
00673 Error("WritePluginMacros", "cannot create directory %s", sdd.Data());
00674 return -1;
00675 }
00676 }
00677 TString fn;
00678 fn.Form("P%03d_%s.C", idx, h->fClass.Data());
00679 const char *fd = gSystem->ConcatFileName(sdd, fn);
00680 FILE *f = fopen(fd, "w");
00681 fprintf(f, "void P%03d_%s()\n{\n", idx, h->fClass.Data());
00682 fprintf(f, " gPluginMgr->AddHandler(\"%s\", \"%s\", \"%s\",\n",
00683 h->fBase.Data(), h->fRegexp.Data(), h->fClass.Data());
00684 fprintf(f, " \"%s\", \"%s\");\n", h->fPlugin.Data(), h->fCtor.Data());
00685
00686
00687
00688 TObjLink *lnk2 = lnk->Next();
00689 while (lnk2) {
00690 TPluginHandler *h2 = (TPluginHandler *) lnk2->GetObject();
00691 if (h->fBase != h2->fBase || h->fClass != h2->fClass)
00692 break;
00693
00694 fprintf(f, " gPluginMgr->AddHandler(\"%s\", \"%s\", \"%s\",\n",
00695 h2->fBase.Data(), h2->fRegexp.Data(), h2->fClass.Data());
00696 fprintf(f, " \"%s\", \"%s\");\n", h2->fPlugin.Data(), h2->fCtor.Data());
00697
00698 lnk = lnk2;
00699 lnk2 = lnk2->Next();
00700 }
00701 fprintf(f, "}\n");
00702 fclose(f);
00703 delete [] fd;
00704 lnk = lnk->Next();
00705 }
00706 return 0;
00707 }
00708
00709
00710 Int_t TPluginManager::WritePluginRecords(const char *envFile, const char *plugin) const
00711 {
00712
00713
00714
00715
00716
00717
00718
00719 const_cast<TPluginManager*>(this)->LoadHandlersFromPluginDirs();
00720
00721 if (!fHandlers) return 0;
00722
00723 FILE *fd;
00724 if (!envFile || !envFile[0])
00725 fd = stdout;
00726 else
00727 fd = fopen(envFile, "w+");
00728
00729 if (!fd) {
00730 Error("WritePluginRecords", "error opening file %s", envFile);
00731 return -1;
00732 }
00733
00734 TString base, base2;
00735 Int_t idx = 0;
00736
00737 TObjLink *lnk = fHandlers->FirstLink();
00738 while (lnk) {
00739 TPluginHandler *h = (TPluginHandler *) lnk->GetObject();
00740 if (plugin && strcmp(plugin, h->fBase) && strcmp(plugin, h->fClass)) {
00741 lnk = lnk->Next();
00742 continue;
00743 }
00744 if (base != h->fBase) {
00745 idx = 1;
00746 base = h->fBase;
00747 base2 = base;
00748 base2.ReplaceAll("::", "@@");
00749 } else
00750 idx += 1;
00751
00752 if (idx == 1)
00753 fprintf(fd, "Plugin.%s: %s %s %s \"%s\"\n", base2.Data(), h->fRegexp.Data(),
00754 h->fClass.Data(), h->fPlugin.Data(), h->fCtor.Data());
00755 else
00756 fprintf(fd, "+Plugin.%s: %s %s %s \"%s\"\n", base2.Data(), h->fRegexp.Data(),
00757 h->fClass.Data(), h->fPlugin.Data(), h->fCtor.Data());
00758
00759
00760
00761 TObjLink *lnk2 = lnk->Next();
00762 while (lnk2) {
00763 TPluginHandler *h2 = (TPluginHandler *) lnk2->GetObject();
00764 if (h->fBase != h2->fBase || h->fClass != h2->fClass)
00765 break;
00766
00767 fprintf(fd, "+Plugin.%s: %s %s %s \"%s\"\n", base2.Data(), h2->fRegexp.Data(),
00768 h2->fClass.Data(), h2->fPlugin.Data(), h2->fCtor.Data());
00769
00770 lnk = lnk2;
00771 lnk2 = lnk2->Next();
00772 }
00773 lnk = lnk->Next();
00774 }
00775
00776 if (envFile && envFile[0])
00777 fclose(fd);
00778
00779 return 0;
00780 }