#include "QFramework/TQTaggable.h"
#include "TString.h"
#include "TNamed.h"
#include "TClass.h"
#include "TList.h"
#include "TParameter.h"
#include "TIterator.h"
#include "TCollection.h"
#include "QFramework/TQStringUtils.h"
#include "QFramework/TQListUtils.h"
#include "QFramework/TQUtils.h"
#include "QFramework/TQIterator.h"
#include "QFramework/TQFolder.h"
#include "QFramework/TQLibrary.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include <cstdlib>
ClassImp(TQTaggable)
TQTaggable::TQTaggable() :
fTags(0),
fReadFlags(0),
fGlobalIgnoreCase(false),
fGlobalOverwrite(true)
{
}
TQTaggable::TQTaggable(const TString& tags) :
TQTaggable(tags.Data())
{
}
TQTaggable::TQTaggable(const char* str) :
TQTaggable()
{
TString tags(str);
if (TQStringUtils::removeLeading(tags, "-") == 2) {
TQTaggable * flags = TQTaggable::parseFlags(tags);
if (flags) {
flags->exportTags(this);
delete flags;
}
} else {
importTags(tags);
}
}
TQTaggable::TQTaggable(TQTaggable * tags) :
TQTaggable()
{
this->importTags(tags);
}
TQTaggable::TQTaggable(const TQTaggable& tags) :
TQTaggable()
{
this->importTags(tags);
}
TQTaggable * TQTaggable::getBaseTaggable() const {
return 0;
}
TList * TQTaggable::getDescendantTaggables() {
return 0;
}
TList * TQTaggable::getTaggablesByName(const TString& ) {
return 0;
}
TList * TQTaggable::getListOfTaggables(const TString& ) {
return 0;
}
const TString& TQTaggable::getValidKeyCharacters() {
return TQValue::getValidNameCharacters();
}
bool TQTaggable::isValidKey(const TString& key) {
return TQValue::isValidName(key);
}
void TQTaggable::resetReadFlags() {
if (fReadFlags) {
delete fReadFlags;
}
fReadFlags = new TList();
fReadFlags->SetOwner(true);
}
bool TQTaggable::hasUnreadKeys(const TString& filter) {
TList * unreadKeys = getListOfUnreadKeys(filter);
if (unreadKeys) {
delete unreadKeys;
return true;
} else {
return false;
}
}
TList * TQTaggable::getListOfUnreadKeys(const TString& filter) {
TList * unreadKeys = getListOfKeys(filter);
if (!unreadKeys) {
return NULL;
}
TQIterator itr(fReadFlags);
while (itr.hasNext()) {
TObject * tag = unreadKeys->FindObject(itr.readNext()->GetName());
if (tag) {
unreadKeys->Remove(tag);
delete tag;
}
}
if (unreadKeys->GetEntries() == 0) {
delete unreadKeys;
unreadKeys = NULL;
}
return unreadKeys;
}
void TQTaggable::onAccess(TQValue * ) {
}
void TQTaggable::onRead(TQValue * tag) {
if (fReadFlags) {
if (!fReadFlags->FindObject(tag->GetName())) {
fReadFlags->Add(new TObjString(tag->GetName()));
}
}
}
void TQTaggable::onWrite(TQValue * ) {
}
TQTaggable * TQTaggable::parseFlags(const TString& flags) {
TString myFlags = flags;
TQTaggable * tags = new TQTaggable();
bool stop = false;
while (!myFlags.IsNull() && !stop) {
bool negate = false;
if (TQStringUtils::removeLeading(myFlags, "!", 1)) {
negate = true;
}
TString flag;
if (!TQStringUtils::readToken(myFlags, flag, TQStringUtils::getLetters(), 1) &&
!TQStringUtils::readBlock(myFlags, flag, "<>[]{}", "\"\"''")) {
stop = true;
continue;
}
if (tags->hasTag(flag)) {
stop = true;
continue;
}
TString block;
if (TQStringUtils::readBlock(myFlags, block, "[]<>{}", "\"\"''")) {
if (negate || !tags->setTagString(flag, block)) {
stop = true;
}
continue;
}
TString number;
if (TQStringUtils::readToken(myFlags, number, TQStringUtils::getNumerals() + "-")) {
if (!TQStringUtils::isInteger(number)) {
stop = true;
continue;
}
if (negate || !tags->setTagInteger(flag, number.Atoi())) {
stop = true;
}
continue;
}
tags->setTagBool(flag, !negate);
}
if (stop) {
delete tags;
tags = NULL;
}
return tags;
}
TString TQTaggable::getFlags() {
TString flags;
TQIterator itr(this->getListOfKeys(), true);
while (itr.hasNext()) {
TString name = itr.readNext()->GetName();
TString flag;
if (name.Length() == 1 && TQStringUtils::getLetters().Index(name) != kNPOS) {
flag.Append(name);
} else {
flag.Append(TString("<") + name + ">");
}
TQValue * val = this->findTag(name);
if (!val) {
continue;
}
if (!val->isBool()) {
if (val->isInteger()) {
flag.Append(TString::Format("%d", val->getInteger()));
} else {
flag.Append(TString::Format("[%s]", val->getString().Data()));
}
} else {
if (!val->getBool()) {
flag.Prepend("!");
}
}
flags.Append(flag);
}
return flags;
}
int TQTaggable::setTag(TQValue * tag, const TString& destination, bool overwrite) {
if (!tag)
return 0;
if (destination.IsNull()) {
if (!fTags) {
fTags = new TList();
} else {
TObject * existing = fTags->FindObject(tag->GetName());
if (existing) {
if (!overwrite) {
return 0;
}
fTags->Remove(existing);
delete existing;
}
}
this->fTags->Add(tag);
this->onWrite(tag);
return 1;
} else {
TList * taggables = this->getTaggablesByName(destination);
if (!taggables)
return 0;
int nTags = 0;
TQIterator itr(taggables);
while (itr.hasNext()) {
TQTaggable* t = dynamic_cast<TQTaggable*>(itr.readNext());
if(!t) continue;
if (nTags == 0)
nTags += t->setTag(tag, "", overwrite);
else
nTags += t->setTag(tag->copy(), "", overwrite);
}
delete taggables;
return nTags;
}
}
void TQTaggable::setGlobalIgnoreCase(bool globalIgnoreCase) {
fGlobalIgnoreCase = globalIgnoreCase;
}
bool TQTaggable::getGlobalIgnoreCase() const {
return fGlobalIgnoreCase;
}
void TQTaggable::setGlobalOverwrite(bool globalOverwrite) {
fGlobalOverwrite = globalOverwrite;
}
bool TQTaggable::getGlobalOverwrite() const {
TQTaggable* base = this->getBaseTaggable();
return base ? base->getGlobalOverwrite() : fGlobalOverwrite;
}
TQValue * TQTaggable::findTag(TString name) {
if (!fTags) return nullptr;
bool ignoreCase = (TQStringUtils::removeLeading(name, "^", 1) > 0) || fGlobalIgnoreCase;
TQValue * tag = NULL;
TQIterator itr(fTags);
while (itr.hasNext() && !tag) {
TObject * thisObj = itr.readNext();
if (!thisObj) {
continue;
}
TString thisName = thisObj->GetName();
if ((name.CompareTo(thisName, ignoreCase ? TString::kIgnoreCase : TString::kExact) == 0)
&& thisObj->InheritsFrom(TQValue::Class())) {
tag = (TQValue*)thisObj;
}
}
return tag;
}
bool TQTaggable::hasMatchingTag(const TString& name) const {
return this->countMatchingTags(name)>0;
}
int TQTaggable::countMatchingTags(const TString& name) const {
if (!fTags) return 0;
int retval = 0;
TQIterator itr(fTags);
while (itr.hasNext()) {
TObject * thisObj = itr.readNext();
if (!thisObj) {
continue;
}
if(TQStringUtils::matches(thisObj->GetName(),name)) retval++;
}
return retval;
}
bool TQTaggable::hasEquivalentTag(const TQValue* reference, bool recurseUp) {
if (!reference) return false;
TQValue* existing = nullptr;
TString key = reference->GetName();
if (recurseUp) TQStringUtils::ensureLeadingText(key,"~");
getTag(key, existing);
if (!existing) {
return false;
}
return reference->isEquivalentTo(existing);
}
bool TQTaggable::hasEquivalentTag(const TQValue& reference, bool recurseUp) {
return this->hasEquivalentTag(&reference, recurseUp);
}
bool TQTaggable::hasEquivalentTag(const TString& key, const TString& value) {
return this->hasEquivalentTag(TQValueString(key,value));
}
bool TQTaggable::hasEquivalentTag(const TString& key, const double value) {
return this->hasEquivalentTag(TQValueDouble(key,value));
}
bool TQTaggable::hasEquivalentTag(const TString& key, const int value) {
return this->hasEquivalentTag(TQValueInteger(key,value));
}
bool TQTaggable::hasEquivalentTag(const TString& key, const bool value) {
return this->hasEquivalentTag(TQValueBool(key,value));
}
bool TQTaggable::isTagOverwrittenByDescendants(TString key) {
TQStringUtils::removeLeading(key, "~");
TQStringUtils::ensureTrailingText(key,"~");
TList * descendantTaggables = this->getDescendantTaggables();
TQIterator itr(descendantTaggables,true);
while(itr.hasNext()){
TQTaggable* child = dynamic_cast<TQTaggable*>(itr.readNext());
if(!child) continue;
if(child->hasTag(key)){
return true;
}
}
return false;
}
bool TQTaggable::getTag(const TString& key, TQValue * &tag) {
TString myKey(key);
bool recursiveUp = TQStringUtils::removeLeading(myKey, "~", 1) > 0;
bool recursiveDown = TQStringUtils::removeTrailing(myKey, "~", 1) > 0;
TQValue * value = findTag(myKey);
if (value) {
tag = (TQValue*)value;
onAccess(tag);
return true;
} else {
if (recursiveUp) {
TQTaggable * baseTaggable = getBaseTaggable();
if (baseTaggable) {
return baseTaggable->getTag(key, tag);
}
}
if (recursiveDown){
TList * descendantTaggables = this->getDescendantTaggables();
TQIterator itr(descendantTaggables,true);
while(itr.hasNext()){
TQTaggable* child = dynamic_cast<TQTaggable*>(itr.readNext());
if(!child) continue;
if(child->getTag(key,tag)){
DEBUGclass("found tag '%s' with value '%s' on %p",key.Data(),tag->getValueAsString().Data(),child);
return true;
}
}
}
return false;
}
}
int TQTaggable::getTagsSize(){
if (!fTags) return 0;
int size=sizeof(*fTags);;
TQValueIterator itr(fTags);
while(itr.hasNext()){
TQValue* obj = itr.readNext();
size += obj->getSize();
}
return size;
}
int TQTaggable::getFlagsSize(){
int size=0;
if(fReadFlags){
size+=sizeof(*fReadFlags);;
TQStringIterator flagitr(fReadFlags);
while(flagitr.hasNext()){
TObjString* objstr = flagitr.readNext();
size += sizeof(*objstr);
}
}
return size;
}
TList * TQTaggable::getListOfKeys(const TString& filter) {
TList * list = NULL;
if (!fTags) return NULL;
TQValueIterator itr(fTags);
while(itr.hasNext()){
TQValue* obj = itr.readNext();
if(!obj) continue;
if (!filter.IsNull() && !TQStringUtils::matchesFilter(obj->GetName(), filter, ",", true)) {
continue;
}
if (!list) {
list = new TList();
list->SetOwner(true);
}
list->Add(new TObjString(obj->GetName()));
}
return list;
}
bool TQTaggable::tagsAreEquivalentTo(TQTaggable * tags, const TString& filter) {
if (!tags) {
return false;
}
TList * keys = TQListUtils::getMergedListOfNames(
this->getListOfKeys(filter), tags->getListOfKeys(filter), true);
TQIterator itr(keys, true);
while (itr.hasNext()) {
TString name = itr.readNext()->GetName();
TQValue * myTag = this->findTag(name);
TQValue * theirTag = tags->findTag(name);
if (!myTag || !theirTag || !myTag->isEquivalentTo(theirTag)) {
return false;
}
}
return true;
}
bool TQTaggable::printDiffOfTags(TQTaggable * tags, const TString& options) {
TQTaggable * opts = TQTaggable::parseFlags(options);
if (!opts) {
std::cout << TQStringUtils::makeBoldRed(TString::Format("TQTaggable::printDiffOfTags(...): "
"Failed to parse options '%s'", options.Data())).Data() << std::endl;
return false;
}
bool result = false;
result = this->printDiffOfTags(tags, *opts);
delete opts;
return result;
}
bool TQTaggable::printDiffOfTags(TQTaggable * tags, TQTaggable& options) {
const int cColWidth_Name = 50;
const int cColWidth_Comp = 20;
const int cColWidth_Details = 30;
if (!tags) {
return false;
}
int indent = options.getTagIntegerDefault("i", 0) * 2;
bool folderPrintDiff = options.getTagBoolDefault("z", false);
bool onlyListMismatches = options.getTagBoolDefault("m", false);
bool printDetails = options.getTagBoolDefault("d", false);
bool equivalent = true;
TList * keys = TQListUtils::getMergedListOfNames(
this->getListOfKeys(), tags->getListOfKeys(), true);
TString line;
if (!folderPrintDiff) {
line = TQStringUtils::fixedWidth("Tag", 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;
}
TQIterator itr(keys, true);
while (itr.hasNext()) {
TString name = itr.readNext()->GetName();
TQValue * myTag = this->findTag(name);
TQValue * theirTag = tags->findTag(name);
if (folderPrintDiff) {
line = TQStringUtils::fixedWidth(TQStringUtils::repeatSpaces(indent) +
TString::Format("\033[0;36m<%s>\033[0m", name.Data()), cColWidth_Name, "l");
} else {
line = TQStringUtils::fixedWidth(TQStringUtils::repeatSpaces(indent) + name, cColWidth_Name, "l");
}
TString comp;
bool thisEquivalent = true;
if (myTag && theirTag) {
if (myTag->isEquivalentTo(theirTag)) {
comp = TQStringUtils::makeBoldGreen("<1> == <2>");
} else {
thisEquivalent = false;
comp = TQStringUtils::makeBoldRed("<1> != <2>");
}
} else if (myTag) {
thisEquivalent = false;
comp = TQStringUtils::makeBoldRed("<1> - ");
} else if (theirTag) {
thisEquivalent = false;
comp = TQStringUtils::makeBoldRed(" - <2>");
}
if (!onlyListMismatches || !thisEquivalent) {
line.Append(TQStringUtils::fixedWidth(comp, cColWidth_Comp, "l"));
if (printDetails) {
TString detail1;
TString detail2;
if (myTag) {
detail1 = myTag->getValueAsString();
}
if (theirTag) {
detail2 = theirTag->getValueAsString();
}
line.Append(TQStringUtils::fixedWidth(detail1, cColWidth_Details, "l"));
line.Append(TQStringUtils::fixedWidth(detail2, cColWidth_Details, "l"));
}
std::cout << line.Data() << std::endl;
}
if (!thisEquivalent) {
equivalent = false;
}
}
return equivalent;
}
int TQTaggable::removeTag(const TString& key) {
int nTags = 0;
if (!fTags) {
return 0;
}
TString myKey = key;
TQValue * tag = findTag(myKey);
if (tag) {
fTags->Remove(tag);
delete tag;
nTags++;
}
if (fTags->GetEntries() == 0) {
delete fTags;
fTags = NULL;
}
return nTags;
}
int TQTaggable::removeTags(const TString& key) {
int nTags = 0;
if (!fTags) {
return 0;
}
TQValueIterator itr(this->fTags);
while(itr.hasNext()){
TQValue* tag = itr.readNext();
if(TQStringUtils::matches(tag->GetName(),key)){
fTags->Remove(tag);
delete tag;
nTags++;
}
}
if (fTags->GetEntries() == 0) {
delete fTags;
fTags = NULL;
}
return nTags;
}
bool TQTaggable::renameTag(const TString& oldKey, const TString& newKey) {
if (this->hasTag(newKey) || !TQValue::isValidName(newKey)) {
return false;
}
TQValue * tag = findTag(oldKey);
if (tag) {
tag->setName(newKey.Data());
return true;
} else {
return false;
}
}
int TQTaggable::renameTags(const TString& oldPrefix, const TString& newPrefix) {
int n = 0;
TQIterator itr(this->getListOfKeys(), true);
while (itr.hasNext()) {
TString key = itr.readNext()->GetName();
TString oldKey = key;
if (!TQStringUtils::removeLeadingText(key, oldPrefix)) {
continue;
}
if (renameTag(oldKey, newPrefix + key)) {
n++;
}
}
return n;
}
void TQTaggable::clear() {
this->clearTags();
}
int TQTaggable::clearTags() {
int n = 0;
if (fTags) {
n = fTags->GetEntries();
fTags->Delete();
delete fTags;
fTags = NULL;
}
return n;
}
int TQTaggable::printClaim(const TString& definition) {
TString missing;
TString invalid;
TString unexpected;
int result = claimTags(definition, missing, invalid, unexpected);
std::cout << "Missing : " << missing.Data() << std::endl;
std::cout << "Invalid : " << invalid.Data() << std::endl;
std::cout << "Unexpected: " << unexpected.Data() << std::endl;
return result;
}
int TQTaggable::claimTags(const TString& definition, bool printErrMsg) {
TString errMsg;
int result = claimTags(definition, errMsg);
if (printErrMsg && result < 1) {
std::cout << "TQTaggable::claimTags(...): " << errMsg.Data() << std::endl;
}
return result;
}
int TQTaggable::claimTags(const TString& definition, TString& message) {
if (message.IsNull()) {
message = "tag";
}
TString missing;
TString invalid;
TString unexpected;
int result = claimTags(definition, missing, invalid, unexpected);
if (result < 0) {
message = "Failed to parse definition";
} else if (!missing.IsNull()) {
message = TString::Format("Missing %s '%s'", message.Data(),
TQStringUtils::getFirstToken(missing).Data());
} else if (!invalid.IsNull()) {
message = TString::Format("Invalid %s '%s'", message.Data(),
TQStringUtils::getFirstToken(invalid).Data());
} else if (!unexpected.IsNull()) {
message = TString::Format("Unexpected %s '%s'", message.Data(),
TQStringUtils::getFirstToken(unexpected).Data());
}
return result;
}
int TQTaggable::claimTags(const TString& definition, TString& missing,
TString& invalid, TString& unexpected) {
bool fulfilled = true;
TList * unlisted = this->getListOfKeys();
bool nothingElse = false;
bool error = false;
TQIterator itr(TQStringUtils::tokenize(definition, ",", true, "[]"), true);
while (!error && itr.hasNext()) {
TString token = itr.readNext()->GetName();
if (token.CompareTo("!!") == 0) {
nothingElse = true;
continue;
}
bool unaccepted = TQStringUtils::removeLeading(token, "!", 1);
bool optional = false;
TString block;
if (TQStringUtils::readBlock(token, block, "[]")) {
if (unaccepted || !token.IsNull()) {
error = true;
continue;
}
optional = true;
token = block;
}
TString keyFilter;
if (!TQStringUtils::readToken(token, keyFilter, TQValue::getValidNameCharacters() + "?*")) {
error = true;
continue;
}
TString typeFilter;
bool forceType = false;
if (TQStringUtils::removeLeading(token, ":", 1)) {
if (!TQStringUtils::readToken(token, typeFilter, "ibds")) {
error = true;
continue;
}
forceType = (TQStringUtils::removeLeading(token, "!", 1) > 0);
}
TString numConstraint;
if (TQStringUtils::removeLeading(token, ":", 1)) {
if (TQStringUtils::isEmpty(token, true)) {
error = true;
continue;
}
numConstraint = token;
} else if (!TQStringUtils::isEmpty(token, true)) {
error = true;
continue;
}
bool found = false;
TQListUtils::removeElements(unlisted, keyFilter);
TQIterator itrKeys(this->getListOfKeys(keyFilter), true);
while (itrKeys.hasNext()) {
TString key = itrKeys.readNext()->GetName();
TQValue * tag = this->findTag(key);
if (!tag) {
continue;
}
found = true;
if (unaccepted) {
fulfilled = false;
TQStringUtils::append(unexpected, key, ", ");
continue;
}
if (!typeFilter.IsNull() && ((forceType && (
(tag->isInteger() && !typeFilter.Contains("i")) ||
(tag->isBool() && !typeFilter.Contains("b")) ||
(tag->isDouble() && !typeFilter.Contains("d")) ||
(tag->isString() && !typeFilter.Contains("s")))) ||
( !forceType && (
(typeFilter.Contains("i") && !tag->isValidInteger()) ||
(typeFilter.Contains("b") && !tag->isValidBool()) ||
(typeFilter.Contains("d") && !tag->isValidDouble()))))) {
fulfilled = false;
TQStringUtils::append(invalid, key, ", ");
continue;
}
if (!numConstraint.IsNull()) {
int test = TQStringUtils::testNumber(tag->getDouble(), numConstraint);
if (test < 0) {
error = true;
continue;
} else if (!tag->isValidDouble() || test == 0) {
fulfilled = false;
TQStringUtils::append(invalid, key, ", ");
continue;
}
}
}
if (!found && !optional && !unaccepted) {
fulfilled = false;
TQStringUtils::append(missing, keyFilter, ", ");
}
}
if (!error) {
if (nothingElse) {
if (unlisted && unlisted->GetEntries() > 0) {
fulfilled = false;
}
TQStringUtils::append(unexpected, TQStringUtils::concatNames(unlisted, ", "), ", ");
}
}
if (unlisted) {
delete unlisted;
}
if (!error) {
return fulfilled ? 1 : 0;
} else {
return -1;
}
}
bool TQTaggable::hasTag(const TString& key) {
TQValue * dummy = 0;
return getTag(key, dummy);
}
bool TQTaggable::hasTagDouble(const TString& key) {
double dummy = 0.;
return getTagDouble(key, dummy);
}
bool TQTaggable::hasTagInteger(const TString& key) {
int dummy = 0;
return getTagInteger(key, dummy);
}
bool TQTaggable::hasTagBool(const TString& key) {
bool dummy = false;
return getTagBool(key, dummy);
}
bool TQTaggable::hasTagString(const TString& key) {
TString dummy;
return getTagString(key, dummy);
}
bool TQTaggable::tagIsOfTypeDouble(const TString& key) {
TQValue * dummy = NULL;
getTag(key, dummy);
return (dummy != NULL) && dummy->isDouble();
}
bool TQTaggable::tagIsOfTypeInteger(const TString& key) {
TQValue * dummy = NULL;
getTag(key, dummy);
return (dummy != NULL) && dummy->isInteger();
}
bool TQTaggable::tagIsOfTypeBool(const TString& key) {
TQValue * dummy = NULL;
getTag(key, dummy);
return (dummy != NULL) && dummy->isBool();
}
bool TQTaggable::tagIsOfTypeString(const TString& key) {
TQValue * dummy = NULL;
getTag(key, dummy);
return (dummy != NULL) && dummy->isString();
}
bool TQTaggable::allTagsValidDoubles() {
TQIterator itr(getListOfKeys(), true);
while (itr.hasNext()) {
if (!hasTagDouble(itr.readNext()->GetName())) {
return false;
}
}
return true;
}
bool TQTaggable::allTagsValidIntegers() {
TQIterator itr(getListOfKeys(), true);
while (itr.hasNext()) {
if (!hasTagDouble(itr.readNext()->GetName())) {
return false;
}
}
return true;
}
bool TQTaggable::allTagsValidBools() {
TQIterator itr(getListOfKeys(), true);
while (itr.hasNext()) {
if (!hasTagBool(itr.readNext()->GetName())) {
return false;
}
}
return true;
}
bool TQTaggable::allTagsOfTypeDouble() {
TQIterator itr(getListOfKeys(), true);
while (itr.hasNext()) {
if (!tagIsOfTypeDouble(itr.readNext()->GetName())) {
return false;
}
}
return true;
}
bool TQTaggable::allTagsOfTypeInteger() {
TQIterator itr(getListOfKeys(), true);
while (itr.hasNext()) {
if (!tagIsOfTypeInteger(itr.readNext()->GetName())) {
return false;
}
}
return true;
}
bool TQTaggable::allTagsOfTypeBool() {
TQIterator itr(getListOfKeys(), true);
while (itr.hasNext()) {
if (!tagIsOfTypeBool(itr.readNext()->GetName())) {
return false;
}
}
return true;
}
bool TQTaggable::allTagsOfTypeString() {
TQIterator itr(getListOfKeys(), true);
while (itr.hasNext()) {
if (!tagIsOfTypeString(itr.readNext()->GetName())) {
return false;
}
}
return true;
}
int TQTaggable::countTagUp(const TString& key) {
int nTags = 0;
if (hasTag(key))
nTags++;
TQTaggable * baseTaggable = getBaseTaggable();
if (baseTaggable)
nTags += baseTaggable->countTagUp(key);
return nTags;
}
int TQTaggable::countTagDown(const TString& key) {
int nTags = 0;
if (hasTag(key))
nTags++;
TList * taggables = getDescendantTaggables();
if (taggables) {
TIterator * itr = taggables->MakeIterator();
TObject * obj;
while ((obj = itr->Next())) {
if (obj->InheritsFrom(TQTaggable::Class()))
nTags += ((TQTaggable*)obj)->countTagDown(key);
}
delete itr;
delete taggables;
}
return nTags;
}
bool TQTaggable::getOp(const TString& op, int &opCode) {
if (op.Length() == 0)
opCode = kOpNone;
else if (op.CompareTo("~") == 0)
opCode = kOpRec;
else if (op.CompareTo("||") == 0)
opCode = kOpOR;
else if (op.CompareTo("&&") == 0)
opCode = kOpAND;
else if (op.CompareTo("+") == 0)
opCode = kOpADD;
else if (op.CompareTo("*") == 0)
opCode = kOpMULT;
else if (op.CompareTo("#") == 0)
opCode = kOpCNT;
else
return false;
return true;
}
bool TQTaggable::parseKey(TString key, TString &bareKey, int &opUp, int &opDown) {
TString prefix;
TString keyName;
TString appendix;
TQStringUtils::readToken(key, prefix, "~|&+*#");
TQStringUtils::readToken(key, keyName, TQValue::getValidNameCharacters());
TQStringUtils::readToken(key, appendix, "~|&+*#");
if (key.Length() != 0)
return false;
int tmpOpUp = kOpNone;
int tmpOpDown = kOpNone;
if (!getOp(prefix, tmpOpUp) || !getOp(appendix, tmpOpDown))
return false;
opUp = tmpOpUp;
opDown = tmpOpDown;
bareKey = keyName;
return true;
}
int TQTaggable::getNTags() const {
if (fTags)
return fTags->GetEntries();
else
return 0;
}
void TQTaggable::printTags(TString options) {
TQTaggable * taggable = this;
TList * printed = new TList();
const int cColWidth_Key = 40;
const int cColWidth_Type = 10;
const int cColWidth_Value = 40;
bool printRecursive = options.Contains("r");
TString line;
line.Append(TQStringUtils::fixedWidth("Key", cColWidth_Key));
line.Append(TQStringUtils::fixedWidth("Type", cColWidth_Type));
line.Append(TQStringUtils::fixedWidth("Value", cColWidth_Value));
std::cout << TQStringUtils::makeBoldWhite(line) << std::endl;
std::cout << TQStringUtils::makeBoldWhite(TQStringUtils::repeat("=", TQStringUtils::getWidth(line))) << std::endl;
while (taggable) {
TQIterator itr(taggable->getListOfTags());
while(itr.hasNext()){
TObject* obj = itr.readNext();
if(!obj) continue;
if (printed->FindObject(obj->GetName()))
continue;
printed->Add(obj);
TString key = obj->GetName();
TString value, type;
if (taggable->getValueOfTagAsString(key, value)
&& taggable->getTypeOfTagAsString(key, type)) {
if (taggable != this)
key.Prepend("\033[1;31m~\033[0m");
line.Clear();
line.Append(TQStringUtils::fixedWidth(key, cColWidth_Key));
line.Append(TQStringUtils::fixedWidth(type, cColWidth_Type));
line.Append(TQStringUtils::fixedWidth(value, cColWidth_Value));
std::cout << line.Data() << std::endl;
}
}
if (printRecursive)
taggable = taggable->getBaseTaggable();
else
taggable = 0;
}
delete printed;
}
TList * TQTaggable::getListOfTags() {
return fTags;
}
TList * TQTaggable::getListOfTagNames() {
TList* l = new TList();
if (!fTags) return l;
TQValueIterator itr(fTags);
while(itr.hasNext()){
TQValue* v = itr.readNext();
TObjString* s = new TObjString(v->GetName());
l->Add(s);
}
l->SetOwner(true);
return l;
}
TQTaggable * TQTaggable::parseParameterList(const TString& parameter, const TString& sep, bool trim, const TString& blocks, const TString& quotes) {
TQTaggable * pars = new TQTaggable();
int i = 0;
bool error = false;
TQIterator itr(TQStringUtils::tokenize(parameter, sep, trim, blocks, quotes), true);
while (itr.hasNext() && !error) {
TString thisPar = itr.readNext()->GetName();
if (!pars->importTagWithPrefix(thisPar, "", false, TString::Format("%d", i++))) {
error = true;
}
}
if (pars->getNTags() == 0 || error) {
delete pars;
pars = NULL;
}
return pars;
}
int TQTaggable::importTagsWithPrefix(TString tags, const TString& prefix,
bool overwrite, bool keepStringQuotes, TString fallbackKey) {
int nTags = 0;
TString tag;
bool stop = false;
while (!tags.IsNull() && !stop) {
tag.Clear();
int nChars = 0;
nChars += TQStringUtils::readUpTo(tags, tag, ",", "[]{}", "''\"\"");
nChars += TQStringUtils::removeLeading(tags, ",", 1);
stop = (nChars == 0);
TString probe = tag;
TString newPrefix;
TString block;
TQStringUtils::readBlanksAndNewlines(probe);
TQStringUtils::readToken(probe, newPrefix, getValidKeyCharacters());
TQStringUtils::readBlanksAndNewlines(probe);
int nBlockChar = TQStringUtils::readBlock(probe, block, "[]{}", "''\"\"");
TQStringUtils::readBlanksAndNewlines(probe);
if (!newPrefix.IsNull() && probe.IsNull() && nBlockChar > 0)
nTags += importTagsWithPrefix(block, prefix + newPrefix, overwrite, keepStringQuotes);
else
nTags += importTagWithPrefix(tag, prefix, overwrite, fallbackKey, keepStringQuotes);
}
return nTags;
}
int TQTaggable::importTags(TString tags, bool overwrite, bool keepStringQuotes) {
return importTagsWithPrefix(tags, "", overwrite, keepStringQuotes);
}
int TQTaggable::importTagsWithPrefix(const TQTaggable * tags, const TString& prefix, bool overwrite, bool recursive, TString fallbackKey) {
if(!tags) return 0;
return this->importTagsWithPrefix(*tags,prefix,overwrite,recursive, fallbackKey);
}
int TQTaggable::importTagsWithPrefix(const TQTaggable& tags, const TString& prefix, bool overwrite, bool recursive, TString fallbackKey) {
int nTags = 0;
TQIterator itr(tags.fTags);
while (itr.hasNext()){
TQValue* val = dynamic_cast<TQValue*>(itr.readNext());
if(!val) continue;
if (overwrite || !hasTag(val->getNameConst())) {
TQValue * newTag = 0;
if (prefix.IsNull())
newTag = val->copy();
else
newTag = val->copy(prefix + val->getName());
int nSubTags = setTag(newTag);
if (nSubTags > 0)
nTags += nSubTags;
else
delete newTag;
}
}
if (recursive) {
TQTaggable * base = tags.getBaseTaggable();
nTags += importTagsWithPrefix(base, prefix, false, true, fallbackKey);
}
return nTags;
}
int TQTaggable::importTagsWithoutPrefix(const TQTaggable& tags, const TString& prefix, bool overwrite, bool recursive) {
int nTags = 0;
TQValueIterator itr(tags.fTags);
while (itr.hasNext()){
TQValue* val = itr.readNext();
if(!val) continue;
if (overwrite || !this->hasTag(val->getNameConst())) {
TQValue * newTag = 0;
if (prefix.IsNull())
newTag = val->copy();
else {
TString name(val->getNameConst());
if(TQStringUtils::removeLeadingText(name,prefix)){
newTag = val->copy(name);
}
}
int nSubTags = setTag(newTag);
if (nSubTags > 0)
nTags += nSubTags;
else
delete newTag;
}
}
if (recursive) {
TQTaggable * base = tags.getBaseTaggable();
nTags += importTagsWithoutPrefix(base, prefix, false, true);
}
return nTags;
}
int TQTaggable::importTagsWithoutPrefix(const TQTaggable* tags, const TString& prefix, bool overwrite, bool recursive) {
if(!tags) return 0;
return this->importTagsWithoutPrefix(*tags,prefix,overwrite,recursive);
}
TList* TQTaggable::makeListOfTags(TList* unTags){
TList* tags = new TList();
if (!unTags)
return NULL;
TQIterator itr(unTags);
while (itr.hasNext()){
TObject * obj = itr.readNext();
TQValue * newTag = NULL;
TQValue* oldTag = dynamic_cast<TQValue*>(obj);
if(oldTag)
tags->Add(oldTag->copy());
if (obj->InheritsFrom(TNamed::Class()))
newTag = TQValue::newString(
obj->GetName(), ((TNamed*)obj)->GetTitle());
else if (obj->InheritsFrom(TParameter<double>::Class()))
newTag = TQValue::newDouble(
obj->GetName(), ((TParameter<double>*)obj)->GetVal());
else if (obj->InheritsFrom(TParameter<int>::Class()))
newTag = TQValue::newInteger(
obj->GetName(), ((TParameter<int>*)obj)->GetVal());
else if (obj->InheritsFrom(TParameter<float>::Class()))
newTag = TQValue::newBool(
obj->GetName(), ((TParameter<float>*)obj)->GetVal() != 0.);
if(newTag){
tags->Add(newTag);
}
delete obj;
}
return tags;
}
int TQTaggable::importTags(const TQTaggable * tags, bool overwrite, bool recursive) {
return importTagsWithPrefix(tags, "", overwrite, recursive);
}
int TQTaggable::importTags(std::shared_ptr<TQTaggable> tags, bool overwrite, bool recursive) {
return importTagsWithPrefix(tags.get(), "", overwrite, recursive);
}
int TQTaggable::importTags(const TQTaggable& tags, bool overwrite, bool recursive) {
return importTagsWithPrefix(&tags, "", overwrite, recursive);
}
int TQTaggable::importTagWithPrefix(const TString& tagBackup, const TString& prefix,
bool overwrite, TString fallbackKey, bool keepStringQuotes) {
TString tag(tagBackup);
TString key = prefix;
TQStringUtils::readBlanksAndNewlines(tag);
int nKey = TQStringUtils::readToken(tag, key, getValidKeyCharacters());
TString assign;
TQStringUtils::readBlanksAndNewlines(tag);
TQStringUtils::readToken(tag, assign, "=");
bool usingFallbackKey = false;
if (nKey == 0 || assign.CompareTo("=") != 0) {
if (fallbackKey.IsNull()) {
return 0;
} else {
key = fallbackKey;
tag = tagBackup;
usingFallbackKey = true;
}
}
TQStringUtils::readBlanksAndNewlines(tag);
if (usingFallbackKey && tag.IsNull()) {
return 0;
}
if (!overwrite && hasTag(key))
return 0;
TString val;
bool singleQuotes = (TQStringUtils::readBlock(tag, val, "''") > 0);
bool doubleQuotes = false;
if (!singleQuotes) {
doubleQuotes = (TQStringUtils::readBlock(tag, val, "\"\"") > 0);
}
if (singleQuotes || doubleQuotes) {
val = TQStringUtils::trim(val);
if (keepStringQuotes) {
if (singleQuotes) {
val = TString("'") + val + "'";
} else if (doubleQuotes) {
val = TString("\"") + val + "\"";
}
}
return setTagString(key, val);
}
if (TQStringUtils::readBlock(tag, val, "{}", "''\"\"") > 0) {
return this->setTagList(key,val);
}
val = TQStringUtils::trim(tag);
if (TQStringUtils::isDouble(val)) {
return setTagDouble(key, val.Atof());
} else if (TQStringUtils::isInteger(val)) {
return setTagInteger(key, (int)val.Atof());
} else if (TQStringUtils::isBool(val)) {
return setTagBool(key, TQStringUtils::getBoolFromString(val));
} else if (val.CompareTo("!") == 0) {
if (removeTag(key)) {
return 1;
}
} else {
return setTagString(key, val);
}
return 0;
}
int TQTaggable::importTag(TString tag, bool overwrite, bool keepStringQuotes) {
return importTagWithPrefix(tag, "", overwrite, keepStringQuotes);
}
int TQTaggable::setTag(const TString& key, const TString& value, const TString& destination) {
return setTagString(key, value, destination);
}
int TQTaggable::setTag(const TString& key, const char* value, const TString& destination) {
TString s(value);
return setTagString(key, s, destination);
}
int TQTaggable::setTag(const TString& key, double value, const TString& destination) {
return setTagDouble(key, value, destination);
}
int TQTaggable::setTag(const TString& key, int value, const TString& destination) {
return setTagInteger(key, value, destination);
}
int TQTaggable::setTag(const TString& key, bool value, const TString& destination) {
return setTagBool(key, value, destination);
}
int TQTaggable::setTag(const char* key, const TString& value, const TString& destination) {
return setTagString(key, value, destination);
}
int TQTaggable::setTag(const char* key, const char* value, const TString& destination) {
TString s(value);
return setTagString(key, s, destination);
}
int TQTaggable::setTag(const char* key, double value, const TString& destination) {
return setTagDouble(key, value, destination);
}
int TQTaggable::setTag(const char* key, int value, const TString& destination) {
return setTagInteger(key, value, destination);
}
int TQTaggable::setTag(const char* key, bool value, const TString& destination) {
return setTagBool(key, value, destination);
}
bool TQTaggable::hasTagWithIndex(const TString& key){
TQIterator itr(getListOfKeys(key + ".*"), true);
while (itr.hasNext()){
TString listKeyName = itr.readNext()->GetName();
TQStringUtils::removeLeadingText(listKeyName, key + ".");
std::vector<TString> splitKey = TQStringUtils::split(listKeyName, ".");
if (splitKey.size() > 0 && TQStringUtils::isInteger(splitKey[0])){
return true;
}
}
return false;
}
bool TQTaggable::hasTagWithoutIndex(const TString& key){
std::vector<TString> splitKey = TQStringUtils::split(key, ".");
if (splitKey.size() > 1 && TQStringUtils::isInteger(splitKey[splitKey.size()-1])){
TString keyWithoutIndex = TQStringUtils::merge(splitKey, ".", 0, splitKey.size()-1);
return claimTags(keyWithoutIndex);
}
return false;
}
bool TQTaggable::canSetThisTag(const TString& key, bool& treatAsList){
treatAsList = false;
bool alreadyDefined = claimTags(key);
bool alreadyDefinedWithIndex = hasTagWithIndex(key);
bool alreadyDefinedWithoutIndex = hasTagWithoutIndex(key);
if (alreadyDefinedWithIndex)
treatAsList = true;
DEBUGclass("key: %s", key.Data());
DEBUGclass("alreadyDefined: %s", alreadyDefined ? "true" : "false");
DEBUGclass("alreadyDefinedWithIndex: %s", alreadyDefinedWithIndex ? "true" : "false");
DEBUGclass("alreadyDefinedWithoutIndex: %s", alreadyDefinedWithoutIndex ? "true" : "false");
DEBUGclass("treatAsList: %s", treatAsList ? "true" : "false");
if (getGlobalOverwrite())
return true;
if (alreadyDefined || alreadyDefinedWithoutIndex)
return false;
return true;
}
int TQTaggable::setTagAuto(const TString& key, TString value, const TString& destination) {
TString val;
int nTags = 0;
if ((TQStringUtils::readBlock(value, val, "''")) > 0 || (TQStringUtils::readBlock(value, val, "\"\"") > 0)) {
val = TQStringUtils::trim(val);
if (!val.IsNull()) {
nTags = setTagString(key, val);
}
return nTags;
}
bool enclosedInBrackets = TQStringUtils::readBlock(value, val, "{}", "''\"\"");
bool b = false;
if (!enclosedInBrackets){
val = TQStringUtils::trim(value);
b = TQStringUtils::findFree(val,',',"()[]{}") <(size_t)val.Length();
}
bool isList = (enclosedInBrackets || b);
bool treatAsList = false;
if (!canSetThisTag(key, treatAsList))
return nTags;
if (isList or treatAsList) {
nTags = this->setTagList(key,val);
if (enclosedInBrackets or treatAsList)
return nTags;
}
if(nTags > 0) return nTags;
if (TQStringUtils::isDouble(val)) {
nTags = setTagDouble(key, val.Atof(), destination);
} else if (TQStringUtils::isInteger(val)) {
nTags = setTagInteger(key, (int)val.Atof(), destination);
} else if (TQStringUtils::isBool(val)) {
nTags = setTagBool(key, TQStringUtils::getBoolFromString(val), destination);
} else if (val.CompareTo("!") == 0) {
if (removeTag(key)) {
nTags++;
}
} else {
nTags = setTagString(key, val, destination);
}
return nTags;
}
int TQTaggable::setTagList(const TString& key, TString value, const TString& destination){
TQTaggable * list = TQTaggable::parseParameterList(value, ",", true, "{}()[]", "''\"\"");
if (!list) return 0;
int nTags = 0;
TQValue * val = NULL;
if(fGlobalOverwrite){
int i = 0;
while(removeTag(TString::Format("%s.%d",key.Data(),i))){
++i;
}
}
TQIterator itr(list->getListOfKeys(), true);
while (itr.hasNext()) {
TString listKeyName = itr.readNext()->GetName();
list->getTag(listKeyName, val);
nTags += setTag(val->copy(key + "." + listKeyName), destination);
}
delete list;
return nTags;
}
template<class T>
int TQTaggable::setTagList(const TString& key, const std::vector<T>& list, const TString& destination){
int nTags = 0;
for(const auto& x:list){
nTags += this->setTag(TString::Format("%s.%d",key.Data(),nTags), x, destination);
}
return nTags;
}
template int TQTaggable::setTagList<bool>(const TString& key, const std::vector<bool>& list, const TString& destination);
template int TQTaggable::setTagList<int>(const TString& key, const std::vector<int>& list, const TString& destination);
template int TQTaggable::setTagList<double>(const TString& key, const std::vector<double>& list, const TString& destination);
template int TQTaggable::setTagList<TString>(const TString& key, const std::vector<TString>& list, const TString& destination);
template int TQTaggable::setTagList<const char*>(const TString& key, const std::vector<const char*>& list, const TString& destination);
int TQTaggable::setTagDouble(TString key, double value, const TString& destination) {
bool dontOverwrite = TQStringUtils::removeTrailing(key, "?", 1);
TQValue * tag = TQValue::newDouble(key, value);
if (!tag)
return 0;
int nTags = setTag(tag, destination, this->getGlobalOverwrite() && !dontOverwrite);
if (nTags == 0)
delete tag;
return nTags;
}
int TQTaggable::setTagInteger(TString key, int value, const TString& destination) {
bool dontOverwrite = TQStringUtils::removeTrailing(key, "?", 1);
TQValue * tag = TQValue::newInteger(key, value);
if (!tag)
return 0;
int nTags = setTag(tag, destination, this->getGlobalOverwrite() && !dontOverwrite);
if (nTags == 0)
delete tag;
return nTags;
}
int TQTaggable::setTagBool(TString key, bool value, const TString& destination) {
bool dontOverwrite = TQStringUtils::removeTrailing(key, "?", 1);
TQValue * tag = TQValue::newBool(key, value);
if (!tag)
return 0;
int nTags = setTag(tag, destination, this->getGlobalOverwrite() && !dontOverwrite);
if (nTags == 0)
delete tag;
return nTags;
}
int TQTaggable::setTagString(TString key, const TString& value, const TString& destination) {
bool dontOverwrite = TQStringUtils::removeTrailing(key, "?", 1);
TQValue * tag = TQValue::newString(key, value);
if (!tag)
return 0;
int nTags = setTag(tag, destination, this->getGlobalOverwrite() && !dontOverwrite);
if (nTags == 0)
delete tag;
return nTags;
}
int TQTaggable::exportTags(TQTaggable * dest, const TString& subDest, const TString& filter, bool recursive) {
if (!dest)
return 0;
int nTags = 0;
TQIterator itr(fTags);
while (itr.hasNext()){
TQValue* val = dynamic_cast<TQValue*>(itr.readNext());
if(!val) continue;
if (!filter.IsNull() && !TQStringUtils::matchesFilter(val->GetName(), filter, ",", true)) {
continue;
}
TQValue* newTag = val->copy();
if (dest->setTag(newTag, subDest, dest->getGlobalOverwrite()))
nTags++;
}
if(recursive && this->getBaseTaggable()){
nTags += this->getBaseTaggable()->exportTags(dest,subDest,filter,recursive);
}
return nTags;
}
TString TQTaggable::exportTagsAsString(const TString& filter, bool xmlStyle) {
TString result;
bool first = true;
TQIterator itr(fTags);
while(itr.hasNext()){
TQValue* val = dynamic_cast<TQValue*>(itr.readNext());
if(!val) continue;
if (!filter.IsNull() && !TQStringUtils::matchesFilter(val->GetName(), filter, ",", true)) {
continue;
}
if (!first) {
if (xmlStyle)
result.Append(" ");
else
result.Append(", ");
}
first = false;
result.Append(val->getAsString(xmlStyle));
}
return result;
}
TString TQTaggable::exportTagsAsConfigString(const TString& prefix, const TString& filter){
TString result;
TQIterator itr(fTags);
while(itr.hasNext()){
TQValue* val = dynamic_cast<TQValue*>(itr.readNext());
if(!val) continue;
if (!filter.IsNull() && !TQStringUtils::matchesFilter(val->GetName(), filter, ",", true)) {
continue;
}
result.Append(prefix);
result.Append(val->getName());
result.Append(": ");
result.Append(val->getValueAsString());
result.Append("\n");
}
return result;
}
TString TQTaggable::replaceInText(const TString& in, const TString& prefix, bool keepQuotes) {
int nReplaced = 0;
int nFailed = 0;
return replaceInText(in, nReplaced, nFailed, prefix, keepQuotes);
}
TString TQTaggable::replaceInTextRecursive(TString in, const TString& prefix, bool keepQuotes) {
int nReplaced = 0;
int nFailed = 0;
while(true){
in = replaceInText(in, nReplaced, nFailed, prefix, keepQuotes);
if(nReplaced == 0) return in;
}
}
TString TQTaggable::replaceInText(const TString& in, const char* prefix, bool keepQuotes){
return this->replaceInText(in,(TString)prefix,keepQuotes);
}
TString TQTaggable::replaceInText(const TString& in, bool keepQuotes) {
return replaceInText(in, "", keepQuotes);
}
TString TQTaggable::replaceInText(const TString& in, int &nReplaced, int &nFailed, bool keepQuotes) {
return this->replaceInText(in, nReplaced, nFailed, "", keepQuotes);
}
TString TQTaggable::replaceInText(TString in, int &nReplaced, int &nFailed, const TString& prefix, bool keepQuotes) {
TString out;
nReplaced = 0;
nFailed = 0;
while (!in.IsNull()) {
TQStringUtils::readUpTo(in, out, "$");
if (in.IsNull())
continue;
TString field;
int nMarker = TQStringUtils::readToken(in, field, "$");
TString def;
int nDef = 0;
if (in.BeginsWith("(")) {
nDef = TQStringUtils::readBlock(in, def, "()[]{}", "''\"\"");
if (nDef > 0)
field.Append(TString::Format("(%s)", def.Data()));
} else {
nDef = TQStringUtils::readToken(in, def, getValidKeyCharacters());
if (nDef > 0)
field.Append(def);
}
if (!def.IsNull()) {
TString keyName = prefix;
TQStringUtils::readUpTo(def, keyName, ",");
TQTaggable tmpTags;
bool missingOptions = false;
if (!def.IsNull()) {
TQStringUtils::removeLeading(def, ",", 1);
missingOptions = (tmpTags.importTagWithPrefix(
def, "", false, "default") == 0);
}
bool hasMatchingTag = hasTag(keyName);
if (nMarker == 1 && !keyName.IsNull() && !missingOptions &&
(hasMatchingTag || tmpTags.hasTag("default"))) {
TString tag;
if (hasMatchingTag) {
if (keepQuotes && tagIsOfTypeString(keyName))
getValueOfTagAsString(keyName, tag);
else
getTagString(keyName, tag);
} else {
if (keepQuotes && tmpTags.tagIsOfTypeString("default"))
tmpTags.getValueOfTagAsString("default", tag);
else
tmpTags.getTagString("default", tag);
}
out.Append(tag);
nReplaced++;
} else {
nFailed++;
out.Append(field);
}
} else {
nFailed++;
out.Append(field);
}
}
return out;
}
TString TQTaggable::getValuesOfTags(const TString& keys, const TString& sep) {
TString values;
TQIterator itr(this->getListOfKeys(keys), true);
while (itr.hasNext()) {
TQStringUtils::append(values, this->getTagStringDefault(itr.readNext()->GetName()), sep);
}
return values;
}
std::vector<TString > TQTaggable::getTagVString(const TString& key){
std::vector<TString> vec;
this->getTag(key,vec);
return vec;
}
TList* TQTaggable::getTagList(const TString& key){
TList* l = new TList();
l->SetOwner(true);
this->getTag(key,l);
return l;
}
std::vector<int > TQTaggable::getTagVInt (const TString& key){
std::vector<int> vec;
this->getTag(key,vec);
return vec;
}
std::vector<int > TQTaggable::getTagVInteger(const TString& key){
std::vector<int> vec;
this->getTag(key,vec);
return vec;
}
std::vector<double> TQTaggable::getTagVDouble(const TString& key){
std::vector<double> vec;
this->getTag(key,vec);
return vec;
}
std::vector<bool > TQTaggable::getTagVBool (const TString& key){
std::vector<bool> vec;
this->getTag(key,vec);
return vec;
}
int TQTaggable::getTag(const TString& key, std::vector<TString>& vec){
int idx = 0;
TString entry;
while(this->getTag(TString::Format("%s.%d",key.Data(),idx),entry)){
vec.push_back(entry);
idx++;
}
if(idx==0 && this->hasTagString(key))
vec.push_back(this->getTagStringDefault(key,""));
return idx;
}
int TQTaggable::getTag(const TString& key, TList* l){
if(!l) return -1;
int idx = 0;
TString entry;
while(this->getTag(TString::Format("%s.%d",key.Data(),idx),entry)){
l->Add(new TObjString(entry));
idx++;
}
if(idx==0 && this->hasTagString(key))
l->Add(new TObjString(this->getTagStringDefault(key,"")));
return idx;
}
int TQTaggable::getTagListLength(const TString& key){
int idx = 0;
while(this->hasTag(TString::Format("%s.%d",key.Data(),idx))){
idx++;
}
if(idx==0 && this->hasTagString(key))
idx = 1;
return idx;
}
int TQTaggable::getTag(const TString& key, std::vector<double>& vec){
int idx = 0;
double entry;
while(this->getTag(TString::Format("%s.%d",key.Data(),idx),entry)){
vec.push_back(entry);
idx++;
}
if(idx==0 && this->hasTagDouble(key)){
vec.push_back(this->getTagDoubleDefault(key,0));
idx++;
}
return idx;
}
int TQTaggable::getTag(const TString& key, std::vector<int>& vec){
int idx = 0;
int entry;
while(this->getTag(TString::Format("%s.%d",key.Data(),idx),entry)){
vec.push_back(entry);
idx++;
}
if(idx==0 && this->hasTagInteger(key)){
vec.push_back(this->getTagIntegerDefault(key,0));
idx++;
}
return idx;
}
int TQTaggable::getTag(const TString& key, std::vector<bool>& vec){
int idx = 0;
bool entry;
while(this->getTag(TString::Format("%s.%d",key.Data(),idx),entry)){
vec.push_back(entry);
idx++;
}
if(idx==0 && this->hasTagBool(key)){
vec.push_back(this->getTagBoolDefault(key,false));
idx++;
}
return idx;
}
bool TQTaggable::getTag(const TString& key, double &value) {
return getTagDouble(key, value);
}
bool TQTaggable::getTag(const TString& key, int &value) {
return getTagInteger(key, value);
}
bool TQTaggable::getTag(const TString& key, bool &value) {
return getTagBool(key, value);
}
bool TQTaggable::getTag(const TString& key, TString &value) {
return getTagString(key, value);
}
bool TQTaggable::getTagDouble(const TString& key, double &value) {
TQValue * val = 0;
if (getTag(key, val) && val->isValidDouble()) {
value = val->getDouble();
onRead(val);
return true;
} else {
return false;
}
}
bool TQTaggable::getTagInteger(const TString& key, int &value) {
TQValue * val = 0;
if (getTag(key, val) && val->isValidInteger()) {
value = val->getInteger();
onRead(val);
return true;
} else {
return false;
}
}
bool TQTaggable::getTagBool(const TString& key, bool &value) {
TQValue * val = 0;
if (getTag(key, val) && val->isValidBool()) {
value = val->getBool();
onRead(val);
return true;
} else {
return false;
}
}
bool TQTaggable::getTagString(const TString& key, TString &value) {
TQValue * val = 0;
if (getTag(key, val)) {
value = val->getString();
onRead(val);
return true;
} else {
return false;
}
}
double TQTaggable::getTagDefault(const TString& key, double defaultVal) {
return getTagDoubleDefault(key, defaultVal);
}
int TQTaggable::getTagDefault(const TString& key, int defaultVal) {
return getTagIntegerDefault(key, defaultVal);
}
bool TQTaggable::getTagDefault(const TString& key, bool defaultVal) {
return getTagBoolDefault(key, defaultVal);
}
TString TQTaggable::getTagDefault(const TString& key, const TString& defaultVal) {
return getTagStringDefault(key, defaultVal);
}
TString TQTaggable::getTagDefault(const TString& key, const char* defaultVal) {
return getTagStringDefault(key, defaultVal);
}
double TQTaggable::getTagDoubleDefault(const TString& key, double defaultVal) {
double value = defaultVal;
getTagDouble(key, value);
return value;
}
int TQTaggable::getTagIntegerDefault(const TString& key, int defaultVal) {
int value = defaultVal;
getTagInteger(key, value);
return value;
}
bool TQTaggable::getTagBoolDefault(const TString& key, bool defaultVal) {
bool value = defaultVal;
getTagBool(key, value);
return value;
}
TString TQTaggable::getTagStringDefault(const TString& key, const TString& defaultVal) {
TString value = defaultVal;
getTagString(key, value);
return value;
}
bool TQTaggable::getTagAsString(const TString& key, TString &tag) {
TQValue * val = 0;
if (getTag(key, val)) {
tag = val->getAsString();
onRead(val);
return true;
} else {
return false;
}
}
bool TQTaggable::getTypeOfTagAsString(const TString& key, TString &type) {
TQValue * val = 0;
if (getTag(key, val)) {
type = val->getTypeAsString();
onRead(val);
return true;
} else {
return false;
}
}
bool TQTaggable::getValueOfTagAsString(const TString& key, TString &value) {
TQValue * val = 0;
if (getTag(key, val)) {
value = val->getValueAsString();
onRead(val);
return true;
} else {
return false;
}
}
TQTaggable::~TQTaggable() {
clear();
if (fReadFlags) {
delete fReadFlags;
}
}
bool TQTaggable::getTag (const TString& key, double &value, bool recursive){
if(recursive)
return this->getTag(TString::Format("~%s",key.Data()),value);
return this->getTag(key,value);
}
bool TQTaggable::getTag (const TString& key, int &value, bool recursive){
if(recursive)
return this->getTag(TString::Format("~%s",key.Data()),value);
return this->getTag(key,value);
}
bool TQTaggable::getTag (const TString& key, bool &value, bool recursive){
if(recursive)
return this->getTag(TString::Format("~%s",key.Data()),value);
return this->getTag(key,value);
}
bool TQTaggable::getTag (const TString& key, TString &value, bool recursive){
if(recursive)
return this->getTag(TString::Format("~%s",key.Data()),value);
return this->getTag(key,value);
}
bool TQTaggable::getTagDouble (const TString& key, double &value, bool recursive){
if(recursive)
return this->getTag(TString::Format("~%s",key.Data()),value);
return this->getTag(key,value);
}
bool TQTaggable::getTagInteger (const TString& key, int &value, bool recursive){
if(recursive)
return this->getTag(TString::Format("~%s",key.Data()),value);
return this->getTag(key,value);
}
bool TQTaggable::getTagBool (const TString& key, bool &value, bool recursive){
if(recursive)
return this->getTag(TString::Format("~%s",key.Data()),value);
return this->getTag(key,value);
}
bool TQTaggable::getTagString (const TString& key, TString &value, bool recursive){
if(recursive)
return this->getTag(TString::Format("~%s",key.Data()),value);
return this->getTag(key,value);
}
bool TQTaggable::exportConfigFile(const TString& filename, const TString& prefix, bool writeUnreadKeys){
TQUtils::ensureDirectoryForFile(filename);
std::ofstream of(filename);
if(!of.good()) return false;
TQValueIterator itr(fTags);
while (itr.hasNext()){
TQValue* val = itr.readNext();
TString key(val->GetName());
if(TQStringUtils::removeLeading(key,".") == 1){
TString value(val->getString());
of << "# " << key << ": " << value << std::endl;
}
}
itr.reset();
while (itr.hasNext()){
TQValue* val = itr.readNext();
TString key(val->GetName());
TString value(val->getString());
if(key.BeginsWith(".")) continue;
if(writeUnreadKeys || fReadFlags->FindObject(key)){
of << prefix << "." << key << ":" << "\t" << value << std::endl;
}
}
of.close();
return true;
}
bool TQTaggable::exportConfigFile(const TString& filename, bool writeUnreadKeys){
return this->exportConfigFile(filename, this->getTagStringDefault(".configname","Config"),writeUnreadKeys);
}
bool TQTaggable::exportConfigFile(bool writeUnreadKeys){
TString fname(this->getTagStringDefault(".filename","config.cfg"));
return this->exportConfigFile(TQFolder::getPathTail(fname), this->getTagStringDefault(".configname","Config"), writeUnreadKeys);
}
int TQTaggable::replaceInTags(TQTaggable& params, const TString& tagFilter) {
TList* lTags = this->getListOfKeys(tagFilter);
if (!lTags) return -1;
TIterator* itr = lTags->MakeIterator();
TObjString* ostr;
while ((ostr = (dynamic_cast<TObjString*>(itr->Next())))) {
if (!ostr) continue;
if (!this->tagIsOfTypeString(ostr->GetString())) continue;
this->setTagString(ostr->GetString(), this->replaceInText(params.replaceInText(this->getTagStringDefault(ostr->GetString(),""))));
}
delete lTags;
delete itr;
return 0;
}
std::string TQTaggable::exportTagsAsStandardString(const TString& filter, bool xmlStyle){
return this->exportTagsAsString(filter,xmlStyle).Data();
}
std::string TQTaggable::exportTagsAsStandardConfigString(const TString& prefix, const TString& filter){
return this->exportTagsAsConfigString(prefix,filter).Data();
}
std::string TQTaggable::replaceInStandardStringRecursive(TString in, const TString& prefix, bool keepQuotes){
return this->replaceInTextRecursive(in,prefix,keepQuotes).Data();
}
std::string TQTaggable::replaceInStandardString(const TString& in, const char* prefix, bool keepQuotes){
return this->replaceInText(in,prefix,keepQuotes).Data();
}
std::string TQTaggable::replaceInStandardString(const TString& in, const TString& prefix, bool keepQuotes){
return this->replaceInText(in,prefix,keepQuotes).Data();
}
std::string TQTaggable::replaceInStandardString(const TString& in, bool keepQuotes){
return this->replaceInText(in,keepQuotes).Data();
}
std::string TQTaggable::getTagStandardStringDefault (const TString& key, const TString& defaultVal){
return this->getTagStringDefault (key,defaultVal).Data();
}
std::vector<std::string > TQTaggable::getTagVStandardString (const TString& key){
std::vector<std::string> retval;
for(const auto& v:this->getTagVString (key)){
retval.push_back(v.Data());
}
return retval;
}
std::map<TString,std::shared_ptr<TQTaggable>> TQTaggable::sGlobalTaggables;
std::shared_ptr<TQTaggable> TQTaggable::getGlobalTaggable(const char* name) {
return TQTaggable::getGlobalTaggable(TString(name));
}
std::shared_ptr<TQTaggable> TQTaggable::getGlobalTaggable(const TString& name){
if (sGlobalTaggables.count(name) < 1) {
sGlobalTaggables[name] = std::make_shared<TQTaggable>();
}
return sGlobalTaggables[name];
}
bool TQTaggable::hasGlobalTaggable(const char* name) {
return TQTaggable::hasGlobalTaggable(TString(name));
}
bool TQTaggable::hasGlobalTaggable(const TString& name){
return sGlobalTaggables.count(name) > 0;
}
bool TQTaggable::removeGlobalTaggable(const char* name) {
return TQTaggable::removeGlobalTaggable(TString(name));
}
bool TQTaggable::removeGlobalTaggable(const TString& name){
return sGlobalTaggables.erase(name) > 0;
}