Skip to content

Commit 3bb2815

Browse files
[Tut] Fix obsolete sprinf() calls and other unsafe old C++ constructs
1 parent b2cb5ef commit 3bb2815

1 file changed

Lines changed: 151 additions & 37 deletions

File tree

tutorials/legacy/rootalias.C

Lines changed: 151 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -11,71 +11,185 @@
1111
///
1212
/// \author Rene Brun
1313

14+
#include <TSystem.h>
15+
#include <TROOT.h>
16+
#include <TCanvas.h>
17+
#include <TPaveText.h>
18+
#include <TText.h>
19+
20+
#include <string>
21+
#include <cstdlib> // std::getenv
22+
#include <cstring> // std::strcmp
23+
#include <algorithm> // std::replace
24+
#include <cstdio> // std::printf
25+
26+
namespace {
27+
inline bool IsWindows()
28+
{
29+
return std::strcmp(gSystem->GetName(), "WinNT") == 0;
30+
}
31+
inline bool IsMac()
32+
{
33+
return std::strcmp(gSystem->GetName(), "Macosx") == 0;
34+
}
35+
36+
// Minimal, pragmatic shell quoting for filenames/paths.
37+
// Good enough for normal paths; not a full shell-escaping library.
38+
std::string QuoteForShell(const std::string &s)
39+
{
40+
if (s.empty())
41+
return "''";
42+
43+
if (IsWindows()) {
44+
// Wrap in double quotes; replace embedded " with ' (rare in paths)
45+
std::string q = s;
46+
std::replace(q.begin(), q.end(), '"', '\'');
47+
return "\"" + q + "\"";
48+
} else {
49+
// POSIX: single-quote, escape internal single quotes with '"'"'
50+
std::string out;
51+
out.reserve(s.size() + 2);
52+
out.push_back('\'');
53+
for (char c : s) {
54+
if (c == '\'')
55+
out += "'\"'\"'";
56+
else
57+
out.push_back(c);
58+
}
59+
out.push_back('\'');
60+
return out;
61+
}
62+
}
63+
64+
std::string GetEnvOrEmpty(const char *name)
65+
{
66+
if (const char *v = std::getenv(name))
67+
return std::string(v);
68+
return {};
69+
}
70+
71+
// Build a command that (on POSIX) returns immediately to keep the ROOT prompt usable.
72+
std::string MaybeBackground(std::string cmd)
73+
{
74+
if (!IsWindows())
75+
cmd += " &";
76+
return cmd;
77+
}
78+
} // namespace
79+
1480
//______________________________________________________________________________
15-
void edit(char *file)
81+
// Open a file in the user's editor, with robust cross-platform fallbacks.
82+
void edit(const char *file)
1683
{
17-
char s[64], *e;
18-
if (!strcmp(gSystem->GetName(), "WinNT")) {
19-
if ((e = std::getenv("EDITOR")))
20-
sprintf(s, "start %s %s", e, file);
84+
const std::string f = (file ? file : "");
85+
const std::string qf = QuoteForShell(f);
86+
const std::string editor = GetEnvOrEmpty("EDITOR");
87+
88+
std::string cmd;
89+
90+
if (IsWindows()) {
91+
// Use "start" to detach a new window (cmd.exe builtin).
92+
if (!editor.empty())
93+
cmd = "start " + editor + " " + qf;
94+
else
95+
cmd = "start notepad " + qf;
96+
} else if (IsMac()) {
97+
// macOS: prefer $EDITOR, else TextEdit
98+
if (!editor.empty())
99+
cmd = MaybeBackground(editor + " " + qf);
21100
else
22-
sprintf(s, "start notepad %s", file);
101+
cmd = MaybeBackground("open -e " + qf);
23102
} else {
24-
if ((e = std::getenv("EDITOR")))
25-
sprintf(s, "%s %s", e, file);
103+
// Linux/Unix: $EDITOR if set; else xdg-open; else xterm+vi
104+
if (!editor.empty())
105+
cmd = MaybeBackground(editor + " " + qf);
26106
else
27-
sprintf(s, "xterm -e vi %s &", file);
107+
cmd =
108+
MaybeBackground("(command -v xdg-open >/dev/null 2>&1 && xdg-open " + qf + ") || (xterm -e vi " + qf + ")");
28109
}
29-
gSystem->Exec(s);
110+
111+
gSystem->Exec(cmd.c_str());
30112
}
31113

32114
//______________________________________________________________________________
33-
void ls(char *path=0)
115+
// List a directory in a compact, friendly way.
116+
void ls(const char *path = nullptr)
34117
{
35-
char s[256];
36-
strcpy(s, (!strcmp(gSystem->GetName(), "WinNT")) ? "dir /w " : "ls ");
37-
if (path) strcat(s,path);
38-
gSystem->Exec(s);
118+
std::string cmd = IsWindows() ? "dir /w" : "ls";
119+
if (path && *path) {
120+
cmd += " ";
121+
cmd += QuoteForShell(path);
122+
}
123+
gSystem->Exec(cmd.c_str());
39124
}
40125

41126
//______________________________________________________________________________
42-
void dir(char *path=0)
127+
// More verbose directory view (traditional Unix-y default).
128+
void dir(const char *path = nullptr)
43129
{
44-
char s[256];
45-
strcpy(s,(!strcmp(gSystem->GetName(), "WinNT")) ? "dir " : "ls -l ");
46-
if (path) strcat(s,path);
47-
gSystem->Exec(s);
130+
std::string cmd = IsWindows() ? "dir" : "ls -alF";
131+
if (path && *path) {
132+
cmd += " ";
133+
cmd += QuoteForShell(path);
134+
}
135+
gSystem->Exec(cmd.c_str());
48136
}
49137

50138
//______________________________________________________________________________
139+
// Return current working directory (keeps macro API stable: returns const char*).
51140
const char *pwd()
52141
{
53-
return gSystem->WorkingDirectory();
142+
static std::string wd; // static so c_str() stays valid after return
143+
wd = gSystem->WorkingDirectory();
144+
return wd.c_str();
54145
}
55146

56147
//______________________________________________________________________________
57-
const char *cd(char *path=0)
148+
// Change directory; if no path is given, just report where we are.
149+
const char *cd(const char *path = nullptr)
58150
{
59-
if (path)
60-
gSystem->ChangeDirectory(path);
61-
return pwd();
151+
if (path && *path)
152+
gSystem->ChangeDirectory(path);
153+
return pwd();
62154
}
63155

64-
TCanvas *bench = 0;
156+
// ===
157+
// The following benchmark helper (seen in your file) is kept as-is in spirit,
158+
// just minor cleanups for clarity. If you have more helpers in your local copy,
159+
// you can apply the same style: std::string, const-correctness, early returns.
160+
// ===
161+
162+
TCanvas *bench = nullptr;
163+
65164
//______________________________________________________________________________
66-
void bexec2(char *macro)
165+
// Colorize a macro name in the summary before/after execution and run it.
166+
void bexec2(const char *macro)
67167
{
68-
printf("in bexec dir=%s\n",pwd());
69-
if (gROOT->IsBatch()) printf("Processing benchmark: %s\n",macro);
70-
TPaveText *summary = (TPaveText*)bench->GetPrimitive("TPave");
71-
TText *tmacro = summary->GetLineWith(macro);
72-
if (tmacro) tmacro->SetTextColor(4);
73-
bench->Modified(); bench->Update();
168+
std::printf("in bexec dir=%s\n", pwd());
169+
if (gROOT->IsBatch())
170+
std::printf("Processing benchmark: %s\n", macro);
171+
172+
if (!bench) {
173+
// If bench isn't prepared yet, just run the macro.
174+
gROOT->Macro(macro);
175+
return;
176+
}
177+
178+
auto *summary = dynamic_cast<TPaveText *>(bench->GetPrimitive("TPave"));
179+
if (summary) {
180+
if (auto *tmacro = summary->GetLineWith(macro))
181+
tmacro->SetTextColor(4);
182+
bench->Modified();
183+
bench->Update();
184+
}
74185

75186
gROOT->Macro(macro);
76187

77-
TPaveText *summary2 = (TPaveText*)bench->GetPrimitive("TPave");
78-
TText *tmacro2 = summary2->GetLineWith(macro);
79-
if (tmacro2) tmacro2->SetTextColor(2);
80-
bench->Modified(); bench->Update();
188+
auto *summary2 = dynamic_cast<TPaveText *>(bench->GetPrimitive("TPave"));
189+
if (summary2) {
190+
if (auto *tmacro2 = summary2->GetLineWith(macro))
191+
tmacro2->SetTextColor(2);
192+
bench->Modified();
193+
bench->Update();
194+
}
81195
}

0 commit comments

Comments
 (0)