diff options
Diffstat (limited to 'src/template.cpp')
-rw-r--r-- | src/template.cpp | 282 |
1 files changed, 269 insertions, 13 deletions
diff --git a/src/template.cpp b/src/template.cpp index 16d1c98..2590486 100644 --- a/src/template.cpp +++ b/src/template.cpp @@ -305,12 +305,12 @@ int TemplateVariant::toInt() const return result; } -const TemplateStructIntf *TemplateVariant::toStruct() const +TemplateStructIntf *TemplateVariant::toStruct() const { return p->type==Struct ? p->strukt : 0; } -const TemplateListIntf *TemplateVariant::toList() const +TemplateListIntf *TemplateVariant::toList() const { return p->type==List ? p->list : 0; } @@ -624,6 +624,14 @@ class TemplateBlockContext QDict< QList<TemplateNodeBlock> > m_blocks; }; +/** @brief A container to store a key-value pair */ +struct TemplateKeyValue +{ + TemplateKeyValue() {} + TemplateKeyValue(const QCString &k,const TemplateVariant &v) : key(k), value(v) {} + QCString key; + TemplateVariant value; +}; /** @brief Internal class representing the implementation of a template * context */ @@ -650,25 +658,28 @@ class TemplateContextImpl : public TemplateContext { TemplateEscapeIntf **ppIntf = m_escapeIntfDict.find(ext); m_activeEscapeIntf = ppIntf ? *ppIntf : 0; } - void setActiveEscapeIntf(TemplateEscapeIntf *intf) - { m_activeEscapeIntf = intf; } - void setSpacelessIntf(TemplateSpacelessIntf *intf) - { m_spacelessIntf = intf; } + void setActiveEscapeIntf(TemplateEscapeIntf *intf) { m_activeEscapeIntf = intf; } + void setSpacelessIntf(TemplateSpacelessIntf *intf) { m_spacelessIntf = intf; } // internal methods TemplateBlockContext *blockContext(); TemplateVariant getPrimary(const QCString &name) const; void setLocation(const QCString &templateName,int line) { m_templateName=templateName; m_line=line; } - QCString templateName() const { return m_templateName; } - int line() const { return m_line; } - QCString outputDirectory() const { return m_outputDir; } - TemplateEscapeIntf *escapeIntf() const { return m_activeEscapeIntf; } + QCString templateName() const { return m_templateName; } + int line() const { return m_line; } + QCString outputDirectory() const { return m_outputDir; } + TemplateEscapeIntf *escapeIntf() const { return m_activeEscapeIntf; } TemplateSpacelessIntf *spacelessIntf() const { return m_spacelessIntf; } - void enableSpaceless(bool b) { m_spacelessEnabled=b; } - bool spacelessEnabled() const { return m_spacelessEnabled && m_spacelessIntf; } + void enableSpaceless(bool b) { m_spacelessEnabled=b; } + bool spacelessEnabled() const { return m_spacelessEnabled && m_spacelessIntf; } void warn(const char *fileName,int line,const char *fmt,...) const; + // index related functions + void openSubIndex(const QCString &indexName); + void closeSubIndex(const QCString &indexName); + void addIndexEntry(const QCString &indexName,const QValueList<TemplateKeyValue> &arguments); + private: const TemplateEngine *m_engine; QCString m_templateName; @@ -680,6 +691,8 @@ class TemplateContextImpl : public TemplateContext TemplateEscapeIntf *m_activeEscapeIntf; TemplateSpacelessIntf *m_spacelessIntf; bool m_spacelessEnabled; + TemplateAutoRef<TemplateStruct> m_indices; + QDict< QStack<TemplateVariant> > m_indexStacks; }; //----------------------------------------------------------------------------- @@ -1831,11 +1844,13 @@ class TemplateImpl : public TemplateNode, public Template TemplateContextImpl::TemplateContextImpl(const TemplateEngine *e) : m_engine(e), m_templateName("<unknown>"), m_line(1), m_activeEscapeIntf(0), - m_spacelessIntf(0), m_spacelessEnabled(FALSE) + m_spacelessIntf(0), m_spacelessEnabled(FALSE), m_indices(TemplateStruct::alloc()) { + m_indexStacks.setAutoDelete(TRUE); m_contextStack.setAutoDelete(TRUE); m_escapeIntfDict.setAutoDelete(TRUE); push(); + set("index",m_indices.get()); } TemplateContextImpl::~TemplateContextImpl() @@ -1969,6 +1984,102 @@ void TemplateContextImpl::warn(const char *fileName,int line,const char *fmt,... m_engine->printIncludeContext(fileName,line); } +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 + { + warn(m_templateName,m_line,"opensubindex for index %s without preceding indexentry",indexName.data()); + return; + } + // get the parent entry to add the list to + 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)); + entry->set("children",list); + entry->set("is_leaf_node",false); + } +} + +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) + { + warn(m_templateName,m_line,"closesubindex for index %s without matching open",indexName.data()); + } + else // stack->count()>=2 + { + if (stack->top()->type()==TemplateVariant::Struct) + { + delete stack->pop(); // pop struct + delete 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()); + if (entry) + { + entry->set("is_leaf_node",true); + } + } + } +} + +void TemplateContextImpl::addIndexEntry(const QCString &indexName,const QValueList<TemplateKeyValue> &arguments) +{ + QValueListConstIterator<TemplateKeyValue> it = arguments.begin(); + //printf("TemplateContextImpl::addIndexEntry(%s)\n",indexName.data()); + //while (it!=arguments.end()) + //{ + // printf(" key=%s value=%s\n",(*it).key.data(),(*it).value.toString().data()); + // ++it; + //} + QStack<TemplateVariant> *stack = m_indexStacks.find(indexName); + if (!stack) // no stack yet, create it! + { + stack = new QStack<TemplateVariant>; + stack->setAutoDelete(TRUE); + m_indexStacks.insert(indexName,stack); + } + TemplateList *list = 0; + if (stack->isEmpty()) // first item, create empty list and add it to the index + { + list = TemplateList::alloc(); + stack->push(new TemplateVariant(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 + { + // remove current entry from the stack + delete stack->pop(); + } + else // first entry after opensubindex + { + ASSERT(stack->top()->type()==TemplateVariant::List); + } + // get list to add new item + list = dynamic_cast<TemplateList*>(stack->top()->toList()); + } + TemplateStruct *entry = TemplateStruct::alloc(); + // add user specified fields to the entry + for (it=arguments.begin();it!=arguments.end();++it) + { + entry->set((*it).key,(*it).value); + } + entry->set("is_leaf_node",true); + stack->push(new TemplateVariant(entry)); + list->append(entry); +} + //---------------------------------------------------------- /** @brief Class representing a piece of plain text in a template */ @@ -3022,6 +3133,148 @@ class TemplateNodeTree : public TemplateNodeCreator<TemplateNodeTree> //---------------------------------------------------------- +/** @brief Class representing an 'indexentry' tag in a template */ +class TemplateNodeIndexEntry : public TemplateNodeCreator<TemplateNodeIndexEntry> +{ + struct Mapping + { + Mapping(const QCString &n,ExprAst *e) : name(n), value(e) {} + ~Mapping() { delete value; } + QCString name; + ExprAst *value; + }; + 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); + ExpressionParser expParser(parser,line); + QValueList<QCString> args = split(data," "); + QValueListIterator<QCString> it = args.begin(); + if (it==args.end() || (*it).find('=')!=-1) + { + parser->warn(parser->templateName(),line,"Missing name for indexentry tag"); + } + else + { + m_name = *it; + ++it; + while (it!=args.end()) + { + QCString arg = *it; + int j=arg.find('='); + if (j>0) + { + ExprAst *expr = expParser.parse(arg.mid(j+1)); + if (expr) + { + m_args.append(new Mapping(arg.left(j),expr)); + } + } + else + { + parser->warn(parser->templateName(),line,"invalid argument '%s' for indexentry tag",arg.data()); + } + ++it; + } + } + TRACE(("}TemplateNodeIndexEntry(%s)\n",data.data())); + } + void render(FTextStream &, TemplateContext *c) + { + if (!m_name.isEmpty()) + { + TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c); + ci->setLocation(m_templateName,m_line); + QListIterator<Mapping> it(m_args); + Mapping *mapping; + QValueList<TemplateKeyValue> list; + for (it.toFirst();(mapping=it.current());++it) + { + list.append(TemplateKeyValue(mapping->name,mapping->value->resolve(c))); + } + ci->addIndexEntry(m_name,list); + } + } + private: + QCString m_name; + QList<Mapping> m_args; +}; + +//---------------------------------------------------------- + +/** @brief Class representing an 'opensubindex' tag in a template */ +class TemplateNodeOpenSubIndex : public TemplateNodeCreator<TemplateNodeOpenSubIndex> +{ + public: + TemplateNodeOpenSubIndex(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data) + : TemplateNodeCreator<TemplateNodeOpenSubIndex>(parser,parent,line) + { + TRACE(("{TemplateNodeOpenSubIndex(%s)\n",data.data())); + m_name = data.stripWhiteSpace(); + if (m_name.isEmpty()) + { + parser->warn(parser->templateName(),line,"Missing argument for opensubindex tag"); + } + else if (m_name.find(' ')!=-1) + { + parser->warn(parser->templateName(),line,"Expected single argument for opensubindex tag got '%s'",data.data()); + m_name=""; + } + TRACE(("}TemplateNodeOpenSubIndex(%s)\n",data.data())); + } + void render(FTextStream &, TemplateContext *c) + { + if (!m_name.isEmpty()) + { + TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c); + ci->setLocation(m_templateName,m_line); + ci->openSubIndex(m_name); + } + } + private: + QCString m_name; +}; + +//---------------------------------------------------------- + +/** @brief Class representing an 'closesubindex' tag in a template */ +class TemplateNodeCloseSubIndex : public TemplateNodeCreator<TemplateNodeCloseSubIndex> +{ + public: + TemplateNodeCloseSubIndex(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data) + : TemplateNodeCreator<TemplateNodeCloseSubIndex>(parser,parent,line) + { + TRACE(("{TemplateNodeCloseSubIndex(%s)\n",data.data())); + m_name = data.stripWhiteSpace(); + if (m_name.isEmpty()) + { + parser->warn(parser->templateName(),line,"Missing argument for closesubindex tag"); + } + else if (m_name.find(' ')!=-1 || m_name.isEmpty()) + { + parser->warn(parser->templateName(),line,"Expected single argument for closesubindex tag got '%s'",data.data()); + m_name=""; + } + TRACE(("}TemplateNodeCloseSubIndex(%s)\n",data.data())); + } + void render(FTextStream &, TemplateContext *c) + { + if (!m_name.isEmpty()) + { + TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c); + ci->setLocation(m_templateName,m_line); + ci->closeSubIndex(m_name); + } + } + private: + QCString m_name; +}; + + +//---------------------------------------------------------- + /** @brief Class representing an 'with' tag in a template */ class TemplateNodeWith : public TemplateNodeCreator<TemplateNodeWith> { @@ -3395,6 +3648,9 @@ static TemplateNodeFactory::AutoRegister<TemplateNodeRepeat> autoRefRepeat("r static TemplateNodeFactory::AutoRegister<TemplateNodeInclude> autoRefInclude("include"); static TemplateNodeFactory::AutoRegister<TemplateNodeMarkers> autoRefMarkers("markers"); static TemplateNodeFactory::AutoRegister<TemplateNodeSpaceless> autoRefSpaceless("spaceless"); +static TemplateNodeFactory::AutoRegister<TemplateNodeIndexEntry> autoRefIndexEntry("indexentry"); +static TemplateNodeFactory::AutoRegister<TemplateNodeOpenSubIndex> autoRefOpenSubIndex("opensubindex"); +static TemplateNodeFactory::AutoRegister<TemplateNodeCloseSubIndex> autoRefCloseSubIndex("closesubindex"); //---------------------------------------------------------- |