From e4cebf12a245705a0ecb714cd3794750af9d0844 Mon Sep 17 00:00:00 2001
From: dimitri <dimitri@afe2bf4a-e733-0410-8a33-86f594647bc7>
Date: Sun, 24 Dec 2000 16:16:39 +0000
Subject: Release-1.2.4

---
 INSTALL                   |   4 +-
 README                    |   4 +-
 VERSION                   |   2 +-
 doc/doxygen_manual.tex    |   2 +-
 doc/grouping.doc          |  16 +++-
 doc/install.doc           |  10 +--
 examples/example.tag      |  13 ++-
 examples/group.cpp        |  76 ++++++++++------
 packages/rpm/doxygen.spec |   2 +-
 src/classdef.cpp          |   2 +-
 src/code.l                |   3 +
 src/declinfo.l            |   5 +-
 src/doc.l                 |   2 +-
 src/doxygen.cpp           |  35 +++++---
 src/index.cpp             |  13 ++-
 src/instdox.cpp           |   2 +-
 src/latexgen.cpp          |   2 +-
 src/memberdef.cpp         |  13 +--
 src/memberlist.cpp        |   4 +-
 src/pre.l                 |   3 +-
 src/scanner.l             | 220 ++++++++++++++++++++++++++++++----------------
 src/tagreader.cpp         |   1 +
 src/util.cpp              | 145 +++++++++---------------------
 src/util.h                |   4 +-
 wintools/make.pl          |   2 +
 25 files changed, 329 insertions(+), 256 deletions(-)

diff --git a/INSTALL b/INSTALL
index babcf9e..4973d7b 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,6 +1,6 @@
-DOXYGEN Version 1.2.3-20001220
+DOXYGEN Version 1.2.4
 
 Please read the installation section of the manual for instructions.
 
 --------
-Dimitri van Heesch (20 December 2000)
+Dimitri van Heesch (24 December 2000)
diff --git a/README b/README
index 2e77ed5..644cf1d 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-DOXYGEN Version 1.2.3-20001220
+DOXYGEN Version 1.2.4
 
 Please read INSTALL for compilation instructions.
 
@@ -7,4 +7,4 @@ The latest version of doxygen can be obtained at
 
 Enjoy,
 
-Dimitri van Heesch (20 December 2000)
+Dimitri van Heesch (24 December 2000)
diff --git a/VERSION b/VERSION
index 37a34b5..e8ea05d 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.2.3-20001220
+1.2.4
diff --git a/doc/doxygen_manual.tex b/doc/doxygen_manual.tex
index 833540e..c86184a 100644
--- a/doc/doxygen_manual.tex
+++ b/doc/doxygen_manual.tex
@@ -15,7 +15,7 @@
 \documentclass[a4paper,ps2pdf]{article}
 \usepackage{a4wide}
 \usepackage{makeidx}
-\usepackage{fancyheadings}
+\usepackage{fancyhdr}
 \usepackage{epsf}
 \usepackage{doxygen}
 \usepackage{multicol}
diff --git a/doc/grouping.doc b/doc/grouping.doc
index 2f1bef7..a09cda0 100644
--- a/doc/grouping.doc
+++ b/doc/grouping.doc
@@ -33,7 +33,21 @@ To define a group, you should put the \ref cmddefgroup "\\defgroup"
 command in a special comment block. The first argument of the command 
 is a label that should uniquely identify the group.  You can make an 
 entity a member of a specific group by putting 
-a \ref cmdingroup "\\ingroup" command inside its documentation.
+a \ref cmdingroup "\\ingroup" command inside its documentation block.
+
+To avoid putting \ref cmdingroup "\\ingroup" commands in the documentation
+of each member you can also group members together by the 
+open marker <code>\@{</code> before the group and the 
+closing marker <code>\@}</code> after the group. The markers can 
+be put in the documentation of the group definition or in a separate 
+documentation block. 
+
+Groups can also be nested using these grouping markers.
+
+Note that compound entities (like classes, files and namespaces) can
+be put into multiple groups, but members (like variable, functions, typedefs
+and enums) can only be a member of one group 
+(this restriction is to avoid ambiguous linking targets).
 
 \par Example:
 \verbinclude group.cpp
diff --git a/doc/install.doc b/doc/install.doc
index 1a065a2..8a2ac19 100644
--- a/doc/install.doc
+++ b/doc/install.doc
@@ -462,19 +462,17 @@ Compilation is now done by performing the following steps:
     nmake
 \endverbatim
 
-<li>To generate the doxygen documentation, do ensure, that the
-    <code>html</code> and <code>latex</code> subdirectories exist.
-    Then go to the <code>doc</code> subdirectory and type:
+<li>To generate the doxygen documentation, go to the <code>doc</code> 
+    subdirectory and type:
 
 \verbatim
-    doxygen
     nmake
 \endverbatim
 
-    The generated docs int HTML are located in the <code>html</code>
+    The generated docs int HTML are located in the <code>..\html</code>
     subdirectory.
 
-    The sources for LaTeX documentation are located in <code>latex</code>
+    The sources for LaTeX documentation are located in <code>..\latex</code>
     subdirectory. From those sources, the DVI, PostScript, and PDF
     documentation can be generated. 
 </ol>
diff --git a/examples/example.tag b/examples/example.tag
index d30de7b..b4eaef9 100644
--- a/examples/example.tag
+++ b/examples/example.tag
@@ -1,2 +1,11 @@
->Test: "class_test.html"
-example a0 "()"
+<tagfile>
+  <compound kind="class">
+    <name>Test</name>
+    <filename>class_test.html</filename>
+    <member kind="function">
+      <name>example</name>
+      <anchor>a0</anchor>
+      <arglist>()</arglist>
+    </member>
+  </compound>
+</tagfile>
diff --git a/examples/group.cpp b/examples/group.cpp
index 53ea371..0993cc2 100644
--- a/examples/group.cpp
+++ b/examples/group.cpp
@@ -1,52 +1,74 @@
-/*! \defgroup group1 The First Group
+/** @defgroup group1 The First Group
  *  This is the first group
+ *  @{
  */
 
