44#elif defined(R__WIN32)
45#define WIN32_LEAN_AND_MEAN
58static const char *
Color(
const char *col)
63 const static bool isTerm = isatty(STDOUT_FILENO);
71Display ROOT files contents in the terminal.
77 -h, --help show this help message and exit
78 -1, --oneColumn Print content in one column
79 -c, --allCycles Force display of all objects' cycles
80 -l, --longListing Use a long listing format.
81 -t, --treeListing Print tree recursively and use a long listing format.
82 -R, --rntupleListing Print RNTuples recursively and use a long listing format.
83 -r, --recursiveListing Traverse file recursively entering any TDirectory.
87 Display contents of the ROOT file 'example.root'.
89- rootls example.root:dir
90 Display contents of the directory 'dir' from the ROOT file 'example.root'.
92- rootls example.root:*
93 Display contents of the ROOT file 'example.root' and his subdirectories.
95- rootls file1.root file2.root
96 Display contents of ROOT files 'file1.root' and 'file2.root'.
99 Display contents of ROOT files whose name ends with '.root'.
101- rootls -1 example.root
102 Display contents of the ROOT file 'example.root' in one column.
104- rootls -l example.root
105 Display contents of the ROOT file 'example.root' and use a long listing format.
107- rootls -t example.root
108 Display contents of the ROOT file 'example.root', use a long listing format and print trees recursively.
110- rootls -r example.root
111 Display contents of the ROOT file 'example.root', traversing recursively any TDirectory.
117 const bool inherits = cl && cl->InheritsFrom(baseClass);
149 int columns = 80, rows = 25;
153 if (::ioctl(STDIN_FILENO, TIOCGWINSZ, &w) == 0 || ::ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == 0 ||
154 ::ioctl(STDERR_FILENO, TIOCGWINSZ, &w) == 0) {
159#elif defined(R__WINDOWS)
161 CONSOLE_SCREEN_BUFFER_INFO csbi;
162 if (::GetConsoleScreenBufferInfo(::GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {
163 columns = csbi.srWindow.Right - csbi.srWindow.Left + 1;
164 rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
168 return {columns, rows};
175 for (
int i = 0; i <
indent; ++i) {
182 static const char *kMonths[12] = {
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
183 "Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"};
184 int monthNo = datime.
GetMonth() - 1;
185 const char *
month = monthNo >= 0 && monthNo < 12 ? kMonths[monthNo] :
"???";
186 std::ios defaultFmt(
nullptr);
187 stream <<
month <<
' ';
188 stream << std::right << std::setfill(
'0') << std::setw(2) << datime.
GetDay() <<
' ';
190 stream.copyfmt(defaultFmt);
198 std::size_t maxNameLen = 0, maxTitleLen = 0;
199 for (
int i = 0; i < branches->GetEntries(); ++i) {
201 maxNameLen = std::max(maxNameLen, strlen(branch->
GetName()));
202 maxTitleLen = std::max(maxTitleLen, strlen(branch->
GetTitle()));
207 for (
int i = 0; i < branches->GetEntries(); ++i) {
210 stream << std::left << std::setw(maxNameLen) << branch->
GetName();
211 std::string titleStr = std::string(
"\"") + branch->
GetTitle() +
"\"";
212 stream << std::setw(maxTitleLen) << titleStr;
224 std::size_t nTotClusters = 0;
225 auto clusterIt =
tree.GetClusterIterator(0);
226 auto clusterStart = clusterIt();
227 const auto nEntries =
tree.GetEntries();
228 while (clusterStart < nEntries) {
230 stream <<
" - # " << nTotClusters <<
": [" << clusterStart <<
", " << clusterIt.GetNextEntry() - 1 <<
"]\n";
232 clusterStart = clusterIt();
235 stream <<
Color(
kAnsiBold) <<
"The total number of clusters is " << nTotClusters <<
"\n";
241 std::size_t minTypeLen = 0)
243 std::size_t maxNameLen = 0, maxTypeLen = 0;
244 std::vector<const ROOT::RFieldDescriptor *> fields;
245 fields.reserve(rootField.
GetLinkIds().size());
247 fields.push_back(&field);
248 maxNameLen = std::max(maxNameLen, field.GetFieldName().length());
249 maxTypeLen = std::max(maxTypeLen, field.GetTypeName().length());
251 maxNameLen = std::max(minNameLen, maxNameLen + 2);
252 maxTypeLen = std::max(minTypeLen, maxTypeLen + 4);
254 std::sort(fields.begin(), fields.end(),
255 [](
const auto &
a,
const auto &
b) { return a->GetFieldName() < b->GetFieldName(); });
258 const char fillChar = minNameLen == 0 ?
' ' :
'.';
259 for (
const auto *field : fields) {
261 stream << std::left << std::setfill(fillChar) << std::setw(maxNameLen) << field->GetFieldName();
262 stream << std::setfill(
' ') << std::setw(maxTypeLen) << field->GetTypeName();
263 if (!field->GetFieldDescription().empty()) {
264 std::string descStr =
'"' + field->GetFieldDescription() +
'"';
265 stream << std::setw(1) << descStr;
273 Indent indent, std::size_t minNameLen = 0, std::size_t minClassLen = 0);
290 std::vector<NodeIdx_t>::const_iterator nodesBegin,
291 std::vector<NodeIdx_t>::const_iterator nodesEnd, std::uint32_t flags,
Indent indent,
292 std::size_t minNameLen = 0, std::size_t minClassLen = 0)
294 std::size_t maxClassLen = 0, maxNameLen = 0;
295 for (
auto childIt = nodesBegin; childIt != nodesEnd; ++childIt) {
296 const auto &child =
tree.fNodes[*childIt];
297 maxClassLen = std::max(maxClassLen, child.fClassName.length());
298 maxNameLen = std::max(maxNameLen, child.fName.length());
300 maxClassLen = std::max(minClassLen, maxClassLen + 2);
301 maxNameLen = std::max(minNameLen, maxNameLen + 2);
303 for (
auto childIt = nodesBegin; childIt != nodesEnd; ++childIt) {
305 const auto &child =
tree.fNodes[childIdx];
307 const char *cycleStr =
"";
310 if (childIt == nodesBegin || child.fName !=
tree.fNodes[childIdx - 1].fName) {
315 if (std::next(childIt) != nodesEnd && child.fName ==
tree.fNodes[childIdx + 1].fName) {
316 cycleStr =
"[current cycle]";
320 cycleStr =
"[backup cycle]";
327 std::string namecycle = child.fName +
';' + std::to_string(child.fKey->GetCycle());
328 stream << std::left << std::setw(maxNameLen) << namecycle;
329 stream <<
" \"" << child.fKey->GetTitle() <<
"\" " << cycleStr;
334 TTree *ttree = child.fKey->ReadObject<
TTree>();
346 const auto &desc = reader->GetDescriptor();
349 Err() <<
"failed to read RNTuple object: " << child.fName <<
"\n";
357 stream << std::flush;
362 Indent indent, std::size_t minNameLen, std::size_t minClassLen)
365 const auto &
node =
tree.fNodes[nodeIdx];
366 if (
node.fNChildren == 0)
369 std::vector<NodeIdx_t> children(
node.fNChildren);
370 std::iota(children.begin(), children.end(),
node.fFirstChild);
380 std::vector<NodeIdx_t>::const_iterator nodesBegin,
381 std::vector<NodeIdx_t>::const_iterator nodesEnd, std::uint32_t flags,
Indent indent)
386 std::size_t minElemWidth = std::numeric_limits<std::size_t>::max();
387 std::size_t maxElemWidth = 0;
388 std::vector<NodeIdx_t> uniqueNodes;
389 std::string_view prevNodeName;
390 for (
auto it = nodesBegin; it != nodesEnd; ++it) {
392 const auto &
node =
tree.fNodes[nodeIdx];
395 if (!displayAllCycles &&
node.fName == prevNodeName)
397 uniqueNodes.push_back(nodeIdx);
398 auto elemWidth =
node.fName.length();
399 if (displayAllCycles) {
401 const auto cycleLen = std::to_string(
node.fCycle).length();
402 elemWidth += cycleLen + 1;
404 minElemWidth = std::min(elemWidth, minElemWidth);
405 maxElemWidth = std::max(elemWidth, maxElemWidth);
406 prevNodeName =
node.fName;
409 const auto nNodes = uniqueNodes.size();
415 const int minCharsBetween = 2;
416 minElemWidth += minCharsBetween;
417 maxElemWidth += minCharsBetween;
420 std::size_t nCols = 0;
421 std::vector<int> colWidths;
423 if (maxElemWidth >
static_cast<std::size_t
>(terminalSize.
x) || oneColumn) {
428 nCols = std::min<int>(nNodes, terminalSize.
x /
static_cast<int>(minElemWidth));
433 for (
auto colIdx = 0u; colIdx < nCols; ++colIdx) {
435 for (
auto j = 0u; j < nNodes; ++j) {
436 if ((j % nCols) == colIdx) {
439 auto nameLen = child.
fName.length();
440 if (displayAllCycles) {
441 const auto cycleLen = std::to_string(child.
fCycle).length();
442 nameLen += cycleLen + 1;
444 width = std::max<int>(
width, nameLen + minCharsBetween);
449 if (totWidth > terminalSize.
x) {
455 colWidths.push_back(
width);
458 if (!colWidths.empty())
468 const bool isTerminal = terminalSize.
x + terminalSize.
y > 0;
471 for (
auto i = 0u; i < nNodes; ++i) {
473 const auto &child =
tree.fNodes[childIdx];
495 bool nextIsDirWithRecursiveDisplay =
false;
497 NodeIdx_t nextChildIdx = uniqueNodes[i + 1];
498 const auto &nextChild =
tree.fNodes[nextChildIdx];
499 nextIsDirWithRecursiveDisplay =
500 nextChild.fNChildren > 0 &&
ClassInheritsFrom(nextChild.fClassName.c_str(),
"TDirectory");
503 const bool isExtremal = (((curCol + 1) % nCols) == 0) || (i == nNodes - 1) || isDirWithRecursiveDisplay ||
504 nextIsDirWithRecursiveDisplay;
505 auto nodeName = child.fName + (displayAllCycles ?
";" + std::to_string(child.fCycle) :
"");
507 stream << std::left << std::setw(colWidths[curCol % nCols]) << nodeName;
509 stream << std::setw(1) << nodeName;
520 if (isDirWithRecursiveDisplay) {
530 const auto &
node =
tree.fNodes[nodeIdx];
531 if (
node.fNChildren == 0)
534 std::vector<NodeIdx_t> children(
node.fNChildren);
535 std::iota(children.begin(), children.end(),
node.fFirstChild);
542 const Indent outerIndent = (args.fSources.size() > 1) * 2;
543 for (
const auto &source : args.fSources) {
544 if (args.fSources.size() > 1) {
545 stream << source.fFileName <<
" :\n";
550 source.fObjectTree.fLeafList.end(), args.fFlags, outerIndent);
553 source.fObjectTree.fLeafList.end(), args.fFlags, outerIndent);
555 const bool manySources = source.fObjectTree.fDirList.size() + source.fObjectTree.fLeafList.size() > 1;
557 for (
NodeIdx_t rootIdx : source.fObjectTree.fDirList) {
575 opts.
AddFlag({
"-h",
"--help"});
576 opts.
AddFlag({
"-1",
"--oneColumn"});
577 opts.
AddFlag({
"-l",
"--longListing"});
578 opts.
AddFlag({
"-t",
"--treeListing"});
579 opts.
AddFlag({
"-R",
"--rntupleListing"});
580 opts.
AddFlag({
"-r",
"--recursiveListing"});
581 opts.
AddFlag({
"-c",
"--allCycles"});
583 opts.
Parse(args, nArgs);
618 auto args =
ParseArgs(
const_cast<const char **
>(argv) + 1, argc - 1);
620 std::cerr <<
"usage: rootls [-1hltr] FILE [FILE ...]\n";
629 std::sort(args.fSources.begin(), args.fSources.end(),
630 [](
const auto &
a,
const auto &
b) { return a.fFileName < b.fFileName; });
634 for (
auto &source : args.fSources) {
635 if (!source.fErrors.empty()) {
637 for (
const auto &
err : source.fErrors)
640 std::sort(source.fObjectTree.fLeafList.begin(), source.fObjectTree.fLeafList.end(),
642 const auto &a = tree.fNodes[aIdx];
643 const auto &b = tree.fNodes[bIdx];
645 return (a.fName != b.fName) ? a.fName < b.fName : a.fCycle > b.fCycle;
static void indent(ostringstream &buf, int indent_level)
externInt_t gErrorIgnoreLevel
errors with level below this value will be ignored. Default is kUnset.
std::vector< double > errors
void AddFlag(std::initializer_list< std::string_view > aliases, EFlagType type=EFlagType::kSwitch, std::string_view help="", std::uint32_t flagOpts=0)
Defines a new flag (either a switch or a flag with argument).
const std::vector< std::string > & GetErrors() const
Returns all parsing errors.
int GetSwitch(std::string_view name) const
If name refers to a previously-defined switch (i.e.
const std::vector< std::string > & GetArgs() const
Retrieves all positional arguments.
void Parse(const char **args, std::size_t nArgs)
Metadata stored for every field of an RNTuple.
ROOT::DescriptorId_t GetId() const
const std::vector< ROOT::DescriptorId_t > & GetLinkIds() const
The on-storage metadata of an RNTuple.
RFieldDescriptorIterable GetFieldIterable(const RFieldDescriptor &fieldDesc) const
static std::unique_ptr< RNTupleReader > Open(std::string_view ntupleName, std::string_view storage, const ROOT::RNTupleReadOptions &options=ROOT::RNTupleReadOptions())
Open an RNTuple for reading.
Representation of an RNTuple data set in a ROOT file.
A TTree is a list of TBranches.
Long64_t GetTotBytes(Option_t *option="") const
Return total number of bytes in the branch (excluding current buffer) if option ="*" includes all sub...
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.
This class stores the date and time with a precision of one second in an unsigned 32 bit word (950130...
const char * GetName() const override
Returns name of object.
const char * GetTitle() const override
Returns title of object.
A TTree represents a columnar dataset.
subroutine node(ivo, nuserm, iposp)
void InitLog(const char *name, int defaultVerbosity=1)
std::string NodeFullPath(const RootObjTree &tree, NodeIdx_t nodeIdx, ENodeFullPathOpt opt)
Given a node, returns its full path. If opt == kIncludeFilename, the path is prepended by "filename....
@ kRecursive
Recurse into subdirectories when matching objects.
std::vector< ROOT::CmdLine::RootSource > ParseRootSources(const std::vector< std::string > &sourcesRaw, std::uint32_t flags)
Given a list of strings like "file.root:dir/obj", converts each string to a RootSource.
static const char *const kLongHelp
static void PrintDatime(std::ostream &stream, const TDatime &datime)
static void PrintRNTuple(std::ostream &stream, const ROOT::RNTupleDescriptor &desc, Indent indent, const ROOT::RFieldDescriptor &rootField, std::size_t minNameLen=0, std::size_t minTypeLen=0)
static void PrintTTree(std::ostream &stream, T &tree, Indent indent)
static void PrintNodesDetailed(std::ostream &stream, const RootObjTree &tree, std::vector< NodeIdx_t >::const_iterator nodesBegin, std::vector< NodeIdx_t >::const_iterator nodesEnd, std::uint32_t flags, Indent indent, std::size_t minNameLen=0, std::size_t minClassLen=0)
Prints a ls -l-like output:
static const char *const kAnsiGreen
static void PrintClusters(std::ostream &stream, TTree &tree, Indent indent)
static void RootLs(const RootLsArgs &args, std::ostream &stream=std::cout)
static const char *const kAnsiBlue
static void PrintChildrenDetailed(std::ostream &stream, const RootObjTree &tree, NodeIdx_t nodeIdx, std::uint32_t flags, Indent indent, std::size_t minNameLen=0, std::size_t minClassLen=0)
static const char *const kAnsiBold
static const char * Color(const char *col)
static const char *const kAnsiNone
static void PrintIndent(std::ostream &stream, Indent indent)
static bool ClassInheritsFrom(const char *class_, const char *baseClass)
static void PrintNodesInColumns(std::ostream &stream, const RootObjTree &tree, std::vector< NodeIdx_t >::const_iterator nodesBegin, std::vector< NodeIdx_t >::const_iterator nodesEnd, std::uint32_t flags, Indent indent)
static RootLsArgs ParseArgs(const char **args, int nArgs)
static V2i GetTerminalSize()
static void PrintChildrenInColumns(std::ostream &stream, const RootObjTree &tree, NodeIdx_t nodeIdx, std::uint32_t flags, Indent indent)
A representation of all objects involved in a rootls-style ROOT file listing.
std::vector< RootSource > fSources
EPrintUsage fPrintUsageAndExit