diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2021-10-15 11:16:22 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2021-10-15 11:16:22 +0900 |
commit | 558fa54c62ec59357cb5c40a411f16f1c1754f33 (patch) | |
tree | 9468f1b169143cbb375fc223ca2f78539a908085 /src/template.cpp | |
parent | ce6f802772f02771c3bf86ccf78d0fc1731947c5 (diff) | |
download | doxygen-558fa54c62ec59357cb5c40a411f16f1c1754f33.tar.gz doxygen-558fa54c62ec59357cb5c40a411f16f1c1754f33.tar.bz2 doxygen-558fa54c62ec59357cb5c40a411f16f1c1754f33.zip |
Imported Upstream version 1.9.2upstream/1.9.2
Diffstat (limited to 'src/template.cpp')
-rwxr-xr-x[-rw-r--r--] | src/template.cpp | 1660 |
1 files changed, 899 insertions, 761 deletions
diff --git a/src/template.cpp b/src/template.cpp index d5e8275..aeab71c 100644..100755 --- a/src/template.cpp +++ b/src/template.cpp @@ -15,26 +15,22 @@ #include "template.h" -#include <stdio.h> -#include <stdarg.h> - -#include <qlist.h> -#include <qarray.h> -#include <qdict.h> -#include <qstrlist.h> -#include <qvaluelist.h> -#include <qstack.h> -#include <qfile.h> -#include <qregexp.h> -#include <qcstring.h> -#include <qdir.h> - -#include "sortdict.h" -#include "ftextstream.h" +#include <vector> +#include <algorithm> +#include <unordered_map> +#include <deque> +#include <cstdio> +#include <fstream> +#include <sstream> + #include "message.h" #include "util.h" #include "resourcemgr.h" #include "portable.h" +#include "regex.h" +#include "fileinfo.h" +#include "dir.h" +#include "utf8.h" #define ENABLE_TRACING 0 @@ -102,40 +98,44 @@ static std::vector<QCString> split(const QCString &str,const QCString &sep, /** Strips spaces surrounding `=` from string \a in, so * `foo = 10 bar=5 baz= 'hello'` will become `foo=10 bar=5 baz='hello'` */ -static QCString removeSpacesAroundEquals(const char *s) +static void removeSpacesAroundEquals(QCString &s) { - QCString result(s); - const char *p=result.data(); - char *q = result.rawData(); - char c; - while ((c=*p++)) + //printf(">removeSpacesAroundEquals(%s)\n",qPrint(s)); + uint i=0, dstIdx=0, l=s.length(); + while (i<l) { - if (c==' ') // found a space, see if there is a = as well + char c = s[i++]; + if (c==' ') { - const char *t = p; - bool found=FALSE; - while (*t==' ' || *t=='=') { if (*t++=='=') found=TRUE; } - if (found) + bool found=false; + // look ahead for space or '=' + uint j=i; + while (j<l && (s[j]==' '|| s[j]=='=')) { - c='='; - p=t; // move p to end of '\s*=\s*' sequence + if (s[j]=='=') found=true; + j++; + } + if (found) // found a '=', write it without spaces + { + c = '='; + i=j; } } - *q++=c; + s[dstIdx++]=c; } - if (q<p) result.resize(q-result.data()+1); - return result; + s.resize(dstIdx+1); + //printf("<removeSpacesAroundEquals(%s)\n",qPrint(s)); } //---------------------------------------------------------------------------- #if ENABLE_TRACING -static QCString replace(const char *s,char csrc,char cdst) +static QCString replace(const QCString &s,char csrc,char cdst) { QCString result = s; - for (char *p=result.data();*p;p++) + for (uint i=0;i<result.length();i++) { - if (*p==csrc) *p=cdst; + if (result[i]==csrc) result[i]=cdst; } return result; } @@ -145,96 +145,121 @@ static QCString replace(const char *s,char csrc,char cdst) TemplateVariant::TemplateVariant(TemplateStructIntf *s) - : m_type(Struct), m_strukt(s), m_raw(FALSE) { - m_strukt->addRef(); + m_variant.set<TemplateStructIntf*>(s); + s->addRef(); } TemplateVariant::TemplateVariant(TemplateListIntf *l) - : m_type(List), m_list(l), m_raw(FALSE) { - m_list->addRef(); + m_variant.set<TemplateListIntf*>(l); + l->addRef(); } TemplateVariant::~TemplateVariant() { - if (m_type==Struct) m_strukt->release(); - else if (m_type==List) m_list->release(); + try + { + if (m_variant.is<TemplateStructIntf*>()) m_variant.get<TemplateStructIntf*>()->release(); + else if (m_variant.is<TemplateListIntf*>()) m_variant.get<TemplateListIntf*>()->release(); + } + catch(...) + { + // should never happen + } } TemplateVariant::TemplateVariant(const TemplateVariant &v) - : m_type(v.m_type), m_strukt(0), m_raw(FALSE) { - m_raw = v.m_raw; - switch (m_type) - { - case None: break; - case Bool: m_boolVal = v.m_boolVal; break; - case Integer: m_intVal = v.m_intVal; break; - case String: m_strVal = v.m_strVal; break; - case Struct: m_strukt = v.m_strukt; m_strukt->addRef(); break; - case List: m_list = v.m_list; m_list->addRef(); break; - case Function: m_delegate= v.m_delegate;break; - } + m_raw = v.m_raw; + m_variant = v.m_variant; + if (m_variant.is<TemplateStructIntf*>()) m_variant.get<TemplateStructIntf*>()->addRef(); + else if (m_variant.is<TemplateListIntf*>()) m_variant.get<TemplateListIntf*>()->addRef(); } -TemplateVariant &TemplateVariant::operator=(const TemplateVariant &v) +TemplateVariant::TemplateVariant(TemplateVariant &&v) { - // assignment can change the type of the variable, so we have to be - // careful with reference counted content. - TemplateStructIntf *tmpStruct = m_type==Struct ? m_strukt : 0; - TemplateListIntf *tmpList = m_type==List ? m_list : 0; - Type tmpType = m_type; + m_raw = std::move(v.m_raw); + m_variant = std::move(v.m_variant); + v.m_variant.invalidate(); +} - m_type = v.m_type; - m_raw = v.m_raw; - switch (m_type) +TemplateVariant &TemplateVariant::operator=(const TemplateVariant &v) +{ + if (this!=&v) { - case None: break; - case Bool: m_boolVal = v.m_boolVal; break; - case Integer: m_intVal = v.m_intVal; break; - case String: m_strVal = v.m_strVal; break; - case Struct: m_strukt = v.m_strukt; m_strukt->addRef(); break; - case List: m_list = v.m_list; m_list->addRef(); break; - case Function: m_delegate= v.m_delegate;break; + // assignment can change the type of the variable, so we have to be + // careful with reference counted content. + TemplateStructIntf *tmpStruct = m_variant.is<TemplateStructIntf*>() ? m_variant.get<TemplateStructIntf*>() : nullptr; + TemplateListIntf *tmpList = m_variant.is<TemplateListIntf*>() ? m_variant.get<TemplateListIntf*>() : nullptr; + + m_raw = v.m_raw; + m_variant = v.m_variant; + + if (m_variant.is<TemplateStructIntf*>()) m_variant.get<TemplateStructIntf*>()->addRef(); + else if (m_variant.is<TemplateListIntf*>()) m_variant.get<TemplateListIntf*>()->addRef(); + + // release overwritten reference counted values + if (tmpStruct) tmpStruct->release(); + else if (tmpList ) tmpList->release(); } + return *this; +} - // release overwritten reference counted values - if (tmpType==Struct && tmpStruct) tmpStruct->release(); - else if (tmpType==List && tmpList ) tmpList->release(); +TemplateVariant &TemplateVariant::operator=(TemplateVariant &&v) +{ + m_raw = std::move(v.m_raw); + m_variant = std::move(v.m_variant); + v.m_variant.invalidate(); return *this; } bool TemplateVariant::toBool() const { - switch (m_type) + switch (type()) { - case None: return FALSE; - case Bool: return m_boolVal; - case Integer: return m_intVal!=0; - case String: return !m_strVal.isEmpty(); - case Struct: return TRUE; - case List: return m_list->count()!=0; - case Function: return FALSE; + case Type::None: return false; + case Type::Bool: return m_variant.get<bool>(); + case Type::Int: return m_variant.get<int>()!=0; + case Type::String: return !m_variant.get<QCString>().isEmpty(); + case Type::Struct: return true; + case Type::List: return m_variant.get<TemplateListIntf*>()->count()!=0; + case Type::Function: return false; } return FALSE; } int TemplateVariant::toInt() const { - switch (m_type) + switch (type()) { - case None: return 0; - case Bool: return m_boolVal ? 1 : 0; - case Integer: return m_intVal; - case String: return m_strVal.toInt(); - case Struct: return 0; - case List: return m_list->count(); - case Function: return 0; + case Type::None: return 0; + case Type::Bool: return m_variant.get<bool>() ? 1 : 0; + case Type::Int: return m_variant.get<int>(); + case Type::String: return !m_variant.get<QCString>().toInt(); + case Type::Struct: return 0; + case Type::List: return m_variant.get<TemplateListIntf*>()->count(); + case Type::Function: return 0; } return 0; } +QCString TemplateVariant::toString() const +{ + switch (type()) + { + case Type::None: return QCString(); + case Type::Bool: return m_variant.get<bool>() ? "true" : "false"; + case Type::Int: return QCString().setNum(m_variant.get<int>()); + case Type::String: return m_variant.get<QCString>(); + case Type::Struct: return structToString(); + case Type::List: return listToString(); + case Type::Function: return "[function]"; + } + return QCString(); +} + + //- Template struct implementation -------------------------------------------- @@ -242,9 +267,8 @@ int TemplateVariant::toInt() const class TemplateStruct::Private { public: - Private() : fields(17), refCount(0) - { fields.setAutoDelete(TRUE); } - QDict<TemplateVariant> fields; + Private() : refCount(0) {} + std::unordered_map<std::string,TemplateVariant> fields; int refCount = 0; }; @@ -273,23 +297,34 @@ int TemplateStruct::release() return count; } -void TemplateStruct::set(const char *name,const TemplateVariant &v) +void TemplateStruct::set(const QCString &name,const TemplateVariant &v) { - TemplateVariant *pv = p->fields.find(name); - if (pv) // change existing field + auto it = p->fields.find(name.str()); + if (it!=p->fields.end()) // change existing field { - *pv = v; + it->second = v; } else // insert new field { - p->fields.insert(name,new TemplateVariant(v)); + p->fields.insert(std::make_pair(name.str(),v)); } } -TemplateVariant TemplateStruct::get(const char *name) const +TemplateVariant TemplateStruct::get(const QCString &name) const { - TemplateVariant *v = p->fields.find(name); - return v ? *v : TemplateVariant(); + auto it = p->fields.find(name.str()); + return it!=p->fields.end() ? it->second : TemplateVariant(); +} + +StringVector TemplateStruct::fields() const +{ + StringVector result; + for (const auto &kv : p->fields) + { + result.push_back(kv.first); + } + std::sort(result.begin(),result.end()); + return result; } TemplateStruct *TemplateStruct::alloc() @@ -487,13 +522,14 @@ class TemplateBlockContext public: TemplateBlockContext(); TemplateNodeBlock *get(const QCString &name) const; - TemplateNodeBlock *pop(const QCString &name) const; + TemplateNodeBlock *pop(const QCString &name); void add(TemplateNodeBlock *block); void add(TemplateBlockContext *ctx); void push(TemplateNodeBlock *block); void clear(); + using NodeBlockList = std::deque<TemplateNodeBlock*>; private: - QDict< QList<TemplateNodeBlock> > m_blocks; + std::map< std::string, NodeBlockList > m_blocks; }; /** @brief A container to store a key-value pair */ @@ -516,7 +552,8 @@ class TemplateContextImpl : public TemplateContext // TemplateContext methods void push(); void pop(); - void set(const char *name,const TemplateVariant &v); + void set(const QCString &name,const TemplateVariant &v); + void update(const QCString &name,const TemplateVariant &v); TemplateVariant get(const QCString &name) const; const TemplateVariant *getRef(const QCString &name) const; void setOutputDirectory(const QCString &dir) @@ -524,11 +561,12 @@ class TemplateContextImpl : public TemplateContext void setEscapeIntf(const QCString &ext,TemplateEscapeIntf *intf) { int i=(!ext.isEmpty() && ext.at(0)=='.') ? 1 : 0; - m_escapeIntfDict.insert(ext.mid(i),new TemplateEscapeIntf*(intf)); + m_escapeIntfMap.insert(std::make_pair(ext.mid(i).str(),intf)); } void selectEscapeIntf(const QCString &ext) - { TemplateEscapeIntf **ppIntf = m_escapeIntfDict.find(ext); - m_activeEscapeIntf = ppIntf ? *ppIntf : 0; + { + auto it = m_escapeIntfMap.find(ext.str()); + m_activeEscapeIntf = it!=m_escapeIntfMap.end() ? it->second : 0; } void setActiveEscapeIntf(TemplateEscapeIntf *intf) { m_activeEscapeIntf = intf; } void setSpacelessIntf(TemplateSpacelessIntf *intf) { m_spacelessIntf = intf; } @@ -555,7 +593,7 @@ class TemplateContextImpl : public TemplateContext QCString encoding() const { return m_encoding; } void setEncoding(const QCString &file,int line,const QCString &enc); QCString recode(const QCString &s); - void warn(const char *fileName,int line,const char *fmt,...) const; + void warn(const QCString &fileName,int line,const char *fmt,...) const; // index related functions void openSubIndex(const QCString &indexName); @@ -567,15 +605,15 @@ class TemplateContextImpl : public TemplateContext QCString m_templateName; int m_line = 0; QCString m_outputDir; - QList< QDict<TemplateVariant> > m_contextStack; + std::deque< std::map<std::string,TemplateVariant> > m_contextStack; TemplateBlockContext m_blockContext; - QDict<TemplateEscapeIntf*> m_escapeIntfDict; + std::unordered_map<std::string, TemplateEscapeIntf*> m_escapeIntfMap; TemplateEscapeIntf *m_activeEscapeIntf = 0; TemplateSpacelessIntf *m_spacelessIntf = 0; bool m_spacelessEnabled = false; bool m_tabbingEnabled = false; TemplateAutoRef<TemplateStruct> m_indices; - QDict< QStack<TemplateVariant> > m_indexStacks; + std::unordered_map< std::string, std::stack<TemplateVariant> > m_indexStacks; QCString m_encoding; void *m_fromUtf8 = 0; }; @@ -588,12 +626,11 @@ class FilterAdd public: static int variantIntValue(const TemplateVariant &v,bool &isInt) { - isInt = v.type()==TemplateVariant::Integer; - if (!isInt && v.type()==TemplateVariant::String) + if (!v.isInt() && v.isString()) { return v.toString().toInt(&isInt); } - return isInt ? v.toInt() : 0; + return v.isInt() ? v.toInt() : 0; } static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &arg) { @@ -609,7 +646,7 @@ class FilterAdd { return lhsValue+rhsValue; } - else if (v.type()==TemplateVariant::String && arg.type()==TemplateVariant::String) + else if (v.isString() && arg.isString()) { return TemplateVariant(v.toString() + arg.toString()); } @@ -628,15 +665,15 @@ class FilterGet public: static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &arg) { - if (v.isValid() && v.type()==TemplateVariant::Struct && arg.type()==TemplateVariant::String) + if (v.isValid() && v.isStruct() && arg.isString()) { TemplateVariant result = v.toStruct()->get(arg.toString()); - //printf("\nok[%s]=%d\n",arg.toString().data(),result.type()); + //printf("\nok[%s]=%d\n",qPrint(arg.toString()),result.type()); return result; } else { - //printf("\nnok[%s]\n",arg.toString().data()); + //printf("\nnok[%s]\n",qPrint(arg.toString())); return FALSE; } } @@ -650,7 +687,7 @@ class FilterRaw public: static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &) { - if (v.isValid() && (v.type()==TemplateVariant::String || v.type()==TemplateVariant::Integer)) + if (v.isValid() && (v.isString() || v.isInt())) { return TemplateVariant(v.toString(),TRUE); } @@ -663,6 +700,46 @@ class FilterRaw //----------------------------------------------------------------------------- +/** @brief The implementation of the "keep" filter */ +class FilterKeep +{ + public: + static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &args) + { + if (v.isValid() && v.isList() && args.isString()) + { + //printf("FilterKeep::apply: v=%s args=%s\n",qPrint(v.toString()),qPrint(args.toString())); + TemplateListIntf::ConstIterator *it = v.toList()->createIterator(); + + TemplateList *result = TemplateList::alloc(); + TemplateVariant item; + for (it->toFirst();(it->current(item));it->toNext()) + { + //printf("item type=%s\n",item.typeAsString()); + TemplateStructIntf *s = item.toStruct(); + if (s) + { + TemplateVariant value = s->get(args.toString()); + //printf("value type=%s\n",value.typeAsString()); + if (value.toBool()) + { + //printf("keeping it\n"); + result->append(item); + } + else + { + //printf("Dropping it\n"); + } + } + } + return result; + } + return v; + } +}; + +//----------------------------------------------------------------------------- + /** @brief The implementation of the "list" filter */ class FilterList { @@ -671,7 +748,7 @@ class FilterList { if (v.isValid()) { - if (v.type()==TemplateVariant::List) // input is already a list + if (v.isList()) // input is already a list { return v; } @@ -694,7 +771,7 @@ class FilterTexLabel public: static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &) { - if (v.isValid() && (v.type()==TemplateVariant::String)) + if (v.isValid() && (v.isString())) { return TemplateVariant(latexEscapeLabelName(v.toString()),TRUE); } @@ -713,7 +790,7 @@ class FilterTexIndex public: static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &) { - if (v.isValid() && (v.type()==TemplateVariant::String)) + if (v.isValid() && (v.isString())) { return TemplateVariant(latexEscapeIndexChars(v.toString()),TRUE); } @@ -732,8 +809,8 @@ class FilterAppend public: static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &arg) { - if ((v.type()==TemplateVariant::String || v.type()==TemplateVariant::Integer) && - (arg.type()==TemplateVariant::String || arg.type()==TemplateVariant::Integer)) + if ((v.isString() || v.isInt()) && + (arg.isString() || arg.isInt())) { return TemplateVariant(v.toString() + arg.toString()); } @@ -752,8 +829,8 @@ class FilterPrepend public: static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &arg) { - if ((v.type()==TemplateVariant::String || v.type()==TemplateVariant::Integer) && - arg.type()==TemplateVariant::String) + if ((v.isString() || v.isInt()) && + arg.isString()) { return TemplateVariant(arg.toString() + v.toString()); } @@ -776,11 +853,11 @@ class FilterLength { return TemplateVariant(); } - if (v.type()==TemplateVariant::List) + if (v.isList()) { return TemplateVariant((int)v.toList()->count()); } - else if (v.type()==TemplateVariant::String) + else if (v.isString()) { return TemplateVariant((int)v.toString().length()); } @@ -803,7 +880,7 @@ class FilterDefault { return arg; } - else if (v.type()==TemplateVariant::String && v.toString().isEmpty()) + else if (v.isString() && v.toString().isEmpty()) { return arg; } @@ -822,7 +899,7 @@ class FilterFlatten public: static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &) { - if (!v.isValid() || v.type()!=TemplateVariant::List) + if (!v.isValid() || !v.isList()) { return v; } @@ -835,7 +912,7 @@ class FilterFlatten } private: - static void flatten(TemplateListIntf *tree,TemplateList *list) + static void flatten(const TemplateListIntf *tree,TemplateList *list) { TemplateListIntf::ConstIterator *it = tree->createIterator(); TemplateVariant item; @@ -847,7 +924,7 @@ class FilterFlatten list->append(item); // if s has "children" then recurse into the children TemplateVariant children = s->get("children"); - if (children.isValid() && children.type()==TemplateVariant::List) + if (children.isValid() && children.isList()) { flatten(children.toList(),list); } @@ -872,50 +949,42 @@ class FilterListSort QCString key; TemplateVariant value; }; - class SortList : public QList<ListElem> - { - public: - SortList() { setAutoDelete(TRUE); } - private: - int compareValues(const ListElem *item1,const ListElem *item2) const - { - return qstrcmp(item1->key,item2->key); - } - }; public: static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &args) { - if (v.type()==TemplateVariant::List && args.type()==TemplateVariant::String) + if (v.isList() && args.isString()) { - //printf("FilterListSort::apply: v=%s args=%s\n",v.toString().data(),args.toString().data()); + //printf("FilterListSort::apply: v=%s args=%s\n",qPrint(v.toString()),qPrint(args.toString())); TemplateListIntf::ConstIterator *it = v.toList()->createIterator(); TemplateVariant item; TemplateList *result = TemplateList::alloc(); // create list of items based on v using the data in args as a sort key + using SortList = std::vector<ListElem>; SortList sortList; + sortList.reserve(v.toList()->count()); for (it->toFirst();(it->current(item));it->toNext()) { TemplateStructIntf *s = item.toStruct(); if (s) { QCString sortKey = determineSortKey(s,args.toString()); - sortList.append(new ListElem(sortKey,item)); - //printf("sortKey=%s\n",sortKey.data()); + sortList.emplace_back(sortKey,item); + //printf("sortKey=%s\n",qPrint(sortKey)); } } delete it; // sort the list - sortList.sort(); + std::sort(sortList.begin(), + sortList.end(), + [](const auto &lhs,const auto &rhs) { return lhs.key < rhs.key; }); // add sorted items to the result list - QListIterator<ListElem> sit(sortList); - ListElem *elem; - for (sit.toFirst();(elem=sit.current());++sit) + for (const auto &elem : sortList) { - result->append(elem->value); + result->append(elem.value); } return result; } @@ -935,7 +1004,7 @@ class FilterListSort { QCString var = arg.mid(i+2,j-i-2); TemplateVariant val=s->get(var); - //printf("found argument %s value=%s\n",var.data(),val.toString().data()); + //printf("found argument %s value=%s\n",qPrint(var),qPrint(val.toString())); result+=val.toString(); p=j+2; } @@ -960,58 +1029,50 @@ class FilterGroupBy QCString key; TemplateVariant value; }; - class SortList : public QList<ListElem> - { - public: - SortList() { setAutoDelete(TRUE); } - private: - int compareValues(const ListElem *item1,const ListElem *item2) const - { - return qstrcmp(item1->key,item2->key); - } - }; public: static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &args) { - if (v.type()==TemplateVariant::List && args.type()==TemplateVariant::String) + if (v.isList() && args.isString()) { - //printf("FilterListSort::apply: v=%s args=%s\n",v.toString().data(),args.toString().data()); + //printf("FilterListSort::apply: v=%s args=%s\n",qPrint(v.toString()),qPrint(args.toString())); TemplateListIntf::ConstIterator *it = v.toList()->createIterator(); TemplateVariant item; TemplateList *result = TemplateList::alloc(); // create list of items based on v using the data in args as a sort key + using SortList = std::vector<ListElem>; SortList sortList; + sortList.reserve(v.toList()->count()); for (it->toFirst();(it->current(item));it->toNext()) { TemplateStructIntf *s = item.toStruct(); if (s) { QCString sortKey = determineSortKey(s,args.toString()); - sortList.append(new ListElem(sortKey,item)); - //printf("sortKey=%s\n",sortKey.data()); + sortList.emplace_back(sortKey,item); + //printf("sortKey=%s\n",qPrint(sortKey)); } } delete it; // sort the list - sortList.sort(); + std::sort(sortList.begin(), + sortList.end(), + [](const auto &lhs,const auto &rhs) { return lhs.key < rhs.key; }); // add sorted items to the result list - QListIterator<ListElem> sit(sortList); - ListElem *elem; TemplateList *groupList=0; QCString prevKey; - for (sit.toFirst();(elem=sit.current());++sit) + for (const auto &elem : sortList) { - if (groupList==0 || elem->key!=prevKey) + if (groupList==0 || elem.key!=prevKey) { groupList = TemplateList::alloc(); result->append(groupList); - prevKey = elem->key; + prevKey = elem.key; } - groupList->append(elem->value); + groupList->append(elem.value); } return result; } @@ -1034,7 +1095,7 @@ class FilterRelative public: static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &) { - if (v.isValid() && v.type()==TemplateVariant::String && v.toString().left(2)=="..") + if (v.isValid() && v.isString() && v.toString().left(2)=="..") { return TRUE; } @@ -1053,11 +1114,11 @@ class FilterPaginate public: static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &args) { - if (v.isValid() && v.type()==TemplateVariant::List && - args.isValid() && args.type()==TemplateVariant::Integer) + if (v.isValid() && v.isList() && + args.isValid() && args.isInt()) { int pageSize = args.toInt(); - TemplateListIntf *list = v.toList(); + const TemplateListIntf *list = v.toList(); TemplateList *result = TemplateList::alloc(); TemplateListIntf::ConstIterator *it = list->createIterator(); TemplateVariant item; @@ -1096,118 +1157,90 @@ class FilterAlphaIndex private: struct ListElem { - ListElem(uint k,const TemplateVariant &v) : key(k), value(v) {} - uint key; + ListElem(std::string k,const TemplateVariant &v) : key(k), value(v) {} + std::string key; TemplateVariant value; }; - class SortList : public QList<ListElem> + static QCString keyToLabel(const char *startLetter) { - public: - SortList() { setAutoDelete(TRUE); } - private: - int compareValues(const ListElem *item1,const ListElem *item2) const - { - return item1->key-item2->key; - } - }; - static QCString keyToLetter(uint startLetter) - { - return QString(QChar(startLetter)).utf8(); - } - static QCString keyToLabel(uint startLetter) - { - char s[11]; // 0x12345678 + '\0' - if ((startLetter>='0' && startLetter<='9') || - (startLetter>='a' && startLetter<='z') || - (startLetter>='A' && startLetter<='Z')) + //printf(">keyToLabel(%s)\n",qPrint(startLetter)); + const char *p = startLetter; + char c = *p; + QCString result; + if (c<127 && c>31) // printable ASCII character { - int i=0; - if (startLetter>='0' && startLetter<='9') s[i++] = 'x'; - s[i++]=(char)tolower((char)startLetter); - s[i++]=0; + result+=c; } else { + result="0x"; const char hex[]="0123456789abcdef"; - int i=0; - s[i++]='x'; - if (startLetter>(1<<24)) // 4 byte character - { - s[i++]=hex[(startLetter>>28)&0xf]; - s[i++]=hex[(startLetter>>24)&0xf]; - } - if (startLetter>(1<<16)) // 3 byte character - { - s[i++]=hex[(startLetter>>20)&0xf]; - s[i++]=hex[(startLetter>>16)&0xf]; - } - if (startLetter>(1<<8)) // 2 byte character + while ((c=*p++)) { - s[i++]=hex[(startLetter>>12)&0xf]; - s[i++]=hex[(startLetter>>8)&0xf]; + result+=hex[((unsigned char)c)>>4]; + result+=hex[((unsigned char)c)&0xf]; } - // one byte character - s[i++]=hex[(startLetter>>4)&0xf]; - s[i++]=hex[(startLetter>>0)&0xf]; - s[i++]=0; } - return s; + //printf("<keyToLabel(%s)\n",qPrint(result)); + return result; } - static uint determineSortKey(TemplateStructIntf *s,const QCString &attribName) + static std::string determineSortKey(TemplateStructIntf *s,const QCString &attribName) { TemplateVariant v = s->get(attribName); int index = getPrefixIndex(v.toString()); - return getUtf8CodeToUpper(v.toString(),index); + return convertUTF8ToUpper(getUTF8CharAt(v.toString().str(),index)); } public: static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &args) { - if (v.type()==TemplateVariant::List && args.type()==TemplateVariant::String) + if (v.isList() && args.isString()) { - //printf("FilterListSort::apply: v=%s args=%s\n",v.toString().data(),args.toString().data()); + //printf("FilterListSort::apply: v=%s args=%s\n",qPrint(v.toString()),qPrint(args.toString())); TemplateListIntf::ConstIterator *it = v.toList()->createIterator(); TemplateVariant item; TemplateList *result = TemplateList::alloc(); // create list of items based on v using the data in args as a sort key + using SortList = std::vector<ListElem>; SortList sortList; + sortList.reserve(v.toList()->count()); for (it->toFirst();(it->current(item));it->toNext()) { TemplateStructIntf *s = item.toStruct(); if (s) { - uint sortKey = determineSortKey(s,args.toString()); - sortList.append(new ListElem(sortKey,item)); - //printf("sortKey=%s\n",sortKey.data()); + std::string sortKey = determineSortKey(s,args.toString()); + sortList.emplace_back(sortKey,item); + //printf("sortKey=%s\n",qPrint(sortKey)); } } delete it; // sort the list - sortList.sort(); + std::sort(sortList.begin(), + sortList.end(), + [](const auto &lhs,const auto &rhs) { return lhs.key < rhs.key; }); // create an index from the sorted list - uint letter=0; - QListIterator<ListElem> sit(sortList); - ListElem *elem; + std::string letter; TemplateStruct *indexNode = 0; TemplateList *indexList = 0; - for (sit.toFirst();(elem=sit.current());++sit) + for (const auto &elem : sortList) { - if (letter!=elem->key || indexNode==0) + if (letter!=elem.key || indexNode==0) { // create new indexNode indexNode = TemplateStruct::alloc(); indexList = TemplateList::alloc(); - indexNode->set("letter", keyToLetter(elem->key)); - indexNode->set("label", keyToLabel(elem->key)); + indexNode->set("letter", elem.key); + indexNode->set("label", keyToLabel(elem.key.c_str())); indexNode->set("items",indexList); result->append(indexNode); - letter=elem->key; + letter=elem.key; } - indexList->append(elem->value); + indexList->append(elem.value); } return result; } @@ -1223,7 +1256,7 @@ class FilterStripPath public: static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &) { - if (!v.isValid() || v.type()!=TemplateVariant::String) + if (!v.isValid() || !v.isString()) { return v; } @@ -1250,7 +1283,7 @@ class FilterNoWrap public: static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &) { - if (!v.isValid() || v.type()!=TemplateVariant::String) + if (!v.isValid() || !v.isString()) { return v; } @@ -1271,7 +1304,7 @@ class FilterDivisibleBy { return TemplateVariant(); } - if (v.type()==TemplateVariant::Integer && n.type()==TemplateVariant::Integer) + if (v.isInt() && n.isInt()) { int ni = n.toInt(); if (ni>0) @@ -1298,7 +1331,7 @@ class FilterIsRelativeURL public: static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &) { - if (v.isValid() && v.type()==TemplateVariant::String) + if (v.isValid() && v.isString()) { QCString s = v.toString(); if (!s.isEmpty() && s.at(0)=='!') return TRUE; @@ -1315,7 +1348,7 @@ class FilterIsAbsoluteURL public: static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &) { - if (v.isValid() && v.type()==TemplateVariant::String) + if (v.isValid() && v.isString()) { QCString s = v.toString(); if (!s.isEmpty() && s.at(0)=='^') return TRUE; @@ -1326,6 +1359,72 @@ class FilterIsAbsoluteURL //-------------------------------------------------------------------- +/** @brief The implementation of the "lower" filter */ +class FilterLower +{ + public: + static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &) + { + if (v.isValid() && v.isString()) + { + return v.toString().lower(); + } + return v; + } +}; + +//-------------------------------------------------------------------- + +/** @brief The implementation of the "upper" filter */ +class FilterUpper +{ + public: + static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &) + { + if (v.isValid() && v.isString()) + { + return v.toString().upper(); + } + return v; + } +}; + +//-------------------------------------------------------------------- + +/** @brief The implementation of the "upper" filter */ +class FilterHex +{ + public: + static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &) + { + if (v.isValid()) + { + return QCString().sprintf("%x",v.toInt()); + } + return v; + } +}; + + +//-------------------------------------------------------------------- + +/** @brief The implementation of the "e" filter */ +class FilterEscape +{ + public: + static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &) + { + if (v.isValid() && v.isString()) + { + return convertToHtml(v.toString()); + } + return v; + } +}; + + +//-------------------------------------------------------------------- + /** @brief The implementation of the "decodeURL" filter * The leading character is removed from the value in case it is a ^ or !. * - ^ is used to encode a absolute URL @@ -1336,7 +1435,7 @@ class FilterDecodeURL public: static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &) { - if (v.isValid() && v.type()==TemplateVariant::String) + if (v.isValid() && v.isString()) { QCString s = v.toString(); if (!s.isEmpty() && (s.at(0)=='^' || s.at(0)=='!')) @@ -1366,11 +1465,11 @@ class TemplateFilterFactory TemplateVariant apply(const QCString &name,const TemplateVariant &v,const TemplateVariant &arg, bool &ok) { - FilterFunction *func = (FilterFunction*)m_registry.find(name); - if (func) + auto it = m_registry.find(name.str()); + if (it!=m_registry.end()) { ok=TRUE; - return (*func)(v,arg); + return it->second(v,arg); } else { @@ -1381,7 +1480,7 @@ class TemplateFilterFactory void registerFilter(const QCString &name,FilterFunction *func) { - m_registry.insert(name,(void*)func); + m_registry.insert(std::make_pair(name.str(),func)); } /** @brief Helper class for registering a filter function */ @@ -1395,15 +1494,20 @@ class TemplateFilterFactory }; private: - QDict<void> m_registry; + std::unordered_map<std::string,FilterFunction*> m_registry; }; // register a handlers for each filter we support static TemplateFilterFactory::AutoRegister<FilterAdd> fAdd("add"); static TemplateFilterFactory::AutoRegister<FilterGet> fGet("get"); +static TemplateFilterFactory::AutoRegister<FilterHex> fHex("hex"); static TemplateFilterFactory::AutoRegister<FilterRaw> fRaw("raw"); +static TemplateFilterFactory::AutoRegister<FilterKeep> fKeep("keep"); static TemplateFilterFactory::AutoRegister<FilterList> fList("list"); +static TemplateFilterFactory::AutoRegister<FilterLower> fLower("lower"); +static TemplateFilterFactory::AutoRegister<FilterUpper> fUpper("upper"); static TemplateFilterFactory::AutoRegister<FilterAppend> fAppend("append"); +static TemplateFilterFactory::AutoRegister<FilterEscape> fEscape("escape"); static TemplateFilterFactory::AutoRegister<FilterLength> fLength("length"); static TemplateFilterFactory::AutoRegister<FilterNoWrap> fNoWrap("nowrap"); static TemplateFilterFactory::AutoRegister<FilterFlatten> fFlatten("flatten"); @@ -1434,6 +1538,8 @@ class ExprAst virtual TemplateVariant resolve(TemplateContext *) { return TemplateVariant(); } }; +using ExprAstList = std::vector< std::unique_ptr<ExprAst> >; + /** @brief Class representing a number in the AST */ class ExprAstNumber : public ExprAst { @@ -1450,8 +1556,8 @@ class ExprAstNumber : public ExprAst class ExprAstVariable : public ExprAst { public: - ExprAstVariable(const char *name) : m_name(name) - { TRACE(("ExprAstVariable(%s)\n",name)); } + ExprAstVariable(const QCString &name) : m_name(name) + { TRACE(("ExprAstVariable(%s)\n",name.data())); } const QCString &name() const { return m_name; } virtual TemplateVariant resolve(TemplateContext *c) { @@ -1459,7 +1565,7 @@ class ExprAstVariable : public ExprAst TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c); if (!v.isValid()) { - if (ci) ci->warn(ci->templateName(),ci->line(),"undefined variable '%s' in expression",m_name.data()); + if (ci) ci->warn(ci->templateName(),ci->line(),"undefined variable '%s' in expression",qPrint(m_name)); } return v; } @@ -1470,10 +1576,9 @@ class ExprAstVariable : public ExprAst class ExprAstFunctionVariable : public ExprAst { public: - ExprAstFunctionVariable(ExprAst *var,const QList<ExprAst> &args) - : m_var(var), m_args(args) + ExprAstFunctionVariable(ExprAst *var, ExprAstList &&args) + : m_var(var), m_args(std::move(args)) { TRACE(("ExprAstFunctionVariable()\n")); - m_args.setAutoDelete(TRUE); } ~ExprAstFunctionVariable() { @@ -1482,13 +1587,13 @@ class ExprAstFunctionVariable : public ExprAst virtual TemplateVariant resolve(TemplateContext *c) { std::vector<TemplateVariant> args; - for (uint i=0;i<m_args.count();i++) + for (const auto &exprArg : m_args) { - TemplateVariant v = m_args.at(i)->resolve(c); + TemplateVariant v = exprArg->resolve(c); args.push_back(v); } TemplateVariant v = m_var->resolve(c); - if (v.type()==TemplateVariant::Function) + if (v.isFunction()) { v = v.call(args); } @@ -1496,29 +1601,29 @@ class ExprAstFunctionVariable : public ExprAst } private: ExprAst *m_var = 0; - QList<ExprAst> m_args; + ExprAstList m_args; }; /** @brief Class representing a filter in the AST */ class ExprAstFilter : public ExprAst { public: - ExprAstFilter(const char *name,ExprAst *arg) : m_name(name), m_arg(arg) - { TRACE(("ExprAstFilter(%s)\n",name)); } + ExprAstFilter(const QCString &name,ExprAst *arg) : m_name(name), m_arg(arg) + { TRACE(("ExprAstFilter(%s)\n",name.data())); } ~ExprAstFilter() { delete m_arg; } const QCString &name() const { return m_name; } TemplateVariant apply(const TemplateVariant &v,TemplateContext *c) { TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c); if (ci==0) return v; // should not happen - TRACE(("Applying filter '%s' to '%s' (type=%d)\n",m_name.data(),v.toString().data(),v.type())); + TRACE(("Applying filter '%s' to '%s' (type=%d)\n",qPrint(m_name),qPrint(v.toString()),v.type())); TemplateVariant arg; if (m_arg) arg = m_arg->resolve(c); bool ok; TemplateVariant result = TemplateFilterFactory::instance()->apply(m_name,v,arg,ok); if (!ok) { - ci->warn(ci->templateName(),ci->line(),"unknown filter '%s'",m_name.data()); + ci->warn(ci->templateName(),ci->line(),"unknown filter '%s'",qPrint(m_name)); } return result; } @@ -1548,8 +1653,8 @@ class ExprAstFilterAppl : public ExprAst class ExprAstLiteral : public ExprAst { public: - ExprAstLiteral(const char *lit) : m_literal(lit) - { TRACE(("ExprAstLiteral(%s)\n",lit)); } + ExprAstLiteral(const QCString &lit) : m_literal(lit) + { TRACE(("ExprAstLiteral(%s)\n",lit.data())); } const QCString &literal() const { return m_literal; } virtual TemplateVariant resolve(TemplateContext *) { return TemplateVariant(m_literal); } private: @@ -1616,7 +1721,7 @@ class ExprAstBinary : public ExprAst case Operator::NotEqual: return TemplateVariant(!(lhs == rhs)); case Operator::Less: - if (lhs.type()==TemplateVariant::String && rhs.type()==TemplateVariant::String) + if (lhs.isString() && rhs.isString()) { return lhs.toString()<rhs.toString(); } @@ -1625,7 +1730,7 @@ class ExprAstBinary : public ExprAst return lhs.toInt()<rhs.toInt(); } case Operator::Greater: - if (lhs.type()==TemplateVariant::String && rhs.type()==TemplateVariant::String) + if (lhs.isString() && rhs.isString()) { return !(lhs.toString()<rhs.toString()); } @@ -1634,7 +1739,7 @@ class ExprAstBinary : public ExprAst return lhs.toInt()>rhs.toInt(); } case Operator::LessEqual: - if (lhs.type()==TemplateVariant::String && rhs.type()==TemplateVariant::String) + if (lhs.isString() && rhs.isString()) { return lhs.toString()==rhs.toString() || lhs.toString()<rhs.toString(); } @@ -1643,7 +1748,7 @@ class ExprAstBinary : public ExprAst return lhs.toInt()<=rhs.toInt(); } case Operator::GreaterEqual: - if (lhs.type()==TemplateVariant::String && rhs.type()==TemplateVariant::String) + if (lhs.isString() && rhs.isString()) { return lhs.toString()==rhs.toString() || !(lhs.toString()<rhs.toString()); } @@ -1708,7 +1813,7 @@ class TemplateNode TemplateNode(TemplateNode *parent) : m_parent(parent) {} virtual ~TemplateNode() {} - virtual void render(FTextStream &ts, TemplateContext *c) = 0; + virtual void render(TextStream &ts, TemplateContext *c) = 0; TemplateNode *parent() { return m_parent; } @@ -1718,25 +1823,59 @@ class TemplateNode //---------------------------------------------------------- +/** @brief Class representing a lexical token in a template */ +class TemplateToken +{ + public: + enum Type { Text, Variable, Block }; + TemplateToken(Type t,const QCString &d,int l) : type(t), data(d), line(l) {} + Type type = Text; + QCString data; + int line = 0; +}; + +using TemplateTokenPtr = std::unique_ptr<TemplateToken>; +using TemplateTokenStream = std::deque< TemplateTokenPtr >; + +//---------------------------------------------------------- + +/** @brief Class representing a list of AST nodes in a template */ +class TemplateNodeList : public std::vector< std::unique_ptr<TemplateNode> > +{ + public: + void render(TextStream &ts,TemplateContext *c) + { + TRACE(("{TemplateNodeList::render\n")); + for (const auto &tn : *this) + { + tn->render(ts,c); + } + TRACE(("}TemplateNodeList::render\n")); + } +}; + +//---------------------------------------------------------- + /** @brief Parser for templates */ class TemplateParser { public: TemplateParser(const TemplateEngine *engine, - const QCString &templateName,QList<TemplateToken> &tokens); - void parse(TemplateNode *parent,int line,const QStrList &stopAt, - QList<TemplateNode> &nodes); + const QCString &templateName, + TemplateTokenStream &tokens); + void parse(TemplateNode *parent,int line,const StringVector &stopAt, + TemplateNodeList &nodes); bool hasNextToken() const; - TemplateToken *takeNextToken(); + TemplateTokenPtr takeNextToken(); void removeNextToken(); - void prependToken(const TemplateToken *token); + void prependToken(TemplateTokenPtr &&token); const TemplateToken *currentToken() const; QCString templateName() const { return m_templateName; } - void warn(const char *fileName,int line,const char *fmt,...) const; + void warn(const QCString &fileName,int line,const char *fmt,...) const; private: const TemplateEngine *m_engine = 0; QCString m_templateName; - QList<TemplateToken> &m_tokens; + TemplateTokenStream &m_tokens; }; //-------------------------------------------------------------------- @@ -1754,10 +1893,10 @@ class ExpressionParser { } - ExprAst *parse(const char *expr) + ExprAst *parse(const QCString &expr) { - if (expr==0) return 0; - m_tokenStream = expr; + if (expr.isEmpty()) return 0; + m_tokenStream = expr.data(); getNextToken(); return parseExpression(); } @@ -1978,6 +2117,7 @@ class ExpressionParser { warn(m_parser->templateName(),m_line,"unexpected operator '%s' in expression", Operator::toString(m_curToken.op)); + abort(); } break; default: @@ -1998,7 +2138,7 @@ class ExpressionParser ExprAst *parseIdentifier() { - TRACE(("{parseIdentifier(%s)\n",m_curToken.id.data())); + TRACE(("{parseIdentifier(%s)\n",qPrint(m_curToken.id))); ExprAst *id = new ExprAstVariable(m_curToken.id); getNextToken(); TRACE(("}parseIdentifier()\n")); @@ -2007,7 +2147,7 @@ class ExpressionParser ExprAst *parseLiteral() { - TRACE(("{parseLiteral(%s)\n",m_curToken.id.data())); + TRACE(("{parseLiteral(%s)\n",qPrint(m_curToken.id))); ExprAst *expr = new ExprAstLiteral(m_curToken.id); getNextToken(); TRACE(("}parseLiteral()\n")); @@ -2016,7 +2156,7 @@ class ExpressionParser ExprAst *parseIdentifierOptionalArgs() { - TRACE(("{parseIdentifierOptionalArgs(%s)\n",m_curToken.id.data())); + TRACE(("{parseIdentifierOptionalArgs(%s)\n",qPrint(m_curToken.id))); ExprAst *expr = parseIdentifier(); if (expr) { @@ -2024,17 +2164,15 @@ class ExpressionParser m_curToken.op==Operator::Colon) { getNextToken(); - ExprAst *argExpr = parsePrimaryExpression(); - QList<ExprAst> args; - args.append(argExpr); + ExprAstList args; + args.push_back(std::unique_ptr<ExprAst>(parsePrimaryExpression())); while (m_curToken.type==ExprToken::Operator && m_curToken.op==Operator::Comma) { getNextToken(); - argExpr = parsePrimaryExpression(); - args.append(argExpr); + args.push_back(std::unique_ptr<ExprAst>(parsePrimaryExpression())); } - expr = new ExprAstFunctionVariable(expr,args); + expr = new ExprAstFunctionVariable(expr,std::move(args)); } } TRACE(("}parseIdentifierOptionalArgs()\n")); @@ -2062,7 +2200,7 @@ class ExpressionParser ExprAstFilter *parseFilter() { - TRACE(("{parseFilter(%s)\n",m_curToken.id.data())); + TRACE(("{parseFilter(%s)\n",qPrint(m_curToken.id))); QCString filterName = m_curToken.id; getNextToken(); ExprAst *argExpr=0; @@ -2272,8 +2410,8 @@ class ExpressionParser m_curToken.id = s; p++; } - //TRACE(("token type=%d op=%d num=%d id=%s\n", - // m_curToken.type,m_curToken.op,m_curToken.num,m_curToken.id.data())); + TRACE(("token type=%d op=%d num=%d id=%s\n", + m_curToken.type,m_curToken.op,m_curToken.num,qPrint(m_curToken.id))); m_tokenStream = p; return TRUE; @@ -2287,42 +2425,6 @@ class ExpressionParser //---------------------------------------------------------- -/** @brief Class representing a lexical token in a template */ -class TemplateToken -{ - public: - enum Type { Text, Variable, Block }; - TemplateToken(Type t,const char *d,int l) : type(t), data(d), line(l) {} - Type type = Text; - QCString data; - int line = 0; -}; - -//---------------------------------------------------------- - -/** @brief Class representing a list of AST nodes in a template */ -class TemplateNodeList : public QList<TemplateNode> -{ - public: - TemplateNodeList() - { - setAutoDelete(TRUE); - } - void render(FTextStream &ts,TemplateContext *c) - { - TRACE(("{TemplateNodeList::render\n")); - QListIterator<TemplateNode> it(*this); - TemplateNode *tn=0; - for (it.toFirst();(tn=it.current());++it) - { - tn->render(ts,c); - } - TRACE(("}TemplateNodeList::render\n")); - } -}; - -//---------------------------------------------------------- - /** @brief Internal class representing the implementation of a template */ class TemplateImpl : public TemplateNode, public Template { @@ -2330,7 +2432,7 @@ class TemplateImpl : public TemplateNode, public Template TemplateImpl(TemplateEngine *e,const QCString &name,const QCString &data, const QCString &extension); ~TemplateImpl(); - void render(FTextStream &ts, TemplateContext *c); + void render(TextStream &ts, TemplateContext *c); TemplateEngine *engine() const { return m_engine; } TemplateBlockContext *blockContext() { return &m_blockContext; } @@ -2351,7 +2453,8 @@ class TemplateStructWeakRef : public TemplateStructIntf { public: TemplateStructWeakRef(TemplateStructIntf *ref) : m_ref(ref), m_refCount(0) {} - virtual TemplateVariant get(const char *name) const { return m_ref->get(name); } + virtual TemplateVariant get(const QCString &name) const { return m_ref->get(name); } + virtual StringVector fields() const { return m_ref->fields(); } virtual int addRef() { return ++m_refCount; } virtual int release() { int count=--m_refCount; if (count<=0) { delete this; } return count; } private: @@ -2365,9 +2468,6 @@ TemplateContextImpl::TemplateContextImpl(const TemplateEngine *e) : m_engine(e), m_templateName("<unknown>"), m_line(1), m_activeEscapeIntf(0), m_spacelessIntf(0), m_spacelessEnabled(FALSE), m_tabbingEnabled(FALSE), m_indices(TemplateStruct::alloc()) { - m_indexStacks.setAutoDelete(TRUE); - m_contextStack.setAutoDelete(TRUE); - m_escapeIntfDict.setAutoDelete(TRUE); m_fromUtf8 = (void*)(-1); push(); set("index",m_indices.get()); @@ -2389,24 +2489,24 @@ void TemplateContextImpl::setEncoding(const QCString &templateName,int line,cons m_encoding=enc; if (!enc.isEmpty()) { - m_fromUtf8 = portable_iconv_open(enc,"UTF-8"); + m_fromUtf8 = portable_iconv_open(enc.data(),"UTF-8"); if (m_fromUtf8==(void*)(-1)) { - warn(templateName,line,"unsupported character conversion: '%s'->'UTF-8'\n", enc.data()); + warn(templateName,line,"unsupported character conversion: '%s'->'UTF-8'\n", qPrint(enc)); } } - //printf("TemplateContextImpl::setEncoding(%s)\n",enc.data()); + //printf("TemplateContextImpl::setEncoding(%s)\n",qPrint(enc)); } QCString TemplateContextImpl::recode(const QCString &s) { - //printf("TemplateContextImpl::recode(%s)\n",s.data()); + //printf("TemplateContextImpl::recode(%s)\n",qPrint(s)); int iSize = s.length(); int oSize = iSize*4+1; QCString output(oSize); size_t iLeft = iSize; size_t oLeft = oSize; - char *iPtr = s.rawData(); + const char *iPtr = s.data(); char *oPtr = output.rawData(); if (!portable_iconv(m_fromUtf8,&iPtr,&iLeft,&oPtr,&oLeft)) { @@ -2421,14 +2521,32 @@ QCString TemplateContextImpl::recode(const QCString &s) } } -void TemplateContextImpl::set(const char *name,const TemplateVariant &v) +void TemplateContextImpl::set(const QCString &name,const TemplateVariant &v) { - TemplateVariant *pv = m_contextStack.getFirst()->find(name); - if (pv) + auto &ctx = m_contextStack.front(); + auto it = ctx.find(name.str()); + if (it!=ctx.end()) { - m_contextStack.getFirst()->remove(name); + ctx.erase(it); } - m_contextStack.getFirst()->insert(name,new TemplateVariant(v)); + ctx.insert(std::make_pair(name.str(),v)); +} + +void TemplateContextImpl::update(const QCString &name,const TemplateVariant &v) +{ + int depth=0; + for (auto &ctx : m_contextStack) + { + auto it = ctx.find(name.str()); + if (it!=ctx.end()) + { + ctx.erase(it); + ctx.insert(std::make_pair(name.str(),v)); + return; + } + depth++; + } + warn(m_templateName,m_line,"requesting update for non-existing variable '%s'",qPrint(name)); } TemplateVariant TemplateContextImpl::get(const QCString &name) const @@ -2445,15 +2563,15 @@ TemplateVariant TemplateContextImpl::get(const QCString &name) const QCString propName = name.mid(i+1); while (!propName.isEmpty()) { - //printf("getPrimary(%s) type=%d:%s\n",objName.data(),v.type(),v.toString().data()); - if (v.type()==TemplateVariant::Struct) + //printf("getPrimary(%s) type=%zu:%s\n",qPrint(objName),v.type(),qPrint(v.toString())); + if (v.isStruct()) { i = propName.find("."); int l = i==-1 ? propName.length() : i; v = v.toStruct()->get(propName.left(l)); if (!v.isValid()) { - warn(m_templateName,m_line,"requesting non-existing property '%s' for object '%s'",propName.left(l).data(),objName.data()); + warn(m_templateName,m_line,"requesting non-existing property '%s' for object '%s'",qPrint(propName.left(l)),qPrint(objName)); } if (i!=-1) { @@ -2465,7 +2583,7 @@ TemplateVariant TemplateContextImpl::get(const QCString &name) const propName.resize(0); } } - else if (v.type()==TemplateVariant::List) + else if (v.isList()) { i = propName.find("."); int l = i==-1 ? propName.length() : i; @@ -2477,7 +2595,7 @@ TemplateVariant TemplateContextImpl::get(const QCString &name) const } else { - warn(m_templateName,m_line,"list index '%s' is not valid",propName.data()); + warn(m_templateName,m_line,"list index '%s' is not valid",qPrint(propName)); break; } if (i!=-1) @@ -2491,7 +2609,7 @@ TemplateVariant TemplateContextImpl::get(const QCString &name) const } else { - warn(m_templateName,m_line,"using . on an object '%s' is not an struct or list",objName.data()); + warn(m_templateName,m_line,"using . on an object '%s' is not an struct or list",qPrint(objName)); return TemplateVariant(); } } @@ -2501,12 +2619,13 @@ TemplateVariant TemplateContextImpl::get(const QCString &name) const const TemplateVariant *TemplateContextImpl::getRef(const QCString &name) const { - QListIterator< QDict<TemplateVariant> > it(m_contextStack); - QDict<TemplateVariant> *dict; - for (it.toFirst();(dict=it.current());++it) + for (const auto &ctx : m_contextStack) { - TemplateVariant *v = dict->find(name); - if (v) return v; + auto it = ctx.find(name.str()); + if (it!=ctx.end()) + { + return &it->second; + } } return 0; // not found } @@ -2519,17 +2638,19 @@ TemplateVariant TemplateContextImpl::getPrimary(const QCString &name) const void TemplateContextImpl::push() { - QDict<TemplateVariant> *dict = new QDict<TemplateVariant>; - dict->setAutoDelete(TRUE); - m_contextStack.prepend(dict); + m_contextStack.push_front(std::map<std::string,TemplateVariant>()); } void TemplateContextImpl::pop() { - if (!m_contextStack.removeFirst()) + if (m_contextStack.empty()) { warn(m_templateName,m_line,"pop() called on empty context stack!\n"); } + else + { + m_contextStack.pop_front(); + } } TemplateBlockContext *TemplateContextImpl::blockContext() @@ -2537,7 +2658,7 @@ TemplateBlockContext *TemplateContextImpl::blockContext() return &m_blockContext; } -void TemplateContextImpl::warn(const char *fileName,int line,const char *fmt,...) const +void TemplateContextImpl::warn(const QCString &fileName,int line,const char *fmt,...) const { va_list args; va_start(args,fmt); @@ -2548,20 +2669,21 @@ void TemplateContextImpl::warn(const char *fileName,int line,const char *fmt,... void TemplateContextImpl::openSubIndex(const QCString &indexName) { - //printf("TemplateContextImpl::openSubIndex(%s)\n",indexName.data()); - QStack<TemplateVariant> *stack = m_indexStacks.find(indexName); - if (!stack || stack->isEmpty() || stack->top()->type()==TemplateVariant::List) // error: no stack yet or no entry + //printf("TemplateContextImpl::openSubIndex(%s)\n",qPrint(indexName)); + auto kv = m_indexStacks.find(indexName.str()); + if (kv==m_indexStacks.end() || kv->second.empty() || kv->second.top().isList()) // error: no stack yet or no entry { - warn(m_templateName,m_line,"opensubindex for index %s without preceding indexentry",indexName.data()); + warn(m_templateName,m_line,"opensubindex for index %s without preceding indexentry",qPrint(indexName)); return; } // get the parent entry to add the list to - TemplateStruct *entry = dynamic_cast<TemplateStruct*>(stack->top()->toStruct()); + auto &stack = kv->second; + TemplateStruct *entry = dynamic_cast<TemplateStruct*>(stack.top().toStruct()); if (entry) { // add new list to the stack TemplateList *list = TemplateList::alloc(); - stack->push(new TemplateVariant(list)); + stack.emplace(list); entry->set("children",list); entry->set("is_leaf_node",false); } @@ -2569,36 +2691,37 @@ void TemplateContextImpl::openSubIndex(const QCString &indexName) void TemplateContextImpl::closeSubIndex(const QCString &indexName) { - //printf("TemplateContextImpl::closeSubIndex(%s)\n",indexName.data()); - QStack<TemplateVariant> *stack = m_indexStacks.find(indexName); - if (!stack || stack->count()<3) + //printf("TemplateContextImpl::closeSubIndex(%s)\n",qPrint(indexName)); + auto kv = m_indexStacks.find(indexName.str()); + if (kv==m_indexStacks.end() || kv->second.size()<3) { - warn(m_templateName,m_line,"closesubindex for index %s without matching open",indexName.data()); + warn(m_templateName,m_line,"closesubindex for index %s without matching open",qPrint(indexName)); } - else // stack->count()>=2 + else { - if (stack->top()->type()==TemplateVariant::Struct) + auto &stack = kv->second; // stack.size()>2 + if (stack.top().isStruct()) { - delete stack->pop(); // pop struct - delete stack->pop(); // pop list + stack.pop(); // pop struct + stack.pop(); // pop list } else // empty list! correct "is_left_node" attribute of the parent entry { - delete stack->pop(); // pop list - TemplateStruct *entry = dynamic_cast<TemplateStruct*>(stack->top()->toStruct()); + stack.pop(); // pop list + TemplateStruct *entry = dynamic_cast<TemplateStruct*>(stack.top().toStruct()); if (entry) { entry->set("is_leaf_node",true); } } } - //fprintf(stderr,"TemplateContextImpl::closeSubIndex(%s) end g_count=%d\n\n",indexName.data(),g_count); + //fprintf(stderr,"TemplateContextImpl::closeSubIndex(%s) end g_count=%d\n\n",qPrint(indexName),g_count); } static void getPathListFunc(TemplateStructIntf *entry,TemplateList *list) { TemplateVariant parent = entry->get("parent"); - if (parent.type()==TemplateVariant::Struct) + if (parent.isStruct()) { getPathListFunc(parent.toStruct(),list); } @@ -2616,49 +2739,49 @@ static TemplateVariant getPathFunc(const void *ctx, const std::vector<TemplateVa void TemplateContextImpl::addIndexEntry(const QCString &indexName,const std::vector<TemplateKeyValue> &arguments) { auto it = arguments.begin(); - //printf("TemplateContextImpl::addIndexEntry(%s)\n",indexName.data()); + //printf("TemplateContextImpl::addIndexEntry(%s)\n",qPrint(indexName)); //while (it!=arguments.end()) //{ // printf(" key=%s value=%s\n",(*it).key.data(),(*it).value.toString().data()); // ++it; //} TemplateVariant parent(FALSE); - QStack<TemplateVariant> *stack = m_indexStacks.find(indexName); - if (!stack) // no stack yet, create it! + auto kv = m_indexStacks.find(indexName.str()); + if (kv==m_indexStacks.end()) // no stack yet, create it! { - stack = new QStack<TemplateVariant>; - stack->setAutoDelete(TRUE); - m_indexStacks.insert(indexName,stack); + kv = m_indexStacks.insert(std::make_pair(indexName.str(),std::stack<TemplateVariant>())).first; } TemplateList *list = 0; - if (stack->isEmpty()) // first item, create empty list and add it to the index + auto &stack = kv->second; + if (stack.empty()) // first item, create empty list and add it to the index { list = TemplateList::alloc(); - stack->push(new TemplateVariant(list)); + stack.emplace(list); m_indices->set(indexName,list); // make list available under index } else // stack not empty { - if (stack->top()->type()==TemplateVariant::Struct) // already an entry in the list + if (stack.top().isStruct()) // already an entry in the list { // remove current entry from the stack - delete stack->pop(); + stack.pop(); } else // first entry after opensubindex { - ASSERT(stack->top()->type()==TemplateVariant::List); + ASSERT(stack.top().isList()); } - if (stack->count()>1) + if (stack.size()>1) { - TemplateVariant *tmp = stack->pop(); + TemplateVariant tmp = stack.top(); + stack.pop(); // To prevent a cyclic dependency between parent and child which causes a memory // leak, we wrap the parent into a weak reference version. - parent = new TemplateStructWeakRef(stack->top()->toStruct()); - stack->push(tmp); - ASSERT(parent.type()==TemplateVariant::Struct); + parent = new TemplateStructWeakRef(stack.top().toStruct()); + stack.push(tmp); + ASSERT(parent.isStruct()); } // get list to add new item - list = dynamic_cast<TemplateList*>(stack->top()->toList()); + list = dynamic_cast<TemplateList*>(stack.top().toList()); } TemplateStruct *entry = TemplateStruct::alloc(); // add user specified fields to the entry @@ -2678,9 +2801,9 @@ void TemplateContextImpl::addIndexEntry(const QCString &indexName,const std::vec entry->set("first",list->count()==0); entry->set("index",list->count()); entry->set("parent",parent); - entry->set("path",TemplateVariant::Delegate::fromFunction(entry,getPathFunc)); + entry->set("path",TemplateVariant::FunctionDelegate::fromFunction(entry,getPathFunc)); entry->set("last",true); - stack->push(new TemplateVariant(entry)); + stack.emplace(entry); list->append(entry); } @@ -2696,11 +2819,11 @@ class TemplateNodeText : public TemplateNode TRACE(("TemplateNodeText('%s')\n",replace(data,'\n',' ').data())); } - void render(FTextStream &ts, TemplateContext *c) + void render(TextStream &ts, TemplateContext *c) { TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c); if (ci==0) return; // should not happen - //printf("TemplateNodeText::render(%s) needsRecoding=%d ci=%p\n",m_data.data(),ci->needsRecoding(),ci); + //printf("TemplateNodeText::render(%s) needsRecoding=%d ci=%p\n",qPrint(m_data),ci->needsRecoding(),ci); if (ci->spacelessEnabled()) { if (ci->needsRecoding()) @@ -2737,12 +2860,12 @@ class TemplateNodeVariable : public TemplateNode TemplateNodeVariable(TemplateParser *parser,TemplateNode *parent,int line,const QCString &var) : TemplateNode(parent), m_templateName(parser->templateName()), m_line(line) { - TRACE(("TemplateNodeVariable(%s)\n",var.data())); + TRACE(("TemplateNodeVariable(%s)\n",qPrint(var))); ExpressionParser expParser(parser,line); m_var = expParser.parse(var); if (m_var==0) { - parser->warn(m_templateName,line,"invalid expression '%s' for variable",var.data()); + parser->warn(m_templateName,line,"invalid expression '%s' for variable",qPrint(var)); } } ~TemplateNodeVariable() @@ -2750,7 +2873,7 @@ class TemplateNodeVariable : public TemplateNode delete m_var; } - void render(FTextStream &ts, TemplateContext *c) + void render(TextStream &ts, TemplateContext *c) { TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c); if (ci==0) return; // should not happen @@ -2758,7 +2881,7 @@ class TemplateNodeVariable : public TemplateNode if (m_var) { TemplateVariant v = m_var->resolve(c); - if (v.type()==TemplateVariant::Function) + if (v.isFunction()) { v = v.call(std::vector<TemplateVariant>()); } @@ -2791,7 +2914,6 @@ class TemplateNodeVariable : public TemplateNode QCString m_templateName; int m_line = 0; ExprAst *m_var = 0; - QList<ExprAst> m_args; }; //---------------------------------------------------------- @@ -2821,36 +2943,35 @@ template<class T> class TemplateNodeCreator : public TemplateNode return dynamic_cast<TemplateImpl*>(root); } protected: - void mkpath(TemplateContextImpl *ci,const QCString &fileName) + void mkpath(TemplateContextImpl *ci,const std::string &fileName) { - int i=fileName.find('/'); - QCString outputDir = ci->outputDirectory(); - QDir d(outputDir); + size_t i=fileName.find('/'); + std::string outputDir = ci->outputDirectory().str(); + Dir d(outputDir); if (!d.exists()) { - QDir rootDir; - rootDir.setPath(QDir::currentDirPath()); + Dir rootDir; if (!rootDir.mkdir(outputDir)) { err("tag OUTPUT_DIRECTORY: Output directory '%s' does not " - "exist and cannot be created\n",outputDir.data()); + "exist and cannot be created\n",outputDir.c_str()); return; } d.setPath(outputDir); } - int j=0; - while (i!=-1) // fileName contains path part + size_t j=0; + while (i!=std::string::npos) // fileName contains path part { if (d.exists()) { - bool ok = d.mkdir(fileName.mid(j,i-j)); + bool ok = d.mkdir(fileName.substr(j,i-j)); if (!ok) { - err("Failed to create directory '%s'\n",(fileName.mid(j,i-j)).data()); + err("Failed to create directory '%s'\n",(fileName.substr(j,i-j)).c_str()); break; } - QCString dirName = outputDir+'/'+fileName.left(i); - d = QDir(dirName); + std::string dirName = outputDir+'/'+fileName.substr(0,i); + d = Dir(dirName); j = i+1; } i=fileName.find('/',i+1); @@ -2869,67 +2990,59 @@ class TemplateNodeIf : public TemplateNodeCreator<TemplateNodeIf> TemplateNodeIf(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data) : TemplateNodeCreator<TemplateNodeIf>(parser,parent,line) { - m_ifGuardedNodes.setAutoDelete(TRUE); - TRACE(("{TemplateNodeIf(%s)\n",data.data())); + TRACE(("{TemplateNodeIf(%s)\n",qPrint(data))); if (data.isEmpty()) { parser->warn(m_templateName,line,"missing argument for if tag"); } - QStrList stopAt; - stopAt.append("endif"); - stopAt.append("elif"); - stopAt.append("else"); + StringVector stopAt = { "endif", "elif", "else" }; // if 'nodes' { - GuardedNodes *guardedNodes = new GuardedNodes; + m_ifGuardedNodes.push_back(std::make_unique<GuardedNodes>()); + auto &guardedNodes = m_ifGuardedNodes.back(); ExpressionParser ex(parser,line); guardedNodes->line = line; guardedNodes->guardAst = ex.parse(data); parser->parse(this,line,stopAt,guardedNodes->trueNodes); - m_ifGuardedNodes.append(guardedNodes); } - TemplateToken *tok = parser->takeNextToken(); + auto tok = parser->takeNextToken(); // elif 'nodes' while (tok && tok->data.left(5)=="elif ") { + m_ifGuardedNodes.push_back(std::make_unique<GuardedNodes>()); + auto &guardedNodes = m_ifGuardedNodes.back(); ExpressionParser ex(parser,line); - GuardedNodes *guardedNodes = new GuardedNodes; guardedNodes->line = tok->line; guardedNodes->guardAst = ex.parse(tok->data.mid(5)); parser->parse(this,tok->line,stopAt,guardedNodes->trueNodes); - m_ifGuardedNodes.append(guardedNodes); // proceed to the next token - delete tok; tok = parser->takeNextToken(); } // else 'nodes' if (tok && tok->data=="else") { - stopAt.removeLast(); // remove "else" - stopAt.removeLast(); // remove "elif" + stopAt.pop_back(); // remove "else" + stopAt.pop_back(); // remove "elif" parser->parse(this,line,stopAt,m_falseNodes); parser->removeNextToken(); // skip over endif } - delete tok; - TRACE(("}TemplateNodeIf(%s)\n",data.data())); + TRACE(("}TemplateNodeIf(%s)\n",qPrint(data))); } ~TemplateNodeIf() { } - void render(FTextStream &ts, TemplateContext *c) + void render(TextStream &ts, TemplateContext *c) { TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c); if (ci==0) return; // should not happen ci->setLocation(m_templateName,m_line); //printf("TemplateNodeIf::render #trueNodes=%d #falseNodes=%d\n",m_trueNodes.count(),m_falseNodes.count()); bool processed=FALSE; - QListIterator<GuardedNodes> li(m_ifGuardedNodes); - GuardedNodes *nodes; - for (li.toFirst();(nodes=li.current()) && !processed;++li) + for (auto &nodes : m_ifGuardedNodes) { if (nodes->guardAst) { @@ -2938,6 +3051,7 @@ class TemplateNodeIf : public TemplateNodeCreator<TemplateNodeIf> { nodes->trueNodes.render(ts,c); processed=TRUE; + break; } } else @@ -2960,7 +3074,7 @@ class TemplateNodeIf : public TemplateNodeCreator<TemplateNodeIf> ExprAst *guardAst = 0; TemplateNodeList trueNodes; }; - QList<GuardedNodes> m_ifGuardedNodes; + std::vector< std::unique_ptr<GuardedNodes> > m_ifGuardedNodes; TemplateNodeList m_falseNodes; }; @@ -2972,26 +3086,25 @@ class TemplateNodeRepeat : public TemplateNodeCreator<TemplateNodeRepeat> TemplateNodeRepeat(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data) : TemplateNodeCreator<TemplateNodeRepeat>(parser,parent,line) { - TRACE(("{TemplateNodeRepeat(%s)\n",data.data())); + TRACE(("{TemplateNodeRepeat(%s)\n",qPrint(data))); ExpressionParser expParser(parser,line); m_expr = expParser.parse(data); - QStrList stopAt; - stopAt.append("endrepeat"); + StringVector stopAt = { "endrepeat" }; parser->parse(this,line,stopAt,m_repeatNodes); parser->removeNextToken(); // skip over endrepeat - TRACE(("}TemplateNodeRepeat(%s)\n",data.data())); + TRACE(("}TemplateNodeRepeat(%s)\n",qPrint(data))); } ~TemplateNodeRepeat() { delete m_expr; } - void render(FTextStream &ts, TemplateContext *c) + void render(TextStream &ts, TemplateContext *c) { TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c); if (ci==0) return; // should not happen ci->setLocation(m_templateName,m_line); TemplateVariant v; - if (m_expr && (v=m_expr->resolve(c)).type()==TemplateVariant::Integer) + if (m_expr && (v=m_expr->resolve(c)).isInt()) { int i, n = v.toInt(); for (i=0;i<n;i++) @@ -3027,7 +3140,7 @@ class TemplateNodeRange : public TemplateNodeCreator<TemplateNodeRange> TemplateNodeRange(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data) : TemplateNodeCreator<TemplateNodeRange>(parser,parent,line), m_down(FALSE) { - TRACE(("{TemplateNodeRange(%s)\n",data.data())); + TRACE(("{TemplateNodeRange(%s)\n",qPrint(data))); QCString start,end; int i1 = data.find(" from "); int i2 = data.find(" to "); @@ -3085,11 +3198,10 @@ class TemplateNodeRange : public TemplateNodeCreator<TemplateNodeRange> m_startExpr = expParser.parse(start); m_endExpr = expParser.parse(end); - QStrList stopAt; - stopAt.append("endrange"); + StringVector stopAt = { "endrange" }; parser->parse(this,line,stopAt,m_loopNodes); parser->removeNextToken(); // skip over endrange - TRACE(("}TemplateNodeRange(%s)\n",data.data())); + TRACE(("}TemplateNodeRange(%s)\n",qPrint(data))); } ~TemplateNodeRange() @@ -3098,7 +3210,7 @@ class TemplateNodeRange : public TemplateNodeCreator<TemplateNodeRange> delete m_endExpr; } - void render(FTextStream &ts, TemplateContext *c) + void render(TextStream &ts, TemplateContext *c) { TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c); if (ci==0) return; // should not happen @@ -3109,7 +3221,7 @@ class TemplateNodeRange : public TemplateNodeCreator<TemplateNodeRange> { TemplateVariant vs = m_startExpr->resolve(c); TemplateVariant ve = m_endExpr->resolve(c); - if (vs.type()==TemplateVariant::Integer && ve.type()==TemplateVariant::Integer) + if (vs.isInt() && ve.isInt()) { int s = vs.toInt(); int e = ve.toInt(); @@ -3161,11 +3273,11 @@ class TemplateNodeRange : public TemplateNodeCreator<TemplateNodeRange> s,m_down?"downto":"to",e); } } - else if (vs.type()!=TemplateVariant::Integer) + else if (!vs.isInt()) { ci->warn(m_templateName,m_line,"range requires a start value of integer type!"); } - else if (ve.type()!=TemplateVariant::Integer) + else if (!ve.isInt()) { ci->warn(m_templateName,m_line,"range requires an end value of integer type!"); } @@ -3197,7 +3309,7 @@ class TemplateNodeFor : public TemplateNodeCreator<TemplateNodeFor> TemplateNodeFor(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data) : TemplateNodeCreator<TemplateNodeFor>(parser,parent,line), m_reversed(FALSE) { - TRACE(("{TemplateNodeFor(%s)\n",data.data())); + TRACE(("{TemplateNodeFor(%s)\n",qPrint(data))); QCString exprStr; int i = data.find(" in "); if (i==-1) @@ -3239,19 +3351,16 @@ class TemplateNodeFor : public TemplateNodeCreator<TemplateNodeFor> ExpressionParser expParser(parser,line); m_expr = expParser.parse(exprStr); - QStrList stopAt; - stopAt.append("endfor"); - stopAt.append("empty"); + StringVector stopAt = { "endfor", "empty" }; parser->parse(this,line,stopAt,m_loopNodes); - TemplateToken *tok = parser->takeNextToken(); + auto tok = parser->takeNextToken(); if (tok && tok->data=="empty") { - stopAt.removeLast(); + stopAt.pop_back(); parser->parse(this,line,stopAt,m_emptyNodes); parser->removeNextToken(); // skip over endfor } - delete tok; - TRACE(("}TemplateNodeFor(%s)\n",data.data())); + TRACE(("}TemplateNodeFor(%s)\n",qPrint(data))); } ~TemplateNodeFor() @@ -3259,7 +3368,7 @@ class TemplateNodeFor : public TemplateNodeCreator<TemplateNodeFor> delete m_expr; } - void render(FTextStream &ts, TemplateContext *c) + void render(TextStream &ts, TemplateContext *c) { TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c); if (ci==0) return; // should not happen @@ -3269,7 +3378,7 @@ class TemplateNodeFor : public TemplateNodeCreator<TemplateNodeFor> if (m_expr) { TemplateVariant v = m_expr->resolve(c); - if (v.type()==TemplateVariant::Function) + if (v.isFunction()) { v = v.call(std::vector<TemplateVariant>()); } @@ -3310,7 +3419,7 @@ class TemplateNodeFor : public TemplateNodeCreator<TemplateNodeFor> { c->set(m_vars[vi++],ve); } - else if (m_vars.size()>1 && ve.type()==TemplateVariant::Struct) + else if (m_vars.size()>1 && ve.isStruct()) // loop variables represent elements in a list item { for (uint i=0;i<m_vars.size();i++,vi++) @@ -3333,7 +3442,7 @@ class TemplateNodeFor : public TemplateNodeCreator<TemplateNodeFor> } else // simple type... { - ci->warn(m_templateName,m_line,"for requires a variable of list type, got type '%s'!",v.typeAsString().data()); + ci->warn(m_templateName,m_line,"for requires a variable of list type, got type '%s'!",qPrint(v.typeAsString())); } } } @@ -3356,13 +3465,12 @@ class TemplateNodeMsg : public TemplateNodeCreator<TemplateNodeMsg> : TemplateNodeCreator<TemplateNodeMsg>(parser,parent,line) { TRACE(("{TemplateNodeMsg()\n")); - QStrList stopAt; - stopAt.append("endmsg"); + StringVector stopAt = { "endmsg" }; parser->parse(this,line,stopAt,m_nodes); parser->removeNextToken(); // skip over endmsg TRACE(("}TemplateNodeMsg()\n")); } - void render(FTextStream &, TemplateContext *c) + void render(TextStream &, TemplateContext *c) { TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c); if (ci==0) return; // should not happen @@ -3371,9 +3479,10 @@ class TemplateNodeMsg : public TemplateNodeCreator<TemplateNodeMsg> ci->setActiveEscapeIntf(0); // avoid escaping things we send to standard out bool enable = ci->spacelessEnabled(); ci->enableSpaceless(FALSE); - FTextStream ts(stdout); - m_nodes.render(ts,c); - ts << endl; + TextStream t(&std::cout); + m_nodes.render(t,c); + t.flush(); + std::cout << "\n"; ci->setActiveEscapeIntf(escIntf); ci->enableSpaceless(enable); } @@ -3391,20 +3500,19 @@ class TemplateNodeBlock : public TemplateNodeCreator<TemplateNodeBlock> TemplateNodeBlock(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data) : TemplateNodeCreator<TemplateNodeBlock>(parser,parent,line) { - TRACE(("{TemplateNodeBlock(%s)\n",data.data())); + TRACE(("{TemplateNodeBlock(%s)\n",qPrint(data))); m_blockName = data; if (m_blockName.isEmpty()) { parser->warn(parser->templateName(),line,"block tag without name"); } - QStrList stopAt; - stopAt.append("endblock"); + StringVector stopAt = { "endblock" }; parser->parse(this,line,stopAt,m_nodes); parser->removeNextToken(); // skip over endblock - TRACE(("}TemplateNodeBlock(%s)\n",data.data())); + TRACE(("}TemplateNodeBlock(%s)\n",qPrint(data))); } - void render(FTextStream &ts, TemplateContext *c) + void render(TextStream &ts, TemplateContext *c) { TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c); if (ci==0) return; // should not happen @@ -3417,8 +3525,7 @@ class TemplateNodeBlock : public TemplateNodeCreator<TemplateNodeBlock> if (nb) // block is overruled { ci->push(); - QGString super; - FTextStream ss(&super); + TextStream ss; // get super block of block nb TemplateNodeBlock *sb = ci->blockContext()->get(m_blockName); if (sb && sb!=nb && sb!=this) // nb and sb both overrule this block @@ -3429,6 +3536,7 @@ class TemplateNodeBlock : public TemplateNodeCreator<TemplateNodeBlock> { m_nodes.render(ss,c); // render parent of nb to string } + QCString super = ss.str(); // add 'block.super' variable to allow access to parent block content TemplateAutoRef<TemplateStruct> superBlock(TemplateStruct::alloc()); superBlock->set("super",TemplateVariant(super.data(),TRUE)); @@ -3469,23 +3577,23 @@ class TemplateNodeExtend : public TemplateNodeCreator<TemplateNodeExtend> TemplateNodeExtend(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data) : TemplateNodeCreator<TemplateNodeExtend>(parser,parent,line) { - TRACE(("{TemplateNodeExtend(%s)\n",data.data())); + TRACE(("{TemplateNodeExtend(%s)\n",qPrint(data))); ExpressionParser ep(parser,line); if (data.isEmpty()) { parser->warn(m_templateName,line,"extend tag is missing template file argument"); } m_extendExpr = ep.parse(data); - QStrList stopAt; + StringVector stopAt; parser->parse(this,line,stopAt,m_nodes); - TRACE(("}TemplateNodeExtend(%s)\n",data.data())); + TRACE(("}TemplateNodeExtend(%s)\n",qPrint(data))); } ~TemplateNodeExtend() { delete m_extendExpr; } - void render(FTextStream &ts, TemplateContext *c) + void render(TextStream &ts, TemplateContext *c) { TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c); if (ci==0) return; // should not happen @@ -3510,16 +3618,14 @@ class TemplateNodeExtend : public TemplateNodeCreator<TemplateNodeExtend> TemplateBlockContext *bc = ci->blockContext(); // add overruling blocks to the context - QListIterator<TemplateNode> li(m_nodes); - TemplateNode *n; - for (li.toFirst();(n=li.current());++li) + for (const auto &n : m_nodes) { - TemplateNodeBlock *nb = dynamic_cast<TemplateNodeBlock*>(n); + TemplateNodeBlock *nb = dynamic_cast<TemplateNodeBlock*>(n.get()); if (nb) { bc->add(nb); } - TemplateNodeMsg *msg = dynamic_cast<TemplateNodeMsg*>(n); + TemplateNodeMsg *msg = dynamic_cast<TemplateNodeMsg*>(n.get()); if (msg) { msg->render(ts,c); @@ -3535,7 +3641,7 @@ class TemplateNodeExtend : public TemplateNodeCreator<TemplateNodeExtend> } else { - ci->warn(m_templateName,m_line,"failed to load template %s for extend",extendFile.data()); + ci->warn(m_templateName,m_line,"failed to load template %s for extend",qPrint(extendFile)); } } } @@ -3552,7 +3658,7 @@ class TemplateNodeInclude : public TemplateNodeCreator<TemplateNodeInclude> TemplateNodeInclude(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data) : TemplateNodeCreator<TemplateNodeInclude>(parser,parent,line) { - TRACE(("TemplateNodeInclude(%s)\n",data.data())); + TRACE(("TemplateNodeInclude(%s)\n",qPrint(data))); ExpressionParser ep(parser,line); if (data.isEmpty()) { @@ -3564,7 +3670,7 @@ class TemplateNodeInclude : public TemplateNodeCreator<TemplateNodeInclude> { delete m_includeExpr; } - void render(FTextStream &ts, TemplateContext *c) + void render(TextStream &ts, TemplateContext *c) { TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c); if (ci==0) return; // should not happen @@ -3590,7 +3696,7 @@ class TemplateNodeInclude : public TemplateNodeCreator<TemplateNodeInclude> } else { - ci->warn(m_templateName,m_line,"failed to load template '%s' for include",includeFile.data()?includeFile.data():""); + ci->warn(m_templateName,m_line,"failed to load template '%s' for include",qPrint(includeFile)); } } } @@ -3603,22 +3709,18 @@ class TemplateNodeInclude : public TemplateNodeCreator<TemplateNodeInclude> //---------------------------------------------------------- -static void stripLeadingWhiteSpace(QGString &s) +static void stripLeadingWhiteSpace(QCString &s) { - const char *src = s.data(); - if (src) + uint i=0, dstIdx=0, l=s.length(); + bool skipSpaces=true; + while (i<l) { - char *dst = s.data(); - char c; - bool skipSpaces=TRUE; - while ((c=*src++)) - { - if (c=='\n') { *dst++=c; skipSpaces=TRUE; } - else if (c==' ' && skipSpaces) {} - else { *dst++=c; skipSpaces=FALSE; } - } - *dst='\0'; + char c = s[i++]; + if (c=='\n') { s[dstIdx++]=c; skipSpaces=true; } + else if (c==' ' && skipSpaces) {} + else { s[dstIdx++] = c; skipSpaces=false; } } + s.resize(dstIdx+1); } /** @brief Class representing an 'create' tag in a template */ @@ -3628,7 +3730,7 @@ class TemplateNodeCreate : public TemplateNodeCreator<TemplateNodeCreate> TemplateNodeCreate(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data) : TemplateNodeCreator<TemplateNodeCreate>(parser,parent,line), m_templateExpr(0), m_fileExpr(0) { - TRACE(("TemplateNodeCreate(%s)\n",data.data())); + TRACE(("TemplateNodeCreate(%s)\n",qPrint(data))); if (data.isEmpty()) { parser->warn(m_templateName,line,"create tag is missing arguments"); @@ -3661,7 +3763,7 @@ class TemplateNodeCreate : public TemplateNodeCreator<TemplateNodeCreate> delete m_templateExpr; delete m_fileExpr; } - void render(FTextStream &, TemplateContext *c) + void render(TextStream &, TemplateContext *c) { TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c); if (ci==0) return; // should not happen @@ -3694,21 +3796,21 @@ class TemplateNodeCreate : public TemplateNodeCreator<TemplateNodeCreate> TemplateImpl *createTemplate = ct ? dynamic_cast<TemplateImpl*>(ct) : 0; if (createTemplate) { - mkpath(ci,outputFile); + mkpath(ci,outputFile.str()); if (!ci->outputDirectory().isEmpty()) { outputFile.prepend(ci->outputDirectory()+"/"); } - //printf("NoteCreate(%s)\n",outputFile.data()); - QFile f(outputFile); - if (f.open(IO_WriteOnly)) + //printf("NoteCreate(%s)\n",qPrint(outputFile)); + std::ofstream f(outputFile.str(),std::ofstream::out | std::ofstream::binary); + if (f.is_open()) { + TextStream ts(&f); TemplateEscapeIntf *escIntf = ci->escapeIntf(); ci->selectEscapeIntf(extension); - FTextStream ts(&f); - QGString out; - FTextStream os(&out); + TextStream os; createTemplate->render(os,c); + QCString out = os.str(); stripLeadingWhiteSpace(out); ts << out; t->engine()->unload(t); @@ -3716,12 +3818,12 @@ class TemplateNodeCreate : public TemplateNodeCreator<TemplateNodeCreate> } else { - ci->warn(m_templateName,m_line,"failed to open output file '%s' for create command",outputFile.data()); + ci->warn(m_templateName,m_line,"failed to open output file '%s' for create command",qPrint(outputFile)); } } else { - ci->warn(m_templateName,m_line,"failed to load template '%s' for include",templateFile.data()); + ci->warn(m_templateName,m_line,"failed to load template '%s' for include",qPrint(templateFile)); } t->engine()->setOutputExtension(""); } @@ -3751,18 +3853,17 @@ class TemplateNodeTree : public TemplateNodeCreator<TemplateNodeTree> TemplateNodeTree(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data) : TemplateNodeCreator<TemplateNodeTree>(parser,parent,line) { - TRACE(("{TemplateNodeTree(%s)\n",data.data())); + TRACE(("{TemplateNodeTree(%s)\n",qPrint(data))); ExpressionParser ep(parser,line); if (data.isEmpty()) { parser->warn(m_templateName,line,"recursetree tag is missing data argument"); } m_treeExpr = ep.parse(data); - QStrList stopAt; - stopAt.append("endrecursetree"); + StringVector stopAt = { "endrecursetree" }; parser->parse(this,line,stopAt,m_treeNodes); parser->removeNextToken(); // skip over endrecursetree - TRACE(("}TemplateNodeTree(%s)\n",data.data())); + TRACE(("}TemplateNodeTree(%s)\n",qPrint(data))); } ~TemplateNodeTree() { @@ -3780,8 +3881,7 @@ class TemplateNodeTree : public TemplateNodeCreator<TemplateNodeTree> TemplateContext *c = ctx->templateCtx; TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c); if (ci==0) return QCString(); // should not happen - QGString result; - FTextStream ss(&result); + TextStream ss; c->push(); TemplateVariant node; TemplateListIntf::ConstIterator *it = ctx->list->createIterator(); @@ -3799,7 +3899,7 @@ class TemplateNodeTree : public TemplateNodeCreator<TemplateNodeTree> if (list && list->count()>0) // non-empty list { TreeContext childCtx(this,list,ctx->templateCtx); - TemplateVariant children(TemplateVariant::Delegate::fromFunction(&childCtx,renderChildrenStub)); + TemplateVariant children(TemplateVariant::FunctionDelegate::fromFunction(&childCtx,renderChildrenStub)); children.setRaw(TRUE); c->set("children",children); m_treeNodes.render(ss,c); @@ -3807,7 +3907,7 @@ class TemplateNodeTree : public TemplateNodeCreator<TemplateNodeTree> } else if (list==0) { - ci->warn(m_templateName,m_line,"recursetree: children attribute has type '%s' instead of list\n",v.typeAsString().data()); + ci->warn(m_templateName,m_line,"recursetree: children attribute has type '%s' instead of list\n",qPrint(v.typeAsString())); } } //else @@ -3823,9 +3923,9 @@ class TemplateNodeTree : public TemplateNodeCreator<TemplateNodeTree> } c->pop(); delete it; - return result.data(); + return ss.str(); } - void render(FTextStream &ts, TemplateContext *c) + void render(TextStream &ts, TemplateContext *c) { //printf("TemplateNodeTree::render()\n"); TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c); @@ -3856,17 +3956,15 @@ class TemplateNodeIndexEntry : public TemplateNodeCreator<TemplateNodeIndexEntry { struct Mapping { - Mapping(const QCString &n,ExprAst *e) : name(n), value(e) {} - ~Mapping() { delete value; } + Mapping(const QCString &n,std::unique_ptr<ExprAst> &&e) : name(n), value(std::move(e)) {} QCString name; - ExprAst *value = 0; + std::unique_ptr<ExprAst> value = 0; }; public: TemplateNodeIndexEntry(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data) : TemplateNodeCreator<TemplateNodeIndexEntry>(parser,parent,line) { - TRACE(("{TemplateNodeIndexEntry(%s)\n",data.data())); - m_args.setAutoDelete(TRUE); + TRACE(("{TemplateNodeIndexEntry(%s)\n",qPrint(data))); ExpressionParser expParser(parser,line); std::vector<QCString> args = split(data," "); auto it = args.begin(); @@ -3887,38 +3985,36 @@ class TemplateNodeIndexEntry : public TemplateNodeCreator<TemplateNodeIndexEntry ExprAst *expr = expParser.parse(arg.mid(j+1)); if (expr) { - m_args.append(new Mapping(arg.left(j),expr)); + m_args.emplace_back(arg.left(j),std::unique_ptr<ExprAst>(expr)); } } else { - parser->warn(parser->templateName(),line,"invalid argument '%s' for indexentry tag",arg.data()); + parser->warn(parser->templateName(),line,"invalid argument '%s' for indexentry tag",qPrint(arg)); } ++it; } } - TRACE(("}TemplateNodeIndexEntry(%s)\n",data.data())); + TRACE(("}TemplateNodeIndexEntry(%s)\n",qPrint(data))); } - void render(FTextStream &, TemplateContext *c) + void render(TextStream &, TemplateContext *c) { TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c); if (ci==0) return; // should not happen if (!m_name.isEmpty()) { ci->setLocation(m_templateName,m_line); - QListIterator<Mapping> it(m_args); - Mapping *mapping; std::vector<TemplateKeyValue> list; - for (it.toFirst();(mapping=it.current());++it) + for (const auto &mapping : m_args) { - list.push_back(TemplateKeyValue(mapping->name,mapping->value->resolve(c))); + list.emplace_back(mapping.name,mapping.value->resolve(c)); } ci->addIndexEntry(m_name,list); } } private: QCString m_name; - QList<Mapping> m_args; + std::vector<Mapping> m_args; }; //---------------------------------------------------------- @@ -3930,7 +4026,7 @@ class TemplateNodeOpenSubIndex : public TemplateNodeCreator<TemplateNodeOpenSubI TemplateNodeOpenSubIndex(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data) : TemplateNodeCreator<TemplateNodeOpenSubIndex>(parser,parent,line) { - TRACE(("{TemplateNodeOpenSubIndex(%s)\n",data.data())); + TRACE(("{TemplateNodeOpenSubIndex(%s)\n",qPrint(data))); m_name = data.stripWhiteSpace(); if (m_name.isEmpty()) { @@ -3938,12 +4034,12 @@ class TemplateNodeOpenSubIndex : public TemplateNodeCreator<TemplateNodeOpenSubI } else if (m_name.find(' ')!=-1) { - parser->warn(parser->templateName(),line,"Expected single argument for opensubindex tag got '%s'",data.data()); + parser->warn(parser->templateName(),line,"Expected single argument for opensubindex tag got '%s'",qPrint(data)); m_name=""; } - TRACE(("}TemplateNodeOpenSubIndex(%s)\n",data.data())); + TRACE(("}TemplateNodeOpenSubIndex(%s)\n",qPrint(data))); } - void render(FTextStream &, TemplateContext *c) + void render(TextStream &, TemplateContext *c) { TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c); if (ci==0) return; // should not happen @@ -3966,7 +4062,7 @@ class TemplateNodeCloseSubIndex : public TemplateNodeCreator<TemplateNodeCloseSu TemplateNodeCloseSubIndex(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data) : TemplateNodeCreator<TemplateNodeCloseSubIndex>(parser,parent,line) { - TRACE(("{TemplateNodeCloseSubIndex(%s)\n",data.data())); + TRACE(("{TemplateNodeCloseSubIndex(%s)\n",qPrint(data))); m_name = data.stripWhiteSpace(); if (m_name.isEmpty()) { @@ -3974,12 +4070,12 @@ class TemplateNodeCloseSubIndex : public TemplateNodeCreator<TemplateNodeCloseSu } else if (m_name.find(' ')!=-1 || m_name.isEmpty()) { - parser->warn(parser->templateName(),line,"Expected single argument for closesubindex tag got '%s'",data.data()); + parser->warn(parser->templateName(),line,"Expected single argument for closesubindex tag got '%s'",qPrint(data)); m_name=""; } - TRACE(("}TemplateNodeCloseSubIndex(%s)\n",data.data())); + TRACE(("}TemplateNodeCloseSubIndex(%s)\n",qPrint(data))); } - void render(FTextStream &, TemplateContext *c) + void render(TextStream &, TemplateContext *c) { TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c); if (ci==0) return; // should not happen @@ -4001,19 +4097,18 @@ class TemplateNodeWith : public TemplateNodeCreator<TemplateNodeWith> { struct Mapping { - Mapping(const QCString &n,ExprAst *e) : name(n), value(e) {} - ~Mapping() { delete value; } + Mapping(const QCString &n,std::unique_ptr<ExprAst> &&e) : name(n), value(std::move(e)) {} QCString name; - ExprAst *value; + std::unique_ptr<ExprAst> value; }; public: TemplateNodeWith(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data) : TemplateNodeCreator<TemplateNodeWith>(parser,parent,line) { - TRACE(("{TemplateNodeWith(%s)\n",data.data())); - m_args.setAutoDelete(TRUE); + TRACE(("{TemplateNodeWith(%s)\n",qPrint(data))); ExpressionParser expParser(parser,line); - QCString filteredData = removeSpacesAroundEquals(data); + QCString filteredData = data; + removeSpacesAroundEquals(filteredData); std::vector<QCString> args = split(filteredData," "); auto it = args.begin(); while (it!=args.end()) @@ -4025,43 +4120,40 @@ class TemplateNodeWith : public TemplateNodeCreator<TemplateNodeWith> ExprAst *expr = expParser.parse(arg.mid(j+1)); if (expr) { - m_args.append(new Mapping(arg.left(j),expr)); + m_args.emplace_back(arg.left(j),std::unique_ptr<ExprAst>(expr)); } } else { - parser->warn(parser->templateName(),line,"invalid argument '%s' for 'with' tag",arg.data()); + parser->warn(parser->templateName(),line,"invalid argument '%s' for 'with' tag",qPrint(arg)); } ++it; } - QStrList stopAt; - stopAt.append("endwith"); + StringVector stopAt = { "endwith" }; parser->parse(this,line,stopAt,m_nodes); parser->removeNextToken(); // skip over endwith - TRACE(("}TemplateNodeWith(%s)\n",data.data())); + TRACE(("}TemplateNodeWith(%s)\n",qPrint(data))); } ~TemplateNodeWith() { } - void render(FTextStream &ts, TemplateContext *c) + void render(TextStream &ts, TemplateContext *c) { TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c); if (ci==0) return; // should not happen ci->setLocation(m_templateName,m_line); c->push(); - QListIterator<Mapping> it(m_args); - Mapping *mapping; - for (it.toFirst();(mapping=it.current());++it) + for (const auto &mapping : m_args) { - TemplateVariant value = mapping->value->resolve(c); - ci->set(mapping->name,value); + TemplateVariant value = mapping.value->resolve(c); + ci->set(mapping.name,value); } m_nodes.render(ts,c); c->pop(); } private: TemplateNodeList m_nodes; - QList<Mapping> m_args; + std::vector<Mapping> m_args; }; //---------------------------------------------------------- @@ -4073,8 +4165,7 @@ class TemplateNodeCycle : public TemplateNodeCreator<TemplateNodeCycle> TemplateNodeCycle(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data) : TemplateNodeCreator<TemplateNodeCycle>(parser,parent,line) { - TRACE(("{TemplateNodeCycle(%s)\n",data.data())); - m_args.setAutoDelete(TRUE); + TRACE(("{TemplateNodeCycle(%s)\n",qPrint(data))); m_index=0; ExpressionParser expParser(parser,line); std::vector<QCString> args = split(data," "); @@ -4084,24 +4175,25 @@ class TemplateNodeCycle : public TemplateNodeCreator<TemplateNodeCycle> ExprAst *expr = expParser.parse(*it); if (expr) { - m_args.append(expr); + m_args.push_back(std::unique_ptr<ExprAst>(expr)); } ++it; } - if (m_args.count()<2) + if (m_args.size()<2) { - parser->warn(parser->templateName(),line,"expected at least two arguments for cycle command, got %d",m_args.count()); + parser->warn(parser->templateName(),line,"expected at least two arguments for cycle command, got %zu",m_args.size()); } - TRACE(("}TemplateNodeCycle(%s)\n",data.data())); + TRACE(("}TemplateNodeCycle(%s)\n",qPrint(data))); } - void render(FTextStream &ts, TemplateContext *c) + void render(TextStream &ts, TemplateContext *c) { TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c); + if (ci==0) return; // should not happen ci->setLocation(m_templateName,m_line); - if (m_index<m_args.count()) + if (m_index<m_args.size()) { - TemplateVariant v = m_args.at(m_index)->resolve(c); - if (v.type()==TemplateVariant::Function) + TemplateVariant v = m_args[m_index]->resolve(c); + if (v.isFunction()) { v = v.call(std::vector<TemplateVariant>()); } @@ -4128,14 +4220,14 @@ class TemplateNodeCycle : public TemplateNodeCreator<TemplateNodeCycle> } } } - if (++m_index==m_args.count()) // wrap around + if (++m_index==m_args.size()) // wrap around { m_index=0; } } private: - uint m_index = 0; - QList<ExprAst> m_args; + size_t m_index = 0; + ExprAstList m_args; }; //---------------------------------------------------------- @@ -4152,24 +4244,23 @@ class TemplateNodeSet : public TemplateNodeCreator<TemplateNodeSet> }; public: TemplateNodeSet(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data) - : TemplateNodeCreator<TemplateNodeSet>(parser,parent,line), m_mapping(0) + : TemplateNodeCreator<TemplateNodeSet>(parser,parent,line) { - TRACE(("{TemplateNodeSet(%s)\n",data.data())); + TRACE(("{TemplateNodeSet(%s)\n",qPrint(data))); ExpressionParser expParser(parser,line); // data format: name=expression int j=data.find('='); ExprAst *expr = 0; if (j>0 && (expr = expParser.parse(data.mid(j+1)))) { - m_mapping = new Mapping(data.left(j),expr); + m_mapping = std::make_unique<Mapping>(data.left(j),expr); } - TRACE(("}TemplateNodeSet(%s)\n",data.data())); + TRACE(("}TemplateNodeSet(%s)\n",qPrint(data))); } ~TemplateNodeSet() { - delete m_mapping; } - void render(FTextStream &, TemplateContext *c) + void render(TextStream &, TemplateContext *c) { TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c); if (ci==0) return; // should not happen @@ -4181,7 +4272,7 @@ class TemplateNodeSet : public TemplateNodeCreator<TemplateNodeSet> } } private: - Mapping *m_mapping = 0; + std::unique_ptr<Mapping> m_mapping; }; //---------------------------------------------------------- @@ -4194,13 +4285,12 @@ class TemplateNodeSpaceless : public TemplateNodeCreator<TemplateNodeSpaceless> : TemplateNodeCreator<TemplateNodeSpaceless>(parser,parent,line) { TRACE(("{TemplateNodeSpaceless()\n")); - QStrList stopAt; - stopAt.append("endspaceless"); + StringVector stopAt = { "endspaceless" }; parser->parse(this,line,stopAt,m_nodes); parser->removeNextToken(); // skip over endwith TRACE(("}TemplateNodeSpaceless()\n")); } - void render(FTextStream &ts, TemplateContext *c) + void render(TextStream &ts, TemplateContext *c) { TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c); if (ci==0) return; // should not happen @@ -4223,7 +4313,7 @@ class TemplateNodeMarkers : public TemplateNodeCreator<TemplateNodeMarkers> TemplateNodeMarkers(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data) : TemplateNodeCreator<TemplateNodeMarkers>(parser,parent,line), m_listExpr(0), m_patternExpr(0) { - TRACE(("{TemplateNodeMarkers(%s)\n",data.data())); + TRACE(("{TemplateNodeMarkers(%s)\n",qPrint(data))); int i = data.find(" in "); int w = data.find(" with "); if (i==-1 || w==-1 || w<i) @@ -4237,18 +4327,17 @@ class TemplateNodeMarkers : public TemplateNodeCreator<TemplateNodeMarkers> m_listExpr = expParser.parse(data.mid(i+4,w-i-4)); m_patternExpr = expParser.parse(data.right(data.length()-w-6)); } - QStrList stopAt; - stopAt.append("endmarkers"); + StringVector stopAt = { "endmarkers" }; parser->parse(this,line,stopAt,m_nodes); parser->removeNextToken(); // skip over endmarkers - TRACE(("}TemplateNodeMarkers(%s)\n",data.data())); + TRACE(("}TemplateNodeMarkers(%s)\n",qPrint(data))); } ~TemplateNodeMarkers() { delete m_listExpr; delete m_patternExpr; } - void render(FTextStream &ts, TemplateContext *c) + void render(TextStream &ts, TemplateContext *c) { TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c); if (ci==0) return; // should not happen @@ -4260,30 +4349,36 @@ class TemplateNodeMarkers : public TemplateNodeCreator<TemplateNodeMarkers> TemplateVariant patternStr = m_patternExpr->resolve(c); if (list) { - if (patternStr.type()==TemplateVariant::String) + if (patternStr.isString()) { TemplateListIntf::ConstIterator *it = list->createIterator(); c->push(); - QCString str = patternStr.toString(); - QRegExp marker("@[0-9]+"); // pattern for a marker, i.e. @0, @1 ... @12, etc - int index=0,newIndex,matchLen; - while ((newIndex=marker.match(str,index,&matchLen))!=-1) + std::string str = patternStr.toString().str(); + + static const reg::Ex marker(R"(@\d+)"); + reg::Iterator re_it(str,marker); + reg::Iterator end; + size_t index=0; + for ( ; re_it!=end ; ++re_it) { + const auto &match = *re_it; + size_t newIndex = match.position(); + size_t matchLen = match.length(); + std::string part = str.substr(index,newIndex-index); if (ci->needsRecoding()) { - ts << ci->recode(str.mid(index,newIndex-index)); // write text before marker + ts << ci->recode(QCString(part)); // write text before marker } else { - ts << str.mid(index,newIndex-index); // write text before marker + ts << part; // write text before marker } - bool ok; - uint entryIndex = str.mid(newIndex+1,matchLen-1).toUInt(&ok); // get marker id + unsigned long entryIndex = std::stoul(match.str().substr(1)); TemplateVariant var; - uint i=0; + size_t i=0; // search for list element at position id for (it->toFirst(); (it->current(var)) && i<entryIndex; it->toNext(),i++) {} - if (ok && i==entryIndex) // found element + if (i==entryIndex) // found element { TemplateAutoRef<TemplateStruct> s(TemplateStruct::alloc()); s->set("id",(int)i); @@ -4294,10 +4389,6 @@ class TemplateNodeMarkers : public TemplateNodeCreator<TemplateNodeMarkers> m_nodes.render(ts,c); ci->enableSpaceless(wasSpaceless); } - else if (!ok) - { - ci->warn(m_templateName,m_line,"markers pattern string has invalid markers '%s'",str.data()); - } else if (i<entryIndex) { ci->warn(m_templateName,m_line,"markers list does not an element for marker position %d",i); @@ -4306,11 +4397,11 @@ class TemplateNodeMarkers : public TemplateNodeCreator<TemplateNodeMarkers> } if (ci->needsRecoding()) { - ts << ci->recode(str.right(str.length()-index)); // write text after last marker + ts << ci->recode(str.substr(index)); // write text after last marker } else { - ts << str.right(str.length()-index); // write text after last marker + ts << str.substr(index); // write text after last marker } c->pop(); delete it; @@ -4343,13 +4434,12 @@ class TemplateNodeTabbing : public TemplateNodeCreator<TemplateNodeTabbing> : TemplateNodeCreator<TemplateNodeTabbing>(parser,parent,line) { TRACE(("{TemplateNodeTabbing()\n")); - QStrList stopAt; - stopAt.append("endtabbing"); + StringVector stopAt = { "endtabbing" }; parser->parse(this,line,stopAt,m_nodes); parser->removeNextToken(); // skip over endtabbing TRACE(("}TemplateNodeTabbing()\n")); } - void render(FTextStream &ts, TemplateContext *c) + void render(TextStream &ts, TemplateContext *c) { TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c); if (ci==0) return; // should not happen @@ -4372,7 +4462,7 @@ class TemplateNodeResource : public TemplateNodeCreator<TemplateNodeResource> TemplateNodeResource(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data) : TemplateNodeCreator<TemplateNodeResource>(parser,parent,line) { - TRACE(("{TemplateNodeResource(%s)\n",data.data())); + TRACE(("{TemplateNodeResource(%s)\n",qPrint(data))); ExpressionParser ep(parser,line); int i; if (data.isEmpty()) @@ -4386,19 +4476,25 @@ class TemplateNodeResource : public TemplateNodeCreator<TemplateNodeResource> m_resExpr = ep.parse(data.left(i)); // part before as m_asExpr = ep.parse(data.mid(i+4)); // part after as } + else if ((i=data.find(" append "))!=-1) // resource a appends to b + { + m_resExpr = ep.parse(data.left(i)); // part before append + m_asExpr = ep.parse(data.mid(i+8)); // part after append + m_append = true; + } else // resource a { m_resExpr = ep.parse(data); m_asExpr = 0; } - TRACE(("}TemplateNodeResource(%s)\n",data.data())); + TRACE(("}TemplateNodeResource(%s)\n",qPrint(data))); } ~TemplateNodeResource() { delete m_resExpr; delete m_asExpr; } - void render(FTextStream &, TemplateContext *c) + void render(TextStream &, TemplateContext *c) { TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c); if (ci==0) return; // should not happen @@ -4416,13 +4512,14 @@ class TemplateNodeResource : public TemplateNodeCreator<TemplateNodeResource> if (m_asExpr) { QCString targetFile = m_asExpr->resolve(c).toString(); - mkpath(ci,targetFile); + mkpath(ci,targetFile.str()); if (targetFile.isEmpty()) - { ci->warn(m_templateName,m_line,"invalid parameter at right side of 'as' for resource command\n"); + { + ci->warn(m_templateName,m_line,"invalid parameter at right side of '%s' for resource command\n", m_append ? "append" : "as"); } else { - ResourceMgr::instance().copyResourceAs(resourceFile,outputDirectory,targetFile); + ResourceMgr::instance().copyResourceAs(resourceFile,outputDirectory,targetFile,m_append); } } else @@ -4435,6 +4532,7 @@ class TemplateNodeResource : public TemplateNodeCreator<TemplateNodeResource> private: ExprAst *m_resExpr = 0; ExprAst *m_asExpr = 0; + bool m_append = false; }; //---------------------------------------------------------- @@ -4446,7 +4544,7 @@ class TemplateNodeEncoding : public TemplateNodeCreator<TemplateNodeEncoding> TemplateNodeEncoding(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data) : TemplateNodeCreator<TemplateNodeEncoding>(parser,parent,line) { - TRACE(("{TemplateNodeEncoding(%s)\n",data.data())); + TRACE(("{TemplateNodeEncoding(%s)\n",qPrint(data))); ExpressionParser ep(parser,line); if (data.isEmpty()) { @@ -4457,17 +4555,16 @@ class TemplateNodeEncoding : public TemplateNodeCreator<TemplateNodeEncoding> { m_encExpr = ep.parse(data); } - QStrList stopAt; - stopAt.append("endencoding"); + StringVector stopAt = { "endencoding" }; parser->parse(this,line,stopAt,m_nodes); parser->removeNextToken(); // skip over endencoding - TRACE(("}TemplateNodeEncoding(%s)\n",data.data())); + TRACE(("}TemplateNodeEncoding(%s)\n",qPrint(data))); } ~TemplateNodeEncoding() { delete m_encExpr; } - void render(FTextStream &ts, TemplateContext *c) + void render(TextStream &ts, TemplateContext *c) { TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c); if (ci==0) return; // should not happen @@ -4514,13 +4611,14 @@ class TemplateNodeFactory int line, const QCString &data) { - if (m_registry.find(name)==0) return 0; - return ((CreateFunc)m_registry[name])(parser,parent,line,data); + auto it = m_registry.find(name.str()); + if (it==m_registry.end()) return 0; + return it->second(parser,parent,line,data); } void registerTemplateNode(const QCString &name,CreateFunc func) { - m_registry.insert(name,(void*)func); + m_registry.insert(std::make_pair(name.str(),func)); } /** @brief Helper class for registering a template AST node */ @@ -4534,7 +4632,7 @@ class TemplateNodeFactory }; private: - QDict<void> m_registry; + std::unordered_map<std::string,CreateFunc> m_registry; }; // register a handler for each start tag we support @@ -4562,57 +4660,53 @@ static TemplateNodeFactory::AutoRegister<TemplateNodeCloseSubIndex> autoRefClose //---------------------------------------------------------- -TemplateBlockContext::TemplateBlockContext() : m_blocks(257) +TemplateBlockContext::TemplateBlockContext() { - m_blocks.setAutoDelete(TRUE); } TemplateNodeBlock *TemplateBlockContext::get(const QCString &name) const { - QList<TemplateNodeBlock> *list = m_blocks.find(name); - if (list==0 || list->count()==0) + auto it = m_blocks.find(name.str()); + if (it==m_blocks.end() || it->second.empty()) { return 0; } else { - return list->getLast(); + return it->second.back(); } } -TemplateNodeBlock *TemplateBlockContext::pop(const QCString &name) const +TemplateNodeBlock *TemplateBlockContext::pop(const QCString &name) { - QList<TemplateNodeBlock> *list = m_blocks.find(name); - if (list==0 || list->count()==0) + auto it = m_blocks.find(name.str()); + if (it==m_blocks.end() || it->second.empty()) { return 0; } else { - return list->take(list->count()-1); + TemplateNodeBlock *bld = it->second.back(); + it->second.pop_back(); + return bld; } } void TemplateBlockContext::add(TemplateNodeBlock *block) { - QList<TemplateNodeBlock> *list = m_blocks.find(block->name()); - if (list==0) + auto it = m_blocks.find(block->name().str()); + if (it==m_blocks.end()) { - list = new QList<TemplateNodeBlock>; - m_blocks.insert(block->name(),list); + it = m_blocks.insert(std::make_pair(block->name().str(),NodeBlockList())).first; } - list->prepend(block); + it->second.push_front(block); } void TemplateBlockContext::add(TemplateBlockContext *ctx) { - QDictIterator< QList<TemplateNodeBlock> > di(ctx->m_blocks); - QList<TemplateNodeBlock> *list; - for (di.toFirst();(list=di.current());++di) + for (auto &kv : ctx->m_blocks) { - QListIterator<TemplateNodeBlock> li(*list); - TemplateNodeBlock *nb; - for (li.toFirst();(nb=li.current());++li) + for (auto &nb : kv.second) { add(nb); } @@ -4626,13 +4720,12 @@ void TemplateBlockContext::clear() void TemplateBlockContext::push(TemplateNodeBlock *block) { - QList<TemplateNodeBlock> *list = m_blocks.find(block->name()); - if (list==0) + auto it = m_blocks.find(block->name().str()); + if (it==m_blocks.end()) { - list = new QList<TemplateNodeBlock>; - m_blocks.insert(block->name(),list); + it = m_blocks.insert(std::make_pair(block->name().str(),NodeBlockList())).first; } - list->append(block); + it->second.push_back(block); } @@ -4643,12 +4736,12 @@ class TemplateLexer { public: TemplateLexer(const TemplateEngine *engine,const QCString &fileName,const QCString &data); - void tokenize(QList<TemplateToken> &tokens); + void tokenize(TemplateTokenStream &tokens); void setOpenCloseCharacters(char openChar,char closeChar) { m_openChar=openChar; m_closeChar=closeChar; } private: - void addToken(QList<TemplateToken> &tokens, - const char *data,int line,int startPos,int endPos, + void addToken(TemplateTokenStream &tokens, + const QCString &data,int line,int startPos,int endPos, TemplateToken::Type type); void reset(); const TemplateEngine *m_engine = 0; @@ -4665,7 +4758,7 @@ TemplateLexer::TemplateLexer(const TemplateEngine *engine,const QCString &fileNa m_closeChar='}'; } -void TemplateLexer::tokenize(QList<TemplateToken> &tokens) +void TemplateLexer::tokenize(TemplateTokenStream &tokens) { enum LexerStates { @@ -4680,8 +4773,8 @@ void TemplateLexer::tokenize(QList<TemplateToken> &tokens) StateEndVariable }; + if (m_data.isEmpty()) return; const char *p=m_data.data(); - if (p==0) return; int state=StateText; int pos=0; int lastTokenPos=0; @@ -4748,10 +4841,10 @@ void TemplateLexer::tokenize(QList<TemplateToken> &tokens) { // found tag! state=StateText; - addToken(tokens,m_data.data(),line,lastTokenPos, + addToken(tokens,m_data,line,lastTokenPos, emptyOutputLine ? startLinePos : markStartPos, TemplateToken::Text); - addToken(tokens,m_data.data(),line,markStartPos+2, + addToken(tokens,m_data,line,markStartPos+2, pos-1,TemplateToken::Block); lastTokenPos = pos+1; } @@ -4781,7 +4874,7 @@ void TemplateLexer::tokenize(QList<TemplateToken> &tokens) { // found comment tag! state=StateText; - addToken(tokens,m_data.data(),line,lastTokenPos, + addToken(tokens,m_data,line,lastTokenPos, emptyOutputLine ? startLinePos : markStartPos, TemplateToken::Text); lastTokenPos = pos+1; @@ -4829,10 +4922,10 @@ void TemplateLexer::tokenize(QList<TemplateToken> &tokens) { // found variable tag! state=StateText; - addToken(tokens,m_data.data(),line,lastTokenPos, + addToken(tokens,m_data,line,lastTokenPos, emptyOutputLine ? startLinePos : markStartPos, TemplateToken::Text); - addToken(tokens,m_data.data(),line,markStartPos+2, + addToken(tokens,m_data,line,markStartPos+2, pos-1,TemplateToken::Variable); lastTokenPos = pos+1; } @@ -4862,24 +4955,23 @@ void TemplateLexer::tokenize(QList<TemplateToken> &tokens) } if (lastTokenPos<pos) { - addToken(tokens,m_data.data(),line, + addToken(tokens,m_data,line, lastTokenPos,pos, TemplateToken::Text); } } -void TemplateLexer::addToken(QList<TemplateToken> &tokens, - const char *data,int line, +void TemplateLexer::addToken(TemplateTokenStream &tokens, + const QCString &data,int line, int startPos,int endPos, TemplateToken::Type type) { if (startPos<endPos) { - int len = endPos-startPos+1; - QCString text(len); - qstrncpy(text.rawData(),data+startPos,len); + int len = endPos-startPos; + QCString text = data.mid(startPos,len); if (type!=TemplateToken::Text) text = text.stripWhiteSpace(); - tokens.append(new TemplateToken(type,text,line)); + tokens.push_back(std::make_unique<TemplateToken>(type,text,line)); } } @@ -4887,29 +4979,29 @@ void TemplateLexer::addToken(QList<TemplateToken> &tokens, TemplateParser::TemplateParser(const TemplateEngine *engine, const QCString &templateName, - QList<TemplateToken> &tokens) : + TemplateTokenStream &tokens) : m_engine(engine), m_templateName(templateName), m_tokens(tokens) { } void TemplateParser::parse( - TemplateNode *parent,int line,const QStrList &stopAt, - QList<TemplateNode> &nodes) + TemplateNode *parent,int line,const StringVector &stopAt, + TemplateNodeList &nodes) { TRACE(("{TemplateParser::parse\n")); // process the tokens. Build node list while (hasNextToken()) { - TemplateToken *tok = takeNextToken(); - //printf("%p:Token type=%d data='%s' line=%d\n", - // parent,tok->type,tok->data.data(),tok->line); + auto tok = takeNextToken(); + TRACE(("%p:Token type=%d data='%s' line=%d\n", + (void*)parent,tok->type,qPrint(tok->data),tok->line)); switch(tok->type) { case TemplateToken::Text: - nodes.append(new TemplateNodeText(this,parent,tok->line,tok->data)); + nodes.push_back(std::make_unique<TemplateNodeText>(this,parent,tok->line,tok->data)); break; case TemplateToken::Variable: // {{ var }} - nodes.append(new TemplateNodeVariable(this,parent,tok->line,tok->data)); + nodes.push_back(std::make_unique<TemplateNodeVariable>(this,parent,tok->line,tok->data)); break; case TemplateToken::Block: // {% tag %} { @@ -4919,22 +5011,23 @@ void TemplateParser::parse( { command=command.left(sep); } - if (stopAt.contains(command)) + TemplateToken *tok_ptr = tok.get(); + if (std::find(stopAt.begin(),stopAt.end(),command.str())!=stopAt.end()) { - prependToken(tok); + prependToken(std::move(tok)); TRACE(("}TemplateParser::parse: stop\n")); return; } QCString arg; if (sep!=-1) { - arg = tok->data.mid(sep+1); + arg = tok_ptr->data.mid(sep+1); } - TemplateNode *node = TemplateNodeFactory::instance()-> - create(command,this,parent,tok->line,arg); + std::unique_ptr<TemplateNode> node { TemplateNodeFactory::instance()-> + create(command,this,parent,tok_ptr->line,arg) }; if (node) { - nodes.append(node); + nodes.push_back(std::move(node)); } else if (command=="empty" || command=="else" || command=="endif" || command=="endfor" || @@ -4945,59 +5038,59 @@ void TemplateParser::parse( command=="endrange" || command=="endtabbing" || command=="endencoding") { - warn(m_templateName,tok->line,"Found tag '%s' without matching start tag",command.data()); + warn(m_templateName,tok_ptr->line,"Found tag '%s' without matching start tag",qPrint(command)); } else { - warn(m_templateName,tok->line,"Unknown tag '%s'",command.data()); + warn(m_templateName,tok_ptr->line,"Unknown tag '%s'",qPrint(command)); } } break; } - delete tok; } - if (!stopAt.isEmpty()) + if (!stopAt.empty()) { - QStrListIterator it(stopAt); - const char *s; QCString options; - for (it.toFirst();(s=it.current());++it) + for (const auto &s : stopAt) { if (!options.isEmpty()) options+=", "; - options+=s; + options+=s.c_str(); } warn(m_templateName,line,"Unclosed tag in template, expected one of: %s", - options.data()); + qPrint(options)); } TRACE(("}TemplateParser::parse: last token\n")); } bool TemplateParser::hasNextToken() const { - return !m_tokens.isEmpty(); + return !m_tokens.empty(); } -TemplateToken *TemplateParser::takeNextToken() +TemplateTokenPtr TemplateParser::takeNextToken() { - return m_tokens.take(0); + if (m_tokens.empty()) return TemplateTokenPtr(); + auto tok = std::move(m_tokens.front()); + m_tokens.pop_front(); + return tok; } const TemplateToken *TemplateParser::currentToken() const { - return m_tokens.getFirst(); + return m_tokens.front().get(); } void TemplateParser::removeNextToken() { - m_tokens.removeFirst(); + m_tokens.pop_front(); } -void TemplateParser::prependToken(const TemplateToken *token) +void TemplateParser::prependToken(TemplateTokenPtr &&token) { - m_tokens.prepend(token); + m_tokens.push_front(std::move(token)); } -void TemplateParser::warn(const char *fileName,int line,const char *fmt,...) const +void TemplateParser::warn(const QCString &fileName,int line,const char *fmt,...) const { va_list args; va_start(args,fmt); @@ -5022,33 +5115,30 @@ TemplateImpl::TemplateImpl(TemplateEngine *engine,const QCString &name,const QCS { lexer.setOpenCloseCharacters('<','>'); } - QList<TemplateToken> tokens; - tokens.setAutoDelete(TRUE); + TemplateTokenStream tokens; lexer.tokenize(tokens); TemplateParser parser(engine,name,tokens); - parser.parse(this,1,QStrList(),m_nodes); + parser.parse(this,1,StringVector(),m_nodes); } TemplateImpl::~TemplateImpl() { - //printf("deleting template %s\n",m_name.data()); + //printf("deleting template %s\n",qPrint(m_name)); } -void TemplateImpl::render(FTextStream &ts, TemplateContext *c) +void TemplateImpl::render(TextStream &ts, TemplateContext *c) { TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c); if (ci==0) return; // should not happen - if (!m_nodes.isEmpty()) + if (!m_nodes.empty()) { - TemplateNodeExtend *ne = dynamic_cast<TemplateNodeExtend*>(m_nodes.getFirst()); + TemplateNodeExtend *ne = dynamic_cast<TemplateNodeExtend*>(m_nodes.front().get()); if (ne==0) // normal template, add blocks to block context { TemplateBlockContext *bc = ci->blockContext(); - QListIterator<TemplateNode> li(m_nodes); - TemplateNode *n; - for (li.toFirst();(n=li.current());++li) + for (const auto &n : m_nodes) { - TemplateNodeBlock *nb = dynamic_cast<TemplateNodeBlock*>(n); + TemplateNodeBlock *nb = dynamic_cast<TemplateNodeBlock*>(n.get()); if (nb) { bc->add(nb); @@ -5082,63 +5172,66 @@ class TemplateEngine::Private int m_line = 0; }; public: - Private(TemplateEngine *engine) : m_templateCache(17) /*, m_indent(0)*/, m_engine(engine) + Private(TemplateEngine *engine) : m_engine(engine) { - m_templateCache.setAutoDelete(TRUE); - m_includeStack.setAutoDelete(TRUE); } Template *loadByName(const QCString &fileName,int line) { //for (int i=0;i<m_indent;i++) printf(" "); //m_indent++; - //printf("loadByName(%s,%d) {\n",fileName.data(),line); - m_includeStack.append(new IncludeEntry(IncludeEntry::Template,fileName,QCString(),line)); - Template *templ = m_templateCache.find(fileName); - if (templ==0) // first time template is referenced + //printf("loadByName(%s,%d) {\n",qPrint(fileName),line); + m_includeStack.emplace_back(IncludeEntry::Template,fileName,QCString(),line); + auto kv = m_templateCache.find(fileName.str()); + if (kv==m_templateCache.end()) // first time template is referenced { QCString filePath = m_templateDirName+"/"+fileName; - QFile f(filePath); - if (f.open(IO_ReadOnly)) - { - QFileInfo fi(filePath); - int size=fi.size(); - QCString data(size+1); - if (f.readBlock(data.rawData(),size)==size) - { - templ = new TemplateImpl(m_engine,filePath,data,m_extension); - m_templateCache.insert(fileName,templ); - return templ; - } - } - // fallback to default built-in template - const QCString data = ResourceMgr::instance().getAsString(fileName); - if (!data.isEmpty()) - { - templ = new TemplateImpl(m_engine,fileName,data,m_extension); - m_templateCache.insert(fileName,templ); + std::ifstream f(filePath.str(),std::ifstream::in | std::ifstream::binary); + if (f.is_open()) // read template from disk + { + FileInfo fi(filePath.str()); + int size=(int)fi.size(); + QCString data(size+1); + f.read(data.rawData(),size); + if (!f.fail()) + { + kv = m_templateCache.insert( + std::make_pair(fileName.str(), + std::make_unique<TemplateImpl>(m_engine,filePath,data,m_extension))).first; + } } - else + else // fallback to default built-in template { - err("Could not open template file %s\n",fileName.data()); + const QCString data = ResourceMgr::instance().getAsString(fileName); + if (!data.isEmpty()) + { + kv = m_templateCache.insert( + std::make_pair(fileName.str(), + std::make_unique<TemplateImpl>(m_engine,fileName,data,m_extension))).first; + } + else + { + err("Could not open template file %s\n",qPrint(fileName)); + } } } - return templ; + return kv!=m_templateCache.end() ? kv->second.get() : 0; } + void unload(Template * /*t*/) { //(void)t; //m_indent--; //for (int i=0;i<m_indent;i++) printf(" "); //printf("}\n"); - m_includeStack.removeLast(); + m_includeStack.pop_back(); } void enterBlock(const QCString &fileName,const QCString &blockName,int line) { //for (int i=0;i<m_indent;i++) printf(" "); //m_indent++; - //printf("enterBlock(%s,%s,%d) {\n",fileName.data(),blockName.data(),line); - m_includeStack.append(new IncludeEntry(IncludeEntry::Block,fileName,blockName,line)); + //printf("enterBlock(%s,%s,%d) {\n",qPrint(fileName),qPrint(blockName),line); + m_includeStack.emplace_back(IncludeEntry::Block,fileName,blockName,line); } void leaveBlock() @@ -5146,34 +5239,33 @@ class TemplateEngine::Private //m_indent--; //for (int i=0;i<m_indent;i++) printf(" "); //printf("}\n"); - m_includeStack.removeLast(); + m_includeStack.pop_back(); } - void printIncludeContext(const char *fileName,int line) const + void printIncludeContext(const QCString &fileName,int line) const { - QListIterator<IncludeEntry> li(m_includeStack); - li.toLast(); - IncludeEntry *ie=li.current(); - while ((ie=li.current())) + auto it = m_includeStack.rbegin(); + while (it!=m_includeStack.rend()) { - --li; - IncludeEntry *next=li.current(); - if (ie->type()==IncludeEntry::Template) + const IncludeEntry &ie = *it; + ++it; + const IncludeEntry *next = it!=m_includeStack.rend() ? &(*it) : 0; + if (ie.type()==IncludeEntry::Template) { if (next) { - warn(fileName,line," inside template '%s' included from template '%s' at line %d",ie->fileName().data(),next->fileName().data(),ie->line()); + warn(fileName,line," inside template '%s' included from template '%s' at line %d",qPrint(ie.fileName()),qPrint(next->fileName()),ie.line()); } } - else // ie->type()==IncludeEntry::Block + else // ie.type()==IncludeEntry::Block { - warn(fileName,line," included by block '%s' inside template '%s' at line %d",ie->blockName().data(), - ie->fileName().data(),ie->line()); + warn(fileName,line," included by block '%s' inside template '%s' at line %d",qPrint(ie.blockName()), + qPrint(ie.fileName()),ie.line()); } } } - void setOutputExtension(const char *extension) + void setOutputExtension(const QCString &extension) { m_extension = extension; } @@ -5183,16 +5275,16 @@ class TemplateEngine::Private return m_extension; } - void setTemplateDir(const char *dirName) + void setTemplateDir(const QCString &dirName) { m_templateDirName = dirName; } private: - QDict<Template> m_templateCache; + std::unordered_map< std::string, std::unique_ptr<Template> > m_templateCache; //mutable int m_indent; TemplateEngine *m_engine = 0; - QList<IncludeEntry> m_includeStack; + std::vector<IncludeEntry> m_includeStack; QCString m_extension; QCString m_templateDirName; }; @@ -5237,12 +5329,12 @@ void TemplateEngine::leaveBlock() p->leaveBlock(); } -void TemplateEngine::printIncludeContext(const char *fileName,int line) const +void TemplateEngine::printIncludeContext(const QCString &fileName,int line) const { p->printIncludeContext(fileName,line); } -void TemplateEngine::setOutputExtension(const char *extension) +void TemplateEngine::setOutputExtension(const QCString &extension) { p->setOutputExtension(extension); } @@ -5252,9 +5344,55 @@ QCString TemplateEngine::outputExtension() const return p->outputExtension(); } -void TemplateEngine::setTemplateDir(const char *dirName) +void TemplateEngine::setTemplateDir(const QCString &dirName) { p->setTemplateDir(dirName); } +//----------------------------------------------------------------------------------------- + +QCString TemplateVariant::listToString() const +{ + QCString result="["; + const TemplateListIntf *list = toList(); + if (list) + { + bool first=true; + TemplateVariant ve; + TemplateListIntf::ConstIterator *it = list->createIterator(); + for (it->toFirst();it->current(ve);it->toNext()) + { + if (!first) result+=",\n"; + result+="'"+ve.toString()+"'"; + first=false; + } + delete it; + } + result+="]"; + return result; +} + +QCString TemplateVariant::structToString() const +{ + QCString result="{"; + const TemplateStructIntf *strukt = toStruct(); + if (strukt) + { + bool first=true; + for (const auto &s : strukt->fields()) + { + if (!first) result+=","; + result+=s; + if (dynamic_cast<const TemplateStructWeakRef*>(strukt)==0) // avoid endless recursion + { + result+=":'"; + result+=strukt->get(QCString(s)).toString(); + result+="'"; + } + first=false; + } + } + result+="}"; + return result; +} |