Logo ROOT  
Reference Guide
Loading...
Searching...
No Matches
TApplication.cxx
Go to the documentation of this file.
1// @(#)root/base:$Id$
2// Author: Fons Rademakers 22/12/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/** \class TApplication
13\ingroup Base
14
15This class creates the ROOT Application Environment that interfaces
16to the windowing system eventloop and eventhandlers.
17This class must be instantiated exactly once in any given
18application. Normally the specific application class inherits from
19TApplication (see TRint).
20*/
21
22#include "RConfigure.h"
23#include "TApplication.h"
24#include "TException.h"
25#include "TGuiFactory.h"
26#include "TVirtualX.h"
27#include "TROOT.h"
28#include "TSystem.h"
29#include "TString.h"
30#include "TError.h"
31#include "TObjArray.h"
32#include "TObjString.h"
33#include "TTimer.h"
34#include "TInterpreter.h"
35#include "TStyle.h"
36#include "TVirtualPad.h"
37#include "TEnv.h"
38#include "TColor.h"
39#include "TPluginManager.h"
40#include "TClassTable.h"
41#include "TBrowser.h"
42#include "TUrl.h"
43#include "TVirtualMutex.h"
44#include "TClassEdit.h"
45#include "TMethod.h"
46#include "TDataMember.h"
47#include "TApplicationCommandLineOptionsHelp.h"
48#include "TPRegexp.h"
49#include <cstdlib>
50#include <iostream>
51#include <fstream>
52
56TList *TApplication::fgApplications = nullptr; // List of available applications
57
58////////////////////////////////////////////////////////////////////////////////
59
60class TIdleTimer : public TTimer {
61public:
63 Bool_t Notify() override;
64};
65
66////////////////////////////////////////////////////////////////////////////////
67/// Notify handler.
68
70{
71 gApplication->HandleIdleTimer();
72 Reset();
73 return kFALSE;
74}
75
76
77
79{
80 // Insure that the files, canvases and sockets are closed.
81
82 // If we get here, the tear down has started. We have no way to know what
83 // has or has not yet been done. In particular on Ubuntu, this was called
84 // after the function static in TSystem.cxx has been destructed. So we
85 // set gROOT in its end-of-life mode which prevents executing code, like
86 // autoloading libraries (!) that is pointless ...
87 if (gROOT) {
88 gROOT->SetBit(kInvalidObject);
89 gROOT->EndOfProcessCleanups();
90 }
91}
92
93////////////////////////////////////////////////////////////////////////////////
94/// Default ctor. Can be used by classes deriving from TApplication.
95
104
105////////////////////////////////////////////////////////////////////////////////
106/// Create an application environment. The application environment
107/// provides an interface to the graphics system and eventloop
108/// (be it X, Windows, macOS or BeOS). After creating the application
109/// object start the eventloop by calling its Run() method. The command
110/// line options recognized by TApplication are described in the GetOptions()
111/// method. The recognized options are removed from the argument array.
112/// The original list of argument options can be retrieved via the Argc()
113/// and Argv() methods. The "options" and "numOptions" arguments are not used,
114/// except if you want to by-pass the argv processing by GetOptions()
115/// in which case you should specify numOptions<0. All options will
116/// still be available via the Argv() method for later use.
117
118TApplication::TApplication(const char *appClassName, Int_t *argc, char **argv,
119 void * /*options*/, Int_t numOptions) :
120 fArgc(0), fArgv(nullptr), fAppImp(nullptr), fIsRunning(kFALSE), fReturnFromRun(kFALSE),
122 fFiles(nullptr), fIdleTimer(nullptr), fSigHandler(nullptr), fExitOnException(kDontExit),
123 fAppRemote(nullptr)
124{
126
127 // Create the list of applications the first time
128 if (!fgApplications)
129 fgApplications = new TList;
130
131 // Add the new TApplication early, so that the destructor of the
132 // default TApplication (if it is called in the block of code below)
133 // will not destroy the files, socket or TColor that have already been
134 // created.
135 fgApplications->Add(this);
136
138 // allow default TApplication to be replaced by a "real" TApplication
139 delete gApplication;
140 gApplication = nullptr;
141 gROOT->SetBatch(kFALSE);
143 }
144
145 if (gApplication) {
146 Error("TApplication", "only one instance of TApplication allowed");
147 fgApplications->Remove(this);
148 return;
149 }
150
151 if (!gROOT)
152 ::Fatal("TApplication::TApplication", "ROOT system not initialized");
153
154 if (!gSystem)
155 ::Fatal("TApplication::TApplication", "gSystem not initialized");
156
157 static Bool_t hasRegisterAtExit(kFALSE);
158 if (!hasRegisterAtExit) {
159 // If we are the first TApplication register the atexit)
161 hasRegisterAtExit = kTRUE;
162 }
163 gROOT->SetName(appClassName);
164
165 // copy command line arguments, can be later accessed via Argc() and Argv()
166 if (argc && *argc > 0) {
167 fArgc = *argc;
168 fArgv = (char **)new char*[fArgc];
169 }
170
171 for (int i = 0; i < fArgc; i++)
172 fArgv[i] = StrDup(argv[i]);
173
174 if (numOptions >= 0)
175 GetOptions(argc, argv);
176
177 if (fArgv)
178 gSystem->SetProgname(fArgv[0]);
179
180 // Alternative to '-b' command line switch (i.e. for pyROOT)
181 if (gSystem->Getenv("ROOT_BATCH"))
182 MakeBatch();
183
184 // Tell TSystem the TApplication has been created
185 gSystem->NotifyApplicationCreated();
186
187 fAppImp = gGuiFactory->CreateApplicationImp(appClassName, argc, argv);
189
190 // Initialize the graphics environment
191 if (gClassTable->GetDict("TPad")) {
193 InitializeGraphics(gROOT->IsWebDisplay());
194 }
195
196 // Save current interpreter context
197 gInterpreter->SaveContext();
198 gInterpreter->SaveGlobalsContext();
199
200 // to allow user to interact with TCanvas's under WIN32
201 gROOT->SetLineHasBeenProcessed();
202
203 //Needs to be done last
204 gApplication = this;
205 gROOT->SetApplication(this);
206
207}
208
209////////////////////////////////////////////////////////////////////////////////
210/// TApplication dtor.
211
213{
214 for (int i = 0; i < fArgc; i++)
215 if (fArgv[i]) delete [] fArgv[i];
216 delete [] fArgv;
217
218 if (fgApplications)
219 fgApplications->Remove(this);
220
221 // Reduce the risk of the files or sockets being closed after the
222 // end of 'main' (or more exactly before the library start being
223 // unloaded).
224 if (fgApplications == nullptr || fgApplications->FirstLink() == nullptr ) {
225 TROOT::ShutDown();
226 }
227
228 // Now that all the canvases and files have been closed we can
229 // delete the implementation.
231}
232
233////////////////////////////////////////////////////////////////////////////////
234/// Static method. This method should be called from static library
235/// initializers if the library needs the low level graphics system.
236
241
242////////////////////////////////////////////////////////////////////////////////
243/// Initialize the graphics environment.
244/// If @param only_web is specified, only web-related part of graphics is loaded
245
247{
249 return;
250
251 if (!only_web) {
252 // Load the graphics related libraries
254
255 // Try to load TrueType font renderer. Only try to load if not in batch
256 // mode and Root.UseTTFonts is true and Root.TTFontPath exists. Abort silently
257 // if libttf or libGX11TTF are not found in $ROOTSYS/lib or $ROOTSYS/ttf/lib.
258 const char *ttpath = gEnv->GetValue("Root.TTFontPath",
259 TROOT::GetTTFFontDir());
260 char *ttfont = gSystem->Which(ttpath, "arialbd.ttf", kReadPermission);
261 // Check for use of DFSG - fonts
262 if (!ttfont)
263 ttfont = gSystem->Which(ttpath, "FreeSansBold.ttf", kReadPermission);
264
265 #if !defined(R__WIN32)
266 if (!gROOT->IsBatch() && !strcmp(gVirtualX->GetName(), "X11") &&
267 ttfont && gEnv->GetValue("Root.UseTTFonts", 1)) {
268 if (gClassTable->GetDict("TGX11TTF")) {
269 // in principle we should not have linked anything against libGX11TTF
270 // but with ACLiC this can happen, initialize TGX11TTF by hand
271 // (normally this is done by the static library initializer)
272 ProcessLine("TGX11TTF::Activate();");
273 } else {
275 if ((h = gROOT->GetPluginManager()->FindHandler("TVirtualX", "x11ttf")))
276 if (h->LoadPlugin() == -1)
277 Info("InitializeGraphics", "no TTF support");
278 }
279 }
280 #endif
281 delete [] ttfont;
282 }
283
284 if (!only_web || !fAppImp) {
285 // Create WM dependent application environment
286 if (fAppImp)
287 delete fAppImp;
288 fAppImp = gGuiFactory->CreateApplicationImp(gROOT->GetName(), &fArgc, fArgv);
289 if (!fAppImp) {
290 MakeBatch();
291 fAppImp = gGuiFactory->CreateApplicationImp(gROOT->GetName(), &fArgc, fArgv);
292 }
293 }
294
295 // Create the canvas colors early so they are allocated before
296 // any color table expensive bitmaps get allocated in GUI routines (like
297 // creation of XPM bitmaps).
299
300 // Hook for further initializing the WM dependent application environment
301 Init();
302
303 // Set default screen factor (if not disabled in rc file)
304 if (!only_web && gEnv->GetValue("Canvas.UseScreenFactor", 1)) {
305 Int_t x, y;
306 UInt_t w, h;
307 if (gVirtualX) {
308 gVirtualX->GetGeometry(-1, x, y, w, h);
309 if (h > 0)
310 gStyle->SetScreenFactor(0.001 * h);
311 }
312 }
313}
314
315////////////////////////////////////////////////////////////////////////////////
316/// Clear list containing macro files passed as program arguments.
317/// This method is called from TRint::Run() to ensure that the macro
318/// files are only executed the first time Run() is called.
319
321{
322 if (fFiles) {
323 fFiles->Delete();
325 }
326}
327
328////////////////////////////////////////////////////////////////////////////////
329/// Return specified argument.
330
331char *TApplication::Argv(Int_t index) const
332{
333 if (fArgv) {
334 if (index >= fArgc) {
335 Error("Argv", "index (%d) >= number of arguments (%d)", index, fArgc);
336 return nullptr;
337 }
338 return fArgv[index];
339 }
340 return nullptr;
341}
342
343////////////////////////////////////////////////////////////////////////////////
344/// Get and handle command line options. Arguments handled are removed
345/// from the argument array. See CommandLineOptionsHelp.h for options.
346
347void TApplication::GetOptions(Int_t *argc, char **argv)
348{
349 static char null[1] = { "" };
350
351 fNoLog = kFALSE;
352 fQuit = kFALSE;
353 fFiles = nullptr;
354
355 if (!argc)
356 return;
357
358 int i, j;
359 TString pwd;
360
361 for (i = 1; i < *argc; i++) {
362 if (!strcmp(argv[i], "-?") || !strncmp(argv[i], "-h", 2) ||
363 !strncmp(argv[i], "--help", 6)) {
364 fprintf(stderr, kCommandLineOptionsHelp);
365 Terminate(0);
366 } else if (!strncmp(argv[i], "--version", 9)) {
367 fprintf(stderr, "ROOT Version: %s\n", gROOT->GetVersion());
368 fprintf(stderr, "Built for %s on %s\n",
369 gSystem->GetBuildArch(),
370 gROOT->GetGitDate());
371
372 fprintf(stderr, "From %s@%s\n",
373 gROOT->GetGitBranch(),
374 gROOT->GetGitCommit());
375
376 Terminate(0);
377 } else if (!strcmp(argv[i], "-config")) {
378 fprintf(stderr, "ROOT ./configure options:\n%s\n", gROOT->GetConfigOptions());
379 Terminate(0);
380 } else if (!strcmp(argv[i], "-a")) {
381 fprintf(stderr, "ROOT splash screen is not visible with root.exe, use root instead.\n");
382 Terminate(0);
383 } else if (!strcmp(argv[i], "-b")) {
384 MakeBatch();
385 argv[i] = null;
386 } else if (!strcmp(argv[i], "-n")) {
387 fNoLog = kTRUE;
388 argv[i] = null;
389 } else if (!strcmp(argv[i], "-t")) {
391 // EnableImplicitMT() only enables thread safety if IMT was configured;
392 // enable thread safety even with IMT off:
394 argv[i] = null;
395 } else if (!strcmp(argv[i], "-q")) {
396 fQuit = kTRUE;
397 argv[i] = null;
398 } else if (!strcmp(argv[i], "-l")) {
399 // used by front-end program to not display splash screen
400 fNoLogo = kTRUE;
401 argv[i] = null;
402 } else if (!strcmp(argv[i], "-x")) {
404 argv[i] = null;
405 } else if (!strcmp(argv[i], "-splash")) {
406 // used when started by front-end program to signal that
407 // splash screen can be popped down (TRint::PrintLogo())
408 argv[i] = null;
409 } else if (strncmp(argv[i], "--web", 5) == 0) {
410 // the web mode is requested
411 const char *opt = argv[i] + 5;
412 argv[i] = null;
413 gROOT->SetWebDisplay((*opt == '=') ? opt + 1 : "");
414 } else if (!strcmp(argv[i], "-e")) {
415 argv[i] = null;
416 ++i;
417
418 if ( i < *argc ) {
419 if (!fFiles) fFiles = new TObjArray;
420 TObjString *expr = new TObjString(argv[i]);
421 expr->SetBit(kExpression);
422 fFiles->Add(expr);
423 argv[i] = null;
424 } else {
425 Warning("GetOptions", "-e must be followed by an expression.");
426 }
427 } else if (!strcmp(argv[i], "--")) {
428 TObjString* macro = nullptr;
429 bool warnShown = false;
430
431 if (fFiles) {
432 for (auto f: *fFiles) {
433 TObjString *file = dynamic_cast<TObjString *>(f);
434 if (!file) {
435 if (!dynamic_cast<TNamed*>(f)) {
436 Error("GetOptions()", "Inconsistent file entry (not a TObjString)!");
437 if (f)
438 f->Dump();
439 } // else we did not find the file.
440 continue;
441 }
442
443 if (file->TestBit(kExpression))
444 continue;
445 if (file->String().EndsWith(".root"))
446 continue;
447 if (file->String().Contains('('))
448 continue;
449
450 if (macro && !warnShown && (warnShown = true))
451 Warning("GetOptions", "-- is used with several macros. "
452 "The arguments will be passed to the last one.");
453
454 macro = file;
455 }
456 }
457
458 if (macro) {
459 argv[i] = null;
460 ++i;
461 TString& str = macro->String();
462
463 str += '(';
464 for (; i < *argc; i++) {
465 str += argv[i];
466 str += ',';
467 argv[i] = null;
468 }
469 str.EndsWith(",") ? str[str.Length() - 1] = ')' : str += ')';
470 } else {
471 Warning("GetOptions", "no macro to pass arguments to was provided. "
472 "Everything after the -- will be ignored.");
473 for (; i < *argc; i++)
474 argv[i] = null;
475 }
476 } else if (argv[i][0] != '-' && argv[i][0] != '+') {
478 Long_t id, flags, modtime;
479 char *arg = strchr(argv[i], '(');
480 if (arg) *arg = '\0';
481 TString expandedDir(argv[i]);
482 if (gSystem->ExpandPathName(expandedDir)) {
483 // ROOT-9959: we do not continue if we could not expand the path
484 continue;
485 }
486 TUrl udir(expandedDir, kTRUE);
487 // remove options and anchor to check the path
488 TString sfx = udir.GetFileAndOptions();
489 TString fln = udir.GetFile();
490 sfx.Replace(sfx.Index(fln), fln.Length(), "");
491 TString path = udir.GetFile();
492 if (strcmp(udir.GetProtocol(), "file")) {
493 path = udir.GetUrl();
494 path.Replace(path.Index(sfx), sfx.Length(), "");
495 }
496 // 'path' is the full URL without suffices (options and/or anchor)
497 if (arg) *arg = '(';
498 if (!arg && !gSystem->GetPathInfo(path.Data(), &id, &size, &flags, &modtime)) {
499 if ((flags & 2)) {
500 // if directory set it in fWorkDir
501 if (pwd == "") {
502 pwd = gSystem->WorkingDirectory();
503 fWorkDir = expandedDir;
504 gSystem->ChangeDirectory(expandedDir);
505 argv[i] = null;
506 } else if (!strcmp(gROOT->GetName(), "Rint")) {
507 Warning("GetOptions", "only one directory argument can be specified (%s)", expandedDir.Data());
508 }
509 } else if (size > 0) {
510 // if file add to list of files to be processed
511 if (!fFiles) fFiles = new TObjArray;
512 fFiles->Add(new TObjString(path.Data()));
513 argv[i] = null;
514 } else {
515 Warning("GetOptions", "file %s has size 0, skipping", expandedDir.Data());
516 }
517 } else {
518 if (TString(udir.GetFile()).EndsWith(".root")) {
519 if (!strcmp(udir.GetProtocol(), "file")) {
520 // file ending on .root but does not exist, likely a typo
521 // warn user if plain root...
522 if (!strcmp(gROOT->GetName(), "Rint"))
523 Warning("GetOptions", "file %s not found", expandedDir.Data());
524 } else {
525 // remote file, give it the benefit of the doubt and add it to list of files
526 if (!fFiles) fFiles = new TObjArray;
527 fFiles->Add(new TObjString(argv[i]));
528 argv[i] = null;
529 }
530 } else {
531 TString mode,fargs,io;
532 TString fname = gSystem->SplitAclicMode(expandedDir,mode,fargs,io);
533 char *mac;
534 if (!fFiles) fFiles = new TObjArray;
535 if ((mac = gSystem->Which(TROOT::GetMacroPath(), fname,
536 kReadPermission))) {
537 // if file add to list of files to be processed
538 fFiles->Add(new TObjString(argv[i]));
539 argv[i] = null;
540 delete [] mac;
541 } else {
542 // if file add an invalid entry to list of files to be processed
543 fFiles->Add(new TNamed("NOT FOUND!", argv[i]));
544 // only warn if we're plain root,
545 // other progs might have their own params
546 if (!strcmp(gROOT->GetName(), "Rint")) {
547 Error("GetOptions", "macro %s not found", fname.Data());
548 // Return 2 as the Python interpreter does in case the macro
549 // is not found.
550 Terminate(2);
551 }
552 }
553 }
554 }
555 }
556 // ignore unknown options
557 }
558
559 // go back to startup directory
560 if (pwd != "")
561 gSystem->ChangeDirectory(pwd);
562
563 // remove handled arguments from argument array
564 j = 0;
565 for (i = 0; i < *argc; i++) {
566 if (strcmp(argv[i], "")) {
567 argv[j] = argv[i];
568 j++;
569 }
570 }
571
572 *argc = j;
573}
574
575////////////////////////////////////////////////////////////////////////////////
576/// Handle idle timeout. When this timer expires the registered idle command
577/// will be executed by this routine and a signal will be emitted.
578
580{
581 if (!fIdleCommand.IsNull())
583
584 Emit("HandleIdleTimer()");
585}
586
587////////////////////////////////////////////////////////////////////////////////
588/// Handle exceptions (kSigBus, kSigSegmentationViolation,
589/// kSigIllegalInstruction and kSigFloatingException) trapped in TSystem.
590/// Specific TApplication implementations may want something different here.
591
593{
594 if (TROOT::Initialized()) {
595 if (gException) {
596 gInterpreter->RewindDictionary();
597 gInterpreter->ClearFileBusy();
598 }
599 if (fExitOnException == kExit)
600 gSystem->Exit(128 + sig);
601 else if (fExitOnException == kAbort)
602 gSystem->Abort();
603 else
604 Throw(sig);
605 }
606 gSystem->Exit(128 + sig);
607}
608
609////////////////////////////////////////////////////////////////////////////////
610/// Set the exit on exception option. Setting this option determines what
611/// happens in HandleException() in case an exception (kSigBus,
612/// kSigSegmentationViolation, kSigIllegalInstruction or kSigFloatingException)
613/// is trapped. Choices are: kDontExit (default), kExit or kAbort.
614/// Returns the previous value.
615
622
623/////////////////////////////////////////////////////////////////////////////////
624/// The function generates and executes a command that loads the Doxygen URL in
625/// a browser. It works for Mac, Windows and Linux. In the case of Linux, the
626/// function also checks if the DISPLAY is set. If it isn't, a warning message
627/// and the URL will be displayed on the terminal.
628///
629/// \param[in] url web page to be displayed in a browser
630
632{
633 // We check what operating system the user has.
634#ifdef R__MACOSX
635 // Command for opening a browser on Mac.
636 TString cMac("open ");
637 // We generate the full command and execute it.
638 cMac.Append(url);
639 gSystem->Exec(cMac);
640#elif defined(R__WIN32)
641 // Command for opening a browser on Windows.
642 TString cWindows("start \"\" ");
643 cWindows.Append(url);
644 gSystem->Exec(cWindows);
645#else
646 // Command for opening a browser in Linux.
647 TString cLinux("xdg-open ");
648 // For Linux we check if the DISPLAY is set.
649 if (gSystem->Getenv("DISPLAY")) {
650 // If the DISPLAY is set it will open the browser.
651 cLinux.Append(url);
652 gSystem->Exec(cLinux);
653 } else {
654 // Else the user will have a warning and the URL in the terminal.
655 Warning("OpenInBrowser", "The $DISPLAY is not set! Please open (e.g. Ctrl-click) %s\n", url.Data());
656 return;
657 }
658#endif
659 Info("OpenInBrowser", "A new tab should have opened in your browser.");
660}
661
662namespace {
663enum EUrl { kURLforClass, kURLforNameSpace, kURLforStruct };
664////////////////////////////////////////////////////////////////////////////////
665/// The function generates a URL address for class or namespace (scopeName).
666/// This is the URL to the online reference guide, generated by Doxygen.
667/// With the enumeration "EUrl" we pick which case we need - the one for
668/// class (kURLforClass) or the one for namespace (kURLforNameSpace).
669///
670/// \param[in] scopeName the name of the class or the namespace
671/// \param[in] scopeType the enumerator for class or namespace
672
673static TString UrlGenerator(TString scopeName, EUrl scopeType)
674{
675 // We start the URL with a static part, the same for all scopes and members.
676 TString url = "https://root.cern/doc/";
677 // Then we check the ROOT version used.
678 TPRegexp re4(R"(.*/(v\d)-(\d\d)-00-patches)");
679 const char *branchName = gROOT->GetGitBranch();
680 TObjArray *objarr = re4.MatchS(branchName);
681 TString version;
682 // We extract the correct version name for the URL.
683 if (objarr && objarr->GetEntries() == 3) {
684 // We have a valid version of ROOT and we will extract the correct name for the URL.
685 version = ((TObjString *)objarr->At(1))->GetString() + ((TObjString *)objarr->At(2))->GetString();
686 } else {
687 // If it's not a supported version, we will go to "master" branch.
688 version = "master";
689 }
690 delete objarr;
691 url.Append(version);
692 url.Append("/");
693 // We will replace all "::" with "_1_1" and all "_" with "__" in the
694 // classes definitions, due to Doxygen syntax requirements.
695 scopeName.ReplaceAll("_", "__");
696 scopeName.ReplaceAll("::", "_1_1");
697 // We build the URL for the correct scope type and name.
698 if (scopeType == kURLforClass) {
699 url.Append("class");
700 } else if (scopeType == kURLforStruct) {
701 url.Append("struct");
702 } else {
703 url.Append("namespace");
704 }
705 url.Append(scopeName);
706 url.Append(".html");
707 return url;
708}
709} // namespace
710
711namespace {
712////////////////////////////////////////////////////////////////////////////////
713/// The function returns a TString with the arguments of a method from the
714/// scope (scopeName), but modified with respect to Doxygen syntax - spacing
715/// around special symbols and adding the missing scopes ("std::").
716/// "FormatMethodArgsForDoxygen" works for functions defined inside namespaces
717/// as well. We avoid looking up twice for the TFunction by passing "func".
718///
719/// \param[in] scopeName the name of the class/namespace/struct
720/// \param[in] func pointer to the method
721
722static TString FormatMethodArgsForDoxygen(const TString &scopeName, TFunction *func)
723{
724 // With "GetSignature" we get the arguments of the method and put them in a TString.
725 TString methodArguments = func->GetSignature();
726 // "methodArguments" is modified with respect of Doxygen requirements.
727 methodArguments.ReplaceAll(" = ", "=");
728 methodArguments.ReplaceAll("* ", " *");
729 methodArguments.ReplaceAll("*=", " *=");
730 methodArguments.ReplaceAll("*)", " *)");
731 methodArguments.ReplaceAll("*,", " *,");
732 methodArguments.ReplaceAll("*& ", " *&");
733 methodArguments.ReplaceAll("& ", " &");
734 // TODO: prepend "std::" to all stdlib classes!
735 methodArguments.ReplaceAll("ostream", "std::ostream");
736 methodArguments.ReplaceAll("istream", "std::istream");
737 methodArguments.ReplaceAll("map", "std::map");
738 methodArguments.ReplaceAll("vector", "std::vector");
739 // We need to replace the "currentClass::foo" with "foo" in the arguments.
740 // TODO: protect the global functions.
741 TString scopeNameRE("\\b");
742 scopeNameRE.Append(scopeName);
743 scopeNameRE.Append("::\\b");
744 TPRegexp argFix(scopeNameRE);
745 argFix.Substitute(methodArguments, "");
746 return methodArguments;
747}
748} // namespace
749
750namespace {
751////////////////////////////////////////////////////////////////////////////////
752/// The function returns a TString with the text as an encoded url so that it
753/// can be passed to the function OpenInBrowser
754///
755/// \param[in] text the input text
756/// \return the text appropriately escaped
757
758static TString FormatHttpUrl(TString text)
759{
760 text.ReplaceAll("\n","%0A");
761 text.ReplaceAll("#","%23");
762 text.ReplaceAll(";","%3B");
763 text.ReplaceAll("\"","%22");
764 text.ReplaceAll("`","%60");
765 text.ReplaceAll("+","%2B");
766 text.ReplaceAll("/","%2F");
767 return text;
768}
769} // namespace
770
771namespace {
772////////////////////////////////////////////////////////////////////////////////
773/// The function checks if a member function of a scope is defined as inline.
774/// If so, it also checks if it is virtual. Then the return type of "func" is
775/// modified for the need of Doxygen and with respect to the function
776/// definition. We pass pointer to the method (func) to not re-do the
777/// TFunction lookup.
778///
779/// \param[in] scopeName the name of the class/namespace/struct
780/// \param[in] func pointer to the method
781
782static TString FormatReturnTypeForDoxygen(const TString &scopeName, TFunction *func)
783{
784 // We put the return type of "func" in a TString "returnType".
785 TString returnType = func->GetReturnTypeName();
786 // If the return type is a type nested in the current class, it will appear scoped (Class::Enumeration).
787 // Below we make sure to remove the current class, because the syntax of Doxygen requires it.
788 TString scopeNameRE("\\b");
789 scopeNameRE.Append(scopeName);
790 scopeNameRE.Append("::\\b");
791 TPRegexp returnFix(scopeNameRE);
792 returnFix.Substitute(returnType, "");
793 // We check is if the method is defined as inline.
794 if (func->ExtraProperty() & kIsInlined) {
795 // We check if the function is defined as virtual.
796 if (func->Property() & kIsVirtual) {
797 // If the function is virtual, we append "virtual" before the return type.
798 returnType.Prepend("virtual ");
799 }
800 returnType.ReplaceAll(" *", "*");
801 } else {
802 // If the function is not inline we only change the spacing in "returnType"
803 returnType.ReplaceAll("*", " *");
804 }
805 // In any case (with no respect to virtual/inline check) we need to change
806 // the return type as following.
807 // TODO: prepend "std::" to all stdlib classes!
808 returnType.ReplaceAll("istream", "std::istream");
809 returnType.ReplaceAll("ostream", "std::ostream");
810 returnType.ReplaceAll("map", "std::map");
811 returnType.ReplaceAll("vector", "std::vector");
812 returnType.ReplaceAll("&", " &");
813 return returnType;
814}
815} // namespace
816
817namespace {
818////////////////////////////////////////////////////////////////////////////////
819/// The function generates a URL for "dataMemberName" defined in "scopeName".
820/// It returns a TString with the URL used in the online reference guide,
821/// generated with Doxygen. For data members the URL consist of 2 parts -
822/// URL for "scopeName" and a part for "dataMemberName".
823/// For enumerator, the URL could be separated into 3 parts - URL for
824/// "scopeName", part for the enumeration and a part for the enumerator.
825///
826/// \param[in] scopeName the name of the class/namespace/struct
827/// \param[in] dataMemberName the name of the data member/enumerator
828/// \param[in] dataMember pointer to the data member/enumerator
829/// \param[in] scopeType enumerator to the scope type
830
831static TString
832GetUrlForDataMember(const TString &scopeName, const TString &dataMemberName, TDataMember *dataMember, EUrl scopeType)
833{
834 // We first check if the data member is not enumerator.
835 if (!dataMember->IsEnum()) {
836 // If we work with data members, we have to append a hashed with MD5 text, consisting of:
837 // "Type ClassName::DataMemberNameDataMemberName(arguments)".
838 // We first get the type of the data member.
839 TString md5DataMember(dataMember->GetFullTypeName());
840 md5DataMember.Append(" ");
841 // We append the scopeName and "::".
842 md5DataMember.Append(scopeName);
843 md5DataMember.Append("::");
844 // We append the dataMemberName twice.
845 md5DataMember.Append(dataMemberName);
846 md5DataMember.Append(dataMemberName);
847 // We call UrlGenerator for the scopeName.
848 TString urlForDataMember = UrlGenerator(scopeName, scopeType);
849 // Then we append "#a" and the hashed text.
850 urlForDataMember.Append("#a");
851 urlForDataMember.Append(md5DataMember.MD5());
852 return urlForDataMember;
853 }
854 // If the data member is enumerator, then we first have to check if the enumeration is anonymous.
855 // Doxygen requires different syntax for anonymous enumeration ("scopeName::@1@1").
856 // We create a TString with the name of the scope and the enumeration from which the enumerator is.
857 TString scopeEnumeration = dataMember->GetTrueTypeName();
858 TString md5EnumClass;
859 if (scopeEnumeration.Contains("(unnamed)")) {
860 // FIXME: need to investigate the numbering scheme.
861 md5EnumClass.Append(scopeName);
862 md5EnumClass.Append("::@1@1");
863 } else {
864 // If the enumeration is not anonymous we put "scopeName::Enumeration" in a TString,
865 // which will be hashed with MD5 later.
866 md5EnumClass.Append(scopeEnumeration);
867 // We extract the part after "::" (this is the enumerator name).
868 TString enumOnlyName = TClassEdit::GetUnqualifiedName(scopeEnumeration);
869 // The syntax is "Class::EnumeratorEnumerator
870 md5EnumClass.Append(enumOnlyName);
871 }
872 // The next part of the URL is hashed "@ scopeName::EnumeratorEnumerator".
873 TString md5Enumerator("@ ");
874 md5Enumerator.Append(scopeName);
875 md5Enumerator.Append("::");
876 md5Enumerator.Append(dataMemberName);
877 md5Enumerator.Append(dataMemberName);
878 // We make the URL for the "scopeName".
879 TString url = UrlGenerator(scopeName, scopeType);
880 // Then we have to append the hashed text for the enumerator.
881 url.Append("#a");
882 url.Append(md5EnumClass.MD5());
883 // We append "a" and then the next hashed text.
884 url.Append("a");
885 url.Append(md5Enumerator.MD5());
886 return url;
887}
888} // namespace
889
890namespace {
891////////////////////////////////////////////////////////////////////////////////
892/// The function generates URL for enumeration. The hashed text consist of:
893/// "Class::EnumerationEnumeration".
894///
895/// \param[in] scopeName the name of the class/namespace/struct
896/// \param[in] enumeration the name of the enumeration
897/// \param[in] scopeType enumerator for class/namespace/struct
898
899static TString GetUrlForEnumeration(TString scopeName, const TString &enumeration, EUrl scopeType)
900{
901 // The URL consists of URL for the "scopeName", "#a" and hashed as MD5 text.
902 // The text is "Class::EnumerationEnumeration.
903 TString md5Enumeration(scopeName);
904 md5Enumeration.Append("::");
905 md5Enumeration.Append(enumeration);
906 md5Enumeration.Append(enumeration);
907 // We make the URL for the scope "scopeName".
908 TString url(UrlGenerator(scopeName, scopeType));
909 // Then we have to append "#a" and the hashed text.
910 url.Append("#a");
911 url.Append(md5Enumeration.MD5());
912 return url;
913}
914} // namespace
915
916namespace {
917enum EMethodKind { kURLforMethod, kURLforStructor };
918////////////////////////////////////////////////////////////////////////////////
919/// The function generates URL for any member function (including Constructor/
920/// Destructor) of "scopeName". Doxygen first generates the URL for the scope.
921/// We do that with the help of "UrlGenerator". Then we append "#a" and a
922/// hashed with MD5 text. It consists of:
923/// "ReturnType ScopeName::MethodNameMethodName(Method arguments)".
924/// For constructor/destructor of a class, the return type is not appended.
925///
926/// \param[in] scopeName the name of the class/namespace/struct
927/// \param[in] methodName the name of the method from the scope
928/// \param[in] func pointer to the method
929/// \param[in] methodType enumerator for method or constructor
930/// \param[in] scopeType enumerator for class/namespace/struct
931
932static TString GetUrlForMethod(const TString &scopeName, const TString &methodName, TFunction *func,
933 EMethodKind methodType, EUrl scopeType)
934{
935 TString md5Text;
936 if (methodType == kURLforMethod) {
937 // In the case of method, we append the return type too.
938 // "FormatReturnTypeForDoxygen" modifies the return type with respect to Doxygen's requirement.
939 md5Text.Append((FormatReturnTypeForDoxygen(scopeName, func)));
940 if (scopeType == kURLforNameSpace) {
941 // We need to append "constexpr" if we work with constexpr functions in namespaces.
942 if (func->Property() & kIsConstexpr) {
943 md5Text.Prepend("constexpr ");
944 }
945 }
946 md5Text.Append(" ");
947 }
948 // We append ScopeName::MethodNameMethodName.
949 md5Text.Append(scopeName);
950 md5Text.Append("::");
951 md5Text.Append(methodName);
952 md5Text.Append(methodName);
953 // We use "FormatMethodArgsForDoxygen" to modify the arguments of Method with respect of Doxygen.
954 md5Text.Append(FormatMethodArgsForDoxygen(scopeName, func));
955 // We generate the URL for the class/namespace/struct.
956 TString url = UrlGenerator(scopeName, scopeType);
957 url.Append("#a");
958 // We append the hashed text.
959 url.Append(md5Text.MD5());
960 return url;
961}
962} // namespace
963
964////////////////////////////////////////////////////////////////////////////////
965/// It gets the ROOT installation setup as TString
966///
967/// \return a string with several lines
968///
970{
971 std::vector<TString> lines;
972 lines.emplace_back("```");
973 lines.emplace_back(TString::Format("ROOT v%s",
974 gROOT->GetVersion()));
975 lines.emplace_back(TString::Format("Built for %s on %s", gSystem->GetBuildArch(), gROOT->GetGitDate()));
976 if (!strcmp(gROOT->GetGitBranch(), gROOT->GetGitCommit())) {
977 static const char *months[] = {"January","February","March","April","May",
978 "June","July","August","September","October",
979 "November","December"};
980 Int_t idatqq = gROOT->GetVersionDate();
981 Int_t iday = idatqq%100;
982 Int_t imonth = (idatqq/100)%100;
983 Int_t iyear = (idatqq/10000);
984
985 lines.emplace_back(TString::Format("From tag %s, %d %s %4d",
986 gROOT->GetGitBranch(),
987 iday,months[imonth-1],iyear));
988 } else {
989 // If branch and commit are identical - e.g. "v5-34-18" - then we have
990 // a release build. Else specify the git hash this build was made from.
991 lines.emplace_back(TString::Format("From %s@%s",
992 gROOT->GetGitBranch(),
993 gROOT->GetGitCommit()));
994 }
995 lines.emplace_back(TString::Format("With %s std%ld",
996 gSystem->GetBuildCompilerVersionStr(), __cplusplus));
997 lines.emplace_back("Binary directory: "+ gROOT->GetBinDir());
998 lines.emplace_back("```");
999 TString setup = "";
1000 for (auto& line : lines) {
1001 setup.Append(line);
1002 setup.Append('\n');
1003 }
1004 setup.Chop(); // trim final `\n`
1005 return setup;
1006}
1007
1008////////////////////////////////////////////////////////////////////////////////
1009/// It opens a Forum topic in a web browser with prefilled ROOT version
1010///
1011/// \param[in] type the issue type (only bug supported right now)
1012
1014{
1015 // https://meta.discourse.org/t/how-to-create-a-post-clicking-a-link/96197
1016
1017 if (type == "bug") {
1018 //OpenInBrowser("\"https://root-forum.cern.ch/new-topic?title=topic%20title&body=topic%20body&category=category/subcategory&tags=email,planned\"");
1019 TString report_template =
1020R"(___
1021_Please read [tips for efficient and successful posting](https://root-forum.cern.ch/t/tips-for-efficient-and-successful-posting/28292) and [posting code](https://root-forum.cern.ch/t/posting-code-read-this-first/28293)_
1022
1023### Describe the bug
1024<!--
1025A clear and concise description of what the wrong behavior is.
1026-->
1027### Expected behavior
1028<!--
1029A clear and concise description of what you expected to happen.
1030-->
1031
1032### To Reproduce
1033<!--
1034Steps to reproduce the behavior:
10351. Your code that triggers the issue: at least a part; ideally something we can run ourselves.
10362. Don't forget to attach the required input files!
10373. How to run your code and / or build it, e.g. `root myMacro.C`, ...
1038-->
1039
1040### Setup
1041)"+GetSetup()+
1042R"(
1043<!--
1044Please specify also how you obtained ROOT, such as `dnf install` / binary download / you built it yourself.
1045-->
1046
1047### Additional context
1048<!--
1049Add any other context about the problem here.
1050-->)";
1051 report_template = FormatHttpUrl(report_template);
1052
1053 OpenInBrowser("\"https://root-forum.cern.ch/new-topic?category=ROOT&tags=bug&body="+report_template+"&\"");
1054 } else {
1055 Warning("OpenForumTopic", "cannot find \"%s\" as type for a Forum topic\n"
1056 "Available types are 'bug'.", type.Data());
1057 }
1058}
1059
1060////////////////////////////////////////////////////////////////////////////////
1061/// It opens a GitHub issue in a web browser with prefilled ROOT version
1062///
1063/// \param[in] type the issue type (bug, feature or improvement)
1064
1065void TApplication::OpenGitHubIssue(const TString &type)
1066{
1067 // https://docs.github.com/en/issues/tracking-your-work-with-issues/creating-an-issue#creating-an-issue-from-a-url-query
1068
1069 if (type == "bug") {
1071 "\"https://github.com/root-project/root/issues/new?labels=bug&template=bug_report.yml&root-version=" +
1072 FormatHttpUrl(GetSetup()) + "\"");
1073 } else if (type == "improvement") {
1074 OpenInBrowser("\"https://github.com/root-project/root/issues/"
1075 "new?labels=improvement&template=improvement_report.yml&root-version=" +
1076 FormatHttpUrl(GetSetup()) + "\"");
1077 } else if (type == "feature") {
1079 "\"https://github.com/root-project/root/issues/new?labels=new+feature&template=feature_request.yml\"");
1080 } else {
1081 Warning("OpenGitHubIssue",
1082 "Cannot find GitHub issue type \"%s\".\n"
1083 "Available types are 'bug', 'feature' and 'improvement'.",
1084 type.Data());
1085 }
1086}
1087
1088////////////////////////////////////////////////////////////////////////////////
1089/// It opens the online reference guide, generated with Doxygen, for the
1090/// chosen scope (class/namespace/struct) or member (method/function/
1091/// data member/enumeration/enumerator. If the user types incorrect value,
1092/// it will return an error or warning.
1093///
1094/// \param[in] strippedClass the scope or scope::member
1095
1096void TApplication::OpenReferenceGuideFor(const TString &strippedClass)
1097{
1098 // We check if the user is searching for a scope and if the scope exists.
1099 if (TClass *clas = TClass::GetClass(strippedClass)) {
1100 // We check what scope he is searching for (class/namespace/struct).
1101 // Enumerators will switch between the possible cases.
1102 EUrl scopeType;
1103 if (clas->Property() & kIsNamespace) {
1104 scopeType = kURLforNameSpace;
1105 } else if (clas->Property() & kIsStruct) {
1106 scopeType = kURLforStruct;
1107 } else {
1108 scopeType = kURLforClass;
1109 }
1110 // If the user search directly for a scope we open the URL for him with OpenInBrowser.
1111 OpenInBrowser(UrlGenerator(strippedClass, scopeType));
1112 return;
1113 }
1114 // Else we subtract the name of the method and remove it from the command.
1115 TString memberName = TClassEdit::GetUnqualifiedName(strippedClass);
1116 // Error out if "strippedClass" is un-scoped (and it's not a class, see `TClass::GetClass(strippedClass)` above).
1117 // TODO: Global functions.
1118 if (strippedClass == memberName) {
1119 Error("OpenReferenceGuideFor", "Unknown entity \"%s\" - global variables / functions not supported yet!",
1120 strippedClass.Data());
1121 return;
1122 }
1123 // Else we remove the member name to be left with the scope.
1124 TString scopeName = strippedClass(0, strippedClass.Length() - memberName.Length() - 2);
1125 // We check if the scope exists in ROOT.
1126 TClass *cl = TClass::GetClass(scopeName);
1127 if (!cl) {
1128 // That's a member of something ROOT doesn't know.
1129 Warning("OpenReferenceGuideFor", "\"%s\" does not exist in ROOT!", scopeName.Data());
1130 return;
1131 }
1132 // We have enumerators for the three available cases - class, namespace and struct.
1133 EUrl scopeType;
1134 if (cl->Property() & kIsNamespace) {
1135 scopeType = kURLforNameSpace;
1136 } else if (cl->Property() & kIsStruct) {
1137 scopeType = kURLforStruct;
1138 } else {
1139 scopeType = kURLforClass;
1140 }
1141 // If the user wants to search for a method, we take its name (memberName) and
1142 // modify it - we delete everything starting at the first "(" so the user won't have to
1143 // do it by hand when they use Tab.
1144 int bracket = memberName.First("(");
1145 if (bracket > 0) {
1146 memberName.Remove(bracket);
1147 }
1148 // We check if "memberName" is a member function of "cl" or any of its base classes.
1149 if (TFunction *func = cl->GetMethodAllAny(memberName)) {
1150 // If so we find the name of the class that it belongs to.
1151 TString baseClName = ((TMethod *)func)->GetClass()->GetName();
1152 // We define an enumerator to distinguish between structor and method.
1153 EMethodKind methodType;
1154 // We check if "memberName" is a constructor.
1155 if (baseClName == memberName) {
1156 methodType = kURLforStructor;
1157 // We check if "memberName" is a destructor.
1158 } else if (memberName[0] == '~') {
1159 methodType = kURLforStructor;
1160 // We check if "memberName" is a method.
1161 } else {
1162 methodType = kURLforMethod;
1163 }
1164 // We call "GetUrlForMethod" for the correct class and scope.
1165 OpenInBrowser(GetUrlForMethod(baseClName, memberName, func, methodType, scopeType));
1166 return;
1168 // We check if "memberName" is an enumeration.
1169 if (cl->GetListOfEnums()->FindObject(memberName)) {
1170 // If so with OpenInBrowser we open the URL generated with GetUrlForEnumeration
1171 // with respect to the "scopeType".
1172 OpenInBrowser(GetUrlForEnumeration(scopeName, memberName, scopeType));
1173 return;
1174 }
1175
1176 // We check if "memberName" is enumerator defined in one the base classes of "scopeName".
1177 if (auto enumerator = (TDataMember *)cl->GetListOfAllPublicDataMembers()->FindObject(memberName)) {
1178 // We find the actual scope (might be in a base) and open the URL in a browser.
1179 TString baseClName = ((TMethod *)enumerator->GetClass())->GetName();
1180 OpenInBrowser(GetUrlForDataMember(baseClName, memberName, enumerator, scopeType));
1181 return;
1182 }
1183
1184 // Warning message will appear if the user types the function name incorrectly
1185 // or the function is not a member function of "cl" or any of its base classes.
1186 Warning("OpenReferenceGuideFor", "cannot find \"%s\" as member of %s or its base classes! Check %s\n", memberName.Data(),
1187 scopeName.Data(), UrlGenerator(scopeName, scopeType).Data());
1189
1190////////////////////////////////////////////////////////////////////////////////
1191/// The function (".forum <type>") submits a new post on the ROOT forum
1192/// via web browser.
1193/// \note You can use "bug" as <type>.
1194/// \param[in] line command from the command line
1195
1196void TApplication::Forum(const char *line)
1197{
1198 // We first check if the user chose a correct syntax.
1199 TString strippedCommand = TString(line).Strip(TString::kBoth);
1200 if (!strippedCommand.BeginsWith(".forum ")) {
1201 Error("Forum", "Unknown command! Use 'bug' after '.forum '");
1202 return;
1203 }
1204 // We remove the command ".forum" from the TString.
1205 strippedCommand.Remove(0, 7);
1206 // We strip the command line after removing ".help" or ".?".
1207 strippedCommand = strippedCommand.Strip(TString::kBoth);
1208
1209 OpenForumTopic(strippedCommand);
1211
1212////////////////////////////////////////////////////////////////////////////////
1213/// The function (".gh <type>") submits a new issue on GitHub via web browser.
1214/// \note You can use "bug", "feature" or "improvement" as <type>.
1215/// \param[in] line command from the command line
1216
1217void TApplication::GitHub(const char *line)
1218{
1219 // We first check if the user chose a correct syntax.
1220 TString strippedCommand = TString(line).Strip(TString::kBoth);
1221 if (!strippedCommand.BeginsWith(".gh ")) {
1222 Error("GitHub", "Unknown command! Use 'bug', 'feature' or 'improvement' after '.gh '");
1223 return;
1224 }
1225 // We remove the command ".gh" from the TString.
1226 strippedCommand.Remove(0, 4);
1227 // We strip the command line after removing ".help" or ".?".
1228 strippedCommand = strippedCommand.Strip(TString::kBoth);
1229
1230 OpenGitHubIssue(strippedCommand);
1231}
1232
1233////////////////////////////////////////////////////////////////////////////////
1234/// The function lists useful commands (".help") or opens the online reference
1235/// guide, generated with Doxygen (".help scope" or ".help scope::member").
1236/// \note You can use ".?" as the short version of ".help"
1237/// \param[in] line command from the command line
1238
1239void TApplication::Help(const char *line)
1240{
1241 // We first check if the user wants to print the help on the interpreter.
1242 TString strippedCommand = TString(line).Strip(TString::kBoth);
1243 // If the user chooses ".help" or ".?".
1244 if ((strippedCommand == ".help") || (strippedCommand == ".?")) {
1245 gInterpreter->ProcessLine(line);
1246 Printf("\n ROOT special commands.");
1247 Printf(" ==============================================================================");
1248 Printf(" .L <filename>[flags]: load the given file with optional flags like\n"
1249 " + to compile or ++ to force recompile.\n"
1250 " Type .? TSystem::CompileMacro for a list of all flags.\n"
1251 " <filename> can also be a shared library; skip flags.");
1252 Printf(" .(x|X) <filename>[flags](args) :\n"
1253 " same as .L <filename>[flags] and runs then a function\n"
1254 " with signature: ret_type filename(args).");
1255 Printf(" .credits : show credits");
1256 Printf(" .demo : launch GUI demo");
1257 Printf(" .forum bug : ask for help with a bug or crash at the ROOT forum.");
1258 Printf(" .gh [bug|feature|improvement]\n"
1259 " : submit a bug report, feature or improvement suggestion");
1260 Printf(" .help Class::Member : open reference guide for that class member (or .?).\n"
1261 " Specifying '::Member' is optional.");
1262 Printf(" .help edit : show line editing shortcuts (or .?)");
1263 Printf(" .license : show license");
1264 Printf(" .libraries : show loaded libraries");
1265 Printf(" .ls : list contents of current TDirectory");
1266 Printf(" .pwd : show current TDirectory, pad and style");
1267 Printf(" .quit (or .exit) : quit ROOT (long form of .q)");
1268 Printf(" .R [user@]host[:dir] [-l user] [-d dbg] [script] :\n"
1269 " launch process in a remote host");
1270 Printf(" .qqq : quit ROOT - mandatory");
1271 Printf(" .qqqqq : exit process immediately");
1272 Printf(" .qqqqqqq : abort process");
1273 Printf(" .which [file] : show path of macro file");
1274 Printf(" .![OS_command] : execute OS-specific shell command");
1275 Printf(" .!root -? : print ROOT usage (CLI options)");
1276 return;
1277 } else {
1278 // If the user wants to use the extended ".help scopeName" command to access
1279 // the online reference guide, we first check if the command starts correctly.
1280 if ((!strippedCommand.BeginsWith(".help ")) && (!strippedCommand.BeginsWith(".? "))) {
1281 Error("Help", "Unknown command!");
1282 return;
1283 }
1284 // We remove the command ".help" or ".?" from the TString.
1285 if (strippedCommand.BeginsWith(".? ")) {
1286 strippedCommand.Remove(0, 3);
1287 } else {
1288 strippedCommand.Remove(0, 5);
1289 }
1290 // We strip the command line after removing ".help" or ".?".
1291 strippedCommand = strippedCommand.Strip(TString::kBoth);
1292
1293 if (strippedCommand == "edit") {
1294 Printf("\n ROOT terminal keyboard shortcuts (GNU-readline style).");
1295 #ifdef R__MACOSX
1296 #define FOOTNOTE " *"
1297 Printf("* Some of these commands might be intercepted by macOS predefined system shortcuts.");
1298 // https://apple.stackexchange.com/questions/18043/how-can-i-make-ctrlright-left-arrow-stop-changing-desktops-in-lion
1299 #else
1300 #define FOOTNOTE ""
1301 #endif
1302 Printf(" ==============================================================================");
1303 Printf(" Arrow_Left : move cursor left [Ctrl+B]");
1304 Printf(" Arrow_Right : move cursor right [Ctrl+F] [Ctrl+G]");
1305 #ifdef R__MACOSX
1306 Printf(" Fn+Arrow_Left : move cursor to beginning of line [Ctrl+A]");
1307 #else
1308 Printf(" Home : move cursor to beginning of line [Ctrl+A]");
1309 #endif
1310 #ifdef R__MACOSX
1311 Printf(" Fn+Arrow_Right : move cursor to end of line [Ctrl+E]");
1312 #else
1313 Printf(" End : move cursor to end of line [Ctrl+E]");
1314 #endif
1315 Printf(" Ctrl+Arrow_Left : jump to previous word [Esc,B] [Alt,B]" FOOTNOTE);
1316 Printf(" Ctrl+Arrow_Right : jump to next word [Esc,F] [Alt,F]" FOOTNOTE);
1317
1318 Printf(" Backspace : delete previous character [Ctrl+H]");
1319 Printf(" Del : delete next character [Ctrl+D]");
1320 Printf(" Esc,Backspace : delete previous word [Ctrl+W] [Esc,Ctrl+H] [Alt+Backspace] [Esc,Del] [Esc,Ctrl+Del]" FOOTNOTE);// Del is 0x7F on macOS
1321 Printf(" Ctrl+Del : delete next word [Esc,D] [Alt,D]" FOOTNOTE);
1322 Printf(" Ctrl+U : cut all characters between cursor and start of line");
1323 Printf(" Ctrl+K : cut all characters between cursor and end of line");
1324
1325 Printf(" Ctrl+T : transpose characters");
1326 Printf(" Esc,C : character to upper and jump to next word");
1327 Printf(" Esc,L : word to lower case and jump to its end");
1328 Printf(" Esc,U : word to upper case and jump to its end");
1329 Printf(" Ctrl+Shift+C : copy clipboard content");
1330 Printf(" Ctrl+Shift+V : paste clipboard content [Ctrl+Y] [Alt+Y]");
1331 #ifdef R__MACOSX
1332 Printf(" Fn+Enter : toggle overwrite mode");
1333 #else
1334 Printf(" Ins : toggle overwrite mode");
1335 #endif
1337 Printf(" Ctrl+_ : undo last keypress action");
1338 Printf(" Tab : autocomplete command or print suggestions [Ctrl+I] [Esc,Tab]");
1339 Printf(" Enter : execute command [Ctrl+J] [Ctrl+M]");
1340 Printf(" Ctrl+L : clear prompt screen");
1341 Printf(" Ctrl+D : quit ROOT (if empty line)");
1342 Printf(" Ctrl+C : send kSigInt interrupt signal");
1343 Printf(" Ctrl+Z : send kSigStop pause job signal");
1344 Printf(" Ctrl+\\ : send kSigQuit quit job signal");
1345
1346 Printf(" Arrow_Down : navigate downwards in command history [Ctrl+N]");
1347 Printf(" Arrow_Up : navigate upwards in command history [Ctrl+P]");
1348 Printf(" Ctrl+R ; Ctrl+S : search command in your history by typing a string.\n"
1349 " Use Backspace if you mistyped (but not arrows).\n"
1350 " Press Ctrl+R (Ctrl+S) repeateadly to navigate matches in reverse (forward) order");
1351 Printf(" Arrow_Right : after Ctrl+R (Ctrl+S), select current match of the history search\n"
1352 " [Ctrl+O] [Enter] [Ctrl+J] [Ctrl+M] [Arrow_Left] [Esc,Esc].\n"
1353 " Use Ctrl+F or Ctrl+G to cancel search and revert original line");
1354
1355 return;
1356 }
1357 // We call the function what handles the extended ".help scopeName" command.
1358 OpenReferenceGuideFor(strippedCommand);
1359 }
1360}
1361
1362/// Load shared libs necessary for graphics. These libraries are only
1363/// loaded when gROOT->IsBatch() is kFALSE.
1364
1366{
1367 if (gROOT->IsBatch())
1368 return;
1369
1370 if (auto h = gROOT->GetPluginManager()->FindHandler("TVirtualPad"))
1371 if (h->LoadPlugin() == -1)
1372 return;
1373
1374 TString name;
1375 TString title1 = "ROOT interface to ";
1376 TString nativex, title;
1377
1378#ifdef R__WIN32
1379 nativex = "win32gdk";
1380 name = "Win32gdk";
1381 title = title1 + "Win32gdk";
1382#elif defined(R__HAS_COCOA)
1383 nativex = "quartz";
1384 name = "quartz";
1385 title = title1 + "Quartz";
1386#else
1387 nativex = "x11";
1388 name = "X11";
1389 title = title1 + "X11";
1390#endif
1391
1392 TString guiBackend = gEnv->GetValue("Gui.Backend", "native");
1393 guiBackend.ToLower();
1394 if (guiBackend == "native") {
1395 guiBackend = nativex;
1396 } else {
1397 name = guiBackend;
1398 title = title1 + guiBackend;
1399 }
1400
1401 if (auto h = gROOT->GetPluginManager()->FindHandler("TVirtualX", guiBackend)) {
1402 if (h->LoadPlugin() == -1) {
1403 gROOT->SetBatch(kTRUE);
1404 return;
1405 }
1406 gVirtualX = (TVirtualX *) h->ExecPlugin(2, name.Data(), title.Data());
1408 }
1409
1410 TString guiFactory = gEnv->GetValue("Gui.Factory", "native");
1411 guiFactory.ToLower();
1412 if (guiFactory == "native")
1413 guiFactory = "root";
1414
1415 if (auto h = gROOT->GetPluginManager()->FindHandler("TGuiFactory", guiFactory)) {
1416 if (h->LoadPlugin() == -1) {
1417 gROOT->SetBatch(kTRUE);
1418 return;
1419 }
1420 gGuiFactory = (TGuiFactory *) h->ExecPlugin(0);
1421 }
1423
1424////////////////////////////////////////////////////////////////////////////////
1425/// Switch to batch mode.
1426
1428{
1429 gROOT->SetBatch();
1432#ifndef R__WIN32
1433 if (gVirtualX != gGXBatch) delete gVirtualX;
1434#endif
1436}
1437
1438////////////////////////////////////////////////////////////////////////////////
1439/// Parse the content of a line starting with ".R" (already stripped-off)
1440/// The format is
1441/// ~~~ {.cpp}
1442/// [user@]host[:dir] [-l user] [-d dbg] [script]
1443/// ~~~
1444/// The variable 'dir' is the remote directory to be used as working dir.
1445/// The username can be specified in two ways, "-l" having the priority
1446/// (as in ssh).
1447/// A 'dbg' value > 0 gives increasing verbosity.
1448/// The last argument 'script' allows to specify an alternative script to
1449/// be executed remotely to startup the session.
1450
1452 TString &hostdir, TString &user,
1453 Int_t &dbg, TString &script)
1454{
1455 if (!ln || strlen(ln) <= 0)
1456 return 0;
1457
1458 Int_t rc = 0;
1459 Bool_t isHostDir = kTRUE;
1460 Bool_t isScript = kFALSE;
1461 Bool_t isUser = kFALSE;
1462 Bool_t isDbg = kFALSE;
1463
1464 TString line(ln);
1465 TString tkn;
1466 Int_t from = 0;
1467 while (line.Tokenize(tkn, from, " ")) {
1468 if (tkn == "-l") {
1469 // Next is a user name
1470 isUser = kTRUE;
1471 } else if (tkn == "-d") {
1472 isDbg = kTRUE;
1473 } else if (tkn == "-close") {
1474 rc = 1;
1475 } else if (tkn.BeginsWith("-")) {
1476 ::Warning("TApplication::ParseRemoteLine","unknown option: %s", tkn.Data());
1477 } else {
1478 if (isUser) {
1479 user = tkn;
1480 isUser = kFALSE;
1481 } else if (isDbg) {
1482 dbg = tkn.Atoi();
1483 isDbg = kFALSE;
1484 } else if (isHostDir) {
1485 hostdir = tkn;
1486 hostdir.ReplaceAll(":","/");
1487 isHostDir = kFALSE;
1488 isScript = kTRUE;
1489 } else if (isScript) {
1490 // Add everything left
1491 script = tkn;
1492 script.Insert(0, "\"");
1493 script += "\"";
1494 // isScript = kFALSE; // [clang-tidy] never read
1495 break;
1496 }
1497 }
1498 }
1499
1500 // Done
1501 return rc;
1502}
1503
1504////////////////////////////////////////////////////////////////////////////////
1505/// Process the content of a line starting with ".R" (already stripped-off)
1506/// The format is
1507/// ~~~ {.cpp}
1508/// [user@]host[:dir] [-l user] [-d dbg] [script] | [host] -close
1509/// ~~~
1510/// The variable 'dir' is the remote directory to be used as working dir.
1511/// The username can be specified in two ways, "-l" having the priority
1512/// (as in ssh).
1513/// A 'dbg' value > 0 gives increasing verbosity.
1514/// The last argument 'script' allows to specify an alternative script to
1515/// be executed remotely to startup the session.
1516
1518{
1519 if (!line) return 0;
1520
1521 if (!strncmp(line, "-?", 2) || !strncmp(line, "-h", 2) ||
1522 !strncmp(line, "--help", 6)) {
1523 Info("ProcessRemote", "remote session help:");
1524 Printf(".R [user@]host[:dir] [-l user] [-d dbg] [[<]script] | [host] -close");
1525 Printf("Create a ROOT session on the specified remote host.");
1526 Printf("The variable \"dir\" is the remote directory to be used as working dir.");
1527 Printf("The username can be specified in two ways, \"-l\" having the priority");
1528 Printf("(as in ssh). A \"dbg\" value > 0 gives increasing verbosity.");
1529 Printf("The last argument \"script\" allows to specify an alternative script to");
1530 Printf("be executed remotely to startup the session, \"roots\" being");
1531 Printf("the default. If the script is preceded by a \"<\" the script will be");
1532 Printf("sourced, after which \"roots\" is executed. The sourced script can be ");
1533 Printf("used to change the PATH and other variables, allowing an alternative");
1534 Printf("\"roots\" script to be found.");
1535 Printf("To close down a session do \".R host -close\".");
1536 Printf("To switch between sessions do \".R host\", to switch to the local");
1537 Printf("session do \".R\".");
1538 Printf("To list all open sessions do \"gApplication->GetApplications()->Print()\".");
1539 return 0;
1540 }
1541
1542 TString hostdir, user, script;
1543 Int_t dbg = 0;
1544 Int_t rc = ParseRemoteLine(line, hostdir, user, dbg, script);
1545 if (hostdir.Length() <= 0) {
1546 // Close the remote application if required
1547 if (rc == 1) {
1549 delete fAppRemote;
1550 }
1551 // Return to local run
1552 fAppRemote = nullptr;
1553 // Done
1554 return 1;
1555 } else if (rc == 1) {
1556 // close an existing remote application
1557 TApplication *ap = TApplication::Open(hostdir, 0, nullptr);
1558 if (ap) {
1560 delete ap;
1561 }
1562 }
1563 // Attach or start a remote application
1564 if (user.Length() > 0)
1565 hostdir.Insert(0, TString::Format("%s@", user.Data()));
1566 const char *sc = (script.Length() > 0) ? script.Data() : nullptr;
1567 TApplication *ap = TApplication::Open(hostdir, dbg, sc);
1568 if (ap) {
1569 fAppRemote = ap;
1570 }
1571
1572 // Done
1573 return 1;
1574}
1575
1576namespace {
1577 static int PrintFile(const char* filename) {
1578 TString sFileName(filename);
1579 gSystem->ExpandPathName(sFileName);
1580 if (gSystem->AccessPathName(sFileName)) {
1581 Error("ProcessLine()", "Cannot find file %s", filename);
1582 return 1;
1583 }
1584 std::ifstream instr(sFileName);
1585 TString content;
1586 content.ReadFile(instr);
1587 Printf("%s", content.Data());
1588 return 0;
1589 }
1590 } // namespace
1591
1592////////////////////////////////////////////////////////////////////////////////
1593/// Process a single command line, either a C++ statement or an interpreter
1594/// command starting with a ".".
1595/// Return the return value of the command cast to a long.
1596
1598{
1599 if (!line || !*line) return 0;
1600
1601 // If we are asked to go remote do it
1602 if (!strncmp(line, ".R", 2)) {
1603 Int_t n = 2;
1604 while (*(line+n) == ' ')
1605 n++;
1606 return ProcessRemote(line+n, err);
1607 }
1608
1609 // Redirect, if requested
1612 return fAppRemote->ProcessLine(line, err);
1613 }
1614
1615 if (!strncasecmp(line, ".qqqqqqq", 7)) {
1616 gSystem->Abort();
1617 } else if (!strncasecmp(line, ".qqqqq", 5)) {
1618 Info("ProcessLine", "Bye... (try '.qqqqqqq' if still running)");
1619 gSystem->Exit(1);
1620 } else if (!strncasecmp(line, ".exit", 4) || !strncasecmp(line, ".quit", 2)) {
1621 Terminate(0);
1622 return 0;
1623 }
1624
1625 if (!strncmp(line, ".gh", 3)) {
1626 GitHub(line);
1627 return 1;
1628 }
1629
1630 if (!strncmp(line, ".forum", 6)) {
1631 Forum(line);
1632 return 1;
1633 }
1634
1635 if (!strncmp(line, ".?", 2) || !strncmp(line, ".help", 5)) {
1636 Help(line);
1637 return 1;
1638 }
1639
1640 if (!strncmp(line, ".demo", 5)) {
1641 if (gROOT->IsBatch()) {
1642 Error("ProcessLine", "Cannot show demos in batch mode!");
1643 return 1;
1644 }
1645 ProcessLine(".x " + TROOT::GetTutorialDir() + "/demos.C");
1646 return 0;
1647 }
1648
1649 if (!strncmp(line, ".license", 8)) {
1650 return PrintFile(TROOT::GetDocDir() + "/LICENSE");
1651 }
1652
1653 if (!strncmp(line, ".credits", 8)) {
1654 TString credits = TROOT::GetDocDir() + "/CREDITS";
1655 if (gSystem->AccessPathName(credits, kReadPermission))
1656 credits = TROOT::GetDocDir() + "/README/CREDITS";
1657 return PrintFile(credits);
1658 }
1659
1660 if (!strncmp(line, ".pwd", 4)) {
1661 if (gDirectory)
1662 Printf("Current directory: %s", gDirectory->GetPath());
1663 if (gPad)
1664 Printf("Current pad: %s", gPad->GetName());
1665 if (gStyle)
1666 Printf("Current style: %s", gStyle->GetName());
1667 return 1;
1668 }
1669
1670 if (!strncmp(line, ".ls", 3)) {
1671 const char *opt = nullptr;
1672 if (line[3]) opt = &line[3];
1673 if (gDirectory) gDirectory->ls(opt);
1674 return 1;
1675 }
1676
1677 if (!strncmp(line, ".which", 6)) {
1678 char *fn = Strip(line+7);
1679 char *s = strtok(fn, "+("); // this method does not need to be reentrant
1680 char *mac = gSystem->Which(TROOT::GetMacroPath(), s, kReadPermission);
1681 if (!mac)
1682 Printf("No macro %s in path %s", s, TROOT::GetMacroPath());
1683 else
1684 Printf("%s", mac);
1685 delete [] fn;
1686 delete [] mac;
1687 return mac ? 1 : 0;
1688 }
1689
1690 if (!strncmp(line, ".L", 2) || !strncmp(line, ".U", 2)) {
1691 TString aclicMode, arguments, io;
1692 TString fname = gSystem->SplitAclicMode(line+3, aclicMode, arguments, io);
1693
1694 char *mac = gSystem->Which(TROOT::GetMacroPath(), fname, kReadPermission);
1695 if (arguments.Length())
1696 Warning("ProcessLine", "argument(s) \"%s\" ignored with .%c", arguments.Data(), line[1]);
1697 Longptr_t retval = 0;
1698 if (!mac) {
1699 Error("ProcessLine", "macro %s not found in path %s", fname.Data(), TROOT::GetMacroPath());
1700 } else {
1701 TString cmd(line + 1);
1702 Ssiz_t posSpace = cmd.Index(' ');
1703 if (posSpace == kNPOS)
1704 cmd.Remove(1);
1705 else
1706 cmd.Remove(posSpace);
1707 auto tempbuf = TString::Format(".%s %s%s%s", cmd.Data(), mac, aclicMode.Data(), io.Data());
1708 delete[] mac;
1709 if (sync)
1710 retval = gInterpreter->ProcessLineSynch(tempbuf.Data(), (TInterpreter::EErrorCode *)err);
1711 else
1712 retval = gInterpreter->ProcessLine(tempbuf.Data(), (TInterpreter::EErrorCode *)err);
1713 }
1714
1715 InitializeGraphics(gROOT->IsWebDisplay());
1716
1717 return retval;
1718 }
1719
1720 if (!strncmp(line, ".X", 2) || !strncmp(line, ".x", 2)) {
1721 return ProcessFile(line+3, err, line[2] == 'k');
1722 }
1724 if (!strcmp(line, ".reset")) {
1725 // Do nothing, .reset disabled in Cling because too many side effects
1726 Printf("*** .reset not allowed, please use gROOT->Reset() ***");
1727 return 0;
1728
1729#if 0
1730 // delete the ROOT dictionary since CINT will destroy all objects
1731 // referenced by the dictionary classes (TClass et. al.)
1732 gROOT->GetListOfClasses()->Delete();
1733 // fall through
1734#endif
1735 }
1736
1737 if (!strcmp(line, ".libraries")) {
1738 // List the loaded libraries
1739 gSystem->ListLibraries();
1740 return 0;
1741 }
1742
1743 if (sync)
1744 return gInterpreter->ProcessLineSynch(line, (TInterpreter::EErrorCode*)err);
1745 else
1746 return gInterpreter->ProcessLine(line, (TInterpreter::EErrorCode*)err);
1747}
1748
1749////////////////////////////////////////////////////////////////////////////////
1750/// Process a file containing a C++ macro.
1751
1752Longptr_t TApplication::ProcessFile(const char *file, Int_t *error, Bool_t keep)
1753{
1754 return ExecuteFile(file, error, keep);
1755}
1756
1757////////////////////////////////////////////////////////////////////////////////
1758/// Execute a file containing a C++ macro (static method). Can be used
1759/// while TApplication is not yet created.
1760
1761Longptr_t TApplication::ExecuteFile(const char *file, Int_t *error, Bool_t keep)
1762{
1763 static const Int_t kBufSize = 1024;
1764
1765 if (!file || !*file) return 0;
1766
1767 TString aclicMode;
1768 TString arguments;
1769 TString io;
1770 TString fname = gSystem->SplitAclicMode(file, aclicMode, arguments, io);
1771
1772 char *exnam = gSystem->Which(TROOT::GetMacroPath(), fname, kReadPermission);
1773 if (!exnam) {
1774 ::Error("TApplication::ExecuteFile", "macro %s not found in path %s", fname.Data(),
1776 delete [] exnam;
1777 if (error)
1779 return 0;
1780 }
1781
1782 ::std::ifstream macro(exnam, std::ios::in);
1783 if (!macro.good()) {
1784 ::Error("TApplication::ExecuteFile", "%s no such file", exnam);
1785 if (error)
1787 delete [] exnam;
1788 return 0;
1789 }
1790
1791 char currentline[kBufSize];
1792 char dummyline[kBufSize];
1793 int tempfile = 0;
1794 int comment = 0;
1795 int ifndefc = 0;
1796 int ifdef = 0;
1797 char *s = nullptr;
1798 Bool_t execute = kFALSE;
1799 Longptr_t retval = 0;
1800
1801 while (1) {
1802 bool res = (bool)macro.getline(currentline, kBufSize);
1803 if (macro.eof()) break;
1804 if (!res) {
1805 // Probably only read kBufSize, let's ignore the remainder of
1806 // the line.
1807 macro.clear();
1808 while (!macro.getline(dummyline, kBufSize) && !macro.eof()) {
1809 macro.clear();
1810 }
1811 }
1812 s = currentline;
1813 while (s && (*s == ' ' || *s == '\t')) s++; // strip-off leading blanks
1814
1815 // very simple minded pre-processor parsing, only works in case macro file
1816 // starts with "#ifndef __CLING__" (__CINT__ for backward compatibility).
1817 // In that case everything till next "#else" or "#endif" will be skipped.
1818 if (*s == '#') {
1819 char *cs = Compress(currentline);
1820 if (strstr(cs, "#ifndef__CLING__") || strstr(cs, "#ifndef__CINT__") ||
1821 strstr(cs, "#if!defined(__CLING__)") || strstr(cs, "#if!defined(__CINT__)"))
1822 ifndefc = 1;
1823 else if (ifndefc && (strstr(cs, "#ifdef") || strstr(cs, "#ifndef") ||
1824 strstr(cs, "#ifdefined") || strstr(cs, "#if!defined")))
1825 ifdef++;
1826 else if (ifndefc && strstr(cs, "#endif")) {
1827 if (ifdef)
1828 ifdef--;
1829 else
1830 ifndefc = 0;
1831 } else if (ifndefc && !ifdef && strstr(cs, "#else"))
1832 ifndefc = 0;
1833 delete [] cs;
1834 }
1835 if (!*s || *s == '#' || ifndefc || !strncmp(s, "//", 2)) continue;
1836
1837 if (!comment && (!strncmp(s, ".X", 2) || !strncmp(s, ".x", 2))) {
1838 retval = ExecuteFile(s+3);
1839 execute = kTRUE;
1840 continue;
1841 }
1842
1843 if (!strncmp(s, "/*", 2)) comment = 1;
1844 if (comment) {
1845 // handle slightly more complex cases like: /* */ /*
1846again:
1847 s = strstr(s, "*/");
1848 if (s) {
1849 comment = 0;
1850 s += 2;
1851
1852 while (s && (*s == ' ' || *s == '\t')) s++; // strip-off leading blanks
1853 if (!*s) continue;
1854 if (!strncmp(s, "//", 2)) continue;
1855 if (!strncmp(s, "/*", 2)) {
1856 comment = 1;
1857 goto again;
1858 }
1859 }
1860 }
1861 if (!comment && *s == '{') tempfile = 1;
1862 if (!comment) break;
1864 macro.close();
1865
1866 if (!execute) {
1867 TString exname = exnam;
1868 if (!tempfile) {
1869 // We have a script that does NOT contain an unnamed macro,
1870 // so we can call the script compiler on it.
1871 exname += aclicMode;
1872 }
1873 exname += arguments;
1874 exname += io;
1875
1876 TString tempbuf;
1877 if (tempfile) {
1878 tempbuf.Form(".x %s", exname.Data());
1879 } else {
1880 tempbuf.Form(".X%s %s", keep ? "k" : " ", exname.Data());
1881 }
1882 retval = gInterpreter->ProcessLineSynch(tempbuf,(TInterpreter::EErrorCode*)error);
1883 }
1884
1885 delete [] exnam;
1886 return retval;
1887}
1889////////////////////////////////////////////////////////////////////////////////
1890/// Main application eventloop. Calls system dependent eventloop via gSystem.
1891
1892void TApplication::Run(Bool_t retrn)
1893{
1894 SetReturnFromRun(retrn);
1895
1896 fIsRunning = kTRUE;
1897
1898 gSystem->Run();
1900}
1901
1902////////////////////////////////////////////////////////////////////////////////
1903/// Set the command to be executed after the system has been idle for
1904/// idleTimeInSec seconds. Normally called via TROOT::Idle(...).
1905
1906void TApplication::SetIdleTimer(UInt_t idleTimeInSec, const char *command)
1907{
1909 fIdleCommand = command;
1910 fIdleTimer = new TIdleTimer(idleTimeInSec*1000);
1911 gSystem->AddTimer(fIdleTimer);
1912}
1913
1914////////////////////////////////////////////////////////////////////////////////
1915/// Remove idle timer. Normally called via TROOT::Idle(0).
1916
1918{
1919 if (fIdleTimer) {
1920 // timers are removed from the gSystem timer list by their dtor
1922 }
1923}
1924
1925////////////////////////////////////////////////////////////////////////////////
1926/// Called when system starts idleing.
1927
1929{
1931 fIdleTimer->Reset();
1932 gSystem->AddTimer(fIdleTimer);
1933 }
1934}
1935
1936////////////////////////////////////////////////////////////////////////////////
1937/// Called when system stops idleing.
1938
1940{
1941 if (fIdleTimer)
1942 gSystem->RemoveTimer(fIdleTimer);
1943}
1945////////////////////////////////////////////////////////////////////////////////
1946/// What to do when tab is pressed. Re-implemented by TRint.
1947/// See TTabCom::Hook() for meaning of return values.
1948
1949Int_t TApplication::TabCompletionHook(char* /*buf*/, int* /*pLoc*/, std::ostream& /*out*/)
1950{
1951 return -1;
1953
1954
1955////////////////////////////////////////////////////////////////////////////////
1956/// Terminate the application by call TSystem::Exit() unless application has
1957/// been told to return from Run(), by a call to SetReturnFromRun().
1958
1959void TApplication::Terminate(Int_t status)
1961 Emit("Terminate(Int_t)", status);
1962
1963 if (fReturnFromRun)
1964 gSystem->ExitLoop();
1965 else {
1966 gSystem->Exit(status);
1967 }
1968}
1969
1970////////////////////////////////////////////////////////////////////////////////
1971/// Emit signal when a line has been processed.
1972
1973void TApplication::LineProcessed(const char *line)
1974{
1975 Emit("LineProcessed(const char*)", line);
1976}
1977
1978////////////////////////////////////////////////////////////////////////////////
1979/// Emit signal when console keyboard key was pressed.
1980
1982{
1983 Emit("KeyPressed(Int_t)", key);
1984}
1985
1986////////////////////////////////////////////////////////////////////////////////
1987/// Emit signal when return key was pressed.
1988
1990{
1991 Emit("ReturnPressed(char*)", text);
1992}
1993
1994////////////////////////////////////////////////////////////////////////////////
1995/// Set console echo mode:
1996///
1997/// - mode = kTRUE - echo input symbols
1998/// - mode = kFALSE - noecho input symbols
1999
2001{
2003
2004////////////////////////////////////////////////////////////////////////////////
2005/// Static function used to create a default application environment.
2006
2008{
2010 // gApplication is set at the end of 'new TApplication.
2011 if (!gApplication) {
2012 char *a = StrDup("RootApp");
2013 char *b = StrDup("-b");
2014 char *argv[2];
2015 Int_t argc = 2;
2016 argv[0] = a;
2017 argv[1] = b;
2018 new TApplication("RootApp", &argc, argv, nullptr, 0);
2019 if (gDebug > 0)
2020 Printf("<TApplication::CreateApplication>: "
2021 "created default TApplication");
2022 delete [] a; delete [] b;
2024 }
2025}
2026
2027////////////////////////////////////////////////////////////////////////////////
2028/// Static function used to attach to an existing remote application
2029/// or to start one.
2030
2031TApplication *TApplication::Open(const char *url,
2032 Int_t debug, const char *script)
2033{
2034 TApplication *ap = nullptr;
2035 TUrl nu(url);
2036 Int_t nnew = 0;
2037
2038 // Look among the existing ones
2039 if (fgApplications) {
2040 TIter nxa(fgApplications);
2041 while ((ap = (TApplication *) nxa())) {
2042 TString apn(ap->ApplicationName());
2043 if (apn == url) {
2044 // Found matching application
2045 return ap;
2046 } else {
2047 // Check if same machine and user
2048 TUrl au(apn);
2049 if (strlen(au.GetUser()) > 0 && strlen(nu.GetUser()) > 0 &&
2050 !strcmp(au.GetUser(), nu.GetUser())) {
2051 if (!strncmp(au.GetHost(), nu.GetHost(), strlen(nu.GetHost())))
2052 // New session on a known machine
2053 nnew++;
2054 }
2055 }
2056 }
2057 } else {
2058 ::Error("TApplication::Open", "list of applications undefined - protocol error");
2059 return ap;
2060 }
2061
2062 // If new session on a known machine pass the number as option
2063 if (nnew > 0) {
2064 nnew++;
2065 nu.SetOptions(TString::Format("%d", nnew).Data());
2066 }
2067
2068 // Instantiate the TApplication object to be run
2069 TPluginHandler *h = nullptr;
2070 if ((h = gROOT->GetPluginManager()->FindHandler("TApplication","remote"))) {
2071 if (h->LoadPlugin() == 0) {
2072 ap = (TApplication *) h->ExecPlugin(3, nu.GetUrl(), debug, script);
2073 } else {
2074 ::Error("TApplication::Open", "failed to load plugin for TApplicationRemote");
2075 }
2076 } else {
2077 ::Error("TApplication::Open", "failed to find plugin for TApplicationRemote");
2078 }
2079
2080 // Add to the list
2081 if (ap && !(ap->TestBit(kInvalidObject))) {
2082 fgApplications->Add(ap);
2083 gROOT->GetListOfBrowsables()->Add(ap, ap->ApplicationName());
2084 TIter next(gROOT->GetListOfBrowsers());
2085 TBrowser *b;
2086 while ((b = (TBrowser*) next()))
2087 b->Add(ap, ap->ApplicationName());
2088 gROOT->RefreshBrowsers();
2089 } else {
2091 ::Error("TApplication::Open",
2092 "TApplicationRemote for %s could not be instantiated", url);
2093 }
2094
2095 // Done
2096 return ap;
2097}
2098
2099////////////////////////////////////////////////////////////////////////////////
2100/// Static function used to close a remote application
2101
2103{
2104 if (app) {
2105 app->Terminate(0);
2106 fgApplications->Remove(app);
2107 gROOT->GetListOfBrowsables()->RecursiveRemove(app);
2108 TIter next(gROOT->GetListOfBrowsers());
2109 TBrowser *b;
2110 while ((b = (TBrowser*) next()))
2111 b->RecursiveRemove(app);
2112 gROOT->RefreshBrowsers();
2113 }
2114}
2115
2116////////////////////////////////////////////////////////////////////////////////
2117/// Show available sessions
2118
2119void TApplication::ls(Option_t *opt) const
2120{
2121 if (fgApplications) {
2122 TIter nxa(fgApplications);
2123 TApplication *a = nullptr;
2124 while ((a = (TApplication *) nxa())) {
2125 a->Print(opt);
2126 }
2127 } else {
2128 Print(opt);
2129 }
2130}
2131
2132////////////////////////////////////////////////////////////////////////////////
2133/// Static method returning the list of available applications
2134
2136{
2137 return fgApplications;
2138}
#define SafeDelete(p)
Definition RConfig.hxx:525
#define b(i)
Definition RSha256.hxx:100
#define f(i)
Definition RSha256.hxx:104
#define a(i)
Definition RSha256.hxx:99
#define h(i)
Definition RSha256.hxx:106
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
int Int_t
Signed integer 4 bytes (int).
Definition RtypesCore.h:59
long Longptr_t
Integer large enough to hold a pointer (platform-dependent).
Definition RtypesCore.h:89
int Ssiz_t
String size (currently int).
Definition RtypesCore.h:81
unsigned int UInt_t
Unsigned integer 4 bytes (unsigned int).
Definition RtypesCore.h:60
long Long_t
Signed long integer 4 bytes (long). Size depends on architecture.
Definition RtypesCore.h:68
bool Bool_t
Boolean (0=false, 1=true) (bool).
Definition RtypesCore.h:77
constexpr Bool_t kFALSE
Definition RtypesCore.h:108
constexpr Ssiz_t kNPOS
The equivalent of std::string::npos for the ROOT class TString.
Definition RtypesCore.h:131
long long Long64_t
Portable signed long integer 8 bytes.
Definition RtypesCore.h:83
constexpr Bool_t kTRUE
Definition RtypesCore.h:107
const char Option_t
Option string (const char).
Definition RtypesCore.h:80
static void CallEndOfProcessCleanups()
#define FOOTNOTE
TApplication * gApplication
externTApplication * gApplication
externTClassTable * gClassTable
@ kIsInlined
@ kIsConstexpr
Definition TDictionary.h:93
@ kIsStruct
Definition TDictionary.h:66
@ kIsVirtual
Definition TDictionary.h:72
@ kIsNamespace
Definition TDictionary.h:95
Error("WriteTObject","The current directory (%s) is not associated with a file. The object (%s) has not been written.", GetName(), objname)
#define gDirectory
Definition TDirectory.h:385
externTEnv * gEnv
Definition TEnv.h:170
R__EXTERN ExceptionContext_t * gException
Definition TException.h:69
R__EXTERN void Throw(int code)
If an exception context has been set (using the TRY and RETRY macros) jump back to where it was set.
XFontStruct * id
Definition TGX11.cxx:147
char name[80]
Definition TGX11.cxx:148
externTGuiFactory * gGuiFactory
Definition TGuiFactory.h:66
externTGuiFactory * gBatchGuiFactory
Definition TGuiFactory.h:67
#define gInterpreter
externTVirtualMutex * gInterpreterMutex
Double_t err
@ kInvalidObject
Definition TObject.h:382
Int_t gDebug
Definition TROOT.cxx:777
#define gROOT
Definition TROOT.h:417
externTVirtualMutex * gROOTMutex
Definition TROOT.h:63
char * Compress(const char *str)
Remove all blanks from the string str.
Definition TString.cxx:2579
char * Strip(const char *str, char c=' ')
Strip leading and trailing c (blanks by default) from a string.
Definition TString.cxx:2528
void Printf(const char *fmt,...)
Formats a string in a circular formatting buffer and prints the string.
Definition TString.cxx:2510
char * StrDup(const char *str)
Duplicate the string str.
Definition TString.cxx:2564
externTStyle * gStyle
Definition TStyle.h:442
@ kReadPermission
Definition TSystem.h:55
externTSystem * gSystem
Definition TSystem.h:582
#define R__LOCKGUARD(mutex)
#define gPad
#define gVirtualX
Definition TVirtualX.h:375
externTVirtualX * gGXBatch
Definition TVirtualX.h:377
This class creates the ROOT Application Environment that interfaces to the windowing system eventloop...
EExitOnException ExitOnException(EExitOnException opt=kExit)
Set the exit on exception option.
virtual void KeyPressed(Int_t key)
Emit signal when console keyboard key was pressed.
virtual Longptr_t ProcessLine(const char *line, Bool_t sync=kFALSE, Int_t *error=nullptr)
Process a single command line, either a C++ statement or an interpreter command starting with a "....
static TList * fgApplications
static void Close(TApplication *app)
Static function used to close a remote application.
virtual void SetEchoMode(Bool_t mode)
Set console echo mode:
virtual void Help(const char *line)
The function lists useful commands (".help") or opens the online reference guide, generated with Doxy...
virtual void LineProcessed(const char *line)
Emit signal when a line has been processed.
void ClearInputFiles()
Clear list containing macro files passed as program arguments.
TApplicationImp * fAppImp
!Window system specific application implementation
TApplication(const TApplication &)=delete
static Longptr_t ExecuteFile(const char *file, Int_t *error=nullptr, Bool_t keep=kFALSE)
Execute a file containing a C++ macro (static method).
void InitializeGraphics(Bool_t only_web=kFALSE)
Initialize the graphics environment.
virtual void Open()
virtual void LoadGraphicsLibs()
Load shared libs necessary for graphics.
virtual void StopIdleing()
Called when system stops idleing.
virtual void StartIdleing()
Called when system starts idleing.
virtual void Run(Bool_t retrn=kFALSE)
Main application eventloop. Calls system dependent eventloop via gSystem.
virtual ~TApplication()
TApplication dtor.
void OpenReferenceGuideFor(const TString &strippedClass)
It opens the online reference guide, generated with Doxygen, for the chosen scope (class/namespace/st...
virtual void HandleException(Int_t sig)
Handle exceptions (kSigBus, kSigSegmentationViolation, kSigIllegalInstruction and kSigFloatingExcepti...
virtual void MakeBatch()
Switch to batch mode.
void OpenGitHubIssue(const TString &type)
It opens a GitHub issue in a web browser with prefilled ROOT version.
Bool_t fReturnFromRun
virtual void Init()
TString fIdleCommand
char ** Argv() const
static Bool_t fgGraphNeeded
virtual void Terminate(Int_t status=0)
Terminate the application by call TSystem::Exit() unless application has been told to return from Run...
void OpenInBrowser(const TString &url)
The function generates and executes a command that loads the Doxygen URL in a browser.
virtual const char * ApplicationName() const
virtual void Forum(const char *line)
The function (".forum <type>") submits a new post on the ROOT forum via web browser.
void SetReturnFromRun(Bool_t ret)
virtual Int_t TabCompletionHook(char *buf, int *pLoc, std::ostream &out)
What to do when tab is pressed.
EExitOnException fExitOnException
TObjArray * fFiles
const char * GetIdleCommand() const
TApplication()
Default ctor. Can be used by classes deriving from TApplication.
virtual Longptr_t ProcessFile(const char *file, Int_t *error=nullptr, Bool_t keep=kFALSE)
Process a file containing a C++ macro.
void OpenForumTopic(const TString &type)
It opens a Forum topic in a web browser with prefilled ROOT version.
TString fWorkDir
virtual void ReturnPressed(char *text)
Emit signal when return key was pressed.
static Bool_t fgGraphInit
virtual void RemoveIdleTimer()
Remove idle timer. Normally called via TROOT::Idle(0).
virtual void SetIdleTimer(UInt_t idleTimeInSec, const char *command)
Set the command to be executed after the system has been idle for idleTimeInSec seconds.
virtual void GitHub(const char *line)
The function (".gh <type>") submits a new issue on GitHub via web browser.
static void CreateApplication()
Static function used to create a default application environment.
virtual void GetOptions(Int_t *argc, char **argv)
Get and handle command line options.
static TList * GetApplications()
Static method returning the list of available applications.
std::atomic< bool > fIsRunning
static void NeedGraphicsLibs()
Static method.
static Int_t ParseRemoteLine(const char *ln, TString &hostdir, TString &user, Int_t &dbg, TString &script)
Parse the content of a line starting with ".R" (already stripped-off) The format is.
TTimer * fIdleTimer
void ls(Option_t *option="") const override
Show available sessions.
TString GetSetup()
It gets the ROOT installation setup as TString.
virtual void HandleIdleTimer()
Handle idle timeout.
TSignalHandler * fSigHandler
virtual Longptr_t ProcessRemote(const char *line, Int_t *error=nullptr)
Process the content of a line starting with ".R" (already stripped-off) The format is.
TApplication * fAppRemote
char ** fArgv
Using a TBrowser one can browse all ROOT objects.
Definition TBrowser.h:37
TList * GetListOfAllPublicDataMembers(Bool_t load=kTRUE)
Returns a list of all public data members of this class and its base classes.
Definition TClass.cxx:3920
TList * GetListOfEnums(Bool_t load=kTRUE)
Return a list containing the TEnums of a class.
Definition TClass.cxx:3744
Long_t Property() const override
Returns the properties of the TClass as a bit field stored as a Long_t value.
Definition TClass.cxx:6191
TMethod * GetMethodAllAny(const char *method)
Return pointer to method without looking at parameters.
Definition TClass.cxx:4442
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:2994
static void InitializeColors()
All ROOT classes may have RTTI (run time type identification) support added.
Definition TDataMember.h:31
const char * GetTrueTypeName() const
Get the desugared type name of this data member, including const and volatile qualifiers.
Bool_t IsEnum() const
Return true if data member is an enum.
const char * GetFullTypeName() const
Get the concrete type name of this data member, including const and volatile qualifiers.
Global functions class (global functions are obtained from CINT).
Definition TFunction.h:30
Long_t Property() const override
Get property description word. For meaning of bits see EProperty.
const char * GetSignature()
Return signature of function.
Long_t ExtraProperty() const
Get property description word. For meaning of bits see EProperty.
const char * GetReturnTypeName() const
Get full type description of function return type, e,g.: "class TDirectory*".
TIdleTimer(Long_t ms)
Bool_t Notify() override
Notify handler.
void ls(Option_t *option="") const override
List this line with its attributes.
Definition TLine.cxx:353
A doubly linked list.
Definition TList.h:38
TObject * FindObject(const char *name) const override
Find an object in this list using its name.
Definition TList.cxx:708
The TNamed class is the base class for all named ROOT classes.
Definition TNamed.h:29
An array of TObjects.
Definition TObjArray.h:31
Int_t GetEntries() const override
Return the number of objects in array (i.e.
TObject * At(Int_t idx) const override
Definition TObjArray.h:170
Collectable string class.
Definition TObjString.h:28
TString & String()
Definition TObjString.h:48
Bool_t TestBit(UInt_t f) const
Definition TObject.h:204
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:1084
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:888
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1098
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition TObject.cxx:1126
virtual void Print(Option_t *option="") const
This method must be overridden when a class wants to print itself.
Definition TObject.cxx:661
void ResetBit(UInt_t f)
Definition TObject.h:203
@ kInvalidObject
if object ctor succeeded but object should not be used
Definition TObject.h:81
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition TObject.cxx:1072
void Emit(const char *signal, const T &arg)
Activate signal with single parameter.
Definition TQObject.h:164
static const char * GetMacroPath()
Get macro search path. Static utility function.
Definition TROOT.cxx:2917
static Bool_t Initialized()
Return kTRUE if the TROOT object has been initialized.
Definition TROOT.cxx:3067
static const TString & GetTutorialDir()
Get the tutorials directory in the installation. Static utility function.
Definition TROOT.cxx:3444
static const TString & GetDocDir()
Get the documentation directory in the installation. Static utility function.
Definition TROOT.cxx:3407
Basic string class.
Definition TString.h:138
Ssiz_t Length() const
Definition TString.h:425
void ToLower()
Change string to lower-case.
Definition TString.cxx:1189
TString & Insert(Ssiz_t pos, const char *s)
Definition TString.h:670
Int_t Atoi() const
Return integer value of string.
Definition TString.cxx:1994
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 & Replace(Ssiz_t pos, Ssiz_t n, const char *s)
Definition TString.h:703
Ssiz_t First(char c) const
Find first occurrence of a character c.
Definition TString.cxx:545
const char * Data() const
Definition TString.h:384
TString & Chop()
Definition TString.h:700
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition TString.h:713
TString MD5() const
Return the MD5 digest for this string, in a string representation.
Definition TString.cxx:947
@ kBoth
Definition TString.h:284
Bool_t BeginsWith(const char *s, ECaseCompare cmp=kExact) const
Definition TString.h:632
TString & Prepend(const char *cs)
Definition TString.h:682
std::istream & ReadFile(std::istream &str)
Replace string with the contents of strm, stopping at an EOF.
Definition Stringio.cxx:29
TString & Remove(Ssiz_t pos)
Definition TString.h:694
TString & Append(const char *cs)
Definition TString.h:581
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Definition TString.cxx:2385
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition TString.cxx:2363
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:641
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:660
void Reset()
Reset the timer.
Definition TTimer.cxx:162
TTimer(const TTimer &)=delete
This class represents a WWW compatible URL.
Definition TUrl.h:33
const char * GetUrl(Bool_t withDeflt=kFALSE) const
Return full URL.
Definition TUrl.cxx:395
const char * GetFileAndOptions() const
Return the file and its options (the string specified behind the ?).
Definition TUrl.cxx:508
const char * GetFile() const
Definition TUrl.h:69
const char * GetProtocol() const
Definition TUrl.h:64
TText * text
TLine * line
static constexpr const char kCommandLineOptionsHelp[]
Double_t y[n]
Definition legend1.C:17
Double_t x[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
void EnableImplicitMT(UInt_t numthreads=0)
Enable ROOT's implicit multi-threading for all objects and methods that provide an internal paralleli...
Definition TROOT.cxx:613
void EnableThreadSafety()
Enable support for multi-threading within the ROOT code in particular, enables the global mutex to ma...
Definition TROOT.cxx:575
const char * GetUnqualifiedName(const char *name)
Return the start of the unqualified name include in 'original'.