util.cpp
Go to the documentation of this file.
1 /*****************************************************************************
2  *
3  *
4  * Copyright (C) 1997-2015 by Dimitri van Heesch.
5  *
6  * Permission to use, copy, modify, and distribute this software and its
7  * documentation under the terms of the GNU General Public License is hereby
8  * granted. No representations are made about the suitability of this software
9  * for any purpose. It is provided "as is" without express or implied warranty.
10  * See the GNU General Public License for more details.
11  *
12  * Documents produced by Doxygen are derivative works derived from the
13  * input used in their production; they are not affected by this license.
14  *
15  */
16 
17 #include <stdlib.h>
18 #include <ctype.h>
19 #include <errno.h>
20 #include <math.h>
21 #include <limits.h>
22 
23 #include "md5.h"
24 
25 #include <qregexp.h>
26 #include <qfileinfo.h>
27 #include <qdir.h>
28 #include <qdatetime.h>
29 #include <qcache.h>
30 
31 #include "util.h"
32 #include "message.h"
33 #include "classdef.h"
34 #include "filedef.h"
35 #include "doxygen.h"
36 #include "outputlist.h"
37 #include "defargs.h"
38 #include "language.h"
39 #include "config.h"
40 #include "htmlhelp.h"
41 #include "example.h"
42 #include "version.h"
43 #include "groupdef.h"
44 #include "reflist.h"
45 #include "pagedef.h"
46 #include "debug.h"
47 #include "searchindex.h"
48 #include "doxygen.h"
49 #include "textdocvisitor.h"
50 #include "portable.h"
51 #include "parserintf.h"
52 #include "bufstr.h"
53 #include "image.h"
54 #include "growbuf.h"
55 #include "entry.h"
56 #include "arguments.h"
57 #include "memberlist.h"
58 #include "classlist.h"
59 #include "namespacedef.h"
60 #include "membername.h"
61 #include "filename.h"
62 #include "membergroup.h"
63 #include "dirdef.h"
64 #include "htmlentity.h"
65 
66 #define ENABLE_TRACINGSUPPORT 0
67 
68 #if defined(_OS_MAC_) && ENABLE_TRACINGSUPPORT
69 #define TRACINGSUPPORT
70 #endif
71 
72 #ifdef TRACINGSUPPORT
73 #include <execinfo.h>
74 #include <unistd.h>
75 #endif
76 
77 
78 //------------------------------------------------------------------------
79 
80 // selects one of the name to sub-dir mapping algorithms that is used
81 // to select a sub directory when CREATE_SUBDIRS is set to YES.
82 
83 #define ALGO_COUNT 1
84 #define ALGO_CRC16 2
85 #define ALGO_MD5 3
86 
87 //#define MAP_ALGO ALGO_COUNT
88 //#define MAP_ALGO ALGO_CRC16
89 #define MAP_ALGO ALGO_MD5
90 
91 #define REL_PATH_TO_ROOT "../../"
92 
93 //------------------------------------------------------------------------
94 // TextGeneratorOLImpl implementation
95 //------------------------------------------------------------------------
96 
98 {
99 }
100 
101 void TextGeneratorOLImpl::writeString(const char *s,bool keepSpaces) const
102 {
103  if (s==0) return;
104  //printf("TextGeneratorOlImpl::writeString('%s',%d)\n",s,keepSpaces);
105  if (keepSpaces)
106  {
107  const char *p=s;
108  if (p)
109  {
110  char cs[2];
111  char c;
112  cs[1]='\0';
113  while ((c=*p++))
114  {
115  if (c==' ') m_od.writeNonBreakableSpace(1);
116  else cs[0]=c,m_od.docify(cs);
117  }
118  }
119  }
120  else
121  {
122  m_od.docify(s);
123  }
124 }
125 
127 {
128  m_od.lineBreak("typebreak");
129  int i;
130  for (i=0;i<indent;i++)
131  {
133  }
134 }
135 
136 void TextGeneratorOLImpl::writeLink(const char *extRef,const char *file,
137  const char *anchor,const char *text
138  ) const
139 {
140  //printf("TextGeneratorOlImpl::writeLink('%s')\n",text);
141  m_od.writeObjectLink(extRef,file,anchor,text);
142 }
143 
144 //------------------------------------------------------------------------
145 //------------------------------------------------------------------------
146 
147 // an inheritance tree of depth of 100000 should be enough for everyone :-)
148 const int maxInheritanceDepth = 100000;
149 
150 /*!
151  Removes all anonymous scopes from string s
152  Possible examples:
153 \verbatim
154  "bla::@10::blep" => "bla::blep"
155  "bla::@10::@11::blep" => "bla::blep"
156  "@10::blep" => "blep"
157  " @10::blep" => "blep"
158  "@9::@10::blep" => "blep"
159  "bla::@1" => "bla"
160  "bla::@1::@2" => "bla"
161  "bla @1" => "bla"
162 \endverbatim
163  */
165 {
167  if (s.isEmpty()) return result;
168  static QRegExp re("[ :]*@[0-9]+[: ]*");
169  int i,l,sl=s.length();
170  int p=0;
171  while ((i=re.match(s,p,&l))!=-1)
172  {
173  result+=s.mid(p,i-p);
174  int c=i;
175  bool b1=FALSE,b2=FALSE;
176  while (c<i+l && s.at(c)!='@') if (s.at(c++)==':') b1=TRUE;
177  c=i+l-1;
178  while (c>=i && s.at(c)!='@') if (s.at(c--)==':') b2=TRUE;
179  if (b1 && b2)
180  {
181  result+="::";
182  }
183  p=i+l;
184  }
185  result+=s.right(sl-p);
186  //printf("removeAnonymousScopes(`%s')=`%s'\n",s.data(),result.data());
187  return result;
188 }
189 
190 // replace anonymous scopes with __anonymous__ or replacement if provided
191 QCString replaceAnonymousScopes(const QCString &s,const char *replacement)
192 {
194  if (s.isEmpty()) return result;
195  static QRegExp re("@[0-9]+");
196  int i,l,sl=s.length();
197  int p=0;
198  while ((i=re.match(s,p,&l))!=-1)
199  {
200  result+=s.mid(p,i-p);
201  if (replacement)
202  {
203  result+=replacement;
204  }
205  else
206  {
207  result+="__anonymous__";
208  }
209  p=i+l;
210  }
211  result+=s.right(sl-p);
212  //printf("replaceAnonymousScopes(`%s')=`%s'\n",s.data(),result.data());
213  return result;
214 }
215 
216 
217 // strip anonymous left hand side part of the scope
219 {
220  int i,p=0,l;
221  QCString newScope;
222  int sl = s.length();
223  while ((i=getScopeFragment(s,p,&l))!=-1)
224  {
225  //printf("Scope fragment %s\n",s.mid(i,l).data());
226  if (Doxygen::namespaceSDict->find(s.left(i+l))!=0)
227  {
228  if (s.at(i)!='@')
229  {
230  if (!newScope.isEmpty()) newScope+="::";
231  newScope+=s.mid(i,l);
232  }
233  }
234  else if (i<sl)
235  {
236  if (!newScope.isEmpty()) newScope+="::";
237  newScope+=s.right(sl-i);
238  goto done;
239  }
240  p=i+l;
241  }
242 done:
243  //printf("stripAnonymousNamespaceScope(`%s')=`%s'\n",s.data(),newScope.data());
244  return newScope;
245 }
246 
247 void writePageRef(OutputDocInterface &od,const char *cn,const char *mn)
248 {
249  od.pushGeneratorState();
250 
253  if (Config_getBool("PDF_HYPERLINKS")) od.disable(OutputGenerator::Latex);
254  if (Config_getBool("RTF_HYPERLINKS")) od.disable(OutputGenerator::RTF);
255  od.startPageRef();
257  od.endPageRef(cn,mn);
258 
259  od.popGeneratorState();
260 }
261 
262 /*! Generate a place holder for a position in a list. Used for
263  * translators to be able to specify different elements orders
264  * depending on whether text flows from left to right or visa versa.
265  */
267 {
268  const int maxMarkerStrLen = 20;
269  char result[maxMarkerStrLen];
270  qsnprintf(result,maxMarkerStrLen,"@%d",id);
271  return result;
272 }
273 
275 {
276  // look at all the strings in the list and strip the longest match
277  const char *s=l.first();
278  QCString potential;
279  unsigned int length = 0;
280  while (s)
281  {
282  QCString prefix = s;
283  if (prefix.length() > length &&
284  qstricmp(path.left(prefix.length()),prefix)==0) // case insensitive compare
285  {
286  length = prefix.length();
287  potential = path.right(path.length()-prefix.length());
288  }
289  s = l.next();
290  }
291  if (length) return potential;
292  return path;
293 }
294 
295 /*! strip part of \a path if it matches
296  * one of the paths in the Config_getList("STRIP_FROM_PATH") list
297  */
299 {
300  return stripFromPath(path,Config_getList("STRIP_FROM_PATH"));
301 }
302 
303 /*! strip part of \a path if it matches
304  * one of the paths in the Config_getList("INCLUDE_PATH") list
305  */
307 {
308  return stripFromPath(path,Config_getList("STRIP_FROM_INC_PATH"));
309 }
310 
311 /*! try to determine if \a name is a source or a header file name by looking
312  * at the extension. A number of variations is allowed in both upper and
313  * lower case) If anyone knows or uses another extension please let me know :-)
314  */
315 int guessSection(const char *name)
316 {
317  QCString n=((QCString)name).lower();
318  if (n.right(2)==".c" || // source
319  n.right(3)==".cc" ||
320  n.right(4)==".cxx" ||
321  n.right(4)==".cpp" ||
322  n.right(4)==".c++" ||
323  n.right(5)==".java" ||
324  n.right(2)==".m" ||
325  n.right(2)==".M" ||
326  n.right(3)==".mm" ||
327  n.right(3)==".ii" || // inline
328  n.right(4)==".ixx" ||
329  n.right(4)==".ipp" ||
330  n.right(4)==".i++" ||
331  n.right(4)==".inl" ||
332  n.right(4)==".xml"
333  ) return Entry::SOURCE_SEC;
334  if (n.right(2)==".h" || // header
335  n.right(3)==".hh" ||
336  n.right(4)==".hxx" ||
337  n.right(4)==".hpp" ||
338  n.right(4)==".h++" ||
339  n.right(4)==".idl" ||
340  n.right(4)==".ddl" ||
341  n.right(5)==".pidl"
342  ) return Entry::HEADER_SEC;
343  return 0;
344 }
345 
346 QCString resolveTypeDef(Definition *context,const QCString &qualifiedName,
347  Definition **typedefContext)
348 {
349  //printf("<<resolveTypeDef(%s,%s)\n",
350  // context ? context->name().data() : "<none>",qualifiedName.data());
352  if (qualifiedName.isEmpty())
353  {
354  //printf(" qualified name empty!\n");
355  return result;
356  }
357 
358  Definition *mContext=context;
359  if (typedefContext) *typedefContext=context;
360 
361  // see if the qualified name has a scope part
362  int scopeIndex = qualifiedName.findRev("::");
363  QCString resName=qualifiedName;
364  if (scopeIndex!=-1) // strip scope part for the name
365  {
366  resName=qualifiedName.right(qualifiedName.length()-scopeIndex-2);
367  if (resName.isEmpty())
368  {
369  // qualifiedName was of form A:: !
370  //printf(" qualified name of form A::!\n");
371  return result;
372  }
373  }
374  MemberDef *md=0;
375  while (mContext && md==0)
376  {
377  // step 1: get the right scope
378  Definition *resScope=mContext;
379  if (scopeIndex!=-1)
380  {
381  // split-off scope part
382  QCString resScopeName = qualifiedName.left(scopeIndex);
383  //printf("resScopeName=`%s'\n",resScopeName.data());
384 
385  // look-up scope in context
386  int is,ps=0;
387  int l;
388  while ((is=getScopeFragment(resScopeName,ps,&l))!=-1)
389  {
390  QCString qualScopePart = resScopeName.mid(is,l);
391  QCString tmp = resolveTypeDef(mContext,qualScopePart);
392  if (!tmp.isEmpty()) qualScopePart=tmp;
393  resScope = resScope->findInnerCompound(qualScopePart);
394  //printf("qualScopePart=`%s' resScope=%p\n",qualScopePart.data(),resScope);
395  if (resScope==0) break;
396  ps=is+l;
397  }
398  }
399  //printf("resScope=%s\n",resScope?resScope->name().data():"<none>");
400 
401  // step 2: get the member
402  if (resScope) // no scope or scope found in the current context
403  {
404  //printf("scope found: %s, look for typedef %s\n",
405  // resScope->qualifiedName().data(),resName.data());
406  MemberNameSDict *mnd=0;
407  if (resScope->definitionType()==Definition::TypeClass)
408  {
410  }
411  else
412  {
414  }
415  MemberName *mn=mnd->find(resName);
416  if (mn)
417  {
418  MemberNameIterator mni(*mn);
419  MemberDef *tmd=0;
420  int minDist=-1;
421  for (;(tmd=mni.current());++mni)
422  {
423  //printf("Found member %s resScope=%s outerScope=%s mContext=%p\n",
424  // tmd->name().data(), resScope->name().data(),
425  // tmd->getOuterScope()->name().data(), mContext);
426  if (tmd->isTypedef() /*&& tmd->getOuterScope()==resScope*/)
427  {
428  int dist=isAccessibleFrom(resScope,0,tmd);
429  if (dist!=-1 && (md==0 || dist<minDist))
430  {
431  md = tmd;
432  minDist = dist;
433  }
434  }
435  }
436  }
437  }
438  mContext=mContext->getOuterScope();
439  }
440 
441  // step 3: get the member's type
442  if (md)
443  {
444  //printf(">>resolveTypeDef: Found typedef name `%s' in scope `%s' value=`%s' args='%s'\n",
445  // qualifiedName.data(),context->name().data(),md->typeString(),md->argsString()
446  // );
447  result=md->typeString();
448  QCString args = md->argsString();
449  if (args.find(")(")!=-1) // typedef of a function/member pointer
450  {
451  result+=args;
452  }
453  else if (args.find('[')!=-1) // typedef of an array
454  {
455  result+=args;
456  }
457  if (typedefContext) *typedefContext=md->getOuterScope();
458  }
459  else
460  {
461  //printf(">>resolveTypeDef: Typedef `%s' not found in scope `%s'!\n",
462  // qualifiedName.data(),context ? context->name().data() : "<global>");
463  }
464  return result;
465 
466 }
467 
468 
469 /*! Get a class definition given its name.
470  * Returns 0 if the class is not found.
471  */
472 ClassDef *getClass(const char *n)
473 {
474  if (n==0 || n[0]=='\0') return 0;
475  QCString name=n;
477  //if (result==0 && !exact) // also try generic and protocol versions
478  //{
479  // result = Doxygen::classSDict->find(name+"-g");
480  // if (result==0)
481  // {
482  // result = Doxygen::classSDict->find(name+"-p");
483  // }
484  //}
485  //printf("getClass(%s)=%s\n",n,result?result->name().data():"<none>");
486  return result;
487 }
488 
490 {
491  if (name==0 || name[0]=='\0') return 0;
493  if (subst)
494  {
495  int count=0; // recursion detection guard
496  QCString *newSubst;
497  while ((newSubst=Doxygen::namespaceAliasDict[*subst]) && count<10)
498  {
499  subst=newSubst;
500  count++;
501  }
502  if (count==10)
503  {
504  warn_uncond("possible recursive namespace alias detected for %s!\n",name);
505  }
506  return Doxygen::namespaceSDict->find(subst->data());
507  }
508  else
509  {
510  return Doxygen::namespaceSDict->find(name);
511  }
512 }
513 
514 static QDict<MemberDef> g_resolvedTypedefs;
515 static QDict<Definition> g_visitedNamespaces;
516 
517 // forward declaration
519  FileDef *fileScope,
520  const char *n,
521  MemberDef **pTypeDef,
522  QCString *pTemplSpec,
523  QCString *pResolvedType
524  );
526  const QCString &explicitScopePart);
527 
528 /*! Returns the class representing the value of the typedef represented by \a md
529  * within file \a fileScope.
530  *
531  * Example: typedef A T; will return the class representing A if it is a class.
532  *
533  * Example: typedef int T; will return 0, since "int" is not a class.
534  */
536  MemberDef **pMemType,QCString *pTemplSpec,
537  QCString *pResolvedType,
538  ArgumentList *actTemplParams)
539 {
540  //printf("newResolveTypedef(md=%p,cachedVal=%p)\n",md,md->getCachedTypedefVal());
541  bool isCached = md->isTypedefValCached(); // value already cached
542  if (isCached)
543  {
544  //printf("Already cached %s->%s [%s]\n",
545  // md->name().data(),
546  // md->getCachedTypedefVal()?md->getCachedTypedefVal()->name().data():"<none>",
547  // md->getCachedResolvedTypedef()?md->getCachedResolvedTypedef().data():"<none>");
548 
549  if (pTemplSpec) *pTemplSpec = md->getCachedTypedefTemplSpec();
550  if (pResolvedType) *pResolvedType = md->getCachedResolvedTypedef();
551  return md->getCachedTypedefVal();
552  }
553  //printf("new typedef\n");
554  QCString qname = md->qualifiedName();
555  if (g_resolvedTypedefs.find(qname)) return 0; // typedef already done
556 
557  g_resolvedTypedefs.insert(qname,md); // put on the trace list
558 
559  ClassDef *typeClass = md->getClassDef();
560  QCString type = md->typeString(); // get the "value" of the typedef
561  if (typeClass && typeClass->isTemplate() &&
562  actTemplParams && actTemplParams->count()>0)
563  {
565  typeClass->templateArguments(),actTemplParams);
566  }
567  QCString typedefValue = type;
568  int tl=type.length();
569  int ip=tl-1; // remove * and & at the end
570  while (ip>=0 && (type.at(ip)=='*' || type.at(ip)=='&' || type.at(ip)==' '))
571  {
572  ip--;
573  }
574  type=type.left(ip+1);
575  type.stripPrefix("const "); // strip leading "const"
576  type.stripPrefix("struct "); // strip leading "struct"
577  type.stripPrefix("union "); // strip leading "union"
578  int sp=0;
579  tl=type.length(); // length may have been changed
580  while (sp<tl && type.at(sp)==' ') sp++;
581  MemberDef *memTypeDef = 0;
583  fileScope,type,&memTypeDef,0,pResolvedType);
584  // if type is a typedef then return what it resolves to.
585  if (memTypeDef && memTypeDef->isTypedef())
586  {
587  result=newResolveTypedef(fileScope,memTypeDef,pMemType,pTemplSpec);
588  goto done;
589  }
590  else if (memTypeDef && memTypeDef->isEnumerate() && pMemType)
591  {
592  *pMemType = memTypeDef;
593  }
594 
595  //printf("type=%s result=%p\n",type.data(),result);
596  if (result==0)
597  {
598  // try unspecialized version if type is template
599  int si=type.findRev("::");
600  int i=type.find('<');
601  if (si==-1 && i!=-1) // typedef of a template => try the unspecialized version
602  {
603  if (pTemplSpec) *pTemplSpec = type.mid(i);
604  result = getResolvedClassRec(md->getOuterScope(),fileScope,
605  type.left(i),0,0,pResolvedType);
606  //printf("result=%p pRresolvedType=%s sp=%d ip=%d tl=%d\n",
607  // result,pResolvedType?pResolvedType->data():"<none>",sp,ip,tl);
608  }
609  else if (si!=-1) // A::B
610  {
611  i=type.find('<',si);
612  if (i==-1) // Something like A<T>::B => lookup A::B
613  {
614  i=type.length();
615  }
616  else // Something like A<T>::B<S> => lookup A::B, spec=<S>
617  {
618  if (pTemplSpec) *pTemplSpec = type.mid(i);
619  }
620  result = getResolvedClassRec(md->getOuterScope(),fileScope,
621  stripTemplateSpecifiersFromScope(type.left(i),FALSE),0,0,
622  pResolvedType);
623  }
624 
625  //if (result) ip=si+sp+1;
626  }
627 
628 done:
629  if (pResolvedType)
630  {
631  if (result)
632  {
633  *pResolvedType=result->qualifiedName();
634  //printf("*pResolvedType=%s\n",pResolvedType->data());
635  if (sp>0) pResolvedType->prepend(typedefValue.left(sp));
636  if (ip<tl-1) pResolvedType->append(typedefValue.right(tl-ip-1));
637  }
638  else
639  {
640  *pResolvedType=typedefValue;
641  }
642  }
643 
644  // remember computed value for next time
645  if (result && result->getDefFileName()!="<code>")
646  // this check is needed to prevent that temporary classes that are
647  // introduced while parsing code fragments are being cached here.
648  {
649  //printf("setting cached typedef %p in result %p\n",md,result);
650  //printf("==> %s (%s,%d)\n",result->name().data(),result->getDefFileName().data(),result->getDefLine());
651  //printf("*pResolvedType=%s\n",pResolvedType?pResolvedType->data():"<none>");
652  md->cacheTypedefVal(result,
653  pTemplSpec ? *pTemplSpec : QCString(),
654  pResolvedType ? *pResolvedType : QCString()
655  );
656  }
657 
658  g_resolvedTypedefs.remove(qname); // remove from the trace list
659 
660  return result;
661 }
662 
663 /*! Substitutes a simple unqualified \a name within \a scope. Returns the
664  * value of the typedef or \a name if no typedef was found.
665  */
667  MemberDef **pTypeDef=0)
668 {
670  if (name.isEmpty()) return result;
671 
672  // lookup scope fragment in the symbol map
673  DefinitionIntf *di = Doxygen::symbolMap->find(name);
674  if (di==0) return result; // no matches
675 
676  MemberDef *bestMatch=0;
677  if (di->definitionType()==DefinitionIntf::TypeSymbolList) // multi symbols
678  {
679  // search for the best match
681  Definition *d;
682  int minDistance=10000; // init at "infinite"
683  for (dli.toFirst();(d=dli.current());++dli) // foreach definition
684  {
685  // only look at members
687  {
688  // that are also typedefs
689  MemberDef *md = (MemberDef *)d;
690  if (md->isTypedef()) // d is a typedef
691  {
692  // test accessibility of typedef within scope.
693  int distance = isAccessibleFromWithExpScope(scope,fileScope,d,"");
694  if (distance!=-1 && distance<minDistance)
695  // definition is accessible and a better match
696  {
697  minDistance=distance;
698  bestMatch = md;
699  }
700  }
701  }
702  }
703  }
704  else if (di->definitionType()==DefinitionIntf::TypeMember) // single symbol
705  {
706  Definition *d = (Definition*)di;
707  // that are also typedefs
708  MemberDef *md = (MemberDef *)di;
709  if (md->isTypedef()) // d is a typedef
710  {
711  // test accessibility of typedef within scope.
712  int distance = isAccessibleFromWithExpScope(scope,fileScope,d,"");
713  if (distance!=-1) // definition is accessible
714  {
715  bestMatch = md;
716  }
717  }
718  }
719  if (bestMatch)
720  {
721  result = bestMatch->typeString();
722  if (pTypeDef) *pTypeDef=bestMatch;
723  }
724 
725  //printf("substTypedef(%s,%s)=%s\n",scope?scope->name().data():"<global>",
726  // name.data(),result.data());
727  return result;
728 }
729 
731 {
732  if (cl)
733  {
735  Definition *cd;
736  for (cli.toFirst();(cd=cli.current());++cli)
737  {
738  if (cd->localName()==localName)
739  {
740  return cd;
741  }
742  }
743  }
744  return 0;
745 }
746 
747 /*! Starting with scope \a start, the string \a path is interpreted as
748  * a part of a qualified scope name (e.g. A::B::C), and the scope is
749  * searched. If found the scope definition is returned, otherwise 0
750  * is returned.
751  */
752 static Definition *followPath(Definition *start,FileDef *fileScope,const QCString &path)
753 {
754  int is,ps;
755  int l;
756  Definition *current=start;
757  ps=0;
758  //printf("followPath: start='%s' path='%s'\n",start?start->name().data():"<none>",path.data());
759  // for each part of the explicit scope
760  while ((is=getScopeFragment(path,ps,&l))!=-1)
761  {
762  // try to resolve the part if it is a typedef
763  MemberDef *typeDef=0;
764  QCString qualScopePart = substTypedef(current,fileScope,path.mid(is,l),&typeDef);
765  //printf(" qualScopePart=%s\n",qualScopePart.data());
766  if (typeDef)
767  {
768  ClassDef *type = newResolveTypedef(fileScope,typeDef);
769  if (type)
770  {
771  //printf("Found type %s\n",type->name().data());
772  return type;
773  }
774  }
775  Definition *next = current->findInnerCompound(qualScopePart);
776  //printf("++ Looking for %s inside %s result %s\n",
777  // qualScopePart.data(),
778  // current->name().data(),
779  // next?next->name().data():"<null>");
780  if (next==0) // failed to follow the path
781  {
782  //printf("==> next==0!\n");
784  {
785  next = endOfPathIsUsedClass(
786  ((NamespaceDef *)current)->getUsedClasses(),qualScopePart);
787  }
788  else if (current->definitionType()==Definition::TypeFile)
789  {
790  next = endOfPathIsUsedClass(
791  ((FileDef *)current)->getUsedClasses(),qualScopePart);
792  }
793  current = next;
794  if (current==0) break;
795  }
796  else // continue to follow scope
797  {
798  current = next;
799  //printf("==> current = %p\n",current);
800  }
801  ps=is+l;
802  }
803  //printf("followPath(start=%s,path=%s) result=%s\n",
804  // start->name().data(),path.data(),current?current->name().data():"<null>");
805  return current; // path could be followed
806 }
807 
809  FileDef *fileScope,
810  Definition *item,
811  const QCString &explicitScopePart=""
812  )
813 {
814  //printf("accessibleViaUsingClass(%p)\n",cl);
815  if (cl) // see if the class was imported via a using statement
816  {
818  Definition *ucd;
819  bool explicitScopePartEmpty = explicitScopePart.isEmpty();
820  for (cli.toFirst();(ucd=cli.current());++cli)
821  {
822  //printf("Trying via used class %s\n",ucd->name().data());
823  Definition *sc = explicitScopePartEmpty ? ucd : followPath(ucd,fileScope,explicitScopePart);
824  if (sc && sc==item) return TRUE;
825  //printf("Try via used class done\n");
826  }
827  }
828  return FALSE;
829 }
830 
832  FileDef *fileScope,
833  Definition *item,
834  const QCString &explicitScopePart="")
835 {
836  static QDict<void> visitedDict;
837  if (nl) // check used namespaces for the class
838  {
839  NamespaceSDict::Iterator nli(*nl);
840  NamespaceDef *und;
841  int count=0;
842  for (nli.toFirst();(und=nli.current());++nli,count++)
843  {
844  //printf("[Trying via used namespace %s: count=%d/%d\n",und->name().data(),
845  // count,nl->count());
846  Definition *sc = explicitScopePart.isEmpty() ? und : followPath(und,fileScope,explicitScopePart);
847  if (sc && item->getOuterScope()==sc)
848  {
849  //printf("] found it\n");
850  return TRUE;
851  }
852  QCString key=und->name();
853  if (und->getUsedNamespaces() && visitedDict.find(key)==0)
854  {
855  visitedDict.insert(key,(void *)0x08);
856 
857  if (accessibleViaUsingNamespace(und->getUsedNamespaces(),fileScope,item,explicitScopePart))
858  {
859  //printf("] found it via recursion\n");
860  return TRUE;
861  }
862 
863  visitedDict.remove(key);
864  }
865  //printf("] Try via used namespace done\n");
866  }
867  }
868  return FALSE;
869 }
870 
871 const int MAX_STACK_SIZE = 1000;
872 
873 /** Helper class representing the stack of items considered while resolving
874  * the scope.
875  */
877 {
878  public:
879  AccessStack() : m_index(0) {}
880  void push(Definition *scope,FileDef *fileScope,Definition *item)
881  {
882  if (m_index<MAX_STACK_SIZE)
883  {
884  m_elements[m_index].scope = scope;
885  m_elements[m_index].fileScope = fileScope;
886  m_elements[m_index].item = item;
887  m_index++;
888  }
889  }
890  void push(Definition *scope,FileDef *fileScope,Definition *item,const QCString &expScope)
891  {
892  if (m_index<MAX_STACK_SIZE)
893  {
894  m_elements[m_index].scope = scope;
895  m_elements[m_index].fileScope = fileScope;
896  m_elements[m_index].item = item;
897  m_elements[m_index].expScope = expScope;
898  m_index++;
899  }
900  }
901  void pop()
902  {
903  if (m_index>0) m_index--;
904  }
905  bool find(Definition *scope,FileDef *fileScope, Definition *item)
906  {
907  int i=0;
908  for (i=0;i<m_index;i++)
909  {
910  AccessElem *e = &m_elements[i];
911  if (e->scope==scope && e->fileScope==fileScope && e->item==item)
912  {
913  return TRUE;
914  }
915  }
916  return FALSE;
917  }
918  bool find(Definition *scope,FileDef *fileScope, Definition *item,const QCString &expScope)
919  {
920  int i=0;
921  for (i=0;i<m_index;i++)
922  {
923  AccessElem *e = &m_elements[i];
924  if (e->scope==scope && e->fileScope==fileScope && e->item==item && e->expScope==expScope)
925  {
926  return TRUE;
927  }
928  }
929  return FALSE;
930  }
931 
932  private:
933  /** Element in the stack. */
934  struct AccessElem
935  {
940  };
941  int m_index;
943 };
944 
945 /* Returns the "distance" (=number of levels up) from item to scope, or -1
946  * if item in not inside scope.
947  */
949 {
950  //printf("<isAccesibleFrom(scope=%s,item=%s itemScope=%s)\n",
951  // scope->name().data(),item->name().data(),item->getOuterScope()->name().data());
952 
953  static AccessStack accessStack;
954  if (accessStack.find(scope,fileScope,item))
955  {
956  return -1;
957  }
958  accessStack.push(scope,fileScope,item);
959 
960  int result=0; // assume we found it
961  int i;
962 
963  Definition *itemScope=item->getOuterScope();
964  bool memberAccessibleFromScope =
965  (item->definitionType()==Definition::TypeMember && // a member
966  itemScope && itemScope->definitionType()==Definition::TypeClass && // of a class
967  scope->definitionType()==Definition::TypeClass && // accessible
968  ((ClassDef*)scope)->isAccessibleMember((MemberDef *)item) // from scope
969  );
970  bool nestedClassInsideBaseClass =
971  (item->definitionType()==Definition::TypeClass && // a nested class
972  itemScope && itemScope->definitionType()==Definition::TypeClass && // inside a base
973  scope->definitionType()==Definition::TypeClass && // class of scope
974  ((ClassDef*)scope)->isBaseClass((ClassDef*)itemScope,TRUE)
975  );
976 
977  if (itemScope==scope || memberAccessibleFromScope || nestedClassInsideBaseClass)
978  {
979  //printf("> found it\n");
980  if (nestedClassInsideBaseClass) result++; // penalty for base class to prevent
981  // this is preferred over nested class in this class
982  // see bug 686956
983  }
984  else if (scope==Doxygen::globalScope)
985  {
986  if (fileScope)
987  {
988  SDict<Definition> *cl = fileScope->getUsedClasses();
989  if (accessibleViaUsingClass(cl,fileScope,item))
990  {
991  //printf("> found via used class\n");
992  goto done;
993  }
994  NamespaceSDict *nl = fileScope->getUsedNamespaces();
995  if (accessibleViaUsingNamespace(nl,fileScope,item))
996  {
997  //printf("> found via used namespace\n");
998  goto done;
999  }
1000  }
1001  //printf("> reached global scope\n");
1002  result=-1; // not found in path to globalScope
1003  }
1004  else // keep searching
1005  {
1006  // check if scope is a namespace, which is using other classes and namespaces
1007  if (scope->definitionType()==Definition::TypeNamespace)
1008  {
1009  NamespaceDef *nscope = (NamespaceDef*)scope;
1010  //printf(" %s is namespace with %d used classes\n",nscope->name().data(),nscope->getUsedClasses());
1011  SDict<Definition> *cl = nscope->getUsedClasses();
1012  if (accessibleViaUsingClass(cl,fileScope,item))
1013  {
1014  //printf("> found via used class\n");
1015  goto done;
1016  }
1017  NamespaceSDict *nl = nscope->getUsedNamespaces();
1018  if (accessibleViaUsingNamespace(nl,fileScope,item))
1019  {
1020  //printf("> found via used namespace\n");
1021  goto done;
1022  }
1023  }
1024  // repeat for the parent scope
1025  i=isAccessibleFrom(scope->getOuterScope(),fileScope,item);
1026  //printf("> result=%d\n",i);
1027  result= (i==-1) ? -1 : i+2;
1028  }
1029 done:
1030  accessStack.pop();
1031  //Doxygen::lookupCache.insert(key,new int(result));
1032  return result;
1033 }
1034 
1035 
1036 /* Returns the "distance" (=number of levels up) from item to scope, or -1
1037  * if item in not in this scope. The explicitScopePart limits the search
1038  * to scopes that match \a scope (or its parent scope(s)) plus the explicit part.
1039  * Example:
1040  *
1041  * class A { public: class I {}; };
1042  * class B { public: class J {}; };
1043  *
1044  * - Looking for item=='J' inside scope=='B' will return 0.
1045  * - Looking for item=='I' inside scope=='B' will return -1
1046  * (as it is not found in B nor in the global scope).
1047  * - Looking for item=='A::I' inside scope=='B', first the match B::A::I is tried but
1048  * not found and then A::I is searched in the global scope, which matches and
1049  * thus the result is 1.
1050  */
1052  Definition *item,const QCString &explicitScopePart)
1053 {
1054  if (explicitScopePart.isEmpty())
1055  {
1056  // handle degenerate case where there is no explicit scope.
1057  return isAccessibleFrom(scope,fileScope,item);
1058  }
1059 
1060  static AccessStack accessStack;
1061  if (accessStack.find(scope,fileScope,item,explicitScopePart))
1062  {
1063  return -1;
1064  }
1065  accessStack.push(scope,fileScope,item,explicitScopePart);
1066 
1067 
1068  //printf(" <isAccessibleFromWithExpScope(%s,%s,%s)\n",scope?scope->name().data():"<global>",
1069  // item?item->name().data():"<none>",
1070  // explicitScopePart.data());
1071  int result=0; // assume we found it
1072  Definition *newScope = followPath(scope,fileScope,explicitScopePart);
1073  if (newScope) // explicitScope is inside scope => newScope is the result
1074  {
1075  Definition *itemScope = item->getOuterScope();
1076  //printf(" scope traversal successful %s<->%s!\n",itemScope->name().data(),newScope->name().data());
1077  //if (newScope && newScope->definitionType()==Definition::TypeClass)
1078  //{
1079  // ClassDef *cd = (ClassDef *)newScope;
1080  // printf("---> Class %s: bases=%p\n",cd->name().data(),cd->baseClasses());
1081  //}
1082  if (itemScope==newScope) // exact match of scopes => distance==0
1083  {
1084  //printf("> found it\n");
1085  }
1086  else if (itemScope && newScope &&
1087  itemScope->definitionType()==Definition::TypeClass &&
1088  newScope->definitionType()==Definition::TypeClass &&
1089  ((ClassDef*)newScope)->isBaseClass((ClassDef*)itemScope,TRUE,0)
1090  )
1091  {
1092  // inheritance is also ok. Example: looking for B::I, where
1093  // class A { public: class I {} };
1094  // class B : public A {}
1095  // but looking for B::I, where
1096  // class A { public: class I {} };
1097  // class B { public: class I {} };
1098  // will find A::I, so we still prefer a direct match and give this one a distance of 1
1099  result=1;
1100 
1101  //printf("scope(%s) is base class of newScope(%s)\n",
1102  // scope->name().data(),newScope->name().data());
1103  }
1104  else
1105  {
1106  int i=-1;
1107  if (newScope->definitionType()==Definition::TypeNamespace)
1108  {
1109  g_visitedNamespaces.insert(newScope->name(),newScope);
1110  // this part deals with the case where item is a class
1111  // A::B::C but is explicit referenced as A::C, where B is imported
1112  // in A via a using directive.
1113  //printf("newScope is a namespace: %s!\n",newScope->name().data());
1114  NamespaceDef *nscope = (NamespaceDef*)newScope;
1115  SDict<Definition> *cl = nscope->getUsedClasses();
1116  if (cl)
1117  {
1119  Definition *cd;
1120  for (cli.toFirst();(cd=cli.current());++cli)
1121  {
1122  //printf("Trying for class %s\n",cd->name().data());
1123  if (cd==item)
1124  {
1125  //printf("> class is used in this scope\n");
1126  goto done;
1127  }
1128  }
1129  }
1130  NamespaceSDict *nl = nscope->getUsedNamespaces();
1131  if (nl)
1132  {
1133  NamespaceSDict::Iterator nli(*nl);
1134  NamespaceDef *nd;
1135  for (nli.toFirst();(nd=nli.current());++nli)
1136  {
1137  if (g_visitedNamespaces.find(nd->name())==0)
1138  {
1139  //printf("Trying for namespace %s\n",nd->name().data());
1140  i = isAccessibleFromWithExpScope(scope,fileScope,item,nd->name());
1141  if (i!=-1)
1142  {
1143  //printf("> found via explicit scope of used namespace\n");
1144  goto done;
1145  }
1146  }
1147  }
1148  }
1149  }
1150  // repeat for the parent scope
1151  if (scope!=Doxygen::globalScope)
1152  {
1153  i = isAccessibleFromWithExpScope(scope->getOuterScope(),fileScope,
1154  item,explicitScopePart);
1155  }
1156  //printf(" | result=%d\n",i);
1157  result = (i==-1) ? -1 : i+2;
1158  }
1159  }
1160  else // failed to resolve explicitScope
1161  {
1162  //printf(" failed to resolve: scope=%s\n",scope->name().data());
1164  {
1165  NamespaceDef *nscope = (NamespaceDef*)scope;
1166  NamespaceSDict *nl = nscope->getUsedNamespaces();
1167  if (accessibleViaUsingNamespace(nl,fileScope,item,explicitScopePart))
1168  {
1169  //printf("> found in used namespace\n");
1170  goto done;
1171  }
1172  }
1173  if (scope==Doxygen::globalScope)
1174  {
1175  if (fileScope)
1176  {
1177  NamespaceSDict *nl = fileScope->getUsedNamespaces();
1178  if (accessibleViaUsingNamespace(nl,fileScope,item,explicitScopePart))
1179  {
1180  //printf("> found in used namespace\n");
1181  goto done;
1182  }
1183  }
1184  //printf("> not found\n");
1185  result=-1;
1186  }
1187  else // continue by looking into the parent scope
1188  {
1189  int i=isAccessibleFromWithExpScope(scope->getOuterScope(),fileScope,
1190  item,explicitScopePart);
1191  //printf("> result=%d\n",i);
1192  result= (i==-1) ? -1 : i+2;
1193  }
1194  }
1195 
1196 done:
1197  //printf(" > result=%d\n",result);
1198  accessStack.pop();
1199  //Doxygen::lookupCache.insert(key,new int(result));
1200  return result;
1201 }
1202 
1204 {
1205  int i = name.find('<');
1206  return name.findRev("::",i==-1 ? name.length() : i);
1207 }
1208 
1210  FileDef *fileScope,
1211  Definition *d,
1212  const QCString &explicitScopePart,
1213  ArgumentList *actTemplParams,
1214  int &minDistance,
1215  ClassDef *&bestMatch,
1216  MemberDef *&bestTypedef,
1217  QCString &bestTemplSpec,
1218  QCString &bestResolvedType
1219  )
1220 {
1221  //printf(" => found type %x name=%s d=%p\n",
1222  // d->definitionType(),d->name().data(),d);
1223 
1224  // only look at classes and members that are enums or typedefs
1227  (((MemberDef*)d)->isTypedef() || ((MemberDef*)d)->isEnumerate())
1228  )
1229  )
1230  {
1231  g_visitedNamespaces.clear();
1232  // test accessibility of definition within scope.
1233  int distance = isAccessibleFromWithExpScope(scope,fileScope,d,explicitScopePart);
1234  //printf(" %s; distance %s (%p) is %d\n",scope->name().data(),d->name().data(),d,distance);
1235  if (distance!=-1) // definition is accessible
1236  {
1237  // see if we are dealing with a class or a typedef
1238  if (d->definitionType()==Definition::TypeClass) // d is a class
1239  {
1240  ClassDef *cd = (ClassDef *)d;
1241  //printf("cd=%s\n",cd->name().data());
1242  if (!cd->isTemplateArgument()) // skip classes that
1243  // are only there to
1244  // represent a template
1245  // argument
1246  {
1247  //printf("is not a templ arg\n");
1248  if (distance<minDistance) // found a definition that is "closer"
1249  {
1250  minDistance=distance;
1251  bestMatch = cd;
1252  bestTypedef = 0;
1253  bestTemplSpec.resize(0);
1254  bestResolvedType = cd->qualifiedName();
1255  }
1256  else if (distance==minDistance &&
1257  fileScope && bestMatch &&
1258  fileScope->getUsedNamespaces() &&
1259  d->getOuterScope()->definitionType()==Definition::TypeNamespace &&
1260  bestMatch->getOuterScope()==Doxygen::globalScope
1261  )
1262  {
1263  // in case the distance is equal it could be that a class X
1264  // is defined in a namespace and in the global scope. When searched
1265  // in the global scope the distance is 0 in both cases. We have
1266  // to choose one of the definitions: we choose the one in the
1267  // namespace if the fileScope imports namespaces and the definition
1268  // found was in a namespace while the best match so far isn't.
1269  // Just a non-perfect heuristic but it could help in some situations
1270  // (kdecore code is an example).
1271  minDistance=distance;
1272  bestMatch = cd;
1273  bestTypedef = 0;
1274  bestTemplSpec.resize(0);
1275  bestResolvedType = cd->qualifiedName();
1276  }
1277  }
1278  else
1279  {
1280  //printf(" is a template argument!\n");
1281  }
1282  }
1283  else if (d->definitionType()==Definition::TypeMember)
1284  {
1285  MemberDef *md = (MemberDef *)d;
1286  //printf(" member isTypedef()=%d\n",md->isTypedef());
1287  if (md->isTypedef()) // d is a typedef
1288  {
1289  QCString args=md->argsString();
1290  if (args.isEmpty()) // do not expand "typedef t a[4];"
1291  {
1292  //printf(" found typedef!\n");
1293 
1294  // we found a symbol at this distance, but if it didn't
1295  // resolve to a class, we still have to make sure that
1296  // something at a greater distance does not match, since
1297  // that symbol is hidden by this one.
1298  if (distance<minDistance)
1299  {
1300  QCString spec;
1301  QCString type;
1302  minDistance=distance;
1303  MemberDef *enumType = 0;
1304  ClassDef *cd = newResolveTypedef(fileScope,md,&enumType,&spec,&type,actTemplParams);
1305  if (cd) // type resolves to a class
1306  {
1307  //printf(" bestTypeDef=%p spec=%s type=%s\n",md,spec.data(),type.data());
1308  bestMatch = cd;
1309  bestTypedef = md;
1310  bestTemplSpec = spec;
1311  bestResolvedType = type;
1312  }
1313  else if (enumType) // type resolves to a enum
1314  {
1315  //printf(" is enum\n");
1316  bestMatch = 0;
1317  bestTypedef = enumType;
1318  bestTemplSpec = "";
1319  bestResolvedType = enumType->qualifiedName();
1320  }
1321  else if (md->isReference()) // external reference
1322  {
1323  bestMatch = 0;
1324  bestTypedef = md;
1325  bestTemplSpec = spec;
1326  bestResolvedType = type;
1327  }
1328  else
1329  {
1330  bestMatch = 0;
1331  bestTypedef = md;
1332  bestTemplSpec.resize(0);
1333  bestResolvedType.resize(0);
1334  //printf(" no match\n");
1335  }
1336  }
1337  else
1338  {
1339  //printf(" not the best match %d min=%d\n",distance,minDistance);
1340  }
1341  }
1342  else
1343  {
1344  //printf(" not a simple typedef\n")
1345  }
1346  }
1347  else if (md->isEnumerate())
1348  {
1349  if (distance<minDistance)
1350  {
1351  minDistance=distance;
1352  bestMatch = 0;
1353  bestTypedef = md;
1354  bestTemplSpec = "";
1355  bestResolvedType = md->qualifiedName();
1356  }
1357  }
1358  }
1359  } // if definition accessible
1360  else
1361  {
1362  //printf(" Not accessible!\n");
1363  }
1364  } // if definition is a class or member
1365  //printf(" bestMatch=%p bestResolvedType=%s\n",bestMatch,bestResolvedType.data());
1366 }
1367 
1368 /* Find the fully qualified class name referred to by the input class
1369  * or typedef name against the input scope.
1370  * Loops through scope and each of its parent scopes looking for a
1371  * match against the input name. Can recursively call itself when
1372  * resolving typedefs.
1373  */
1375  FileDef *fileScope,
1376  const char *n,
1377  MemberDef **pTypeDef,
1378  QCString *pTemplSpec,
1379  QCString *pResolvedType
1380  )
1381 {
1382  //printf("[getResolvedClassRec(%s,%s)\n",scope?scope->name().data():"<global>",n);
1383  QCString name;
1384  QCString explicitScopePart;
1385  QCString strippedTemplateParams;
1388  &strippedTemplateParams);
1389  ArgumentList actTemplParams;
1390  if (!strippedTemplateParams.isEmpty()) // template part that was stripped
1391  {
1392  stringToArgumentList(strippedTemplateParams,&actTemplParams);
1393  }
1394 
1395  int qualifierIndex = computeQualifiedIndex(name);
1396  //printf("name=%s qualifierIndex=%d\n",name.data(),qualifierIndex);
1397  if (qualifierIndex!=-1) // qualified name
1398  {
1399  // split off the explicit scope part
1400  explicitScopePart=name.left(qualifierIndex);
1401  // todo: improve namespace alias substitution
1402  replaceNamespaceAliases(explicitScopePart,explicitScopePart.length());
1403  name=name.mid(qualifierIndex+2);
1404  }
1405 
1406  if (name.isEmpty())
1407  {
1408  //printf("] empty name\n");
1409  return 0; // empty name
1410  }
1411 
1412  //printf("Looking for symbol %s\n",name.data());
1413  DefinitionIntf *di = Doxygen::symbolMap->find(name);
1414  // the -g (for C# generics) and -p (for ObjC protocols) are now already
1415  // stripped from the key used in the symbolMap, so that is not needed here.
1416  if (di==0)
1417  {
1418  //di = Doxygen::symbolMap->find(name+"-g");
1419  //if (di==0)
1420  //{
1421  di = Doxygen::symbolMap->find(name+"-p");
1422  if (di==0)
1423  {
1424  //printf("no such symbol!\n");
1425  return 0;
1426  }
1427  //}
1428  }
1429  //printf("found symbol!\n");
1430 
1431  bool hasUsingStatements =
1432  (fileScope && ((fileScope->getUsedNamespaces() &&
1433  fileScope->getUsedNamespaces()->count()>0) ||
1434  (fileScope->getUsedClasses() &&
1435  fileScope->getUsedClasses()->count()>0))
1436  );
1437  //printf("hasUsingStatements=%d\n",hasUsingStatements);
1438  // Since it is often the case that the same name is searched in the same
1439  // scope over an over again (especially for the linked source code generation)
1440  // we use a cache to collect previous results. This is possible since the
1441  // result of a lookup is deterministic. As the key we use the concatenated
1442  // scope, the name to search for and the explicit scope prefix. The speedup
1443  // achieved by this simple cache can be enormous.
1444  int scopeNameLen = scope->name().length()+1;
1445  int nameLen = name.length()+1;
1446  int explicitPartLen = explicitScopePart.length();
1447  int fileScopeLen = hasUsingStatements ? 1+fileScope->absFilePath().length() : 0;
1448 
1449  // below is a more efficient coding of
1450  // QCString key=scope->name()+"+"+name+"+"+explicitScopePart;
1451  QCString key(scopeNameLen+nameLen+explicitPartLen+fileScopeLen+1);
1452  char *p=key.rawData();
1453  qstrcpy(p,scope->name()); *(p+scopeNameLen-1)='+';
1454  p+=scopeNameLen;
1455  qstrcpy(p,name); *(p+nameLen-1)='+';
1456  p+=nameLen;
1457  qstrcpy(p,explicitScopePart);
1458  p+=explicitPartLen;
1459 
1460  // if a file scope is given and it contains using statements we should
1461  // also use the file part in the key (as a class name can be in
1462  // two different namespaces and a using statement in a file can select
1463  // one of them).
1464  if (hasUsingStatements)
1465  {
1466  // below is a more efficient coding of
1467  // key+="+"+fileScope->name();
1468  *p++='+';
1469  qstrcpy(p,fileScope->absFilePath());
1470  p+=fileScopeLen-1;
1471  }
1472  *p='\0';
1473 
1475  //printf("Searching for %s result=%p\n",key.data(),pval);
1476  if (pval)
1477  {
1478  //printf("LookupInfo %p %p '%s' %p\n",
1479  // pval->classDef, pval->typeDef, pval->templSpec.data(),
1480  // pval->resolvedType.data());
1481  if (pTemplSpec) *pTemplSpec=pval->templSpec;
1482  if (pTypeDef) *pTypeDef=pval->typeDef;
1483  if (pResolvedType) *pResolvedType=pval->resolvedType;
1484  //printf("] cachedMatch=%s\n",
1485  // pval->classDef?pval->classDef->name().data():"<none>");
1486  //if (pTemplSpec)
1487  // printf("templSpec=%s\n",pTemplSpec->data());
1488  return pval->classDef;
1489  }
1490  else // not found yet; we already add a 0 to avoid the possibility of
1491  // endless recursion.
1492  {
1494  }
1495 
1496  ClassDef *bestMatch=0;
1497  MemberDef *bestTypedef=0;
1498  QCString bestTemplSpec;
1499  QCString bestResolvedType;
1500  int minDistance=10000; // init at "infinite"
1501 
1502  if (di->definitionType()==DefinitionIntf::TypeSymbolList) // not a unique name
1503  {
1504  //printf(" name is not unique\n");
1506  Definition *d;
1507  int count=0;
1508  for (dli.toFirst();(d=dli.current());++dli,++count) // foreach definition
1509  {
1510  getResolvedSymbol(scope,fileScope,d,explicitScopePart,&actTemplParams,
1511  minDistance,bestMatch,bestTypedef,bestTemplSpec,
1512  bestResolvedType);
1513  }
1514  }
1515  else // unique name
1516  {
1517  //printf(" name is unique\n");
1518  Definition *d = (Definition *)di;
1519  getResolvedSymbol(scope,fileScope,d,explicitScopePart,&actTemplParams,
1520  minDistance,bestMatch,bestTypedef,bestTemplSpec,
1521  bestResolvedType);
1522  }
1523 
1524  if (pTypeDef)
1525  {
1526  *pTypeDef = bestTypedef;
1527  }
1528  if (pTemplSpec)
1529  {
1530  *pTemplSpec = bestTemplSpec;
1531  }
1532  if (pResolvedType)
1533  {
1534  *pResolvedType = bestResolvedType;
1535  }
1536  //printf("getResolvedClassRec: bestMatch=%p pval->resolvedType=%s\n",
1537  // bestMatch,bestResolvedType.data());
1538 
1539  pval=Doxygen::lookupCache->find(key);
1540  if (pval)
1541  {
1542  pval->classDef = bestMatch;
1543  pval->typeDef = bestTypedef;
1544  pval->templSpec = bestTemplSpec;
1545  pval->resolvedType = bestResolvedType;
1546  }
1547  else
1548  {
1549  Doxygen::lookupCache->insert(key,new LookupInfo(bestMatch,bestTypedef,bestTemplSpec,bestResolvedType));
1550  }
1551  //printf("] bestMatch=%s distance=%d\n",
1552  // bestMatch?bestMatch->name().data():"<none>",minDistance);
1553  //if (pTemplSpec)
1554  // printf("templSpec=%s\n",pTemplSpec->data());
1555  return bestMatch;
1556 }
1557 
1558 /* Find the fully qualified class name referred to by the input class
1559  * or typedef name against the input scope.
1560  * Loops through scope and each of its parent scopes looking for a
1561  * match against the input name.
1562  */
1564  FileDef *fileScope,
1565  const char *n,
1566  MemberDef **pTypeDef,
1567  QCString *pTemplSpec,
1568  bool mayBeUnlinkable,
1569  bool mayBeHidden,
1570  QCString *pResolvedType
1571  )
1572 {
1573  static bool optimizeOutputVhdl = Config_getBool("OPTIMIZE_OUTPUT_VHDL");
1574  g_resolvedTypedefs.clear();
1575  if (scope==0 ||
1576  (scope->definitionType()!=Definition::TypeClass &&
1578  ) ||
1579  (scope->getLanguage()==SrcLangExt_Java && QCString(n).find("::")!=-1)
1580  )
1581  {
1582  scope=Doxygen::globalScope;
1583  }
1584  //printf("------------ getResolvedClass(scope=%s,file=%s,name=%s,mayUnlinkable=%d)\n",
1585  // scope?scope->name().data():"<global>",
1586  // fileScope?fileScope->name().data():"<none>",
1587  // n,
1588  // mayBeUnlinkable
1589  // );
1590  ClassDef *result;
1591  if (optimizeOutputVhdl)
1592  {
1593  result = getClass(n);
1594  }
1595  else
1596  {
1597  result = getResolvedClassRec(scope,fileScope,n,pTypeDef,pTemplSpec,pResolvedType);
1598  }
1599  if (result==0) // for nested classes imported via tag files, the scope may not
1600  // present, so we check the class name directly as well.
1601  // See also bug701314
1602  {
1603  result = getClass(n);
1604  }
1605  if (!mayBeUnlinkable && result && !result->isLinkable())
1606  {
1607  if (!mayBeHidden || !result->isHidden())
1608  {
1609  //printf("result was %s\n",result?result->name().data():"<none>");
1610  result=0; // don't link to artificial/hidden classes unless explicitly allowed
1611  }
1612  }
1613  //printf("getResolvedClass(%s,%s)=%s\n",scope?scope->name().data():"<global>",
1614  // n,result?result->name().data():"<none>");
1615  return result;
1616 }
1617 
1618 //-------------------------------------------------------------------------
1619 //-------------------------------------------------------------------------
1620 //-------------------------------------------------------------------------
1621 //-------------------------------------------------------------------------
1622 
1623 static bool findOperator(const QCString &s,int i)
1624 {
1625  int b = s.findRev("operator",i);
1626  if (b==-1) return FALSE; // not found
1627  b+=8;
1628  while (b<i) // check if there are only spaces in between
1629  // the operator and the >
1630  {
1631  if (!isspace((uchar)s.at(b))) return FALSE;
1632  b++;
1633  }
1634  return TRUE;
1635 }
1636 
1637 static bool findOperator2(const QCString &s,int i)
1638 {
1639  int b = s.findRev("operator",i);
1640  if (b==-1) return FALSE; // not found
1641  b+=8;
1642  while (b<i) // check if there are only non-ascii
1643  // characters in front of the operator
1644  {
1645  if (isId((uchar)s.at(b))) return FALSE;
1646  b++;
1647  }
1648  return TRUE;
1649 }
1650 
1651 static const char constScope[] = { 'c', 'o', 'n', 's', 't', ':' };
1652 static const char virtualScope[] = { 'v', 'i', 'r', 't', 'u', 'a', 'l', ':' };
1653 
1654 // Note: this function is not reentrant due to the use of static buffer!
1656 {
1657  static bool cliSupport = Config_getBool("CPP_CLI_SUPPORT");
1658  static bool vhdl = Config_getBool("OPTIMIZE_OUTPUT_VHDL");
1659 
1660  if (s.isEmpty() || vhdl) return s;
1661  static GrowBuf growBuf;
1662  //int resultLen = 1024;
1663  //int resultPos = 0;
1664  //QCString result(resultLen);
1665  // we use growBuf.addChar(c) instead of result+=c to
1666  // improve the performance of this function
1667  growBuf.clear();
1668  uint i;
1669  uint l=s.length();
1670  uint csp=0;
1671  uint vsp=0;
1672  char c;
1673  for (i=0;i<l;i++)
1674  {
1675 nextChar:
1676  c=s.at(i);
1677 
1678  // search for "const"
1679  if (csp<6 && c==constScope[csp] && // character matches substring "const"
1680  (csp>0 || // if it is the first character
1681  i==0 || // the previous may not be a digit
1682  !isId(s.at(i-1))
1683  )
1684  )
1685  csp++;
1686  else // reset counter
1687  csp=0;
1688 
1689  // search for "virtual"
1690  if (vsp<8 && c==virtualScope[vsp] && // character matches substring "virtual"
1691  (vsp>0 || // if it is the first character
1692  i==0 || // the previous may not be a digit
1693  !isId(s.at(i-1))
1694  )
1695  )
1696  vsp++;
1697  else // reset counter
1698  vsp=0;
1699 
1700  if (c=='"') // quoted string
1701  {
1702  i++;
1703  growBuf.addChar(c);
1704  while (i<l)
1705  {
1706  char cc=s.at(i);
1707  growBuf.addChar(cc);
1708  if (cc=='\\') // escaped character
1709  {
1710  growBuf.addChar(s.at(i+1));
1711  i+=2;
1712  }
1713  else if (cc=='"') // end of string
1714  { i++; goto nextChar; }
1715  else // any other character
1716  { i++; }
1717  }
1718  }
1719  else if (i<l-2 && c=='<' && // current char is a <
1720  (isId(s.at(i+1)) || isspace((uchar)s.at(i+1))) && // next char is an id char or space
1721  (i<8 || !findOperator(s,i)) // string in front is not "operator"
1722  )
1723  {
1724  growBuf.addChar('<');
1725  growBuf.addChar(' ');
1726  }
1727  else if (i>0 && c=='>' && // current char is a >
1728  (isId(s.at(i-1)) || isspace((uchar)s.at(i-1)) || s.at(i-1)=='*' || s.at(i-1)=='&' || s.at(i-1)=='.') && // prev char is an id char or space
1729  (i<8 || !findOperator(s,i)) // string in front is not "operator"
1730  )
1731  {
1732  growBuf.addChar(' ');
1733  growBuf.addChar('>');
1734  }
1735  else if (i>0 && c==',' && !isspace((uchar)s.at(i-1))
1736  && ((i<l-1 && (isId(s.at(i+1)) || s.at(i+1)=='[')) // the [ is for attributes (see bug702170)
1737  || (i<l-2 && s.at(i+1)=='$' && isId(s.at(i+2))) // for PHP
1738  || (i<l-3 && s.at(i+1)=='&' && s.at(i+2)=='$' && isId(s.at(i+3))))) // for PHP
1739  {
1740  growBuf.addChar(',');
1741  growBuf.addChar(' ');
1742  }
1743  else if (i>0 &&
1744  (
1745  (s.at(i-1)==')' && isId(c)) // ")id" -> ") id"
1746  ||
1747  (c=='\'' && s.at(i-1)==' ') // "'id" -> "' id"
1748  ||
1749  (i>1 && s.at(i-2)==' ' && s.at(i-1)==' ') // " id" -> " id"
1750  )
1751  )
1752  {
1753  growBuf.addChar(' ');
1754  growBuf.addChar(c);
1755  }
1756  else if (c=='t' && csp==5 /*&& (i<5 || !isId(s.at(i-5)))*/ &&
1757  !(isId(s.at(i+1)) /*|| s.at(i+1)==' '*/ ||
1758  s.at(i+1)==')' ||
1759  s.at(i+1)==',' ||
1760  s.at(i+1)=='\0'
1761  )
1762  )
1763  // prevent const ::A from being converted to const::A
1764  {
1765  growBuf.addChar('t');
1766  growBuf.addChar(' ');
1767  if (s.at(i+1)==' ') i++;
1768  csp=0;
1769  }
1770  else if (c==':' && csp==6 /*&& (i<6 || !isId(s.at(i-6)))*/)
1771  // replace const::A by const ::A
1772  {
1773  growBuf.addChar(' ');
1774  growBuf.addChar(':');
1775  csp=0;
1776  }
1777  else if (c=='l' && vsp==7 /*&& (i<7 || !isId(s.at(i-7)))*/ &&
1778  !(isId(s.at(i+1)) /*|| s.at(i+1)==' '*/ ||
1779  s.at(i+1)==')' ||
1780  s.at(i+1)==',' ||
1781  s.at(i+1)=='\0'
1782  )
1783  )
1784  // prevent virtual ::A from being converted to virtual::A
1785  {
1786  growBuf.addChar('l');
1787  growBuf.addChar(' ');
1788  if (s.at(i+1)==' ') i++;
1789  vsp=0;
1790  }
1791  else if (c==':' && vsp==8 /*&& (i<8 || !isId(s.at(i-8)))*/)
1792  // replace virtual::A by virtual ::A
1793  {
1794  growBuf.addChar(' ');
1795  growBuf.addChar(':');
1796  vsp=0;
1797  }
1798  else if (!isspace((uchar)c) || // not a space
1799  ( i>0 && i<l-1 && // internal character
1800  (isId(s.at(i-1)) || s.at(i-1)==')' || s.at(i-1)==',' || s.at(i-1)=='>' || s.at(i-1)==']') &&
1801  (isId(s.at(i+1)) ||
1802  (i<l-2 && s.at(i+1)=='$' && isId(s.at(i+2))) ||
1803  (i<l-3 && s.at(i+1)=='&' && s.at(i+2)=='$' && isId(s.at(i+3)))
1804  )
1805  )
1806  )
1807  {
1808  if (c=='\t') c=' ';
1809  if (c=='*' || c=='&' || c=='@' || c=='$')
1810  {
1811  //uint rl=result.length();
1812  uint rl=growBuf.getPos();
1813  if ((rl>0 && (isId(growBuf.at(rl-1)) || growBuf.at(rl-1)=='>')) &&
1814  ((c!='*' && c!='&') || !findOperator2(s,i)) // avoid splitting operator* and operator->* and operator&
1815  )
1816  {
1817  growBuf.addChar(' ');
1818  }
1819  }
1820  else if (c=='-')
1821  {
1822  uint rl=growBuf.getPos();
1823  if (rl>0 && growBuf.at(rl-1)==')' && i<l-1 && s.at(i+1)=='>') // trailing return type ')->' => ') ->'
1824  {
1825  growBuf.addChar(' ');
1826  }
1827  }
1828  growBuf.addChar(c);
1829  if (cliSupport &&
1830  (c=='^' || c=='%') && i>1 && isId(s.at(i-1)) &&
1831  !findOperator(s,i)
1832  )
1833  {
1834  growBuf.addChar(' '); // C++/CLI: Type^ name and Type% name
1835  }
1836  }
1837  }
1838  growBuf.addChar(0);
1839  //printf("removeRedundantWhiteSpace(`%s')=`%s'\n",s.data(),growBuf.get());
1840  //result.resize(resultPos);
1841  return growBuf.get();
1842 }
1843 
1844 /**
1845  * Returns the position in the string where a function parameter list
1846  * begins, or -1 if one is not found.
1847  */
1849 {
1850  int pos=-1;
1851  int templateDepth=0;
1852  do
1853  {
1854  if (templateDepth > 0)
1855  {
1856  int nextOpenPos=name.findRev('>', pos);
1857  int nextClosePos=name.findRev('<', pos);
1858  if (nextOpenPos!=-1 && nextOpenPos>nextClosePos)
1859  {
1860  ++templateDepth;
1861  pos=nextOpenPos-1;
1862  }
1863  else if (nextClosePos!=-1)
1864  {
1865  --templateDepth;
1866  pos=nextClosePos-1;
1867  }
1868  else // more >'s than <'s, see bug701295
1869  {
1870  return -1;
1871  }
1872  }
1873  else
1874  {
1875  int lastAnglePos=name.findRev('>', pos);
1876  int bracePos=name.findRev('(', pos);
1877  if (lastAnglePos!=-1 && lastAnglePos>bracePos)
1878  {
1879  ++templateDepth;
1880  pos=lastAnglePos-1;
1881  }
1882  else
1883  {
1884  int bp = bracePos>0 ? name.findRev('(',bracePos-1) : -1;
1885  // bp test is to allow foo(int(&)[10]), but we need to make an exception for operator()
1886  return bp==-1 || (bp>=8 && name.mid(bp-8,10)=="operator()") ? bracePos : bp;
1887  }
1888  }
1889  } while (pos!=-1);
1890  return -1;
1891 }
1892 
1894 {
1895  int sl=scope.length();
1896  int nl=name.length();
1897  return (name==scope || // equal
1898  (scope.right(nl)==name && // substring
1899  sl-nl>1 && scope.at(sl-nl-1)==':' && scope.at(sl-nl-2)==':' // scope
1900  )
1901  );
1902 }
1903 
1905 {
1906  int sl=scope.length();
1907  int nl=name.length();
1908  return (name==scope || // equal
1909  (scope.left(nl)==name && // substring
1910  sl>nl+1 && scope.at(nl)==':' && scope.at(nl+1)==':' // scope
1911  )
1912  );
1913 }
1914 
1915 
1917  FileDef *fileScope,Definition *self,
1918  const char *text, bool autoBreak,bool external,
1919  bool keepSpaces,int indentLevel)
1920 {
1921  //printf("linkify=`%s'\n",text);
1922  static QRegExp regExp("[a-z_A-Z\\x80-\\xFF][~!a-z_A-Z0-9$\\\\.:\\x80-\\xFF]*");
1923  static QRegExp regExpSplit("(?!:),");
1924  QCString txtStr=text;
1925  int strLen = txtStr.length();
1926  //printf("linkifyText scope=%s fileScope=%s strtxt=%s strlen=%d external=%d\n",
1927  // scope?scope->name().data():"<none>",
1928  // fileScope?fileScope->name().data():"<none>",
1929  // txtStr.data(),strLen,external);
1930  int matchLen;
1931  int index=0;
1932  int newIndex;
1933  int skipIndex=0;
1934  int floatingIndex=0;
1935  if (strLen==0) return;
1936  // read a word from the text string
1937  while ((newIndex=regExp.match(txtStr,index,&matchLen))!=-1 &&
1938  (newIndex==0 || !(txtStr.at(newIndex-1)>='0' && txtStr.at(newIndex-1)<='9')) // avoid matching part of hex numbers
1939  )
1940  {
1941  // add non-word part to the result
1942  floatingIndex+=newIndex-skipIndex+matchLen;
1943  bool insideString=FALSE;
1944  int i;
1945  for (i=index;i<newIndex;i++)
1946  {
1947  if (txtStr.at(i)=='"') insideString=!insideString;
1948  }
1949 
1950  //printf("floatingIndex=%d strlen=%d autoBreak=%d\n",floatingIndex,strLen,autoBreak);
1951  if (strLen>35 && floatingIndex>30 && autoBreak) // try to insert a split point
1952  {
1953  QCString splitText = txtStr.mid(skipIndex,newIndex-skipIndex);
1954  int splitLength = splitText.length();
1955  int offset=1;
1956  i=splitText.find(regExpSplit,0);
1957  if (i==-1) { i=splitText.find('<'); if (i!=-1) offset=0; }
1958  if (i==-1) i=splitText.find('>');
1959  if (i==-1) i=splitText.find(' ');
1960  //printf("splitText=[%s] len=%d i=%d offset=%d\n",splitText.data(),splitLength,i,offset);
1961  if (i!=-1) // add a link-break at i in case of Html output
1962  {
1963  out.writeString(splitText.left(i+offset),keepSpaces);
1964  out.writeBreak(indentLevel==0 ? 0 : indentLevel+1);
1965  out.writeString(splitText.right(splitLength-i-offset),keepSpaces);
1966  floatingIndex=splitLength-i-offset+matchLen;
1967  }
1968  else
1969  {
1970  out.writeString(splitText,keepSpaces);
1971  }
1972  }
1973  else
1974  {
1975  //ol.docify(txtStr.mid(skipIndex,newIndex-skipIndex));
1976  out.writeString(txtStr.mid(skipIndex,newIndex-skipIndex),keepSpaces);
1977  }
1978  // get word from string
1979  QCString word=txtStr.mid(newIndex,matchLen);
1980  QCString matchWord = substitute(substitute(word,"\\","::"),".","::");
1981  //printf("linkifyText word=%s matchWord=%s scope=%s\n",
1982  // word.data(),matchWord.data(),scope?scope->name().data():"<none>");
1983  bool found=FALSE;
1984  if (!insideString)
1985  {
1986  ClassDef *cd=0;
1987  FileDef *fd=0;
1988  MemberDef *md=0;
1989  NamespaceDef *nd=0;
1990  GroupDef *gd=0;
1991  //printf("** Match word '%s'\n",matchWord.data());
1992 
1993  MemberDef *typeDef=0;
1994  cd=getResolvedClass(scope,fileScope,matchWord,&typeDef);
1995  if (typeDef) // First look at typedef then class, see bug 584184.
1996  {
1997  //printf("Found typedef %s\n",typeDef->name().data());
1998  if (external ? typeDef->isLinkable() : typeDef->isLinkableInProject())
1999  {
2000  if (typeDef->getOuterScope()!=self)
2001  {
2002  out.writeLink(typeDef->getReference(),
2003  typeDef->getOutputFileBase(),
2004  typeDef->anchor(),
2005  word);
2006  found=TRUE;
2007  }
2008  }
2009  }
2010  if (!found && (cd || (cd=getClass(matchWord))))
2011  {
2012  //printf("Found class %s\n",cd->name().data());
2013  // add link to the result
2014  if (external ? cd->isLinkable() : cd->isLinkableInProject())
2015  {
2016  if (cd!=self)
2017  {
2018  out.writeLink(cd->getReference(),cd->getOutputFileBase(),cd->anchor(),word);
2019  found=TRUE;
2020  }
2021  }
2022  }
2023  else if ((cd=getClass(matchWord+"-p"))) // search for Obj-C protocols as well
2024  {
2025  // add link to the result
2026  if (external ? cd->isLinkable() : cd->isLinkableInProject())
2027  {
2028  if (cd!=self)
2029  {
2030  out.writeLink(cd->getReference(),cd->getOutputFileBase(),cd->anchor(),word);
2031  found=TRUE;
2032  }
2033  }
2034  }
2035 // else if ((cd=getClass(matchWord+"-g"))) // C# generic as well
2036 // {
2037 // // add link to the result
2038 // if (external ? cd->isLinkable() : cd->isLinkableInProject())
2039 // {
2040 // if (cd!=self)
2041 // {
2042 // out.writeLink(cd->getReference(),cd->getOutputFileBase(),cd->anchor(),word);
2043 // found=TRUE;
2044 // }
2045 // }
2046 // }
2047  else
2048  {
2049  //printf(" -> nothing\n");
2050  }
2051 
2052  int m = matchWord.findRev("::");
2053  QCString scopeName;
2054  if (scope &&
2055  (scope->definitionType()==Definition::TypeClass ||
2057  )
2058  )
2059  {
2060  scopeName=scope->name();
2061  }
2062  else if (m!=-1)
2063  {
2064  scopeName = matchWord.left(m);
2065  matchWord = matchWord.mid(m+2);
2066  }
2067 
2068  //printf("ScopeName=%s\n",scopeName.data());
2069  //if (!found) printf("Trying to link %s in %s\n",word.data(),scopeName.data());
2070  if (!found &&
2071  getDefs(scopeName,matchWord,0,md,cd,fd,nd,gd) &&
2072  //(md->isTypedef() || md->isEnumerate() ||
2073  // md->isReference() || md->isVariable()
2074  //) &&
2075  (external ? md->isLinkable() : md->isLinkableInProject())
2076  )
2077  {
2078  //printf("Found ref scope=%s\n",d?d->name().data():"<global>");
2079  //ol.writeObjectLink(d->getReference(),d->getOutputFileBase(),
2080  // md->anchor(),word);
2081  if (md!=self && (self==0 || md->name()!=self->name()))
2082  // name check is needed for overloaded members, where getDefs just returns one
2083  {
2084  out.writeLink(md->getReference(),md->getOutputFileBase(),
2085  md->anchor(),word);
2086  //printf("found symbol %s\n",matchWord.data());
2087  found=TRUE;
2088  }
2089  }
2090  }
2091 
2092  if (!found) // add word to the result
2093  {
2094  out.writeString(word,keepSpaces);
2095  }
2096  // set next start point in the string
2097  //printf("index=%d/%d\n",index,txtStr.length());
2098  skipIndex=index=newIndex+matchLen;
2099  }
2100  // add last part of the string to the result.
2101  //ol.docify(txtStr.right(txtStr.length()-skipIndex));
2102  out.writeString(txtStr.right(txtStr.length()-skipIndex),keepSpaces);
2103 }
2104 
2105 
2107 {
2108  QCString exampleLine=theTranslator->trWriteList(ed->count());
2109 
2110  //bool latexEnabled = ol.isEnabled(OutputGenerator::Latex);
2111  //bool manEnabled = ol.isEnabled(OutputGenerator::Man);
2112  //bool htmlEnabled = ol.isEnabled(OutputGenerator::Html);
2113  QRegExp marker("@[0-9]+");
2114  int index=0,newIndex,matchLen;
2115  // now replace all markers in inheritLine with links to the classes
2116  while ((newIndex=marker.match(exampleLine,index,&matchLen))!=-1)
2117  {
2118  bool ok;
2119  ol.parseText(exampleLine.mid(index,newIndex-index));
2120  uint entryIndex = exampleLine.mid(newIndex+1,matchLen-1).toUInt(&ok);
2121  Example *e=ed->at(entryIndex);
2122  if (ok && e)
2123  {
2124  ol.pushGeneratorState();
2125  //if (latexEnabled) ol.disable(OutputGenerator::Latex);
2128  // link for Html / man
2129  //printf("writeObjectLink(file=%s)\n",e->file.data());
2130  ol.writeObjectLink(0,e->file,e->anchor,e->name);
2131  ol.popGeneratorState();
2132 
2133  ol.pushGeneratorState();
2134  //if (latexEnabled) ol.enable(OutputGenerator::Latex);
2137  // link for Latex / pdf with anchor because the sources
2138  // are not hyperlinked (not possible with a verbatim environment).
2139  ol.writeObjectLink(0,e->file,0,e->name);
2140  //if (manEnabled) ol.enable(OutputGenerator::Man);
2141  //if (htmlEnabled) ol.enable(OutputGenerator::Html);
2142  ol.popGeneratorState();
2143  }
2144  index=newIndex+matchLen;
2145  }
2146  ol.parseText(exampleLine.right(exampleLine.length()-index));
2147  ol.writeString(".");
2148 }
2149 
2150 
2151 QCString argListToString(ArgumentList *al,bool useCanonicalType,bool showDefVals)
2152 {
2153  QCString result;
2154  if (al==0) return result;
2155  ArgumentListIterator ali(*al);
2156  Argument *a=ali.current();
2157  result+="(";
2158  while (a)
2159  {
2160  QCString type1 = useCanonicalType && !a->canType.isEmpty() ?
2161  a->canType : a->type;
2162  QCString type2;
2163  int i=type1.find(")("); // hack to deal with function pointers
2164  if (i!=-1)
2165  {
2166  type2=type1.mid(i);
2167  type1=type1.left(i);
2168  }
2169  if (!a->attrib.isEmpty())
2170  {
2171  result+=a->attrib+" ";
2172  }
2173  if (!a->name.isEmpty() || !a->array.isEmpty())
2174  {
2175  result+= type1+" "+a->name+type2+a->array;
2176  }
2177  else
2178  {
2179  result+= type1+type2;
2180  }
2181  if (!a->defval.isEmpty() && showDefVals)
2182  {
2183  result+="="+a->defval;
2184  }
2185  ++ali;
2186  a = ali.current();
2187  if (a) result+=", ";
2188  }
2189  result+=")";
2190  if (al->constSpecifier) result+=" const";
2191  if (al->volatileSpecifier) result+=" volatile";
2192  if (!al->trailingReturnType.isEmpty()) result+=" -> "+al->trailingReturnType;
2193  if (al->pureSpecifier) result+=" =0";
2194  return removeRedundantWhiteSpace(result);
2195 }
2196 
2198 {
2199  QCString result;
2200  if (al==0) return result;
2201  result="<";
2202  ArgumentListIterator ali(*al);
2203  Argument *a=ali.current();
2204  while (a)
2205  {
2206  if (!a->name.isEmpty()) // add template argument name
2207  {
2208  if (a->type.left(4)=="out") // C# covariance
2209  {
2210  result+="out ";
2211  }
2212  else if (a->type.left(3)=="in") // C# contravariance
2213  {
2214  result+="in ";
2215  }
2216  if (lang==SrcLangExt_Java || lang==SrcLangExt_CSharp)
2217  {
2218  result+=a->type+" ";
2219  }
2220  result+=a->name;
2221  }
2222  else // extract name from type
2223  {
2224  int i=a->type.length()-1;
2225  while (i>=0 && isId(a->type.at(i))) i--;
2226  if (i>0)
2227  {
2228  result+=a->type.right(a->type.length()-i-1);
2229  if (a->type.find("...")!=-1)
2230  {
2231  result+="...";
2232  }
2233  }
2234  else // nothing found -> take whole name
2235  {
2236  result+=a->type;
2237  }
2238  }
2239  if (!a->typeConstraint.isEmpty() && lang==SrcLangExt_Java)
2240  {
2241  result+=" extends "; // TODO: now Java specific, C# has where...
2242  result+=a->typeConstraint;
2243  }
2244  ++ali;
2245  a=ali.current();
2246  if (a) result+=", ";
2247  }
2248  result+=">";
2249  return removeRedundantWhiteSpace(result);
2250 }
2251 
2252 
2253 // compute the HTML anchors for a list of members
2255 {
2256  //int count=0;
2257  if (ml==0) return;
2258  MemberListIterator mli(*ml);
2259  MemberDef *md;
2260  for (;(md=mli.current());++mli)
2261  {
2262  if (!md->isReference())
2263  {
2264  //QCString anchor;
2265  //if (groupId==-1)
2266  // anchor.sprintf("%c%d",id,count++);
2267  //else
2268  // anchor.sprintf("%c%d_%d",id,groupId,count++);
2269  //if (cd) anchor.prepend(escapeCharsInString(cd->name(),FALSE));
2270  md->setAnchor();
2271  //printf("setAnchors(): Member %s outputFileBase=%s anchor %s result %s\n",
2272  // md->name().data(),md->getOutputFileBase().data(),anchor.data(),md->anchor().data());
2273  }
2274  }
2275 }
2276 
2277 //----------------------------------------------------------------------------
2278 
2279 /*! takes the \a buf of the given length \a len and converts CR LF (DOS)
2280  * or CR (MAC) line ending to LF (Unix). Returns the length of the
2281  * converted content (i.e. the same as \a len (Unix, MAC) or
2282  * smaller (DOS).
2283  */
2284 int filterCRLF(char *buf,int len)
2285 {
2286  int src = 0; // source index
2287  int dest = 0; // destination index
2288  char c; // current character
2289 
2290  while (src<len)
2291  {
2292  c = buf[src++]; // Remember the processed character.
2293  if (c == '\r') // CR to be solved (MAC, DOS)
2294  {
2295  c = '\n'; // each CR to LF
2296  if (src<len && buf[src] == '\n')
2297  ++src; // skip LF just after CR (DOS)
2298  }
2299  else if ( c == '\0' && src<len-1) // filter out internal \0 characters, as it will confuse the parser
2300  {
2301  c = ' '; // turn into a space
2302  }
2303  buf[dest++] = c; // copy the (modified) character to dest
2304  }
2305  return dest; // length of the valid part of the buf
2306 }
2307 
2308 static QCString getFilterFromList(const char *name,const QStrList &filterList,bool &found)
2309 {
2310  found=FALSE;
2311  // compare the file name to the filter pattern list
2312  QStrListIterator sli(filterList);
2313  char* filterStr;
2314  for (sli.toFirst(); (filterStr = sli.current()); ++sli)
2315  {
2316  QCString fs = filterStr;
2317  int i_equals=fs.find('=');
2318  if (i_equals!=-1)
2319  {
2320  QCString filterPattern = fs.left(i_equals);
2321  QRegExp fpat(filterPattern,portable_fileSystemIsCaseSensitive(),TRUE);
2322  if (fpat.match(name)!=-1)
2323  {
2324  // found a match!
2325  QCString filterName = fs.mid(i_equals+1);
2326  if (filterName.find(' ')!=-1)
2327  { // add quotes if the name has spaces
2328  filterName="\""+filterName+"\"";
2329  }
2330  found=TRUE;
2331  return filterName;
2332  }
2333  }
2334  }
2335 
2336  // no match
2337  return "";
2338 }
2339 
2340 /*! looks for a filter for the file \a name. Returns the name of the filter
2341  * if there is a match for the file name, otherwise an empty string.
2342  * In case \a inSourceCode is TRUE then first the source filter list is
2343  * considered.
2344  */
2345 QCString getFileFilter(const char* name,bool isSourceCode)
2346 {
2347  // sanity check
2348  if (name==0) return "";
2349 
2350  QStrList& filterSrcList = Config_getList("FILTER_SOURCE_PATTERNS");
2351  QStrList& filterList = Config_getList("FILTER_PATTERNS");
2352 
2353  QCString filterName;
2354  bool found=FALSE;
2355  if (isSourceCode && !filterSrcList.isEmpty())
2356  { // first look for source filter pattern list
2357  filterName = getFilterFromList(name,filterSrcList,found);
2358  }
2359  if (!found && filterName.isEmpty())
2360  { // then look for filter pattern list
2361  filterName = getFilterFromList(name,filterList,found);
2362  }
2363  if (!found)
2364  { // then use the generic input filter
2365  return Config_getString("INPUT_FILTER");
2366  }
2367  else
2368  {
2369  return filterName;
2370  }
2371 }
2372 
2373 
2375 {
2376  bool error=FALSE;
2377  static QCString inputEncoding = Config_getString("INPUT_ENCODING");
2378  const char *outputEncoding = "UTF-8";
2379  if (inputEncoding.isEmpty() || qstricmp(inputEncoding,outputEncoding)==0) return input;
2380  int inputSize=input.length();
2381  int outputSize=inputSize*4+1;
2382  QCString output(outputSize);
2383  void *cd = portable_iconv_open(outputEncoding,inputEncoding);
2384  if (cd==(void *)(-1))
2385  {
2386  err("unsupported character conversion: '%s'->'%s'\n",
2387  inputEncoding.data(),outputEncoding);
2388  error=TRUE;
2389  }
2390  if (!error)
2391  {
2392  size_t iLeft=inputSize;
2393  size_t oLeft=outputSize;
2394  char *inputPtr = input.rawData();
2395  char *outputPtr = output.rawData();
2396  if (!portable_iconv(cd, &inputPtr, &iLeft, &outputPtr, &oLeft))
2397  {
2398  outputSize-=(int)oLeft;
2399  output.resize(outputSize+1);
2400  output.at(outputSize)='\0';
2401  //printf("iconv: input size=%d output size=%d\n[%s]\n",size,newSize,srcBuf.data());
2402  }
2403  else
2404  {
2405  err("failed to translate characters from %s to %s: check INPUT_ENCODING\ninput=[%s]\n",
2406  inputEncoding.data(),outputEncoding,input.data());
2407  error=TRUE;
2408  }
2409  }
2411  return error ? input : output;
2412 }
2413 
2414 /*! reads a file with name \a name and returns it as a string. If \a filter
2415  * is TRUE the file will be filtered by any user specified input filter.
2416  * If \a name is "-" the string will be read from standard input.
2417  */
2418 QCString fileToString(const char *name,bool filter,bool isSourceCode)
2419 {
2420  if (name==0 || name[0]==0) return 0;
2421  QFile f;
2422 
2423  bool fileOpened=FALSE;
2424  if (name[0]=='-' && name[1]==0) // read from stdin
2425  {
2426  fileOpened=f.open(IO_ReadOnly,stdin);
2427  if (fileOpened)
2428  {
2429  const int bSize=4096;
2430  QCString contents(bSize);
2431  int totalSize=0;
2432  int size;
2433  while ((size=f.readBlock(contents.rawData()+totalSize,bSize))==bSize)
2434  {
2435  totalSize+=bSize;
2436  contents.resize(totalSize+bSize);
2437  }
2438  totalSize = filterCRLF(contents.rawData(),totalSize+size)+2;
2439  contents.resize(totalSize);
2440  contents.at(totalSize-2)='\n'; // to help the scanner
2441  contents.at(totalSize-1)='\0';
2442  return contents;
2443  }
2444  }
2445  else // read from file
2446  {
2447  QFileInfo fi(name);
2448  if (!fi.exists() || !fi.isFile())
2449  {
2450  err("file `%s' not found\n",name);
2451  return "";
2452  }
2453  BufStr buf(fi.size());
2454  fileOpened=readInputFile(name,buf,filter,isSourceCode);
2455  if (fileOpened)
2456  {
2457  int s = buf.size();
2458  if (s>1 && buf.at(s-2)!='\n')
2459  {
2460  buf.at(s-1)='\n';
2461  buf.addChar(0);
2462  }
2463  return buf.data();
2464  }
2465  }
2466  if (!fileOpened)
2467  {
2468  err("cannot open file `%s' for reading\n",name);
2469  }
2470  return "";
2471 }
2472 
2473 QCString dateToString(bool includeTime)
2474 {
2476  QCString sourceDateEpoch = portable_getenv("SOURCE_DATE_EPOCH");
2477  if (!sourceDateEpoch.isEmpty())
2478  {
2479  bool ok;
2480  uint64 epoch = sourceDateEpoch.toUInt64(&ok);
2481  if (!ok)
2482  {
2483  static bool warnedOnce=FALSE;
2484  if (!warnedOnce)
2485  {
2486  warn_uncond("Environment variable SOURCE_DATE_EPOCH does not contain a valid number; value is '%s'\n",
2487  sourceDateEpoch.data());
2488  warnedOnce=TRUE;
2489  }
2490  }
2491  else if (epoch>UINT_MAX)
2492  {
2493  static bool warnedOnce=FALSE;
2494  if (!warnedOnce)
2495  {
2496  warn_uncond("Environment variable SOURCE_DATA_EPOCH must have a value smaller than or equal to %llu; actual value %llu\n",UINT_MAX,epoch);
2497  warnedOnce=TRUE;
2498  }
2499  }
2500  else // all ok, replace current time with epoch value
2501  {
2502  current.setTime_t((ulong)epoch); // TODO: add support for 64bit epoch value
2503  }
2504  }
2505  return theTranslator->trDateTime(current.date().year(),
2506  current.date().month(),
2507  current.date().day(),
2508  current.date().dayOfWeek(),
2509  current.time().hour(),
2510  current.time().minute(),
2511  current.time().second(),
2512  includeTime);
2513 }
2514 
2516 {
2517  const QDate &d=QDate::currentDate();
2518  QCString result;
2519  result.sprintf("%d", d.year());
2520  return result;
2521 }
2522 
2523 //----------------------------------------------------------------------
2524 // recursive function that returns the number of branches in the
2525 // inheritance tree that the base class `bcd' is below the class `cd'
2526 
2527 int minClassDistance(const ClassDef *cd,const ClassDef *bcd,int level)
2528 {
2529  if (bcd->categoryOf()) // use class that is being extended in case of
2530  // an Objective-C category
2531  {
2532  bcd=bcd->categoryOf();
2533  }
2534  if (cd==bcd) return level;
2535  if (level==256)
2536  {
2537  warn_uncond("class %s seem to have a recursive "
2538  "inheritance relation!\n",cd->name().data());
2539  return -1;
2540  }
2541  int m=maxInheritanceDepth;
2542  if (cd->baseClasses())
2543  {
2544  BaseClassListIterator bcli(*cd->baseClasses());
2545  BaseClassDef *bcdi;
2546  for (;(bcdi=bcli.current());++bcli)
2547  {
2548  int mc=minClassDistance(bcdi->classDef,bcd,level+1);
2549  if (mc<m) m=mc;
2550  if (m<0) break;
2551  }
2552  }
2553  return m;
2554 }
2555 
2557 {
2558  if (bcd->categoryOf()) // use class that is being extended in case of
2559  // an Objective-C category
2560  {
2561  bcd=bcd->categoryOf();
2562  }
2563  if (cd==bcd)
2564  {
2565  goto exit;
2566  }
2567  if (level==256)
2568  {
2569  err("Internal inconsistency: found class %s seem to have a recursive "
2570  "inheritance relation! Please send a bug report to dimitri@stack.nl\n",cd->name().data());
2571  }
2572  else if (cd->baseClasses())
2573  {
2574  BaseClassListIterator bcli(*cd->baseClasses());
2575  BaseClassDef *bcdi;
2576  for (;(bcdi=bcli.current()) && prot!=Private;++bcli)
2577  {
2578  Protection baseProt = classInheritedProtectionLevel(bcdi->classDef,bcd,bcdi->prot,level+1);
2579  if (baseProt==Private) prot=Private;
2580  else if (baseProt==Protected) prot=Protected;
2581  }
2582  }
2583 exit:
2584  //printf("classInheritedProtectionLevel(%s,%s)=%d\n",cd->name().data(),bcd->name().data(),prot);
2585  return prot;
2586 }
2587 
2588 //static void printArgList(ArgumentList *al)
2589 //{
2590 // if (al==0) return;
2591 // ArgumentListIterator ali(*al);
2592 // Argument *a;
2593 // printf("(");
2594 // for (;(a=ali.current());++ali)
2595 // {
2596 // printf("t=`%s' n=`%s' v=`%s' ",a->type.data(),!a->name.isEmpty()>0?a->name.data():"",!a->defval.isEmpty()>0?a->defval.data():"");
2597 // }
2598 // printf(")");
2599 //}
2600 
2601 #ifndef NEWMATCH
2602 // strip any template specifiers that follow className in string s
2604  const QCString &namespaceName,
2605  const QCString &className,
2606  const QCString &s
2607  )
2608 {
2609  //printf("trimTemplateSpecifiers(%s,%s,%s)\n",namespaceName.data(),className.data(),s.data());
2610  QCString scopeName=mergeScopes(namespaceName,className);
2611  ClassDef *cd=getClass(scopeName);
2612  if (cd==0) return s; // should not happen, but guard anyway.
2613 
2614  QCString result=s;
2615 
2616  int i=className.length()-1;
2617  if (i>=0 && className.at(i)=='>') // template specialization
2618  {
2619  // replace unspecialized occurrences in s, with their specialized versions.
2620  int count=1;
2621  int cl=i+1;
2622  while (i>=0)
2623  {
2624  char c=className.at(i);
2625  if (c=='>') count++,i--;
2626  else if (c=='<') { count--; if (count==0) break; }
2627  else i--;
2628  }
2629  QCString unspecClassName=className.left(i);
2630  int l=i;
2631  int p=0;
2632  while ((i=result.find(unspecClassName,p))!=-1)
2633  {
2634  if (result.at(i+l)!='<') // unspecialized version
2635  {
2636  result=result.left(i)+className+result.right(result.length()-i-l);
2637  l=cl;
2638  }
2639  p=i+l;
2640  }
2641  }
2642 
2643  //printf("result after specialization: %s\n",result.data());
2644 
2646  //printf("QualifiedName = %s\n",qualName.data());
2647  // We strip the template arguments following className (if any)
2648  if (!qualName.isEmpty()) // there is a class name
2649  {
2650  int is,ps=0;
2651  int p=0,l,i;
2652 
2653  while ((is=getScopeFragment(qualName,ps,&l))!=-1)
2654  {
2655  QCString qualNamePart = qualName.right(qualName.length()-is);
2656  //printf("qualNamePart=%s\n",qualNamePart.data());
2657  while ((i=result.find(qualNamePart,p))!=-1)
2658  {
2659  int ql=qualNamePart.length();
2660  result=result.left(i)+cd->name()+result.right(result.length()-i-ql);
2661  p=i+cd->name().length();
2662  }
2663  ps=is+l;
2664  }
2665  }
2666  //printf("result=%s\n",result.data());
2667 
2668  return result.stripWhiteSpace();
2669 }
2670 
2671 /*!
2672  * @param pattern pattern to look for
2673  * @param s string to search in
2674  * @param p position to start
2675  * @param len resulting pattern length
2676  * @returns position on which string is found, or -1 if not found
2677  */
2678 static int findScopePattern(const QCString &pattern,const QCString &s,
2679  int p,int *len)
2680 {
2681  int sl=s.length();
2682  int pl=pattern.length();
2683  int sp=0;
2684  *len=0;
2685  while (p<sl)
2686  {
2687  sp=p; // start of match
2688  int pp=0; // pattern position
2689  while (p<sl && pp<pl)
2690  {
2691  if (s.at(p)=='<') // skip template arguments while matching
2692  {
2693  int bc=1;
2694  //printf("skipping pos=%d c=%c\n",p,s.at(p));
2695  p++;
2696  while (p<sl)
2697  {
2698  if (s.at(p)=='<') bc++;
2699  else if (s.at(p)=='>')
2700  {
2701  bc--;
2702  if (bc==0)
2703  {
2704  p++;
2705  break;
2706  }
2707  }
2708  //printf("skipping pos=%d c=%c\n",p,s.at(p));
2709  p++;
2710  }
2711  }
2712  else if (s.at(p)==pattern.at(pp))
2713  {
2714  //printf("match at position p=%d pp=%d c=%c\n",p,pp,s.at(p));
2715  p++;
2716  pp++;
2717  }
2718  else // no match
2719  {
2720  //printf("restarting at %d c=%c pat=%s\n",p,s.at(p),pattern.data());
2721  p=sp+1;
2722  break;
2723  }
2724  }
2725  if (pp==pl) // whole pattern matches
2726  {
2727  *len=p-sp;
2728  return sp;
2729  }
2730  }
2731  return -1;
2732 }
2733 
2734 static QCString trimScope(const QCString &name,const QCString &s)
2735 {
2736  int scopeOffset=name.length();
2737  QCString result=s;
2738  do // for each scope
2739  {
2740  QCString tmp;
2741  QCString scope=name.left(scopeOffset)+"::";
2742  //printf("Trying with scope=`%s'\n",scope.data());
2743 
2744  int i,p=0,l;
2745  while ((i=findScopePattern(scope,result,p,&l))!=-1) // for each occurrence
2746  {
2747  tmp+=result.mid(p,i-p); // add part before pattern
2748  p=i+l;
2749  }
2750  tmp+=result.right(result.length()-p); // add trailing part
2751 
2752  scopeOffset=name.findRev("::",scopeOffset-1);
2753  result = tmp;
2754  } while (scopeOffset>0);
2755  //printf("trimScope(name=%s,scope=%s)=%s\n",name.data(),s.data(),result.data());
2756  return result;
2757 }
2758 #endif
2759 
2761 {
2762  //printf("trimBaseClassScope level=%d `%s'\n",level,s.data());
2763  BaseClassListIterator bcli(*bcl);
2764  BaseClassDef *bcd;
2765  for (;(bcd=bcli.current());++bcli)
2766  {
2767  ClassDef *cd=bcd->classDef;
2768  //printf("Trying class %s\n",cd->name().data());
2769  int spos=s.find(cd->name()+"::");
2770  if (spos!=-1)
2771  {
2772  s = s.left(spos)+s.right(
2773  s.length()-spos-cd->name().length()-2
2774  );
2775  }
2776  //printf("base class `%s'\n",cd->name().data());
2777  if (cd->baseClasses())
2779  }
2780 }
2781 
2782 #if 0
2783 /*! if either t1 or t2 contains a namespace scope, then remove that
2784  * scope. If neither or both have a namespace scope, t1 and t2 remain
2785  * unchanged.
2786  */
2787 static void trimNamespaceScope(QCString &t1,QCString &t2,const QCString &nsName)
2788 {
2789  int p1=t1.length();
2790  int p2=t2.length();
2791  for (;;)
2792  {
2793  int i1=p1==0 ? -1 : t1.findRev("::",p1);
2794  int i2=p2==0 ? -1 : t2.findRev("::",p2);
2795  if (i1==-1 && i2==-1)
2796  {
2797  return;
2798  }
2799  if (i1!=-1 && i2==-1) // only t1 has a scope
2800  {
2801  QCString scope=t1.left(i1);
2802  replaceNamespaceAliases(scope,i1);
2803 
2804  int so=nsName.length();
2805  do
2806  {
2807  QCString fullScope=nsName.left(so);
2808  if (!fullScope.isEmpty() && !scope.isEmpty()) fullScope+="::";
2809  fullScope+=scope;
2810  if (!fullScope.isEmpty() && Doxygen::namespaceSDict[fullScope]!=0) // scope is a namespace
2811  {
2812  t1 = t1.right(t1.length()-i1-2);
2813  return;
2814  }
2815  if (so==0)
2816  {
2817  so=-1;
2818  }
2819  else if ((so=nsName.findRev("::",so-1))==-1)
2820  {
2821  so=0;
2822  }
2823  }
2824  while (so>=0);
2825  }
2826  else if (i1==-1 && i2!=-1) // only t2 has a scope
2827  {
2828  QCString scope=t2.left(i2);
2829  replaceNamespaceAliases(scope,i2);
2830 
2831  int so=nsName.length();
2832  do
2833  {
2834  QCString fullScope=nsName.left(so);
2835  if (!fullScope.isEmpty() && !scope.isEmpty()) fullScope+="::";
2836  fullScope+=scope;
2837  if (!fullScope.isEmpty() && Doxygen::namespaceSDict[fullScope]!=0) // scope is a namespace
2838  {
2839  t2 = t2.right(t2.length()-i2-2);
2840  return;
2841  }
2842  if (so==0)
2843  {
2844  so=-1;
2845  }
2846  else if ((so=nsName.findRev("::",so-1))==-1)
2847  {
2848  so=0;
2849  }
2850  }
2851  while (so>=0);
2852  }
2853  p1 = QMAX(i1-2,0);
2854  p2 = QMAX(i2-2,0);
2855  }
2856 }
2857 #endif
2858 
2860 {
2861  if (target==str) { target.resize(0); return; }
2862  int i,p=0;
2863  int l=str.length();
2864  bool changed=FALSE;
2865  while ((i=target.find(str,p))!=-1)
2866  {
2867  bool isMatch = (i==0 || !isId(target.at(i-1))) && // not a character before str
2868  (i+l==(int)target.length() || !isId(target.at(i+l))); // not a character after str
2869  if (isMatch)
2870  {
2871  int i1=target.find('*',i+l);
2872  int i2=target.find('&',i+l);
2873  if (i1==-1 && i2==-1)
2874  {
2875  // strip str from target at index i
2876  target=target.left(i)+target.right(target.length()-i-l);
2877  changed=TRUE;
2878  i-=l;
2879  }
2880  else if ((i1!=-1 && i<i1) || (i2!=-1 && i<i2)) // str before * or &
2881  {
2882  // move str to front
2883  target=str+" "+target.left(i)+target.right(target.length()-i-l);
2884  changed=TRUE;
2885  i++;
2886  }
2887  }
2888  p = i+l;
2889  }
2890  if (changed) target=target.stripWhiteSpace();
2891 }
2892 
2893 /*! According to the C++ spec and Ivan Vecerina:
2894 
2895  Parameter declarations that differ only in the presence or absence
2896  of const and/or volatile are equivalent.
2897 
2898  So the following example, show what is stripped by this routine
2899  for const. The same is done for volatile.
2900 
2901  \code
2902  const T param -> T param // not relevant
2903  const T& param -> const T& param // const needed
2904  T* const param -> T* param // not relevant
2905  const T* param -> const T* param // const needed
2906  \endcode
2907  */
2909 {
2910  //printf("stripIrrelevantConstVolatile(%s)=",s.data());
2911  stripIrrelevantString(s,"const");
2912  stripIrrelevantString(s,"volatile");
2913  //printf("%s\n",s.data());
2914 }
2915 
2916 
2917 // a bit of debug support for matchArguments
2918 #define MATCH
2919 #define NOMATCH
2920 //#define MATCH printf("Match at line %d\n",__LINE__);
2921 //#define NOMATCH printf("Nomatch at line %d\n",__LINE__);
2922 
2923 #ifndef NEWMATCH
2924 static bool matchArgument(const Argument *srcA,const Argument *dstA,
2925  const QCString &className,
2926  const QCString &namespaceName,
2927  NamespaceSDict *usingNamespaces,
2928  SDict<Definition> *usingClasses)
2929 {
2930  //printf("match argument start `%s|%s' <-> `%s|%s' using nsp=%p class=%p\n",
2931  // srcA->type.data(),srcA->name.data(),
2932  // dstA->type.data(),dstA->name.data(),
2933  // usingNamespaces,
2934  // usingClasses);
2935 
2936  // TODO: resolve any typedefs names that are part of srcA->type
2937  // before matching. This should use className and namespaceName
2938  // and usingNamespaces and usingClass to determine which typedefs
2939  // are in-scope, so it will not be very efficient :-(
2940 
2941  QCString srcAType=trimTemplateSpecifiers(namespaceName,className,srcA->type);
2942  QCString dstAType=trimTemplateSpecifiers(namespaceName,className,dstA->type);
2943  QCString srcAName=srcA->name.stripWhiteSpace();
2944  QCString dstAName=dstA->name.stripWhiteSpace();
2945  srcAType.stripPrefix("class ");
2946  dstAType.stripPrefix("class ");
2947 
2948  // allow distinguishing "const A" from "const B" even though
2949  // from a syntactic point of view they would be two names of the same
2950  // type "const". This is not fool prove of course, but should at least
2951  // catch the most common cases.
2952  if ((srcAType=="const" || srcAType=="volatile") && !srcAName.isEmpty())
2953  {
2954  srcAType+=" ";
2955  srcAType+=srcAName;
2956  }
2957  if ((dstAType=="const" || dstAType=="volatile") && !dstAName.isEmpty())
2958  {
2959  dstAType+=" ";
2960  dstAType+=dstAName;
2961  }
2962  if (srcAName=="const" || srcAName=="volatile")
2963  {
2964  srcAType+=srcAName;
2965  srcAName.resize(0);
2966  }
2967  else if (dstA->name=="const" || dstA->name=="volatile")
2968  {
2969  dstAType+=dstA->name;
2970  dstAName.resize(0);
2971  }
2972 
2973  stripIrrelevantConstVolatile(srcAType);
2974  stripIrrelevantConstVolatile(dstAType);
2975 
2976  // strip typename keyword
2977  if (qstrncmp(srcAType,"typename ",9)==0)
2978  {
2979  srcAType = srcAType.right(srcAType.length()-9);
2980  }
2981  if (qstrncmp(dstAType,"typename ",9)==0)
2982  {
2983  dstAType = dstAType.right(dstAType.length()-9);
2984  }
2985 
2986  srcAType = removeRedundantWhiteSpace(srcAType);
2987  dstAType = removeRedundantWhiteSpace(dstAType);
2988 
2989  //srcAType=stripTemplateSpecifiersFromScope(srcAType,FALSE);
2990  //dstAType=stripTemplateSpecifiersFromScope(dstAType,FALSE);
2991 
2992  //printf("srcA=`%s|%s' dstA=`%s|%s'\n",srcAType.data(),srcAName.data(),
2993  // dstAType.data(),dstAName.data());
2994 
2995  if (srcA->array!=dstA->array) // nomatch for char[] against char
2996  {
2997  NOMATCH
2998  return FALSE;
2999  }
3000  if (srcAType!=dstAType) // check if the argument only differs on name
3001  {
3002 
3003  // remove a namespace scope that is only in one type
3004  // (assuming a using statement was used)
3005  //printf("Trimming %s<->%s: %s\n",srcAType.data(),dstAType.data(),namespaceName.data());
3006  //trimNamespaceScope(srcAType,dstAType,namespaceName);
3007  //printf("After Trimming %s<->%s\n",srcAType.data(),dstAType.data());
3008 
3009  //QCString srcScope;
3010  //QCString dstScope;
3011 
3012  // strip redundant scope specifiers
3013  if (!className.isEmpty())
3014  {
3015  srcAType=trimScope(className,srcAType);
3016  dstAType=trimScope(className,dstAType);
3017  //printf("trimScope: `%s' <=> `%s'\n",srcAType.data(),dstAType.data());
3018  ClassDef *cd;
3019  if (!namespaceName.isEmpty())
3020  cd=getClass(namespaceName+"::"+className);
3021  else
3022  cd=getClass(className);
3023  if (cd && cd->baseClasses())
3024  {
3025  trimBaseClassScope(cd->baseClasses(),srcAType);
3026  trimBaseClassScope(cd->baseClasses(),dstAType);
3027  }
3028  //printf("trimBaseClassScope: `%s' <=> `%s'\n",srcAType.data(),dstAType.data());
3029  }
3030  if (!namespaceName.isEmpty())
3031  {
3032  srcAType=trimScope(namespaceName,srcAType);
3033  dstAType=trimScope(namespaceName,dstAType);
3034  }
3035  //printf("#usingNamespace=%d\n",usingNamespaces->count());
3036  if (usingNamespaces && usingNamespaces->count()>0)
3037  {
3038  NamespaceSDict::Iterator nli(*usingNamespaces);
3039  NamespaceDef *nd;
3040  for (;(nd=nli.current());++nli)
3041  {
3042  srcAType=trimScope(nd->name(),srcAType);
3043  dstAType=trimScope(nd->name(),dstAType);
3044  }
3045  }
3046  //printf("#usingClasses=%d\n",usingClasses->count());
3047  if (usingClasses && usingClasses->count()>0)
3048  {
3049  SDict<Definition>::Iterator cli(*usingClasses);
3050  Definition *cd;
3051  for (;(cd=cli.current());++cli)
3052  {
3053  srcAType=trimScope(cd->name(),srcAType);
3054  dstAType=trimScope(cd->name(),dstAType);
3055  }
3056  }
3057 
3058  //printf("2. srcA=%s|%s dstA=%s|%s\n",srcAType.data(),srcAName.data(),
3059  // dstAType.data(),dstAName.data());
3060 
3061  if (!srcAName.isEmpty() && !dstA->type.isEmpty() &&
3062  (srcAType+" "+srcAName)==dstAType)
3063  {
3064  MATCH
3065  return TRUE;
3066  }
3067  else if (!dstAName.isEmpty() && !srcA->type.isEmpty() &&
3068  (dstAType+" "+dstAName)==srcAType)
3069  {
3070  MATCH
3071  return TRUE;
3072  }
3073 
3074 
3075  uint srcPos=0,dstPos=0;
3076  bool equal=TRUE;
3077  while (srcPos<srcAType.length() && dstPos<dstAType.length() && equal)
3078  {
3079  equal=srcAType.at(srcPos)==dstAType.at(dstPos);
3080  if (equal) srcPos++,dstPos++;
3081  }
3082  uint srcATypeLen=srcAType.length();
3083  uint dstATypeLen=dstAType.length();
3084  if (srcPos<srcATypeLen && dstPos<dstATypeLen)
3085  {
3086  // if nothing matches or the match ends in the middle or at the
3087  // end of a string then there is no match
3088  if (srcPos==0 || dstPos==0)
3089  {
3090  NOMATCH
3091  return FALSE;
3092  }
3093  if (isId(srcAType.at(srcPos)) && isId(dstAType.at(dstPos)))
3094  {
3095  //printf("partial match srcPos=%d dstPos=%d!\n",srcPos,dstPos);
3096  // check if a name if already found -> if no then there is no match
3097  if (!srcAName.isEmpty() || !dstAName.isEmpty())
3098  {
3099  NOMATCH
3100  return FALSE;
3101  }
3102  // types only
3103  while (srcPos<srcATypeLen && isId(srcAType.at(srcPos))) srcPos++;
3104  while (dstPos<dstATypeLen && isId(dstAType.at(dstPos))) dstPos++;
3105  if (srcPos<srcATypeLen ||
3106  dstPos<dstATypeLen ||
3107  (srcPos==srcATypeLen && dstPos==dstATypeLen)
3108  )
3109  {
3110  NOMATCH
3111  return FALSE;
3112  }
3113  }
3114  else
3115  {
3116  // otherwise we assume that a name starts at the current position.
3117  while (srcPos<srcATypeLen && isId(srcAType.at(srcPos))) srcPos++;
3118  while (dstPos<dstATypeLen && isId(dstAType.at(dstPos))) dstPos++;
3119 
3120  // if nothing more follows for both types then we assume we have
3121  // found a match. Note that now `signed int' and `signed' match, but
3122  // seeing that int is not a name can only be done by looking at the
3123  // semantics.
3124 
3125  if (srcPos!=srcATypeLen || dstPos!=dstATypeLen)
3126  {
3127  NOMATCH
3128  return FALSE;
3129  }
3130  }
3131  }
3132  else if (dstPos<dstAType.length())
3133  {
3134  if (!isspace((uchar)dstAType.at(dstPos))) // maybe the names differ
3135  {
3136  if (!dstAName.isEmpty()) // dst has its name separated from its type
3137  {
3138  NOMATCH
3139  return FALSE;
3140  }
3141  while (dstPos<dstAType.length() && isId(dstAType.at(dstPos))) dstPos++;
3142  if (dstPos!=dstAType.length())
3143  {
3144  NOMATCH
3145  return FALSE; // more than a difference in name -> no match
3146  }
3147  }
3148  else // maybe dst has a name while src has not
3149  {
3150  dstPos++;
3151  while (dstPos<dstAType.length() && isId(dstAType.at(dstPos))) dstPos++;
3152  if (dstPos!=dstAType.length() || !srcAName.isEmpty())
3153  {
3154  NOMATCH
3155  return FALSE; // nope not a name -> no match
3156  }
3157  }
3158  }
3159  else if (srcPos<srcAType.length())
3160  {
3161  if (!isspace((uchar)srcAType.at(srcPos))) // maybe the names differ
3162  {
3163  if (!srcAName.isEmpty()) // src has its name separated from its type
3164  {
3165  NOMATCH
3166  return FALSE;
3167  }
3168  while (srcPos<srcAType.length() && isId(srcAType.at(srcPos))) srcPos++;
3169  if (srcPos!=srcAType.length())
3170  {
3171  NOMATCH
3172  return FALSE; // more than a difference in name -> no match
3173  }
3174  }
3175  else // maybe src has a name while dst has not
3176  {
3177  srcPos++;
3178  while (srcPos<srcAType.length() && isId(srcAType.at(srcPos))) srcPos++;
3179  if (srcPos!=srcAType.length() || !dstAName.isEmpty())
3180  {
3181  NOMATCH
3182  return FALSE; // nope not a name -> no match
3183  }
3184  }
3185  }
3186  }
3187  MATCH
3188  return TRUE;
3189 }
3190 
3191 
3192 /*!
3193  * Matches the arguments list srcAl with the argument list dstAl
3194  * Returns TRUE if the argument lists are equal. Two argument list are
3195  * considered equal if the number of arguments is equal and the types of all
3196  * arguments are equal. Furthermore the const and volatile specifiers
3197  * stored in the list should be equal.
3198  */
3200  const char *cl,const char *ns,bool checkCV,
3201  NamespaceSDict *usingNamespaces,
3202  SDict<Definition> *usingClasses)
3203 {
3205  QCString namespaceName=ns;
3206 
3207  // strip template specialization from class name if present
3208  //int til=className.find('<'),tir=className.find('>');
3209  //if (til!=-1 && tir!=-1 && tir>til)
3210  //{
3211  // className=className.left(til)+className.right(className.length()-tir-1);
3212  //}
3213 
3214  //printf("matchArguments(%s,%s) className=%s namespaceName=%s checkCV=%d usingNamespaces=%d usingClasses=%d\n",
3215  // srcAl ? argListToString(srcAl).data() : "",
3216  // dstAl ? argListToString(dstAl).data() : "",
3217  // cl,ns,checkCV,
3218  // usingNamespaces?usingNamespaces->count():0,
3219  // usingClasses?usingClasses->count():0
3220  // );
3221 
3222  if (srcAl==0 || dstAl==0)
3223  {
3224  bool match = srcAl==dstAl; // at least one of the members is not a function
3225  if (match)
3226  {
3227  MATCH
3228  return TRUE;
3229  }
3230  else
3231  {
3232  NOMATCH
3233  return FALSE;
3234  }
3235  }
3236 
3237  // handle special case with void argument
3238  if ( srcAl->count()==0 && dstAl->count()==1 &&
3239  dstAl->getFirst()->type=="void" )
3240  { // special case for finding match between func() and func(void)
3241  Argument *a=new Argument;
3242  a->type = "void";
3243  srcAl->append(a);
3244  MATCH
3245  return TRUE;
3246  }
3247  if ( dstAl->count()==0 && srcAl->count()==1 &&
3248  srcAl->getFirst()->type=="void" )
3249  { // special case for finding match between func(void) and func()
3250  Argument *a=new Argument;
3251  a->type = "void";
3252  dstAl->append(a);
3253  MATCH
3254  return TRUE;
3255  }
3256 
3257  if (srcAl->count() != dstAl->count())
3258  {
3259  NOMATCH
3260  return FALSE; // different number of arguments -> no match
3261  }
3262 
3263  if (checkCV)
3264  {
3265  if (srcAl->constSpecifier != dstAl->constSpecifier)
3266  {
3267  NOMATCH
3268  return FALSE; // one member is const, the other not -> no match
3269  }
3270  if (srcAl->volatileSpecifier != dstAl->volatileSpecifier)
3271  {
3272  NOMATCH
3273  return FALSE; // one member is volatile, the other not -> no match
3274  }
3275  }
3276 
3277  // so far the argument list could match, so we need to compare the types of
3278  // all arguments.
3279  ArgumentListIterator srcAli(*srcAl),dstAli(*dstAl);
3280  Argument *srcA,*dstA;
3281  for (;(srcA=srcAli.current()) && (dstA=dstAli.current());++srcAli,++dstAli)
3282  {
3283  if (!matchArgument(srcA,dstA,className,namespaceName,
3284  usingNamespaces,usingClasses))
3285  {
3286  NOMATCH
3287  return FALSE;
3288  }
3289  }
3290  MATCH
3291  return TRUE; // all arguments match
3292 }
3293 
3294 #endif
3295 
3296 #if 0
3297 static QCString resolveSymbolName(FileDef *fs,Definition *symbol,QCString &templSpec)
3298 {
3299  ASSERT(symbol!=0);
3300  if (symbol->definitionType()==Definition::TypeMember &&
3301  ((MemberDef*)symbol)->isTypedef()) // if symbol is a typedef then try
3302  // to resolve it
3303  {
3304  MemberDef *md = 0;
3305  ClassDef *cd = newResolveTypedef(fs,(MemberDef*)symbol,&md,&templSpec);
3306  if (cd)
3307  {
3308  return cd->qualifiedName()+templSpec;
3309  }
3310  else if (md)
3311  {
3312  return md->qualifiedName();
3313  }
3314  }
3315  return symbol->qualifiedName();
3316 }
3317 #endif
3318 
3320 {
3321  int i=s.find(" class ");
3322  if (i!=-1) return s.left(i)+s.mid(i+6);
3323  i=s.find(" typename ");
3324  if (i!=-1) return s.left(i)+s.mid(i+9);
3325  i=s.find(" union ");
3326  if (i!=-1) return s.left(i)+s.mid(i+6);
3327  i=s.find(" struct ");
3328  if (i!=-1) return s.left(i)+s.mid(i+7);
3329  return s;
3330 }
3331 
3332 // forward decl for circular dependencies
3334 
3336 {
3337 
3338  QCString templSpec = spec.stripWhiteSpace();
3339  // this part had been commented out before... but it is needed to match for instance
3340  // std::list<std::string> against list<string> so it is now back again!
3341  if (!templSpec.isEmpty() && templSpec.at(0) == '<')
3342  {
3343  templSpec = "< " + extractCanonicalType(d,fs,templSpec.right(templSpec.length()-1).stripWhiteSpace());
3344  }
3345  QCString resolvedType = resolveTypeDef(d,templSpec);
3346  if (!resolvedType.isEmpty()) // not known as a typedef either
3347  {
3348  templSpec = resolvedType;
3349  }
3350  //printf("getCanonicalTemplateSpec(%s)=%s\n",spec.data(),templSpec.data());
3351  return templSpec;
3352 }
3353 
3354 
3356  Definition *d,FileDef *fs,const QCString &word,
3357  QCString *tSpec,int count=0)
3358 {
3359  if (count>10) return word; // oops recursion
3360 
3361  QCString symName,result,templSpec,tmpName;
3362  //DefinitionList *defList=0;
3363  if (tSpec && !tSpec->isEmpty())
3364  templSpec = stripDeclKeywords(getCanonicalTemplateSpec(d,fs,*tSpec));
3365 
3366  if (word.findRev("::")!=-1 && !(tmpName=stripScope(word)).isEmpty())
3367  {
3368  symName=tmpName; // name without scope
3369  }
3370  else
3371  {
3372  symName=word;
3373  }
3374  //printf("getCanonicalTypeForIdentifier(%s,[%s->%s]) start\n",
3375  // word.data(),tSpec?tSpec->data():"<none>",templSpec.data());
3376 
3377  ClassDef *cd = 0;
3378  MemberDef *mType = 0;
3379  QCString ts;
3380  QCString resolvedType;
3381 
3382  // lookup class / class template instance
3383  cd = getResolvedClass(d,fs,word+templSpec,&mType,&ts,TRUE,TRUE,&resolvedType);
3384  bool isTemplInst = cd && !templSpec.isEmpty();
3385  if (!cd && !templSpec.isEmpty())
3386  {
3387  // class template specialization not known, look up class template
3388  cd = getResolvedClass(d,fs,word,&mType,&ts,TRUE,TRUE,&resolvedType);
3389  }
3390  if (cd && cd->isUsedOnly()) cd=0; // ignore types introduced by usage relations
3391 
3392  //printf("cd=%p mtype=%p\n",cd,mType);
3393  //printf(" getCanonicalTypeForIdentifer: symbol=%s word=%s cd=%s d=%s fs=%s cd->isTemplate=%d\n",
3394  // symName.data(),
3395  // word.data(),
3396  // cd?cd->name().data():"<none>",
3397  // d?d->name().data():"<none>",
3398  // fs?fs->name().data():"<none>",
3399  // cd?cd->isTemplate():-1
3400  // );
3401 
3402  //printf(" >>>> word '%s' => '%s' templSpec=%s ts=%s tSpec=%s isTemplate=%d resolvedType=%s\n",
3403  // (word+templSpec).data(),
3404  // cd?cd->qualifiedName().data():"<none>",
3405  // templSpec.data(),ts.data(),
3406  // tSpec?tSpec->data():"<null>",
3407  // cd?cd->isTemplate():FALSE,
3408  // resolvedType.data());
3409 
3410  //printf(" mtype=%s\n",mType?mType->name().data():"<none>");
3411 
3412  if (cd) // resolves to a known class type
3413  {
3414  if (cd==d && tSpec) *tSpec="";
3415 
3416  if (mType && mType->isTypedef()) // but via a typedef
3417  {
3418  result = resolvedType+ts; // the +ts was added for bug 685125
3419  }
3420  else
3421  {
3422  if (isTemplInst)
3423  {
3424  // spec is already part of class type
3425  templSpec="";
3426  if (tSpec) *tSpec="";
3427  }
3428  else if (!ts.isEmpty() && templSpec.isEmpty())
3429  {
3430  // use formal template args for spec
3431  templSpec = stripDeclKeywords(getCanonicalTemplateSpec(d,fs,ts));
3432  }
3433 
3434  result = removeRedundantWhiteSpace(cd->qualifiedName() + templSpec);
3435 
3436  if (cd->isTemplate() && tSpec) //
3437  {
3438  if (!templSpec.isEmpty()) // specific instance
3439  {
3440  result=cd->name()+templSpec;
3441  }
3442  else // use template type
3443  {
3445  }
3446  // template class, so remove the template part (it is part of the class name)
3447  *tSpec="";
3448  }
3449  else if (ts.isEmpty() && !templSpec.isEmpty() && cd && !cd->isTemplate() && tSpec)
3450  {
3451  // obscure case, where a class is used as a template, but doxygen think it is
3452  // not (could happen when loading the class from a tag file).
3453  *tSpec="";
3454  }
3455  }
3456  }
3457  else if (mType && mType->isEnumerate()) // an enum
3458  {
3459  result = mType->qualifiedName();
3460  }
3461  else if (mType && mType->isTypedef()) // a typedef
3462  {
3463  //result = mType->qualifiedName(); // changed after 1.7.2
3464  //result = mType->typeString();
3465  //printf("word=%s typeString=%s\n",word.data(),mType->typeString());
3466  if (word!=mType->typeString())
3467  {
3468  result = getCanonicalTypeForIdentifier(d,fs,mType->typeString(),tSpec,count+1);
3469  }
3470  else
3471  {
3472  result = mType->typeString();
3473  }
3474  }
3475  else // fallback
3476  {
3477  resolvedType = resolveTypeDef(d,word);
3478  //printf("typedef [%s]->[%s]\n",word.data(),resolvedType.data());
3479  if (resolvedType.isEmpty()) // not known as a typedef either
3480  {
3481  result = word;
3482  }
3483  else
3484  {
3485  result = resolvedType;
3486  }
3487  }
3488  //printf("getCanonicalTypeForIdentifier [%s]->[%s]\n",word.data(),result.data());
3489  return result;
3490 }
3491 
3493 {
3494  type = type.stripWhiteSpace();
3495 
3496  // strip const and volatile keywords that are not relevant for the type
3498 
3499  // strip leading keywords
3500  type.stripPrefix("class ");
3501  type.stripPrefix("struct ");
3502  type.stripPrefix("union ");
3503  type.stripPrefix("enum ");
3504  type.stripPrefix("typename ");
3505 
3506  type = removeRedundantWhiteSpace(type);
3507  //printf("extractCanonicalType(type=%s) start: def=%s file=%s\n",type.data(),
3508  // d ? d->name().data() : "<null>",fs ? fs->name().data() : "<null>");
3509 
3510  //static QRegExp id("[a-z_A-Z\\x80-\\xFF][:a-z_A-Z0-9\\x80-\\xFF]*");
3511 
3512  QCString canType;
3513  QCString templSpec,word;
3514  int i,p=0,pp=0;
3515  while ((i=extractClassNameFromType(type,p,word,templSpec))!=-1)
3516  // foreach identifier in the type
3517  {
3518  //printf(" i=%d p=%d\n",i,p);
3519  if (i>pp) canType += type.mid(pp,i-pp);
3520 
3521 
3522  QCString ct = getCanonicalTypeForIdentifier(d,fs,word,&templSpec);
3523 
3524  // in case the ct is empty it means that "word" represents scope "d"
3525  // and this does not need to be added to the canonical
3526  // type (it is redundant), so/ we skip it. This solves problem 589616.
3527  if (ct.isEmpty() && type.mid(p,2)=="::")
3528  {
3529  p+=2;
3530  }
3531  else
3532  {
3533  canType += ct;
3534  }
3535  //printf(" word=%s templSpec=%s canType=%s ct=%s\n",
3536  // word.data(),templSpec.data(),canType.data(),ct.data());
3537  if (!templSpec.isEmpty()) // if we didn't use up the templSpec already
3538  // (i.e. type is not a template specialization)
3539  // then resolve any identifiers inside.
3540  {
3541  static QRegExp re("[a-z_A-Z\\x80-\\xFF][a-z_A-Z0-9\\x80-\\xFF]*");
3542  int tp=0,tl,ti;
3543  // for each identifier template specifier
3544  //printf("adding resolved %s to %s\n",templSpec.data(),canType.data());
3545  while ((ti=re.match(templSpec,tp,&tl))!=-1)
3546  {
3547  canType += templSpec.mid(tp,ti-tp);
3548  canType += getCanonicalTypeForIdentifier(d,fs,templSpec.mid(ti,tl),0);
3549  tp=ti+tl;
3550  }
3551  canType+=templSpec.right(templSpec.length()-tp);
3552  }
3553 
3554  pp=p;
3555  }
3556  canType += type.right(type.length()-pp);
3557  //printf("extractCanonicalType = '%s'->'%s'\n",type.data(),canType.data());
3558 
3559  return removeRedundantWhiteSpace(canType);
3560 }
3561 
3563 {
3564  QCString type = arg->type.stripWhiteSpace();
3565  QCString name = arg->name;
3566  //printf("----- extractCanonicalArgType(type=%s,name=%s)\n",type.data(),name.data());
3567  if ((type=="const" || type=="volatile") && !name.isEmpty())
3568  { // name is part of type => correct
3569  type+=" ";
3570  type+=name;
3571  }
3572  if (name=="const" || name=="volatile")
3573  { // name is part of type => correct
3574  if (!type.isEmpty()) type+=" ";
3575  type+=name;
3576  }
3577  if (!arg->array.isEmpty())
3578  {
3579  type+=arg->array;
3580  }
3581 
3582  return extractCanonicalType(d,fs,type);
3583 }
3584 
3585 static bool matchArgument2(
3586  Definition *srcScope,FileDef *srcFileScope,Argument *srcA,
3587  Definition *dstScope,FileDef *dstFileScope,Argument *dstA
3588  )
3589 {
3590  //printf(">> match argument: %s::`%s|%s' (%s) <-> %s::`%s|%s' (%s)\n",
3591  // srcScope ? srcScope->name().data() : "",
3592  // srcA->type.data(),srcA->name.data(),srcA->canType.data(),
3593  // dstScope ? dstScope->name().data() : "",
3594  // dstA->type.data(),dstA->name.data(),dstA->canType.data());
3595 
3596  //if (srcA->array!=dstA->array) // nomatch for char[] against char
3597  //{
3598  // NOMATCH
3599  // return FALSE;
3600  //}
3601  QCString sSrcName = " "+srcA->name;
3602  QCString sDstName = " "+dstA->name;
3603  QCString srcType = srcA->type;
3604  QCString dstType = dstA->type;
3607  //printf("'%s'<->'%s'\n",sSrcName.data(),dstType.right(sSrcName.length()).data());
3608  //printf("'%s'<->'%s'\n",sDstName.data(),srcType.right(sDstName.length()).data());
3609  if (sSrcName==dstType.right(sSrcName.length()))
3610  { // case "unsigned int" <-> "unsigned int i"
3611  srcA->type+=sSrcName;
3612  srcA->name="";
3613  srcA->canType=""; // invalidate cached type value
3614  }
3615  else if (sDstName==srcType.right(sDstName.length()))
3616  { // case "unsigned int i" <-> "unsigned int"
3617  dstA->type+=sDstName;
3618  dstA->name="";
3619  dstA->canType=""; // invalidate cached type value
3620  }
3621 
3622  if (srcA->canType.isEmpty())
3623  {
3624  srcA->canType = extractCanonicalArgType(srcScope,srcFileScope,srcA);
3625  }
3626  if (dstA->canType.isEmpty())
3627  {
3628  dstA->canType = extractCanonicalArgType(dstScope,dstFileScope,dstA);
3629  }
3630 
3631  if (srcA->canType==dstA->canType)
3632  {
3633  MATCH
3634  return TRUE;
3635  }
3636  else
3637  {
3638  //printf(" Canonical types do not match [%s]<->[%s]\n",
3639  // srcA->canType.data(),dstA->canType.data());
3640  NOMATCH
3641  return FALSE;
3642  }
3643 }
3644 
3645 
3646 // new algorithm for argument matching
3647 bool matchArguments2(Definition *srcScope,FileDef *srcFileScope,ArgumentList *srcAl,
3648  Definition *dstScope,FileDef *dstFileScope,ArgumentList *dstAl,
3649  bool checkCV
3650  )
3651 {
3652  //printf("*** matchArguments2\n");
3653  ASSERT(srcScope!=0 && dstScope!=0);
3654 
3655  if (srcAl==0 || dstAl==0)
3656  {
3657  bool match = srcAl==dstAl; // at least one of the members is not a function
3658  if (match)
3659  {
3660  MATCH
3661  return TRUE;
3662  }
3663  else
3664  {
3665  NOMATCH
3666  return FALSE;
3667  }
3668  }
3669 
3670  // handle special case with void argument
3671  if ( srcAl->count()==0 && dstAl->count()==1 &&
3672  dstAl->getFirst()->type=="void" )
3673  { // special case for finding match between func() and func(void)
3674  Argument *a=new Argument;
3675  a->type = "void";
3676  srcAl->append(a);
3677  MATCH
3678  return TRUE;
3679  }
3680  if ( dstAl->count()==0 && srcAl->count()==1 &&
3681  srcAl->getFirst()->type=="void" )
3682  { // special case for finding match between func(void) and func()
3683  Argument *a=new Argument;
3684  a->type = "void";
3685  dstAl->append(a);
3686  MATCH
3687  return TRUE;
3688  }
3689 
3690  if (srcAl->count() != dstAl->count())
3691  {
3692  NOMATCH
3693  return FALSE; // different number of arguments -> no match
3694  }
3695 
3696  if (checkCV)
3697  {
3698  if (srcAl->constSpecifier != dstAl->constSpecifier)
3699  {
3700  NOMATCH
3701  return FALSE; // one member is const, the other not -> no match
3702  }
3703  if (srcAl->volatileSpecifier != dstAl->volatileSpecifier)
3704  {
3705  NOMATCH
3706  return FALSE; // one member is volatile, the other not -> no match
3707  }
3708  }
3709 
3710  // so far the argument list could match, so we need to compare the types of
3711  // all arguments.
3712  ArgumentListIterator srcAli(*srcAl),dstAli(*dstAl);
3713  Argument *srcA,*dstA;
3714  for (;(srcA=srcAli.current()) && (dstA=dstAli.current());++srcAli,++dstAli)
3715  {
3716  if (!matchArgument2(srcScope,srcFileScope,srcA,
3717  dstScope,dstFileScope,dstA)
3718  )
3719  {
3720  NOMATCH
3721  return FALSE;
3722  }
3723  }
3724  MATCH
3725  return TRUE; // all arguments match
3726 }
3727 
3728 
3729 
3730 // merges the initializer of two argument lists
3731 // pre: the types of the arguments in the list should match.
3732 void mergeArguments(ArgumentList *srcAl,ArgumentList *dstAl,bool forceNameOverwrite)
3733 {
3734  //printf("mergeArguments `%s', `%s'\n",
3735  // argListToString(srcAl).data(),argListToString(dstAl).data());
3736 
3737  if (srcAl==0 || dstAl==0 || srcAl->count()!=dstAl->count())
3738  {
3739  return; // invalid argument lists -> do not merge
3740  }
3741 
3742  ArgumentListIterator srcAli(*srcAl),dstAli(*dstAl);
3743  Argument *srcA,*dstA;
3744  for (;(srcA=srcAli.current()) && (dstA=dstAli.current());++srcAli,++dstAli)
3745  {
3746  if (srcA->defval.isEmpty() && !dstA->defval.isEmpty())
3747  {
3748  //printf("Defval changing `%s'->`%s'\n",srcA->defval.data(),dstA->defval.data());
3749  srcA->defval=dstA->defval.copy();
3750  }
3751  else if (!srcA->defval.isEmpty() && dstA->defval.isEmpty())
3752  {
3753  //printf("Defval changing `%s'->`%s'\n",dstA->defval.data(),srcA->defval.data());
3754  dstA->defval=srcA->defval.copy();
3755  }
3756 
3757  // fix wrongly detected const or volatile specifiers before merging.
3758  // example: "const A *const" is detected as type="const A *" name="const"
3759  if (srcA->name=="const" || srcA->name=="volatile")
3760  {
3761  srcA->type+=" "+srcA->name;
3762  srcA->name.resize(0);
3763  }
3764  if (dstA->name=="const" || dstA->name=="volatile")
3765  {
3766  dstA->type+=" "+dstA->name;
3767  dstA->name.resize(0);
3768  }
3769 
3770  if (srcA->type==dstA->type)
3771  {
3772  //printf("1. merging %s:%s <-> %s:%s\n",srcA->type.data(),srcA->name.data(),dstA->type.data(),dstA->name.data());
3773  if (srcA->name.isEmpty() && !dstA->name.isEmpty())
3774  {
3775  //printf("type: `%s':=`%s'\n",srcA->type.data(),dstA->type.data());
3776  //printf("name: `%s':=`%s'\n",srcA->name.data(),dstA->name.data());
3777  srcA->type = dstA->type.copy();
3778  srcA->name = dstA->name.copy();
3779  }
3780  else if (!srcA->name.isEmpty() && dstA->name.isEmpty())
3781  {
3782  //printf("type: `%s':=`%s'\n",dstA->type.data(),srcA->type.data());
3783  //printf("name: `%s':=`%s'\n",dstA->name.data(),srcA->name.data());
3784  dstA->type = srcA->type.copy();
3785  dstA->name = dstA->name.copy();
3786  }
3787  else if (!srcA->name.isEmpty() && !dstA->name.isEmpty())
3788  {
3789  //printf("srcA->name=%s dstA->name=%s\n",srcA->name.data(),dstA->name.data());
3790  if (forceNameOverwrite)
3791  {
3792  srcA->name = dstA->name;
3793  }
3794  else
3795  {
3796  if (srcA->docs.isEmpty() && !dstA->docs.isEmpty())
3797  {
3798  srcA->name = dstA->name;
3799  }
3800  else if (!srcA->docs.isEmpty() && dstA->docs.isEmpty())
3801  {
3802  dstA->name = srcA->name;
3803  }
3804  }
3805  }
3806  }
3807  else
3808  {
3809  //printf("2. merging '%s':'%s' <-> '%s':'%s'\n",srcA->type.data(),srcA->name.data(),dstA->type.data(),dstA->name.data());
3810  srcA->type=srcA->type.stripWhiteSpace();
3811  dstA->type=dstA->type.stripWhiteSpace();
3812  if (srcA->type+" "+srcA->name==dstA->type) // "unsigned long:int" <-> "unsigned long int:bla"
3813  {
3814  srcA->type+=" "+srcA->name;
3815  srcA->name=dstA->name;
3816  }
3817  else if (dstA->type+" "+dstA->name==srcA->type) // "unsigned long int bla" <-> "unsigned long int"
3818  {
3819  dstA->type+=" "+dstA->name;
3820  dstA->name=srcA->name;
3821  }
3822  else if (srcA->name.isEmpty() && !dstA->name.isEmpty())
3823  {
3824  srcA->name = dstA->name;
3825  }
3826  else if (dstA->name.isEmpty() && !srcA->name.isEmpty())
3827  {
3828  dstA->name = srcA->name;
3829  }
3830  }
3831  int i1=srcA->type.find("::"),
3832  i2=dstA->type.find("::"),
3833  j1=srcA->type.length()-i1-2,
3834  j2=dstA->type.length()-i2-2;
3835  if (i1!=-1 && i2==-1 && srcA->type.right(j1)==dstA->type)
3836  {
3837  //printf("type: `%s':=`%s'\n",dstA->type.data(),srcA->type.data());
3838  //printf("name: `%s':=`%s'\n",dstA->name.data(),srcA->name.data());
3839  dstA->type = srcA->type.left(i1+2)+dstA->type;
3840  dstA->name = dstA->name.copy();
3841  }
3842  else if (i1==-1 && i2!=-1 && dstA->type.right(j2)==srcA->type)
3843  {
3844  //printf("type: `%s':=`%s'\n",srcA->type.data(),dstA->type.data());
3845  //printf("name: `%s':=`%s'\n",dstA->name.data(),srcA->name.data());
3846  srcA->type = dstA->type.left(i2+2)+srcA->type;
3847  srcA->name = dstA->name.copy();
3848  }
3849  if (srcA->docs.isEmpty() && !dstA->docs.isEmpty())
3850  {
3851  srcA->docs = dstA->docs.copy();
3852  }
3853  else if (dstA->docs.isEmpty() && !srcA->docs.isEmpty())
3854  {
3855  dstA->docs = srcA->docs.copy();
3856  }
3857  //printf("Merge argument `%s|%s' `%s|%s'\n",
3858  // srcA->type.data(),srcA->name.data(),
3859  // dstA->type.data(),dstA->name.data());
3860  }
3861 }
3862 
3864  const char *args,
3865  bool checkStatics,
3866  FileDef *currentFile,
3867  bool checkCV,
3868  const char *forceTagFile,
3869  QList<MemberDef> &members)
3870 {
3871  //printf(" Function with global scope name `%s' args=`%s'\n",
3872  // mn->memberName(),args);
3873  MemberListIterator mli(*mn);
3874  MemberDef *md;
3875  for (mli.toFirst();(md=mli.current());++mli)
3876  {
3877  FileDef *fd=md->getFileDef();
3878  GroupDef *gd=md->getGroupDef();
3879  //printf(" md->name()=`%s' md->args=`%s' fd=%p gd=%p current=%p ref=%s\n",
3880  // md->name().data(),args,fd,gd,currentFile,md->getReference().data());
3881  if (
3882  ((gd && gd->isLinkable()) || (fd && fd->isLinkable()) || md->isReference()) &&
3883  md->getNamespaceDef()==0 && md->isLinkable() &&
3884  (!checkStatics || (!md->isStatic() && !md->isDefine()) ||
3885  currentFile==0 || fd==currentFile) // statics must appear in the same file
3886  )
3887  {
3888  bool match=TRUE;
3889  ArgumentList *argList=0;
3890  if (args && !md->isDefine() && qstrcmp(args,"()")!=0)
3891  {
3892  argList=new ArgumentList;
3893  ArgumentList *mdAl = md->argumentList();
3894  stringToArgumentList(args,argList);
3895  match=matchArguments2(
3896  md->getOuterScope(),fd,mdAl,
3897  Doxygen::globalScope,fd,argList,
3898  checkCV);
3899  delete argList; argList=0;
3900  }
3901  if (match && (forceTagFile==0 || md->getReference()==forceTagFile))
3902  {
3903  //printf("Found match!\n");
3904  members.append(md);
3905  }
3906  }
3907  }
3908 }
3909 
3910 /*!
3911  * Searches for a member definition given its name `memberName' as a string.
3912  * memberName may also include a (partial) scope to indicate the scope
3913  * in which the member is located.
3914  *
3915  * The parameter `scName' is a string representing the name of the scope in
3916  * which the link was found.
3917  *
3918  * In case of a function args contains a string representation of the
3919  * argument list. Passing 0 means the member has no arguments.
3920  * Passing "()" means any argument list will do, but "()" is preferred.
3921  *
3922  * The function returns TRUE if the member is known and documented or
3923  * FALSE if it is not.
3924  * If TRUE is returned parameter `md' contains a pointer to the member
3925  * definition. Furthermore exactly one of the parameter `cd', `nd', or `fd'
3926  * will be non-zero:
3927  * - if `cd' is non zero, the member was found in a class pointed to by cd.
3928  * - if `nd' is non zero, the member was found in a namespace pointed to by nd.
3929  * - if `fd' is non zero, the member was found in the global namespace of
3930  * file fd.
3931  */
3932 bool getDefs(const QCString &scName,
3933  const QCString &mbName,
3934  const char *args,
3935  MemberDef *&md,
3936  ClassDef *&cd,
3937  FileDef *&fd,
3938  NamespaceDef *&nd,
3939  GroupDef *&gd,
3940  bool forceEmptyScope,
3941  FileDef *currentFile,
3942  bool checkCV,
3943  const char *forceTagFile
3944  )
3945 {
3946  fd=0, md=0, cd=0, nd=0, gd=0;
3947  if (mbName.isEmpty()) return FALSE; /* empty name => nothing to link */
3948 
3949  QCString scopeName=scName;
3950  QCString memberName=mbName;
3951  scopeName = substitute(scopeName,"\\","::"); // for PHP
3952  memberName = substitute(memberName,"\\","::"); // for PHP
3953  //printf("Search for name=%s args=%s in scope=%s forceEmpty=%d\n",
3954  // memberName.data(),args,scopeName.data(),forceEmptyScope);
3955 
3956  int is,im=0,pm=0;
3957  // strip common part of the scope from the scopeName
3958  while ((is=scopeName.findRev("::"))!=-1 &&
3959  (im=memberName.find("::",pm))!=-1 &&
3960  (scopeName.right(scopeName.length()-is-2)==memberName.mid(pm,im-pm))
3961  )
3962  {
3963  scopeName=scopeName.left(is);
3964  pm=im+2;
3965  }
3966  //printf("result after scope corrections scope=%s name=%s\n",
3967  // scopeName.data(),memberName.data());
3968 
3969  QCString mName=memberName;
3970  QCString mScope;
3971  if (memberName.left(9)!="operator " && // treat operator conversion methods
3972  // as a special case
3973  (im=memberName.findRev("::"))!=-1 &&
3974  im<(int)memberName.length()-2 // not A::
3975  )
3976  {
3977  mScope=memberName.left(im);
3978  mName=memberName.right(memberName.length()-im-2);
3979  }
3980 
3981  // handle special the case where both scope name and member scope are equal
3982  if (mScope==scopeName) scopeName.resize(0);
3983 
3984  //printf("mScope=`%s' mName=`%s'\n",mScope.data(),mName.data());
3985 
3987  //printf("mName=%s mn=%p\n",mName.data(),mn);
3988 
3989  if ((!forceEmptyScope || scopeName.isEmpty()) && // this was changed for bug638856, forceEmptyScope => empty scopeName
3990  mn && !(scopeName.isEmpty() && mScope.isEmpty()))
3991  {
3992  //printf(" >member name '%s' found\n",mName.data());
3993  int scopeOffset=scopeName.length();
3994  do
3995  {
3996  QCString className = scopeName.left(scopeOffset);
3997  if (!className.isEmpty() && !mScope.isEmpty())
3998  {
3999  className+="::"+mScope;
4000  }
4001  else if (!mScope.isEmpty())
4002  {
4003  className=mScope;
4004  }
4005 
4006  MemberDef *tmd=0;
4007  ClassDef *fcd=getResolvedClass(Doxygen::globalScope,0,className,&tmd);
4008  if (fcd==0 && className.find('<')!=-1) // try without template specifiers as well
4009  {
4010  QCString nameWithoutTemplates = stripTemplateSpecifiersFromScope(className,FALSE);
4011  fcd=getResolvedClass(Doxygen::globalScope,0,nameWithoutTemplates,&tmd);
4012  }
4013  //printf("Trying class scope %s: fcd=%p tmd=%p\n",className.data(),fcd,tmd);
4014  // todo: fill in correct fileScope!
4015  if (fcd && // is it a documented class
4016  fcd->isLinkable()
4017  )
4018  {
4019  //printf(" Found fcd=%p\n",fcd);
4020  MemberListIterator mmli(*mn);
4021  MemberDef *mmd;
4022  int mdist=maxInheritanceDepth;
4023  ArgumentList *argList=0;
4024  if (args)
4025  {
4026  argList=new ArgumentList;
4027  stringToArgumentList(args,argList);
4028  }
4029  for (mmli.toFirst();(mmd=mmli.current());++mmli)
4030  {
4031  if (!mmd->isStrongEnumValue())
4032  {
4033  ArgumentList *mmdAl = mmd->argumentList();
4034  bool match=args==0 ||
4035  matchArguments2(mmd->getOuterScope(),mmd->getFileDef(),mmdAl,
4036  fcd,fcd->getFileDef(),argList,
4037  checkCV
4038  );
4039  //printf("match=%d\n",match);
4040  if (match)
4041  {
4042  ClassDef *mcd=mmd->getClassDef();
4043  if (mcd)
4044  {
4045  int m=minClassDistance(fcd,mcd);
4046  if (m<mdist && mcd->isLinkable())
4047  {
4048  mdist=m;
4049  cd=mcd;
4050  md=mmd;
4051  }
4052  }
4053  }
4054  }
4055  }
4056  if (argList)
4057  {
4058  delete argList; argList=0;
4059  }
4060  if (mdist==maxInheritanceDepth && args && qstrcmp(args,"()")==0)
4061  // no exact match found, but if args="()" an arbitrary member will do
4062  {
4063  //printf(" >Searching for arbitrary member\n");
4064  for (mmli.toFirst();(mmd=mmli.current());++mmli)
4065  {
4066  //if (mmd->isLinkable())
4067  //{
4068  ClassDef *mcd=mmd->getClassDef();
4069  //printf(" >Class %s found\n",mcd->name().data());
4070  if (mcd)
4071  {
4072  int m=minClassDistance(fcd,mcd);
4073  if (m<mdist /* && mcd->isLinkable()*/ )
4074  {
4075  //printf("Class distance %d\n",m);
4076  mdist=m;
4077  cd=mcd;
4078  md=mmd;
4079  }
4080  }
4081  //}
4082  }
4083  }
4084  //printf(" >Succes=%d\n",mdist<maxInheritanceDepth);
4085  if (mdist<maxInheritanceDepth)
4086  {
4087  if (!md->isLinkable() || md->isStrongEnumValue())
4088  {
4089  md=0; // avoid returning things we cannot link to
4090  cd=0;
4091  return FALSE; // match found, but was not linkable
4092  }
4093  else
4094  {
4095  gd=md->getGroupDef();
4096  if (gd) cd=0;
4097  return TRUE; /* found match */
4098  }
4099  }
4100  }
4101  if (tmd && tmd->isEnumerate() && tmd->isStrong()) // scoped enum
4102  {
4103  //printf("Found scoped enum!\n");
4104  MemberList *tml = tmd->enumFieldList();
4105  if (tml)
4106  {
4107  MemberListIterator tmi(*tml);
4108  MemberDef *emd;
4109  for (;(emd=tmi.current());++tmi)
4110  {
4111  if (emd->localName()==mName)
4112  {
4113  if (emd->isLinkable())
4114  {
4115  cd=tmd->getClassDef();
4116  md=emd;
4117  return TRUE;
4118  }
4119  else
4120  {
4121  cd=0;
4122  md=0;
4123  return FALSE;
4124  }
4125  }
4126  }
4127  }
4128  }
4129  /* go to the parent scope */
4130  if (scopeOffset==0)
4131  {
4132  scopeOffset=-1;
4133  }
4134  else if ((scopeOffset=scopeName.findRev("::",scopeOffset-1))==-1)
4135  {
4136  scopeOffset=0;
4137  }
4138  } while (scopeOffset>=0);
4139 
4140  }
4141  if (mn && scopeName.isEmpty() && mScope.isEmpty()) // Maybe a related function?
4142  {
4143  //printf("Global symbol\n");
4144  MemberListIterator mmli(*mn);
4145  MemberDef *mmd, *fuzzy_mmd = 0;
4146  ArgumentList *argList = 0;
4147  bool hasEmptyArgs = args && qstrcmp(args, "()") == 0;
4148 
4149  if (args)
4150  stringToArgumentList(args, argList = new ArgumentList);
4151 
4152  for (mmli.toFirst(); (mmd = mmli.current()); ++mmli)
4153  {
4154  if (!mmd->isLinkable() || (!mmd->isRelated() && !mmd->isForeign()) ||
4155  !mmd->getClassDef())
4156  continue;
4157 
4158  if (!args) break;
4159 
4160  ArgumentList *mmdAl = mmd->argumentList();
4161  if (matchArguments2(mmd->getOuterScope(),mmd->getFileDef(),mmdAl,
4162  Doxygen::globalScope,mmd->getFileDef(),argList,
4163  checkCV
4164  )
4165  ) break;
4166 
4167  if (!fuzzy_mmd && hasEmptyArgs)
4168  fuzzy_mmd = mmd;
4169  }
4170 
4171  if (argList) delete argList, argList = 0;
4172 
4173  mmd = mmd ? mmd : fuzzy_mmd;
4174 
4175  if (mmd && !mmd->isStrongEnumValue())
4176  {
4177  md = mmd;
4178  cd = mmd->getClassDef();
4179  return TRUE;
4180  }
4181  }
4182 
4183 
4184  // maybe an namespace, file or group member ?
4185  //printf("Testing for global symbol scopeName=`%s' mScope=`%s' :: mName=`%s'\n",
4186  // scopeName.data(),mScope.data(),mName.data());
4187  if ((mn=Doxygen::functionNameSDict->find(mName))) // name is known
4188  {
4189  //printf(" >symbol name found\n");
4190  NamespaceDef *fnd=0;
4191  int scopeOffset=scopeName.length();
4192  do
4193  {
4194  QCString namespaceName = scopeName.left(scopeOffset);
4195  if (!namespaceName.isEmpty() && !mScope.isEmpty())
4196  {
4197  namespaceName+="::"+mScope;
4198  }
4199  else if (!mScope.isEmpty())
4200  {
4201  namespaceName=mScope.copy();
4202  }
4203  //printf("Trying namespace %s\n",namespaceName.data());
4204  if (!namespaceName.isEmpty() &&
4205  (fnd=Doxygen::namespaceSDict->find(namespaceName)) &&
4206  fnd->isLinkable()
4207  )
4208  {
4209  //printf("Symbol inside existing namespace `%s' count=%d\n",
4210  // namespaceName.data(),mn->count());
4211  bool found=FALSE;
4212  MemberListIterator mmli(*mn);
4213  MemberDef *mmd;
4214  for (mmli.toFirst();((mmd=mmli.current()) && !found);++mmli)
4215  {
4216  //printf("mmd->getNamespaceDef()=%p fnd=%p\n",
4217  // mmd->getNamespaceDef(),fnd);
4218  MemberDef *emd = mmd->getEnumScope();
4219  if (emd && emd->isStrong())
4220  {
4221  //printf("yes match %s<->%s!\n",mScope.data(),emd->localName().data());
4222  if (emd->getNamespaceDef()==fnd &&
4223  rightScopeMatch(mScope,emd->localName()))
4224  {
4225  //printf("found it!\n");
4226  nd=fnd;
4227  md=mmd;
4228  found=TRUE;
4229  }
4230  else
4231  {
4232  md=0;
4233  cd=0;
4234  return FALSE;
4235  }
4236  }
4237  else if (mmd->getNamespaceDef()==fnd /* && mmd->isLinkable() */ )
4238  { // namespace is found
4239  bool match=TRUE;
4240  ArgumentList *argList=0;
4241  if (args && qstrcmp(args,"()")!=0)
4242  {
4243  argList=new ArgumentList;
4244  ArgumentList *mmdAl = mmd->argumentList();
4245  stringToArgumentList(args,argList);
4246  match=matchArguments2(
4247  mmd->getOuterScope(),mmd->getFileDef(),mmdAl,
4248  fnd,mmd->getFileDef(),argList,
4249  checkCV);
4250  }
4251  if (match)
4252  {
4253  nd=fnd;
4254  md=mmd;
4255  found=TRUE;
4256  }
4257  if (args)
4258  {
4259  delete argList; argList=0;
4260  }
4261  }
4262  }
4263  if (!found && args && !qstrcmp(args,"()"))
4264  // no exact match found, but if args="()" an arbitrary
4265  // member will do
4266  {
4267  for (mmli.toFirst();((mmd=mmli.current()) && !found);++mmli)
4268  {
4269  if (mmd->getNamespaceDef()==fnd /*&& mmd->isLinkable() */ )
4270  {
4271  nd=fnd;
4272  md=mmd;
4273  found=TRUE;
4274  }
4275  }
4276  }
4277  if (found)
4278  {
4279  if (!md->isLinkable())
4280  {
4281  md=0; // avoid returning things we cannot link to
4282  nd=0;
4283  return FALSE; // match found but not linkable
4284  }
4285  else
4286  {
4287  gd=md->getGroupDef();
4288  if (gd && gd->isLinkable()) nd=0; else gd=0;
4289  return TRUE;
4290  }
4291  }
4292  }
4293  else
4294  {
4295  //printf("not a namespace\n");
4296  bool found=FALSE;
4297  MemberListIterator mmli(*mn);
4298  MemberDef *mmd;
4299  for (mmli.toFirst();(mmd=mmli.current());++mmli)
4300  {
4301  MemberDef *tmd = mmd->getEnumScope();
4302  //printf("try member %s tmd=%s\n",mmd->name().data(),tmd?tmd->name().data():"<none>");
4303  int ni=namespaceName.findRev("::");
4304  //printf("namespaceName=%s ni=%d\n",namespaceName.data(),ni);
4305  bool notInNS = tmd && ni==-1 && tmd->getNamespaceDef()==0 && (mScope.isEmpty() || mScope==tmd->name());
4306  bool sameNS = tmd && tmd->getNamespaceDef() && namespaceName.left(ni)==tmd->getNamespaceDef()->name();
4307  //printf("notInNS=%d sameNS=%d\n",notInNS,sameNS);
4308  if (tmd && tmd->isStrong() && // C++11 enum class
4309  (notInNS || sameNS) &&
4310  namespaceName.length()>0 // enum is part of namespace so this should not be empty
4311  )
4312  {
4313  md=mmd;
4314  fd=mmd->getFileDef();
4315  gd=mmd->getGroupDef();
4316  if (gd && gd->isLinkable()) fd=0; else gd=0;
4317  //printf("Found scoped enum %s fd=%p gd=%p\n",
4318  // mmd->name().data(),fd,gd);
4319  return TRUE;
4320  }
4321  }
4322  }
4323  if (scopeOffset==0)
4324  {
4325  scopeOffset=-1;
4326  }
4327  else if ((scopeOffset=scopeName.findRev("::",scopeOffset-1))==-1)
4328  {
4329  scopeOffset=0;
4330  }
4331  } while (scopeOffset>=0);
4332 
4333  //else // no scope => global function
4334  {
4335  QList<MemberDef> members;
4336  // search for matches with strict static checking
4337  findMembersWithSpecificName(mn,args,TRUE,currentFile,checkCV,forceTagFile,members);
4338  if (members.count()==0) // nothing found
4339  {
4340  // search again without strict static checking
4341  findMembersWithSpecificName(mn,args,FALSE,currentFile,checkCV,forceTagFile,members);
4342  }
4343  //printf("found %d members\n",members.count());
4344  if (members.count()!=1 && args && !qstrcmp(args,"()"))
4345  {
4346  // no exact match found, but if args="()" an arbitrary
4347  // member will do
4348  MemberListIterator mni(*mn);
4349  for (mni.toLast();(md=mni.current());--mni)
4350  {
4351  //printf("Found member `%s'\n",md->name().data());
4352  //printf("member is linkable md->name()=`%s'\n",md->name().data());
4353  fd=md->getFileDef();
4354  gd=md->getGroupDef();
4355  MemberDef *tmd = md->getEnumScope();
4356  if (
4357  (gd && gd->isLinkable()) || (fd && fd->isLinkable()) ||
4358  (tmd && tmd->isStrong())
4359  )
4360  {
4361  members.append(md);
4362  }
4363  }
4364  }
4365  //printf("found %d candidate members\n",members.count());
4366  if (members.count()>0) // at least one match
4367  {
4368  if (currentFile)
4369  {
4370  //printf("multiple results; pick one from file:%s\n", currentFile->name().data());
4371  QListIterator<MemberDef> mit(members);
4372  for (mit.toFirst();(md=mit.current());++mit)
4373  {
4374  if (md->getFileDef() && md->getFileDef()->name() == currentFile->name())
4375  {
4376  break; // found match in the current file
4377  }
4378  }
4379  if (!md) // member not in the current file
4380  {
4381  md=members.getLast();
4382  }
4383  }
4384  else
4385  {
4386  md=members.getLast();
4387  }
4388  }
4389  if (md && (md->getEnumScope()==0 || !md->getEnumScope()->isStrong()))
4390  // found a matching global member, that is not a scoped enum value (or uniquely matches)
4391  {
4392  fd=md->getFileDef();
4393  gd=md->getGroupDef();
4394  //printf("fd=%p gd=%p gd->isLinkable()=%d\n",fd,gd,gd->isLinkable());
4395  if (gd && gd->isLinkable()) fd=0; else gd=0;
4396  return TRUE;
4397  }
4398  }
4399  }
4400 
4401  // no nothing found
4402  return FALSE;
4403 }
4404 
4405 /*!
4406  * Searches for a scope definition given its name as a string via parameter
4407  * `scope`.
4408  *
4409  * The parameter `docScope` is a string representing the name of the scope in
4410  * which the `scope` string was found.
4411  *
4412  * The function returns TRUE if the scope is known and documented or
4413  * FALSE if it is not.
4414  * If TRUE is returned exactly one of the parameter `cd`, `nd`
4415  * will be non-zero:
4416  * - if `cd` is non zero, the scope was a class pointed to by cd.
4417  * - if `nd` is non zero, the scope was a namespace pointed to by nd.
4418  */
4419 static bool getScopeDefs(const char *docScope,const char *scope,
4420  ClassDef *&cd, NamespaceDef *&nd)
4421 {
4422  cd=0;nd=0;
4423 
4424  QCString scopeName=scope;
4425  //printf("getScopeDefs: docScope=`%s' scope=`%s'\n",docScope,scope);
4426  if (scopeName.isEmpty()) return FALSE;
4427 
4428  bool explicitGlobalScope=FALSE;
4429  if (scopeName.at(0)==':' && scopeName.at(1)==':')
4430  {
4431  scopeName=scopeName.right(scopeName.length()-2);
4432  explicitGlobalScope=TRUE;
4433  }
4434 
4435  QCString docScopeName=docScope;
4436  int scopeOffset=explicitGlobalScope ? 0 : docScopeName.length();
4437 
4438  do // for each possible docScope (from largest to and including empty)
4439  {
4440  QCString fullName=scopeName.copy();
4441  if (scopeOffset>0) fullName.prepend(docScopeName.left(scopeOffset)+"::");
4442 
4443  if (((cd=getClass(fullName)) || // normal class
4444  (cd=getClass(fullName+"-p")) //|| // ObjC protocol
4445  //(cd=getClass(fullName+"-g")) // C# generic
4446  ) && cd->isLinkable())
4447  {
4448  return TRUE; // class link written => quit
4449  }
4450  else if ((nd=Doxygen::namespaceSDict->find(fullName)) && nd->isLinkable())
4451  {
4452  return TRUE; // namespace link written => quit
4453  }
4454  if (scopeOffset==0)
4455  {
4456  scopeOffset=-1;
4457  }
4458  else if ((scopeOffset=docScopeName.findRev("::",scopeOffset-1))==-1)
4459  {
4460  scopeOffset=0;
4461  }
4462  } while (scopeOffset>=0);
4463 
4464  return FALSE;
4465 }
4466 
4467 static bool isLowerCase(QCString &s)
4468 {
4469  uchar *p=(uchar*)s.data();
4470  if (p==0) return TRUE;
4471  int c;
4472  while ((c=*p++)) if (!islower(c)) return FALSE;
4473  return TRUE;
4474 }
4475 
4476 /*! Returns an object to reference to given its name and context
4477  * @post return value TRUE implies *resContext!=0 or *resMember!=0
4478  */
4479 bool resolveRef(/* in */ const char *scName,
4480  /* in */ const char *name,
4481  /* in */ bool inSeeBlock,
4482  /* out */ Definition **resContext,
4483  /* out */ MemberDef **resMember,
4484  bool lookForSpecialization,
4485  FileDef *currentFile,
4486  bool checkScope
4487  )
4488 {
4489  //printf("resolveRef(scope=%s,name=%s,inSeeBlock=%d)\n",scName,name,inSeeBlock);
4490  QCString tsName = name;
4491  //bool memberScopeFirst = tsName.find('#')!=-1;
4492  QCString fullName = substitute(tsName,"#","::");
4493  if (fullName.find("anonymous_namespace{")==-1)
4494  {
4495  fullName = removeRedundantWhiteSpace(substitute(fullName,".","::"));
4496  }
4497  else
4498  {
4499  fullName = removeRedundantWhiteSpace(fullName);
4500  }
4501 
4502  int bracePos=findParameterList(fullName);
4503  int endNamePos=bracePos!=-1 ? bracePos : fullName.length();
4504  int scopePos=fullName.findRev("::",endNamePos);
4505  bool explicitScope = fullName.left(2)=="::" && // ::scope or #scope
4506  (scopePos>2 || // ::N::A
4507  tsName.left(2)=="::" || // ::foo in local scope
4508  scName==0 // #foo in global scope
4509  );
4510 
4511  // default result values
4512  *resContext=0;
4513  *resMember=0;
4514 
4515  if (bracePos==-1) // simple name
4516  {
4517  ClassDef *cd=0;
4518  NamespaceDef *nd=0;
4519 
4520  // the following if() was commented out for releases in the range
4521  // 1.5.2 to 1.6.1, but has been restored as a result of bug report 594787.
4522  if (!inSeeBlock && scopePos==-1 && isLowerCase(tsName))
4523  { // link to lower case only name => do not try to autolink
4524  return FALSE;
4525  }
4526 
4527  //printf("scName=%s fullName=%s\n",scName,fullName.data());
4528 
4529  // check if this is a class or namespace reference
4530  if (scName!=fullName && getScopeDefs(scName,fullName,cd,nd))
4531  {
4532  if (cd) // scope matches that of a class
4533  {
4534  *resContext = cd;
4535  }
4536  else // scope matches that of a namespace
4537  {
4538  ASSERT(nd!=0);
4539  *resContext = nd;
4540  }
4541  return TRUE;
4542  }
4543  else if (scName==fullName || (!inSeeBlock && scopePos==-1))
4544  // nothing to link => output plain text
4545  {
4546  //printf("found scName=%s fullName=%s scName==fullName=%d "
4547  // "inSeeBlock=%d scopePos=%d!\n",
4548  // scName,fullName.data(),scName==fullName,inSeeBlock,scopePos);
4549  return FALSE;
4550  }
4551  // continue search...
4552  }
4553 
4554  // extract userscope+name
4555  QCString nameStr=fullName.left(endNamePos);
4556  if (explicitScope) nameStr=nameStr.mid(2);
4557 
4558  // extract arguments
4559  QCString argsStr;
4560  if (bracePos!=-1) argsStr=fullName.right(fullName.length()-bracePos);
4561 
4562  // strip template specifier
4563  // TODO: match against the correct partial template instantiation
4564  int templPos=nameStr.find('<');
4565  bool tryUnspecializedVersion = FALSE;
4566  if (templPos!=-1 && nameStr.find("operator")==-1)
4567  {
4568  int endTemplPos=nameStr.findRev('>');
4569  if (endTemplPos!=-1)
4570  {
4571  if (!lookForSpecialization)
4572  {
4573  nameStr=nameStr.left(templPos)+nameStr.right(nameStr.length()-endTemplPos-1);
4574  }
4575  else
4576  {
4577  tryUnspecializedVersion = TRUE;
4578  }
4579  }
4580  }
4581 
4582  QCString scopeStr=scName;
4583 
4584  MemberDef *md = 0;
4585  ClassDef *cd = 0;
4586  FileDef *fd = 0;
4587  NamespaceDef *nd = 0;
4588  GroupDef *gd = 0;
4589 
4590  // check if nameStr is a member or global.
4591  //printf("getDefs(scope=%s,name=%s,args=%s checkScope=%d)\n",
4592  // scopeStr.data(),nameStr.data(),argsStr.data(),checkScope);
4593  if (getDefs(scopeStr,nameStr,argsStr,
4594  md,cd,fd,nd,gd,
4595  //scopePos==0 && !memberScopeFirst, // forceEmptyScope
4596  explicitScope, // replaces prev line due to bug 600829
4597  currentFile,
4598  TRUE // checkCV
4599  )
4600  )
4601  {
4602  //printf("after getDefs checkScope=%d nameStr=%s cd=%p nd=%p\n",checkScope,nameStr.data(),cd,nd);
4603  if (checkScope && md && md->getOuterScope()==Doxygen::globalScope &&
4604  !md->isStrongEnumValue() &&
4605  (!scopeStr.isEmpty() || nameStr.find("::")>0))
4606  {
4607  // we did find a member, but it is a global one while we were explicitly
4608  // looking for a scoped variable. See bug 616387 for an example why this check is needed.
4609  // note we do need to support autolinking to "::symbol" hence the >0
4610  //printf("not global member!\n");
4611  *resContext=0;
4612  *resMember=0;
4613  return FALSE;
4614  }
4615  //printf("after getDefs md=%p cd=%p fd=%p nd=%p gd=%p\n",md,cd,fd,nd,gd);
4616  if (md) { *resMember=md; *resContext=md; }
4617  else if (cd) *resContext=cd;
4618  else if (nd) *resContext=nd;
4619  else if (fd) *resContext=fd;
4620  else if (gd) *resContext=gd;
4621  else { *resContext=0; *resMember=0; return FALSE; }
4622  //printf("member=%s (md=%p) anchor=%s linkable()=%d context=%s\n",
4623  // md->name().data(),md,md->anchor().data(),md->isLinkable(),(*resContext)->name().data());
4624  return TRUE;
4625  }
4626  else if (inSeeBlock && !nameStr.isEmpty() && (gd=Doxygen::groupSDict->find(nameStr)))
4627  { // group link
4628  *resContext=gd;
4629  return TRUE;
4630  }
4631  else if (tsName.find('.')!=-1) // maybe a link to a file
4632  {
4633  bool ambig;
4634  fd=findFileDef(Doxygen::inputNameDict,tsName,ambig);
4635  if (fd && !ambig)
4636  {
4637  *resContext=fd;
4638  return TRUE;
4639  }
4640  }
4641 
4642  if (tryUnspecializedVersion)
4643  {
4644  return resolveRef(scName,name,inSeeBlock,resContext,resMember,FALSE,0,checkScope);
4645  }
4646  if (bracePos!=-1) // Try without parameters as well, could be a contructor invocation
4647  {
4648  *resContext=getClass(fullName.left(bracePos));
4649  if (*resContext)
4650  {
4651  return TRUE;
4652  }
4653  }
4654  //printf("resolveRef: %s not found!\n",name);
4655 
4656  return FALSE;
4657 }
4658 
4659 QCString linkToText(SrcLangExt lang,const char *link,bool isFileName)
4660 {
4661  //static bool optimizeOutputJava = Config_getBool("OPTIMIZE_OUTPUT_JAVA");
4662  QCString result=link;
4663  if (!result.isEmpty())
4664  {
4665  // replace # by ::
4666  result=substitute(result,"#","::");
4667  // replace . by ::
4668  if (!isFileName && result.find('<')==-1) result=substitute(result,".","::");
4669  // strip leading :: prefix if present
4670  if (result.at(0)==':' && result.at(1)==':')
4671  {
4672  result=result.right(result.length()-2);
4673  }
4675  if (sep!="::")
4676  {
4677  result=substitute(result,"::",sep);
4678  }
4679  }
4680  return result;
4681 }
4682 
4683 #if 0
4684 /*
4685  * generate a reference to a class, namespace or member.
4686  * `scName' is the name of the scope that contains the documentation
4687  * string that is returned.
4688  * `name' is the name that we want to link to.
4689  * `name' may have five formats:
4690  * 1) "ScopeName"
4691  * 2) "memberName()" one of the (overloaded) function or define
4692  * with name memberName.
4693  * 3) "memberName(...)" a specific (overloaded) function or define
4694  * with name memberName
4695  * 4) "::name a global variable or define
4696  * 4) "\#memberName member variable, global variable or define
4697  * 5) ("ScopeName::")+"memberName()"
4698  * 6) ("ScopeName::")+"memberName(...)"
4699  * 7) ("ScopeName::")+"memberName"
4700  * instead of :: the \# symbol may also be used.
4701  */
4702 
4703 bool generateRef(OutputDocInterface &od,const char *scName,
4704  const char *name,bool inSeeBlock,const char *rt)
4705 {
4706  //printf("generateRef(scName=%s,name=%s,inSee=%d,rt=%s)\n",scName,name,inSeeBlock,rt);
4707 
4708  Definition *compound;
4709  MemberDef *md;
4710 
4711  // create default link text
4712  QCString linkText = linkToText(rt,FALSE);
4713 
4714  if (resolveRef(scName,name,inSeeBlock,&compound,&md))
4715  {
4716  if (md && md->isLinkable()) // link to member
4717  {
4718  od.writeObjectLink(md->getReference(),
4719  md->getOutputFileBase(),
4720  md->anchor(),linkText);
4721  // generate the page reference (for LaTeX)
4722  if (!md->isReference())
4723  {
4724  writePageRef(od,md->getOutputFileBase(),md->anchor());
4725  }
4726  return TRUE;
4727  }
4728  else if (compound && compound->isLinkable()) // link to compound
4729  {
4730  if (rt==0 && compound->definitionType()==Definition::TypeGroup)
4731  {
4732  linkText=((GroupDef *)compound)->groupTitle();
4733  }
4734  if (compound && compound->definitionType()==Definition::TypeFile)
4735  {
4736  linkText=linkToText(rt,TRUE);
4737  }
4738  od.writeObjectLink(compound->getReference(),
4739  compound->getOutputFileBase(),
4740  0,linkText);
4741  if (!compound->isReference())
4742  {
4743  writePageRef(od,compound->getOutputFileBase(),0);
4744  }
4745  return TRUE;
4746  }
4747  }
4748  od.docify(linkText);
4749  return FALSE;
4750 }
4751 #endif
4752 
4753 bool resolveLink(/* in */ const char *scName,
4754  /* in */ const char *lr,
4755  /* in */ bool /*inSeeBlock*/,
4756  /* out */ Definition **resContext,
4757  /* out */ QCString &resAnchor
4758  )
4759 {
4760  *resContext=0;
4761 
4762  QCString linkRef=lr;
4763  QCString linkRefWithoutTemplates = stripTemplateSpecifiersFromScope(linkRef,FALSE);
4764  //printf("ResolveLink linkRef=%s\n",lr);
4765  FileDef *fd;
4766  GroupDef *gd;
4767  PageDef *pd;
4768  ClassDef *cd;
4769  DirDef *dir;
4770  NamespaceDef *nd;
4771  SectionInfo *si=0;
4772  bool ambig;
4773  if (linkRef.isEmpty()) // no reference name!
4774  {
4775  return FALSE;
4776  }
4777  else if ((pd=Doxygen::pageSDict->find(linkRef))) // link to a page
4778  {
4779  GroupDef *gd = pd->getGroupDef();
4780  if (gd)
4781  {
4782  if (!pd->name().isEmpty()) si=Doxygen::sectionDict->find(pd->name());
4783  *resContext=gd;
4784  if (si) resAnchor = si->label;
4785  }
4786  else
4787  {
4788  *resContext=pd;
4789  }
4790  return TRUE;
4791  }
4792  else if ((si=Doxygen::sectionDict->find(linkRef)))
4793  {
4794  *resContext=si->definition;
4795  resAnchor = si->label;
4796  return TRUE;
4797  }
4798  else if ((pd=Doxygen::exampleSDict->find(linkRef))) // link to an example
4799  {
4800  *resContext=pd;
4801  return TRUE;
4802  }
4803  else if ((gd=Doxygen::groupSDict->find(linkRef))) // link to a group
4804  {
4805  *resContext=gd;
4806  return TRUE;
4807  }
4808  else if ((fd=findFileDef(Doxygen::inputNameDict,linkRef,ambig)) // file link
4809  && fd->isLinkable())
4810  {
4811  *resContext=fd;
4812  return TRUE;
4813  }
4814  else if ((cd=getClass(linkRef))) // class link
4815  {
4816  *resContext=cd;
4817  resAnchor=cd->anchor();
4818  return TRUE;
4819  }
4820  else if ((cd=getClass(linkRefWithoutTemplates))) // C#/Java generic class link
4821  {
4822  *resContext=cd;
4823  resAnchor=cd->anchor();
4824  return TRUE;
4825  }
4826  else if ((cd=getClass(linkRef+"-p"))) // Obj-C protocol link
4827  {
4828  *resContext=cd;
4829  resAnchor=cd->anchor();
4830  return TRUE;
4831  }
4832 // else if ((cd=getClass(linkRef+"-g"))) // C# generic link
4833 // {
4834 // *resContext=cd;
4835 // resAnchor=cd->anchor();
4836 // return TRUE;
4837 // }
4838  else if ((nd=Doxygen::namespaceSDict->find(linkRef)))
4839  {
4840  *resContext=nd;
4841  return TRUE;
4842  }
4843  else if ((dir=Doxygen::directories->find(QFileInfo(linkRef).absFilePath().utf8()+"/"))
4844  && dir->isLinkable()) // TODO: make this location independent like filedefs
4845  {
4846  *resContext=dir;
4847  return TRUE;
4848  }
4849  else // probably a member reference
4850  {
4851  MemberDef *md;
4852  bool res = resolveRef(scName,lr,TRUE,resContext,&md);
4853  if (md) resAnchor=md->anchor();
4854  return res;
4855  }
4856 }
4857 
4858 
4859 //----------------------------------------------------------------------
4860 // General function that generates the HTML code for a reference to some
4861 // file, class or member from text `lr' within the context of class `clName'.
4862 // This link has the text 'lt' (if not 0), otherwise `lr' is used as a
4863 // basis for the link's text.
4864 // returns TRUE if a link could be generated.
4865 
4866 bool generateLink(OutputDocInterface &od,const char *clName,
4867  const char *lr,bool inSeeBlock,const char *lt)
4868 {
4869  //printf("generateLink(clName=%s,lr=%s,lr=%s)\n",clName,lr,lt);
4870  Definition *compound;
4871  //PageDef *pageDef=0;
4872  QCString anchor,linkText=linkToText(SrcLangExt_Unknown,lt,FALSE);
4873  //printf("generateLink linkText=%s\n",linkText.data());
4874  if (resolveLink(clName,lr,inSeeBlock,&compound,anchor))
4875  {
4876  if (compound) // link to compound
4877  {
4878  if (lt==0 && anchor.isEmpty() && /* compound link */
4879  compound->definitionType()==Definition::TypeGroup /* is group */
4880  )
4881  {
4882  linkText=((GroupDef *)compound)->groupTitle(); // use group's title as link
4883  }
4884  else if (compound->definitionType()==Definition::TypeFile)
4885  {
4886  linkText=linkToText(compound->getLanguage(),lt,TRUE);
4887  }
4888  od.writeObjectLink(compound->getReference(),
4889  compound->getOutputFileBase(),anchor,linkText);
4890  if (!compound->isReference())
4891  {
4892  writePageRef(od,compound->getOutputFileBase(),anchor);
4893  }
4894  }
4895  else
4896  {
4897  err("%s:%d: Internal error: resolveLink successful but no compound found!",__FILE__,__LINE__);
4898  }
4899  return TRUE;
4900  }
4901  else // link could not be found
4902  {
4903  od.docify(linkText);
4904  return FALSE;
4905  }
4906 }
4907 
4908 void generateFileRef(OutputDocInterface &od,const char *name,const char *text)
4909 {
4910  //printf("generateFileRef(%s,%s)\n",name,text);
4911  QCString linkText = text ? text : name;
4912  //FileInfo *fi;
4913  FileDef *fd;
4914  bool ambig;
4915  if ((fd=findFileDef(Doxygen::inputNameDict,name,ambig)) &&
4916  fd->isLinkable())
4917  // link to documented input file
4918  od.writeObjectLink(fd->getReference(),fd->getOutputFileBase(),0,linkText);
4919  else
4920  od.docify(linkText);
4921 }
4922 
4923 //----------------------------------------------------------------------
4924 
4925 #if 0
4927 {
4928  int i=0,l,p;
4929  QCString result;
4930  if (s.isEmpty()) return result;
4931  QRegExp r("[a-z_A-Z][a-z_A-Z0-9]*");
4932  while ((p=r.match(s,i,&l))!=-1)
4933  {
4934  QCString *subst;
4935  if (p>i) result+=s.mid(i,p-i);
4936  if ((subst=substituteDict[s.mid(p,l)]))
4937  {
4938  result+=*subst;
4939  }
4940  else
4941  {
4942  result+=s.mid(p,l);
4943  }
4944  i=p+l;
4945  }
4946  result+=s.mid(i,s.length()-i);
4947  return result;
4948 }
4949 #endif
4950 
4951 //----------------------------------------------------------------------
4952 
4953 /** Cache element for the file name to FileDef mapping cache. */
4955 {
4956  FindFileCacheElem(FileDef *fd,bool ambig) : fileDef(fd), isAmbig(ambig) {}
4958  bool isAmbig;
4959 };
4960 
4962 
4963 FileDef *findFileDef(const FileNameDict *fnDict,const char *n,bool &ambig)
4964 {
4965  ambig=FALSE;
4966  if (n==0) return 0;
4967 
4968  const int maxAddrSize = 20;
4969  char addr[maxAddrSize];
4970  qsnprintf(addr,maxAddrSize,"%p:",fnDict);
4971  QCString key = addr;
4972  key+=n;
4973 
4974  g_findFileDefCache.setAutoDelete(TRUE);
4975  FindFileCacheElem *cachedResult = g_findFileDefCache.find(key);
4976  //printf("key=%s cachedResult=%p\n",key.data(),cachedResult);
4977  if (cachedResult)
4978  {
4979  ambig = cachedResult->isAmbig;
4980  //printf("cached: fileDef=%p\n",cachedResult->fileDef);
4981  return cachedResult->fileDef;
4982  }
4983  else
4984  {
4985  cachedResult = new FindFileCacheElem(0,FALSE);
4986  }
4987 
4989  QCString path;
4990  int slashPos;
4991  FileName *fn;
4992  if (name.isEmpty()) goto exit;
4993  slashPos=QMAX(name.findRev('/'),name.findRev('\\'));
4994  if (slashPos!=-1)
4995  {
4996  path=name.left(slashPos+1);
4997  name=name.right(name.length()-slashPos-1);
4998  //printf("path=%s name=%s\n",path.data(),name.data());
4999  }
5000  if (name.isEmpty()) goto exit;
5001  if ((fn=(*fnDict)[name]))
5002  {
5003  //printf("fn->count()=%d\n",fn->count());
5004  if (fn->count()==1)
5005  {
5006  FileDef *fd = fn->getFirst();
5007 #if defined(_WIN32) || defined(__MACOSX__) // Windows or MacOSX
5008  bool isSamePath = fd->getPath().right(path.length()).lower()==path.lower();
5009 #else // Unix
5010  bool isSamePath = fd->getPath().right(path.length())==path;
5011 #endif
5012  if (path.isEmpty() || isSamePath)
5013  {
5014  cachedResult->fileDef = fd;
5015  g_findFileDefCache.insert(key,cachedResult);
5016  //printf("=1 ===> add to cache %p\n",fd);
5017  return fd;
5018  }
5019  }
5020  else // file name alone is ambiguous
5021  {
5022  int count=0;
5023  FileNameIterator fni(*fn);
5024  FileDef *fd;
5025  FileDef *lastMatch=0;
5026  QCString pathStripped = stripFromIncludePath(path);
5027  for (fni.toFirst();(fd=fni.current());++fni)
5028  {
5029  QCString fdStripPath = stripFromIncludePath(fd->getPath());
5030  if (path.isEmpty() || fdStripPath.right(pathStripped.length())==pathStripped)
5031  {
5032  count++;
5033  lastMatch=fd;
5034  }
5035  }
5036  //printf(">1 ===> add to cache %p\n",fd);
5037 
5038  ambig=(count>1);
5039  cachedResult->isAmbig = ambig;
5040  cachedResult->fileDef = lastMatch;
5041  g_findFileDefCache.insert(key,cachedResult);
5042  return lastMatch;
5043  }
5044  }
5045  else
5046  {
5047  //printf("not found!\n");
5048  }
5049 exit:
5050  //printf("0 ===> add to cache %p: %s\n",cachedResult,n);
5051  g_findFileDefCache.insert(key,cachedResult);
5052  //delete cachedResult;
5053  return 0;
5054 }
5055 
5056 //----------------------------------------------------------------------
5057 
5058 QCString showFileDefMatches(const FileNameDict *fnDict,const char *n)
5059 {
5060  QCString result;
5061  QCString name=n;
5062  QCString path;
5063  int slashPos=QMAX(name.findRev('/'),name.findRev('\\'));
5064  if (slashPos!=-1)
5065  {
5066  path=name.left(slashPos+1);
5067  name=name.right(name.length()-slashPos-1);
5068  }
5069  FileName *fn;
5070  if ((fn=(*fnDict)[name]))
5071  {
5072  FileNameIterator fni(*fn);
5073  FileDef *fd;
5074  for (fni.toFirst();(fd=fni.current());++fni)
5075  {
5076  if (path.isEmpty() || fd->getPath().right(path.length())==path)
5077  {
5078  result+=" "+fd->absFilePath()+"\n";
5079  }
5080  }
5081  }
5082  return result;
5083 }
5084 
5085 //----------------------------------------------------------------------
5086 
5087 /// substitute all occurrences of \a src in \a s by \a dst
5088 QCString substitute(const QCString &s,const QCString &src,const QCString &dst)
5089 {
5090  if (s.isEmpty() || src.isEmpty()) return s;
5091  const char *p, *q;
5092  int srcLen = src.length();
5093  int dstLen = dst.length();
5094  int resLen;
5095  if (srcLen!=dstLen)
5096  {
5097  int count;
5098  for (count=0, p=s.data(); (q=strstr(p,src))!=0; p=q+srcLen) count++;
5099  resLen = s.length()+count*(dstLen-srcLen);
5100  }
5101  else // result has same size as s
5102  {
5103  resLen = s.length();
5104  }
5105  QCString result(resLen+1);
5106  char *r;
5107  for (r=result.rawData(), p=s; (q=strstr(p,src))!=0; p=q+srcLen)
5108  {
5109  int l = (int)(q-p);
5110  memcpy(r,p,l);
5111  r+=l;
5112  if (dst) memcpy(r,dst,dstLen);
5113  r+=dstLen;
5114  }
5115  qstrcpy(r,p);
5116  //printf("substitute(%s,%s,%s)->%s\n",s,src,dst,result.data());
5117  return result;
5118 }
5119 
5120 //----------------------------------------------------------------------
5121 
5123  const char *projName,const char *projNum,const char *projBrief)
5124 {
5125  QCString result = s;
5126  if (title) result = substitute(result,"$title",title);
5127  result = substitute(result,"$datetime",dateToString(TRUE));
5128  result = substitute(result,"$date",dateToString(FALSE));
5129  result = substitute(result,"$year",yearToString());
5130  result = substitute(result,"$doxygenversion",versionString);
5131  result = substitute(result,"$projectname",projName);
5132  result = substitute(result,"$projectnumber",projNum);
5133  result = substitute(result,"$projectbrief",projBrief);
5134  result = substitute(result,"$projectlogo",stripPath(Config_getString("PROJECT_LOGO")));
5135  return result;
5136 }
5137 
5138 //----------------------------------------------------------------------
5139 
5140 /*! Returns the character index within \a name of the first prefix
5141  * in Config_getList("IGNORE_PREFIX") that matches \a name at the left hand side,
5142  * or zero if no match was found
5143  */
5145 {
5146  if (name.isEmpty()) return 0;
5147  static QStrList &sl = Config_getList("IGNORE_PREFIX");
5148  char *s = sl.first();
5149  while (s)
5150  {
5151  const char *ps=s;
5152  const char *pd=name.data();
5153  int i=0;
5154  while (*ps!=0 && *pd!=0 && *ps==*pd) ps++,pd++,i++;
5155  if (*ps==0 && *pd!=0)
5156  {
5157  return i;
5158  }
5159  s = sl.next();
5160  }
5161  return 0;
5162 }
5163 
5164 //----------------------------------------------------------------------------
5165 
5167 {
5168  if (bcl==0) return;
5169  BaseClassListIterator bcli(*bcl);
5170  for ( ; bcli.current(); ++bcli)
5171  {
5172  ClassDef *cd=bcli.current()->classDef;
5173  if (cd->baseClasses()==0) // no base classes => new root
5174  {
5176  }
5177  cd->visited=FALSE;
5178  }
5179 }
5180 //----------------------------------------------------------------------------
5181 
5183 {
5184  BaseClassList *bcl;
5185 
5186  if (cd->getLanguage()==SrcLangExt_VHDL) // reverse baseClass/subClass relation
5187  {
5188  if (cd->baseClasses()==0) return FALSE;
5189  bcl=cd->baseClasses();
5190  }
5191  else
5192  {
5193  if (cd->subClasses()==0) return FALSE;
5194  bcl=cd->subClasses();
5195  }
5196 
5197  BaseClassListIterator bcli(*bcl);
5198  for ( ; bcli.current() ; ++bcli)
5199  {
5200  if (bcli.current()->classDef->isVisibleInHierarchy())
5201  {
5202  return TRUE;
5203  }
5204  }
5205  return FALSE;
5206 }
5207 
5208 
5209 //----------------------------------------------------------------------------
5210 
5212 {
5214  ClassDef *cd;
5215  for ( ; (cd=cli.current()); ++cli)
5216  {
5217  cd->visited=FALSE;
5219  }
5220 }
5221 
5222 //----------------------------------------------------------------------------
5223 
5225 {
5226  if (bcl)
5227  {
5228  BaseClassListIterator bcli(*bcl);
5229  for ( ; bcli.current(); ++bcli)
5230  {
5231  ClassDef *cd=bcli.current()->classDef;
5232  if (cd->isVisibleInHierarchy()) return TRUE;
5233  hasVisibleRoot(cd->baseClasses());
5234  }
5235  }
5236  return FALSE;
5237 }
5238 
5239 //----------------------------------------------------------------------
5240 
5241 // note that this function is not reentrant due to the use of static growBuf!
5242 QCString escapeCharsInString(const char *name,bool allowDots,bool allowUnderscore)
5243 {
5244  static bool caseSenseNames = Config_getBool("CASE_SENSE_NAMES");
5245  static bool allowUnicodeNames = Config_getBool("ALLOW_UNICODE_NAMES");
5246  static GrowBuf growBuf;
5247  growBuf.clear();
5248  char c;
5249  const char *p=name;
5250  while ((c=*p++)!=0)
5251  {
5252  switch(c)
5253  {
5254  case '_': if (allowUnderscore) growBuf.addChar('_'); else growBuf.addStr("__"); break;
5255  case '-': growBuf.addChar('-'); break;
5256  case ':': growBuf.addStr("_1"); break;
5257  case '/': growBuf.addStr("_2"); break;
5258  case '<': growBuf.addStr("_3"); break;
5259  case '>': growBuf.addStr("_4"); break;
5260  case '*': growBuf.addStr("_5"); break;
5261  case '&': growBuf.addStr("_6"); break;
5262  case '|': growBuf.addStr("_7"); break;
5263  case '.': if (allowDots) growBuf.addChar('.'); else growBuf.addStr("_8"); break;
5264  case '!': growBuf.addStr("_9"); break;
5265  case ',': growBuf.addStr("_00"); break;
5266  case ' ': growBuf.addStr("_01"); break;
5267  case '{': growBuf.addStr("_02"); break;
5268  case '}': growBuf.addStr("_03"); break;
5269  case '?': growBuf.addStr("_04"); break;
5270  case '^': growBuf.addStr("_05"); break;
5271  case '%': growBuf.addStr("_06"); break;
5272  case '(': growBuf.addStr("_07"); break;
5273  case ')': growBuf.addStr("_08"); break;
5274  case '+': growBuf.addStr("_09"); break;
5275  case '=': growBuf.addStr("_0A"); break;
5276  case '$': growBuf.addStr("_0B"); break;
5277  case '\\': growBuf.addStr("_0C"); break;
5278  case '@': growBuf.addStr("_0D"); break;
5279  default:
5280  if (c<0)
5281  {
5282  char ids[5];
5283  const unsigned char uc = (unsigned char)c;
5284  bool doEscape = TRUE;
5285  if (allowUnicodeNames && uc <= 0xf7)
5286  {
5287  const char* pt = p;
5288  ids[ 0 ] = c;
5289  int l = 0;
5290  if ((uc&0xE0)==0xC0)
5291  {
5292  l=2; // 11xx.xxxx: >=2 byte character
5293  }
5294  if ((uc&0xF0)==0xE0)
5295  {
5296  l=3; // 111x.xxxx: >=3 byte character
5297  }
5298  if ((uc&0xF8)==0xF0)
5299  {
5300  l=4; // 1111.xxxx: >=4 byte character
5301  }
5302  doEscape = l==0;
5303  for (int m=1; m<l && !doEscape; ++m)
5304  {
5305  unsigned char ct = (unsigned char)*pt;
5306  if (ct==0 || (ct&0xC0)!=0x80) // invalid unicode character
5307  {
5308  doEscape=TRUE;
5309  }
5310  else
5311  {
5312  ids[ m ] = *pt++;
5313  }
5314  }
5315  if ( !doEscape ) // got a valid unicode character
5316  {
5317  ids[ l ] = 0;
5318  growBuf.addStr( ids );
5319  p += l - 1;
5320  }
5321  }
5322  if (doEscape) // not a valid unicode char or escaping needed
5323  {
5324  static char map[] = "0123456789ABCDEF";
5325  unsigned char id = (unsigned char)c;
5326  ids[0]='_';
5327  ids[1]='x';
5328  ids[2]=map[id>>4];
5329  ids[3]=map[id&0xF];
5330  ids[4]=0;
5331  growBuf.addStr(ids);
5332  }
5333  }
5334  else if (caseSenseNames || !isupper(c))
5335  {
5336  growBuf.addChar(c);
5337  }
5338  else
5339  {
5340  growBuf.addChar('_');
5341  growBuf.addChar(tolower(c));
5342  }
5343  break;
5344  }
5345  }
5346  growBuf.addChar(0);
5347  return growBuf.get();
5348 }
5349 
5350 /*! This function determines the file name on disk of an item
5351  * given its name, which could be a class name with template
5352  * arguments, so special characters need to be escaped.
5353  */
5354 QCString convertNameToFile(const char *name,bool allowDots,bool allowUnderscore)
5355 {
5356  static bool shortNames = Config_getBool("SHORT_NAMES");
5357  static bool createSubdirs = Config_getBool("CREATE_SUBDIRS");
5358  QCString result;
5359  if (shortNames) // use short names only
5360  {
5361  static QDict<int> usedNames(10007);
5362  usedNames.setAutoDelete(TRUE);
5363  static int count=1;
5364 
5365  int *value=usedNames.find(name);
5366  int num;
5367  if (value==0)
5368  {
5369  usedNames.insert(name,new int(count));
5370  num = count++;
5371  }
5372  else
5373  {
5374  num = *value;
5375  }
5376  result.sprintf("a%05d",num);
5377  }
5378  else // long names
5379  {
5380  result=escapeCharsInString(name,allowDots,allowUnderscore);
5381  int resultLen = result.length();
5382  if (resultLen>=128) // prevent names that cannot be created!
5383  {
5384  // third algorithm based on MD5 hash
5385  uchar md5_sig[16];
5386  QCString sigStr(33);
5387  MD5Buffer((const unsigned char *)result.data(),resultLen,md5_sig);
5388  MD5SigToString(md5_sig,sigStr.rawData(),33);
5389  result=result.left(128-32)+sigStr;
5390  }
5391  }
5392  if (createSubdirs)
5393  {
5394  int l1Dir=0,l2Dir=0;
5395 
5396 #if MAP_ALGO==ALGO_COUNT
5397  // old algorithm, has the problem that after regeneration the
5398  // output can be located in a different dir.
5399  if (Doxygen::htmlDirMap==0)
5400  {
5401  Doxygen::htmlDirMap=new QDict<int>(100003);
5402  Doxygen::htmlDirMap->setAutoDelete(TRUE);
5403  }
5404  static int curDirNum=0;
5405  int *dirNum = Doxygen::htmlDirMap->find(result);
5406  if (dirNum==0) // new name
5407  {
5408  Doxygen::htmlDirMap->insert(result,new int(curDirNum));
5409  l1Dir = (curDirNum)&0xf; // bits 0-3
5410  l2Dir = (curDirNum>>4)&0xff; // bits 4-11
5411  curDirNum++;
5412  }
5413  else // existing name
5414  {
5415  l1Dir = (*dirNum)&0xf; // bits 0-3
5416  l2Dir = ((*dirNum)>>4)&0xff; // bits 4-11
5417  }
5418 #elif MAP_ALGO==ALGO_CRC16
5419  // second algorithm based on CRC-16 checksum
5420  int dirNum = qChecksum(result,result.length());
5421  l1Dir = dirNum&0xf;
5422  l2Dir = (dirNum>>4)&0xff;
5423 #elif MAP_ALGO==ALGO_MD5
5424  // third algorithm based on MD5 hash
5425  uchar md5_sig[16];
5426  MD5Buffer((const unsigned char *)result.data(),result.length(),md5_sig);
5427  l1Dir = md5_sig[14]&0xf;
5428  l2Dir = md5_sig[15];
5429 #endif
5430  result.prepend(QCString().sprintf("d%x/d%02x/",l1Dir,l2Dir));
5431  }
5432  //printf("*** convertNameToFile(%s)->%s\n",name,result.data());
5433  return result;
5434 }
5435 
5437 {
5438  QCString result;
5439  if (Config_getBool("CREATE_SUBDIRS"))
5440  {
5441  if (name==0)
5442  {
5443  return REL_PATH_TO_ROOT;
5444  }
5445  else
5446  {
5447  QCString n = name;
5448  int i = n.findRev('/');
5449  if (i!=-1)
5450  {
5451  result=REL_PATH_TO_ROOT;
5452  }
5453  }
5454  }
5455  return result;
5456 }
5457 
5459 {
5460  if (Config_getBool("CREATE_SUBDIRS"))
5461  {
5462  // create 4096 subdirectories
5463  int l1,l2;
5464  for (l1=0;l1<16;l1++)
5465  {
5466  d.mkdir(QCString().sprintf("d%x",l1));
5467  for (l2=0;l2<256;l2++)
5468  {
5469  d.mkdir(QCString().sprintf("d%x/d%02x",l1,l2));
5470  }
5471  }
5472  }
5473 }
5474 
5475 /*! Input is a scopeName, output is the scopename split into a
5476  * namespace part (as large as possible) and a classname part.
5477  */
5478 void extractNamespaceName(const QCString &scopeName,
5479  QCString &className,QCString &namespaceName,
5480  bool allowEmptyClass)
5481 {
5482  int i,p;
5483  QCString clName=scopeName;
5484  NamespaceDef *nd = 0;
5485  if (!clName.isEmpty() && (nd=getResolvedNamespace(clName)) && getClass(clName)==0)
5486  { // the whole name is a namespace (and not a class)
5487  namespaceName=nd->name().copy();
5488  className.resize(0);
5489  goto done;
5490  }
5491  p=clName.length()-2;
5492  while (p>=0 && (i=clName.findRev("::",p))!=-1)
5493  // see if the first part is a namespace (and not a class)
5494  {
5495  //printf("Trying %s\n",clName.left(i).data());
5496  if (i>0 && (nd=getResolvedNamespace(clName.left(i))) && getClass(clName.left(i))==0)
5497  {
5498  //printf("found!\n");
5499  namespaceName=nd->name().copy();
5500  className=clName.right(clName.length()-i-2);
5501  goto done;
5502  }
5503  p=i-2; // try a smaller piece of the scope
5504  }
5505  //printf("not found!\n");
5506 
5507  // not found, so we just have to guess.
5508  className=scopeName.copy();
5509  namespaceName.resize(0);
5510 
5511 done:
5512  if (className.isEmpty() && !namespaceName.isEmpty() && !allowEmptyClass)
5513  {
5514  // class and namespace with the same name, correct to return the class.
5515  className=namespaceName.copy();
5516  namespaceName.resize(0);
5517  }
5518  //printf("extractNamespace `%s' => `%s|%s'\n",scopeName.data(),
5519  // className.data(),namespaceName.data());
5520  if (/*className.right(2)=="-g" ||*/ className.right(2)=="-p")
5521  {
5522  className = className.left(className.length()-2);
5523  }
5524  return;
5525 }
5526 
5528 {
5529  QCString result=scope.copy();
5530  if (!templ.isEmpty() && scope.find('<')==-1)
5531  {
5532  int si,pi=0;
5533  ClassDef *cd=0;
5534  while (
5535  (si=scope.find("::",pi))!=-1 && !getClass(scope.left(si)+templ) &&
5536  ((cd=getClass(scope.left(si)))==0 || cd->templateArguments()==0)
5537  )
5538  {
5539  //printf("Tried `%s'\n",(scope.left(si)+templ).data());
5540  pi=si+2;
5541  }
5542  if (si==-1) // not nested => append template specifier
5543  {
5544  result+=templ;
5545  }
5546  else // nested => insert template specifier before after first class name
5547  {
5548  result=scope.left(si) + templ + scope.right(scope.length()-si);
5549  }
5550  }
5551  //printf("insertTemplateSpecifierInScope(`%s',`%s')=%s\n",
5552  // scope.data(),templ.data(),result.data());
5553  return result;
5554 }
5555 
5556 #if 0 // original version
5557 /*! Strips the scope from a name. Examples: A::B will return A
5558  * and A<T>::B<N::C<D> > will return A<T>.
5559  */
5560 QCString stripScope(const char *name)
5561 {
5562  QCString result = name;
5563  int l=result.length();
5564  int p=l-1;
5565  bool done;
5566  int count;
5567 
5568  while (p>=0)
5569  {
5570  char c=result.at(p);
5571  switch (c)
5572  {
5573  case ':':
5574  //printf("stripScope(%s)=%s\n",name,result.right(l-p-1).data());
5575  return result.right(l-p-1);
5576  case '>':
5577  count=1;
5578  done=FALSE;
5579  //printf("pos < = %d\n",p);
5580  p--;
5581  while (p>=0 && !done)
5582  {
5583  c=result.at(p--);
5584  switch (c)
5585  {
5586  case '>': count++; break;
5587  case '<': count--; if (count<=0) done=TRUE; break;
5588  default:
5589  //printf("c=%c count=%d\n",c,count);
5590  break;
5591  }
5592  }
5593  //printf("pos > = %d\n",p+1);
5594  break;
5595  default:
5596  p--;
5597  }
5598  }
5599  //printf("stripScope(%s)=%s\n",name,name);
5600  return name;
5601 }
5602 #endif
5603 
5604 // new version by Davide Cesari which also works for Fortran
5606 {
5607  QCString result = name;
5608  int l=result.length();
5609  int p;
5610  bool done = FALSE;
5611  bool skipBracket=FALSE; // if brackets do not match properly, ignore them altogether
5612  int count=0;
5613 
5614  do
5615  {
5616  p=l-1; // start at the end of the string
5617  while (p>=0 && count>=0)
5618  {
5619  char c=result.at(p);
5620  switch (c)
5621  {
5622  case ':':
5623  // only exit in the case of ::
5624  //printf("stripScope(%s)=%s\n",name,result.right(l-p-1).data());
5625  if (p>0 && result.at(p-1)==':') return result.right(l-p-1);
5626  p--;
5627  break;
5628  case '>':
5629  if (skipBracket) // we don't care about brackets
5630  {
5631  p--;
5632  }
5633  else // count open/close brackets
5634  {
5635  if (p>0 && result.at(p-1)=='>') // skip >> operator
5636  {
5637  p-=2;
5638  break;
5639  }
5640  count=1;
5641  //printf("pos < = %d\n",p);
5642  p--;
5643  bool foundMatch=false;
5644  while (p>=0 && !foundMatch)
5645  {
5646  c=result.at(p--);
5647  switch (c)
5648  {
5649  case '>':
5650  count++;
5651  break;
5652  case '<':
5653  if (p>0)
5654  {
5655  if (result.at(p-1) == '<') // skip << operator
5656  {
5657  p--;
5658  break;
5659  }
5660  }
5661  count--;
5662  foundMatch = count==0;
5663  break;
5664  default:
5665  //printf("c=%c count=%d\n",c,count);
5666  break;
5667  }
5668  }
5669  }
5670  //printf("pos > = %d\n",p+1);
5671  break;
5672  default:
5673  p--;
5674  }
5675  }
5676  done = count==0 || skipBracket; // reparse if brackets do not match
5677  skipBracket=TRUE;
5678  }
5679  while (!done); // if < > unbalanced repeat ignoring them
5680  //printf("stripScope(%s)=%s\n",name,name);
5681  return name;
5682 }
5683 
5684 /*! Converts a string to a HTML id string */
5685 QCString convertToId(const char *s)
5686 {
5687  static const char hex[] = "0123456789ABCDEF";
5688  static GrowBuf growBuf;
5689  growBuf.clear();
5690  if (s==0) return "";
5691  const char *p=s;
5692  char c;
5693  bool first=TRUE;
5694  while ((c=*p++))
5695  {
5696  char encChar[4];
5697  if ((c>='0' && c<='9') || (c>='a' && c<='z') || (c>='A' && c<='Z') || c=='-' || c==':' || c=='.')
5698  { // any permissive character except _
5699  if (first && c>='0' && c<='9') growBuf.addChar('a'); // don't start with a digit
5700  growBuf.addChar(c);
5701  }
5702  else
5703  {
5704  encChar[0]='_';
5705  encChar[1]=hex[((unsigned char)c)>>4];
5706  encChar[2]=hex[((unsigned char)c)&0xF];
5707  encChar[3]=0;
5708  growBuf.addStr(encChar);
5709  }
5710  first=FALSE;
5711  }
5712  growBuf.addChar(0);
5713  return growBuf.get();
5714 }
5715 
5716 /*! Converts a string to an XML-encoded string */
5717 QCString convertToXML(const char *s)
5718 {
5719  static GrowBuf growBuf;
5720  growBuf.clear();
5721  if (s==0) return "";
5722  const char *p=s;
5723  char c;
5724  while ((c=*p++))
5725  {
5726  switch (c)
5727  {
5728  case '<': growBuf.addStr("&lt;"); break;
5729  case '>': growBuf.addStr("&gt;"); break;
5730  case '&': growBuf.addStr("&amp;"); break;
5731  case '\'': growBuf.addStr("&apos;"); break;
5732  case '"': growBuf.addStr("&quot;"); break;
5733  case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8:
5734  case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18:
5735  case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26:
5736  case 27: case 28: case 29: case 30: case 31:
5737  break; // skip invalid XML characters (see http://www.w3.org/TR/2000/REC-xml-20001006#NT-Char)
5738  default: growBuf.addChar(c); break;
5739  }
5740  }
5741  growBuf.addChar(0);
5742  return growBuf.get();
5743 }
5744 
5745 /*! Converts a string to a HTML-encoded string */
5746 QCString convertToHtml(const char *s,bool keepEntities)
5747 {
5748  static GrowBuf growBuf;
5749  growBuf.clear();
5750  if (s==0) return "";
5751  const char *p=s;
5752  char c;
5753  while ((c=*p++))
5754  {
5755  switch (c)
5756  {
5757  case '<': growBuf.addStr("&lt;"); break;
5758  case '>': growBuf.addStr("&gt;"); break;
5759  case '&': if (keepEntities)
5760  {
5761  const char *e=p;
5762  char ce;
5763  while ((ce=*e++))
5764  {
5765  if (ce==';' || (!(isId(ce) || ce=='#'))) break;
5766  }
5767  if (ce==';') // found end of an entity
5768  {
5769  // copy entry verbatim
5770  growBuf.addChar(c);
5771  while (p<e) growBuf.addChar(*p++);
5772  }
5773  else
5774  {
5775  growBuf.addStr("&amp;");
5776  }
5777  }
5778  else
5779  {
5780  growBuf.addStr("&amp;");
5781  }
5782  break;
5783  case '\'': growBuf.addStr("&#39;"); break;
5784  case '"': growBuf.addStr("&quot;"); break;
5785  default: growBuf.addChar(c); break;
5786  }
5787  }
5788  growBuf.addChar(0);
5789  return growBuf.get();
5790 }
5791 
5793 {
5794  static GrowBuf growBuf;
5795  growBuf.clear();
5796  if (s==0) return "";
5797  const char *p=s;
5798  char c;
5799  while ((c=*p++))
5800  {
5801  switch (c)
5802  {
5803  case '"': growBuf.addStr("\\\""); break;
5804  case '\\': growBuf.addStr("\\\\"); break;
5805  default: growBuf.addChar(c); break;
5806  }
5807  }
5808  growBuf.addChar(0);
5809  return convertCharEntitiesToUTF8(growBuf.get());
5810 }
5811 
5812 QCString convertToLaTeX(const QCString &s,bool insideTabbing,bool keepSpaces)
5813 {
5814  QGString result;
5815  FTextStream t(&result);
5816  filterLatexString(t,s,insideTabbing,FALSE,FALSE,keepSpaces);
5817  return result.data();
5818 }
5819 
5820 
5821 
5823 {
5824  QCString result;
5825  static QRegExp entityPat("&[a-zA-Z]+[0-9]*;");
5826 
5827  if (s.length()==0) return result;
5828  static GrowBuf growBuf;
5829  growBuf.clear();
5830  int p,i=0,l;
5831  while ((p=entityPat.match(s,i,&l))!=-1)
5832  {
5833  if (p>i)
5834  {
5835  growBuf.addStr(s.mid(i,p-i));
5836  }
5837  QCString entity = s.mid(p,l);
5839  const char *code=0;
5840  if (symType!=DocSymbol::Sym_Unknown && (code=HtmlEntityMapper::instance()->utf8(symType)))
5841  {
5842  growBuf.addStr(code);
5843  }
5844  else
5845  {
5846  growBuf.addStr(s.mid(p,l));
5847  }
5848  i=p+l;
5849  }
5850  growBuf.addStr(s.mid(i,s.length()-i));
5851  growBuf.addChar(0);
5852  //printf("convertCharEntitiesToUTF8(%s)->%s\n",s.data(),growBuf.get());
5853  return growBuf.get();
5854 }
5855 
5856 /*! Returns the standard string that is generated when the \\overload
5857  * command is used.
5858  */
5860 {
5861  return theTranslator->trOverloadText();
5862  //"This is an overloaded member function, "
5863  // "provided for convenience. It differs from the above "
5864  // "function only in what argument(s) it accepts.";
5865 }
5866 
5868  MemberGroupSDict **ppMemberGroupSDict,
5869  Definition *context)
5870 {
5871  ASSERT(context!=0);
5872  //printf("addMemberToMemberGroup()\n");
5873  if (ml==0) return;
5874  MemberListIterator mli(*ml);
5875  MemberDef *md;
5876  uint index;
5877  for (index=0;(md=mli.current());)
5878  {
5879  if (md->isEnumerate()) // insert enum value of this enum into groups
5880  {
5881  MemberList *fmdl=md->enumFieldList();
5882  if (fmdl!=0)
5883  {
5884  MemberListIterator fmli(*fmdl);
5885  MemberDef *fmd;
5886  for (fmli.toFirst();(fmd=fmli.current());++fmli)
5887  {
5888  int groupId=fmd->getMemberGroupId();
5889  if (groupId!=-1)
5890  {
5892  //QCString *pGrpHeader = Doxygen::memberHeaderDict[groupId];
5893  //QCString *pDocs = Doxygen::memberDocDict[groupId];
5894  if (info)
5895  {
5896  if (*ppMemberGroupSDict==0)
5897  {
5898  *ppMemberGroupSDict = new MemberGroupSDict;
5899  (*ppMemberGroupSDict)->setAutoDelete(TRUE);
5900  }
5901  MemberGroup *mg = (*ppMemberGroupSDict)->find(groupId);
5902  if (mg==0)
5903  {
5904  mg = new MemberGroup(
5905  context,
5906  groupId,
5907  info->header,
5908  info->doc,
5909  info->docFile,
5910  info->docLine
5911  );
5912  (*ppMemberGroupSDict)->append(groupId,mg);
5913  }
5914  mg->insertMember(fmd); // insert in member group
5915  fmd->setMemberGroup(mg);
5916  }
5917  }
5918  }
5919  }
5920  }
5921  int groupId=md->getMemberGroupId();
5922  if (groupId!=-1)
5923  {
5925  //QCString *pGrpHeader = Doxygen::memberHeaderDict[groupId];
5926  //QCString *pDocs = Doxygen::memberDocDict[groupId];
5927  if (info)
5928  {
5929  if (*ppMemberGroupSDict==0)
5930  {
5931  *ppMemberGroupSDict = new MemberGroupSDict;
5932  (*ppMemberGroupSDict)->setAutoDelete(TRUE);
5933  }
5934  MemberGroup *mg = (*ppMemberGroupSDict)->find(groupId);
5935  if (mg==0)
5936  {
5937  mg = new MemberGroup(
5938  context,
5939  groupId,
5940  info->header,
5941  info->doc,
5942  info->docFile,
5943  info->docLine
5944  );
5945  (*ppMemberGroupSDict)->append(groupId,mg);
5946  }
5947  md = ml->take(index); // remove from member list
5948  mg->insertMember(md); // insert in member group
5949  mg->setRefItems(info->m_sli);
5950  md->setMemberGroup(mg);
5951  continue;
5952  }
5953  }
5954  ++mli;++index;
5955  }
5956 }
5957 
5958 /*! Extracts a (sub-)string from \a type starting at \a pos that
5959  * could form a class. The index of the match is returned and the found
5960  * class \a name and a template argument list \a templSpec. If -1 is returned
5961  * there are no more matches.
5962  */
5963 int extractClassNameFromType(const QCString &type,int &pos,QCString &name,QCString &templSpec,SrcLangExt lang)
5964 {
5965  static const QRegExp re_norm("[a-z_A-Z\\x80-\\xFF][a-z_A-Z0-9:\\x80-\\xFF]*");
5966  static const QRegExp re_ftn("[a-z_A-Z\\x80-\\xFF][()=_a-z_A-Z0-9:\\x80-\\xFF]*");
5967  QRegExp re;
5968 
5969  name.resize(0);
5970  templSpec.resize(0);
5971  int i,l;
5972  int typeLen=type.length();
5973  if (typeLen>0)
5974  {
5975  if (lang == SrcLangExt_Fortran)
5976  {
5977  if (type.at(pos)==',') return -1;
5978  if (type.left(4).lower()=="type")
5979  {
5980  re = re_norm;
5981  }
5982  else
5983  {
5984  re = re_ftn;
5985  }
5986  }
5987  else
5988  {
5989  re = re_norm;
5990  }
5991 
5992  if ((i=re.match(type,pos,&l))!=-1) // for each class name in the type
5993  {
5994  int ts=i+l;
5995  int te=ts;
5996  int tl=0;
5997  while (type.at(ts)==' ' && ts<typeLen) ts++,tl++; // skip any whitespace
5998  if (type.at(ts)=='<') // assume template instance
5999  {
6000  // locate end of template
6001  te=ts+1;
6002  int brCount=1;
6003  while (te<typeLen && brCount!=0)
6004  {
6005  if (type.at(te)=='<')
6006  {
6007  if (te<typeLen-1 && type.at(te+1)=='<') te++; else brCount++;
6008  }
6009  if (type.at(te)=='>')
6010  {
6011  if (te<typeLen-1 && type.at(te+1)=='>') te++; else brCount--;
6012  }
6013  te++;
6014  }
6015  }
6016  name = type.mid(i,l);
6017  if (te>ts)
6018  {
6019  templSpec = type.mid(ts,te-ts),tl+=te-ts;
6020  pos=i+l+tl;
6021  }
6022  else // no template part
6023  {
6024  pos=i+l;
6025  }
6026  //printf("extractClassNameFromType([in] type=%s,[out] pos=%d,[out] name=%s,[out] templ=%s)=TRUE\n",
6027  // type.data(),pos,name.data(),templSpec.data());
6028  return i;
6029  }
6030  }
6031  pos = typeLen;
6032  //printf("extractClassNameFromType([in] type=%s,[out] pos=%d,[out] name=%s,[out] templ=%s)=FALSE\n",
6033  // type.data(),pos,name.data(),templSpec.data());
6034  return -1;
6035 }
6036 
6038  const QCString &name,
6039  Definition *context,
6040  const ArgumentList * formalArgs)
6041 {
6042  // skip until <
6043  int p=name.find('<');
6044  if (p==-1) return name;
6045  p++;
6046  QCString result = name.left(p);
6047 
6048  static QRegExp re("[a-z_A-Z\\x80-\\xFF][a-z_A-Z0-9\\x80-\\xFF]*");
6049  int l,i;
6050  // for each identifier in the template part (e.g. B<T> -> T)
6051  while ((i=re.match(name,p,&l))!=-1)
6052  {
6053  result += name.mid(p,i-p);
6054  QCString n = name.mid(i,l);
6055  bool found=FALSE;
6056  if (formalArgs) // check that n is not a formal template argument
6057  {
6058  ArgumentListIterator formAli(*formalArgs);
6059  Argument *formArg;
6060  for (formAli.toFirst();
6061  (formArg=formAli.current()) && !found;
6062  ++formAli
6063  )
6064  {
6065  found = formArg->name==n;
6066  }
6067  }
6068  if (!found)
6069  {
6070  // try to resolve the type
6071  ClassDef *cd = getResolvedClass(context,0,n);
6072  if (cd)
6073  {
6074  result+=cd->name();
6075  }
6076  else
6077  {
6078  result+=n;
6079  }
6080  }
6081  else
6082  {
6083  result+=n;
6084  }
6085  p=i+l;
6086  }
6087  result+=name.right(name.length()-p);
6088  //printf("normalizeNonTemplateArgumentInString(%s)=%s\n",name.data(),result.data());
6089  return removeRedundantWhiteSpace(result);
6090 }
6091 
6092 
6093 /*! Substitutes any occurrence of a formal argument from argument list
6094  * \a formalArgs in \a name by the corresponding actual argument in
6095  * argument list \a actualArgs. The result after substitution
6096  * is returned as a string. The argument \a name is used to
6097  * prevent recursive substitution.
6098  */
6100  const QCString &name,
6101  ArgumentList *formalArgs,
6102  ArgumentList *actualArgs)
6103 {
6104  //printf("substituteTemplateArgumentsInString(name=%s formal=%s actualArg=%s)\n",
6105  // name.data(),argListToString(formalArgs).data(),argListToString(actualArgs).data());
6106  if (formalArgs==0) return name;
6107  QCString result;
6108  static QRegExp re("[a-z_A-Z\\x80-\\xFF][a-z_A-Z0-9\\x80-\\xFF]*");
6109  int p=0,l,i;
6110  // for each identifier in the base class name (e.g. B<T> -> B and T)
6111  while ((i=re.match(name,p,&l))!=-1)
6112  {
6113  result += name.mid(p,i-p);
6114  QCString n = name.mid(i,l);
6115  ArgumentListIterator formAli(*formalArgs);
6116  ArgumentListIterator actAli(*actualArgs);
6117  Argument *formArg;
6118  Argument *actArg;
6119 
6120  // if n is a template argument, then we substitute it
6121  // for its template instance argument.
6122  bool found=FALSE;
6123  for (formAli.toFirst();
6124  (formArg=formAli.current()) && !found;
6125  ++formAli,++actAli
6126  )
6127  {
6128  actArg = actAli.current();
6129  if (formArg->type.left(6)=="class " && formArg->name.isEmpty())
6130  {
6131  formArg->name = formArg->type.mid(6);
6132  formArg->type = "class";
6133  }
6134  if (formArg->type.left(9)=="typename " && formArg->name.isEmpty())
6135  {
6136  formArg->name = formArg->type.mid(9);
6137  formArg->type = "typename";
6138  }
6139  if (formArg->type=="class" || formArg->type=="typename" || formArg->type.left(8)=="template")
6140  {
6141  //printf("n=%s formArg->type='%s' formArg->name='%s' formArg->defval='%s'\n",
6142  // n.data(),formArg->type.data(),formArg->name.data(),formArg->defval.data());
6143  //printf(">> formArg->name='%s' actArg->type='%s' actArg->name='%s'\n",
6144  // formArg->name.data(),actArg ? actArg->type.data() : "",actArg ? actArg->name.data() : ""
6145  // );
6146  if (formArg->name==n && actArg && !actArg->type.isEmpty()) // base class is a template argument
6147  {
6148  // replace formal argument with the actual argument of the instance
6149  if (!leftScopeMatch(actArg->type,n))
6150  // the scope guard is to prevent recursive lockup for
6151  // template<class A> class C : public<A::T>,
6152  // where A::T would become A::T::T here,
6153  // since n==A and actArg->type==A::T
6154  // see bug595833 for an example
6155  {
6156  if (actArg->name.isEmpty())
6157  {
6158  result += actArg->type+" ";
6159  found=TRUE;
6160  }
6161  else
6162  // for case where the actual arg is something like "unsigned int"
6163  // the "int" part is in actArg->name.
6164  {
6165  result += actArg->type+" "+actArg->name+" ";
6166  found=TRUE;
6167  }
6168  }
6169  }
6170  else if (formArg->name==n &&
6171  actArg==0 &&
6172  !formArg->defval.isEmpty() &&
6173  formArg->defval!=name /* to prevent recursion */
6174  )
6175  {
6176  result += substituteTemplateArgumentsInString(formArg->defval,formalArgs,actualArgs)+" ";
6177  found=TRUE;
6178  }
6179  }
6180  else if (formArg->name==n &&
6181  actArg==0 &&
6182  !formArg->defval.isEmpty() &&
6183  formArg->defval!=name /* to prevent recursion */
6184  )
6185  {
6186  result += substituteTemplateArgumentsInString(formArg->defval,formalArgs,actualArgs)+" ";
6187  found=TRUE;
6188  }
6189  }
6190  if (!found)
6191  {
6192  result += n;
6193  }
6194  p=i+l;
6195  }
6196  result+=name.right(name.length()-p);
6197  //printf(" Inheritance relation %s -> %s\n",
6198  // name.data(),result.data());
6199  return result.stripWhiteSpace();
6200 }
6201 
6202 /*! Makes a deep copy of the list of argument lists \a srcLists.
6203  * Will allocate memory, that is owned by the caller.
6204  */
6206 {
6207  ASSERT(srcLists!=0);
6208  QList<ArgumentList> *dstLists = new QList<ArgumentList>;
6209  dstLists->setAutoDelete(TRUE);
6210  QListIterator<ArgumentList> sli(*srcLists);
6211  ArgumentList *sl;
6212  for (;(sl=sli.current());++sli)
6213  {
6214  dstLists->append(sl->deepCopy());
6215  }
6216  return dstLists;
6217 }
6218 
6219 /*! Strips template specifiers from scope \a fullName, except those
6220  * that make up specialized classes. The switch \a parentOnly
6221  * determines whether or not a template "at the end" of a scope
6222  * should be considered, e.g. with \a parentOnly is \c TRUE, A<T>::B<S> will
6223  * try to strip <T> and not <S>, while \a parentOnly is \c FALSE will
6224  * strip both unless A<T> or B<S> are specialized template classes.
6225  */
6227  bool parentOnly,
6228  QCString *pLastScopeStripped)
6229 {
6230  QCString result;
6231  int p=0;
6232  int l=fullName.length();
6233  int i=fullName.find('<');
6234  while (i!=-1)
6235  {
6236  //printf("1:result+=%s\n",fullName.mid(p,i-p).data());
6237  int e=i+1;
6238  bool done=FALSE;
6239  int count=1;
6240  while (e<l && !done)
6241  {
6242  char c=fullName.at(e++);
6243  if (c=='<')
6244  {
6245  count++;
6246  }
6247  else if (c=='>')
6248  {
6249  count--;
6250  done = count==0;
6251  }
6252  }
6253  int si= fullName.find("::",e);
6254 
6255  if (parentOnly && si==-1) break;
6256  // we only do the parent scope, so we stop here if needed
6257 
6258  result+=fullName.mid(p,i-p);
6259  //printf(" trying %s\n",(result+fullName.mid(i,e-i)).data());
6260  if (getClass(result+fullName.mid(i,e-i))!=0)
6261  {
6262  result+=fullName.mid(i,e-i);
6263  //printf(" 2:result+=%s\n",fullName.mid(i,e-i-1).data());
6264  }
6265  else if (pLastScopeStripped)
6266  {
6267  //printf(" last stripped scope '%s'\n",fullName.mid(i,e-i).data());
6268  *pLastScopeStripped=fullName.mid(i,e-i);
6269  }
6270  p=e;
6271  i=fullName.find('<',p);
6272  }
6273  result+=fullName.right(l-p);
6274  //printf("3:result+=%s\n",fullName.right(l-p).data());
6275  return result;
6276 }
6277 
6278 /*! Merges two scope parts together. The parts may (partially) overlap.
6279  * Example1: \c A::B and \c B::C will result in \c A::B::C <br>
6280  * Example2: \c A and \c B will be \c A::B <br>
6281  * Example3: \c A::B and B will be \c A::B
6282  *
6283  * @param leftScope the left hand part of the scope.
6284  * @param rightScope the right hand part of the scope.
6285  * @returns the merged scope.
6286  */
6287 QCString mergeScopes(const QCString &leftScope,const QCString &rightScope)
6288 {
6289  // case leftScope=="A" rightScope=="A::B" => result = "A::B"
6290  if (leftScopeMatch(rightScope,leftScope)) return rightScope;
6291  QCString result;
6292  int i=0,p=leftScope.length();
6293 
6294  // case leftScope=="A::B" rightScope=="B::C" => result = "A::B::C"
6295  // case leftScope=="A::B" rightScope=="B" => result = "A::B"
6296  bool found=FALSE;
6297  while ((i=leftScope.findRev("::",p))!=-1)
6298  {
6299  if (leftScopeMatch(rightScope,leftScope.right(leftScope.length()-i-2)))
6300  {
6301  result = leftScope.left(i+2)+rightScope;
6302  found=TRUE;
6303  }
6304  p=i-1;
6305  }
6306  if (found) return result;
6307 
6308  // case leftScope=="A" rightScope=="B" => result = "A::B"
6309  result=leftScope.copy();
6310  if (!result.isEmpty() && !rightScope.isEmpty()) result+="::";
6311  result+=rightScope;
6312  return result;
6313 }
6314 
6315 /*! Returns a fragment from scope \a s, starting at position \a p.
6316  *
6317  * @param s the scope name as a string.
6318  * @param p the start position (0 is the first).
6319  * @param l the resulting length of the fragment.
6320  * @returns the location of the fragment, or -1 if non is found.
6321  */
6322 int getScopeFragment(const QCString &s,int p,int *l)
6323 {
6324  int sl=s.length();
6325  int sp=p;
6326  int count=0;
6327  bool done;
6328  if (sp>=sl) return -1;
6329  while (sp<sl)
6330  {
6331  char c=s.at(sp);
6332  if (c==':') sp++,p++; else break;
6333  }
6334  while (sp<sl)
6335  {
6336  char c=s.at(sp);
6337  switch (c)
6338  {
6339  case ':': // found next part
6340  goto found;
6341  case '<': // skip template specifier
6342  count=1;sp++;
6343  done=FALSE;
6344  while (sp<sl && !done)
6345  {
6346  // TODO: deal with << and >> operators!
6347  char c=s.at(sp++);
6348  switch(c)
6349  {
6350  case '<': count++; break;
6351  case '>': count--; if (count==0) done=TRUE; break;
6352  default: break;
6353  }
6354  }
6355  break;
6356  default:
6357  sp++;
6358  break;
6359  }
6360  }
6361 found:
6362  *l=sp-p;
6363  //printf("getScopeFragment(%s,%d)=%s\n",s.data(),p,s.mid(p,*l).data());
6364  return p;
6365 }
6366 
6367 //----------------------------------------------------------------------------
6368 
6369 PageDef *addRelatedPage(const char *name,const QCString &ptitle,
6370  const QCString &doc,
6371  QList<SectionInfo> * /*anchors*/,
6372  const char *fileName,int startLine,
6373  const QList<ListItemInfo> *sli,
6374  GroupDef *gd,
6375  TagInfo *tagInfo,
6376  SrcLangExt lang
6377  )
6378 {
6379  PageDef *pd=0;
6380  //printf("addRelatedPage(name=%s gd=%p)\n",name,gd);
6381  if ((pd=Doxygen::pageSDict->find(name)) && !tagInfo)
6382  {
6383  // append documentation block to the page.
6384  pd->setDocumentation(doc,fileName,startLine);
6385  //printf("Adding page docs `%s' pi=%p name=%s\n",doc.data(),pd,name);
6386  }
6387  else // new page
6388  {
6390  if (baseName.right(4)==".tex")
6391  baseName=baseName.left(baseName.length()-4);
6393  baseName=baseName.left(baseName.length()-Doxygen::htmlFileExtension.length());
6394 
6395  QCString title=ptitle.stripWhiteSpace();
6396  pd=new PageDef(fileName,startLine,baseName,doc,title);
6397 
6398  pd->setRefItems(sli);
6399  pd->setLanguage(lang);
6400 
6401  if (tagInfo)
6402  {
6403  pd->setReference(tagInfo->tagName);
6404  pd->setFileName(tagInfo->fileName);
6405  }
6406 
6407  //printf("Appending page `%s'\n",baseName.data());
6408  Doxygen::pageSDict->append(baseName,pd);
6409 
6410  if (gd) gd->addPage(pd);
6411 
6412  if (!pd->title().isEmpty())
6413  {
6414  //outputList->writeTitle(pi->name,pi->title);
6415 
6416  // a page name is a label as well!
6417  QCString file;
6418  if (gd)
6419  {
6420  file=gd->getOutputFileBase();
6421  }
6422  else
6423  {
6424  file=pd->getOutputFileBase();
6425  }
6426  SectionInfo *si = Doxygen::sectionDict->find(pd->name());
6427  if (si)
6428  {
6429  if (si->lineNr != -1)
6430  {
6431  warn(file,-1,"multiple use of section label '%s', (first occurrence: %s, line %d)",pd->name().data(),si->fileName.data(),si->lineNr);
6432  }
6433  else
6434  {
6435  warn(file,-1,"multiple use of section label '%s', (first occurrence: %s)",pd->name().data(),si->fileName.data());
6436  }
6437  }
6438  else
6439  {
6440  si=new SectionInfo(
6441  file,-1,pd->name(),pd->title(),SectionInfo::Page,0,pd->getReference());
6442  //printf("si->label=`%s' si->definition=%s si->fileName=`%s'\n",
6443  // si->label.data(),si->definition?si->definition->name().data():"<none>",
6444  // si->fileName.data());
6445  //printf(" SectionInfo: sec=%p sec->fileName=%s\n",si,si->fileName.data());
6446  //printf("Adding section key=%s si->fileName=%s\n",pageName.data(),si->fileName.data());
6447  Doxygen::sectionDict->append(pd->name(),si);
6448  }
6449  }
6450  }
6451  return pd;
6452 }
6453 
6454 //----------------------------------------------------------------------------
6455 
6457  const char *key,
6458  const char *prefix, const char *name,const char *title,const char *args,Definition *scope)
6459 {
6460  //printf("addRefItem(sli=%p,key=%s,prefix=%s,name=%s,title=%s,args=%s)\n",sli,key,prefix,name,title,args);
6461  if (sli && key && key[0]!='@') // check for @ to skip anonymous stuff (see bug427012)
6462  {
6463  QListIterator<ListItemInfo> slii(*sli);
6464  ListItemInfo *lii;
6465  for (slii.toFirst();(lii=slii.current());++slii)
6466  {
6467  RefList *refList = Doxygen::xrefLists->find(lii->type);
6468  if (refList
6469  &&
6470  (
6471  // either not a built-in list or the list is enabled
6472  (lii->type!="todo" || Config_getBool("GENERATE_TODOLIST")) &&
6473  (lii->type!="test" || Config_getBool("GENERATE_TESTLIST")) &&
6474  (lii->type!="bug" || Config_getBool("GENERATE_BUGLIST")) &&
6475  (lii->type!="deprecated" || Config_getBool("GENERATE_DEPRECATEDLIST"))
6476  )
6477  )
6478  {
6479  RefItem *item = refList->getRefItem(lii->itemId);
6480  ASSERT(item!=0);
6481 
6482  item->prefix = prefix;
6483  item->scope = scope;
6484  item->name = name;
6485  item->title = title;
6486  item->args = args;
6487 
6488  refList->insertIntoList(key,item);
6489 
6490  }
6491  }
6492  }
6493 }
6494 
6496 {
6497  GroupList *groups = d->partOfGroups();
6498  if (groups) // write list of group to which this definition belongs
6499  {
6500  if (root)
6501  {
6502  ol.pushGeneratorState();
6504  ol.writeString("<div class=\"ingroups\">");
6505  }
6506  GroupListIterator gli(*groups);
6507  GroupDef *gd;
6508  bool first=true;
6509  for (gli.toFirst();(gd=gli.current());++gli)
6510  {
6512  {
6513  ol.writeString(" &raquo; ");
6514  }
6515  if (!first) { ol.writeString(" &#124; "); } else first=FALSE;
6516  ol.writeObjectLink(gd->getReference(),gd->getOutputFileBase(),0,gd->groupTitle());
6517  }
6518  if (root)
6519  {
6520  ol.writeString("</div>");
6521  ol.popGeneratorState();
6522  }
6523  return true;
6524  }
6525  return false;
6526 }
6527 
6529 {
6531 }
6532 
6534  bool insideTabbing,bool insidePre,bool insideItem,bool keepSpaces)
6535 {
6536  if (str==0) return;
6537  //if (strlen(str)<2) stackTrace();
6538  const unsigned char *p=(const unsigned char *)str;
6539  const unsigned char *q;
6540  int cnt;
6541  unsigned char c;
6542  unsigned char pc='\0';
6543  while (*p)
6544  {
6545  c=*p++;
6546 
6547  if (insidePre)
6548  {
6549  switch(c)
6550  {
6551  case '\\': t << "\\(\\backslash\\)"; break;
6552  case '{': t << "\\{"; break;
6553  case '}': t << "\\}"; break;
6554  case '_': t << "\\_"; break;
6555  case ' ': if (keepSpaces) t << "~"; else t << ' ';
6556  break;
6557  default:
6558  t << (char)c;
6559  break;
6560  }
6561  }
6562  else
6563  {
6564  switch(c)
6565  {
6566  case '#': t << "\\#"; break;
6567  case '$': t << "\\$"; break;
6568  case '%': t << "\\%"; break;
6569  case '^': t << "$^\\wedge$"; break;
6570  case '&': // possibility to have a special symbol
6571  q = p;
6572  cnt = 2; // we have to count & and ; as well
6573  while ((*q >= 'a' && *q <= 'z') || (*q >= 'A' && *q <= 'Z') || (*q >= '0' && *q <= '9'))
6574  {
6575  cnt++;
6576  q++;
6577  }
6578  if (*q == ';')
6579  {
6580  --p; // we need & as well
6582  if (res == DocSymbol::Sym_Unknown)
6583  {
6584  p++;
6585  t << "\\&";
6586  }
6587  else
6588  {
6589  t << HtmlEntityMapper::instance()->latex(res);
6590  q++;
6591  p = q;
6592  }
6593  }
6594  else
6595  {
6596  t << "\\&";
6597  }
6598  break;
6599  case '*': t << "$\\ast$"; break;
6600  case '_': if (!insideTabbing) t << "\\+";
6601  t << "\\_";
6602  if (!insideTabbing) t << "\\+";
6603  break;
6604  case '{': t << "\\{"; break;
6605  case '}': t << "\\}"; break;
6606  case '<': t << "$<$"; break;
6607  case '>': t << "$>$"; break;
6608  case '|': t << "$\\vert$"; break;
6609  case '~': t << "$\\sim$"; break;
6610  case '[': if (Config_getBool("PDF_HYPERLINKS") || insideItem)
6611  t << "\\mbox{[}";
6612  else
6613  t << "[";
6614  break;
6615  case ']': if (pc=='[') t << "$\\,$";
6616  if (Config_getBool("PDF_HYPERLINKS") || insideItem)
6617  t << "\\mbox{]}";
6618  else
6619  t << "]";
6620  break;
6621  case '-': t << "-\\/";
6622  break;
6623  case '\\': t << "\\textbackslash{}";
6624  break;
6625  case '"': t << "\\char`\\\"{}";
6626  break;
6627  case '\'': t << "\\textquotesingle{}";
6628  break;
6629  case ' ': if (keepSpaces) { if (insideTabbing) t << "\\>"; else t << '~'; } else t << ' ';
6630  break;
6631 
6632  default:
6633  //if (!insideTabbing && forceBreaks && c!=' ' && *p!=' ')
6634  if (!insideTabbing &&
6635  ((c>='A' && c<='Z' && pc!=' ' && pc!='\0' && *p) || (c==':' && pc!=':') || (pc=='.' && isId(c)))
6636  )
6637  {
6638  t << "\\+";
6639  }
6640  t << (char)c;
6641  }
6642  }
6643  pc = c;
6644  }
6645 }
6646 
6647 QCString latexEscapeLabelName(const char *s,bool insideTabbing)
6648 {
6649  QGString result;
6650  QCString tmp(qstrlen(s)+1);
6651  FTextStream t(&result);
6652  const char *p=s;
6653  char c;
6654  int i;
6655  while ((c=*p++))
6656  {
6657  switch (c)
6658  {
6659  case '|': t << "\\texttt{\"|}"; break;
6660  case '!': t << "\"!"; break;
6661  case '%': t << "\\%"; break;
6662  case '{': t << "\\lcurly{}"; break;
6663  case '}': t << "\\rcurly{}"; break;
6664  case '~': t << "````~"; break; // to get it a bit better in index together with other special characters
6665  // NOTE: adding a case here, means adding it to while below as well!
6666  default:
6667  i=0;
6668  // collect as long string as possible, before handing it to docify
6669  tmp[i++]=c;
6670  while ((c=*p) && c!='|' && c!='!' && c!='%' && c!='{' && c!='}' && c!='~')
6671  {
6672  tmp[i++]=c;
6673  p++;
6674  }
6675  tmp[i]=0;
6676  filterLatexString(t,tmp.data(),insideTabbing);
6677  break;
6678  }
6679  }
6680  return result.data();
6681 }
6682 
6683 QCString latexEscapeIndexChars(const char *s,bool insideTabbing)
6684 {
6685  QGString result;
6686  QCString tmp(qstrlen(s)+1);
6687  FTextStream t(&result);
6688  const char *p=s;
6689  char c;
6690  int i;
6691  while ((c=*p++))
6692  {
6693  switch (c)
6694  {
6695  case '!': t << "\"!"; break;
6696  case '"': t << "\"\""; break;
6697  case '@': t << "\"@"; break;
6698  case '|': t << "\\texttt{\"|}"; break;
6699  case '[': t << "["; break;
6700  case ']': t << "]"; break;
6701  case '{': t << "\\lcurly{}"; break;
6702  case '}': t << "\\rcurly{}"; break;
6703  // NOTE: adding a case here, means adding it to while below as well!
6704  default:
6705  i=0;
6706  // collect as long string as possible, before handing it to docify
6707  tmp[i++]=c;
6708  while ((c=*p) && c!='"' && c!='@' && c!='[' && c!=']' && c!='!' && c!='{' && c!='}' && c!='|')
6709  {
6710  tmp[i++]=c;
6711  p++;
6712  }
6713  tmp[i]=0;
6714  filterLatexString(t,tmp.data(),insideTabbing);
6715  break;
6716  }
6717  }
6718  return result.data();
6719 }
6720 
6722 {
6723  QGString result;
6724  FTextStream t(&result);
6725  const char *p=s;
6726  char c;
6727  int i;
6728  while ((c=*p++))
6729  {
6730  switch (c)
6731  {
6732  case '\\': t << "\\textbackslash{}"; break;
6733  case '{': t << "\\{"; break;
6734  case '}': t << "\\}"; break;
6735  default:
6736  t << c;
6737  break;
6738  }
6739  }
6740  return result.data();
6741 }
6742 
6743 
6745 {
6746  static QCString g_nextTag( "AAAAAAAAAA" );
6747  static QDict<QCString> g_tagDict( 5003 );
6748 
6749  g_tagDict.setAutoDelete(TRUE);
6750 
6751  // To overcome the 40-character tag limitation, we
6752  // substitute a short arbitrary string for the name
6753  // supplied, and keep track of the correspondence
6754  // between names and strings.
6755  QCString key( name );
6756  QCString* tag = g_tagDict.find( key );
6757  if ( !tag )
6758  {
6759  // This particular name has not yet been added
6760  // to the list. Add it, associating it with the
6761  // next tag value, and increment the next tag.
6762  tag = new QCString( g_nextTag.copy() ); // Make sure to use a deep copy!
6763  g_tagDict.insert( key, tag );
6764 
6765  // This is the increment part
6766  char* nxtTag = g_nextTag.rawData() + g_nextTag.length() - 1;
6767  for ( unsigned int i = 0; i < g_nextTag.length(); ++i, --nxtTag )
6768  {
6769  if ( ( ++(*nxtTag) ) > 'Z' )
6770  {
6771  *nxtTag = 'A';
6772  }
6773  else
6774  {
6775  // Since there was no carry, we can stop now
6776  break;
6777  }
6778  }
6779  }
6780 
6781  return *tag;
6782 }
6783 
6784 bool checkExtension(const char *fName, const char *ext)
6785 {
6786  return (QCString(fName).right(QCString(ext).length())==ext);
6787 }
6788 
6789 QCString stripExtensionGeneral(const char *fName, const char *ext)
6790 {
6791  QCString result=fName;
6792  if (result.right(QCString(ext).length())==QCString(ext))
6793  {
6794  result=result.left(result.length()-QCString(ext).length());
6795  }
6796  return result;
6797 }
6798 
6799 QCString stripExtension(const char *fName)
6800 {
6802 }
6803 
6805 {
6806  while (i>0)
6807  {
6808  QCString ns = scope.left(i);
6810  if (s)
6811  {
6812  scope=*s+scope.right(scope.length()-i);
6813  i=s->length();
6814  }
6815  if (i>0 && ns==scope.left(i)) break;
6816  }
6817 }
6818 
6819 QCString stripPath(const char *s)
6820 {
6821  QCString result=s;
6822  int i=result.findRev('/');
6823  if (i!=-1)
6824  {
6825  result=result.mid(i+1);
6826  }
6827  i=result.findRev('\\');
6828  if (i!=-1)
6829  {
6830  result=result.mid(i+1);
6831  }
6832  return result;
6833 }
6834 
6835 /** returns \c TRUE iff string \a s contains word \a w */
6836 bool containsWord(const QCString &s,const QCString &word)
6837 {
6838  static QRegExp wordExp("[a-z_A-Z\\x80-\\xFF]+");
6839  int p=0,i,l;
6840  while ((i=wordExp.match(s,p,&l))!=-1)
6841  {
6842  if (s.mid(i,l)==word) return TRUE;
6843  p=i+l;
6844  }
6845  return FALSE;
6846 }
6847 
6849 {
6850  static QRegExp wordExp("[a-z_A-Z\\x80-\\xFF]+");
6851  int p=0,i,l;
6852  while ((i=wordExp.match(s,p,&l))!=-1)
6853  {
6854  if (s.mid(i,l)==word)
6855  {
6856  if (i>0 && isspace((uchar)s.at(i-1)))
6857  i--,l++;
6858  else if (i+l<(int)s.length() && isspace(s.at(i+l)))
6859  l++;
6860  s = s.left(i)+s.mid(i+l); // remove word + spacing
6861  return TRUE;
6862  }
6863  p=i+l;
6864  }
6865  return FALSE;
6866 }
6867 
6868 /** Special version of QCString::stripWhiteSpace() that only strips
6869  * completely blank lines.
6870  * @param s the string to be stripped
6871  * @param docLine the line number corresponding to the start of the
6872  * string. This will be adjusted based on the number of lines stripped
6873  * from the start.
6874  * @returns The stripped string.
6875  */
6877 {
6878  const char *p = s.data();
6879  if (p==0) return 0;
6880 
6881  // search for leading empty lines
6882  int i=0,li=-1,l=s.length();
6883  char c;
6884  while ((c=*p++))
6885  {
6886  if (c==' ' || c=='\t' || c=='\r') i++;
6887  else if (c=='\n') i++,li=i,docLine++;
6888  else break;
6889  }
6890 
6891  // search for trailing empty lines
6892  int b=l-1,bi=-1;
6893  p=s.data()+b;
6894  while (b>=0)
6895  {
6896  c=*p; p--;
6897  if (c==' ' || c=='\t' || c=='\r') b--;
6898  else if (c=='\n') bi=b,b--;
6899  else break;
6900  }
6901 
6902  // return whole string if no leading or trailing lines where found
6903  if (li==-1 && bi==-1) return s;
6904 
6905  // return substring
6906  if (bi==-1) bi=l;
6907  if (li==-1) li=0;
6908  if (bi<=li) return 0; // only empty lines
6909  return s.mid(li,bi-li);
6910 }
6911 
6912 #if 0
6913 void stringToSearchIndex(const QCString &docBaseUrl,const QCString &title,
6914  const QCString &str,bool priority,const QCString &anchor)
6915 {
6916  static bool searchEngine = Config_getBool("SEARCHENGINE");
6917  if (searchEngine)
6918  {
6919  Doxygen::searchIndex->setCurrentDoc(title,docBaseUrl,anchor);
6920  static QRegExp wordPattern("[a-z_A-Z\\x80-\\xFF][a-z_A-Z0-9\\x80-\\xFF]*");
6921  int i,p=0,l;
6922  while ((i=wordPattern.match(str,p,&l))!=-1)
6923  {
6924  Doxygen::searchIndex->addWord(str.mid(i,l),priority);
6925  p=i+l;
6926  }
6927  }
6928 }
6929 #endif
6930 
6931 //--------------------------------------------------------------------------
6932 
6933 static QDict<int> g_extLookup;
6934 
6935 static struct Lang2ExtMap
6936 {
6937  const char *langName;
6938  const char *parserName;
6940 }
6941 g_lang2extMap[] =
6942 {
6943 // language parser parser option
6944  { "idl", "c", SrcLangExt_IDL },
6945  { "java", "c", SrcLangExt_Java },
6946  { "javascript", "c", SrcLangExt_JS },
6947  { "csharp", "c", SrcLangExt_CSharp },
6948  { "d", "c", SrcLangExt_D },
6949  { "php", "c", SrcLangExt_PHP },
6950  { "objective-c", "c", SrcLangExt_ObjC },
6951  { "c", "c", SrcLangExt_Cpp },
6952  { "c++", "c", SrcLangExt_Cpp },
6953  { "python", "python", SrcLangExt_Python },
6954  { "fortran", "fortran", SrcLangExt_Fortran },
6955  { "fortranfree", "fortranfree", SrcLangExt_Fortran },
6956  { "fortranfixed", "fortranfixed", SrcLangExt_Fortran },
6957  { "vhdl", "vhdl", SrcLangExt_VHDL },
6958  { "xml", "xml", SrcLangExt_XML },
6959  { "tcl", "tcl", SrcLangExt_Tcl },
6960  { "md", "md", SrcLangExt_Markdown },
6961  { 0, 0, (SrcLangExt)0 }
6962 };
6963 
6964 bool updateLanguageMapping(const QCString &extension,const QCString &language)
6965 {
6966  const Lang2ExtMap *p = g_lang2extMap;
6967  QCString langName = language.lower();
6968  while (p->langName)
6969  {
6970  if (langName==p->langName) break;
6971  p++;
6972  }
6973  if (!p->langName) return FALSE;
6974 
6975  // found the language
6976  SrcLangExt parserId = p->parserId;
6977  QCString extName = extension.lower();
6978  if (extName.isEmpty()) return FALSE;
6979  if (extName.at(0)!='.') extName.prepend(".");
6980  if (g_extLookup.find(extension)!=0) // language was already register for this ext
6981  {
6982  g_extLookup.remove(extension);
6983  }
6984  //printf("registering extension %s\n",extName.data());
6985  g_extLookup.insert(extName,new int(parserId));
6986  if (!Doxygen::parserManager->registerExtension(extName,p->parserName))
6987  {
6988  err("Failed to assign extension %s to parser %s for language %s\n",
6989  extName.data(),p->parserName,language.data());
6990  }
6991  else
6992  {
6993  //msg("Registered extension %s to language parser %s...\n",
6994  // extName.data(),language.data());
6995  }
6996  return TRUE;
6997 }
6998 
7000 {
7001  // NOTE: when adding an extension, also add the extension in config.xml
7002  g_extLookup.setAutoDelete(TRUE);
7003  // extension parser id
7004  updateLanguageMapping(".dox", "c");
7005  updateLanguageMapping(".txt", "c");
7006  updateLanguageMapping(".doc", "c");
7007  updateLanguageMapping(".c", "c");
7008  updateLanguageMapping(".C", "c");
7009  updateLanguageMapping(".cc", "c");
7010  updateLanguageMapping(".CC", "c");
7011  updateLanguageMapping(".cxx", "c");
7012  updateLanguageMapping(".cpp", "c");
7013  updateLanguageMapping(".c++", "c");
7014  updateLanguageMapping(".ii", "c");
7015  updateLanguageMapping(".ixx", "c");
7016  updateLanguageMapping(".ipp", "c");
7017  updateLanguageMapping(".i++", "c");
7018  updateLanguageMapping(".inl", "c");
7019  updateLanguageMapping(".h", "c");
7020  updateLanguageMapping(".H", "c");
7021  updateLanguageMapping(".hh", "c");
7022  updateLanguageMapping(".HH", "c");
7023  updateLanguageMapping(".hxx", "c");
7024  updateLanguageMapping(".hpp", "c");
7025  updateLanguageMapping(".h++", "c");
7026  updateLanguageMapping(".idl", "idl");
7027  updateLanguageMapping(".ddl", "idl");
7028  updateLanguageMapping(".odl", "idl");
7029  updateLanguageMapping(".java", "java");
7030  updateLanguageMapping(".as", "javascript");
7031  updateLanguageMapping(".js", "javascript");
7032  updateLanguageMapping(".cs", "csharp");
7033  updateLanguageMapping(".d", "d");
7034  updateLanguageMapping(".php", "php");
7035  updateLanguageMapping(".php4", "php");
7036  updateLanguageMapping(".php5", "php");
7037  updateLanguageMapping(".inc", "php");
7038  updateLanguageMapping(".phtml", "php");
7039  updateLanguageMapping(".m", "objective-c");
7040  updateLanguageMapping(".M", "objective-c");
7041  updateLanguageMapping(".mm", "c"); // see bug746361
7042  updateLanguageMapping(".py", "python");
7043  updateLanguageMapping(".pyw", "python");
7044  updateLanguageMapping(".f", "fortran");
7045  updateLanguageMapping(".for", "fortran");
7046  updateLanguageMapping(".f90", "fortran");
7047  updateLanguageMapping(".vhd", "vhdl");
7048  updateLanguageMapping(".vhdl", "vhdl");
7049  updateLanguageMapping(".tcl", "tcl");
7050  updateLanguageMapping(".ucf", "vhdl");
7051  updateLanguageMapping(".qsf", "vhdl");
7052  updateLanguageMapping(".md", "md");
7053  updateLanguageMapping(".markdown", "md");
7054 }
7055 
7057 {
7058  updateLanguageMapping(".xml", "xml");
7059 }
7060 
7062 {
7063  int i = fileName.findRev('.');
7064  if (i!=-1) // name has an extension
7065  {
7066  QCString extStr=fileName.right(fileName.length()-i).lower();
7067  if (!extStr.isEmpty()) // non-empty extension
7068  {
7069  int *pVal=g_extLookup.find(extStr);
7070  if (pVal) // listed extension
7071  {
7072  //printf("getLanguageFromFileName(%s)=%x\n",extStr.data(),*pVal);
7073  return (SrcLangExt)*pVal;
7074  }
7075  }
7076  }
7077  //printf("getLanguageFromFileName(%s) not found!\n",fileName.data());
7078  return SrcLangExt_Cpp; // not listed => assume C-ish language.
7079 }
7080 
7081 //--------------------------------------------------------------------------
7082 
7084  const char *n)
7085 {
7086  if (scope==0 ||
7089  )
7090  )
7091  {
7092  scope=Doxygen::globalScope;
7093  }
7094 
7095  QCString name = n;
7096  if (name.isEmpty())
7097  return 0; // no name was given
7098 
7099  DefinitionIntf *di = Doxygen::symbolMap->find(name);
7100  if (di==0)
7101  return 0; // could not find any matching symbols
7102 
7103  // mostly copied from getResolvedClassRec()
7104  QCString explicitScopePart;
7105  int qualifierIndex = computeQualifiedIndex(name);
7106  if (qualifierIndex!=-1)
7107  {
7108  explicitScopePart = name.left(qualifierIndex);
7109  replaceNamespaceAliases(explicitScopePart,explicitScopePart.length());
7110  name = name.mid(qualifierIndex+2);
7111  }
7112  //printf("explicitScopePart=%s\n",explicitScopePart.data());
7113 
7114  int minDistance = 10000;
7115  MemberDef *bestMatch = 0;
7116 
7118  {
7119  //printf("multiple matches!\n");
7120  // find the closest closest matching definition
7122  Definition *d;
7123  for (dli.toFirst();(d=dli.current());++dli)
7124  {
7126  {
7127  g_visitedNamespaces.clear();
7128  int distance = isAccessibleFromWithExpScope(scope,fileScope,d,explicitScopePart);
7129  if (distance!=-1 && distance<minDistance)
7130  {
7131  minDistance = distance;
7132  bestMatch = (MemberDef *)d;
7133  //printf("new best match %s distance=%d\n",bestMatch->qualifiedName().data(),distance);
7134  }
7135  }
7136  }
7137  }
7138  else if (di->definitionType()==Definition::TypeMember)
7139  {
7140  //printf("unique match!\n");
7141  Definition *d = (Definition *)di;
7142  g_visitedNamespaces.clear();
7143  int distance = isAccessibleFromWithExpScope(scope,fileScope,d,explicitScopePart);
7144  if (distance!=-1 && distance<minDistance)
7145  {
7146  minDistance = distance;
7147  bestMatch = (MemberDef *)d;
7148  //printf("new best match %s distance=%d\n",bestMatch->qualifiedName().data(),distance);
7149  }
7150  }
7151  return bestMatch;
7152 }
7153 
7154 /*! Returns true iff the given name string appears to be a typedef in scope. */
7155 bool checkIfTypedef(Definition *scope,FileDef *fileScope,const char *n)
7156 {
7157  MemberDef *bestMatch = getMemberFromSymbol(scope,fileScope,n);
7158 
7159  if (bestMatch && bestMatch->isTypedef())
7160  return TRUE; // closest matching symbol is a typedef
7161  else
7162  return FALSE;
7163 }
7164 
7165 const char *writeUtf8Char(FTextStream &t,const char *s)
7166 {
7167  char c=*s++;
7168  t << c;
7169  if (c<0) // multibyte character
7170  {
7171  if (((uchar)c&0xE0)==0xC0)
7172  {
7173  t << *s++; // 11xx.xxxx: >=2 byte character
7174  }
7175  if (((uchar)c&0xF0)==0xE0)
7176  {
7177  t << *s++; // 111x.xxxx: >=3 byte character
7178  }
7179  if (((uchar)c&0xF8)==0xF0)
7180  {
7181  t << *s++; // 1111.xxxx: >=4 byte character
7182  }
7183  if (((uchar)c&0xFC)==0xF8)
7184  {
7185  t << *s++; // 1111.1xxx: >=5 byte character
7186  }
7187  if (((uchar)c&0xFE)==0xFC)
7188  {
7189  t << *s++; // 1111.1xxx: 6 byte character
7190  }
7191  }
7192  return s;
7193 }
7194 
7195 int nextUtf8CharPosition(const QCString &utf8Str,int len,int startPos)
7196 {
7197  int bytes=1;
7198  if (startPos>=len) return len;
7199  char c = utf8Str[startPos];
7200  if (c<0) // multibyte utf-8 character
7201  {
7202  if (((uchar)c&0xE0)==0xC0)
7203  {
7204  bytes++; // 11xx.xxxx: >=2 byte character
7205  }
7206  if (((uchar)c&0xF0)==0xE0)
7207  {
7208  bytes++; // 111x.xxxx: >=3 byte character
7209  }
7210  if (((uchar)c&0xF8)==0xF0)
7211  {
7212  bytes++; // 1111.xxxx: >=4 byte character
7213  }
7214  if (((uchar)c&0xFC)==0xF8)
7215  {
7216  bytes++; // 1111.1xxx: >=5 byte character
7217  }
7218  if (((uchar)c&0xFE)==0xFC)
7219  {
7220  bytes++; // 1111.1xxx: 6 byte character
7221  }
7222  }
7223  else if (c=='&') // skip over character entities
7224  {
7225  static QRegExp re1("&#[0-9]+;"); // numerical entity
7226  static QRegExp re2("&[A-Z_a-z]+;"); // named entity
7227  int l1,l2;
7228  int i1 = re1.match(utf8Str,startPos,&l1);
7229  int i2 = re2.match(utf8Str,startPos,&l2);
7230  if (i1!=-1)
7231  {
7232  bytes=l1;
7233  }
7234  else if (i2!=-1)
7235  {
7236  bytes=l2;
7237  }
7238  }
7239  return startPos+bytes;
7240 }
7241 
7243  const QCString &doc,const QCString &fileName,int lineNr)
7244 {
7245  QGString s;
7246  if (doc.isEmpty()) return s.data();
7247  FTextStream t(&s);
7248  DocNode *root = validatingParseDoc(fileName,lineNr,
7249  (Definition*)scope,(MemberDef*)md,doc,FALSE,FALSE);
7250  TextDocVisitor *visitor = new TextDocVisitor(t);
7251  root->accept(visitor);
7252  delete visitor;
7253  delete root;
7255  int i=0;
7256  int charCnt=0;
7257  int l=result.length();
7258  bool addEllipsis=FALSE;
7259  while ((i=nextUtf8CharPosition(result,l,i))<l)
7260  {
7261  charCnt++;
7262  if (charCnt>=80) break;
7263  }
7264  if (charCnt>=80) // try to truncate the string
7265  {
7266  while ((i=nextUtf8CharPosition(result,l,i))<l && charCnt<100)
7267  {
7268  charCnt++;
7269  if (result.at(i)>=0 && isspace(result.at(i)))
7270  {
7271  addEllipsis=TRUE;
7272  }
7273  else if (result.at(i)==',' ||
7274  result.at(i)=='.' ||
7275  result.at(i)=='?')
7276  {
7277  break;
7278  }
7279  }
7280  }
7281  if (addEllipsis || charCnt==100) result=result.left(i)+"...";
7282  return result.data();
7283 }
7284 
7285 //--------------------------------------------------------------------------------------
7286 
7287 static QDict<void> aliasesProcessed;
7288 
7289 static QCString expandAliasRec(const QCString s,bool allowRecursion=FALSE);
7290 
7291 struct Marker
7292 {
7293  Marker(int p, int n,int s) : pos(p),number(n),size(s) {}
7294  int pos; // position in the string
7295  int number; // argument number
7296  int size; // size of the marker
7297 };
7298 
7299 /** For a string \a s that starts with a command name, returns the character
7300  * offset within that string representing the first character after the
7301  * command. For an alias with argument, this is the offset to the
7302  * character just after the argument list.
7303  *
7304  * Examples:
7305  * - s=="a b" returns 1
7306  * - s=="a{2,3} b" returns 6
7307  * = s=="#" returns 0
7308  */
7309 static int findEndOfCommand(const char *s)
7310 {
7311  const char *p = s;
7312  char c;
7313  int i=0;
7314  if (p)
7315  {
7316  while ((c=*p) && isId(c)) p++;
7317  if (c=='{')
7318  {
7320  i+=args.length();
7321  }
7322  i+=p-s;
7323  }
7324  return i;
7325 }
7326 
7327 /** Replaces the markers in an alias definition \a aliasValue
7328  * with the corresponding values found in the comma separated argument
7329  * list \a argList and the returns the result after recursive alias expansion.
7330  */
7331 static QCString replaceAliasArguments(const QCString &aliasValue,const QCString &argList)
7332 {
7333  //printf("----- replaceAliasArguments(val=[%s],args=[%s])\n",aliasValue.data(),argList.data());
7334 
7335  // first make a list of arguments from the comma separated argument list
7337  args.setAutoDelete(TRUE);
7338  int i,l=(int)argList.length();
7339  int s=0;
7340  for (i=0;i<l;i++)
7341  {
7342  char c = argList.at(i);
7343  if (c==',' && (i==0 || argList.at(i-1)!='\\'))
7344  {
7345  args.append(new QCString(argList.mid(s,i-s)));
7346  s=i+1; // start of next argument
7347  }
7348  else if (c=='@' || c=='\\')
7349  {
7350  // check if this is the start of another aliased command (see bug704172)
7351  i+=findEndOfCommand(argList.data()+i+1);
7352  }
7353  }
7354  if (l>s) args.append(new QCString(argList.right(l-s)));
7355  //printf("found %d arguments\n",args.count());
7356 
7357  // next we look for the positions of the markers and add them to a list
7358  QList<Marker> markerList;
7359  markerList.setAutoDelete(TRUE);
7360  l = aliasValue.length();
7361  int markerStart=0;
7362  int markerEnd=0;
7363  for (i=0;i<l;i++)
7364  {
7365  if (markerStart==0 && aliasValue.at(i)=='\\') // start of a \xx marker
7366  {
7367  markerStart=i+1;
7368  }
7369  else if (markerStart>0 && aliasValue.at(i)>='0' && aliasValue.at(i)<='9')
7370  {
7371  // read digit that make up the marker number
7372  markerEnd=i+1;
7373  }
7374  else
7375  {
7376  if (markerStart>0 && markerEnd>markerStart) // end of marker
7377  {
7378  int markerLen = markerEnd-markerStart;
7379  markerList.append(new Marker(markerStart-1, // include backslash
7380  atoi(aliasValue.mid(markerStart,markerLen)),markerLen+1));
7381  //printf("found marker at %d with len %d and number %d\n",
7382  // markerStart-1,markerLen+1,atoi(aliasValue.mid(markerStart,markerLen)));
7383  }
7384  markerStart=0; // outside marker
7385  markerEnd=0;
7386  }
7387  }
7388  if (markerStart>0)
7389  {
7390  markerEnd=l;
7391  }
7392  if (markerStart>0 && markerEnd>markerStart)
7393  {
7394  int markerLen = markerEnd-markerStart;
7395  markerList.append(new Marker(markerStart-1, // include backslash
7396  atoi(aliasValue.mid(markerStart,markerLen)),markerLen+1));
7397  //printf("found marker at %d with len %d and number %d\n",
7398  // markerStart-1,markerLen+1,atoi(aliasValue.mid(markerStart,markerLen)));
7399  }
7400 
7401  // then we replace the markers with the corresponding arguments in one pass
7402  QCString result;
7403  int p=0;
7404  for (i=0;i<(int)markerList.count();i++)
7405  {
7406  Marker *m = markerList.at(i);
7407  result+=aliasValue.mid(p,m->pos-p);
7408  //printf("part before marker %d: '%s'\n",i,aliasValue.mid(p,m->pos-p).data());
7409  if (m->number>0 && m->number<=(int)args.count()) // valid number
7410  {
7411  result+=expandAliasRec(*args.at(m->number-1),TRUE);
7412  //printf("marker index=%d pos=%d number=%d size=%d replacement %s\n",i,m->pos,m->number,m->size,
7413  // args.at(m->number-1)->data());
7414  }
7415  p=m->pos+m->size; // continue after the marker
7416  }
7417  result+=aliasValue.right(l-p); // append remainder
7418  //printf("string after replacement of markers: '%s'\n",result.data());
7419 
7420  // expand the result again
7421  result = substitute(result,"\\{","{");
7422  result = substitute(result,"\\}","}");
7423  result = expandAliasRec(substitute(result,"\\,",","));
7424 
7425  return result;
7426 }
7427 
7429 {
7430  QGString result;
7431  const char *p = s.data();
7432  char c,pc=0;
7433  while ((c=*p++))
7434  {
7435  if (c==',' && pc!='\\')
7436  {
7437  result+="\\,";
7438  }
7439  else
7440  {
7441  result+=c;
7442  }
7443  pc=c;
7444  }
7445  result+='\0';
7446  //printf("escapeCommas: '%s'->'%s'\n",s.data(),result.data());
7447  return result.data();
7448 }
7449 
7450 static QCString expandAliasRec(const QCString s,bool allowRecursion)
7451 {
7452  QCString result;
7453  static QRegExp cmdPat("[\\\\@][a-z_A-Z][a-z_A-Z0-9]*");
7454  QCString value=s;
7455  int i,p=0,l;
7456  while ((i=cmdPat.match(value,p,&l))!=-1)
7457  {
7458  result+=value.mid(p,i-p);
7459  QCString args = extractAliasArgs(value,i+l);
7460  bool hasArgs = !args.isEmpty(); // found directly after command
7461  int argsLen = args.length();
7462  QCString cmd = value.mid(i+1,l-1);
7463  QCString cmdNoArgs = cmd;
7464  int numArgs=0;
7465  if (hasArgs)
7466  {
7467  numArgs = countAliasArguments(args);
7468  cmd += QCString().sprintf("{%d}",numArgs); // alias name + {n}
7469  }
7470  QCString *aliasText=Doxygen::aliasDict.find(cmd);
7471  if (numArgs>1 && aliasText==0)
7472  { // in case there is no command with numArgs parameters, but there is a command with 1 parameter,
7473  // we also accept all text as the argument of that command (so you don't have to escape commas)
7474  aliasText=Doxygen::aliasDict.find(cmdNoArgs+"{1}");
7475  if (aliasText)
7476  {
7477  cmd = cmdNoArgs+"{1}";
7478  args = escapeCommas(args); // escape , so that everything is seen as one argument
7479  }
7480  }
7481  //printf("Found command s='%s' cmd='%s' numArgs=%d args='%s' aliasText=%s\n",
7482  // s.data(),cmd.data(),numArgs,args.data(),aliasText?aliasText->data():"<none>");
7483  if ((allowRecursion || aliasesProcessed.find(cmd)==0) && aliasText) // expand the alias
7484  {
7485  //printf("is an alias!\n");
7486  if (!allowRecursion) aliasesProcessed.insert(cmd,(void *)0x8);
7487  QCString val = *aliasText;
7488  if (hasArgs)
7489  {
7490  val = replaceAliasArguments(val,args);
7491  //printf("replace '%s'->'%s' args='%s'\n",
7492  // aliasText->data(),val.data(),args.data());
7493  }
7494  result+=expandAliasRec(val);
7495  if (!allowRecursion) aliasesProcessed.remove(cmd);
7496  p=i+l;
7497  if (hasArgs) p+=argsLen+2;
7498  }
7499  else // command is not an alias
7500  {
7501  //printf("not an alias!\n");
7502  result+=value.mid(i,l);
7503  p=i+l;
7504  }
7505  }
7506  result+=value.right(value.length()-p);
7507 
7508  //printf("expandAliases '%s'->'%s'\n",s.data(),result.data());
7509  return result;
7510 }
7511 
7512 
7513 int countAliasArguments(const QCString argList)
7514 {
7515  int count=1;
7516  int l = argList.length();
7517  int i;
7518  for (i=0;i<l;i++)
7519  {
7520  char c = argList.at(i);
7521  if (c==',' && (i==0 || argList.at(i-1)!='\\')) count++;
7522  else if (c=='@' || c=='\\')
7523  {
7524  // check if this is the start of another aliased command (see bug704172)
7525  i+=findEndOfCommand(argList.data()+i+1);
7526  }
7527  }
7528  //printf("countAliasArguments=%d\n",count);
7529  return count;
7530 }
7531 
7533 {
7534  int i;
7535  int bc=0;
7536  char prevChar=0;
7537  if (args.at(pos)=='{') // alias has argument
7538  {
7539  for (i=pos;i<(int)args.length();i++)
7540  {
7541  if (prevChar!='\\')
7542  {
7543  if (args.at(i)=='{') bc++;
7544  if (args.at(i)=='}') bc--;
7545  prevChar=args.at(i);
7546  }
7547  else
7548  {
7549  prevChar=0;
7550  }
7551 
7552  if (bc==0)
7553  {
7554  //printf("extractAliasArgs('%s')->'%s'\n",args.data(),args.mid(pos+1,i-pos-1).data());
7555  return args.mid(pos+1,i-pos-1);
7556  }
7557  }
7558  }
7559  return "";
7560 }
7561 
7563 {
7564  QCString result;
7565  aliasesProcessed.clear();
7566  //printf("Expanding: '%s'\n",aliasCmd.data());
7567  result = expandAliasRec(aliasCmd);
7568  //printf("Expanding result: '%s'->'%s'\n",aliasCmd.data(),result.data());
7569  return result;
7570 }
7571 
7573 {
7574  QCString result;
7575  aliasesProcessed.clear();
7576  // avoid expanding this command recursively
7577  aliasesProcessed.insert(aliasName,(void *)0x8);
7578  // expand embedded commands
7579  //printf("Expanding: '%s'->'%s'\n",aliasName.data(),aliasValue.data());
7580  result = expandAliasRec(aliasValue);
7581  //printf("Expanding result: '%s'->'%s'\n",aliasName.data(),result.data());
7582  return result;
7583 }
7584 
7586 {
7587  if (al==0) return;
7589  ArgumentListIterator ali(*al);
7590  Argument *a;
7591  for (;(a=ali.current());++ali)
7592  {
7593  ol.startConstraintParam();
7594  ol.parseText(a->name);
7595  ol.endConstraintParam();
7596  ol.startConstraintType();
7597  linkifyText(TextGeneratorOLImpl(ol),d,0,0,a->type);
7598  ol.endConstraintType();
7599  ol.startConstraintDocs();
7600  ol.generateDoc(d->docFile(),d->docLine(),d,0,a->docs,TRUE,FALSE);
7601  ol.endConstraintDocs();
7602  }
7603  ol.endConstraintList();
7604 }
7605 
7606 //----------------------------------------------------------------------------
7607 
7609 {
7610 #ifdef TRACINGSUPPORT
7611  void *backtraceFrames[128];
7612  int frameCount = backtrace(backtraceFrames, 128);
7613  static char cmd[40960];
7614  char *p = cmd;
7615  p += sprintf(p,"/usr/bin/atos -p %d ", (int)getpid());
7616  for (int x = 0; x < frameCount; x++)
7617  {
7618  p += sprintf(p,"%p ", backtraceFrames[x]);
7619  }
7620  fprintf(stderr,"========== STACKTRACE START ==============\n");
7621  if (FILE *fp = popen(cmd, "r"))
7622  {
7623  char resBuf[512];
7624  while (size_t len = fread(resBuf, 1, sizeof(resBuf), fp))
7625  {
7626  fwrite(resBuf, 1, len, stderr);
7627  }
7628  pclose(fp);
7629  }
7630  fprintf(stderr,"============ STACKTRACE END ==============\n");
7631  //fprintf(stderr,"%s\n", frameStrings[x]);
7632 #endif
7633 }
7634 
7635 static int transcodeCharacterBuffer(const char *fileName,BufStr &srcBuf,int size,
7636  const char *inputEncoding,const char *outputEncoding)
7637 {
7638  if (inputEncoding==0 || outputEncoding==0) return size;
7639  if (qstricmp(inputEncoding,outputEncoding)==0) return size;
7640  void *cd = portable_iconv_open(outputEncoding,inputEncoding);
7641  if (cd==(void *)(-1))
7642  {
7643  err("unsupported character conversion: '%s'->'%s': %s\n"
7644  "Check the INPUT_ENCODING setting in the config file!\n",
7645  inputEncoding,outputEncoding,strerror(errno));
7646  exit(1);
7647  }
7648  int tmpBufSize=size*4+1;
7649  BufStr tmpBuf(tmpBufSize);
7650  size_t iLeft=size;
7651  size_t oLeft=tmpBufSize;
7652  char *srcPtr = srcBuf.data();
7653  char *dstPtr = tmpBuf.data();
7654  uint newSize=0;
7655  if (!portable_iconv(cd, &srcPtr, &iLeft, &dstPtr, &oLeft))
7656  {
7657  newSize = tmpBufSize-(int)oLeft;
7658  srcBuf.shrink(newSize);
7659  strncpy(srcBuf.data(),tmpBuf.data(),newSize);
7660  //printf("iconv: input size=%d output size=%d\n[%s]\n",size,newSize,srcBuf.data());
7661  }
7662  else
7663  {
7664  err("%s: failed to translate characters from %s to %s: check INPUT_ENCODING\n",
7665  fileName,inputEncoding,outputEncoding);
7666  exit(1);
7667  }
7669  return newSize;
7670 }
7671 
7672 //! read a file name \a fileName and optionally filter and transcode it
7673 bool readInputFile(const char *fileName,BufStr &inBuf,bool filter,bool isSourceCode)
7674 {
7675  // try to open file
7676  int size=0;
7677  //uint oldPos = dest.curPos();
7678  //printf(".......oldPos=%d\n",oldPos);
7679 
7680  QFileInfo fi(fileName);
7681  if (!fi.exists()) return FALSE;
7682  QCString filterName = getFileFilter(fileName,isSourceCode);
7683  if (filterName.isEmpty() || !filter)
7684  {
7685  QFile f(fileName);
7686  if (!f.open(IO_ReadOnly))
7687  {
7688  err("could not open file %s\n",fileName);
7689  return FALSE;
7690  }
7691  size=fi.size();
7692  // read the file
7693  inBuf.skip(size);
7694  if (f.readBlock(inBuf.data()/*+oldPos*/,size)!=size)
7695  {
7696  err("problems while reading file %s\n",fileName);
7697  return FALSE;
7698  }
7699  }
7700  else
7701  {
7702  QCString cmd=filterName+" \""+fileName+"\"";
7703  Debug::print(Debug::ExtCmd,0,"Executing popen(`%s`)\n",qPrint(cmd));
7704  FILE *f=portable_popen(cmd,"r");
7705  if (!f)
7706  {
7707  err("could not execute filter %s\n",filterName.data());
7708  return FALSE;
7709  }
7710  const int bufSize=1024;
7711  char buf[bufSize];
7712  int numRead;
7713  while ((numRead=(int)fread(buf,1,bufSize,f))>0)
7714  {
7715  //printf(">>>>>>>>Reading %d bytes\n",numRead);
7716  inBuf.addArray(buf,numRead),size+=numRead;
7717  }
7718  portable_pclose(f);
7719  inBuf.at(inBuf.curPos()) ='\0';
7720  Debug::print(Debug::FilterOutput, 0, "Filter output\n");
7721  Debug::print(Debug::FilterOutput,0,"-------------\n%s\n-------------\n",qPrint(inBuf));
7722  }
7723 
7724  int start=0;
7725  if (size>=2 &&
7726  ((inBuf.at(0)==-1 && inBuf.at(1)==-2) || // Litte endian BOM
7727  (inBuf.at(0)==-2 && inBuf.at(1)==-1) // big endian BOM
7728  )
7729  ) // UCS-2 encoded file
7730  {
7731  transcodeCharacterBuffer(fileName,inBuf,inBuf.curPos(),
7732  "UCS-2","UTF-8");
7733  }
7734  else if (size>=3 &&
7735  (uchar)inBuf.at(0)==0xEF &&
7736  (uchar)inBuf.at(1)==0xBB &&
7737  (uchar)inBuf.at(2)==0xBF
7738  ) // UTF-8 encoded file
7739  {
7740  inBuf.dropFromStart(3); // remove UTF-8 BOM: no translation needed
7741  }
7742  else // transcode according to the INPUT_ENCODING setting
7743  {
7744  // do character transcoding if needed.
7745  transcodeCharacterBuffer(fileName,inBuf,inBuf.curPos(),
7746  Config_getString("INPUT_ENCODING"),"UTF-8");
7747  }
7748 
7749  //inBuf.addChar('\n'); /* to prevent problems under Windows ? */
7750 
7751  // and translate CR's
7752  size=inBuf.curPos()-start;
7753  int newSize=filterCRLF(inBuf.data()+start,size);
7754  //printf("filter char at %p size=%d newSize=%d\n",dest.data()+oldPos,size,newSize);
7755  if (newSize!=size) // we removed chars
7756  {
7757  inBuf.shrink(newSize); // resize the array
7758  //printf(".......resizing from %d to %d result=[%s]\n",oldPos+size,oldPos+newSize,dest.data());
7759  }
7760  inBuf.addChar(0);
7761  return TRUE;
7762 }
7763 
7764 // Replace %word by word in title
7766 {
7767  QCString tf;
7768  static QRegExp re("%[A-Z_a-z]");
7769  int p=0,i,l;
7770  while ((i=re.match(title,p,&l))!=-1)
7771  {
7772  tf+=title.mid(p,i-p);
7773  tf+=title.mid(i+1,l-1); // skip %
7774  p=i+l;
7775  }
7776  tf+=title.right(title.length()-p);
7777  return tf;
7778 }
7779 
7780 //----------------------------------------------------------------------------
7781 // returns TRUE if the name of the file represented by `fi' matches
7782 // one of the file patterns in the `patList' list.
7783 
7784 bool patternMatch(const QFileInfo &fi,const QStrList *patList)
7785 {
7786  bool found=FALSE;
7787  if (patList)
7788  {
7789  QStrListIterator it(*patList);
7790  QCString pattern;
7791 
7792  QCString fn = fi.fileName().data();
7793  QCString fp = fi.filePath().data();
7794  QCString afp= fi.absFilePath().data();
7795 
7796  for (it.toFirst();(pattern=it.current());++it)
7797  {
7798  if (!pattern.isEmpty())
7799  {
7800  int i=pattern.find('=');
7801  if (i!=-1) pattern=pattern.left(i); // strip of the extension specific filter name
7802 
7803 #if defined(_WIN32) || defined(__MACOSX__) // Windows or MacOSX
7804  QRegExp re(pattern,FALSE,TRUE); // case insensitive match
7805 #else // unix
7806  QRegExp re(pattern,TRUE,TRUE); // case sensitive match
7807 #endif
7808  found = re.match(fn)!=-1 ||
7809  re.match(fp)!=-1 ||
7810  re.match(afp)!=-1;
7811  if (found) break;
7812  //printf("Matching `%s' against pattern `%s' found=%d\n",
7813  // fi->fileName().data(),pattern.data(),found);
7814  }
7815  }
7816  }
7817  return found;
7818 }
7819 
7820 #if 0 // move to HtmlGenerator::writeSummaryLink
7821 void writeSummaryLink(OutputList &ol,const char *label,const char *title,
7822  bool &first,const char *file)
7823 {
7824  if (first)
7825  {
7826  ol.writeString(" <div class=\"summary\">\n");
7827  first=FALSE;
7828  }
7829  else
7830  {
7831  ol.writeString(" &#124;\n");
7832  }
7833  if (file)
7834  {
7835  ol.writeString("<a href=\"");
7836  ol.writeString(file);
7838  }
7839  else
7840  {
7841  ol.writeString("<a href=\"#");
7842  ol.writeString(label);
7843  }
7844  ol.writeString("\">");
7845  ol.writeString(title);
7846  ol.writeString("</a>");
7847 }
7848 #endif
7849 
7851 {
7852  static bool extLinksInWindow = Config_getBool("EXT_LINKS_IN_WINDOW");
7853  if (extLinksInWindow) return "target=\"_blank\" "; else return "";
7854 }
7855 
7856 QCString externalRef(const QCString &relPath,const QCString &ref,bool href)
7857 {
7858  QCString result;
7859  if (!ref.isEmpty())
7860  {
7862  if (dest)
7863  {
7864  result = *dest;
7865  int l = result.length();
7866  if (!relPath.isEmpty() && l>0 && result.at(0)=='.')
7867  { // relative path -> prepend relPath.
7868  result.prepend(relPath);
7869  l+=relPath.length();
7870  }
7871  if (!href){
7872  result.prepend("doxygen=\""+ref+":");
7873  l+=10+ref.length();
7874  }
7875  if (l>0 && result.at(l-1)!='/') result+='/';
7876  if (!href) result.append("\" ");
7877  }
7878  }
7879  else
7880  {
7881  result = relPath;
7882  }
7883  return result;
7884 }
7885 
7886 /** Writes the intensity only bitmap representated by \a data as an image to
7887  * directory \a dir using the colors defined by HTML_COLORSTYLE_*.
7888  */
7890 {
7891  static int hue = Config_getInt("HTML_COLORSTYLE_HUE");
7892  static int sat = Config_getInt("HTML_COLORSTYLE_SAT");
7893  static int gamma = Config_getInt("HTML_COLORSTYLE_GAMMA");
7894  while (data->name)
7895  {
7897  fileName=(QCString)dir+"/"+data->name;
7898  QFile f(fileName);
7899  if (f.open(IO_WriteOnly))
7900  {
7901  ColoredImage img(data->width,data->height,data->content,data->alpha,
7902  sat,hue,gamma);
7903  img.save(fileName);
7904  }
7905  else
7906  {
7907  fprintf(stderr,"Warning: Cannot open file %s for writing\n",data->name);
7908  }
7910  data++;
7911  }
7912 }
7913 
7914 /** Replaces any markers of the form \#\#AA in input string \a str
7915  * by new markers of the form \#AABBCC, where \#AABBCC represents a
7916  * valid color, based on the intensity represented by hex number AA
7917  * and the current HTML_COLORSTYLE_* settings.
7918  */
7920 {
7921  QCString result;
7922  QCString s=str;
7923  if (s.isEmpty()) return result;
7924  static QRegExp re("##[0-9A-Fa-f][0-9A-Fa-f]");
7925  static const char hex[] = "0123456789ABCDEF";
7926  static int hue = Config_getInt("HTML_COLORSTYLE_HUE");
7927  static int sat = Config_getInt("HTML_COLORSTYLE_SAT");
7928  static int gamma = Config_getInt("HTML_COLORSTYLE_GAMMA");
7929  int i,l,sl=s.length(),p=0;
7930  while ((i=re.match(s,p,&l))!=-1)
7931  {
7932  result+=s.mid(p,i-p);
7933  QCString lumStr = s.mid(i+2,l-2);
7934 #define HEXTONUM(x) (((x)>='0' && (x)<='9') ? ((x)-'0') : \
7935  ((x)>='a' && (x)<='f') ? ((x)-'a'+10) : \
7936  ((x)>='A' && (x)<='F') ? ((x)-'A'+10) : 0)
7937 
7938  double r,g,b;
7939  int red,green,blue;
7940  int level = HEXTONUM(lumStr[0])*16+HEXTONUM(lumStr[1]);
7941  ColoredImage::hsl2rgb(hue/360.0,sat/255.0,
7942  pow(level/255.0,gamma/100.0),&r,&g,&b);
7943  red = (int)(r*255.0);
7944  green = (int)(g*255.0);
7945  blue = (int)(b*255.0);
7946  char colStr[8];
7947  colStr[0]='#';
7948  colStr[1]=hex[red>>4];
7949  colStr[2]=hex[red&0xf];
7950  colStr[3]=hex[green>>4];
7951  colStr[4]=hex[green&0xf];
7952  colStr[5]=hex[blue>>4];
7953  colStr[6]=hex[blue&0xf];
7954  colStr[7]=0;
7955  //printf("replacing %s->%s (level=%d)\n",lumStr.data(),colStr,level);
7956  result+=colStr;
7957  p=i+l;
7958  }
7959  result+=s.right(sl-p);
7960  return result;
7961 }
7962 
7963 /** Copies the contents of file with name \a src to the newly created
7964  * file with name \a dest. Returns TRUE if successful.
7965  */
7966 bool copyFile(const QCString &src,const QCString &dest)
7967 {
7968  QFile sf(src);
7969  if (sf.open(IO_ReadOnly))
7970  {
7971  QFileInfo fi(src);
7972  QFile df(dest);
7973  if (df.open(IO_WriteOnly))
7974  {
7975  char *buffer = new char[fi.size()];
7976  sf.readBlock(buffer,fi.size());
7977  df.writeBlock(buffer,fi.size());
7978  df.flush();
7979  delete[] buffer;
7980  }
7981  else
7982  {
7983  err("could not write to file %s\n",dest.data());
7984  return FALSE;
7985  }
7986  }
7987  else
7988  {
7989  err("could not open user specified file %s\n",src.data());
7990  return FALSE;
7991  }
7992  return TRUE;
7993 }
7994 
7995 /** Returns the section of text, in between a pair of markers.
7996  * Full lines are returned, excluding the lines on which the markers appear.
7997  */
7998 QCString extractBlock(const QCString text,const QCString marker)
7999 {
8000  QCString result;
8001  int p=0,i;
8002  bool found=FALSE;
8003 
8004  // find the character positions of the markers
8005  int m1 = text.find(marker);
8006  if (m1==-1) return result;
8007  int m2 = text.find(marker,m1+marker.length());
8008  if (m2==-1) return result;
8009 
8010  // find start and end line positions for the markers
8011  int l1=-1,l2=-1;
8012  while (!found && (i=text.find('\n',p))!=-1)
8013  {
8014  found = (p<=m1 && m1<i); // found the line with the start marker
8015  p=i+1;
8016  }
8017  l1=p;
8018  int lp=i;
8019  if (found)
8020  {
8021  while ((i=text.find('\n',p))!=-1)
8022  {
8023  if (p<=m2 && m2<i) // found the line with the end marker
8024  {
8025  l2=p;
8026  break;
8027  }
8028  p=i+1;
8029  lp=i;
8030  }
8031  }
8032  if (l2==-1) // marker at last line without newline (see bug706874)
8033  {
8034  l2=lp;
8035  }
8036  //printf("text=[%s]\n",text.mid(l1,l2-l1).data());
8037  return l2>l1 ? text.mid(l1,l2-l1) : QCString();
8038 }
8039 
8040 /** Returns a string representation of \a lang. */
8042 {
8043  switch(lang)
8044  {
8045  case SrcLangExt_Unknown: return "Unknown";
8046  case SrcLangExt_IDL: return "IDL";
8047  case SrcLangExt_Java: return "Java";
8048  case SrcLangExt_CSharp: return "C#";
8049  case SrcLangExt_D: return "D";
8050  case SrcLangExt_PHP: return "PHP";
8051  case SrcLangExt_ObjC: return "Objective-C";
8052  case SrcLangExt_Cpp: return "C++";
8053  case SrcLangExt_JS: return "Javascript";
8054  case SrcLangExt_Python: return "Python";
8055  case SrcLangExt_Fortran: return "Fortran";
8056  case SrcLangExt_VHDL: return "VHDL";
8057  case SrcLangExt_XML: return "XML";
8058  case SrcLangExt_Tcl: return "Tcl";
8059  case SrcLangExt_Markdown: return "Markdown";
8060  }
8061  return "Unknown";
8062 }
8063 
8064 /** Returns the scope separator to use given the programming language \a lang */
8066 {
8067  if (lang==SrcLangExt_Java || lang==SrcLangExt_CSharp || lang==SrcLangExt_VHDL || lang==SrcLangExt_Python)
8068  {
8069  return ".";
8070  }
8071  else if (lang==SrcLangExt_PHP && !classScope)
8072  {
8073  return "\\";
8074  }
8075  else
8076  {
8077  return "::";
8078  }
8079 }
8080 
8081 /** Corrects URL \a url according to the relative path \a relPath.
8082  * Returns the corrected URL. For absolute URLs no correction will be done.
8083  */
8084 QCString correctURL(const QCString &url,const QCString &relPath)
8085 {
8086  QCString result = url;
8087  if (!relPath.isEmpty() &&
8088  url.left(5)!="http:" && url.left(6)!="https:" &&
8089  url.left(4)!="ftp:" && url.left(5)!="file:")
8090  {
8091  result.prepend(relPath);
8092  }
8093  return result;
8094 }
8095 
8096 //---------------------------------------------------------------------------
8097 
8099 {
8100  static bool extractPrivate = Config_getBool("EXTRACT_PRIVATE");
8101  static bool extractPackage = Config_getBool("EXTRACT_PACKAGE");
8102 
8103  return (prot!=Private && prot!=Package) ||
8104  (prot==Private && extractPrivate) ||
8105  (prot==Package && extractPackage);
8106 }
8107 
8108 //---------------------------------------------------------------------------
8109 
8111 {
8112  if (s.isEmpty()) return s; // empty string -> we're done
8113 
8114  //printf("stripIndentation:\n%s\n------\n",s.data());
8115  // compute minimum indentation over all lines
8116  const char *p=s.data();
8117  char c;
8118  int indent=0;
8119  int minIndent=1000000; // "infinite"
8120  bool searchIndent=TRUE;
8121  static int tabSize=Config_getInt("TAB_SIZE");
8122  while ((c=*p++))
8123  {
8124  if (c=='\t') indent+=tabSize - (indent%tabSize);
8125  else if (c=='\n') indent=0,searchIndent=TRUE;
8126  else if (c==' ') indent++;
8127  else if (searchIndent)
8128  {
8129  searchIndent=FALSE;
8130  if (indent<minIndent) minIndent=indent;
8131  }
8132  }
8133 
8134  // no indent to remove -> we're done
8135  if (minIndent==0) return s;
8136 
8137  // remove minimum indentation for each line
8138  QGString result;
8139  p=s.data();
8140  indent=0;
8141  while ((c=*p++))
8142  {
8143  if (c=='\n') // start of new line
8144  {
8145  indent=0;
8146  result+=c;
8147  }
8148  else if (indent<minIndent) // skip until we reach minIndent
8149  {
8150  if (c=='\t')
8151  {
8152  int newIndent = indent+tabSize-(indent%tabSize);
8153  int i=newIndent;
8154  while (i>minIndent) // if a tab crosses the minIndent boundary fill the rest with spaces
8155  {
8156  result+=' ';
8157  i--;
8158  }
8159  indent=newIndent;
8160  }
8161  else // space
8162  {
8163  indent++;
8164  }
8165  }
8166  else // copy anything until the end of the line
8167  {
8168  result+=c;
8169  }
8170  }
8171 
8172  result+='\0';
8173  return result.data();
8174 }
8175 
8176 
8177 bool fileVisibleInIndex(FileDef *fd,bool &genSourceFile)
8178 {
8179  static bool allExternals = Config_getBool("ALLEXTERNALS");
8180  bool isDocFile = fd->isDocumentationFile();
8181  genSourceFile = !isDocFile && fd->generateSourceFile();
8182  return ( ((allExternals && fd->isLinkable()) ||
8183  fd->isLinkableInProject()
8184  ) &&
8185  !isDocFile
8186  );
8187 }
8188 
8190 {
8191  static bool referencedByRelation = Config_getBool("REFERENCED_BY_RELATION");
8192  static bool referencesRelation = Config_getBool("REFERENCES_RELATION");
8193 
8194  //printf("--> addDocCrossReference src=%s,dst=%s\n",src->name().data(),dst->name().data());
8195  if (dst->isTypedef() || dst->isEnumerate()) return; // don't add types
8196  if ((referencedByRelation || dst->hasCallerGraph()) &&
8197  src->showInCallGraph()
8198  )
8199  {
8200  dst->addSourceReferencedBy(src);
8201  MemberDef *mdDef = dst->memberDefinition();
8202  if (mdDef)
8203  {
8204  mdDef->addSourceReferencedBy(src);
8205  }
8206  MemberDef *mdDecl = dst->memberDeclaration();
8207  if (mdDecl)
8208  {
8209  mdDecl->addSourceReferencedBy(src);
8210  }
8211  }
8212  if ((referencesRelation || src->hasCallGraph()) &&
8213  src->showInCallGraph()
8214  )
8215  {
8216  src->addSourceReferences(dst);
8217  MemberDef *mdDef = src->memberDefinition();
8218  if (mdDef)
8219  {
8220  mdDef->addSourceReferences(dst);
8221  }
8222  MemberDef *mdDecl = src->memberDeclaration();
8223  if (mdDecl)
8224  {
8225  mdDecl->addSourceReferences(dst);
8226  }
8227  }
8228 }
8229 
8230 //--------------------------------------------------------------------------------------
8231 
8232 /*! @brief Get one unicode character as an unsigned integer from utf-8 string
8233  *
8234  * @param s utf-8 encoded string
8235  * @param idx byte position of given string \a s.
8236  * @return the unicode codepoint, 0 - MAX_UNICODE_CODEPOINT
8237  * @see getNextUtf8OrToLower()
8238  * @see getNextUtf8OrToUpper()
8239  */
8240 uint getUtf8Code( const QCString& s, int idx )
8241 {
8242  const int length = s.length();
8243  if (idx >= length) { return 0; }
8244  const uint c0 = (uchar)s.at(idx);
8245  if ( c0 < 0xC2 || c0 >= 0xF8 ) // 1 byte character
8246  {
8247  return c0;
8248  }
8249  if (idx+1 >= length) { return 0; }
8250  const uint c1 = ((uchar)s.at(idx+1)) & 0x3f;
8251  if ( c0 < 0xE0 ) // 2 byte character
8252  {
8253  return ((c0 & 0x1f) << 6) | c1;
8254  }
8255  if (idx+2 >= length) { return 0; }
8256  const uint c2 = ((uchar)s.at(idx+2)) & 0x3f;
8257  if ( c0 < 0xF0 ) // 3 byte character
8258  {
8259  return ((c0 & 0x0f) << 12) | (c1 << 6) | c2;
8260  }
8261  if (idx+3 >= length) { return 0; }
8262  // 4 byte character
8263  const uint c3 = ((uchar)s.at(idx+3)) & 0x3f;
8264  return ((c0 & 0x07) << 18) | (c1 << 12) | (c2 << 6) | c3;
8265 }
8266 
8267 
8268 /*! @brief Returns one unicode character as an unsigned integer
8269  * from utf-8 string, making the character lower case if it was upper case.
8270  *
8271  * @param s utf-8 encoded string
8272  * @param idx byte position of given string \a s.
8273  * @return the unicode codepoint, 0 - MAX_UNICODE_CODEPOINT, excludes 'A'-'Z'
8274  * @see getNextUtf8Code()
8275 */
8276 uint getUtf8CodeToLower( const QCString& s, int idx )
8277 {
8278  const uint v = getUtf8Code( s, idx );
8279  return v < 0x7f ? tolower( v ) : v;
8280 }
8281 
8282 
8283 /*! @brief Returns one unicode character as ian unsigned interger
8284  * from utf-8 string, making the character upper case if it was lower case.
8285  *
8286  * @param s utf-8 encoded string
8287  * @param idx byte position of given string \a s.
8288  * @return the unicode codepoint, 0 - MAX_UNICODE_CODEPOINT, excludes 'A'-'Z'
8289  * @see getNextUtf8Code()
8290  */
8291 uint getUtf8CodeToUpper( const QCString& s, int idx )
8292 {
8293  const uint v = getUtf8Code( s, idx );
8294  return v < 0x7f ? toupper( v ) : v;
8295 }
8296 
8297 //--------------------------------------------------------------------------------------
8298 
8299 bool namespaceHasVisibleChild(NamespaceDef *nd,bool includeClasses)
8300 {
8301  if (nd->getNamespaceSDict())
8302  {
8304  NamespaceDef *cnd;
8305  for (cnli.toFirst();(cnd=cnli.current());++cnli)
8306  {
8307  if (cnd->isLinkableInProject() && cnd->localName().find('@')==-1)
8308  {
8309  return TRUE;
8310  }
8311  else if (namespaceHasVisibleChild(cnd,includeClasses))
8312  {
8313  return TRUE;
8314  }
8315  }
8316  }
8317  if (includeClasses && nd->getClassSDict())
8318  {
8320  ClassDef *cd;
8321  for (;(cd=cli.current());++cli)
8322  {
8323  if (cd->isLinkableInProject() && cd->templateMaster()==0)
8324  {
8325  return TRUE;
8326  }
8327  }
8328  }
8329  return FALSE;
8330 }
8331 
8332 //----------------------------------------------------------------------------
8333 
8335 {
8336  static bool allExternals = Config_getBool("ALLEXTERNALS");
8337  return (allExternals && cd->isLinkable()) || cd->isLinkableInProject();
8338 }
8339 
8340 //----------------------------------------------------------------------------
8341 
8343 {
8344  QRegExp re("\\[[^\\]]+\\]"); // [...]
8345  int l=0;
8346  if (re.match(docs,0,&l)==0)
8347  {
8348  int inPos = docs.find("in", 1,FALSE);
8349  int outPos = docs.find("out",1,FALSE);
8350  bool input = inPos!=-1 && inPos<l;
8351  bool output = outPos!=-1 && outPos<l;
8352  if (input || output) // in,out attributes
8353  {
8354  docs = docs.mid(l); // strip attributes
8355  if (input && output) return "[in,out]";
8356  else if (input) return "[in]";
8357  else if (output) return "[out]";
8358  }
8359  }
8360  return QCString();
8361 }
8362 
8363 //-----------------------------------------------------------
8364 
8365 /** Computes for a given list type \a inListType, which are the
8366  * the corresponding list type(s) in the base class that are to be
8367  * added to this list.
8368  *
8369  * So for public inheritance, the mapping is 1-1, so outListType1=inListType
8370  * Private members are to be hidden completely.
8371  *
8372  * For protected inheritance, both protected and public members of the
8373  * base class should be joined in the protected member section.
8374  *
8375  * For private inheritance, both protected and public members of the
8376  * base class should be joined in the private member section.
8377  */
8379  MemberListType inListType,
8380  Protection inProt,
8381  int *outListType1,
8382  int *outListType2
8383  )
8384 {
8385  static bool extractPrivate = Config_getBool("EXTRACT_PRIVATE");
8386  // default representing 1-1 mapping
8387  *outListType1=inListType;
8388  *outListType2=-1;
8389  if (inProt==Public)
8390  {
8391  switch (inListType) // in the private section of the derived class,
8392  // the private section of the base class should not
8393  // be visible
8394  {
8401  *outListType1=-1;
8402  *outListType2=-1;
8403  break;
8404  default:
8405  break;
8406  }
8407  }
8408  else if (inProt==Protected) // Protected inheritance
8409  {
8410  switch (inListType) // in the protected section of the derived class,
8411  // both the public and protected members are shown
8412  // as protected
8413  {
8426  *outListType1=-1;
8427  *outListType2=-1;
8428  break;
8429 
8431  *outListType2=MemberListType_pubMethods;
8432  break;
8434  *outListType2=MemberListType_pubStaticMethods;
8435  break;
8437  *outListType2=MemberListType_pubSlots;
8438  break;
8440  *outListType2=MemberListType_pubAttribs;
8441  break;
8443  *outListType2=MemberListType_pubStaticAttribs;
8444  break;
8446  *outListType2=MemberListType_pubTypes;
8447  break;
8448  default:
8449  break;
8450  }
8451  }
8452  else if (inProt==Private)
8453  {
8454  switch (inListType) // in the private section of the derived class,
8455  // both the public and protected members are shown
8456  // as private
8457  {
8470  *outListType1=-1;
8471  *outListType2=-1;
8472  break;
8473 
8475  if (extractPrivate)
8476  {
8477  *outListType1=MemberListType_pubMethods;
8478  *outListType2=MemberListType_proMethods;
8479  }
8480  else
8481  {
8482  *outListType1=-1;
8483  *outListType2=-1;
8484  }
8485  break;
8487  if (extractPrivate)
8488  {
8489  *outListType1=MemberListType_pubStaticMethods;
8490  *outListType2=MemberListType_proStaticMethods;
8491  }
8492  else
8493  {
8494  *outListType1=-1;
8495  *outListType2=-1;
8496  }
8497  break;
8499  if (extractPrivate)
8500  {
8501  *outListType1=MemberListType_pubSlots;
8502  *outListType2=MemberListType_proSlots;
8503  }
8504  else
8505  {
8506  *outListType1=-1;
8507  *outListType2=-1;
8508  }
8509  break;
8511  if (extractPrivate)
8512  {
8513  *outListType1=MemberListType_pubAttribs;
8514  *outListType2=MemberListType_proAttribs;
8515  }
8516  else
8517  {
8518  *outListType1=-1;
8519  *outListType2=-1;
8520  }
8521  break;
8523  if (extractPrivate)
8524  {
8525  *outListType1=MemberListType_pubStaticAttribs;
8526  *outListType2=MemberListType_proStaticAttribs;
8527  }
8528  else
8529  {
8530  *outListType1=-1;
8531  *outListType2=-1;
8532  }
8533  break;
8535  if (extractPrivate)
8536  {
8537  *outListType1=MemberListType_pubTypes;
8538  *outListType2=MemberListType_proTypes;
8539  }
8540  else
8541  {
8542  *outListType1=-1;
8543  *outListType2=-1;
8544  }
8545  break;
8546  default:
8547  break;
8548  }
8549  }
8550  //printf("convertProtectionLevel(type=%d prot=%d): %d,%d\n",
8551  // inListType,inProt,*outListType1,*outListType2);
8552 }
8553 
8555 {
8556  if (Doxygen::mainPage==0) return FALSE;
8557  if (Doxygen::mainPage->title().isEmpty()) return FALSE;
8558  if (Doxygen::mainPage->title().lower()=="notitle") return FALSE;
8559  return TRUE;
8560 }
8561 
8563 {
8564  QCString imgExt = Config_getEnum("DOT_IMAGE_FORMAT");
8565  imgExt = imgExt.replace( QRegExp(":.*"), "" );
8566  return imgExt;
8567 }
8568 
8570 {
8571  // add default pattern if needed
8572  QStrList &filePatternList = Config_getList("FILE_PATTERNS");
8573  if (filePatternList.isEmpty())
8574  {
8575  QDictIterator<int> it( g_extLookup );
8576  QCString pattern;
8577  bool caseSens = portable_fileSystemIsCaseSensitive();
8578  for (;it.current();++it)
8579  {
8580  pattern = "*";
8581  pattern += it.currentKey();
8582  filePatternList.append(pattern.data());
8583  if (caseSens) filePatternList.append(pattern.upper().data());
8584  }
8585  }
8586 }
8587 
8588 bool openOutputFile(const char *outFile,QFile &f)
8589 {
8590  bool fileOpened=FALSE;
8591  bool writeToStdout=(outFile[0]=='-' && outFile[1]=='\0');
8592  if (writeToStdout) // write to stdout
8593  {
8594  fileOpened = f.open(IO_WriteOnly,stdout);
8595  }
8596  else // write to file
8597  {
8598  QFileInfo fi(outFile);
8599  if (fi.exists()) // create a backup
8600  {
8601  QDir dir=fi.dir();
8602  QFileInfo backup(fi.fileName()+".bak");
8603  if (backup.exists()) // remove existing backup
8604  dir.remove(backup.fileName());
8605  dir.rename(fi.fileName(),fi.fileName()+".bak");
8606  }
8607  f.setName(outFile);
8608  fileOpened = f.open(IO_WriteOnly|IO_Translate);
8609  }
8610  return fileOpened;
8611 }
8612 
int findParameterList(const QCString &name)
Definition: util.cpp:1848
static QCString name
Definition: declinfo.cpp:673
static QDict< RefList > * xrefLists
Definition: doxygen.h:129
Traverses directory structures and contents in a platform-independent way.
Definition: qdir.h:52
QCString convertToXML(const char *s)
Definition: util.cpp:5717
#define MATCH
Definition: util.cpp:2918
ClassDef * classDef
Definition: classdef.h:520
QCString type
Definition: arguments.h:67
static QString cleanDirPath(const QString &dirPath)
Definition: qdir.cpp:1077
char * data() const
Definition: bufstr.h:81
bool resize(uint newlen)
Definition: qcstring.h:225
static int transcodeCharacterBuffer(const char *fileName, BufStr &srcBuf, int size, const char *inputEncoding, const char *outputEncoding)
Definition: util.cpp:7635
static GroupSDict * groupSDict
Definition: doxygen.h:119
Q_EXPORT int qstrncmp(const char *str1, const char *str2, uint len)
Definition: qcstring.h:101
static MemberNameSDict * functionNameSDict
Definition: doxygen.h:116
static void getResolvedSymbol(Definition *scope, FileDef *fileScope, Definition *d, const QCString &explicitScopePart, ArgumentList *actTemplParams, int &minDistance, ClassDef *&bestMatch, MemberDef *&bestTypedef, QCString &bestTemplSpec, QCString &bestResolvedType)
Definition: util.cpp:1209
QCString prefix
type prefix for the name
Definition: reflist.h:35
void generateFileRef(OutputDocInterface &od, const char *name, const char *text)
Definition: util.cpp:4908
char * rawData() const
Definition: qcstring.h:216
QCString docFile() const
unsigned short width
Definition: util.h:437
Definition * item
Definition: util.cpp:938
static QCString substTypedef(Definition *scope, FileDef *fileScope, const QCString &name, MemberDef **pTypeDef=0)
Definition: util.cpp:666
QCString getCanonicalTemplateSpec(Definition *d, FileDef *fs, const QCString &spec)
Definition: util.cpp:3335
void setAnchors(MemberList *ml)
Definition: util.cpp:2254
FileDef * getFileDef() const
Definition: classdef.cpp:4429
QCString title
display name of the entity
Definition: reflist.h:38
bool isLinkable() const
Definition: groupdef.cpp:1645
QCString fileToString(const char *name, bool filter, bool isSourceCode)
Definition: util.cpp:2418
QCString substituteKeywords(const QCString &s, const char *title, const char *projName, const char *projNum, const char *projBrief)
Definition: util.cpp:5122
virtual void disable(OutputGenerator::OutputType o)=0
virtual bool isLinkable() const =0
This class represents an function or template argument list.
Definition: arguments.h:82
Concrete visitor implementation for TEXT output.
bool isTypedefValCached() const
Definition: memberdef.cpp:4572
QList< ArgumentList > * copyArgumentLists(const QList< ArgumentList > *srcLists)
Definition: util.cpp:6205
char * data() const
Definition: qgstring.h:42
QCString stripWhiteSpace() const
Definition: qcstring.cpp:295
bool isLinkableInProject() const
Definition: classdef.cpp:2707
static QCString scope
Definition: declinfo.cpp:668
static Definition * followPath(Definition *start, FileDef *fileScope, const QCString &path)
Definition: util.cpp:752
static QCString aliasName
Definition: scanner.cpp:10889
static int findScopePattern(const QCString &pattern, const QCString &s, int p, int *len)
Definition: util.cpp:2678
void clear()
Definition: growbuf.h:15
int isAccessibleFrom(Definition *scope, FileDef *fileScope, Definition *item)
Definition: util.cpp:948
virtual void writeNonBreakableSpace(int)=0
bool matchArguments2(Definition *srcScope, FileDef *srcFileScope, ArgumentList *srcAl, Definition *dstScope, FileDef *dstFileScope, ArgumentList *dstAl, bool checkCV)
Definition: util.cpp:3647
BaseClassList * subClasses() const
Definition: classdef.cpp:4404
virtual QCString getReference() const
bool isLinkable() const
Definition: filedef.h:117
static bool findOperator(const QCString &s, int i)
Definition: util.cpp:1623
bool readInputFile(const char *fileName, BufStr &inBuf, bool filter, bool isSourceCode)
read a file name fileName and optionally filter and transcode it
Definition: util.cpp:7673
bool openOutputFile(const char *outFile, QFile &f)
Definition: util.cpp:8588
static void stripIrrelevantString(QCString &target, const QCString &str)
Definition: util.cpp:2859
static QDict< Definition > g_visitedNamespaces
Definition: util.cpp:515
void addStr(const char *s)
Definition: growbuf.h:19
QCString generateMarker(int id)
Definition: util.cpp:266
static constexpr double g
Definition: Units.h:144
bool resolveLink(const char *scName, const char *lr, bool, Definition **resContext, QCString &resAnchor)
Definition: util.cpp:4753
bool isReference() const
Definition: memberdef.cpp:5127
virtual QCString trOverloadText()=0
static PageSDict * exampleSDict
Definition: doxygen.h:101
static QCString result
bool isEmpty() const
Definition: qcstring.h:189
virtual bool remove(const QString &fileName, bool acceptAbsPath=TRUE)
Definition: qdir.cpp:915
QCString getReference() const
Definition: memberdef.cpp:1001
QCString escapeCharsInString(const char *name, bool allowDots, bool allowUnderscore)
Definition: util.cpp:5242
The QRegExp class provides pattern matching using regular expressions or wildcards.
Definition: qregexp.h:46
bool fileVisibleInIndex(FileDef *fd, bool &genSourceFile)
Definition: util.cpp:8177
virtual void pushGeneratorState()=0
QCString title() const
Definition: pagedef.h:54
#define REL_PATH_TO_ROOT
Definition: util.cpp:91
void startConstraintDocs()
Definition: outputlist.h:443
uint length() const
Definition: qcstring.h:195
QCString convertCharEntitiesToUTF8(const QCString &s)
Definition: util.cpp:5822
OutputDocInterface & m_od
Definition: util.h:88
unsigned char * alpha
Definition: util.h:440
void append(const type *d)
Definition: qlist.h:73
FILE * portable_popen(const char *name, const char *type)
Definition: portable.cpp:400
virtual void writeBreak(int indent) const =0
void mergeArguments(ArgumentList *srcAl, ArgumentList *dstAl, bool forceNameOverwrite)
Definition: util.cpp:3732
const char * portable_getenv(const char *variable)
Definition: portable.cpp:317
#define IO_WriteOnly
Definition: qiodevice.h:62
bool generateSourceFile() const
Definition: filedef.cpp:1396
int guessSection(const char *name)
Definition: util.cpp:315
void setMemberGroup(MemberGroup *grp)
Definition: memberdef.cpp:3290
Definition: types.h:26
static QCString htmlFileExtension
Definition: doxygen.h:130
void writeString(const char *text)
Definition: outputlist.h:119
Definition * scope
Definition: util.cpp:936
bool generateDoc(const char *fileName, int startLine, Definition *ctx, MemberDef *md, const QCString &docStr, bool indexWords, bool isExample, const char *exampleName=0, bool singleLine=FALSE, bool linkFromIndex=FALSE)
Definition: outputlist.cpp:131
Definition: qcache.h:85
virtual QCString trPageAbbreviation()=0
void setLanguage(SrcLangExt lang)
type * first()
Definition: qinternallist.h:87
#define qsnprintf
Definition: qcstring.h:73
QTime time() const
Definition: qdatetime.h:172
ArgumentList * templateArguments() const
Definition: classdef.cpp:4419
QCString defval
Definition: arguments.h:71
QCString resolvedType
Definition: doxygen.h:87
void disableAllBut(OutputGenerator::OutputType o)
Definition: outputlist.cpp:49
void setAnchor()
Definition: memberdef.cpp:3334
char & at(uint i) const
Definition: qcstring.h:326
void writeLink(const char *extRef, const char *file, const char *anchor, const char *text) const
Definition: util.cpp:136
unsigned char * content
Definition: util.h:439
bool save(const char *fileName)
Definition: image.cpp:525
bool mainPageHasTitle()
Definition: util.cpp:8554
QCString argListToString(ArgumentList *al, bool useCanonicalType, bool showDefVals)
Definition: util.cpp:2151
static QDict< void > aliasesProcessed
Definition: util.cpp:7287
void writePageRef(OutputDocInterface &od, const char *cn, const char *mn)
Definition: util.cpp:247
DocSymbol::SymType name2sym(const QCString &symName) const
Give code of the requested HTML entity name.
Definition: htmlentity.cpp:471
constexpr T pow(T x)
Definition: pow.h:72
void setRefItems(const QList< ListItemInfo > *sli)
void setAutoDelete(bool val)
Definition: sortdict.h:545
QCString stripAnonymousNamespaceScope(const QCString &s)
Definition: util.cpp:218
size_t portable_iconv(void *cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
Definition: portable_c.c:24
NamespaceSDict * getUsedNamespaces() const
Definition: filedef.cpp:1251
const bool FALSE
Definition: qglobal.h:370
void writeTypeConstraints(OutputList &ol, Definition *d, ArgumentList *al)
Definition: util.cpp:7585
void endConstraintDocs()
Definition: outputlist.h:445
Definition: types.h:26
static constexpr double fs
Definition: Units.h:100
QList< ListItemInfo > * m_sli
Definition: membergroup.h:152
The QDate class provides date functions.
Definition: qdatetime.h:50
QCString label
Definition: section.h:56
bool leftScopeMatch(const QCString &scope, const QCString &name)
Definition: util.cpp:1904
static void hsl2rgb(double h, double s, double l, double *pRed, double *pGreen, double *pBlue)
Definition: image.cpp:428
int size
Definition: util.cpp:7296
MemberList * enumFieldList() const
Definition: memberdef.cpp:4497
bool isLinkableInProject() const
Definition: memberdef.cpp:1150
QCString latexEscapeIndexChars(const char *s, bool insideTabbing)
Definition: util.cpp:6683
virtual void popGeneratorState()=0
RefItem * getRefItem(int todoItemId)
Definition: reflist.cpp:74
error
Definition: include.cc:26
type * at(uint i) const
Definition: qlist.h:94
bool copyFile(const QCString &src, const QCString &dest)
Definition: util.cpp:7966
static QCString className
Definition: declinfo.cpp:669
static QDict< MemberDef > g_resolvedTypedefs
Definition: util.cpp:514
int readBlock(char *data, uint len)
Definition: qfile_unix.cpp:473
static int findEndOfCommand(const char *s)
Definition: util.cpp:7309
int m_index
Definition: util.cpp:941
#define Config_getList(val)
Definition: config.cpp:662
Definition: entry.h:50
static FileNameDict * inputNameDict
Definition: doxygen.h:108
QCString resolveAliasCmd(const QCString aliasCmd)
Definition: util.cpp:7562
QCString left(uint len) const
Definition: qcstring.cpp:213
bool isDefine() const
Definition: memberdef.cpp:4170
static QCString stripDeclKeywords(const QCString &s)
Definition: util.cpp:3319
uint getUtf8CodeToLower(const QCString &s, int idx)
Returns one unicode character as an unsigned integer from utf-8 string, making the character lower ca...
Definition: util.cpp:8276
bool stripPrefix(const char *prefix)
Definition: qcstring.cpp:201
DocRoot * validatingParseDoc(const char *fileName, int startLine, Definition *ctx, MemberDef *md, const char *input, bool indexWords, bool isExample, const char *exampleName, bool singleLine, bool linkFromIndex)
Definition: docparser.cpp:7179
void addChar(char c)
Definition: bufstr.h:42
void writeColoredImgData(const char *dir, ColoredImgDataItem data[])
Definition: util.cpp:7889
static HtmlEntityMapper * instance()
Definition: htmlentity.cpp:341
QCString getOverloadDocs()
Definition: util.cpp:5859
virtual bool isReference() const
bool insert(const char *k, const type *d, int c=1, int p=0)
Definition: qcache.h:101
bool protectionLevelVisible(Protection prot)
Definition: util.cpp:8098
QCString convertToLaTeX(const QCString &s, bool insideTabbing, bool keepSpaces)
Definition: util.cpp:5812
void endConstraintParam()
Definition: outputlist.h:437
QTextStream & hex(QTextStream &s)
QCString relativePathToRoot(const char *name)
Definition: util.cpp:5436
TFile * outFile
Definition: makeDST.cxx:36
Simplified and optimized version of QTextStream.
Definition: ftextstream.h:11
ClassDef * classDef
Definition: doxygen.h:84
uint size() const
Definition: qcstring.h:201
string dir
int errno
Contains the last error code.
Definition: structcmd.h:53
QCString header
Definition: membergroup.h:147
QDir dir(bool absPath=FALSE) const
Definition: qfileinfo.cpp:393
int find(char c, int index=0, bool cs=TRUE) const
Definition: qcstring.cpp:41
int count() const
Definition: sortdict.h:284
NamespaceSDict * getUsedNamespaces() const
static QCString getCanonicalTypeForIdentifier(Definition *d, FileDef *fs, const QCString &word, QCString *tSpec, int count=0)
Definition: util.cpp:3355
MemberDef * getMemberFromSymbol(Definition *scope, FileDef *fileScope, const char *n)
Definition: util.cpp:7083
const char * latex(DocSymbol::SymType symb) const
Access routine to the LaTeX code of the HTML entity.
Definition: htmlentity.cpp:426
void setName(const QString &name)
Definition: qfile.cpp:167
virtual QCString getOutputFileBase() const =0
const char * groupTitle() const
Definition: groupdef.h:54
bool namespaceHasVisibleChild(NamespaceDef *nd, bool includeClasses)
Definition: util.cpp:8299
const int MAX_STACK_SIZE
Definition: util.cpp:871
bool hasCallerGraph() const
Definition: memberdef.cpp:4562
GroupList * partOfGroups() const
void append(const char *key, const T *d)
Definition: sortdict.h:135
static constexpr double mg
Definition: Units.h:145
static QCString args
Definition: declinfo.cpp:674
SrcLangExt
Definition: types.h:41
static QStrList * l
Definition: config.cpp:1044
Definition: types.h:26
uint curPos() const
Definition: bufstr.h:97
QCString correctURL(const QCString &url, const QCString &relPath)
Definition: util.cpp:8084
QCString getReference() const
Definition: classdef.cpp:3814
int findRev(char c, int index=-1, bool cs=TRUE) const
Definition: qcstring.cpp:95
QCString getFileFilter(const char *name, bool isSourceCode)
Definition: util.cpp:2345
QString filePath() const
Definition: qfileinfo.cpp:321
QAsciiDict< Entry > cl
MemberDef * memberDefinition() const
Definition: memberdef.cpp:4593
virtual void writeString(const char *, bool) const =0
QCString removeAnonymousScopes(const QCString &s)
Definition: util.cpp:164
unsigned char uchar
Definition: nybbler.cc:11
bool parseText(const QCString &textStr)
Definition: outputlist.cpp:175
void initDefaultExtensionMapping()
Definition: util.cpp:6999
#define IO_Translate
Definition: qiodevice.h:66
void setFileName(const char *name)
Definition: pagedef.cpp:66
static StringDict aliasDict
Definition: doxygen.h:125
QCString getDefFileName() const
QCString copy() const
Definition: qcstring.h:250
ClassDef * getClass(const char *n)
Definition: util.cpp:472
void writeBreak(int indent) const
Definition: util.cpp:126
void shrink(uint newlen)
Definition: bufstr.h:58
QCString canType
Definition: arguments.h:68
static QCString replaceAliasArguments(const QCString &aliasValue, const QCString &argList)
Definition: util.cpp:7331
bool constSpecifier
Definition: arguments.h:99
bool isFile() const
QCString extractBlock(const QCString text, const QCString marker)
Definition: util.cpp:7998
#define IO_ReadOnly
Definition: qiodevice.h:61
QCString transcodeCharacterStringToUTF8(const QCString &input)
Definition: util.cpp:2374
bool isTemplateArgument() const
Definition: classdef.cpp:4474
QCString extractDirection(QCString &docs)
Definition: util.cpp:8342
#define Config_getEnum(val)
Definition: config.cpp:663
static QCString stripFromPath(const QCString &path, QStrList &l)
Definition: util.cpp:274
QString absFilePath() const
QCString convertToId(const char *s)
Definition: util.cpp:5685
bool hasCallGraph() const
Definition: memberdef.cpp:4557
int portable_iconv_close(void *cd)
Definition: portable_c.c:30
#define Config_getInt(val)
Definition: config.cpp:661
FileDef * getFileDef() const
Definition: memberdef.cpp:4075
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:92
static NamespaceSDict * namespaceSDict
Definition: doxygen.h:120
QCString typeConstraint
Definition: arguments.h:73
int hour() const
Definition: qdatetime.cpp:648
QCString substituteTemplateArgumentsInString(const QCString &name, ArgumentList *formalArgs, ArgumentList *actualArgs)
Definition: util.cpp:6099
static NamespaceDef * globalScope
Definition: doxygen.h:128
int itemId
Definition: types.h:101
bool rightScopeMatch(const QCString &scope, const QCString &name)
Definition: util.cpp:1893
static ParserManager * parserManager
Definition: doxygen.h:141
void popGeneratorState()
Definition: outputlist.cpp:121
const char * name
Definition: util.h:436
QCString stripTemplateSpecifiersFromScope(const QCString &fullName, bool parentOnly, QCString *pLastScopeStripped)
Definition: util.cpp:6226
virtual DefType definitionType() const =0
QCString showFileDefMatches(const FileNameDict *fnDict, const char *n)
Definition: util.cpp:5058
def cli(ctx)
Definition: main.py:7
This class contains the information about the argument of a function or template. ...
Definition: arguments.h:28
const char * typeString() const
Definition: memberdef.cpp:4035
QCString getLanguageSpecificSeparator(SrcLangExt lang, bool classScope)
Definition: util.cpp:8065
QCString tagName
Definition: entry.h:52
void push(Definition *scope, FileDef *fileScope, Definition *item, const QCString &expScope)
Definition: util.cpp:890
uint count() const
Definition: qlist.h:66
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 SrcLangExt language
Definition: scanner.cpp:10895
static StringDict tagDestinationDict
Definition: doxygen.h:124
static QCString extractCanonicalArgType(Definition *d, FileDef *fs, const Argument *arg)
Definition: util.cpp:3562
int writeBlock(const char *data, uint len)
Definition: qfile_unix.cpp:537
bool findAndRemoveWord(QCString &s, const QCString &word)
Definition: util.cpp:6848
const char * data() const
Definition: qstring.h:542
bool volatileSpecifier
Definition: arguments.h:101
static QCString escapeCommas(const QCString &s)
Definition: util.cpp:7428
virtual bool mkdir(const QString &dirName, bool acceptAbsPath=TRUE) const
Definition: qdir_unix.cpp:98
MemberDef * getEnumScope() const
Definition: memberdef.cpp:4487
void setTime_t(uint secsSince1Jan1970UTC)
Definition: qdatetime.cpp:1142
QAsciiDict< Entry > fn
static QCString getFilterFromList(const char *name, const QStrList &filterList, bool &found)
Definition: util.cpp:2308
type * getLast() const
Definition: qlist.h:96
static SearchIndexIntf * searchIndex
Definition: doxygen.h:133
FileDef * fileDef
Definition: util.cpp:4957
SrcLangExt parserId
Definition: util.cpp:6939
Q_EXPORT uint qstrlen(const char *str)
Definition: qcstring.h:81
void addChar(char c)
Definition: growbuf.h:16
QCString upper() const
Definition: qcstring.cpp:279
type * current() const
#define QMAX(a, b)
Definition: qglobal.h:390
const QCString & name() const
Definition: definition.h:114
bool recursivelyAddGroupListToTitle(OutputList &ol, Definition *d, bool root)
Definition: util.cpp:6495
static QDate currentDate()
Definition: qdatetime.cpp:437
static Protection baseProt
Definition: scanner.cpp:10857
const double e
int qstricmp(const char *str1, const char *str2)
Definition: qcstring.cpp:567
static ClassDef * getResolvedClassRec(Definition *scope, FileDef *fileScope, const char *n, MemberDef **pTypeDef, QCString *pTemplSpec, QCString *pResolvedType)
Definition: util.cpp:1374
static int input(void)
Definition: code.cpp:15695
int countAliasArguments(const QCString argList)
Definition: util.cpp:7513
QCString yearToString()
Definition: util.cpp:2515
FindFileCacheElem(FileDef *fd, bool ambig)
Definition: util.cpp:4956
fileName
Definition: dumpTree.py:9
QCString getCachedTypedefTemplSpec() const
Definition: memberdef.cpp:4582
QCString parseCommentAsText(const Definition *scope, const MemberDef *md, const QCString &doc, const QCString &fileName, int lineNr)
Definition: util.cpp:7242
static QCString expandAliasRec(const QCString s, bool allowRecursion=FALSE)
Definition: util.cpp:7450
bool containsWord(const QCString &s, const QCString &word)
Definition: util.cpp:6836
FileDef * fileScope
Definition: util.cpp:937
char & at(uint i) const
Definition: bufstr.h:85
void writeString(const char *s, bool keepSpaces) const
Definition: util.cpp:101
void pushGeneratorState()
Definition: outputlist.cpp:111
QCString stripExtensionGeneral(const char *fName, const char *ext)
Definition: util.cpp:6789
static const char constScope[]
Definition: util.cpp:1651
bool getDefs(const QCString &scName, const QCString &mbName, const char *args, MemberDef *&md, ClassDef *&cd, FileDef *&fd, NamespaceDef *&nd, GroupDef *&gd, bool forceEmptyScope, FileDef *currentFile, bool checkCV, const char *forceTagFile)
Definition: util.cpp:3932
bool isLinkableInProject() const
Definition: filedef.cpp:1877
void addArray(const char *a, int len)
Definition: bufstr.h:47
QCString name() const
Definition: filedef.cpp:1193
QCString linkToText(SrcLangExt lang, const char *link, bool isFileName)
Definition: util.cpp:4659
def key(type, name=None)
Definition: graph.py:13
static constexpr double m2
Definition: Units.h:72
static bool matchArgument(const Argument *srcA, const Argument *dstA, const QCString &className, const QCString &namespaceName, NamespaceSDict *usingNamespaces, SDict< Definition > *usingClasses)
Definition: util.cpp:2924
virtual bool rename(const QString &name, const QString &newName, bool acceptAbsPaths=TRUE)
Definition: qdir_unix.cpp:119
void MD5Buffer(const unsigned char *buf, unsigned int len, unsigned char sig[16])
Definition: md5.c:275
bool isTemplate() const
Definition: classdef.cpp:4444
virtual QCString trDateTime(int year, int month, int day, int dayOfWeek, int hour, int minutes, int seconds, bool includeTime)=0
QCString convertToHtml(const char *s, bool keepEntities)
Definition: util.cpp:5746
QCString right(uint len) const
Definition: qcstring.cpp:231
SrcLangExt getLanguage() const
std::void_t< T > n
QCString convertToJSString(const char *s)
Definition: util.cpp:5792
virtual void endPageRef(const char *, const char *)=0
const double a
const char * writeUtf8Char(FTextStream &t, const char *s)
Definition: util.cpp:7165
bool open(int)
Definition: qfile_unix.cpp:134
static DirSDict * directories
Definition: doxygen.h:139
virtual void addWord(const char *word, bool hiPriority)=0
void stripIrrelevantConstVolatile(QCString &s)
Definition: util.cpp:2908
char versionString[]
Definition: version.cpp:1
bool find(Definition *scope, FileDef *fileScope, Definition *item)
Definition: util.cpp:905
unsigned short height
Definition: util.h:438
QCString anchor() const
Definition: classdef.cpp:4606
virtual void docify(const char *s)=0
FileDef * findFileDef(const FileNameDict *fnDict, const char *n, bool &ambig)
Definition: util.cpp:4963
void startConstraintParam()
Definition: outputlist.h:435
bool isForeign() const
Definition: memberdef.cpp:4200
#define HEXTONUM(x)
uint64 toUInt64(bool *ok=0) const
Definition: qcstring.cpp:463
virtual void lineBreak(const char *style)=0
bool accessibleViaUsingNamespace(const NamespaceSDict *nl, FileDef *fileScope, Definition *item, const QCString &explicitScopePart="")
Definition: util.cpp:831
bool classHasVisibleChildren(ClassDef *cd)
Definition: util.cpp:5182
int pos
Definition: util.cpp:7294
QCString stripIndentation(const QCString &s)
Definition: util.cpp:8110
QCString fileName
Definition: section.h:61
static void print(DebugMask mask, int prio, const char *fmt,...)
Definition: debug.cpp:84
static QDict< DefinitionIntf > * symbolMap
Definition: doxygen.h:134
unsigned long ulong
Definition: qglobal.h:352
void stringToArgumentList(const char *argsString, ArgumentList *al, QCString *extraTypeChars)
Definition: defargs.cpp:2922
QCString & prepend(const char *s)
Definition: qcstring.cpp:387
static bool findOperator2(const QCString &s, int i)
Definition: util.cpp:1637
static const char virtualScope[]
Definition: util.cpp:1652
p
Definition: test.py:223
void disable(OutputGenerator::OutputType o)
Definition: outputlist.cpp:79
uint getUtf8Code(const QCString &s, int idx)
Get one unicode character as an unsigned integer from utf-8 string.
Definition: util.cpp:8240
QCString latexEscapeLabelName(const char *s, bool insideTabbing)
Definition: util.cpp:6647
void append(const type *d)
Definition: qinternallist.h:61
static SectionDict * sectionDict
Definition: doxygen.h:117
bool isLinkable() const
Marker(int p, int n, int s)
Definition: util.cpp:7293
bool updateLanguageMapping(const QCString &extension, const QCString &language)
Definition: util.cpp:6964
A bunch of utility functions.
static PageSDict * pageSDict
Definition: doxygen.h:102
void initFilePattern(void)
Definition: util.cpp:8569
static Entry * current
static void findMembersWithSpecificName(MemberName *mn, const char *args, bool checkStatics, FileDef *currentFile, bool checkCV, const char *forceTagFile, QList< MemberDef > &members)
Definition: util.cpp:3863
const char * data() const
Definition: qcstring.h:207
void addGroupListToTitle(OutputList &ol, Definition *d)
Definition: util.cpp:6528
Definition: dirdef.h:44
bool isLinkable() const
Definition: classdef.cpp:2729
QCString anchor() const
Definition: memberdef.cpp:1031
void addImageFile(const char *name)
Definition: index.h:147
CodeOutputInterface * code
QCString dateToString(bool includeTime)
Definition: util.cpp:2473
#define Config_getString(val)
Definition: config.cpp:660
type * current() const
Definition: qlist.h:146
void * portable_iconv_open(const char *tocode, const char *fromcode)
Definition: portable_c.c:19
string tmp
Definition: languages.py:63
bool isStrong() const
Definition: memberdef.cpp:4345
static QIntDict< MemberGroupInfo > memGrpInfoDict
Definition: doxygen.h:126
double distance(double x1, double y1, double z1, double x2, double y2, double z2)
bool isStrongEnumValue() const
Definition: memberdef.cpp:4350
void startConstraintType()
Definition: outputlist.h:439
int lineNr
Definition: section.h:62
#define Config_getBool(val)
Definition: config.cpp:664
void setReference(const char *r)
QCString latexEscapePDFString(const char *s)
Definition: util.cpp:6721
ClassDef * getClassDef() const
Definition: memberdef.cpp:4070
static bool matchArgument2(Definition *srcScope, FileDef *srcFileScope, Argument *srcA, Definition *dstScope, FileDef *dstFileScope, Argument *dstA)
Definition: util.cpp:3585
static constexpr double ps
Definition: Units.h:99
void endConstraintType()
Definition: outputlist.h:441
QCString getDotImageExtension(void)
Definition: util.cpp:8562
type * getFirst() const
Definition: qlist.h:95
QCString anchor
Definition: example.h:30
int getPrefixIndex(const QCString &name)
Definition: util.cpp:5144
double gamma(double KE, const simb::MCParticle *part)
virtual QCString qualifiedName() const
void addPage(PageDef *def)
Definition: groupdef.cpp:222
QCString & insert(uint index, const char *s)
Definition: qcstring.cpp:355
type * next()
Definition: qinternallist.h:89
void warn(const char *file, int line, const char *fmt,...)
Definition: message.cpp:183
AccessStack()
Definition: util.cpp:879
ClassDef * getCachedTypedefVal() const
Definition: memberdef.cpp:4577
void initClassHierarchy(ClassSDict *cl)
Definition: util.cpp:5211
QCString name
name of the entity containing the reference
Definition: reflist.h:37
void err(const char *fmt,...)
Definition: message.cpp:226
bool visited
Definition: classdef.h:402
void filterLatexString(FTextStream &t, const char *str, bool insideTabbing, bool insidePre, bool insideItem, bool keepSpaces)
Definition: util.cpp:6533
static QCache< FindFileCacheElem > g_findFileDefCache(5000)
int minute() const
Definition: qdatetime.cpp:657
virtual void writeObjectLink(const char *ref, const char *file, const char *anchor, const char *name)=0
QCString name
Definition: example.h:31
SDict< Definition > * getUsedClasses() const
Definition: filedef.h:123
QCString absFilePath() const
Definition: filedef.h:96
void extractNamespaceName(const QCString &scopeName, QCString &className, QCString &namespaceName, bool allowEmptyClass)
Definition: util.cpp:5478
QCString qualifiedNameWithTemplateParameters(QList< ArgumentList > *actualParams=0, int *actualParamIndex=0) const
Definition: classdef.cpp:3855
QCString removeRedundantWhiteSpace(const QCString &s)
Definition: util.cpp:1655
int extractClassNameFromType(const QCString &type, int &pos, QCString &name, QCString &templSpec, SrcLangExt lang)
Definition: util.cpp:5963
Buffer used to store strings.
Definition: bufstr.h:30
QCString mid(uint index, uint len=0xffffffff) const
Definition: qcstring.cpp:246
QCString getOutputFileBase() const
Definition: filedef.h:83
bool portable_fileSystemIsCaseSensitive()
Definition: portable.cpp:391
The QDateTime class provides date and time functions.
Definition: qdatetime.h:161
void writeExample(OutputList &ol, ExampleSDict *ed)
Definition: util.cpp:2106
int match(const QCString &str, int index=0, int *len=0, bool indexIsStart=TRUE) const
Definition: qregexp.cpp:649
The QFile class is an I/O device that operates on files.
Definition: qfile.h:50
int nextUtf8CharPosition(const QCString &utf8Str, int len, int startPos)
Definition: util.cpp:7195
NamespaceSDict * getNamespaceSDict() const
Definition: namespacedef.h:101
ClassDef * categoryOf() const
Definition: classdef.cpp:4514
QCString & sprintf(const char *format,...)
Definition: qcstring.cpp:27
bool checkIfTypedef(Definition *scope, FileDef *fileScope, const char *n)
Definition: util.cpp:7155
SDict< Definition > * getUsedClasses() const
Definition: namespacedef.h:66
QCString getOutputFileBase() const
Definition: classdef.cpp:3533
uint size() const
bool pureSpecifier
Definition: arguments.h:103
pval
Definition: tracks.py:168
static struct Lang2ExtMap g_lang2extMap[]
void setRefItems(const QList< ListItemInfo > *sli)
virtual Definition * getOuterScope() const
bool isHidden() const
GroupDef * getGroupDef() const
Definition: memberdef.cpp:4095
QCString attrib
Definition: arguments.h:66
void addDocCrossReference(MemberDef *src, MemberDef *dst)
Definition: util.cpp:8189
const char * get()
Definition: growbuf.h:38
ArgumentList * argumentList() const
Definition: memberdef.cpp:4512
virtual void startPageRef()=0
virtual Definition * findInnerCompound(const char *name)
NamespaceDef * getResolvedNamespace(const char *name)
Definition: util.cpp:489
int dayOfWeek() const
Definition: qdatetime.cpp:228
bool showInCallGraph() const
Definition: memberdef.cpp:4458
void addCodeOnlyMappings()
Definition: util.cpp:7056
MemberDef * memberDeclaration() const
Definition: memberdef.cpp:4598
SrcLangExt getLanguageFromFileName(const QCString fileName)
Definition: util.cpp:7061
QCString qualifiedName() const
Definition: memberdef.cpp:3968
QDate date() const
Definition: qdatetime.h:171
bool isVisibleInHierarchy()
Definition: classdef.cpp:2743
type * find(const char *k, bool ref=TRUE) const
Definition: qcache.h:107
static Definition * endOfPathIsUsedClass(SDict< Definition > *cl, const QCString &localName)
Definition: util.cpp:730
void MD5SigToString(unsigned char signature[16], char *str, int len)
Definition: md5.c:285
int computeQualifiedIndex(const QCString &name)
Definition: util.cpp:1203
static MemberNameSDict * memberNameSDict
Definition: doxygen.h:115
QCString tempArgListToString(ArgumentList *al, SrcLangExt lang)
Definition: util.cpp:2197
void addSourceReferences(MemberDef *d)
constexpr double dist(const TReal *x, const TReal *y, const unsigned int dimension)
QCString stripScope(const char *name)
Definition: util.cpp:5605
MemberDef * typeDef
Definition: doxygen.h:85
QCString resolveTypeDef(Definition *context, const QCString &qualifiedName, Definition **typedefContext)
Definition: util.cpp:346
bool accessibleViaUsingClass(const SDict< Definition > *cl, FileDef *fileScope, Definition *item, const QCString &explicitScopePart="")
Definition: util.cpp:808
int getMemberGroupId() const
Definition: memberdef.cpp:4532
QCString getCachedResolvedTypedef() const
Definition: memberdef.cpp:4587
QCString expandAlias(const QCString &aliasName, const QCString &aliasValue)
Definition: util.cpp:7572
void addSourceReferencedBy(MemberDef *d)
void skip(uint s)
Definition: bufstr.h:53
A model of a page symbol.
Definition: pagedef.h:29
static QDateTime currentDateTime()
Definition: qdatetime.cpp:1340
uint toUInt(bool *ok=0) const
Definition: qcstring.cpp:445
QCString getPath() const
Definition: filedef.h:110
int portable_pclose(FILE *stream)
Definition: portable.cpp:405
void push(Definition *scope, FileDef *fileScope, Definition *item)
Definition: util.cpp:880
virtual void writeLink(const char *extRef, const char *file, const char *anchor, const char *text) const =0
QCString name
Definition: arguments.h:69
static QCString trimScope(const QCString &name, const QCString &s)
Definition: util.cpp:2734
std::string pattern
Definition: regex_t.cc:35
void replaceNamespaceAliases(QCString &scope, int i)
Definition: util.cpp:6804
static StringDict namespaceAliasDict
Definition: doxygen.h:118
QCString convertNameToFile(const char *name, bool allowDots, bool allowUnderscore)
Definition: util.cpp:5354
const char * parserName
Definition: util.cpp:6938
QCString fileName
Definition: entry.h:53
static QCString type
Definition: declinfo.cpp:672
QCString extractAliasArgs(const QCString &args, int pos)
Definition: util.cpp:7532
Q_EXPORT char * qstrcpy(char *dst, const char *src)
Definition: qcstring.h:87
QString fileName() const
QCString doc
virtual void setCurrentDoc(Definition *ctx, const char *anchor, bool isSourceFile)=0
const int maxInheritanceDepth
Definition: util.cpp:148
QCString getOutputFileBase() const
Definition: memberdef.cpp:941
QCString substituteClassNames(const QCString &s)
QCString insertTemplateSpecifierInScope(const QCString &scope, const QCString &templ)
Definition: util.cpp:5527
bool isEmpty() const
Definition: qinternallist.h:57
int month() const
Definition: qdatetime.cpp:202
Definition * scope
scope to use for references.
Definition: reflist.h:36
static bool isLowerCase(QCString &s)
Definition: util.cpp:4467
char at(int i) const
Definition: growbuf.h:40
QCString type
Definition: types.h:100
int year() const
Definition: qdatetime.cpp:189
void cacheTypedefVal(ClassDef *val, const QCString &templSpec, const QCString &resolvedType)
Definition: memberdef.cpp:4827
Protection classInheritedProtectionLevel(ClassDef *cd, ClassDef *bcd, Protection prot, int level)
Definition: util.cpp:2556
QCString trailingReturnType
Definition: arguments.h:105
bool hasVisibleRoot(BaseClassList *bcl)
Definition: util.cpp:5224
T * at(uint i)
Definition: sortdict.h:258
static bool * b
Definition: config.cpp:1043
void addMembersToMemberGroup(MemberList *ml, MemberGroupSDict **ppMemberGroupSDict, Definition *context)
Definition: util.cpp:5867
void flush()
Definition: qfile.cpp:228
NamespaceDef * getNamespaceDef() const
Definition: memberdef.cpp:4080
void addRefItem(const QList< ListItemInfo > *sli, const char *key, const char *prefix, const char *name, const char *title, const char *args, Definition *scope)
Definition: util.cpp:6456
Protection
Definition: types.h:26
Translator * theTranslator
Definition: language.cpp:157
ArgumentList * deepCopy() const
Definition: arguments.cpp:20
int second() const
Definition: qdatetime.cpp:666
bool isDocumentationFile() const
Definition: filedef.cpp:1728
static QCString trimTemplateSpecifiers(const QCString &namespaceName, const QCString &className, const QCString &s)
Definition: util.cpp:2603
virtual void setDocumentation(const char *d, const char *docFile, int docLine, bool stripWhiteSpace=TRUE)
Definition: definition.cpp:612
bool checkExtension(const char *fName, const char *ext)
Definition: util.cpp:6784
bool isId(int c)
Definition: util.h:224
list x
Definition: train.py:276
bool find(Definition *scope, FileDef *fileScope, Definition *item, const QCString &expScope)
Definition: util.cpp:918
MemberListType
Definition: types.h:104
void startConstraintList(const char *header)
Definition: outputlist.h:433
QCString normalizeNonTemplateArgumentsInString(const QCString &name, Definition *context, const ArgumentList *formalArgs)
Definition: util.cpp:6037
QCString docFile
Definition: membergroup.h:149
void convertProtectionLevel(MemberListType inListType, Protection inProt, int *outListType1, int *outListType2)
Definition: util.cpp:8378
void trimBaseClassScope(BaseClassList *bcl, QCString &s, int level=0)
Definition: util.cpp:2760
void createSubDirs(QDir &d)
Definition: util.cpp:5458
friend class Iterator
Definition: sortdict.h:289
void pop()
Definition: util.cpp:901
static unsigned filter(unsigned char *out, const unsigned char *in, unsigned w, unsigned h, const LodePNG_InfoColor *info)
Definition: lodepng.cpp:3576
virtual QCString trTypeConstraints()=0
float pi
Definition: units.py:11
QCString replaceColorMarkers(const char *str)
Definition: util.cpp:7919
#define NOMATCH
Definition: util.cpp:2919
PageDef * addRelatedPage(const char *name, const QCString &ptitle, const QCString &doc, QList< SectionInfo > *, const char *fileName, int startLine, const QList< ListItemInfo > *sli, GroupDef *gd, TagInfo *tagInfo, SrcLangExt lang)
Definition: util.cpp:6369
int getScopeFragment(const QCString &s, int p, int *l)
Definition: util.cpp:6322
static QCache< LookupInfo > * lookupCache
Definition: doxygen.h:138
bool isUsedOnly() const
Definition: classdef.cpp:4579
list cmd
Definition: getreco.py:22
QCString stripLeadingAndTrailingEmptyLines(const QCString &s, int &docLine)
Definition: util.cpp:6876
ClassDef * newResolveTypedef(FileDef *fileScope, MemberDef *md, MemberDef **pMemType, QCString *pTemplSpec, QCString *pResolvedType, ArgumentList *actTemplParams)
Definition: util.cpp:535
static QCString baseName
Definition: scanner.cpp:10890
bool isRelated() const
Definition: memberdef.cpp:4195
ClassSDict * getClassSDict() const
Definition: namespacedef.h:98
const char * cs
int getPos() const
Definition: growbuf.h:39
int docLine() const
const char * argsString() const
Definition: memberdef.cpp:4040
static QDict< int > * htmlDirMap
Definition: doxygen.h:137
The QFileInfo class provides system-independent file information.
Definition: qfileinfo.h:51
QCString getOutputFileBase() const
Definition: groupdef.cpp:1512
QCString lower() const
Definition: qcstring.cpp:263
bool isStatic() const
Definition: memberdef.cpp:4205
Definition * definition
Definition: section.h:60
unsigned long long uint64
Definition: qglobal.h:361
type * take(uint i)
Definition: qlist.h:81
Q_EXPORT int qstrcmp(const char *str1, const char *str2)
Definition: qcstring.h:95
QCString templSpec
Definition: doxygen.h:86
bool isTypedef() const
Definition: memberdef.cpp:4155
virtual QCString trWriteList(int numEntries)=0
T * find(const char *key)
Definition: sortdict.h:232
void linkifyText(const TextGeneratorIntf &out, Definition *scope, FileDef *fileScope, Definition *self, const char *text, bool autoBreak, bool external, bool keepSpaces, int indentLevel)
Definition: util.cpp:1916
bool classVisibleInIndex(ClassDef *cd)
Definition: util.cpp:8334
QCString utf8() const
Definition: qstring.cpp:14507
bool patternMatch(const QFileInfo &fi, const QStrList *patList)
Definition: util.cpp:7784
bool isLinkable() const
Definition: dirdef.cpp:63
if(!yymsg) yymsg
ClassDef * getResolvedClass(Definition *scope, FileDef *fileScope, const char *n, MemberDef **pTypeDef, QCString *pTemplSpec, bool mayBeUnlinkable, bool mayBeHidden, QCString *pResolvedType)
Definition: util.cpp:1563
void writeObjectLink(const char *ref, const char *file, const char *anchor, const char *name)
Definition: outputlist.h:149
static bool insidePre
unsigned uint
Definition: qglobal.h:351
TextGeneratorOLImpl(OutputDocInterface &od)
Definition: util.cpp:97
int day() const
Definition: qdatetime.cpp:215
void setAutoDelete(bool enable)
Definition: qlist.h:99
static ClassSDict * classSDict
Definition: doxygen.h:99
QCString getOutputFileBase() const
Definition: pagedef.cpp:58
QCString mergeScopes(const QCString &leftScope, const QCString &rightScope)
Definition: util.cpp:6287
QCString externalLinkTarget()
Definition: util.cpp:7850
QCString args
optional arguments for the entity (if function)
Definition: reflist.h:39
bool isLinkable() const
Definition: memberdef.cpp:1161
void insertIntoList(const char *key, RefItem *item)
Definition: reflist.cpp:118
byte bytes
Alias for common language habits.
Definition: datasize.h:101
QCString stripFromIncludePath(const QCString &path)
Definition: util.cpp:306
bool matchArguments(ArgumentList *srcAl, ArgumentList *dstAl, const char *cl, const char *ns, bool checkCV, NamespaceSDict *usingNamespaces, SDict< Definition > *usingClasses)
Definition: util.cpp:3199
void endConstraintList()
Definition: outputlist.h:447
QAsciiDict< Entry > ns
static PageDef * mainPage
Definition: doxygen.h:103
std::string nl(std::size_t i=1)
bool generateLink(OutputDocInterface &od, const char *clName, const char *lr, bool inSeeBlock, const char *lt)
Definition: util.cpp:4866
constexpr std::enable_if_t< are_cv_compatible< TO, FROM >::value, std::add_pointer_t< std::remove_pointer_t< TO > > > addr(FROM &from)
Definition: ensurePointer.h:35
virtual void accept(DocVisitor *v)=0
type * toLast()
Definition: qlist.h:136
const char * langName
Definition: util.cpp:6937
QCString stripExtension(const char *fName)
Definition: util.cpp:6799
QCString & replace(uint index, uint len, const char *s)
Definition: qcstring.cpp:411
QCString file
Definition: example.h:32
static QCString * s
Definition: config.cpp:1042
static bool getScopeDefs(const char *docScope, const char *scope, ClassDef *&cd, NamespaceDef *&nd)
Definition: util.cpp:4419
QCString localName() const
const char * qPrint(const char *s)
Definition: qcstring.h:797
union ptb::content::word::word word
const bool TRUE
Definition: qglobal.h:371
static QCString str
static IndexList * indexList
Definition: doxygen.h:149
int number
Definition: util.cpp:7295
void dropFromStart(uint bytes)
Definition: bufstr.h:101
Portable versions of functions that are platform dependent.
QCString rtfFormatBmkStr(const char *name)
Definition: util.cpp:6744
static void initBaseClassHierarchy(BaseClassList *bcl)
Definition: util.cpp:5166
QCString substitute(const QCString &s, const QCString &src, const QCString &dst)
substitute all occurrences of src in s by dst
Definition: util.cpp:5088
bool resolveRef(const char *scName, const char *name, bool inSeeBlock, Definition **resContext, MemberDef **resMember, bool lookForSpecialization, FileDef *currentFile, bool checkScope)
Definition: util.cpp:4479
static QDict< int > g_extLookup
Definition: util.cpp:6933
QCString replaceAnonymousScopes(const QCString &s, const char *replacement)
Definition: util.cpp:191
QCString & append(const char *s)
Definition: qcstring.cpp:383
bool isEnumerate() const
Definition: memberdef.cpp:4145
BaseClassList * baseClasses() const
Definition: classdef.cpp:4399
GroupDef * getGroupDef() const
Definition: pagedef.cpp:52
int minClassDistance(const ClassDef *cd, const ClassDef *bcd, int level)
Definition: util.cpp:2527
QCString externalRef(const QCString &relPath, const QCString &ref, bool href)
Definition: util.cpp:7856
QCString array
Definition: arguments.h:70
bool exists() const
Definition: qfileinfo.cpp:265
QCString langToString(SrcLangExt lang)
Definition: util.cpp:8041
#define ASSERT(x)
Definition: qglobal.h:590
QCString docs
Definition: arguments.h:72
void warn_uncond(const char *fmt,...)
Definition: message.cpp:218
QCString filterTitle(const QCString &title)
Definition: util.cpp:7765
QCString stripPath(const char *s)
Definition: util.cpp:6819
int isAccessibleFromWithExpScope(Definition *scope, FileDef *fileScope, Definition *item, const QCString &explicitScopePart)
Definition: util.cpp:1051
void stackTrace()
Definition: util.cpp:7608
int filterCRLF(char *buf, int len)
Definition: util.cpp:2284
static QCString extractCanonicalType(Definition *d, FileDef *fs, QCString type)
Definition: util.cpp:3492
type * toFirst()
Definition: qlist.h:135
void insertMember(MemberDef *md)
Definition: membergroup.cpp:69