Doxygen
template.cpp
浏览该文件的文档.
1 /******************************************************************************
2  *
3  * Copyright (C) 1997-2015 by Dimitri van Heesch.
4  *
5  * Permission to use, copy, modify, and distribute this software and its
6  * documentation under the terms of the GNU General Public License is hereby
7  * granted. No representations are made about the suitability of this software
8  * for any purpose. It is provided "as is" without express or implied warranty.
9  * See the GNU General Public License for more details.
10  *
11  * Documents produced by Doxygen are derivative works derived from the
12  * input used in their production; they are not affected by this license.
13  *
14  */
15 
16 #include "template.h"
17 
18 #include <vector>
19 #include <algorithm>
20 #include <unordered_map>
21 #include <deque>
22 #include <cstdio>
23 #include <fstream>
24 #include <sstream>
25 
26 #include "message.h"
27 #include "util.h"
28 #include "resourcemgr.h"
29 #include "portable.h"
30 #include "regex.h"
31 #include "fileinfo.h"
32 #include "dir.h"
33 #include "utf8.h"
34 
35 #define ENABLE_TRACING 0
36 
37 #if ENABLE_TRACING
38 #define TRACE(x) printf x
39 #else
40 #define TRACE(x)
41 #endif
42 
43 class TemplateToken;
44 
45 //-------------------------------------------------------------------
46 
47 static std::vector<QCString> split(const QCString &str,const QCString &sep,
48  bool allowEmptyEntries=FALSE,bool cleanup=TRUE)
49 {
50  std::vector<QCString> lst;
51 
52  int j = 0;
53  int i = str.find( sep, j );
54 
55  while (i!=-1)
56  {
57  if ( str.mid(j,i-j).length() > 0 )
58  {
59  if (cleanup)
60  {
61  lst.push_back(str.mid(j,i-j).stripWhiteSpace());
62  }
63  else
64  {
65  lst.push_back(str.mid(j,i-j));
66  }
67  }
68  else if (allowEmptyEntries)
69  {
70  lst.push_back("");
71  }
72  j = i + sep.length();
73  i = str.find(sep,j);
74  }
75 
76  int l = str.length() - 1;
77  if (str.mid(j,l-j+1).length()>0)
78  {
79  if (cleanup)
80  {
81  lst.push_back(str.mid(j,l-j+1).stripWhiteSpace());
82  }
83  else
84  {
85  lst.push_back(str.mid(j,l-j+1));
86  }
87  }
88  else if (allowEmptyEntries)
89  {
90  lst.push_back("");
91  }
92 
93  return lst;
94 }
95 
96 //----------------------------------------------------------------------------
97 
98 /** Strips spaces surrounding `=` from string \a in, so
99  * `foo = 10 bar=5 baz= 'hello'` will become `foo=10 bar=5 baz='hello'`
100  */
102 {
103  //printf(">removeSpacesAroundEquals(%s)\n",qPrint(s));
104  uint i=0, dstIdx=0, l=s.length();
105  while (i<l)
106  {
107  char c = s[i++];
108  if (c==' ')
109  {
110  bool found=false;
111  // look ahead for space or '='
112  uint j=i;
113  while (j<l && (s[j]==' '|| s[j]=='='))
114  {
115  if (s[j]=='=') found=true;
116  j++;
117  }
118  if (found) // found a '=', write it without spaces
119  {
120  c = '=';
121  i=j;
122  }
123  }
124  s[dstIdx++]=c;
125  }
126  s.resize(dstIdx+1);
127  //printf("<removeSpacesAroundEquals(%s)\n",qPrint(s));
128 }
129 
130 //----------------------------------------------------------------------------
131 
132 #if ENABLE_TRACING
133 static QCString replace(const QCString &s,char csrc,char cdst)
134 {
135  QCString result = s;
136  for (uint i=0;i<result.length();i++)
137  {
138  if (result[i]==csrc) result[i]=cdst;
139  }
140  return result;
141 }
142 #endif
143 
144 //- Template struct & list forward declarations ------------------------------
145 
146 class TemplateStruct;
147 using TemplateStructPtr = std::shared_ptr<TemplateStruct>;
148 
149 /** @brief Default implementation of a context value of type struct. */
151 {
152  public:
153  // TemplateStructIntf methods
154  virtual TemplateVariant get(const QCString &name) const;
155  virtual StringVector fields() const;
156 
157  /** Creates an instance and returns a shared pointer to it */
158  static TemplateStructPtr alloc();
159 
160  /** Sets the value the field of a struct
161  * @param[in] name The name of the field.
162  * @param[in] v The value to set.
163  */
164  virtual void set(const QCString &name,const TemplateVariant &v);
165 
166  /** Removes the field from the struct */
167  virtual void remove(const QCString &name);
168 
169  /** Creates a struct */
170  TemplateStruct() = default; //{ printf("%p:TemplateStruct::TemplateStruct()\n",(void*)this); }
171  /** Destroys the struct */
172  virtual ~TemplateStruct() = default; //{ printf("%p:TemplateStruct::~TemplateStruct()\n",(void*)this); }
173 
174  private:
175 
176  std::unordered_map<std::string,TemplateVariant> m_fields;
177 };
178 
179 void TemplateStruct::set(const QCString &name,const TemplateVariant &v)
180 {
181  auto it = m_fields.find(name.str());
182  if (it!=m_fields.end()) // change existing field
183  {
184  it->second = v;
185  }
186  else // insert new field
187  {
188  m_fields.insert(std::make_pair(name.str(),v));
189  }
190 }
191 
193 {
194  auto it = m_fields.find(name.str());
195  if (it!=m_fields.end())
196  {
197  m_fields.erase(it);
198  }
199 }
200 
202 {
203  auto it = m_fields.find(name.str());
204  return it!=m_fields.end() ? it->second : TemplateVariant();
205 }
206 
208 {
209  StringVector result;
210  for (const auto &kv : m_fields)
211  {
212  result.push_back(kv.first);
213  }
214  std::sort(result.begin(),result.end());
215  return result;
216 }
217 
219 {
220  return std::make_shared<TemplateStruct>();
221 }
222 
223 class TemplateList;
224 using TemplateListPtr = std::shared_ptr<TemplateList>;
225 
226 //- Template list implementation ----------------------------------------------
227 
228 // iterator support
229 template<class List>
231 {
232  public:
235  virtual void toFirst()
236  {
237  m_index=0;
238  }
239  virtual void toLast()
240  {
241  uint count = m_list.count();
242  m_index = count>0 ? count-1 : 0;
243  }
244  virtual void toNext()
245  {
246  if (m_index<m_list.count()) { m_index++; }
247  }
248  virtual void toPrev()
249  {
250  if (m_index>0) { --m_index; }
251  }
252  virtual bool current(TemplateVariant &v) const
253  {
254  if (m_index<m_list.count())
255  {
256  v = m_list.at(m_index);
257  return TRUE;
258  }
259  else
260  {
261  v = TemplateVariant();
262  return FALSE;
263  }
264  }
265  private:
266  const List &m_list;
267  size_t m_index = 0;
268 };
269 
270 //-------------------------------------------------------------------------------
271 //
272 /** @brief Default implementation of a context value of type list. */
274 {
275  public:
276  // TemplateListIntf methods
277  virtual uint count() const
278  {
279  return static_cast<uint>(m_elems.size());
280  }
281  virtual TemplateVariant at(uint index) const
282  {
283  return index < m_elems.size() ? m_elems[index] : TemplateVariant();
284  }
286  {
287  return std::make_unique< TemplateListGenericConstIterator<TemplateList> >(*this);
288  }
289 
290  /** Creates an instance and returns a shared pointer to it */
292  {
293  return std::make_shared<TemplateList>();
294  }
295 
296  /** Appends element \a v to the end of the list */
297  virtual void append(const TemplateVariant &v)
298  {
299  m_elems.push_back(v);
300  }
301 
302  void removeAt(uint index)
303  {
304  if (index<m_elems.size())
305  {
306  m_elems.erase(m_elems.begin()+index);
307  }
308  }
309 
310  void insertAt(uint index,TemplateListPtr list)
311  {
312  auto it = m_elems.begin()+index;
313  m_elems.insert(it,list->m_elems.begin(),list->m_elems.end());
314  }
315 
316  /** Creates a list */
317  TemplateList() = default; //{ printf("%p:TemplateList::TemplateList()\n",(void*)this); }
318  /** Destroys the list */
319  virtual ~TemplateList() = default; //{ printf("%p:TemplateList::~TemplateList()\n",(void*)this); }
320 
321  private:
323 };
324 
325 //- TemplateVariant implementation -------------------------------------------
326 
328 {
329  m_raw = std::move(v.m_raw);
330  m_variant = std::move(v.m_variant);
331  v.m_variant.invalidate();
332 }
333 
335 {
336  m_raw = std::move(v.m_raw);
337  m_variant = std::move(v.m_variant);
338  v.m_variant.invalidate();
339  return *this;
340 }
341 
343 {
344  if (!m_variant.valid())
345  {
346  return FALSE;
347  }
348  if (isBool() && other.isBool())
349  {
350  return m_variant.get<static_cast<uint8_t>(Type::Bool)>() == other.m_variant.get<static_cast<uint8_t>(Type::Bool)>();
351  }
352  else if (isInt() && other.isInt())
353  {
354  return m_variant.get<static_cast<uint8_t>(Type::Int)>() == other.m_variant.get<static_cast<uint8_t>(Type::Int)>();
355  }
356  else if (isList() && other.isList())
357  {
358  return toList() == other.toList();
359  }
360  else if ((isStruct() || isWeakStruct()) && (other.isStruct() || other.isWeakStruct()))
361  {
362  return toStruct() == other.toStruct();
363  }
364  return toString()==other.toString();
365 }
366 
368 {
369  switch (type())
370  {
371  case Type::None: return false;
372  case Type::Bool: return m_variant.get<static_cast<uint8_t>(Type::Bool)>();
373  case Type::Int: return m_variant.get<static_cast<uint8_t>(Type::Int)>()!=0;
374  case Type::String: return !m_variant.get<static_cast<uint8_t>(Type::String)>().isEmpty();
375  case Type::Struct: return true;
376  case Type::List: return m_variant.get<static_cast<uint8_t>(Type::List)>()->count()!=0;
377  case Type::Function: return false;
378  case Type::WeakStruct: return true;
379  }
380  return FALSE;
381 }
382 
384 {
385  switch (type())
386  {
387  case Type::None: return 0;
388  case Type::Bool: return m_variant.get<static_cast<uint8_t>(Type::Bool)>() ? 1 : 0;
389  case Type::Int: return m_variant.get<static_cast<uint8_t>(Type::Int)>();
390  case Type::String: return !m_variant.get<static_cast<uint8_t>(Type::String)>().toInt();
391  case Type::Struct: return 0;
392  case Type::List: return m_variant.get<static_cast<uint8_t>(Type::List)>()->count();
393  case Type::Function: return 0;
394  case Type::WeakStruct: return 0;
395  }
396  return 0;
397 }
398 
400 {
401  switch (type())
402  {
403  case Type::None: return QCString();
404  case Type::Bool: return m_variant.get<static_cast<uint8_t>(Type::Bool)>() ? "true" : "false";
405  case Type::Int: return QCString().setNum(m_variant.get<static_cast<uint8_t>(Type::Int)>());
406  case Type::String: return m_variant.get<static_cast<uint8_t>(Type::String)>();
407  case Type::Struct: return structToString();
408  case Type::List: return listToString();
409  case Type::Function: return "[function]";
410  case Type::WeakStruct: return structToString();
411  }
412  return QCString();
413 }
414 
415 /** Return a string representation of the type of the value stored in the variant */
416 const char *TemplateVariant::typeAsString() const
417 {
418  switch (type())
419  {
420  case Type::None: return "invalid";
421  case Type::Bool: return "bool";
422  case Type::Int: return "integer";
423  case Type::String: return "string";
424  case Type::Struct: return "struct";
425  case Type::List: return "list";
426  case Type::Function: return "function";
427  case Type::WeakStruct: return "struct";
428  }
429  return "invalid";
430 }
431 
433 {
434  return isList() ? m_variant.get<static_cast<uint8_t>(Type::List)>() : nullptr;
435 }
437 {
438  return isList() ? m_variant.get<static_cast<uint8_t>(Type::List)>() : nullptr;
439 }
440 
442 {
443  return isStruct() ? m_variant.get<static_cast<uint8_t>(Type::Struct)>() :
444  isWeakStruct() ? m_variant.get<static_cast<uint8_t>(Type::WeakStruct)>().lock() :
445  nullptr;
446 }
448 {
449  return isStruct() ? m_variant.get<static_cast<uint8_t>(Type::Struct)>() :
450  isWeakStruct() ? m_variant.get<static_cast<uint8_t>(Type::WeakStruct)>().lock() :
451  nullptr;
452 }
453 
454 TemplateVariant TemplateVariant::call(const std::vector<TemplateVariant> &args)
455 {
456  return isFunction() ? m_variant.get<static_cast<uint8_t>(Type::Function)>()(args) : TemplateVariant();
457 }
458 
459 //- Template struct implementation --------------------------------------------
460 
461 
462 /** @brief Private data of a template struct object */
464 {
465  public:
466  Private(std::initializer_list<StructField> fs) : fields(fs) {}
467  std::unordered_map<std::string,TemplateVariant> fields;
468 };
469 
471  std::initializer_list<StructField> fields)
472  : p(std::make_unique<Private>(fields))
473 {
474 }
475 
477 {
478 }
479 
481 {
482  auto it = p->fields.find(name.str());
483  return it!=p->fields.end() ? it->second : TemplateVariant();
484 }
485 
487 {
488  StringVector result;
489  for (const auto &kv : p->fields)
490  {
491  result.push_back(kv.first);
492  }
493  std::sort(result.begin(),result.end());
494  return result;
495 }
496 
497 TemplateStructIntfPtr TemplateImmutableStruct::alloc(std::initializer_list<StructField> fields)
498 {
499  return std::make_shared<TemplateImmutableStruct>(fields);
500 }
501 
502 //- Template immutable list implementation ------------------------------------
503 
504 /** @brief Private data of a template immutable list object */
506 {
507  public:
508  Private(std::initializer_list<TemplateVariant> e) : elems(e) {}
511  int index = -1;
512 };
513 
514 TemplateImmutableList::TemplateImmutableList(std::initializer_list<TemplateVariant> elements)
515  : p(std::make_unique<Private>(elements))
516 {
517 }
518 
520  : p(std::make_unique<Private>(elements))
521 {
522 }
523 
525 {
526 }
527 
529 {
530  return static_cast<uint>(p->elems.size());
531 }
532 
534  {
535  return std::make_unique< TemplateListGenericConstIterator<TemplateImmutableList> >(*this);
536  }
537 
539 {
540  return index<p->elems.size() ? p->elems[index] : TemplateVariant();
541 }
542 
543 TemplateListIntfPtr TemplateImmutableList::alloc(std::initializer_list<TemplateVariant> elements)
544 {
545  return std::make_shared<TemplateImmutableList>(elements);
546 }
547 
549 {
550  return std::make_shared<TemplateImmutableList>(elements);
551 }
552 
553 //- Operator types ------------------------------------------------------------
554 
555 /** @brief Class representing operators that can appear in template expressions */
556 class Operator
557 {
558  public:
559  /* Operator precedence (low to high)
560  or
561  and
562  not
563  in
564  ==, !=, <, >, <=, >=
565  +, -
566  *, /, %
567  |
568  :
569  ,
570  */
571  enum Type
572  {
577  };
578 
579  static const char *toString(Type op)
580  {
581  switch(op)
582  {
583  case Or: return "or";
584  case And: return "and";
585  case Not: return "not";
586  case In: return "in";
587  case Equal: return "==";
588  case NotEqual: return "!=";
589  case Less: return "<";
590  case Greater: return ">";
591  case LessEqual: return "<=";
592  case GreaterEqual: return ">=";
593  case Plus: return "+";
594  case Minus: return "-";
595  case Multiply: return "*";
596  case Divide: return "/";
597  case Modulo: return "%";
598  case Filter: return "|";
599  case Colon: return ":";
600  case Comma: return ",";
601  case LeftParen: return "(";
602  case RightParen: return ")";
603  case Last: return "?";
604  }
605  return "?";
606  }
607 };
608 
609 //-----------------------------------------------------------------------------
610 
611 class TemplateNodeBlock;
612 
613 /** @brief Class holding stacks of blocks available in the context */
615 {
616  public:
618  TemplateNodeBlock *get(const QCString &name) const;
619  TemplateNodeBlock *pop(const QCString &name);
620  void add(TemplateNodeBlock *block);
621  void add(TemplateBlockContext *ctx);
622  void push(TemplateNodeBlock *block);
623  void clear();
624  using NodeBlockList = std::deque<TemplateNodeBlock*>;
625  private:
626  std::map< std::string, NodeBlockList > m_blocks;
627 };
628 
629 /** @brief A container to store a key-value pair */
631 {
633  TemplateKeyValue(const QCString &k,const TemplateVariant &v) : key(k), value(v) {}
636 };
637 
638 /** @brief Internal class representing the implementation of a template
639  * context */
641 {
642  public:
644  virtual ~TemplateContextImpl();
645 
646  using EscapeIntfMap = std::unordered_map<std::string, std::unique_ptr<TemplateEscapeIntf>>;
648  {
649  for (const auto &kv : map)
650  {
651  m_escapeIntfMap.insert(std::make_pair(kv.first,kv.second->clone()));
652  }
653  }
654 
655  // TemplateContext methods
656  void push();
657  void pop();
658  void set(const QCString &name,const TemplateVariant &v);
659  //void update(const QCString &name,const TemplateVariant &v);
660  TemplateVariant get(const QCString &name) const;
661  const TemplateVariant *getRef(const QCString &name) const;
662  void setOutputDirectory(const QCString &dir)
663  { m_outputDir = dir; }
664  void setEscapeIntf(const QCString &ext,std::unique_ptr<TemplateEscapeIntf> intf)
665  {
666  int i=(!ext.isEmpty() && ext.at(0)=='.') ? 1 : 0;
667  m_escapeIntfMap.insert(std::make_pair(ext.mid(i).str(),std::move(intf)));
668  }
669  void selectEscapeIntf(const QCString &ext)
670  {
671  auto it = m_escapeIntfMap.find(ext.str());
672  m_activeEscapeIntf = it!=m_escapeIntfMap.end() ? it->second.get() : 0;
673  }
677  void setSpacelessIntf(std::unique_ptr<TemplateSpacelessIntf> intf) { m_spacelessIntf = std::move(intf); }
678 
679  // internal methods
681  TemplateVariant getPrimary(const QCString &name) const;
685  int line() const { return m_line; }
687  std::unique_ptr<TemplateSpacelessIntf> &spacelessIntf() { return m_spacelessIntf; }
688  const std::unique_ptr<TemplateSpacelessIntf> &spacelessInfo() const { return m_spacelessIntf; }
689  void enableSpaceless(bool b) { if (b && !m_spacelessEnabled) m_spacelessIntf->reset();
691  }
693  void enableTabbing(bool b) { m_tabbingEnabled=b;
695  }
696  bool tabbingEnabled() const { return m_tabbingEnabled; }
697  bool needsRecoding() const { return !m_encoding.isEmpty(); }
698  QCString encoding() const { return m_encoding; }
699  void setEncoding(const QCString &file,int line,const QCString &enc);
700  QCString recode(const QCString &s);
701  void warn(const QCString &fileName,int line,const char *fmt,...) const;
702 
703  // index related functions
704  void openSubIndex(const QCString &indexName);
705  void closeSubIndex(const QCString &indexName);
706  void addIndexEntry(const QCString &indexName,const std::vector<TemplateKeyValue> &arguments);
707  const TemplateStructPtr indices() const { return m_indices; }
708 
709  private:
711  QCString m_templateName = "<unknown>";
712  int m_line = 1;
714  std::deque< std::unordered_map<std::string,TemplateVariant> > m_contextStack;
718  std::unique_ptr<TemplateSpacelessIntf> m_spacelessIntf;
719  bool m_spacelessEnabled = false;
720  bool m_tabbingEnabled = false;
722  std::unordered_map< std::string, std::stack<TemplateVariant> > m_indexStacks;
724  void *m_fromUtf8 = 0;
725 };
726 
727 //-----------------------------------------------------------------------------
728 
729 /** @brief The implementation of the "add" filter */
731 {
732  public:
733  static int variantIntValue(const TemplateVariant &v,bool &isInt)
734  {
735  if (!v.isInt() && v.isString())
736  {
737  return v.toString().toInt(&isInt);
738  }
739  return v.isInt() ? v.toInt() : 0;
740  }
742  {
743  if (!v.isValid())
744  {
745  return arg;
746  }
747  bool lhsIsInt;
748  int lhsValue = variantIntValue(v,lhsIsInt);
749  bool rhsIsInt;
750  int rhsValue = variantIntValue(arg,rhsIsInt);
751  if (lhsIsInt && rhsIsInt)
752  {
753  return lhsValue+rhsValue;
754  }
755  else if (v.isString() && arg.isString())
756  {
757  return TemplateVariant(v.toString() + arg.toString());
758  }
759  else
760  {
761  return v;
762  }
763  }
764 };
765 
766 //-----------------------------------------------------------------------------
767 
768 /** @brief The implementation of the "get" filter */
770 {
771  public:
773  {
774  if (v.isValid() && (v.isStruct() || v.isWeakStruct()) && arg.isString())
775  {
777  if (s)
778  {
779  TemplateVariant result = v.toStruct()->get(arg.toString());
780  //printf("\nok[%s]=%d\n",qPrint(arg.toString()),result.type());
781  return result;
782  }
783  else
784  {
785  return false;
786  }
787  }
788  else
789  {
790  //printf("\nnok[%s]\n",qPrint(arg.toString()));
791  return false;
792  }
793  }
794 };
795 
796 //-----------------------------------------------------------------------------
797 
798 /** @brief The implementation of the "raw" filter */
800 {
801  public:
803  {
804  if (v.isValid() && (v.isString() || v.isInt()))
805  {
806  return TemplateVariant(v.toString(),TRUE);
807  }
808  else
809  {
810  return v;
811  }
812  }
813 };
814 
815 //-----------------------------------------------------------------------------
816 
817 /** @brief The implementation of the "keep" filter */
819 {
820  public:
822  {
823  if (v.isValid() && (v.isList()) && args.isString())
824  {
825  TemplateListIntfPtr list = v.toList();
826  if (list)
827  {
828  //printf("FilterKeep::apply: v=%s args=%s\n",qPrint(v.toString()),qPrint(args.toString()));
829  TemplateListIntf::ConstIteratorPtr it = list->createIterator();
830 
832  TemplateVariant item;
833  for (it->toFirst();(it->current(item));it->toNext())
834  {
835  //printf("item type=%s\n",item.typeAsString());
836  TemplateStructIntfPtr s = item.toStruct();
837  if (s)
838  {
839  TemplateVariant value = s->get(args.toString());
840  //printf("value type=%s\n",value.typeAsString());
841  if (value.toBool())
842  {
843  //printf("keeping it\n");
844  result->append(item);
845  }
846  else
847  {
848  //printf("Dropping it\n");
849  }
850  }
851  }
852  return TemplateVariant(std::static_pointer_cast<TemplateListIntf>(result));
853  }
854  }
855  return v;
856  }
857 };
858 
859 //-----------------------------------------------------------------------------
860 
861 /** @brief The implementation of the "list" filter */
863 {
864  public:
866  {
867  if (v.isValid())
868  {
869  if (v.isList()) // input is already a list
870  {
871  return v;
872  }
873  // create a list with v as the only element
875  list->append(v);
876  return TemplateVariant(std::static_pointer_cast<TemplateListIntf>(list));
877  }
878  else
879  {
880  return v;
881  }
882  }
883 };
884 
885 //-----------------------------------------------------------------------------
886 /** @brief The implementation of the "texlabel" filter */
888 {
889  public:
891  {
892  if (v.isValid() && (v.isString()))
893  {
895  }
896  else
897  {
898  return v;
899  }
900  }
901 };
902 
903 //-----------------------------------------------------------------------------
904 
905 /** @brief The implementation of the "texindex" filter */
907 {
908  public:
910  {
911  if (v.isValid() && (v.isString()))
912  {
914  }
915  else
916  {
917  return v;
918  }
919  }
920 };
921 
922 //-----------------------------------------------------------------------------
923 
924 /** @brief The implementation of the "append" filter */
926 {
927  public:
929  {
930  if ((v.isString() || v.isInt()) &&
931  (arg.isString() || arg.isInt()))
932  {
933  return TemplateVariant(v.toString() + arg.toString());
934  }
935  else
936  {
937  return v;
938  }
939  }
940 };
941 
942 //-----------------------------------------------------------------------------
943 
944 /** @brief The implementation of the "prepend" filter */
946 {
947  public:
949  {
950  if ((v.isString() || v.isInt()) &&
951  arg.isString())
952  {
953  return TemplateVariant(arg.toString() + v.toString());
954  }
955  else
956  {
957  return v;
958  }
959  }
960 };
961 
962 //--------------------------------------------------------------------
963 
964 /** @brief The implementation of the "length" filter */
966 {
967  public:
969  {
970  if (!v.isValid())
971  {
972  return TemplateVariant();
973  }
974  if (v.isList())
975  {
976  return TemplateVariant((int)v.toList()->count());
977  }
978  else if (v.isString())
979  {
980  return TemplateVariant((int)v.toString().length());
981  }
982  else
983  {
984  return TemplateVariant();
985  }
986  }
987 };
988 
989 //--------------------------------------------------------------------
990 
991 /** @brief The implementation of the "default" filter */
993 {
994  public:
996  {
997  if (!v.isValid())
998  {
999  return arg;
1000  }
1001  else if (v.isString() && v.toString().isEmpty())
1002  {
1003  return arg;
1004  }
1005  else
1006  {
1007  return v;
1008  }
1009  }
1010 };
1011 
1012 //--------------------------------------------------------------------
1013 
1014 /** @brief The implementation of the "flatten" filter */
1016 {
1017  public:
1019  {
1020  if (!v.isValid() || !v.isList())
1021  {
1022  return v;
1023  }
1024  else
1025  {
1027  TemplateListIntfPtr tree = v.toList();
1028  flatten(tree,list);
1029  return TemplateVariant(std::static_pointer_cast<TemplateListIntf>(list));
1030  }
1031  }
1032 
1033  private:
1034  static void flatten(const TemplateListIntfPtr tree,TemplateListPtr list)
1035  {
1036  if (tree)
1037  {
1038  TemplateListIntf::ConstIteratorPtr it = tree->createIterator();
1039  TemplateVariant item;
1040  for (it->toFirst();(it->current(item));it->toNext())
1041  {
1042  TemplateStructIntfPtr s = item.toStruct();
1043  if (s)
1044  {
1045  list->append(item);
1046  // if s has "children" then recurse into the children
1047  TemplateVariant children = s->get("children");
1048  if (children.isValid() && children.isList())
1049  {
1050  flatten(children.toList(),list);
1051  }
1052  }
1053  else
1054  {
1055  list->append(item);
1056  }
1057  }
1058  }
1059  }
1060 };
1061 
1062 //--------------------------------------------------------------------
1063 
1064 /** @brief The implementation of the "listsort" filter */
1066 {
1067  struct ListElem
1068  {
1069  ListElem(const QCString &k,const TemplateVariant &v) : key(k), value(v) {}
1072  };
1073  public:
1075  {
1076  if (v.isList() && args.isString())
1077  {
1078  //printf("FilterListSort::apply: v=%s args=%s\n",qPrint(v.toString()),qPrint(args.toString()));
1079  TemplateListIntfPtr list = v.toList();
1080  if (list)
1081  {
1082  TemplateListIntf::ConstIteratorPtr it = list->createIterator();
1083 
1084  TemplateVariant item;
1086 
1087  // create list of items based on v using the data in args as a sort key
1088  using SortList = std::vector<ListElem>;
1089  SortList sortList;
1090  sortList.reserve(v.toList()->count());
1091  for (it->toFirst();(it->current(item));it->toNext())
1092  {
1093  TemplateStructIntfPtr s = item.toStruct();
1094  if (s)
1095  {
1096  QCString sortKey = determineSortKey(s,args.toString());
1097  sortList.emplace_back(sortKey,item);
1098  //printf("sortKey=%s\n",qPrint(sortKey));
1099  }
1100  }
1101 
1102  // sort the list
1103  std::sort(sortList.begin(),
1104  sortList.end(),
1105  [](const auto &lhs,const auto &rhs) { return lhs.key < rhs.key; });
1106 
1107  // add sorted items to the result list
1108  for (const auto &elem : sortList)
1109  {
1110  result->append(elem.value);
1111  }
1112  return TemplateVariant(std::static_pointer_cast<TemplateListIntf>(result));
1113  }
1114  }
1115  return v;
1116  }
1117 
1118  private:
1120  {
1121  int i,p=0;
1122  QCString result;
1123  while ((i=arg.find("{{",p))!=-1)
1124  {
1125  result+=arg.mid(p,i-p);
1126  int j=arg.find("}}",i+2);
1127  if (j!=-1)
1128  {
1129  QCString var = arg.mid(i+2,j-i-2);
1130  TemplateVariant val=s->get(var);
1131  //printf("found argument %s value=%s\n",qPrint(var),qPrint(val.toString()));
1132  result+=val.toString();
1133  p=j+2;
1134  }
1135  else
1136  {
1137  p=i+1;
1138  }
1139  }
1140  result+=arg.right(arg.length()-p);
1141  return result;
1142  }
1143 };
1144 
1145 //--------------------------------------------------------------------
1146 
1147 /** @brief The implementation of the "groupBy" filter */
1149 {
1150  struct ListElem
1151  {
1152  ListElem(const QCString &k,const TemplateVariant &v) : key(k), value(v) {}
1155  };
1156  public:
1158  {
1159  if (v.isList() && args.isString())
1160  {
1161  TemplateListIntfPtr list = v.toList();
1162  if (list)
1163  {
1164  //printf("FilterListSort::apply: v=%s args=%s\n",qPrint(v.toString()),qPrint(args.toString()));
1165  TemplateListIntf::ConstIteratorPtr it = list->createIterator();
1166 
1167  TemplateVariant item;
1169 
1170  // create list of items based on v using the data in args as a sort key
1171  using SortList = std::vector<ListElem>;
1172  SortList sortList;
1173  sortList.reserve(v.toList()->count());
1174  for (it->toFirst();(it->current(item));it->toNext())
1175  {
1176  TemplateStructIntfPtr s = item.toStruct();
1177  if (s)
1178  {
1179  QCString sortKey = determineSortKey(s,args.toString());
1180  sortList.emplace_back(sortKey,item);
1181  //printf("sortKey=%s\n",qPrint(sortKey));
1182  }
1183  }
1184 
1185  // sort the list
1186  std::sort(sortList.begin(),
1187  sortList.end(),
1188  [](const auto &lhs,const auto &rhs) { return lhs.key < rhs.key; });
1189 
1190  // add sorted items to the result list
1191  TemplateListPtr groupList;
1192  QCString prevKey;
1193  for (const auto &elem : sortList)
1194  {
1195  if (groupList==0 || elem.key!=prevKey)
1196  {
1197  groupList = TemplateList::alloc();
1198  result->append(std::static_pointer_cast<TemplateListIntf>(groupList));
1199  prevKey = elem.key;
1200  }
1201  groupList->append(elem.value);
1202  }
1203  return TemplateVariant(std::static_pointer_cast<TemplateListIntf>(result));
1204  }
1205  }
1206  return v;
1207  }
1208 
1209  private:
1210  static QCString determineSortKey(const TemplateStructIntfPtr s,const QCString &attribName)
1211  {
1212  TemplateVariant v = s->get(attribName);
1213  return v.toString();
1214  }
1215 };
1216 
1217 //--------------------------------------------------------------------
1218 
1219 /** @brief The implementation of the "relative" filter */
1221 {
1222  public:
1224  {
1225  if (v.isValid() && v.isString() && v.toString().left(2)=="..")
1226  {
1227  return TRUE;
1228  }
1229  else
1230  {
1231  return FALSE;
1232  }
1233  }
1234 };
1235 
1236 //--------------------------------------------------------------------
1237 
1238 /** @brief The implementation of the "paginate" filter */
1240 {
1241  public:
1243  {
1244  if (v.isValid() && v.isList() &&
1245  args.isValid() && args.isInt())
1246  {
1247  int pageSize = args.toInt();
1248  const TemplateListIntfPtr list = v.toList();
1250  TemplateListIntf::ConstIteratorPtr it = list->createIterator();
1251  TemplateVariant item;
1252  TemplateListPtr pageList;
1253  int i = 0;
1254  for (it->toFirst();(it->current(item));it->toNext())
1255  {
1256  if (pageList==0)
1257  {
1258  pageList = TemplateList::alloc();
1259  result->append(std::static_pointer_cast<TemplateListIntf>(pageList));
1260  }
1261  pageList->append(item);
1262  i++;
1263  if (i==pageSize) // page is full start a new one
1264  {
1265  pageList=0;
1266  i=0;
1267  }
1268  }
1269  return TemplateVariant(std::static_pointer_cast<TemplateListIntf>(result));
1270  }
1271  else // wrong arguments
1272  {
1273  return v;
1274  }
1275  }
1276 };
1277 
1278 //--------------------------------------------------------------------
1279 
1280 /** @brief The implementation of the "alphaIndex" filter */
1282 {
1283  private:
1284  struct ListElem
1285  {
1286  ListElem(std::string k,const TemplateVariant &v) : key(k), value(v) {}
1287  std::string key;
1289  };
1290  static QCString keyToLabel(const char *startLetter)
1291  {
1292  //printf(">keyToLabel(%s)\n",qPrint(startLetter));
1293  const char *p = startLetter;
1294  char c = *p;
1295  QCString result;
1296  if (c<127 && c>31) // printable ASCII character
1297  {
1298  result+=c;
1299  }
1300  else
1301  {
1302  result="0x";
1303  const char hex[]="0123456789abcdef";
1304  while ((c=*p++))
1305  {
1306  result+=hex[((unsigned char)c)>>4];
1307  result+=hex[((unsigned char)c)&0xf];
1308  }
1309  }
1310  //printf("<keyToLabel(%s)\n",qPrint(result));
1311  return result;
1312  }
1313  static std::string determineSortKey(const TemplateStructIntfPtr s,const QCString &attribName)
1314  {
1315  TemplateVariant v = s->get(attribName);
1316  int index = getPrefixIndex(v.toString());
1317  return convertUTF8ToUpper(getUTF8CharAt(v.toString().str(),index));
1318  }
1319 
1320  public:
1322  {
1323  if (v.isList() && args.isString())
1324  {
1325  TemplateListIntfPtr list = v.toList();
1326  if (list)
1327  {
1328  //printf("FilterListSort::apply: v=%s args=%s\n",qPrint(v.toString()),qPrint(args.toString()));
1329  TemplateListIntf::ConstIteratorPtr it = list->createIterator();
1330 
1331  TemplateVariant item;
1333 
1334  // create list of items based on v using the data in args as a sort key
1335  using SortList = std::vector<ListElem>;
1336  SortList sortList;
1337  sortList.reserve(v.toList()->count());
1338  for (it->toFirst();(it->current(item));it->toNext())
1339  {
1340  TemplateStructIntfPtr s = item.toStruct();
1341  if (s)
1342  {
1343  std::string sortKey = determineSortKey(s,args.toString());
1344  sortList.emplace_back(sortKey,item);
1345  //printf("sortKey=%s\n",qPrint(sortKey));
1346  }
1347  }
1348 
1349  // sort the list
1350  std::sort(sortList.begin(),
1351  sortList.end(),
1352  [](const auto &lhs,const auto &rhs) { return lhs.key < rhs.key; });
1353 
1354  // create an index from the sorted list
1355  std::string letter;
1356  TemplateStructPtr indexNode;
1357  TemplateListPtr indexList;
1358  for (const auto &elem : sortList)
1359  {
1360  if (letter!=elem.key || indexNode==0)
1361  {
1362  // create new indexNode
1363  indexNode = TemplateStruct::alloc();
1364  indexList = TemplateList::alloc();
1365  indexNode->set("letter", elem.key);
1366  indexNode->set("label", keyToLabel(elem.key.c_str()));
1367  indexNode->set("items",std::static_pointer_cast<TemplateListIntf>(indexList));
1368  result->append(std::static_pointer_cast<TemplateStructIntf>(indexNode));
1369  letter=elem.key;
1370  }
1371  indexList->append(elem.value);
1372  }
1373  return TemplateVariant(std::static_pointer_cast<TemplateListIntf>(result));
1374  }
1375  }
1376  return v;
1377  }
1378 };
1379 
1380 //--------------------------------------------------------------------
1381 
1382 /** @brief The implementation of the "default" filter */
1384 {
1385  public:
1387  {
1388  if (!v.isValid() || !v.isString())
1389  {
1390  return v;
1391  }
1392  QCString result = v.toString();
1393  int i=result.findRev('/');
1394  if (i!=-1)
1395  {
1396  result=result.mid(i+1);
1397  }
1398  i=result.findRev('\\');
1399  if (i!=-1)
1400  {
1401  result=result.mid(i+1);
1402  }
1403  return result;
1404  }
1405 };
1406 
1407 //--------------------------------------------------------------------
1408 
1409 /** @brief The implementation of the "default" filter */
1411 {
1412  public:
1414  {
1415  if (!v.isValid() || !v.isString())
1416  {
1417  return v;
1418  }
1419  QCString s = v.toString();
1420  return substitute(s," ","&#160;");
1421  }
1422 };
1423 
1424 //--------------------------------------------------------------------
1425 
1426 /** @brief The implementation of the "divisibleby" filter */
1428 {
1429  public:
1431  {
1432  if (!v.isValid() || !n.isValid())
1433  {
1434  return TemplateVariant();
1435  }
1436  if (v.isInt() && n.isInt())
1437  {
1438  int ni = n.toInt();
1439  if (ni>0)
1440  {
1441  return TemplateVariant((v.toInt()%ni)==0);
1442  }
1443  else
1444  {
1445  return TemplateVariant(FALSE);
1446  }
1447  }
1448  else
1449  {
1450  return TemplateVariant();
1451  }
1452  }
1453 };
1454 
1455 //--------------------------------------------------------------------
1456 
1457 /** @brief The implementation of the "isRelativeURL" filter */
1459 {
1460  public:
1462  {
1463  if (v.isValid() && v.isString())
1464  {
1465  QCString s = v.toString();
1466  if (!s.isEmpty() && s.at(0)=='!') return TRUE;
1467  }
1468  return FALSE;
1469  }
1470 };
1471 
1472 //--------------------------------------------------------------------
1473 
1474 /** @brief The implementation of the "isRelativeURL" filter */
1476 {
1477  public:
1479  {
1480  if (v.isValid() && v.isString())
1481  {
1482  QCString s = v.toString();
1483  if (!s.isEmpty() && s.at(0)=='^') return TRUE;
1484  }
1485  return FALSE;
1486  }
1487 };
1488 
1489 //--------------------------------------------------------------------
1490 
1491 /** @brief The implementation of the "lower" filter */
1493 {
1494  public:
1496  {
1497  if (v.isValid() && v.isString())
1498  {
1499  return v.toString().lower();
1500  }
1501  return v;
1502  }
1503 };
1504 
1505 //--------------------------------------------------------------------
1506 
1507 /** @brief The implementation of the "upper" filter */
1509 {
1510  public:
1512  {
1513  if (v.isValid() && v.isString())
1514  {
1515  return v.toString().upper();
1516  }
1517  return v;
1518  }
1519 };
1520 
1521 //--------------------------------------------------------------------
1522 
1523 /** @brief The implementation of the "upper" filter */
1525 {
1526  public:
1528  {
1529  if (v.isValid())
1530  {
1531  return QCString().sprintf("%x",v.toInt());
1532  }
1533  return v;
1534  }
1535 };
1536 
1537 
1538 //--------------------------------------------------------------------
1539 
1540 /** @brief The implementation of the "e" filter */
1542 {
1543  public:
1545  {
1546  if (v.isValid() && v.isString())
1547  {
1548  return convertToHtml(v.toString());
1549  }
1550  return v;
1551  }
1552 };
1553 
1554 
1555 //--------------------------------------------------------------------
1556 
1557 /** @brief The implementation of the "decodeURL" filter
1558  * The leading character is removed from the value in case it is a ^ or !.
1559  * - ^ is used to encode a absolute URL
1560  * - ! is used to encode a relative URL
1561  */
1563 {
1564  public:
1566  {
1567  if (v.isValid() && v.isString())
1568  {
1569  QCString s = v.toString();
1570  if (!s.isEmpty() && (s.at(0)=='^' || s.at(0)=='!'))
1571  {
1572  return s.mid(1);
1573  }
1574  }
1575  return v;
1576  }
1577 };
1578 
1579 
1580 //--------------------------------------------------------------------
1581 
1582 /** @brief Factory singleton for registering and creating filters */
1584 {
1585  public:
1587 
1589  {
1590  static std::unique_ptr<TemplateFilterFactory> instance;
1591  if (instance==0) instance = std::make_unique<TemplateFilterFactory>();
1592  return *instance;
1593  }
1594 
1595  TemplateVariant apply(const QCString &name,const TemplateVariant &v,const TemplateVariant &arg, bool &ok)
1596  {
1597  auto it = m_registry.find(name.str());
1598  if (it!=m_registry.end())
1599  {
1600  ok=TRUE;
1601  return it->second(v,arg);
1602  }
1603  else
1604  {
1605  ok=FALSE;
1606  return v;
1607  }
1608  }
1609 
1610  void registerFilter(const QCString &name,FilterFunction *func)
1611  {
1612  m_registry.insert(std::make_pair(name.str(),func));
1613  }
1614 
1615  /** @brief Helper class for registering a filter function */
1616  template<class T> class AutoRegister
1617  {
1618  public:
1620  {
1622  }
1623  };
1624 
1625  private:
1626  std::unordered_map<std::string,FilterFunction*> m_registry;
1627 };
1628 
1629 // register a handlers for each filter we support
1657 
1658 //--------------------------------------------------------------------
1659 
1660 /** @brief Base class for all nodes in the abstract syntax tree of an
1661  * expression.
1662  */
1663 class ExprAst
1664 {
1665  public:
1666  virtual ~ExprAst() {}
1668 };
1669 
1670 using ExprAstPtr = std::unique_ptr<ExprAst>;
1671 using ExprAstList = std::vector< ExprAstPtr >;
1672 
1673 /** @brief Class representing a number in the AST */
1674 class ExprAstNumber : public ExprAst
1675 {
1676  public:
1677  ExprAstNumber(int num) : m_number(num)
1678  { TRACE(("ExprAstNumber(%d)\n",num)); }
1679  int number() const { return m_number; }
1681  private:
1682  int m_number = 0;
1683 };
1684 
1685 /** @brief Class representing a variable in the AST */
1686 class ExprAstVariable : public ExprAst
1687 {
1688  public:
1690  { TRACE(("ExprAstVariable(%s)\n",name.data())); }
1691  const QCString &name() const { return m_name; }
1693  {
1694  TemplateVariant v = c->get(m_name);
1695  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
1696  if (!v.isValid())
1697  {
1698  if (ci) ci->warn(ci->templateName(),ci->line(),"undefined variable '%s' in expression",qPrint(m_name));
1699  }
1700  return v;
1701  }
1702  private:
1704 };
1705 
1707 {
1708  public:
1710  : m_var(std::move(var)), m_args(std::move(args))
1711  { TRACE(("ExprAstFunctionVariable()\n"));
1712  }
1714  {
1715  std::vector<TemplateVariant> args;
1716  for (const auto &exprArg : m_args)
1717  {
1718  TemplateVariant v = exprArg->resolve(c);
1719  args.push_back(v);
1720  }
1721  TemplateVariant v = m_var->resolve(c);
1722  if (v.isFunction())
1723  {
1724  v = v.call(args);
1725  }
1726  return v;
1727  }
1728  private:
1731 };
1732 
1733 /** @brief Class representing a filter in the AST */
1734 class ExprAstFilter : public ExprAst
1735 {
1736  public:
1737  ExprAstFilter(const QCString &name,ExprAstPtr &&arg) : m_name(name), m_arg(std::move(arg))
1738  { TRACE(("ExprAstFilter(%s)\n",name.data())); }
1739  const QCString &name() const { return m_name; }
1741  {
1742  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
1743  if (ci==0) return v; // should not happen
1744  TRACE(("Applying filter '%s' to '%s' (type=%d)\n",qPrint(m_name),qPrint(v.toString()),v.type()));
1745  TemplateVariant arg;
1746  if (m_arg) arg = m_arg->resolve(c);
1747  bool ok;
1749  if (!ok)
1750  {
1751  ci->warn(ci->templateName(),ci->line(),"unknown filter '%s'",qPrint(m_name));
1752  }
1753  return result;
1754  }
1755  private:
1758 };
1759 
1760 using ExprAstFilterPtr = std::unique_ptr<ExprAstFilter>;
1761 
1762 /** @brief Class representing a filter applied to an expression in the AST */
1764 {
1765  public:
1767  : m_expr(std::move(expr)), m_filter(std::move(filter))
1768  { TRACE(("ExprAstFilterAppl\n")); }
1770  {
1771  return m_filter->apply(m_expr->resolve(c),c);
1772  }
1773  private:
1776 };
1777 
1778 /** @brief Class representing a string literal in the AST */
1779 class ExprAstLiteral : public ExprAst
1780 {
1781  public:
1782  ExprAstLiteral(const QCString &lit) : m_literal(lit)
1783  { TRACE(("ExprAstLiteral(%s)\n",lit.data())); }
1784  const QCString &literal() const { return m_literal; }
1786  private:
1788 };
1789 
1790 /** @brief Class representing a negation (not) operator in the AST */
1791 class ExprAstNegate : public ExprAst
1792 {
1793  public:
1794  ExprAstNegate(ExprAstPtr &&expr) : m_expr(std::move(expr))
1795  { TRACE(("ExprAstNegate\n")); }
1797  { return TemplateVariant(!m_expr->resolve(c).toBool()); }
1798  private:
1800 };
1801 
1802 class ExprAstUnary : public ExprAst
1803 {
1804  public:
1805  ExprAstUnary(Operator::Type op,ExprAstPtr &&expr) : m_operator(op), m_expr(std::move(expr))
1806  { TRACE(("ExprAstUnary %s\n",Operator::toString(op))); }
1808  {
1809  TemplateVariant expr = m_expr->resolve(c);
1810  switch (m_operator)
1811  {
1812  case Operator::Minus:
1813  return -expr.toInt();
1814  default:
1815  return TemplateVariant();
1816  }
1817  }
1818  private:
1821 };
1822 
1823 /** @brief Class representing a binary operator in the AST */
1824 class ExprAstBinary : public ExprAst
1825 {
1826  public:
1828  : m_operator(op), m_lhs(std::move(lhs)), m_rhs(std::move(rhs))
1829  { TRACE(("ExprAstBinary %s\n",Operator::toString(op))); }
1831  {
1832  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
1833  if (ci==0) return TemplateVariant(); // should not happen
1834  TemplateVariant lhs = m_lhs->resolve(c);
1835  TemplateVariant rhs = m_rhs ? m_rhs->resolve(c) : TemplateVariant();
1836  switch(m_operator)
1837  {
1838  case Operator::Or:
1839  return TemplateVariant(lhs.toBool() || rhs.toBool());
1840  case Operator::And:
1841  return TemplateVariant(lhs.toBool() && rhs.toBool());
1842  case Operator::Equal:
1843  return TemplateVariant(lhs == rhs);
1844  case Operator::NotEqual:
1845  return TemplateVariant(!(lhs == rhs));
1846  case Operator::Less:
1847  if (lhs.isString() && rhs.isString())
1848  {
1849  return lhs.toString()<rhs.toString();
1850  }
1851  else
1852  {
1853  return lhs.toInt()<rhs.toInt();
1854  }
1855  case Operator::Greater:
1856  if (lhs.isString() && rhs.isString())
1857  {
1858  return !(lhs.toString()<rhs.toString());
1859  }
1860  else
1861  {
1862  return lhs.toInt()>rhs.toInt();
1863  }
1864  case Operator::LessEqual:
1865  if (lhs.isString() && rhs.isString())
1866  {
1867  return lhs.toString()==rhs.toString() || lhs.toString()<rhs.toString();
1868  }
1869  else
1870  {
1871  return lhs.toInt()<=rhs.toInt();
1872  }
1874  if (lhs.isString() && rhs.isString())
1875  {
1876  return lhs.toString()==rhs.toString() || !(lhs.toString()<rhs.toString());
1877  }
1878  else
1879  {
1880  return lhs.toInt()>=rhs.toInt();
1881  }
1882  case Operator::Plus:
1883  {
1884  return TemplateVariant(lhs.toInt() + rhs.toInt());
1885  }
1886  case Operator::Minus:
1887  {
1888  return TemplateVariant(lhs.toInt() - rhs.toInt());
1889  }
1890  case Operator::Multiply:
1891  {
1892  return TemplateVariant(lhs.toInt() * rhs.toInt());
1893  }
1894  case Operator::Divide:
1895  {
1896  int denom = rhs.toInt();
1897  if (denom!=0)
1898  {
1899  return TemplateVariant(lhs.toInt() / denom);
1900  }
1901  else // divide by zero
1902  {
1903  ci->warn(ci->templateName(),ci->line(),"division by zero while evaluating expression is undefined");
1904  return 0;
1905  }
1906  }
1907  case Operator::Modulo:
1908  {
1909  int denom = rhs.toInt();
1910  if (denom!=0)
1911  {
1912  return TemplateVariant(lhs.toInt() % denom);
1913  }
1914  else // module zero
1915  {
1916  ci->warn(ci->templateName(),ci->line(),"modulo zero while evaluating expression is undefined");
1917  return 0;
1918  }
1919  }
1920  default:
1921  return TemplateVariant();
1922  }
1923  }
1924  private:
1928 };
1929 
1930 //----------------------------------------------------------
1931 
1932 /** @brief Base class of all nodes in a template's AST */
1934 {
1935  public:
1937  virtual ~TemplateNode() {}
1938 
1939  virtual void render(TextStream &ts, TemplateContext *c) = 0;
1940 
1942 
1943  private:
1945 };
1946 
1947 using TemplateNodePtr = std::unique_ptr<TemplateNode>;
1948 
1949 //----------------------------------------------------------
1950 
1951 /** @brief Class representing a lexical token in a template */
1953 {
1954  public:
1955  enum Type { Text, Variable, Block };
1956  TemplateToken(Type t,const QCString &d,int l) : type(t), data(d), line(l) {}
1959  int line = 0;
1960 };
1961 
1962 using TemplateTokenPtr = std::unique_ptr<TemplateToken>;
1963 using TemplateTokenStream = std::deque< TemplateTokenPtr >;
1964 
1965 //----------------------------------------------------------
1966 
1967 /** @brief Class representing a list of AST nodes in a template */
1968 class TemplateNodeList : public std::vector< TemplateNodePtr >
1969 {
1970  public:
1972  {
1973  TRACE(("{TemplateNodeList::render\n"));
1974  for (const auto &tn : *this)
1975  {
1976  tn->render(ts,c);
1977  }
1978  TRACE(("}TemplateNodeList::render\n"));
1979  }
1980 };
1981 
1982 //----------------------------------------------------------
1983 
1984 /** @brief Parser for templates */
1986 {
1987  public:
1988  TemplateParser(const TemplateEngine *engine,
1989  const QCString &templateName,
1990  TemplateTokenStream &tokens);
1991  void parse(TemplateNode *parent,int line,const StringVector &stopAt,
1992  TemplateNodeList &nodes);
1993  bool hasNextToken() const;
1995  void removeNextToken();
1996  void prependToken(TemplateTokenPtr &&token);
1997  const TemplateToken *currentToken() const;
1999  void warn(const QCString &fileName,int line,const char *fmt,...) const;
2000  private:
2004 };
2005 
2006 //--------------------------------------------------------------------
2007 
2008 /** @brief Recursive decent parser for Django style template expressions.
2009  */
2011 {
2012  public:
2013  ExpressionParser(const TemplateParser *parser,int line)
2014  : m_parser(parser), m_line(line), m_tokenStream(0)
2015  {
2016  }
2018  {
2019  }
2020 
2022  {
2023  if (expr.isEmpty()) return 0;
2024  m_tokenStream = expr.data();
2025  getNextToken();
2026  return parseExpression();
2027  }
2028 
2029  private:
2030 
2031  /** @brief Class representing a token within an expression. */
2033  {
2034  public:
2036  {
2037  }
2038  enum Type
2039  {
2041  };
2042 
2044  int num;
2047  };
2048 
2050  {
2051  TRACE(("{parseExpression(%s)\n",m_tokenStream));
2052  ExprAstPtr result { parseOrExpression() };
2053  TRACE(("}parseExpression(%s)\n",m_tokenStream));
2054  return result;
2055  }
2056 
2058  {
2059  TRACE(("{parseOrExpression(%s)\n",m_tokenStream));
2060  ExprAstPtr lhs { parseAndExpression() };
2061  if (lhs)
2062  {
2065  {
2066  getNextToken();
2067  ExprAstPtr rhs { parseAndExpression() };
2068  lhs = std::make_unique<ExprAstBinary>(Operator::Or,std::move(lhs),std::move(rhs));
2069  }
2070  }
2071  TRACE(("}parseOrExpression(%s)\n",m_tokenStream));
2072  return lhs;
2073  }
2074 
2076  {
2077  TRACE(("{parseAndExpression(%s)\n",m_tokenStream));
2078  ExprAstPtr lhs { parseNotExpression() };
2079  if (lhs)
2080  {
2083  {
2084  getNextToken();
2085  ExprAstPtr rhs { parseNotExpression() };
2086  lhs = std::make_unique<ExprAstBinary>(Operator::And,std::move(lhs),std::move(rhs));
2087  }
2088  }
2089  TRACE(("}parseAndExpression(%s)\n",m_tokenStream));
2090  return lhs;
2091  }
2092 
2094  {
2095  TRACE(("{parseNotExpression(%s)\n",m_tokenStream));
2096  ExprAstPtr result;
2099  {
2100  getNextToken();
2102  if (expr==0)
2103  {
2104  warn(m_parser->templateName(),m_line,"argument missing for not operator");
2105  return 0;
2106  }
2107  result = std::make_unique<ExprAstNegate>(std::move(expr));
2108  }
2109  else
2110  {
2111  result = parseCompareExpression();
2112  }
2113  TRACE(("}parseNotExpression(%s)\n",m_tokenStream));
2114  return result;
2115  }
2116 
2118  {
2119  TRACE(("{parseCompareExpression(%s)\n",m_tokenStream));
2121  if (lhs)
2122  {
2125  (op==Operator::Less ||
2126  op==Operator::Greater ||
2127  op==Operator::Equal ||
2128  op==Operator::NotEqual ||
2129  op==Operator::LessEqual ||
2131  )
2132  )
2133  {
2134  getNextToken();
2135  ExprAstPtr rhs { parseNotExpression() };
2136  lhs = std::make_unique<ExprAstBinary>(op,std::move(lhs),std::move(rhs));
2137  }
2138  }
2139  TRACE(("}parseCompareExpression(%s)\n",m_tokenStream));
2140  return lhs;
2141  }
2142 
2144  {
2145  TRACE(("{parseAdditiveExpression(%s)\n",m_tokenStream));
2147  if (lhs)
2148  {
2151  {
2153  getNextToken();
2155  lhs = std::make_unique<ExprAstBinary>(op,std::move(lhs),std::move(rhs));
2156  }
2157  }
2158  TRACE(("}parseAdditiveExpression(%s)\n",m_tokenStream));
2159  return lhs;
2160  }
2161 
2163  {
2164  TRACE(("{parseMultiplicativeExpression(%s)\n",m_tokenStream));
2166  if (lhs)
2167  {
2170  {
2172  getNextToken();
2174  lhs = std::make_unique<ExprAstBinary>(op,std::move(lhs),std::move(rhs));
2175  }
2176  }
2177  TRACE(("}parseMultiplicativeExpression(%s)\n",m_tokenStream));
2178  return lhs;
2179  }
2180 
2182  {
2183  TRACE(("{parseUnaryExpression(%s)\n",m_tokenStream));
2184  ExprAstPtr result;
2186  {
2188  {
2189  getNextToken();
2190  result = parsePrimaryExpression();
2191  }
2192  else if (m_curToken.op==Operator::Minus)
2193  {
2194  getNextToken();
2196  result = std::make_unique<ExprAstUnary>(m_curToken.op,std::move(rhs));
2197  }
2198  else
2199  {
2200  result = parsePrimaryExpression();
2201  }
2202  }
2203  else
2204  {
2205  result = parsePrimaryExpression();
2206  }
2207  TRACE(("}parseUnaryExpression(%s)\n",m_tokenStream));
2208  return result;
2209  }
2210 
2212  {
2213  TRACE(("{parsePrimary(%s)\n",m_tokenStream));
2214  ExprAstPtr result;
2215  switch (m_curToken.type)
2216  {
2217  case ExprToken::Number:
2218  result = parseNumber();
2219  break;
2220  case ExprToken::Identifier:
2221  result = parseFilteredVariable();
2222  break;
2223  case ExprToken::Literal:
2224  result = parseLiteral();
2225  break;
2226  case ExprToken::Operator:
2228  {
2229  getNextToken(); // skip over opening bracket
2230  result = parseExpression();
2233  {
2234  warn(m_parser->templateName(),m_line,"missing closing parenthesis");
2235  }
2236  else
2237  {
2238  getNextToken(); // skip over closing bracket
2239  }
2240  }
2241  else
2242  {
2243  warn(m_parser->templateName(),m_line,"unexpected operator '%s' in expression",
2245  abort();
2246  }
2247  break;
2248  default:
2249  warn(m_parser->templateName(),m_line,"unexpected token in expression");
2250  }
2251  TRACE(("}parsePrimary(%s)\n",m_tokenStream));
2252  return result;
2253  }
2254 
2256  {
2257  TRACE(("{parseNumber(%d)\n",m_curToken.num));
2258  ExprAstPtr num = std::make_unique<ExprAstNumber>(m_curToken.num);
2259  getNextToken();
2260  TRACE(("}parseNumber()\n"));
2261  return num;
2262  }
2263 
2265  {
2266  TRACE(("{parseIdentifier(%s)\n",qPrint(m_curToken.id)));
2267  ExprAstPtr id = std::make_unique<ExprAstVariable>(m_curToken.id);
2268  getNextToken();
2269  TRACE(("}parseIdentifier()\n"));
2270  return id;
2271  }
2272 
2274  {
2275  TRACE(("{parseLiteral(%s)\n",qPrint(m_curToken.id)));
2276  ExprAstPtr expr = std::make_unique<ExprAstLiteral>(m_curToken.id);
2277  getNextToken();
2278  TRACE(("}parseLiteral()\n"));
2279  return expr;
2280  }
2281 
2283  {
2284  TRACE(("{parseIdentifierOptionalArgs(%s)\n",qPrint(m_curToken.id)));
2285  ExprAstPtr expr { parseIdentifier() };
2286  if (expr)
2287  {
2290  {
2291  getNextToken();
2292  ExprAstList args;
2293  args.push_back(std::unique_ptr<ExprAst>(parsePrimaryExpression()));
2296  {
2297  getNextToken();
2298  args.push_back(std::unique_ptr<ExprAst>(parsePrimaryExpression()));
2299  }
2300  expr = std::make_unique<ExprAstFunctionVariable>(std::move(expr),std::move(args));
2301  }
2302  }
2303  TRACE(("}parseIdentifierOptionalArgs()\n"));
2304  return expr;
2305  }
2306 
2308  {
2309  TRACE(("{parseFilteredVariable()\n"));
2311  if (expr)
2312  {
2315  {
2316  getNextToken();
2317  ExprAstFilterPtr filter = parseFilter();
2318  if (!filter) break;
2319  expr = std::make_unique<ExprAstFilterAppl>(std::move(expr),std::move(filter));
2320  }
2321  }
2322  TRACE(("}parseFilteredVariable()\n"));
2323  return expr;
2324  }
2325 
2327  {
2328  TRACE(("{parseFilter(%s)\n",qPrint(m_curToken.id)));
2329  QCString filterName = m_curToken.id;
2330  getNextToken();
2331  ExprAstPtr argExpr;
2334  {
2335  getNextToken();
2336  argExpr = parsePrimaryExpression();
2337  }
2338  ExprAstFilterPtr filter = std::make_unique<ExprAstFilter>(filterName,std::move(argExpr));
2339  TRACE(("}parseFilter()\n"));
2340  return filter;
2341  }
2342 
2343 
2345  {
2346  const char *p = m_tokenStream;
2347  char s[2];
2348  s[1]=0;
2349  if (p==0 || *p=='\0') return FALSE;
2350  while (*p==' ') p++; // skip over spaces
2351  char c=*p;
2352  if (*p=='\0') // only spaces...
2353  {
2354  m_tokenStream = p;
2355  return FALSE;
2356  }
2357  const char *q = p;
2358  switch (c)
2359  {
2360  case '=':
2361  if (c=='=' && *(p+1)=='=') // equal
2362  {
2364  p+=2;
2365  }
2366  break;
2367  case '!':
2368  if (c=='!' && *(p+1)=='=') // not equal
2369  {
2371  p+=2;
2372  }
2373  break;
2374  case '<':
2375  if (c=='<' && *(p+1)=='=') // less or equal
2376  {
2378  p+=2;
2379  }
2380  else // less
2381  {
2383  p++;
2384  }
2385  break;
2386  case '>':
2387  if (c=='>' && *(p+1)=='=') // greater or equal
2388  {
2390  p+=2;
2391  }
2392  else // greater
2393  {
2395  p++;
2396  }
2397  break;
2398  case '(':
2400  p++;
2401  break;
2402  case ')':
2404  p++;
2405  break;
2406  case '|':
2408  p++;
2409  break;
2410  case '+':
2412  p++;
2413  break;
2414  case '-':
2416  p++;
2417  break;
2418  case '*':
2420  p++;
2421  break;
2422  case '/':
2424  p++;
2425  break;
2426  case '%':
2428  p++;
2429  break;
2430  case ':':
2432  p++;
2433  break;
2434  case ',':
2436  p++;
2437  break;
2438  case 'n':
2439  if (strncmp(p,"not ",4)==0)
2440  {
2442  p+=4;
2443  }
2444  break;
2445  case 'a':
2446  if (strncmp(p,"and ",4)==0)
2447  {
2449  p+=4;
2450  }
2451  break;
2452  case 'o':
2453  if (strncmp(p,"or ",3)==0)
2454  {
2456  p+=3;
2457  }
2458  break;
2459  default:
2460  break;
2461  }
2462  if (p!=q) // found an operator
2463  {
2465  }
2466  else // no token found yet
2467  {
2468  if (c>='0' && c<='9') // number?
2469  {
2471  const char *np = p;
2472  m_curToken.num = 0;
2473  while (*np>='0' && *np<='9')
2474  {
2475  m_curToken.num*=10;
2476  m_curToken.num+=*np-'0';
2477  np++;
2478  }
2479  p=np;
2480  }
2481  else if (c=='_' || (c>='a' && c<='z') || (c>='A' && c<='Z')) // identifier?
2482  {
2484  s[0]=c;
2485  m_curToken.id = s;
2486  p++;
2487  while ((c=*p) &&
2488  (c=='_' || c=='.' ||
2489  (c>='a' && c<='z') ||
2490  (c>='A' && c<='Z') ||
2491  (c>='0' && c<='9'))
2492  )
2493  {
2494  s[0]=c;
2495  m_curToken.id+=s;
2496  p++;
2497  }
2498  if (m_curToken.id=="True") // treat true literal as numerical 1
2499  {
2501  m_curToken.num = 1;
2502  }
2503  else if (m_curToken.id=="False") // treat false literal as numerical 0
2504  {
2506  m_curToken.num = 0;
2507  }
2508  }
2509  else if (c=='"' || c=='\'') // string literal
2510  {
2512  m_curToken.id.resize(0);
2513  p++;
2514  char tokenChar = c;
2515  char cp=0;
2516  while ((c=*p) && (c!=tokenChar || (c==tokenChar && cp=='\\')))
2517  {
2518  s[0]=c;
2519  if (c!='\\' || cp=='\\') // don't add escapes
2520  {
2521  m_curToken.id+=s;
2522  }
2523  cp=c;
2524  p++;
2525  }
2526  if (*p==tokenChar) p++;
2527  }
2528  }
2529  if (p==q) // still no valid token found -> error
2530  {
2532  s[0]=c;
2533  s[1]=0;
2534  warn(m_parser->templateName(),m_line,"Found unknown token '%s' (%d) while parsing %s",s,c,m_tokenStream);
2535  m_curToken.id = s;
2536  p++;
2537  }
2538  TRACE(("token type=%d op=%d num=%d id=%s\n",
2540 
2541  m_tokenStream = p;
2542  return TRUE;
2543  }
2544 
2547  int m_line = 0;
2548  const char *m_tokenStream;
2549 };
2550 
2551 //----------------------------------------------------------
2552 
2553 /** @brief Internal class representing the implementation of a template */
2554 class TemplateImpl : public TemplateNode, public Template
2555 {
2556  public:
2557  TemplateImpl(TemplateEngine *e,const QCString &name,const QCString &data,
2558  const QCString &extension);
2559  ~TemplateImpl();
2560  void render(TextStream &ts, TemplateContext *c);
2561 
2562  TemplateEngine *engine() const { return m_engine; }
2564 
2565  private:
2570 };
2571 
2572 //----------------------------------------------------------
2573 
2575  : m_engine(e), m_indices(TemplateStruct::alloc())
2576 {
2577  //printf("%p:TemplateContextImpl::TemplateContextImpl()\n",(void*)this);
2578  m_fromUtf8 = (void*)(-1);
2579  push();
2580  set("index",std::static_pointer_cast<TemplateStructIntf>(m_indices));
2581 }
2582 
2584 {
2585  pop();
2586  //printf("%p:TemplateContextImpl::~TemplateContextImpl()\n",(void*)this);
2587 }
2588 
2589 void TemplateContextImpl::setEncoding(const QCString &templateName,int line,const QCString &enc)
2590 {
2591  if (enc==m_encoding) return; // nothing changed
2592  if (m_fromUtf8!=(void *)(-1))
2593  {
2595  m_fromUtf8 = (void*)(-1);
2596  }
2597  m_encoding=enc;
2598  if (!enc.isEmpty())
2599  {
2600  m_fromUtf8 = portable_iconv_open(enc.data(),"UTF-8");
2601  if (m_fromUtf8==(void*)(-1))
2602  {
2603  warn(templateName,line,"unsupported character conversion: '%s'->'UTF-8'\n", qPrint(enc));
2604  }
2605  }
2606  //printf("TemplateContextImpl::setEncoding(%s)\n",qPrint(enc));
2607 }
2608 
2610 {
2611  //printf("TemplateContextImpl::recode(%s)\n",qPrint(s));
2612  int iSize = s.length();
2613  int oSize = iSize*4+1;
2614  QCString output(oSize);
2615  size_t iLeft = iSize;
2616  size_t oLeft = oSize;
2617  const char *iPtr = s.data();
2618  char *oPtr = output.rawData();
2619  if (!portable_iconv(m_fromUtf8,&iPtr,&iLeft,&oPtr,&oLeft))
2620  {
2621  oSize -= (int)oLeft;
2622  output.resize(oSize+1);
2623  output.at(oSize)='\0';
2624  return output;
2625  }
2626  else
2627  {
2628  return s;
2629  }
2630 }
2631 
2633 {
2634  auto &ctx = m_contextStack.front();
2635  auto it = ctx.find(name.str());
2636  if (it!=ctx.end())
2637  {
2638  ctx.erase(it);
2639  }
2640  ctx.insert(std::make_pair(name.str(),v));
2641  //printf("TemplateContextImpl::set(%s) #stacks=%lu front().size()=%lu\n",
2642  // qPrint(name),m_contextStack.size(),m_contextStack.size()>0 ? m_contextStack.front().size() : 0);
2643 }
2644 
2645 
2647 {
2648  int i=name.find('.');
2649  if (i==-1) // simple name
2650  {
2651  return getPrimary(name);
2652  }
2653  else // obj.prop
2654  {
2655  QCString objName = name.left(i);
2656  TemplateVariant v = getPrimary(objName);
2657  QCString propName = name.mid(i+1);
2658  while (!propName.isEmpty())
2659  {
2660  //printf("getPrimary(%s) type=%zu:%s\n",qPrint(objName),v.type(),qPrint(v.toString()));
2661  if (v.isStruct() || v.isWeakStruct())
2662  {
2664  if (s)
2665  {
2666  i = propName.find(".");
2667  int l = i==-1 ? propName.length() : i;
2668  v = s->get(propName.left(l));
2669  if (!v.isValid())
2670  {
2671  warn(m_templateName,m_line,"requesting non-existing property '%s' for object '%s'",qPrint(propName.left(l)),qPrint(objName));
2672  }
2673  if (i!=-1)
2674  {
2675  objName = propName.left(i);
2676  propName = propName.mid(i+1);
2677  }
2678  else
2679  {
2680  propName.resize(0);
2681  }
2682  }
2683  else
2684  {
2685  return TemplateVariant();
2686  }
2687  }
2688  else if (v.isList())
2689  {
2690  TemplateListIntfPtr list = v.toList();
2691  if (list)
2692  {
2693  i = propName.find(".");
2694  int l = i==-1 ? propName.length() : i;
2695  bool b;
2696  int index = propName.left(l).toInt(&b);
2697  if (b)
2698  {
2699  v = list->at(index);
2700  }
2701  else
2702  {
2703  warn(m_templateName,m_line,"list index '%s' is not valid",qPrint(propName));
2704  break;
2705  }
2706  if (i!=-1)
2707  {
2708  propName = propName.mid(i+1);
2709  }
2710  else
2711  {
2712  propName.resize(0);
2713  }
2714  }
2715  else
2716  {
2717  return TemplateVariant();
2718  }
2719  }
2720  else
2721  {
2722  warn(m_templateName,m_line,"using . on an object '%s' is not an struct or list",qPrint(objName));
2723  return TemplateVariant();
2724  }
2725  }
2726  return v;
2727  }
2728 }
2729 
2731 {
2732  for (const auto &ctx : m_contextStack)
2733  {
2734  auto it = ctx.find(name.str());
2735  if (it!=ctx.end())
2736  {
2737  return &it->second;
2738  }
2739  }
2740  return 0; // not found
2741 }
2742 
2744 {
2745  const TemplateVariant *v = getRef(name);
2746  return v ? *v : TemplateVariant();
2747 }
2748 
2750 {
2751  m_contextStack.push_front(std::unordered_map<std::string,TemplateVariant>());
2752  //printf("TemplateContextImpl::push() #stacks=%lu\n",m_contextStack.size());
2753 }
2754 
2756 {
2757  //printf("TemplateContextImpl::pop() #stacks=%lu\n",m_contextStack.size());
2758  if (m_contextStack.empty())
2759  {
2760  warn(m_templateName,m_line,"pop() called on empty context stack!\n");
2761  }
2762  else
2763  {
2764  m_contextStack.pop_front();
2765  }
2766 }
2767 
2769 {
2770  return &m_blockContext;
2771 }
2772 
2773 void TemplateContextImpl::warn(const QCString &fileName,int line,const char *fmt,...) const
2774 {
2775  va_list args;
2776  va_start(args,fmt);
2777  va_warn(fileName,line,fmt,args);
2778  va_end(args);
2779  m_engine->printIncludeContext(fileName,line);
2780 }
2781 
2783 {
2784  //printf("TemplateContextImpl::openSubIndex(%s)\n",qPrint(indexName));
2785  auto kv = m_indexStacks.find(indexName.str());
2786  if (kv==m_indexStacks.end() || kv->second.empty() || kv->second.top().isList()) // error: no stack yet or no entry
2787  {
2788  warn(m_templateName,m_line,"opensubindex for index %s without preceding indexentry",qPrint(indexName));
2789  return;
2790  }
2791  // get the parent entry to add the list to
2792  auto &stack = kv->second;
2793  TemplateStructPtr entry = std::dynamic_pointer_cast<TemplateStruct>(stack.top().toStruct());
2794  if (entry)
2795  {
2796  // add new list to the stack
2798  stack.emplace(std::static_pointer_cast<TemplateListIntf>(list));
2799  entry->set("children",std::static_pointer_cast<TemplateListIntf>(list));
2800  entry->set("is_leaf_node",false);
2801  }
2802 }
2803 
2805 {
2806  //printf("TemplateContextImpl::closeSubIndex(%s)\n",qPrint(indexName));
2807  auto kv = m_indexStacks.find(indexName.str());
2808  if (kv==m_indexStacks.end() || kv->second.size()<3)
2809  {
2810  warn(m_templateName,m_line,"closesubindex for index %s without matching open",qPrint(indexName));
2811  }
2812  else
2813  {
2814  auto &stack = kv->second; // stack.size()>2
2815  if (stack.top().isStruct() || stack.top().isWeakStruct())
2816  {
2817  stack.pop(); // pop struct
2818  stack.pop(); // pop list
2819  }
2820  else // empty list! correct "is_left_node" attribute of the parent entry
2821  {
2822  stack.pop(); // pop list
2823  TemplateStructPtr entry = std::dynamic_pointer_cast<TemplateStruct>(stack.top().toStruct());
2824  if (entry)
2825  {
2826  entry->set("is_leaf_node",true);
2827  }
2828  }
2829  }
2830  //fprintf(stderr,"TemplateContextImpl::closeSubIndex(%s) end g_count=%d\n\n",qPrint(indexName),g_count);
2831 }
2832 
2834 {
2835  if (entry)
2836  {
2837  TemplateVariant parent = entry->get("parent");
2838  if (parent.isStruct() || parent.isWeakStruct())
2839  {
2840  getPathListFunc(parent.toStruct(),list);
2841  }
2842  list->append(entry);
2843  }
2844 }
2845 
2847 {
2849  getPathListFunc(entryWeakRef.lock(),result);
2850  return std::static_pointer_cast<TemplateListIntf>(result);
2851 }
2852 
2853 void TemplateContextImpl::addIndexEntry(const QCString &indexName,const std::vector<TemplateKeyValue> &arguments)
2854 {
2855  //auto it = arguments.begin();
2856  //printf("%p:> TemplateContextImpl::addIndexEntry(%s)\n",(void*)this,qPrint(indexName));
2857  //while (it!=arguments.end())
2858  //{
2859  // printf(" key=%s value=%s\n",(*it).key.data(),(*it).value.toString().data());
2860  // ++it;
2861  //}
2862  TemplateVariant parent(FALSE);
2863  auto kv = m_indexStacks.find(indexName.str());
2864  if (kv==m_indexStacks.end()) // no stack yet, create it!
2865  {
2866  kv = m_indexStacks.insert(std::make_pair(indexName.str(),std::stack<TemplateVariant>())).first;
2867  }
2868  TemplateListPtr list;
2869  auto &stack = kv->second;
2870  if (stack.empty()) // first item, create empty list and add it to the index
2871  {
2872  list = TemplateList::alloc();
2873  stack.emplace(std::static_pointer_cast<TemplateListIntf>(list));
2874  m_indices->set(indexName,std::static_pointer_cast<TemplateListIntf>(list)); // make list available under index
2875  }
2876  else // stack not empty
2877  {
2878  if (stack.top().isStruct() || stack.top().isWeakStruct()) // already an entry in the list
2879  {
2880  // remove current entry from the stack
2881  stack.pop();
2882  }
2883  else // first entry after opensubindex
2884  {
2885  ASSERT(stack.top().isList());
2886  }
2887  if (stack.size()>1)
2888  {
2889  TemplateVariant tmp = stack.top();
2890  stack.pop();
2891  // To prevent a cyclic dependency between parent and child which causes a memory
2892  // leak, we wrap the parent into a weak reference version.
2893  //parent = TemplateVariant(TemplateStructIntfWeakPtr(stack.top().toStruct()));
2894  stack.push(tmp);
2895  }
2896  // get list to add new item
2897  list = std::dynamic_pointer_cast<TemplateList>(stack.top().toList());
2898  }
2900  // add user specified fields to the entry
2901  for (auto it=arguments.begin();it!=arguments.end();++it)
2902  {
2903  entry->set((*it).key,(*it).value);
2904  }
2905  if (list->count()>0)
2906  {
2907  TemplateStructPtr lastEntry = std::dynamic_pointer_cast<TemplateStruct>(list->at(list->count()-1).toStruct());
2908  if (lastEntry)
2909  {
2910  lastEntry->set("last",false);
2911  }
2912  }
2913  entry->set("is_leaf_node",true);
2914  entry->set("first",list->count()==0);
2915  entry->set("index",list->count());
2916  entry->set("parent",parent);
2917  TemplateStructIntfWeakPtr entryWeak(std::static_pointer_cast<TemplateStructIntf>(entry));
2918  entry->set("path",TemplateVariant([entryWeak](const TemplateVariantList &){ return getPathFunc(entryWeak); }));
2919  entry->set("last",true);
2920  stack.push(TemplateVariant(std::static_pointer_cast<TemplateStructIntf>(entry)));
2921  list->append(TemplateVariant(std::static_pointer_cast<TemplateStructIntf>(entry)));
2922 }
2923 
2924 //----------------------------------------------------------
2925 
2926 /** @brief Class representing a piece of plain text in a template */
2928 {
2929  public:
2931  : TemplateNode(parent), m_data(data)
2932  {
2933  TRACE(("TemplateNodeText('%s')\n",replace(data,'\n',' ').data()));
2934  }
2935 
2937  {
2938  TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c);
2939  if (ci==0) return; // should not happen
2940  //printf("TemplateNodeText::render(%s) needsRecoding=%d ci=%p\n",qPrint(m_data),ci->needsRecoding(),ci);
2941  if (ci->spacelessEnabled())
2942  {
2943  if (ci->needsRecoding())
2944  {
2945  ts << ci->recode(ci->spacelessIntf()->remove(m_data));
2946  }
2947  else
2948  {
2949  ts << ci->spacelessIntf()->remove(m_data);
2950  }
2951  }
2952  else
2953  {
2954  if (ci->needsRecoding())
2955  {
2956  ts << ci->recode(m_data);
2957  }
2958  else
2959  {
2960  ts << m_data;
2961  }
2962  }
2963  }
2964  private:
2966 };
2967 
2968 //----------------------------------------------------------
2969 
2970 /** @brief Class representing a variable in a template */
2972 {
2973  public:
2975  : TemplateNode(parent), m_templateName(parser->templateName()), m_line(line)
2976  {
2977  TRACE(("TemplateNodeVariable(%s)\n",qPrint(var)));
2978  ExpressionParser expParser(parser,line);
2979  m_var = expParser.parse(var);
2980  if (m_var==0)
2981  {
2982  parser->warn(m_templateName,line,"invalid expression '%s' for variable",qPrint(var));
2983  }
2984  }
2986  {
2987  }
2988 
2990  {
2991  TRACE(("{TemplateNodeVariable::render\n"));
2992  TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c);
2993  if (ci==0) return; // should not happen
2995  if (m_var)
2996  {
2997  TemplateVariant v = m_var->resolve(c);
2998  if (v.isFunction())
2999  {
3000  v = v.call();
3001  }
3002  if (ci->escapeIntf() && !v.raw())
3003  {
3004  if (ci->needsRecoding())
3005  {
3006  ts << ci->recode(ci->escapeIntf()->escape(v.toString()));
3007  }
3008  else
3009  {
3010  ts << ci->escapeIntf()->escape(v.toString());
3011  }
3012  }
3013  else
3014  {
3015  if (ci->needsRecoding())
3016  {
3017  ts << ci->recode(v.toString());
3018  }
3019  else
3020  {
3021  ts << v.toString();
3022  }
3023  }
3024  }
3025  TRACE(("}TemplateNodeVariable::render\n"));
3026  }
3027 
3028  private:
3030  int m_line = 0;
3032 };
3033 
3034 //----------------------------------------------------------
3035 
3036 /** @brief Helper class for creating template AST tag nodes and returning
3037  * the template for a given node.
3038  */
3039 template<class T> class TemplateNodeCreator : public TemplateNode
3040 {
3041  public:
3043  : TemplateNode(parent), m_templateName(parser->templateName()), m_line(line) {}
3046  int line,
3047  const QCString &data)
3048  {
3049  return std::make_unique<T>(parser,parent,line,data);
3050  }
3052  {
3053  TemplateNode *root = this;
3054  while (root && root->parent())
3055  {
3056  root = root->parent();
3057  }
3058  return dynamic_cast<TemplateImpl*>(root);
3059  }
3060  protected:
3061  void mkpath(const TemplateContextImpl *ci,const std::string &fileName)
3062  {
3063  size_t i=fileName.find('/');
3064  std::string outputDir = ci->outputDirectory().str();
3065  Dir d(outputDir);
3066  if (!d.exists())
3067  {
3068  Dir rootDir;
3069  if (!rootDir.mkdir(outputDir))
3070  {
3071  err("tag OUTPUT_DIRECTORY: Output directory '%s' does not "
3072  "exist and cannot be created\n",outputDir.c_str());
3073  return;
3074  }
3075  d.setPath(outputDir);
3076  }
3077  size_t j=0;
3078  while (i!=std::string::npos) // fileName contains path part
3079  {
3080  if (d.exists())
3081  {
3082  bool ok = d.mkdir(fileName.substr(j,i-j));
3083  if (!ok)
3084  {
3085  err("Failed to create directory '%s'\n",(fileName.substr(j,i-j)).c_str());
3086  break;
3087  }
3088  std::string dirName = outputDir+'/'+fileName.substr(0,i);
3089  d = Dir(dirName);
3090  j = i+1;
3091  }
3092  i=fileName.find('/',i+1);
3093  }
3094  }
3096  int m_line = 0;
3097 };
3098 
3099 //----------------------------------------------------------
3100 
3101 /** @brief Class representing an 'if' tag in a template */
3102 class TemplateNodeIf : public TemplateNodeCreator<TemplateNodeIf>
3103 {
3104  public:
3105  TemplateNodeIf(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data) :
3107  {
3108  TRACE(("{TemplateNodeIf(%s)\n",qPrint(data)));
3109  if (data.isEmpty())
3110  {
3111  parser->warn(m_templateName,line,"missing argument for if tag");
3112  }
3113  StringVector stopAt = { "endif", "elif", "else" };
3114 
3115  // if 'nodes'
3116  {
3117  m_ifGuardedNodes.push_back(std::make_unique<GuardedNodes>());
3118  auto &guardedNodes = m_ifGuardedNodes.back();
3119  ExpressionParser ex(parser,line);
3120  guardedNodes->line = line;
3121  guardedNodes->guardAst = ex.parse(data);
3122  parser->parse(this,line,stopAt,guardedNodes->trueNodes);
3123  }
3124  auto tok = parser->takeNextToken();
3125 
3126  // elif 'nodes'
3127  while (tok && tok->data.left(5)=="elif ")
3128  {
3129  m_ifGuardedNodes.push_back(std::make_unique<GuardedNodes>());
3130  auto &guardedNodes = m_ifGuardedNodes.back();
3131  ExpressionParser ex(parser,line);
3132  guardedNodes->line = tok->line;
3133  guardedNodes->guardAst = ex.parse(tok->data.mid(5));
3134  parser->parse(this,tok->line,stopAt,guardedNodes->trueNodes);
3135  // proceed to the next token
3136  tok = parser->takeNextToken();
3137  }
3138 
3139  // else 'nodes'
3140  if (tok && tok->data=="else")
3141  {
3142  stopAt.pop_back(); // remove "else"
3143  stopAt.pop_back(); // remove "elif"
3144  parser->parse(this,line,stopAt,m_falseNodes);
3145  parser->removeNextToken(); // skip over endif
3146  }
3147  TRACE(("}TemplateNodeIf(%s)\n",qPrint(data)));
3148  }
3150  {
3151  }
3152 
3154  {
3155  TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c);
3156  if (ci==0) return; // should not happen
3158  //printf("TemplateNodeIf::render #trueNodes=%d #falseNodes=%d\n",m_trueNodes.count(),m_falseNodes.count());
3159  bool processed=FALSE;
3160  for (auto &nodes : m_ifGuardedNodes)
3161  {
3162  if (nodes->guardAst)
3163  {
3164  TemplateVariant guardValue = nodes->guardAst->resolve(c);
3165  if (guardValue.toBool()) // render nodes for the first guard that evaluated to 'true'
3166  {
3167  nodes->trueNodes.render(ts,c);
3168  processed=TRUE;
3169  break;
3170  }
3171  }
3172  else
3173  {
3174  ci->warn(m_templateName,nodes->line,"invalid expression for if/elif");
3175  }
3176  }
3177  if (!processed)
3178  {
3179  // all guards are false, render 'else' nodes
3180  m_falseNodes.render(ts,c);
3181  }
3182  }
3183  private:
3185  {
3186  int line = 0;
3189  };
3190  std::vector< std::unique_ptr<GuardedNodes> > m_ifGuardedNodes;
3192 };
3193 
3194 //----------------------------------------------------------
3195 /** @brief Class representing a 'for' tag in a template */
3196 class TemplateNodeRepeat : public TemplateNodeCreator<TemplateNodeRepeat>
3197 {
3198  public:
3201  {
3202  TRACE(("{TemplateNodeRepeat(%s)\n",qPrint(data)));
3203  ExpressionParser expParser(parser,line);
3204  m_expr = expParser.parse(data);
3205  StringVector stopAt = { "endrepeat" };
3206  parser->parse(this,line,stopAt,m_repeatNodes);
3207  parser->removeNextToken(); // skip over endrepeat
3208  TRACE(("}TemplateNodeRepeat(%s)\n",qPrint(data)));
3209  }
3211  {
3212  TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c);
3213  if (ci==0) return; // should not happen
3215  TemplateVariant v;
3216  if (m_expr && (v=m_expr->resolve(c)).isInt())
3217  {
3218  int i, n = v.toInt();
3219  for (i=0;i<n;i++)
3220  {
3222  s->set("counter0", (int)i);
3223  s->set("counter", (int)(i+1));
3224  s->set("revcounter", (int)(n-i));
3225  s->set("revcounter0", (int)(n-i-1));
3226  s->set("first",i==0);
3227  s->set("last", i==n-1);
3228  c->set("repeatloop",std::static_pointer_cast<TemplateStructIntf>(s));
3229  // render all items for this iteration of the loop
3230  m_repeatNodes.render(ts,c);
3231  }
3232  }
3233  else // simple type...
3234  {
3235  ci->warn(m_templateName,m_line,"for requires a variable of list type!");
3236  }
3237  }
3238  private:
3241 };
3242 
3243 //----------------------------------------------------------
3244 
3245 /** @brief Class representing a 'range' tag in a template */
3246 class TemplateNodeRange : public TemplateNodeCreator<TemplateNodeRange>
3247 {
3248  public:
3251  {
3252  TRACE(("{TemplateNodeRange(%s)\n",qPrint(data)));
3253  QCString start,end;
3254  int i1 = data.find(" from ");
3255  int i2 = data.find(" to ");
3256  int i3 = data.find(" downto ");
3257  if (i1==-1)
3258  {
3259  if (data.endsWith(" from"))
3260  {
3261  parser->warn(m_templateName,line,"range missing after 'from' keyword");
3262  }
3263  else if (data=="from")
3264  {
3265  parser->warn(m_templateName,line,"range needs an iterator variable and a range");
3266  }
3267  else
3268  {
3269  parser->warn(m_templateName,line,"range is missing 'from' keyword");
3270  }
3271  }
3272  else if (i2==-1 && i3==-1)
3273  {
3274  if (data.endsWith(" to"))
3275  {
3276  parser->warn(m_templateName,line,"range is missing end value after 'to' keyword");
3277  }
3278  else if (data.endsWith(" downto"))
3279  {
3280  parser->warn(m_templateName,line,"range is missing end value after 'downto' keyword");
3281  }
3282  else
3283  {
3284  parser->warn(m_templateName,line,"range is missing 'to' or 'downto' keyword");
3285  }
3286  }
3287  else
3288  {
3289  m_var = data.left(i1).stripWhiteSpace();
3290  if (m_var.isEmpty())
3291  {
3292  parser->warn(m_templateName,line,"range needs an iterator variable");
3293  }
3294  start = data.mid(i1+6,i2-i1-6).stripWhiteSpace();
3295  if (i2!=-1)
3296  {
3297  end = data.right(data.length()-i2-4).stripWhiteSpace();
3298  m_down = FALSE;
3299  }
3300  else if (i3!=-1)
3301  {
3302  end = data.right(data.length()-i3-8).stripWhiteSpace();
3303  m_down = TRUE;
3304  }
3305  }
3306  ExpressionParser expParser(parser,line);
3307  m_startExpr = expParser.parse(start);
3308  m_endExpr = expParser.parse(end);
3309 
3310  StringVector stopAt = { "endrange" };
3311  parser->parse(this,line,stopAt,m_loopNodes);
3312  parser->removeNextToken(); // skip over endrange
3313  TRACE(("}TemplateNodeRange(%s)\n",qPrint(data)));
3314  }
3315 
3317  {
3318  TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c);
3319  if (ci==0) return; // should not happen
3321  //printf("TemplateNodeRange::render #loopNodes=%d\n",
3322  // m_loopNodes.count());
3323  if (m_startExpr && m_endExpr)
3324  {
3325  TemplateVariant vs = m_startExpr->resolve(c);
3326  TemplateVariant ve = m_endExpr->resolve(c);
3327  if (vs.isInt() && ve.isInt())
3328  {
3329  int s = vs.toInt();
3330  int e = ve.toInt();
3331  int l = m_down ? s-e+1 : e-s+1;
3332  if (l>0)
3333  {
3334  c->push();
3335  //int index = m_reversed ? list.count() : 0;
3336  const TemplateVariant *parentLoop = c->getRef("forloop");
3337  uint index = 0;
3338  int i = m_down ? e : s;
3339  bool done=false;
3340  while (!done)
3341  {
3342  // set the forloop meta-data variable
3344  ls->set("counter0", (int)index);
3345  ls->set("counter", (int)(index+1));
3346  ls->set("revcounter", (int)(l-index));
3347  ls->set("revcounter0", (int)(l-index-1));
3348  ls->set("first",index==0);
3349  ls->set("last", (int)index==l-1);
3350  ls->set("parentloop",parentLoop ? *parentLoop : TemplateVariant());
3351  c->set("forloop",std::static_pointer_cast<TemplateStructIntf>(ls));
3352 
3353  // set the iterator variable
3354  c->set(m_var,i);
3355 
3356  // render all items for this iteration of the loop
3357  m_loopNodes.render(ts,c);
3358 
3359  index++;
3360  if (m_down)
3361  {
3362  i--;
3363  done = i<e;
3364  }
3365  else
3366  {
3367  i++;
3368  done = i>e;
3369  }
3370  }
3371  c->pop();
3372  }
3373  else
3374  {
3375  ci->warn(m_templateName,m_line,"range %d %s %d is empty!",
3376  s,m_down?"downto":"to",e);
3377  }
3378  }
3379  else if (!vs.isInt())
3380  {
3381  ci->warn(m_templateName,m_line,"range requires a start value of integer type!");
3382  }
3383  else if (!ve.isInt())
3384  {
3385  ci->warn(m_templateName,m_line,"range requires an end value of integer type!");
3386  }
3387  }
3388  else if (!m_startExpr)
3389  {
3390  ci->warn(m_templateName,m_line,"range has empty start value");
3391  }
3392  else if (!m_endExpr)
3393  {
3394  ci->warn(m_templateName,m_line,"range has empty end value");
3395  }
3396  }
3397 
3398  private:
3399  bool m_down = false;
3404 };
3405 
3406 //----------------------------------------------------------
3407 
3408 /** @brief Class representing a 'for' tag in a template */
3409 class TemplateNodeFor : public TemplateNodeCreator<TemplateNodeFor>
3410 {
3411  public:
3414  {
3415  TRACE(("{TemplateNodeFor(%s)\n",qPrint(data)));
3416  QCString exprStr;
3417  int i = data.find(" in ");
3418  if (i==-1)
3419  {
3420  if (data.endsWith(" in"))
3421  {
3422  parser->warn(m_templateName,line,"for is missing container after 'in' keyword");
3423  }
3424  else if (data=="in")
3425  {
3426  parser->warn(m_templateName,line,"for needs at least one iterator variable");
3427  }
3428  else
3429  {
3430  parser->warn(m_templateName,line,"for is missing 'in' keyword");
3431  }
3432  }
3433  else
3434  {
3435  m_vars = split(data.left(i),",");
3436  if (m_vars.size()==0)
3437  {
3438  parser->warn(m_templateName,line,"for needs at least one iterator variable");
3439  }
3440 
3441  int j = data.find(" reversed",i);
3442  m_reversed = (j!=-1);
3443 
3444  if (j==-1) j=data.length();
3445  if (j>i+4)
3446  {
3447  exprStr = data.mid(i+4,j-i-4); // skip over " in " part
3448  }
3449  if (exprStr.isEmpty())
3450  {
3451  parser->warn(m_templateName,line,"for is missing container after 'in' keyword");
3452  }
3453  }
3454  ExpressionParser expParser(parser,line);
3455  m_expr = expParser.parse(exprStr);
3456 
3457  StringVector stopAt = { "endfor", "empty" };
3458  parser->parse(this,line,stopAt,m_loopNodes);
3459  auto tok = parser->takeNextToken();
3460  if (tok && tok->data=="empty")
3461  {
3462  stopAt.pop_back();
3463  parser->parse(this,line,stopAt,m_emptyNodes);
3464  parser->removeNextToken(); // skip over endfor
3465  }
3466  TRACE(("}TemplateNodeFor(%s)\n",qPrint(data)));
3467  }
3468 
3470  {
3471  TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c);
3472  if (ci==0) return; // should not happen
3474  //printf("TemplateNodeFor::render #loopNodes=%d #emptyNodes=%d\n",
3475  // m_loopNodes.count(),m_emptyNodes.count());
3476  if (m_expr)
3477  {
3478  TemplateVariant v = m_expr->resolve(c);
3479  if (v.isFunction())
3480  {
3481  v = v.call();
3482  }
3483  const TemplateListIntfPtr list = v.toList();
3484  if (list)
3485  {
3486  uint listSize = list->count();
3487  if (listSize==0) // empty for loop
3488  {
3489  m_emptyNodes.render(ts,c);
3490  return;
3491  }
3492  c->push();
3493  //int index = m_reversed ? list.count() : 0;
3494  //TemplateVariant v;
3495  const TemplateVariant *parentLoop = c->getRef("forloop");
3496  uint index = m_reversed ? listSize-1 : 0;
3497  TemplateListIntf::ConstIteratorPtr it = list->createIterator();
3498  TemplateVariant ve;
3499  for (m_reversed ? it->toLast() : it->toFirst();
3500  (it->current(ve));
3501  m_reversed ? it->toPrev() : it->toNext())
3502  {
3504  s->set("counter0", (int)index);
3505  s->set("counter", (int)(index+1));
3506  s->set("revcounter", (int)(listSize-index));
3507  s->set("revcounter0", (int)(listSize-index-1));
3508  s->set("first",index==0);
3509  s->set("last", index==listSize-1);
3510  s->set("parentloop",parentLoop ? *parentLoop : TemplateVariant());
3511  c->set("forloop",std::static_pointer_cast<TemplateStructIntf>(s));
3512 
3513  // add variables for this loop to the context
3514  //obj->addVariableToContext(index,m_vars,c);
3515  uint vi=0;
3516  if (m_vars.size()==1) // loop variable represents an item
3517  {
3518  c->set(m_vars[vi++],ve);
3519  }
3520  else if (m_vars.size()>1 && (ve.isStruct() || ve.isWeakStruct()))
3521  // loop variables represent elements in a list item
3522  {
3523  TemplateStructIntfPtr vs = ve.toStruct();
3524  if (vs)
3525  {
3526  for (uint i=0;i<m_vars.size();i++,vi++)
3527  {
3528  c->set(m_vars[vi],vs->get(m_vars[vi]));
3529  }
3530  }
3531  }
3532  for (;vi<m_vars.size();vi++)
3533  {
3534  c->set(m_vars[vi],TemplateVariant());
3535  }
3536 
3537  // render all items for this iteration of the loop
3538  m_loopNodes.render(ts,c);
3539 
3540  if (m_reversed) index--; else index++;
3541  }
3542  c->pop();
3543  }
3544  else // simple type...
3545  {
3546  ci->warn(m_templateName,m_line,"for requires a variable of list type, got type '%s'!",qPrint(v.typeAsString()));
3547  }
3548  }
3549  }
3550 
3551  private:
3552  bool m_reversed = false;
3554  std::vector<QCString> m_vars;
3557 };
3558 
3559 //----------------------------------------------------------
3560 
3561 /** @brief Class representing an 'markers' tag in a template */
3562 class TemplateNodeMsg : public TemplateNodeCreator<TemplateNodeMsg>
3563 {
3564  public:
3567  {
3568  TRACE(("{TemplateNodeMsg()\n"));
3569  StringVector stopAt = { "endmsg" };
3570  parser->parse(this,line,stopAt,m_nodes);
3571  parser->removeNextToken(); // skip over endmsg
3572  TRACE(("}TemplateNodeMsg()\n"));
3573  }
3575  {
3576  TRACE(("{TemplateNodeMsg::render\n"));
3577  TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c);
3578  if (ci==0) return; // should not happen
3580  TemplateEscapeIntf *escIntf = ci->escapeIntf();
3581  ci->setActiveEscapeIntf(0); // avoid escaping things we send to standard out
3582  bool enable = ci->spacelessEnabled();
3583  ci->enableSpaceless(FALSE);
3584  TextStream t(&std::cout);
3585  m_nodes.render(t,c);
3586  t.flush();
3587  std::cout << "\n";
3588  ci->setActiveEscapeIntf(escIntf);
3589  ci->enableSpaceless(enable);
3590  TRACE(("}TemplateNodeMsg::render\n"));
3591  }
3592  private:
3594 };
3595 
3596 
3597 //----------------------------------------------------------
3598 
3599 /** @brief Class representing a 'block' tag in a template */
3600 class TemplateNodeBlock : public TemplateNodeCreator<TemplateNodeBlock>
3601 {
3602  public:
3605  {
3606  TRACE(("{TemplateNodeBlock(%s)\n",qPrint(data)));
3607  m_blockName = data;
3608  if (m_blockName.isEmpty())
3609  {
3610  parser->warn(parser->templateName(),line,"block tag without name");
3611  }
3612  StringVector stopAt = { "endblock" };
3613  parser->parse(this,line,stopAt,m_nodes);
3614  parser->removeNextToken(); // skip over endblock
3615  TRACE(("}TemplateNodeBlock(%s)\n",qPrint(data)));
3616  }
3617 
3619  {
3620  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
3621  if (ci==0) return; // should not happen
3623  TemplateImpl *t = getTemplate();
3624  if (t)
3625  {
3626  // remove block from the context, so block.super can work
3628  if (nb) // block is overruled
3629  {
3630  ci->push();
3631  TextStream ss;
3632  // get super block of block nb
3634  if (sb && sb!=nb && sb!=this) // nb and sb both overrule this block
3635  {
3636  sb->render(ss,c); // render parent of nb to string
3637  }
3638  else if (nb!=this) // only nb overrules this block
3639  {
3640  m_nodes.render(ss,c); // render parent of nb to string
3641  }
3642  QCString super = ss.str();
3643  // add 'block.super' variable to allow access to parent block content
3645  superBlock->set("super",TemplateVariant(super.data(),TRUE));
3646  ci->set("block",std::static_pointer_cast<TemplateStructIntf>(superBlock));
3647  // render the overruled block contents
3648  t->engine()->enterBlock(nb->m_templateName,nb->m_blockName,nb->m_line);
3649  nb->m_nodes.render(ts,c);
3650  t->engine()->leaveBlock();
3651  ci->pop();
3652  // re-add block to the context
3653  ci->blockContext()->push(nb);
3654  }
3655  else // block has no overrule
3656  {
3658  m_nodes.render(ts,c);
3659  t->engine()->leaveBlock();
3660  }
3661  }
3662  }
3663 
3664  QCString name() const
3665  {
3666  return m_blockName;
3667  }
3668 
3669  private:
3672 };
3673 
3674 //----------------------------------------------------------
3675 
3676 /** @brief Class representing a 'extend' tag in a template */
3677 class TemplateNodeExtend : public TemplateNodeCreator<TemplateNodeExtend>
3678 {
3679  public:
3682  {
3683  TRACE(("{TemplateNodeExtend(%s)\n",qPrint(data)));
3684  ExpressionParser ep(parser,line);
3685  if (data.isEmpty())
3686  {
3687  parser->warn(m_templateName,line,"extend tag is missing template file argument");
3688  }
3689  m_extendExpr = ep.parse(data);
3690  StringVector stopAt;
3691  parser->parse(this,line,stopAt,m_nodes);
3692  TRACE(("}TemplateNodeExtend(%s)\n",qPrint(data)));
3693  }
3694 
3696  {
3697  TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c);
3698  if (ci==0) return; // should not happen
3700  if (m_extendExpr==0) return;
3701 
3702  QCString extendFile = m_extendExpr->resolve(c).toString();
3703  if (extendFile.isEmpty())
3704  {
3705  ci->warn(m_templateName,m_line,"invalid parameter for extend command");
3706  }
3707 
3708  // goto root of tree (template node)
3709  TemplateImpl *t = getTemplate();
3710  if (t)
3711  {
3712  Template *bt = t->engine()->loadByName(extendFile,m_line);
3713  TemplateImpl *baseTemplate = bt ? dynamic_cast<TemplateImpl*>(bt) : 0;
3714  if (baseTemplate)
3715  {
3716  // fill block context
3717  TemplateBlockContext *bc = ci->blockContext();
3718 
3719  // add overruling blocks to the context
3720  for (const auto &n : m_nodes)
3721  {
3722  TemplateNodeBlock *nb = dynamic_cast<TemplateNodeBlock*>(n.get());
3723  if (nb)
3724  {
3725  bc->add(nb);
3726  }
3727  TemplateNodeMsg *msg = dynamic_cast<TemplateNodeMsg*>(n.get());
3728  if (msg)
3729  {
3730  msg->render(ts,c);
3731  }
3732  }
3733 
3734  // render the base template with the given context
3735  baseTemplate->render(ts,c);
3736 
3737  // clean up
3738  bc->clear();
3739  }
3740  else
3741  {
3742  ci->warn(m_templateName,m_line,"failed to load template %s for extend",qPrint(extendFile));
3743  }
3744  t->engine()->unload(bt);
3745  }
3746  }
3747 
3748  private:
3751 };
3752 
3753 /** @brief Class representing an 'include' tag in a template */
3754 class TemplateNodeInclude : public TemplateNodeCreator<TemplateNodeInclude>
3755 {
3756  public:
3759  {
3760  TRACE(("TemplateNodeInclude(%s)\n",qPrint(data)));
3761  ExpressionParser ep(parser,line);
3762  if (data.isEmpty())
3763  {
3764  parser->warn(m_templateName,line,"include tag is missing template file argument");
3765  }
3766  m_includeExpr = ep.parse(data);
3767  }
3769  {
3770  TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c);
3771  if (ci==0) return; // should not happen
3773  if (m_includeExpr)
3774  {
3775  QCString includeFile = m_includeExpr->resolve(c).toString();
3776  if (includeFile.isEmpty())
3777  {
3778  ci->warn(m_templateName,m_line,"invalid parameter for include command\n");
3779  }
3780  else
3781  {
3782  TemplateImpl *t = getTemplate();
3783  if (t)
3784  {
3785  Template *it = t->engine()->loadByName(includeFile,m_line);
3786  TemplateImpl *incTemplate = it ? dynamic_cast<TemplateImpl*>(it) : 0;
3787  if (incTemplate)
3788  {
3789  incTemplate->render(ts,c);
3790  }
3791  else
3792  {
3793  ci->warn(m_templateName,m_line,"failed to load template '%s' for include",qPrint(includeFile));
3794  }
3795  t->engine()->unload(it);
3796  }
3797  }
3798  }
3799  }
3800 
3801  private:
3803 };
3804 
3805 //----------------------------------------------------------
3806 
3808 {
3809  bool skipSpaces=true;
3810  const char *src = s.data();
3811  char *dst = s.rawData();
3812  char c;
3813  while ((c=*src++))
3814  {
3815  if (c=='\n') { *dst++=c; skipSpaces=true; }
3816  else if (c==' ' && skipSpaces) {}
3817  else { *dst++ = c; skipSpaces=false; }
3818  }
3819  s.resize(dst-s.data()+1);
3820 }
3821 
3822 /** @brief Class representing an 'create' tag in a template */
3823 class TemplateNodeCreate : public TemplateNodeCreator<TemplateNodeCreate>
3824 {
3825  public:
3828  {
3829  TRACE(("TemplateNodeCreate(%s)\n",qPrint(data)));
3830  if (data.isEmpty())
3831  {
3832  parser->warn(m_templateName,line,"create tag is missing arguments");
3833  }
3834  int i = data.find(" from ");
3835  if (i==-1)
3836  {
3837  if (data.endsWith(" from"))
3838  {
3839  parser->warn(m_templateName,line,"create is missing template name after 'from' keyword");
3840  }
3841  else if (data=="from")
3842  {
3843  parser->warn(m_templateName,line,"create needs a file name and a template name");
3844  }
3845  else
3846  {
3847  parser->warn(m_templateName,line,"create is missing 'from' keyword");
3848  }
3849  }
3850  else
3851  {
3852  ExpressionParser ep(parser,line);
3853  m_fileExpr = ep.parse(data.left(i).stripWhiteSpace());
3854  m_templateExpr = ep.parse(data.mid(i+6).stripWhiteSpace());
3855  }
3856  }
3858  {
3859  TRACE(("{TemplateNodeCreate::render\n"));
3860  TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c);
3861  if (ci==0) return; // should not happen
3863  if (m_templateExpr && m_fileExpr)
3864  {
3865  QCString templateFile = m_templateExpr->resolve(c).toString();
3866  QCString outputFile = m_fileExpr->resolve(c).toString();
3867  if (templateFile.isEmpty())
3868  {
3869  ci->warn(m_templateName,m_line,"empty template name parameter for create command\n");
3870  }
3871  else if (outputFile.isEmpty())
3872  {
3873  ci->warn(m_templateName,m_line,"empty file name parameter for create command\n");
3874  }
3875  else
3876  {
3877  TemplateImpl *t = getTemplate();
3878  if (t)
3879  {
3880  QCString extension=outputFile;
3881  int i=extension.findRev('.');
3882  if (i!=-1)
3883  {
3884  extension=extension.right(extension.length()-i-1);
3885  }
3886  t->engine()->setOutputExtension(extension);
3887  Template *ct = t->engine()->loadByName(templateFile,m_line);
3888  TemplateImpl *createTemplate = ct ? dynamic_cast<TemplateImpl*>(ct) : 0;
3889  if (createTemplate)
3890  {
3891  mkpath(ci,outputFile.str());
3892  if (!ci->outputDirectory().isEmpty())
3893  {
3894  outputFile.prepend(ci->outputDirectory()+"/");
3895  }
3896  //printf("NoteCreate(%s)\n",qPrint(outputFile));
3897  std::ofstream f(outputFile.str(),std::ofstream::out | std::ofstream::binary);
3898  if (f.is_open())
3899  {
3900  TextStream ts(&f);
3901  TemplateEscapeIntf *escIntf = ci->escapeIntf();
3902  ci->selectEscapeIntf(extension);
3903  TextStream os;
3904  createTemplate->render(os,c);
3905  QCString out = os.str();
3907  ts << out;
3908  t->engine()->unload(t);
3909  ci->setActiveEscapeIntf(escIntf);
3910  }
3911  else
3912  {
3913  ci->warn(m_templateName,m_line,"failed to open output file '%s' for create command",qPrint(outputFile));
3914  }
3915  }
3916  else
3917  {
3918  ci->warn(m_templateName,m_line,"failed to load template '%s' for include",qPrint(templateFile));
3919  }
3920  t->engine()->setOutputExtension("");
3921  }
3922  }
3923  }
3924  TRACE(("}TemplateNodeCreate::render\n"));
3925  }
3926 
3927  private:
3930 };
3931 
3932 //----------------------------------------------------------
3933 
3934 /** @brief Class representing an 'tree' tag in a template */
3935 class TemplateNodeTree : public TemplateNodeCreator<TemplateNodeTree>
3936 {
3938  {
3940  : object(o), list(l), templateCtx(c) {}
3944  };
3945  public:
3948  {
3949  TRACE(("{TemplateNodeTree(%s)\n",qPrint(data)));
3950  ExpressionParser ep(parser,line);
3951  if (data.isEmpty())
3952  {
3953  parser->warn(m_templateName,line,"recursetree tag is missing data argument");
3954  }
3955  m_treeExpr = ep.parse(data);
3956  StringVector stopAt = { "endrecursetree" };
3957  parser->parse(this,line,stopAt,m_treeNodes);
3958  parser->removeNextToken(); // skip over endrecursetree
3959  TRACE(("}TemplateNodeTree(%s)\n",qPrint(data)));
3960  }
3962  {
3963  //printf("TemplateNodeTree::renderChildren(%d)\n",ctx->list->count());
3964  // render all children of node to a string and return it
3965  TemplateContext *c = ctx->templateCtx;
3966  TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c);
3967  if (ci==0) return QCString(); // should not happen
3968  TextStream ss;
3969  c->push();
3970  TemplateVariant node;
3971  TemplateListIntf::ConstIteratorPtr it = ctx->list->createIterator();
3972  for (it->toFirst();(it->current(node));it->toNext())
3973  {
3974  c->set("node",node);
3975  bool hasChildren=FALSE;
3976  const TemplateStructIntfPtr ns = node.toStruct();
3977  if (ns) // node is a struct
3978  {
3979  TemplateVariant v = ns->get("children");
3980  if (v.isValid()) // with a field 'children'
3981  {
3982  const TemplateListIntfPtr list = v.toList();
3983  if (list && list->count()>0) // non-empty list
3984  {
3985  TreeContext childCtx(this,list,ctx->templateCtx);
3986  TemplateVariant children(
3987  [childCtx](const TemplateVariantList &) {
3988  return TemplateVariant(childCtx.object->renderChildren(&childCtx),TRUE);
3989  });
3990  children.setRaw(TRUE);
3991  c->set("children",children);
3992  m_treeNodes.render(ss,c);
3993  hasChildren=TRUE;
3994  }
3995  else if (list==0)
3996  {
3997  ci->warn(m_templateName,m_line,"recursetree: children attribute has type '%s' instead of list\n",qPrint(v.typeAsString()));
3998  }
3999  }
4000  //else
4001  //{
4002  // ci->warn(m_templateName,m_line,"recursetree: children attribute is not valid");
4003  //}
4004  }
4005  if (!hasChildren)
4006  {
4007  c->set("children",TemplateVariant("")); // provide default
4008  m_treeNodes.render(ss,c);
4009  }
4010  }
4011  c->pop();
4012  return ss.str();
4013  }
4015  {
4016  //printf("TemplateNodeTree::render()\n");
4017  TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c);
4018  if (ci==0) return; // should not happen
4020  TemplateVariant v = m_treeExpr->resolve(c);
4021  const TemplateListIntfPtr list = v.toList();
4022  if (list)
4023  {
4024  TreeContext ctx(this,list,c);
4025  ts << renderChildren(&ctx);
4026  }
4027  else
4028  {
4029  ci->warn(m_templateName,m_line,"recursetree's argument should be a list type");
4030  }
4031  }
4032 
4033  private:
4036 };
4037 
4038 //----------------------------------------------------------
4039 
4040 /** @brief Class representing an 'indexentry' tag in a template */
4041 class TemplateNodeIndexEntry : public TemplateNodeCreator<TemplateNodeIndexEntry>
4042 {
4043  struct Mapping
4044  {
4045  Mapping(const QCString &n,std::unique_ptr<ExprAst> &&e) : name(n), value(std::move(e)) {}
4048  };
4049  public:
4052  {
4053  TRACE(("{TemplateNodeIndexEntry(%s)\n",qPrint(data)));
4054  ExpressionParser expParser(parser,line);
4055  std::vector<QCString> args = split(data," ");
4056  auto it = args.begin();
4057  if (it==args.end() || (*it).find('=')!=-1)
4058  {
4059  parser->warn(parser->templateName(),line,"Missing name for indexentry tag");
4060  }
4061  else
4062  {
4063  m_name = *it;
4064  ++it;
4065  while (it!=args.end())
4066  {
4067  QCString arg = *it;
4068  int j=arg.find('=');
4069  if (j>0)
4070  {
4071  ExprAstPtr expr = expParser.parse(arg.mid(j+1));
4072  if (expr)
4073  {
4074  m_args.emplace_back(arg.left(j),std::move(expr));
4075  }
4076  }
4077  else
4078  {
4079  parser->warn(parser->templateName(),line,"invalid argument '%s' for indexentry tag",qPrint(arg));
4080  }
4081  ++it;
4082  }
4083  }
4084  TRACE(("}TemplateNodeIndexEntry(%s)\n",qPrint(data)));
4085  }
4087  {
4088  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
4089  if (ci==0) return; // should not happen
4090  if (!m_name.isEmpty())
4091  {
4093  std::vector<TemplateKeyValue> list;
4094  for (const auto &mapping : m_args)
4095  {
4096  list.emplace_back(mapping.name,mapping.value->resolve(c));
4097  }
4098  ci->addIndexEntry(m_name,list);
4099  }
4100  }
4101  private:
4103  std::vector<Mapping> m_args;
4104 };
4105 
4106 //----------------------------------------------------------
4107 
4108 /** @brief Class representing an 'opensubindex' tag in a template */
4109 class TemplateNodeOpenSubIndex : public TemplateNodeCreator<TemplateNodeOpenSubIndex>
4110 {
4111  public:
4114  {
4115  TRACE(("{TemplateNodeOpenSubIndex(%s)\n",qPrint(data)));
4116  m_name = data.stripWhiteSpace();
4117  if (m_name.isEmpty())
4118  {
4119  parser->warn(parser->templateName(),line,"Missing argument for opensubindex tag");
4120  }
4121  else if (m_name.find(' ')!=-1)
4122  {
4123  parser->warn(parser->templateName(),line,"Expected single argument for opensubindex tag got '%s'",qPrint(data));
4124  m_name="";
4125  }
4126  TRACE(("}TemplateNodeOpenSubIndex(%s)\n",qPrint(data)));
4127  }
4129  {
4130  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
4131  if (ci==0) return; // should not happen
4132  if (!m_name.isEmpty())
4133  {
4135  ci->openSubIndex(m_name);
4136  }
4137  }
4138  private:
4140 };
4141 
4142 //----------------------------------------------------------
4143 
4144 /** @brief Class representing an 'closesubindex' tag in a template */
4145 class TemplateNodeCloseSubIndex : public TemplateNodeCreator<TemplateNodeCloseSubIndex>
4146 {
4147  public:
4150  {
4151  TRACE(("{TemplateNodeCloseSubIndex(%s)\n",qPrint(data)));
4152  m_name = data.stripWhiteSpace();
4153  if (m_name.isEmpty())
4154  {
4155  parser->warn(parser->templateName(),line,"Missing argument for closesubindex tag");
4156  }
4157  else if (m_name.find(' ')!=-1 || m_name.isEmpty())
4158  {
4159  parser->warn(parser->templateName(),line,"Expected single argument for closesubindex tag got '%s'",qPrint(data));
4160  m_name="";
4161  }
4162  TRACE(("}TemplateNodeCloseSubIndex(%s)\n",qPrint(data)));
4163  }
4165  {
4166  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
4167  if (ci==0) return; // should not happen
4168  if (!m_name.isEmpty())
4169  {
4171  ci->closeSubIndex(m_name);
4172  }
4173  }
4174  private:
4176 };
4177 
4178 
4179 //----------------------------------------------------------
4180 
4181 /** @brief Class representing an 'with' tag in a template */
4182 class TemplateNodeWith : public TemplateNodeCreator<TemplateNodeWith>
4183 {
4184  struct Mapping
4185  {
4186  Mapping(const QCString &n,ExprAstPtr &&e) : name(n), value(std::move(e)) {}
4189  };
4190  public:
4193  {
4194  TRACE(("{TemplateNodeWith(%s)\n",qPrint(data)));
4195  ExpressionParser expParser(parser,line);
4196  QCString filteredData = data;
4197  removeSpacesAroundEquals(filteredData);
4198  std::vector<QCString> args = split(filteredData," ");
4199  auto it = args.begin();
4200  while (it!=args.end())
4201  {
4202  QCString arg = *it;
4203  int j=arg.find('=');
4204  if (j>0)
4205  {
4206  ExprAstPtr expr = expParser.parse(arg.mid(j+1));
4207  if (expr)
4208  {
4209  m_args.emplace_back(arg.left(j),std::move(expr));
4210  }
4211  }
4212  else
4213  {
4214  parser->warn(parser->templateName(),line,"invalid argument '%s' for 'with' tag",qPrint(arg));
4215  }
4216  ++it;
4217  }
4218  StringVector stopAt = { "endwith" };
4219  parser->parse(this,line,stopAt,m_nodes);
4220  parser->removeNextToken(); // skip over endwith
4221  TRACE(("}TemplateNodeWith(%s)\n",qPrint(data)));
4222  }
4224  {
4225  }
4227  {
4228  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
4229  if (ci==0) return; // should not happen
4231  c->push();
4232  for (const auto &mapping : m_args)
4233  {
4234  TemplateVariant value = mapping.value->resolve(c);
4235  ci->set(mapping.name,value);
4236  }
4237  m_nodes.render(ts,c);
4238  c->pop();
4239  }
4240  private:
4242  std::vector<Mapping> m_args;
4243 };
4244 
4245 //----------------------------------------------------------
4246 
4247 /** @brief Class representing an 'cycle' tag in a template */
4248 class TemplateNodeCycle : public TemplateNodeCreator<TemplateNodeCycle>
4249 {
4250  public:
4253  {
4254  TRACE(("{TemplateNodeCycle(%s)\n",qPrint(data)));
4255  m_index=0;
4256  ExpressionParser expParser(parser,line);
4257  std::vector<QCString> args = split(data," ");
4258  auto it = args.begin();
4259  while (it!=args.end())
4260  {
4261  ExprAstPtr expr = expParser.parse(*it);
4262  if (expr)
4263  {
4264  m_args.emplace_back(std::move(expr));
4265  }
4266  ++it;
4267  }
4268  if (m_args.size()<2)
4269  {
4270  parser->warn(parser->templateName(),line,"expected at least two arguments for cycle command, got %zu",m_args.size());
4271  }
4272  TRACE(("}TemplateNodeCycle(%s)\n",qPrint(data)));
4273  }
4275  {
4276  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
4277  if (ci==0) return; // should not happen
4279  if (m_index<m_args.size())
4280  {
4281  TemplateVariant v = m_args[m_index]->resolve(c);
4282  if (v.isFunction())
4283  {
4284  v = v.call();
4285  }
4286  if (ci->escapeIntf() && !v.raw())
4287  {
4288  if (ci->needsRecoding())
4289  {
4290  ts << ci->recode(ci->escapeIntf()->escape(v.toString()));
4291  }
4292  else
4293  {
4294  ts << ci->escapeIntf()->escape(v.toString());
4295  }
4296  }
4297  else
4298  {
4299  if (ci->needsRecoding())
4300  {
4301  ts << ci->recode(v.toString());
4302  }
4303  else
4304  {
4305  ts << v.toString();
4306  }
4307  }
4308  }
4309  if (++m_index==m_args.size()) // wrap around
4310  {
4311  m_index=0;
4312  }
4313  }
4314  private:
4315  size_t m_index = 0;
4317 };
4318 
4319 //----------------------------------------------------------
4320 
4321 /** @brief Class representing an 'set' tag in a template */
4322 class TemplateNodeSet : public TemplateNodeCreator<TemplateNodeSet>
4323 {
4324  struct Mapping
4325  {
4326  Mapping(const QCString &n,ExprAstPtr &&e) : name(n), value(std::move(e)) {}
4329  };
4330  public:
4333  {
4334  TRACE(("{TemplateNodeSet(%s)\n",qPrint(data)));
4335  ExpressionParser expParser(parser,line);
4336  // data format: name=expression
4337  int j=data.find('=');
4338  ExprAstPtr expr = 0;
4339  if (j>0 && (expr = expParser.parse(data.mid(j+1))))
4340  {
4341  m_mapping = std::make_unique<Mapping>(data.left(j),std::move(expr));
4342  }
4343  TRACE(("}TemplateNodeSet(%s)\n",qPrint(data)));
4344  }
4346  {
4347  }
4349  {
4350  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
4351  if (ci==0) return; // should not happen
4353  if (m_mapping)
4354  {
4355  TemplateVariant value = m_mapping->value->resolve(c);
4356  ci->set(m_mapping->name,value);
4357  }
4358  }
4359  private:
4360  std::unique_ptr<Mapping> m_mapping;
4361 };
4362 
4363 //----------------------------------------------------------
4364 
4365 /** @brief Class representing an 'spaceless' tag in a template */
4366 class TemplateNodeSpaceless : public TemplateNodeCreator<TemplateNodeSpaceless>
4367 {
4368  public:
4371  {
4372  TRACE(("{TemplateNodeSpaceless()\n"));
4373  StringVector stopAt = { "endspaceless" };
4374  parser->parse(this,line,stopAt,m_nodes);
4375  parser->removeNextToken(); // skip over endwith
4376  TRACE(("}TemplateNodeSpaceless()\n"));
4377  }
4379  {
4380  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
4381  if (ci==0) return; // should not happen
4383  bool wasSpaceless = ci->spacelessEnabled();
4384  ci->enableSpaceless(TRUE);
4385  m_nodes.render(ts,c);
4386  ci->enableSpaceless(wasSpaceless);
4387  }
4388  private:
4390 };
4391 
4392 //----------------------------------------------------------
4393 
4394 /** @brief Class representing an 'markers' tag in a template */
4395 class TemplateNodeMarkers : public TemplateNodeCreator<TemplateNodeMarkers>
4396 {
4397  public:
4400  {
4401  TRACE(("{TemplateNodeMarkers(%s)\n",qPrint(data)));
4402  int i = data.find(" in ");
4403  int w = data.find(" with ");
4404  if (i==-1 || w==-1 || w<i)
4405  {
4406  parser->warn(m_templateName,line,"markers tag as wrong format. Expected: markers <var> in <list> with <string_with_markers>");
4407  }
4408  else
4409  {
4410  ExpressionParser expParser(parser,line);
4411  m_var = data.left(i);
4412  m_listExpr = expParser.parse(data.mid(i+4,w-i-4));
4413  m_patternExpr = expParser.parse(data.right(data.length()-w-6));
4414  }
4415  StringVector stopAt = { "endmarkers" };
4416  parser->parse(this,line,stopAt,m_nodes);
4417  parser->removeNextToken(); // skip over endmarkers
4418  TRACE(("}TemplateNodeMarkers(%s)\n",qPrint(data)));
4419  }
4421  {
4422  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
4423  if (ci==0) return; // should not happen
4425  if (!m_var.isEmpty() && m_listExpr && m_patternExpr)
4426  {
4427  TemplateVariant v = m_listExpr->resolve(c);
4428  const TemplateListIntfPtr list = v.toList();
4429  TemplateVariant patternStr = m_patternExpr->resolve(c);
4430  if (list)
4431  {
4432  if (patternStr.isString())
4433  {
4434  TemplateListIntf::ConstIteratorPtr it = list->createIterator();
4435  c->push();
4436  std::string str = patternStr.toString().str();
4437 
4438  static const reg::Ex marker(R"(@\d+)");
4439  reg::Iterator re_it(str,marker);
4441  size_t index=0;
4442  for ( ; re_it!=end ; ++re_it)
4443  {
4444  const auto &match = *re_it;
4445  size_t newIndex = match.position();
4446  size_t matchLen = match.length();
4447  std::string part = str.substr(index,newIndex-index);
4448  if (ci->needsRecoding())
4449  {
4450  ts << ci->recode(QCString(part)); // write text before marker
4451  }
4452  else
4453  {
4454  ts << part; // write text before marker
4455  }
4456  unsigned long entryIndex = std::stoul(match.str().substr(1));
4457  TemplateVariant var;
4458  size_t i=0;
4459  // search for list element at position id
4460  for (it->toFirst(); (it->current(var)) && i<entryIndex; it->toNext(),i++) {}
4461  if (i==entryIndex) // found element
4462  {
4464  s->set("id",(int)i);
4465  c->set("markers",std::static_pointer_cast<TemplateStructIntf>(s));
4466  c->set(m_var,var); // define local variable to hold element of list type
4467  bool wasSpaceless = ci->spacelessEnabled();
4468  ci->enableSpaceless(TRUE);
4469  m_nodes.render(ts,c);
4470  ci->enableSpaceless(wasSpaceless);
4471  }
4472  else if (i<entryIndex)
4473  {
4474  ci->warn(m_templateName,m_line,"markers list does not an element for marker position %d",i);
4475  }
4476  index=newIndex+matchLen; // set index just after marker
4477  }
4478  if (ci->needsRecoding())
4479  {
4480  ts << ci->recode(str.substr(index)); // write text after last marker
4481  }
4482  else
4483  {
4484  ts << str.substr(index); // write text after last marker
4485  }
4486  c->pop();
4487  }
4488  else
4489  {
4490  ci->warn(m_templateName,m_line,"markers requires a parameter of string type after 'with'!");
4491  }
4492  }
4493  else
4494  {
4495  ci->warn(m_templateName,m_line,"markers requires a parameter of list type after 'in'!");
4496  }
4497  }
4498  }
4499  private:
4504 };
4505 
4506 //----------------------------------------------------------
4507 
4508 /** @brief Class representing an 'tabbing' tag in a template */
4509 class TemplateNodeTabbing : public TemplateNodeCreator<TemplateNodeTabbing>
4510 {
4511  public:
4514  {
4515  TRACE(("{TemplateNodeTabbing()\n"));
4516  StringVector stopAt = { "endtabbing" };
4517  parser->parse(this,line,stopAt,m_nodes);
4518  parser->removeNextToken(); // skip over endtabbing
4519  TRACE(("}TemplateNodeTabbing()\n"));
4520  }
4522  {
4523  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
4524  if (ci==0) return; // should not happen
4526  bool wasTabbing = ci->tabbingEnabled();
4527  ci->enableTabbing(TRUE);
4528  m_nodes.render(ts,c);
4529  ci->enableTabbing(wasTabbing);
4530  }
4531  private:
4533 };
4534 
4535 //----------------------------------------------------------
4536 
4537 /** @brief Class representing an 'markers' tag in a template */
4538 class TemplateNodeResource : public TemplateNodeCreator<TemplateNodeResource>
4539 {
4540  public:
4543  {
4544  TRACE(("{TemplateNodeResource(%s)\n",qPrint(data)));
4545  ExpressionParser ep(parser,line);
4546  int i;
4547  if (data.isEmpty())
4548  {
4549  parser->warn(m_templateName,line,"resource tag is missing resource file argument");
4550  m_resExpr.reset();
4551  m_asExpr.reset();
4552  }
4553  else if ((i=data.find(" as "))!=-1) // resource a as b
4554  {
4555  m_resExpr = ep.parse(data.left(i)); // part before as
4556  m_asExpr = ep.parse(data.mid(i+4)); // part after as
4557  }
4558  else if ((i=data.find(" append "))!=-1) // resource a appends to b
4559  {
4560  m_resExpr = ep.parse(data.left(i)); // part before append
4561  m_asExpr = ep.parse(data.mid(i+8)); // part after append
4562  m_append = true;
4563  }
4564  else // resource a
4565  {
4566  m_resExpr = ep.parse(data);
4567  m_asExpr.reset();
4568  }
4569  TRACE(("}TemplateNodeResource(%s)\n",qPrint(data)));
4570  }
4572  {
4573  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
4574  if (ci==0) return; // should not happen
4576  if (m_resExpr)
4577  {
4578  QCString resourceFile = m_resExpr->resolve(c).toString();
4579  if (resourceFile.isEmpty())
4580  {
4581  ci->warn(m_templateName,m_line,"invalid parameter for resource command\n");
4582  }
4583  else
4584  {
4585  QCString outputDirectory = ci->outputDirectory();
4586  if (m_asExpr)
4587  {
4588  QCString targetFile = m_asExpr->resolve(c).toString();
4589  mkpath(ci,targetFile.str());
4590  if (targetFile.isEmpty())
4591  {
4592  ci->warn(m_templateName,m_line,"invalid parameter at right side of '%s' for resource command\n", m_append ? "append" : "as");
4593  }
4594  else
4595  {
4596  ResourceMgr::instance().copyResourceAs(resourceFile,outputDirectory,targetFile,m_append);
4597  }
4598  }
4599  else
4600  {
4601  ResourceMgr::instance().copyResource(resourceFile,outputDirectory);
4602  }
4603  }
4604  }
4605  }
4606  private:
4609  bool m_append = false;
4610 };
4611 
4612 //----------------------------------------------------------
4613 
4614 /** @brief Class representing the 'encoding' tag in a template */
4615 class TemplateNodeEncoding : public TemplateNodeCreator<TemplateNodeEncoding>
4616 {
4617  public:
4620  {
4621  TRACE(("{TemplateNodeEncoding(%s)\n",qPrint(data)));
4622  ExpressionParser ep(parser,line);
4623  if (data.isEmpty())
4624  {
4625  parser->warn(m_templateName,line,"encoding tag is missing encoding argument");
4626  m_encExpr.reset();
4627  }
4628  else
4629  {
4630  m_encExpr = ep.parse(data);
4631  }
4632  StringVector stopAt = { "endencoding" };
4633  parser->parse(this,line,stopAt,m_nodes);
4634  parser->removeNextToken(); // skip over endencoding
4635  TRACE(("}TemplateNodeEncoding(%s)\n",qPrint(data)));
4636  }
4638  {
4639  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
4640  if (ci==0) return; // should not happen
4642  QCString encStr;
4643  if (m_encExpr)
4644  {
4645  encStr = m_encExpr->resolve(c).toString();
4646  }
4647  QCString oldEncStr = ci->encoding();
4648  if (!encStr.isEmpty())
4649  {
4650  ci->setEncoding(m_templateName,m_line,encStr);
4651  }
4652  m_nodes.render(ts,c);
4653  ci->setEncoding(m_templateName,m_line,oldEncStr);
4654  }
4655  private:
4658 };
4659 
4660 //----------------------------------------------------------
4661 
4662 /** @brief Factory class for creating tag AST nodes found in a template */
4664 {
4665  public:
4667  TemplateNode *parent,
4668  int line,
4669  const QCString &data);
4670 
4672  {
4673  static std::unique_ptr<TemplateNodeFactory> instance;
4674  if (instance==0) instance = std::make_unique<TemplateNodeFactory>();
4675  return *instance;
4676  }
4677 
4679  TemplateParser *parser,
4680  TemplateNode *parent,
4681  int line,
4682  const QCString &data)
4683  {
4684  auto it = m_registry.find(name.str());
4685  if (it==m_registry.end()) return 0;
4686  return it->second(parser,parent,line,data);
4687  }
4688 
4690  {
4691  m_registry.insert(std::make_pair(name.str(),func));
4692  }
4693 
4694  /** @brief Helper class for registering a template AST node */
4695  template<class T> class AutoRegister
4696  {
4697  public:
4699  {
4700  TemplateNodeFactory::instance().registerTemplateNode(key,T::createInstance);
4701  }
4702  };
4703 
4704  private:
4705  std::unordered_map<std::string,CreateFunc> m_registry;
4706 };
4707 
4708 // register a handler for each start tag we support
4730 
4731 //----------------------------------------------------------
4732 
4734 {
4735 }
4736 
4738 {
4739  auto it = m_blocks.find(name.str());
4740  if (it==m_blocks.end() || it->second.empty())
4741  {
4742  return 0;
4743  }
4744  else
4745  {
4746  return it->second.back();
4747  }
4748 }
4749 
4751 {
4752  auto it = m_blocks.find(name.str());
4753  if (it==m_blocks.end() || it->second.empty())
4754  {
4755  return 0;
4756  }
4757  else
4758  {
4759  TemplateNodeBlock *bld = it->second.back();
4760  it->second.pop_back();
4761  return bld;
4762  }
4763 }
4764 
4766 {
4767  auto it = m_blocks.find(block->name().str());
4768  if (it==m_blocks.end())
4769  {
4770  it = m_blocks.insert(std::make_pair(block->name().str(),NodeBlockList())).first;
4771  }
4772  it->second.push_front(block);
4773 }
4774 
4776 {
4777  for (auto &kv : ctx->m_blocks)
4778  {
4779  for (auto &nb : kv.second)
4780  {
4781  add(nb);
4782  }
4783  }
4784 }
4785 
4787 {
4788  m_blocks.clear();
4789 }
4790 
4792 {
4793  auto it = m_blocks.find(block->name().str());
4794  if (it==m_blocks.end())
4795  {
4796  it = m_blocks.insert(std::make_pair(block->name().str(),NodeBlockList())).first;
4797  }
4798  it->second.push_back(block);
4799 }
4800 
4801 
4802 //----------------------------------------------------------
4803 
4804 /** @brief Lexer class for turning a template into a list of tokens */
4806 {
4807  public:
4808  TemplateLexer(const TemplateEngine *engine,const QCString &fileName,const QCString &data);
4809  void tokenize(TemplateTokenStream &tokens);
4810  void setOpenCloseCharacters(char openChar,char closeChar)
4811  { m_openChar=openChar; m_closeChar=closeChar; }
4812  private:
4813  void addToken(TemplateTokenStream &tokens,
4814  const QCString &data,int line,int startPos,int endPos,
4815  TemplateToken::Type type);
4816  void reset();
4820  char m_openChar = 0;
4821  char m_closeChar = 0;
4822 };
4823 
4824 TemplateLexer::TemplateLexer(const TemplateEngine *engine,const QCString &fileName,const QCString &data) :
4825  m_engine(engine), m_fileName(fileName), m_data(data)
4826 {
4827  m_openChar='{';
4828  m_closeChar='}';
4829 }
4830 
4832 {
4833  enum LexerStates
4834  {
4835  StateText,
4836  StateBeginTemplate,
4837  StateTag,
4838  StateEndTag,
4839  StateComment,
4840  StateEndComment,
4841  StateMaybeVar,
4842  StateVariable,
4843  StateEndVariable
4844  };
4845 
4846  if (m_data.isEmpty()) return;
4847  const char *p=m_data.data();
4848  int state=StateText;
4849  int pos=0;
4850  int lastTokenPos=0;
4851  int startLinePos=0;
4852  bool emptyOutputLine=TRUE;
4853  int line=1;
4854  char c;
4855  int markStartPos=-1;
4856  for (;(c=*p);p++,pos++)
4857  {
4858  switch (state)
4859  {
4860  case StateText:
4861  if (c==m_openChar) // {{ or {% or {# or something else
4862  {
4863  state=StateBeginTemplate;
4864  }
4865  else if (c!=' ' && c!='\t' && c!='\n') // non-whitespace text
4866  {
4867  emptyOutputLine=FALSE;
4868  }
4869  break;
4870  case StateBeginTemplate:
4871  switch (c)
4872  {
4873  case '%': // {%
4874  state=StateTag;
4875  markStartPos=pos-1;
4876  break;
4877  case '#': // {#
4878  state=StateComment;
4879  markStartPos=pos-1;
4880  break;
4881  case '{': // {{
4882  if (m_openChar=='{')
4883  {
4884  state=StateMaybeVar;
4885  }
4886  else
4887  {
4888  state=StateVariable;
4889  }
4890  markStartPos=pos-1;
4891  break;
4892  default:
4893  state=StateText;
4894  emptyOutputLine=FALSE;
4895  break;
4896  }
4897  break;
4898  case StateTag:
4899  if (c=='\n')
4900  {
4901  warn(m_fileName,line,"unexpected new line inside %c%%...%%%c block",m_openChar,m_closeChar);
4903  }
4904  else if (c=='%') // %} or something else
4905  {
4906  state=StateEndTag;
4907  }
4908  break;
4909  case StateEndTag:
4910  if (c==m_closeChar) // %}
4911  {
4912  // found tag!
4913  state=StateText;
4914  addToken(tokens,m_data,line,lastTokenPos,
4915  emptyOutputLine ? startLinePos : markStartPos,
4917  addToken(tokens,m_data,line,markStartPos+2,
4918  pos-1,TemplateToken::Block);
4919  lastTokenPos = pos+1;
4920  }
4921  else // something else
4922  {
4923  if (c=='\n')
4924  {
4925  warn(m_fileName,line,"unexpected new line inside %c%%...%%%c block",m_openChar,m_closeChar);
4927  }
4928  state=StateTag;
4929  }
4930  break;
4931  case StateComment:
4932  if (c=='\n')
4933  {
4934  warn(m_fileName,line,"unexpected new line inside %c#...#%c block",m_openChar,m_closeChar);
4936  }
4937  else if (c=='#') // #} or something else
4938  {
4939  state=StateEndComment;
4940  }
4941  break;
4942  case StateEndComment:
4943  if (c==m_closeChar) // #}
4944  {
4945  // found comment tag!
4946  state=StateText;
4947  addToken(tokens,m_data,line,lastTokenPos,
4948  emptyOutputLine ? startLinePos : markStartPos,
4950  lastTokenPos = pos+1;
4951  }
4952  else // something else
4953  {
4954  if (c=='\n')
4955  {
4956  warn(m_fileName,line,"unexpected new line inside %c#...#%c block",m_openChar,m_closeChar);
4958  }
4959  state=StateComment;
4960  }
4961  break;
4962  case StateMaybeVar:
4963  switch (c)
4964  {
4965  case '#': // {{#
4966  state=StateComment;
4967  markStartPos=pos-1;
4968  break;
4969  case '%': // {{%
4970  state=StateTag;
4971  markStartPos=pos-1;
4972  break;
4973  default: // {{
4974  state=StateVariable;
4975  break;
4976  }
4977  break;
4978  case StateVariable:
4979  emptyOutputLine=FALSE; // assume a variable expands to content
4980  if (c=='\n')
4981  {
4982  warn(m_fileName,line,"unexpected new line inside %c{...}%c block",m_openChar,m_closeChar);
4984  }
4985  else if (c=='}') // }} or something else
4986  {
4987  state=StateEndVariable;
4988  }
4989  break;
4990  case StateEndVariable:
4991  if (c==m_closeChar) // }}
4992  {
4993  // found variable tag!
4994  state=StateText;
4995  addToken(tokens,m_data,line,lastTokenPos,
4996  emptyOutputLine ? startLinePos : markStartPos,
4998  addToken(tokens,m_data,line,markStartPos+2,
4999  pos-1,TemplateToken::Variable);
5000  lastTokenPos = pos+1;
5001  }
5002  else // something else
5003  {
5004  if (c=='\n')
5005  {
5006  warn(m_fileName,line,"unexpected new line inside %c{...}%c block",m_openChar,m_closeChar);
5008  }
5009  state=StateVariable;
5010  }
5011  break;
5012  }
5013  if (c=='\n') // new line
5014  {
5015  state=StateText;
5016  startLinePos=pos+1;
5017  // if the current line only contain commands and whitespace,
5018  // then skip it in the output by moving lastTokenPos
5019  if (markStartPos!=-1 && emptyOutputLine) lastTokenPos = startLinePos;
5020  // reset markers
5021  markStartPos=-1;
5022  line++;
5023  emptyOutputLine=TRUE;
5024  }
5025  }
5026  if (lastTokenPos<pos)
5027  {
5028  addToken(tokens,m_data,line,
5029  lastTokenPos,pos,
5031  }
5032 }
5033 
5035  const QCString &data,int line,
5036  int startPos,int endPos,
5037  TemplateToken::Type type)
5038 {
5039  if (startPos<endPos)
5040  {
5041  int len = endPos-startPos;
5042  QCString text = data.mid(startPos,len);
5043  if (type!=TemplateToken::Text) text = text.stripWhiteSpace();
5044  tokens.push_back(std::make_unique<TemplateToken>(type,text,line));
5045  }
5046 }
5047 
5048 //----------------------------------------------------------
5049 
5051  const QCString &templateName,
5052  TemplateTokenStream &tokens) :
5053  m_engine(engine), m_templateName(templateName), m_tokens(tokens)
5054 {
5055 }
5056 
5058  TemplateNode *parent,int line,const StringVector &stopAt,
5059  TemplateNodeList &nodes)
5060 {
5061  TRACE(("{TemplateParser::parse\n"));
5062  // process the tokens. Build node list
5063  while (hasNextToken())
5064  {
5065  auto tok = takeNextToken();
5066  TRACE(("%p:Token type=%d data='%s' line=%d\n",
5067  (void*)parent,tok->type,qPrint(tok->data),tok->line));
5068  switch(tok->type)
5069  {
5070  case TemplateToken::Text:
5071  nodes.push_back(std::make_unique<TemplateNodeText>(this,parent,tok->line,tok->data));
5072  break;
5073  case TemplateToken::Variable: // {{ var }}
5074  nodes.push_back(std::make_unique<TemplateNodeVariable>(this,parent,tok->line,tok->data));
5075  break;
5076  case TemplateToken::Block: // {% tag %}
5077  {
5078  QCString command = tok->data;
5079  int sep = command.find(' ');
5080  if (sep!=-1)
5081  {
5082  command=command.left(sep);
5083  }
5084  TemplateToken *tok_ptr = tok.get();
5085  if (std::find(stopAt.begin(),stopAt.end(),command.str())!=stopAt.end())
5086  {
5087  prependToken(std::move(tok));
5088  TRACE(("}TemplateParser::parse: stop\n"));
5089  return;
5090  }
5091  QCString arg;
5092  if (sep!=-1)
5093  {
5094  arg = tok_ptr->data.mid(sep+1);
5095  }
5097  command,this,parent,tok_ptr->line,arg);
5098  if (node)
5099  {
5100  nodes.push_back(std::move(node));
5101  }
5102  else if (command=="empty" || command=="else" ||
5103  command=="endif" || command=="endfor" ||
5104  command=="endblock" || command=="endwith" ||
5105  command=="endrecursetree" || command=="endspaceless" ||
5106  command=="endmarkers" || command=="endmsg" ||
5107  command=="endrepeat" || command=="elif" ||
5108  command=="endrange" || command=="endtabbing" ||
5109  command=="endencoding")
5110  {
5111  warn(m_templateName,tok_ptr->line,"Found tag '%s' without matching start tag",qPrint(command));
5112  }
5113  else
5114  {
5115  warn(m_templateName,tok_ptr->line,"Unknown tag '%s'",qPrint(command));
5116  }
5117  }
5118  break;
5119  }
5120  }
5121  if (!stopAt.empty())
5122  {
5123  QCString options;
5124  for (const auto &s : stopAt)
5125  {
5126  if (!options.isEmpty()) options+=", ";
5127  options+=s.c_str();
5128  }
5129  warn(m_templateName,line,"Unclosed tag in template, expected one of: %s",
5130  qPrint(options));
5131  }
5132  TRACE(("}TemplateParser::parse: last token\n"));
5133 }
5134 
5136 {
5137  return !m_tokens.empty();
5138 }
5139 
5141 {
5142  if (m_tokens.empty()) return TemplateTokenPtr();
5143  auto tok = std::move(m_tokens.front());
5144  m_tokens.pop_front();
5145  return tok;
5146 }
5147 
5149 {
5150  return m_tokens.front().get();
5151 }
5152 
5154 {
5155  m_tokens.pop_front();
5156 }
5157 
5159 {
5160  m_tokens.push_front(std::move(token));
5161 }
5162 
5163 void TemplateParser::warn(const QCString &fileName,int line,const char *fmt,...) const
5164 {
5165  va_list args;
5166  va_start(args,fmt);
5167  va_warn(fileName,line,fmt,args);
5168  va_end(args);
5169  m_engine->printIncludeContext(fileName,line);
5170 }
5171 
5172 
5173 
5174 //----------------------------------------------------------
5175 
5176 
5178  const QCString &extension)
5179  : TemplateNode(0)
5180 {
5181  //printf("%p:TemplateImpl::TemplateImpl(%s)\n",(void*)this,qPrint(name));
5182  m_name = name;
5183  m_engine = engine;
5184  TemplateLexer lexer(engine,name,data);
5185  if (extension=="tex")
5186  {
5187  lexer.setOpenCloseCharacters('<','>');
5188  }
5189  TemplateTokenStream tokens;
5190  lexer.tokenize(tokens);
5191  TemplateParser parser(engine,name,tokens);
5192  parser.parse(this,1,StringVector(),m_nodes);
5193 }
5194 
5196 {
5197  //printf("%p:TemplateImpl::~TemplateImpl(%s)\n",(void*)this,qPrint(m_name));
5198 }
5199 
5201 {
5202  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
5203  if (ci==0) return; // should not happen
5204  if (!m_nodes.empty())
5205  {
5206  TemplateNodeExtend *ne = dynamic_cast<TemplateNodeExtend*>(m_nodes.front().get());
5207  if (ne==0) // normal template, add blocks to block context
5208  {
5209  TemplateBlockContext *bc = ci->blockContext();
5210  for (const auto &n : m_nodes)
5211  {
5212  TemplateNodeBlock *nb = dynamic_cast<TemplateNodeBlock*>(n.get());
5213  if (nb)
5214  {
5215  bc->add(nb);
5216  }
5217  }
5218  }
5219  m_nodes.render(ts,c);
5220  }
5221 }
5222 
5223 //----------------------------------------------------------
5224 
5225 /** @brief Private data of the template engine */
5227 {
5229  {
5230  public:
5231  enum Type { Template, Block };
5234  Type type() const { return m_type; }
5235  QCString fileName() const { return m_fileName; }
5236  QCString blockName() const { return m_blockName; }
5237  int line() const { return m_line; }
5238 
5239  private:
5243  int m_line = 0;
5244  };
5245  public:
5246  Private(TemplateEngine *engine) : m_engine(engine)
5247  {
5248  //printf("%p:TemplateEngine::Private::Private()\n",(void*)this);
5249  }
5251  {
5252  //printf("%p:TemplateEngine::Private::~Private()\n",(void*)this);
5253  }
5254  Template *loadByName(const QCString &fileName,int line)
5255  {
5256  //for (int i=0;i<m_indent;i++) printf(" ");
5257  //m_indent++;
5258  //printf("loadByName(%s,%d) {\n",qPrint(fileName),line);
5259  m_includeStack.emplace_back(IncludeEntry::Template,fileName,QCString(),line);
5260  auto kv = m_templateCache.find(fileName.str());
5261  if (kv==m_templateCache.end()) // first time template is referenced
5262  {
5263  QCString filePath = m_templateDirName+"/"+fileName;
5264  std::ifstream f(filePath.str(),std::ifstream::in | std::ifstream::binary);
5265  if (f.is_open()) // read template from disk
5266  {
5267  FileInfo fi(filePath.str());
5268  int size=(int)fi.size();
5269  QCString data(size+1);
5270  f.read(data.rawData(),size);
5271  if (!f.fail())
5272  {
5273  kv = m_templateCache.insert(
5274  std::make_pair(fileName.str(),
5275  std::make_unique<TemplateImpl>(m_engine,filePath,data,m_extension))).first;
5276  }
5277  }
5278  else // fallback to default built-in template
5279  {
5280  const QCString data = ResourceMgr::instance().getAsString(fileName);
5281  if (!data.isEmpty())
5282  {
5283  kv = m_templateCache.insert(
5284  std::make_pair(fileName.str(),
5285  std::make_unique<TemplateImpl>(m_engine,fileName,data,m_extension))).first;
5286  }
5287  else
5288  {
5289  err("Could not open template file %s\n",qPrint(fileName));
5290  }
5291  }
5292  }
5293  return kv!=m_templateCache.end() ? kv->second.get() : 0;
5294  }
5295 
5296  void unload(Template * /*t*/)
5297  {
5298  //(void)t;
5299  //m_indent--;
5300  //for (int i=0;i<m_indent;i++) printf(" ");
5301  //printf("}\n");
5302  m_includeStack.pop_back();
5303  }
5304 
5305  void enterBlock(const QCString &fileName,const QCString &blockName,int line)
5306  {
5307  //for (int i=0;i<m_indent;i++) printf(" ");
5308  //m_indent++;
5309  //printf("enterBlock(%s,%s,%d) {\n",qPrint(fileName),qPrint(blockName),line);
5310  m_includeStack.emplace_back(IncludeEntry::Block,fileName,blockName,line);
5311  }
5312 
5313  void leaveBlock()
5314  {
5315  //m_indent--;
5316  //for (int i=0;i<m_indent;i++) printf(" ");
5317  //printf("}\n");
5318  m_includeStack.pop_back();
5319  }
5320 
5321  void printIncludeContext(const QCString &fileName,int line) const
5322  {
5323  auto it = m_includeStack.rbegin();
5324  while (it!=m_includeStack.rend())
5325  {
5326  const IncludeEntry &ie = *it;
5327  ++it;
5328  const IncludeEntry *next = it!=m_includeStack.rend() ? &(*it) : 0;
5329  if (ie.type()==IncludeEntry::Template)
5330  {
5331  if (next)
5332  {
5333  warn(fileName,line," inside template '%s' included from template '%s' at line %d",qPrint(ie.fileName()),qPrint(next->fileName()),ie.line());
5334  }
5335  }
5336  else // ie.type()==IncludeEntry::Block
5337  {
5338  warn(fileName,line," included by block '%s' inside template '%s' at line %d",qPrint(ie.blockName()),
5339  qPrint(ie.fileName()),ie.line());
5340  }
5341  }
5342  }
5343 
5344  void setOutputExtension(const QCString &extension)
5345  {
5346  m_extension = extension;
5347  }
5348 
5350  {
5351  return m_extension;
5352  }
5353 
5354  void setTemplateDir(const QCString &dirName)
5355  {
5356  m_templateDirName = dirName;
5357  }
5358 
5359  private:
5360  std::unordered_map< std::string, std::unique_ptr<Template> > m_templateCache;
5361  //mutable int m_indent;
5363  std::vector<IncludeEntry> m_includeStack;
5366 };
5367 
5368 TemplateEngine::TemplateEngine() : p(std::make_unique<Private>(this))
5369 {
5370 }
5371 
5373 {
5374 }
5375 
5376 std::unique_ptr<TemplateContext> TemplateEngine::createContext() const
5377 {
5378  return std::make_unique<TemplateContextImpl>(this);
5379 }
5380 
5382 {
5383  return p->loadByName(fileName,line);
5384 }
5385 
5387 {
5388  p->unload(t);
5389 }
5390 
5391 void TemplateEngine::enterBlock(const QCString &fileName,const QCString &blockName,int line)
5392 {
5393  p->enterBlock(fileName,blockName,line);
5394 }
5395 
5397 {
5398  p->leaveBlock();
5399 }
5400 
5401 void TemplateEngine::printIncludeContext(const QCString &fileName,int line) const
5402 {
5403  p->printIncludeContext(fileName,line);
5404 }
5405 
5407 {
5408  p->setOutputExtension(extension);
5409 }
5410 
5412 {
5413  return p->outputExtension();
5414 }
5415 
5417 {
5418  p->setTemplateDir(dirName);
5419 }
5420 
5421 //-----------------------------------------------------------------------------------------
5422 
5424 {
5425  QCString result="[";
5426  const TemplateListIntfPtr list = toList();
5427  if (list)
5428  {
5429  bool first=true;
5430  TemplateVariant ve;
5431  TemplateListIntf::ConstIteratorPtr it = list->createIterator();
5432  for (it->toFirst();it->current(ve);it->toNext())
5433  {
5434  if (!first) result+=",\n";
5435  result+="'"+ve.toString()+"'";
5436  first=false;
5437  }
5438  }
5439  result+="]";
5440  return result;
5441 }
5442 
5444 {
5445  QCString result="{";
5446  const TemplateStructIntfPtr strukt = toStruct();
5447  if (strukt)
5448  {
5449  bool first=true;
5450  for (const auto &s : strukt->fields())
5451  {
5452  if (!first) result+=",";
5453  result+=s;
5454  if (!isWeakStruct()) // avoid endless recursion
5455  {
5456  result+=":'";
5457  result+=strukt->get(QCString(s)).toString();
5458  result+="'";
5459  }
5460  first=false;
5461  }
5462  }
5463  result+="}";
5464  return result;
5465 }
5466 
TemplateListGenericConstIterator::TemplateListGenericConstIterator
TemplateListGenericConstIterator(const List &l)
Definition: template.cpp:233
TemplateNodeText::render
void render(TextStream &ts, TemplateContext *c)
Definition: template.cpp:2936
ExpressionParser::m_line
int m_line
Definition: template.cpp:2547
TemplateVariant::toStruct
TemplateStructIntfPtr toStruct()
Returns the pointer to struct referenced by this variant or 0 if this variant does not have struct ty...
Definition: template.cpp:441
TemplateNodeOpenSubIndex::render
void render(TextStream &, TemplateContext *c)
Definition: template.cpp:4128
TemplateContextImpl::encoding
QCString encoding() const
Definition: template.cpp:698
StringVector
std::vector< std::string > StringVector
Definition: containers.h:32
TemplateNodeSet::render
void render(TextStream &, TemplateContext *c)
Definition: template.cpp:4348
ResourceMgr::copyResource
bool copyResource(const QCString &name, const QCString &targetDir) const
Copies a registered resource to a given target directory
Definition: resourcemgr.cpp:180
fListSort
static TemplateFilterFactory::AutoRegister< FilterListSort > fListSort("listsort")
TemplateNodeIndexEntry::m_args
std::vector< Mapping > m_args
Definition: template.cpp:4103
FilterAlphaIndex::keyToLabel
static QCString keyToLabel(const char *startLetter)
Definition: template.cpp:1290
TemplateContextImpl::setEncoding
void setEncoding(const QCString &file, int line, const QCString &enc)
Definition: template.cpp:2589
TemplateImmutableStruct::alloc
static TemplateStructIntfPtr alloc(std::initializer_list< StructField > fields)
Creates an instance and returns a shared pointer to it
Definition: template.cpp:497
TemplateContextImpl::warn
void warn(const QCString &fileName, int line, const char *fmt,...) const
Definition: template.cpp:2773
TemplateEngine::Private::IncludeEntry::Block
@ Block
Definition: template.cpp:5231
TemplateNodeTree::TemplateNodeTree
TemplateNodeTree(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:3946
FilterAppend::apply
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &arg)
Definition: template.cpp:928
TemplateNodeMsg
Class representing an 'markers' tag in a template
Definition: template.cpp:3562
TemplateNodeRange::m_loopNodes
TemplateNodeList m_loopNodes
Definition: template.cpp:3403
ResourceMgr::copyResourceAs
bool copyResourceAs(const QCString &name, const QCString &targetDir, const QCString &targetName, bool append=false) const
Copies a registered resource to a given target directory under a given target name
Definition: resourcemgr.cpp:79
TemplateNodeSpaceless::render
void render(TextStream &ts, TemplateContext *c)
Definition: template.cpp:4378
TemplateParser::prependToken
void prependToken(TemplateTokenPtr &&token)
Definition: template.cpp:5158
ExpressionParser::parseIdentifier
ExprAstPtr parseIdentifier()
Definition: template.cpp:2264
FilterDefault
The implementation of the "default" filter
Definition: template.cpp:992
portable_iconv
size_t portable_iconv(void *cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
template.h
TemplateVariant::Type::String
@ String
TemplateNodeMsg::TemplateNodeMsg
TemplateNodeMsg(TemplateParser *parser, TemplateNode *parent, int line, const QCString &)
Definition: template.cpp:3565
ExprAstFunctionVariable::ExprAstFunctionVariable
ExprAstFunctionVariable(ExprAstPtr &&var, ExprAstList &&args)
Definition: template.cpp:1709
FilterListSort::apply
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &args)
Definition: template.cpp:1074
TemplateVariantList
std::vector< TemplateVariant > TemplateVariantList
Definition: template.h:261
TemplateListGenericConstIterator::current
virtual bool current(TemplateVariant &v) const
Definition: template.cpp:252
autoRefTree
static TemplateNodeFactory::AutoRegister< TemplateNodeTree > autoRefTree("recursetree")
TemplateImmutableList::createIterator
virtual TemplateListIntf::ConstIteratorPtr createIterator() const
Creates a new iterator for this list.
Definition: template.cpp:533
FilterIsRelativeURL::apply
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &)
Definition: template.cpp:1461
TemplateContextImpl::indices
const TemplateStructPtr indices() const
Definition: template.cpp:707
ResourceMgr::instance
static ResourceMgr & instance()
Returns the one and only instance of this class
Definition: resourcemgr.cpp:32
TemplateFilterFactory::apply
TemplateVariant apply(const QCString &name, const TemplateVariant &v, const TemplateVariant &arg, bool &ok)
Definition: template.cpp:1595
autoRefIndexEntry
static TemplateNodeFactory::AutoRegister< TemplateNodeIndexEntry > autoRefIndexEntry("indexentry")
autoRefIf
static TemplateNodeFactory::AutoRegister< TemplateNodeIf > autoRefIf("if")
TemplateNodeRange::render
void render(TextStream &ts, TemplateContext *c)
Definition: template.cpp:3316
fUpper
static TemplateFilterFactory::AutoRegister< FilterUpper > fUpper("upper")
FilterUpper
The implementation of the "upper" filter
Definition: template.cpp:1508
fileinfo.h
FilterPaginate
The implementation of the "paginate" filter
Definition: template.cpp:1239
ExprAstVariable
Class representing a variable in the AST
Definition: template.cpp:1686
ExprAstFilterPtr
std::unique_ptr< ExprAstFilter > ExprAstFilterPtr
Definition: template.cpp:1760
TemplateVariant::isList
constexpr bool isList() const
Returns TRUE if the variant holds a list value
Definition: template.h:213
FilterHex
The implementation of the "upper" filter
Definition: template.cpp:1524
TemplateEngine::Private::IncludeEntry::m_line
int m_line
Definition: template.cpp:5243
TemplateStruct::set
virtual void set(const QCString &name, const TemplateVariant &v)
Sets the value the field of a struct
Definition: template.cpp:179
TemplateImmutableList::p
std::unique_ptr< Private > p
Definition: template.h:330
TemplateTokenStream
std::deque< TemplateTokenPtr > TemplateTokenStream
Definition: template.cpp:1963
TemplateNodeOpenSubIndex
Class representing an 'opensubindex' tag in a template
Definition: template.cpp:4109
FilterIsAbsoluteURL::apply
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &)
Definition: template.cpp:1478
TemplateNodeCycle
Class representing an 'cycle' tag in a template
Definition: template.cpp:4248
TemplateContextImpl::setActiveEscapeIntf
void setActiveEscapeIntf(TemplateEscapeIntf *intf)
Definition: template.cpp:674
reg::replace
std::string replace(const std::string &str, const Ex &re, const std::string &replacement)
Searching in a given input string for parts that match regular expression re and replaces those parts...
Definition: regex.cpp:740
TemplateFilterFactory::AutoRegister
Helper class for registering a filter function
Definition: template.cpp:1616
Operator::Modulo
@ Modulo
Definition: template.cpp:574
QCString::rawData
char * rawData()
Returns a writable pointer to the data.
Definition: qcstring.h:157
TemplateNodeCreator::createInstance
static TemplateNodePtr createInstance(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:3044
ExprAstFilterAppl
Class representing a filter applied to an expression in the AST
Definition: template.cpp:1763
FilterNoWrap
The implementation of the "default" filter
Definition: template.cpp:1410
ExprAstUnary::m_operator
Operator::Type m_operator
Definition: template.cpp:1819
TemplateImmutableStruct::p
std::unique_ptr< Private > p
Definition: template.h:376
fGet
static TemplateFilterFactory::AutoRegister< FilterGet > fGet("get")
autoRefExtend
static TemplateNodeFactory::AutoRegister< TemplateNodeExtend > autoRefExtend("extend")
TemplateParser::m_templateName
QCString m_templateName
Definition: template.cpp:2002
TemplateKeyValue::TemplateKeyValue
TemplateKeyValue()
Definition: template.cpp:632
TemplateNodeFor::m_loopNodes
TemplateNodeList m_loopNodes
Definition: template.cpp:3555
ExprAstVariable::ExprAstVariable
ExprAstVariable(const QCString &name)
Definition: template.cpp:1689
TemplateNodeResource::m_resExpr
ExprAstPtr m_resExpr
Definition: template.cpp:4607
ExprAstVariable::m_name
QCString m_name
Definition: template.cpp:1703
stripLeadingWhiteSpace
static void stripLeadingWhiteSpace(QCString &s)
Definition: template.cpp:3807
TemplateToken::line
int line
Definition: template.cpp:1959
TemplateEngine::Private::IncludeEntry::m_fileName
QCString m_fileName
Definition: template.cpp:5241
TemplateEngine::Private::printIncludeContext
void printIncludeContext(const QCString &fileName, int line) const
Definition: template.cpp:5321
TemplateNodeCreator::mkpath
void mkpath(const TemplateContextImpl *ci, const std::string &fileName)
Definition: template.cpp:3061
TemplateEngine::TemplateEngine
TemplateEngine()
Create a template engine.
Definition: template.cpp:5368
TemplateVariant::Type::List
@ List
ResourceMgr::getAsString
QCString getAsString(const QCString &name) const
Gets the resource data as a C string
Definition: resourcemgr.cpp:192
FilterRelative::apply
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &)
Definition: template.cpp:1223
ExprAstNumber::number
int number() const
Definition: template.cpp:1679
TemplateNodeIndexEntry
Class representing an 'indexentry' tag in a template
Definition: template.cpp:4041
ExprAstLiteral::resolve
virtual TemplateVariant resolve(TemplateContext *)
Definition: template.cpp:1785
TemplateContextImpl::m_tabbingEnabled
bool m_tabbingEnabled
Definition: template.cpp:720
TemplateContextImpl::m_indexStacks
std::unordered_map< std::string, std::stack< TemplateVariant > > m_indexStacks
Definition: template.cpp:722
FilterRaw
The implementation of the "raw" filter
Definition: template.cpp:799
TemplateEscapeIntf::enableTabbing
virtual void enableTabbing(bool b)=0
Setting tabbing mode on or off (for LaTeX)
TemplateStruct::get
virtual TemplateVariant get(const QCString &name) const
Gets the value for a field name.
Definition: template.cpp:201
QCString::upper
QCString upper() const
Definition: qcstring.h:237
TemplateImmutableStruct::Private::fields
std::unordered_map< std::string, TemplateVariant > fields
Definition: template.cpp:467
Dir
Class representing a directory in the file system
Definition: dir.h:68
Operator::Minus
@ Minus
Definition: template.cpp:574
Private
@ Private
Definition: types.h:26
TemplateNodeIf::GuardedNodes::line
int line
Definition: template.cpp:3186
fEscape
static TemplateFilterFactory::AutoRegister< FilterEscape > fEscape("escape")
FilterEscape
The implementation of the "e" filter
Definition: template.cpp:1541
TemplateNodeRange::m_startExpr
ExprAstPtr m_startExpr
Definition: template.cpp:3400
TemplateEngine::Private::setOutputExtension
void setOutputExtension(const QCString &extension)
Definition: template.cpp:5344
ExprAstNegate
Class representing a negation (not) operator in the AST
Definition: template.cpp:1791
TemplateNodeWith::render
void render(TextStream &ts, TemplateContext *c)
Definition: template.cpp:4226
FilterListSort::ListElem
Definition: template.cpp:1067
TemplateNodeCreate
Class representing an 'create' tag in a template
Definition: template.cpp:3823
TemplateNodeList
Class representing a list of AST nodes in a template
Definition: template.cpp:1968
TemplateEngine::Private::Private
Private(TemplateEngine *engine)
Definition: template.cpp:5246
TemplateVariant::isFunction
constexpr bool isFunction() const
Returns TRUE if the variant holds a function value
Definition: template.h:215
ExpressionParser::ExprToken::Type
Type
Definition: template.cpp:2038
TemplateImmutableList::Private
Private data of a template immutable list object
Definition: template.cpp:505
TemplateNodeRepeat::render
void render(TextStream &ts, TemplateContext *c)
Definition: template.cpp:3210
QCString::length
uint length() const
Returns the length of the string, not counting the 0-terminator.
Definition: qcstring.h:147
TemplateListPtr
std::shared_ptr< TemplateList > TemplateListPtr
Definition: template.cpp:224
fIsRelativeURL
static TemplateFilterFactory::AutoRegister< FilterIsRelativeURL > fIsRelativeURL("isRelativeURL")
Operator::Type
Type
Definition: template.cpp:571
TemplateParser::currentToken
const TemplateToken * currentToken() const
Definition: template.cpp:5148
Operator::GreaterEqual
@ GreaterEqual
Definition: template.cpp:574
ExprAstFilter::apply
TemplateVariant apply(const TemplateVariant &v, TemplateContext *c)
Definition: template.cpp:1740
TemplateContextImpl::m_spacelessEnabled
bool m_spacelessEnabled
Definition: template.cpp:719
TemplateImmutableList::Private::elems
TemplateVariantList elems
Definition: template.cpp:510
TemplateImmutableList::TemplateImmutableList
TemplateImmutableList(std::initializer_list< TemplateVariant > elements)
Creates a list
Definition: template.cpp:514
TemplateContextImpl::escapeIntf
TemplateEscapeIntf * escapeIntf()
Definition: template.cpp:675
ExpressionParser::m_curToken
ExprToken m_curToken
Definition: template.cpp:2546
TemplateContextImpl::enableTabbing
void enableTabbing(bool b)
Definition: template.cpp:693
TemplateContextImpl::setLocation
void setLocation(const QCString &templateName, int line)
Definition: template.cpp:682
TemplateEngine::Private::m_extension
QCString m_extension
Definition: template.cpp:5364
QCString::findRev
int findRev(char c, int index=-1, bool cs=TRUE) const
Definition: qcstring.cpp:86
TemplateContextImpl::m_blockContext
TemplateBlockContext m_blockContext
Definition: template.cpp:715
TemplateEngine::outputExtension
QCString outputExtension() const
Returns the output extension, set via setOutputExtension()
Definition: template.cpp:5411
TemplateImpl::m_engine
TemplateEngine * m_engine
Definition: template.cpp:2566
TemplateNodeTree::TreeContext::object
TemplateNodeTree * object
Definition: template.cpp:3941
TemplateNodeBlock::TemplateNodeBlock
TemplateNodeBlock(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:3603
TemplateVariant::structToString
QCString structToString() const
Definition: template.cpp:5443
TemplateNodeIf::~TemplateNodeIf
~TemplateNodeIf()
Definition: template.cpp:3149
TemplateParser
Parser for templates
Definition: template.cpp:1985
QCString::isEmpty
bool isEmpty() const
Returns TRUE iff the string is empty
Definition: qcstring.h:144
ExprAstNegate::resolve
virtual TemplateVariant resolve(TemplateContext *c)
Definition: template.cpp:1796
ExpressionParser::ExprToken::Number
@ Number
Definition: template.cpp:2040
TemplateEngine::Private::IncludeEntry::Type
Type
Definition: template.cpp:5231
reg::match
bool match(const std::string &str, Match &match, const Ex &re)
Matches a given string str for a match against regular expression re.
Definition: regex.cpp:729
TemplateListGenericConstIterator::m_list
const List & m_list
Definition: template.cpp:266
ExprAstFilterAppl::resolve
virtual TemplateVariant resolve(TemplateContext *c)
Definition: template.cpp:1769
TemplateVariant::call
TemplateVariant call(const std::vector< TemplateVariant > &args=std::vector< TemplateVariant >())
Return the result of apply this function with args.
Definition: template.cpp:454
TemplateFilterFactory::FilterFunction
TemplateVariant() FilterFunction(const TemplateVariant &v, const TemplateVariant &arg)
Definition: template.cpp:1586
TemplateNodeOpenSubIndex::m_name
QCString m_name
Definition: template.cpp:4139
TemplateNodeBlock
Class representing a 'block' tag in a template
Definition: template.cpp:3600
autoRefInclude
static TemplateNodeFactory::AutoRegister< TemplateNodeInclude > autoRefInclude("include")
TemplateNodeFor::render
void render(TextStream &ts, TemplateContext *c)
Definition: template.cpp:3469
TemplateFilterFactory::registerFilter
void registerFilter(const QCString &name, FilterFunction *func)
Definition: template.cpp:1610
Operator::In
@ In
Definition: template.cpp:573
TemplateVariant::isBool
constexpr bool isBool() const
Returns TRUE if the variant holds a boolean value
Definition: template.h:205
TemplateBlockContext::push
void push(TemplateNodeBlock *block)
Definition: template.cpp:4791
FilterListSort::determineSortKey
static QCString determineSortKey(const TemplateStructIntfPtr s, const QCString &arg)
Definition: template.cpp:1119
FilterListSort
The implementation of the "listsort" filter
Definition: template.cpp:1065
TemplateNodeCreator
Helper class for creating template AST tag nodes and returning the template for a given node.
Definition: template.cpp:3039
TemplateNodeVariable::m_var
ExprAstPtr m_var
Definition: template.cpp:3031
TemplateNodeResource::TemplateNodeResource
TemplateNodeResource(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:4541
ExpressionParser::ExprToken::Operator
@ Operator
Definition: template.cpp:2040
FilterPrepend::apply
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &arg)
Definition: template.cpp:948
split
static std::vector< QCString > split(const QCString &str, const QCString &sep, bool allowEmptyEntries=FALSE, bool cleanup=TRUE)
Definition: template.cpp:47
TemplateTokenPtr
std::unique_ptr< TemplateToken > TemplateTokenPtr
Definition: template.cpp:1962
ExpressionParser::parseNumber
ExprAstPtr parseNumber()
Definition: template.cpp:2255
TemplateNodeFor::m_reversed
bool m_reversed
Definition: template.cpp:3552
TemplateNodeIndexEntry::TemplateNodeIndexEntry
TemplateNodeIndexEntry(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:4050
TemplateNodeSet::Mapping::value
ExprAstPtr value
Definition: template.cpp:4328
TemplateListGenericConstIterator::toFirst
virtual void toFirst()
Moves iterator to the first element in the list
Definition: template.cpp:235
TemplateLexer::reset
void reset()
ExprAstVariable::name
const QCString & name() const
Definition: template.cpp:1691
TemplateImmutableList::count
virtual uint count() const
Returns the number of elements in the list
Definition: template.cpp:528
ExprAstFunctionVariable::m_args
ExprAstList m_args
Definition: template.cpp:1730
FilterDivisibleBy
The implementation of the "divisibleby" filter
Definition: template.cpp:1427
TemplateNodeVariable::render
void render(TextStream &ts, TemplateContext *c)
Definition: template.cpp:2989
TemplateNodeText
Class representing a piece of plain text in a template
Definition: template.cpp:2927
TemplateEngine::loadByName
Template * loadByName(const QCString &fileName, int fromLine)
Creates a new template whose contents are in a file.
Definition: template.cpp:5381
TemplateFilterFactory
Factory singleton for registering and creating filters
Definition: template.cpp:1583
TemplateNodeRepeat::TemplateNodeRepeat
TemplateNodeRepeat(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:3199
TemplateStruct
Default implementation of a context value of type struct.
Definition: template.cpp:150
FilterIsRelativeURL
The implementation of the "isRelativeURL" filter
Definition: template.cpp:1458
TemplateVariant::listToString
QCString listToString() const
Definition: template.cpp:5423
TemplateEscapeIntf::escape
virtual QCString escape(const QCString &input)=0
Returns the input after escaping certain characters
fAlphaIndex
static TemplateFilterFactory::AutoRegister< FilterAlphaIndex > fAlphaIndex("alphaIndex")
FilterTexIndex::apply
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &)
Definition: template.cpp:909
QCString::str
std::string str() const
Definition: qcstring.h:442
TemplateNodeEncoding::TemplateNodeEncoding
TemplateNodeEncoding(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:4618
TemplateNodeSet
Class representing an 'set' tag in a template
Definition: template.cpp:4322
TemplateContextImpl::m_activeEscapeIntf
TemplateEscapeIntf * m_activeEscapeIntf
Definition: template.cpp:717
ExprAstFilterAppl::m_expr
ExprAstPtr m_expr
Definition: template.cpp:1774
TemplateEngine::p
std::unique_ptr< Private > p
Definition: template.h:539
TemplateNodeEncoding
Class representing the 'encoding' tag in a template
Definition: template.cpp:4615
TemplateContextImpl::setSpacelessIntf
void setSpacelessIntf(std::unique_ptr< TemplateSpacelessIntf > intf)
Sets the interface that will be used inside a spaceless block to remove any redundant whitespace.
Definition: template.cpp:677
Template
Abstract interface for a template.
Definition: template.h:475
autoRefResource
static TemplateNodeFactory::AutoRegister< TemplateNodeResource > autoRefResource("resource")
TemplateContextImpl::TemplateContextImpl
TemplateContextImpl(const TemplateEngine *e)
Definition: template.cpp:2574
ExprAstNumber
Class representing a number in the AST
Definition: template.cpp:1674
fAppend
static TemplateFilterFactory::AutoRegister< FilterAppend > fAppend("append")
FilterLength::apply
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &)
Definition: template.cpp:968
TemplateVariant::m_raw
bool m_raw
Definition: template.h:258
TemplateContextImpl::get
TemplateVariant get(const QCString &name) const
Gets the value for a given key
Definition: template.cpp:2646
FilterStripPath::apply
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &)
Definition: template.cpp:1386
TemplateParser::templateName
QCString templateName() const
Definition: template.cpp:1998
FilterTexIndex
The implementation of the "texindex" filter
Definition: template.cpp:906
TemplateVariant::isWeakStruct
constexpr bool isWeakStruct() const
Returns TRUE if the variant holds a struct value
Definition: template.h:217
TemplateNodeTree
Class representing an 'tree' tag in a template
Definition: template.cpp:3935
TemplateEngine::setOutputExtension
void setOutputExtension(const QCString &extension)
Sets the extension of the output file.
Definition: template.cpp:5406
TemplateNodeOpenSubIndex::TemplateNodeOpenSubIndex
TemplateNodeOpenSubIndex(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:4112
TemplateVariant::Type::Struct
@ Struct
TemplateNodeSet::m_mapping
std::unique_ptr< Mapping > m_mapping
Definition: template.cpp:4360
TemplateContextImpl::m_templateName
QCString m_templateName
Definition: template.cpp:711
FilterFlatten
The implementation of the "flatten" filter
Definition: template.cpp:1015
ExpressionParser::parseIdentifierOptionalArgs
ExprAstPtr parseIdentifierOptionalArgs()
Definition: template.cpp:2282
TemplateContextImpl::line
int line() const
Definition: template.cpp:685
TemplateListGenericConstIterator::toNext
virtual void toNext()
Moves iterator to the next element in the list
Definition: template.cpp:244
TemplateContextImpl::~TemplateContextImpl
virtual ~TemplateContextImpl()
Definition: template.cpp:2583
TemplateNodeInclude::m_includeExpr
ExprAstPtr m_includeExpr
Definition: template.cpp:3802
TemplateNodeCreate::render
void render(TextStream &, TemplateContext *c)
Definition: template.cpp:3857
err
void err(const char *fmt,...)
Definition: message.cpp:203
FilterAlphaIndex
The implementation of the "alphaIndex" filter
Definition: template.cpp:1281
TemplateNodeMarkers::m_listExpr
ExprAstPtr m_listExpr
Definition: template.cpp:4502
TemplateNodeWith::Mapping::name
QCString name
Definition: template.cpp:4187
TemplateImmutableList::Private::index
int index
Definition: template.cpp:511
QCString::at
char & at(size_t i)
Returns a reference to the character at index i.
Definition: qcstring.h:477
TemplateNodeMarkers::m_patternExpr
ExprAstPtr m_patternExpr
Definition: template.cpp:4503
TemplateNodeCloseSubIndex
Class representing an 'closesubindex' tag in a template
Definition: template.cpp:4145
TextStream
Text streaming class that buffers data.
Definition: textstream.h:33
TemplateEngine::Private::unload
void unload(Template *)
Definition: template.cpp:5296
FilterAlphaIndex::ListElem::ListElem
ListElem(std::string k, const TemplateVariant &v)
Definition: template.cpp:1286
portable_iconv_open
void * portable_iconv_open(const char *tocode, const char *fromcode)
TemplateNodeMarkers::render
void render(TextStream &ts, TemplateContext *c)
Definition: template.cpp:4420
TemplateBlockContext::TemplateBlockContext
TemplateBlockContext()
Definition: template.cpp:4733
TemplateImpl::engine
TemplateEngine * engine() const
Definition: template.cpp:2562
QCString::find
int find(char c, int index=0, bool cs=TRUE) const
Definition: qcstring.cpp:38
ExpressionParser::parseAdditiveExpression
ExprAstPtr parseAdditiveExpression()
Definition: template.cpp:2143
FilterDefault::apply
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &arg)
Definition: template.cpp:995
TemplateNodeTree::render
void render(TextStream &ts, TemplateContext *c)
Definition: template.cpp:4014
TemplateNodeVariable::~TemplateNodeVariable
~TemplateNodeVariable()
Definition: template.cpp:2985
fFlatten
static TemplateFilterFactory::AutoRegister< FilterFlatten > fFlatten("flatten")
TemplateNodeWith::TemplateNodeWith
TemplateNodeWith(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:4191
TemplateToken::data
QCString data
Definition: template.cpp:1958
ExprAstUnary::ExprAstUnary
ExprAstUnary(Operator::Type op, ExprAstPtr &&expr)
Definition: template.cpp:1805
TemplateEngine::printIncludeContext
void printIncludeContext(const QCString &fileName, int line) const
Prints the current template file include stack
Definition: template.cpp:5401
Operator::Or
@ Or
Definition: template.cpp:573
fLower
static TemplateFilterFactory::AutoRegister< FilterLower > fLower("lower")
TextStream::flush
void flush()
Flushes the buffer.
Definition: textstream.h:188
TemplateNodeResource::render
void render(TextStream &, TemplateContext *c)
Definition: template.cpp:4571
TemplateNodeFactory::AutoRegister
Helper class for registering a template AST node
Definition: template.cpp:4695
Operator::Comma
@ Comma
Definition: template.cpp:574
FilterListSort::ListElem::key
QCString key
Definition: template.cpp:1070
TemplateStruct::m_fields
std::unordered_map< std::string, TemplateVariant > m_fields
Definition: template.cpp:176
TemplateImmutableStruct::TemplateImmutableStruct
TemplateImmutableStruct(std::initializer_list< StructField > fields)
Creates a struct
Definition: template.cpp:470
FilterPaginate::apply
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &args)
Definition: template.cpp:1242
TemplateLexer
Lexer class for turning a template into a list of tokens
Definition: template.cpp:4805
TemplateNodeBlock::m_nodes
TemplateNodeList m_nodes
Definition: template.cpp:3671
TemplateContextImpl::spacelessIntf
std::unique_ptr< TemplateSpacelessIntf > & spacelessIntf()
Definition: template.cpp:687
TemplateImpl
Internal class representing the implementation of a template
Definition: template.cpp:2554
warn
void warn(const QCString &file, int line, const char *fmt,...)
Definition: message.cpp:151
TemplateStructIntfPtr
std::shared_ptr< TemplateStructIntf > TemplateStructIntfPtr
Definition: template.h:33
TemplateListIntf::ConstIterator
Abstract interface for a iterator of a list.
Definition: template.h:272
TemplateEngine::Private::m_engine
TemplateEngine * m_engine
Definition: template.cpp:5362
TemplateNodeWith::Mapping
Definition: template.cpp:4184
TemplateContextImpl::m_fromUtf8
void * m_fromUtf8
Definition: template.cpp:724
reg::Iterator
Iterator class to iterator through matches.
Definition: regex.h:242
fIsAbsoluteURL
static TemplateFilterFactory::AutoRegister< FilterIsAbsoluteURL > fIsAbsoluteURL("isAbsoluteURL")
TemplateList::~TemplateList
virtual ~TemplateList()=default
Destroys the list
TemplateNodeTree::TreeContext::TreeContext
TreeContext(TemplateNodeTree *o, const TemplateListIntfPtr l, TemplateContext *c)
Definition: template.cpp:3939
TemplateNode::render
virtual void render(TextStream &ts, TemplateContext *c)=0
TemplateNodeIf::m_ifGuardedNodes
std::vector< std::unique_ptr< GuardedNodes > > m_ifGuardedNodes
Definition: template.cpp:3190
TemplateEngine::Private::IncludeEntry::line
int line() const
Definition: template.cpp:5237
end
DirIterator end(const DirIterator &) noexcept
Definition: dir.cpp:128
TemplateNodeCycle::m_args
ExprAstList m_args
Definition: template.cpp:4316
TemplateNodeSet::TemplateNodeSet
TemplateNodeSet(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:4331
TemplateListIntf::ConstIteratorPtr
std::unique_ptr< ConstIterator > ConstIteratorPtr
Definition: template.h:292
TemplateNodeWith::Mapping::Mapping
Mapping(const QCString &n, ExprAstPtr &&e)
Definition: template.cpp:4186
TemplateListIntf
Abstract read-only interface for a context value of type list.
Definition: template.h:268
TemplateLexer::addToken
void addToken(TemplateTokenStream &tokens, const QCString &data, int line, int startPos, int endPos, TemplateToken::Type type)
Definition: template.cpp:5034
ExpressionParser
Recursive decent parser for Django style template expressions.
Definition: template.cpp:2010
TemplateListGenericConstIterator::toPrev
virtual void toPrev()
Moves iterator to the previous element in the list
Definition: template.cpp:248
TemplateNodeTabbing::m_nodes
TemplateNodeList m_nodes
Definition: template.cpp:4532
TemplateParser::removeNextToken
void removeNextToken()
Definition: template.cpp:5153
TemplateNodeRepeat
Class representing a 'for' tag in a template
Definition: template.cpp:3196
ExpressionParser::ExprToken::op
Operator::Type op
Definition: template.cpp:2046
FilterKeep
The implementation of the "keep" filter
Definition: template.cpp:818
TemplateNodeTree::m_treeNodes
TemplateNodeList m_treeNodes
Definition: template.cpp:4035
TemplateNodeFor::TemplateNodeFor
TemplateNodeFor(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:3412
TemplateNodeMsg::m_nodes
TemplateNodeList m_nodes
Definition: template.cpp:3593
TemplateNodeSpaceless::m_nodes
TemplateNodeList m_nodes
Definition: template.cpp:4389
TemplateNodeCloseSubIndex::TemplateNodeCloseSubIndex
TemplateNodeCloseSubIndex(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:4148
TemplateNodeVariable::m_line
int m_line
Definition: template.cpp:3030
TemplateNodeInclude::render
void render(TextStream &ts, TemplateContext *c)
Definition: template.cpp:3768
TemplateVariant::Type::Int
@ Int
FilterLower
The implementation of the "lower" filter
Definition: template.cpp:1492
TemplateNodeResource
Class representing an 'markers' tag in a template
Definition: template.cpp:4538
TemplateImpl::blockContext
TemplateBlockContext * blockContext()
Definition: template.cpp:2563
Variant::get
Type< index > & get()
Return a non-constant reference to the value held by the variant container.
Definition: variant.h:285
TemplateNode::~TemplateNode
virtual ~TemplateNode()
Definition: template.cpp:1937
TemplateBlockContext
Class holding stacks of blocks available in the context
Definition: template.cpp:614
TemplateNodeEncoding::render
void render(TextStream &ts, TemplateContext *c)
Definition: template.cpp:4637
TemplateNodeBlock::render
void render(TextStream &ts, TemplateContext *c)
Definition: template.cpp:3618
ExpressionParser::parseUnaryExpression
ExprAstPtr parseUnaryExpression()
Definition: template.cpp:2181
uint
unsigned uint
Definition: qcstring.h:40
TemplateNodeIndexEntry::m_name
QCString m_name
Definition: template.cpp:4102
TemplateNodeFor::m_emptyNodes
TemplateNodeList m_emptyNodes
Definition: template.cpp:3556
TemplateNodeIndexEntry::Mapping::name
QCString name
Definition: template.cpp:4046
ExpressionParser::parseNotExpression
ExprAstPtr parseNotExpression()
Definition: template.cpp:2093
ExpressionParser::parseExpression
ExprAstPtr parseExpression()
Definition: template.cpp:2049
TemplateParser::m_tokens
TemplateTokenStream & m_tokens
Definition: template.cpp:2003
Variant::valid
constexpr bool valid() const
Returns true iff the Variant holds a valid type.
Definition: variant.h:255
TemplateParser::warn
void warn(const QCString &fileName, int line, const char *fmt,...) const
Definition: template.cpp:5163
TemplateStruct::remove
virtual void remove(const QCString &name)
Removes the field from the struct
Definition: template.cpp:192
ExpressionParser::parseCompareExpression
ExprAstPtr parseCompareExpression()
Definition: template.cpp:2117
Operator::LessEqual
@ LessEqual
Definition: template.cpp:573
TemplateNodeWith
Class representing an 'with' tag in a template
Definition: template.cpp:4182
TemplateEngine::createContext
std::unique_ptr< TemplateContext > createContext() const
Creates a new context that can be using to render a template.
Definition: template.cpp:5376
TemplateVariant
Variant type which can hold one value of a fixed set of types.
Definition: template.h:98
TemplateNodeFor::m_vars
std::vector< QCString > m_vars
Definition: template.cpp:3554
TemplateNodeText::m_data
QCString m_data
Definition: template.cpp:2965
FilterGroupBy::ListElem::ListElem
ListElem(const QCString &k, const TemplateVariant &v)
Definition: template.cpp:1152
QCString::stripWhiteSpace
QCString stripWhiteSpace() const
returns a copy of this string with leading and trailing whitespace removed
Definition: qcstring.h:243
autoRefTabbing
static TemplateNodeFactory::AutoRegister< TemplateNodeTabbing > autoRefTabbing("tabbing")
FileInfo::size
size_t size() const
Definition: fileinfo.cpp:23
TemplateNodeInclude::TemplateNodeInclude
TemplateNodeInclude(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:3757
TemplateNodeText::TemplateNodeText
TemplateNodeText(TemplateParser *, TemplateNode *parent, int, const QCString &data)
Definition: template.cpp:2930
Operator::RightParen
@ RightParen
Definition: template.cpp:575
ExprAst
Base class for all nodes in the abstract syntax tree of an expression.
Definition: template.cpp:1663
TemplateEngine::Private::leaveBlock
void leaveBlock()
Definition: template.cpp:5313
FilterAdd::apply
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &arg)
Definition: template.cpp:741
TemplateNodeTabbing
Class representing an 'tabbing' tag in a template
Definition: template.cpp:4509
QCString::left
QCString left(size_t len) const
Definition: qcstring.h:212
ExprAstFilter::ExprAstFilter
ExprAstFilter(const QCString &name, ExprAstPtr &&arg)
Definition: template.cpp:1737
TemplateContextImpl::getRef
const TemplateVariant * getRef(const QCString &name) const
Returns a pointer to the value corresponding to a given key.
Definition: template.cpp:2730
FilterNoWrap::apply
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &)
Definition: template.cpp:1413
TemplateEngine::Private
Private data of the template engine
Definition: template.cpp:5226
message.h
TemplateVariant::isInt
constexpr bool isInt() const
Returns TRUE if the variant holds an integer value
Definition: template.h:207
TemplateList::TemplateList
TemplateList()=default
Creates a list
TemplateNodeExtend::m_nodes
TemplateNodeList m_nodes
Definition: template.cpp:3750
autoRefRange
static TemplateNodeFactory::AutoRegister< TemplateNodeRange > autoRefRange("range")
TemplateContextImpl::EscapeIntfMap
std::unordered_map< std::string, std::unique_ptr< TemplateEscapeIntf > > EscapeIntfMap
Definition: template.cpp:646
TemplateImmutableStruct::Private
Private data of a template struct object
Definition: template.cpp:463
ExpressionParser::parseAndExpression
ExprAstPtr parseAndExpression()
Definition: template.cpp:2075
TemplateList::append
virtual void append(const TemplateVariant &v)
Appends element v to the end of the list
Definition: template.cpp:297
TemplateNodeTree::TreeContext::templateCtx
TemplateContext * templateCtx
Definition: template.cpp:3943
ExpressionParser::parse
ExprAstPtr parse(const QCString &expr)
Definition: template.cpp:2021
Operator::toString
static const char * toString(Type op)
Definition: template.cpp:579
TemplateContextImpl::closeSubIndex
void closeSubIndex(const QCString &indexName)
Definition: template.cpp:2804
TemplateStruct::fields
virtual StringVector fields() const
Return the list of fields.
Definition: template.cpp:207
TemplateKeyValue::key
QCString key
Definition: template.cpp:634
TemplateEngine::Private::m_templateCache
std::unordered_map< std::string, std::unique_ptr< Template > > m_templateCache
Definition: template.cpp:5360
ExprAstUnary::m_expr
ExprAstPtr m_expr
Definition: template.cpp:1820
Operator::LeftParen
@ LeftParen
Definition: template.cpp:575
FilterList
The implementation of the "list" filter
Definition: template.cpp:862
TemplateNodeWith::m_nodes
TemplateNodeList m_nodes
Definition: template.cpp:4241
autoRefWith
static TemplateNodeFactory::AutoRegister< TemplateNodeWith > autoRefWith("with")
TemplateParser::hasNextToken
bool hasNextToken() const
Definition: template.cpp:5135
ExpressionParser::ExprToken
Class representing a token within an expression.
Definition: template.cpp:2032
TemplateEngine::Private::loadByName
Template * loadByName(const QCString &fileName, int line)
Definition: template.cpp:5254
TemplateNodeRange::m_endExpr
ExprAstPtr m_endExpr
Definition: template.cpp:3401
TemplateContextImpl::getPrimary
TemplateVariant getPrimary(const QCString &name) const
Definition: template.cpp:2743
fDivisibleBy
static TemplateFilterFactory::AutoRegister< FilterDivisibleBy > fDivisibleBy("divisibleby")
ExpressionParser::ExprToken::id
QCString id
Definition: template.cpp:2045
Operator::NotEqual
@ NotEqual
Definition: template.cpp:573
FilterLength
The implementation of the "length" filter
Definition: template.cpp:965
TemplateList::removeAt
void removeAt(uint index)
Definition: template.cpp:302
TemplateNodeRange::TemplateNodeRange
TemplateNodeRange(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:3249
TemplateContextImpl::tabbingEnabled
bool tabbingEnabled() const
Definition: template.cpp:696
FilterAlphaIndex::apply
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &args)
Definition: template.cpp:1321
TemplateNodeCloseSubIndex::render
void render(TextStream &, TemplateContext *c)
Definition: template.cpp:4164
TemplateNodeRange::m_var
QCString m_var
Definition: template.cpp:3402
FilterGroupBy::ListElem::key
QCString key
Definition: template.cpp:1153
TemplateNodeRange::m_down
bool m_down
Definition: template.cpp:3399
resourcemgr.h
TemplateContextImpl::openSubIndex
void openSubIndex(const QCString &indexName)
Definition: template.cpp:2782
TemplateImmutableList::at
virtual TemplateVariant at(uint index) const
Returns the element at index position index.
Definition: template.cpp:538
TemplateContextImpl::m_escapeIntfMap
EscapeIntfMap m_escapeIntfMap
Definition: template.cpp:716
TemplateLexer::m_openChar
char m_openChar
Definition: template.cpp:4820
Operator::Divide
@ Divide
Definition: template.cpp:574
TemplateStructIntfWeakPtr
std::weak_ptr< TemplateStructIntf > TemplateStructIntfWeakPtr
Definition: template.h:34
TRACE
#define TRACE(x)
Definition: template.cpp:40
ExprAstFilter::m_name
QCString m_name
Definition: template.cpp:1756
FilterAlphaIndex::determineSortKey
static std::string determineSortKey(const TemplateStructIntfPtr s, const QCString &attribName)
Definition: template.cpp:1313
TemplateNodeIndexEntry::Mapping::value
ExprAstPtr value
Definition: template.cpp:4047
TemplateNodeInclude
Class representing an 'include' tag in a template
Definition: template.cpp:3754
ExprAstLiteral::ExprAstLiteral
ExprAstLiteral(const QCString &lit)
Definition: template.cpp:1782
TemplateNodeIf::GuardedNodes::guardAst
ExprAstPtr guardAst
Definition: template.cpp:3187
TemplateNodeIf::m_falseNodes
TemplateNodeList m_falseNodes
Definition: template.cpp:3191
autoRefCycle
static TemplateNodeFactory::AutoRegister< TemplateNodeCycle > autoRefCycle("cycle")
ExprAstFunctionVariable::m_var
ExprAstPtr m_var
Definition: template.cpp:1729
fHex
static TemplateFilterFactory::AutoRegister< FilterHex > fHex("hex")
TemplateEngine::Private::IncludeEntry::blockName
QCString blockName() const
Definition: template.cpp:5236
TemplateNodeResource::m_append
bool m_append
Definition: template.cpp:4609
TemplateNodeTree::TreeContext::list
const TemplateListIntfPtr list
Definition: template.cpp:3942
getUTF8CharAt
std::string getUTF8CharAt(const std::string &input, size_t pos)
Returns the UTF8 character found at byte position pos in the input string.
Definition: utf8.cpp:127
TemplateVariant::TemplateVariant
TemplateVariant()
Constructs an invalid variant.
Definition: template.h:127
TemplateImmutableList::Private::Private
Private(std::initializer_list< TemplateVariant > e)
Definition: template.cpp:508
ExprAstNumber::ExprAstNumber
ExprAstNumber(int num)
Definition: template.cpp:1677
TemplateContextImpl::enableSpaceless
void enableSpaceless(bool b)
Definition: template.cpp:689
TemplateFilterFactory::instance
static TemplateFilterFactory & instance()
Definition: template.cpp:1588
TemplateLexer::m_engine
const TemplateEngine * m_engine
Definition: template.cpp:4817
TemplateNodeFor
Class representing a 'for' tag in a template
Definition: template.cpp:3409
TemplateLexer::m_fileName
QCString m_fileName
Definition: template.cpp:4818
FilterUpper::apply
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &)
Definition: template.cpp:1511
TemplateNodeFactory::registerTemplateNode
void registerTemplateNode(const QCString &name, CreateFunc func)
Definition: template.cpp:4689
QCString::lower
QCString lower() const
Definition: qcstring.h:232
TemplateContextImpl::setEscapeIntf
void setEscapeIntf(const QCString &ext, std::unique_ptr< TemplateEscapeIntf > intf)
Sets the interface that will be used for escaping the result of variable expansion before writing it ...
Definition: template.cpp:664
Operator::Not
@ Not
Definition: template.cpp:573
TemplateLexer::m_closeChar
char m_closeChar
Definition: template.cpp:4821
ExprAstFilter
Class representing a filter in the AST
Definition: template.cpp:1734
TemplateNodeExtend::TemplateNodeExtend
TemplateNodeExtend(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:3680
TemplateEngine::Private::IncludeEntry
Definition: template.cpp:5228
FilterDecodeURL
The implementation of the "decodeURL" filter The leading character is removed from the value in case ...
Definition: template.cpp:1562
ExprAstUnary
Definition: template.cpp:1802
getPathFunc
static TemplateVariant getPathFunc(const TemplateStructIntfWeakPtr entryWeakRef)
Definition: template.cpp:2846
Operator::Equal
@ Equal
Definition: template.cpp:573
latexEscapeLabelName
QCString latexEscapeLabelName(const QCString &s)
Definition: util.cpp:5086
TemplateContext::set
virtual void set(const QCString &name, const TemplateVariant &v)=0
Sets a value in the current scope.
ExpressionParser::getNextToken
bool getNextToken()
Definition: template.cpp:2344
TemplateToken::TemplateToken
TemplateToken(Type t, const QCString &d, int l)
Definition: template.cpp:1956
ExpressionParser::~ExpressionParser
virtual ~ExpressionParser()
Definition: template.cpp:2017
ExpressionParser::m_parser
const TemplateParser * m_parser
Definition: template.cpp:2545
autoRefSet
static TemplateNodeFactory::AutoRegister< TemplateNodeSet > autoRefSet("set")
ExprAstLiteral::m_literal
QCString m_literal
Definition: template.cpp:1787
TemplateContextImpl::outputDirectory
QCString outputDirectory() const
Definition: template.cpp:686
TemplateContextImpl::recode
QCString recode(const QCString &s)
Definition: template.cpp:2609
TRUE
#define TRUE
Definition: qcstring.h:36
ExpressionParser::ExprToken::Literal
@ Literal
Definition: template.cpp:2040
FilterGroupBy::ListElem::value
TemplateVariant value
Definition: template.cpp:1154
FilterRelative
The implementation of the "relative" filter
Definition: template.cpp:1220
TemplateContextImpl::push
void push()
Push a new scope on the stack.
Definition: template.cpp:2749
TemplateNodeMsg::render
void render(TextStream &, TemplateContext *c)
Definition: template.cpp:3574
FilterAlphaIndex::ListElem::key
std::string key
Definition: template.cpp:1287
TemplateNodeCreate::TemplateNodeCreate
TemplateNodeCreate(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:3826
fPrepend
static TemplateFilterFactory::AutoRegister< FilterPrepend > fPrepend("prepend")
TemplateNodeVariable
Class representing a variable in a template
Definition: template.cpp:2971
FilterIsAbsoluteURL
The implementation of the "isRelativeURL" filter
Definition: template.cpp:1475
ExprAst::~ExprAst
virtual ~ExprAst()
Definition: template.cpp:1666
regex.h
QCString::toInt
int toInt(bool *ok=0, int base=10) const
Definition: qcstring.cpp:244
TemplateList::count
virtual uint count() const
Returns the number of elements in the list
Definition: template.cpp:277
TemplateEngine::Private::IncludeEntry::IncludeEntry
IncludeEntry(Type type, const QCString &fileName, const QCString &blockName, int line)
Definition: template.cpp:5232
FilterAlphaIndex::ListElem::value
TemplateVariant value
Definition: template.cpp:1288
TemplateNodeCycle::m_index
size_t m_index
Definition: template.cpp:4315
fStripPath
static TemplateFilterFactory::AutoRegister< FilterStripPath > fStripPath("stripPath")
FilterGroupBy
The implementation of the "groupBy" filter
Definition: template.cpp:1148
TemplateVariant::isStruct
constexpr bool isStruct() const
Returns TRUE if the variant holds a struct value
Definition: template.h:211
getPathListFunc
static void getPathListFunc(const TemplateStructIntfPtr entry, TemplateListPtr list)
Definition: template.cpp:2833
fAdd
static TemplateFilterFactory::AutoRegister< FilterAdd > fAdd("add")
fLength
static TemplateFilterFactory::AutoRegister< FilterLength > fLength("length")
TemplateContext
Abstract interface for a template context.
Definition: template.h:422
TemplateEngine::Private::IncludeEntry::type
Type type() const
Definition: template.cpp:5234
TemplateLexer::setOpenCloseCharacters
void setOpenCloseCharacters(char openChar, char closeChar)
Definition: template.cpp:4810
TemplateNodeCloseSubIndex::m_name
QCString m_name
Definition: template.cpp:4175
TemplateNodeIf::GuardedNodes
Definition: template.cpp:3184
TemplateNodeCreator::getTemplate
TemplateImpl * getTemplate()
Definition: template.cpp:3051
TextStream::str
std::string str() const
Return the contents of the buffer as a std::string object
Definition: textstream.h:208
TemplateNodeResource::m_asExpr
ExprAstPtr m_asExpr
Definition: template.cpp:4608
va_warn
void va_warn(const QCString &file, int line, const char *fmt, va_list args)
Definition: message.cpp:159
TemplateList::alloc
static TemplateListPtr alloc()
Creates an instance and returns a shared pointer to it
Definition: template.cpp:291
TemplateNodeExtend::m_extendExpr
ExprAstPtr m_extendExpr
Definition: template.cpp:3749
TemplateVariant::Type::WeakStruct
@ WeakStruct
TemplateNodeIndexEntry::render
void render(TextStream &, TemplateContext *c)
Definition: template.cpp:4086
TemplateEngine::~TemplateEngine
~TemplateEngine()
Destroys the template engine.
Definition: template.cpp:5372
TemplateNodeList::render
void render(TextStream &ts, TemplateContext *c)
Definition: template.cpp:1971
autoRefCloseSubIndex
static TemplateNodeFactory::AutoRegister< TemplateNodeCloseSubIndex > autoRefCloseSubIndex("closesubindex")
ExprAstBinary::m_lhs
ExprAstPtr m_lhs
Definition: template.cpp:1926
ExprAstFunctionVariable::resolve
virtual TemplateVariant resolve(TemplateContext *c)
Definition: template.cpp:1713
Operator::Last
@ Last
Definition: template.cpp:576
TemplateNodeCreator::m_templateName
QCString m_templateName
Definition: template.cpp:3095
TemplateNodeVariable::m_templateName
QCString m_templateName
Definition: template.cpp:3029
TemplateEngine::Private::m_includeStack
std::vector< IncludeEntry > m_includeStack
Definition: template.cpp:5363
TemplateNodeMarkers::TemplateNodeMarkers
TemplateNodeMarkers(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:4398
TemplateNode::parent
TemplateNode * parent()
Definition: template.cpp:1941
TemplateContextImpl::setOutputDirectory
void setOutputDirectory(const QCString &dir)
When files are created (i.e.
Definition: template.cpp:662
FilterAdd
The implementation of the "add" filter
Definition: template.cpp:730
FilterHex::apply
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &)
Definition: template.cpp:1527
TemplateNodeWith::m_args
std::vector< Mapping > m_args
Definition: template.cpp:4242
TemplateKeyValue::TemplateKeyValue
TemplateKeyValue(const QCString &k, const TemplateVariant &v)
Definition: template.cpp:633
TemplateListGenericConstIterator::~TemplateListGenericConstIterator
virtual ~TemplateListGenericConstIterator()
Definition: template.cpp:234
TemplateNodeEncoding::m_encExpr
ExprAstPtr m_encExpr
Definition: template.cpp:4656
TemplateVariant::raw
constexpr bool raw() const
Returns whether or not the value of the Value is raw.
Definition: template.h:245
TemplateToken::Text
@ Text
Definition: template.cpp:1955
TemplateNodeRange
Class representing a 'range' tag in a template
Definition: template.cpp:3246
FilterTexLabel
The implementation of the "texlabel" filter
Definition: template.cpp:887
ExpressionParser::ExpressionParser
ExpressionParser(const TemplateParser *parser, int line)
Definition: template.cpp:2013
TemplateBlockContext::add
void add(TemplateNodeBlock *block)
Definition: template.cpp:4765
TemplateNodeIf::render
void render(TextStream &ts, TemplateContext *c)
Definition: template.cpp:3153
FilterLower::apply
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &)
Definition: template.cpp:1495
ExprAstBinary::m_rhs
ExprAstPtr m_rhs
Definition: template.cpp:1927
TemplateNodeMarkers::m_nodes
TemplateNodeList m_nodes
Definition: template.cpp:4500
TemplateToken
Class representing a lexical token in a template
Definition: template.cpp:1952
TemplateParser::parse
void parse(TemplateNode *parent, int line, const StringVector &stopAt, TemplateNodeList &nodes)
Definition: template.cpp:5057
ExpressionParser::ExprToken::type
Type type
Definition: template.cpp:2043
FilterKeep::apply
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &args)
Definition: template.cpp:821
getPrefixIndex
int getPrefixIndex(const QCString &name)
Definition: util.cpp:3357
QCString::setNum
QCString & setNum(short n)
Definition: qcstring.h:372
TemplateNodeIf
Class representing an 'if' tag in a template
Definition: template.cpp:3102
TemplateNode::TemplateNode
TemplateNode(TemplateNode *parent)
Definition: template.cpp:1936
TemplateEngine::Private::IncludeEntry::fileName
QCString fileName() const
Definition: template.cpp:5235
TemplateVariant::operator==
bool operator==(TemplateVariant &other) const
Compares this QVariant with v and returns true if they are equal; otherwise returns false.
Definition: template.cpp:342
ExpressionParser::parsePrimaryExpression
ExprAstPtr parsePrimaryExpression()
Definition: template.cpp:2211
ExprAstFunctionVariable
Definition: template.cpp:1706
TemplateContextImpl::m_line
int m_line
Definition: template.cpp:712
TemplateList::insertAt
void insertAt(uint index, TemplateListPtr list)
Definition: template.cpp:310
FilterListSort::ListElem::ListElem
ListElem(const QCString &k, const TemplateVariant &v)
Definition: template.cpp:1069
TemplateImpl::m_blockContext
TemplateBlockContext m_blockContext
Definition: template.cpp:2569
ExprAstPtr
std::unique_ptr< ExprAst > ExprAstPtr
Definition: template.cpp:1670
FilterRaw::apply
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &)
Definition: template.cpp:802
utf8.h
Various UTF8 related helper functions.
TemplateContextImpl::needsRecoding
bool needsRecoding() const
Definition: template.cpp:697
TemplateImmutableStruct::get
virtual TemplateVariant get(const QCString &name) const
Gets the value for a field name.
Definition: template.cpp:480
TemplateContext::get
virtual TemplateVariant get(const QCString &name) const =0
Gets the value for a given key
TemplateImmutableStruct::~TemplateImmutableStruct
virtual ~TemplateImmutableStruct()
Destroys the struct
Definition: template.cpp:476
TemplateKeyValue
A container to store a key-value pair
Definition: template.cpp:630
TemplateContextImpl::copyEscapeIntfMap
void copyEscapeIntfMap(const EscapeIntfMap &map)
Definition: template.cpp:647
autoRefFor
static TemplateNodeFactory::AutoRegister< TemplateNodeFor > autoRefFor("for")
FilterTexLabel::apply
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &)
Definition: template.cpp:890
ExpressionParser::parseMultiplicativeExpression
ExprAstPtr parseMultiplicativeExpression()
Definition: template.cpp:2162
TemplateNodeExtend
Class representing a 'extend' tag in a template
Definition: template.cpp:3677
TemplateBlockContext::NodeBlockList
std::deque< TemplateNodeBlock * > NodeBlockList
Definition: template.cpp:624
TemplateNodeSet::~TemplateNodeSet
~TemplateNodeSet()
Definition: template.cpp:4345
TemplateList::createIterator
virtual TemplateListIntf::ConstIteratorPtr createIterator() const
Creates a new iterator for this list.
Definition: template.cpp:285
QCString::mid
QCString mid(size_t index, size_t len=static_cast< size_t >(-1)) const
Definition: qcstring.h:224
autoRefCreate
static TemplateNodeFactory::AutoRegister< TemplateNodeCreate > autoRefCreate("create")
substitute
QCString substitute(const QCString &s, const QCString &src, const QCString &dst)
substitute all occurrences of src in s by dst
Definition: qcstring.cpp:465
TemplateListIntfPtr
std::shared_ptr< TemplateListIntf > TemplateListIntfPtr
Definition: template.h:32
FilterAlphaIndex::ListElem
Definition: template.cpp:1284
TemplateNode
Base class of all nodes in a template's AST
Definition: template.cpp:1933
TemplateEngine::Private::IncludeEntry::m_type
Type m_type
Definition: template.cpp:5240
ExpressionParser::parseFilter
ExprAstFilterPtr parseFilter()
Definition: template.cpp:2326
TemplateStructIntf
Abstract interface for a context value of type struct.
Definition: template.h:337
TemplateNodeTree::renderChildren
QCString renderChildren(const TreeContext *ctx)
Definition: template.cpp:3961
removeSpacesAroundEquals
static void removeSpacesAroundEquals(QCString &s)
Strips spaces surrounding = from string in, so ‘foo = 10 bar=5 baz= 'hello’will becomefoo=10 bar=5 ba...
Definition: template.cpp:101
TemplateFilterFactory::m_registry
std::unordered_map< std::string, FilterFunction * > m_registry
Definition: template.cpp:1626
ExpressionParser::ExprToken::num
int num
Definition: template.cpp:2044
TemplateImpl::m_name
QCString m_name
Definition: template.cpp:2567
fNoWrap
static TemplateFilterFactory::AutoRegister< FilterNoWrap > fNoWrap("nowrap")
FilterDivisibleBy::apply
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &n)
Definition: template.cpp:1430
QCString::append
QCString & append(char c)
Definition: qcstring.h:318
TemplateEngine::Private::m_templateDirName
QCString m_templateDirName
Definition: template.cpp:5365
TemplateNodeIf::GuardedNodes::trueNodes
TemplateNodeList trueNodes
Definition: template.cpp:3188
TemplateLexer::tokenize
void tokenize(TemplateTokenStream &tokens)
Definition: template.cpp:4831
TemplateImmutableList::alloc
static TemplateListIntfPtr alloc(std::initializer_list< TemplateVariant > elements)
Creates an instance and returns a shared pointer to it
Definition: template.cpp:543
TemplateLexer::TemplateLexer
TemplateLexer(const TemplateEngine *engine, const QCString &fileName, const QCString &data)
Definition: template.cpp:4824
TemplateNodeIndexEntry::Mapping
Definition: template.cpp:4043
TemplateBlockContext::get
TemplateNodeBlock * get(const QCString &name) const
Definition: template.cpp:4737
TemplateContextImpl::addIndexEntry
void addIndexEntry(const QCString &indexName, const std::vector< TemplateKeyValue > &arguments)
Definition: template.cpp:2853
ExpressionParser::ExprToken::Identifier
@ Identifier
Definition: template.cpp:2040
TemplateVariant::toString
QCString toString() const
Returns the variant as a string.
Definition: template.cpp:399
TemplateContextImpl::m_indices
TemplateStructPtr m_indices
Definition: template.cpp:721
TemplateNodeTree::m_treeExpr
ExprAstPtr m_treeExpr
Definition: template.cpp:4034
reg::Ex
Class representing a regular expression.
Definition: regex.h:48
TemplateParser::m_engine
const TemplateEngine * m_engine
Definition: template.cpp:2001
TemplateImpl::~TemplateImpl
~TemplateImpl()
Definition: template.cpp:5195
msg
void msg(const char *fmt,...)
Definition: message.cpp:53
TemplateEngine::Private::outputExtension
QCString outputExtension() const
Definition: template.cpp:5349
TemplateNodeVariable::TemplateNodeVariable
TemplateNodeVariable(TemplateParser *parser, TemplateNode *parent, int line, const QCString &var)
Definition: template.cpp:2974
TemplateVariant::Type::Bool
@ Bool
ExpressionParser::m_tokenStream
const char * m_tokenStream
Definition: template.cpp:2548
hex
static const char * hex
Definition: htmldocvisitor.cpp:65
TemplateNodeCreate::m_templateExpr
ExprAstPtr m_templateExpr
Definition: template.cpp:3928
TemplateVariant::Type::Function
@ Function
fList
static TemplateFilterFactory::AutoRegister< FilterList > fList("list")
ExprAstLiteral::literal
const QCString & literal() const
Definition: template.cpp:1784
ExprAstNegate::ExprAstNegate
ExprAstNegate(ExprAstPtr &&expr)
Definition: template.cpp:1794
TemplateContextImpl::m_engine
const TemplateEngine * m_engine
Definition: template.cpp:710
QCString::endsWith
bool endsWith(const char *s) const
Definition: qcstring.h:420
TemplateEngine::Private::setTemplateDir
void setTemplateDir(const QCString &dirName)
Definition: template.cpp:5354
FilterDecodeURL::apply
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &)
Definition: template.cpp:1565
TemplateList::m_elems
TemplateVariantList m_elems
Definition: template.cpp:322
FileInfo
Minimal replacement for QFileInfo.
Definition: fileinfo.h:22
fPaginate
static TemplateFilterFactory::AutoRegister< FilterPaginate > fPaginate("paginate")
TemplateVariant::isValid
constexpr bool isValid() const
Returns TRUE if the variant holds a valid value, or FALSE otherwise
Definition: template.h:203
autoRefSpaceless
static TemplateNodeFactory::AutoRegister< TemplateNodeSpaceless > autoRefSpaceless("spaceless")
TemplateContextImpl::set
void set(const QCString &name, const TemplateVariant &v)
Sets a value in the current scope.
Definition: template.cpp:2632
qPrint
const char * qPrint(const char *s)
Definition: qcstring.h:589
TemplateNodeCreator::TemplateNodeCreator
TemplateNodeCreator(TemplateParser *parser, TemplateNode *parent, int line)
Definition: template.cpp:3042
ExprAst::resolve
virtual TemplateVariant resolve(TemplateContext *)
Definition: template.cpp:1667
TemplateContextImpl::spacelessInfo
const std::unique_ptr< TemplateSpacelessIntf > & spacelessInfo() const
Definition: template.cpp:688
Dir::setPath
void setPath(const std::string &path)
Definition: dir.cpp:171
ExprAstBinary::resolve
virtual TemplateVariant resolve(TemplateContext *c)
Definition: template.cpp:1830
ExpressionParser::parseOrExpression
ExprAstPtr parseOrExpression()
Definition: template.cpp:2057
ExprAstBinary::m_operator
Operator::Type m_operator
Definition: template.cpp:1925
TemplateImmutableList::~TemplateImmutableList
virtual ~TemplateImmutableList()
Destroys the list
Definition: template.cpp:524
TemplateToken::Block
@ Block
Definition: template.cpp:1955
FilterAdd::variantIntValue
static int variantIntValue(const TemplateVariant &v, bool &isInt)
Definition: template.cpp:733
TemplateVariant::typeAsString
const char * typeAsString() const
Returns a string representation of this variant's type
Definition: template.cpp:416
TemplateNodeFor::m_expr
ExprAstPtr m_expr
Definition: template.cpp:3553
TemplateVariant::setRaw
void setRaw(bool b)
Sets whether or not the value of the Variant should be escaped or written as-is (raw).
Definition: template.h:240
TemplateNodeRepeat::m_expr
ExprAstPtr m_expr
Definition: template.cpp:3240
Operator::Colon
@ Colon
Definition: template.cpp:574
ExprAstNegate::m_expr
ExprAstPtr m_expr
Definition: template.cpp:1799
TemplateVariant::toBool
bool toBool() const
Returns the variant as a boolean.
Definition: template.cpp:367
TemplateEscapeIntf
Interface used to escape characters in a string
Definition: template.h:384
TemplateBlockContext::pop
TemplateNodeBlock * pop(const QCString &name)
Definition: template.cpp:4750
TemplateEngine
Engine to create templates and template contexts.
Definition: template.h:492
TemplateNodeIf::TemplateNodeIf
TemplateNodeIf(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:3105
FilterEscape::apply
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &)
Definition: template.cpp:1544
TemplateContextImpl::pop
void pop()
Pop the current scope from the stack.
Definition: template.cpp:2755
TemplateListGenericConstIterator::m_index
size_t m_index
Definition: template.cpp:267
ASSERT
#define ASSERT(x)
Definition: qcstring.h:44
ExprAstBinary::ExprAstBinary
ExprAstBinary(Operator::Type op, ExprAstPtr &&lhs, ExprAstPtr &&rhs)
Definition: template.cpp:1827
TemplateNodeFactory::instance
static TemplateNodeFactory & instance()
Definition: template.cpp:4671
FilterListSort::ListElem::value
TemplateVariant value
Definition: template.cpp:1071
QCString::data
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string
Definition: qcstring.h:153
TemplateParser::TemplateParser
TemplateParser(const TemplateEngine *engine, const QCString &templateName, TemplateTokenStream &tokens)
Definition: template.cpp:5050
TemplateNode::m_parent
TemplateNode * m_parent
Definition: template.cpp:1944
TemplateEngine::enterBlock
void enterBlock(const QCString &fileName, const QCString &blockName, int line)
Definition: template.cpp:5391
TemplateParser::takeNextToken
TemplateTokenPtr takeNextToken()
Definition: template.cpp:5140
TemplateStruct::TemplateStruct
TemplateStruct()=default
Creates a struct
TemplateImpl::TemplateImpl
TemplateImpl(TemplateEngine *e, const QCString &name, const QCString &data, const QCString &extension)
Definition: template.cpp:5177
TemplateList::at
virtual TemplateVariant at(uint index) const
Returns the element at index position index.
Definition: template.cpp:281
TemplateEngine::Private::enterBlock
void enterBlock(const QCString &fileName, const QCString &blockName, int line)
Definition: template.cpp:5305
TemplateImmutableList::Private::Private
Private(const TemplateVariantList &e)
Definition: template.cpp:509
FilterGet::apply
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &arg)
Definition: template.cpp:772
Dir::exists
bool exists() const
Definition: dir.cpp:199
TemplateVariant::toInt
int toInt() const
Returns the variant as an integer.
Definition: template.cpp:383
TemplateNodeFactory::m_registry
std::unordered_map< std::string, CreateFunc > m_registry
Definition: template.cpp:4705
TemplateNodeSpaceless::TemplateNodeSpaceless
TemplateNodeSpaceless(TemplateParser *parser, TemplateNode *parent, int line, const QCString &)
Definition: template.cpp:4369
fTexLabel
static TemplateFilterFactory::AutoRegister< FilterTexLabel > fTexLabel("texLabel")
autoRefRepeat
static TemplateNodeFactory::AutoRegister< TemplateNodeRepeat > autoRefRepeat("repeat")
TemplateContext::push
virtual void push()=0
Push a new scope on the stack.
fRaw
static TemplateFilterFactory::AutoRegister< FilterRaw > fRaw("raw")
Operator
Class representing operators that can appear in template expressions
Definition: template.cpp:556
TemplateBlockContext::clear
void clear()
Definition: template.cpp:4786
fDecodeURL
static TemplateFilterFactory::AutoRegister< FilterDecodeURL > fDecodeURL("decodeURL")
ExprAstFilterAppl::m_filter
ExprAstFilterPtr m_filter
Definition: template.cpp:1775
TemplateNodeCycle::TemplateNodeCycle
TemplateNodeCycle(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:4251
TemplateStruct::~TemplateStruct
virtual ~TemplateStruct()=default
Destroys the struct
ExpressionParser::ExprToken::ExprToken
ExprToken()
Definition: template.cpp:2035
TemplateContextImpl
Internal class representing the implementation of a template context
Definition: template.cpp:640
TemplateNodeBlock::name
QCString name() const
Definition: template.cpp:3664
TemplateNodeSpaceless
Class representing an 'spaceless' tag in a template
Definition: template.cpp:4366
Operator::Multiply
@ Multiply
Definition: template.cpp:574
TemplateNodeMarkers::m_var
QCString m_var
Definition: template.cpp:4501
TemplateListGenericConstIterator::toLast
virtual void toLast()
Moves iterator to the last element in the list
Definition: template.cpp:239
autoRefMarkers
static TemplateNodeFactory::AutoRegister< TemplateNodeMarkers > autoRefMarkers("markers")
TemplateToken::Type
Type
Definition: template.cpp:1955
TemplateVariant::operator=
TemplateVariant & operator=(const TemplateVariant &v)=default
Assigns the value of the variant v to this variant.
TemplateNodeIndexEntry::Mapping::Mapping
Mapping(const QCString &n, std::unique_ptr< ExprAst > &&e)
Definition: template.cpp:4045
TemplateEngine::setTemplateDir
void setTemplateDir(const QCString &dirName)
Sets the search directory where to look for template files
Definition: template.cpp:5416
TemplateContextImpl::m_spacelessIntf
std::unique_ptr< TemplateSpacelessIntf > m_spacelessIntf
Definition: template.cpp:718
TemplateEngine::unload
void unload(Template *t)
Indicates that template t is no longer needed.
Definition: template.cpp:5386
FilterFlatten::flatten
static void flatten(const TemplateListIntfPtr tree, TemplateListPtr list)
Definition: template.cpp:1034
fDefault
static TemplateFilterFactory::AutoRegister< FilterDefault > fDefault("default")
FilterStripPath
The implementation of the "default" filter
Definition: template.cpp:1383
TemplateContextImpl::m_outputDir
QCString m_outputDir
Definition: template.cpp:713
ExprAstUnary::resolve
virtual TemplateVariant resolve(TemplateContext *c)
Definition: template.cpp:1807
portable.h
Portable versions of functions that are platform dependent.
ExpressionParser::parseFilteredVariable
ExprAstPtr parseFilteredVariable()
Definition: template.cpp:2307
convertUTF8ToUpper
std::string convertUTF8ToUpper(const std::string &input)
Converts the input string into a upper case version, also taking into account non-ASCII characters th...
Definition: utf8.cpp:192
TemplateNodeCreator::m_line
int m_line
Definition: template.cpp:3096
TemplateContextImpl::blockContext
TemplateBlockContext * blockContext()
Definition: template.cpp:2768
fGroupBy
static TemplateFilterFactory::AutoRegister< FilterGroupBy > fGroupBy("groupBy")
portable_iconv_close
int portable_iconv_close(void *cd)
Operator::Plus
@ Plus
Definition: template.cpp:574
ExprAstList
std::vector< ExprAstPtr > ExprAstList
Definition: template.cpp:1671
TemplateNodeCycle::render
void render(TextStream &ts, TemplateContext *c)
Definition: template.cpp:4274
TemplateContextImpl::m_contextStack
std::deque< std::unordered_map< std::string, TemplateVariant > > m_contextStack
Definition: template.cpp:714
FilterGet
The implementation of the "get" filter
Definition: template.cpp:769
TemplateImmutableStruct::Private::Private
Private(std::initializer_list< StructField > fs)
Definition: template.cpp:466
TemplateNodeFactory::CreateFunc
TemplateNodePtr(* CreateFunc)(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:4666
TemplateContext::getRef
virtual const TemplateVariant * getRef(const QCString &name) const =0
Returns a pointer to the value corresponding to a given key.
TemplateContextImpl::selectEscapeIntf
void selectEscapeIntf(const QCString &ext)
Definition: template.cpp:669
dir.h
TemplateNodeRepeat::m_repeatNodes
TemplateNodeList m_repeatNodes
Definition: template.cpp:3239
ExpressionParser::ExprToken::Unknown
@ Unknown
Definition: template.cpp:2040
TemplateList
Default implementation of a context value of type list.
Definition: template.cpp:273
TemplateBlockContext::m_blocks
std::map< std::string, NodeBlockList > m_blocks
Definition: template.cpp:626
TemplateImpl::m_nodes
TemplateNodeList m_nodes
Definition: template.cpp:2568
TemplateNodeEncoding::m_nodes
TemplateNodeList m_nodes
Definition: template.cpp:4657
Dir::mkdir
bool mkdir(const std::string &path, bool acceptsAbsPath=true) const
Definition: dir.cpp:237
util.h
A bunch of utility functions.
ExprAstNumber::resolve
virtual TemplateVariant resolve(TemplateContext *)
Definition: template.cpp:1680
ExprAstFilterAppl::ExprAstFilterAppl
ExprAstFilterAppl(ExprAstPtr &&expr, ExprAstFilterPtr &&filter)
Definition: template.cpp:1766
TemplateContextImpl::escapeIntf
const TemplateEscapeIntf * escapeIntf() const
Definition: template.cpp:676
TemplateNodeFactory
Factory class for creating tag AST nodes found in a template
Definition: template.cpp:4663
FilterPrepend
The implementation of the "prepend" filter
Definition: template.cpp:945
ExprAstFilter::m_arg
ExprAstPtr m_arg
Definition: template.cpp:1757
TemplateToken::Variable
@ Variable
Definition: template.cpp:1955
Operator::And
@ And
Definition: template.cpp:573
TemplateNodeTabbing::TemplateNodeTabbing
TemplateNodeTabbing(TemplateParser *parser, TemplateNode *parent, int line, const QCString &)
Definition: template.cpp:4512
TemplateNodeWith::Mapping::value
ExprAstPtr value
Definition: template.cpp:4188
TemplateEngine::Private::~Private
~Private()
Definition: template.cpp:5250
TemplateNodeFactory::create
TemplateNodePtr create(const QCString &name, TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:4678
FilterFlatten::apply
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &)
Definition: template.cpp:1018
TemplateNodeExtend::render
void render(TextStream &ts, TemplateContext *c)
Definition: template.cpp:3695
latexEscapeIndexChars
QCString latexEscapeIndexChars(const QCString &s)
Definition: util.cpp:5129
fTexIndex
static TemplateFilterFactory::AutoRegister< FilterTexIndex > fTexIndex("texIndex")
TemplateVariant::Type::None
@ None
TemplateEngine::Private::IncludeEntry::m_blockName
QCString m_blockName
Definition: template.cpp:5242
TemplateContextImpl::spacelessEnabled
bool spacelessEnabled() const
Definition: template.cpp:692
FilterAppend
The implementation of the "append" filter
Definition: template.cpp:925
TemplateToken::type
Type type
Definition: template.cpp:1957
ExprAstFilter::name
const QCString & name() const
Definition: template.cpp:1739
TemplateContextImpl::templateName
QCString templateName() const
Definition: template.cpp:684
TemplateNodeCreate::m_fileExpr
ExprAstPtr m_fileExpr
Definition: template.cpp:3929
TemplateNodeTabbing::render
void render(TextStream &ts, TemplateContext *c)
Definition: template.cpp:4521
TemplateNodeSet::Mapping::Mapping
Mapping(const QCString &n, ExprAstPtr &&e)
Definition: template.cpp:4326
TemplateVariant::toList
TemplateListIntfPtr toList()
Returns the pointer to list referenced by this variant or 0 if this variant does not have list type.
Definition: template.cpp:432
TemplateContext::pop
virtual void pop()=0
Pop the current scope from the stack.
ExpressionParser::parseLiteral
ExprAstPtr parseLiteral()
Definition: template.cpp:2273
TemplateEngine::leaveBlock
void leaveBlock()
Definition: template.cpp:5396
FilterGroupBy::apply
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &args)
Definition: template.cpp:1157
TemplateListGenericConstIterator
Definition: template.cpp:230
autoRefOpenSubIndex
static TemplateNodeFactory::AutoRegister< TemplateNodeOpenSubIndex > autoRefOpenSubIndex("opensubindex")
TemplateLexer::m_data
QCString m_data
Definition: template.cpp:4819
autoRefMsg
static TemplateNodeFactory::AutoRegister< TemplateNodeMsg > autoRefMsg("msg")
QCString::right
QCString right(size_t len) const
Definition: qcstring.h:217
TemplateNodeWith::~TemplateNodeWith
~TemplateNodeWith()
Definition: template.cpp:4223
QCString::prepend
QCString & prepend(const char *s)
Definition: qcstring.h:339
TemplateImmutableStruct::fields
virtual StringVector fields() const
Return the list of fields.
Definition: template.cpp:486
QCString::resize
bool resize(size_t newlen)
Resizes the string to hold newlen characters (this value should also count the 0-terminator).
Definition: qcstring.h:164
TemplateContextImpl::m_encoding
QCString m_encoding
Definition: template.cpp:723
Operator::Filter
@ Filter
Definition: template.cpp:574
TemplateVariant::isString
constexpr bool isString() const
Returns TRUE if the variant holds a string value
Definition: template.h:209
QCString::sprintf
QCString & sprintf(const char *format,...)
Definition: qcstring.cpp:24
ExprAstBinary
Class representing a binary operator in the AST
Definition: template.cpp:1824
convertToHtml
QCString convertToHtml(const QCString &s, bool keepEntities)
Definition: util.cpp:4063
Operator::Less
@ Less
Definition: template.cpp:573
TemplateNodeSet::Mapping::name
QCString name
Definition: template.cpp:4327
TemplateNodeMarkers
Class representing an 'markers' tag in a template
Definition: template.cpp:4395
TemplateNodePtr
std::unique_ptr< TemplateNode > TemplateNodePtr
Definition: template.cpp:1947
ExprAstNumber::m_number
int m_number
Definition: template.cpp:1682
TemplateKeyValue::value
TemplateVariant value
Definition: template.cpp:635
TemplateVariant::m_variant
VariantT m_variant
Definition: template.h:257
fKeep
static TemplateFilterFactory::AutoRegister< FilterKeep > fKeep("keep")
TemplateImpl::render
void render(TextStream &ts, TemplateContext *c)
Definition: template.cpp:5200
TemplateVariant::type
constexpr Type type() const
Returns the type held by this variant
Definition: template.h:248
fRelative
static TemplateFilterFactory::AutoRegister< FilterRelative > fRelative("relative")
autoRefEncoding
static TemplateNodeFactory::AutoRegister< TemplateNodeEncoding > autoRefEncoding("encoding")
FALSE
#define FALSE
Definition: qcstring.h:33
TemplateNodeTree::TreeContext
Definition: template.cpp:3937
TemplateEngine::Private::IncludeEntry::Template
@ Template
Definition: template.cpp:5231
FilterGroupBy::ListElem
Definition: template.cpp:1150
TemplateStructPtr
std::shared_ptr< TemplateStruct > TemplateStructPtr
Definition: template.cpp:147
TemplateStruct::alloc
static TemplateStructPtr alloc()
Creates an instance and returns a shared pointer to it
Definition: template.cpp:218
FilterGroupBy::determineSortKey
static QCString determineSortKey(const TemplateStructIntfPtr s, const QCString &attribName)
Definition: template.cpp:1210
FilterList::apply
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &)
Definition: template.cpp:865
autoRefBlock
static TemplateNodeFactory::AutoRegister< TemplateNodeBlock > autoRefBlock("block")
TemplateNodeSet::Mapping
Definition: template.cpp:4324
QCString
This is an alternative implementation of QCString.
Definition: qcstring.h:108
Operator::Greater
@ Greater
Definition: template.cpp:573
TemplateNodeBlock::m_blockName
QCString m_blockName
Definition: template.cpp:3670
ExprAstVariable::resolve
virtual TemplateVariant resolve(TemplateContext *c)
Definition: template.cpp:1692
ExprAstLiteral
Class representing a string literal in the AST
Definition: template.cpp:1779