-/*! \defgroup group2 The Second Group
+/** @brief class C1 in group 1 */
+class C1 {};
+
+/** @brief class C2 in group 1 */
+class C2 {};
+
+/** function in group 1 */
+void func() {}
+
+/** @} end of group1 */
+
+/**
+ *  @defgroup group2 The Second Group
  *  This is the second group
  */
 
-/*! \defgroup group3 The Third Group
+/** @defgroup group3 The Third Group
  *  This is the third group
  */
 
-/*! \defgroup group4 The Fourth Group
- *  \ingroup group3
+/** @defgroup group4 The Fourth Group
+ *  @ingroup group3
  *  Group 4 is a subgroup of group 3
  */
 
-/*! \ingroup group1 
- *  \brief class C1 in group 1
- */
-class C1 {};
-
-/*! \ingroup group1
- *  \brief class C2 in group 1
- */
-class C2 {};
-
-/*! \ingroup group2
- *  \brief class C3 in group 2
+/**
+ *  @ingroup group2
+ *  @brief class C3 in group 2
  */
 class C3 {};
 
-/*! \ingroup group2
- *  \brief class C4 in group 2
+/** @ingroup group2
+ *  @brief class C4 in group 2
  */
 class C4 {};
 
-/*! \ingroup group3
- *  \brief class C5 in \link group3 the third group\endlink.
+/** @ingroup group3
+ *  @brief class C5 in @link group3 the third group@endlink.
  */
 class C5 {};
 
-/*! \ingroup group1 group2 group3 group4
- *  namespace N1 is in all groups
- *  \sa \link group1 The first group\endlink, group2, group3, group4
+/** @ingroup group1 group2 group3 group4
+ *  namespace N1 is in four groups
+ *  @sa @link group1 The first group@endlink, group2, group3, group4 
+ *
+ *  Also see @ref mypage2
  */
 namespace N1 {};
 
-/*! \file
- *  \ingroup group3
- *  \brief this file in group 3
+/** @file
+ *  @ingroup group3
+ *  @brief this file in group 3
+ */
+
+/** @defgroup group5 The Fifth Group
+ *  This is the fifth group
+ *  @{
+ */
+
+/** @page mypage1 This is a section in group 5
+ *  Text of the first section
+ */
+
+/** @page mypage2 This is another section in group 5
+ *  Text of the second section
  */
+
+/** @} */
+
diff --git a/packages/rpm/doxygen.spec b/packages/rpm/doxygen.spec
index 8646581..77ffff3 100644
--- a/packages/rpm/doxygen.spec
+++ b/packages/rpm/doxygen.spec
@@ -1,5 +1,5 @@
 Name: doxygen
-Version: 1.2.3-20001220
+Version: 1.2.4
 Summary: documentation system for C, C++ and IDL
 Release: 1
 Source0: doxygen-%{version}.src.tar.gz
diff --git a/src/classdef.cpp b/src/classdef.cpp
index 01bc655..e339c41 100644
--- a/src/classdef.cpp
+++ b/src/classdef.cpp
@@ -654,7 +654,6 @@ void ClassDef::writeDocumentation(OutputList &ol)
   QCString pageTitle=name().copy();
   QCString pageType;
   ArgumentList *outerTempArgList = outerTemplateArguments();
-  if (outerTempArgList) pageType+=" Template";
   switch(compType)
   {
     case Class:  pageType+=" Class"; break;
@@ -663,6 +662,7 @@ void ClassDef::writeDocumentation(OutputList &ol)
     default:     pageType+=" Interface"; break;
   } 
   pageTitle+=pageType+" Reference";
+  if (outerTempArgList) pageTitle.prepend(" Template");
   startFile(ol,fileName,pageTitle);
   startTitle(ol,getOutputFileBase());
   parseText(ol,theTranslator->trCompoundReference(name(),compType,outerTempArgList!=0));
