template.cpp
Go to the documentation of this file.
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 <stdio.h>
19 #include <stdarg.h>
20 
21 #include <qlist.h>
22 #include <qarray.h>
23 #include <qdict.h>
24 #include <qstrlist.h>
25 #include <qvaluelist.h>
26 #include <qstack.h>
27 #include <qfile.h>
28 #include <qregexp.h>
29 #include <qcstring.h>
30 #include <qdir.h>
31 
32 #include "sortdict.h"
33 #include "ftextstream.h"
34 #include "message.h"
35 #include "util.h"
36 #include "resourcemgr.h"
37 
38 #define ENABLE_TRACING 0
39 
40 #if ENABLE_TRACING
41 #define TRACE(x) printf x
42 #else
43 #define TRACE(x)
44 #endif
45 
46 class TemplateToken;
47 
48 //-------------------------------------------------------------------
49 
50 static QValueList<QCString> split(const QCString &str,const QCString &sep,
51  bool allowEmptyEntries=FALSE,bool cleanup=TRUE)
52 {
54 
55  int j = 0;
56  int i = str.find( sep, j );
57 
58  while (i!=-1)
59  {
60  if ( str.mid(j,i-j).length() > 0 )
61  {
62  if (cleanup)
63  {
64  lst.append(str.mid(j,i-j).stripWhiteSpace());
65  }
66  else
67  {
68  lst.append(str.mid(j,i-j));
69  }
70  }
71  else if (allowEmptyEntries)
72  {
73  lst.append("");
74  }
75  j = i + sep.length();
76  i = str.find(sep,j);
77  }
78 
79  int l = str.length() - 1;
80  if (str.mid(j,l-j+1).length()>0)
81  {
82  if (cleanup)
83  {
84  lst.append(str.mid(j,l-j+1).stripWhiteSpace());
85  }
86  else
87  {
88  lst.append(str.mid(j,l-j+1));
89  }
90  }
91  else if (allowEmptyEntries)
92  {
93  lst.append("");
94  }
95 
96  return lst;
97 }
98 
99 //----------------------------------------------------------------------------
100 
101 /** Strips spaces surrounding `=` from string \a in, so
102  * `foo = 10 bar=5 baz= 'hello'` will become `foo=10 bar=5 baz='hello'`
103  */
105 {
106  QCString result(s);
107  const char *p=result.data();
108  char *q = result.rawData();
109  char c;
110  while ((c=*p++))
111  {
112  if (c==' ') // found a space, see if there is a = as well
113  {
114  const char *t = p;
115  bool found=FALSE;
116  while (*t==' ' || *t=='=') { if (*t++=='=') found=TRUE; }
117  if (found)
118  {
119  c='=';
120  p=t; // move p to end of '\s*=\s*' sequence
121  }
122  }
123  *q++=c;
124  }
125  if (q<p) result.resize(q-result.data()+1);
126  return result;
127 }
128 
129 //----------------------------------------------------------------------------
130 
131 #if ENABLE_TRACING
132 static QCString replace(const char *s,char csrc,char cdst)
133 {
134  QCString result = s;
135  for (char *p=result.data();*p;p++)
136  {
137  if (*p==csrc) *p=cdst;
138  }
139  return result;
140 }
141 #endif
142 
143 //- TemplateVariant implementation -------------------------------------------
144 
145 
147  : m_type(Struct), m_strukt(s), m_raw(FALSE)
148 {
149  m_strukt->addRef();
150 }
151 
153  : m_type(List), m_list(l), m_raw(FALSE)
154 {
155  m_list->addRef();
156 }
157 
159 {
160  if (m_type==Struct) m_strukt->release();
161  else if (m_type==List) m_list->release();
162 }
163 
165  : m_type(v.m_type), m_strukt(0), m_raw(FALSE)
166 {
167  m_raw = v.m_raw;
168  switch (m_type)
169  {
170  case None: break;
171  case Bool: m_boolVal = v.m_boolVal; break;
172  case Integer: m_intVal = v.m_intVal; break;
173  case String: m_strVal = v.m_strVal; break;
174  case Struct: m_strukt = v.m_strukt; m_strukt->addRef(); break;
175  case List: m_list = v.m_list; m_list->addRef(); break;
176  case Function: m_delegate= v.m_delegate;break;
177  }
178 }
179 
181 {
182  // assignment can change the type of the variable, so we have to be
183  // careful with reference counted content.
184  TemplateStructIntf *tmpStruct = m_type==Struct ? m_strukt : 0;
185  TemplateListIntf *tmpList = m_type==List ? m_list : 0;
186  Type tmpType = m_type;
187 
188  m_type = v.m_type;
189  m_raw = v.m_raw;
190  switch (m_type)
191  {
192  case None: break;
193  case Bool: m_boolVal = v.m_boolVal; break;
194  case Integer: m_intVal = v.m_intVal; break;
195  case String: m_strVal = v.m_strVal; break;
196  case Struct: m_strukt = v.m_strukt; m_strukt->addRef(); break;
197  case List: m_list = v.m_list; m_list->addRef(); break;
198  case Function: m_delegate= v.m_delegate;break;
199  }
200 
201  // release overwritten reference counted values
202  if (tmpType==Struct && tmpStruct) tmpStruct->release();
203  else if (tmpType==List && tmpList ) tmpList->release();
204  return *this;
205 }
206 
208 {
209  switch (m_type)
210  {
211  case None: return FALSE;
212  case Bool: return m_boolVal;
213  case Integer: return m_intVal!=0;
214  case String: return !m_strVal.isEmpty();
215  case Struct: return TRUE;
216  case List: return m_list->count()!=0;
217  case Function: return FALSE;
218  }
219  return FALSE;
220 }
221 
223 {
224  switch (m_type)
225  {
226  case None: return 0;
227  case Bool: return m_boolVal ? 1 : 0;
228  case Integer: return m_intVal;
229  case String: return m_strVal.toInt();
230  case Struct: return 0;
231  case List: return m_list->count();
232  case Function: return 0;
233  }
234  return 0;
235 }
236 
237 //- Template struct implementation --------------------------------------------
238 
239 
240 /** @brief Private data of a template struct object */
242 {
243  public:
244  Private() : fields(17), refCount(0)
245  { fields.setAutoDelete(TRUE); }
246  QDict<TemplateVariant> fields;
247  int refCount;
248 };
249 
251 {
252  p = new Private;
253 }
254 
256 {
257  delete p;
258 }
259 
261 {
262  return ++p->refCount;
263 }
264 
266 {
267  int count = --p->refCount;
268  if (count<=0)
269  {
270  delete this;
271  }
272  return count;
273 }
274 
275 void TemplateStruct::set(const char *name,const TemplateVariant &v)
276 {
277  TemplateVariant *pv = p->fields.find(name);
278  if (pv) // change existing field
279  {
280  *pv = v;
281  }
282  else // insert new field
283  {
284  p->fields.insert(name,new TemplateVariant(v));
285  }
286 }
287 
289 {
290  TemplateVariant *v = p->fields.find(name);
291  return v ? *v : TemplateVariant();
292 }
293 
295 {
296  return new TemplateStruct;
297 }
298 
299 //- Template list implementation ----------------------------------------------
300 
301 
302 /** @brief Private data of a template list object */
304 {
305  public:
306  Private() : index(-1), refCount(0) {}
308  int index;
309  int refCount;
310 };
311 
312 
314 {
315  p = new Private;
316 }
317 
319 {
320  delete p;
321 }
322 
324 {
325  return ++p->refCount;
326 }
327 
329 {
330  int count = --p->refCount;
331  if (count<=0)
332  {
333  delete this;
334  }
335  return count;
336 }
337 
339 {
340  return p->elems.count();
341 }
342 
344 {
345  p->elems.append(v);
346 }
347 
348 // iterator support
350 {
351  public:
352  TemplateListConstIterator(const TemplateList &l) : m_list(l) { m_index=-1; }
354  virtual void toFirst()
355  {
356  m_it = m_list.p->elems.begin();
357  m_index=0;
358  }
359  virtual void toLast()
360  {
361  m_it = m_list.p->elems.fromLast();
362  m_index=m_list.count()-1;
363  }
364  virtual void toNext()
365  {
366  if (m_it!=m_list.p->elems.end())
367  {
368  ++m_it;
369  ++m_index;
370  }
371  }
372  virtual void toPrev()
373  {
374  if (m_index>0)
375  {
376  --m_it;
377  --m_index;
378  }
379  else
380  {
381  m_index=-1;
382  }
383  }
384  virtual bool current(TemplateVariant &v) const
385  {
386  if (m_index<0 || m_it==m_list.p->elems.end())
387  {
388  v = TemplateVariant();
389  return FALSE;
390  }
391  else
392  {
393  v = *m_it;
394  return TRUE;
395  }
396  }
397  private:
400  int m_index;
401 };
402 
404 {
405  return new TemplateListConstIterator(*this);
406 }
407 
409 {
410  if (index>=0 && index<(int)p->elems.count())
411  {
412  return p->elems[index];
413  }
414  else
415  {
416  return TemplateVariant();
417  }
418 }
419 
421 {
422  return new TemplateList;
423 }
424 
425 //- Operator types ------------------------------------------------------------
426 
427 /** @brief Class representing operators that can appear in template expressions */
428 class Operator
429 {
430  public:
431  /* Operator precedence (low to high)
432  or
433  and
434  not
435  in
436  ==, !=, <, >, <=, >=
437  +, -
438  *, /, %
439  |
440  :
441  ,
442  */
443  enum Type
444  {
445  Or, And, Not, In, Equal, NotEqual, Less, Greater, LessEqual,
446  GreaterEqual, Plus, Minus, Multiply, Divide, Modulo, Filter, Colon, Comma,
447  LeftParen, RightParen,
448  Last
449  };
450 
451  static const char *toString(Type op)
452  {
453  switch(op)
454  {
455  case Or: return "or";
456  case And: return "and";
457  case Not: return "not";
458  case In: return "in";
459  case Equal: return "==";
460  case NotEqual: return "!=";
461  case Less: return "<";
462  case Greater: return ">";
463  case LessEqual: return "<=";
464  case GreaterEqual: return ">=";
465  case Plus: return "+";
466  case Minus: return "-";
467  case Multiply: return "*";
468  case Divide: return "/";
469  case Modulo: return "%";
470  case Filter: return "|";
471  case Colon: return ":";
472  case Comma: return ",";
473  case LeftParen: return "(";
474  case RightParen: return ")";
475  case Last: return "?";
476  }
477  return "?";
478  }
479 };
480 
481 //-----------------------------------------------------------------------------
482 
483 class TemplateNodeBlock;
484 
485 /** @brief Class holding stacks of blocks available in the context */
487 {
488  public:
490  TemplateNodeBlock *get(const QCString &name) const;
491  TemplateNodeBlock *pop(const QCString &name) const;
492  void add(TemplateNodeBlock *block);
493  void add(TemplateBlockContext *ctx);
494  void push(TemplateNodeBlock *block);
495  void clear();
496  private:
497  QDict< QList<TemplateNodeBlock> > m_blocks;
498 };
499 
500 /** @brief A container to store a key-value pair */
502 {
504  TemplateKeyValue(const QCString &k,const TemplateVariant &v) : key(k), value(v) {}
507 };
508 
509 /** @brief Internal class representing the implementation of a template
510  * context */
512 {
513  public:
515  virtual ~TemplateContextImpl();
516 
517  // TemplateContext methods
518  void push();
519  void pop();
520  void set(const char *name,const TemplateVariant &v);
521  TemplateVariant get(const QCString &name) const;
522  const TemplateVariant *getRef(const QCString &name) const;
524  { m_outputDir = dir; }
526  {
527  int i=(!ext.isEmpty() && ext.at(0)=='.') ? 1 : 0;
528  m_escapeIntfDict.insert(ext.mid(i),new TemplateEscapeIntf*(intf));
529  }
530  void selectEscapeIntf(const QCString &ext)
531  { TemplateEscapeIntf **ppIntf = m_escapeIntfDict.find(ext);
532  m_activeEscapeIntf = ppIntf ? *ppIntf : 0;
533  }
534  void setActiveEscapeIntf(TemplateEscapeIntf *intf) { m_activeEscapeIntf = intf; }
535  void setSpacelessIntf(TemplateSpacelessIntf *intf) { m_spacelessIntf = intf; }
536 
537  // internal methods
538  TemplateBlockContext *blockContext();
539  TemplateVariant getPrimary(const QCString &name) const;
540  void setLocation(const QCString &templateName,int line)
541  { m_templateName=templateName; m_line=line; }
542  QCString templateName() const { return m_templateName; }
543  int line() const { return m_line; }
544  QCString outputDirectory() const { return m_outputDir; }
545  TemplateEscapeIntf *escapeIntf() const { return m_activeEscapeIntf; }
546  TemplateSpacelessIntf *spacelessIntf() const { return m_spacelessIntf; }
547  void enableSpaceless(bool b) { if (b && !m_spacelessEnabled) m_spacelessIntf->reset();
548  m_spacelessEnabled=b;
549  }
550  bool spacelessEnabled() const { return m_spacelessEnabled && m_spacelessIntf; }
551  void enableTabbing(bool b) { m_tabbingEnabled=b;
552  if (m_activeEscapeIntf) m_activeEscapeIntf->enableTabbing(b);
553  }
554  bool tabbingEnabled() const { return m_tabbingEnabled; }
555  void warn(const char *fileName,int line,const char *fmt,...) const;
556 
557  // index related functions
558  void openSubIndex(const QCString &indexName);
559  void closeSubIndex(const QCString &indexName);
560  void addIndexEntry(const QCString &indexName,const QValueList<TemplateKeyValue> &arguments);
561 
562  private:
565  int m_line;
569  QDict<TemplateEscapeIntf*> m_escapeIntfDict;
575  QDict< QStack<TemplateVariant> > m_indexStacks;
576 };
577 
578 //-----------------------------------------------------------------------------
579 
580 /** @brief The implementation of the "add" filter */
582 {
583  public:
584  static int variantIntValue(const TemplateVariant &v,bool &isInt)
585  {
586  isInt = v.type()==TemplateVariant::Integer;
587  if (!isInt && v.type()==TemplateVariant::String)
588  {
589  return v.toString().toInt(&isInt);
590  }
591  return isInt ? v.toInt() : 0;
592  }
594  {
595  if (!v.isValid())
596  {
597  return arg;
598  }
599  bool lhsIsInt;
600  int lhsValue = variantIntValue(v,lhsIsInt);
601  bool rhsIsInt;
602  int rhsValue = variantIntValue(arg,rhsIsInt);
603  if (lhsIsInt && rhsIsInt)
604  {
605  return lhsValue+rhsValue;
606  }
608  {
609  return TemplateVariant(v.toString() + arg.toString());
610  }
611  else
612  {
613  return v;
614  }
615  }
616 };
617 
618 //-----------------------------------------------------------------------------
619 
620 /** @brief The implementation of the "get" filter */
622 {
623  public:
625  {
627  {
629  //printf("\nok[%s]=%d\n",arg.toString().data(),result.type());
630  return result;
631  }
632  else
633  {
634  //printf("\nnok[%s]\n",arg.toString().data());
635  return FALSE;
636  }
637  }
638 };
639 
640 //-----------------------------------------------------------------------------
641 
642 /** @brief The implementation of the "raw" filter */
644 {
645  public:
647  {
649  {
650  return TemplateVariant(v.toString(),TRUE);
651  }
652  else
653  {
654  return v;
655  }
656  }
657 };
658 
659 //-----------------------------------------------------------------------------
660 
661 /** @brief The implementation of the "list" filter */
663 {
664  public:
666  {
667  if (v.isValid())
668  {
669  if (v.type()==TemplateVariant::List) // input is already a list
670  {
671  return v;
672  }
673  // create a list with v as the only element
675  list->append(v);
676  return list;
677  }
678  else
679  {
680  return v;
681  }
682  }
683 };
684 
685 //-----------------------------------------------------------------------------
686 /** @brief The implementation of the "texlabel" filter */
688 {
689  public:
691  {
692  if (v.isValid() && (v.type()==TemplateVariant::String))
693  {
695  }
696  else
697  {
698  return v;
699  }
700  }
701 };
702 
703 //-----------------------------------------------------------------------------
704 
705 /** @brief The implementation of the "texindex" filter */
707 {
708  public:
710  {
711  if (v.isValid() && (v.type()==TemplateVariant::String))
712  {
714  }
715  else
716  {
717  return v;
718  }
719  }
720 };
721 
722 //-----------------------------------------------------------------------------
723 
724 /** @brief The implementation of the "append" filter */
726 {
727  public:
729  {
732  {
733  return TemplateVariant(v.toString() + arg.toString());
734  }
735  else
736  {
737  return v;
738  }
739  }
740 };
741 
742 //-----------------------------------------------------------------------------
743 
744 /** @brief The implementation of the "prepend" filter */
746 {
747  public:
749  {
752  {
753  return TemplateVariant(arg.toString() + v.toString());
754  }
755  else
756  {
757  return v;
758  }
759  }
760 };
761 
762 //--------------------------------------------------------------------
763 
764 /** @brief The implementation of the "length" filter */
766 {
767  public:
769  {
770  if (!v.isValid())
771  {
772  return TemplateVariant();
773  }
774  if (v.type()==TemplateVariant::List)
775  {
776  return TemplateVariant(v.toList()->count());
777  }
778  else if (v.type()==TemplateVariant::String)
779  {
780  return TemplateVariant((int)v.toString().length());
781  }
782  else
783  {
784  return TemplateVariant();
785  }
786  }
787 };
788 
789 //--------------------------------------------------------------------
790 
791 /** @brief The implementation of the "default" filter */
793 {
794  public:
796  {
797  if (!v.isValid())
798  {
799  return arg;
800  }
801  else if (v.type()==TemplateVariant::String && v.toString().isEmpty())
802  {
803  return arg;
804  }
805  else
806  {
807  return v;
808  }
809  }
810 };
811 
812 //--------------------------------------------------------------------
813 
814 /** @brief The implementation of the "flatten" filter */
816 {
817  public:
819  {
820  if (!v.isValid() || v.type()!=TemplateVariant::List)
821  {
822  return v;
823  }
824  else
825  {
827  flatten(v.toList(),list);
828  return TemplateVariant(list);
829  }
830  }
831 
832  private:
834  {
836  TemplateVariant item;
837  for (it->toFirst();(it->current(item));it->toNext())
838  {
839  TemplateStructIntf *s = item.toStruct();
840  if (s)
841  {
842  list->append(item);
843  // if s has "children" then recurse into the children
844  TemplateVariant children = s->get("children");
845  if (children.isValid() && children.type()==TemplateVariant::List)
846  {
847  flatten(children.toList(),list);
848  }
849  }
850  else
851  {
852  list->append(item);
853  }
854  }
855  delete it;
856  }
857 };
858 
859 //--------------------------------------------------------------------
860 
861 /** @brief The implementation of the "listsort" filter */
863 {
864  struct ListElem
865  {
866  ListElem(const QCString &k,const TemplateVariant &v) : key(k), value(v) {}
869  };
870  class SortList : public QList<ListElem>
871  {
872  public:
873  SortList() { setAutoDelete(TRUE); }
874  private:
875  int compareValues(const ListElem *item1,const ListElem *item2) const
876  {
877  return qstrcmp(item1->key,item2->key);
878  }
879  };
880  public:
882  {
884  {
885  //printf("FilterListSort::apply: v=%s args=%s\n",v.toString().data(),args.toString().data());
887 
888  TemplateVariant item;
890 
891  // create list of items based on v using the data in args as a sort key
892  SortList sortList;
893  for (it->toFirst();(it->current(item));it->toNext())
894  {
895  TemplateStructIntf *s = item.toStruct();
896  if (s)
897  {
898  QCString sortKey = determineSortKey(s,args.toString());
899  sortList.append(new ListElem(sortKey,item));
900  //printf("sortKey=%s\n",sortKey.data());
901  }
902  }
903  delete it;
904 
905  // sort the list
906  sortList.sort();
907 
908  // add sorted items to the result list
909  QListIterator<ListElem> sit(sortList);
910  ListElem *elem;
911  for (sit.toFirst();(elem=sit.current());++sit)
912  {
913  result->append(elem->value);
914  }
915  return result;
916  }
917  return v;
918  }
919 
920  private:
922  {
923  int i,p=0;
925  while ((i=arg.find("{{",p))!=-1)
926  {
927  result+=arg.mid(p,i-p);
928  int j=arg.find("}}",i+2);
929  if (j!=-1)
930  {
931  QCString var = arg.mid(i+2,j-i-2);
932  TemplateVariant val=s->get(var);
933  //printf("found argument %s value=%s\n",var.data(),val.toString().data());
934  result+=val.toString();
935  p=j+2;
936  }
937  else
938  {
939  p=i+1;
940  }
941  }
942  result+=arg.right(arg.length()-p);
943  return result;
944  }
945 };
946 
947 //--------------------------------------------------------------------
948 
949 /** @brief The implementation of the "groupBy" filter */
951 {
952  struct ListElem
953  {
954  ListElem(const QCString &k,const TemplateVariant &v) : key(k), value(v) {}
957  };
958  class SortList : public QList<ListElem>
959  {
960  public:
961  SortList() { setAutoDelete(TRUE); }
962  private:
963  int compareValues(const ListElem *item1,const ListElem *item2) const
964  {
965  return qstrcmp(item1->key,item2->key);
966  }
967  };
968  public:
970  {
972  {
973  //printf("FilterListSort::apply: v=%s args=%s\n",v.toString().data(),args.toString().data());
975 
976  TemplateVariant item;
978 
979  // create list of items based on v using the data in args as a sort key
980  SortList sortList;
981  for (it->toFirst();(it->current(item));it->toNext())
982  {
983  TemplateStructIntf *s = item.toStruct();
984  if (s)
985  {
986  QCString sortKey = determineSortKey(s,args.toString());
987  sortList.append(new ListElem(sortKey,item));
988  //printf("sortKey=%s\n",sortKey.data());
989  }
990  }
991  delete it;
992 
993  // sort the list
994  sortList.sort();
995 
996  // add sorted items to the result list
997  QListIterator<ListElem> sit(sortList);
998  ListElem *elem;
999  TemplateList *groupList=0;
1000  QCString prevKey;
1001  for (sit.toFirst();(elem=sit.current());++sit)
1002  {
1003  if (groupList==0 || elem->key!=prevKey)
1004  {
1005  groupList = TemplateList::alloc();
1006  result->append(groupList);
1007  prevKey = elem->key;
1008  }
1009  groupList->append(elem->value);
1010  }
1011  return result;
1012  }
1013  return v;
1014  }
1015 
1016  private:
1018  {
1019  TemplateVariant v = s->get(attribName);
1020  return v.toString();
1021  }
1022 };
1023 
1024 //--------------------------------------------------------------------
1025 
1026 /** @brief The implementation of the "relative" filter */
1028 {
1029  public:
1031  {
1032  if (v.isValid() && v.type()==TemplateVariant::String && v.toString().left(2)=="..")
1033  {
1034  return TRUE;
1035  }
1036  else
1037  {
1038  return FALSE;
1039  }
1040  }
1041 };
1042 
1043 //--------------------------------------------------------------------
1044 
1045 /** @brief The implementation of the "paginate" filter */
1047 {
1048  public:
1050  {
1051  if (v.isValid() && v.type()==TemplateVariant::List &&
1052  args.isValid() && args.type()==TemplateVariant::Integer)
1053  {
1054  int pageSize = args.toInt();
1055  TemplateListIntf *list = v.toList();
1058  TemplateVariant item;
1059  TemplateList *pageList=0;
1060  int i = 0;
1061  for (it->toFirst();(it->current(item));it->toNext())
1062  {
1063  if (pageList==0)
1064  {
1065  pageList = TemplateList::alloc();
1066  result->append(pageList);
1067  }
1068  pageList->append(item);
1069  i++;
1070  if (i==pageSize) // page is full start a new one
1071  {
1072  pageList=0;
1073  i=0;
1074  }
1075  }
1076  delete it;
1077  return result;
1078  }
1079  else // wrong arguments
1080  {
1081  return v;
1082  }
1083  }
1084 };
1085 
1086 //--------------------------------------------------------------------
1087 
1088 /** @brief The implementation of the "alphaIndex" filter */
1090 {
1091  private:
1092  struct ListElem
1093  {
1094  ListElem(uint k,const TemplateVariant &v) : key(k), value(v) {}
1097  };
1098  class SortList : public QList<ListElem>
1099  {
1100  public:
1101  SortList() { setAutoDelete(TRUE); }
1102  private:
1103  int compareValues(const ListElem *item1,const ListElem *item2) const
1104  {
1105  return item1->key-item2->key;
1106  }
1107  };
1108  static QCString keyToLetter(uint startLetter)
1109  {
1110  return QString(QChar(startLetter)).utf8();
1111  }
1112  static QCString keyToLabel(uint startLetter)
1113  {
1114  char s[11]; // 0x12345678 + '\0'
1115  if ((startLetter>='0' && startLetter<='9') ||
1116  (startLetter>='a' && startLetter<='z') ||
1117  (startLetter>='A' && startLetter<='Z'))
1118  {
1119  int i=0;
1120  if (startLetter>='0' && startLetter<='9') s[i++] = 'x';
1121  s[i++]=tolower((char)startLetter);
1122  s[i++]=0;
1123  }
1124  else
1125  {
1126  const char hex[]="0123456789abcdef";
1127  int i=0;
1128  s[i++]='x';
1129  if (startLetter>(1<<24)) // 4 byte character
1130  {
1131  s[i++]=hex[(startLetter>>28)&0xf];
1132  s[i++]=hex[(startLetter>>24)&0xf];
1133  }
1134  if (startLetter>(1<<16)) // 3 byte character
1135  {
1136  s[i++]=hex[(startLetter>>20)&0xf];
1137  s[i++]=hex[(startLetter>>16)&0xf];
1138  }
1139  if (startLetter>(1<<8)) // 2 byte character
1140  {
1141  s[i++]=hex[(startLetter>>12)&0xf];
1142  s[i++]=hex[(startLetter>>8)&0xf];
1143  }
1144  // one byte character
1145  s[i++]=hex[(startLetter>>4)&0xf];
1146  s[i++]=hex[(startLetter>>0)&0xf];
1147  s[i++]=0;
1148  }
1149  return s;
1150  }
1152  {
1153  TemplateVariant v = s->get(attribName);
1154  int index = getPrefixIndex(v.toString());
1155  return getUtf8CodeToUpper(v.toString(),index);
1156  }
1157 
1158  public:
1160  {
1162  {
1163  //printf("FilterListSort::apply: v=%s args=%s\n",v.toString().data(),args.toString().data());
1165 
1166  TemplateVariant item;
1168 
1169  // create list of items based on v using the data in args as a sort key
1170  SortList sortList;
1171  for (it->toFirst();(it->current(item));it->toNext())
1172  {
1173  TemplateStructIntf *s = item.toStruct();
1174  if (s)
1175  {
1176  uint sortKey = determineSortKey(s,args.toString());
1177  sortList.append(new ListElem(sortKey,item));
1178  //printf("sortKey=%s\n",sortKey.data());
1179  }
1180  }
1181  delete it;
1182 
1183  // sort the list
1184  sortList.sort();
1185 
1186  // create an index from the sorted list
1187  uint letter=0;
1188  QListIterator<ListElem> sit(sortList);
1189  ListElem *elem;
1190  TemplateStruct *indexNode = 0;
1191  TemplateList *indexList = 0;
1192  for (sit.toFirst();(elem=sit.current());++sit)
1193  {
1194  if (letter!=elem->key || indexNode==0)
1195  {
1196  // create new indexNode
1197  indexNode = TemplateStruct::alloc();
1198  indexList = TemplateList::alloc();
1199  indexNode->set("letter", keyToLetter(elem->key));
1200  indexNode->set("label", keyToLabel(elem->key));
1201  indexNode->set("items",indexList);
1202  result->append(indexNode);
1203  letter=elem->key;
1204  }
1205  indexList->append(elem->value);
1206  }
1207  return result;
1208  }
1209  return v;
1210  }
1211 };
1212 
1213 //--------------------------------------------------------------------
1214 
1215 /** @brief The implementation of the "default" filter */
1217 {
1218  public:
1220  {
1221  if (!v.isValid() || v.type()!=TemplateVariant::String)
1222  {
1223  return v;
1224  }
1225  QCString result = v.toString();
1226  int i=result.findRev('/');
1227  if (i!=-1)
1228  {
1229  result=result.mid(i+1);
1230  }
1231  i=result.findRev('\\');
1232  if (i!=-1)
1233  {
1234  result=result.mid(i+1);
1235  }
1236  return result;
1237  }
1238 };
1239 
1240 //--------------------------------------------------------------------
1241 
1242 /** @brief The implementation of the "default" filter */
1244 {
1245  public:
1247  {
1248  if (!v.isValid() || v.type()!=TemplateVariant::String)
1249  {
1250  return v;
1251  }
1252  QCString s = v.toString();
1253  return substitute(s," ","&#160;");
1254  }
1255 };
1256 
1257 //--------------------------------------------------------------------
1258 
1259 /** @brief The implementation of the "divisibleby" filter */
1261 {
1262  public:
1264  {
1265  if (!v.isValid() || !n.isValid())
1266  {
1267  return TemplateVariant();
1268  }
1270  {
1271  int ni = n.toInt();
1272  if (ni>0)
1273  {
1274  return TemplateVariant((v.toInt()%ni)==0);
1275  }
1276  else
1277  {
1278  return TemplateVariant(FALSE);
1279  }
1280  }
1281  else
1282  {
1283  return TemplateVariant();
1284  }
1285  }
1286 };
1287 
1288 
1289 //--------------------------------------------------------------------
1290 
1291 /** @brief Factory singleton for registering and creating filters */
1293 {
1294  public:
1295  typedef TemplateVariant (FilterFunction)(const TemplateVariant &v,const TemplateVariant &arg);
1296 
1298  {
1299  static TemplateFilterFactory *instance = 0;
1300  if (instance==0) instance = new TemplateFilterFactory;
1301  return instance;
1302  }
1303 
1304  TemplateVariant apply(const QCString &name,const TemplateVariant &v,const TemplateVariant &arg, bool &ok)
1305  {
1306  FilterFunction *func = (FilterFunction*)m_registry.find(name);
1307  if (func)
1308  {
1309  ok=TRUE;
1310  return (*func)(v,arg);
1311  }
1312  else
1313  {
1314  ok=FALSE;
1315  return v;
1316  }
1317  }
1318 
1319  void registerFilter(const QCString &name,FilterFunction *func)
1320  {
1321  m_registry.insert(name,(void*)func);
1322  }
1323 
1324  /** @brief Helper class for registering a filter function */
1325  template<class T> class AutoRegister
1326  {
1327  public:
1329  {
1331  }
1332  };
1333 
1334  private:
1335  QDict<void> m_registry;
1336 };
1337 
1338 // register a handlers for each filter we support
1358 
1359 //--------------------------------------------------------------------
1360 
1361 /** @brief Base class for all nodes in the abstract syntax tree of an
1362  * expression.
1363  */
1364 class ExprAst
1365 {
1366  public:
1367  virtual ~ExprAst() {}
1369 };
1370 
1371 /** @brief Class representing a number in the AST */
1372 class ExprAstNumber : public ExprAst
1373 {
1374  public:
1375  ExprAstNumber(int num) : m_number(num)
1376  { TRACE(("ExprAstNumber(%d)\n",num)); }
1377  int number() const { return m_number; }
1378  virtual TemplateVariant resolve(TemplateContext *) { return TemplateVariant(m_number); }
1379  private:
1381 };
1382 
1383 /** @brief Class representing a variable in the AST */
1384 class ExprAstVariable : public ExprAst
1385 {
1386  public:
1387  ExprAstVariable(const char *name) : m_name(name)
1388  { TRACE(("ExprAstVariable(%s)\n",name)); }
1389  const QCString &name() const { return m_name; }
1391  {
1392  TemplateVariant v = c->get(m_name);
1393  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
1394  if (!v.isValid())
1395  {
1396  if (ci) ci->warn(ci->templateName(),ci->line(),"undefined variable '%s' in expression",m_name.data());
1397  }
1398  return v;
1399  }
1400  private:
1402 };
1403 
1405 {
1406  public:
1408  : m_var(var), m_args(args)
1409  { TRACE(("ExprAstFunctionVariable()\n"));
1410  m_args.setAutoDelete(TRUE);
1411  }
1413  {
1414  delete m_var;
1415  }
1417  {
1419  for (uint i=0;i<m_args.count();i++)
1420  {
1421  TemplateVariant v = m_args.at(i)->resolve(c);
1422  args.append(v);
1423  }
1424  TemplateVariant v = m_var->resolve(c);
1426  {
1427  v = v.call(args);
1428  }
1429  return v;
1430  }
1431  private:
1434 };
1435 
1436 /** @brief Class representing a filter in the AST */
1437 class ExprAstFilter : public ExprAst
1438 {
1439  public:
1440  ExprAstFilter(const char *name,ExprAst *arg) : m_name(name), m_arg(arg)
1441  { TRACE(("ExprAstFilter(%s)\n",name)); }
1442  ~ExprAstFilter() { delete m_arg; }
1443  const QCString &name() const { return m_name; }
1445  {
1446  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
1447  if (ci==0) return v; // should not happen
1448  TRACE(("Applying filter '%s' to '%s' (type=%d)\n",m_name.data(),v.toString().data(),v.type()));
1449  TemplateVariant arg;
1450  if (m_arg) arg = m_arg->resolve(c);
1451  bool ok;
1453  if (!ok)
1454  {
1455  ci->warn(ci->templateName(),ci->line(),"unknown filter '%s'",m_name.data());
1456  }
1457  return result;
1458  }
1459  private:
1462 };
1463 
1464 /** @brief Class representing a filter applied to an expression in the AST */
1466 {
1467  public:
1469  : m_expr(expr), m_filter(filter)
1470  { TRACE(("ExprAstFilterAppl\n")); }
1471  ~ExprAstFilterAppl() { delete m_expr; delete m_filter; }
1473  {
1474  return m_filter->apply(m_expr->resolve(c),c);
1475  }
1476  private:
1479 };
1480 
1481 /** @brief Class representing a string literal in the AST */
1482 class ExprAstLiteral : public ExprAst
1483 {
1484  public:
1485  ExprAstLiteral(const char *lit) : m_literal(lit)
1486  { TRACE(("ExprAstLiteral(%s)\n",lit)); }
1487  const QCString &literal() const { return m_literal; }
1488  virtual TemplateVariant resolve(TemplateContext *) { return TemplateVariant(m_literal); }
1489  private:
1491 };
1492 
1493 /** @brief Class representing a negation (not) operator in the AST */
1494 class ExprAstNegate : public ExprAst
1495 {
1496  public:
1497  ExprAstNegate(ExprAst *expr) : m_expr(expr)
1498  { TRACE(("ExprAstNegate\n")); }
1499  ~ExprAstNegate() { delete m_expr; }
1501  { return TemplateVariant(!m_expr->resolve(c).toBool()); }
1502  private:
1504 };
1505 
1506 class ExprAstUnary : public ExprAst
1507 {
1508  public:
1509  ExprAstUnary(Operator::Type op,ExprAst *exp) : m_operator(op), m_exp(exp)
1510  { TRACE(("ExprAstUnary %s\n",Operator::toString(op))); }
1511  ~ExprAstUnary() { delete m_exp; }
1513  {
1514  TemplateVariant exp = m_exp->resolve(c);
1515  switch (m_operator)
1516  {
1517  case Operator::Minus:
1518  return -exp.toInt();
1519  default:
1520  return TemplateVariant();
1521  }
1522  }
1523  private:
1526 };
1527 
1528 /** @brief Class representing a binary operator in the AST */
1529 class ExprAstBinary : public ExprAst
1530 {
1531  public:
1533  : m_operator(op), m_lhs(lhs), m_rhs(rhs)
1534  { TRACE(("ExprAstBinary %s\n",Operator::toString(op))); }
1535  ~ExprAstBinary() { delete m_lhs; delete m_rhs; }
1537  {
1538  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
1539  if (ci==0) return TemplateVariant(); // should not happen
1540  TemplateVariant lhs = m_lhs->resolve(c);
1541  TemplateVariant rhs = m_rhs ? m_rhs->resolve(c) : TemplateVariant();
1542  switch(m_operator)
1543  {
1544  case Operator::Or:
1545  return TemplateVariant(lhs.toBool() || rhs.toBool());
1546  case Operator::And:
1547  return TemplateVariant(lhs.toBool() && rhs.toBool());
1548  case Operator::Equal:
1549  return TemplateVariant(lhs == rhs);
1550  case Operator::NotEqual:
1551  return TemplateVariant(!(lhs == rhs));
1552  case Operator::Less:
1554  {
1555  return lhs.toString()<rhs.toString();
1556  }
1557  else
1558  {
1559  return lhs.toInt()<rhs.toInt();
1560  }
1561  case Operator::Greater:
1563  {
1564  return !(lhs.toString()<rhs.toString());
1565  }
1566  else
1567  {
1568  return lhs.toInt()>rhs.toInt();
1569  }
1570  case Operator::LessEqual:
1572  {
1573  return lhs.toString()==rhs.toString() || lhs.toString()<rhs.toString();
1574  }
1575  else
1576  {
1577  return lhs.toInt()<=rhs.toInt();
1578  }
1581  {
1582  return lhs.toString()==rhs.toString() || !(lhs.toString()<rhs.toString());
1583  }
1584  else
1585  {
1586  return lhs.toInt()>=rhs.toInt();
1587  }
1588  case Operator::Plus:
1589  {
1590  return TemplateVariant(lhs.toInt() + rhs.toInt());
1591  }
1592  case Operator::Minus:
1593  {
1594  return TemplateVariant(lhs.toInt() - rhs.toInt());
1595  }
1596  case Operator::Multiply:
1597  {
1598  return TemplateVariant(lhs.toInt() * rhs.toInt());
1599  }
1600  case Operator::Divide:
1601  {
1602  int denom = rhs.toInt();
1603  if (denom!=0)
1604  {
1605  return TemplateVariant(lhs.toInt() / denom);
1606  }
1607  else // divide by zero
1608  {
1609  ci->warn(ci->templateName(),ci->line(),"division by zero while evaluating expression is undefined");
1610  return 0;
1611  }
1612  }
1613  case Operator::Modulo:
1614  {
1615  int denom = rhs.toInt();
1616  if (denom!=0)
1617  {
1618  return TemplateVariant(lhs.toInt() % denom);
1619  }
1620  else // module zero
1621  {
1622  ci->warn(ci->templateName(),ci->line(),"modulo zero while evaluating expression is undefined");
1623  return 0;
1624  }
1625  }
1626  default:
1627  return TemplateVariant();
1628  }
1629  }
1630  private:
1634 };
1635 
1636 //----------------------------------------------------------
1637 
1638 /** @brief Base class of all nodes in a template's AST */
1640 {
1641  public:
1642  TemplateNode(TemplateNode *parent) : m_parent(parent) {}
1643  virtual ~TemplateNode() {}
1644 
1645  virtual void render(FTextStream &ts, TemplateContext *c) = 0;
1646 
1647  TemplateNode *parent() { return m_parent; }
1648 
1649  private:
1651 };
1652 
1653 //----------------------------------------------------------
1654 
1655 /** @brief Parser for templates */
1657 {
1658  public:
1659  TemplateParser(const TemplateEngine *engine,
1660  const QCString &templateName,QList<TemplateToken> &tokens);
1661  void parse(TemplateNode *parent,int line,const QStrList &stopAt,
1663  bool hasNextToken() const;
1664  TemplateToken *takeNextToken();
1665  void removeNextToken();
1666  void prependToken(const TemplateToken *token);
1667  const TemplateToken *currentToken() const;
1668  QCString templateName() const { return m_templateName; }
1669  void warn(const char *fileName,int line,const char *fmt,...) const;
1670  private:
1674 };
1675 
1676 //--------------------------------------------------------------------
1677 
1678 /** @brief Recursive decent parser for Django style template expressions.
1679  */
1681 {
1682  public:
1684  : m_parser(parser), m_line(line), m_tokenStream(0)
1685  {
1686  }
1688  {
1689  }
1690 
1691  ExprAst *parse(const char *expr)
1692  {
1693  if (expr==0) return 0;
1694  m_tokenStream = expr;
1695  getNextToken();
1696  return parseExpression();
1697  }
1698 
1699  private:
1700 
1701  /** @brief Class representing a token within an expression. */
1703  {
1704  public:
1705  ExprToken() : type(Unknown), num(-1), op(Operator::Or)
1706  {
1707  }
1708  enum Type
1709  {
1710  Unknown, Operator, Number, Identifier, Literal
1711  };
1712 
1714  int num;
1717  };
1718 
1720  {
1721  TRACE(("{parseExpression(%s)\n",m_tokenStream));
1722  ExprAst *result = parseOrExpression();
1723  TRACE(("}parseExpression(%s)\n",m_tokenStream));
1724  return result;
1725  }
1726 
1728  {
1729  TRACE(("{parseOrExpression(%s)\n",m_tokenStream));
1730  ExprAst *lhs = parseAndExpression();
1731  if (lhs)
1732  {
1733  while (m_curToken.type==ExprToken::Operator &&
1734  m_curToken.op==Operator::Or)
1735  {
1736  getNextToken();
1737  ExprAst *rhs = parseAndExpression();
1738  lhs = new ExprAstBinary(Operator::Or,lhs,rhs);
1739  }
1740  }
1741  TRACE(("}parseOrExpression(%s)\n",m_tokenStream));
1742  return lhs;
1743  }
1744 
1746  {
1747  TRACE(("{parseAndExpression(%s)\n",m_tokenStream));
1748  ExprAst *lhs = parseNotExpression();
1749  if (lhs)
1750  {
1751  while (m_curToken.type==ExprToken::Operator &&
1752  m_curToken.op==Operator::And)
1753  {
1754  getNextToken();
1755  ExprAst *rhs = parseNotExpression();
1756  lhs = new ExprAstBinary(Operator::And,lhs,rhs);
1757  }
1758  }
1759  TRACE(("}parseAndExpression(%s)\n",m_tokenStream));
1760  return lhs;
1761  }
1762 
1764  {
1765  TRACE(("{parseNotExpression(%s)\n",m_tokenStream));
1766  ExprAst *result=0;
1767  if (m_curToken.type==ExprToken::Operator &&
1768  m_curToken.op==Operator::Not)
1769  {
1770  getNextToken();
1771  ExprAst *expr = parseCompareExpression();
1772  if (expr==0)
1773  {
1774  warn(m_parser->templateName(),m_line,"argument missing for not operator");
1775  return 0;
1776  }
1777  result = new ExprAstNegate(expr);
1778  }
1779  else
1780  {
1781  result = parseCompareExpression();
1782  }
1783  TRACE(("}parseNotExpression(%s)\n",m_tokenStream));
1784  return result;
1785  }
1786 
1788  {
1789  TRACE(("{parseCompareExpression(%s)\n",m_tokenStream));
1790  ExprAst *lhs = parseAdditiveExpression();
1791  if (lhs)
1792  {
1793  Operator::Type op = m_curToken.op;
1794  if (m_curToken.type==ExprToken::Operator &&
1795  (op==Operator::Less ||
1796  op==Operator::Greater ||
1797  op==Operator::Equal ||
1798  op==Operator::NotEqual ||
1799  op==Operator::LessEqual ||
1801  )
1802  )
1803  {
1804  getNextToken();
1805  ExprAst *rhs = parseNotExpression();
1806  lhs = new ExprAstBinary(op,lhs,rhs);
1807  }
1808  }
1809  TRACE(("}parseCompareExpression(%s)\n",m_tokenStream));
1810  return lhs;
1811  }
1812 
1814  {
1815  TRACE(("{parseAdditiveExpression(%s)\n",m_tokenStream));
1816  ExprAst *lhs = parseMultiplicativeExpression();
1817  if (lhs)
1818  {
1819  while (m_curToken.type==ExprToken::Operator &&
1820  (m_curToken.op==Operator::Plus || m_curToken.op==Operator::Minus))
1821  {
1822  Operator::Type op = m_curToken.op;
1823  getNextToken();
1824  ExprAst *rhs = parseMultiplicativeExpression();
1825  lhs = new ExprAstBinary(op,lhs,rhs);
1826  }
1827  }
1828  TRACE(("}parseAdditiveExpression(%s)\n",m_tokenStream));
1829  return lhs;
1830  }
1831 
1833  {
1834  TRACE(("{parseMultiplicativeExpression(%s)\n",m_tokenStream));
1835  ExprAst *lhs = parseUnaryExpression();
1836  if (lhs)
1837  {
1838  while (m_curToken.type==ExprToken::Operator &&
1839  (m_curToken.op==Operator::Multiply || m_curToken.op==Operator::Divide || m_curToken.op==Operator::Modulo))
1840  {
1841  Operator::Type op = m_curToken.op;
1842  getNextToken();
1843  ExprAst *rhs = parseUnaryExpression();
1844  lhs = new ExprAstBinary(op,lhs,rhs);
1845  }
1846  }
1847  TRACE(("}parseMultiplicativeExpression(%s)\n",m_tokenStream));
1848  return lhs;
1849  }
1850 
1852  {
1853  TRACE(("{parseUnaryExpression(%s)\n",m_tokenStream));
1854  ExprAst *result=0;
1855  if (m_curToken.type==ExprToken::Operator)
1856  {
1857  if (m_curToken.op==Operator::Plus)
1858  {
1859  getNextToken();
1860  result = parsePrimaryExpression();
1861  }
1862  else if (m_curToken.op==Operator::Minus)
1863  {
1864  getNextToken();
1865  ExprAst *rhs = parsePrimaryExpression();
1866  result = new ExprAstUnary(m_curToken.op,rhs);
1867  }
1868  else
1869  {
1870  result = parsePrimaryExpression();
1871  }
1872  }
1873  else
1874  {
1875  result = parsePrimaryExpression();
1876  }
1877  TRACE(("}parseUnaryExpression(%s)\n",m_tokenStream));
1878  return result;
1879  }
1880 
1882  {
1883  TRACE(("{parsePrimary(%s)\n",m_tokenStream));
1884  ExprAst *result=0;
1885  switch (m_curToken.type)
1886  {
1887  case ExprToken::Number:
1888  result = parseNumber();
1889  break;
1890  case ExprToken::Identifier:
1891  result = parseFilteredVariable();
1892  break;
1893  case ExprToken::Literal:
1894  result = parseLiteral();
1895  break;
1896  case ExprToken::Operator:
1897  if (m_curToken.op==Operator::LeftParen)
1898  {
1899  getNextToken(); // skip over opening bracket
1900  result = parseExpression();
1901  if (m_curToken.type!=ExprToken::Operator ||
1902  m_curToken.op!=Operator::RightParen)
1903  {
1904  warn(m_parser->templateName(),m_line,"missing closing parenthesis");
1905  }
1906  else
1907  {
1908  getNextToken(); // skip over closing bracket
1909  }
1910  }
1911  else
1912  {
1913  warn(m_parser->templateName(),m_line,"unexpected operator '%s' in expression",
1914  Operator::toString(m_curToken.op));
1915  }
1916  break;
1917  default:
1918  warn(m_parser->templateName(),m_line,"unexpected token in expression");
1919  }
1920  TRACE(("}parsePrimary(%s)\n",m_tokenStream));
1921  return result;
1922  }
1923 
1925  {
1926  TRACE(("{parseNumber(%d)\n",m_curToken.num));
1927  ExprAst *num = new ExprAstNumber(m_curToken.num);
1928  getNextToken();
1929  TRACE(("}parseNumber()\n"));
1930  return num;
1931  }
1932 
1934  {
1935  TRACE(("{parseIdentifier(%s)\n",m_curToken.id.data()));
1936  ExprAst *id = new ExprAstVariable(m_curToken.id);
1937  getNextToken();
1938  TRACE(("}parseIdentifier()\n"));
1939  return id;
1940  }
1941 
1943  {
1944  TRACE(("{parseLiteral(%s)\n",m_curToken.id.data()));
1945  ExprAst *expr = new ExprAstLiteral(m_curToken.id);
1946  getNextToken();
1947  TRACE(("}parseLiteral()\n"));
1948  return expr;
1949  }
1950 
1952  {
1953  TRACE(("{parseIdentifierOptionalArgs(%s)\n",m_curToken.id.data()));
1954  ExprAst *expr = parseIdentifier();
1955  if (expr)
1956  {
1957  if (m_curToken.type==ExprToken::Operator &&
1958  m_curToken.op==Operator::Colon)
1959  {
1960  getNextToken();
1961  ExprAst *argExpr = parsePrimaryExpression();
1963  args.append(argExpr);
1964  while (m_curToken.type==ExprToken::Operator &&
1965  m_curToken.op==Operator::Comma)
1966  {
1967  getNextToken();
1968  argExpr = parsePrimaryExpression();
1969  args.append(argExpr);
1970  }
1971  expr = new ExprAstFunctionVariable(expr,args);
1972  }
1973  }
1974  TRACE(("}parseIdentifierOptionalArgs()\n"));
1975  return expr;
1976  }
1977 
1979  {
1980  TRACE(("{parseFilteredVariable()\n"));
1981  ExprAst *expr = parseIdentifierOptionalArgs();
1982  if (expr)
1983  {
1984  while (m_curToken.type==ExprToken::Operator &&
1985  m_curToken.op==Operator::Filter)
1986  {
1987  getNextToken();
1988  ExprAstFilter *filter = parseFilter();
1989  if (!filter) break;
1990  expr = new ExprAstFilterAppl(expr,filter);
1991  }
1992  }
1993  TRACE(("}parseFilteredVariable()\n"));
1994  return expr;
1995  }
1996 
1998  {
1999  TRACE(("{parseFilter(%s)\n",m_curToken.id.data()));
2000  QCString filterName = m_curToken.id;
2001  getNextToken();
2002  ExprAst *argExpr=0;
2003  if (m_curToken.type==ExprToken::Operator &&
2004  m_curToken.op==Operator::Colon)
2005  {
2006  getNextToken();
2007  argExpr = parsePrimaryExpression();
2008  }
2009  ExprAstFilter *filter = new ExprAstFilter(filterName,argExpr);
2010  TRACE(("}parseFilter()\n"));
2011  return filter;
2012  }
2013 
2014 
2016  {
2017  const char *p = m_tokenStream;
2018  char s[2];
2019  s[1]=0;
2020  if (p==0 || *p=='\0') return FALSE;
2021  while (*p==' ') p++; // skip over spaces
2022  char c=*p;
2023  if (*p=='\0') // only spaces...
2024  {
2025  m_tokenStream = p;
2026  return FALSE;
2027  }
2028  const char *q = p;
2029  switch (c)
2030  {
2031  case '=':
2032  if (c=='=' && *(p+1)=='=') // equal
2033  {
2034  m_curToken.op = Operator::Equal;
2035  p+=2;
2036  }
2037  break;
2038  case '!':
2039  if (c=='!' && *(p+1)=='=') // not equal
2040  {
2041  m_curToken.op = Operator::NotEqual;
2042  p+=2;
2043  }
2044  break;
2045  case '<':
2046  if (c=='<' && *(p+1)=='=') // less or equal
2047  {
2048  m_curToken.op = Operator::LessEqual;
2049  p+=2;
2050  }
2051  else // less
2052  {
2053  m_curToken.op = Operator::Less;
2054  p++;
2055  }
2056  break;
2057  case '>':
2058  if (c=='>' && *(p+1)=='=') // greater or equal
2059  {
2060  m_curToken.op = Operator::GreaterEqual;
2061  p+=2;
2062  }
2063  else // greater
2064  {
2065  m_curToken.op = Operator::Greater;
2066  p++;
2067  }
2068  break;
2069  case '(':
2070  m_curToken.op = Operator::LeftParen;
2071  p++;
2072  break;
2073  case ')':
2074  m_curToken.op = Operator::RightParen;
2075  p++;
2076  break;
2077  case '|':
2078  m_curToken.op = Operator::Filter;
2079  p++;
2080  break;
2081  case '+':
2082  m_curToken.op = Operator::Plus;
2083  p++;
2084  break;
2085  case '-':
2086  m_curToken.op = Operator::Minus;
2087  p++;
2088  break;
2089  case '*':
2090  m_curToken.op = Operator::Multiply;
2091  p++;
2092  break;
2093  case '/':
2094  m_curToken.op = Operator::Divide;
2095  p++;
2096  break;
2097  case '%':
2098  m_curToken.op = Operator::Modulo;
2099  p++;
2100  break;
2101  case ':':
2102  m_curToken.op = Operator::Colon;
2103  p++;
2104  break;
2105  case ',':
2106  m_curToken.op = Operator::Comma;
2107  p++;
2108  break;
2109  case 'n':
2110  if (strncmp(p,"not ",4)==0)
2111  {
2112  m_curToken.op = Operator::Not;
2113  p+=4;
2114  }
2115  break;
2116  case 'a':
2117  if (strncmp(p,"and ",4)==0)
2118  {
2119  m_curToken.op = Operator::And;
2120  p+=4;
2121  }
2122  break;
2123  case 'o':
2124  if (strncmp(p,"or ",3)==0)
2125  {
2126  m_curToken.op = Operator::Or;
2127  p+=3;
2128  }
2129  break;
2130  default:
2131  break;
2132  }
2133  if (p!=q) // found an operator
2134  {
2135  m_curToken.type = ExprToken::Operator;
2136  }
2137  else // no token found yet
2138  {
2139  if (c>='0' && c<='9') // number?
2140  {
2141  m_curToken.type = ExprToken::Number;
2142  const char *np = p;
2143  m_curToken.num = 0;
2144  while (*np>='0' && *np<='9')
2145  {
2146  m_curToken.num*=10;
2147  m_curToken.num+=*np-'0';
2148  np++;
2149  }
2150  p=np;
2151  }
2152  else if (c=='_' || (c>='a' && c<='z') || (c>='A' && c<='Z')) // identifier?
2153  {
2154  m_curToken.type = ExprToken::Identifier;
2155  s[0]=c;
2156  m_curToken.id = s;
2157  p++;
2158  while ((c=*p) &&
2159  (c=='_' || c=='.' ||
2160  (c>='a' && c<='z') ||
2161  (c>='A' && c<='Z') ||
2162  (c>='0' && c<='9'))
2163  )
2164  {
2165  s[0]=c;
2166  m_curToken.id+=s;
2167  p++;
2168  }
2169  if (m_curToken.id=="True") // treat true literal as numerical 1
2170  {
2171  m_curToken.type = ExprToken::Number;
2172  m_curToken.num = 1;
2173  }
2174  else if (m_curToken.id=="False") // treat false literal as numerical 0
2175  {
2176  m_curToken.type = ExprToken::Number;
2177  m_curToken.num = 0;
2178  }
2179  }
2180  else if (c=='"' || c=='\'') // string literal
2181  {
2182  m_curToken.type = ExprToken::Literal;
2183  m_curToken.id.resize(0);
2184  p++;
2185  char tokenChar = c;
2186  char cp=0;
2187  while ((c=*p) && (c!=tokenChar || (c==tokenChar && cp=='\\')))
2188  {
2189  s[0]=c;
2190  if (c!='\\' || cp=='\\') // don't add escapes
2191  {
2192  m_curToken.id+=s;
2193  }
2194  cp=c;
2195  p++;
2196  }
2197  if (*p==tokenChar) p++;
2198  }
2199  }
2200  if (p==q) // still no valid token found -> error
2201  {
2202  m_curToken.type = ExprToken::Unknown;
2203  char s[2];
2204  s[0]=c;
2205  s[1]=0;
2206  warn(m_parser->templateName(),m_line,"Found unknown token '%s' (%d) while parsing %s",s,c,m_tokenStream);
2207  m_curToken.id = s;
2208  p++;
2209  }
2210  //TRACE(("token type=%d op=%d num=%d id=%s\n",
2211  // m_curToken.type,m_curToken.op,m_curToken.num,m_curToken.id.data()));
2212 
2213  m_tokenStream = p;
2214  return TRUE;
2215  }
2216 
2219  int m_line;
2220  const char *m_tokenStream;
2221 };
2222 
2223 //----------------------------------------------------------
2224 
2225 /** @brief Class representing a lexical token in a template */
2227 {
2228  public:
2229  enum Type { Text, Variable, Block };
2230  TemplateToken(Type t,const char *d,int l) : type(t), data(d), line(l) {}
2233  int line;
2234 };
2235 
2236 //----------------------------------------------------------
2237 
2238 /** @brief Class representing a list of AST nodes in a template */
2239 class TemplateNodeList : public QList<TemplateNode>
2240 {
2241  public:
2243  {
2244  setAutoDelete(TRUE);
2245  }
2247  {
2248  TRACE(("{TemplateNodeList::render\n"));
2249  QListIterator<TemplateNode> it(*this);
2250  TemplateNode *tn=0;
2251  for (it.toFirst();(tn=it.current());++it)
2252  {
2253  tn->render(ts,c);
2254  }
2255  TRACE(("}TemplateNodeList::render\n"));
2256  }
2257 };
2258 
2259 //----------------------------------------------------------
2260 
2261 /** @brief Internal class representing the implementation of a template */
2262 class TemplateImpl : public TemplateNode, public Template
2263 {
2264  public:
2266  const QCString &extension);
2267  ~TemplateImpl();
2268  void render(FTextStream &ts, TemplateContext *c);
2269 
2270  TemplateEngine *engine() const { return m_engine; }
2271  TemplateBlockContext *blockContext() { return &m_blockContext; }
2272 
2273  private:
2278 };
2279 
2280 //----------------------------------------------------------
2281 
2282 /** @brief Weak reference wrapper for TemplateStructIntf that provides access to the
2283  * wrapped struct without holding a reference.
2284  */
2286 {
2287  public:
2288  TemplateStructWeakRef(TemplateStructIntf *ref) : m_ref(ref), m_refCount(0) {}
2289  virtual TemplateVariant get(const char *name) const { return m_ref->get(name); }
2290  virtual int addRef() { return ++m_refCount; }
2291  virtual int release() { int count=--m_refCount; if (count<=0) { delete this; } return count; }
2292  private:
2295 };
2296 
2297 //----------------------------------------------------------
2298 
2300  : m_engine(e), m_templateName("<unknown>"), m_line(1), m_activeEscapeIntf(0),
2301  m_spacelessIntf(0), m_spacelessEnabled(FALSE), m_tabbingEnabled(FALSE), m_indices(TemplateStruct::alloc())
2302 {
2303  m_indexStacks.setAutoDelete(TRUE);
2305  m_escapeIntfDict.setAutoDelete(TRUE);
2306  push();
2307  set("index",m_indices.get());
2308 }
2309 
2311 {
2312  pop();
2313 }
2314 
2316 {
2317  TemplateVariant *pv = m_contextStack.getFirst()->find(name);
2318  if (pv)
2319  {
2320  m_contextStack.getFirst()->remove(name);
2321  }
2322  m_contextStack.getFirst()->insert(name,new TemplateVariant(v));
2323 }
2324 
2326 {
2327  int i=name.find('.');
2328  if (i==-1) // simple name
2329  {
2330  return getPrimary(name);
2331  }
2332  else // obj.prop
2333  {
2334  QCString objName = name.left(i);
2335  TemplateVariant v = getPrimary(objName);
2336  QCString propName = name.mid(i+1);
2337  while (!propName.isEmpty())
2338  {
2339  //printf("getPrimary(%s) type=%d:%s\n",objName.data(),v.type(),v.toString().data());
2340  if (v.type()==TemplateVariant::Struct)
2341  {
2342  i = propName.find(".");
2343  int l = i==-1 ? propName.length() : i;
2344  v = v.toStruct()->get(propName.left(l));
2345  if (!v.isValid())
2346  {
2347  warn(m_templateName,m_line,"requesting non-existing property '%s' for object '%s'",propName.left(l).data(),objName.data());
2348  }
2349  if (i!=-1)
2350  {
2351  objName = propName.left(i);
2352  propName = propName.mid(i+1);
2353  }
2354  else
2355  {
2356  propName.resize(0);
2357  }
2358  }
2359  else if (v.type()==TemplateVariant::List)
2360  {
2361  i = propName.find(".");
2362  int l = i==-1 ? propName.length() : i;
2363  bool b;
2364  int index = propName.left(l).toInt(&b);
2365  if (b)
2366  {
2367  v = v.toList()->at(index);
2368  }
2369  else
2370  {
2371  warn(m_templateName,m_line,"list index '%s' is not valid",propName.data());
2372  break;
2373  }
2374  if (i!=-1)
2375  {
2376  propName = propName.mid(i+1);
2377  }
2378  else
2379  {
2380  propName.resize(0);
2381  }
2382  }
2383  else
2384  {
2385  warn(m_templateName,m_line,"using . on an object '%s' is not an struct or list",objName.data());
2386  return TemplateVariant();
2387  }
2388  }
2389  return v;
2390  }
2391 }
2392 
2394 {
2396  QDict<TemplateVariant> *dict;
2397  for (it.toFirst();(dict=it.current());++it)
2398  {
2399  TemplateVariant *v = dict->find(name);
2400  if (v) return v;
2401  }
2402  return 0; // not found
2403 }
2404 
2406 {
2407  const TemplateVariant *v = getRef(name);
2408  return v ? *v : TemplateVariant();
2409 }
2410 
2412 {
2413  QDict<TemplateVariant> *dict = new QDict<TemplateVariant>;
2414  dict->setAutoDelete(TRUE);
2415  m_contextStack.prepend(dict);
2416 }
2417 
2419 {
2420  if (!m_contextStack.removeFirst())
2421  {
2422  warn(m_templateName,m_line,"pop() called on empty context stack!\n");
2423  }
2424 }
2425 
2427 {
2428  return &m_blockContext;
2429 }
2430 
2431 void TemplateContextImpl::warn(const char *fileName,int line,const char *fmt,...) const
2432 {
2433  va_list args;
2434  va_start(args,fmt);
2435  va_warn(fileName,line,fmt,args);
2436  va_end(args);
2437  m_engine->printIncludeContext(fileName,line);
2438 }
2439 
2441 {
2442  printf("TemplateContextImpl::openSubIndex(%s)\n",indexName.data());
2443  QStack<TemplateVariant> *stack = m_indexStacks.find(indexName);
2444  if (!stack || stack->isEmpty() || stack->top()->type()==TemplateVariant::List) // error: no stack yet or no entry
2445  {
2446  warn(m_templateName,m_line,"opensubindex for index %s without preceding indexentry",indexName.data());
2447  return;
2448  }
2449  // get the parent entry to add the list to
2450  TemplateStruct *entry = dynamic_cast<TemplateStruct*>(stack->top()->toStruct());
2451  if (entry)
2452  {
2453  // add new list to the stack
2455  stack->push(new TemplateVariant(list));
2456  entry->set("children",list);
2457  entry->set("is_leaf_node",false);
2458  }
2459 }
2460 
2462 {
2463  printf("TemplateContextImpl::closeSubIndex(%s)\n",indexName.data());
2464  QStack<TemplateVariant> *stack = m_indexStacks.find(indexName);
2465  if (!stack || stack->count()<3)
2466  {
2467  warn(m_templateName,m_line,"closesubindex for index %s without matching open",indexName.data());
2468  }
2469  else // stack->count()>=2
2470  {
2471  if (stack->top()->type()==TemplateVariant::Struct)
2472  {
2473  delete stack->pop(); // pop struct
2474  delete stack->pop(); // pop list
2475  }
2476  else // empty list! correct "is_left_node" attribute of the parent entry
2477  {
2478  delete stack->pop(); // pop list
2479  TemplateStruct *entry = dynamic_cast<TemplateStruct*>(stack->top()->toStruct());
2480  if (entry)
2481  {
2482  entry->set("is_leaf_node",true);
2483  }
2484  }
2485  }
2486  //fprintf(stderr,"TemplateContextImpl::closeSubIndex(%s) end g_count=%d\n\n",indexName.data(),g_count);
2487 }
2488 
2490 {
2491  TemplateVariant parent = entry->get("parent");
2492  if (parent.type()==TemplateVariant::Struct)
2493  {
2494  getPathListFunc(parent.toStruct(),list);
2495  }
2496  list->append(entry);
2497 }
2498 
2500 {
2503  getPathListFunc(entry,result);
2504  return result;
2505 }
2506 
2508 {
2510  //printf("TemplateContextImpl::addIndexEntry(%s)\n",indexName.data());
2511  //while (it!=arguments.end())
2512  //{
2513  // printf(" key=%s value=%s\n",(*it).key.data(),(*it).value.toString().data());
2514  // ++it;
2515  //}
2517  QStack<TemplateVariant> *stack = m_indexStacks.find(indexName);
2518  if (!stack) // no stack yet, create it!
2519  {
2520  stack = new QStack<TemplateVariant>;
2521  stack->setAutoDelete(TRUE);
2522  m_indexStacks.insert(indexName,stack);
2523  }
2524  TemplateList *list = 0;
2525  if (stack->isEmpty()) // first item, create empty list and add it to the index
2526  {
2527  list = TemplateList::alloc();
2528  stack->push(new TemplateVariant(list));
2529  m_indices->set(indexName,list); // make list available under index
2530  }
2531  else // stack not empty
2532  {
2533  if (stack->top()->type()==TemplateVariant::Struct) // already an entry in the list
2534  {
2535  // remove current entry from the stack
2536  delete stack->pop();
2537  }
2538  else // first entry after opensubindex
2539  {
2540  ASSERT(stack->top()->type()==TemplateVariant::List);
2541  }
2542  if (stack->count()>1)
2543  {
2544  TemplateVariant *tmp = stack->pop();
2545  // To prevent a cyclic dependency between parent and child which causes a memory
2546  // leak, we wrap the parent into a weak reference version.
2547  parent = new TemplateStructWeakRef(stack->top()->toStruct());
2548  stack->push(tmp);
2549  ASSERT(parent.type()==TemplateVariant::Struct);
2550  }
2551  // get list to add new item
2552  list = dynamic_cast<TemplateList*>(stack->top()->toList());
2553  }
2555  // add user specified fields to the entry
2556  for (it=arguments.begin();it!=arguments.end();++it)
2557  {
2558  entry->set((*it).key,(*it).value);
2559  }
2560  if (list->count()>0)
2561  {
2562  TemplateStruct *lastEntry = dynamic_cast<TemplateStruct*>(list->at(list->count()-1).toStruct());
2563  lastEntry->set("last",false);
2564  }
2565  entry->set("is_leaf_node",true);
2566  entry->set("first",list->count()==0);
2567  entry->set("index",list->count());
2568  entry->set("parent",parent);
2570  entry->set("last",true);
2571  stack->push(new TemplateVariant(entry));
2572  list->append(entry);
2573 }
2574 
2575 //----------------------------------------------------------
2576 
2577 /** @brief Class representing a piece of plain text in a template */
2579 {
2580  public:
2582  : TemplateNode(parent), m_data(data)
2583  {
2584  TRACE(("TemplateNodeText('%s')\n",replace(data,'\n',' ').data()));
2585  }
2586 
2588  {
2589  //printf("TemplateNodeText::render(%s)\n",m_data.data());
2590  TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c);
2591  if (ci==0) return; // should not happen
2592  if (ci->spacelessEnabled())
2593  {
2594  ts << ci->spacelessIntf()->remove(m_data);
2595  }
2596  else
2597  {
2598  ts << m_data;
2599  }
2600  }
2601  private:
2603 };
2604 
2605 //----------------------------------------------------------
2606 
2607 /** @brief Class representing a variable in a template */
2609 {
2610  public:
2612  : TemplateNode(parent), m_templateName(parser->templateName()), m_line(line)
2613  {
2614  TRACE(("TemplateNodeVariable(%s)\n",var.data()));
2615  ExpressionParser expParser(parser,line);
2616  m_var = expParser.parse(var);
2617  if (m_var==0)
2618  {
2619  parser->warn(m_templateName,line,"invalid expression '%s' for variable",var.data());
2620  }
2621  }
2623  {
2624  delete m_var;
2625  }
2626 
2628  {
2629  TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c);
2630  if (ci==0) return; // should not happen
2632  if (m_var)
2633  {
2634  TemplateVariant v = m_var->resolve(c);
2636  {
2638  }
2639  if (ci->escapeIntf() && !v.raw())
2640  {
2641  ts << ci->escapeIntf()->escape(v.toString());
2642  }
2643  else
2644  {
2645  ts << v.toString();
2646  }
2647  }
2648  }
2649 
2650  private:
2652  int m_line;
2655 };
2656 
2657 //----------------------------------------------------------
2658 
2659 /** @brief Helper class for creating template AST tag nodes and returning
2660  * the template for a given node.
2661  */
2662 template<class T> class TemplateNodeCreator : public TemplateNode
2663 {
2664  public:
2666  : TemplateNode(parent), m_templateName(parser->templateName()), m_line(line) {}
2669  int line,
2670  const QCString &data)
2671  {
2672  return new T(parser,parent,line,data);
2673  }
2675  {
2676  TemplateNode *root = this;
2677  while (root && root->parent())
2678  {
2679  root = root->parent();
2680  }
2681  return dynamic_cast<TemplateImpl*>(root);
2682  }
2683  protected:
2685  {
2686  int i=fileName.find('/');
2687  QCString outputDir = ci->outputDirectory();
2688  QDir d(outputDir);
2689  if (!d.exists())
2690  {
2691  QDir rootDir;
2692  rootDir.setPath(QDir::currentDirPath());
2693  if (!rootDir.mkdir(outputDir))
2694  {
2695  err("tag OUTPUT_DIRECTORY: Output directory `%s' does not "
2696  "exist and cannot be created\n",outputDir.data());
2697  return;
2698  }
2699  d.setPath(outputDir);
2700  }
2701  int j=0;
2702  while (i!=-1) // fileName contains path part
2703  {
2704  if (d.exists())
2705  {
2706  bool ok = d.mkdir(fileName.mid(j,i-j));
2707  if (!ok) break;
2708  QCString dirName = outputDir+'/'+fileName.left(i);
2709  d = QDir(dirName);
2710  j = i+1;
2711  }
2712  i=fileName.find('/',i+1);
2713  }
2714  }
2716  int m_line;
2717 };
2718 
2719 //----------------------------------------------------------
2720 
2721 /** @brief Class representing an 'if' tag in a template */
2722 class TemplateNodeIf : public TemplateNodeCreator<TemplateNodeIf>
2723 {
2724  public:
2726  TemplateNodeCreator<TemplateNodeIf>(parser,parent,line)
2727  {
2728  m_ifGuardedNodes.setAutoDelete(TRUE);
2729  TRACE(("{TemplateNodeIf(%s)\n",data.data()));
2730  if (data.isEmpty())
2731  {
2732  parser->warn(m_templateName,line,"missing argument for if tag");
2733  }
2734  QStrList stopAt;
2735  stopAt.append("endif");
2736  stopAt.append("elif");
2737  stopAt.append("else");
2738 
2739  // if 'nodes'
2740  GuardedNodes *guardedNodes = new GuardedNodes;
2741  ExpressionParser ex(parser,line);
2742  guardedNodes->line = line;
2743  guardedNodes->guardAst = ex.parse(data);
2744  parser->parse(this,line,stopAt,guardedNodes->trueNodes);
2745  m_ifGuardedNodes.append(guardedNodes);
2746  TemplateToken *tok = parser->takeNextToken();
2747 
2748  // elif 'nodes'
2749  while (tok && tok->data.left(5)=="elif ")
2750  {
2751  ExpressionParser ex(parser,line);
2752  guardedNodes = new GuardedNodes;
2753  guardedNodes->line = tok->line;
2754  guardedNodes->guardAst = ex.parse(tok->data.mid(5));
2755  parser->parse(this,tok->line,stopAt,guardedNodes->trueNodes);
2756  m_ifGuardedNodes.append(guardedNodes);
2757  // proceed to the next token
2758  delete tok;
2759  tok = parser->takeNextToken();
2760  }
2761 
2762  // else 'nodes'
2763  if (tok && tok->data=="else")
2764  {
2765  stopAt.removeLast(); // remove "else"
2766  stopAt.removeLast(); // remove "elif"
2767  parser->parse(this,line,stopAt,m_falseNodes);
2768  parser->removeNextToken(); // skip over endif
2769  }
2770  delete tok;
2771  TRACE(("}TemplateNodeIf(%s)\n",data.data()));
2772  }
2774  {
2775  }
2776 
2778  {
2779  TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c);
2780  if (ci==0) return; // should not happen
2782  //printf("TemplateNodeIf::render #trueNodes=%d #falseNodes=%d\n",m_trueNodes.count(),m_falseNodes.count());
2783  bool processed=FALSE;
2784  QListIterator<GuardedNodes> li(m_ifGuardedNodes);
2786  for (li.toFirst();(nodes=li.current()) && !processed;++li)
2787  {
2788  if (nodes->guardAst)
2789  {
2790  TemplateVariant guardValue = nodes->guardAst->resolve(c);
2791  if (guardValue.toBool()) // render nodes for the first guard that evaluated to 'true'
2792  {
2793  nodes->trueNodes.render(ts,c);
2794  processed=TRUE;
2795  }
2796  }
2797  else
2798  {
2799  ci->warn(m_templateName,nodes->line,"invalid expression for if/elif");
2800  }
2801  }
2802  if (!processed)
2803  {
2804  // all guards are false, render 'else' nodes
2805  m_falseNodes.render(ts,c);
2806  }
2807  }
2808  private:
2810  {
2811  GuardedNodes() : guardAst(0) {}
2812  ~GuardedNodes() { delete guardAst; }
2813  int line;
2816  };
2819 };
2820 
2821 //----------------------------------------------------------
2822 /** @brief Class representing a 'for' tag in a template */
2823 class TemplateNodeRepeat : public TemplateNodeCreator<TemplateNodeRepeat>
2824 {
2825  public:
2827  : TemplateNodeCreator<TemplateNodeRepeat>(parser,parent,line)
2828  {
2829  TRACE(("{TemplateNodeRepeat(%s)\n",data.data()));
2830  ExpressionParser expParser(parser,line);
2831  m_expr = expParser.parse(data);
2832  QStrList stopAt;
2833  stopAt.append("endrepeat");
2834  parser->parse(this,line,stopAt,m_repeatNodes);
2835  parser->removeNextToken(); // skip over endrepeat
2836  TRACE(("}TemplateNodeRepeat(%s)\n",data.data()));
2837  }
2839  {
2840  delete m_expr;
2841  }
2843  {
2844  TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c);
2845  if (ci==0) return; // should not happen
2847  TemplateVariant v;
2848  if (m_expr && (v=m_expr->resolve(c)).type()==TemplateVariant::Integer)
2849  {
2850  int i, n = v.toInt();
2851  for (i=0;i<n;i++)
2852  {
2854  s->set("counter0", (int)i);
2855  s->set("counter", (int)(i+1));
2856  s->set("revcounter", (int)(n-i));
2857  s->set("revcounter0", (int)(n-i-1));
2858  s->set("first",i==0);
2859  s->set("last", i==n-1);
2860  c->set("repeatloop",s.get());
2861  // render all items for this iteration of the loop
2862  m_repeatNodes.render(ts,c);
2863  }
2864  }
2865  else // simple type...
2866  {
2867  ci->warn(m_templateName,m_line,"for requires a variable of list type!");
2868  }
2869  }
2870  private:
2873 };
2874 
2875 //----------------------------------------------------------
2876 
2877 /** @brief Class representing a 'range' tag in a template */
2878 class TemplateNodeRange : public TemplateNodeCreator<TemplateNodeRange>
2879 {
2880  public:
2882  : TemplateNodeCreator<TemplateNodeRange>(parser,parent,line), m_down(FALSE)
2883  {
2884  TRACE(("{TemplateNodeRange(%s)\n",data.data()));
2885  QCString start,end;
2886  int i1 = data.find(" from ");
2887  int i2 = data.find(" to ");
2888  int i3 = data.find(" downto ");
2889  if (i1==-1)
2890  {
2891  if (data.right(5)==" from")
2892  {
2893  parser->warn(m_templateName,line,"range missing after 'from' keyword");
2894  }
2895  else if (data=="from")
2896  {
2897  parser->warn(m_templateName,line,"range needs an iterator variable and a range");
2898  }
2899  else
2900  {
2901  parser->warn(m_templateName,line,"range is missing 'from' keyword");
2902  }
2903  }
2904  else if (i2==-1 && i3==-1)
2905  {
2906  if (data.right(3)==" to")
2907  {
2908  parser->warn(m_templateName,line,"range is missing end value after 'to' keyword");
2909  }
2910  else if (data.right(7)==" downto")
2911  {
2912  parser->warn(m_templateName,line,"range is missing end value after 'downto' keyword");
2913  }
2914  else
2915  {
2916  parser->warn(m_templateName,line,"range is missing 'to' or 'downto' keyword");
2917  }
2918  }
2919  else
2920  {
2921  m_var = data.left(i1).stripWhiteSpace();
2922  if (m_var.isEmpty())
2923  {
2924  parser->warn(m_templateName,line,"range needs an iterator variable");
2925  }
2926  start = data.mid(i1+6,i2-i1-6).stripWhiteSpace();
2927  if (i2!=-1)
2928  {
2929  end = data.right(data.length()-i2-4).stripWhiteSpace();
2930  m_down = FALSE;
2931  }
2932  else if (i3!=-1)
2933  {
2934  end = data.right(data.length()-i3-8).stripWhiteSpace();
2935  m_down = TRUE;
2936  }
2937  }
2938  ExpressionParser expParser(parser,line);
2939  m_startExpr = expParser.parse(start);
2940  m_endExpr = expParser.parse(end);
2941 
2942  QStrList stopAt;
2943  stopAt.append("endrange");
2944  parser->parse(this,line,stopAt,m_loopNodes);
2945  parser->removeNextToken(); // skip over endrange
2946  TRACE(("}TemplateNodeRange(%s)\n",data.data()));
2947  }
2948 
2950  {
2951  delete m_startExpr;
2952  delete m_endExpr;
2953  }
2954 
2956  {
2957  TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c);
2958  if (ci==0) return; // should not happen
2960  //printf("TemplateNodeRange::render #loopNodes=%d\n",
2961  // m_loopNodes.count());
2962  if (m_startExpr && m_endExpr)
2963  {
2964  TemplateVariant vs = m_startExpr->resolve(c);
2965  TemplateVariant ve = m_endExpr->resolve(c);
2967  {
2968  int s = vs.toInt();
2969  int e = ve.toInt();
2970  int l = m_down ? s-e+1 : e-s+1;
2971  if (l>0)
2972  {
2973  c->push();
2974  //int index = m_reversed ? list.count() : 0;
2975  const TemplateVariant *parentLoop = c->getRef("forloop");
2976  uint index = 0;
2977  int i = m_down ? e : s;
2978  bool done=false;
2979  while (!done)
2980  {
2981  // set the forloop meta-data variable
2983  s->set("counter0", (int)index);
2984  s->set("counter", (int)(index+1));
2985  s->set("revcounter", (int)(l-index));
2986  s->set("revcounter0", (int)(l-index-1));
2987  s->set("first",index==0);
2988  s->set("last", (int)index==l-1);
2989  s->set("parentloop",parentLoop ? *parentLoop : TemplateVariant());
2990  c->set("forloop",s.get());
2991 
2992  // set the iterator variable
2993  c->set(m_var,i);
2994 
2995  // render all items for this iteration of the loop
2996  m_loopNodes.render(ts,c);
2997 
2998  index++;
2999  if (m_down)
3000  {
3001  i--;
3002  done = i<e;
3003  }
3004  else
3005  {
3006  i++;
3007  done = i>e;
3008  }
3009  }
3010  c->pop();
3011  }
3012  else
3013  {
3014  ci->warn(m_templateName,m_line,"range %d %s %d is empty!",
3015  s,m_down?"downto":"to",e);
3016  }
3017  }
3018  else if (vs.type()!=TemplateVariant::Integer)
3019  {
3020  ci->warn(m_templateName,m_line,"range requires a start value of integer type!");
3021  }
3022  else if (ve.type()!=TemplateVariant::Integer)
3023  {
3024  ci->warn(m_templateName,m_line,"range requires an end value of integer type!");
3025  }
3026  }
3027  else if (!m_startExpr)
3028  {
3029  ci->warn(m_templateName,m_line,"range has empty start value");
3030  }
3031  else if (!m_endExpr)
3032  {
3033  ci->warn(m_templateName,m_line,"range has empty end value");
3034  }
3035  }
3036 
3037  private:
3038  bool m_down;
3043 };
3044 
3045 //----------------------------------------------------------
3046 
3047 /** @brief Class representing a 'for' tag in a template */
3048 class TemplateNodeFor : public TemplateNodeCreator<TemplateNodeFor>
3049 {
3050  public:
3052  : TemplateNodeCreator<TemplateNodeFor>(parser,parent,line), m_reversed(FALSE)
3053  {
3054  TRACE(("{TemplateNodeFor(%s)\n",data.data()));
3055  QCString exprStr;
3056  int i = data.find(" in ");
3057  if (i==-1)
3058  {
3059  if (data.right(3)==" in")
3060  {
3061  parser->warn(m_templateName,line,"for is missing container after 'in' keyword");
3062  }
3063  else if (data=="in")
3064  {
3065  parser->warn(m_templateName,line,"for needs at least one iterator variable");
3066  }
3067  else
3068  {
3069  parser->warn(m_templateName,line,"for is missing 'in' keyword");
3070  }
3071  }
3072  else
3073  {
3074  m_vars = split(data.left(i),",");
3075  if (m_vars.count()==0)
3076  {
3077  parser->warn(m_templateName,line,"for needs at least one iterator variable");
3078  }
3079 
3080  int j = data.find(" reversed",i);
3081  m_reversed = (j!=-1);
3082 
3083  if (j==-1) j=data.length();
3084  if (j>i+4)
3085  {
3086  exprStr = data.mid(i+4,j-i-4); // skip over " in " part
3087  }
3088  if (exprStr.isEmpty())
3089  {
3090  parser->warn(m_templateName,line,"for is missing container after 'in' keyword");
3091  }
3092  }
3093  ExpressionParser expParser(parser,line);
3094  m_expr = expParser.parse(exprStr);
3095 
3096  QStrList stopAt;
3097  stopAt.append("endfor");
3098  stopAt.append("empty");
3099  parser->parse(this,line,stopAt,m_loopNodes);
3100  TemplateToken *tok = parser->takeNextToken();
3101  if (tok && tok->data=="empty")
3102  {
3103  stopAt.removeLast();
3104  parser->parse(this,line,stopAt,m_emptyNodes);
3105  parser->removeNextToken(); // skip over endfor
3106  }
3107  delete tok;
3108  TRACE(("}TemplateNodeFor(%s)\n",data.data()));
3109  }
3110 
3112  {
3113  delete m_expr;
3114  }
3115 
3117  {
3118  TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c);
3119  if (ci==0) return; // should not happen
3121  //printf("TemplateNodeFor::render #loopNodes=%d #emptyNodes=%d\n",
3122  // m_loopNodes.count(),m_emptyNodes.count());
3123  if (m_expr)
3124  {
3125  TemplateVariant v = m_expr->resolve(c);
3127  {
3129  }
3130  const TemplateListIntf *list = v.toList();
3131  if (list)
3132  {
3133  uint listSize = list->count();
3134  if (listSize==0) // empty for loop
3135  {
3136  m_emptyNodes.render(ts,c);
3137  return;
3138  }
3139  c->push();
3140  //int index = m_reversed ? list.count() : 0;
3141  TemplateVariant v;
3142  const TemplateVariant *parentLoop = c->getRef("forloop");
3143  uint index = m_reversed ? listSize-1 : 0;
3145  for (m_reversed ? it->toLast() : it->toFirst();
3146  (it->current(v));
3147  m_reversed ? it->toPrev() : it->toNext())
3148  {
3150  s->set("counter0", (int)index);
3151  s->set("counter", (int)(index+1));
3152  s->set("revcounter", (int)(listSize-index));
3153  s->set("revcounter0", (int)(listSize-index-1));
3154  s->set("first",index==0);
3155  s->set("last", index==listSize-1);
3156  s->set("parentloop",parentLoop ? *parentLoop : TemplateVariant());
3157  c->set("forloop",s.get());
3158 
3159  // add variables for this loop to the context
3160  //obj->addVariableToContext(index,m_vars,c);
3161  uint vi=0;
3162  if (m_vars.count()==1) // loop variable represents an item
3163  {
3164  c->set(m_vars[vi++],v);
3165  }
3166  else if (m_vars.count()>1 && v.type()==TemplateVariant::Struct)
3167  // loop variables represent elements in a list item
3168  {
3169  for (uint i=0;i<m_vars.count();i++,vi++)
3170  {
3171  c->set(m_vars[vi],v.toStruct()->get(m_vars[vi]));
3172  }
3173  }
3174  for (;vi<m_vars.count();vi++)
3175  {
3176  c->set(m_vars[vi],TemplateVariant());
3177  }
3178 
3179  // render all items for this iteration of the loop
3180  m_loopNodes.render(ts,c);
3181 
3182  if (m_reversed) index--; else index++;
3183  }
3184  c->pop();
3185  delete it;
3186  }
3187  else // simple type...
3188  {
3189  ci->warn(m_templateName,m_line,"for requires a variable of list type, got type '%s'!",v.typeAsString().data());
3190  }
3191  }
3192  }
3193 
3194  private:
3200 };
3201 
3202 //----------------------------------------------------------
3203 
3204 /** @brief Class representing an 'markers' tag in a template */
3205 class TemplateNodeMsg : public TemplateNodeCreator<TemplateNodeMsg>
3206 {
3207  public:
3209  : TemplateNodeCreator<TemplateNodeMsg>(parser,parent,line)
3210  {
3211  TRACE(("{TemplateNodeMsg()\n"));
3212  QStrList stopAt;
3213  stopAt.append("endmsg");
3214  parser->parse(this,line,stopAt,m_nodes);
3215  parser->removeNextToken(); // skip over endmsg
3216  TRACE(("}TemplateNodeMsg()\n"));
3217  }
3219  {
3220  TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c);
3221  if (ci==0) return; // should not happen
3223  TemplateEscapeIntf *escIntf = ci->escapeIntf();
3224  ci->setActiveEscapeIntf(0); // avoid escaping things we send to standard out
3225  bool enable = ci->spacelessEnabled();
3226  ci->enableSpaceless(FALSE);
3227  FTextStream ts(stdout);
3228  m_nodes.render(ts,c);
3229  ts << endl;
3230  ci->setActiveEscapeIntf(escIntf);
3231  ci->enableSpaceless(enable);
3232  }
3233  private:
3235 };
3236 
3237 
3238 //----------------------------------------------------------
3239 
3240 /** @brief Class representing a 'block' tag in a template */
3241 class TemplateNodeBlock : public TemplateNodeCreator<TemplateNodeBlock>
3242 {
3243  public:
3245  : TemplateNodeCreator<TemplateNodeBlock>(parser,parent,line)
3246  {
3247  TRACE(("{TemplateNodeBlock(%s)\n",data.data()));
3248  m_blockName = data;
3249  if (m_blockName.isEmpty())
3250  {
3251  parser->warn(parser->templateName(),line,"block tag without name");
3252  }
3253  QStrList stopAt;
3254  stopAt.append("endblock");
3255  parser->parse(this,line,stopAt,m_nodes);
3256  parser->removeNextToken(); // skip over endblock
3257  TRACE(("}TemplateNodeBlock(%s)\n",data.data()));
3258  }
3259 
3261  {
3262  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
3263  if (ci==0) return; // should not happen
3265  TemplateImpl *t = getTemplate();
3266  if (t)
3267  {
3268  // remove block from the context, so block.super can work
3269  TemplateNodeBlock *nb = ci->blockContext()->pop(m_blockName);
3270  if (nb) // block is overruled
3271  {
3272  ci->push();
3273  QGString super;
3274  FTextStream ss(&super);
3275  // get super block of block nb
3276  TemplateNodeBlock *sb = ci->blockContext()->get(m_blockName);
3277  if (sb && sb!=nb && sb!=this) // nb and sb both overrule this block
3278  {
3279  sb->render(ss,c); // render parent of nb to string
3280  }
3281  else if (nb!=this) // only nb overrules this block
3282  {
3283  m_nodes.render(ss,c); // render parent of nb to string
3284  }
3285  // add 'block.super' variable to allow access to parent block content
3287  superBlock->set("super",TemplateVariant(super.data(),TRUE));
3288  ci->set("block",superBlock.get());
3289  // render the overruled block contents
3290  t->engine()->enterBlock(nb->m_templateName,nb->m_blockName,nb->m_line);
3291  nb->m_nodes.render(ts,c);
3292  t->engine()->leaveBlock();
3293  ci->pop();
3294  // re-add block to the context
3295  ci->blockContext()->push(nb);
3296  }
3297  else // block has no overrule
3298  {
3299  t->engine()->enterBlock(m_templateName,m_blockName,m_line);
3300  m_nodes.render(ts,c);
3301  t->engine()->leaveBlock();
3302  }
3303  }
3304  }
3305 
3306  QCString name() const
3307  {
3308  return m_blockName;
3309  }
3310 
3311  private:
3314 };
3315 
3316 //----------------------------------------------------------
3317 
3318 /** @brief Class representing a 'extend' tag in a template */
3319 class TemplateNodeExtend : public TemplateNodeCreator<TemplateNodeExtend>
3320 {
3321  public:
3323  : TemplateNodeCreator<TemplateNodeExtend>(parser,parent,line)
3324  {
3325  TRACE(("{TemplateNodeExtend(%s)\n",data.data()));
3326  ExpressionParser ep(parser,line);
3327  if (data.isEmpty())
3328  {
3329  parser->warn(m_templateName,line,"extend tag is missing template file argument");
3330  }
3331  m_extendExpr = ep.parse(data);
3332  QStrList stopAt;
3333  parser->parse(this,line,stopAt,m_nodes);
3334  TRACE(("}TemplateNodeExtend(%s)\n",data.data()));
3335  }
3337  {
3338  delete m_extendExpr;
3339  }
3340 
3342  {
3343  TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c);
3344  if (ci==0) return; // should not happen
3346  if (m_extendExpr==0) return;
3347 
3348  QCString extendFile = m_extendExpr->resolve(c).toString();
3349  if (extendFile.isEmpty())
3350  {
3351  ci->warn(m_templateName,m_line,"invalid parameter for extend command");
3352  }
3353 
3354  // goto root of tree (template node)
3355  TemplateImpl *t = getTemplate();
3356  if (t)
3357  {
3358  Template *bt = t->engine()->loadByName(extendFile,m_line);
3359  TemplateImpl *baseTemplate = bt ? dynamic_cast<TemplateImpl*>(bt) : 0;
3360  if (baseTemplate)
3361  {
3362  // fill block context
3363  TemplateBlockContext *bc = ci->blockContext();
3364 
3365  // add overruling blocks to the context
3366  QListIterator<TemplateNode> li(m_nodes);
3367  TemplateNode *n;
3368  for (li.toFirst();(n=li.current());++li)
3369  {
3370  TemplateNodeBlock *nb = dynamic_cast<TemplateNodeBlock*>(n);
3371  if (nb)
3372  {
3373  bc->add(nb);
3374  }
3375  TemplateNodeMsg *msg = dynamic_cast<TemplateNodeMsg*>(n);
3376  if (msg)
3377  {
3378  msg->render(ts,c);
3379  }
3380  }
3381 
3382  // render the base template with the given context
3383  baseTemplate->render(ts,c);
3384 
3385  // clean up
3386  bc->clear();
3387  t->engine()->unload(t);
3388  }
3389  else
3390  {
3391  ci->warn(m_templateName,m_line,"failed to load template %s for extend",extendFile.data());
3392  }
3393  }
3394  }
3395 
3396  private:
3399 };
3400 
3401 /** @brief Class representing an 'include' tag in a template */
3402 class TemplateNodeInclude : public TemplateNodeCreator<TemplateNodeInclude>
3403 {
3404  public:
3406  : TemplateNodeCreator<TemplateNodeInclude>(parser,parent,line)
3407  {
3408  TRACE(("TemplateNodeInclude(%s)\n",data.data()));
3409  ExpressionParser ep(parser,line);
3410  if (data.isEmpty())
3411  {
3412  parser->warn(m_templateName,line,"include tag is missing template file argument");
3413  }
3414  m_includeExpr = ep.parse(data);
3415  }
3417  {
3418  delete m_includeExpr;
3419  }
3421  {
3422  TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c);
3423  if (ci==0) return; // should not happen
3425  if (m_includeExpr)
3426  {
3427  QCString includeFile = m_includeExpr->resolve(c).toString();
3428  if (includeFile.isEmpty())
3429  {
3430  ci->warn(m_templateName,m_line,"invalid parameter for include command\n");
3431  }
3432  else
3433  {
3434  TemplateImpl *t = getTemplate();
3435  if (t)
3436  {
3437  Template *it = t->engine()->loadByName(includeFile,m_line);
3438  TemplateImpl *incTemplate = it ? dynamic_cast<TemplateImpl*>(it) : 0;
3439  if (incTemplate)
3440  {
3441  incTemplate->render(ts,c);
3442  t->engine()->unload(t);
3443  }
3444  else
3445  {
3446  ci->warn(m_templateName,m_line,"failed to load template '%s' for include",includeFile.data()?includeFile.data():"");
3447  }
3448  }
3449  }
3450  }
3451  }
3452 
3453  private:
3455 };
3456 
3457 //----------------------------------------------------------
3458 
3460 {
3461  const char *src = s.data();
3462  if (src)
3463  {
3464  char *dst = s.data();
3465  char c;
3466  bool skipSpaces=TRUE;
3467  while ((c=*src++))
3468  {
3469  if (c=='\n') { *dst++=c; skipSpaces=TRUE; }
3470  else if (c==' ' && skipSpaces) {}
3471  else { *dst++=c; skipSpaces=FALSE; }
3472  }
3473  *dst='\0';
3474  }
3475 }
3476 
3477 /** @brief Class representing an 'create' tag in a template */
3478 class TemplateNodeCreate : public TemplateNodeCreator<TemplateNodeCreate>
3479 {
3480  public:
3482  : TemplateNodeCreator<TemplateNodeCreate>(parser,parent,line), m_templateExpr(0), m_fileExpr(0)
3483  {
3484  TRACE(("TemplateNodeCreate(%s)\n",data.data()));
3485  ExpressionParser ep(parser,line);
3486  if (data.isEmpty())
3487  {
3488  parser->warn(m_templateName,line,"create tag is missing arguments");
3489  }
3490  int i = data.find(" from ");
3491  if (i==-1)
3492  {
3493  if (data.right(3)==" from")
3494  {
3495  parser->warn(m_templateName,line,"create is missing template name after 'from' keyword");
3496  }
3497  else if (data=="from")
3498  {
3499  parser->warn(m_templateName,line,"create needs a file name and a template name");
3500  }
3501  else
3502  {
3503  parser->warn(m_templateName,line,"create is missing 'from' keyword");
3504  }
3505  }
3506  else
3507  {
3508  ExpressionParser ep(parser,line);
3509  m_fileExpr = ep.parse(data.left(i).stripWhiteSpace());
3510  m_templateExpr = ep.parse(data.mid(i+6).stripWhiteSpace());
3511  }
3512  }
3514  {
3515  delete m_templateExpr;
3516  delete m_fileExpr;
3517  }
3519  {
3520  TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c);
3521  if (ci==0) return; // should not happen
3523  if (m_templateExpr && m_fileExpr)
3524  {
3525  QCString templateFile = m_templateExpr->resolve(c).toString();
3526  QCString outputFile = m_fileExpr->resolve(c).toString();
3527  if (templateFile.isEmpty())
3528  {
3529  ci->warn(m_templateName,m_line,"empty template name parameter for create command\n");
3530  }
3531  else if (outputFile.isEmpty())
3532  {
3533  ci->warn(m_templateName,m_line,"empty file name parameter for create command\n");
3534  }
3535  else
3536  {
3537  TemplateImpl *t = getTemplate();
3538  if (t)
3539  {
3540  QCString extension=outputFile;
3541  int i=extension.findRev('.');
3542  if (i!=-1)
3543  {
3544  extension=extension.right(extension.length()-i-1);
3545  }
3546  t->engine()->setOutputExtension(extension);
3547  Template *ct = t->engine()->loadByName(templateFile,m_line);
3548  TemplateImpl *createTemplate = ct ? dynamic_cast<TemplateImpl*>(ct) : 0;
3549  if (createTemplate)
3550  {
3551  mkpath(ci,outputFile);
3552  if (!ci->outputDirectory().isEmpty())
3553  {
3554  outputFile.prepend(ci->outputDirectory()+"/");
3555  }
3556  //printf("NoteCreate(%s)\n",outputFile.data());
3557  QFile f(outputFile);
3558  if (f.open(IO_WriteOnly))
3559  {
3560  TemplateEscapeIntf *escIntf = ci->escapeIntf();
3561  ci->selectEscapeIntf(extension);
3562  FTextStream ts(&f);
3563  QGString out;
3564  FTextStream os(&out);
3565  createTemplate->render(os,c);
3567  ts << out;
3568  t->engine()->unload(t);
3569  ci->setActiveEscapeIntf(escIntf);
3570  }
3571  else
3572  {
3573  ci->warn(m_templateName,m_line,"failed to open output file '%s' for create command",outputFile.data());
3574  }
3575  }
3576  else
3577  {
3578  ci->warn(m_templateName,m_line,"failed to load template '%s' for include",templateFile.data());
3579  }
3580  t->engine()->setOutputExtension("");
3581  }
3582  }
3583  }
3584  }
3585 
3586  private:
3589 };
3590 
3591 //----------------------------------------------------------
3592 
3593 /** @brief Class representing an 'tree' tag in a template */
3594 class TemplateNodeTree : public TemplateNodeCreator<TemplateNodeTree>
3595 {
3597  {
3599  : object(o), list(l), templateCtx(c) {}
3603  };
3604  public:
3606  : TemplateNodeCreator<TemplateNodeTree>(parser,parent,line)
3607  {
3608  TRACE(("{TemplateNodeTree(%s)\n",data.data()));
3609  ExpressionParser ep(parser,line);
3610  if (data.isEmpty())
3611  {
3612  parser->warn(m_templateName,line,"recursetree tag is missing data argument");
3613  }
3614  m_treeExpr = ep.parse(data);
3615  QStrList stopAt;
3616  stopAt.append("endrecursetree");
3617  parser->parse(this,line,stopAt,m_treeNodes);
3618  parser->removeNextToken(); // skip over endrecursetree
3619  TRACE(("}TemplateNodeTree(%s)\n",data.data()));
3620  }
3622  {
3623  delete m_treeExpr;
3624  }
3626  {
3627  return TemplateVariant(((TreeContext*)ctx)->object->
3628  renderChildren((const TreeContext*)ctx),TRUE);
3629  }
3631  {
3632  //printf("TemplateNodeTree::renderChildren(%d)\n",ctx->list->count());
3633  // render all children of node to a string and return it
3634  TemplateContext *c = ctx->templateCtx;
3635  TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c);
3636  if (ci==0) return QCString(); // should not happen
3637  QGString result;
3638  FTextStream ss(&result);
3639  c->push();
3640  TemplateVariant node;
3642  for (it->toFirst();(it->current(node));it->toNext())
3643  {
3644  c->set("node",node);
3645  bool hasChildren=FALSE;
3646  const TemplateStructIntf *ns = node.toStruct();
3647  if (ns) // node is a struct
3648  {
3649  TemplateVariant v = ns->get("children");
3650  if (v.isValid()) // with a field 'children'
3651  {
3652  const TemplateListIntf *list = v.toList();
3653  if (list && list->count()>0) // non-empty list
3654  {
3655  TreeContext childCtx(this,list,ctx->templateCtx);
3656  TemplateVariant children(TemplateVariant::Delegate::fromFunction(&childCtx,renderChildrenStub));
3657  children.setRaw(TRUE);
3658  c->set("children",children);
3659  m_treeNodes.render(ss,c);
3660  hasChildren=TRUE;
3661  }
3662  else if (list==0)
3663  {
3664  ci->warn(m_templateName,m_line,"recursetree: children attribute has type '%s' instead of list\n",v.typeAsString().data());
3665  }
3666  }
3667  //else
3668  //{
3669  // ci->warn(m_templateName,m_line,"recursetree: children attribute is not valid");
3670  //}
3671  }
3672  if (!hasChildren)
3673  {
3674  c->set("children",TemplateVariant("")); // provide default
3675  m_treeNodes.render(ss,c);
3676  }
3677  }
3678  c->pop();
3679  delete it;
3680  return result.data();
3681  }
3683  {
3684  //printf("TemplateNodeTree::render()\n");
3685  TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c);
3686  if (ci==0) return; // should not happen
3688  TemplateVariant v = m_treeExpr->resolve(c);
3689  const TemplateListIntf *list = v.toList();
3690  if (list)
3691  {
3692  TreeContext ctx(this,list,c);
3693  ts << renderChildren(&ctx);
3694  }
3695  else
3696  {
3697  ci->warn(m_templateName,m_line,"recursetree's argument should be a list type");
3698  }
3699  }
3700 
3701  private:
3704 };
3705 
3706 //----------------------------------------------------------
3707 
3708 /** @brief Class representing an 'indexentry' tag in a template */
3709 class TemplateNodeIndexEntry : public TemplateNodeCreator<TemplateNodeIndexEntry>
3710 {
3711  struct Mapping
3712  {
3713  Mapping(const QCString &n,ExprAst *e) : name(n), value(e) {}
3714  ~Mapping() { delete value; }
3717  };
3718  public:
3720  : TemplateNodeCreator<TemplateNodeIndexEntry>(parser,parent,line)
3721  {
3722  TRACE(("{TemplateNodeIndexEntry(%s)\n",data.data()));
3723  m_args.setAutoDelete(TRUE);
3724  ExpressionParser expParser(parser,line);
3725  QValueList<QCString> args = split(data," ");
3726  QValueListIterator<QCString> it = args.begin();
3727  if (it==args.end() || (*it).find('=')!=-1)
3728  {
3729  parser->warn(parser->templateName(),line,"Missing name for indexentry tag");
3730  }
3731  else
3732  {
3733  m_name = *it;
3734  ++it;
3735  while (it!=args.end())
3736  {
3737  QCString arg = *it;
3738  int j=arg.find('=');
3739  if (j>0)
3740  {
3741  ExprAst *expr = expParser.parse(arg.mid(j+1));
3742  if (expr)
3743  {
3744  m_args.append(new Mapping(arg.left(j),expr));
3745  }
3746  }
3747  else
3748  {
3749  parser->warn(parser->templateName(),line,"invalid argument '%s' for indexentry tag",arg.data());
3750  }
3751  ++it;
3752  }
3753  }
3754  TRACE(("}TemplateNodeIndexEntry(%s)\n",data.data()));
3755  }
3757  {
3758  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
3759  if (ci==0) return; // should not happen
3760  if (!m_name.isEmpty())
3761  {
3763  QListIterator<Mapping> it(m_args);
3764  Mapping *mapping;
3766  for (it.toFirst();(mapping=it.current());++it)
3767  {
3768  list.append(TemplateKeyValue(mapping->name,mapping->value->resolve(c)));
3769  }
3770  ci->addIndexEntry(m_name,list);
3771  }
3772  }
3773  private:
3776 };
3777 
3778 //----------------------------------------------------------
3779 
3780 /** @brief Class representing an 'opensubindex' tag in a template */
3781 class TemplateNodeOpenSubIndex : public TemplateNodeCreator<TemplateNodeOpenSubIndex>
3782 {
3783  public:
3785  : TemplateNodeCreator<TemplateNodeOpenSubIndex>(parser,parent,line)
3786  {
3787  TRACE(("{TemplateNodeOpenSubIndex(%s)\n",data.data()));
3788  m_name = data.stripWhiteSpace();
3789  if (m_name.isEmpty())
3790  {
3791  parser->warn(parser->templateName(),line,"Missing argument for opensubindex tag");
3792  }
3793  else if (m_name.find(' ')!=-1)
3794  {
3795  parser->warn(parser->templateName(),line,"Expected single argument for opensubindex tag got '%s'",data.data());
3796  m_name="";
3797  }
3798  TRACE(("}TemplateNodeOpenSubIndex(%s)\n",data.data()));
3799  }
3801  {
3802  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
3803  if (ci==0) return; // should not happen
3804  if (!m_name.isEmpty())
3805  {
3807  ci->openSubIndex(m_name);
3808  }
3809  }
3810  private:
3812 };
3813 
3814 //----------------------------------------------------------
3815 
3816 /** @brief Class representing an 'closesubindex' tag in a template */
3817 class TemplateNodeCloseSubIndex : public TemplateNodeCreator<TemplateNodeCloseSubIndex>
3818 {
3819  public:
3821  : TemplateNodeCreator<TemplateNodeCloseSubIndex>(parser,parent,line)
3822  {
3823  TRACE(("{TemplateNodeCloseSubIndex(%s)\n",data.data()));
3824  m_name = data.stripWhiteSpace();
3825  if (m_name.isEmpty())
3826  {
3827  parser->warn(parser->templateName(),line,"Missing argument for closesubindex tag");
3828  }
3829  else if (m_name.find(' ')!=-1 || m_name.isEmpty())
3830  {
3831  parser->warn(parser->templateName(),line,"Expected single argument for closesubindex tag got '%s'",data.data());
3832  m_name="";
3833  }
3834  TRACE(("}TemplateNodeCloseSubIndex(%s)\n",data.data()));
3835  }
3837  {
3838  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
3839  if (ci==0) return; // should not happen
3840  if (!m_name.isEmpty())
3841  {
3843  ci->closeSubIndex(m_name);
3844  }
3845  }
3846  private:
3848 };
3849 
3850 
3851 //----------------------------------------------------------
3852 
3853 /** @brief Class representing an 'with' tag in a template */
3854 class TemplateNodeWith : public TemplateNodeCreator<TemplateNodeWith>
3855 {
3856  struct Mapping
3857  {
3858  Mapping(const QCString &n,ExprAst *e) : name(n), value(e) {}
3859  ~Mapping() { delete value; }
3862  };
3863  public:
3865  : TemplateNodeCreator<TemplateNodeWith>(parser,parent,line)
3866  {
3867  TRACE(("{TemplateNodeWith(%s)\n",data.data()));
3868  m_args.setAutoDelete(TRUE);
3869  ExpressionParser expParser(parser,line);
3870  QCString filteredData = removeSpacesAroundEquals(data);
3871  QValueList<QCString> args = split(filteredData," ");
3872  QValueListIterator<QCString> it = args.begin();
3873  while (it!=args.end())
3874  {
3875  QCString arg = *it;
3876  int j=arg.find('=');
3877  if (j>0)
3878  {
3879  ExprAst *expr = expParser.parse(arg.mid(j+1));
3880  if (expr)
3881  {
3882  m_args.append(new Mapping(arg.left(j),expr));
3883  }
3884  }
3885  else
3886  {
3887  parser->warn(parser->templateName(),line,"invalid argument '%s' for 'with' tag",arg.data());
3888  }
3889  ++it;
3890  }
3891  QStrList stopAt;
3892  stopAt.append("endwith");
3893  parser->parse(this,line,stopAt,m_nodes);
3894  parser->removeNextToken(); // skip over endwith
3895  TRACE(("}TemplateNodeWith(%s)\n",data.data()));
3896  }
3898  {
3899  }
3901  {
3902  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
3903  if (ci==0) return; // should not happen
3905  c->push();
3906  QListIterator<Mapping> it(m_args);
3907  Mapping *mapping;
3908  for (it.toFirst();(mapping=it.current());++it)
3909  {
3910  TemplateVariant value = mapping->value->resolve(c);
3911  ci->set(mapping->name,value);
3912  }
3913  m_nodes.render(ts,c);
3914  c->pop();
3915  }
3916  private:
3919 };
3920 
3921 //----------------------------------------------------------
3922 
3923 /** @brief Class representing an 'cycle' tag in a template */
3924 class TemplateNodeCycle : public TemplateNodeCreator<TemplateNodeCycle>
3925 {
3926  public:
3928  : TemplateNodeCreator<TemplateNodeCycle>(parser,parent,line)
3929  {
3930  TRACE(("{TemplateNodeCycle(%s)\n",data.data()));
3931  m_args.setAutoDelete(TRUE);
3932  m_index=0;
3933  ExpressionParser expParser(parser,line);
3934  QValueList<QCString> args = split(data," ");
3935  QValueListIterator<QCString> it = args.begin();
3936  while (it!=args.end())
3937  {
3938  ExprAst *expr = expParser.parse(*it);
3939  if (expr)
3940  {
3941  m_args.append(expr);
3942  }
3943  ++it;
3944  }
3945  if (m_args.count()<2)
3946  {
3947  parser->warn(parser->templateName(),line,"expected at least two arguments for cycle command, got %d",m_args.count());
3948  }
3949  TRACE(("}TemplateNodeCycle(%s)\n",data.data()));
3950  }
3952  {
3953  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
3955  if (m_index<m_args.count())
3956  {
3957  TemplateVariant v = m_args.at(m_index)->resolve(c);
3959  {
3961  }
3962  if (ci->escapeIntf() && !v.raw())
3963  {
3964  ts << ci->escapeIntf()->escape(v.toString());
3965  }
3966  else
3967  {
3968  ts << v.toString();
3969  }
3970  }
3971  if (++m_index==m_args.count()) // wrap around
3972  {
3973  m_index=0;
3974  }
3975  }
3976  private:
3979 };
3980 
3981 //----------------------------------------------------------
3982 
3983 /** @brief Class representing an 'set' tag in a template */
3984 class TemplateNodeSet : public TemplateNodeCreator<TemplateNodeSet>
3985 {
3986  struct Mapping
3987  {
3988  Mapping(const QCString &n,ExprAst *e) : name(n), value(e) {}
3989  ~Mapping() { delete value; }
3992  };
3993  public:
3995  : TemplateNodeCreator<TemplateNodeSet>(parser,parent,line), m_mapping(0)
3996  {
3997  TRACE(("{TemplateNodeSet(%s)\n",data.data()));
3998  ExpressionParser expParser(parser,line);
3999  // data format: name=expression
4000  int j=data.find('=');
4001  ExprAst *expr = 0;
4002  if (j>0 && (expr = expParser.parse(data.mid(j+1))))
4003  {
4004  m_mapping = new Mapping(data.left(j),expr);
4005  }
4006  TRACE(("}TemplateNodeSet(%s)\n",data.data()));
4007  }
4009  {
4010  delete m_mapping;
4011  }
4013  {
4014  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
4015  if (ci==0) return; // should not happen
4017  if (m_mapping)
4018  {
4019  TemplateVariant value = m_mapping->value->resolve(c);
4020  ci->set(m_mapping->name,value);
4021  }
4022  }
4023  private:
4025 };
4026 
4027 //----------------------------------------------------------
4028 
4029 /** @brief Class representing an 'spaceless' tag in a template */
4030 class TemplateNodeSpaceless : public TemplateNodeCreator<TemplateNodeSpaceless>
4031 {
4032  public:
4034  : TemplateNodeCreator<TemplateNodeSpaceless>(parser,parent,line)
4035  {
4036  TRACE(("{TemplateNodeSpaceless()\n"));
4037  QStrList stopAt;
4038  stopAt.append("endspaceless");
4039  parser->parse(this,line,stopAt,m_nodes);
4040  parser->removeNextToken(); // skip over endwith
4041  TRACE(("}TemplateNodeSpaceless()\n"));
4042  }
4044  {
4045  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
4046  if (ci==0) return; // should not happen
4048  bool wasSpaceless = ci->spacelessEnabled();
4049  ci->enableSpaceless(TRUE);
4050  m_nodes.render(ts,c);
4051  ci->enableSpaceless(wasSpaceless);
4052  }
4053  private:
4055 };
4056 
4057 //----------------------------------------------------------
4058 
4059 /** @brief Class representing an 'markers' tag in a template */
4060 class TemplateNodeMarkers : public TemplateNodeCreator<TemplateNodeMarkers>
4061 {
4062  public:
4064  : TemplateNodeCreator<TemplateNodeMarkers>(parser,parent,line), m_listExpr(0), m_patternExpr(0)
4065  {
4066  TRACE(("{TemplateNodeMarkers(%s)\n",data.data()));
4067  int i = data.find(" in ");
4068  int w = data.find(" with ");
4069  if (i==-1 || w==-1 || w<i)
4070  {
4071  parser->warn(m_templateName,line,"markers tag as wrong format. Expected: markers <var> in <list> with <string_with_markers>");
4072  }
4073  else
4074  {
4075  ExpressionParser expParser(parser,line);
4076  m_var = data.left(i);
4077  m_listExpr = expParser.parse(data.mid(i+4,w-i-4));
4078  m_patternExpr = expParser.parse(data.right(data.length()-w-6));
4079  }
4080  QStrList stopAt;
4081  stopAt.append("endmarkers");
4082  parser->parse(this,line,stopAt,m_nodes);
4083  parser->removeNextToken(); // skip over endmarkers
4084  TRACE(("}TemplateNodeMarkers(%s)\n",data.data()));
4085  }
4087  {
4088  delete m_listExpr;
4089  delete m_patternExpr;
4090  }
4092  {
4093  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
4094  if (ci==0) return; // should not happen
4096  if (!m_var.isEmpty() && m_listExpr && m_patternExpr)
4097  {
4098  TemplateVariant v = m_listExpr->resolve(c);
4099  const TemplateListIntf *list = v.toList();
4100  TemplateVariant patternStr = m_patternExpr->resolve(c);
4101  if (list)
4102  {
4103  if (patternStr.type()==TemplateVariant::String)
4104  {
4106  c->push();
4107  QCString str = patternStr.toString();
4108  QRegExp marker("@[0-9]+"); // pattern for a marker, i.e. @0, @1 ... @12, etc
4109  int index=0,newIndex,matchLen;
4110  while ((newIndex=marker.match(str,index,&matchLen))!=-1)
4111  {
4112  ts << str.mid(index,newIndex-index); // write text before marker
4113  bool ok;
4114  uint entryIndex = str.mid(newIndex+1,matchLen-1).toUInt(&ok); // get marker id
4116  uint i=0;
4117  // search for list element at position id
4118  for (it->toFirst(); (it->current(var)) && i<entryIndex; it->toNext(),i++) {}
4119  if (ok && i==entryIndex) // found element
4120  {
4122  s->set("id",(int)i);
4123  c->set("markers",s.get());
4124  c->set(m_var,var); // define local variable to hold element of list type
4125  bool wasSpaceless = ci->spacelessEnabled();
4126  ci->enableSpaceless(TRUE);
4127  m_nodes.render(ts,c);
4128  ci->enableSpaceless(wasSpaceless);
4129  }
4130  else if (!ok)
4131  {
4132  ci->warn(m_templateName,m_line,"markers pattern string has invalid markers '%s'",str.data());
4133  }
4134  else if (i<entryIndex)
4135  {
4136  ci->warn(m_templateName,m_line,"markers list does not an element for marker position %d",i);
4137  }
4138  index=newIndex+matchLen; // set index just after marker
4139  }
4140  ts << str.right(str.length()-index); // write text after last marker
4141  c->pop();
4142  delete it;
4143  }
4144  else
4145  {
4146  ci->warn(m_templateName,m_line,"markers requires a parameter of string type after 'with'!");
4147  }
4148  }
4149  else
4150  {
4151  ci->warn(m_templateName,m_line,"markers requires a parameter of list type after 'in'!");
4152  }
4153  }
4154  }
4155  private:
4160 };
4161 
4162 //----------------------------------------------------------
4163 
4164 /** @brief Class representing an 'tabbing' tag in a template */
4165 class TemplateNodeTabbing : public TemplateNodeCreator<TemplateNodeTabbing>
4166 {
4167  public:
4169  : TemplateNodeCreator<TemplateNodeTabbing>(parser,parent,line)
4170  {
4171  TRACE(("{TemplateNodeTabbing()\n"));
4172  QStrList stopAt;
4173  stopAt.append("endtabbing");
4174  parser->parse(this,line,stopAt,m_nodes);
4175  parser->removeNextToken(); // skip over endtabbing
4176  TRACE(("}TemplateNodeTabbing()\n"));
4177  }
4179  {
4180  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
4181  if (ci==0) return; // should not happen
4183  bool wasTabbing = ci->tabbingEnabled();
4184  ci->enableTabbing(TRUE);
4185  m_nodes.render(ts,c);
4186  ci->enableTabbing(wasTabbing);
4187  }
4188  private:
4190 };
4191 
4192 //----------------------------------------------------------
4193 
4194 /** @brief Class representing an 'markers' tag in a template */
4195 class TemplateNodeResource : public TemplateNodeCreator<TemplateNodeResource>
4196 {
4197  public:
4199  : TemplateNodeCreator<TemplateNodeResource>(parser,parent,line)
4200  {
4201  TRACE(("{TemplateNodeResource(%s)\n",data.data()));
4202  ExpressionParser ep(parser,line);
4203  int i;
4204  if (data.isEmpty())
4205  {
4206  parser->warn(m_templateName,line,"resource tag is missing resource file argument");
4207  m_resExpr=0;
4208  m_asExpr=0;
4209  }
4210  else if ((i=data.find(" as "))!=-1) // resource a as b
4211  {
4212  m_resExpr = ep.parse(data.left(i)); // part before as
4213  m_asExpr = ep.parse(data.mid(i+4)); // part after as
4214  }
4215  else // resource a
4216  {
4217  m_resExpr = ep.parse(data);
4218  m_asExpr = 0;
4219  }
4220  TRACE(("}TemplateNodeResource(%s)\n",data.data()));
4221  }
4223  {
4224  delete m_resExpr;
4225  delete m_asExpr;
4226  }
4228  {
4229  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
4230  if (ci==0) return; // should not happen
4232  if (m_resExpr)
4233  {
4234  QCString resourceFile = m_resExpr->resolve(c).toString();
4235  if (resourceFile.isEmpty())
4236  {
4237  ci->warn(m_templateName,m_line,"invalid parameter for resource command\n");
4238  }
4239  else
4240  {
4242  if (m_asExpr)
4243  {
4244  QCString targetFile = m_asExpr->resolve(c).toString();
4245  mkpath(ci,targetFile);
4246  if (targetFile.isEmpty())
4247  {
4248  ci->warn(m_templateName,m_line,"invalid parameter at right side of 'as' for resource command\n");
4249  }
4250  else
4251  {
4252  ResourceMgr::instance().copyResourceAs(resourceFile,outputDirectory,targetFile);
4253  }
4254  }
4255  else
4256  {
4257  ResourceMgr::instance().copyResource(resourceFile,outputDirectory);
4258  }
4259  }
4260  }
4261  }
4262  private:
4265 };
4266 
4267 //----------------------------------------------------------
4268 
4269 /** @brief Factory class for creating tag AST nodes found in a template */
4271 {
4272  public:
4273  typedef TemplateNode *(*CreateFunc)(TemplateParser *parser,
4275  int line,
4276  const QCString &data);
4277 
4279  {
4280  static TemplateNodeFactory *instance = 0;
4281  if (instance==0) instance = new TemplateNodeFactory;
4282  return instance;
4283  }
4284 
4286  TemplateParser *parser,
4287  TemplateNode *parent,
4288  int line,
4289  const QCString &data)
4290  {
4291  if (m_registry.find(name)==0) return 0;
4292  return ((CreateFunc)m_registry[name])(parser,parent,line,data);
4293  }
4294 
4295  void registerTemplateNode(const QCString &name,CreateFunc func)
4296  {
4297  m_registry.insert(name,(void*)func);
4298  }
4299 
4300  /** @brief Helper class for registering a template AST node */
4301  template<class T> class AutoRegister
4302  {
4303  public:
4305  {
4307  }
4308  };
4309 
4310  private:
4311  QDict<void> m_registry;
4312 };
4313 
4314 // register a handler for each start tag we support
4335 
4336 //----------------------------------------------------------
4337 
4339 {
4340  m_blocks.setAutoDelete(TRUE);
4341 }
4342 
4344 {
4345  QList<TemplateNodeBlock> *list = m_blocks.find(name);
4346  if (list==0 || list->count()==0)
4347  {
4348  return 0;
4349  }
4350  else
4351  {
4352  return list->getLast();
4353  }
4354 }
4355 
4357 {
4358  QList<TemplateNodeBlock> *list = m_blocks.find(name);
4359  if (list==0 || list->count()==0)
4360  {
4361  return 0;
4362  }
4363  else
4364  {
4365  return list->take(list->count()-1);
4366  }
4367 }
4368 
4370 {
4371  QList<TemplateNodeBlock> *list = m_blocks.find(block->name());
4372  if (list==0)
4373  {
4374  list = new QList<TemplateNodeBlock>;
4375  m_blocks.insert(block->name(),list);
4376  }
4377  list->prepend(block);
4378 }
4379 
4381 {
4382  QDictIterator< QList<TemplateNodeBlock> > di(ctx->m_blocks);
4384  for (di.toFirst();(list=di.current());++di)
4385  {
4388  for (li.toFirst();(nb=li.current());++li)
4389  {
4390  add(nb);
4391  }
4392  }
4393 }
4394 
4396 {
4397  m_blocks.clear();
4398 }
4399 
4401 {
4402  QList<TemplateNodeBlock> *list = m_blocks.find(block->name());
4403  if (list==0)
4404  {
4405  list = new QList<TemplateNodeBlock>;
4406  m_blocks.insert(block->name(),list);
4407  }
4408  list->append(block);
4409 }
4410 
4411 
4412 //----------------------------------------------------------
4413 
4414 /** @brief Lexer class for turning a template into a list of tokens */
4416 {
4417  public:
4418  TemplateLexer(const TemplateEngine *engine,const QCString &fileName,const QCString &data);
4419  void tokenize(QList<TemplateToken> &tokens);
4420  void setOpenCloseCharacters(char openChar,char closeChar)
4421  { m_openChar=openChar; m_closeChar=closeChar; }
4422  private:
4423  void addToken(QList<TemplateToken> &tokens,
4424  const char *data,int line,int startPos,int endPos,
4426  void reset();
4432 };
4433 
4435  m_engine(engine), m_fileName(fileName), m_data(data)
4436 {
4437  m_openChar='{';
4438  m_closeChar='}';
4439 }
4440 
4442 {
4443  enum LexerStates
4444  {
4445  StateText,
4446  StateBeginTemplate,
4447  StateTag,
4448  StateEndTag,
4449  StateComment,
4450  StateEndComment,
4451  StateMaybeVar,
4452  StateVariable,
4453  StateEndVariable
4454  };
4455 
4456  const char *p=m_data.data();
4457  if (p==0) return;
4458  int state=StateText;
4459  int pos=0;
4460  int lastTokenPos=0;
4461  int startLinePos=0;
4462  bool emptyOutputLine=TRUE;
4463  int line=1;
4464  char c;
4465  int markStartPos=-1;
4466  for (;(c=*p);p++,pos++)
4467  {
4468  switch (state)
4469  {
4470  case StateText:
4471  if (c==m_openChar) // {{ or {% or {# or something else
4472  {
4473  state=StateBeginTemplate;
4474  }
4475  else if (c!=' ' && c!='\t' && c!='\n') // non-whitepace text
4476  {
4477  emptyOutputLine=FALSE;
4478  }
4479  break;
4480  case StateBeginTemplate:
4481  switch (c)
4482  {
4483  case '%': // {%
4484  state=StateTag;
4485  markStartPos=pos-1;
4486  break;
4487  case '#': // {#
4488  state=StateComment;
4489  markStartPos=pos-1;
4490  break;
4491  case '{': // {{
4492  if (m_openChar=='{')
4493  {
4494  state=StateMaybeVar;
4495  }
4496  else
4497  {
4498  state=StateVariable;
4499  }
4500  markStartPos=pos-1;
4501  break;
4502  default:
4503  state=StateText;
4504  emptyOutputLine=FALSE;
4505  break;
4506  }
4507  break;
4508  case StateTag:
4509  if (c=='\n')
4510  {
4511  warn(m_fileName,line,"unexpected new line inside %c%%...%%%c block",m_openChar,m_closeChar);
4513  }
4514  else if (c=='%') // %} or something else
4515  {
4516  state=StateEndTag;
4517  }
4518  break;
4519  case StateEndTag:
4520  if (c==m_closeChar) // %}
4521  {
4522  // found tag!
4523  state=StateText;
4524  addToken(tokens,m_data.data(),line,lastTokenPos,
4525  emptyOutputLine ? startLinePos : markStartPos,
4527  addToken(tokens,m_data.data(),line,markStartPos+2,
4528  pos-1,TemplateToken::Block);
4529  lastTokenPos = pos+1;
4530  }
4531  else // something else
4532  {
4533  if (c=='\n')
4534  {
4535  warn(m_fileName,line,"unexpected new line inside %c%%...%%%c block",m_openChar,m_closeChar);
4537  }
4538  state=StateTag;
4539  }
4540  break;
4541  case StateComment:
4542  if (c=='\n')
4543  {
4544  warn(m_fileName,line,"unexpected new line inside %c#...#%c block",m_openChar,m_closeChar);
4546  }
4547  else if (c=='#') // #} or something else
4548  {
4549  state=StateEndComment;
4550  }
4551  break;
4552  case StateEndComment:
4553  if (c==m_closeChar) // #}
4554  {
4555  // found comment tag!
4556  state=StateText;
4557  addToken(tokens,m_data.data(),line,lastTokenPos,
4558  emptyOutputLine ? startLinePos : markStartPos,
4560  lastTokenPos = pos+1;
4561  }
4562  else // something else
4563  {
4564  if (c=='\n')
4565  {
4566  warn(m_fileName,line,"unexpected new line inside %c#...#%c block",m_openChar,m_closeChar);
4568  }
4569  state=StateComment;
4570  }
4571  break;
4572  case StateMaybeVar:
4573  switch (c)
4574  {
4575  case '#': // {{#
4576  state=StateComment;
4577  markStartPos=pos-1;
4578  break;
4579  case '%': // {{%
4580  state=StateTag;
4581  markStartPos=pos-1;
4582  break;
4583  default: // {{
4584  state=StateVariable;
4585  break;
4586  }
4587  break;
4588  case StateVariable:
4589  emptyOutputLine=FALSE; // assume a variable expands to content
4590  if (c=='\n')
4591  {
4592  warn(m_fileName,line,"unexpected new line inside %c{...}%c block",m_openChar,m_closeChar);
4594  }
4595  else if (c=='}') // }} or something else
4596  {
4597  state=StateEndVariable;
4598  }
4599  break;
4600  case StateEndVariable:
4601  if (c==m_closeChar) // }}
4602  {
4603  // found variable tag!
4604  state=StateText;
4605  addToken(tokens,m_data.data(),line,lastTokenPos,
4606  emptyOutputLine ? startLinePos : markStartPos,
4608  addToken(tokens,m_data.data(),line,markStartPos+2,
4609  pos-1,TemplateToken::Variable);
4610  lastTokenPos = pos+1;
4611  }
4612  else // something else
4613  {
4614  if (c=='\n')
4615  {
4616  warn(m_fileName,line,"unexpected new line inside %c{...}%c block",m_openChar,m_closeChar);
4618  }
4619  state=StateVariable;
4620  }
4621  break;
4622  }
4623  if (c=='\n') // new line
4624  {
4625  state=StateText;
4626  startLinePos=pos+1;
4627  // if the current line only contain commands and whitespace,
4628  // then skip it in the output by moving lastTokenPos
4629  if (markStartPos!=-1 && emptyOutputLine) lastTokenPos = startLinePos;
4630  // reset markers
4631  markStartPos=-1;
4632  line++;
4633  emptyOutputLine=TRUE;
4634  }
4635  }
4636  if (lastTokenPos<pos)
4637  {
4638  addToken(tokens,m_data.data(),line,
4639  lastTokenPos,pos,
4641  }
4642 }
4643 
4645  const char *data,int line,
4646  int startPos,int endPos,
4648 {
4649  if (startPos<endPos)
4650  {
4651  int len = endPos-startPos+1;
4652  QCString text(len);
4653  qstrncpy(text.rawData(),data+startPos,len);
4654  if (type!=TemplateToken::Text) text = text.stripWhiteSpace();
4655  tokens.append(new TemplateToken(type,text,line));
4656  }
4657 }
4658 
4659 //----------------------------------------------------------
4660 
4662  const QCString &templateName,
4663  QList<TemplateToken> &tokens) :
4664  m_engine(engine), m_templateName(templateName), m_tokens(tokens)
4665 {
4666 }
4667 
4669  TemplateNode *parent,int line,const QStrList &stopAt,
4671 {
4672  TRACE(("{TemplateParser::parse\n"));
4673  // process the tokens. Build node list
4674  while (hasNextToken())
4675  {
4676  TemplateToken *tok = takeNextToken();
4677  //printf("%p:Token type=%d data='%s' line=%d\n",
4678  // parent,tok->type,tok->data.data(),tok->line);
4679  switch(tok->type)
4680  {
4681  case TemplateToken::Text:
4682  nodes.append(new TemplateNodeText(this,parent,tok->line,tok->data));
4683  break;
4684  case TemplateToken::Variable: // {{ var }}
4685  nodes.append(new TemplateNodeVariable(this,parent,tok->line,tok->data));
4686  break;
4687  case TemplateToken::Block: // {% tag %}
4688  {
4689  QCString command = tok->data;
4690  int sep = command.find(' ');
4691  if (sep!=-1)
4692  {
4693  command=command.left(sep);
4694  }
4695  if (stopAt.contains(command))
4696  {
4697  prependToken(tok);
4698  TRACE(("}TemplateParser::parse: stop\n"));
4699  return;
4700  }
4701  QCString arg;
4702  if (sep!=-1)
4703  {
4704  arg = tok->data.mid(sep+1);
4705  }
4707  create(command,this,parent,tok->line,arg);
4708  if (node)
4709  {
4710  nodes.append(node);
4711  }
4712  else if (command=="empty" || command=="else" ||
4713  command=="endif" || command=="endfor" ||
4714  command=="endblock" || command=="endwith" ||
4715  command=="endrecursetree" || command=="endspaceless" ||
4716  command=="endmarkers" || command=="endmsg" ||
4717  command=="endrepeat" || command=="elif" ||
4718  command=="endrange" || command=="endtabbing")
4719  {
4720  warn(m_templateName,tok->line,"Found tag '%s' without matching start tag",command.data());
4721  }
4722  else
4723  {
4724  warn(m_templateName,tok->line,"Unknown tag '%s'",command.data());
4725  }
4726  }
4727  break;
4728  }
4729  delete tok;
4730  }
4731  if (!stopAt.isEmpty())
4732  {
4733  QStrListIterator it(stopAt);
4734  const char *s;
4735  QCString options;
4736  for (it.toFirst();(s=it.current());++it)
4737  {
4738  if (!options.isEmpty()) options+=", ";
4739  options+=s;
4740  }
4741  warn(m_templateName,line,"Unclosed tag in template, expected one of: %s",
4742  options.data());
4743  }
4744  TRACE(("}TemplateParser::parse: last token\n"));
4745 }
4746 
4748 {
4749  return !m_tokens.isEmpty();
4750 }
4751 
4753 {
4754  return m_tokens.take(0);
4755 }
4756 
4758 {
4759  return m_tokens.getFirst();
4760 };
4761 
4763 {
4765 }
4766 
4768 {
4769  m_tokens.prepend(token);
4770 }
4771 
4772 void TemplateParser::warn(const char *fileName,int line,const char *fmt,...) const
4773 {
4774  va_list args;
4775  va_start(args,fmt);
4776  va_warn(fileName,line,fmt,args);
4777  va_end(args);
4778  m_engine->printIncludeContext(fileName,line);
4779 }
4780 
4781 
4782 
4783 //----------------------------------------------------------
4784 
4785 
4787  const QCString &extension)
4788  : TemplateNode(0)
4789 {
4790  m_name = name;
4791  m_engine = engine;
4792  TemplateLexer lexer(engine,name,data);
4793  if (extension=="tex")
4794  {
4795  lexer.setOpenCloseCharacters('<','>');
4796  }
4797  QList<TemplateToken> tokens;
4798  tokens.setAutoDelete(TRUE);
4799  lexer.tokenize(tokens);
4800  TemplateParser parser(engine,name,tokens);
4801  parser.parse(this,1,QStrList(),m_nodes);
4802 }
4803 
4805 {
4806  //printf("deleting template %s\n",m_name.data());
4807 }
4808 
4810 {
4811  TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
4812  if (ci==0) return; // should not happen
4813  if (!m_nodes.isEmpty())
4814  {
4815  TemplateNodeExtend *ne = dynamic_cast<TemplateNodeExtend*>(m_nodes.getFirst());
4816  if (ne==0) // normal template, add blocks to block context
4817  {
4818  TemplateBlockContext *bc = ci->blockContext();
4820  TemplateNode *n;
4821  for (li.toFirst();(n=li.current());++li)
4822  {
4823  TemplateNodeBlock *nb = dynamic_cast<TemplateNodeBlock*>(n);
4824  if (nb)
4825  {
4826  bc->add(nb);
4827  }
4828  }
4829  }
4830  m_nodes.render(ts,c);
4831  }
4832 }
4833 
4834 //----------------------------------------------------------
4835 
4836 /** @brief Private data of the template engine */
4838 {
4840  {
4841  public:
4842  enum Type { Template, Block };
4844  : m_type(type), m_fileName(fileName), m_blockName(blockName), m_line(line) {}
4845  Type type() const { return m_type; }
4846  QCString fileName() const { return m_fileName; }
4847  QCString blockName() const { return m_blockName; }
4848  int line() const { return m_line; }
4849 
4850  private:
4854  int m_line;
4855  };
4856  public:
4857  Private(TemplateEngine *engine) : m_templateCache(17) /*, m_indent(0)*/, m_engine(engine)
4858  {
4859  m_templateCache.setAutoDelete(TRUE);
4860  m_includeStack.setAutoDelete(TRUE);
4861  }
4863  {
4864  //for (int i=0;i<m_indent;i++) printf(" ");
4865  //m_indent++;
4866  //printf("loadByName(%s,%d) {\n",fileName.data(),line);
4867  m_includeStack.append(new IncludeEntry(IncludeEntry::Template,fileName,QCString(),line));
4868  Template *templ = m_templateCache.find(fileName);
4869  if (templ==0)
4870  {
4871  const QCString data = ResourceMgr::instance().getAsString(fileName);
4872  if (!data.isEmpty())
4873  {
4874  templ = new TemplateImpl(m_engine,fileName,data,m_extension);
4875  m_templateCache.insert(fileName,templ);
4876  }
4877  else
4878  {
4879  err("Cound not open template file %s\n",fileName.data());
4880  }
4881  }
4882  return templ;
4883  }
4884  void unload(Template * /*t*/)
4885  {
4886  //(void)t;
4887  //m_indent--;
4888  //for (int i=0;i<m_indent;i++) printf(" ");
4889  //printf("}\n");
4890  m_includeStack.removeLast();
4891  }
4892 
4894  {
4895  //for (int i=0;i<m_indent;i++) printf(" ");
4896  //m_indent++;
4897  //printf("enterBlock(%s,%s,%d) {\n",fileName.data(),blockName.data(),line);
4898  m_includeStack.append(new IncludeEntry(IncludeEntry::Block,fileName,blockName,line));
4899  }
4900 
4901  void leaveBlock()
4902  {
4903  //m_indent--;
4904  //for (int i=0;i<m_indent;i++) printf(" ");
4905  //printf("}\n");
4906  m_includeStack.removeLast();
4907  }
4908 
4909  void printIncludeContext(const char *fileName,int line) const
4910  {
4911  QListIterator<IncludeEntry> li(m_includeStack);
4912  li.toLast();
4913  IncludeEntry *ie=li.current();
4914  while ((ie=li.current()))
4915  {
4916  --li;
4917  IncludeEntry *next=li.current();
4918  if (ie->type()==IncludeEntry::Template)
4919  {
4920  if (next)
4921  {
4922  warn(fileName,line," inside template '%s' included from template '%s' at line %d",ie->fileName().data(),next->fileName().data(),ie->line());
4923  }
4924  }
4925  else // ie->type()==IncludeEntry::Block
4926  {
4927  warn(fileName,line," included by block '%s' inside template '%s' at line %d",ie->blockName().data(),
4928  ie->fileName().data(),ie->line());
4929  }
4930  }
4931  }
4932 
4933  void setOutputExtension(const char *extension)
4934  {
4935  m_extension = extension;
4936  }
4937 
4939  {
4940  return m_extension;
4941  }
4942 
4943  private:
4944  QDict<Template> m_templateCache;
4945  //mutable int m_indent;
4949 };
4950 
4952 {
4953  p = new Private(this);
4954 }
4955 
4957 {
4958  delete p;
4959 }
4960 
4962 {
4963  return new TemplateContextImpl(this);
4964 }
4965 
4967 {
4968  delete ctx;
4969 }
4970 
4972 {
4973  return p->loadByName(fileName,line);
4974 }
4975 
4977 {
4978  p->unload(t);
4979 }
4980 
4982 {
4983  p->enterBlock(fileName,blockName,line);
4984 }
4985 
4987 {
4988  p->leaveBlock();
4989 }
4990 
4992 {
4993  p->printIncludeContext(fileName,line);
4994 }
4995 
4996 void TemplateEngine::setOutputExtension(const char *extension)
4997 {
4998  p->setOutputExtension(extension);
4999 }
5000 
5002 {
5003  return p->outputExtension();
5004 }
5005 
5006 
5007 
static QCString name
Definition: declinfo.cpp:673
TemplateNodeBlock(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:3244
Traverses directory structures and contents in a platform-independent way.
Definition: qdir.h:52
void render(FTextStream &ts, TemplateContext *c)
Definition: template.cpp:2246
ExprAstLiteral(const char *lit)
Definition: template.cpp:1485
void render(FTextStream &, TemplateContext *c)
Definition: template.cpp:3800
end
while True: pbar.update(maxval-len(onlies[E][S])) #print iS, "/", len(onlies[E][S]) found = False for...
virtual ~TemplateStruct()
Definition: template.cpp:255
void setAutoDelete(bool del)
Definition: qstack.h:55
QList< IncludeEntry > m_includeStack
Definition: template.cpp:4947
static TemplateNodeFactory::AutoRegister< TemplateNodeFor > autoRefFor("for")
bool resize(uint newlen)
Definition: qcstring.h:225
static TemplateNodeFactory::AutoRegister< TemplateNodeRange > autoRefRange("range")
char * rawData() const
Definition: qcstring.h:216
void render(FTextStream &ts, TemplateContext *c)
Definition: template.cpp:4178
void enableSpaceless(bool b)
Definition: template.cpp:547
virtual int addRef()
Definition: template.cpp:2290
virtual void pop()=0
void setOpenCloseCharacters(char openChar, char closeChar)
Definition: template.cpp:4420
Class representing an &#39;tabbing&#39; tag in a template.
Definition: template.cpp:4165
Abstract interface for a template context.
Definition: template.h:489
ExprAst * m_templateExpr
Definition: template.cpp:3587
virtual void push()=0
static TemplateFilterFactory::AutoRegister< FilterNoWrap > fNoWrap("nowrap")
Class representing an &#39;create&#39; tag in a template.
Definition: template.cpp:3478
QCString outputDirectory() const
Definition: template.cpp:544
bool removeFirst()
Definition: qlist.h:79
QCString getAsString(const char *name) const
Class representing a token within an expression.
Definition: template.cpp:1702
void printIncludeContext(const char *fileName, int line) const
Definition: template.cpp:4909
char * data() const
Definition: qgstring.h:42
QCString stripWhiteSpace() const
Definition: qcstring.cpp:295
static constexpr double nb
Definition: Units.h:81
static TemplateList * alloc()
Definition: template.cpp:420
static TemplateFilterFactory::AutoRegister< FilterTexLabel > fTexLabel("texLabel")
char * qstrncpy(char *dst, const char *src, uint len)
Definition: qcstring.cpp:557
The implementation of the "divisibleby" filter.
Definition: template.cpp:1260
QList< Entry > entry
Class representing a &#39;for&#39; tag in a template.
Definition: template.cpp:3048
Abstract interface for a template.
Definition: template.h:542
QDict< TemplateVariant > fields
Definition: template.cpp:246
The implementation of the "flatten" filter.
Definition: template.cpp:815
virtual TemplateVariant resolve(TemplateContext *c)
Definition: template.cpp:1500
static TemplateNode * createInstance(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:2667
static QValueList< QCString > split(const QCString &str, const QCString &sep, bool allowEmptyEntries=FALSE, bool cleanup=TRUE)
Definition: template.cpp:50
virtual int count() const
Definition: template.cpp:338
static const char * toString(Type op)
Definition: template.cpp:451
Iterator append(const T &x)
Definition: qvaluelist.h:372
bool spacelessEnabled() const
Definition: template.cpp:550
virtual void set(const char *name, const TemplateVariant &v)
Definition: template.cpp:275
static QCString result
bool isEmpty() const
Definition: qcstring.h:189
The implementation of the "append" filter.
Definition: template.cpp:725
QValueList< QCString > m_vars
Definition: template.cpp:3197
TemplateNodeIndexEntry(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:3719
The implementation of the "length" filter.
Definition: template.cpp:765
The QRegExp class provides pattern matching using regular expressions or wildcards.
Definition: qregexp.h:46
const QCString & literal() const
Definition: template.cpp:1487
virtual int addRef()
Definition: template.cpp:323
virtual ~TemplateContextImpl()
Definition: template.cpp:2310
Class representing operators that can appear in template expressions.
Definition: template.cpp:428
#define Template
Definition: declinfo.cpp:738
void msg(const char *fmt,...)
Definition: message.cpp:107
virtual TemplateVariant resolve(TemplateContext *c)
Definition: template.cpp:1472
ExprAstFilter * m_filter
Definition: template.cpp:1478
Internal class representing the implementation of a template.
Definition: template.cpp:2262
ExprAst * m_endExpr
Definition: template.cpp:3040
ExprAst * m_exp
Definition: template.cpp:1525
TemplateNodeList m_loopNodes
Definition: template.cpp:3198
ExprAst * parseNumber()
Definition: template.cpp:1924
Internal class representing the implementation of a template context.
Definition: template.cpp:511
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &arg)
Definition: template.cpp:624
void setEscapeIntf(const QCString &ext, TemplateEscapeIntf *intf)
Definition: template.cpp:525
QDict< void > m_registry
Definition: template.cpp:1335
uint length() const
Definition: qcstring.h:195
static TemplateFilterFactory::AutoRegister< FilterStripPath > fStripPath("stripPath")
void enterBlock(const QCString &fileName, const QCString &blockName, int line)
Definition: template.cpp:4981
virtual bool current(TemplateVariant &v) const =0
void append(const type *d)
Definition: qlist.h:73
void render(FTextStream &ts, TemplateContext *c)
Definition: template.cpp:2842
virtual void setPath(const QString &path)
Definition: qdir.cpp:248
QCString m_name
Definition: template.cpp:2275
TemplateBlockContext * blockContext()
Definition: template.cpp:2271
Iterator end()
Definition: qvaluelist.h:363
#define IO_WriteOnly
Definition: qiodevice.h:62
The implementation of the "relative" filter.
Definition: template.cpp:1027
TemplateNodeCreate(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:3481
TemplateNode(TemplateNode *parent)
Definition: template.cpp:1642
QCString name() const
Definition: template.cpp:3306
TemplateLexer(const TemplateEngine *engine, const QCString &fileName, const QCString &data)
Definition: template.cpp:4434
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &)
Definition: template.cpp:690
Operator::Type m_operator
Definition: template.cpp:1524
TemplateEngine * m_engine
Definition: template.cpp:2274
static TemplateNodeFactory::AutoRegister< TemplateNodeCloseSubIndex > autoRefCloseSubIndex("closesubindex")
void render(FTextStream &ts, TemplateContext *c)
Definition: template.cpp:4043
void enterBlock(const QCString &fileName, const QCString &blockName, int line)
Definition: template.cpp:4893
ExprAst * m_expr
Definition: template.cpp:1477
Class representing an &#39;indexentry&#39; tag in a template.
Definition: template.cpp:3709
virtual TemplateVariant resolve(TemplateContext *c)
Definition: template.cpp:1512
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &)
Definition: template.cpp:665
virtual TemplateVariant get(const char *name) const =0
T * get() const
Definition: template.h:318
int command
TemplateToken * takeNextToken()
Definition: template.cpp:4752
char & at(uint i) const
Definition: qcstring.h:326
static TemplateNodeFactory::AutoRegister< TemplateNodeSet > autoRefSet("set")
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &)
Definition: template.cpp:646
QDict< QList< TemplateNodeBlock > > m_blocks
Definition: template.cpp:497
static QCString blockName
QCString m_outputDir
Definition: template.cpp:566
virtual QCString escape(const QCString &input)=0
ExpressionParser(const TemplateParser *parser, int line)
Definition: template.cpp:1683
The implementation of the "default" filter.
Definition: template.cpp:792
void render(FTextStream &, TemplateContext *c)
Definition: template.cpp:3836
int compareValues(const ListElem *item1, const ListElem *item2) const
Definition: template.cpp:1103
QCString m_blockName
Definition: template.cpp:3312
ExprAst * parseCompareExpression()
Definition: template.cpp:1787
TemplateListIntf * toList() const
Definition: template.h:256
Coord add(Coord c1, Coord c2)
Definition: restypedef.cpp:23
ExprAstFilter(const char *name, ExprAst *arg)
Definition: template.cpp:1440
Class representing a &#39;for&#39; tag in a template.
Definition: template.cpp:2823
TemplateNodeRepeat(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:2826
ExprAst * parseFilteredVariable()
Definition: template.cpp:1978
TemplateListIntf * m_list
Definition: template.h:297
ListElem(const QCString &k, const TemplateVariant &v)
Definition: template.cpp:954
const bool FALSE
Definition: qglobal.h:370
void tokenize(QList< TemplateToken > &tokens)
Definition: template.cpp:4441
The implementation of the "default" filter.
Definition: template.cpp:1216
bool copyResource(const char *name, const char *targetDir) const
static TemplateNodeFactory::AutoRegister< TemplateNodeSpaceless > autoRefSpaceless("spaceless")
QDict< void > m_registry
Definition: template.cpp:4311
ExprAstUnary(Operator::Type op, ExprAst *exp)
Definition: template.cpp:1509
Definition: types.h:26
static ResourceMgr & instance()
Definition: resourcemgr.cpp:35
Class representing a string literal in the AST.
Definition: template.cpp:1482
virtual int release()=0
TemplateNodeMsg(TemplateParser *parser, TemplateNode *parent, int line, const QCString &)
Definition: template.cpp:3208
static TemplateFilterFactory::AutoRegister< FilterListSort > fListSort("listsort")
Class representing an &#39;set&#39; tag in a template.
Definition: template.cpp:3984
Definition: qstack.h:46
QCString latexEscapeIndexChars(const char *s, bool insideTabbing)
Definition: util.cpp:6683
static TemplateNodeFactory::AutoRegister< TemplateNodeCycle > autoRefCycle("cycle")
const std::string instance
TemplateNodeList m_emptyNodes
Definition: template.cpp:3199
Default implementation of a context value of type list.
Definition: template.h:376
void render(FTextStream &, TemplateContext *c)
Definition: template.cpp:3756
ExprAstFilterAppl(ExprAst *expr, ExprAstFilter *filter)
Definition: template.cpp:1468
QCString m_name
Definition: template.cpp:1401
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &)
Definition: template.cpp:768
QCString typeAsString() const
Definition: template.h:145
static TemplateNodeFactory::AutoRegister< TemplateNodeIndexEntry > autoRefIndexEntry("indexentry")
TemplateVariant call(const QValueList< TemplateVariant > &args)
Definition: template.h:272
static TemplateNodeFactory::AutoRegister< TemplateNodeExtend > autoRefExtend("extend")
static TemplateFilterFactory::AutoRegister< FilterTexIndex > fTexIndex("texIndex")
TemplateNodeBlock * get(const QCString &name) const
Definition: template.cpp:4343
const TemplateToken * currentToken() const
Definition: template.cpp:4757
QCString left(uint len) const
Definition: qcstring.cpp:213
bool toBool() const
Definition: template.cpp:207
The QString class provides an abstraction of Unicode text and the classic C null-terminated char arra...
Definition: qstring.h:350
ExprAst * m_extendExpr
Definition: template.cpp:3397
virtual const TemplateVariant * getRef(const QCString &name) const =0
QDict< TemplateEscapeIntf * > m_escapeIntfDict
Definition: template.cpp:569
auto lit(char arg)
Definition: parse_shims.h:11
static TemplateNodeFactory::AutoRegister< TemplateNodeMsg > autoRefMsg("msg")
void setOutputDirectory(const QCString &dir)
Definition: template.cpp:523
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &)
Definition: template.cpp:1219
void render(FTextStream &ts, TemplateContext *c)
Definition: template.cpp:3682
Class representing an &#39;tree&#39; tag in a template.
Definition: template.cpp:3594
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &)
Definition: template.cpp:1246
TemplateVariant value
Definition: template.cpp:868
QTextStream & hex(QTextStream &s)
Simplified and optimized version of QTextStream.
Definition: ftextstream.h:11
Abstract interface for a context value of type struct.
Definition: template.h:406
string dir
virtual int release()
Definition: template.cpp:328
ExprAst * parseNotExpression()
Definition: template.cpp:1763
int find(char c, int index=0, bool cs=TRUE) const
Definition: qcstring.cpp:41
void render(FTextStream &, TemplateContext *c)
Definition: template.cpp:4227
static TemplateFilterFactory::AutoRegister< FilterPrepend > fPrepend("prepend")
static TemplateVariant getPathFunc(const void *ctx, const QValueList< TemplateVariant > &)
Definition: template.cpp:2499
void closeSubIndex(const QCString &indexName)
Definition: template.cpp:2461
static Delegate fromFunction(const void *obj, StubType func)
Definition: template.h:112
Helper class for creating template AST tag nodes and returning the template for a given node...
Definition: template.cpp:2662
TemplateNodeTree(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:3605
static TemplateFilterFactory::AutoRegister< FilterGet > fGet("get")
Private data of the template engine.
Definition: template.cpp:4837
TemplateParser(const TemplateEngine *engine, const QCString &templateName, QList< TemplateToken > &tokens)
Definition: template.cpp:4661
Class representing a &#39;block&#39; tag in a template.
Definition: template.cpp:3241
The implementation of the "paginate" filter.
Definition: template.cpp:1046
TemplateVariant & operator=(const TemplateVariant &v)
Definition: template.cpp:180
Class representing an &#39;with&#39; tag in a template.
Definition: template.cpp:3854
Delegate m_delegate
Definition: template.h:299
void render(FTextStream &ts, TemplateContext *c)
Definition: template.cpp:3116
Class representing a lexical token in a template.
Definition: template.cpp:2226
static TemplateFilterFactory::AutoRegister< FilterAdd > fAdd("add")
static void getPathListFunc(TemplateStructIntf *entry, TemplateList *list)
Definition: template.cpp:2489
int line() const
Definition: template.cpp:543
void warn(const char *fileName, int line, const char *fmt,...) const
Definition: template.cpp:4772
The QChar class provides a light-weight Unicode character.
Definition: qstring.h:56
virtual void append(const TemplateVariant &v)
Definition: template.cpp:343
ExprAstFilter * parseFilter()
Definition: template.cpp:1997
static TemplateFilterFactory::AutoRegister< FilterPaginate > fPaginate("paginate")
static TemplateFilterFactory::AutoRegister< FilterDivisibleBy > fDivisibleBy("divisibleby")
static QCString args
Definition: declinfo.cpp:674
TemplateNodeOpenSubIndex(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:3784
static QStrList * l
Definition: config.cpp:1044
virtual void toPrev()
Definition: template.cpp:372
Class representing an &#39;include&#39; tag in a template.
Definition: template.cpp:3402
int findRev(char c, int index=-1, bool cs=TRUE) const
Definition: qcstring.cpp:95
TemplateNodeCloseSubIndex(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:3820
Class representing a &#39;extend&#39; tag in a template.
Definition: template.cpp:3319
void render(FTextStream &ts, TemplateContext *c)
Definition: template.cpp:4809
virtual ~TemplateNode()
Definition: template.cpp:1643
void registerTemplateNode(const QCString &name, CreateFunc func)
Definition: template.cpp:4295
Class representing a variable in a template.
Definition: template.cpp:2608
int toInt() const
Definition: template.cpp:222
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &arg)
Definition: template.cpp:795
TemplateNodeInclude(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:3405
static TemplateFilterFactory * instance()
Definition: template.cpp:1297
void printIncludeContext(const char *fileName, int line) const
Definition: template.cpp:4991
ExprAst * m_arg
Definition: template.cpp:1461
QCString m_data
Definition: template.cpp:4429
QCString m_name
Definition: template.cpp:1460
ExprAst * parse(const char *expr)
Definition: template.cpp:1691
TemplateNodeIf(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:2725
TemplateContextImpl(const TemplateEngine *e)
Definition: template.cpp:2299
QCString m_strVal
Definition: template.h:291
QCString data
Definition: template.cpp:2232
Private data of a template list object.
Definition: template.cpp:303
void push(const type *d)
Definition: qstack.h:58
static uint determineSortKey(TemplateStructIntf *s, const QCString &attribName)
Definition: template.cpp:1151
TemplateAutoRef< TemplateStruct > m_indices
Definition: template.cpp:574
Parser for templates.
Definition: template.cpp:1656
static TemplateNodeFactory * instance()
Definition: template.cpp:4278
The implementation of the "prepend" filter.
Definition: template.cpp:745
static QCString removeSpacesAroundEquals(const char *s)
Definition: template.cpp:104
The implementation of the "get" filter.
Definition: template.cpp:621
TemplateImpl(TemplateEngine *e, const QCString &name, const QCString &data, const QCString &extension)
Definition: template.cpp:4786
Factory class for creating tag AST nodes found in a template.
Definition: template.cpp:4270
TemplateContext * createContext() const
Definition: template.cpp:4961
uint contains(const type *d) const
Definition: qinternallist.h:78
static TemplateNodeFactory::AutoRegister< TemplateNodeRepeat > autoRefRepeat("repeat")
TemplateSpacelessIntf * spacelessIntf() const
Definition: template.cpp:546
Class representing a list of AST nodes in a template.
Definition: template.cpp:2239
static TemplateNodeFactory::AutoRegister< TemplateNodeCreate > autoRefCreate("create")
virtual TemplateVariant resolve(TemplateContext *)
Definition: template.cpp:1488
void setOutputExtension(const char *extension)
Definition: template.cpp:4996
TemplateBlockContext m_blockContext
Definition: template.cpp:568
static TemplateNodeFactory::AutoRegister< TemplateNodeMarkers > autoRefMarkers("markers")
TemplateNodeWith(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:3864
ListElem(const QCString &k, const TemplateVariant &v)
Definition: template.cpp:866
ExprAst * m_includeExpr
Definition: template.cpp:3454
TemplateNodeVariable(TemplateParser *parser, TemplateNode *parent, int line, const QCString &var)
Definition: template.cpp:2611
uint count() const
Definition: qlist.h:66
void setActiveEscapeIntf(TemplateEscapeIntf *intf)
Definition: template.cpp:534
uint getUtf8CodeToUpper(const QCString &s, int idx)
Returns one unicode character as ian unsigned interger from utf-8 string, making the character upper ...
Definition: util.cpp:8291
static TemplateFilterFactory::AutoRegister< FilterAlphaIndex > fAlphaIndex("alphaIndex")
ExprAst * parseOrExpression()
Definition: template.cpp:1727
TemplateEscapeIntf * escapeIntf() const
Definition: template.cpp:545
virtual bool mkdir(const QString &dirName, bool acceptAbsPath=TRUE) const
Definition: qdir_unix.cpp:98
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &args)
Definition: template.cpp:881
type * getLast() const
Definition: qlist.h:96
TemplateNode * parent()
Definition: template.cpp:1647
QTextStream & reset(QTextStream &s)
QCString m_fileName
Definition: template.cpp:4428
ExprAstNegate(ExprAst *expr)
Definition: template.cpp:1497
virtual void set(const char *name, const TemplateVariant &v)=0
QCString toString() const
Definition: template.h:232
static TemplateFilterFactory::AutoRegister< FilterGroupBy > fGroupBy("groupBy")
Class representing a number in the AST.
Definition: template.cpp:1372
QValueList< TemplateVariant > elems
Definition: template.cpp:307
TemplateNodeList m_treeNodes
Definition: template.cpp:3703
ExprAst * parseIdentifier()
Definition: template.cpp:1933
type * current() const
Mapping(const QCString &n, ExprAst *e)
Definition: template.cpp:3858
const double e
TemplateStructIntf * m_strukt
Definition: template.h:296
ExprAst * m_expr
Definition: template.cpp:3196
void set(const char *name, const TemplateVariant &v)
Definition: template.cpp:2315
QList< Mapping > m_args
Definition: template.cpp:3775
ExprAst * parseExpression()
Definition: template.cpp:1719
virtual TemplateVariant at(int index) const
Definition: template.cpp:408
int number() const
Definition: template.cpp:1377
Class representing a filter applied to an expression in the AST.
Definition: template.cpp:1465
const TemplateParser * m_parser
Definition: template.cpp:2217
void removeNextToken()
Definition: template.cpp:4762
fileName
Definition: dumpTree.py:9
TemplateNodeBlock * pop(const QCString &name) const
Definition: template.cpp:4356
void unload(Template *)
Definition: template.cpp:4884
bt
Definition: tracks.py:83
#define nodes
uint count() const
Definition: qstack.h:56
Class representing a binary operator in the AST.
Definition: template.cpp:1529
TemplateNodeText(TemplateParser *, TemplateNode *parent, int, const QCString &data)
Definition: template.cpp:2581
The implementation of the "raw" filter.
Definition: template.cpp:643
QList< Mapping > m_args
Definition: template.cpp:3918
TemplateNodeList m_nodes
Definition: template.cpp:3313
bool isEmpty() const
Definition: qstack.h:57
def key(type, name=None)
Definition: graph.py:13
Class representing an &#39;markers&#39; tag in a template.
Definition: template.cpp:4060
void render(FTextStream &ts, TemplateContext *c)
Definition: template.cpp:2587
bool isEmpty() const
Definition: qlist.h:67
Base class for all nodes in the abstract syntax tree of an expression.
Definition: template.cpp:1364
virtual TemplateVariant resolve(TemplateContext *)
Definition: template.cpp:1368
QCString right(uint len) const
Definition: qcstring.cpp:231
const TemplateVariant * getRef(const QCString &name) const
Definition: template.cpp:2393
TemplateNodeSet(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:3994
The implementation of the "texlabel" filter.
Definition: template.cpp:687
The implementation of the "add" filter.
Definition: template.cpp:581
std::void_t< T > n
int compareValues(const ListElem *item1, const ListElem *item2) const
Definition: template.cpp:875
static QCString keyToLabel(uint startLetter)
Definition: template.cpp:1112
bool open(int)
Definition: qfile_unix.cpp:134
int toInt(bool *ok=0) const
Definition: qcstring.cpp:439
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &)
Definition: template.cpp:709
Mapping(const QCString &n, ExprAst *e)
Definition: template.cpp:3988
static QCString keyToLetter(uint startLetter)
Definition: template.cpp:1108
virtual TemplateVariant resolve(TemplateContext *c)
Definition: template.cpp:1416
void sort()
Definition: qlist.h:85
static QString currentDirPath()
Definition: qdir_unix.cpp:141
Class representing an &#39;markers&#39; tag in a template.
Definition: template.cpp:4195
TemplateNodeList m_repeatNodes
Definition: template.cpp:2871
virtual ~ExpressionParser()
Definition: template.cpp:1687
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &n)
Definition: template.cpp:1263
TemplateNodeList m_falseNodes
Definition: template.cpp:2818
static void flatten(TemplateListIntf *tree, TemplateList *list)
Definition: template.cpp:833
QCString templateName() const
Definition: template.cpp:1668
The implementation of the "list" filter.
Definition: template.cpp:662
QValueList< TemplateVariant >::ConstIterator m_it
Definition: template.cpp:399
QDict< Template > m_templateCache
Definition: template.cpp:4944
static TemplateVariant renderChildrenStub(const void *ctx, const QValueList< TemplateVariant > &)
Definition: template.cpp:3625
TemplateEngine * m_engine
Definition: template.cpp:4946
Operator::Type m_operator
Definition: template.cpp:1631
#define Operator
Definition: declinfo.cpp:740
const TemplateEngine * m_engine
Definition: template.cpp:1671
void unload(Template *t)
Definition: template.cpp:4976
Class representing an &#39;cycle&#39; tag in a template.
Definition: template.cpp:3924
ListElem(uint k, const TemplateVariant &v)
Definition: template.cpp:1094
void registerFilter(const QCString &name, FilterFunction *func)
Definition: template.cpp:1319
virtual int count() const =0
TemplateNodeList m_nodes
Definition: template.cpp:4189
QCString & prepend(const char *s)
Definition: qcstring.cpp:387
ExprAstFunctionVariable(ExprAst *var, const QList< ExprAst > &args)
Definition: template.cpp:1407
static TemplateFilterFactory::AutoRegister< FilterRaw > fRaw("raw")
Abstract interface for a iterator of a list.
Definition: template.h:333
p
Definition: test.py:223
QList< GuardedNodes > m_ifGuardedNodes
Definition: template.cpp:2817
QList< ExprAst > m_args
Definition: template.cpp:2654
void render(FTextStream &ts, TemplateContext *c)
Definition: template.cpp:4091
QCString latexEscapeLabelName(const char *s, bool insideTabbing)
Definition: util.cpp:6647
void append(const type *d)
Definition: qinternallist.h:61
Class representing a negation (not) operator in the AST.
Definition: template.cpp:1494
TemplateNode * create(const QCString &name, TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:4285
TemplateVariant value
Definition: template.cpp:506
A bunch of utility functions.
static TemplateNodeFactory::AutoRegister< TemplateNodeOpenSubIndex > autoRefOpenSubIndex("opensubindex")
ExprAst * m_rhs
Definition: template.cpp:1633
Interface used to escape characters in a string.
Definition: template.h:457
const char * data() const
Definition: qcstring.h:207
QList< ExprAst > m_args
Definition: template.cpp:1433
virtual bool current(TemplateVariant &v) const
Definition: template.cpp:384
TemplateBlockContext m_blockContext
Definition: template.cpp:2277
ExprAst * m_treeExpr
Definition: template.cpp:3702
type * current() const
Definition: qlist.h:146
string tmp
Definition: languages.py:63
virtual TemplateListIntf::ConstIterator * createIterator() const
Definition: template.cpp:403
TemplateBlockContext * blockContext()
Definition: template.cpp:2426
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &args)
Definition: template.cpp:969
QCString renderChildren(const TreeContext *ctx)
Definition: template.cpp:3630
static TemplateFilterFactory::AutoRegister< FilterRelative > fRelative("relative")
ExprAst * m_expr
Definition: template.cpp:1503
bool isValid() const
Definition: template.h:161
int compareValues(const ListElem *item1, const ListElem *item2) const
Definition: template.cpp:963
TemplateNodeSpaceless(TemplateParser *parser, TemplateNode *parent, int line, const QCString &)
Definition: template.cpp:4033
type * getFirst() const
Definition: qlist.h:95
static TemplateNodeFactory::AutoRegister< TemplateNodeBlock > autoRefBlock("block")
virtual TemplateListIntf::ConstIterator * createIterator() const =0
ExprAst * m_lhs
Definition: template.cpp:1632
int getPrefixIndex(const QCString &name)
Definition: util.cpp:5144
virtual int addRef()=0
Class holding stacks of blocks available in the context.
Definition: template.cpp:486
TemplateNodeMarkers(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:4063
void render(FTextStream &, TemplateContext *c)
Definition: template.cpp:3518
TemplateEngine * engine() const
Definition: template.cpp:2270
void warn(const char *file, int line, const char *fmt,...)
Definition: message.cpp:183
Class representing an &#39;spaceless&#39; tag in a template.
Definition: template.cpp:4030
virtual TemplateVariant resolve(TemplateContext *c)
Definition: template.cpp:1390
void render(FTextStream &, TemplateContext *c)
Definition: template.cpp:3218
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &)
Definition: template.cpp:818
TemplateNodeList m_nodes
Definition: template.cpp:4156
void err(const char *fmt,...)
Definition: message.cpp:226
virtual ~ExprAst()
Definition: template.cpp:1367
TemplateVariant apply(const TemplateVariant &v, TemplateContext *c)
Definition: template.cpp:1444
type * pop()
Definition: qstack.h:59
void add(TemplateNodeBlock *block)
Definition: template.cpp:4369
const TemplateEngine * m_engine
Definition: template.cpp:563
virtual QCString remove(const QCString &input)=0
static TemplateFilterFactory::AutoRegister< FilterAppend > fAppend("append")
TemplateNodeList m_nodes
Definition: template.cpp:3398
bool raw() const
Definition: template.h:287
const TemplateListIntf * list
Definition: template.cpp:3601
static TemplateNodeFactory::AutoRegister< TemplateNodeIf > autoRefIf("if")
Class representing an &#39;closesubindex&#39; tag in a template.
Definition: template.cpp:3817
Variant type which can hold one value of a fixed set of types.
Definition: template.h:90
static TemplateNodeFactory::AutoRegister< TemplateNodeInclude > autoRefInclude("include")
QCString outputExtension() const
Definition: template.cpp:5001
QCString mid(uint index, uint len=0xffffffff) const
Definition: qcstring.cpp:246
void destroyContext(TemplateContext *ctx)
Definition: template.cpp:4966
ExprAstBinary(Operator::Type op, ExprAst *lhs, ExprAst *rhs)
Definition: template.cpp:1532
static int variantIntValue(const TemplateVariant &v, bool &isInt)
Definition: template.cpp:584
TemplateImpl * getTemplate()
Definition: template.cpp:2674
TemplateVariant apply(const QCString &name, const TemplateVariant &v, const TemplateVariant &arg, bool &ok)
Definition: template.cpp:1304
TemplateVariant get(const QCString &name) const
Definition: template.cpp:2325
int match(const QCString &str, int index=0, int *len=0, bool indexIsStart=TRUE) const
Definition: qregexp.cpp:649
Private data of a template struct object.
Definition: template.cpp:241
The QFile class is an I/O device that operates on files.
Definition: qfile.h:50
Template * loadByName(const QCString &fileName, int fromLine)
Definition: template.cpp:4971
static void stripLeadingWhiteSpace(QGString &s)
Definition: template.cpp:3459
void mkpath(TemplateContextImpl *ci, const QCString &fileName)
Definition: template.cpp:2684
virtual ~TemplateListConstIterator()
Definition: template.cpp:353
Engine to create templates and template contexts.
Definition: template.h:559
TemplateNodeList m_nodes
Definition: template.cpp:3234
ExprAst * parseAndExpression()
Definition: template.cpp:1745
ExprAst * parseAdditiveExpression()
Definition: template.cpp:1813
virtual int release()
Definition: template.cpp:2291
const QCString & name() const
Definition: template.cpp:1443
void render(FTextStream &ts, TemplateContext *c)
Definition: template.cpp:2955
void openSubIndex(const QCString &indexName)
Definition: template.cpp:2440
virtual void render(FTextStream &ts, TemplateContext *c)=0
Class representing a filter in the AST.
Definition: template.cpp:1437
void setRaw(bool b)
Definition: template.h:282
QCString m_templateName
Definition: template.cpp:564
TemplateNodeFor(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:3051
TemplateListConstIterator(const TemplateList &l)
Definition: template.cpp:352
virtual int release()
Definition: template.cpp:265
Class representing a &#39;range&#39; tag in a template.
Definition: template.cpp:2878
QList< TemplateToken > & m_tokens
Definition: template.cpp:1673
A container to store a key-value pair.
Definition: template.cpp:501
ExprAst * m_startExpr
Definition: template.cpp:3039
TemplateStructIntf * m_ref
Definition: template.cpp:2293
std::vector< size_t > Mapping(std::vector< geo::AuxDetGeo * > &adgeo)
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &arg)
Definition: template.cpp:728
virtual void toLast()
Definition: template.cpp:359
int var
Definition: 018_def.c:9
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &arg)
Definition: template.cpp:748
virtual TemplateVariant get(const QCString &name) const =0
ExprAst * parseMultiplicativeExpression()
Definition: template.cpp:1832
void warn(const char *fileName, int line, const char *fmt,...) const
Definition: template.cpp:2431
void leaveBlock()
Definition: template.cpp:4986
TemplateNodeList m_nodes
Definition: template.cpp:3917
ExprAst * parseUnaryExpression()
Definition: template.cpp:1851
The implementation of the "listsort" filter.
Definition: template.cpp:862
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &arg)
Definition: template.cpp:593
virtual int release()=0
TemplateContext * templateCtx
Definition: template.cpp:3602
void push(TemplateNodeBlock *block)
Definition: template.cpp:4400
uint toUInt(bool *ok=0) const
Definition: qcstring.cpp:445
static TemplateFilterFactory::AutoRegister< FilterFlatten > fFlatten("flatten")
static TemplateNodeFactory::AutoRegister< TemplateNodeWith > autoRefWith("with")
void render(FTextStream &ts, TemplateContext *c)
Definition: template.cpp:3260
void line(double t, double *p, double &x, double &y, double &z)
Mapping(const QCString &n, ExprAst *e)
Definition: template.cpp:3713
TreeContext(TemplateNodeTree *o, const TemplateListIntf *l, TemplateContext *c)
Definition: template.cpp:3598
Mapping * m_mapping
Definition: template.cpp:4024
ExprAstVariable(const char *name)
Definition: template.cpp:1387
static QCString type
Definition: declinfo.cpp:672
void setSpacelessIntf(TemplateSpacelessIntf *intf)
Definition: template.cpp:535
Class representing a piece of plain text in a template.
Definition: template.cpp:2578
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &args)
Definition: template.cpp:1049
def func()
Definition: docstring.py:7
void addIndexEntry(const QCString &indexName, const QValueList< TemplateKeyValue > &arguments)
Definition: template.cpp:2507
void prependToken(const TemplateToken *token)
Definition: template.cpp:4767
ExprAst * parseLiteral()
Definition: template.cpp:1942
Class representing an &#39;if&#39; tag in a template.
Definition: template.cpp:2722
ExprAst * m_listExpr
Definition: template.cpp:4158
bool isEmpty() const
Definition: qinternallist.h:57
virtual TemplateVariant at(int index) const =0
ExprAst * m_patternExpr
Definition: template.cpp:4159
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &args)
Definition: template.cpp:1159
bool copyResourceAs(const char *name, const char *targetDir, const char *targetName) const
Definition: resourcemgr.cpp:76
Iterator begin()
Definition: qvaluelist.h:361
TemplateVariant getPrimary(const QCString &name) const
Definition: template.cpp:2405
static TemplateFilterFactory::AutoRegister< FilterDefault > fDefault("default")
static bool * b
Definition: config.cpp:1043
TemplateVariant value
Definition: template.cpp:956
TemplateNode * m_parent
Definition: template.cpp:1650
static TemplateNodeFactory::AutoRegister< TemplateNodeTree > autoRefTree("recursetree")
Class representing a variable in the AST.
Definition: template.cpp:1384
void render(FTextStream &ts, TemplateContext *c)
Definition: template.cpp:3900
ExprAstNumber(int num)
Definition: template.cpp:1375
static TemplateNodeFactory::AutoRegister< TemplateNodeTabbing > autoRefTabbing("tabbing")
void render(FTextStream &ts, TemplateContext *c)
Definition: template.cpp:3420
static TemplateVariant apply(const TemplateVariant &v, const TemplateVariant &)
Definition: template.cpp:1030
TemplateNodeTabbing(TemplateParser *parser, TemplateNode *parent, int line, const QCString &)
Definition: template.cpp:4168
ExprToken m_curToken
Definition: template.cpp:2218
QList< ExprAst > m_args
Definition: template.cpp:3978
vector< vector< double > > clear
TemplateNodeList m_nodes
Definition: template.cpp:4054
TemplateNodeList m_loopNodes
Definition: template.cpp:3042
const char * m_tokenStream
Definition: template.cpp:2220
Lexer class for turning a template into a list of tokens.
Definition: template.cpp:4415
static unsigned filter(unsigned char *out, const unsigned char *in, unsigned w, unsigned h, const LodePNG_InfoColor *info)
Definition: lodepng.cpp:3576
TemplateStructIntf * toStruct() const
Definition: template.h:264
TemplateNodeCreator(TemplateParser *parser, TemplateNode *parent, int line)
Definition: template.cpp:2665
const TemplateList & m_list
Definition: template.cpp:398
ExprAst * parsePrimaryExpression()
Definition: template.cpp:1881
virtual int addRef()=0
void prepend(const type *d)
Definition: qlist.h:72
void addToken(QList< TemplateToken > &tokens, const char *data, int line, int startPos, int endPos, TemplateToken::Type type)
Definition: template.cpp:4644
QCString m_templateName
Definition: template.cpp:1672
Base class of all nodes in a template&#39;s AST.
Definition: template.cpp:1639
Class representing an &#39;markers&#39; tag in a template.
Definition: template.cpp:3205
TemplateToken(Type t, const char *d, int l)
Definition: template.cpp:2230
Type type() const
Definition: template.h:142
void render(FTextStream &ts, TemplateContext *c)
Definition: template.cpp:3951
void setLocation(const QCString &templateName, int line)
Definition: template.cpp:540
TemplateNodeList m_nodes
Definition: template.cpp:2276
QCString m_templateName
Definition: template.cpp:2715
virtual TemplateVariant get(const char *name) const
Definition: template.cpp:288
void enableTabbing(bool b)
Definition: template.cpp:551
QCString m_literal
Definition: template.cpp:1490
virtual TemplateVariant resolve(TemplateContext *)
Definition: template.cpp:1378
void render(FTextStream &ts, TemplateContext *c)
Definition: template.cpp:2777
bool tabbingEnabled() const
Definition: template.cpp:554
TemplateNodeCycle(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:3927
Abstract read-only interface for a context value of type list.
Definition: template.h:329
type * take(uint i)
Definition: qlist.h:81
Q_EXPORT int qstrcmp(const char *str1, const char *str2)
Definition: qcstring.h:95
const TemplateEngine * m_engine
Definition: template.cpp:4427
Helper class for registering a filter function.
Definition: template.cpp:1325
The implementation of the "texindex" filter.
Definition: template.cpp:706
QCString outputExtension() const
Definition: template.cpp:4938
void render(FTextStream &ts, TemplateContext *c)
Definition: template.cpp:2627
QList< QDict< TemplateVariant > > m_contextStack
Definition: template.cpp:567
Private(TemplateEngine *engine)
Definition: template.cpp:4857
QCString utf8() const
Definition: qstring.cpp:14507
Template * loadByName(const QCString &fileName, int line)
Definition: template.cpp:4862
The implementation of the "groupBy" filter.
Definition: template.cpp:950
TemplateSpacelessIntf * m_spacelessIntf
Definition: template.cpp:571
Default implementation of a context value of type struct.
Definition: template.h:426
void render(FTextStream &, TemplateContext *c)
Definition: template.cpp:4012
Recursive decent parser for Django style template expressions.
Definition: template.cpp:1680
TemplateKeyValue(const QCString &k, const TemplateVariant &v)
Definition: template.cpp:504
#define TRACE(x)
Definition: template.cpp:43
TemplateNodeRange(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:2881
void parse(TemplateNode *parent, int line, const QStrList &stopAt, QList< TemplateNode > &nodes)
Definition: template.cpp:4668
void va_warn(const char *file, int line, const char *fmt, va_list args)
Definition: message.cpp:191
unsigned uint
Definition: qglobal.h:351
TemplateNodeList trueNodes
Definition: template.cpp:2815
void setAutoDelete(bool enable)
Definition: qlist.h:99
Class representing an &#39;opensubindex&#39; tag in a template.
Definition: template.cpp:3781
void selectEscapeIntf(const QCString &ext)
Definition: template.cpp:530
QCString templateName() const
Definition: template.cpp:542
QAsciiDict< Entry > ns
The implementation of the "default" filter.
Definition: template.cpp:1243
bool removeLast()
Definition: qinternallist.h:68
const QCString & name() const
Definition: template.cpp:1389
static QCString determineSortKey(TemplateStructIntf *s, const QCString &attribName)
Definition: template.cpp:1017
void render(FTextStream &ts, TemplateContext *c)
Definition: template.cpp:3341
virtual void toFirst()
Definition: template.cpp:354
Weak reference wrapper for TemplateStructIntf that provides access to the wrapped struct without hold...
Definition: template.cpp:2285
TemplateNodeResource(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:4198
type * toLast()
Definition: qlist.h:136
The implementation of the "alphaIndex" filter.
Definition: template.cpp:1089
virtual void toNext()
Definition: template.cpp:364
static QCString * s
Definition: config.cpp:1042
Interface used to remove redundant spaces inside a spaceless block.
Definition: template.h:469
virtual bool exists() const
Definition: qdir.cpp:820
def parent(G, child, parent_type)
Definition: graph.py:67
const bool TRUE
Definition: qglobal.h:371
static QCString str
static TemplateNodeFactory::AutoRegister< TemplateNodeResource > autoRefResource("resource")
QDict< QStack< TemplateVariant > > m_indexStacks
Definition: template.cpp:575
QCString substitute(const QCString &s, const QCString &src, const QCString &dst)
substitute all occurrences of src in s by dst
Definition: util.cpp:5088
Factory singleton for registering and creating filters.
Definition: template.cpp:1292
QTextStream & endl(QTextStream &s)
virtual int addRef()
Definition: template.cpp:260
TemplateEscapeIntf * m_activeEscapeIntf
Definition: template.cpp:570
type * top() const
Definition: qstack.h:63
virtual TemplateVariant resolve(TemplateContext *c)
Definition: template.cpp:1536
ExprAst * m_fileExpr
Definition: template.cpp:3588
void setOutputExtension(const char *extension)
Definition: template.cpp:4933
static TemplateStruct * alloc()
Definition: template.cpp:294
TemplateStructWeakRef(TemplateStructIntf *ref)
Definition: template.cpp:2288
Definition: qlist.h:54
#define ASSERT(x)
Definition: qglobal.h:590
ExprAst * parseIdentifierOptionalArgs()
Definition: template.cpp:1951
TemplateNodeTree * object
Definition: template.cpp:3600
static TemplateFilterFactory::AutoRegister< FilterList > fList("list")
TemplateNodeExtend(TemplateParser *parser, TemplateNode *parent, int line, const QCString &data)
Definition: template.cpp:3322
bool hasNextToken() const
Definition: template.cpp:4747
Helper class for registering a template AST node.
Definition: template.cpp:4301
type * toFirst()
Definition: qlist.h:135
static TemplateFilterFactory::AutoRegister< FilterLength > fLength("length")
static QCString determineSortKey(TemplateStructIntf *s, const QCString &arg)
Definition: template.cpp:921
IncludeEntry(Type type, const QCString &fileName, const QCString &blockName, int line)
Definition: template.cpp:4843