Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TRint.cxx
Go to the documentation of this file.
1 // @(#)root/rint:$Id$
2 // Author: Rene Brun 17/02/95
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 //////////////////////////////////////////////////////////////////////////
13 // //
14 // Rint //
15 // //
16 // Rint is the ROOT Interactive Interface. It allows interactive access //
17 // to the ROOT system via the Cling C/C++ interpreter. //
18 // //
19 //////////////////////////////////////////////////////////////////////////
20 
21 #include "TROOT.h"
22 #include "TClass.h"
23 #include "TClassEdit.h"
24 #include "TVirtualX.h"
25 #include "TStyle.h"
26 #include "TObjectTable.h"
27 #include "TClassTable.h"
28 #include "TStopwatch.h"
29 #include "TBenchmark.h"
30 #include "TRint.h"
31 #include "TSystem.h"
32 #include "TEnv.h"
33 #include "TSysEvtHandler.h"
34 #include "TSystemDirectory.h"
35 #include "TError.h"
36 #include "TException.h"
37 #include "TInterpreter.h"
38 #include "TObjArray.h"
39 #include "TObjString.h"
40 #include "TStorage.h" // ROOT::Internal::gMmallocDesc
41 #include "TTabCom.h"
42 #include "TError.h"
43 #include <stdlib.h>
44 #include <algorithm>
45 
46 #include "Getline.h"
47 
48 #ifdef R__UNIX
49 #include <signal.h>
50 #endif
51 
52 ////////////////////////////////////////////////////////////////////////////////
53 
54 static Int_t Key_Pressed(Int_t key)
55 {
56  gApplication->KeyPressed(key);
57  return 0;
58 }
59 
60 ////////////////////////////////////////////////////////////////////////////////
61 
62 static Int_t BeepHook()
63 {
64  if (!gSystem) return 0;
65  gSystem->Beep();
66  return 1;
67 }
68 
69 ////////////////////////////////////////////////////////////////////////////////
70 /// Restore terminal to non-raw mode.
71 
72 static void ResetTermAtExit()
73 {
74  Getlinem(kCleanUp, 0);
75 }
76 
77 
78 //----- Interrupt signal handler -----------------------------------------------
79 ////////////////////////////////////////////////////////////////////////////////
80 
81 class TInterruptHandler : public TSignalHandler {
82 public:
83  TInterruptHandler() : TSignalHandler(kSigInterrupt, kFALSE) { }
84  Bool_t Notify();
85 };
86 
87 ////////////////////////////////////////////////////////////////////////////////
88 /// TRint interrupt handler.
89 
90 Bool_t TInterruptHandler::Notify()
91 {
92  if (fDelay) {
93  fDelay++;
94  return kTRUE;
95  }
96 
97  // make sure we use the sbrk heap (in case of mapped files)
98  ROOT::Internal::gMmallocDesc = 0;
99 
100  if (TROOT::Initialized() && gROOT->IsLineProcessing()) {
101  Break("TInterruptHandler::Notify", "keyboard interrupt");
102  Getlinem(kInit, "Root > ");
103  gCling->Reset();
104 #ifndef WIN32
105  if (gException)
106  Throw(GetSignal());
107 #endif
108  } else {
109  // Reset input.
110  Getlinem(kClear, ((TRint*)gApplication)->GetPrompt());
111  }
112 
113  return kTRUE;
114 }
115 
116 //----- Terminal Input file handler --------------------------------------------
117 ////////////////////////////////////////////////////////////////////////////////
118 
119 class TTermInputHandler : public TFileHandler {
120 public:
121  TTermInputHandler(Int_t fd) : TFileHandler(fd, 1) { }
122  Bool_t Notify();
123  Bool_t ReadNotify() { return Notify(); }
124 };
125 
126 ////////////////////////////////////////////////////////////////////////////////
127 /// Notify implementation. Call the application interupt handler.
128 
129 Bool_t TTermInputHandler::Notify()
130 {
131  return gApplication->HandleTermInput();
132 }
133 
134 
135 ClassImp(TRint);
136 
137 ////////////////////////////////////////////////////////////////////////////////
138 /// Create an application environment. The TRint environment provides an
139 /// interface to the WM manager functionality and eventloop via inheritance
140 /// of TApplication and in addition provides interactive access to
141 /// the Cling C++ interpreter via the command line.
142 
143 TRint::TRint(const char *appClassName, Int_t *argc, char **argv, void *options,
144  Int_t numOptions, Bool_t noLogo):
145  TApplication(appClassName, argc, argv, options, numOptions),
146  fCaughtSignal(-1)
147 {
148  fNcmd = 0;
149  fDefaultPrompt = "root [%d] ";
150  fInterrupt = kFALSE;
151 
152  gBenchmark = new TBenchmark();
153 
154  if (!noLogo && !NoLogoOpt()) {
155  Bool_t lite = (Bool_t) gEnv->GetValue("Rint.WelcomeLite", 0);
156  PrintLogo(lite);
157  }
158 
159  // Explicitly load libMathCore it cannot be auto-loaded it when using one
160  // of its freestanding functions. Once functions can trigger autoloading we
161  // can get rid of this.
162  if (!gClassTable->GetDict("TRandom"))
163  gSystem->Load("libMathCore");
164 
165  if (!gInterpreter->HasPCMForLibrary("std")) {
166  // Load some frequently used includes
167  Int_t includes = gEnv->GetValue("Rint.Includes", 1);
168  // When the interactive ROOT starts, it can automatically load some frequently
169  // used includes. However, this introduces several overheads
170  // -The initialisation takes more time
171  // -Memory overhead when including <vector>
172  // In $ROOTSYS/etc/system.rootrc, you can set the variable Rint.Includes to 0
173  // to disable the loading of these includes at startup.
174  // You can set the variable to 1 (default) to load only <iostream>, <string> and <DllImport.h>
175  // You can set it to 2 to load in addition <vector> and <utility>
176  // We strongly recommend setting the variable to 2 if your scripts include <vector>
177  // and you execute your scripts multiple times.
178  if (includes > 0) {
179  TString code;
180  code = "#include <iostream>\n"
181  "#include <string>\n" // for std::string std::iostream.
182  "#include <DllImport.h>\n";// Defined R__EXTERN
183  if (includes > 1) {
184  code += "#include <vector>\n"
185  "#include <utility>";
186  }
187  ProcessLine(code, kTRUE);
188  }
189  }
190 
191  // Load user functions
192  const char *logon;
193  logon = gEnv->GetValue("Rint.Load", (char*)0);
194  if (logon) {
195  char *mac = gSystem->Which(TROOT::GetMacroPath(), logon, kReadPermission);
196  if (mac)
197  ProcessLine(Form(".L %s",logon), kTRUE);
198  delete [] mac;
199  }
200 
201  // Execute logon macro
202  ExecLogon();
203 
204  // Save current interpreter context
205  gCling->SaveContext();
206  gCling->SaveGlobalsContext();
207 
208  // Install interrupt and terminal input handlers
209  TInterruptHandler *ih = new TInterruptHandler();
210  ih->Add();
211  SetSignalHandler(ih);
212 
213  // Handle stdin events
214  fInputHandler = new TTermInputHandler(0);
215  fInputHandler->Add();
216 
217  // Goto into raw terminal input mode
218  char defhist[kMAXPATHLEN];
219  snprintf(defhist, sizeof(defhist), "%s/.root_hist", gSystem->HomeDirectory());
220  logon = gEnv->GetValue("Rint.History", defhist);
221  // In the code we had HistorySize and HistorySave, in the rootrc and doc
222  // we have HistSize and HistSave. Keep the doc as it is and check
223  // now also for HistSize and HistSave in case the user did not use
224  // the History versions
225  int hist_size = gEnv->GetValue("Rint.HistorySize", 500);
226  if (hist_size == 500)
227  hist_size = gEnv->GetValue("Rint.HistSize", 500);
228  int hist_save = gEnv->GetValue("Rint.HistorySave", 400);
229  if (hist_save == 400)
230  hist_save = gEnv->GetValue("Rint.HistSave", 400);
231  const char *envHist = gSystem->Getenv("ROOT_HIST");
232  if (envHist) {
233  hist_size = atoi(envHist);
234  envHist = strchr(envHist, ':');
235  if (envHist)
236  hist_save = atoi(envHist+1);
237  }
238  Gl_histsize(hist_size, hist_save);
239  Gl_histinit((char *)logon);
240 
241  // black on white or white on black?
242  static const char* defaultColorsBW[] = {
243  "bold blue", "magenta", "bold green", "bold red underlined", "default"
244  };
245  static const char* defaultColorsWB[] = {
246  "yellow", "magenta", "bold green", "bold red underlined", "default"
247  };
248 
249  const char** defaultColors = defaultColorsBW;
250  TString revColor = gEnv->GetValue("Rint.ReverseColor", "no");
251  if (revColor.Contains("yes", TString::kIgnoreCase)) {
252  defaultColors = defaultColorsWB;
253  }
254  TString colorType = gEnv->GetValue("Rint.TypeColor", defaultColors[0]);
255  TString colorTabCom = gEnv->GetValue("Rint.TabComColor", defaultColors[1]);
256  TString colorBracket = gEnv->GetValue("Rint.BracketColor", defaultColors[2]);
257  TString colorBadBracket = gEnv->GetValue("Rint.BadBracketColor", defaultColors[3]);
258  TString colorPrompt = gEnv->GetValue("Rint.PromptColor", defaultColors[4]);
259  Gl_setColors(colorType, colorTabCom, colorBracket, colorBadBracket, colorPrompt);
260 
261  Gl_windowchanged();
262 
263  atexit(ResetTermAtExit);
264 
265  // Setup for tab completion
266  gTabCom = new TTabCom;
267  Gl_in_key = &Key_Pressed;
268  Gl_beep_hook = &BeepHook;
269 
270  // tell Cling to use our getline
271  gCling->SetGetline(Getline, Gl_histadd);
272 }
273 
274 ////////////////////////////////////////////////////////////////////////////////
275 /// Destructor.
276 
277 TRint::~TRint()
278 {
279  delete gTabCom;
280  gTabCom = 0;
281  Gl_in_key = 0;
282  Gl_beep_hook = 0;
283  fInputHandler->Remove();
284  delete fInputHandler;
285  // We can't know where the signal handler was changed since we started ...
286  // so for now let's not delete it.
287 // TSignalHandler *ih = GetSignalHandler();
288 // ih->Remove();
289 // SetSignalHandler(0);
290 // delete ih;
291 }
292 
293 ////////////////////////////////////////////////////////////////////////////////
294 /// Execute logon macro's. There are three levels of logon macros that
295 /// will be executed: the system logon etc/system.rootlogon.C, the global
296 /// user logon ~/.rootlogon.C and the local ./.rootlogon.C. For backward
297 /// compatibility also the logon macro as specified by the Rint.Logon
298 /// environment setting, by default ./rootlogon.C, will be executed.
299 /// No logon macros will be executed when the system is started with
300 /// the -n option.
301 
302 void TRint::ExecLogon()
303 {
304  if (NoLogOpt()) return;
305 
306  TString name = ".rootlogon.C";
307  TString sname = "system";
308  sname += name;
309  char *s = gSystem->ConcatFileName(TROOT::GetEtcDir(), sname);
310  if (!gSystem->AccessPathName(s, kReadPermission)) {
311  ProcessFile(s);
312  }
313  delete [] s;
314  s = gSystem->ConcatFileName(gSystem->HomeDirectory(), name);
315  if (!gSystem->AccessPathName(s, kReadPermission)) {
316  ProcessFile(s);
317  }
318  delete [] s;
319  // avoid executing ~/.rootlogon.C twice
320  if (strcmp(gSystem->HomeDirectory(), gSystem->WorkingDirectory())) {
321  if (!gSystem->AccessPathName(name, kReadPermission))
322  ProcessFile(name);
323  }
324 
325  // execute also the logon macro specified by "Rint.Logon"
326  const char *logon = gEnv->GetValue("Rint.Logon", (char*)0);
327  if (logon) {
328  char *mac = gSystem->Which(TROOT::GetMacroPath(), logon, kReadPermission);
329  if (mac)
330  ProcessFile(logon);
331  delete [] mac;
332  }
333 }
334 
335 ////////////////////////////////////////////////////////////////////////////////
336 /// Main application eventloop. First process files given on the command
337 /// line and then go into the main application event loop, unless the -q
338 /// command line option was specified in which case the program terminates.
339 /// When return is true this method returns even when -q was specified.
340 ///
341 /// When QuitOpt is true and return is false, terminate the application with
342 /// an error code equal to either the ProcessLine error (if any) or the
343 /// return value of the command casted to a long.
344 
345 void TRint::Run(Bool_t retrn)
346 {
347  if (!QuitOpt()) {
348  // Promt prompt only if we are expecting / allowing input.
349  Getlinem(kInit, GetPrompt());
350  }
351 
352  Long_t retval = 0;
353  Int_t error = 0;
354  volatile Bool_t needGetlinemInit = kFALSE;
355 
356  if (strlen(WorkingDirectory())) {
357  // if directory specified as argument make it the working directory
358  gSystem->ChangeDirectory(WorkingDirectory());
359  TSystemDirectory *workdir = new TSystemDirectory("workdir", gSystem->WorkingDirectory());
360  TObject *w = gROOT->GetListOfBrowsables()->FindObject("workdir");
361  TObjLink *lnk = gROOT->GetListOfBrowsables()->FirstLink();
362  while (lnk) {
363  if (lnk->GetObject() == w) {
364  lnk->SetObject(workdir);
365  lnk->SetOption(gSystem->WorkingDirectory());
366  break;
367  }
368  lnk = lnk->Next();
369  }
370  delete w;
371  }
372 
373  // Process shell command line input files
374  if (InputFiles()) {
375  // Make sure that calls into the event loop
376  // ignore end-of-file on the terminal.
377  fInputHandler->DeActivate();
378  TIter next(InputFiles());
379  RETRY {
380  retval = 0; error = 0;
381  Int_t nfile = 0;
382  while (TObject *fileObj = next()) {
383  if (dynamic_cast<TNamed*>(fileObj)) {
384  // A file that TApplication did not find. Note the error.
385  retval = 1;
386  continue;
387  }
388  TObjString *file = (TObjString *)fileObj;
389  char cmd[kMAXPATHLEN+50];
390  if (!fNcmd)
391  printf("\n");
392  Bool_t rootfile = kFALSE;
393 
394  if (file->TestBit(kExpression)) {
395  snprintf(cmd, kMAXPATHLEN+50, "%s", (const char*)file->String());
396  } else {
397  if (file->String().EndsWith(".root") || file->String().BeginsWith("file:")) {
398  rootfile = kTRUE;
399  } else {
400  rootfile = gROOT->IsRootFile(file->String());
401  }
402  if (rootfile) {
403  // special trick to be able to open files using UNC path names
404  if (file->String().BeginsWith("\\\\"))
405  file->String().Prepend("\\\\");
406  file->String().ReplaceAll("\\","/");
407  const char *rfile = (const char*)file->String();
408  Printf("Attaching file %s as _file%d...", rfile, nfile);
409  snprintf(cmd, kMAXPATHLEN+50, "TFile *_file%d = TFile::Open(\"%s\")", nfile++, rfile);
410  } else {
411  Printf("Processing %s...", (const char*)file->String());
412  snprintf(cmd, kMAXPATHLEN+50, ".x %s", (const char*)file->String());
413  }
414  }
415  Getlinem(kCleanUp, 0);
416  Gl_histadd(cmd);
417  fNcmd++;
418 
419  // The ProcessLine might throw an 'exception'. In this case,
420  // GetLinem(kInit,"Root >") is called and we are jump back
421  // to RETRY ... and we have to avoid the Getlinem(kInit, GetPrompt());
422  needGetlinemInit = kFALSE;
423  retval = ProcessLineNr("ROOT_cli_", cmd, &error);
424  gCling->EndOfLineAction();
425 
426  // The ProcessLine has successfully completed and we need
427  // to call Getlinem(kInit, GetPrompt());
428  needGetlinemInit = kTRUE;
429 
430  if (error != 0 || fCaughtSignal != -1) break;
431  }
432  } ENDTRY;
433 
434  if (QuitOpt()) {
435  if (retrn) return;
436  if (error) {
437  retval = error;
438  } else if (fCaughtSignal != -1) {
439  retval = fCaughtSignal + 128;
440  }
441  // Bring retval into sensible range, 0..255.
442  if (retval < 0 || retval > 255)
443  retval = 255;
444  Terminate(retval);
445  }
446 
447  // Allow end-of-file on the terminal to be noticed
448  // after we finish processing the command line input files.
449  fInputHandler->Activate();
450 
451  ClearInputFiles();
452 
453  if (needGetlinemInit) Getlinem(kInit, GetPrompt());
454  }
455 
456  if (QuitOpt()) {
457  printf("\n");
458  if (retrn) return;
459  Terminate(fCaughtSignal != -1 ? fCaughtSignal + 128 : 0);
460  }
461 
462  TApplication::Run(retrn);
463 
464  // Reset to happiness.
465  fCaughtSignal = -1;
466 
467  Getlinem(kCleanUp, 0);
468 }
469 
470 ////////////////////////////////////////////////////////////////////////////////
471 /// Print the ROOT logo on standard output.
472 
473 void TRint::PrintLogo(Bool_t lite)
474 {
475  if (!lite) {
476  // Fancy formatting: the content of lines are format strings; their %s is
477  // replaced by spaces needed to make all lines as long as the longest line.
478  std::vector<TString> lines;
479  // Here, %%s results in %s after TString::Format():
480  lines.emplace_back(TString::Format("Welcome to ROOT %s%%shttps://root.cern",
481  gROOT->GetVersion()));
482  lines.emplace_back(TString::Format("(c) 1995-2020, The ROOT Team; conception: R. Brun, F. Rademakers%%s"));
483  lines.emplace_back(TString::Format("Built for %s on %s%%s", gSystem->GetBuildArch(), gROOT->GetGitDate()));
484  if (!strcmp(gROOT->GetGitBranch(), gROOT->GetGitCommit())) {
485  static const char *months[] = {"January","February","March","April","May",
486  "June","July","August","September","October",
487  "November","December"};
488  Int_t idatqq = gROOT->GetVersionDate();
489  Int_t iday = idatqq%100;
490  Int_t imonth = (idatqq/100)%100;
491  Int_t iyear = (idatqq/10000);
492 
493  lines.emplace_back(TString::Format("From tag %s, %d %s %4d%%s",
494  gROOT->GetGitBranch(),
495  iday,months[imonth-1],iyear));
496  } else {
497  // If branch and commit are identical - e.g. "v5-34-18" - then we have
498  // a release build. Else specify the git hash this build was made from.
499  lines.emplace_back(TString::Format("From %s@%s %%s",
500  gROOT->GetGitBranch(),
501  gROOT->GetGitCommit()));
502  }
503  lines.emplace_back(TString("Try '.help', '.demo', '.license', '.credits', '.quit'/'.q'%s"));
504 
505  // Find the longest line and its length:
506  auto itLongest = std::max_element(lines.begin(), lines.end(),
507  [](const TString& left, const TString& right) {
508  return left.Length() < right.Length(); });
509  Ssiz_t lenLongest = itLongest->Length();
510 
511 
512  Printf(" %s", TString('-', lenLongest).Data());
513  for (const auto& line: lines) {
514  // Print the line, expanded with the necessary spaces at %s, and
515  // surrounded by some ASCII art.
516  Printf(" | %s |",
517  TString::Format(line.Data(),
518  TString(' ', lenLongest - line.Length()).Data()).Data());
519  }
520  Printf(" %s\n", TString('-', lenLongest).Data());
521  }
522 
523 #ifdef R__UNIX
524  // Popdown X logo, only if started with -splash option
525  for (int i = 0; i < Argc(); i++)
526  if (!strcmp(Argv(i), "-splash"))
527  kill(getppid(), SIGUSR1);
528 #endif
529 }
530 
531 ////////////////////////////////////////////////////////////////////////////////
532 /// Get prompt from interpreter. Either "root [n]" or "end with '}'".
533 
534 char *TRint::GetPrompt()
535 {
536  char *s = gCling->GetPrompt();
537  if (s[0])
538  strlcpy(fPrompt, s, sizeof(fPrompt));
539  else
540  snprintf(fPrompt, sizeof(fPrompt), fDefaultPrompt.Data(), fNcmd);
541 
542  return fPrompt;
543 }
544 
545 ////////////////////////////////////////////////////////////////////////////////
546 /// Set a new default prompt. It returns the previous prompt.
547 /// The prompt may contain a %d which will be replaced by the commend
548 /// number. The default prompt is "root [%d] ". The maximum length of
549 /// the prompt is 55 characters. To set the prompt in an interactive
550 /// session do:
551 /// root [0] ((TRint*)gROOT->GetApplication())->SetPrompt("aap> ")
552 /// aap>
553 
554 const char *TRint::SetPrompt(const char *newPrompt)
555 {
556  static TString op;
557  op = fDefaultPrompt;
558 
559  if (newPrompt && strlen(newPrompt) <= 55)
560  fDefaultPrompt = newPrompt;
561  else
562  Error("SetPrompt", "newPrompt too long (> 55 characters)");
563 
564  return op.Data();
565 }
566 
567 ////////////////////////////////////////////////////////////////////////////////
568 /// Handle input coming from terminal.
569 
570 Bool_t TRint::HandleTermInput()
571 {
572  static TStopwatch timer;
573  const char *line;
574 
575  if ((line = Getlinem(kOneChar, 0))) {
576  if (line[0] == 0 && Gl_eof())
577  Terminate(0);
578 
579  gVirtualX->SetKeyAutoRepeat(kTRUE);
580 
581  Gl_histadd(line);
582 
583  TString sline = line;
584 
585  // strip off '\n' and leading and trailing blanks
586  sline = sline.Chop();
587  sline = sline.Strip(TString::kBoth);
588  ReturnPressed((char*)sline.Data());
589 
590  fInterrupt = kFALSE;
591 
592  if (!gCling->GetMore() && !sline.IsNull()) fNcmd++;
593 
594  // prevent recursive calling of this input handler
595  fInputHandler->DeActivate();
596 
597  if (gROOT->Timer()) timer.Start();
598 
599  TTHREAD_TLS(Bool_t) added;
600  added = kFALSE; // reset on each call.
601 
602  // This is needed when working with remote sessions
603  SetBit(kProcessRemotely);
604 
605  try {
606  TRY {
607  if (!sline.IsNull())
608  LineProcessed(sline);
609  ProcessLineNr("ROOT_prompt_", sline);
610  } CATCH(excode) {
611  // enable again input handler
612  fInputHandler->Activate();
613  added = kTRUE;
614  Throw(excode);
615  } ENDTRY;
616  }
617  // handle every exception
618  catch (std::exception& e) {
619  // enable again intput handler
620  if (!added) fInputHandler->Activate();
621 
622  int err;
623  char *demangledType_c = TClassEdit::DemangleTypeIdName(typeid(e), err);
624  const char* demangledType = demangledType_c;
625  if (err) {
626  demangledType_c = nullptr;
627  demangledType = "<UNKNOWN>";
628  }
629  Error("HandleTermInput()", "%s caught: %s", demangledType, e.what());
630  free(demangledType_c);
631  }
632  catch (...) {
633  // enable again intput handler
634  if (!added) fInputHandler->Activate();
635  Error("HandleTermInput()", "Exception caught!");
636  }
637 
638  if (gROOT->Timer()) timer.Print("u");
639 
640  // enable again intput handler
641  fInputHandler->Activate();
642 
643  if (!sline.BeginsWith(".reset"))
644  gCling->EndOfLineAction();
645 
646  gTabCom->ClearAll();
647  Getlinem(kInit, GetPrompt());
648  }
649  return kTRUE;
650 }
651 
652 ////////////////////////////////////////////////////////////////////////////////
653 /// Handle signals (kSigBus, kSigSegmentationViolation,
654 /// kSigIllegalInstruction and kSigFloatingException) trapped in TSystem.
655 /// Specific TApplication implementations may want something different here.
656 
657 void TRint::HandleException(Int_t sig)
658 {
659  fCaughtSignal = sig;
660  if (TROOT::Initialized()) {
661  if (gException) {
662  Getlinem(kCleanUp, 0);
663  Getlinem(kInit, "Root > ");
664  }
665  }
666  TApplication::HandleException(sig);
667 }
668 
669 ////////////////////////////////////////////////////////////////////////////////
670 /// Terminate the application. Reset the terminal to sane mode and call
671 /// the logoff macro defined via Rint.Logoff environment variable.
672 
673 void TRint::Terminate(Int_t status)
674 {
675  Getlinem(kCleanUp, 0);
676 
677  if (ReturnFromRun()) {
678  gSystem->ExitLoop();
679  } else {
680  delete gTabCom;
681  gTabCom = 0;
682 
683  //Execute logoff macro
684  const char *logoff;
685  logoff = gEnv->GetValue("Rint.Logoff", (char*)0);
686  if (logoff && !NoLogOpt()) {
687  char *mac = gSystem->Which(TROOT::GetMacroPath(), logoff, kReadPermission);
688  if (mac)
689  ProcessFile(logoff);
690  delete [] mac;
691  }
692 
693  TApplication::Terminate(status);
694  }
695 }
696 
697 ////////////////////////////////////////////////////////////////////////////////
698 /// Set console mode:
699 ///
700 /// mode = kTRUE - echo input symbols
701 /// mode = kFALSE - noecho input symbols
702 
703 void TRint::SetEchoMode(Bool_t mode)
704 {
705  Gl_config("noecho", mode ? 0 : 1);
706 }
707 
708 ////////////////////////////////////////////////////////////////////////////////
709 /// Process the content of a line starting with ".R" (already stripped-off)
710 /// The format is
711 /// [user@]host[:dir] [-l user] [-d dbg] [script]
712 /// The variable 'dir' is the remote directory to be used as working dir.
713 /// The username can be specified in two ways, "-l" having the priority
714 /// (as in ssh).
715 /// A 'dbg' value > 0 gives increasing verbosity.
716 /// The last argument 'script' allows to specify an alternative script to
717 /// be executed remotely to startup the session.
718 
719 Long_t TRint::ProcessRemote(const char *line, Int_t *)
720 {
721  Long_t ret = TApplication::ProcessRemote(line);
722 
723  if (ret == 1) {
724  if (fAppRemote) {
725  TString prompt; prompt.Form("%s:root [%%d] ", fAppRemote->ApplicationName());
726  SetPrompt(prompt);
727  } else {
728  SetPrompt("root [%d] ");
729  }
730  }
731 
732  return ret;
733 }
734 
735 
736 ////////////////////////////////////////////////////////////////////////////////
737 /// Calls ProcessLine() possibly prepending a #line directive for
738 /// better diagnostics. Must be called after fNcmd has been increased for
739 /// the next line.
740 
741 Long_t TRint::ProcessLineNr(const char* filestem, const char *line, Int_t *error /*= 0*/)
742 {
743  Int_t err;
744  if (!error)
745  error = &err;
746  if (line && line[0] != '.') {
747  TString lineWithNr = TString::Format("#line 1 \"%s%d\"\n", filestem, fNcmd - 1);
748  int res = ProcessLine(lineWithNr + line, kFALSE, error);
749  if (*error == TInterpreter::kProcessing) {
750  if (!fNonContinuePrompt.Length())
751  fNonContinuePrompt = fDefaultPrompt;
752  SetPrompt("root (cont'ed, cancel with .@) [%d]");
753  } else if (fNonContinuePrompt.Length()) {
754  SetPrompt(fNonContinuePrompt);
755  fNonContinuePrompt.Clear();
756  }
757  return res;
758  }
759  if (line && line[0] == '.' && line[1] == '@') {
760  ProcessLine(line, kFALSE, error);
761  SetPrompt("root [%d] ");
762  }
763  return ProcessLine(line, kFALSE, error);
764 }
765 
766 
767 ////////////////////////////////////////////////////////////////////////////////
768 /// Forward tab completion request to our TTabCom::Hook().
769 
770 Int_t TRint::TabCompletionHook(char *buf, int *pLoc, std::ostream& out)
771 {
772  if (gTabCom)
773  return gTabCom->Hook(buf, pLoc, out);
774 
775  return -1;
776 }