diff --git a/src/code.l b/src/code.l
index 619eb2a..ec3599c 100644
--- a/src/code.l
+++ b/src/code.l
@@ -1140,6 +1140,9 @@ TYPEKW  ("bool"|"char"|"double"|"float"|"int"|"long"|"short"|"signed"|"unsigned"
 <Body>[0-9]+				{
 					  g_code->codify(yytext);
 					}
+<Body>[0-9]+[xX][0-9A-F]+		{
+					  g_code->codify(yytext);
+					}
 <MemberCall2,FuncCall>{KEYWORD}/([^a-z_A-Z0-9]) {
 					  addParmType();
 					  g_parmName=yytext; 
diff --git a/src/declinfo.l b/src/declinfo.l
index 84e2abd..7a1b020 100644
--- a/src/declinfo.l
+++ b/src/declinfo.l
@@ -225,6 +225,9 @@ void parseFuncDecl(const QCString &decl,QCString &cl,QCString &ctl,QCString &t,
   BEGIN( Start );
   declinfoYYlex();
 
+  //printf("type=`%s' class=`%s' name=`%s' args=`%s'\n",
+  //        type.data(),scope.data(),name.data(),args.data());
+
   cl=scope.copy();
   //printf("scope=`%s'\n",scope.data());
   int il=0,ir=0;
@@ -248,7 +251,7 @@ void parseFuncDecl(const QCString &decl,QCString &cl,QCString &ctl,QCString &t,
   a=removeRedundantWhiteSpace(args);
   exc=removeRedundantWhiteSpace(exceptionString);
   
-  if (!t.isEmpty() && t.at(t.length()-1)==')')
+  if (!t.isEmpty() && t.at(t.length()-1)==')') // for function pointers
   {
     a.prepend(")");
     t=t.left(t.length()-1);
diff --git a/src/doc.l b/src/doc.l
index 150bcaa..3a0f64f 100644
--- a/src/doc.l
+++ b/src/doc.l
@@ -760,7 +760,7 @@ FILE      ({FILESCHAR}*{FILEECHAR}+("."{FILESCHAR}*{FILEECHAR}+)*)|("\""[^\n\"]+
 ID        [a-z_A-Z][a-z_A-Z0-9]*
 SCOPENAME (({ID}?{BN}*"::"{BN}*)*)((~{BN}*)?{ID})
 SCOPEMASK {ID}?(("::"|"#")?(~)?{ID})+
-URLMASK   [a-z_A-Z0-9\~\:\?\@\%\#\.\-\+\/\=]+
+URLMASK   [a-z_A-Z0-9\~\:\?\@\&\%\#\.\-\+\/\=]+
 NONTERM   [\{\}\[\]\`\~\@\|\-\+\#\$\/\\\!\%\^\&\*()a-z_A-Z<>0-9]
 WORD      ({NONTERM}+([^\n\t ]*{NONTERM}+)?)|("\""[^\n\"]"\"")
 ATTR      ({B}+[^>\n]*)?
diff --git a/src/doxygen.cpp b/src/doxygen.cpp
index fb37b7e..8a12922 100644
--- a/src/doxygen.cpp
+++ b/src/doxygen.cpp
@@ -66,8 +66,6 @@
 // lists
 ClassList      classList;          // all documented classes
 NamespaceList  namespaceList;      // all namespaces
-//PageList       *exampleList = new PageList; // all example files
-//PageList       *pageList = new PageList; // all related documentation pages
 MemberNameList memberNameList;     // class member + related functions
 MemberNameList functionNameList;   // all unrelated functions
 FileNameList   inputNameList;      // all input files
@@ -122,7 +120,6 @@ void clearAll()
   namespaceDict.clear();     
   memberNameDict.clear();  
   functionNameDict.clear();
-  //substituteDict.clear();   
   sectionDict.clear();       
   inputNameDict->clear();    
   excludeNameDict.clear();  
@@ -1077,7 +1074,6 @@ static void findUsingDeclarations(Entry *root)
         }
         else if (fd)
         {
-          //printf("Inside file %s\n",fd->name().data());
           fd->addUsingDeclaration(usingCd);
         }
       }
@@ -1252,7 +1248,7 @@ static MemberDef *addVariableToFile(
               );
 
   bool ambig;
-  FileDef *fd=findFileDef(inputNameDict,root->fileName,ambig);
+  FileDef *fd = findFileDef(inputNameDict,root->fileName,ambig);
 
   // see if the function is inside a namespace
   NamespaceDef *nd = 0;
@@ -1678,8 +1674,9 @@ static void buildMemberList(Entry *root)
         //}
 
         // new member function, signal or slot.
-        //printf("new member: %s class template args=`%s'\n",
-        //          root->args.data(),argListToString(cd->templateArguments()).data());
+        //printf("new member: %s member template args=`%s'\n",
+        //          root->args.data(),
+        //          argListToString(root->mtArgList).data());
         MemberDef *md=new MemberDef(
             root->fileName,root->startLine,
             root->type,name,root->args,root->exception,
@@ -3246,11 +3243,12 @@ static void findMember(Entry *root,QCString funcDecl,QCString related,bool overl
     }
   }
   
-  if (root->tArgList==0 && !classTempList.isEmpty())
+  if (root->tArgList==0 && root->mtArgList==0 && !classTempList.isEmpty())
   {
     // no template specifiers found during parsing (because \fn was used), 
     // but there are template names in the scope, so we build the template 
     // specifiers from that.
+    printf("Building template list from `%s'\n",classTempList.data());
     root->tArgList = new ArgumentList;
     QRegExp re(idMask);
     int i,p=0,l;
@@ -3385,7 +3383,7 @@ static void findMember(Entry *root,QCString funcDecl,QCString related,bool overl
                          "4. class definition %s found\n",cd->name().data());
             int ci;
             ArgumentList *classTemplArgs = cd->templateArguments();
-            ArgumentList *funcTemplArgs  = md->templateArguments();
+            ArgumentList *funcTemplArgs  = md->memberDefTemplateArguments();
             if ((ci=cd->name().find("::"))!=-1) // nested class
             {
               ClassDef *parentClass = getClass(cd->name().left(ci));
@@ -3475,8 +3473,11 @@ static void findMember(Entry *root,QCString funcDecl,QCString related,bool overl
               //printf("root->tArgList=`%s'\n",argListToString(root->tArgList).data());
               if (matching) // replace member's argument list
               {
-                //printf("Setting scope template argument of member to %s\n",
-                //    argListToString(root->tArgList).data()
+                //printf("Setting scope template argument of member %s to %s\n",
+                //    md->name().data(), argListToString(root->tArgList).data()
+                //    );
+                //printf("Setting member template argument of member %s to %s\n",
+                //    md->name().data(), argListToString(root->mtArgList).data()
                 //    );
                 md->setScopeDefTemplateArguments(root->tArgList);
                 md->setMemberDefTemplateArguments(root->mtArgList);
@@ -3949,7 +3950,17 @@ static void findEnums(Entry *root)
       else if (isGlobal)
       {
         md->setDefinition(name);
-        fd->insertMember(md);
+        if (fd==0 && root->tagInfo)
+        {
+          bool ambig;
+          QCString filePathName = root->parent->fileName;
+          fd=findFileDef(inputNameDict,filePathName,ambig);
+        }
+        if (fd) 
+        {
+          fd->insertMember(md);
+          md->setFileDef(fd);
+        }
       }
       else if (cd)
       {
diff --git a/src/index.cpp b/src/index.cpp
index 9ef8bc1..08a77cd 100644
--- a/src/index.cpp
+++ b/src/index.cpp
@@ -704,7 +704,7 @@ int countNamespaces()
   NamespaceDef *nd;
   for (;(nd=nli.current());++nli)
   {
-    if (nd->isLinkableInProject() && nd->countMembers()>0) count++;
+    if (nd->isLinkableInProject()) count++;
   }
   return count;
 }
@@ -746,12 +746,17 @@ void writeNamespaceIndex(OutputList &ol)
   //ol.newParagraph();
   ol.endTextBlock();
 
-  ol.startIndexList();
+  bool first=TRUE;
   NamespaceDef *nd=namespaceList.first();
   while (nd)
   {
-    if (nd->isLinkableInProject() && nd->countMembers()>0)
+    if (nd->isLinkableInProject())
     {
+      if (first)
+      {
+        ol.startIndexList();
+        first=FALSE;
+      }
       ol.writeStartAnnoItem("namespace",nd->getOutputFileBase(),0,nd->name());
       if (!nd->briefDescription().isEmpty())
       {
@@ -776,7 +781,7 @@ void writeNamespaceIndex(OutputList &ol)
     }
     nd=namespaceList.next();
   }
-  ol.endIndexList();
+  if (!first) ol.endIndexList();
   if (hasHtmlHelp)
   {
     htmlHelp->decContentsDepth();
diff --git a/src/instdox.cpp b/src/instdox.cpp
index e891f3c..97df7c6 100644
--- a/src/instdox.cpp
+++ b/src/instdox.cpp
@@ -146,7 +146,7 @@ void writeInstallScript()
     t << "      print STDERR \"Error: opening file $oldf for writing\\n\";\n";
     t << "      exit 1;\n";
     t << "    }\n";
-    t << "    if ($oldf!=\"tree.js\") {\n";
+    t << "    if ($oldf ne \"tree.js\") {\n";
     t << "      while (<F>) {\n";
     t << "        s/doxygen\\=\\\"([^ \\\"\\:\\t\\>\\<]*)\\:([^ \\\"\\t\\>\\<]*)\\\" (href|src)=\\\"\\2/doxygen\\=\\\"$1:$subst{$1}\\\" \\3=\\\"$subst{$1}/g;\n";
     t << "        print G \"$_\";\n";
diff --git a/src/latexgen.cpp b/src/latexgen.cpp
index 7baafa1..416b5e3 100644
--- a/src/latexgen.cpp
+++ b/src/latexgen.cpp
@@ -510,7 +510,7 @@ void LatexGenerator::startIndexSection(IndexSections is)
         bool found=FALSE;
         while (nd && !found)
         {
-          if (nd->isLinkableInProject() && nd->countMembers()>0)
+          if (nd->isLinkableInProject())
           {
             if (Config::compactLatexFlag) t << "\\section"; else t << "\\chapter";
             t << "{"; // Namespace Documentation}\n":
diff --git a/src/memberdef.cpp b/src/memberdef.cpp
index cf6d9c2..c6c5354 100644
--- a/src/memberdef.cpp
+++ b/src/memberdef.cpp
@@ -258,7 +258,7 @@ MemberDef::MemberDef(const char *df,int dl,
   initLines=0;
   type=t;
   args=a;
-  args=args.stripWhiteSpace();
+  args=removeRedundantWhiteSpace(args);
   if (type.isEmpty()) decl=name()+args; else decl=type+" "+name()+args;
   declLine=0;
   memberGroup=0;
@@ -763,11 +763,11 @@ void MemberDef::writeDeclaration(OutputList &ol,
 
     // if member template specifiers are not part of the name, but they are
     // present, we add them
-    if (tArgList && !(name().find('<')!=-1 && name().find('>')!=-1)
-        && cd && cd->templateArguments())
-    {
-      ol.docify(tempArgListToString(tArgList));
-    }
+    //if (tArgList && !(name().find('<')!=-1 && name().find('>')!=-1)
+    //    && cd && cd->templateArguments())
+    //{
+    //  ol.docify(tempArgListToString(tArgList));
+    //}
 
     if (argsString()) 
     {
@@ -923,6 +923,7 @@ void MemberDef::writeDocumentation(MemberList *ml,OutputList &ol,
         if (si==-1) si=0;
         while ((pi=r.match(ldef,i+l,&l))!=-1) ei=i=pi+l;
         // first si characters of ldef contain compound type name
+        ol.startMemberDocName();
         ol.docify(ldef.left(si));
         ol.docify(" { ... } ");
         // last ei characters of ldef contain pointer/reference specifiers
diff --git a/src/memberlist.cpp b/src/memberlist.cpp
index 7a1a538..964607f 100644
--- a/src/memberlist.cpp
+++ b/src/memberlist.cpp
@@ -292,7 +292,7 @@ void MemberList::writePlainDeclarations(OutputList &ol,
             {
               if (!Config::genTagFile.isEmpty())
               {
-                tagFile << "    <member>" << endl;
+                tagFile << "    <member kind=\"enumeration\">" << endl;
                 tagFile << "      <name>" << convertToXML(md->name()) << "</name>" << endl; 
                 tagFile << "      <anchor>" << convertToXML(md->anchor()) << "</anchor>" << endl; 
                 tagFile << "      <arglist>" << convertToXML(md->argsString()) << "</arglist>" << endl; 
@@ -332,7 +332,7 @@ void MemberList::writePlainDeclarations(OutputList &ol,
               {
               if (!Config::genTagFile.isEmpty())
               {
-                tagFile << "    <member>" << endl;
+                tagFile << "    <member kind=\"enumvalue\">" << endl;
                 tagFile << "      <name>" << convertToXML(fmd->name()) << "</name>" << endl; 
                 tagFile << "      <anchor>" << convertToXML(fmd->anchor()) << "</anchor>" << endl; 
                 tagFile << "      <arglist>" << convertToXML(fmd->argsString()) << "</arglist>" << endl; 
diff --git a/src/pre.l b/src/pre.l
index e6103b8..570bdc0 100644
--- a/src/pre.l
+++ b/src/pre.l
@@ -1000,7 +1000,8 @@ BN	[ \t\r\n]
   					  if (g_includeStack.isEmpty()) 
 					    g_curlyCount--;
 					  outputChar(*yytext);
-					  ASSERT(g_curlyCount>=0);
+					  // This should hold otherwise the preprocessor is confused
+					  //ASSERT(g_curlyCount>=0); 
   					}
 <CopyLine>"'"\\[0-7]{1,3}"'"		{ 
   					  outputArray(yytext,yyleng);
diff --git a/src/scanner.l b/src/scanner.l
index cfcc689..6bf33ed 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -141,7 +141,8 @@ static QCString         *pCopyRoundString;
 static QCString         *pCopyCurlyString;
 static QCString         *pCopyQuotedString;
 static QCString         *pSkipDoc;
-static QCString         autoGroupName;
+static QStack<QCString> autoGroupNameStack;
+static QCString         lastDefGroup;
 
 static bool             insideFormula;
 
@@ -165,6 +166,7 @@ static void initParser()
   virt = Normal;
   baseVirt = Normal;
   isTypedef = FALSE;
+  autoGroupNameStack.clear();
 }
 
 static void initEntry()
@@ -174,11 +176,49 @@ static void initEntry()
   current->virt       = virt;
   current->stat       = gstat;
   current->mGrpId     = memberGroupId;
-  if (!autoGroupName.isEmpty())
+  if (!autoGroupNameStack.isEmpty())
   {
-    current->groups->append(new QCString(autoGroupName));
+    current->groups->append(new QCString(*autoGroupNameStack.top()));
   }
 }
+
+//-----------------------------------------------------------------------------
+
+/// remove old group name (if given) and add new one (if given)
+static void setCurrentGroup( QCString *oldgroup, QCString *newgroup )
+{
+   if (oldgroup)
+   {
+      /* remove auto group name from current entry and discard it */
+      QCString *s = current->groups->first();
+      int i=0;
+      while (s)
+      {
+         if (*s==*oldgroup)
+         {
+            current->groups->remove(i);
+            break;
+         }
+         s=current->groups->next();
+         i++;
+      }
+   }
+
+   /* use new group name instead? */
+   if ( newgroup )
+   {
+      current->groups->append(new QCString(*newgroup));
+   } 
+}
+
+static int newMemberGroupId()
+{
+  static int curGroupId=0;
+  return curGroupId++;
+}
+
+static void startGroup();
+static void endGroup();
 //-----------------------------------------------------------------------------
 
 static void lineCount()
@@ -213,12 +253,6 @@ static QCString stripQuotes(const char *s)
   return name;
 }
 
-static int newMemberGroupId()
-{
-  static int curGroupId=0;
-  return curGroupId++;
-}
-
 static void newDocState();
 
 //-----------------------------------------------------------------
@@ -707,6 +741,10 @@ TITLE     [tT][iI][tT][lL][eE]
 					  current->bodyLine  = yyLineNr;
 					  if (current->mtArgList) // transfer template arguments
 					  {
+					    if (current->tArgList)
+					    {
+					      delete current->tArgList;
+					    }
 					    current->tArgList = current->mtArgList;
 					    current->mtArgList = 0;
 					  }
@@ -721,6 +759,15 @@ TITLE     [tT][iI][tT][lL][eE]
 					  current->fileName  = yyFileName;
 					  current->startLine = yyLineNr;
 					  current->bodyLine  = yyLineNr;
+					  if (current->mtArgList) // transfer template arguments
+					  {
+					    if (current->tArgList)
+					    {
+					      delete current->tArgList;
+					    }
+					    current->tArgList = current->mtArgList;
+					    current->mtArgList = 0;
+					  }
 					  lineCount() ;
 					  BEGIN( CompoundName ) ;
 					}
@@ -771,13 +818,15 @@ TITLE     [tT][iI][tT][lL][eE]
 					  //  printf("-------> member template \n");
 					    if (current->mtArgList)
 					    {
-					      current->mtArgList->clear();
+					      if (current->tArgList)
+					      {
+					        delete current->tArgList;
+					      }
+					      current->tArgList = current->mtArgList;
+					      current->mtArgList = 0;
                                             }
-					    else
-					    {
-					      current->mtArgList = new ArgumentList;
-					      current->mtArgList->setAutoDelete(TRUE);
-					    }
+					    current->mtArgList = new ArgumentList;
+					    current->mtArgList->setAutoDelete(TRUE);
 					    currentArgumentList = current->mtArgList;
 					  //}
 					  //else // class template specifier
@@ -858,6 +907,11 @@ TITLE     [tT][iI][tT][lL][eE]
   					  sharpCount=0;
 					  lineCount();
 					  addType( current );
+					  if (current->mtArgList && current->tArgList==0)
+					  {
+					    current->tArgList=current->mtArgList;
+					    current->mtArgList=0;
+					  }
   					  current->name=yytext;
 					  current->name=current->name.stripWhiteSpace();
 					  current->scopeSpec.resize(0);
@@ -1101,26 +1155,7 @@ TITLE     [tT][iI][tT][lL][eE]
 					  }
   					}
 <FindMembers,FindFields>"//"([!*]?){B}*"@{"|"/*"([!*]?){B}*"@{"	{
-					  if (memberGroupId!=NOGROUP)
-					  {
-  					    warn(yyFileName,yyLineNr,"Warning: ignoring nested member group. "
-					         "Previous command was found at line %d.",lastMemberGroupLine);
-					  }
-					  else if (memberGroupHeader.isEmpty())
-					  {
-					    //warn("Warning: member group does not have a header "
-					    //	 "at line %d of %s.\n",yyLineNr,yyFileName);
-					    memberGroupHeader="[NOHEADER]";
-					    memberGroupId = newMemberGroupId();
-					    current->mGrpId = memberGroupId;
-					    lastMemberGroupLine = yyLineNr;
-					  }
-					  else
-					  {
-					    memberGroupId = newMemberGroupId();
-					    current->mGrpId = memberGroupId;
-					    lastMemberGroupLine = yyLineNr;
-					  }
+  					  startGroup();
 					  tmpDocType=-1;
 					  if (current_root->section & Entry::SCOPE_MASK)
 					      current->inside = current_root->name+"::";
@@ -1139,43 +1174,7 @@ TITLE     [tT][iI][tT][lL][eE]
 					  }
   					}
 <FindMembers,FindFields,ReadInitializer>"//"([!*]?){B}*"@}"|"/*"([!*]?){B}*"@}"{B}*"*/"	{
-					  if (memberGroupId==NOGROUP && autoGroupName.isEmpty())
-					  {
-					    warn(yyFileName,yyLineNr,
-                                                 "Warning: end of group without matching begin.");
-					  }
-					  else if (memberGroupId!=NOGROUP) // end of member group
-					  {
-  					    memberHeaderDict.insert(memberGroupId,
-					                            new QCString(memberGroupHeader.stripWhiteSpace())
-					  			  );
-					    memberDocDict.insert(memberGroupId,
-					      	               new QCString(memberGroupDocs)
-							      );
-					    memberGroupId=NOGROUP;
-					    if (YY_START!=ReadInitializer) 
-					    {
-					      current->mGrpId=NOGROUP;
-					    }
-					    memberGroupHeader.resize(0);
-					    memberGroupDocs.resize(0);
-					  }
-					  else if (!autoGroupName.isEmpty()) // end of group
-					  {
-					    QCString *s = current->groups->first();
-					    int i=0;
-					    while (s)
-					    {
-					      if (*s==autoGroupName)
-					      {
-					         current->groups->remove(i);
-					         break;
-					      }
-					      s=current->groups->next();
-					      i++;
-					    }
-					    autoGroupName.resize(0);
-					  }
+  					  endGroup();
   					}
 <FindMembers>"="			{
   					  current->bodyLine = yyLineNr;
@@ -2604,6 +2603,7 @@ TITLE     [tT][iI][tT][lL][eE]
  					  BEGIN( ExampleDocArg1 );
 					}
 <LineDoc>{CMD}"name"[^\n]*\n		{
+  					  lastDefGroup.resize(0);
   					  memberGroupHeader=&yytext[5];
 					  memberGroupHeader=memberGroupHeader.stripWhiteSpace(); 
 					  current->section = Entry::MEMBERGRP_SEC;
@@ -2613,12 +2613,10 @@ TITLE     [tT][iI][tT][lL][eE]
 					  BEGIN( lastDocContext );
   					}
 <Doc,JavaDoc>{CMD}"name"{B}+ 		{
-  					  //printf("--> mgroup found!\n");
+  					  lastDefGroup.resize(0);
 					  current->section = Entry::MEMBERGRP_SEC;
 					  current->fileName = yyFileName;
 					  current->startLine = yyLineNr;
-  					  //lastMemberGroupContext = lastDocContext;
-					  //lastDocContext = StoreGroupDocs;
 					  memberGroupHeader.resize(0);
 					  memberGroupDocs.resize(0);
 					  BEGIN(GroupHeader);
@@ -2761,8 +2759,10 @@ TITLE     [tT][iI][tT][lL][eE]
   					  yyLineNr++;
 					  
   					}
-<GroupDocArg1>{ID}(".html"?)		{ // the .html stuff is for Qt compatibility
+<GroupDocArg1>{ID}(".html"?)		{ 
   					  current->name = yytext;
+					  lastDefGroup = yytext;
+  					  // the .html stuff is for Qt compatibility
 					  if (current->name.right(5)==".html") 
 					    current->name=current->name.left(current->name.length()-5);
 					  BEGIN(GroupDocArg2);
@@ -2990,6 +2990,9 @@ TITLE     [tT][iI][tT][lL][eE]
 <SkipCode>"//"				{
   					  *pSkipDoc+=yytext;
   					}
+<SkipCode>"/*"				{
+  					  *pSkipDoc+=yytext;
+  					}
 <SkipCode>[^ \<\*\t\/\\\n]+		{
   					  *pSkipDoc+=yytext;
   					}
@@ -3028,10 +3031,10 @@ TITLE     [tT][iI][tT][lL][eE]
 							  lineCount();
 							  BEGIN( GroupName );
   							}
-<ClassDoc,Doc,JavaDoc>{CMD}"{"				{
+<ClassDoc,Doc,JavaDoc>"@{"				{
   							  if (current->section == Entry::GROUPDOC_SEC)
 							  {
-							    autoGroupName=current->name;
+							    autoGroupNameStack.push(new QCString(current->name));
 							  }
 							  else if (current->section == Entry::MEMBERGRP_SEC)
 							  {
@@ -3044,6 +3047,9 @@ TITLE     [tT][iI][tT][lL][eE]
 							    warn(yyFileName,yyLineNr,"Warning: @{ may only be used in a group block!\n");
 							  }
   							}
+<ClassDoc,Doc,JavaDoc>"@}"				{
+  							  endGroup();
+  							}
 <ExampleDoc,PageDoc,ClassDoc>.    	 	        { current->doc += yytext; }
 <Doc,JavaDoc,LineDoc,ExampleDoc,PageDoc,ClassDoc>^{B}*"//" 
 <Doc,ExampleDoc,PageDoc,ClassDoc>"//"  			{ current->doc += yytext; }
@@ -3500,6 +3506,64 @@ TITLE     [tT][iI][tT][lL][eE]
 
 //----------------------------------------------------------------------------
 
+static void startGroup()
+{
+  if (memberGroupId!=NOGROUP)
+  {
+    warn(yyFileName,yyLineNr,"Warning: ignoring nested member group. "
+	"Previous command was found at line %d.",lastMemberGroupLine);
+  }
+  else if (!lastDefGroup.isEmpty())
+  {
+    setCurrentGroup( autoGroupNameStack.top(), &lastDefGroup);   
+    autoGroupNameStack.push(new QCString(lastDefGroup));
+    lastDefGroup.resize(0);
+  }
+  else 
+  {
+    if (memberGroupHeader.isEmpty())
+    {
+      //warn("Warning: member group does not have a header "
+      //	 "at line %d of %s.\n",yyLineNr,yyFileName);
+      memberGroupHeader="[NOHEADER]";
+    }
+    memberGroupId = newMemberGroupId();
+    current->mGrpId = memberGroupId;
+    lastMemberGroupLine = yyLineNr;
+  }
+}
+
+static void endGroup()
+{
+  if (memberGroupId==NOGROUP && autoGroupNameStack.isEmpty())
+  {
+    warn(yyFileName,yyLineNr,
+	"Warning: end of group without matching begin.");
+  }
+  else if (memberGroupId!=NOGROUP) // end of member group
+  {
+    memberHeaderDict.insert(memberGroupId,
+	new QCString(memberGroupHeader.stripWhiteSpace())
+			   );
+    memberDocDict.insert(memberGroupId,
+	new QCString(memberGroupDocs)
+			);
+    memberGroupId=NOGROUP;
+    if (YY_START!=ReadInitializer) 
+    {
+      current->mGrpId=NOGROUP;
+    }
+    memberGroupHeader.resize(0);
+    memberGroupDocs.resize(0);
+  }
+  else if (!autoGroupNameStack.isEmpty()) // end of group
+  {
+    QCString *oldName = autoGroupNameStack.pop();
+    setCurrentGroup(oldName,autoGroupNameStack.top());
+    delete oldName;
+  }
+}
+
 static void newDocState()
 {
   if (tmpDocType!=-1)
diff --git a/src/tagreader.cpp b/src/tagreader.cpp
index c226320..3e74d77 100644
--- a/src/tagreader.cpp
+++ b/src/tagreader.cpp
@@ -719,6 +719,7 @@ void TagFileParser::buildMemberList(Entry *ce,QList<TagMemberInfo> &members)
     me->protection = tmi->prot;
     me->virt       = tmi->virt;
     me->stat       = tmi->isStatic;
+    me->fileName   = ce->fileName;
     TagInfo *ti    = new TagInfo;
     ti->tagName    = m_tagName;
     ti->anchor     = tmi->anchor;
diff --git a/src/util.cpp b/src/util.cpp
index 45e1e07..43e9b2c 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -299,12 +299,8 @@ QCString stripAnnonymousNamespaceScope(const QCString &s)
 
 void writePageRef(OutputList &ol,const char *cn,const char *mn)
 {
-  //bool htmlOn = ol.isEnabled(OutputGenerator::Html);
-  //bool manOn  = ol.isEnabled(OutputGenerator::Man);
-
   ol.pushGeneratorState();
   
-  //ol.enableAll();
   ol.disable(OutputGenerator::Html);
   ol.disable(OutputGenerator::Man);
   if (Config::pdfHyperFlag) ol.disable(OutputGenerator::Latex);
@@ -313,12 +309,13 @@ void writePageRef(OutputList &ol,const char *cn,const char *mn)
   ol.docify(theTranslator->trPageAbbreviation());
   ol.endPageRef(cn,mn);
 
-  //if (htmlOn) ol.enable(OutputGenerator::Html);
-  //if (manOn)  ol.enable(OutputGenerator::Man);
-
   ol.popGeneratorState();
 }
 
+/*! Generate a place holder for a position in a list. Used for
+ *  translators to be able to specify different elements orders
+ *  depending on whether text flows from left to right or visa versa.
+ */
 QCString generateMarker(int id)
 {
   QCString result;
@@ -326,8 +323,9 @@ QCString generateMarker(int id)
   return result;
 }
 
-// strip part of the path if it matches
-// one of the paths in the stripFromPath list
+/*! strip part of \a path if it matches
+ *  one of the paths in the Config::stripFromPath list
+ */
 QCString stripFromPath(const QCString &path)
 {
   const char *s=Config::stripFromPath.first();
@@ -343,9 +341,10 @@ QCString stripFromPath(const QCString &path)
   return path;
 }
 
-// try to determine if this files is a source or a header file by looking
-// at the extension (5 variations are allowed in both upper and lower case)
-// If anyone knows or uses another extension please let me know :-)
+/*! try to determine if \a name is a source or a header file name by looking
+ * at the extension. A number of variations is allowed in both upper and 
+ * lower case) If anyone knows or uses another extension please let me know :-)
+ */
 int guessSection(const char *name)
 {
   QCString n=((QCString)name).lower();
@@ -369,35 +368,9 @@ int guessSection(const char *name)
   return 0;
 }
 
-
-//QCString resolveDefines(const char *n)
-//{
-//  return n;
-//  if (n)
-//  {
-//    Define *def=defineDict[n]; 
-//    if (def && def->nargs==0 && !def->definition.isEmpty())
-//    {
-//      return def->definition;
-//    }
-//    return n;
-//  }
-//  return 0;
-//}
-
-//QCString resolveTypedefs(const QCString &n)
-//{
-// QCString *subst=typedefDict[n];
-//  if (subst && !subst->isEmpty())
-//  {
-//    return *subst;
-//  }
-//  else
-//  {
-//    return n;
-//  }
-//}
-
+/*! Get a class definition given its name. 
+ *  Returns 0 if the class is not found.
+ */
 ClassDef *getClass(const char *name)
 {
   if (name==0 || name[0]=='\0') return 0;
@@ -515,9 +488,11 @@ QCString removeRedundantWhiteSpace(const QCString &s)
 	(i!=0 && i!=l-1 && isId(s.at(i-1)) && isId(s.at(i+1)))
        )
     {
-      if ((c=='*' || c=='&' || c=='@') && 
-	  !result.isEmpty() && isId(result.at(result.length()-1))
-	 ) result+=' ';
+      if ((c=='*' || c=='&' || c=='@'))
+      {  
+        uint rl=result.length();
+	if (rl>0 && (isId(result.at(rl-1)) || result.at(rl-1)=='>')) result+=' ';
+      }
       result+=c;
     }
   }
@@ -571,12 +546,6 @@ void linkifyText(const TextGeneratorIntf &out,const char *scName,const char *nam
       if (i==-1) i=splitText.find(' ');
       if (i!=-1) // add a link-break at i in case of Html output
       {
-        //ol.docify(splitText.left(i+1));
-        //ol.pushGeneratorState();
-        //ol.disableAllBut(OutputGenerator::Html);
-        //ol.lineBreak();
-        //ol.popGeneratorState();
-        //ol.docify(splitText.right(splitLength-i-1));
         out.writeString(splitText.left(i+1));
         out.writeBreak();
         out.writeString(splitText.right(splitLength-i-1));
@@ -644,12 +613,13 @@ void linkifyText(const TextGeneratorIntf &out,const char *scName,const char *nam
         }
       } while (!found && scopeOffset>=0);
 
-      //if (!found) printf("Trying to link %s in %s\n",word.data(),scName);
+      //if (!found) printf("Trying to link %s in %s\n",word.data(),scName); 
       if (!found && 
           getDefs(scName,word,0,md,cd,fd,nd,gd) && 
           (md->isTypedef() || md->isEnumerate() || 
-           md->isReference() || md->isVariable()) && 
-           (external ? md->isLinkable() : md->isLinkableInProject()) 
+           md->isReference() || md->isVariable()
+          ) && 
+          (external ? md->isLinkable() : md->isLinkableInProject()) 
          )
       {
         //printf("Found ref\n");
@@ -760,26 +730,6 @@ QCString argListToString(ArgumentList *al)
   return result;
 }
 
-//QCString tempArgListToString(ArgumentList *al)
-//{
-//  QCString result;
-//  if (al==0) return result;
-//  Argument *a=al->first();
-//  result+="<";
-//  while (a)
-//  {
-//    int ni=a->type.findRev(' ');
-//    if (ni!=-1) 
-//      result+=a->type.right(a->type.length()-ni-1);
-//    else
-//      result+=a->type;
-//    a = al->next();
-//    if (a) result+=",";
-//  }
-//  result+=">";
-//  return result;
-//}
-
 QCString tempArgListToString(ArgumentList *al)
 {
   QCString result;
@@ -1001,13 +951,16 @@ void setAnchors(char id,MemberList *ml,int groupId)
   MemberDef *md;
   for (;(md=mli.current());++mli)
   {
-    QCString anchor;
-    if (groupId==-1)
-      anchor.sprintf("%c%d",id,count++);
-    else
-      anchor.sprintf("%c%d_%d",id,groupId,count++);
-    //printf("Member %s anchor %s\n",md->name(),anchor.data());
-    md->setAnchor(anchor);
+    if (!md->isReference())
+    {
+      QCString anchor;
+      if (groupId==-1)
+        anchor.sprintf("%c%d",id,count++);
+      else
+        anchor.sprintf("%c%d_%d",id,groupId,count++);
+      //printf("Member %s anchor %s\n",md->name(),anchor.data());
+      md->setAnchor(anchor);
+    }
   }
 }
 
@@ -2112,7 +2065,7 @@ bool getDefs(const QCString &scName,const QCString &memberName,
       {
         QList<MemberDef> members;
         
-        //printf("Function with global scope `%s' args=`%s'\n",namespaceName.data(),args);
+        //printf("  Function with global scope `%s' args=`%s'\n",namespaceName.data(),args);
         MemberListIterator mli(*mn);
         for (mli.toFirst();(md=mli.current());++mli)
         {
@@ -2821,28 +2774,6 @@ QCString convertNameToFile(const char *name,bool allowDots)
   return result;
 }
 
-/*! Converts a string to HTML-encoded string */
-QCString convertToHtml(const QCString &s)
-{
-  QCString result;
-  char c;
-  const char *p=s.data();
-  while ((c=*p++)!=0)
-  {
-    switch(c)
-    {
-      case '<': result+="&lt;"; break;
-      case '>': result+="&gt;"; break;
-      case '&': result+="&amp;"; break;
-      case '"': result+="&quot;"; break;
-      default: 
-          result+=c;
-          break;
-    }
-  }
-  return result;
-}
-
 /*! Input is a scopeName, output is the scopename split into a
  *  namespace part (as large as possible) and a classname part.
  */
@@ -2923,6 +2854,7 @@ QCString stripScope(const char *name)
   return result;
 }
 
+/*! Converts a string to an XML-encoded string */
 QCString convertToXML(const char *s)
 {
   QCString result;
@@ -2943,3 +2875,10 @@ QCString convertToXML(const char *s)
   }
   return result;
 }
+
+/*! Converts a string to a HTML-encoded string */
+QCString convertToHtml(const char *s)
+{
+  return convertToXML(s);
+}
+
diff --git a/src/util.h b/src/util.h
index 91a1a55..0b5e846 100644
--- a/src/util.h
+++ b/src/util.h
@@ -133,7 +133,6 @@ void setFileNameForSections(QList<QCString> *anchorList,const char *fileName);
 QCString stripAnnonymousScope(const QCString &s);
 QCString stripAnnonymousNamespaceScope(const QCString &s);
 QCString stripFromPath(const QCString &path);
-QCString convertToXML(const char *s);
 bool rightScopeMatch(const QCString &scope, const QCString &name);
 bool leftScopeMatch(const QCString &scope, const QCString &name);
 void writePageRef(OutputList &ol,const char *cn,const char *mn);
@@ -145,12 +144,13 @@ void initClassHierarchy(ClassList *cl);
 bool hasVisibleRoot(BaseClassList *bcl);
 int minClassDistance(ClassDef *cd,ClassDef *bcd,int level=0);
 QCString convertNameToFile(const char *name,bool allowDots=FALSE);
-QCString convertToHtml(const QCString &s);
 void extractNamespaceName(const QCString &scopeName,
                           QCString &className,QCString &namespaceName);
 QCString insertTemplateSpecifierInScope(const QCString &scope,const QCString &templ);
 QCString stripScope(const char *name);
 int iSystem(const char *command,const char *args,bool isBatchFile=FALSE);
+QCString convertToHtml(const char *s);
+QCString convertToXML(const char *s);
 
 #endif
 
diff --git a/wintools/make.pl b/wintools/make.pl
index e34fc2a..737f1ee 100755
--- a/wintools/make.pl
+++ b/wintools/make.pl
@@ -11,6 +11,8 @@ use Cwd;
 
 # get current working directory
 $pwd=cwd();
+# work-around slashes problems for badly ported perl interpreters
+$pwd=~s{/}{\\}g;
 
 # create config file
 open(FILE,">makeconfig") || die "Cannot create file makeconfig!";
-- 
cgit v0.12

