From ef7de92ccb6ba809d3d8e40c10fa9174548f582d Mon Sep 17 00:00:00 2001 From: Jolly Chen Date: Mon, 15 Apr 2024 14:06:19 +0200 Subject: [PATCH] [Tree] Fix globbing of ? when also used as query When ? is used in TChain::Add in both the filename for globbing and as a starter for a query string, TChain::Add fails to find the intended file, because everything after the first ? is interpreted as the query string. This commit changes the behaviour so that any ? characters before the last '.root' are interpreted as a wildcard characters. Fixes #10239 --- tree/tree/src/TChain.cxx | 22 ++++++++++++++++++++++ tree/tree/test/TChainParsing.cxx | 12 ++++++++++++ 2 files changed, 34 insertions(+) diff --git a/tree/tree/src/TChain.cxx b/tree/tree/src/TChain.cxx index fb0e6bd8e41a1..2533490418e3e 100644 --- a/tree/tree/src/TChain.cxx +++ b/tree/tree/src/TChain.cxx @@ -367,6 +367,28 @@ Int_t TChain::Add(const char *name, Long64_t nentries /* = TTree::kMaxEntries */ TString basename, treename, query, suffix; ParseTreeFilename(name, basename, treename, query, suffix); + // Special case: ? used for query string AND as wildcard in the filename. + // In this case, everything after the first ? is parsed as query/suffix + // string in ParseTreeFilename. We assume that everything until the last + // occurence of .root should be part of the basename so we remove it + // from the suffix and add it back to the basename. + // See: https://github.com/root-project/root/issues/10239 + static const char *dotr = ".root"; + static Ssiz_t dotrl = strlen(dotr); + // Find the last one + Ssiz_t lastDotrIdx = kNPOS; + Ssiz_t dotrIdx = suffix.Index(dotr); + while (dotrIdx != kNPOS) { + lastDotrIdx = dotrIdx; + dotrIdx = suffix.Index(dotr, dotrIdx + 1); + } + if (lastDotrIdx != kNPOS) { + // Add the part up until '.root' to the basename for globbing + basename.Append(suffix, lastDotrIdx + dotrl); + // Remove the part up until '.root' from the suffix + suffix.Replace(0, lastDotrIdx + dotrl, ""); + } + // case with one single file if (!basename.MaybeWildcard()) { return AddFile(name, nentries); diff --git a/tree/tree/test/TChainParsing.cxx b/tree/tree/test/TChainParsing.cxx index 29b869359fa4b..92efeda7a6376 100644 --- a/tree/tree/test/TChainParsing.cxx +++ b/tree/tree/test/TChainParsing.cxx @@ -240,6 +240,7 @@ TEST(TChainParsing, RecursiveGlob) TChain none; TChain nested; TChain globDir; + TChain regex; nodir.Add("*"); const auto *nodirFiles = nodir.GetListOfFiles(); @@ -274,6 +275,17 @@ TEST(TChainParsing, RecursiveGlob) for (std::size_t i = 0; i < expectedFileNamesGlobDir.size(); i++) { EXPECT_EQ(globDirChainFileNames[i], expectedFileNamesGlobDir[i]); } + + regex.Add("test*/subdir?/[0-9]?.root?#events"); + const auto *regexChainFiles = regex.GetListOfFiles(); + ASSERT_TRUE(regexChainFiles); + EXPECT_EQ(regexChainFiles->GetEntries(), 3); + std::vector expectedFileNamesRegex{ + ConcatUnixFileName(cwd, "testglob/subdir1/1a.root"), + ConcatUnixFileName(cwd, "testglob/subdir1/1b.root"), + ConcatUnixFileName(cwd, "testglob/subdir3/3a.root")}; + auto regexChainFileNames = GetFileNamesVec(regexChainFiles); + EXPECT_VEC_EQ(regexChainFileNames, expectedFileNamesRegex); } #if !defined(_MSC_VER) || defined(R__ENABLE_BROKEN_WIN_TESTS)