#include "TROOT.h"
#include "TClass.h"
#include "TVirtualX.h"
#include "TStyle.h"
#include "TObjectTable.h"
#include "TClassTable.h"
#include "TStopwatch.h"
#include "TBenchmark.h"
#include "TRint.h"
#include "TSystem.h"
#include "TEnv.h"
#include "TSysEvtHandler.h"
#include "TSystemDirectory.h"
#include "TError.h"
#include "TException.h"
#include "TInterpreter.h"
#include "TObjArray.h"
#include "TObjString.h"
#include "TTabCom.h"
#include "TError.h"
#include <stdlib.h>
#include <algorithm>
#include "Getline.h"
#ifdef R__UNIX
#include <signal.h>
#endif
R__EXTERN void *gMmallocDesc;
static Int_t Key_Pressed(Int_t key)
{
gApplication->KeyPressed(key);
return 0;
}
static Int_t BeepHook()
{
if (!gSystem) return 0;
gSystem->Beep();
return 1;
}
static void ResetTermAtExit()
{
Getlinem(kCleanUp, 0);
}
class TInterruptHandler : public TSignalHandler {
public:
TInterruptHandler() : TSignalHandler(kSigInterrupt, kFALSE) { }
Bool_t Notify();
};
Bool_t TInterruptHandler::Notify()
{
if (fDelay) {
fDelay++;
return kTRUE;
}
gMmallocDesc = 0;
Break("TInterruptHandler::Notify", "keyboard interrupt");
if (TROOT::Initialized()) {
Getlinem(kInit, "Root > ");
gCling->Reset();
#ifndef WIN32
if (gException)
Throw(GetSignal());
#endif
}
return kTRUE;
}
class TTermInputHandler : public TFileHandler {
public:
TTermInputHandler(Int_t fd) : TFileHandler(fd, 1) { }
Bool_t Notify();
Bool_t ReadNotify() { return Notify(); }
};
Bool_t TTermInputHandler::Notify()
{
return gApplication->HandleTermInput();
}
ClassImp(TRint)
TRint::TRint(const char *appClassName, Int_t *argc, char **argv, void *options,
Int_t numOptions, Bool_t noLogo)
: TApplication(appClassName, argc, argv, options, numOptions)
{
fNcmd = 0;
fDefaultPrompt = "root [%d] ";
fInterrupt = kFALSE;
gBenchmark = new TBenchmark();
if (!noLogo && !NoLogoOpt()) {
Bool_t lite = (Bool_t) gEnv->GetValue("Rint.WelcomeLite", 0);
PrintLogo(lite);
}
if (!gClassTable->GetDict("TRandom"))
gSystem->Load("libMathCore");
Int_t includes = gEnv->GetValue("Rint.Includes", 1);
if (includes > 0) {
ProcessLine("#include <iostream>", kTRUE);
ProcessLine("#include <string>", kTRUE);
ProcessLine("#include <DllImport.h>", kTRUE);
if (includes > 1) {
ProcessLine("#include <vector>", kTRUE);
ProcessLine("#include <utility>", kTRUE);
}
}
const char *logon;
logon = gEnv->GetValue("Rint.Load", (char*)0);
if (logon) {
char *mac = gSystem->Which(TROOT::GetMacroPath(), logon, kReadPermission);
if (mac)
ProcessLine(Form(".L %s",logon), kTRUE);
delete [] mac;
}
ExecLogon();
gCling->SaveContext();
gCling->SaveGlobalsContext();
TInterruptHandler *ih = new TInterruptHandler();
ih->Add();
SetSignalHandler(ih);
fInputHandler = new TTermInputHandler(0);
fInputHandler->Add();
char defhist[kMAXPATHLEN];
snprintf(defhist, sizeof(defhist), "%s/.root_hist", gSystem->HomeDirectory());
logon = gEnv->GetValue("Rint.History", defhist);
int hist_size = gEnv->GetValue("Rint.HistorySize", 500);
if (hist_size == 500)
hist_size = gEnv->GetValue("Rint.HistSize", 500);
int hist_save = gEnv->GetValue("Rint.HistorySave", 400);
if (hist_save == 400)
hist_save = gEnv->GetValue("Rint.HistSave", 400);
const char *envHist = gSystem->Getenv("ROOT_HIST");
if (envHist) {
hist_size = atoi(envHist);
envHist = strchr(envHist, ':');
if (envHist)
hist_save = atoi(envHist+1);
}
Gl_histsize(hist_size, hist_save);
Gl_histinit((char *)logon);
static const char* defaultColorsBW[] = {
"bold blue", "magenta", "bold green", "bold red underlined", "default"
};
static const char* defaultColorsWB[] = {
"yellow", "magenta", "bold green", "bold red underlined", "default"
};
const char** defaultColors = defaultColorsBW;
TString revColor = gEnv->GetValue("Rint.ReverseColor", "no");
if (revColor.Contains("yes", TString::kIgnoreCase)) {
defaultColors = defaultColorsWB;
}
TString colorType = gEnv->GetValue("Rint.TypeColor", defaultColors[0]);
TString colorTabCom = gEnv->GetValue("Rint.TabComColor", defaultColors[1]);
TString colorBracket = gEnv->GetValue("Rint.BracketColor", defaultColors[2]);
TString colorBadBracket = gEnv->GetValue("Rint.BadBracketColor", defaultColors[3]);
TString colorPrompt = gEnv->GetValue("Rint.PromptColor", defaultColors[4]);
Gl_setColors(colorType, colorTabCom, colorBracket, colorBadBracket, colorPrompt);
Gl_windowchanged();
atexit(ResetTermAtExit);
gTabCom = new TTabCom;
Gl_in_key = &Key_Pressed;
Gl_beep_hook = &BeepHook;
gCling->SetGetline(Getline, Gl_histadd);
}
TRint::~TRint()
{
delete gTabCom;
gTabCom = 0;
Gl_in_key = 0;
Gl_beep_hook = 0;
fInputHandler->Remove();
delete fInputHandler;
}
void TRint::ExecLogon()
{
if (NoLogOpt()) return;
TString name = ".rootlogon.C";
TString sname = "system";
sname += name;
#ifdef ROOTETCDIR
char *s = gSystem->ConcatFileName(ROOTETCDIR, sname);
#else
TString etc = gRootDir;
#ifdef WIN32
etc += "\\etc";
#else
etc += "/etc";
#endif
char *s = gSystem->ConcatFileName(etc, sname);
#endif
if (!gSystem->AccessPathName(s, kReadPermission)) {
ProcessFile(s);
}
delete [] s;
s = gSystem->ConcatFileName(gSystem->HomeDirectory(), name);
if (!gSystem->AccessPathName(s, kReadPermission)) {
ProcessFile(s);
}
delete [] s;
if (strcmp(gSystem->HomeDirectory(), gSystem->WorkingDirectory())) {
if (!gSystem->AccessPathName(name, kReadPermission))
ProcessFile(name);
}
const char *logon = gEnv->GetValue("Rint.Logon", (char*)0);
if (logon) {
char *mac = gSystem->Which(TROOT::GetMacroPath(), logon, kReadPermission);
if (mac)
ProcessFile(logon);
delete [] mac;
}
}
void TRint::Run(Bool_t retrn)
{
Getlinem(kInit, GetPrompt());
Long_t retval = 0;
Int_t error = 0;
volatile Bool_t needGetlinemInit = kFALSE;
if (strlen(WorkingDirectory())) {
gSystem->ChangeDirectory(WorkingDirectory());
TSystemDirectory *workdir = new TSystemDirectory("workdir", gSystem->WorkingDirectory());
TObject *w = gROOT->GetListOfBrowsables()->FindObject("workdir");
TObjLink *lnk = gROOT->GetListOfBrowsables()->FirstLink();
while (lnk) {
if (lnk->GetObject() == w) {
lnk->SetObject(workdir);
lnk->SetOption(gSystem->WorkingDirectory());
break;
}
lnk = lnk->Next();
}
delete w;
}
if (InputFiles()) {
fInputHandler->DeActivate();
TIter next(InputFiles());
RETRY {
retval = 0; error = 0;
Int_t nfile = 0;
TObjString *file;
while ((file = (TObjString *)next())) {
char cmd[kMAXPATHLEN+50];
if (!fNcmd)
printf("\n");
Bool_t rootfile = kFALSE;
if (file->TestBit(kExpression)) {
snprintf(cmd, kMAXPATHLEN+50, "%s", (const char*)file->String());
} else {
if (file->String().EndsWith(".root") || file->String().BeginsWith("file:")) {
rootfile = kTRUE;
} else {
rootfile = gROOT->IsRootFile(file->String());
}
if (rootfile) {
if (file->String().BeginsWith("\\\\"))
file->String().Prepend("\\\\");
file->String().ReplaceAll("\\","/");
const char *rfile = (const char*)file->String();
Printf("Attaching file %s as _file%d...", rfile, nfile);
snprintf(cmd, kMAXPATHLEN+50, "TFile *_file%d = TFile::Open(\"%s\")", nfile++, rfile);
} else {
Printf("Processing %s...", (const char*)file->String());
snprintf(cmd, kMAXPATHLEN+50, ".x %s", (const char*)file->String());
}
}
Getlinem(kCleanUp, 0);
Gl_histadd(cmd);
fNcmd++;
needGetlinemInit = kFALSE;
retval = ProcessLineNr("ROOT_cli_", cmd, &error);
gCling->EndOfLineAction();
needGetlinemInit = kTRUE;
if (error != 0) break;
}
} ENDTRY;
if (QuitOpt()) {
if (retrn) return;
if (error) {
retval = error;
}
if (retval < 0) retval = 1;
else if (retval > 125) retval = 1;
Terminate(retval);
}
fInputHandler->Activate();
ClearInputFiles();
if (needGetlinemInit) Getlinem(kInit, GetPrompt());
}
if (QuitOpt()) {
printf("\n");
if (retrn) return;
Terminate(0);
}
TApplication::Run(retrn);
Getlinem(kCleanUp, 0);
}
void TRint::PrintLogo(Bool_t lite)
{
if (!lite) {
std::vector<TString> lines;
lines.emplace_back(TString::Format("Welcome to ROOT %s%%shttp://root.cern.ch",
gROOT->GetVersion()));
lines.emplace_back(TString::Format("%%s(c) 1995-2014, The ROOT Team"));
lines.emplace_back(TString::Format("Built for %s%%s", gSystem->GetBuildArch()));
if (!strcmp(gROOT->GetGitBranch(), gROOT->GetGitCommit())) {
static const char *months[] = {"January","February","March","April","May",
"June","July","August","September","October",
"November","December"};
Int_t idatqq = gROOT->GetVersionDate();
Int_t iday = idatqq%100;
Int_t imonth = (idatqq/100)%100;
Int_t iyear = (idatqq/10000);
lines.emplace_back(TString::Format("From tag %s, %d %s %4d%%s",
gROOT->GetGitBranch(),
iday,months[imonth-1],iyear));
} else {
lines.emplace_back(TString::Format("From %s@%s, %s%%s",
gROOT->GetGitBranch(),
gROOT->GetGitCommit(), gROOT->GetGitDate()));
}
lines.emplace_back(TString("Try '.help', '.demo', '.license', '.credits', '.quit'/'.q'%s"));
auto itLongest = std::max_element(lines.begin(), lines.end(),
[](const TString& left, const TString& right) {
return left.Length() < right.Length(); });
Ssiz_t lenLongest = itLongest->Length();
Printf(" %s", TString('-', lenLongest).Data());
for (const auto& line: lines) {
Printf(" | %s |",
TString::Format(line.Data(),
TString(' ', lenLongest - line.Length()).Data()).Data());
}
Printf(" %s\n", TString('-', lenLongest).Data());
}
#ifdef R__UNIX
for (int i = 0; i < Argc(); i++)
if (!strcmp(Argv(i), "-splash"))
kill(getppid(), SIGUSR1);
#endif
}
char *TRint::GetPrompt()
{
char *s = gCling->GetPrompt();
if (s[0])
strlcpy(fPrompt, s, sizeof(fPrompt));
else
snprintf(fPrompt, sizeof(fPrompt), fDefaultPrompt.Data(), fNcmd);
return fPrompt;
}
const char *TRint::SetPrompt(const char *newPrompt)
{
static TString op = fDefaultPrompt;
if (newPrompt && strlen(newPrompt) <= 55)
fDefaultPrompt = newPrompt;
else
Error("SetPrompt", "newPrompt too long (> 55 characters)");
return op.Data();
}
Bool_t TRint::HandleTermInput()
{
static TStopwatch timer;
const char *line;
if ((line = Getlinem(kOneChar, 0))) {
if (line[0] == 0 && Gl_eof())
Terminate(0);
gVirtualX->SetKeyAutoRepeat(kTRUE);
Gl_histadd(line);
TString sline = line;
sline = sline.Chop();
sline = sline.Strip(TString::kBoth);
ReturnPressed((char*)sline.Data());
fInterrupt = kFALSE;
if (!gCling->GetMore() && !sline.IsNull()) fNcmd++;
fInputHandler->DeActivate();
if (gROOT->Timer()) timer.Start();
#ifdef R__EH
Bool_t added = kFALSE;
#endif
SetBit(kProcessRemotely);
#ifdef R__EH
try {
#endif
TRY {
if (!sline.IsNull())
LineProcessed(sline);
ProcessLineNr("ROOT_prompt_", sline);
} CATCH(excode) {
fInputHandler->Activate();
#ifdef R__EH
added = kTRUE;
#endif
Throw(excode);
} ENDTRY;
#ifdef R__EH
}
catch (...) {
if (!added) fInputHandler->Activate();
throw;
}
#endif
if (gROOT->Timer()) timer.Print("u");
fInputHandler->Activate();
if (!sline.BeginsWith(".reset"))
gCling->EndOfLineAction();
gTabCom->ClearAll();
Getlinem(kInit, GetPrompt());
}
return kTRUE;
}
void TRint::HandleException(Int_t sig)
{
if (TROOT::Initialized()) {
if (gException) {
Getlinem(kCleanUp, 0);
Getlinem(kInit, "Root > ");
}
}
TApplication::HandleException(sig);
}
void TRint::Terminate(Int_t status)
{
Getlinem(kCleanUp, 0);
if (ReturnFromRun()) {
gSystem->ExitLoop();
} else {
delete gTabCom;
gTabCom = 0;
const char *logoff;
logoff = gEnv->GetValue("Rint.Logoff", (char*)0);
if (logoff && !NoLogOpt()) {
char *mac = gSystem->Which(TROOT::GetMacroPath(), logoff, kReadPermission);
if (mac)
ProcessFile(logoff);
delete [] mac;
}
TApplication::Terminate(status);
}
}
void TRint::SetEchoMode(Bool_t mode)
{
Gl_config("noecho", mode ? 0 : 1);
}
Long_t TRint::ProcessRemote(const char *line, Int_t *)
{
Long_t ret = TApplication::ProcessRemote(line);
if (ret == 1) {
if (fAppRemote) {
TString prompt; prompt.Form("%s:root [%%d] ", fAppRemote->ApplicationName());
SetPrompt(prompt);
} else {
SetPrompt("root [%d] ");
}
}
return ret;
}
Long_t TRint::ProcessLineNr(const char* filestem, const char *line, Int_t *error )
{
Int_t err;
if (!error)
error = &err;
if (line && line[0] != '.') {
TString lineWithNr = TString::Format("#line 1 \"%s%d\"\n", filestem, fNcmd - 1);
int res = ProcessLine(lineWithNr + line, kFALSE, error);
if (*error == TInterpreter::kProcessing)
SetPrompt("root (cont'ed, cancel with .@) [%d]");
else
SetPrompt("root [%d] ");
return res;
}
if (line && line[0] == '.' && line[1] == '@') {
ProcessLine(line, kFALSE, error);
SetPrompt("root [%d] ");
}
return ProcessLine(line, kFALSE, error);
}
Int_t TRint::TabCompletionHook(char *buf, int *pLoc, std::ostream& out)
{
if (gTabCom)
return gTabCom->Hook(buf, pLoc, out);
return -1;
}