Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TTabCom.cxx
Go to the documentation of this file.
1// @(#)root/rint:$Id$
2// Author: Christian Lacunza <lacunza@cdfsg6.lbl.gov> 27/04/99
3
4// Modified by Artur Szostak <artur@alice.phy.uct.ac.za> : 1 June 2003
5// Added support for namespaces.
6
7/*************************************************************************
8 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
9 * All rights reserved. *
10 * *
11 * For the licensing terms see $ROOTSYS/LICENSE. *
12 * For the list of contributors see $ROOTSYS/README/CREDITS. *
13 *************************************************************************/
14
15////////////////////////////////////////////////////////////////////////////
16// //
17// TTabCom //
18// //
19// This class performs basic tab completion. //
20// You should be able to hit [TAB] to complete a partially typed: //
21// //
22// username //
23// environment variable //
24// preprocessor directive //
25// pragma //
26// filename (with a context-sensitive path) //
27// public member function or data member (including base classes) //
28// global variable, function, or class name //
29// //
30// Also, something like //
31// //
32// someObject->Func([TAB] //
33// someObject.Func([TAB] //
34// someClass::Func([TAB] //
35// someClass var([TAB] //
36// new someClass([TAB] //
37// //
38// will print a list of prototypes for the indicated //
39// method or constructor. //
40// //
41// Current limitations and bugs: //
42// //
43// 1. you can only use one member access operator at a time. //
44// eg, this will work: gROOT->GetListOfG[TAB] //
45// but this will not: gROOT->GetListOfGlobals()->Conta[TAB] //
46// //
47// 2. nothing is guaranteed to work on windows //
48// (for one thing, /bin/env and /etc/passwd are hardcoded) //
49// //
50// 3. CINT shortcut #2 is deliberately not supported. //
51// (using "operator.()" instead of "operator->()") //
52// //
53// 4. most identifiers (including C++ identifiers, usernames, //
54// environment variables, etc) //
55// are restriceted to this character set: [_a-zA-Z0-9] //
56// therefore, you won't be able to complete things like //
57// //
58// operator new //
59// operator+ //
60// etc //
61// //
62// 5. ~whatever[TAB] always tries to complete a username. //
63// use whitespace (~ whatever[TAB]) if you want to complete a global //
64// identifier. //
65// //
66// 6. CINT shortcut #3 is not supported when trying to complete //
67// the name of a global object. (it is supported when trying to //
68// complete a member of a global object) //
69// //
70// 7. the list of #pragma's is hardcoded //
71// (ie not obtained from the interpreter at runtime) //
72// ==> user-defined #pragma's will not be recognized //
73// //
74// 8. the system include directories are also hardcoded //
75// because i don't know how to get them from the interpreter. //
76// fons, maybe they should be #ifdef'd for the different sytems? //
77// //
78// 9. the TabCom.FileIgnore resource is always applied, even if you //
79// are not trying to complete a filename. //
80// //
81// 10. anything in quotes is assumed to be a filename //
82// so (among other things) you can't complete a quoted class name: //
83// eg, TClass class1( "TDict[TAB] //
84// this won't work... looks for a file in pwd starting with TDict //
85// //
86// 11. the prototypes tend to omit the word "const" a lot. //
87// this is a problem with ROOT or CINT. //
88// //
89// 12. when listing ambiguous matches, only one column is used, //
90// even if there are many completions. //
91// //
92// 13. anonymous objects are not currently identified //
93// so, for example, //
94// //
95// root> printf( TString([TAB //
96// //
97// gives an error message instead of listing TString's constructors. //
98// (this could be fixed) //
99// //
100// 14. the routine that adds the "appendage" isn't smart enough to know //
101// if it's already there: //
102// //
103// root> TCanvas::Update() //
104// press [TAB] here ^ //
105// root> TCanvas::Update()() //
106// (this could be fixed) //
107// //
108// 15. the appendage is only applied if there is exactly 1 match. //
109// eg, this //
110// //
111// root> G__at[TAB] //
112// root> G__ateval //
113// //
114// happens instead of this //
115// //
116// root> G__at[TAB] //
117// root> G__ateval( //
118// //
119// because there are several overloaded versions of G__ateval(). //
120// (this could be fixed) //
121// //
122////////////////////////////////////////////////////////////////////////////
123
124#include <cstdio>
125#include <cassert>
126#include <set>
127
128#include "RConfigure.h"
129#include "TTabCom.h"
130#include "TClass.h"
131#include "TClassTable.h"
132#include "TDataMember.h"
133#include "TSystem.h"
134#include "TROOT.h"
135#include "TMethod.h"
136#include "TEnv.h"
137#include "TBenchmark.h"
138#include "TError.h"
139#include "TGlobal.h"
140#include "TList.h"
141#include "THashList.h"
142#include "TObjString.h"
143#include "Getline.h"
144#include "TFunction.h"
145#include "TMethodArg.h"
146#include "TInterpreter.h"
147#include "Riostream.h"
148#include "Rstrstream.h"
149#include "strlcpy.h"
150
151#define BUF_SIZE 1024 // must be smaller than/equal to fgLineBufSize in Getline.cxx and
152 // lineBufSize in cppcompleter.py
153#define IfDebug(x) if(gDebug==TTabCom::kDebug) x
154
155#ifdef R__WIN32
156const char kDelim = ';';
157#else
158const char kDelim = ':';
159#endif
160
161
162// ----------------------------------------------------------------------------
163//
164// global/file scope variables
165//
166TTabCom *gTabCom = nullptr;
167
168// ----------------------------------------------------------------------------
169//
170// constructors
171//
172
173////////////////////////////////////////////////////////////////////////////////
174/// Default constructor.
175
177 fpClasses(nullptr),
178 fPrevInterpMarker(0),
179 fpDirectives(nullptr),
180 fpEnvVars(nullptr),
181 fpFiles(nullptr),
182 fpGlobals(nullptr),
183 fpPragmas(nullptr),
184 fpSysIncFiles(nullptr),
185 fpUsers(nullptr),
186 fBuf(nullptr),
187 fpLoc(nullptr),
188 fVarIsPointer(kFALSE),
189 fLastIter(0)
190{
191 InitPatterns();
192}
193
194//
195// constructors
196//
197// ----------------------------------------------------------------------------
198
200{
201 // Destructor.
202
203 ClearAll();
204 ClearSysIncFiles(); // this one stays cached
205 ClearUsers(); // this one stays cached
206}
207
208// ----------------------------------------------------------------------------
209//
210// public member functions
211//
212
213
214////////////////////////////////////////////////////////////////////////////////
215/// Clear classes and namespace collections.
216
218{
219 if (fpClasses) {
220 delete fpClasses;
221 fpClasses = nullptr;
222 }
223
224}
225
226////////////////////////////////////////////////////////////////////////////////
227/// Forget all Cpp directives seen so far.
228
230{
231 if (!fpDirectives)
232 return;
233 fpDirectives->Delete(nullptr);
234 delete fpDirectives;
235 fpDirectives = nullptr;
236}
237
238////////////////////////////////////////////////////////////////////////////////
239/// Forget all environment variables seen so far.
240
242{
243 if (!fpEnvVars)
244 return;
245 fpEnvVars->Delete(nullptr);
246 delete fpEnvVars;
247 fpEnvVars = nullptr;
248}
249
250////////////////////////////////////////////////////////////////////////////////
251/// Close all files.
252
254{
255 if (!fpFiles)
256 return;
257 fpFiles->Delete(nullptr);
258 delete fpFiles;
259 fpFiles = nullptr;
260}
261
262////////////////////////////////////////////////////////////////////////////////
263/// Forget all global functions seen so far.
264/// Not needed anymore. Use gROOT->GetListOfGlobalFunctions()
265
269
270////////////////////////////////////////////////////////////////////////////////
271/// Forget all global variables seen so far.
272/// With teh new implamentation the list is gROOT->GetListOfGlobals(true).
273
275{
276}
277
278////////////////////////////////////////////////////////////////////////////////
279/// Forget all pragmas seen so far.
280
282{
283 if (!fpPragmas)
284 return;
285 fpPragmas->Delete(nullptr);
286 delete fpPragmas;
287 fpPragmas = nullptr;
288}
289
290////////////////////////////////////////////////////////////////////////////////
291/// Close system files.
292
294{
295 if (!fpSysIncFiles)
296 return;
297 fpSysIncFiles->Delete(nullptr);
298 delete fpSysIncFiles;
299 fpSysIncFiles = nullptr;
300}
301
302////////////////////////////////////////////////////////////////////////////////
303/// Forget all user seen so far.
304
306{
307 if (!fpUsers)
308 return;
309 fpUsers->Delete(nullptr);
310 delete fpUsers;
311 fpUsers = nullptr;
312}
313
314////////////////////////////////////////////////////////////////////////////////
315/// clears all lists
316/// except for user names and system include files.
317
319{
320 ClearClasses();
322 ClearEnvVars();
323 ClearFiles();
325 ClearGlobals();
326 ClearPragmas();
327// ClearSysIncFiles(); <-- this one stays cached
328// ClearUsers(); <-- this one stays cached
329}
330
331////////////////////////////////////////////////////////////////////////////////
332/// Do the class rehash.
333
339
340////////////////////////////////////////////////////////////////////////////////
341/// Cpp rehashing.
342
348
349////////////////////////////////////////////////////////////////////////////////
350/// Environemnt variables rehashing.
351
357
358////////////////////////////////////////////////////////////////////////////////
359/// Close files.
360
362{
363 ClearFiles(); /* path unknown */
364} // think about this
365
366////////////////////////////////////////////////////////////////////////////////
367/// Reload global functions.
368
373
374////////////////////////////////////////////////////////////////////////////////
375/// Reload globals.
376
382
383////////////////////////////////////////////////////////////////////////////////
384/// Reload pragmas.
385
391
392////////////////////////////////////////////////////////////////////////////////
393/// Reload system include files.
394
400
401////////////////////////////////////////////////////////////////////////////////
402/// Reload users.
403
405{
406 ClearUsers();
408}
409
410////////////////////////////////////////////////////////////////////////////////
411/// clears and then rebuilds all lists
412/// except for user names and system include files.
413
415{
419 RehashFiles();
423// RehashSysIncFiles(); <-- this one stays cached
424// RehashUsers(); <-- this one stays cached
425}
426
427////////////////////////////////////////////////////////////////////////////////
428/// Return the list of classes.
429
431{
432 if (!fpClasses) {
433 fpClasses = new THashList;
434 // Iterate over the table from the map file.
435 THashList* entries = gInterpreter->GetMapfile()->GetTable();
436 TIter next(entries);
437 while (const auto key = next()) {
438 // This is not needed with the new rootmap format
439 const char* className = key->GetName();
440 if (!strncmp(className, "Library.", 8))
441 className += 8;
442
443 if (!strstr(className, ".h"))
444 fpClasses->Add(new TObjString(className));
445 }
446
447 // We might have autoload entries that don't have a rootmap entry
448 // (libCore) and no interpreter info (not yet loaded).
449 TClassTable::Init(); // reset counter
450 while (const char* className = TClassTable::Next()) {
451 if (!fpClasses->FindObject(className)) {
452 fpClasses->Add(new TObjString(className));
453 }
454 }
455
456 // Add possible identifiers coming from the global module index.
457 // FIXME: Consolidate all this -- we have ultimate source of information
458 // clang's identifier table and the ASTIndentifiers.
459 gInterpreter->AddAvailableIndentifiers(*fpClasses);
460 }
461
462 if (fPrevInterpMarker != gInterpreter->GetInterpreterStateMarker()) {
463 ClassInfo_t* ci = gInterpreter->ClassInfo_Factory(kFALSE /*all*/);
464 while (gInterpreter->ClassInfo_Next(ci)) {
465 const char* className = gInterpreter->ClassInfo_FullName(ci);
466 if (strstr(className, "(anonymous)") || strstr(className, "(unnamed)"))
467 continue;
468 if (!fpClasses->FindObject(className)) {
469 fpClasses->Add(new TObjString(className));
470 }
471 }
472 gInterpreter->ClassInfo_Delete(ci);
473 }
474
475 return fpClasses;
476}
477
478////////////////////////////////////////////////////////////////////////////////
479/// Return the list of CPP directives.
480
482{
483 if (!fpDirectives) {
485
486 fpDirectives->Add(new TObjString("if"));
487 fpDirectives->Add(new TObjString("ifdef"));
488 fpDirectives->Add(new TObjString("ifndef"));
489 fpDirectives->Add(new TObjString("elif"));
490 fpDirectives->Add(new TObjString("else"));
491 fpDirectives->Add(new TObjString("endif"));
492 fpDirectives->Add(new TObjString("include"));
493 fpDirectives->Add(new TObjString("define"));
494 fpDirectives->Add(new TObjString("undef"));
495 fpDirectives->Add(new TObjString("line"));
496 fpDirectives->Add(new TObjString("error"));
497 fpDirectives->Add(new TObjString("pragma"));
498 }
499
500 return fpDirectives;
501}
502
503////////////////////////////////////////////////////////////////////////////////
504/// "path" should be initialized with a colon separated list of
505/// system directories
506
508{
509 static TString previousPath;
510
511 if (path && fpFiles && strcmp(path, previousPath) == 0) {
512 return fpFiles;
513 } else {
514 ClearFiles();
515
517 previousPath = path;
518 }
519
520 return fpFiles;
521}
522
523////////////////////////////////////////////////////////////////////////////////
524/// Uses "env" (Unix) or "set" (Windows) to get list of environment variables.
525
527{
528 if (!fpEnvVars) {
529 TString outf = ".TTabCom-";
531 if (!fout) return nullptr;
532 fclose(fout);
533 TString cmd;
534
535#ifndef WIN32
536 char *env = gSystem->Which(gSystem->Getenv("PATH"), "env", kExecutePermission);
537 if (!env)
538 return nullptr;
539 cmd = env;
540 cmd += " > ";
541 delete [] env;
542#else
543 cmd = "set > ";
544#endif
545 cmd += outf;
546 cmd += "\n";
547 gSystem->Exec(cmd.Data());
548
549 // open the file
550 std::ifstream file1(outf);
551 if (!file1) {
552 Error("TTabCom::GetListOfEnvVars", "could not open file \"%s\"",
553 outf.Data());
555 return nullptr;
556 }
557 // parse, add
558 fpEnvVars = new TContainer;
560 while (file1) // i think this loop goes one time extra which
561 // results in an empty string in the list, but i don't think it causes any
562 // problems.
563 {
564 line.ReadToDelim(file1, '=');
565 file1.ignore(32000, '\n');
566 fpEnvVars->Add(new TObjString(line.Data()));
567 }
568
569 file1.close();
571 }
572
573 return fpEnvVars;
574}
575
576////////////////////////////////////////////////////////////////////////////////
577/// Return the list of globals.
578
580{
581 return (TSeqCollection*)gROOT->GetListOfGlobals(true);
582}
583
584////////////////////////////////////////////////////////////////////////////////
585/// Return the list of global functions.
586
588{
589 return gROOT->GetListOfGlobalFunctions(true);
590}
591
592////////////////////////////////////////////////////////////////////////////////
593/// Return the list of pragmas
594
596{
597 if (!fpPragmas) {
598 fpPragmas = new TContainer;
599
600 fpPragmas->Add(new TObjString("ANSI "));
601 fpPragmas->Add(new TObjString("autocompile "));
602 fpPragmas->Add(new TObjString("bytecode "));
603 fpPragmas->Add(new TObjString("compile "));
604 fpPragmas->Add(new TObjString("endbytecode "));
605 fpPragmas->Add(new TObjString("endcompile "));
606 fpPragmas->Add(new TObjString("include "));
607 fpPragmas->Add(new TObjString("includepath "));
608 fpPragmas->Add(new TObjString("K&R "));
609 fpPragmas->Add(new TObjString("link "));
610 fpPragmas->Add(new TObjString("preprocess "));
611 fpPragmas->Add(new TObjString("preprocessor "));
612 fpPragmas->Add(new TObjString("security level"));
613 // "setertti " omitted. Ordinary user should not use this statement
614 // "setstdio " omitted. Ordinary user should not use this statement
615 // "setstream " omitted. Ordinary user should not use this statement
616 // "stub" omitted. Ordinary user should not use this statement
617
618 }
619
620 return fpPragmas;
621}
622
623////////////////////////////////////////////////////////////////////////////////
624/// Return the list of system include files.
625
634
635////////////////////////////////////////////////////////////////////////////////
636/// reads from "/etc/passwd"
637
639{
640 if (!fpUsers) {
641 fpUsers = new TContainer;
642
643 std::ifstream passwd;
644 TString user;
645
646 passwd.open("/etc/passwd");
647 while (passwd) {
648 user.ReadToDelim(passwd, ':');
649 fpUsers->Add(new TObjString(user));
650 passwd.ignore(32000, '\n');
651 }
652 passwd.close();
653 }
654
655 return fpUsers;
656}
657
658//
659// public member functions
660//
661// ----------------------------------------------------------------------------
662
663// ----------------------------------------------------------------------------
664//
665// static utility functions
666//
667
668////////////////////////////////////////////////////////////////////////////////
669///[static utility function]///////////////////////////////////////////
670///
671/// if all the strings in "*pList" have the same ith character,
672/// that character is returned.
673/// otherwise 0 is returned.
674///
675/// any string "s" for which "ExcludedByFignore(s)" is true
676/// will be ignored unless All the strings in "*pList"
677/// are "ExcludedByFignore()"
678///
679/// in addition, the number of strings which were not
680/// "ExcludedByFignore()" is returned in "nGoodStrings".
681///
682//////////////////////////////////////////////////////////////////////////
683
686{
687 assert(pList != nullptr);
688
689 TIter next(pList);
690 TObject *pObj;
691 const char *s = "";
692 char ch0;
695
696 // init
697 nGoodStrings = 0;
699
700 // first look for a good string
701 do {
702 if ((pObj = next())) {
703 s = pObj->GetName();
705 if (isGood) {
707 nGoodStrings += 1;
708 }
709 } else {
710 // reached end of list without finding a single good string.
711 // just use the first one.
712 next.Reset();
713 pObj = next();
714 if (pObj) s = pObj->GetName();
715 break;
716 }
717 }
718 while (!isGood);
719
720 // found a good string...
721 ch0 = s[i];
722
723 // all subsequent good strings must have the same ith char
724 do {
725 if ((pObj = next())) {
726 s = pObj->GetName();
728 if (isGood)
729 nGoodStrings += 1;
730 } else
731 return ch0;
732 }
733 while (((int) strlen(s) >= i && s[i] == ch0) ||
735
736 return 0;
737}
738
739////////////////////////////////////////////////////////////////////////////////
740///[static utility function]/////////////////////////////
741///
742/// adds a TObjString to "*pList"
743/// for each entry found in the system directory "dirName"
744///
745/// directories that do not exist are silently ignored.
746///
747///////////////////////////////////////////////////////////
748
751{
752 assert(dirName != nullptr);
753 assert(pList != nullptr);
754
755 // open the directory
756 void *dir = gSystem->OpenDirectory(dirName);
757
758 // it is normal for this function to receive names of directories that do not exist.
759 // they should be ignored and should not generate any error messages.
760 if (!dir)
761 return;
762
763 // put each filename in the list
764 const char *tmp_ptr; // gSystem->GetDirEntry() returns 0 when no more files.
765 TString fileName;
766
767 while ((tmp_ptr = gSystem->GetDirEntry(dir))) {
768 fileName = tmp_ptr;
769
770 // skip "." and ".."
771 if (fileName == "." || fileName == "..")
772 continue;
773
774 // add to list
775 pList->Add(new TObjString(dirName + fileName.Prepend("/")));
776 }
777 // NOTE:
778 // with a path like "/usr/include:/usr/include/CC:$ROOTDIR/include:$ROOTDIR/cint/include:..."
779 // the above loop could get traversed 700 times or more.
780 // ==> keep it minimal or it could cost whole seconds on slower machines.
781 // also: TClonesArray doesn't help.
782
783 // close the directory
785}
786
787// -----\/-------- homemade RTTI ---------------\/------------------------
788////////////////////////////////////////////////////////////////////////////////
789///[static utility function]/////////////////////////////
790///
791/// returns empty string on failure.
792/// otherwise returns something like this: "TROOT*".
793/// fails for non-class types (ie, int, char, etc).
794/// fails for pointers to functions.
795///
796////////////////////////////////////
797
799{
800
801 ///////////////////////////////////
802 //
803 // note that because of the strange way this function works,
804 // CINT will print
805 //
806 // Error: No symbol asdf in current scope FILE:/var/tmp/gaaa001HR LINE:1
807 //
808 // if "varName" is not defined. (in this case, varName=="asdf")
809 // i don't know how to suppress this.
810 //
811 ///////////////////////////////////
812
813 assert(varName != nullptr);
814 IfDebug(std::cerr << "DetermineClass(\"" << varName << "\");" << std::endl);
815
816 // @todo This is a long ugly workaround, replace with access via gInterpreter
817 TString outf = ".TTabCom-";
819 if (!fout) return "";
820 fclose(fout);
821
822 TString cmd(".> ");
823 cmd += outf;
824 //redirect
825 gROOT->ProcessLineSync(cmd.Data());
826
827 cmd = "gROOT->ProcessLine(\"";
828 cmd += varName;
829 cmd += "\");";
830 cmd += "\n";
831 gROOT->ProcessLineSync(cmd.Data());
832 // the type of the variable whose name is "varName"
833 // should now be stored on disk in the file "tmpfile"
834
835 gROOT->ProcessLineSync(".>");
836
837 TString type = "";
838 int c;
839
840 // open the file
841 std::ifstream file1(outf);
842 if (!file1) {
843 Error("TTabCom::DetermineClass", "could not open file \"%s\"",
844 outf.Data());
845 goto cleanup;
846 }
847 // first char should be '(', which we can ignore.
848 c = file1.get();
849 if (!file1 || c <= 0 || c != '(') {
850 Error("TTabCom::DetermineClass", "variable \"%s\" not defined?",
851 varName);
852 goto cleanup;
853 }
854 IfDebug(std::cerr << (char) c << std::flush);
855
856 // in case of success, "class TClassName*)0x12345" remains or TClassName 0x[0-9][a-f]+
857 // in case of objects
858 // since the opening '(' was removed.
859
860 if (type == "const" || type == "class") {
861 file1 >> type;
862 // ignore ' '
863 c = file1.get();
864 IfDebug(std::cerr << (char) c << std::flush);
865 }
866
867 // this is what we want
868 type.ReadToDelim(file1, ')');
869 IfDebug(std::cerr << type << std::endl);
870
871 // new version of Cling returns: "qualifiers TClassName *const) 0x12345"
872 // we start stripping off right "const"
873 if (type.EndsWith(" *const"))
874 type.Remove(type.Length() - 5);
875 // we strip off left qualifiers
876 if (type.BeginsWith("const "))
877 type.Remove(0, 6);
878 if (type.BeginsWith("volatile ")) // this automatically takes care of variant "const volatile"
879 type.Remove(0, 9);
880
881cleanup:
882 // done reading from file
883 file1.close();
885
886 return type;
887}
888
889////////////////////////////////////////////////////////////////////////////////
890///[static utility function]/////////////////////////////
891///
892/// returns true iff "s" ends with one of
893/// the strings listed in the "TabCom.FileIgnore" resource.
894///
895//////////////////////////////////////////////////////////////
896
898{
899 const char *fignore = gEnv->GetValue("TabCom.FileIgnore", (char *) nullptr);
900
901 if (!fignore) {
902 return kFALSE;
903 } else {
904#ifdef R__SSTREAM
905 std::istringstream endings((char *) fignore);
906#else
907 std::istrstream endings((char *) fignore); // do i need to make a copy first?
908#endif
909 TString ending;
910
911 ending.ReadToDelim(endings, kDelim);
912
913 while (!ending.IsNull()) {
914 if (s.EndsWith(ending))
915 return kTRUE;
916 else
917 ending.ReadToDelim(endings, kDelim); // next
918 }
919 return kFALSE;
920 }
921}
922
923////////////////////////////////////////////////////////////////////////////////
924///[static utility function]/////////////////////////////
925///
926/// returns a colon-separated string of directories
927/// that CINT will search when you call `#include<...>`
928///
929/// returns empty string on failure.
930///
931////////////////////////////////////////////////////////////
932
934{
935 // >i noticed that .include doesn't list the standard directories like
936 // >/usr/include or /usr/include/CC.
937 // >
938 // >how can i get a list of all the directories the interpreter will
939 // >search through when the user does a #include<...> ?
940 //
941 // Right now, there is no easy command to tell you about it. Instead, I can
942 // describe it here.
943 //
944 // 1) CINT first searches current working directory for #include "xxx"
945 // (#include <xxx> does not)
946 //
947 // 2) CINT searches include path directories given by -I option
948 //
949 // 3) CINT searches following standard include directories.
950 // $CINTSYSDIR/include
951 // $CINTSYSDIR/stl
952 // $CINTSYSDIR/msdev/include if VC++4.0
953 // $CINTSYSDIR/sc/include if Symantec C++
954 // /usr/include
955 // /usr/include/g++ if gcc,g++
956 // /usr/include/CC if HP-UX
957 // /usr/include/codelibs if HP-UX
958 //
959 // .include command only displays 2).
960 //
961 // Thank you
962 // Masaharu Goto
963
964 // 1) current dir
965 // ----------------------------------------------
966 // N/A
967
968
969 // 2) -I option (and #pragma includepath)
970 // ----------------------------------------------
971
972 // get this part of the include path from the interpreter
973 // and stick it in a tmp file.
974 TString outf = ".TTabCom-";
976 if (!fout) return "";
978 fclose(fout);
979
980 // open the tmp file
981 std::ifstream file1(outf);
982 if (!file1) { // error
983 Error("TTabCom::GetSysIncludePath", "could not open file \"%s\"",
984 outf.Data());
986 return "";
987 }
988 // parse it.
989 TString token; // input buffer
990 TString path; // all directories so far (colon-separated)
991 file1 >> token; // skip "include"
992 file1 >> token; // skip "path:"
993 while (file1) {
994 file1 >> token;
995 if (!token.IsNull()) {
996 if (path.Length() > 0)
997 path.Append(":");
998 path.Append(token.Data() + 2); // +2 skips "-I"
999 }
1000 }
1001
1002 // done with the tmp file
1003 file1.close();
1005
1006 // 3) standard directories
1007 // ----------------------------------------------
1008
1009#ifndef CINTINCDIR
1010 TString sCINTSYSDIR("$ROOTSYS/cint");
1011#else
1013#endif
1014 path.Append(":" + sCINTSYSDIR + "/include");
1015// path.Append(":"+CINTSYSDIR+"/stl");
1016// path.Append(":"+CINTSYSDIR+"/msdev/include");
1017// path.Append(":"+CINTSYSDIR+"/sc/include");
1018 path.Append(":/usr/include");
1019// path.Append(":/usr/include/g++");
1020// path.Append(":/usr/include/CC");
1021// path.Append(":/usr/include/codelibs");
1022
1023 return path;
1024}
1025
1026////////////////////////////////////////////////////////////////////////////////
1027///[static utility function]/////////////////////////////
1028///
1029/// calls TSystem::GetPathInfo() to see if "fileName"
1030/// is a system directory.
1031///
1032////////////////////////////////////////////////////////
1033
1034Bool_t TTabCom::IsDirectory(const char fileName[])
1035{
1036 FileStat_t stat;
1037 if (!gSystem->GetPathInfo(fileName, stat))
1038 return R_ISDIR(stat.fMode);
1039 else
1040 return false;
1041}
1042
1043////////////////////////////////////////////////////////////////////////////////
1044///[static utility function]/////////////////////////////
1045///
1046/// creates a list containing the full path name for each file
1047/// in the (colon separated) string "path1"
1048///
1049/// memory is allocated with "new", so
1050/// whoever calls this function takes responsibility for deleting it.
1051///
1052///////////////////////////////////////////////////////////////////////
1053
1055{
1056 assert(path1 != nullptr);
1057 if (!path1[0]) path1 = ".";
1058
1059 TContainer *pList = new TContainer; // maybe use RTTI here? (since its a static function)
1060#ifdef R__SSTREAM
1061 std::istringstream path((char *) path1);
1062#else
1063 std::istrstream path((char *) path1);
1064#endif
1065
1066 while (path.good())
1067 {
1069 dirName.ReadToDelim(path, kDelim);
1070 if (dirName.IsNull())
1071 continue;
1072
1073 IfDebug(std::cerr << "NewListOfFilesInPath(): dirName = " << dirName <<
1074 std::endl);
1075
1077 }
1078
1079 return pList;
1080}
1081
1082////////////////////////////////////////////////////////////////////////////////
1083///[static utility function]/////////////////////////////
1084///
1085/// true if "fileName"
1086/// 1. is an absolute path ("/tmp/a")
1087/// 2. is a relative path ("../whatever", "./test")
1088/// 3. starts with user name ("~/mail")
1089/// 4. starts with an environment variable ("$ROOTSYS/bin")
1090///
1091///////////////////////////////////////////////////////////////////////////
1092
1094{
1095 char c1 = (fileName.Length() > 0) ? fileName[0] : 0;
1096 return c1 == '/' || c1 == '~' || c1 == '$' || fileName.BeginsWith("./")
1097 || fileName.BeginsWith("../");
1098}
1099
1100////////////////////////////////////////////////////////////////////////////////
1101///[static utility function]/////////////////////////////
1102///
1103/// calling "NoMsg( errorLevel )",
1104/// sets "gErrorIgnoreLevel" to "errorLevel+1" so that
1105/// all errors with "level < errorLevel" will be ignored.
1106///
1107/// calling the function with a negative argument
1108/// (e.g., "NoMsg( -1 )")
1109/// resets gErrorIgnoreLevel to its previous value.
1110///
1111///////////////////////////////////////////////////////////////////
1112
1114{
1115 ////////////////////////////////////////////////////////////////
1116 //
1117 // if you call the function twice with a non-negative argument
1118 // (without an intervening call with a negative argument)
1119 // it will complain because it is almost certainly an error
1120 // that will cause the function to loose track of the previous
1121 // value of gErrorIgnoreLevel.
1122 //
1123 // most common causes: 1. suspiciously placed "return;" statement
1124 // 2. calling a function that calls "NoMsg()"
1125 //
1126 //////////////////////////////////////////////////////////////////
1127
1128 const Int_t kNotDefined = -2;
1129 static Int_t old_level = kNotDefined;
1130
1131 if (errorLevel < 0) // reset
1132 {
1133 if (old_level == kNotDefined) {
1134 std::cerr << "NoMsg(): ERROR 1. old_level==" << old_level << std::endl;
1135 return;
1136 }
1137
1138 gErrorIgnoreLevel = old_level; // restore
1140 } else // set
1141 {
1142 if (old_level != kNotDefined) {
1143 std::cerr << "NoMsg(): ERROR 2. old_level==" << old_level << std::endl;
1144 return;
1145 }
1146
1150 }
1151}
1152
1153//
1154// static utility functions
1155//
1156// ----------------------------------------------------------------------------
1157
1158
1159// ----------------------------------------------------------------------------
1160//
1161// private member functions
1162//
1163//
1164
1165////////////////////////////////////////////////////////////////////////////////
1166/// [private]
1167
1170 const char appendage[],
1171 std::ostream& out,
1173{
1174 // returns position of first change in buffer
1175 // ------------------------------------------
1176 // -2 ==> new line altogether (whole thing needs to be redrawn, including prompt)
1177 // -1 ==> no changes
1178 // 0 ==> beginning of line
1179 // 1 ==> after 1st char
1180 // n ==> after nth char
1181
1182 IfDebug(std::cerr << "TTabCom::Complete() ..." << std::endl);
1183 assert(fpLoc != nullptr);
1184 assert(pListOfCandidates != nullptr);
1185
1186 Int_t pos = 0; // position of first change
1187 const int loc = *fpLoc; // location where TAB was pressed
1188
1189 // -----------------------------------------
1190 //
1191 // 1. get the substring we need to complete
1192 //
1193 // NOTES:
1194 // s1 = original buffer
1195 // s2 = sub-buffer from 0 to wherever the user hit TAB
1196 // s3 = the actual text that needs completing
1197 //
1198 // -----------------------------------------
1199 TString s1(fBuf);
1200 TString s2 = s1(0, loc);
1201 TString s3 = s2(re);
1202
1203 int start = s2.Index(re);
1204
1205 IfDebug(std::cerr << " s1: " << s1 << std::endl);
1206 IfDebug(std::cerr << " s2: " << s2 << std::endl);
1207 IfDebug(std::cerr << " s3: " << s3 << std::endl);
1208 IfDebug(std::cerr << "start: " << start << std::endl);
1209 IfDebug(std::cerr << std::endl);
1210
1211 // -----------------------------------------
1212 // 2. go through each possible completion,
1213 // keeping track of the number of matches
1214 // -----------------------------------------
1215 TList listOfMatches; // list of matches (local filenames only) (insertion order must agree across these 3 lists)
1216 TList listOfFullPaths; // list of matches (full filenames) (insertion order must agree across these 3 lists)
1217 listOfMatches.SetOwner();
1218 listOfFullPaths.SetOwner();
1219
1220 int nMatches = 0; // number of matches
1221 TObject *pObj; // pointer returned by iterator
1225
1226 // stick all matches into "listOfMatches"
1227 while ((pObj = next_candidate())) {
1228 // get the full filename
1229 const char *s4 = pObj->GetName();
1230
1231 assert(s4 != nullptr);
1232
1233 // pick off tail
1234 const char *s5 = strrchr(s4, '/');
1235 if (!s5)
1236 s5 = s4; // no '/' found
1237 else
1238 s5 += 1; // advance past '/'
1239
1240 // if case sensitive (normal behaviour), check for match
1241 // if case insensitive, convert to TString and compare case insensitively
1242 if ((cmp == TString::kExact) && (strstr(s5, s3) == s5)) {
1243 nMatches += 1;
1244 listOfMatches.Add(new TObjString(s5));
1245 listOfFullPaths.Add(new TObjString(s4));
1246 IfDebug(std::cerr << "adding " << s5 << '\t' << s4 << std::endl);
1247 } else if (cmp == TString::kIgnoreCase) {
1248 TString ts5(s5);
1249 if (ts5.BeginsWith(s3, cmp))
1250 {
1251 nMatches += 1;
1252 listOfMatches.Add(new TObjString(s5));
1253 listOfFullPaths.Add(new TObjString(s4));
1254 IfDebug(std::cerr << "adding " << s5 << '\t' << s4 << std::endl);
1255 }
1256 } else {
1257//rdm IfDebug(std::cerr << "considered " << s5 << '\t' << s4 << std::endl);
1258 }
1259
1260 }
1261
1262 // -----------------------------------------
1263 // 3. beep, list, or complete
1264 // depending on how many matches were found
1265 // -----------------------------------------
1266
1267 // 3a. no matches ==> bell
1268 TString partialMatch = "";
1269
1270 if (nMatches == 0) {
1271 // Ring a bell!
1272 gSystem->Beep();
1273 pos = -1;
1274 goto done; //* RETURN *//
1275 }
1276 // 3b. one or more matches.
1277 char match[1024];
1278
1279 if (nMatches == 1) {
1280 // get the (lone) match
1281 const char *short_name = next_match()->GetName();
1282 const char *full_name = next_fullpath()->GetName();
1283
1284 pObj = pListOfCandidates->FindObject(short_name);
1285 if (pObj) {
1286 IfDebug(std::cerr << std::endl << "class: " << pObj->ClassName() << std::endl);
1287 TString className = pObj->ClassName();
1288 if (0);
1289 else if (className == "TMethod" || className == "TFunction") {
1291 if (0 == pFunc->GetNargs())
1292 appendage = "()"; // no args
1293 else
1294 appendage = "("; // user needs to supply some args
1295 } else if (className == "TDataMember") {
1296 appendage = " ";
1297 }
1298 }
1299
1300 CopyMatch(match, sizeof(match), short_name, appendage, full_name);
1301 } else {
1302 // multiple matches ==> complete as far as possible
1303 Char_t ch;
1305
1306 for (int i = 0;
1308 i += 1) {
1309 IfDebug(std::cerr << " i=" << i << " ch=" << ch << std::endl);
1310 partialMatch.Append(ch);
1311 }
1312
1313 const char *s;
1314 const char *s0;
1315
1316 // multiple matches, but maybe only 1 of them is any good.
1317 if (nGoodStrings == 1) {
1318
1319 // find the 1 good match
1320 do {
1321 s = next_match()->GetName();
1322 s0 = next_fullpath()->GetName();
1323 }
1324 while (ExcludedByFignore(s));
1325
1326 // and use it.
1327 CopyMatch(match, sizeof(match), s, appendage, s0);
1328 } else {
1329 IfDebug(std::cerr << "more than 1 GoodString" << std::endl);
1330
1331 if (partialMatch.Length() > s3.Length())
1332 // this partial match is our (partial) completion.
1333 {
1334 CopyMatch(match, sizeof(match), partialMatch.Data());
1335 } else
1336 // couldn't do any completing at all,
1337 // print a list of all the ambiguous matches
1338 // (except for those excluded by "FileIgnore")
1339 {
1340 IfDebug(std::cerr << "printing ambiguous matches" << std::endl);
1341 std::set<std::string> alreadyPrinted;
1342 while ((pObj = next_match())) {
1343 s = pObj->GetName();
1344 if (alreadyPrinted.insert(s).second) {
1345 // Nothing of that name has been printed yet.
1346 s0 = next_fullpath()->GetName();
1347 if (!ExcludedByFignore(s) || nGoodStrings == 0) {
1348 if (IsDirectory(s0))
1349 out << s << "/" << std::endl;
1350 else
1351 out << s << std::endl;
1352 }
1353 }
1354 }
1355 pos = -2;
1356 if (cmp == TString::kExact || partialMatch.Length() < s3.Length()) {
1357 goto done; //* RETURN *//
1358 } // else:
1359 // update the matching part, will have changed
1360 // capitalization because only cmp == TString::kIgnoreCase
1361 // matches.
1362 CopyMatch(match, sizeof(match), partialMatch.Data());
1363 }
1364 }
1365 }
1366
1367
1368 // ---------------------------------------
1369 // 4. finally write text into the buffer.
1370 // ---------------------------------------
1371 {
1372 const int old_len = strlen(fBuf); // old EOL position is old_len
1373 const int match_len = strlen(match);
1374 const int added_len = match_len - (loc - start); // new EOL position will be old_len+added_len
1375
1376 // first check for overflow
1377 if (old_len + added_len + 1 > BUF_SIZE || start > loc || start + match_len + 1 > BUF_SIZE) {
1378 Error("TTabCom::Complete", "buffer overflow");
1379 pos = -2;
1380 goto done; /* RETURN */
1381 }
1382 // debugging output
1383 IfDebug(std::cerr << " i=" << old_len << std::endl);
1384 IfDebug(std::cerr << " L=" << added_len << std::endl);
1385 IfDebug(std::cerr << "loc=" << loc << std::endl);
1386
1387 // slide everything (including the null terminator) over to make space
1388 for (int i = old_len; i >= loc; i -= 1) {
1389 fBuf[i + added_len] = fBuf[i];
1390 }
1391
1392 // insert match
1393 memcpy(fBuf + start, match, match_len);
1394
1395 // the "get"->"Get" case of TString::kIgnore sets pos to -2
1396 // and falls through to update the buffer; we need to return
1397 // -2 in that case, so check here:
1398 if (pos != -2) {
1399 pos = loc; // position of first change in "fBuf"
1400 if (cmp == TString::kIgnoreCase && pos < 0) {
1401 // We might have changed somthing before loc, due to differences in
1402 // capitalization. So return start:
1403 pos = start;
1404 }
1405 }
1406 *fpLoc = loc + added_len; // new cursor position
1407 }
1408
1409done: // <----- goto label
1410 // un-init
1411 fpLoc = nullptr;
1412 fBuf = nullptr;
1413
1414 return pos;
1415}
1416
1417////////////////////////////////////////////////////////////////////////////////
1418/// [private]
1419
1421 const char *localName,
1422 const char *appendage,
1423 const char *fullName) const
1424{
1425 // if "appendage" is 0, no appendage is applied.
1426 //
1427 // if "appendage" is of the form "filenameXXX" then,
1428 // "filename" is ignored and "XXX" is taken to be the appendage,
1429 // but it will only be applied if the file is not a directory...
1430 // if the file is a directory, a "/" will be used for the appendage instead.
1431 //
1432 // if "appendage" is of the form "XXX" then "XXX" will be appended to the match.
1433
1434 assert(dest != nullptr);
1435 assert(localName != nullptr);
1436
1437 // potential buffer overflow.
1439
1440 const char *key = "filename";
1441 const int key_len = strlen(key);
1442
1443 IfDebug(std::cerr << "CopyMatch()." << std::endl);
1444 IfDebug(std::cerr << "localName: " << (localName ? localName : "0") <<
1445 std::endl);
1446 IfDebug(std::cerr << "appendage: " << (appendage ? appendage : "0") <<
1447 std::endl);
1448 IfDebug(std::cerr << " fullName: " << (fullName ? fullName : "0") <<
1449 std::endl);
1450
1451
1452 // check to see if "appendage" starts with "key"
1453 if (appendage && strncmp(appendage, key, key_len) == 0) {
1454 // filenames get special treatment
1455 appendage += key_len;
1456 IfDebug(std::cerr << "new appendage: " << appendage << std::endl);
1457 if (IsDirectory(fullName)) {
1458 if (fullName)
1459 strlcat(dest, "/", dest_len);
1460 } else {
1461 if (appendage)
1463 }
1464 } else {
1465 if (appendage)
1467 }
1468}
1469
1470////////////////////////////////////////////////////////////////////////////////
1471/// [private]
1472
1474{
1475 assert(fBuf != nullptr);
1476
1477 const char *pStart; // start of match
1478 const char *pEnd; // end of match
1479
1480 for (int context = 0; context < kNUM_PAT; ++context) {
1481 pEnd = Matchs(fBuf, *fpLoc, fPat[context], &pStart);
1482 if (pEnd) {
1483 IfDebug(std::cerr << std::endl
1484 << "context=" << context << " "
1485 << "RegExp=" << fRegExp[context]
1486 << std::endl);
1487 return EContext_t(context); //* RETURN *//
1488 }
1489 }
1490
1491 return kUNKNOWN_CONTEXT; //* RETURN *//
1492}
1493
1494////////////////////////////////////////////////////////////////////////////////
1495/// [private]
1496
1498 const char defaultPath[]) const
1499{
1500 if (PathIsSpecifiedInFileName(fileName)) {
1501 TString path = fileName;
1502 gSystem->ExpandPathName(path);
1503 Int_t end = path.Length()-1;
1504 if (end>0 && path[end]!='/' && path[end]!='\\') {
1505 path = gSystem->GetDirName(path);
1506 }
1507 return path;
1508 } else {
1510 if (fileName.Contains("/")) {
1511 Int_t end = fileName.Length()-1;
1512 if (fileName[end] != '/' && fileName[end] != '\\') {
1513 newBase = gSystem->GetDirName(fileName);
1514 } else {
1515 newBase = fileName;
1516 }
1518 } else {
1519 newBase = "";
1521 }
1522 IfDebug(std::cerr << std::endl);
1523 IfDebug(std::cerr << " fileName: " << fileName << std::endl);
1524 IfDebug(std::cerr << " pathBase: " << newBase << std::endl);
1525 if (defaultPath) {
1526 IfDebug(std::cerr << " defaultPath: " << defaultPath << std::endl);
1527 } else {
1528 IfDebug(std::cerr << " defaultPath: " << std::endl);
1529 }
1530 IfDebug(std::cerr << "extendedPath: " << extendedPath << std::endl);
1531 IfDebug(std::cerr << std::endl);
1532
1533 return extendedPath;
1534 }
1535}
1536
1537////////////////////////////////////////////////////////////////////////////////
1538/// [private]
1539
1541{
1542 if (newBase.BeginsWith("/"))
1543 newBase.Remove(TString::kLeading, '/');
1544#ifdef R__SSTREAM
1545 std::stringstream str;
1546#else
1547 std::strstream str;
1548#endif
1549 TString dir;
1551 if (originalPath) str << originalPath;
1552
1553 while (str.good())
1554 {
1555 dir = "";
1556 dir.ReadToDelim(str, kDelim);
1557 if (dir.IsNull())
1558 continue; // ignore blank entries
1559 newPath.Append(dir);
1560 if (!newPath.EndsWith("/"))
1561 newPath.Append("/");
1562 newPath.Append(newBase);
1563 newPath.Append(kDelim);
1564 }
1565
1566 return newPath.Strip(TString::kTrailing, kDelim);
1567}
1568
1569////////////////////////////////////////////////////////////////////////////////
1570/// [private]
1571
1572Int_t TTabCom::Hook(char *buf, int *pLoc, std::ostream& out)
1573{
1574 // initialize
1575 fBuf = buf;
1576 fpLoc = pLoc;
1577
1578 // frodo: iteration counter for recursive MakeClassFromVarName
1579 fLastIter = 0;
1580
1581 // default
1582 Int_t pos = -2; // position of the first character that was changed in the buffer (needed for redrawing)
1583
1584 // get the context this tab was triggered in.
1585 EContext_t context = DetermineContext();
1586
1587 // get the substring that triggered this tab (as defined by "SetPattern()")
1588 const char dummy[] = ".";
1589 TRegexp re1(context == kUNKNOWN_CONTEXT ? dummy : fRegExp[context]);
1590 TString s1(fBuf);
1591 TString s2 = s1(0, *fpLoc);
1592 TString s3 = s2(re1);
1593
1594 switch (context) {
1595 case kUNKNOWN_CONTEXT:
1596 std::cerr << std::endl << "tab completion not implemented for this context" <<
1597 std::endl;
1598 pos = -2;
1599 break;
1600
1601 case kSYS_UserName:
1602 {
1604
1605 pos = Complete("[^~]*$", pListOfUsers, "/", out);
1606 }
1607 break;
1608 case kSYS_EnvVar:
1609 {
1611
1612 pos = Complete("[^$]*$", pEnv, "", out);
1613 }
1614 break;
1615
1616 case kCINT_stdout:
1617 case kCINT_stderr:
1618 case kCINT_stdin:
1619 {
1620 const TString fileName = s3("[^ ><]*$");
1621 const TString filePath = DeterminePath(fileName,nullptr);
1624
1625// pos = Complete( "[^ /]*$", pListOfFiles, " ", out );
1626 pos = Complete("[^ /]*$", pListOfFiles, "filename ", out);
1627 }
1628 break;
1629
1630 case kCINT_Edit:
1631 case kCINT_Load:
1632 case kCINT_Exec:
1633 case kCINT_EXec:
1634 {
1635 const TString fileName = s3("[^ ]*$");
1636 const TString macroPath =
1640
1641// pos = Complete( "[^ /]*$", pListOfFiles, " ", out);
1642 pos = Complete("[^ /]*$", pListOfFiles, "filename ", out);
1643 }
1644 break;
1645
1646 case kCINT_pragma:
1647 {
1648 pos = Complete("[^ ]*$", GetListOfPragmas(), "", out);
1649 }
1650 break;
1651 case kCINT_includeSYS:
1652 {
1653 TString fileName = s3("[^<]*$");
1654 if (PathIsSpecifiedInFileName(fileName) || fileName.Contains("/")) {
1656 DeterminePath(fileName, GetSysIncludePath());
1657
1658// pos = Complete( "[^</]*$", GetListOfFilesInPath( includePath ), "> ", out);
1659 pos =
1661 "filename> ", out);
1662 } else {
1663// pos = Complete( "[^</]*$", GetListOfSysIncFiles(), "> ", out);
1664 pos =
1665 Complete("[^</]*$", GetListOfSysIncFiles(), "filename> ", out);
1666 }
1667 }
1668 break;
1669 case kCINT_includePWD:
1670 {
1671 const TString fileName = s3("[^\"]*$");
1672 const TString includePath = DeterminePath(fileName, ".");
1675
1676// pos = Complete( "[^\"/]*$", pListOfFiles, "\" ", out);
1677 pos = Complete("[^\"/]*$", pListOfFiles, "filename\" ", out);
1678 }
1679 break;
1680
1681 case kCINT_cpp:
1682 {
1683 pos = Complete("[^# ]*$", GetListOfCppDirectives(), " ", out);
1684 }
1685 break;
1686
1687 case kROOT_Load:
1688 {
1689 const TString fileName = s3("[^\"]*$");
1692
1693// pos = Complete( "[^\"/]*$", pListOfFiles, "\");", out);
1694 pos = Complete("[^\"/]*$", pListOfFiles, "filename\");", out);
1695 }
1696 break;
1697
1698 case kSYS_FileName:
1699 {
1700 const TString fileName = s3("[^ \"]*$");
1701 const TString filePath = DeterminePath(fileName,".");
1703
1704 pos = Complete("[^\" /]*$", pListOfFiles, "filename\"", out);
1705 }
1706 break;
1707
1708 case kCXX_ScopeMember:
1709 {
1710 const EContext_t original_context = context; // save this for later
1711
1712 TClass *pClass;
1713 // may be a namespace, class, object, or pointer
1714 TString name = s3("^[_a-zA-Z][_a-zA-Z0-9]*");
1715
1716 IfDebug(std::cerr << std::endl);
1717 IfDebug(std::cerr << "name: " << '"' << name << '"' << std::endl);
1718
1719 // We need to decompose s3 a little more:
1720 // The part name is the partial symbol at the end of ::
1721 // eg. given s3 = "foo::bar::part" , partname = "part"
1722 TString partname = s3("[_a-zA-Z][_a-zA-Z0-9]*$");
1723
1724 // The prefix, considering the s3 = "foo::bar::part" example would be
1725 // prefix = "foo::bar::". prefix equals the empty string if there is only one
1726 // or no set of colons in s3.
1727 // Note: we reconstruct the fully qualified name with a while loop because
1728 // it does not seem that TRegexp can handle something like "([_a-zA-Z][_a-zA-Z0-9]*::)+$"
1729 TString prefix = "";
1730 TString str = s2;
1731 str.Remove(str.Length() - partname.Length(), partname.Length());
1732 while (1) {
1733 TString sym = str("[_a-zA-Z][_a-zA-Z0-9]*::$");
1734 if (sym.Length() == 0)
1735 break;
1736 str.Remove(str.Length() - sym.Length(), sym.Length());
1737 prefix = sym + prefix;
1738 }
1739
1740 // Not the preprefix would be = "foo::" from our previous example or the empty
1741 // string, "" if there is only one or no set of colons in prefix, eg. prefix = "bar::"
1742 TString preprefix = prefix;
1743 TString sym = prefix("[_a-zA-Z][_a-zA-Z0-9]*::$");
1744 preprefix.Remove(preprefix.Length() - sym.Length(), sym.Length());
1745
1746 IfDebug(std::cerr << "prefix: " << '"' << prefix << '"' << std::endl);
1747 IfDebug(std::cerr << "preprefix: " << '"' << preprefix << '"' << std::endl);
1748
1749 TString namesp = prefix;
1750 if (namesp.Length() >= 2)
1751 namesp.Remove(namesp.Length() - 2, 2); // Remove the '::' at the end of the string.
1752 IfDebug(std::cerr << "namesp: " << '"' << namesp << '"' << std::endl);
1753
1754 // Make sure autoloading happens (if it can).
1756
1758 // Add all classes to pList that contain the prefix, i.e. are in the
1759 // specified namespace.
1760 const TSeqCollection *tmp = GetListOfClasses();
1761 if (!tmp) break;
1762
1763 Int_t i;
1764 for (i = 0; i < tmp->GetSize(); i++) {
1765 TString astr = ((TObjString *) tmp->At(i))->String();
1766 TString rxp = "^";
1767 rxp += prefix;
1768 if (astr.Contains(TRegexp(rxp))) {
1769 astr.Remove(0, prefix.Length());
1770 TString s = astr("^[^: ]*");
1771 TObjString *ostr = new TObjString(s);
1772 if (!pList->Contains(ostr))
1773 pList->Add(ostr);
1774 else
1775 delete ostr;
1776 }
1777 }
1778
1779 // If a class with the same name as the Namespace name exists then
1780 // add it to the pList. (I don't think the C++ spec allows for this
1781 // but do this anyway, cant harm).
1783 if (pClass) {
1784 pList->AddAll(pClass->GetListOfAllPublicMethods(true));
1785 pList->AddAll(pClass->GetListOfAllPublicDataMembers(true));
1786 }
1787
1788 pos = Complete("[^: ]*$", pList, "", out);
1789
1790 delete pList;
1791
1792 if (context != original_context)
1793 pos = -2;
1794 }
1795 break;
1796
1797 case kCXX_DirectMember:
1799 {
1800 const EContext_t original_context = context; // save this for later
1801
1802 TClass *pClass;
1803
1804 // frodo: Instead of just passing the last portion of the string to
1805 // MakeClassFromVarName(), we now pass the all string and let
1806 // it decide how to handle it... I know it's not the best way
1807 // because of the context handling, but I wanted to "minimize"
1808 // the changes to the current code and this seemed the best way
1809 // to do it
1810 TString name = s1("[_a-zA-Z][-_a-zA-Z0-9<>():.]*$");
1811
1812 IfDebug(std::cerr << std::endl);
1813 IfDebug(std::cerr << "name: " << '"' << name << '"' << std::endl);
1814
1815 switch (context) {
1816 case kCXX_DirectMember:
1817 pClass = MakeClassFromVarName(name, context);
1818 break;
1820 pClass = MakeClassFromVarName(name, context);
1821 break;
1822 default:
1823 Fatal("TTabCom::Hook","Conext case %d not handled",context);
1824 return 0; // Avoid warning about uninitialized pClass.
1825 }
1826 if (!pClass) {
1827 pos = -2;
1828 break;
1829 }
1830
1832
1833 pList->AddAll(pClass->GetListOfAllPublicMethods());
1834 pList->AddAll(pClass->GetListOfAllPublicDataMembers());
1835
1836 switch (context) {
1837 case kCXX_DirectMember:
1838 {
1839 int* store_fpLoc = fpLoc;
1840 char* store_fBuf = fBuf;
1841 pos = Complete("[^. ]*$", pList, "(", out);
1842 if (pos == -1) {
1844 fBuf = store_fBuf;
1845 pos = Complete("[^. ]*$", pList, "(", out, TString::kIgnoreCase);
1846 }
1847 break;
1848 }
1850 pos = Complete("[^> ]*$", pList, "(", out);
1851 break;
1852 default:
1853 Fatal("TTabCom::Hook","Conext case %d not handled",context);
1854 return 0; // Avoid warning about uninitialized pClass.
1855 }
1856
1857 delete pList;
1858
1859 if (context != original_context)
1860 pos = -2;
1861 }
1862 break;
1863
1864 case kCXX_ScopeProto:
1865 {
1866 const EContext_t original_context = context; // save this for later
1867
1868 // get class
1869 TClass *pClass;
1870 TString name = s3("^[_a-zA-Z][_a-zA-Z0-9]*");
1871 // "name" may now be the name of a class, object, or pointer
1872
1873 IfDebug(std::cerr << std::endl);
1874 IfDebug(std::cerr << "name: " << '"' << name << '"' << std::endl);
1875
1876 // We need to decompose s3 a little more:
1877 // The partname is the method symbol and a bracket at the end of ::
1878 // eg. given s3 = "foo::bar::part(" , partname = "part("
1879 TString partname = s3("[_a-zA-Z][_a-zA-Z0-9]* *($");
1880
1881 // The prefix, considering the s3 = "foo::bar::part" example would be
1882 // prefix = "foo::bar::". prefix equals the empty string if there is only one
1883 // or no set of colons in s3.
1884 // Note: we reconstruct the fully qualified name with a while loop because
1885 // it does not seem that TRegexp can handle something like "([_a-zA-Z][_a-zA-Z0-9]*::)+$"
1886 TString prefix = "";
1887 TString str = s2;
1888 str.Remove(str.Length() - partname.Length(), partname.Length());
1889 while (1) {
1890 TString sym = str("[_a-zA-Z][_a-zA-Z0-9]*::$");
1891 if (sym.Length() == 0)
1892 break;
1893 str.Remove(str.Length() - sym.Length(), sym.Length());
1894 prefix = sym + prefix;
1895 }
1896
1897 // Not the preprefix would be = "foo::" from our previous example or the empty
1898 // string, "" if there is only one or no set of colons in prefix, eg. prefix = "bar::"
1899 TString preprefix = prefix;
1900 TString sym = prefix("[_a-zA-Z][_a-zA-Z0-9]*::$");
1901 preprefix.Remove(preprefix.Length() - sym.Length(), sym.Length());
1902
1903 IfDebug(std::cerr << "prefix: " << '"' << prefix << '"' << std::endl);
1904 IfDebug(std::cerr << "preprefix: " << '"' << preprefix << '"' << std::endl);
1905
1907 if (!pClass) {
1908 pos = -2;
1909 break;
1910 }
1911 // get method name
1912 TString methodName;
1913
1914 // (normal member function)
1915 methodName = s3("[^:>\\.(]*($");
1916 methodName.Chop();
1917 methodName.Remove(TString::kTrailing, ' ');
1918
1919 IfDebug(std::cerr << methodName << std::endl);
1920
1921 // get methods
1923 pList->AddAll(pClass->GetListOfAllPublicMethods());
1924
1925 // print prototypes
1929 while ((pMethod = (TMethod *) nextMethod())) {
1930 if (methodName == pMethod->GetName()) {
1931 foundOne = kTRUE;
1932 out << pMethod->GetReturnTypeName()
1933 << " " << pMethod->GetName()
1934 << pMethod->GetSignature();
1935 const char *comment = pMethod->GetCommentString();
1936 if (comment && comment[0] != '\0') {
1937 out << " \t// " << comment;
1938 }
1939 out << std::endl;
1940 }
1941 }
1942
1943 // done
1944 if (foundOne) {
1945 pos = -2;
1946 } else {
1947 gSystem->Beep();
1948 pos = -1;
1949 }
1950
1951 // cleanup
1952 delete pList;
1953
1954 if (context != original_context)
1955 pos = -2;
1956 }
1957 break;
1958
1959 case kCXX_DirectProto:
1960 case kCXX_IndirectProto:
1961 case kCXX_NewProto:
1963 {
1964 const EContext_t original_context = context; // save this for later
1965
1966 // get class
1967 TClass *pClass;
1968 TString name;
1969 if (context == kCXX_NewProto) {
1970 name = s3("[_a-zA-Z][_a-zA-Z0-9:]* *($", 3);
1971 name.Chop();
1972 name.Remove(TString::kTrailing, ' ');
1973 // "name" should now be the name of a class
1974 } else {
1975 name = s3("^[_a-zA-Z][_a-zA-Z0-9:]*");
1976 // "name" may now be the name of a class, object, or pointer
1977 }
1978 IfDebug(std::cerr << std::endl);
1979 IfDebug(std::cerr << "name: " << '"' << name << '"' << std::endl);
1980
1981 // frodo: Again, passing the all string
1982 TString namerec = s1;
1983
1984 switch (context) {
1985 case kCXX_ScopeProto:
1987 break;
1988 case kCXX_DirectProto:
1989 pClass = MakeClassFromVarName(namerec, context); // frodo
1990 break;
1991 case kCXX_IndirectProto:
1992 pClass = MakeClassFromVarName(namerec, context); // frodo
1993 break;
1994 case kCXX_NewProto:
1996 break;
1999 break;
2000 default:
2001 Fatal("TTabCom::Hook","Conext case %d not handled",context);
2002 return 0; // Avoid warning about uninitialized pClass.
2003 }
2004 if (!pClass) {
2005 pos = -2;
2006 break;
2007 }
2008 // get method name
2009 TString methodName;
2010 if (context == kCXX_ConstructorProto || context == kCXX_NewProto) {
2011 // (constructor)
2012 methodName = name("[_a-zA-Z][_a-zA-Z0-9]*$");
2013 } else {
2014 // (normal member function)
2015 methodName = s3("[^:>\\.(]*($");
2016 methodName.Chop();
2017 methodName.Remove(TString::kTrailing, ' ');
2018 }
2019 IfDebug(std::cerr << methodName << std::endl);
2020
2021 // get methods
2023 pList->AddAll(pClass->GetListOfAllPublicMethods());
2024
2025 // print prototypes
2029 while ((pMethod = (TMethod *) nextMethod())) {
2030 if (methodName == pMethod->GetName()) {
2031 foundOne = kTRUE;
2032 out << pMethod->GetReturnTypeName()
2033 << " " << pMethod->GetName()
2034 << pMethod->GetSignature();
2035 const char *comment = pMethod->GetCommentString();
2036 if (comment && comment[0] != '\0') {
2037 out << " \t// " << comment;
2038 }
2039 out << std::endl;
2040 }
2041 }
2042
2043 // done
2044 if (foundOne) {
2045 pos = -2;
2046 } else {
2047 gSystem->Beep();
2048 pos = -1;
2049 }
2050
2051 // cleanup
2052 delete pList;
2053
2054 if (context != original_context)
2055 pos = -2;
2056 }
2057 break;
2058
2059 case kCXX_Global:
2060 {
2061 // first need to veto a few possibilities.
2062 int l2 = s2.Length(), l3 = s3.Length();
2063
2064 // "abc().whatever[TAB]"
2065 if (l2 > l3 && s2[l2 - l3 - 1] == '.') {
2066 std::cerr << std::endl <<
2067 "tab completion not implemented for this context" << std::endl;
2068 break; // veto
2069 }
2070 // "abc()->whatever[TAB]"
2071 if (l2 > l3 + 1 && s2(l2 - l3 - 2, 2) == "->") {
2072 std::cerr << std::endl <<
2073 "tab completion not implemented for this context" << std::endl;
2074 break; // veto
2075 }
2076
2078
2080 if (pL2) pList->AddAll(pL2);
2081
2082 //
2084 if (pC1) pList->AddAll(pC1);
2085 //
2087 if (pC3) pList->AddAll(pC3);
2088
2089 pos = Complete("[_a-zA-Z][_a-zA-Z0-9]*$", pList, "", out);
2090
2091 delete pList;
2092 }
2093 break;
2094
2095 case kCXX_GlobalProto:
2096 {
2097 // get function name
2098 TString functionName = s3("[_a-zA-Z][_a-zA-Z0-9]*");
2099 IfDebug(std::cerr << functionName << std::endl);
2100
2103 TObject *pObj;
2104 while ((pObj = nextGlobalFunc())) {
2105 if (strcmp(pObj->GetName(), functionName) == 0) {
2107 }
2108 }
2109
2110 if (listOfMatchingGlobalFuncs.IsEmpty()) {
2111 std::cerr << std::endl << "no such function: " << dblquote(functionName)
2112 << std::endl;
2113 } else {
2116 while ((pFunction = (TFunction *) next())) {
2117 out << pFunction->GetReturnTypeName()
2118 << " " << pFunction->GetName()
2119 << pFunction->GetSignature()
2120 << std::endl;
2121 }
2122 }
2123
2124 pos = -2;
2125 }
2126 break;
2127
2128 /******************************************************************/
2129 /* */
2130 /* default: should never happen */
2131 /* */
2132 /******************************************************************/
2133 default:
2134 Fatal("TTabCom::Hook","Conext case %d not handled",context);
2135 return 0; // Avoid warning about uninitialized pClass.
2136 }
2137
2138 return pos;
2139}
2140
2141////////////////////////////////////////////////////////////////////////////////
2142/// [private]
2143
2145{
2146 // add more patterns somewhere below.
2147 // add corresponding enum to "EContext_t"
2148 //
2149 // note:
2150 // 1. in some cases order is important ...
2151 //
2152 // the order of the "case" statements in "switch( context )" in "TTabCom::Hook()" is Not important.
2153 //
2154 // the order of the "SetPattern()" function calls below is Not important.
2155 //
2156 // the order of the initializers in the "EContext_t" enumeration Is important
2157 // because DetermineContext() goes through the array in order, and returns at the first match.
2158 //
2159 // 2. below, "$" will match cursor position
2160
2161 SetPattern(kSYS_UserName, "~[_a-zA-Z0-9]*$");
2162 SetPattern(kSYS_EnvVar, "$[_a-zA-Z0-9]*$");
2163
2164 SetPattern(kCINT_stdout, "; *>>?.*$"); // stdout
2165 SetPattern(kCINT_stderr, "; *2>>?.*$"); // stderr
2166 SetPattern(kCINT_stdin, "; *<.*$"); // stdin
2167
2168 SetPattern(kCINT_Edit, "^ *\\.E .*$");
2169 SetPattern(kCINT_Load, "^ *\\.L .*$");
2170 SetPattern(kCINT_Exec, "^ *\\.x +[-0-9_a-zA-Z~$./]*$");
2171 SetPattern(kCINT_EXec, "^ *\\.X +[-0-9_a-zA-Z~$./]*$");
2172
2173 SetPattern(kCINT_pragma, "^# *pragma +[_a-zA-Z0-9]*$");
2174 SetPattern(kCINT_includeSYS, "^# *include *<[^>]*$"); // system files
2175 SetPattern(kCINT_includePWD, "^# *include *\"[^\"]*$"); // local files
2176
2177 SetPattern(kCINT_cpp, "^# *[_a-zA-Z0-9]*$");
2178
2179 SetPattern(kROOT_Load, "gSystem *-> *Load *( *\"[^\"]*$");
2180
2181 SetPattern(kCXX_NewProto, "new +[_a-zA-Z][_a-zA-Z0-9:]* *($");
2183 "[_a-zA-Z][_a-zA-Z0-9:]* +[_a-zA-Z][_a-zA-Z0-9]* *($");
2185 "[_a-zA-Z][_a-zA-Z0-9]* *:: *[_a-zA-Z0-9]* *($");
2187 "[_a-zA-Z][_a-zA-Z0-9()]* *\\. *[_a-zA-Z0-9]* *($");
2189 "[_a-zA-Z][_a-zA-Z0-9()]* *-> *[_a-zA-Z0-9]* *($");
2190
2192 "[_a-zA-Z][_a-zA-Z0-9]* *:: *[_a-zA-Z0-9]*$");
2194 "[_a-zA-Z][_a-zA-Z0-9()]* *\\. *[_a-zA-Z0-9()]*$"); //
2195
2197 "[_a-zA-Z][_a-zA-Z0-9()]* *-> *[_a-zA-Z0-9()]*$"); // frodo
2198
2199 SetPattern(kSYS_FileName, "\"[-0-9_a-zA-Z~$./]*$");
2200 SetPattern(kCXX_Global, "[_a-zA-Z][_a-zA-Z0-9]*$");
2201 SetPattern(kCXX_GlobalProto, "[_a-zA-Z][_a-zA-Z0-9]* *($");
2202}
2203
2204////////////////////////////////////////////////////////////////////////////////
2205/// [private]
2206/// (does some specific error handling that makes the function unsuitable for general use.)
2207/// returns a new'd TClass given the name of a class.
2208/// user must delete.
2209/// returns 0 in case of error.
2210
2211TClass *TTabCom::MakeClassFromClassName(const char className[]) const
2212{
2213 // the TClass constructor will print a Warning message for classes that don't exist
2214 // so, ignore warnings temporarily.
2215 NoMsg(kWarning);
2216 TClass *pClass = TClass::GetClass(className);
2217 NoMsg(-1);
2218
2219 if (!pClass){
2220 Error("TTabCom::MakeClassFromClassName", "Unknown class \"%s\"", className);
2221 return nullptr;
2222 }
2223
2224 // make sure "className" exists
2225 // if (pClass->Size() == 0) { //namespace has 0 size
2226 if (pClass->GetListOfAllPublicMethods()->GetSize() == 0 &&
2227 pClass->GetListOfAllPublicDataMembers()->GetSize() == 0) {
2228 // i'm assuming this happens iff there was some error.
2229 // (misspelled the class name, for example)
2230 Error("TTabCom::MakeClassFromClassName", "class \"%s\" is not defined.", className);
2231 return nullptr;
2232 }
2233
2234 return pClass;
2235}
2236
2237////////////////////////////////////////////////////////////////////////////////
2238/// Same as above but does not print the error message.
2239
2240TClass *TTabCom::TryMakeClassFromClassName(const char className[]) const
2241{
2242 // the TClass constructor will print a Warning message for classes that don't exist
2243 // so, ignore warnings temporarily.
2244 NoMsg(kWarning);
2245 TClass *pClass = TClass::GetClass(className);
2246 NoMsg(-1);
2247
2248 return pClass;
2249}
2250
2251////////////////////////////////////////////////////////////////////////////////
2252/// [private]
2253/// (does some specific error handling that makes the function unsuitable for general use.)
2254/// returns a new'd TClass given the name of a variable.
2255/// user must delete.
2256/// returns 0 in case of error.
2257/// if user has operator.() or operator->() backwards, will modify: context, *fpLoc and fBuf.
2258/// context sensitive behavior.
2259
2261 EContext_t & context, int iter)
2262{
2263 // frodo:
2264 // Because of the Member and Proto recursion, this has become a bit
2265 // complicated, so here is how it works:
2266 //
2267 // root [1] var.a.b.c[TAB]
2268 //
2269 // will generate the sucessive calls:
2270 // MakeClassFromVarName("var.a.b.c", context, 0) returns the class of "c"
2271 // MakeClassFromVarName("var.a.b", context, 1) returns the class of "b"
2272 // MakeClassFromVarName("var.a", context, 2) returns the class of "a"
2273 // MakeClassFromVarName("var", context, 3)
2274
2275 // need to make sure "varName" exists
2276 // because "DetermineClass()" prints clumsy error message otherwise.
2277 Bool_t varName_exists = GetListOfGlobals()->Contains(varName) || // check in list of globals first.
2278 (gROOT->FindObject(varName) != nullptr); // then check CINT "shortcut #3"
2279
2280
2281 //
2282 // frodo: Member and Proto recursion code
2283 //
2284 if (0) printf("varName is [%s] with iteration [%i]\n", varName, iter);
2285
2286 // ParseReverse will return 0 if there are no "." or "->" in the varName
2288
2289 // If it's not a "simple" variable and if there is at least one "." or "->"
2290 if (!varName_exists && cut != 0)
2291 {
2294
2295 // Check to see if this is the last call (last member/method)
2296 if (iter > fLastIter) fLastIter = iter;
2297
2298 parentName[cut] = 0;
2299 if (0) printf("Parent string is [%s]\n", parentName.Data());
2300
2301 // We are treating here cases like h->SetXTitle(gROOT->Get<TAB>
2302 // i.e. when the parentName has an unbalanced number of paranthesis.
2303 if (cut>2) {
2304 UInt_t level = 0;
2305 for(Int_t i = cut-1; i>=0; --i) {
2306 switch (parentName[i]) {
2307 case '(':
2308 if (level) --level;
2309 else {
2310 parentName = parentName(i+1,cut-i-1);
2311 i = 0;
2312 }
2313 break;
2314 case ')':
2315 ++level; break;
2316 }
2317 }
2318 }
2319
2320 TClass *pclass;
2321 // Can be "." or "->"
2322 if (varName[cut] == '.') {
2323 memberName = varName+cut+1;
2324 if (0) printf("Member/method is [%s]\n", memberName.Data());
2327 } else {
2328 memberName = varName+cut+2;
2329 if (0) printf("Member/method is [%s]\n", memberName.Data());
2332 }
2333
2334 if (0) printf("I got [%s] from MakeClassFromVarName()\n", pclass->GetName());
2335
2336 if (pclass)
2337 {
2338 if (0) printf("Variable [%s] exists!\n", parentName.Data());
2339
2340 // If it's back in the first call of the function, return immediatly
2341 if (iter == 0) return pclass;
2342
2343 if (0) printf("Trying data member [%s] of class [%s] ...\n",
2344 memberName.Data(), pclass->GetName());
2345
2346 // Check if it's a member
2347 TDataMember *dmptr = nullptr; //pclass->GetDataMember(memberName.Data());
2348 TIter next(pclass->GetListOfAllPublicDataMembers());
2349 while ((dmptr = (TDataMember *) next())) {
2350 if (memberName == dmptr->GetName()) break;
2351 }
2352 if (dmptr)
2353 {
2354 if (0) printf("It's a member!\n");
2355
2356 TString returnName = dmptr->GetTypeName();
2357 // if (returnName[returnName.Length()-1] == '*')
2358 // printf("It's a pointer!\n");
2359
2360 TClass *mclass = TClass::GetClass(returnName.Data());
2361 return mclass;
2362 }
2363
2364
2365 // Check if it's a proto: must have ()
2366 // This might not be too safe to use :(
2367 char *parentesis_ptr = (char*)strrchr(memberName.Data(), '(');
2369
2370
2371 if (0) printf("Trying method [%s] of class [%s] ...\n",
2372 memberName.Data(), pclass->GetName());
2373
2374 // Check if it's a method
2375 TMethod *mptr = nullptr; // pclass->GetMethodAny(memberName.Data());
2376 const TList *mlist = pclass->GetListOfAllPublicMethods();
2377 next = mlist;
2378 while ((mptr = (TMethod *) next())) {
2379 if (strcmp(memberName.Data(),mptr->GetName())==0) break;
2380 }
2381 if (mptr)
2382 {
2383 TString returnName = mptr->GetReturnTypeName();
2384
2385 if (0) printf("It's a method called [%s] with return type [%s]\n",
2386 memberName.Data(), returnName.Data());
2387
2388 // This will handle the methods that returns a pointer to a class
2389 if (returnName[returnName.Length()-1] == '*')
2390 {
2391 returnName[returnName.Length()-1] = 0;
2393 }
2394 else
2395 {
2397 }
2398
2399 TClass *mclass = TClass::GetClass(returnName.Data());
2400 return mclass;
2401 }
2402 }
2403 }
2404
2405 //
2406 // frodo: End of Member and Proto recursion code
2407 //
2408
2409
2410 // not found...
2411 if (!varName_exists) {
2412 std::cerr << std::endl << "variable " << dblquote(varName) << " not defined."
2413 << std::endl;
2414 return nullptr; //* RETURN *//
2415 }
2416
2417 /*****************************************************************************************/
2418 /* */
2419 /* this section is really ugly. */
2420 /* and slow. */
2421 /* it could be made a lot better if there was some way to tell whether or not a given */
2422 /* variable is a pointer or a pointer to a pointer. */
2423 /* */
2424 /*****************************************************************************************/
2425
2426 TString className = DetermineClass(varName);
2427
2428 if (className.IsNull() || className == "*") {
2429 // this will happen if "varName" is a fundamental type (as opposed to class type).
2430 // or a pointer to a pointer.
2431 // or a function pointer.
2432 std::cerr << std::endl << "problem determining class of " << dblquote(varName)
2433 << std::endl;
2434 return nullptr; //* RETURN *//
2435 }
2436
2437 fVarIsPointer = className[className.Length() - 1] == '*';
2438
2439 // frodo: I shouldn't have to do this, but for some reason now I have to
2440 // otherwise the varptr->[TAB] won't work :(
2441 if (fVarIsPointer || className[className.Length() - 1] == '&')
2442 className[className.Length()-1] = 0;
2443
2444 // frodo case '.' dealt with in the previous if statement?!
2445 // frodo: I wasn't able to put the automatic "." to "->" replacing working
2446 // so I just commented out.
2447 //
2448
2449
2450 // Bool_t varIsPointer = className[className.Length() - 1] == '*';
2451
2452 //printf("Context is %i, fContext is %i, pointer is %i\n", context, fContext, fVarIsPointer);
2453
2454 if (fVarIsPointer &&
2455 (context == kCXX_DirectMember || context == kCXX_DirectProto)) {
2456 // user is using operator.() instead of operator->()
2457 // ==>
2458 // 1. we are in wrong context.
2459 // 2. user is lazy
2460 // 3. or maybe confused
2461
2462 // 1. fix the context
2463 switch (context) {
2464 case kCXX_DirectMember:
2465 context = kCXX_IndirectMember;
2466 break;
2467 case kCXX_DirectProto:
2468 context = kCXX_IndirectProto;
2469 break;
2470 default:
2471 Fatal("TTabCom::MakeClassFromVarName","Conext case %d not handled",context);
2472 return nullptr; // Avoid warning about uninitialized pClass.
2473 }
2474
2475 // 2. fix the operator.
2476 int i;
2477 for (i = *fpLoc; fBuf[i] != '.'; i -= 1) {
2478 }
2479 int loc = i;
2480 for (i = strlen(fBuf); i >= loc; i -= 1) {
2481 fBuf[i + 1] = fBuf[i];
2482 }
2483 fBuf[loc] = '-';
2484 fBuf[loc + 1] = '>';
2485 *fpLoc += 1;
2486
2487 // 3. inform the user.
2488 std::cerr << std::endl << dblquote(varName) <<
2489 " is of pointer type. Use this operator: ->" << std::endl;
2490 return nullptr;
2491 }
2492
2493 if (context == kCXX_IndirectMember || context == kCXX_IndirectProto) {
2494 if (fVarIsPointer) {
2495 // frodo: This part no longer makes sense...
2496 className.Chop(); // remove the '*'
2497
2498 if (className[className.Length() - 1] == '*') {
2499 std::cerr << std::endl << "can't handle pointers to pointers." << std::endl;
2500 return nullptr; // RETURN
2501 }
2502 } else {
2503 // user is using operator->() instead of operator.()
2504 // ==>
2505 // 1. we are in wrong context.
2506 // 2. user is lazy
2507 // 3. or maybe confused
2508
2509 // 1. fix the context
2510 switch (context) {
2512 context = kCXX_DirectMember;
2513 break;
2514 case kCXX_IndirectProto:
2515 context = kCXX_DirectProto;
2516 break;
2517 default:
2518 Fatal("TTabCom::MakeClassFromVarName","Conext case %d not handled",context);
2519 return nullptr; // Avoid warning about uninitialized pClass.
2520 }
2521
2522 // 2. fix the operator.
2523 int i;
2524 for (i = *fpLoc; fBuf[i - 1] != '-' && fBuf[i] != '>'; i -= 1) {
2525 }
2526 fBuf[i - 1] = '.';
2527 int len = strlen(fBuf);
2528 for (; i < len; i += 1) {
2529 fBuf[i] = fBuf[i + 1];
2530 }
2531 *fpLoc -= 1;
2532
2533 // 3. inform the user.
2534 std::cerr << std::endl << dblquote(varName) <<
2535 " is not of pointer type. Use this operator: ." << std::endl;
2536 return nullptr;
2537 }
2538 }
2539
2540 className.Strip(TString::kBoth);
2541
2542 return TClass::GetClass(className);
2543}
2544
2545////////////////////////////////////////////////////////////////////////////////
2546/// [private]
2547
2548void TTabCom::SetPattern(EContext_t handle, const char regexp[])
2549{
2550 // prevent overflow
2551 if (handle >= kNUM_PAT) {
2552 std::cerr << std::endl
2553 << "ERROR: handle="
2554 << (int) handle << " >= kNUM_PAT=" << (int) kNUM_PAT << std::endl;
2555 return;
2556 }
2557
2558 fRegExp[handle] = regexp;
2559 Makepat(regexp, fPat[handle], MAX_LEN_PAT);
2560}
2561
2562
2563
2564////////////////////////////////////////////////////////////////////////////////
2565///
2566/// Returns the place in the string where to put the \0, starting the search
2567/// from "start"
2568///
2569
2570int TTabCom::ParseReverse(const char *var_str, int start)
2571{
2572 int end = 0;
2573 if (start > (int)strlen(var_str)) start = strlen(var_str);
2574
2575 for (int i = start; i > 0; i--)
2576 {
2577 if (var_str[i] == '.') return i;
2578 if (var_str[i] == '>' && i > 0 && var_str[i-1] == '-') return i-1;
2579 }
2580
2581 return end;
2582}
int Makepat(const char *, Pattern_t *, int)
Make a pattern template from the string pointed to by exp.
Definition Match.cxx:129
const char * Matchs(const char *, size_t len, const Pattern_t *, const char **)
Match a string with a pattern.
Definition Match.cxx:220
#define c(i)
Definition RSha256.hxx:101
#define s0(x)
Definition RSha256.hxx:90
#define s1(x)
Definition RSha256.hxx:91
char Char_t
Character 1 byte (char)
Definition RtypesCore.h:51
constexpr Bool_t kFALSE
Definition RtypesCore.h:108
constexpr Bool_t kTRUE
Definition RtypesCore.h:107
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
R__EXTERN TEnv * gEnv
Definition TEnv.h:170
constexpr Int_t kWarning
Definition TError.h:46
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition TError.cxx:208
Int_t gErrorIgnoreLevel
errors with level below this value will be ignored. Default is kUnset.
Definition TError.cxx:33
void Fatal(const char *location, const char *msgfmt,...)
Use this function in case of a fatal error. It will abort the program.
Definition TError.cxx:267
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t dest
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t UChar_t len
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
char name[80]
Definition TGX11.cxx:110
R__EXTERN TInterpreter * gCling
#define gInterpreter
#define gROOT
Definition TROOT.h:411
@ kExecutePermission
Definition TSystem.h:53
Bool_t R_ISDIR(Int_t mode)
Definition TSystem.h:123
R__EXTERN TSystem * gSystem
Definition TSystem.h:572
#define BUF_SIZE
Definition TTabCom.cxx:151
TTabCom * gTabCom
Definition TTabCom.cxx:166
#define IfDebug(x)
Definition TTabCom.cxx:153
const char kDelim
Definition TTabCom.cxx:158
#define dblquote(x)
Definition TTabCom.h:43
#define MAX_LEN_PAT
Definition TTabCom.h:42
static char * Next()
Returns next class from sorted class table.
static void Init()
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:84
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:2973
Collection abstract base class.
Definition TCollection.h:65
TObject * FindObject(const char *name) const override
Find an object in this collection using its name.
void Delete(Option_t *option="") override=0
Delete this object.
All ROOT classes may have RTTI (run time type identification) support added.
Definition TDataMember.h:31
virtual Int_t GetValue(const char *name, Int_t dflt) const
Returns the integer value for a resource.
Definition TEnv.cxx:490
Global functions class (global functions are obtained from CINT).
Definition TFunction.h:30
THashList implements a hybrid collection class consisting of a hash table and a list to store TObject...
Definition THashList.h:34
virtual int DisplayIncludePath(FILE *) const
void Reset()
A doubly linked list.
Definition TList.h:38
Each ROOT class (see TClass) has a linked list of methods.
Definition TMethod.h:38
Collectable string class.
Definition TObjString.h:28
Mother of all ROOT objects.
Definition TObject.h:41
static const char * GetMacroPath()
Get macro search path. Static utility function.
Definition TROOT.cxx:2764
Regular expression class.
Definition TRegexp.h:31
Sequenceable collection abstract base class.
void Add(TObject *obj) override
Basic string class.
Definition TString.h:138
Ssiz_t Length() const
Definition TString.h:425
std::istream & ReadToDelim(std::istream &str, char delim='\n')
Read up to an EOF, or a delimiting character, whichever comes first.
Definition Stringio.cxx:95
Bool_t EndsWith(const char *pat, ECaseCompare cmp=kExact) const
Return true if string ends with the specified string.
Definition TString.cxx:2250
TSubString Strip(EStripType s=kTrailing, char c=' ') const
Return a substring of self stripped at beginning and/or end.
Definition TString.cxx:1170
TString & Chop()
Definition TString.h:699
@ kLeading
Definition TString.h:284
@ kTrailing
Definition TString.h:284
@ kBoth
Definition TString.h:284
ECaseCompare
Definition TString.h:285
@ kIgnoreCase
Definition TString.h:285
@ kExact
Definition TString.h:285
Bool_t BeginsWith(const char *s, ECaseCompare cmp=kExact) const
Definition TString.h:631
TString & Prepend(const char *cs)
Definition TString.h:681
Bool_t IsNull() const
Definition TString.h:422
TString & Remove(Ssiz_t pos)
Definition TString.h:693
TString & Append(const char *cs)
Definition TString.h:580
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:640
virtual FILE * TempFileName(TString &base, const char *dir=nullptr, const char *suffix=nullptr)
Create a secure temporary file by appending a unique 6 letter string to base.
Definition TSystem.cxx:1510
void Beep(Int_t freq=-1, Int_t duration=-1, Bool_t setDefault=kFALSE)
Beep for duration milliseconds with a tone of frequency freq.
Definition TSystem.cxx:322
virtual Bool_t ExpandPathName(TString &path)
Expand a pathname getting rid of special shell characters like ~.
Definition TSystem.cxx:1285
virtual void FreeDirectory(void *dirp)
Free a directory.
Definition TSystem.cxx:855
virtual void * OpenDirectory(const char *name)
Open a directory.
Definition TSystem.cxx:846
virtual const char * Getenv(const char *env)
Get environment variable.
Definition TSystem.cxx:1676
virtual Int_t Exec(const char *shellcmd)
Execute a command.
Definition TSystem.cxx:651
int GetPathInfo(const char *path, Long_t *id, Long_t *size, Long_t *flags, Long_t *modtime)
Get info about a file: id, size, flags, modification time.
Definition TSystem.cxx:1409
virtual const char * GetDirEntry(void *dirp)
Get a directory entry. Returns 0 if no more entries.
Definition TSystem.cxx:863
virtual const char * GetDynamicPath()
Return the dynamic path (used to find shared libraries).
Definition TSystem.cxx:1806
virtual char * Which(const char *search, const char *file, EAccessMode mode=kFileExists)
Find location of file in a search path.
Definition TSystem.cxx:1559
virtual TString GetDirName(const char *pathname)
Return the directory name in pathname.
Definition TSystem.cxx:1042
virtual int Unlink(const char *name)
Unlink, i.e.
Definition TSystem.cxx:1392
static void NoMsg(Int_t errorLevel)
[static utility function]/////////////////////////////
Definition TTabCom.cxx:1113
const TSeqCollection * GetListOfCppDirectives()
Return the list of CPP directives.
Definition TTabCom.cxx:481
Int_t Hook(char *buf, int *pLoc, std::ostream &out)
[private]
Definition TTabCom.cxx:1572
ULong64_t fPrevInterpMarker
Definition TTabCom.h:209
void ClearFiles()
Close all files.
Definition TTabCom.cxx:253
static TString DetermineClass(const char varName[])
[static utility function]/////////////////////////////
Definition TTabCom.cxx:798
static Bool_t ExcludedByFignore(TString s)
[static utility function]/////////////////////////////
Definition TTabCom.cxx:897
void InitPatterns()
[private]
Definition TTabCom.cxx:2144
void CopyMatch(char *dest, int dest_len, const char *localName, const char *appendage=nullptr, const char *fullName=nullptr) const
[private]
Definition TTabCom.cxx:1420
void RehashEnvVars()
Environemnt variables rehashing.
Definition TTabCom.cxx:352
const TSeqCollection * GetListOfSysIncFiles()
Return the list of system include files.
Definition TTabCom.cxx:626
void ClearAll()
clears all lists except for user names and system include files.
Definition TTabCom.cxx:318
TSeqCollection * fpDirectives
Definition TTabCom.h:210
const TSeqCollection * GetListOfFilesInPath(const char path[])
"path" should be initialized with a colon separated list of system directories
Definition TTabCom.cxx:507
TSeqCollection * fpClasses
Definition TTabCom.h:208
TSeqCollection * fpEnvVars
Definition TTabCom.h:211
void ClearSysIncFiles()
Close system files.
Definition TTabCom.cxx:293
const TSeqCollection * GetListOfEnvVars()
Uses "env" (Unix) or "set" (Windows) to get list of environment variables.
Definition TTabCom.cxx:526
int * fpLoc
Definition TTabCom.h:219
TString DeterminePath(const TString &fileName, const char defaultPath[]) const
[private]
Definition TTabCom.cxx:1497
const TSeqCollection * GetListOfPragmas()
Return the list of pragmas.
Definition TTabCom.cxx:595
char * fBuf
Definition TTabCom.h:218
static TSeqCollection * NewListOfFilesInPath(const char path[])
[static utility function]/////////////////////////////
Definition TTabCom.cxx:1054
TClass * MakeClassFromVarName(const char varName[], EContext_t &context, int iter=0)
[private] (does some specific error handling that makes the function unsuitable for general use....
Definition TTabCom.cxx:2260
Int_t fLastIter
Definition TTabCom.h:224
const TSeqCollection * GetListOfGlobals()
Return the list of globals.
Definition TTabCom.cxx:579
void SetPattern(EContext_t handle, const char regexp[])
[private]
Definition TTabCom.cxx:2548
TSeqCollection * fpUsers
Definition TTabCom.h:216
TSeqCollection * fpSysIncFiles
Definition TTabCom.h:215
TSeqCollection * fpFiles
Definition TTabCom.h:212
void RehashGlobals()
Reload globals.
Definition TTabCom.cxx:377
TClass * MakeClassFromClassName(const char className[]) const
[private] (does some specific error handling that makes the function unsuitable for general use....
Definition TTabCom.cxx:2211
void RehashGlobalFunctions()
Reload global functions.
Definition TTabCom.cxx:369
void ClearGlobalFunctions()
Forget all global functions seen so far.
Definition TTabCom.cxx:266
void ClearPragmas()
Forget all pragmas seen so far.
Definition TTabCom.cxx:281
static Bool_t PathIsSpecifiedInFileName(const TString &fileName)
[static utility function]/////////////////////////////
Definition TTabCom.cxx:1093
TString ExtendPath(const char originalPath[], TString newBase) const
[private]
Definition TTabCom.cxx:1540
TTabCom()
Default constructor.
Definition TTabCom.cxx:176
void RehashPragmas()
Reload pragmas.
Definition TTabCom.cxx:386
const TSeqCollection * GetListOfClasses()
Return the list of classes.
Definition TTabCom.cxx:430
void RehashCppDirectives()
Cpp rehashing.
Definition TTabCom.cxx:343
void RehashUsers()
Reload users.
Definition TTabCom.cxx:404
const TSeqCollection * GetListOfUsers()
reads from "/etc/passwd"
Definition TTabCom.cxx:638
static void AppendListOfFilesInDirectory(const char dirName[], TSeqCollection *pList)
[static utility function]/////////////////////////////
Definition TTabCom.cxx:749
void ClearClasses()
Clear classes and namespace collections.
Definition TTabCom.cxx:217
TSeqCollection * fpPragmas
Definition TTabCom.h:214
@ kCXX_Global
Definition TTabCom.h:181
@ kSYS_UserName
Definition TTabCom.h:121
@ kNUM_PAT
Definition TTabCom.h:186
@ kUNKNOWN_CONTEXT
Definition TTabCom.h:114
@ kCXX_IndirectProto
Definition TTabCom.h:171
@ kCXX_IndirectMember
Definition TTabCom.h:177
@ kCINT_Exec
Definition TTabCom.h:134
@ kCXX_ScopeProto
Definition TTabCom.h:169
@ kCINT_cpp
Definition TTabCom.h:147
@ kSYS_EnvVar
Definition TTabCom.h:122
@ kCXX_ScopeMember
Definition TTabCom.h:175
@ kCXX_GlobalProto
Definition TTabCom.h:182
@ kSYS_FileName
Definition TTabCom.h:164
@ kCXX_DirectMember
Definition TTabCom.h:176
@ kCINT_includeSYS
Definition TTabCom.h:139
@ kCINT_Load
Definition TTabCom.h:133
@ kCXX_ConstructorProto
Definition TTabCom.h:168
@ kCINT_pragma
Definition TTabCom.h:138
@ kCINT_includePWD
Definition TTabCom.h:140
@ kCXX_DirectProto
Definition TTabCom.h:170
@ kCINT_Edit
Definition TTabCom.h:132
@ kCXX_NewProto
Definition TTabCom.h:167
@ kCINT_stdin
Definition TTabCom.h:127
@ kROOT_Load
Definition TTabCom.h:151
@ kCINT_stdout
Definition TTabCom.h:125
@ kCINT_stderr
Definition TTabCom.h:126
@ kCINT_EXec
Definition TTabCom.h:135
Int_t Complete(const TRegexp &re, const TSeqCollection *pListOfCandidates, const char appendage[], std::ostream &out, TString::ECaseCompare cmp=TString::kExact)
[private]
Definition TTabCom.cxx:1168
const char * fRegExp[kNUM_PAT]
Definition TTabCom.h:222
int ParseReverse(const char *var_str, int start)
Returns the place in the string where to put the \0, starting the search from "start".
Definition TTabCom.cxx:2570
virtual ~TTabCom()
Definition TTabCom.cxx:199
TCollection * GetListOfGlobalFunctions()
Return the list of global functions.
Definition TTabCom.cxx:587
void RehashSysIncFiles()
Reload system include files.
Definition TTabCom.cxx:395
static Bool_t IsDirectory(const char fileName[])
[static utility function]/////////////////////////////
Definition TTabCom.cxx:1034
EContext_t DetermineContext() const
[private]
Definition TTabCom.cxx:1473
static TString GetSysIncludePath()
[static utility function]/////////////////////////////
Definition TTabCom.cxx:933
void ClearEnvVars()
Forget all environment variables seen so far.
Definition TTabCom.cxx:241
void ClearCppDirectives()
Forget all Cpp directives seen so far.
Definition TTabCom.cxx:229
void ClearGlobals()
Forget all global variables seen so far.
Definition TTabCom.cxx:274
void ClearUsers()
Forget all user seen so far.
Definition TTabCom.cxx:305
TList TContainer
Definition TTabCom.h:59
void RehashAll()
clears and then rebuilds all lists except for user names and system include files.
Definition TTabCom.cxx:414
void RehashFiles()
Close files.
Definition TTabCom.cxx:361
TClass * TryMakeClassFromClassName(const char className[]) const
Same as above but does not print the error message.
Definition TTabCom.cxx:2240
Pattern_t fPat[kNUM_PAT][1024]
Definition TTabCom.h:221
void RehashClasses()
Do the class rehash.
Definition TTabCom.cxx:334
static Char_t AllAgreeOnChar(int i, const TSeqCollection *pList, Int_t &nGoodStrings)
[static utility function]///////////////////////////////////////////
Definition TTabCom.cxx:684
Bool_t fVarIsPointer
Definition TTabCom.h:223
TLine * line
return c1
Definition legend1.C:41
Int_t fMode
Definition TSystem.h:135