#include "TObject.h"
#include "TFile.h"
#include "TKey.h"
#include "QFramework/TQFolder.h"
#include "QFramework/TQTaggable.h"
#include "QFramework/TQUtils.h"
#include "TClass.h"
#include "QFramework/TQCounter.h"
#include "QFramework/TQIterator.h"
#include "QFramework/TQSample.h"
#include "QFramework/TQValue.h"
#include "TParameter.h"
#include "TCollection.h"
#include "TH1.h"
#include "TH2.h"
#include "TH3.h"
#include "THnBase.h"
#include "QFramework/TQHistogramUtils.h"
#include "QFramework/TQTHnBaseUtils.h"
#include "QFramework/TQStringUtils.h"
#include "QFramework/TQListUtils.h"
#include "THashList.h"
#include "QFramework/TQLink.h"
#include "QFramework/TQImportLink.h"
#include "QFramework/TQTable.h"
#include "QFramework/TQXSecParser.h"
#include "QFramework/TQPathManager.h"
#include "QFramework/TQLibrary.h"
#include <iostream>
#include <algorithm>
#include <fstream>
#include <sstream>
#include <cstdlib>
#include <map>
#include "dirent.h"
ClassImp(TQFolder)
TQFolder::TQFolder() :
TFolder("unknown", ""),
TQTaggable(),
fMyDir(gDirectory),
fOwnMyDir(false),
fBase(NULL),
isFullyResolved(false){
}
TQFolder::TQFolder(const TString& name) :
TFolder(TQFolder::isValidName(name) ? name : "invalid_name", ""),
TQTaggable(),
fMyDir(gDirectory),
fOwnMyDir(false),
fBase(NULL),
isFullyResolved(false){
}
bool TQFolder::IsSortable() const {
return true;
}
int TQFolder::Compare(const TObject * obj) const {
if (obj && obj->InheritsFrom(TQFolder::Class())) {
TString thisName = GetName();
TString thatName = obj->GetName();
return thisName.CompareTo(thatName);
} else {
return -1;
}
}
TQFolder * TQFolder::newFolder(TString name) {
return new TQFolder(name);
}
bool TQFolder::isLazy(){
return !(this->isFullyResolved);
}
TQFolder * TQFolder::newInstance(const TString& name) {
return TQFolder::newFolder(name.IsNull() ? this->GetName() : name.Data());
}
bool TQFolder::parseDestination(TString dest, TString &path, TString &newName) {
int colonpos = TQStringUtils::find(dest,"::");
if((colonpos >= 0) && (colonpos < dest.Length())){
path = dest(0,colonpos);
if(colonpos+2 < dest.Length()){
newName = dest(colonpos+2, dest.Length()-(colonpos+2));
return true;
} else {
return false;
}
} else {
path = dest;
newName.Clear();
return true;
}
return false;
}
bool TQFolder::parseLocation(TString importPath, TString& filename, TString& objname){
filename.Clear();
objname.Clear();
size_t pipepos = TQStringUtils::rfind(importPath,">>");
size_t pos = TQStringUtils::rfind(importPath,":",(pipepos < (size_t)importPath.Length()) ? pipepos : (size_t)importPath.Length());
while(pos > 2 && importPath[pos-1] == ':')
pos = TQStringUtils::rfind(importPath,":",pos-2);
if(pos < (size_t)importPath.Length() && importPath[pos+1] != '/'){
filename = TQStringUtils::trim(importPath(0,pos));
objname = importPath(pos+1,importPath.Length()-pos);
DEBUGclass("filename='%s', objname='%s'",filename.Data(),objname.Data());
return true;
} else {
DEBUGclass("unable to parse location '%s', >>@%d, :@%d",importPath.Data(),pipepos,pos);
filename = importPath;
objname = "";
return true;
}
return false;
}
TFile* TQFolder::openFile(TString& importPath,const TString& opt){
TString filename,objname;
DEBUGclass("function called on path '%s'",importPath.Data());
if(!parseLocation(importPath,filename,objname)) return NULL;
DEBUGclass("parsed location: filename='%s', objname='%s'",filename.Data(),objname.Data());
importPath = objname;
TFile* file = NULL;
if(!filename.IsNull() && TQUtils::fileExists(filename)){
file = TFile::Open(filename.Data(), opt);
if (file && !file->IsOpen()) {
delete file;
file=NULL;
}
}
if(!file){
ERRORclass("unable to open file '%s'",filename.Data());
}
return file;
}
TObject * TQFolder::importObject(TString importPath,bool recurse) {
TDirectory* dir = this->fMyDir;
importPath = TQStringUtils::trim(importPath);
bool local = false;
if (TQStringUtils::countLeading(importPath,":")>0) local = true;
DEBUGclass("function called on path '%s'",importPath.Data());
TFile* file = this->openFile(importPath,"READ");
if(file)
dir = file;
else if (!local) {
ERRORclass("Failed to retrieve object: File not found!");
return NULL;
} else if(!dir)
dir = gDirectory;
TObject * imported = NULL;
if(importPath.IsNull()){
ERRORclass("cannot import object without name or path - did you forget the ':[name]'?");
} else {
DEBUGclass("importing object to path '%s'",importPath.Data());
imported = importObjectFromDirectory(dir, importPath,recurse);
}
if(file){
file->Close();
delete file;
}
return imported;
}
const TString& TQFolder::getValidNameCharacters() {
return TQStringUtils::getDefaultIDCharacters();
}
bool TQFolder::isValidName(const TString& name) {
if (name.CountChar('.') == name.Length()) {
return false;
} else {
return TQStringUtils::isValidIdentifier(name, getValidNameCharacters(), 1, -1);
}
}
bool TQFolder::isValidPath(TString path, bool allowRelativePaths, bool allowWildcards, bool allowArithmeticStringExpressions) {
bool isValid = !path.IsNull();
while (isValid && !path.IsNull()) {
TString pathToken = getPathHead(path);
isValid &= isValidName(pathToken)
|| (allowRelativePaths &&
(pathToken.CompareTo(".") == 0 || pathToken.CompareTo("..") == 0))
|| (allowWildcards &&
(pathToken.CompareTo("*") == 0 || pathToken.CompareTo("?") == 0))
|| (allowArithmeticStringExpressions &&
TQStringUtils::matches(pathToken,"[*]"));
}
return isValid;
}
TString TQFolder::makeValidIdentifier(TString identifier, TString replacement) {
return TQStringUtils::makeValidIdentifier(identifier, getValidNameCharacters(), replacement);
}
TString TQFolder::makeValidPath(TString path, TString replacement,
bool allowRelativePaths, bool allowWildcards) {
bool leadingSlash = TQStringUtils::removeLeading(path, "/", 1);
bool trailingSlash = TQStringUtils::removeTrailing(path, "/", 1);
TString result;
while (!path.IsNull()) {
TString subPath = TQFolder::getPathHead(path);
if ((allowRelativePaths &&
(subPath.CompareTo(".") == 0 || subPath.CompareTo("..") == 0))
|| (allowWildcards &&
(subPath.CompareTo("*") == 0 || subPath.CompareTo("?") == 0))) {
result = TQFolder::concatPaths(result, subPath);
} else {
result = TQFolder::concatPaths(result,
TQFolder::makeValidIdentifier(subPath, replacement));
}
}
if (leadingSlash) {
result.Prepend("/");
}
if (trailingSlash) {
result.Append("/");
}
return result;
}
TString TQFolder::getPathHead(TString &path) {
int pos = 1;
while (pos < path.Length() && path[pos] != '/') {
pos++;
}
int start = path.BeginsWith("/") ? 1 : 0;
TString result = path(start, pos - start);
path.Remove(0, pos + 1);
return result;
}
TString TQFolder::getPathTail(TString &path) {
int pos = path.Length() - 2;
while (pos >= 0 && path[pos] != '/') {
pos--;
}
if (pos >= 0) {
TString result = path(pos + 1,
path.Length() - pos - 1 - (path.EndsWith("/") ? 1 : 0));
path.Remove(std::max(pos,1));
return result;
} else {
TString result = path;
path.Clear();
return result;
}
}
TString TQFolder::getPathWithoutHead(TString path) {
getPathHead(path);
return path;
}
TString TQFolder::getPathWithoutTail(TString path) {
getPathTail(path);
return path;
}
TString TQFolder::concatPaths(TString path1, TString path2) {
TQStringUtils::removeTrailingText(path2,"/.");
TQStringUtils::removeTrailingText(path1,"/.");
TQStringUtils::removeLeadingText(path2,"./");
TQStringUtils::removeTrailing(path1, "/",1);
if (!path1.IsNull()) TQStringUtils::removeLeading(path2, "/",1);
if (!path1.IsNull() && !path2.IsNull()) {
return path1 + "/" + path2;
} else {
return path1 + path2;
}
}
TString TQFolder::concatPaths(const TString& path1, const TString& path2, const TString& path3) {
return concatPaths(concatPaths(path1, path2), path3);
}
TString TQFolder::concatPaths(const TString& path1, const TString& path2, const TString& path3, const TString& path4) {
return concatPaths(concatPaths(path1, path2), concatPaths(path3, path4));
}
TString TQFolder::concatPaths(const TString& path1, const TString& path2, const TString& path3, const TString& path4, const TString& path5) {
return concatPaths(concatPaths(path1, path2), concatPaths(path3, path4), path5);
}
int TQFolder::countPathLevels(TString path, bool checkPathTokens) {
int levels = 0;
while (!path.IsNull()) {
TString subPath = getPathHead(path);
if (isValidName(subPath) || !checkPathTokens) {
levels++;
} else {
return -1;
}
}
return levels;
}
bool TQFolder::isEquivalentTo(TQFolder * f, const TString& options) {
TQTaggable * opts = TQTaggable::parseFlags(options);
if (!opts) {
ERRORclass("Failed to parse options '%s'", options.Data());
return false;
}
bool result = false;
result = this->isEquivalentTo(f, *opts);
delete opts;
return result;
}
bool TQFolder::isEquivalentTo(TQFolder * f, TQTaggable& options) {
if (!f) {
return false;
}
bool equivalent = true;
if (!this->tagsAreEquivalentTo(f)) {
equivalent = false;
}
TList * objects = TQListUtils::getMergedListOfNames(
this->GetListOfFolders(), f->GetListOfFolders(), false);
TQIterator itrObjects(objects, true);
while (itrObjects.hasNext()) {
TString name = itrObjects.readNext()->GetName();
TObject * obj1 = this->FindObject(name);
TObject * obj2 = f->FindObject(name);
if (!obj1 || !obj2) {
equivalent = false;
continue;
}
if (obj1->InheritsFrom(TQFolder::Class()) && obj2->InheritsFrom(TQFolder::Class())) {
if (!((TQFolder*)obj1)->isEquivalentTo((TQFolder*)obj2, options)) {
equivalent = false;
}
} else if (!TQUtils::areEquivalent(obj1, obj2)) {
equivalent = false;
}
}
fIsEquivalentToSnapshot = equivalent;
return equivalent;
}
bool TQFolder::printDiff(const TString& path1, const TString& path2, const TString& options) {
TQFolder * f1 = this->getFolder(path1);
TQFolder * f2 = this->getFolder(path2);
if (f1 && f2) {
return f1->printDiff(f2, options);
} else {
ERRORclass("Failed to find folder '%s'", f1 ? path2.Data() : path1.Data());
return false;
}
}
bool TQFolder::printDiff(TQFolder * f, const TString& options) {
TQTaggable * opts = TQTaggable::parseFlags(options);
if (!opts) {
ERRORclass("Failed to parse options '%s'", options.Data());
return false;
}
bool result = false;
result = this->printDiff(f, *opts, 0);
delete opts;
return result;
}
bool TQFolder::printDiff(TQFolder * f, TQTaggable& options, int indent) {
const int cColWidth_Total = TQLibrary::getConsoleWidth();
const int cColWidth_Name = 0.5*cColWidth_Total;
const int cColWidth_Comp = 0.2*cColWidth_Total;
const int cColWidth_Details = cColWidth_Total - cColWidth_Name - cColWidth_Comp;
if (!f) {
return false;
}
if (indent == 0) {
this->isEquivalentTo(f, options);
}
if (fIsEquivalentToSnapshot) {
return true;
}
bool printDetails = options.getTagBoolDefault("d", false);
TList * objects = TQListUtils::getMergedListOfNames(
this->GetListOfFolders(), f->GetListOfFolders(), false);
TString line;
TString comp;
if (indent == 0) {
line = TQStringUtils::fixedWidth("Name", cColWidth_Name, "l");
line.Append(TQStringUtils::fixedWidth("Comparison", cColWidth_Comp, "l"));
if (printDetails) {
line.Append(TQStringUtils::fixedWidth("Details (1)", cColWidth_Details, "l"));
line.Append(TQStringUtils::fixedWidth("Details (2)", cColWidth_Details, "l"));
}
std::cout << TQStringUtils::makeBoldWhite(line) << std::endl;
std::cout << TQStringUtils::makeBoldWhite(TQStringUtils::repeat("=", line.Length())) << std::endl;
} else {
line = TQStringUtils::fixedWidth(TQStringUtils::repeatSpaces((indent - 1) * 2) + TQStringUtils::makeBoldBlue(this->GetName()) + "/", cColWidth_Name, "l");
std::cout << line << std::endl;
}
TQTaggable tagDiffOpts;
tagDiffOpts.setTagBool("z", true);
tagDiffOpts.setTagBool("m", true);
tagDiffOpts.setTagInteger("i", indent);
tagDiffOpts.setTagBool("d", printDetails);
this->printDiffOfTags(f, tagDiffOpts);
TQIterator itrObjects(objects, true);
while (itrObjects.hasNext()) {
TString name = itrObjects.readNext()->GetName();
TObject * obj1 = this->FindObject(name);
TObject * obj2 = f->FindObject(name);
if (obj1 && obj2) {
if (obj1->InheritsFrom(TQFolder::Class()) && obj2->InheritsFrom(TQFolder::Class())) {
((TQFolder*)obj1)->printDiff((TQFolder*)obj2, options, indent + 1);
continue;
}
if (TQUtils::areEquivalent(obj1, obj2)) {
continue;
}
if (obj1->IsA() == obj2->IsA()) {
comp = TQStringUtils::makeBoldYellow("(1) =? (2)");
} else if (obj1->InheritsFrom(obj2->IsA())) {
comp = TQStringUtils::makeBoldYellow("(1) -> (2)");
} else if (obj2->InheritsFrom(obj1->IsA())) {
comp = TQStringUtils::makeBoldYellow("(1) <- (2)");
} else {
comp = TQStringUtils::makeBoldRed("(1) != (2)");
}
} else if (!obj2) {
if (obj1->InheritsFrom(TQFolder::Class())) {
name = TQStringUtils::makeBoldBlue(name) + "/";
}
comp = TQStringUtils::makeBoldRed("(1) - ");
} else if (!obj1) {
if (obj2->InheritsFrom(TQFolder::Class())) {
name = TQStringUtils::makeBoldBlue(name) + "/";
}
comp = TQStringUtils::makeBoldRed(" - (2)");
}
line = TQStringUtils::fixedWidth(TQStringUtils::repeatSpaces(indent * 2) + name, cColWidth_Name, "l");
line.Append(TQStringUtils::fixedWidth(comp, cColWidth_Comp, "l"));
std::cout << line.Data() << std::endl;
}
return false;
}
void TQFolder::printContents(const TString& options) {
this->printInternal(options,0,true);
}
void TQFolder::print(const TString& options) {
this->printInternal(options,0,true);
}
void TQFolder::printInternal(TString options, int indent,bool resolve) {
const int cColWidth_Total = TQLibrary::getConsoleWidth();
const int cColWidth_Name = std::min((int)(0.5*cColWidth_Total),60);
const int cColWidth_Class = std::min((int)(0.2*cColWidth_Total),30);
const int cColWidth_Details = cColWidth_Total - cColWidth_Name - cColWidth_Class;
TString path = TQStringUtils::readPrefix(options, ":");
if (!path.IsNull()) {
TQFolder * folderToPrint = this->getFolder(path);
if (folderToPrint) {
folderToPrint->printInternal(options,indent,resolve);
} else {
WARNclass("unknown path '%s'",path.Data());
}
return;
}
TString flags;
TString objectFilter;
TString tagFilter;
TString localOptions = options;
int maxDepth = 0;
bool hasMaxDepth = false;
bool hasTagFlag = false;
bool makeTeX = false;
bool stop = false;
while (!stop) {
if (TQStringUtils::readToken(localOptions, flags, "dhHcCl") > 0)
continue;
if (TQStringUtils::removeLeadingText(localOptions, "TeX")){
makeTeX = true;
}
if (TQStringUtils::readToken(localOptions, flags, "f", 1) > 0) {
if (objectFilter.Length() > 0) {
ERRORclass("cannot define more than one object filter using 'f'");
return;
}
if (!(TQStringUtils::readBlock(localOptions, objectFilter, "[]") > 0
&& objectFilter.Length() > 0)) {
ERRORclass("filter definition expected after option 'f'");
return;
}
continue;
}
if (TQStringUtils::readToken(localOptions, flags, "r", 1) > 0) {
TString maxDepthStr;
if (TQStringUtils::readToken(localOptions, maxDepthStr,
TQStringUtils::getNumerals()) > 0) {
if (hasMaxDepth) {
ERRORclass("cannot define more than one maximum recursion depth using 'r'");
return;
} else {
maxDepth = maxDepthStr.Atoi();
if(maxDepth == 0) resolve = false;
hasMaxDepth = true;
}
} else {
maxDepth = -1;
hasMaxDepth = true;
}
continue;
}
if (TQStringUtils::readToken(localOptions, flags, "t", 1) > 0) {
if (hasTagFlag) {
ERRORclass("cannot define more than one tag filter using 't'");
return;
} else {
hasTagFlag = true;
}
TQStringUtils::readBlock(localOptions, tagFilter, "[]");
continue;
}
stop = true;
}
if (localOptions.Length() > 0) {
ERRORclass("unknown option '%c'", localOptions[0]);
return;
}
if(resolve){
DEBUGclass("resolving import links from print funtion");
this->resolveImportLinks(false);
}
bool flagDetails = flags.Contains("d");
bool flagRecursive = flags.Contains("r");
bool hideElements = flags.Contains("h");
bool hideAll = flags.Contains("H");
bool countElements = flags.Contains("c");
bool countElementsRec = flags.Contains("C");
bool flagIndentLines = flags.Contains("l");
if (indent == 0) {
if(!makeTeX){
TString headline;
headline.Append(TQStringUtils::fixedWidth("Name", cColWidth_Name, "l"));
headline.Append(TQStringUtils::fixedWidth("Class", cColWidth_Class, "l"));
if (flagDetails)
headline.Append(TQStringUtils::fixedWidth("Details", cColWidth_Details, "l"));
std::cout << TQStringUtils::makeBoldWhite(headline) << std::endl;
std::cout << TQStringUtils::makeBoldWhite(TQStringUtils::repeat("=", TQStringUtils::getWidth(headline))) << std::endl;
} else {
std::cout << "\\documentclass{standalone}\n";
std::cout << "\\usepackage[T1]{fontenc}\n";
std::cout << "\\usepackage{pxfonts}\n";
std::cout << "\\usepackage[html]{xcolor}\n";
std::cout << "\\definecolor{folder} {HTML}{5555FF}\n";
std::cout << "\\definecolor{samplefolder}{HTML}{55FF55}\n";
std::cout << "\\definecolor{hidden} {HTML}{FF55FF}\n";
std::cout << "\\definecolor{tag} {HTML}{00AAAA}\n";
std::cout << "\\providecommand{\\tabularnewline}{\\\\}\n";
std::cout << "\\newcommand\\hindent{\\hspace{2em}}\n";
std::cout << "\\newcommand\\stylefolder[1]{{\\bfseries\\color{folder}#1}}\n";
std::cout << "\\newcommand\\stylesamplefolder[1]{{\\bfseries\\color{samplefolder}#1}}\n";
std::cout << "\\newcommand\\styletag[1]{{\\color{tag}#1}}\n";
std::cout << "\\newcommand\\stylehidden[1]{{\\bfseries\\color{hidden}#1}}\n";
std::cout << "\\begin{document}\\ttfamily\n";
std::cout << "\\begin{tabular}{l l";
if(flagDetails) std::cout << " l";
std::cout << "}\n";
std::cout << "\\bfseries Name & \\bfseries Class";
if(flagDetails) std::cout << " & \\bfseries Details";
std::cout << "\\tabularnewline\\hline\\hline\n";
}
}
TString indentStr;
if (flagIndentLines)
indentStr = TQStringUtils::getIndentationLines(indent);
else if(makeTeX){
indentStr = TQStringUtils::repeat("\\hindent{}",indent);
} else {
indentStr = TQStringUtils::repeatSpaces(indent * 2);
}
if (hasTagFlag && getNTags() > 0) {
TList * tagKeys = this->getListOfKeys(tagFilter);
if (tagKeys) {
TQIterator itr(tagKeys,true);
while(itr.hasNext()){
TObject* obj = itr.readNext();
TString key = obj->GetName();
TString type;
this->getTypeOfTagAsString(key, type);
TString details;
if (flagDetails) {
this->getValueOfTagAsString(key, details);
}
if(makeTeX){
std::cout << indentStr;
key.ReplaceAll("_","\\_");
std::cout << "\\styletag{<" << key << ">}";
std::cout << " & ";
std::cout << "<Tag:" << type << ">";
if(flagDetails){
std::cout << " & ";
details.ReplaceAll("$","\\$");
details.ReplaceAll("_","\\_");
std::cout << details;
}
std::cout << "\\tabularnewline";
std::cout << std::endl;
} else {
std::cout << indentStr;
std::cout << TQStringUtils::fixedWidth(TQStringUtils::makeTurquoise((TString)"<"+key+">"), cColWidth_Name - 2*indent, "l");
std::cout << TQStringUtils::fixedWidth(TString::Format("<Tag:%s>",type.Data()), cColWidth_Class, "l");
if(flagDetails)
std::cout << TQStringUtils::fixedWidth(details, cColWidth_Details, "l");
std::cout << std::endl;
}
}
}
}
TQIterator itr(this->GetListOfFolders());
while(itr.hasNext()){
TObject* obj = itr.readNext();
TString objName = obj->GetName();
TString className = obj->IsA()->GetName();
if (hideAll && objName.BeginsWith("."))
continue;
TString bareName = objName;
TString nameAppendix;
if (obj->InheritsFrom(TQFolder::Class())) {
if (!objectFilter.IsNull()
&& (!flagRecursive || ((TQFolder*)obj)->getNObjects(objectFilter, true) == 0)
&& !TQStringUtils::matchesFilter(objName, objectFilter, ",", true))
continue;
nameAppendix.Append("/");
if (countElements || countElementsRec) {
int nElements = -1;
int nElementsRec = -1;
if (countElements)
nElements = ((TQFolder*)obj)->getNElements(false);
if (countElementsRec)
nElementsRec = ((TQFolder*)obj)->getNElements(true);
if (countElements && countElementsRec && (nElements != nElementsRec))
nameAppendix = TString::Format(" [c:%d,C:%d]", nElements, nElementsRec);
else if (countElements)
nameAppendix = TString::Format(" [%d]", nElements);
else if (countElementsRec)
nameAppendix = TString::Format(" [%d]", nElementsRec);
}
} else {
if (objectFilter.Length() > 0 && !TQStringUtils::matches(objName, objectFilter))
continue;
}
TString details;
if (flagDetails) {
details = TQStringUtils::getDetails(obj);
}
std::cout << indentStr;
if(makeTeX){
bareName.ReplaceAll("_","\\_");
if (obj->InheritsFrom(TQFolder::Class())) {
if (obj->InheritsFrom(TQSampleFolder::Class())) {
std::cout << "\\stylesamplefolder{" << bareName << "}";
} else if (objName.BeginsWith(".")) {
std::cout << "\\stylehidden{" << bareName << "}";
} else {
std::cout << "\\stylefolder{" << bareName << "}";
}
} else {
std::cout << bareName;
}
std::cout << nameAppendix;
std::cout << " & " << className;
if (flagDetails)
std::cout << " & " << details;
std::cout << "\\tabularnewline";
std::cout << std::endl;
} else {
if (obj->InheritsFrom(TQFolder::Class())) {
if (obj->InheritsFrom(TQSampleFolder::Class())) {
bareName = TQStringUtils::makeBoldGreen(bareName);
} else if (objName.BeginsWith(".")) {
bareName = TQStringUtils::makeBoldPink(bareName);
} else {
bareName = TQStringUtils::makeBoldBlue(bareName);
}
}
std::cout << TQStringUtils::fixedWidth(bareName+nameAppendix, cColWidth_Name-2*indent, "l.");
std::cout << TQStringUtils::fixedWidth(className, cColWidth_Class, "l");
if (flagDetails)
std::cout << TQStringUtils::fixedWidth(details, cColWidth_Details, "l");
std::cout << std::endl;
}
if ((maxDepth == -1 || maxDepth > indent) && obj->InheritsFrom(TQFolder::Class())
&& !(hideElements && objName.BeginsWith(".")))
((TQFolder*)obj)->printInternal(options, indent + 1,true);
}
if(indent == 0 && makeTeX){
std::cout << "\\end{tabular}\n\\end{document}" << std::endl;
}
}
bool TQFolder::checkConsistency(bool verbose) {
bool failed = false;
TQIterator itr(this->getListOfFolders(), true);
while (itr.hasNext()) {
TObject * obj = itr.readNext();
if (!obj->InheritsFrom(TQFolder::Class())) {
continue;
}
TQFolder * folder = (TQFolder*)obj;
if (folder->getBase() != this) {
if (verbose) {
ERRORclass("Folder '%s' in folder '%s' has pointer to wrong base folder", folder->GetName(),this->getPath().Data());
}
failed = true;
} else if (!folder->checkConsistency(verbose)) {
failed = true;
}
}
return !failed;
}
bool TQFolder::isBaseOf(TQFolder * folder) {
if (!folder) {
return false;
}
TQFolder * base = folder->getBase();
if (!base) {
return false;
}
if (this == base) {
return true;
} else {
return isBaseOf(base);
}
}
bool TQFolder::removeObject(const TString& name) {
return (deleteObject(name, true) > 0);
}
int TQFolder::deleteObject(TString path, bool removeOnly, TClass *tclass) {
const bool collapse = (TQStringUtils::removeTrailing(path,"-")>0);
const bool force = (TQStringUtils::removeTrailing(path,"!")>0);
TQIterator itr(this->getListOfObjectPaths(path, tclass),true);
int nDel = 0;
while(itr.hasNext()){
TObject* name = itr.readNext();
TString objpath(name->GetName());
TString objname = TQFolder::getPathTail(objpath);
TQFolder* f = objpath.IsNull() ? this : this->getFolder(objpath);
if(!f) continue;
TObject* obj = f->getObject(objname);
TQFolder* objf = dynamic_cast<TQFolder*>(obj);
if(objf){
if(objf->isEmpty() || force){
DEBUGclass("deleting folder '%s' in '%s' %s",objf->GetName(),objf->getPath().Data(),(objf->isEmpty() ? "(empty)" : "(forced)"));
objf->detachFromBase();
nDel++;
if(!removeOnly) delete objf;
}
} else {
DEBUGclass("deleting object '%s' (class: %s)",obj->GetName(),obj->Class()->GetName());
f->Remove(obj);
nDel++;
if(!removeOnly) delete obj;
}
while(collapse && f->isEmpty()){
TQFolder* tmpf = f->getBase();
f->detachFromBase();
delete f;
f = tmpf;
}
}
return nDel;
}
int TQFolder::deleteAll() {
int nDel = 0;
TQIterator itr(GetListOfFolders());
while (itr.hasNext()) {
TObject * obj = itr.readNext();
Remove(obj);
if (obj->InheritsFrom(TQFolder::Class())) {
nDel += ((TQFolder*)obj)->deleteAll();
}
delete obj;
nDel++;
}
return nDel;
}
void TQFolder::sortByNameRecursive() {
TQFolderIterator itr(this->getListOfFolders("*"),true);
while(itr.hasNext()){
TQFolder* f = itr.readNext();
if(!f) continue;
if(f->isEmpty()) continue;
f->sortByName();
}
}
int TQFolder::sortByName() {
std::vector<TString> names;
TQIterator itr1(this->GetListOfFolders());
while (itr1.hasNext()) {
names.push_back(itr1.readNext()->GetName());
}
std::sort(names.begin(),names.end());
for(auto name:names){
TObject * obj = this->getObject(name);
this->Remove(obj);
this->Add(obj);
}
return names.size();
}
TQFolder * TQFolder::detachFromBase() {
if (fBase) {
fBase->Remove(this);
fBase = 0;
}
return this;
}
bool TQFolder::moveTo(TQFolder * dest, const TString& newName) {
if (!dest) {
DEBUGclass("Null pointer TQFolder destination in moveTo");
return false;
}
DEBUGclass(TString::Format("Will now try to move this folder to destination folder %s", dest->getPath().Data()));
if (dest == this) {
DEBUGclass("Cannot move folder to itself");
return false;
}
if (dest == fBase) {
if (!newName.IsNull() && isValidName(newName)) {
this->SetName(newName.Data());
return true;
} else {
DEBUGclass("newName is null or is not valid");
return false;
}
}
if (this->isBaseOf(dest)) {
DEBUGclass("this instance of TQFolder is a base folder of the destination folder!");
return false;
}
TQFolder * tmpBase = fBase;
fBase = NULL;
TObject * add;
if (newName.IsNull()) {
add = dest->addObject(this);
} else {
add = dest->addObject(this, newName + "::");
}
if (add) {
if (tmpBase) {
tmpBase->Remove(this);
}
return true;
} else {
fBase = tmpBase;
DEBUGclass("Failed to move instance of TQFolder");
return false;
}
}
bool TQFolder::moveTo(const TString& dest) {
DEBUGclass(TString::Format("moveTo called with argument %s", dest.Data()));
TString path;
TString newName;
if (!parseDestination(dest, path, newName)) {
DEBUGclass("Failed to parse destination in moveTo(dest)");
return false;
}
DEBUGclass(TString::Format("Will now try to move this folder to path %s and with new name %s", path.Data(), newName.Data()));
return moveTo(this->getFolder(path), newName);
}
bool TQFolder::moveFolder(const TString& source, const TString& dest) {
TQFolder * src = this->getFolder(source);
if (!src) {
return false;
}
TString path;
TString newName;
if (!parseDestination(dest, path, newName)) {
return false;
}
return src->moveTo(this->getFolder(path), newName);
}
TQFolder * TQFolder::copy(const TString& newName) {
TString name(newName.IsNull() ? this->GetName() : newName.Data());
TQFolder* copy = this->newInstance(name);
if(!copy){
ERRORclass("unable to copy object '%s'",name.Data());
return NULL;
}
copy->importTags(this);
DEBUGclass("resolving import links for copy funtion");
this->resolveImportLinks(true);
TQIterator itr(GetListOfFolders());
while(itr.hasNext()){
TObject*obj = itr.readNext();
if (obj->InheritsFrom(TQFolder::Class())){
TQFolder* f = dynamic_cast<TQFolder*>(obj);
if(f->getTagBoolDefault(".allowCopy",true)){
TQFolder* fcopy = f->copy();
if(fcopy){
copy->addFolder(fcopy);
}
}
} else {
TObject* clone = obj->Clone();
copy->addObject(clone);
}
}
return copy;
}
TQFolder * TQFolder::copyTo(TQFolder * dest) {
if (!dest) {
return NULL;
}
TQFolder * copy = this->copy();
if (dest->addObject(copy)) {
return copy;
} else {
delete copy;
return NULL;
}
}
TQFolder * TQFolder::copyTo(const TString& dest) {
return this->copyTo(this->getFolder(dest));
}
TQFolder * TQFolder::copyFolder(const TString& source, const TString& dest) {
TQFolder * src = this->getFolder(source);
if (!src) {
return NULL;
}
return src->copyTo(this->getFolder(dest));
}
int TQFolder::getNElements(bool recursive, TClass * tclass) {
if(recursive){
DEBUGclass("resolving import links to count elements");
this->resolveImportLinks(recursive);
}
int nElements = 0;
TQIterator itr(this->GetListOfFolders());
while (itr.hasNext()){
TObject * obj = itr.readNext();
if (!tclass || obj->InheritsFrom(tclass))
nElements++;
if (recursive && obj->InheritsFrom(TQFolder::Class()))
nElements += ((TQFolder*)obj)->getNElements(true, tclass);
}
return nElements;
}
int TQFolder::getNObjects(const TString& nameFilter) const {
int nObjects = 0;
TQIterator itr(GetListOfFolders());
while(itr.hasNext()){
TObject* obj = itr.readNext();
if (nameFilter.IsNull() || TQStringUtils::matches(TString(obj->GetName()), nameFilter))
nObjects++;
}
return nObjects;
}
int TQFolder::getNObjects(const TString& nameFilter, bool recursive) {
if(recursive) this->resolveImportLinks(true);
int nObjects = 0;
TQIterator itr(GetListOfFolders());
while(itr.hasNext()){
TObject* obj = itr.readNext();
if (nameFilter.IsNull() || TQStringUtils::matches(TString(obj->GetName()), nameFilter))
nObjects++;
if (recursive && obj->InheritsFrom(TQFolder::Class()))
nObjects += ((TQFolder*)obj)->getNObjects(nameFilter, recursive);
}
return nObjects;
}
bool TQFolder::isEmpty() const {
TCollection* c = this->GetListOfFolders();
if(!c) return true;
return (c->GetEntries() == 0);
}
int TQFolder::getOwnSize() const {
return sizeof(*this);
}
int TQFolder::getSize(bool memoryOnly) {
if(!memoryOnly){
DEBUGclass("resolving import links to estimate size");
this->resolveImportLinks(true);
}
int size = this->getOwnSize() + sizeof(*this->fFolders) + this->getTagsSize() + this->getFlagsSize();
TQIterator itr(GetListOfFolders());
while(itr.hasNext()){
TObject* obj = itr.readNext();
if (obj->InheritsFrom(TQFolder::Class()))
size += ((TQFolder*)obj)->getSize();
else if (obj->InheritsFrom(TH1::Class()))
size += TQHistogramUtils::estimateSize((TH1*)obj);
else
size += sizeof(*obj);
}
return size;
}
TString TQFolder::getSizeAsString(bool memoryOnly) {
double size = (double)getSize(memoryOnly);
int power = 0;
while ((size >= 1000.)) {
power++;
size /= 1000.;
}
TString unit = "B";
if (power == 1)
unit.Prepend("k");
else if (power == 2)
unit.Prepend("M");
else if (power == 3)
unit.Prepend("G");
else if (power == 4)
unit.Prepend("T");
else
unit.Prepend("?");
return TString::Format("%.1f %s", size, unit.Data());
}
void TQFolder::setBase(TQFolder * base_) {
fBase = base_;
}
TQTaggable * TQFolder::getBaseTaggable() const {
return fBase;
}
TList * TQFolder::getDescendantTaggables() {
return this->getListOfFolders("?");
}
TList * TQFolder::getListOfTaggables(const TString& taggables) {
return getListOfFolders(taggables);
}
TList * TQFolder::getTaggablesByName(const TString& taggables) {
return getListOfFolders(taggables);
}
TList * TQFolder::getListOfFolders(const TString& path_, TClass * tClass, bool toplevelOnly, bool firstMatchOnly) {
DEBUGfunc(TString::Format("called with '%s', topLevelOnly=%d, firstMatchOnly=%d",path_.Data(),(int)toplevelOnly,(int)firstMatchOnly));
if(path_.Contains(",")){
TList* retval = new TList();
std::vector<TString> paths = TQStringUtils::split(path_,",");
for(size_t i=0; i<paths.size(); i++){
TList* sublist = this->getListOfFolders(paths[i], tClass, toplevelOnly, firstMatchOnly);
if(sublist){
retval->AddAll(sublist);
delete sublist;
}
}
if(retval->GetEntries() < 1){
delete retval;
return NULL;
}
return retval;
}
TString path = TQStringUtils::trim(path_);
if (TQStringUtils::removeLeading(path,"/") > 0) {
TQFolder * root = getRoot();
return root->getListOfFolders(path, tClass, toplevelOnly, firstMatchOnly);
}
if (path.IsNull()) return 0;
TString find(path);
TString findNext;
Ssiz_t splitPos = find.First('/');
if (splitPos != kNPOS) {
findNext = find(splitPos + 1, find.Length());
find.Remove(splitPos);
TQStringUtils::removeLeading(findNext,"/");
}
TList * list = NULL;
if (find.EqualTo("?") || find.EqualTo("*")) {
bool stop = false;
if (find.EqualTo("*")) {
if(!firstMatchOnly){
DEBUGclass("resolving import links because '*' was found in path");
this->resolveImportLinks(true);
}
if (!findNext.IsNull()) {
list = getListOfFolders(findNext, tClass, toplevelOnly, firstMatchOnly);
if((firstMatchOnly || toplevelOnly) && list && (list->GetEntries() > 0)) stop=true;
} else if (!tClass || this->InheritsFrom(tClass)){
list = new TList();
list->Add(this);
if(toplevelOnly || firstMatchOnly) stop = true;
}
findNext = path;
} else {
if(!firstMatchOnly){
DEBUGclass("resolving import links because '?' was found in path");
this->resolveImportLinks(false);
}
}
if (!stop) {
TQFolderIterator itr(GetListOfFolders());
while (itr.hasNext()){
TQFolder* obj = itr.readNext();
if(!obj) continue;
if (!findNext.IsNull()){
TList * sublist = obj->getListOfFolders(findNext, tClass, toplevelOnly, firstMatchOnly);
if (sublist) {
if (list) {
list->AddAll(sublist);
delete sublist;
} else {
list = sublist;
if(firstMatchOnly) stop = true;
}
}
} else {
if(!tClass || obj->InheritsFrom(tClass)){
if (!list) list = new TList();
list->Add(obj);
if(firstMatchOnly) stop = true;
}
}
}
}
} else if(find.Contains("*")){
DEBUGclass(TString::Format("resolving import links because '*' was found in path '%s'",find.Data()));
this->resolveImportLinks(false);
TQFolderIterator itr(GetListOfFolders());
while (itr.hasNext()){
bool stop = false;
TQFolder* obj = itr.readNext();
if(!obj) continue;
if(!TQStringUtils::matches(obj->GetName(),find)) continue;
if (!findNext.IsNull()){
TList * sublist = obj->getListOfFolders(findNext, tClass, toplevelOnly, firstMatchOnly);
if (sublist) {
if (list) {
list->AddAll(sublist);
delete sublist;
} else {
if(firstMatchOnly) stop=true;
list = sublist;
}
}
} else {
if(!tClass || obj->InheritsFrom(tClass)){
if (!list) list = new TList();
if(firstMatchOnly) stop=true;
list->Add(obj);
}
}
if(stop) break;
}
} else {
TQFolder * element = 0;
if (find.EqualTo("..")) {
element = getBase();
} else if (find.EqualTo(".")) {
element = this;
} else {
DEBUGclass("resolving import link for '%s' in '%s'",find.Data(),this->getPath().Data());
this->resolveImportLink(find,false);
element = dynamic_cast<TQFolder*>(FindObject(find.Data()));
}
if (element){
if (!findNext.IsNull()) {
list = element->getListOfFolders(findNext, tClass, toplevelOnly, firstMatchOnly);
} else {
if(tClass ? element->InheritsFrom(tClass) : element->InheritsFrom(TQFolder::Class())){
list = new TList();
list->Add(element);
}
}
}
}
return list;
}
void TQFolder::getFoldersWithTagEquivalentToInternal(const TQValue* tag, std::vector<TQFolder*>& matches) {
if (this->hasEquivalentTag(tag,true) && !this->isTagOverwrittenByDescendants(tag->GetName()) ) {
matches.push_back(this);
return;
}
TQFolderIterator itr(this->getListOfFolders("?"),true);
while (itr.hasNext()) {
TQFolder* f = itr.readNext();
f->getFoldersWithTagEquivalentToInternal(tag, matches);
}
return;
}
std::vector<TQFolder*> TQFolder::getFoldersWithTagEquivalentTo(const TQValue* tag) {
std::vector<TQFolder*> results = {};
this->getFoldersWithTagEquivalentToInternal(tag, results);
return results;
}
std::vector<TQFolder*> TQFolder::getFoldersWithTagEquivalentTo(const TQValue& tag) {
return this->getFoldersWithTagEquivalentTo(&tag);
}
std::vector<TQFolder*> TQFolder::getFoldersWithTagsEquivalentTo(const std::vector<const TQValue*>& tags) {
std::vector<TQFolder*> results = {this};
std::vector<TQFolder*> previousResults = {};
for (const TQValue* thisTag : tags) {
previousResults = results;
results.clear();
for (TQFolder* prevMatch : previousResults) {
if (!prevMatch) continue;
prevMatch->getFoldersWithTagEquivalentToInternal(thisTag, results);
}
}
return results;
}
std::vector<TString> TQFolder::getFolderPaths(const TString& path_, TClass * tClass, bool toplevelOnly) {
DEBUGclass("getting folder paths for '%s'",path_.Data());
std::vector<TString> vec;
TQFolderIterator itr(this->getListOfFolders(path_,tClass,toplevelOnly),true);
while (itr.hasNext()) {
TQFolder * f = itr.readNext();
if (!f) continue;
vec.push_back(f->getPath());
}
return vec;
}
std::vector<TString> TQFolder::getFolderPathsWildcarded(const TString& path_, TClass * tClass, bool toplevelOnly) {
DEBUGclass("getting wildcarded folder paths for '%s'",path_.Data());
std::vector<TString> vec;
std::map<TString,bool> map;
TQFolderIterator itr(this->getListOfFolders(path_,tClass,toplevelOnly),true);
while (itr.hasNext()) {
TQFolder * f = itr.readNext();
if (!f) continue;
map[f->getPathWildcarded()] = true;
}
for(std::map<TString,bool>::iterator it = map.begin(); it != map.end(); ++it) {
vec.push_back(it->first);
}
return vec;
}
TList * TQFolder::getListOfObjects(TString path, TClass * tclass){
DEBUGclass("getting list of objects for '%s'",path.Data());
TString tail = TQFolder::getPathTail(path);
TList* retval = new TList();
if(!path.IsNull()){
TList* l = this->getListOfFolders(path);
TQFolderIterator itr(l,true);
while(itr.hasNext()){
TQFolder* f = itr.readNext();
if(!f) continue;
TList* sublist = f->getListOfObjects(tail,tclass);
retval->AddAll(sublist);
delete sublist;
}
} else {
TQIterator objItr(this->GetListOfFolders());
while(objItr.hasNext()){
TObject* obj = objItr.readNext();
if(!obj) continue;
if(tail.IsNull() || (tail == "?") || (TQStringUtils::matches(obj->GetName(),tail))){
if(!tclass || obj->InheritsFrom(tclass))
retval->Add(obj);
}
}
}
return retval;
}
TList * TQFolder::getListOfObjectPaths(TString path, TClass * tclass){
DEBUGclass("getting list of object paths for '%s'",path.Data());
TString tail = TQFolder::getPathTail(path);
TList* retval = new TList();
retval->SetOwner(true);
if(!path.IsNull()){
TList* l = this->getListOfFolders(path, tclass);
TQFolderIterator itr(l,true);
while(itr.hasNext()){
TQFolder* f = itr.readNext();
if(!f) continue;
TList* sublist = f->getListOfObjectPaths(tail,tclass);
sublist->SetOwner(false);
retval->AddAll(sublist);
delete sublist;
}
} else {
TQIterator objItr(this->GetListOfFolders());
while(objItr.hasNext()){
TObject* obj = objItr.readNext();
if(!obj) continue;
if(tail.IsNull() || (tail == "?") || (TQStringUtils::matches(obj->GetName(),tail))){
if(!tclass || obj->InheritsFrom(tclass))
retval->Add(new TObjString(TQFolder::concatPaths(this->getPath(),obj->GetName())));
}
}
}
return retval;
}
TObject * TQFolder::getCopyOfObject(const TString& name_, const TString& path_) {
TObject* obj = this->getObject(name_,path_);
if(!obj) return NULL;
TH1* hist = dynamic_cast<TH1*>(obj);
if(hist){
return TQHistogramUtils::copyHistogram(hist,"NODIR");
}
return obj->Clone();
}
TObject * TQFolder::getObject(const TString& name_, const TString& path_) {
DEBUGclass("called on '%s' with name='%s', path='%s'",this->getPath().Data(),name_.Data(),path_.Data());
if (path_.Length() == 0) {
return this->FindObject(name_.Data());
} else if(path_ == "?" || path_ == "*"){
DEBUGclass("getting any object");
TList* l = this->getListOfFolders(path_);
TQFolderIterator itr(l,true);
while(itr.hasNext()){
TQFolder* f = itr.readNext();
if(!f) continue;
TObject* obj = f->getObject(name_);
if(obj) return obj;
}
return NULL;
} else {
DEBUGclass(TString::Format("getting folder '%s'",path_.Data()));
TQFolder * folder = this->getFolder(path_);
if (folder)
return folder->getObject(name_);
else
return NULL;
}
}
TString TQFolder::getObjectPath(TString path) {
DEBUGclass("attempting to get path of object '%s'",path.Data());
TString name = TQFolder::getPathTail(path);
TList* l = this->getListOfFolders(TQFolder::concatPaths("*",path));
TQFolderIterator itr(l,true);
while(itr.hasNext()){
TQFolder* f = itr.readNext();
if(!f) continue;
TQIterator subitr(f->GetListOfFolders());
while(subitr.hasNext()){
TObject* obj = subitr.readNext();
if(TQStringUtils::matches(obj->GetName(),name)){
const TString basepath = f->getTagStringDefault("~basepath",".");
return TQFolder::concatPaths(basepath, f->getPath(), obj->GetName());
}
}
}
return "";
}
TList* TQFolder::getObjectPaths(TString namepattern, TString pathpattern, TClass* objClass) {
DEBUGclass("attempting to get paths of objects '%s'/'%s'",pathpattern.Data(),namepattern.Data());
TQStringUtils::ensureTrailingText(pathpattern,"/*");
pathpattern = TQFolder::concatPaths(pathpattern,namepattern);
namepattern = TQFolder::getPathTail(pathpattern);
std::set<TString> paths;
TQFolderIterator fitr(this->getListOfFolders(pathpattern),true);
while(fitr.hasNext()){
TQFolder* f = fitr.readNext();
TQIterator oitr(f->GetListOfFolders());
while(oitr.hasNext()){
TObject* obj = oitr.readNext();
if(TQStringUtils::matches(obj->GetName(),namepattern) && obj->InheritsFrom(objClass)){
const TString basepath = f->getTagStringDefault("~basepath",".");
paths.insert(TQFolder::concatPaths(basepath, f->getPath(), obj->GetName()));
}
}
}
TList* retval = new TList();
for(const auto& p:paths){
retval->Add(new TObjString( p ));
}
return retval;
}
TString TQFolder::getName() const {
return this->fName;
}
void TQFolder::setName(const TString& newName) {
this->fName = newName;
}
const TString& TQFolder::getNameConst() const {
return this->fName;
}
TQFolder * TQFolder::getFolder(const TString& path){
return this->getFolder(path,(TClass*)NULL);
}
TQFolder * TQFolder::getFolder(const char* path){
return this->getFolder(path,(TClass*)NULL);
}
TQFolder * TQFolder::getFolder(const TString& path_, TClass * tclass) {
TString path = TQStringUtils::trim(path_);
if(path.IsNull()) return this;
if(TQStringUtils::equal(path,"/")) return this->getRoot();
DEBUGclass("attempting to retrieve folder '%s' in '%s'",path.Data(),this->getPath().Data());
TQStringUtils::removeTrailing(path,"/");
bool force = ( TQStringUtils::removeTrailing(path,"!") == 1);
bool autoCreate = ( TQStringUtils::removeTrailing(path,"+") == 1);
TQStringUtils::removeTrailing(path,"/");
DEBUGclass(TString::Format("getting list of folders to get folder '%s'",path.Data()));
TList * list = getListOfFolders(path, tclass, false, true);
if (list && list->GetEntries() > 0) {
TQFolder * firstFolder = (TQFolder*)list->At(0);
delete list;
return firstFolder;
} else if (autoCreate) {
delete list;
TString nameToCreate = path;
TQFolder * baseFolder = this;
Ssiz_t splitPos = path.Last('/');
if (splitPos != kNPOS) {
nameToCreate = path(splitPos + 1, path.Length());
if (splitPos > 0)
path = path(0, splitPos);
else
path = "/.";
baseFolder = getFolder(path + (force ? "+!" : "+"), tclass);
}
if (baseFolder) {
TQFolder * newInstance;
if (tclass){
newInstance = (TQFolder*)(tclass->New());
newInstance->SetName(nameToCreate);
} else {
newInstance = new TQFolder(nameToCreate);
}
if (newInstance) {
if (baseFolder->addFolder(newInstance)) {
newInstance->setDirectory(this->fMyDir);
newInstance->autoSetExportName();
if(force) newInstance->SetName(nameToCreate);
return newInstance;
} else {
delete newInstance;
}
}
}
}
return 0;
}
TQFolder * TQFolder::addFolder(TQFolder * folder_, TString path_, TClass * tclass) {
if (!folder_) return 0;
if (path_.Length() == 0) {
if (!isValidName(folder_->GetName())) { return 0; }
if (folder_->getBase()) { return 0; }
if (FindObject(folder_->GetName())) { return 0; }
folder_->setBase(this);
Add(folder_);
return this;
} else {
return this->addObject(folder_,path_,tclass);
}
return 0;
}
TList * TQFolder::getListOfObjectNames(TClass * class_, bool recursive, TString path_) {
DEBUGclass("resolving import links to retrieve object names");
this->resolveImportLinks(recursive);
if (path_.Length() == 0) {
TList * result = new THashList();
result->SetOwner(true);
TQIterator itr(this->GetListOfFolders());
while(itr.hasNext()){
TObject* obj = itr.readNext();
if (obj->InheritsFrom(TQFolder::Class())) {
if (recursive) {
TList * subList = ((TQFolder*)obj)->getListOfObjectNames(class_, true);
subList->SetOwner(false);
TQIterator subitr(subList);
while (subitr.hasNext()){
TObjString* obs = static_cast<TObjString*>(subitr.readNext());
TString objectName(obs->GetString());
objectName.Prepend(TString(obj->GetName()) + "/");
obs->SetString(objectName.Data());
result->Add(obs);
}
delete subList;
}
} else if (!class_ || obj->InheritsFrom(class_)) {
result->Add(new TObjString(obj->GetName()));
}
}
return result;
} else {
TQFolder * folder = this->getFolder(path_);
if (folder){
return folder->getListOfObjectNames(class_, recursive);
} else {
return 0;
}
}
}
TString TQFolder::getPath() {
TString name(this->GetName());
this->getTagString(".realname",name);
if (fBase) {
if (fBase == getRoot()) {
name.Prepend("/");
return name;
} else {
return TQFolder::concatPaths(fBase->getPath(), name);
}
} else {
return TString("/.");
}
}
TString TQFolder::getPathWildcarded() {
TString name = (this->getTagBoolDefault("wildcarded",false) ? "?" : this->getName());
if (fBase) {
if (fBase == getRoot()) {
return TString::Format("/%s/", name.Data());
} else {
return TQFolder::concatPaths(fBase->getPathWildcarded(), name)+"/";
}
} else {
return TString("/");
}
}
TQFolder * TQFolder::getBase(int depth) const {
if (depth == 1) {
return fBase;
} else if (depth == 0) {
return (TQFolder*)this;
} else if (depth > 1 && fBase) {
return fBase->getBase(depth - 1);
} else {
return NULL;
}
}
int TQFolder::areRelated(const TQFolder* other) const {
if (!other) return 0;
if (this==other) return 1;
int thisDist = this->getDistToRoot();
int otherDist = other->getDistToRoot();
if (thisDist>otherDist) return -1*other->areRelated(this);
else if (thisDist<otherDist) {
int tmp = this->areRelated(other->getBase());
return tmp!=0 ? 1+tmp : 0;
}
return 0;
}
TQFolder * TQFolder::getRoot() {
if (fBase) {
return fBase->getRoot();
} else {
return this;
}
}
bool TQFolder::isRoot() {
return (fBase == NULL);
}
int TQFolder::getDistToRoot() const {
if (fBase) {
return fBase->getDistToRoot() + 1;
} else {
return 0;
}
}
int TQFolder::getDepth() {
DEBUGclass("resolving import links to obtain depth");
this->resolveImportLinks(true);
int depth = 0;
TQIterator itr(GetListOfFolders());
while (itr.hasNext()) {
TObject * obj = itr.readNext();
int localDepth = 1;
if (obj->InheritsFrom(TQFolder::Class())) {
localDepth += ((TQFolder*)obj)->getDepth();
}
depth = (localDepth > depth) ? localDepth : depth;
}
return depth;
}
TList * TQFolder::getTraceToRoot(bool startAtRoot) {
TList * list = NULL;
if (fBase) {
list = fBase->getTraceToRoot(startAtRoot);
}
if (!list) {
list = new TList();
list->SetOwner(false);
}
if (startAtRoot) {
list->AddLast(this);
} else {
list->AddFirst(this);
}
return list;
}
TQFolder * TQFolder::loadLazyFolder(TString path) {
return TQFolder::loadFolder(path,true);
}
TQFolder * TQFolder::loadFolder(TString path, bool lazy) {
TQFolder * dummy = TQFolder::newFolder("dummy");
if(path.Length() == 0){
ERRORclass("unable to open file with no name!");
return NULL;
}
TFile* file = TQFolder::openFile(path,"READ");
if(!file){
return NULL;
}
TObject * imported = dummy->importObjectFromDirectory(file, path,!lazy,TQFolder::Class());
TQFolder * folder = NULL;
if (imported && imported->InheritsFrom(TQFolder::Class())) {
TQFolder * importedFolder = (TQFolder*)imported;
while (importedFolder->getBase() != dummy)
importedFolder = importedFolder->getBase();
folder = importedFolder->detachFromBase();
}
delete dummy;
if(folder){
if(lazy){
folder->setDirectoryInternal(file);
folder->fOwnMyDir = true;
} else {
folder->setDirectoryInternal(NULL);
file->Close();
delete file;
}
folder->autoSetExportName();
} else {
file->Close();
delete file;
}
return folder;
}
TQFolder * TQFolder::loadFromTextFile(TString filename, bool showErrorMessage) {
TString errMsg;
TQFolder * folder = loadFromTextFile(filename, errMsg);
if (!folder && showErrorMessage) {
ERRORclass(errMsg);
}
return folder;
}
TQFolder * TQFolder::loadFromTextFile(TString filename, TString &errorMessage) {
DEBUGclass("loading folder from text file %s",filename.Data());
TString name = filename;
name = TQFolder::getPathTail(name);
TQFolder * folder = TQFolder::newFolder(TQFolder::makeValidIdentifier(name, "_"));
if (folder->importFromTextFile(filename, errorMessage)) {
return folder;
} else {
delete folder;
return NULL;
}
}
TQFolder * TQFolder::addObject(TObject * object, TString destination, TClass* folderClass) {
if (!object) {
return NULL;
}
DEBUGclass("entering function: object='%s', destination='%s'",object->GetName(),destination.Data());
bool overwrite = (TQStringUtils::removeTrailing(destination,"!") >0);
#ifdef _DEBUG_
if(overwrite) DEBUGclass("found overwrite flag");
#endif
TString path;
if (!destination.IsNull()) {
DEBUGclass("reading destination");
TQStringUtils::readUpTo(destination, path, ":");
path = TQStringUtils::trim(path);
}
bool newName = false;
TString name = object->GetName();
if (!destination.IsNull()) {
if (!object->InheritsFrom(TNamed::Class())){
ERRORclass("object '%s' cannot be renamed!",object->GetName());
return 0;
}
if (TQStringUtils::removeLeading(destination, ":") != 2){
ERRORclass("invalid number of ':'!");
return 0;
}
name = TQStringUtils::trim(destination);
if(!name.IsNull()) newName = true;
else name = object->GetName();
}
DEBUGclass("in '%s': adding object '%s' to path '%s' with new name '%s'",this->getPath().Data(),object->GetName(),path.Data(),name.Data());
if (newName && !isValidName(name) && !object->InheritsFrom(TObjString::Class())){
WARNclass("cannot attach object '%s' to path '%s' - invalid name!",object->GetName(),path.Data());
return NULL;
}
TQFolder* otherF = dynamic_cast<TQFolder*>(object);
if(otherF && !otherF->isRoot() && !(otherF->getRoot() == this->getRoot())){
WARNclass("cannot add subfolder of other folder structure!");
return NULL;
}
TQFolder * folder = getFolder(path,folderClass);
if (!folder) {
WARNclass("cannot attach object '%s' to path '%s' - unable to retrieve folder! did you forget the '+' or the '::'?",object->GetName(),path.Data());
return NULL;
}
if (folder->hasObject(name)){
if (overwrite){
folder->deleteObject(name);
} else {
WARNclass("not adding object '%s' to folder '%s' - an object of this name is already present",name.Data(),folder->getPath().Data());
return NULL;
}
}
if (newName)
((TNamed*)object)->SetName(name.Data());
if(otherF){
DEBUGclass("adding folder '%s' to '%s'",otherF->getPath().Data(),folder->getPath().Data());
otherF->detachFromBase();
folder->addFolder(otherF);
} else {
folder->Add(object);
}
return folder;
}
TDirectory * TQFolder::getDirectory(){
return this->fMyDir;
}
int TQFolder::setDirectory(TDirectory* dir, bool own){
DEBUGclass("resolving import links to set directory");
int retval = this->resolveImportLinks(this->fMyDir);
this->clearDirectoryInternal();
this->setDirectoryInternal(dir);
this->fOwnMyDir=own;
return retval;
}
void TQFolder::clearDirectoryInternal(){
if(this->fOwnMyDir){
TFile* f = dynamic_cast<TFile*>(this->fMyDir);
if(f) f->Close();
delete this->fMyDir;
}
}
void TQFolder::setDirectoryInternal(TDirectory* dir){
this->fMyDir = dir;
TCollection* l = TFolder::GetListOfFolders();
if(!l) return;
TQIterator itr(l);
while (itr.hasNext()) {
TQFolder* f = dynamic_cast<TQFolder*>(itr.readNext());
if(!f) continue;
f->setDirectoryInternal(dir);
}
}
TQFolder * TQFolder::addCopyOfObject(TObject * object, TString destination, TClass* folderClass) {
if (!object) {
return NULL;
}
TObject * copy;
if (object->InheritsFrom(TQFolder::Class())) {
copy = ((TQFolder*)object)->copy();
} else if (object->InheritsFrom(TH1::Class())) {
copy = TQHistogramUtils::copyHistogram((TH1*)object,"NODIR");
} else {
copy = object->Clone();
}
if (!copy) {
return NULL;
}
TQFolder * folder = addObject(copy, destination, folderClass);
if (!folder) {
delete copy;
}
return folder;
}
bool TQFolder::hasObject(TString name) {
if (TQStringUtils::removeLeading(name, "/") > 0)
return getRoot()->hasObject(name);
TString objName = TQFolder::getPathTail(name);
if (name.IsNull()) {
return (FindObject(objName.Data()) != 0);
} else {
TQFolder * folder = getFolder(name);
if (folder)
return folder->hasObject(objName);
else
return false;
}
}
int TQFolder::resolveImportLinks(bool recurse) {
return this->resolveImportLinks(NULL,recurse);
}
int TQFolder::resolveImportLinks(TDirectory * dir,bool recurse) {
if(this->isFullyResolved) return 0;
this->isFullyResolved = recurse;
int nLinks = 0;
TQIterator itr1(this->GetListOfFolders());
while (itr1.hasNext()) {
TObject * lnk = itr1.readNext();
if(recurse){
TQFolder* f = dynamic_cast<TQFolder*>(lnk);
if(f){
f->resolveImportLinks(dir,recurse);
if(!f->isFullyResolved) this->isFullyResolved = false;
}
}
if (lnk->InheritsFrom(TQImportLink::Class())) {
if (this->resolveImportLink(lnk->GetName(), dir,recurse)) {
nLinks++;
} else {
this->isFullyResolved = false;
}
}
}
return nLinks;
}
TObject * TQFolder::resolveImportLink(const TString& linkName, bool recurse) {
return this->resolveImportLink(linkName,NULL,recurse);
}
TObject * TQFolder::resolveImportLink(const TString& linkName, TDirectory * dir, bool recurse) {
if (!TQFolder::isValidName(linkName)) {
return NULL;
}
DEBUGclass("attempting to resolve import link '%s' in '%s' from directory '%p'", linkName.Data(),this->getPath().Data(),dir);
TObject * obj = this->getObject(linkName);
TQImportLink * lnk = dynamic_cast<TQImportLink*>(obj);
if (!lnk) return NULL;
TString importPath(TQStringUtils::trim(lnk->getImportPath()));
this->Remove(lnk);
TObject * imported = NULL;
if ((TQStringUtils::removeLeading(importPath, ":", 1) != 0)) {
if(dir){
imported = this->importObjectFromDirectory(dir, importPath,recurse);
} else {
imported = this->importObjectFromDirectory(this->getDirectory(), importPath,recurse);
}
} else {
imported = this->importObject(importPath,recurse);
}
if (imported) {
delete lnk;
} else {
ERRORclass("unable to resolve import ImportLink '%s' from directory '%s'",lnk->getImportPath().Data(),this->getDirectory()->GetName());
this->addObject(lnk);
}
return imported;
}
void TQFolder::autoSetExportName(){
if(this->isRoot()){
this->fExportName = this->GetName();
} else {
TString name(this->getBase()->getExportName());
if(name.IsNull()){
this->fExportName = this->GetName();
} else {
name += "-" + this->getName();
TQStringUtils::ensureLeadingText(name,"--");
this->fExportName = name;
}
}
this->autoSetExportNames();
}
void TQFolder::autoSetExportNames(){
TQFolderIterator itr(this->GetListOfFolders());
while(itr.hasNext()){
TQFolder* f = itr.readNext();
if(!f) continue;
f->autoSetExportName();
}
}
void TQFolder::setExportName(const TString& name){
this->fExportName = name;
this->autoSetExportNames();
}
TObject * TQFolder::importObjectFromDirectory(TDirectory * dir, TString importPath, bool recurse, TClass* expectedClass) {
if(expectedClass && importPath.IsNull()){
importPath = "*";
}
if(importPath.IsNull()){
ERRORclass("cannot import object without name or path!");
return NULL;
}
TString path;
TQStringUtils::readUpTo(importPath, path, ">");
path = TQStringUtils::trim(path);
int nl = TQStringUtils::removeLeading(importPath, ">");
TString destination = TQStringUtils::trim(importPath);
if ((destination.IsNull() && nl != 0) || (!destination.IsNull() && nl != 2)) {
ERRORclass("invalid destination string, please use exactly two pipes '>>' to signify destination!");
return NULL;
}
DEBUGclass("attempting to import object from '%s' to '%s' at '%s'",path.Data(),destination.Data(),this->getPath().Data());
TString objname(TQFolder::getPathHead(path));
TQKeyIterator itr(dir->GetListOfKeys());
TObject * object = NULL;
while(itr.hasNext()){
TKey* key = itr.readNext();
TString keyname(key->GetName());
if( TQStringUtils::matches(keyname, objname ) && !(objname[0] == '*' && keyname[0] == '-') && (!expectedClass || TQStringUtils::equal(expectedClass->GetName(),key->GetClassName()))){
object = dir->Get(keyname);
DEBUGclass("matched '%s' to '%s', obtained object '%s'",key->GetName(),objname.Data(),object->GetName());
break;
}
}
if (!object) {
DEBUGclass("failed to find object matching '%s' in '%s'",objname.Data(),dir->GetName());
return NULL;
}
DEBUGclass("success!");
TQFolder * folder = dynamic_cast<TQFolder*>(object);
if (folder){
folder->detachFromBase();
folder->fMyDir = dir;
folder->autoSetExportName();
if(recurse){
DEBUGclass("resolving import links during import");
folder->resolveImportLinks(true);
}
folder->isFullyResolved = recurse;
if(!path.IsNull()){
DEBUGclass("attempting to retrieve subfolder from '%s' in '%s'",path.Data(),folder->GetName());
TQFolder* f = folder->getFolder(path);
if(!f) return NULL;
f->detachFromBase();
delete folder;
folder = f;
object = f;
}
}
if (object->InheritsFrom(TDirectory::Class())) {
WARNclass("cannot attach objects of class '%s' to folder!",object->ClassName());
return NULL;
}
if (object->InheritsFrom(TH1::Class())) {
((TH1*)object)->SetDirectory(NULL);
}
if (!this->addObject(object, destination)) {
WARNclass("failed to attach object '%s' to destination '%s'!",object->GetName(), destination.Data());
delete object;
return NULL;
}
return object;
}
bool TQFolder::writeFolder(TDirectory * dir, TString name, int depth, bool keepInMemory){
if (name.IsNull()) {
name = GetName();
}
return writeFolderHook(dir, name, depth, keepInMemory);
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
bool TQFolder::writeFolderMaxSize(TDirectory * dir, TString name, int maxSizeInMB, bool keepInMemory){
return writeFolderHook(dir, name, -1, keepInMemory);
}
bool TQFolder::writeFolder(TDirectory * dir, int depth, bool keepInMemory){
TString name = this->GetName();
return writeFolderHook(dir, name, depth, keepInMemory);
}
bool TQFolder::writeFolderMaxSize(TDirectory * dir, int maxSizeInMB, bool keepInMemory){
return writeFolderHook(dir, this->GetName(), -1, keepInMemory);
}
#pragma GCC diagnostic pop
TString TQFolder::makeExportName(TString exportName){
exportName.ReplaceAll("/", "-");
exportName.Prepend("--");
return exportName;
}
const TString& TQFolder::getExportName(){
return this->fExportName;
}
bool TQFolder::split(TDirectory * dir, int depth){
DEBUGclass("resolving import links during split");
this->resolveImportLinks();
this->autoSetExportName();
TQFolderIterator itr(this->GetListOfFolders());
if(depth > 0){
DEBUGclass("@%s: depth > 0, splitting subfolders",this->getPath().Data());
bool failed = false;
while (itr.hasNext()) {
TQFolder* subfolder = itr.readNext();
if(!subfolder) continue;
if(!subfolder->split(dir,depth-1)){
failed = true;
break;
}
}
if(failed) this->resolveImportLinks(true);
return !failed;
} else {
DEBUGclass("@%s: depth <= 0, splitting here",this->getPath().Data());
DEBUGclass("setting directory to %x",dir);
if(dir)
this->setDirectoryInternal(dir);
bool failed = false;
if (!this->fMyDir) {
ERRORclass("cannot write to NULL directory");
return false;
}
DEBUGclass("looping over subfolders...");
while (itr.hasNext()) {
TQFolder* subFolder = itr.readNext();
if(!subFolder) continue;
DEBUGclass("detaching '%s'",subFolder->getPath().Data());
subFolder->autoSetExportName();
const TString exportName(subFolder->getExportName());
subFolder->detachFromBase();
DEBUGclass("writing '%s' (basefolder is now %p)",subFolder->GetName(),(void*)subFolder->getBase());
this->fMyDir->WriteTObject(subFolder, exportName, "Overwrite");
DEBUGclass("adding link for '%s' at '%s'",subFolder->GetName(),exportName.Data());
TQImportLink * importLink = new TQImportLink(subFolder->GetName(), TString(":") + exportName);
this->addObject(importLink);
if(failed) break;
}
TQFolder* f = this;
while(f) {
f->isFullyResolved=false;
f = f->getBase();
}
return !failed;
}
}
bool TQFolder::writeFolderHook(TDirectory * dir, const TString& exportName, int depth, bool keepInMemory){
return this->writeFolderInternal(dir,exportName,depth,keepInMemory);
}
bool TQFolder::writeFolderInternal(TDirectory * dir, const TString& exportName, int depth, bool keepInMemory){
DEBUGclass("entering function");
DEBUGclass("resolving import links to write");
this->resolveImportLinks(true);
this->setDirectoryInternal(dir);
DEBUGclass("considering exportName '%s'",exportName.Data()) ;
if(exportName.IsNull())
this->fExportName = TQFolder::makeExportName(this->getPath());
else
this->fExportName = exportName;
if(this->fExportName.IsNull())
this->autoSetExportName();
DEBUGclass("exportName is now '%s'",this->fExportName.Data()) ;
bool failed = false;
if(depth >= 0){
DEBUGclass("splitting at level %d (target is %p)",depth,(void*)(dir)) ;
if(!this->split(dir,depth)){
ERRORclass("unable to split folder!");
failed = true;
} else {
DEBUGclass("split successful") ;
}
}
DEBUGclass("writing object to directory '%s'@%p",this->fMyDir->GetName(),(void*)(this->fMyDir)) ;
this->fMyDir->WriteTObject(this, this->fExportName, "Overwrite");
if(keepInMemory){
DEBUGclass("resolving split") ;
this->resolveImportLinks(true);
}
DEBUGclass("all done") ;
return !failed;
}
bool TQFolder::isOnDisk(){
return this->isOnDisk(this->fMyDir);
}
bool TQFolder::isOnDisk(TDirectory* dir){
if(!dir) dir=this->fMyDir;
if(!dir) return false;
TList* keys = dir->GetListOfKeys();
if(!keys) return false;
TQIterator itr(keys);
while(itr.hasNext()){
TObject* key = itr.readNext();
if( this->fExportName.CompareTo(key->GetName()) == 0){
return true;
}
}
return false;
}
bool TQFolder::collapse(){
bool retval = false;
TQIterator itr(this->GetListOfFolders());
while (itr.hasNext()) {
TQFolder* f = dynamic_cast<TQFolder*>(itr.readNext());
if(!f) continue;
if(!f->isOnDisk()){
if(f->collapse()) retval = true;
continue;
} else {
TQImportLink * importLink = new TQImportLink(f->GetName(), TString(":") + f->getExportName());
f->deleteAll();
this->deleteObject(f->getName());
this->addObject(importLink);
retval = true;
}
}
return retval;
}
bool TQFolder::writeUpdate(int depth, bool keepInMemory){
if(!this->fMyDir){
ERRORclass("cannot write update without active directory!");
return false;
}
if(!this->fMyDir->IsWritable()){
ERRORclass("cannot write update: active directory '%s' is not writeable!",this->fMyDir->GetName());
return false;
}
std::vector<TQFolder*> subfolders;
if (depth > 0) {
TQIterator itr(this->GetListOfFolders());
while (itr.hasNext()) {
TQFolder* f = dynamic_cast<TQFolder*>(itr.readNext());
if(!f) continue;
subfolders.push_back(f);
}
}
bool failed = false;
for(size_t i=0; i<subfolders.size(); i++ ){
TQFolder * subFolder = subfolders[i];
if (!subFolder->writeUpdate(depth - 1, keepInMemory)){
failed = true;
}
subFolder->detachFromBase();
TQImportLink * importLink = new TQImportLink(subFolder->GetName(), TString(":") + subFolder->getExportName());
this->addObject(importLink);
}
TQFolder* oldBase = this->getBase();
this->fBase = NULL;
this->fMyDir->WriteTObject(this, this->fExportName, "Overwrite");
this->fBase = oldBase;
for(size_t i=0; i<subfolders.size(); i++){
TQFolder * subFolder = subfolders[i];
if(keepInMemory){
this->deleteObject(subFolder->GetName());
this->addObject(subFolder);
} else {
delete subFolder;
}
}
this->isFullyResolved = keepInMemory;
return !failed;
}
bool TQFolder::writeDirectory(TDirectory * baseDir) {
DEBUGclass("resolving import links to write");
this->resolveImportLinks(true);
if (!baseDir) {
return false;
}
TObject * dirObj = baseDir->Get(GetName());
if (dirObj) {
return false;
}
TDirectory * dir = baseDir->mkdir(GetName(), GetTitle());
if (!dir) {
return false;
}
bool success = true;
TQIterator itr(GetListOfFolders());
while (itr.hasNext()) {
TObject * obj = itr.readNext();
if(obj->GetName()[0]=='.') continue;
if (obj->InheritsFrom(TQFolder::Class())) {
if (!((TQFolder*)obj)->writeDirectory(dir)) {
success = false;
}
} else {
dir->WriteTObject(obj);
}
}
return success;
}
bool TQFolder::importFromTextFiles(const TString& filePattern) {
TString errMsg;
bool success = importFromTextFiles(filePattern, errMsg);
if (!success) {
ERRORclass(errMsg);
}
return success;
}
bool TQFolder::importFromTextFiles(const TString& filePattern, TString &errorMessage) {
TList * files = TQUtils::getListOfFilesMatching(filePattern);
TQIterator itr(files, true);
while (itr.hasNext()) {
TString filename = itr.readNext()->GetName();
TString folderName = TQFolder::makeValidPath(filename, "_", false, false);
TQFolder * folder = this->getFolder(folderName + "+");
if (!folder) {
errorMessage = TString::Format("Failed to create subfolder '%s'",
folderName.Data());
return false;
}
if (!folder->importFromTextFile(filename, errorMessage)) {
return false;
}
}
if (itr.getCounter() == 0) {
errorMessage = TString::Format("Cound not find any file matching '%s'",
filePattern.Data());
return false;
}
return true;
}
bool TQFolder::importFromTextFile(const TString& filename) {
TString errMsg;
bool success = importFromTextFile(filename, errMsg);
if (!success) {
ERRORclass(errMsg);
}
return success;
}
bool TQFolder::importFromTextFile(const TString& filename, TString &errorMessage) {
int nNewlines = 1;
TString errFile;
TString errMsg;
bool success = importFromTextFilePrivate(filename, nNewlines, errFile, errMsg);
if (!success) {
if (nNewlines < 0) {
errorMessage = TString::Format("Error related to file '%s': %s",
errFile.Data(), errMsg.Data());
} else {
errorMessage = TString::Format("Error in line %d of file '%s': %s",
nNewlines, errFile.Data(), errMsg.Data());
}
}
return success;
}
bool TQFolder::importFromTextFilePrivate(const TString& filename_, int &nNewlines, TString &errFile, TString &errMsg) {
if(filename_.IsNull()) return false;
TString filename = TQLibrary::getAbsolutePath(filename_);
errFile = filename;
DEBUGclass("reading text file %s",filename.Data());
std::ifstream file(filename.Data());
if (file.fail()) {
nNewlines = -1;
errMsg = "Failed to open file";
return false;
}
TString text = TQStringUtils::readTextFromFile(&file,"#","#*","*#");
DEBUGclass("done",filename.Data());
file.close();
text.ReplaceAll("\r","");
return importFromTextPrivate(text, nNewlines, errFile, errMsg);
}
TList * TQFolder::exportToText(bool includeUntextables, int indent) {
DEBUGclass("resolving import links to export");
this->resolveImportLinks(true);
TList * text = 0;
TString indentStr = TQStringUtils::repeatTabs(indent);
if (this->getNTags() > 0) {
text = new TList();
text->SetOwner(true);
text->AddLast(new TObjString(TString::Format("%s<%s>",
indentStr.Data(), this->exportTagsAsString().Data()).Data()));
}
TQIterator itr(GetListOfFolders());
while (itr.hasNext()) {
TObject * obj = itr.readNext();
if (!text) {
text = new TList();
text->SetOwner(true);
}
if (obj->InheritsFrom(TQFolder::Class())) {
TList * subText = ((TQFolder*)obj)->exportToText(includeUntextables, indent + 1);
if (subText) {
text->AddLast(new TObjString(TString::Format("%s+%s {",
indentStr.Data(), obj->GetName()).Data()));
text->AddAll(subText);
text->AddLast(new TObjString(TString::Format("%s}",
indentStr.Data()).Data()));
subText->SetOwner(false);
delete subText;
} else {
text->AddLast(new TObjString(TString::Format("%s+%s;",
indentStr.Data(), obj->GetName()).Data()));
}
} else if (obj->InheritsFrom(TObjString::Class())){
text->AddLast(new TObjString(TString::Format("%s\"%s\";",indentStr.Data(),obj->GetName())));
} else if(includeUntextables) {
TString details = TQStringUtils::getDetails(obj);
if (!details.IsNull()) {
details.Prepend(" {");
details.Append("}");
}
if(obj->InheritsFrom(TH1::Class())){
text->AddLast(new TObjString(indentStr+TQHistogramUtils::convertToText((TH1*)obj,2)+";"));
} else {
text->AddLast(new TObjString(TString::Format("%s#+%s::%s%s;", indentStr.Data(),
obj->IsA()->GetName(), obj->GetName(), details.Data()).Data()));
}
}
}
return text;
}
bool TQFolder::writeContentsToHTML(std::ostream& out, int expandDepth, bool includeUntextables) {
out << "<div class=\"listing\" style=\"display:" << (expandDepth > 0 ? "block" : "none") << "\">" << std::endl;
TQIterator itrTags(this->getListOfKeys(),true);
while(itrTags.hasNext()){
out << "<div class=\"tag\">";
TObject* obj = itrTags.readNext();
TString name(obj->GetName());
TString value(this->getTagStringDefault(name,""));
out << "<span class=\"tagKey\">" << TQStringUtils::convertPlain2HTML(name) << "</span>";
out << "<span class=\"tagValue\">" << TQStringUtils::convertPlain2HTML(value) << "</span>";
out << "</div>" << std::endl;
}
TQIterator itr(GetListOfFolders());
while (itr.hasNext()) {
TObject * obj = itr.readNext();
TQFolder* f = dynamic_cast<TQFolder*>(obj);
if (f){
out << "<div>" << std::endl;
out << "<div class=\"folder\" onclick=\"toggleDiv(this.nextElementSibling)\"><span class=\"foldername\">" << f->GetName() << "</span></div>" << std::endl;
f->writeContentsToHTML(out,expandDepth-1,includeUntextables);
out << "</div>" << std::endl;
} else if (includeUntextables) {
TString details;
if (obj->InheritsFrom(TH1::Class())) {
details = TQHistogramUtils::getDetailsAsString((TH1*)obj, 2);
} else if (obj->InheritsFrom(TQCounter::Class())) {
details = ((TQCounter*)obj)->getAsString();
}
TString className(obj->IsA()->GetName());
out << "<div class=\"object\"><span class=\"objecttype\"><a style=\"color:inherit; text-decoration:none\" target=\"_blank\" href=\"" << TQFolder::concatPaths(TQLibrary::getWebsite(),className) << ".html\">" << className << "</a></span><span class=\"objectname\">" << obj->GetName() << "</span>";
if(!details.IsNull()) out << "<span class=objectdetails\">" << TQStringUtils::convertPlain2HTML(details) << "</span>";
out << "</div>";
}
}
out << "</div>" << std::endl;
return true;
}
bool TQFolder::exportToHTMLFile(const TString& filename, int expandDepth, bool includeUntextables) {
if(expandDepth < 1) expandDepth = std::numeric_limits<int>::infinity();
std::ofstream out(filename);
if(!out.is_open()) return false;
out << "<html>" << std::endl << "<head>" << std::endl;
out << "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">" << std::endl;
out << "<title>" << this->GetName() << "</title>" << std::endl;
out << "<style id=\"style\" type=\"text/css\">" << std::endl;
out << ".folder { width:100%; background-image:url(" << '"' << TQStringUtils::readSVGtoDataURI(TQFolder::concatPaths(TQLibrary::getTQPATH(),"share/nuoveXT-icons/folder.svg")) << '"' << "); background-size:contain; background-repeat: no-repeat; cursor: hand; }" << std::endl;
out << ".foldername { margin-left:1.5em; font-weight:bold; }" << std::endl;
out << ".listing { margin-left:3em; }" << std::endl;
out << ".tag { display:inline-block; font-size:12pt; font-style:italic; width:100%; }" << std::endl;
out << ".tagkey { display:inline-block; min-width: 200px; color:purple; margin-right:1em; }" << std::endl;
out << ".tagvalue { display: inline-block; width: 80%; vertical-align: top; };" << std::endl;
out << ".object { display:inline-block; }" << std::endl;
out << ".objecttype { display:inline-block; width: 100px; color: darkblue; font-weight:bold; text-decoration:none; }" << std::endl;
out << ".objectname { display:inline-block; width: 200px; }" << std::endl;
out << ".objectdetails { };" << std::endl;
out << "a { font-weight:bold; text-decoration:none; }" << std::endl;
out << "</style>" << std::endl;
out << "<script type=\"text/javascript\">" << std::endl;
out << "function toggleDiv(obj){ if(!obj) return; if(obj.style.display==\"none\") obj.style.display=\"block\"; else obj.style.display=\"none\"; }" << std::endl;
out << "</script>" << std::endl;
out << "</head>" << std::endl;
out << "<body>" << std::endl;
this->writeContentsToHTML(out,expandDepth,includeUntextables);
out << "<hr>" << std::endl;
out << "<div style=\"font-size:12px\">This page was automatically generated by the <a href=\"" << TQLibrary::getWebsite() << "\">HWWAnalysisCode</a> software library. The icons displayed are part of the <a href=\"http://nuovext.pwsp.net/\">nuoveXT</a> icon scheme, licensed under <a href=\"http://www.gnu.org/licenses/lgpl.html\">LGPL</a> (2013).</div>" << std::endl;
out << "</body>" << std::endl;
out << "</html>" << std::endl;
return true;
}
bool TQFolder::exportToTextFile(const TString& filename, bool includeUntextables) {
TList * text = this->exportToText(includeUntextables);
if (text) {
text->AddFirst(new TObjString("# -*- mode: tqfolder -*-"));
bool success = TQStringUtils::writeTextToFile(text, filename);
delete text;
return success;
} else {
return false;
}
}
bool TQFolder::importFromText(const TString& input) {
TString errMsg;
bool success = importFromText(input, errMsg);
if (!success) {
ERRORclass(errMsg);
}
return success;
}
bool TQFolder::importFromText(const TString& input, TString &errorMessage) {
int nNewlines = 1;
TString errFile;
TString errMsg;
bool success = importFromTextPrivate(input, nNewlines, errFile, errMsg);
if (!success) {
if (errFile.IsNull()) {
errorMessage = TString::Format("Error in line %d: %s", nNewlines, errMsg.Data());
} else {
errorMessage = TString::Format("Error in line %d of file '%s': %s",
nNewlines, errFile.Data(), errMsg.Data());
}
}
return success;
}
bool TQFolder::executeCopyCommand(TString object, TString& errMsg, bool moveOnly, const TString& destPrefix){
DEBUGclass("executeCopyCommand called on '%s' with destination prefix '%s'",this->getPath().Data(),destPrefix.Data());
TString source;
object.ReplaceAll("$(BASEFOLDERNAME)",this->GetName());
TQStringUtils::removeLeadingBlanks(object);
if (!TQStringUtils::readToken(object, source, TQStringUtils::getDefaultIDCharacters() + "*?/")) {
errMsg = "Expecting object source for command 'copy'";
return false;
}
TQStringUtils::removeLeadingBlanks(object);
TString dest;
if (!object.IsNull()) {
if (TQStringUtils::removeLeading(object, ">") != 2) {
errMsg = "Expecting destination operator '>>' after source for command 'copy', but found '" + object + "'";
return false;
}
TQStringUtils::removeLeadingBlanks(object);
if (object.IsNull()) {
errMsg = "Expecting destination after operator '>>' for command 'copy', but received no input";
return false;
}
dest = TQFolder::concatPaths(destPrefix,this->replaceInText(object,"~"));
}
TString destObj = TQFolder::getPathTail(dest);
TQFolder* destFolder = this->getFolder(dest);
DEBUGclass("evaluating $copy/$move operator in '%s', source='%s', dest='%s', destObj='%s'",this->getPath().Data(),source.Data(),dest.Data(),destObj.Data());
std::vector<std::pair<TQFolder*,TObject*>> sources;
TQIterator objitr(this->getListOfObjectPaths(source),true);
while(objitr.hasNext()){
TObject * objSourcePath = objitr.readNext();
if (!objSourcePath) continue;
TString srcPath(objSourcePath->GetName());
DEBUGclass("source path '%s' relative to folder '%s'",srcPath.Data(),this->getPath().Data());
TString srcName(TQFolder::getPathTail(srcPath));
TObject* objSource = this->getObject(srcName,srcPath);
if(!objSource) continue;
TQFolder* fSource = this->getFolder(TQFolder::getPathTail(srcPath));
sources.push_back(std::make_pair(fSource,objSource));
}
for(const auto& s:sources){
TQFolder* fSource = s.first;
TObject* objSource = s.second;
if(!moveOnly){
if (objSource->InheritsFrom(TQFolder::Class())) {
objSource = ((TQFolder*)objSource)->copy();
} else {
objSource = objSource->Clone();
}
if (!destFolder->addObject(objSource, destObj)) {
delete objSource;
errMsg = TString::Format("Failed to copy object '%s'", source.Data());
return false;
}
} else {
if (!objSource->InheritsFrom(TQFolder::Class())) {
fSource->Remove(objSource);
}
if (!destFolder->addObject(objSource, destObj)) {
errMsg = TString::Format("Failed to copy object '%s'", source.Data());
return false;
}
}
}
if(sources.size() < 1){
errMsg = TString::Format("Couldn't find object matching '%s' in '%s'", source.Data(), this->getPath().Data());
return false;
}
return true;
}
bool TQFolder::importFromTextPrivate(TString input, int &nNewlines, TString &errFile, TString &errMsg) {
DEBUGclass("entering function");
while (!input.IsNull()) {
DEBUGclass("next up: '%s'",input.Data());
if(errMsg.Length() > 1e7){
throw std::runtime_error("BREAK: too many error messages, debug your input or use 'skipsilent=true' to suppress!");
}
TQStringUtils::readBlanksAndNewlines(input, nNewlines);
TString token;
if (input.BeginsWith("#")) {
TQStringUtils::readUpTo(input, token, "\n");
} else if (input.BeginsWith("@")) {
int np = TQStringUtils::removeLeading(input, "@");
if (np > 1) {
errMsg = TString::Format("Wrong operator '%s'", TQStringUtils::repeat("@", np).Data());
return false;
}
int nNewlinesTmp = nNewlines;
TQStringUtils::readBlanksAndNewlines(input, nNewlines);
if (TQStringUtils::readToken(input, token,
TQStringUtils::getDefaultIDCharacters() + ",/:*?$()") == 0) {
nNewlines = nNewlinesTmp;
errMsg = "Expect object definition after '@'";
return false;
}
TString path = this->replaceInText(token,"~",false);
TCollection* c = this->getListOfFolders(path);
nNewlinesTmp = nNewlines;
TQStringUtils::readBlanksAndNewlines(input, nNewlinesTmp);
if (input.BeginsWith("{")) {
token.Clear();
if (TQStringUtils::readBlock(input, token, "{}[]()", "''\"\"#\n", false, 2) == 0) {
errMsg = TString::Format("Block opened here '%s' not closed properly",TQStringUtils::maxLength(TQStringUtils::compactify(input), 40).Data());
return false;
}
}
TString errMsgHold;
if(c && c->GetEntries() > 0){
TQFolderIterator itr(c,true);
while(itr.hasNext()){
TQFolder* f = itr.readNext();
if(!f) continue;
f->importFromTextPrivate(token, nNewlines, errFile, errMsg);
if (!errMsg.IsNull()) errMsgHold += errMsg + "; \n" ;
}
nNewlines = nNewlinesTmp;
} else {
errMsg = TString::Format("[WARNING] Operation '@%s' produced no matches!",path.Data());
}
errMsg = errMsgHold;
if (!errMsg.IsNull()) {
return false;
}
} else if (input.BeginsWith("+")) {
int np = TQStringUtils::removeLeading(input, "+");
if (np > 1) {
errMsg = TString::Format("Wrong operator '%s'", TQStringUtils::repeat("+", np).Data());
return false;
}
int nNewlinesTmp = nNewlines;
TQStringUtils::readBlanksAndNewlines(input, nNewlines);
if (TQStringUtils::readToken(input, token,
TQStringUtils::getDefaultIDCharacters() + "/:*?$()") == 0) {
nNewlines = nNewlinesTmp;
errMsg = "Expect object definition after '+'";
return false;
}
TString newname = this->replaceInText(token,"~",false);
newname.ReplaceAll("$(BASEFOLDERNAME)",this->GetName());
TQFolder * newObj = this->getFolder(newname + "+");
if (!newObj) {
errMsg = TString::Format("Failed to create object '%s'", token.Data());
return false;
}
nNewlinesTmp = nNewlines;
TQStringUtils::readBlanksAndNewlines(input, nNewlines);
if (input.BeginsWith("{")) {
token.Clear();
if (TQStringUtils::readBlock(input, token, "{}[]()", "''\"\"#\n", false, 2) == 0) {
errMsg = TString::Format("Block opened here '%s' not closed properly",
TQStringUtils::maxLength(TQStringUtils::compactify(input), 40).Data());
return false;
}
if (!newObj->importFromTextPrivate(token, nNewlines, errFile, errMsg)) {
return false;
}
} else if (!TQStringUtils::removeLeading(input, ";", 1)) {
nNewlines = nNewlinesTmp;
errMsg = TString::Format("Missing terminating ';' after object definition '%s'", token.Data());
return false;
}
} else if (input.BeginsWith("<")) {
TString tags;
if (TQStringUtils::readBlock(input, tags, "<>[](){}", "''\"\"#\n", false, 2) == 0) {
errMsg = TString::Format("Tag definition block opened here '%s' not closed properly",
TQStringUtils::maxLength(input, 10).ReplaceAll("\n", " ").Data());
return false;
}
TString dest;
TQStringUtils::readBlanksAndNewlines(input, nNewlines);
if (TQStringUtils::removeLeading(input, "@", 1) > 0) {
int nNewlinesTmp = nNewlines;
TQStringUtils::readBlanksAndNewlines(input, nNewlines);
if (TQStringUtils::readToken(input, dest,
TQStringUtils::getDefaultIDCharacters() + "/*?, ") == 0) {
nNewlines = nNewlinesTmp;
errMsg = "Expecting tag destination path after '@'";
return false;
}
nNewlinesTmp = nNewlines;
TQStringUtils::readBlanksAndNewlines(input, nNewlines);
if (!TQStringUtils::removeLeading(input, ";", 1)) {
nNewlines = nNewlinesTmp;
errMsg = "Missing terminating ';' after tag destination path";
return false;
}
}
tags.ReplaceAll("$(BASEFOLDERNAME)",this->GetName());
TQTaggable tagReader(tags);
tagReader.exportTags(this, dest);
} else if (input.BeginsWith("$")) {
TQStringUtils::removeLeading(input, "$", 1);
TString cmd;
if (!TQStringUtils::readToken(input, cmd, TQStringUtils::getLetters())) {
errMsg = "Missing command after '$'";
return false;
}
TString strParameter;
int nNewlinesTmp = nNewlines;
TQStringUtils::readBlanksAndNewlines(input, nNewlines);
if (input.BeginsWith("(")) {
if (TQStringUtils::readBlock(input, strParameter, "()", "''\"\"#\n", false, 2) == 0) {
errMsg = TString::Format("Parameter block opened here '%s' not closed properly",
TQStringUtils::maxLength(input, 10).ReplaceAll("\n", " ").Data());
return false;
}
} else {
nNewlines = nNewlinesTmp;
errMsg = TString::Format("Missing '(...)' after command '%s'", cmd.Data());
return false;
}
DEBUGclass("parsing command '%s' with arguments %s, input continues as '%s'",cmd.Data(),strParameter.Data(),input.Data());
bool isCmdInclude = (cmd.CompareTo("include", TString::kIgnoreCase) == 0);
bool isCmdImport = (cmd.CompareTo("import", TString::kIgnoreCase) == 0);
bool isCmdCopy = (cmd.CompareTo("copy", TString::kIgnoreCase) == 0);
bool isCmdMove = (cmd.CompareTo("move", TString::kIgnoreCase) == 0);
bool isCmdDelete = (cmd.CompareTo("delete", TString::kIgnoreCase) == 0);
bool isCmdEscape = (cmd.CompareTo("escape", TString::kIgnoreCase) == 0);
bool isCmdIgnore = (cmd.CompareTo("ignore", TString::kIgnoreCase) == 0);
bool isCmdModify = (cmd.CompareTo("modify", TString::kIgnoreCase) == 0);
bool isCmdCreate = (cmd.CompareTo("create", TString::kIgnoreCase) == 0);
bool isCmdFor = (cmd.CompareTo("for", TString::kIgnoreCase) == 0);
bool isCmdForEach = (cmd.CompareTo("foreach", TString::kIgnoreCase) == 0);
if (isCmdForEach) {
isCmdFor = false;
}
bool isCmdReplace = (cmd.CompareTo("replace", TString::kIgnoreCase) == 0);
bool isCmdPrint = (cmd.CompareTo("print", TString::kIgnoreCase) == 0);
bool isCmdPrintLine (cmd.CompareTo("printline", TString::kIgnoreCase) == 0);
bool isCmdWrite = (cmd.CompareTo("write", TString::kIgnoreCase) == 0);
bool acceptNestedBlock = isCmdCopy;
bool expectNestedBlock = isCmdIgnore || isCmdFor || isCmdForEach;
nNewlinesTmp = nNewlines;
TQStringUtils::readBlanksAndNewlines(input, nNewlines);
TString nestedBlock;
if (input.BeginsWith("{") && (acceptNestedBlock || expectNestedBlock)) {
if (TQStringUtils::readBlock(input, nestedBlock, "{}[]()", "''\"\"#\n", false, 2) == 0) {
errMsg = TString::Format("Block opened here '%s' not closed properly",
TQStringUtils::maxLength(input, 10).ReplaceAll("\n", " ").Data());
return false;
}
} else if (!input.BeginsWith("{") && expectNestedBlock) {
nNewlines = nNewlinesTmp;
errMsg = TString::Format("Expecting nested block after command '%s'", cmd.Data());
return false;
} else if (!TQStringUtils::removeLeading(input, ";", 1)) {
nNewlines = nNewlinesTmp;
errMsg = TString::Format("Missing terminating ';' after command '%s'", cmd.Data());
return false;
}
strParameter.ReplaceAll("$(BASEFOLDERNAME)",this->GetName());
if (isCmdInclude) {
TQTaggable param;
param.importTagWithPrefix(strParameter, "", false, "filename");
TString includeFilenameOrig;
int nNewlines2 = 1;
TString errFile2;
TString errMsg2;
if (param.getNTags() != 1 || !param.getTagString("filename", includeFilenameOrig)) {
errMsg = "Wrong number of arguments or invalid argument to command 'include', filename needed.";
return false;
}
includeFilenameOrig = this->replaceInTextRecursive(includeFilenameOrig);
TString includeFilename = TQPathManager::getPathManager()->findConfigPath(includeFilenameOrig);
if(includeFilename.IsNull()){
errMsg = TString::Format("Failed to find file '%s'", includeFilenameOrig.Data());
return false;
}
if (!this->importFromTextFilePrivate(includeFilename, nNewlines2, errFile2, errMsg2)) {
if (nNewlines2 < 0) {
errMsg = TString::Format("Failed to include file '%s': %s", includeFilename.Data(), errMsg2.Data());
} else {
nNewlines = nNewlines2;
errFile = errFile2;
errMsg = errMsg2;
}
return false;
}
} else if (isCmdImport) {
TQStringUtils::unquoteInPlace(strParameter,"\"'");
if (!this->importObject(strParameter)){
errMsg = TString::Format("Failed to import '%s'", strParameter.Data());
return false;
}
} else if (isCmdDelete) {
TQTaggable param;
param.importTagsWithPrefix(strParameter, "", false, false, "object");
TString object;
bool skipSilent = param.getTagBoolDefault("skipsilent",false);
TClass* filter = 0;
if (TQStringUtils::compare(param.getTagStringDefault("filter",""),"s") == 0 || TQStringUtils::compare(param.getTagStringDefault("filter",""),"sample") == 0) {
filter = TQSample::Class();
} else if (TQStringUtils::compare(param.getTagStringDefault("filter",""),"sf") == 0 || TQStringUtils::compare(param.getTagStringDefault("filter",""),"samplefolder") == 0) {
filter = TQSampleFolder::Class();
} else if (TQStringUtils::compare(param.getTagStringDefault("filter",""), "") != 0) {
errMsg = TString::Format("Given argument '%s' for tag 'filter' in command 'delete' unkown.", param.getTagStringDefault("filter","").Data());
return false;
}
if (param.getNTags() < 1){
errMsg = "Wrong number of arguments to command 'delete'";
return false;
} else if(param.getTagString("object", object)){
object = TQStringUtils::trim(object);
if (!this->deleteObject(object, false, filter)) {
if (!skipSilent) {
errMsg = TString::Format("[mostly harmless] in %s: Failed to delete object '%s'", this->getPath().Data(),object.Data());
}
}
} else if(param.getTagString("tags", object)){
TString path;
TQTaggable* obj=NULL;
if(param.getTagString("path",path)){
obj = dynamic_cast<TQTaggable*>(this->getObject(path));
} else {
obj = this;
}
obj->removeTags(object);
}
} else if (isCmdCopy || isCmdMove) {
TQTaggable param;
param.importTagWithPrefix(strParameter, "", false, "object");
TString object;
if (param.getNTags() != 1 || !param.getTagString("object", object)) {
errMsg = "Wrong number of arguments to command 'copy'";
return false;
} else {
if(!this->executeCopyCommand(object,errMsg,isCmdMove)){
WARNclass(TString::Format("copy/move command %s failed, skipping",object.Data()));
}
}
} else if (isCmdIgnore) {
} else if (isCmdForEach || (isCmdFor && strParameter.Contains(":"))) {
TString key;
std::vector<TString> loopElements;
TString tmpLoopElement;
if(isCmdForEach){
if(TQStringUtils::readUpTo(strParameter,key, ",") <1 ) {
errMsg = "foreach-command must have syntax '$foreach(key,item1,item2,...){ ... }'";
return false;
}
TQStringUtils::removeLeadingBlanks(key);
TQStringUtils::removeTrailingBlanks(key);
DEBUGclass("foreach key = '%s'", key.Data());
} else {
TString strItems;
if(TQStringUtils::readUpTo(strParameter,key,":")<1 || TQStringUtils::removeLeading(strParameter,":") !=1 || TQStringUtils::readUpTo(strParameter,strItems,")")<1){
errMsg = "for-command must have syntax '$for(key:elem1,elem2,...){ ... }'";
return false;
}
loopElements = TQStringUtils::split(strItems,",");
}
while (TQStringUtils::removeLeading(strParameter, ",") == 1 && TQStringUtils::readUpTo(strParameter, tmpLoopElement, ",") >= 1) {
TQStringUtils::removeLeadingBlanks(tmpLoopElement);
TQStringUtils::removeTrailingBlanks(tmpLoopElement);
DEBUGclass("foreach found value in definition: '%s'", tmpLoopElement.Data());
loopElements.emplace_back(tmpLoopElement);
tmpLoopElement = "";
}
if (loopElements.empty()) {
errMsg = "you need to specify at least one item. foreach-command must have syntax '$foreach(key,item1,item2,...){ ... }'";
return false;
}
int tmpNewlines(nNewlines);
TQTaggable helper;
for (TString it : loopElements) {
helper.setTagString(key, TQStringUtils::trim(it," \n\t"));
TString tmpBlock = helper.replaceInText(nestedBlock);
tmpNewlines = nNewlines;
if (!this->importFromTextPrivate(tmpBlock, tmpNewlines, errFile, errMsg)){
return false;
}
}
nNewlines = tmpNewlines;
} else if(isCmdFor){
TString key,strItBegin,strItEnd;
if(TQStringUtils::readUpTo(strParameter,key,",")<1 || TQStringUtils::removeLeading(strParameter,",") !=1 ||
TQStringUtils::readUpTo(strParameter,strItBegin,",")<1 || TQStringUtils::removeLeading(strParameter,",") !=1 ||
TQStringUtils::readUpTo(strParameter,strItEnd,",")<1){
errMsg = "for-command must have syntax '$for(key,begin,end){ ... }'";
return false;
}
TQTaggable param(strParameter);
TString sBegin = this->replaceInText(strItBegin);
TString sEnd = this->replaceInText(strItEnd);
if(!TQStringUtils::isInteger(sBegin)){
errMsg = TString::Format("for-command must have integer as beginning, not '%s'",sBegin.Data());
return false;
}
if(!TQStringUtils::isInteger(sEnd)){
errMsg = TString::Format("for-command must have integer as end, not '%s'",sEnd.Data());
return false;
}
int itBegin = atoi(sBegin.Data());
int itEnd = atoi(sEnd.Data());
int step = param.getTagIntegerDefault("step",itEnd >= itBegin ? 1 : -1);
int pad = param.getTagIntegerDefault("pad",1+log10(std::max(itBegin,itEnd-1)));
int tmpNewlines(nNewlines);
TQTaggable helper;
for(int it=itBegin; it<itEnd; it+=step){
helper.setTagString(key,TQStringUtils::padNumber(it,pad));
TString tmpBlock = helper.replaceInText(nestedBlock);
tmpNewlines = nNewlines;
if (!this->importFromTextPrivate(tmpBlock, tmpNewlines, errFile, errMsg)){
return false;
}
}
nNewlines = tmpNewlines;
} else if (isCmdEscape) {
TQStringUtils::removeLeadingBlanks(strParameter);
bool inverted = (TQStringUtils::removeLeading(strParameter,"!") > 0);
if (TQStringUtils::equal(strParameter,"") || TQStringUtils::matches(this->getName(), strParameter)) {
if (!inverted) return true;
} else {
if (inverted) return true;
}
} else if (isCmdModify) {
TQTaggable param;
param.importTags(strParameter);
#ifdef _DEBUG_
param.printTags();
#endif
if ( !(param.hasTagString("tag") && param.hasTagString("operator") && param.hasTag("value")) ) {
errMsg = TString("Missing options! Required values are 'tag=\"tagToModify\", operator=\"+-*/=\", value=someValue'. Optional parameters are 'path=\"path/to/folder\", filter=\"s/sf\", create=true/false, override=false/true, force=true/false (later values are default)");
}
TString path = param.getTagStringDefault("path",".");
TString tag = param.getTagStringDefault("tag","");
TClass* filter = TQFolder::Class();
if (TQStringUtils::compare(param.getTagStringDefault("filter",""),"s") == 0 || TQStringUtils::compare(param.getTagStringDefault("filter",""),"sample") == 0) {
filter = TQSample::Class();
} else if (TQStringUtils::compare(param.getTagStringDefault("filter",""),"sf") == 0 || TQStringUtils::compare(param.getTagStringDefault("filter",""),"samplefolder") == 0) {
filter = TQSampleFolder::Class();
}
TString op = param.getTagStringDefault("operator","=");
bool create = param.getTagBoolDefault("create",false);
bool skipSilent = param.getTagBoolDefault("skipsilent",false);
bool force = param.getTagBoolDefault("force",false);
bool replace = param.getTagBoolDefault("override",!create);
bool isString = param.tagIsOfTypeString("value");
bool isDouble = param.tagIsOfTypeDouble("value");
bool isInt = param.tagIsOfTypeInteger("value");
bool isBool = param.tagIsOfTypeBool("value");
if (!isString && !isDouble && !isInt && !isBool) {
errMsg = TString("Cannot modify! Unsupported tag type.");
return false;
}
bool inverted = false;
if (!isBool) {
inverted = TQStringUtils::removeLeading(op,"!",1) == 1;
}
if (inverted && TQStringUtils::equal(op,"=")) {
errMsg = TString::Format("Are you trying to set a value in inverted mode (operator '!=' for non-boolean value)? This does not makesense!");
return false;
}
bool silent = param.getTagBoolDefault("quiet",param.getTagBoolDefault("silent",false));
if (isString && !( TQStringUtils::equal(op,"=") || TQStringUtils::equal(op,"+") || TQStringUtils::equal(op,"-") ) ) {
errMsg = TString::Format("Unsupported modification operator '%s' for value of type %s",op.Data(),"string");
return false;
}
if (isDouble && !( TQStringUtils::equal(op,"=") || TQStringUtils::equal(op,"+") || TQStringUtils::equal(op,"-") || TQStringUtils::equal(op,"*") || TQStringUtils::equal(op,"/") || TQStringUtils::equal(op,"^") ) ) {
errMsg = TString::Format("Unsupported modification operator '%s' for value of type %s",op.Data(),"double");
return false;
}
if (isInt && !( TQStringUtils::equal(op,"=") || TQStringUtils::equal(op,"+") || TQStringUtils::equal(op,"-") || TQStringUtils::equal(op,"*") || TQStringUtils::equal(op,"/") || TQStringUtils::equal(op,"^") ) ) {
errMsg = TString::Format("Unsupported modification operator '%s' for value of type %s",op.Data(),"int");
return false;
}
if (isBool && !( TQStringUtils::equal(op,"=") || TQStringUtils::equal(op,"==") || TQStringUtils::equal(op,"!=") || TQStringUtils::equal(op,"&&") || TQStringUtils::equal(op,"||") ) ) {
errMsg = TString::Format("Unsupported modification operator '%s' for value of type %s",op.Data(),"bool");
return false;
}
if ( TQStringUtils::equal(op,"/") && (!inverted && ((isDouble && param.getTagDoubleDefault("value",0.) == 0.) || (isInt && param.getTagIntegerDefault("value",0) == 0) ) ) ) {
errMsg = TString("Cannot modify tags! Division by zero is not available yet. ETA: 1/0. days");
return false;
}
TList* targetList = this->getListOfFolders(path,filter);
if (!targetList) {
errMsg = TString::Format("No matching folders found for pattern '%s'",path.Data());
return false;
}
TQFolderIterator itr(targetList);
while (itr.hasNext()) {
TQFolder* folder = itr.readNext();
if (!folder) continue;
if (inverted && (TQStringUtils::equal(op,"/") && (folder->tagIsOfTypeDouble(tag) || folder->tagIsOfTypeInteger(tag)) && folder->getTagDoubleDefault(tag,0.) == 0. )) {
WARNclass(TString::Format("Cannot modify tags for folder '%s' (inverted mode)! Division by zero is not available yet. ETA: 1/0. days; skipping this folder",folder->getName().Data() ).Data());
continue;
}
if (isString) {
if (folder->hasTag(tag) && !folder->tagIsOfTypeString(tag) && !(create||force) ) {
if (!skipSilent)
WARNclass("In folder '%s', skipping modification of tag '%s' with operator '%s' and value '%s' due to type mismatch. Use force=true to modify anyways!",folder->getPath().Data(),tag.Data(),op.Data(), param.getTagStringDefault("value","").Data());
continue;
}
if (!folder->hasTag(tag) && !create ) {
if (!skipSilent)
WARNclass("In folder '%s', skipping modification of tag '%s' with operator '%s' and value '%s' due to tag not being present. Use create=true to modify anyways!",folder->getPath().Data(),tag.Data(),op.Data(), param.getTagStringDefault("value","").Data());
continue;
}
if (folder->hasTag(tag) && !folder->tagIsOfTypeString(tag)) {
if (!force) {
if (!skipSilent)
WARNclass("Tag '%s' at '%s' is already present but of different type!", tag.Data(), folder->getPath().Data());
continue;
} else {
if (!silent) WARNclass("Replacing existing tag '%s' of different type at '%s'!", tag.Data(), folder->getPath().Data());
TString val;
if (!folder->getTagString(tag,val)) {WARNclass("Failed to convert existing tag to string type!"); continue;}
folder->removeTag(tag);
folder->setTagString(tag,val);
}
}
if (TQStringUtils::equal(op,"=") && (replace || !folder->hasTagString(tag) ) ) {folder->setTag(tag,param.getTagStringDefault("value",""));}
if (TQStringUtils::equal(op,"+")) {folder->setTag(tag,inverted ? param.getTagStringDefault("value","") + folder->getTagStringDefault(tag,"") : folder->getTagStringDefault(tag,"") + param.getTagStringDefault("value","")); continue;}
if (TQStringUtils::equal(op,"-")) {
TString tmp = folder->getTagStringDefault(tag,"");
if (inverted) {
TQStringUtils::removeLeadingText(tmp,param.getTagStringDefault("value",""));
} else {
TQStringUtils::removeTrailingText(tmp,param.getTagStringDefault("value",""));
}
folder->setTag(tag,tmp);
continue;
}
} else if (isDouble) {
if (!folder->tagIsOfTypeDouble(tag) && !(create||force) ) {
if (!skipSilent)
WARNclass("In folder '%s', skipping modification of tag '%s' with operator '%s' and value '%f' due to type mismatch. Use force=true to modify anyways!",folder->getPath().Data(),tag.Data(),op.Data(), param.getTagDoubleDefault("value",0.));
continue;
}
if (folder->hasTag(tag) && !folder->tagIsOfTypeDouble(tag)) {
if (!force) {
if (!skipSilent)
WARNclass("Tag '%s' at '%s' is already present but of different type!", tag.Data(), folder->getPath().Data());
continue;
} else {
if (!silent) WARNclass("Replacing existing tag '%s' of different type at '%s'!", tag.Data(), folder->getPath().Data());
double val;
if (!folder->getTagDouble(tag,val)) {WARNclass("Failed to convert existing tag to double type!"); continue;}
folder->removeTag(tag);
folder->setTagDouble(tag,val);
}
}
if (TQStringUtils::equal(op,"=") && (replace || !folder->hasTagDouble(tag) ) ) {folder->setTag(tag,param.getTagDoubleDefault("value",0.)); continue;}
if (TQStringUtils::equal(op,"+")) {folder->setTag(tag,folder->getTagDoubleDefault(tag,0.) + param.getTagDoubleDefault("value",0.)); continue;}
if (TQStringUtils::equal(op,"-")) {folder->setTag(tag,inverted ? param.getTagDoubleDefault("value",0.) - folder->getTagDoubleDefault(tag,0.) : folder->getTagDoubleDefault(tag,0.) - param.getTagDoubleDefault("value",0.)); continue;}
if (TQStringUtils::equal(op,"*")) {folder->setTag(tag,folder->getTagDoubleDefault(tag,0.) * param.getTagDoubleDefault("value",0.)); continue;}
if (TQStringUtils::equal(op,"/")) {folder->setTag(tag,inverted ? param.getTagDoubleDefault("value",0.) / folder->getTagDoubleDefault(tag,0.) : folder->getTagDoubleDefault(tag,0.) / param.getTagDoubleDefault("value",0.)); continue;}
if (TQStringUtils::equal(op,"^")) {folder->setTag(tag,inverted ? pow(param.getTagDoubleDefault("value",0.) , folder->getTagDoubleDefault(tag,0.) ) : pow( folder->getTagDoubleDefault(tag,0.) , param.getTagDoubleDefault("value",0.) ) ); continue;}
} else if (isInt) {
if (!folder->tagIsOfTypeInteger(tag) && !(create||force) ) {
if (!skipSilent)
WARNclass("In folder '%s', skipping modification of tag '%s' with operator '%s' and value '%d' due to type mismatch. Use force=true to modify anyways!",folder->getPath().Data(),tag.Data(),op.Data(), param.getTagIntegerDefault("value",0));
continue;
}
if (folder->hasTag(tag) && !folder->tagIsOfTypeInteger(tag)) {
if (!force) {
WARNclass("Tag '%s' at '%s' is already present but of different type!", tag.Data(), folder->getPath().Data());
continue;
} else {
if (!silent) WARNclass("Replacing existing tag '%s' of different type at '%s'!", tag.Data(), folder->getPath().Data());
int val;
if (!folder->getTagInteger(tag,val)) {WARNclass("Failed to convert existing tag to integer type!"); continue;}
folder->removeTag(tag);
folder->setTagInteger(tag,val);
}
}
if (TQStringUtils::equal(op,"=") && (replace || !folder->hasTagInteger(tag) ) ) {folder->setTag(tag,param.getTagIntegerDefault("value",0)); continue;}
if (TQStringUtils::equal(op,"+")) {folder->setTag(tag,folder->getTagIntegerDefault(tag,0) + param.getTagIntegerDefault("value",0)); continue;}
if (TQStringUtils::equal(op,"-")) {folder->setTag(tag,inverted ? param.getTagIntegerDefault("value",0) - folder->getTagIntegerDefault(tag,0) : folder->getTagIntegerDefault(tag,0) - param.getTagIntegerDefault("value",0)); continue;}
if (TQStringUtils::equal(op,"*")) {folder->setTag(tag,folder->getTagIntegerDefault(tag,0) * param.getTagIntegerDefault("value",0)); continue;}
if (TQStringUtils::equal(op,"/")) {
WARNclass("Performing interger division, results may be unexpected!");
folder->setTag(tag,inverted ? param.getTagIntegerDefault("value",0) / folder->getTagIntegerDefault(tag,0) : folder->getTagIntegerDefault(tag,0) / param.getTagIntegerDefault("value",0));
continue;
}
if (TQStringUtils::equal(op,"^")) { folder->setTag(tag,inverted ? pow( param.getTagIntegerDefault("value",0) , folder->getTagIntegerDefault(tag,0) ) : pow( folder->getTagIntegerDefault(tag,0) , param.getTagIntegerDefault("value",0) ) ); continue; }
}else if (isBool) {
if (!folder->hasTagBool(tag) && !(create||force) ) {
if (!skipSilent)
WARNclass("In folder '%s', skipping modification of tag '%s' with operator '%s' and value '%s' due to type mismatch. Use force=true to modify anyways!",folder->getPath().Data(),tag.Data(),op.Data(), param.getTagBoolDefault("value",false) ? "true":"false" );
continue;
}
if (folder->hasTag(tag) && !folder->hasTagBool(tag)) {
if (!force) {
WARNclass("Tag '%s' at '%s' is already present but of different type!", tag.Data(), folder->getPath().Data());
continue;
} else {
if (!silent) WARNclass("Replacing existing tag '%s' of different type at '%s'!", tag.Data(), folder->getPath().Data());
bool val;
if (!folder->getTagBool(tag,val)) {WARNclass("Failed to convert existing tag to boolean type!"); continue;}
folder->removeTag(tag);
folder->setTagBool(tag,val);
}
}
if (TQStringUtils::equal(op,"=") && (replace || !folder->hasTagBool(tag) ) ) {folder->setTag(tag,param.getTagBoolDefault("value",false)); continue;}
if (TQStringUtils::equal(op,"==")) {folder->setTag(tag,folder->getTagBoolDefault(tag,false) == param.getTagBoolDefault("value",false)); continue;}
if (TQStringUtils::equal(op,"!=")) {folder->setTag(tag,folder->getTagBoolDefault(tag,false) != param.getTagBoolDefault("value",false)); continue;}
if (TQStringUtils::equal(op,"&&")) {folder->setTag(tag,folder->getTagBoolDefault(tag,false) && param.getTagBoolDefault("value",false)); continue;}
if (TQStringUtils::equal(op,"||")) {folder->setTag(tag,folder->getTagBoolDefault(tag,false) || param.getTagBoolDefault("value",false)); continue;}
}
}
delete targetList;
} else if (isCmdReplace) {
TString raw = strParameter;
TString pathFilter, tagFilter, typeFilter;
TQTaggable param;
TQStringUtils::removeLeadingBlanks(raw);
if (TQStringUtils::findFree(raw,"=","()[]{}\"\"''") < TQStringUtils::findFree(raw,",","()[]{}\"\"''") ) {
pathFilter = "*";
tagFilter = "*";
typeFilter = "all";
} else {
if (TQStringUtils::readBlock(raw,tagFilter,"\"\"''") > 0 ) {
TQStringUtils::removeLeadingBlanks(raw);
} else {
TQStringUtils::readUpTo(raw,tagFilter,",");
}
if (TQStringUtils::removeLeading(raw,",") < 1) {
errMsg = TString::Format("Failed to parse line $replace(%s), should be $replace(\"(typeFilter)folderFilter:tagFilter\",tag1=\"value1\",tag2=\"value2\",...)",strParameter.Data());
return false;
}
if (TQStringUtils::readBlock(tagFilter,typeFilter,"()") == 0) typeFilter = "all";
TQStringUtils::readUpTo(tagFilter,pathFilter,":");
TQStringUtils::removeLeading(tagFilter,":",1);
TQStringUtils::removeLeadingBlanks(typeFilter);
TQStringUtils::removeTrailingBlanks(typeFilter);
TQStringUtils::removeTrailingBlanks(pathFilter);
}
TString replaced(this->replaceInText(raw));
if(replaced.Contains("$")){
WARNclass("replacement '%s' in '%s' contains unresolved variables, please double-check!",replaced.Data(),this->getPath().Data());
} else if(replaced.Contains("(")){
WARNclass("replacement '%s' in '%s' brackets, please double-check!",replaced.Data(),this->getPath().Data());
}
param.importTags(replaced);
TClass* cFilter;
if (TQStringUtils::equal(typeFilter,"sf") || TQStringUtils::equal(typeFilter,"samplefolder") ) cFilter = TQSampleFolder::Class();
else if (TQStringUtils::equal(typeFilter,"s") || TQStringUtils::equal(typeFilter,"sample") ) cFilter = TQSample::Class();
else cFilter = TQFolder::Class();
this->replaceInFolderTags(param,pathFilter,tagFilter,cFilter);
} else if (isCmdCreate) {
TQTaggable param;
param.importTags(strParameter);
TString path;
if (param.getNTags() < 1 || !param.getTagString("path", path)) {
errMsg = "Wrong number of arguments to command 'create'";
return false;
} else {
TString type;
param.getTagString("type",type);
type = TQStringUtils::makeLowercase(type);
TQStringUtils::removeLeadingBlanks(path);
bool useRoot = TQStringUtils::removeLeading(path,"/") > 0;
std::vector<TString> vPath = TQStringUtils::split(path,"/");
std::vector<TQFolder*> currentFolders;
currentFolders.push_back(useRoot ? this->getRoot() : this);
for (uint i=0; i<vPath.size(); ++i) {
if (vPath.at(i).Length() < 1) continue;
std::vector<TQFolder*> newFolders;
for(auto currentFolder:currentFolders){
TQFolderIterator folders(currentFolder->getListOfFolders(vPath.at(i)),true);
TQFolder* tmpFolder = NULL;
while(folders.hasNext()){
tmpFolder = folders.readNext();
newFolders.push_back(tmpFolder);
}
if(!tmpFolder){
if (TQStringUtils::equal(type,"s") || TQStringUtils::equal(type,"sample") ) {
tmpFolder = new TQSample(vPath.at(i));
} else if (TQStringUtils::equal(type,"sf") || TQStringUtils::equal(type,"samplefolder") ) {
tmpFolder = new TQSampleFolder(vPath.at(i));
} else {
tmpFolder = new TQFolder(vPath.at(i));
}
currentFolder->addFolder(tmpFolder);
newFolders.push_back(tmpFolder);
}
}
currentFolders = newFolders;
}
}
} else if (isCmdPrint) {
this->print(TQStringUtils::unquote(strParameter));
} else if (isCmdPrintLine) {
INFO( TString::Format("@%s: '%s'" , this->getPath().Data(), this->replaceInText(TQStringUtils::unquote(strParameter)).Data()) );
} else if (isCmdWrite) {
TQTaggable param;
param.importTagWithPrefix(strParameter, "", false, "filename");
TQFolder* target = NULL;
TString filename = param.getTagStringDefault("filename","");
if (filename.Length()==0) {
errMsg = TString::Format("no file name specified");
return false;
}
if (!TQUtils::ensureDirectoryForFile(filename)) {
errMsg = TString::Format("Failed to ensure existance of directory for file '%s'",filename.Data());
return false;
}
if (param.hasTagString("target")) {
target = this->getFolder(param.getTagStringDefault("target",""));
} else {
target = this;
}
if (!target) {
errMsg = TString::Format("could not find target folder '%s'", param.getTagStringDefault("target","").Data());
return false;
}
target->exportToTextFile(filename);
} else {
errMsg = TString::Format("Unknown command '%s'", cmd.Data());
return false;
}
DEBUGclass("next token");
} else if (input.BeginsWith("\"")){
TQStringUtils::removeLeading(input, "\"");
TQStringUtils::readUpTo(input,token,"\"");
TQStringUtils::removeLeading(input, "\"");
if(!TQStringUtils::removeLeading(input, ";")){
errMsg = TString::Format("Missing terminating ';' after string '%s'", token.Data());
}
TObjString* str = new TObjString(token);
this->addObject(str);
} else if (input.BeginsWith("TH")){
TQStringUtils::readUpTo(input,token,";","()[]{}","\"\"''");
if(!TQStringUtils::removeLeading(input, ";")){
errMsg = TString::Format("Missing terminating ';' after histogram '%s'", token.Data());
}
TH1* hist = TQHistogramUtils::convertFromText(token);
this->addObject(hist);
} else if (!input.IsNull()) {
errMsg = TString::Format("Unknown token near '%s'",
TQStringUtils::maxLength(input, 30).ReplaceAll("\n", " ").Data());
return false;
}
}
return true;
}
TQFolder::~TQFolder() {
this->detachFromBase();
this->deleteAll();
this->clearDirectoryInternal();
}
TQFolder* TQFolder::copyDirectoryStructure(const TString& basepath, int maxdepth){
if(basepath.BeginsWith("root://")){
DEBUGclass("detected eos head");
size_t pathpos = basepath.Index("/eos/");
TString eosprefix = basepath(0,pathpos);
TString eosurl(eosprefix);
TQStringUtils::removeTrailing(eosurl,"/");
TQLibrary::getQLibrary()->setEOSurl(eosurl+".cern.ch");
TString path = basepath(pathpos,basepath.Length());
TQFolder* f = TQFolder::copyDirectoryStructureEOS(path,maxdepth);
if(!f) return NULL;
f->setTagBool("eos",true);
f->setTagString("eosprefix",eosprefix);
f->setTagString("eospath",path);
f->setTagString("basepath",basepath);
return f;
} else {
DEBUGclass("using local variant");
TQFolder* f = TQFolder::copyDirectoryStructureLocal(basepath,maxdepth);
if(!f) return NULL;
f->setTagBool("eos",false);
f->setTagString("basepath",basepath);
return f;
}
return NULL;
}
TQFolder* TQFolder::copyDirectoryStructureLocal(const TString& basepath, int maxdepth){
const TString dircmd(TString::Format("find -L %s -maxdepth %d ! -readable -prune -o -type d -print ", basepath.Data(),maxdepth));
const TString filecmd(TString::Format("find -L %s -maxdepth %d ! -readable -prune -o -type f -print ", basepath.Data(),maxdepth+1));
DEBUGclass(dircmd);
TList* dirs = TQUtils::execute(dircmd,4096);
#ifdef _DEBUG_
dirs->Print();
#endif
DEBUGclass(filecmd);
TList* files = TQUtils::execute(filecmd,4096);
#ifdef _DEBUG_
files->Print();
#endif
TString path(basepath);
TString tmppath(path);
TQFolder* f = new TQFolder("tmp");
tmppath = TQFolder::getPathTail(tmppath);
DEBUGclass("Setting name of base folder to '%s'",tmppath.Data());
f->SetName(tmppath);
if(dirs){
dirs->SetOwner(true);
TQIterator ditr(dirs);
while(ditr.hasNext()){
TObject* obj = ditr.readNext();
if(!obj) continue;
TString name = obj->GetName();
DEBUGclass("path including basepath: '%s'",name.Data());
TQStringUtils::removeLeadingText(name,basepath);
if(!TQFolder::isValidPath(name)) {
DEBUGclass("skipping directory '%s' due to invalid name",name.Data());
continue;
}
f->getFolder(TString::Format("%s+",name.Data()));
}
delete dirs;
}
if(files){
files->SetOwner(true);
TQIterator fitr(files);
while(fitr.hasNext()){
TObject* obj = fitr.readNext();
if(!obj) continue;
TString path(obj->GetName());
TQStringUtils::removeLeadingText(path,basepath);
TString name = TQFolder::getPathTail(path);
DEBUGfunc("adding file '%s' to '%s'",name.Data(),path.Data());
if(path.IsNull()){
f->addObject(new TObjString(name));
} else {
TQFolder* newf = f->getFolder(path + "+!");
if(!newf){
DEBUGclass("using invalid_name");
newf = f->getFolder("invalid_name+");
}
if(newf){
DEBUGclass("adding object to '%s'@%x",newf->GetName(),newf);
if(!newf->addObject(new TObjString(name))){
ERRORclass("cannot add object '%s' to '%s'",name.Data(),newf->getPath().Data());
}
}
else ERRORfunc("unable to create '%s'",name.Data(),path.Data());
}
}
delete files;
}
return f;
}
TQFolder* TQFolder::copyDirectoryStructureEOS(const TString& basepath, int maxdepth){
DEBUGclass("copying directory structure '%s'",basepath.Data());
TString path = basepath;
TString foldername = TQFolder::getPathTail(path);
TQFolder* f = new TQFolder(foldername);
f->SetName(foldername);
if(!f) return NULL;
TQIterator itr(TQUtils::execute(TQLibrary::getEOScmd()+" ls "+basepath,1024),true);
while(itr.hasNext()){
TObject* obj = itr.readNext();
TString name = TQStringUtils::makeASCII(obj->GetName());
if(name.Contains("/")){
path = name;
} else {
path = TQFolder::concatPaths(basepath,name);
}
DEBUGclass("looking at '%s'",path.Data());
bool isDir = false;
if(maxdepth > 0){
TList* l = TQUtils::execute(TQLibrary::getEOScmd()+" stat "+path,1024);
if(!l){
ERRORclass("unable to execute '%s stat %s', skipping",TQLibrary::getEOScmd().Data(),path.Data());
continue;
}
TString status(l->Last()->GetName());
delete l;
if(status.IsNull()){
ERRORclass("unable to retrieve status of object '%s', skipping",path.Data());
continue;
}
if(status.Contains("directory") || status.Contains("IsDir")){
isDir = true;
}
}
if(isDir){
TQFolder* subf = TQFolder::copyDirectoryStructureEOS(path,maxdepth-1);
if(subf){
f->Add(subf);
subf->setBase(f);
}
} else {
f->addObject(new TObjString(TQFolder::getPathTail(name)));
}
}
return f;
}
int TQFolder::writeToFile(const TString& filename, bool overwrite, int depth, bool keepInMemory){
DEBUGclass("opening file '%s'",filename.Data());
TFile* f = TFile::Open(filename,overwrite ? "RECREATE" : "UPDATE");
if(!f) return -1;
if(!f->IsOpen()){
delete f;
return -2;
}
DEBUGclass("writing to file");
bool retval = this->writeFolderHook(f,this->GetName(),depth,keepInMemory);
DEBUGclass("closing file");
f->Close();
return (int)(retval);
}
void TQFolder::setInfoTags(){
this->setTagString(".creationDate",TQUtils::getTimeStamp());
this->setTagString(".createdBy",TQLibrary::getApplicationName());
this->setTagString(".libVersion",TQLibrary::getVersion());
this->setTagString(".rootVersion",TQLibrary::getROOTVersion());
this->setTagString(".gccVersion",TQLibrary::getGCCVersion());
}
TQFolder* TQFolder::findCommonBaseFolder(TCollection* fList, bool allowWildcards){
TString base = "";
bool first = true;
TQFolderIterator itr(fList);
while(itr.hasNext()){
TQFolder* f = itr.readNext();
const TString tmppath( allowWildcards ? f->getPathWildcarded() : f->getPath());
if(first){
base = tmppath;
first=false;
} else {
if(TQStringUtils::reduceToCommonPrefix(base,tmppath) < 1) return NULL;
}
}
DEBUGclass(TString::Format("common base appears to be '%s'",base.Data()));
if(base.IsNull()) return NULL;
if(base.EndsWith("/")){
TQFolder* retval = this->getFolder(base);
if(retval) return retval;
}
this->getPathTail(base);
return this->getFolder(base);
}
TList* TQFolder::exportTagsToText(const TString& filter){
TList* folders = this->getListOfFolders("*");
TList* retval = new TList();
TQFolderIterator itr(folders,true);
std::map<TString,TString> tagMap;
while(itr.hasNext()){
TQFolder* obj = itr.readNext();
if(!obj) continue;
TString tags = obj->exportTagsAsString(filter,true);
if(tags.IsNull()) continue;
TString path = obj->getPathWildcarded();
tagMap[path] = tags;
}
for(std::map<TString,TString>::iterator it = tagMap.begin(); it != tagMap.end(); ++it){
TString line = "<" + it->second + "> @ " + it->first + ";";
TObjString* s = new TObjString(line);
retval->Add(s);
}
return retval;
}
bool TQFolder::exportTagsToTextFile(const TString& filename, const TString& filter){
TList * text = this->exportTagsToText(filter);
text->Print();
if (text) {
text->AddFirst(new TObjString("# -*- mode: tqfolder -*-"));
bool success = TQStringUtils::writeTextToFile(text, filename);
delete text;
return success;
} else {
return false;
}
}
bool TQFolder::merge(TQFolder* other, bool sumElements){
if(this->Class() == TQFolder::Class()){
return this->mergeAsFolder(other,sumElements ? MergeMode::SumElements : MergeMode::PreferOther);
} else {
ERRORclass("unable to merge '%s' with 'TQFolder'",this->Class()->GetName());
return false;
}
}
bool TQFolder::mergeAsFolder(TQFolder* other, MergeMode mode){
this->mergeTags(other);
TQFolderIterator itr(other->getListOfFolders("?"));
while(itr.hasNext()){
TQFolder* f = itr.readNext();
if(!f) continue;
TQFolder* thisF = this->getFolder(f->GetName());
if(thisF){
thisF->mergeAsFolder(f,mode);
} else {
f->detachFromBase();
this->addObject(f);
}
}
this->mergeObjects(other,mode);
return true;
}
bool TQFolder::mergeTags(TQFolder* other){
bool overwrite = this->getGlobalOverwrite();
this->setGlobalOverwrite(false);
this->importTags(other);
if(overwrite) this->setGlobalOverwrite(true);
return true;
}
void TQFolder::mergeObjects(TQFolder* other, MergeMode mode){
TQIterator itr(other->GetListOfFolders());
std::map<TString,TObject*> helperMap;
std::map<TString,TObject*>::iterator helperIt;
for (TObject* obj: (*(this->GetListOfFolders())) ) {
if (!obj) continue;
helperMap[obj->GetName()] = obj;
}
while(itr.hasNext()){
TObject* obj = itr.readNext();
if(!obj) continue;
if(obj->InheritsFrom(TQFolder::Class())) continue;
TObject* thisObj = nullptr;
helperIt = helperMap.find(obj->GetName());
if (helperIt != helperMap.end()) thisObj = helperIt->second;
if(!thisObj) {
DEBUGclass("grabbing object '%s'",obj->GetName());
other->Remove(obj);
this->addObject(obj);
} else {
if(mode == PreferThis){
DEBUGclass("leaving object '%s'",thisObj->GetName());
} else if(mode == PreferOther){
DEBUGclass("grabbing & replacing object '%s'",thisObj->GetName());
other->Remove(obj);
this->Remove(thisObj);
delete thisObj;
this->addObject(obj);
} else if(mode == SumElements){
if ( obj->InheritsFrom(TH1::Class()) && thisObj->InheritsFrom(TH1::Class()) ) {
TH1* hist = static_cast<TH1*>(obj);
TH1* thisHist = static_cast<TH1*>(thisObj);
if(TQHistogramUtils::checkConsistency(hist,thisHist)){
DEBUGclass("summing histogram '%s'",thisObj->GetName());
thisHist->Add(hist);
continue;
}
else{
WARNclass("The histograms that you're trying to merge are not consistent. Check the binning and the dimensions for example.");
}
} else if ( obj->InheritsFrom(THnBase::Class()) && thisObj->InheritsFrom(THnBase::Class()) ) {
THnBase* ndimHist = static_cast<THnBase*>(obj);
THnBase* thisndimHist = static_cast<THnBase*>(thisObj);
if(TQTHnBaseUtils::checkConsistency(ndimHist,thisndimHist)){
DEBUGclass("summing n-dim histogram '%s'",thisObj->GetName());
thisndimHist->Add(ndimHist);
continue;
}
} else if ( obj->InheritsFrom(TQCounter::Class()) && thisObj->InheritsFrom(TQCounter::Class()) ) {
TQCounter* counter = static_cast<TQCounter*>(obj);
TQCounter* thisCounter = static_cast<TQCounter*>(thisObj);
if(counter && thisCounter){
DEBUGclass("summing counter '%s'",thisObj->GetName());
thisCounter->add(counter);
continue;
}
} else if ( obj->InheritsFrom(TQTable::Class()) && thisObj->InheritsFrom(TQTable::Class()) ) {
if ( obj->InheritsFrom(TQXSecParser::Class()) || thisObj->InheritsFrom(TQXSecParser::Class()) ) continue;
TQTable* tbl = static_cast<TQTable*>(obj);
TQTable* thisTbl = static_cast<TQTable*>(thisObj);
if(tbl && thisTbl){
DEBUGclass("appending table '%s'",thisObj->GetName());
thisTbl->merge(tbl);
continue;
}
} else if ( obj->InheritsFrom(TObjString::Class()) && thisObj->InheritsFrom(TObjString::Class()) ) {
TObjString* str = static_cast<TObjString*>(obj);
TObjString* thisStr = static_cast<TObjString*>(thisObj);
if(str && thisStr){
if(TQStringUtils::equal(str->String(),thisStr->String())){
continue;
} else {
ERRORclass("cannot merge two TObjStrings with different content!");
continue;
}
}
}
ERRORclass("cannot merge objects '%s' of type '%s' and '%s'",obj->GetName(),obj->ClassName(),thisObj->ClassName());
}
}
}
DEBUGclass("leaving function");
}
int TQFolder::replaceInFolderTags(TQTaggable& params, const TString& path, const TString& tagFilter, TClass* typeFilter ){
TList* targetList = this->getListOfFolders(path,typeFilter);
if (!targetList) {
WARNclass("No matching folders found for pattern '%s'",path.Data());
return -1;
}
TQFolderIterator itr(targetList);
while (itr.hasNext()) {
TQFolder* folder = itr.readNext();
if (!folder) continue;
folder->replaceInTags(params,tagFilter);
}
delete targetList;
return 0;
}