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
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124 #include <stdio.h>
00125 #include <assert.h>
00126
00127 #include "RConfigure.h"
00128 #include "TTabCom.h"
00129 #include "TClass.h"
00130 #include "TSystem.h"
00131 #include "TROOT.h"
00132 #include "TMethod.h"
00133 #include "TEnv.h"
00134 #include "TBenchmark.h"
00135 #include "TError.h"
00136 #include "TGlobal.h"
00137 #include "TList.h"
00138 #include "Getline.h"
00139 #include "TFunction.h"
00140 #include "TMethodArg.h"
00141 #include "TInterpreter.h"
00142 #include "Riostream.h"
00143 #include "Rstrstream.h"
00144
00145 #define BUF_SIZE 1024 // must match value in C_Getline.c (for bounds checking)
00146 #define IfDebug(x) if(gDebug==TTabCom::kDebug) x
00147
00148 #ifdef R__WIN32
00149 #undef tmpnam
00150 #define tmpnam(a) _tempnam(a, 0)
00151 const char kDelim = ';';
00152 #else
00153 const char kDelim = ':';
00154 #endif
00155
00156
00157 ClassImp(TTabCom)
00158
00159
00160
00161
00162 TTabCom *gTabCom = 0;
00163
00164
00165 extern "C" int gl_root_tab_hook(char *buf, int ,
00166 int *pLoc)
00167 {
00168 return gTabCom ? gTabCom->Hook(buf, pLoc) : -1;
00169 }
00170
00171
00172
00173
00174
00175
00176
00177
00178 TTabCom::TTabCom()
00179 {
00180
00181 fpDirectives = 0;
00182 fpPragmas = 0;
00183 fpGlobals = 0;
00184 fpGlobalFuncs = 0;
00185 fpClasses = 0;
00186 fpNamespaces = 0;
00187 fpUsers = 0;
00188 fBuf = 0;
00189 fpLoc = 0;
00190 fpEnvVars = 0;
00191 fpFiles = 0;
00192 fpSysIncFiles = 0;
00193 fVarIsPointer = kFALSE;
00194 fLastIter = 0;
00195
00196 InitPatterns();
00197
00198 Gl_tab_hook = gl_root_tab_hook;
00199 }
00200
00201
00202
00203
00204
00205
00206 TTabCom::~TTabCom()
00207 {
00208
00209
00210 ClearAll();
00211 ClearSysIncFiles();
00212 ClearUsers();
00213 }
00214
00215
00216
00217
00218
00219
00220
00221
00222 void TTabCom::ClearClasses()
00223 {
00224
00225
00226 if (fpClasses) {
00227 fpClasses->Delete(0);
00228 delete fpClasses;
00229 fpClasses = 0;
00230 }
00231
00232
00233
00234 if (fpNamespaces) {
00235 fpNamespaces->Delete(0);
00236 delete fpNamespaces;
00237 fpNamespaces = 0;
00238 }
00239 }
00240
00241
00242 void TTabCom::ClearCppDirectives()
00243 {
00244
00245
00246 if (!fpDirectives)
00247 return;
00248 fpDirectives->Delete(0);
00249 delete fpDirectives;
00250 fpDirectives = 0;
00251 }
00252
00253
00254 void TTabCom::ClearEnvVars()
00255 {
00256
00257 if (!fpEnvVars)
00258 return;
00259 fpEnvVars->Delete(0);
00260 delete fpEnvVars;
00261 fpEnvVars = 0;
00262 }
00263
00264
00265 void TTabCom::ClearFiles()
00266 {
00267
00268 if (!fpFiles)
00269 return;
00270 fpFiles->Delete(0);
00271 delete fpFiles;
00272 fpFiles = 0;
00273 }
00274
00275
00276 void TTabCom::ClearGlobalFunctions()
00277 {
00278
00279 if (!fpGlobalFuncs)
00280 return;
00281 fpGlobalFuncs->Delete(0);
00282 delete fpGlobalFuncs;
00283 fpGlobalFuncs = 0;
00284 }
00285
00286
00287 void TTabCom::ClearGlobals()
00288 {
00289
00290 if (!fpGlobals)
00291 return;
00292 fpGlobals->Delete(0);
00293 delete fpGlobals;
00294 fpGlobals = 0;
00295 }
00296
00297
00298 void TTabCom::ClearPragmas()
00299 {
00300
00301 if (!fpPragmas)
00302 return;
00303 fpPragmas->Delete(0);
00304 delete fpPragmas;
00305 fpPragmas = 0;
00306 }
00307
00308
00309 void TTabCom::ClearSysIncFiles()
00310 {
00311
00312 if (!fpSysIncFiles)
00313 return;
00314 fpSysIncFiles->Delete(0);
00315 delete fpSysIncFiles;
00316 fpSysIncFiles = 0;
00317 }
00318
00319
00320 void TTabCom::ClearUsers()
00321 {
00322
00323 if (!fpUsers)
00324 return;
00325 fpUsers->Delete(0);
00326 delete fpUsers;
00327 fpUsers = 0;
00328 }
00329
00330
00331 void TTabCom::ClearAll()
00332 {
00333
00334
00335
00336 ClearClasses();
00337 ClearCppDirectives();
00338 ClearEnvVars();
00339 ClearFiles();
00340 ClearGlobalFunctions();
00341 ClearGlobals();
00342 ClearPragmas();
00343
00344
00345 }
00346
00347
00348 void TTabCom::RehashClasses()
00349 {
00350
00351 ClearClasses();
00352 GetListOfClasses();
00353 }
00354
00355
00356 void TTabCom::RehashCppDirectives()
00357 {
00358
00359 ClearCppDirectives();
00360 GetListOfCppDirectives();
00361 }
00362
00363
00364 void TTabCom::RehashEnvVars()
00365 {
00366
00367 ClearEnvVars();
00368 GetListOfEnvVars();
00369 }
00370
00371
00372 void TTabCom::RehashFiles()
00373 {
00374
00375 ClearFiles();
00376 }
00377
00378
00379 void TTabCom::RehashGlobalFunctions()
00380 {
00381
00382 ClearGlobalFunctions();
00383 GetListOfGlobalFunctions();
00384 }
00385
00386
00387 void TTabCom::RehashGlobals()
00388 {
00389
00390 ClearGlobals();
00391 GetListOfGlobals();
00392 }
00393
00394
00395 void TTabCom::RehashPragmas()
00396 {
00397
00398 ClearPragmas();
00399 GetListOfPragmas();
00400 }
00401
00402
00403 void TTabCom::RehashSysIncFiles()
00404 {
00405
00406 ClearSysIncFiles();
00407 GetListOfSysIncFiles();
00408 }
00409
00410
00411 void TTabCom::RehashUsers()
00412 {
00413
00414 ClearUsers();
00415 GetListOfUsers();
00416 }
00417
00418
00419 void TTabCom::RehashAll()
00420 {
00421
00422
00423
00424 RehashClasses();
00425 RehashCppDirectives();
00426 RehashEnvVars();
00427 RehashFiles();
00428 RehashGlobalFunctions();
00429 RehashGlobals();
00430 RehashPragmas();
00431
00432
00433 }
00434
00435
00436 const TSeqCollection *TTabCom::GetListOfClasses()
00437 {
00438
00439 if (!fpClasses) {
00440
00441 const char *tmpfilename = tmpnam(0);
00442 FILE *fout = fopen(tmpfilename, "w");
00443 if (!fout) return 0;
00444 gCint->DisplayClass(fout, (char*)"", 0, 0);
00445 fclose(fout);
00446
00447
00448 ifstream file1(tmpfilename);
00449 if (!file1) {
00450 Error("TTabCom::GetListOfClasses", "could not open file \"%s\"",
00451 tmpfilename);
00452 gSystem->Unlink(tmpfilename);
00453 return 0;
00454 }
00455
00456 file1.ignore(32000, '\n');
00457 file1.ignore(32000, '\n');
00458
00459
00460 fpClasses = new TContainer;
00461 fpNamespaces = new TContainer;
00462 TString line;
00463 while (file1) {
00464 line = "";
00465 line.ReadLine(file1, kFALSE);
00466 line = line(23, 32000);
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476 int index;
00477 Bool_t isanamespace = kFALSE;
00478 if (0);
00479 else if ((index = line.Index(" class ")) >= 0)
00480 line = line(1 + index + 6, 32000);
00481 else if ((index = line.Index(" namespace ")) >= 0) {
00482 line = line(1 + index + 10, 32000);
00483 isanamespace = kTRUE;
00484 } else if ((index = line.Index(" struct ")) >= 0)
00485 line = line(1 + index + 7, 32000);
00486 else if ((index = line.Index(" enum ")) >= 0)
00487 line = line(1 + index + 5, 32000);
00488 else if ((index = line.Index(" (unknown) ")) >= 0)
00489 line = line(1 + index + 10, 32000);
00490
00491
00492
00493
00494 line = line("[^ ]*");
00495
00496
00497
00498 if (isanamespace)
00499 fpNamespaces->Add(new TObjString(line));
00500 else
00501 fpClasses->Add(new TObjString(line));
00502 }
00503
00504
00505 file1.close();
00506 gSystem->Unlink(tmpfilename);
00507 }
00508
00509 return fpClasses;
00510 }
00511
00512
00513 const TSeqCollection *TTabCom::GetListOfCppDirectives()
00514 {
00515
00516 if (!fpDirectives) {
00517 fpDirectives = new TContainer;
00518
00519 fpDirectives->Add(new TObjString("if"));
00520 fpDirectives->Add(new TObjString("ifdef"));
00521 fpDirectives->Add(new TObjString("ifndef"));
00522 fpDirectives->Add(new TObjString("elif"));
00523 fpDirectives->Add(new TObjString("else"));
00524 fpDirectives->Add(new TObjString("endif"));
00525 fpDirectives->Add(new TObjString("include"));
00526 fpDirectives->Add(new TObjString("define"));
00527 fpDirectives->Add(new TObjString("undef"));
00528 fpDirectives->Add(new TObjString("line"));
00529 fpDirectives->Add(new TObjString("error"));
00530 fpDirectives->Add(new TObjString("pragma"));
00531 }
00532
00533 return fpDirectives;
00534 }
00535
00536
00537 const TSeqCollection *TTabCom::GetListOfFilesInPath(const char path[])
00538 {
00539
00540
00541
00542 static TString previousPath;
00543
00544 if (path && fpFiles && strcmp(path, previousPath) == 0) {
00545 return fpFiles;
00546 } else {
00547 ClearFiles();
00548
00549 fpFiles = NewListOfFilesInPath(path);
00550 previousPath = path;
00551 }
00552
00553 return fpFiles;
00554 }
00555
00556
00557 const TSeqCollection *TTabCom::GetListOfEnvVars()
00558 {
00559
00560
00561 if (!fpEnvVars) {
00562 const char *tmpfilename = tmpnam(0);
00563 TString cmd;
00564
00565 #ifndef WIN32
00566 char *env = gSystem->Which(gSystem->Getenv("PATH"), "env", kExecutePermission);
00567 if (!env)
00568 return 0;
00569 cmd = env;
00570 cmd += " > ";
00571 delete [] env;
00572 #else
00573 cmd = "set > ";
00574 #endif
00575 cmd += tmpfilename;
00576 cmd += "\n";
00577 gSystem->Exec(cmd.Data());
00578
00579
00580 ifstream file1(tmpfilename);
00581 if (!file1) {
00582 Error("TTabCom::GetListOfEnvVars", "could not open file \"%s\"",
00583 tmpfilename);
00584 gSystem->Unlink(tmpfilename);
00585 return 0;
00586 }
00587
00588 fpEnvVars = new TContainer;
00589 TString line;
00590 while (file1)
00591
00592
00593 {
00594 line.ReadToDelim(file1, '=');
00595 file1.ignore(32000, '\n');
00596 fpEnvVars->Add(new TObjString(line.Data()));
00597 }
00598
00599 file1.close();
00600 gSystem->Unlink(tmpfilename);
00601 }
00602
00603 return fpEnvVars;
00604 }
00605
00606
00607 const TSeqCollection *TTabCom::GetListOfGlobals()
00608 {
00609
00610 if (!fpGlobals) {
00611
00612 fpGlobals = new TContainer;
00613
00614 DataMemberInfo_t *a;
00615 int last = 0;
00616 int nglob = 0;
00617
00618
00619 DataMemberInfo_t *t = gCint->DataMemberInfo_Factory();
00620 while (gCint->DataMemberInfo_Next(t))
00621 nglob++;
00622
00623 for (int i = 0; i < nglob; i++) {
00624 a = gCint->DataMemberInfo_Factory();
00625 gCint->DataMemberInfo_Next(a);
00626
00627 for (int j = 0; j < last; j++)
00628 gCint->DataMemberInfo_Next(a);
00629
00630
00631 if (gCint->DataMemberInfo_IsValid(a) && gCint->DataMemberInfo_Name(a)) {
00632 fpGlobals->Add(new TGlobal(a));
00633 } else
00634 gCint->DataMemberInfo_Delete(a);
00635
00636 last++;
00637 }
00638 gCint->DataMemberInfo_Delete(t);
00639 }
00640
00641 return fpGlobals;
00642 }
00643
00644
00645 const TSeqCollection *TTabCom::GetListOfGlobalFunctions()
00646 {
00647
00648 if (!fpGlobalFuncs) {
00649
00650 fpGlobalFuncs = new TContainer;
00651
00652 MethodInfo_t *a;
00653 int last = 0;
00654 int nglob = 0;
00655
00656
00657 MethodInfo_t *t = gCint->MethodInfo_Factory();
00658 while (gCint->MethodInfo_Next(t))
00659 nglob++;
00660
00661 for (int i = 0; i < nglob; i++) {
00662 a = gCint->MethodInfo_Factory();
00663 gCint->MethodInfo_Next(a);
00664
00665 for (int j = 0; j < last; j++)
00666 gCint->MethodInfo_Next(a);
00667
00668
00669 if (gCint->MethodInfo_IsValid(a) && gCint->MethodInfo_Name(a)) {
00670 fpGlobalFuncs->Add(new TFunction(a));
00671 } else
00672 gCint->MethodInfo_Delete(a);
00673
00674 last++;
00675 }
00676 gCint->MethodInfo_Delete(t);
00677 }
00678
00679 return fpGlobalFuncs;
00680 }
00681
00682
00683 const TSeqCollection *TTabCom::GetListOfPragmas()
00684 {
00685
00686 if (!fpPragmas) {
00687 fpPragmas = new TContainer;
00688
00689 fpPragmas->Add(new TObjString("ANSI "));
00690 fpPragmas->Add(new TObjString("autocompile "));
00691 fpPragmas->Add(new TObjString("bytecode "));
00692 fpPragmas->Add(new TObjString("compile "));
00693 fpPragmas->Add(new TObjString("endbytecode "));
00694 fpPragmas->Add(new TObjString("endcompile "));
00695 fpPragmas->Add(new TObjString("include "));
00696 fpPragmas->Add(new TObjString("includepath "));
00697 fpPragmas->Add(new TObjString("K&R "));
00698 fpPragmas->Add(new TObjString("link "));
00699 fpPragmas->Add(new TObjString("preprocess "));
00700 fpPragmas->Add(new TObjString("preprocessor "));
00701 fpPragmas->Add(new TObjString("security level"));
00702
00703
00704
00705
00706
00707 }
00708
00709 return fpPragmas;
00710 }
00711
00712
00713 const TSeqCollection *TTabCom::GetListOfSysIncFiles()
00714 {
00715
00716 if (!fpSysIncFiles) {
00717 fpSysIncFiles = NewListOfFilesInPath(GetSysIncludePath());
00718 }
00719
00720 return fpSysIncFiles;
00721 }
00722
00723
00724 const TSeqCollection *TTabCom::GetListOfUsers()
00725 {
00726
00727
00728 if (!fpUsers) {
00729 fpUsers = new TContainer;
00730
00731 ifstream passwd;
00732 TString user;
00733
00734 passwd.open("/etc/passwd");
00735 while (passwd) {
00736 user.ReadToDelim(passwd, ':');
00737 fpUsers->Add(new TObjString(user));
00738 passwd.ignore(32000, '\n');
00739 }
00740 passwd.close();
00741 }
00742
00743 return fpUsers;
00744 }
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757 Char_t TTabCom::AllAgreeOnChar(int i, const TSeqCollection * pList,
00758 Int_t & nGoodStrings)
00759 {
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775 assert(pList != 0);
00776
00777 TIter next(pList);
00778 TObject *pObj;
00779 const char *s;
00780 char ch0;
00781 Bool_t isGood;
00782 Bool_t atLeast1GoodString;
00783
00784
00785 nGoodStrings = 0;
00786 atLeast1GoodString = kFALSE;
00787
00788
00789 do {
00790 if ((pObj = next())) {
00791 s = pObj->GetName();
00792 isGood = !ExcludedByFignore(s);
00793 if (isGood) {
00794 atLeast1GoodString = kTRUE;
00795 nGoodStrings += 1;
00796 }
00797 } else {
00798
00799
00800 next.Reset();
00801 pObj = next();
00802 s = pObj->GetName();
00803 break;
00804 }
00805 }
00806 while (!isGood);
00807
00808
00809 ch0 = s[i];
00810
00811
00812 do {
00813 if ((pObj = next())) {
00814 s = pObj->GetName();
00815 isGood = !ExcludedByFignore(s);
00816 if (isGood)
00817 nGoodStrings += 1;
00818 } else
00819 return ch0;
00820 }
00821 while (((int) strlen(s) >= i && s[i] == ch0) ||
00822 (atLeast1GoodString && !isGood));
00823
00824 return 0;
00825 }
00826
00827
00828 void TTabCom::AppendListOfFilesInDirectory(const char dirName[],
00829 TSeqCollection * pList)
00830 {
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840 assert(dirName != 0);
00841 assert(pList != 0);
00842
00843
00844 void *dir = gSystem->OpenDirectory(dirName);
00845
00846
00847
00848 if (!dir)
00849 return;
00850
00851
00852 const char *tmp_ptr;
00853 TString fileName;
00854
00855 while ((tmp_ptr = gSystem->GetDirEntry(dir))) {
00856 fileName = tmp_ptr;
00857
00858
00859 if (fileName == "." || fileName == "..")
00860 continue;
00861
00862
00863 pList->Add(new TObjString(dirName + fileName.Prepend("/")));
00864 }
00865
00866
00867
00868
00869
00870
00871
00872 gSystem->FreeDirectory(dir);
00873 }
00874
00875
00876
00877 TString TTabCom::DetermineClass(const char varName[])
00878 {
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901 assert(varName != 0);
00902 IfDebug(cerr << "DetermineClass(\"" << varName << "\");" << endl);
00903
00904 const char *tmpfile = tmpnam(0);
00905 TString cmd("gROOT->ProcessLine(\"");
00906 cmd += varName;
00907 cmd += "\"); > ";
00908 cmd += tmpfile;
00909 cmd += "\n";
00910
00911 gROOT->ProcessLineSync(cmd.Data());
00912
00913
00914
00915 TString type = "";
00916 int c;
00917
00918
00919 ifstream file1(tmpfile);
00920 if (!file1) {
00921 Error("TTabCom::DetermineClass", "could not open file \"%s\"",
00922 tmpfile);
00923 goto cleanup;
00924 }
00925
00926 c = file1.get();
00927 if (!file1 || c <= 0 || c == '*' || c != '(') {
00928 Error("TTabCom::DetermineClass", "variable \"%s\" not defined?",
00929 varName);
00930 goto cleanup;
00931 }
00932 IfDebug(cerr << (char) c << flush);
00933
00934
00935
00936 file1 >> type;
00937
00938
00939 if (type == "const")
00940 file1 >> type;
00941
00942 if (type != "class" && type != "struct") {
00943 type = "";
00944 goto cleanup;
00945 }
00946
00947 c = file1.get();
00948 IfDebug(cerr << (char) c << flush);
00949
00950
00951 type.ReadToDelim(file1, ')');
00952 IfDebug(cerr << type << endl);
00953
00954
00955
00956 if (type.EndsWith("const"))
00957 type.Remove(type.Length() - 5);
00958
00959 cleanup:
00960
00961 file1.close();
00962 gSystem->Unlink(tmpfile);
00963
00964 return type;
00965 }
00966
00967
00968 Bool_t TTabCom::ExcludedByFignore(TString s)
00969 {
00970
00971
00972
00973
00974
00975
00976
00977 const char *fignore = gEnv->GetValue("TabCom.FileIgnore", (char *) 0);
00978
00979 if (!fignore) {
00980 return kFALSE;
00981 } else {
00982 #ifdef R__SSTREAM
00983 istringstream endings((char *) fignore);
00984 #else
00985 istrstream endings((char *) fignore);
00986 #endif
00987 TString ending;
00988
00989 ending.ReadToDelim(endings, kDelim);
00990
00991 while (!ending.IsNull()) {
00992 if (s.EndsWith(ending))
00993 return kTRUE;
00994 else
00995 ending.ReadToDelim(endings, kDelim);
00996 }
00997 return kFALSE;
00998 }
00999 }
01000
01001
01002 TString TTabCom::GetSysIncludePath()
01003 {
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047
01048
01049
01050
01051
01052 const char *tmpfilename = tmpnam(0);
01053
01054 FILE *fout = fopen(tmpfilename, "w");
01055 if (!fout) return "";
01056 gCint->DisplayIncludePath(fout);
01057 fclose(fout);
01058
01059
01060 ifstream file1(tmpfilename);
01061 if (!file1) {
01062 Error("TTabCom::GetSysIncludePath", "could not open file \"%s\"",
01063 tmpfilename);
01064 gSystem->Unlink(tmpfilename);
01065 return "";
01066 }
01067
01068 TString token;
01069 TString path;
01070 file1 >> token;
01071 file1 >> token;
01072 while (file1) {
01073 file1 >> token;
01074 if (!token.IsNull()) {
01075 if (path.Length() > 0)
01076 path.Append(":");
01077 path.Append(token.Data() + 2);
01078 }
01079 }
01080
01081
01082 file1.close();
01083 gSystem->Unlink(tmpfilename);
01084
01085
01086
01087
01088 #ifndef CINTINCDIR
01089 TString sCINTSYSDIR("$ROOTSYS/cint");
01090 #else
01091 TString sCINTSYSDIR(CINTINCDIR);
01092 #endif
01093 path.Append(":" + sCINTSYSDIR + "/include");
01094
01095
01096
01097 path.Append(":/usr/include");
01098
01099
01100
01101
01102 return path;
01103 }
01104
01105
01106 Bool_t TTabCom::IsDirectory(const char fileName[])
01107 {
01108
01109
01110
01111
01112
01113
01114
01115 FileStat_t stat;
01116 gSystem->GetPathInfo(fileName, stat);
01117 return R_ISDIR(stat.fMode);
01118 }
01119
01120
01121 TSeqCollection *TTabCom::NewListOfFilesInPath(const char path1[])
01122 {
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133 assert(path1 != 0);
01134 if (!path1[0]) path1 = ".";
01135
01136 TContainer *pList = new TContainer;
01137 #ifdef R__SSTREAM
01138 istringstream path((char *) path1);
01139 #else
01140 istrstream path((char *) path1);
01141 #endif
01142
01143 while (path.good())
01144 {
01145 TString dirName;
01146 dirName.ReadToDelim(path, kDelim);
01147 if (dirName.IsNull())
01148 continue;
01149
01150 IfDebug(cerr << "NewListOfFilesInPath(): dirName = " << dirName <<
01151 endl);
01152
01153 AppendListOfFilesInDirectory(dirName, pList);
01154 }
01155
01156 return pList;
01157 }
01158
01159
01160 Bool_t TTabCom::PathIsSpecifiedInFileName(const TString & fileName)
01161 {
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172 char c1 = (fileName.Length() > 0) ? fileName[0] : 0;
01173 return c1 == '/' || c1 == '~' || c1 == '$' || fileName.BeginsWith("./")
01174 || fileName.BeginsWith("../");
01175 }
01176
01177
01178 void TTabCom::NoMsg(Int_t errorLevel)
01179 {
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197
01198
01199
01200
01201
01202
01203
01204
01205 const Int_t kNotDefined = -2;
01206 static Int_t old_level = kNotDefined;
01207
01208 if (errorLevel < 0)
01209 {
01210 if (old_level == kNotDefined) {
01211 cerr << "NoMsg(): ERROR 1. old_level==" << old_level << endl;
01212 return;
01213 }
01214
01215 gErrorIgnoreLevel = old_level;
01216 old_level = kNotDefined;
01217 } else
01218 {
01219 if (old_level != kNotDefined) {
01220 cerr << "NoMsg(): ERROR 2. old_level==" << old_level << endl;
01221 return;
01222 }
01223
01224 old_level = gErrorIgnoreLevel;
01225 if (gErrorIgnoreLevel <= errorLevel)
01226 gErrorIgnoreLevel = errorLevel + 1;
01227 }
01228 }
01229
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243 Int_t TTabCom::Complete(const TRegexp & re,
01244 const TSeqCollection * pListOfCandidates,
01245 const char appendage[],
01246 TString::ECaseCompare cmp)
01247 {
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258 IfDebug(cerr << "TTabCom::Complete() ..." << endl);
01259 assert(fpLoc != 0);
01260 assert(pListOfCandidates != 0);
01261
01262 Int_t pos = 0;
01263 const int loc = *fpLoc;
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275 TString s1(fBuf);
01276 TString s2 = s1(0, loc);
01277 TString s3 = s2(re);
01278
01279 int start = s2.Index(re);
01280
01281 IfDebug(cerr << " s1: " << s1 << endl);
01282 IfDebug(cerr << " s2: " << s2 << endl);
01283 IfDebug(cerr << " s3: " << s3 << endl);
01284 IfDebug(cerr << "start: " << start << endl);
01285 IfDebug(cerr << endl);
01286
01287
01288
01289
01290
01291 TList listOfMatches;
01292 TList listOfFullPaths;
01293 listOfMatches.SetOwner();
01294 listOfFullPaths.SetOwner();
01295
01296 int nMatches = 0;
01297 TObject *pObj;
01298 TIter next_candidate(pListOfCandidates);
01299 TIter next_match(&listOfMatches);
01300 TIter next_fullpath(&listOfFullPaths);
01301
01302
01303 while ((pObj = next_candidate())) {
01304
01305 const char *s4 = pObj->GetName();
01306
01307 assert(s4 != 0);
01308
01309
01310 const char *s5 = strrchr(s4, '/');
01311 if (!s5)
01312 s5 = s4;
01313 else
01314 s5 += 1;
01315
01316
01317
01318 if ((cmp == TString::kExact) && (strstr(s5, s3) == s5)) {
01319 nMatches += 1;
01320 listOfMatches.Add(new TObjString(s5));
01321 listOfFullPaths.Add(new TObjString(s4));
01322 IfDebug(cerr << "adding " << s5 << '\t' << s4 << endl);
01323 } else if (cmp == TString::kIgnoreCase) {
01324 TString ts5(s5);
01325 if (ts5.BeginsWith(s3, cmp))
01326 {
01327 nMatches += 1;
01328 listOfMatches.Add(new TObjString(s5));
01329 listOfFullPaths.Add(new TObjString(s4));
01330 IfDebug(cerr << "adding " << s5 << '\t' << s4 << endl);
01331 }
01332 } else {
01333
01334 }
01335
01336 }
01337
01338
01339
01340
01341
01342
01343
01344 TString partialMatch = "";
01345
01346 if (nMatches == 0) {
01347
01348 gSystem->Beep();
01349 pos = -1;
01350 goto done;
01351 }
01352
01353 char match[1024];
01354
01355 if (nMatches == 1) {
01356
01357 const char *short_name = next_match()->GetName();
01358 const char *full_name = next_fullpath()->GetName();
01359
01360 pObj = pListOfCandidates->FindObject(short_name);
01361 if (pObj) {
01362 IfDebug(cerr << endl << "class: " << pObj->ClassName() << endl);
01363 TString className = pObj->ClassName();
01364 if (0);
01365 else if (className == "TMethod" || className == "TFunction") {
01366 TFunction *pFunc = (TFunction *) pObj;
01367 if (0 == pFunc->GetNargs())
01368 appendage = "()";
01369 else
01370 appendage = "(";
01371 } else if (className == "TDataMember") {
01372 appendage = " ";
01373 }
01374 }
01375
01376 CopyMatch(match, short_name, appendage, full_name);
01377 } else {
01378
01379 Char_t ch;
01380 Int_t nGoodStrings;
01381
01382 for (int i = 0;
01383 (ch = AllAgreeOnChar(i, &listOfMatches, nGoodStrings));
01384 i += 1) {
01385 IfDebug(cerr << " i=" << i << " ch=" << ch << endl);
01386 partialMatch.Append(ch);
01387 }
01388
01389 const char *s;
01390 const char *s0;
01391
01392
01393 if (nGoodStrings == 1) {
01394
01395
01396 do {
01397 s = next_match()->GetName();
01398 s0 = next_fullpath()->GetName();
01399 }
01400 while (ExcludedByFignore(s));
01401
01402
01403 CopyMatch(match, s, appendage, s0);
01404 } else {
01405 IfDebug(cerr << "more than 1 GoodString" << endl);
01406
01407 if (partialMatch.Length() > s3.Length())
01408
01409 {
01410 CopyMatch(match, partialMatch.Data());
01411 } else
01412
01413
01414
01415 {
01416 IfDebug(cerr << "printing ambiguous matches" << endl);
01417 cout << endl;
01418 while ((pObj = next_match())) {
01419 s = pObj->GetName();
01420 s0 = next_fullpath()->GetName();
01421 if (!ExcludedByFignore(s) || nGoodStrings == 0) {
01422 if (IsDirectory(s0))
01423 cout << s << "/" << endl;
01424 else
01425 cout << s << endl;
01426 }
01427 }
01428 pos = -2;
01429 if (cmp == TString::kExact || partialMatch.Length() < s3.Length()) {
01430 goto done;
01431 }
01432
01433
01434
01435 CopyMatch(match, partialMatch.Data());
01436 }
01437 }
01438 }
01439
01440
01441
01442
01443
01444 {
01445 int i = strlen(fBuf);
01446 int l = strlen(match) - (loc - start);
01447
01448
01449 if (strlen(fBuf) + strlen(match) + 1 > BUF_SIZE) {
01450 Error("TTabCom::Complete", "buffer overflow");
01451 pos = -2;
01452 goto done;
01453 }
01454
01455 IfDebug(cerr << " i=" << i << endl);
01456 IfDebug(cerr << " L=" << l << endl);
01457 IfDebug(cerr << "loc=" << loc << endl);
01458
01459
01460 for (; i >= loc; i -= 1) {
01461 fBuf[i + l] = fBuf[i];
01462 }
01463
01464
01465 strncpy(fBuf + start, match, strlen(match));
01466
01467
01468
01469
01470 if (pos != -2) {
01471 pos = loc;
01472 if (cmp == TString::kIgnoreCase && pos < 0) {
01473
01474
01475 pos = start;
01476 }
01477 }
01478 *fpLoc = loc + l;
01479 }
01480
01481 done:
01482
01483 fpLoc = 0;
01484 fBuf = 0;
01485
01486 return pos;
01487 }
01488
01489
01490 void TTabCom::CopyMatch(char dest[], const char localName[],
01491 const char appendage[],
01492 const char fullName[]) const
01493 {
01494
01495
01496
01497
01498
01499
01500
01501
01502
01503
01504
01505 assert(dest != 0);
01506 assert(localName != 0);
01507
01508
01509 strcpy(dest, localName);
01510
01511 const char *key = "filename";
01512 const int key_len = strlen(key);
01513
01514 IfDebug(cerr << "CopyMatch()." << endl);
01515 IfDebug(cerr << "localName: " << (localName ? localName : "0") <<
01516 endl);
01517 IfDebug(cerr << "appendage: " << (appendage ? appendage : "0") <<
01518 endl);
01519 IfDebug(cerr << " fullName: " << (fullName ? fullName : "0") <<
01520 endl);
01521
01522
01523
01524 if (appendage && strncmp(appendage, key, key_len) == 0) {
01525
01526 appendage += key_len;
01527 IfDebug(cerr << "new appendage: " << appendage << endl);
01528 if (IsDirectory(fullName)) {
01529 if (fullName)
01530 strcpy(dest + strlen(localName), "/");
01531 } else {
01532 if (appendage)
01533 strcpy(dest + strlen(localName), appendage);
01534 }
01535 } else {
01536 if (appendage)
01537 strcpy(dest + strlen(localName), appendage);
01538 }
01539 }
01540
01541
01542 TTabCom::EContext_t TTabCom::DetermineContext() const
01543 {
01544
01545
01546 assert(fBuf != 0);
01547
01548 const char *pStart;
01549 const char *pEnd;
01550
01551 for (int context = 0; context < kNUM_PAT; ++context) {
01552 pEnd = Matchs(fBuf, *fpLoc, fPat[context], &pStart);
01553 if (pEnd) {
01554 IfDebug(cerr << endl
01555 << "context=" << context << " "
01556 << "RegExp=" << fRegExp[context]
01557 << endl);
01558 return EContext_t(context);
01559 }
01560 }
01561
01562 return kUNKNOWN_CONTEXT;
01563 }
01564
01565
01566 TString TTabCom::DeterminePath(const TString & fileName,
01567 const char defaultPath[]) const
01568 {
01569
01570
01571 if (PathIsSpecifiedInFileName(fileName)) {
01572 TString path = fileName;
01573 gSystem->ExpandPathName(path);
01574 Int_t end = path.Length()-1;
01575 if (end>0 && path[end]!='/' && path[end]!='\\') {
01576 path = gSystem->DirName(path);
01577 }
01578 return path;
01579 } else {
01580 TString newBase;
01581 TString extendedPath;
01582 if (fileName.Contains("/")) {
01583 Int_t end = fileName.Length()-1;
01584 if (fileName[end] != '/' && fileName[end] != '\\') {
01585 newBase = gSystem->DirName(fileName);
01586 } else {
01587 newBase = fileName;
01588 }
01589 extendedPath = ExtendPath(defaultPath, newBase);
01590 } else {
01591 newBase = "";
01592 extendedPath = defaultPath;
01593 }
01594 IfDebug(cerr << endl);
01595 IfDebug(cerr << " fileName: " << fileName << endl);
01596 IfDebug(cerr << " pathBase: " << newBase << endl);
01597 IfDebug(cerr << " defaultPath: " << defaultPath << endl);
01598 IfDebug(cerr << "extendedPath: " << extendedPath << endl);
01599 IfDebug(cerr << endl);
01600
01601 return extendedPath;
01602 }
01603 }
01604
01605
01606 TString TTabCom::ExtendPath(const char originalPath[], TString newBase) const
01607 {
01608
01609
01610 if (newBase.BeginsWith("/"))
01611 newBase.Remove(TString::kLeading, '/');
01612 #ifdef R__SSTREAM
01613 stringstream str;
01614 #else
01615 strstream str;
01616 #endif
01617 TString dir;
01618 TString newPath;
01619 str << originalPath;
01620
01621 while (str.good())
01622 {
01623 dir = "";
01624 dir.ReadToDelim(str, kDelim);
01625 if (dir.IsNull())
01626 continue;
01627 newPath.Append(dir);
01628 if (!newPath.EndsWith("/"))
01629 newPath.Append("/");
01630 newPath.Append(newBase);
01631 newPath.Append(kDelim);
01632 }
01633
01634 return newPath.Strip(TString::kTrailing, kDelim);
01635 }
01636
01637
01638 Int_t TTabCom::Hook(char *buf, int *pLoc)
01639 {
01640
01641
01642
01643 fBuf = buf;
01644 fpLoc = pLoc;
01645
01646
01647 fLastIter = 0;
01648
01649
01650 Int_t pos = -2;
01651
01652
01653 EContext_t context = DetermineContext();
01654
01655
01656 const char dummy[] = ".";
01657 TRegexp re1(context == kUNKNOWN_CONTEXT ? dummy : fRegExp[context]);
01658 TString s1(fBuf);
01659 TString s2 = s1(0, *fpLoc);
01660 TString s3 = s2(re1);
01661
01662 switch (context) {
01663 case kUNKNOWN_CONTEXT:
01664 cerr << endl << "tab completion not implemented for this context" <<
01665 endl;
01666 pos = -2;
01667 break;
01668
01669 case kSYS_UserName:
01670 {
01671 const TSeqCollection *pListOfUsers = GetListOfUsers();
01672
01673 pos = Complete("[^~]*$", pListOfUsers, "/");
01674 }
01675 break;
01676 case kSYS_EnvVar:
01677 {
01678 const TSeqCollection *pEnv = GetListOfEnvVars();
01679
01680 pos = Complete("[^$]*$", pEnv, "");
01681 }
01682 break;
01683
01684 case kCINT_stdout:
01685 case kCINT_stderr:
01686 case kCINT_stdin:
01687 {
01688 const TString fileName = s3("[^ ><]*$");
01689 const TString filePath = DeterminePath(fileName,0);
01690 const TSeqCollection *pListOfFiles =
01691 GetListOfFilesInPath(filePath.Data());
01692
01693
01694 pos = Complete("[^ /]*$", pListOfFiles, "filename ");
01695 }
01696 break;
01697
01698 case kCINT_Edit:
01699 case kCINT_Load:
01700 case kCINT_Exec:
01701 case kCINT_EXec:
01702 {
01703 const TString fileName = s3("[^ ]*$");
01704 const TString macroPath =
01705 DeterminePath(fileName, TROOT::GetMacroPath());
01706 const TSeqCollection *pListOfFiles =
01707 GetListOfFilesInPath(macroPath.Data());
01708
01709
01710 pos = Complete("[^ /]*$", pListOfFiles, "filename ");
01711 }
01712 break;
01713
01714 case kCINT_pragma:
01715 {
01716 pos = Complete("[^ ]*$", GetListOfPragmas(), "");
01717 }
01718 break;
01719 case kCINT_includeSYS:
01720 {
01721 TString fileName = s3("[^<]*$");
01722 if (PathIsSpecifiedInFileName(fileName) || fileName.Contains("/")) {
01723 TString includePath =
01724 DeterminePath(fileName, GetSysIncludePath());
01725
01726
01727 pos =
01728 Complete("[^</]*$", GetListOfFilesInPath(includePath),
01729 "filename> ");
01730 } else {
01731
01732 pos =
01733 Complete("[^</]*$", GetListOfSysIncFiles(), "filename> ");
01734 }
01735 }
01736 break;
01737 case kCINT_includePWD:
01738 {
01739 const TString fileName = s3("[^\"]*$");
01740 const TString includePath = DeterminePath(fileName, ".");
01741 const TSeqCollection *pListOfFiles =
01742 GetListOfFilesInPath(includePath.Data());
01743
01744
01745 pos = Complete("[^\"/]*$", pListOfFiles, "filename\" ");
01746 }
01747 break;
01748
01749 case kCINT_cpp:
01750 {
01751 pos = Complete("[^# ]*$", GetListOfCppDirectives(), " ");
01752 }
01753 break;
01754
01755 case kROOT_Load:
01756 {
01757 const TString fileName = s3("[^\"]*$");
01758
01759 const TString dynamicPath = DeterminePath(fileName,gEnv->GetValue("Root.DynamicPath",(char *) 0));
01760 const TSeqCollection *pListOfFiles = GetListOfFilesInPath(dynamicPath);
01761
01762
01763 pos = Complete("[^\"/]*$", pListOfFiles, "filename\");");
01764 }
01765 break;
01766
01767 case kSYS_FileName:
01768 {
01769 const TString fileName = s3("[^ \"]*$");
01770 const TString filePath = DeterminePath(fileName,".");
01771 const TSeqCollection *pListOfFiles = GetListOfFilesInPath(filePath.Data());
01772
01773 pos = Complete("[^\" /]*$", pListOfFiles, "filename\"");
01774 }
01775 break;
01776
01777 case kCXX_ScopeMember:
01778 {
01779 const EContext_t original_context = context;
01780
01781 TClass *pClass;
01782
01783 TString name = s3("^[_a-zA-Z][_a-zA-Z0-9]*");
01784
01785 IfDebug(cerr << endl);
01786 IfDebug(cerr << "name: " << '"' << name << '"' << endl);
01787
01788
01789
01790
01791 TString partname = s3("[_a-zA-Z][_a-zA-Z0-9]*$");
01792
01793
01794
01795
01796
01797
01798 TString prefix = "";
01799 TString str = s2;
01800 str.Remove(str.Length() - partname.Length(), partname.Length());
01801 while (1) {
01802 TString sym = str("[_a-zA-Z][_a-zA-Z0-9]*::$");
01803 if (sym.Length() == 0)
01804 break;
01805 str.Remove(str.Length() - sym.Length(), sym.Length());
01806 prefix = sym + prefix;
01807 }
01808
01809
01810
01811 TString preprefix = prefix;
01812 TString sym = prefix("[_a-zA-Z][_a-zA-Z0-9]*::$");
01813 preprefix.Remove(preprefix.Length() - sym.Length(), sym.Length());
01814
01815 IfDebug(cerr << "prefix: " << '"' << prefix << '"' << endl);
01816 IfDebug(cerr << "preprefix: " << '"' << preprefix << '"' << endl);
01817
01818 TString namesp = prefix;
01819 if (namesp.Length() >= 2)
01820 namesp.Remove(namesp.Length() - 2, 2);
01821 IfDebug(cerr << "namesp: " << '"' << namesp << '"' << endl);
01822
01823
01824 delete TryMakeClassFromClassName(namesp);
01825
01826
01827
01828 if (!fpNamespaces)
01829 RehashClasses();
01830
01831
01832
01833 TObjString objstr(namesp);
01834 TObjString *foundstr = 0;
01835 if (fpNamespaces)
01836 foundstr = (TObjString *)fpNamespaces->FindObject(&objstr);
01837 if (foundstr) {
01838 TContainer *pList = new TContainer;
01839
01840
01841
01842 const TSeqCollection *tmp = GetListOfClasses();
01843 if (!tmp) break;
01844
01845 Int_t i;
01846 for (i = 0; i < tmp->GetSize(); i++) {
01847 TString astr = ((TObjString *) tmp->At(i))->String();
01848 TString rxp = "^";
01849 rxp += prefix;
01850 if (astr.Contains(TRegexp(rxp))) {
01851 astr.Remove(0, prefix.Length());
01852 TString s = astr("^[^: ]*");
01853 TObjString *ostr = new TObjString(s);
01854 if (!pList->Contains(ostr))
01855 pList->Add(ostr);
01856 else
01857 delete ostr;
01858 }
01859 }
01860
01861
01862 for (i = 0; i < fpNamespaces->GetSize(); i++) {
01863 TString astr =
01864 ((TObjString *) fpNamespaces->At(i))->String();
01865 TString rxp = "^";
01866 rxp += prefix;
01867 if (astr.Contains(TRegexp(rxp))) {
01868 astr.Remove(0, prefix.Length());
01869 TString s = astr("^[^: ]*");
01870 TObjString *ostr = new TObjString(s);
01871 if (!pList->Contains(ostr))
01872 pList->Add(ostr);
01873 else
01874 delete ostr;
01875 }
01876 }
01877
01878
01879
01880
01881 pClass = TryMakeClassFromClassName(preprefix + name);
01882 if (pClass) {
01883 pList->AddAll(pClass->GetListOfAllPublicMethods());
01884 pList->AddAll(pClass->GetListOfAllPublicDataMembers());
01885 }
01886
01887 pos = Complete("[^: ]*$", pList, "");
01888
01889 delete pList;
01890 if (pClass)
01891 delete pClass;
01892 } else {
01893 pClass = MakeClassFromClassName(preprefix + name);
01894 if (!pClass) {
01895 pos = -2;
01896 break;
01897 }
01898
01899 TContainer *pList = new TContainer;
01900
01901 pList->AddAll(pClass->GetListOfAllPublicMethods());
01902 pList->AddAll(pClass->GetListOfAllPublicDataMembers());
01903
01904 pos = Complete("[^: ]*$", pList, "(");
01905
01906 delete pList;
01907 delete pClass;
01908 }
01909
01910 if (context != original_context)
01911 pos = -2;
01912 }
01913 break;
01914
01915 case kCXX_DirectMember:
01916 case kCXX_IndirectMember:
01917 {
01918 const EContext_t original_context = context;
01919
01920 TClass *pClass;
01921
01922
01923
01924
01925
01926
01927
01928 TString name = s1("[_a-zA-Z][-_a-zA-Z0-9<>():.]*$");
01929
01930 IfDebug(cerr << endl);
01931 IfDebug(cerr << "name: " << '"' << name << '"' << endl);
01932
01933 switch (context) {
01934 case kCXX_DirectMember:
01935 pClass = MakeClassFromVarName(name, context);
01936 break;
01937 case kCXX_IndirectMember:
01938 pClass = MakeClassFromVarName(name, context);
01939 break;
01940 default:
01941 assert(0);
01942 break;
01943 }
01944 if (!pClass) {
01945 pos = -2;
01946 break;
01947 }
01948
01949 TContainer *pList = new TContainer;
01950
01951 pList->AddAll(pClass->GetListOfAllPublicMethods());
01952 pList->AddAll(pClass->GetListOfAllPublicDataMembers());
01953
01954 switch (context) {
01955 case kCXX_DirectMember:
01956 {
01957 int* store_fpLoc = fpLoc;
01958 char* store_fBuf = fBuf;
01959 pos = Complete("[^. ]*$", pList, "(");
01960 if (pos == -1) {
01961 fpLoc = store_fpLoc;
01962 fBuf = store_fBuf;
01963 pos = Complete("[^. ]*$", pList, "(", TString::kIgnoreCase);
01964 }
01965 break;
01966 }
01967 case kCXX_IndirectMember:
01968 pos = Complete("[^> ]*$", pList, "(");
01969 break;
01970 default:
01971 assert(0);
01972 break;
01973 }
01974
01975 delete pList;
01976 delete pClass;
01977
01978 if (context != original_context)
01979 pos = -2;
01980 }
01981 break;
01982
01983 case kCXX_ScopeProto:
01984 {
01985 const EContext_t original_context = context;
01986
01987
01988 TClass *pClass;
01989 TString name = s3("^[_a-zA-Z][_a-zA-Z0-9]*");
01990
01991
01992 IfDebug(cerr << endl);
01993 IfDebug(cerr << "name: " << '"' << name << '"' << endl);
01994
01995
01996
01997
01998 TString partname = s3("[_a-zA-Z][_a-zA-Z0-9]* *($");
01999
02000
02001
02002
02003
02004
02005 TString prefix = "";
02006 TString str = s2;
02007 str.Remove(str.Length() - partname.Length(), partname.Length());
02008 while (1) {
02009 TString sym = str("[_a-zA-Z][_a-zA-Z0-9]*::$");
02010 if (sym.Length() == 0)
02011 break;
02012 str.Remove(str.Length() - sym.Length(), sym.Length());
02013 prefix = sym + prefix;
02014 }
02015
02016
02017
02018 TString preprefix = prefix;
02019 TString sym = prefix("[_a-zA-Z][_a-zA-Z0-9]*::$");
02020 preprefix.Remove(preprefix.Length() - sym.Length(), sym.Length());
02021
02022 IfDebug(cerr << "prefix: " << '"' << prefix << '"' << endl);
02023 IfDebug(cerr << "preprefix: " << '"' << preprefix << '"' << endl);
02024
02025 pClass = MakeClassFromClassName(preprefix + name);
02026 if (!pClass) {
02027 pos = -2;
02028 break;
02029 }
02030
02031 TString methodName;
02032
02033
02034 methodName = s3("[^:>\\.(]*($");
02035 methodName.Chop();
02036 methodName.Remove(TString::kTrailing, ' ');
02037
02038 IfDebug(cerr << methodName << endl);
02039
02040
02041 TContainer *pList = new TContainer;
02042 pList->AddAll(pClass->GetListOfAllPublicMethods());
02043
02044
02045 Bool_t foundOne = kFALSE;
02046 TIter nextMethod(pList);
02047 TMethod *pMethod;
02048 while ((pMethod = (TMethod *) nextMethod())) {
02049 if (methodName == pMethod->GetName()) {
02050 foundOne = kTRUE;
02051 cout << endl << pMethod->GetReturnTypeName()
02052 << " " << pMethod->GetName()
02053 << pMethod->GetSignature();
02054 const char *comment = pMethod->GetCommentString();
02055 if (comment && comment[0] != '\0') {
02056 cout << " \t// " << comment;
02057 }
02058 }
02059 }
02060
02061
02062 if (foundOne) {
02063 cout << endl;
02064 pos = -2;
02065 } else {
02066 gSystem->Beep();
02067 pos = -1;
02068 }
02069
02070
02071 delete pList;
02072 delete pClass;
02073
02074 if (context != original_context)
02075 pos = -2;
02076 }
02077 break;
02078
02079 case kCXX_DirectProto:
02080 case kCXX_IndirectProto:
02081 case kCXX_NewProto:
02082 case kCXX_ConstructorProto:
02083 {
02084 const EContext_t original_context = context;
02085
02086
02087 TClass *pClass;
02088 TString name;
02089 if (context == kCXX_NewProto) {
02090 name = s3("[_a-zA-Z][_a-zA-Z0-9:]* *($", 3);
02091 name.Chop();
02092 name.Remove(TString::kTrailing, ' ');
02093
02094 } else {
02095 name = s3("^[_a-zA-Z][_a-zA-Z0-9:]*");
02096
02097 }
02098 IfDebug(cerr << endl);
02099 IfDebug(cerr << "name: " << '"' << name << '"' << endl);
02100
02101
02102 TString namerec = s1;
02103
02104 switch (context) {
02105 case kCXX_ScopeProto:
02106 pClass = MakeClassFromClassName(name);
02107 break;
02108 case kCXX_DirectProto:
02109 pClass = MakeClassFromVarName(namerec, context);
02110 break;
02111 case kCXX_IndirectProto:
02112 pClass = MakeClassFromVarName(namerec, context);
02113 break;
02114 case kCXX_NewProto:
02115 pClass = MakeClassFromClassName(name);
02116 break;
02117 case kCXX_ConstructorProto:
02118 pClass = MakeClassFromClassName(name);
02119 break;
02120 default:
02121 assert(0);
02122 break;
02123 }
02124 if (!pClass) {
02125 pos = -2;
02126 break;
02127 }
02128
02129 TString methodName;
02130 if (context == kCXX_ConstructorProto || context == kCXX_NewProto) {
02131
02132 methodName = name("[_a-zA-Z][_a-zA-Z0-9]*$");
02133 } else {
02134
02135 methodName = s3("[^:>\\.(]*($");
02136 methodName.Chop();
02137 methodName.Remove(TString::kTrailing, ' ');
02138 }
02139 IfDebug(cerr << methodName << endl);
02140
02141
02142 TContainer *pList = new TContainer;
02143 pList->AddAll(pClass->GetListOfAllPublicMethods());
02144
02145
02146 Bool_t foundOne = kFALSE;
02147 TIter nextMethod(pList);
02148 TMethod *pMethod;
02149 while ((pMethod = (TMethod *) nextMethod())) {
02150 if (methodName == pMethod->GetName()) {
02151 foundOne = kTRUE;
02152 cout << endl << pMethod->GetReturnTypeName()
02153 << " " << pMethod->GetName()
02154 << pMethod->GetSignature();
02155 const char *comment = pMethod->GetCommentString();
02156 if (comment && comment[0] != '\0') {
02157 cout << " \t// " << comment;
02158 }
02159 }
02160 }
02161
02162
02163 if (foundOne) {
02164 cout << endl;
02165 pos = -2;
02166 } else {
02167 gSystem->Beep();
02168 pos = -1;
02169 }
02170
02171
02172 delete pList;
02173 delete pClass;
02174
02175 if (context != original_context)
02176 pos = -2;
02177 }
02178 break;
02179
02180 case kCXX_Global:
02181 {
02182
02183 int l2 = s2.Length(), l3 = s3.Length();
02184
02185
02186 if (l2 > l3 && s2[l2 - l3 - 1] == '.') {
02187 cerr << endl <<
02188 "tab completion not implemented for this context" << endl;
02189 break;
02190 }
02191
02192 if (l2 > l3 + 1 && s2(l2 - l3 - 2, 2) == "->") {
02193 cerr << endl <<
02194 "tab completion not implemented for this context" << endl;
02195 break;
02196 }
02197
02198 TContainer *pList = new TContainer;
02199
02200 const TSeqCollection *pL2 = GetListOfClasses();
02201 if (pL2) pList->AddAll(pL2);
02202
02203 if (fpNamespaces) pList->AddAll(fpNamespaces);
02204
02205 const TSeqCollection *pC1 = GetListOfGlobals();
02206 if (pC1) pList->AddAll(pC1);
02207
02208 const TSeqCollection *pC3 = GetListOfGlobalFunctions();
02209 if (pC3) pList->AddAll(pC3);
02210
02211 pos = Complete("[_a-zA-Z][_a-zA-Z0-9]*$", pList, "");
02212
02213 delete pList;
02214 }
02215 break;
02216
02217 case kCXX_GlobalProto:
02218 {
02219
02220 TString functionName = s3("[_a-zA-Z][_a-zA-Z0-9]*");
02221 IfDebug(cerr << functionName << endl);
02222
02223 TContainer listOfMatchingGlobalFuncs;
02224 TIter nextGlobalFunc(GetListOfGlobalFunctions());
02225 TObject *pObj;
02226 while ((pObj = nextGlobalFunc())) {
02227 if (strcmp(pObj->GetName(), functionName) == 0) {
02228 listOfMatchingGlobalFuncs.Add(pObj);
02229 }
02230 }
02231
02232 if (listOfMatchingGlobalFuncs.IsEmpty()) {
02233 cerr << endl << "no such function: " << dblquote(functionName)
02234 << endl;
02235 } else {
02236 cout << endl;
02237 TIter next(&listOfMatchingGlobalFuncs);
02238 TFunction *pFunction;
02239 while ((pFunction = (TFunction *) next())) {
02240 cout << pFunction->GetReturnTypeName()
02241 << " " << pFunction->GetName()
02242 << pFunction->GetSignature()
02243 << endl;
02244 }
02245 }
02246
02247 pos = -2;
02248 }
02249 break;
02250
02251
02252
02253
02254
02255
02256 default:
02257 assert(0);
02258 break;
02259 }
02260
02261 return pos;
02262 }
02263
02264
02265 void TTabCom::InitPatterns()
02266 {
02267
02268
02269
02270
02271
02272
02273
02274
02275
02276
02277
02278
02279
02280
02281
02282
02283
02284 SetPattern(kSYS_UserName, "~[_a-zA-Z0-9]*$");
02285 SetPattern(kSYS_EnvVar, "$[_a-zA-Z0-9]*$");
02286
02287 SetPattern(kCINT_stdout, "; *>>?.*$");
02288 SetPattern(kCINT_stderr, "; *2>>?.*$");
02289 SetPattern(kCINT_stdin, "; *<.*$");
02290
02291 SetPattern(kCINT_Edit, "^ *\\.E .*$");
02292 SetPattern(kCINT_Load, "^ *\\.L .*$");
02293 SetPattern(kCINT_Exec, "^ *\\.x +[-0-9_a-zA-Z~$./]*$");
02294 SetPattern(kCINT_EXec, "^ *\\.X +[-0-9_a-zA-Z~$./]*$");
02295
02296 SetPattern(kCINT_pragma, "^# *pragma +[_a-zA-Z0-9]*$");
02297 SetPattern(kCINT_includeSYS, "^# *include *<[^>]*$");
02298 SetPattern(kCINT_includePWD, "^# *include *\"[^\"]*$");
02299
02300 SetPattern(kCINT_cpp, "^# *[_a-zA-Z0-9]*$");
02301
02302 SetPattern(kROOT_Load, "gSystem *-> *Load *( *\"[^\"]*$");
02303
02304 SetPattern(kCXX_NewProto, "new +[_a-zA-Z][_a-zA-Z0-9:]* *($");
02305 SetPattern(kCXX_ConstructorProto,
02306 "[_a-zA-Z][_a-zA-Z0-9:]* +[_a-zA-Z][_a-zA-Z0-9]* *($");
02307 SetPattern(kCXX_ScopeProto,
02308 "[_a-zA-Z][_a-zA-Z0-9]* *:: *[_a-zA-Z0-9]* *($");
02309 SetPattern(kCXX_DirectProto,
02310 "[_a-zA-Z][_a-zA-Z0-9()]* *\\. *[_a-zA-Z0-9]* *($");
02311 SetPattern(kCXX_IndirectProto,
02312 "[_a-zA-Z][_a-zA-Z0-9()]* *-> *[_a-zA-Z0-9]* *($");
02313
02314 SetPattern(kCXX_ScopeMember,
02315 "[_a-zA-Z][_a-zA-Z0-9]* *:: *[_a-zA-Z0-9]*$");
02316 SetPattern(kCXX_DirectMember,
02317 "[_a-zA-Z][_a-zA-Z0-9()]* *\\. *[_a-zA-Z0-9()]*$");
02318 SetPattern(kCXX_IndirectMember,
02319 "[_a-zA-Z][_a-zA-Z0-9()]* *-> *[_a-zA-Z0-9()]*$");
02320
02321 SetPattern(kSYS_FileName, "\"[-0-9_a-zA-Z~$./]*$");
02322 SetPattern(kCXX_Global, "[_a-zA-Z][_a-zA-Z0-9]*$");
02323 SetPattern(kCXX_GlobalProto, "[_a-zA-Z][_a-zA-Z0-9]* *($");
02324 }
02325
02326
02327 TClass *TTabCom::MakeClassFromClassName(const char className[]) const
02328 {
02329
02330
02331
02332
02333
02334
02335
02336
02337 NoMsg(kWarning);
02338 TClass *pClass = new TClass(className);
02339 NoMsg(-1);
02340
02341
02342
02343 if (pClass->GetListOfAllPublicMethods()->GetSize() == 0 &&
02344 pClass->GetListOfAllPublicDataMembers()->GetSize() == 0) {
02345
02346
02347 cerr << endl << "class " << dblquote(className) << " not defined." <<
02348 endl;
02349 return 0;
02350 }
02351
02352 return pClass;
02353 }
02354
02355
02356 TClass *TTabCom::TryMakeClassFromClassName(const char className[]) const
02357 {
02358
02359
02360
02361
02362 NoMsg(kWarning);
02363 TClass *pClass = new TClass(className);
02364 NoMsg(-1);
02365
02366
02367
02368 if (pClass->GetListOfAllPublicMethods()->GetSize() == 0 &&
02369 pClass->GetListOfAllPublicDataMembers()->GetSize() == 0) {
02370 return 0;
02371 }
02372
02373 return pClass;
02374 }
02375
02376
02377 TClass *TTabCom::MakeClassFromVarName(const char varName[],
02378 EContext_t & context, int iter)
02379 {
02380
02381
02382
02383
02384
02385
02386
02387
02388
02389
02390
02391
02392
02393
02394
02395
02396
02397
02398
02399
02400
02401
02402 Bool_t varName_exists = GetListOfGlobals()->Contains(varName) ||
02403 (gROOT->FindObject(varName) != 0);
02404
02405
02406
02407
02408
02409 if (0) printf("varName is [%s] with iteration [%i]\n", varName, iter);
02410
02411
02412 Int_t cut = ParseReverse(varName, strlen(varName));
02413
02414
02415 if (!varName_exists && cut != 0)
02416 {
02417 TString parentName = varName;
02418 TString memberName = varName;
02419
02420
02421 if (iter > fLastIter) fLastIter = iter;
02422
02423 parentName[cut] = 0;
02424 if (0) printf("Parent string is [%s]\n", parentName.Data());
02425
02426
02427
02428 if (cut>2) {
02429 UInt_t level = 0;
02430 for(Int_t i = cut-1; i>=0; --i) {
02431 switch (parentName[i]) {
02432 case '(':
02433 if (level) --level;
02434 else {
02435 parentName = parentName(i+1,cut-i-1);
02436 i = 0;
02437 }
02438 break;
02439 case ')':
02440 ++level; break;
02441 }
02442 }
02443 }
02444
02445 TClass *pclass;
02446
02447 if (varName[cut] == '.') {
02448 memberName = varName+cut+1;
02449 if (0) printf("Member/method is [%s]\n", memberName.Data());
02450 EContext_t subcontext = kCXX_DirectMember;
02451 pclass = MakeClassFromVarName(parentName.Data(), subcontext, iter+1);
02452 } else {
02453 memberName = varName+cut+2;
02454 if (0) printf("Member/method is [%s]\n", memberName.Data());
02455 EContext_t subcontext = kCXX_IndirectMember;
02456 pclass = MakeClassFromVarName(parentName.Data(), subcontext, iter+1);
02457 }
02458
02459 if (0) printf("I got [%s] from MakeClassFromVarName()\n", pclass->GetName());
02460
02461 if (pclass)
02462 {
02463 if (0) printf("Variable [%s] exists!\n", parentName.Data());
02464
02465
02466 if (iter == 0) return pclass;
02467
02468 if (0) printf("Trying data member [%s] of class [%s] ...\n",
02469 memberName.Data(), pclass->GetName());
02470
02471
02472 TDataMember *dmptr = 0;
02473 TList *dlist = pclass->GetListOfDataMembers();
02474 TIter next(pclass->GetListOfAllPublicDataMembers());
02475 while ((dmptr = (TDataMember *) next())) {
02476 if (memberName == dmptr->GetName()) break;
02477 }
02478 delete dlist;
02479 if (dmptr)
02480 {
02481 if (0) printf("It's a member!\n");
02482
02483 TString returnName = dmptr->GetTypeName();
02484
02485
02486
02487 TClass *mclass = new TClass(returnName.Data());
02488 return mclass;
02489 }
02490
02491
02492
02493
02494 char *parentesis_ptr = (char*)strrchr(memberName.Data(), '(');
02495 if (parentesis_ptr) *parentesis_ptr = 0;
02496
02497
02498 if (0) printf("Trying method [%s] of class [%s] ...\n",
02499 memberName.Data(), pclass->GetName());
02500
02501
02502 TMethod *mptr = 0;
02503 TList *mlist = pclass->GetListOfAllPublicMethods();
02504 next = mlist;
02505 while ((mptr = (TMethod *) next())) {
02506 if (strcmp(memberName.Data(),mptr->GetName())==0) break;
02507 }
02508 delete mlist;
02509
02510 if (mptr)
02511 {
02512 TString returnName = mptr->GetReturnTypeName();
02513
02514 if (0) printf("It's a method called [%s] with return type [%s]\n",
02515 memberName.Data(), returnName.Data());
02516
02517
02518 if (returnName[returnName.Length()-1] == '*')
02519 {
02520 returnName[returnName.Length()-1] = 0;
02521 fVarIsPointer = kTRUE;
02522 }
02523 else
02524 {
02525 fVarIsPointer = kFALSE;
02526 }
02527
02528 TClass *mclass = new TClass(returnName.Data());
02529 return mclass;
02530 }
02531 }
02532 }
02533
02534
02535
02536
02537
02538
02539
02540 if (!varName_exists) {
02541 cerr << endl << "variable " << dblquote(varName) << " not defined."
02542 << endl;
02543 return 0;
02544 }
02545
02546
02547
02548
02549
02550
02551
02552
02553
02554
02555 TString className = DetermineClass(varName);
02556
02557 if (className.IsNull() || className == "*") {
02558
02559
02560
02561 cerr << endl << "problem determining class of " << dblquote(varName)
02562 << endl;
02563 return 0;
02564 }
02565
02566 fVarIsPointer = className[className.Length() - 1] == '*';
02567
02568
02569
02570 if (fVarIsPointer)
02571 className[className.Length()-1] = 0;
02572
02573
02574
02575
02576
02577
02578
02579
02580
02581
02582
02583 if (fVarIsPointer &&
02584 (context == kCXX_DirectMember || context == kCXX_DirectProto)) {
02585
02586
02587
02588
02589
02590
02591
02592 switch (context) {
02593 case kCXX_DirectMember:
02594 context = kCXX_IndirectMember;
02595 break;
02596 case kCXX_DirectProto:
02597 context = kCXX_IndirectProto;
02598 break;
02599 default:
02600 assert(0);
02601 break;
02602 }
02603
02604
02605 int i;
02606 for (i = *fpLoc; fBuf[i] != '.'; i -= 1) {
02607 }
02608 int loc = i;
02609 for (i = strlen(fBuf); i >= loc; i -= 1) {
02610 fBuf[i + 1] = fBuf[i];
02611 }
02612 fBuf[loc] = '-';
02613 fBuf[loc + 1] = '>';
02614 *fpLoc += 1;
02615
02616
02617 cerr << endl << dblquote(varName) <<
02618 " is of pointer type. Use this operator: ->" << endl;
02619 }
02620
02621 if (context == kCXX_IndirectMember || context == kCXX_IndirectProto) {
02622 if (fVarIsPointer) {
02623
02624 className.Chop();
02625
02626 if (className[className.Length() - 1] == '*') {
02627 cerr << endl << "can't handle pointers to pointers." << endl;
02628 return 0;
02629 }
02630 } else {
02631
02632
02633
02634
02635
02636
02637
02638 switch (context) {
02639 case kCXX_IndirectMember:
02640 context = kCXX_DirectMember;
02641 break;
02642 case kCXX_IndirectProto:
02643 context = kCXX_DirectProto;
02644 break;
02645 default:
02646 assert(0);
02647 break;
02648 }
02649
02650
02651 int i;
02652 for (i = *fpLoc; fBuf[i - 1] != '-' && fBuf[i] != '>'; i -= 1) {
02653 }
02654 fBuf[i - 1] = '.';
02655 int len = strlen(fBuf);
02656 for (; i < len; i += 1) {
02657 fBuf[i] = fBuf[i + 1];
02658 }
02659 *fpLoc -= 1;
02660
02661
02662 cerr << endl << dblquote(varName) <<
02663 " is not of pointer type. Use this operator: ." << endl;
02664 }
02665 }
02666
02667 return new TClass(className);
02668 }
02669
02670
02671 void TTabCom::SetPattern(EContext_t handle, const char regexp[])
02672 {
02673
02674
02675
02676 if (handle >= kNUM_PAT) {
02677 cerr << endl
02678 << "ERROR: handle="
02679 << (int) handle << " >= kNUM_PAT=" << (int) kNUM_PAT << endl;
02680 return;
02681 }
02682
02683 fRegExp[handle] = regexp;
02684 Makepat(regexp, fPat[handle], MAX_LEN_PAT);
02685 }
02686
02687
02688
02689
02690 int TTabCom::ParseReverse(const char *var_str, int start)
02691 {
02692
02693
02694
02695
02696 int end = 0;
02697 if (start > (int)strlen(var_str)) start = strlen(var_str);
02698
02699 for (int i = start; i > 0; i--)
02700 {
02701 if (var_str[i] == '.') return i;
02702 if (var_str[i] == '>' && i > 0 && var_str[i-1] == '-') return i-1;
02703 }
02704
02705 return end;
02706 }