From 6505abff80c988faf734b2e4c31cd2a94c2c10b5 Mon Sep 17 00:00:00 2001
From: dimitri <dimitri@afe2bf4a-e733-0410-8a33-86f594647bc7>
Date: Sun, 17 Dec 2000 15:15:12 +0000
Subject: Release-1.2.3-20001217

---
 INSTALL                          |   4 +-
 Makefile.in                      |   5 +-
 Makefile.win.in                  |  45 --
 Makefile.win_make.in             |  30 ++
 Makefile.win_nmake.in            |  45 ++
 README                           |   4 +-
 VERSION                          |   2 +-
 addon/configgen/config_templ.l   |   9 +
 doc/Makefile.win.in              |  30 --
 doc/Makefile.win_make.in         |  30 ++
 doc/Makefile.win_nmake.in        |  30 ++
 doc/doxygen_manual.tex           |   1 +
 doc/install.doc                  |  27 +-
 make.bat                         |  52 ++-
 packages/rpm/doxygen.spec        |   2 +-
 src/classdef.cpp                 |  42 +-
 src/classlist.cpp                |   5 +
 src/config.l                     |  11 +-
 src/definition.h                 |   2 +-
 src/diagram.cpp                  |  11 +-
 src/doc.l                        |   2 +-
 src/dot.cpp                      |  80 ++--
 src/doxygen.cpp                  | 267 ++++++++----
 src/doxygen.pro.in               |  27 +-
 src/doxygen.t                    |   3 -
 src/doxytag.l                    |  59 ++-
 src/doxytag.pro.in               |  19 +-
 src/entry.cpp                    |   5 +
 src/entry.h                      |   8 +
 src/filedef.cpp                  |  38 +-
 src/filedef.h                    |   7 +-
 src/formula.cpp                  |  14 +-
 src/ftvhelp.cpp                  |  39 +-
 src/groupdef.cpp                 |  60 ++-
 src/htmlgen.cpp                  |   1 +
 src/htmlgen.h                    |   2 +-
 src/index.cpp                    |  33 +-
 src/latexgen.cpp                 |  33 +-
 src/latexgen.h                   |   2 +-
 src/mangen.h                     |   2 +-
 src/memberdef.cpp                |  53 ++-
 src/memberdef.h                  |   3 +
 src/membergroup.h                |   2 -
 src/memberlist.cpp               |  20 +-
 src/namespacedef.cpp             |  14 +-
 src/outputgen.h                  |   2 +-
 src/outputlist.h                 |  34 +-
 src/page.h                       |  10 +
 src/rtfgen.cpp                   |  28 +-
 src/rtfgen.h                     |   2 +-
 src/scanner.l                    | 168 ++++----
 src/sortdict.h                   |  40 +-
 src/tag.h                        |  23 -
 src/tag.l                        | 291 -------------
 src/tagreader.cpp                | 902 +++++++++++++++++++++++++++++++++++++++
 src/tagreader.h                  |  10 +
 src/translator_de.h              |   2 +-
 src/util.cpp                     |  85 +++-
 src/util.h                       |   3 +-
 src/xml.cpp                      |  17 +-
 src/xml.h                        |   1 +
 tmake/lib/win32-mingw/app.t      |   6 +
 tmake/lib/win32-mingw/generic.t  | 241 +++++++++++
 tmake/lib/win32-mingw/lib.t      |   6 +
 tmake/lib/win32-mingw/subdirs.t  |   2 +
 tmake/lib/win32-mingw/tmake.conf |  56 +++
 wintools/make.pl                 |  11 +-
 67 files changed, 2273 insertions(+), 847 deletions(-)
 delete mode 100644 Makefile.win.in
 create mode 100644 Makefile.win_make.in
 create mode 100644 Makefile.win_nmake.in
 delete mode 100644 doc/Makefile.win.in
 create mode 100644 doc/Makefile.win_make.in
 create mode 100644 doc/Makefile.win_nmake.in
 delete mode 100644 src/tag.h
 delete mode 100644 src/tag.l
 create mode 100644 src/tagreader.cpp
 create mode 100644 src/tagreader.h
 create mode 100755 tmake/lib/win32-mingw/app.t
 create mode 100755 tmake/lib/win32-mingw/generic.t
 create mode 100755 tmake/lib/win32-mingw/lib.t
 create mode 100755 tmake/lib/win32-mingw/subdirs.t
 create mode 100755 tmake/lib/win32-mingw/tmake.conf

diff --git a/INSTALL b/INSTALL
index 56ae336..8041a58 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,6 +1,6 @@
-DOXYGEN Version 1.2.3-20001203
+DOXYGEN Version 1.2.3-20001217
 
 Please read the installation section of the manual for instructions.
 
 --------
-Dimitri van Heesch (03 December 2000)
+Dimitri van Heesch (17 December 2000)
diff --git a/Makefile.in b/Makefile.in
index d6b6096..886fcd4 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -69,8 +69,9 @@ pdf: docs
 
 archive: clean
 	tar zcvf dx`date +%y%m%d`.tgz addon tmake doc wintools examples bin objects \
-	       qtools src configure configure.bin Makefile.in Makefile.win.in INSTALL \
-	       make.bat LANGUAGE.HOWTO LICENSE PLATFORMS VERSION packages
+	       qtools src configure configure.bin Makefile.in Makefile.win_nmake.in \
+               Makefile.win_make.in INSTALL make.bat LANGUAGE.HOWTO LICENSE PLATFORMS \
+               VERSION packages
 
 src/version.cpp: Makefile
 	echo "char versionString[]=\"$(VERSION)\";" > src/version.cpp
diff --git a/Makefile.win.in b/Makefile.win.in
deleted file mode 100644
index 4ca50ec..0000000
--- a/Makefile.win.in
+++ /dev/null
@@ -1,45 +0,0 @@
-all: src\version.cpp
-	set TMAKEPATH=$(TMAKEPATH)
-	cd qtools
-	$(MAKE)
-	cd ..
-	cd src 
-	$(MAKE)
-
-clean: FORCE
-	cd examples
-	$(MAKE) clean
-	cd ..
-	cd doc
-	$(MAKE) clean
-	cd ..
-	cd src
-	$(MAKE) clean
-	cd ..
-	-del bin\doxy*.*
-	-del objects\*.o
-
-distclean: clean
-	-del src\Makefile.doxygen \
-	     src\Makefile.doxytag \
-	     src\Makefile.doxysearch
-	-del Makefile src\Makefile examples\Makefile doc\Makefile
-	-del src\doxygen.pro src\doxytag.pro src\doxysearch.pro
-	-del src\version.cpp
-
-docs: FORCE
-	cd examples 
-	$(MAKE)
-	cd ..
-	cd doc
-	$(MAKE)
-	cd ..
-
-ps: docs
-	cd latex
-	$(MAKE)
-
-src\version.cpp: Makefile
-	echo char versionString[]="$(VERSION)"; > src\version.cpp
-
-FORCE:
diff --git a/Makefile.win_make.in b/Makefile.win_make.in
new file mode 100644
index 0000000..a578819
--- /dev/null
+++ b/Makefile.win_make.in
@@ -0,0 +1,30 @@
+all: src\version.cpp
+	set TMAKEPATH=$(TMAKEPATH) & cd qtools & $(MAKE)
+	set TMAKEPATH=$(TMAKEPATH) & cd src & $(MAKE)
+
+clean:
+	cd examples & $(MAKE) clean
+	cd doc & $(MAKE) clean
+	cd src & $(MAKE) clean
+	-del bin\doxy*.*
+	-del objects\*.o
+
+distclean: clean
+	-del src\Makefile.doxygen \
+	     src\Makefile.doxytag \
+	     src\Makefile.doxysearch
+	-del Makefile src\Makefile examples\Makefile doc\Makefile
+	-del src\doxygen.pro src\doxytag.pro src\doxysearch.pro
+	-del src\version.cpp
+
+docs:
+	set TMAKEPATH=$(TMAKEPATH) & cd examples & $(MAKE)
+	set TMAKEPATH=$(TMAKEPATH) & cd doc & $(MAKE)
+
+ps: docs
+	cd latex & $(MAKE)
+
+src\version.cpp: Makefile
+	echo char versionString[]="$(VERSION)"; > src\version.cpp
+
+FORCE:
diff --git a/Makefile.win_nmake.in b/Makefile.win_nmake.in
new file mode 100644
index 0000000..4ca50ec
--- /dev/null
+++ b/Makefile.win_nmake.in
@@ -0,0 +1,45 @@
+all: src\version.cpp
+	set TMAKEPATH=$(TMAKEPATH)
+	cd qtools
+	$(MAKE)
+	cd ..
+	cd src 
+	$(MAKE)
+
+clean: FORCE
+	cd examples
+	$(MAKE) clean
+	cd ..
+	cd doc
+	$(MAKE) clean
+	cd ..
+	cd src
+	$(MAKE) clean
+	cd ..
+	-del bin\doxy*.*
+	-del objects\*.o
+
+distclean: clean
+	-del src\Makefile.doxygen \
+	     src\Makefile.doxytag \
+	     src\Makefile.doxysearch
+	-del Makefile src\Makefile examples\Makefile doc\Makefile
+	-del src\doxygen.pro src\doxytag.pro src\doxysearch.pro
+	-del src\version.cpp
+
+docs: FORCE
+	cd examples 
+	$(MAKE)
+	cd ..
+	cd doc
+	$(MAKE)
+	cd ..
+
+ps: docs
+	cd latex
+	$(MAKE)
+
+src\version.cpp: Makefile
+	echo char versionString[]="$(VERSION)"; > src\version.cpp
+
+FORCE:
diff --git a/README b/README
index 7d5098d..1e88e89 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-DOXYGEN Version 1.2.3-20001203
+DOXYGEN Version 1.2.3-20001217
 
 Please read INSTALL for compilation instructions.
 
@@ -7,4 +7,4 @@ The latest version of doxygen can be obtained at
 
 Enjoy,
 
-Dimitri van Heesch (03 December 2000)
+Dimitri van Heesch (17 December 2000)
diff --git a/VERSION b/VERSION
index d2f09f2..a55b02d 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.2.3-20001203
+1.2.3-20001217
diff --git a/addon/configgen/config_templ.l b/addon/configgen/config_templ.l
index 6cccca9..f680911 100644
--- a/addon/configgen/config_templ.l
+++ b/addon/configgen/config_templ.l
@@ -891,6 +891,15 @@ void checkConfig()
     if (!dp.exists() || !dp.isFile())
     {
       err("Warning: the dot tool could not be found at %s\n",Config::dotPath.data());
+      Config::dotPath="";
+    }
+    else
+    {
+      Config::dotPath=dp.dirPath(TRUE)+"/";
+#if defined(_WIN32) // convert slashes
+      uint i=0,l=Config::dotPath.length();
+      for (i=0;i<l;i++) if (Config::dotPath.at(i)=='/') Config::dotPath.at(i)='\\';
+#endif
     }
   }
   else // make sure the string is empty but not null!
diff --git a/doc/Makefile.win.in b/doc/Makefile.win.in
deleted file mode 100644
index 0e7624d..0000000
--- a/doc/Makefile.win.in
+++ /dev/null
@@ -1,30 +0,0 @@
-#
-# 
-#
-# Copyright (C) 1997-2000 by Dimitri van Heesch.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation under the terms of the GNU General Public License is hereby 
-# granted. No representations are made about the suitability of this software 
-# for any purpose. It is provided "as is" without express or implied warranty.
-# See the GNU General Public License for more details.
-#
-# Documents produced by Doxygen are derivative works derived from the
-# input used in their production; they are not affected by this license.
-
-all: FORCE
-	@xcopy /s /q /i ..\examples ..\html\examples
-	set DOXYGEN_DOCDIR=.
-	set VERSION=$(VERSION)
-	$(DOXYGEN)\bin\doxygen
-	@del ..\latex\refman.tex
-	@copy doxygen_logo*.gif ..\html
-	@copy Makefile.latex ..\latex\Makefile
-	@sed -e "s/\$$VERSION/$(VERSION)/g" doxygen_manual.tex >..\latex\doxygen_manual.tex
-	@sed -e "s/\$$VERSION/$(VERSION)/g" doxygen.sty >..\latex\doxygen.sty 
-	@copy doxygen_logo.eps ..\latex
-
-clean: 
-	del /s /q ..\html ..\latex
-
-FORCE:
diff --git a/doc/Makefile.win_make.in b/doc/Makefile.win_make.in
new file mode 100644
index 0000000..8d8c0c6
--- /dev/null
+++ b/doc/Makefile.win_make.in
@@ -0,0 +1,30 @@
+#
+# 
+#
+# Copyright (C) 1997-2000 by Dimitri van Heesch.
+#
+# Permission to use, copy, modify, and distribute this software and its
+# documentation under the terms of the GNU General Public License is hereby 
+# granted. No representations are made about the suitability of this software 
+# for any purpose. It is provided "as is" without express or implied warranty.
+# See the GNU General Public License for more details.
+#
+# Documents produced by Doxygen are derivative works derived from the
+# input used in their production; they are not affected by this license.
+
+all:
+	@xcopy /s /q /i ..\examples ..\html\examples
+	set DOXYGEN_DOCDIR=. & \
+	set VERSION=$(VERSION) & \
+	$(DOXYGEN)\bin\doxygen
+	@del ..\latex\refman.tex
+	@copy doxygen_logo*.gif ..\html
+	@copy Makefile.latex ..\latex\Makefile
+	@sed -e "s/\$$VERSION/$(VERSION)/g" doxygen_manual.tex >..\latex\doxygen_manual.tex
+	@sed -e "s/\$$VERSION/$(VERSION)/g" doxygen.sty >..\latex\doxygen.sty 
+	@copy doxygen_logo.eps ..\latex
+
+clean: 
+	del /s /q ..\html ..\latex
+
+FORCE:
diff --git a/doc/Makefile.win_nmake.in b/doc/Makefile.win_nmake.in
new file mode 100644
index 0000000..0e7624d
--- /dev/null
+++ b/doc/Makefile.win_nmake.in
@@ -0,0 +1,30 @@
+#
+# 
+#
+# Copyright (C) 1997-2000 by Dimitri van Heesch.
+#
+# Permission to use, copy, modify, and distribute this software and its
+# documentation under the terms of the GNU General Public License is hereby 
+# granted. No representations are made about the suitability of this software 
+# for any purpose. It is provided "as is" without express or implied warranty.
+# See the GNU General Public License for more details.
+#
+# Documents produced by Doxygen are derivative works derived from the
+# input used in their production; they are not affected by this license.
+
+all: FORCE
+	@xcopy /s /q /i ..\examples ..\html\examples
+	set DOXYGEN_DOCDIR=.
+	set VERSION=$(VERSION)
+	$(DOXYGEN)\bin\doxygen
+	@del ..\latex\refman.tex
+	@copy doxygen_logo*.gif ..\html
+	@copy Makefile.latex ..\latex\Makefile
+	@sed -e "s/\$$VERSION/$(VERSION)/g" doxygen_manual.tex >..\latex\doxygen_manual.tex
+	@sed -e "s/\$$VERSION/$(VERSION)/g" doxygen.sty >..\latex\doxygen.sty 
+	@copy doxygen_logo.eps ..\latex
+
+clean: 
+	del /s /q ..\html ..\latex
+
+FORCE:
diff --git a/doc/doxygen_manual.tex b/doc/doxygen_manual.tex
index a9448be..833540e 100644
--- a/doc/doxygen_manual.tex
+++ b/doc/doxygen_manual.tex
@@ -61,6 +61,7 @@ Written by Dimitri van Heesch\\[2ex]
 \input{doxygen_usage}
 \input{doxytag_usage}
 \input{doxysearch_usage}
+\input{doxywizard_usage}
 \input{installdox_usage}
 \input{output}
 \input{autolink}
diff --git a/doc/install.doc b/doc/install.doc
index 1bb1dd2..1a065a2 100644
--- a/doc/install.doc
+++ b/doc/install.doc
@@ -337,29 +337,20 @@ doxygen for Windows.
 
 Here is what is required:
 <ul>
-<li>WinZip to unpack the tar source distribution. This can be found at
-    http://www.winzip.com/ . 
+<li>An unzip/untar tool like WinZip to unpack the tar source distribution. 
+    This can be found at http://www.winzip.com/  
 
     The good, tested, and free alternative is the <code>tar</code> utility
     supplied with <a href="http://sourceware.cygnus.com/cygwin/">cygwin
     tools</a>. Anyway, the cygwin's flex, bison, and sed are also
     recommended below.
 
-    Notice (not related to tar): The good alternative to the WinZip,
-    concerning the zipping/unzipping are the Zip/UnZip utilities by
-    Info-ZIP which are available for free from
-    ftp://ftp.freesoftware.com/pub/infozip/index.html . 
-    There also are archives with binaries for Windows. The tip is to 
-    download the unz540xN.exe and zip23xN.zip (they were used without 
-    problems here) which
-    contain UnZip, Zip, and other auxiliary (but not necessary)
-    utilities related to the UnZip and Zip. 
-    It may be the case that
-    
 <li>Microsoft Visual C++ (I only tested with version 6.0).
     Use the <code>vcvars32.bat</code> batch file to set the environment 
     variables (if you did not select to do this automatically during 
-    installation).
+    installation). 
+
+    Borland C++ or MINGW (see http://www.mingw.org) are also supported. 
 
 <li>Perl 5.0 or higher for Windows. This can be download from:
     http://www.ActiveState.com/Products/ActivePerl/
@@ -387,7 +378,7 @@ Here is what is required:
     steps.
 
 <li>Since Doxygen-1.2.2-20001015, the distribution includes the part
-    of Qt-2.2.0 that is needed for compilation of doxygen, doxytag,
+    of Qt-2.x.x that is needed for compilation of doxygen, doxytag,
     and doxysearch. The missing files for Windows were also created.
     This allows compilation of doxygen on systems without X11 or the
     full Qt. For doxywizard Qt-2.2 is still required however.
@@ -456,13 +447,13 @@ Compilation is now done by performing the following steps:
 <li>goto the doxygen root dir and type:
 
 \verbatim
-    make.bat
+    make.bat msvc
 \endverbatim
 
     This should build the executables 
     <code>doxygen.exe</code>, <code>doxytag.exe</code>, and 
-    <code>doxysearch.exe</code> (The compiler should not produce any 
-    serious warnings or errors).
+    <code>doxysearch.exe</code> using Microsoft's Visual C++ compiler
+    (The compiler should not produce any serious warnings or errors).
 
 <li>To build the examples, go to the <code>examples</code> subdirectory
     and type:
diff --git a/make.bat b/make.bat
index cbb2273..880d8d5 100644
--- a/make.bat
+++ b/make.bat
@@ -1,19 +1,47 @@
+@echo off
 REM make script for Microsoft Visual C++
+REM ...and MINGW and Borland 5.5 also!
+
+if "%1"=="bcc"   SET CC=borland
+if "%1"=="mingw" SET CC=mingw
+if "%1"=="msvc"  SET CC=msvc
+if "%1"=="" goto USAGE
+
+if "%CC%"=="msvc"     SET MAKE=nmake
+if not "%CC%"=="msvc" SET MAKE=make
+
+SET MODE=release
+if "%2"=="debug" SET MODE=debug
 
 REM use perl to create the config file
-perl wintools\make.pl
+perl wintools\make.pl %CC%
 
-type makeconfig Makefile.win.in >Makefile
-type makeconfig qtools\Makefile.in >qtools\Makefile
-type makeconfig src\Makefile.in >src\Makefile
-type makeconfig examples\Makefile.win.in >examples\Makefile
-type makeconfig doc\Makefile.win.in >doc\Makefile
+type makeconfig                 > Makefile
+type Makefile.win_%MAKE%.in     >>Makefile
+type makeconfig                 > qtools\Makefile
+type qtools\Makefile.in         >>qtools\Makefile
+type makeconfig                 > src\Makefile
+type src\Makefile.in            >>src\Makefile
+type makeconfig                 > examples\Makefile
+type examples\Makefile.win.in   >>examples\Makefile
+type makeconfig                 > doc\Makefile
+type doc\Makefile.win_%MAKE%.in >>doc\Makefile
 
-REM build in release mode (replace release with debug to add debug info)
-type qtools\qtools.pro.in | sed "s/\$extraopts/release/g" >qtools\qtools.pro
-type src\doxygen.pro.in | sed "s/\$extraopts/release/g" >src\doxygen.pro
-type src\doxytag.pro.in | sed "s/\$extraopts/release/g" >src\doxytag.pro
-type src\doxysearch.pro.in | sed "s/\$extraopts/release/g" >src\doxysearch.pro
+REM build in release or debug mode 
+type qtools\qtools.pro.in | sed "s/\$extraopts/%MODE%/g" >qtools\qtools.pro
+type src\doxygen.pro.in | sed "s/\$extraopts/%MODE%/g" >src\doxygen.pro
+type src\doxytag.pro.in | sed "s/\$extraopts/%MODE%/g" >src\doxytag.pro
+type src\doxysearch.pro.in | sed "s/\$extraopts/%MODE%/g" >src\doxysearch.pro
 
 REM run make
-nmake
+%MAKE%.exe
+goto END
+
+:USAGE
+echo "Call with '%0 [bcc|mingw|msvc] [debug]'!"
+echo "  bcc:   compile with Borland C++"
+echo "  mingw: compile with GCC for windows (see www.mingw.org)"
+echo "  msvc:  compile with Microsoft Visual C++"
+
+:END
+
diff --git a/packages/rpm/doxygen.spec b/packages/rpm/doxygen.spec
index efbe6aca..3ca27cb 100644
--- a/packages/rpm/doxygen.spec
+++ b/packages/rpm/doxygen.spec
@@ -1,5 +1,5 @@
 Name: doxygen
-Version: 1.2.3-20001203
+Version: 1.2.3-20001217
 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 775b84f..ac104eb 100644
--- a/src/classdef.cpp
+++ b/src/classdef.cpp
@@ -730,7 +730,22 @@ void ClassDef::writeDocumentation(OutputList &ol)
   }
 
 
-  if (!Config::genTagFile.isEmpty()) tagFile << ">" << name() << ":";
+  if (!Config::genTagFile.isEmpty()) 
+  {
+    tagFile << "  <compound kind=\"";
+    switch(compType)
+    {
+      case Class:     tagFile << "class";     break; 
+      case Struct:    tagFile << "struct";    break; 
+      case Union:     tagFile << "union";     break; 
+      case Interface: tagFile << "interface"; break; 
+      case Exception: tagFile << "exception"; break; 
+    }
+    tagFile << "\">" << endl;
+    tagFile << "    <name>" << convertToXML(name()) << "</name>" << endl;
+    tagFile << "    <filename>" << convertToXML(fileName) << ".html</filename>" << endl;
+  }
+
   
   if (Config::classDiagramFlag) ol.disableAllBut(OutputGenerator::Man);
 
@@ -756,7 +771,23 @@ void ClassDef::writeDocumentation(OutputList &ol)
         ClassDef *cd=bcd->classDef;
         if (cd->isLinkable())
         {
-          if (!Config::genTagFile.isEmpty()) tagFile << cd->name() << "?";
+          if (!Config::genTagFile.isEmpty()) 
+          {
+            tagFile << "    <base";
+            if (bcd->prot==Protected)
+            {
+              tagFile << " protection=\"protected\"";
+            }
+            else if (bcd->prot==Private)
+            {
+              tagFile << " protection=\"private\"";
+            }
+            if (bcd->virt==Virtual)
+            {
+              tagFile << " virtualness=\"virtual\"";
+            }
+            tagFile << ">" << convertToXML(cd->name()) << "</base>" << endl;
+          }
           ol.writeObjectLink(cd->getReference(),cd->getOutputFileBase(),0,cd->name()+bcd->templSpecifiers);
         }
         else
@@ -774,8 +805,6 @@ void ClassDef::writeDocumentation(OutputList &ol)
     ol.newParagraph();
   }
 
-  if (!Config::genTagFile.isEmpty()) tagFile << " \"" << fileName << ".html\"\n";
-
   // write subclasses
   if ((count=inheritedBy->count())>0)
   {
@@ -1156,6 +1185,11 @@ void ClassDef::writeDocumentation(OutputList &ol)
   ol.popGeneratorState();
 
   ol.endTextBlock();
+
+  if (!Config::genTagFile.isEmpty()) 
+  {
+    tagFile << "  </compound>" << endl;
+  }
  
   endFile(ol);
 }
diff --git a/src/classlist.cpp b/src/classlist.cpp
index 68436d4..f62ff36 100644
--- a/src/classlist.cpp
+++ b/src/classlist.cpp
@@ -21,6 +21,7 @@
 #include "outputlist.h"
 #include "language.h"
 #include "doc.h"
+#include "doxygen.h"
 
 ClassList::ClassList() : QList<ClassDef>()
 {
@@ -68,6 +69,10 @@ void ClassList::writeDeclaration(OutputList &ol)
             ol.startMemberList();
             found=TRUE;
           }
+          if (!Config::genTagFile.isEmpty()) 
+          {
+            tagFile << "    <class>" << convertToXML(cd->name()) << "</class>" << endl;
+          }
           ol.startMemberItem(FALSE);
           switch (cd->compoundType())
           {
diff --git a/src/config.l b/src/config.l
index 2fcef2f..2aa605c 100644
--- a/src/config.l
+++ b/src/config.l
@@ -1,4 +1,4 @@
-/* This file was generated by configgen on Sun Dec 3 19:18:43 2000
+/* This file was generated by configgen on Fri Dec 15 14:00:31 2000
  * from config_templ.l
  *
  * DO NOT EDIT!
@@ -2853,6 +2853,15 @@ void checkConfig()
     if (!dp.exists() || !dp.isFile())
     {
       err("Warning: the dot tool could not be found at %s\n",Config::dotPath.data());
+      Config::dotPath="";
+    }
+    else
+    {
+      Config::dotPath=dp.dirPath(TRUE)+"/";
+#if defined(_WIN32) // convert slashes
+      uint i=0,l=Config::dotPath.length();
+      for (i=0;i<l;i++) if (Config::dotPath.at(i)=='/') Config::dotPath.at(i)='\\';
+#endif
     }
   }
   else // make sure the string is empty but not null!
diff --git a/src/definition.h b/src/definition.h
index 7332e61..378faf3 100644
--- a/src/definition.h
+++ b/src/definition.h
@@ -76,7 +76,7 @@ class Definition
 
     bool isReference() const { return !ref.isEmpty(); }
     void setReference(const char *r) { ref=r; }
-    QCString getReference() { return ref; }
+    QCString getReference() const { return ref; }
 
     /*! returns the base file name that corresponds with the \a name of this 
      *  definition. This replaces a number of special characters in the
diff --git a/src/diagram.cpp b/src/diagram.cpp
index f9d803c..c60c44d 100644
--- a/src/diagram.cpp
+++ b/src/diagram.cpp
@@ -997,7 +997,8 @@ void ClassDiagram::writeFigure(QTextStream &output,const char *path,
 
   QCString epsBaseName=(QCString)path+"/"+fileName;
   QCString epsName=epsBaseName+".eps";
-  QFile f1(epsName.data());
+  QFile f1;
+  f1.setName(epsName.data());
   if (!f1.open(IO_WriteOnly))
   {
     err("Could not open file %s for writing\n",convertToQCString(f1.name()).data());
@@ -1234,11 +1235,11 @@ void ClassDiagram::writeFigure(QTextStream &output,const char *path,
   f1.close();
   if (Config::usePDFLatexFlag)
   {
-    QCString epstopdfCmd(4096);
-    //epstopdfCmd.sprintf("epstopdf \"%s.eps\" -outfile=\"%s.pdf\"",
-    //               epsBaseName.data(),epsBaseName.data());
+    QCString epstopdfArgs(4096);
+    epstopdfArgs.sprintf("\"%s.eps\" -outfile=\"%s.pdf\"",
+                   epsBaseName.data(),epsBaseName.data());
     //printf("Converting eps using `%s'\n",epstopdfCmd.data());
-    if (iSystem(epstopdfCmd)!=0)
+    if (iSystem("epstopdf",epstopdfArgs)!=0)
     {
        err("Error: Problems running epstopdf. Check your TeX installation!\n");
        return;
diff --git a/src/doc.l b/src/doc.l
index 82883ee..150bcaa 100644
--- a/src/doc.l
+++ b/src/doc.l
@@ -995,7 +995,7 @@ DOCPARAM  ([a-z_A-Z0-9:\<\>\=\.\-]+)|("\"".*"\"")
   					}
 <DocIndexWord>[^\n]+			{
   					  //printf("Adding %s to index\n",yytext);
-					  outDoc->addToIndex(yytext,0);
+					  outDoc->addIndexItem(yytext,0);
   					  BEGIN(DocScan);
   					}
 <DocScan>{CMD}("arg"|"li")/{BN}	        { 
diff --git a/src/dot.cpp b/src/dot.cpp
index 1eff927..c03a31c 100644
--- a/src/dot.cpp
+++ b/src/dot.cpp
@@ -580,20 +580,18 @@ void DotGfxHierarchyTable::writeGraph(QTextStream &out,const char *path)
     t << "}" << endl;
     f.close();
 
-    QCString dotCmd(4096);
-    dotCmd.sprintf("%sdot -Tgif \"%s\" -o \"%s\"",
-                   Config::dotPath.data(),dotName.data(),gifName.data());
+    QCString dotArgs(4096);
+    dotArgs.sprintf("-Tgif \"%s\" -o \"%s\"",dotName.data(),gifName.data());
     //printf("Running: dot -Tgif %s -o %s\n",dotName.data(),gifName.data());
-    if (iSystem(dotCmd)!=0)
+    if (iSystem(Config::dotPath+"dot",dotArgs)!=0)
     {
       err("Problems running dot. Check your installation!\n");
       out << "</table>" << endl;
       return;
     }
-    dotCmd.sprintf("%sdot -Timap \"%s\" -o \"%s\"",
-                   Config::dotPath.data(),dotName.data(),mapName.data());
+    dotArgs.sprintf("-Timap \"%s\" -o \"%s\"",dotName.data(),mapName.data());
     //printf("Running: dot -Timap %s -o %s\n",dotName.data(),mapName.data());
-    if (iSystem(dotCmd)!=0)
+    if (iSystem(Config::dotPath+"dot",dotArgs)!=0)
     {
       err("Problems running dot. Check your installation!\n");
       out << "</table>" << endl;
@@ -996,11 +994,10 @@ static void findMaximalDotGraph(DotNode *root,
     writeDotGraph(root,format,baseName,lrRank,renderParents,
                   curDistance,backArrows);
 
-    QCString dotCmd(4096);
+    QCString dotArgs(4096);
     // create annotated dot file
-    dotCmd.sprintf("%sdot -Tdot \"%s.dot\" -o \"%s_tmp.dot\"",
-                   Config::dotPath.data(),baseName.data(),baseName.data());
-    if (iSystem(dotCmd)!=0)
+    dotArgs.sprintf("-Tdot \"%s.dot\" -o \"%s_tmp.dot\"",baseName.data(),baseName.data());
+    if (iSystem(Config::dotPath+"dot",dotArgs)!=0)
     {
       err("Problems running dot. Check your installation!\n");
       return;
@@ -1103,10 +1100,10 @@ void DotClassGraph::writeGraph(QTextStream &out,
 
   if (format==GIF) // run dot to create a .gif image
   {
-    QCString dotCmd(4096);
-    dotCmd.sprintf("%sdot -Tgif \"%s.dot\" -o \"%s.gif\"",
-                   Config::dotPath.data(),baseName.data(),baseName.data());
-    if (iSystem(dotCmd)!=0)
+    QCString dotArgs(4096);
+    dotArgs.sprintf("-Tgif \"%s.dot\" -o \"%s.gif\"",
+                   baseName.data(),baseName.data());
+    if (iSystem(Config::dotPath+"dot",dotArgs)!=0)
     {
        err("Error: Problems running dot. Check your installation!\n");
        QDir::setCurrent(oldDir);
@@ -1115,9 +1112,8 @@ void DotClassGraph::writeGraph(QTextStream &out,
     if (generateImageMap)
     {
       // run dot again to create an image map
-      dotCmd.sprintf("%sdot -Timap \"%s.dot\" -o \"%s.map\"",
-          Config::dotPath.data(),baseName.data(),baseName.data());
-      if (iSystem(dotCmd)!=0)
+      dotArgs.sprintf("-Timap \"%s.dot\" -o \"%s.map\"",baseName.data(),baseName.data());
+      if (iSystem(Config::dotPath+"dot",dotArgs)!=0)
       {
         err("Error: Problems running dot. Check your installation!\n");
         QDir::setCurrent(oldDir);
@@ -1146,10 +1142,9 @@ void DotClassGraph::writeGraph(QTextStream &out,
   }
   else if (format==EPS) // run dot to create a .eps image
   {
-    QCString dotCmd(4096);
-    dotCmd.sprintf("%sdot -Tps \"%s.dot\" -o \"%s.eps\"",
-                   Config::dotPath.data(),baseName.data(),baseName.data());
-    if (iSystem(dotCmd)!=0)
+    QCString dotArgs(4096);
+    dotArgs.sprintf("-Tps \"%s.dot\" -o \"%s.eps\"",baseName.data(),baseName.data());
+    if (iSystem(Config::dotPath+"dot",dotArgs)!=0)
     {
        err("Error: Problems running dot. Check your installation!\n");
        QDir::setCurrent(oldDir);
@@ -1164,10 +1159,10 @@ void DotClassGraph::writeGraph(QTextStream &out,
     }
     if (Config::usePDFLatexFlag)
     {
-      QCString epstopdfCmd(4096);
-      epstopdfCmd.sprintf("epstopdf \"%s.eps\" -outfile=\"%s.pdf\"",
+      QCString epstopdfArgs(4096);
+      epstopdfArgs.sprintf("epstopdf \"%s.eps\" -outfile=\"%s.pdf\"",
                      baseName.data(),baseName.data());
-      if (iSystem(epstopdfCmd)!=0)
+      if (iSystem("epstopdf",epstopdfArgs)!=0)
       {
          err("Error: Problems running epstopdf. Check your TeX installation!\n");
          QDir::setCurrent(oldDir);
@@ -1307,10 +1302,10 @@ void DotInclDepGraph::writeGraph(QTextStream &out,
   if (format==GIF)
   {
     // run dot to create a .gif image
-    QCString dotCmd(4096);
-    dotCmd.sprintf("%sdot -Tgif \"%s.dot\" -o \"%s.gif\"",
-                   Config::dotPath.data(),baseName.data(),baseName.data());
-    if (iSystem(dotCmd)!=0)
+    QCString dotArgs(4096);
+    dotArgs.sprintf("-Tgif \"%s.dot\" -o \"%s.gif\"",
+                   baseName.data(),baseName.data());
+    if (iSystem(Config::dotPath+"dot",dotArgs)!=0)
     {
       err("Problems running dot. Check your installation!\n");
       QDir::setCurrent(oldDir);
@@ -1320,9 +1315,9 @@ void DotInclDepGraph::writeGraph(QTextStream &out,
     if (generateImageMap)
     {
       // run dot again to create an image map
-      dotCmd.sprintf("%sdot -Timap \"%s.dot\" -o \"%s.map\"",
-          Config::dotPath.data(),baseName.data(),baseName.data());
-      if (iSystem(dotCmd)!=0)
+      dotArgs.sprintf("-Timap \"%s.dot\" -o \"%s.map\"",
+                      baseName.data(),baseName.data());
+      if (iSystem(Config::dotPath+"dot",dotArgs)!=0)
       {
         err("Problems running dot. Check your installation!\n");
         QDir::setCurrent(oldDir);
@@ -1343,10 +1338,10 @@ void DotInclDepGraph::writeGraph(QTextStream &out,
   else if (format==EPS)
   {
     // run dot to create a .eps image
-    QCString dotCmd(4096);
-    dotCmd.sprintf("%sdot -Tps \"%s.dot\" -o \"%s.eps\"",
-                   Config::dotPath.data(),baseName.data(),baseName.data());
-    if (iSystem(dotCmd)!=0)
+    QCString dotArgs(4096);
+    dotArgs.sprintf("-Tps \"%s.dot\" -o \"%s.eps\"",
+                   baseName.data(),baseName.data());
+    if (iSystem(Config::dotPath+"dot",dotArgs)!=0)
     {
       err("Problems running dot. Check your installation!\n");
       QDir::setCurrent(oldDir);
@@ -1361,10 +1356,10 @@ void DotInclDepGraph::writeGraph(QTextStream &out,
     }
     if (Config::usePDFLatexFlag)
     {
-      QCString epstopdfCmd(4096);
-      epstopdfCmd.sprintf("epstopdf \"%s.eps\" -outfile=\"%s.pdf\"",
+      QCString epstopdfArgs(4096);
+      epstopdfArgs.sprintf("\"%s.eps\" -outfile=\"%s.pdf\"",
                      baseName.data(),baseName.data());
-      if (iSystem(epstopdfCmd)!=0)
+      if (iSystem("epstopdf",epstopdfArgs)!=0)
       {
          err("Error: Problems running epstopdf. Check your TeX installation!\n");
          QDir::setCurrent(oldDir);
@@ -1435,10 +1430,9 @@ void generateGraphLegend(const char *path)
   QDir::setCurrent(d.absPath());
 
   // run dot to generate the a .gif image from the graph
-  QCString dotCmd(4096);
-  dotCmd.sprintf("%sdot -Tgif graph_legend.dot -o graph_legend.gif",
-                   Config::dotPath.data());
-  if (iSystem(dotCmd)!=0)
+  QCString dotArgs(4096);
+  dotArgs.sprintf("-Tgif graph_legend.dot -o graph_legend.gif");
+  if (iSystem(Config::dotPath+"dot",dotArgs)!=0)
   {
       err("Problems running dot. Check your installation!\n");
       QDir::setCurrent(oldDir);
diff --git a/src/doxygen.cpp b/src/doxygen.cpp
index 4e951bd..3d7ea26 100644
--- a/src/doxygen.cpp
+++ b/src/doxygen.cpp
@@ -40,7 +40,7 @@
 #include "config.h"
 #include "util.h"
 #include "pre.h"
-#include "tag.h"
+#include "tagreader.h"
 #include "dot.h"
 
 #include "outputlist.h"
@@ -226,14 +226,10 @@ static void addRelatedPage(const char *name,const QCString &ptitle,
   PageInfo *pi=0;
   if ((pi=pageSDict->find(name)))
   {
-    //warn("Warning: Page %s was already documented. Ignoring documentation "
-    //     "at line %d of %s\n",root->name.data(),root->startLine,
-    //                          root->fileName.data());
-
     // append documentation block to the page.
     pi->doc+="\n\n"+doc;
   }
-  else
+  else // new page
   {
     QCString baseName=name;
     if (baseName.right(4)==".tex") 
@@ -380,6 +376,10 @@ static void buildGroupList(Entry *root)
     else
     {
       gd = new GroupDef(root->fileName,root->startLine,root->name,root->type);
+      if (root->tagInfo)
+      {
+        gd->setReference(root->tagInfo->tagName);
+      }
       gd->setBriefDescription(root->brief);
       gd->setDocumentation(root->doc);
       gd->addSectionsToDefinition(root->anchors);
@@ -565,11 +565,9 @@ static void addIncludeFile(ClassDef *cd,FileDef *ifd,Entry *root)
       {
         iName=fd->name();
       }
-      if (Config::verbatimHeaderFlag || Config::sourceBrowseFlag) 
-        // generate code for header
+      if (fd->generateSourceFile()) // generate code for header
       {
         cd->setIncludeFile(fd,iName,local);
-        //fd->setGenerateSource(TRUE);
       }
       else // put #include in the class documentation without link
       {
@@ -728,7 +726,15 @@ static void buildClassList(Entry *root)
 
         //printf("New class: namespace `%s' name=`%s'\n",className.data(),namespaceName.data());
         
-        ClassDef *cd=new ClassDef(root->fileName,root->startLine,fullName,sec);
+        QCString tagName;
+        QCString refFileName;
+        if (root->tagInfo)
+        {
+          tagName     = root->tagInfo->tagName;
+          refFileName = root->tagInfo->fileName;
+        }
+        ClassDef *cd=new ClassDef(root->fileName,root->startLine,fullName,sec,
+                                  tagName,refFileName);
         cd->setDocumentation(root->doc); // copy docs to definition
         cd->setBriefDescription(root->brief);
         //printf("new ClassDef %s tempArgList=%p specScope=%s\n",fullName.data(),root->tArgList,root->scopeSpec.data());
@@ -861,7 +867,12 @@ static void buildNamespaceList(Entry *root)
               )
            */ 
       {
-        NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,fullName);
+        QCString tagName;
+        if (root->tagInfo)
+        {
+          tagName=root->tagInfo->tagName;
+        }
+        NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,fullName,tagName);
         nd->setDocumentation(root->doc); // copy docs to definition
         nd->setBriefDescription(root->brief);
         nd->addSectionsToDefinition(root->anchors);
@@ -1169,6 +1180,11 @@ static MemberDef *addVariableToClass(
       root->type,name,root->args,0,
       prot,Normal,root->stat,FALSE,
       mtype,0,0);
+  if (root->tagInfo) 
+  {
+    md->setAnchor(root->tagInfo->anchor);
+    md->setReference(root->tagInfo->tagName);
+  }
   md->setMemberClass(cd);
   //md->setDefFile(root->fileName);
   //md->setDefLine(root->startLine);
@@ -1283,23 +1299,38 @@ static MemberDef *addVariableToFile(
   MemberName *mn=functionNameDict[name];
   if (mn)
   {
+    QCString nscope=removeAnonymousScopes(scope);
+    NamespaceDef *nd=0;
+    if (!nscope.isEmpty())
+    {
+      nd = getResolvedNamespace(nscope);
+    }
     MemberNameIterator mni(*mn);
     MemberDef *md;
     for (mni.toFirst();(md=mni.current());++mni)
     {
-      QCString nscope=removeAnonymousScopes(scope);
-      NamespaceDef *nd=0;
-      if (!nscope.isEmpty())
-      {
-        nd = getResolvedNamespace(nscope);
-      }
-      if (nd==0 || md->getNamespaceDef()==nd) 
+      if ((nd==0 && root->fileName==md->getFileDef()->absFilePath())
+          || (nd!=0 && md->getNamespaceDef()==nd))
         // variable already in the scope
       {
         addMemberDocs(root,md,def,0,FALSE);
         md->setRefItems(root->todoId,root->testId);
         return md;
       }
+      
+      if (nd==0 && md->isExplicit()!=root->explicitExternal)
+      {
+        // merge ingroup specifiers
+        if (md->getGroupDef()==0 && root->groups->first())
+        {
+          GroupDef *gd=groupDict[root->groups->first()->data()];
+          md->setGroupDef(gd);
+        }
+        else if (md->getGroupDef()!=0 && root->groups->count()==0)
+        {
+          root->groups->append(new QCString(md->getGroupDef()->name()));
+        }
+      }
     } 
   }
   // new global variable, enum value or typedef
@@ -1308,6 +1339,11 @@ static MemberDef *addVariableToFile(
       root->type,name,root->args,0,
       Public, Normal,root->stat,FALSE,
       mtype,0,0);
+  if (root->tagInfo) 
+  {
+    md->setAnchor(root->tagInfo->anchor);
+    md->setReference(root->tagInfo->tagName);
+  }
   //md->setDefFile(root->fileName);
   //md->setDefLine(root->startLine);
   md->setDocumentation(root->doc);
@@ -1322,6 +1358,7 @@ static MemberDef *addVariableToFile(
   md->setMemberGroupId(root->mGrpId);
   md->setBodyDef(fd);
   md->setDefinition(def);
+  md->setExplicitExternal(root->explicitExternal);
   //if (root->mGrpId!=-1) 
   //{
   //  md->setMemberGroup(memberGroupDict[root->mGrpId]);
@@ -1458,8 +1495,7 @@ void buildVarList(Entry *root)
     QCString type=root->type.stripWhiteSpace();
     ClassDef *cd=0;
 
-    int ni;
-    if ((ni=root->name.findRev("::"))!=-1) goto nextMember;
+    if (root->name.findRev("::")!=-1) goto nextMember;
                /* skip this member, because it is a 
                 * static variable definition (always?), which will be
                 * found in a class scope as well, but then we know the
@@ -1634,7 +1670,6 @@ static void buildMemberList(Entry *root)
           name=name.left(i); 
         }
              
-
         //if (Config::includeSourceFlag && !root->body.isEmpty())
         //{
         //  printf("Function: %s\n-----------------\n%s\n------------------\n",
@@ -1649,9 +1684,12 @@ static void buildMemberList(Entry *root)
             root->type,name,root->args,root->exception,
             root->protection,root->virt,root->stat,!root->relates.isEmpty(),
             mtype,root->mtArgList,root->argList);
+        if (root->tagInfo) 
+        {
+          md->setAnchor(root->tagInfo->anchor);
+          md->setReference(root->tagInfo->tagName);
+        }
         md->setMemberClass(cd);
-        //md->setDefFile(root->fileName);
-        //md->setDefLine(root->startLine);
         md->setDocumentation(root->doc);
         md->setBriefDescription(root->brief);
         md->setBodySegment(root->bodyLine,root->endBodyLine);
@@ -1752,12 +1790,6 @@ static void buildMemberList(Entry *root)
       else if (root->parent && 
                !(root->parent->section & Entry::COMPOUND_MASK) &&
                !isMember &&
-
-               //rname.find("::")==-1 && // TODO: remove this check
-               //                             // it breaks cases like 
-               //                             // func<A::B>(), but it is needed
-               //                             // for detect that A::func() is a member 
-               
                root->relates.isEmpty() &&
                root->type.left(7)!="extern " &&
                root->type.left(8)!="typedef " 
@@ -1788,11 +1820,6 @@ static void buildMemberList(Entry *root)
             QCString nsName,rnsName;
             if (nd)  nsName  = nd->name().copy();
             if (rnd) rnsName = rnd->name().copy();
-            QCString groupName,rgroupName;
-            if (md->getGroupDef()) groupName=md->getGroupDef()->name().copy();
-            if (root->groups && root->groups->first()) rgroupName=root->groups->first()->copy(); 
-            //printf("namespace `%s' `%s'\n",nsName.data(),rnsName.data());
-            //printf("groupNames `%s' `%s'\n",groupName.data(),rgroupName.data());
             if ( 
                 matchArguments(md->argumentList(),root->argList,0,nsName)
                )
@@ -1801,18 +1828,16 @@ static void buildMemberList(Entry *root)
               found=(nd && rnd && nsName==rnsName) ||   // members are in the same namespace
                     ((fd!=0 &&                          // no external reference and
                       fd->absFilePath()==root->fileName // prototype in the same file
-                     ) || 
-                     (
-                      !groupName.isEmpty() ||           // member is or was part of a group
-                      !rgroupName.isEmpty()
-                     )
+                     ) 
                     ); 
               // otherwise, allow a duplicate global member with the same argument list
               
               //printf("combining function with prototype found=%d `%s'<->`%s'!\n",
               //    found,fd->absFilePath().data(),root->fileName.data());
-              // merge members documentation and properties
+
+              // merge argument lists
               mergeArguments(root->argList,md->argumentList());
+              // merge documentation
               if (!md->documentation() && !root->doc.isEmpty())
               {
                 md->setDocumentation(root->doc);
@@ -1821,6 +1846,7 @@ static void buildMemberList(Entry *root)
               {
                 md->setBriefDescription(root->brief);
               }
+              // merge body definitions
               if (md->getStartBodyLine()==-1 && root->bodyLine!=-1)
               {
                 md->setBodySegment(root->bodyLine,root->endBodyLine);
@@ -1828,6 +1854,17 @@ static void buildMemberList(Entry *root)
                 md->setBodyDef(findFileDef(inputNameDict,root->fileName,ambig));
               } 
               md->addSectionsToDefinition(root->anchors);
+
+              // merge ingroup specifiers
+              if (md->getGroupDef()==0 && root->groups->first())
+              {
+                GroupDef *gd=groupDict[root->groups->first()->data()];
+                md->setGroupDef(gd);
+              }
+              else if (md->getGroupDef()!=0 && root->groups->count()==0)
+              {
+                root->groups->append(new QCString(md->getGroupDef()->name()));
+              }
             }
           }
         }
@@ -1843,6 +1880,11 @@ static void buildMemberList(Entry *root)
               root->type,name,root->args,root->exception,
               root->protection,root->virt,root->stat,FALSE,
               MemberDef::Function,root->tArgList,root->argList);
+          if (root->tagInfo) 
+          {
+            md->setAnchor(root->tagInfo->anchor);
+            md->setReference(root->tagInfo->tagName);
+          }
           //md->setDefFile(root->fileName);
           //md->setDefLine(root->startLine);
           md->setDocumentation(root->doc);
@@ -1909,25 +1951,17 @@ static void buildMemberList(Entry *root)
 
           if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
           {
+            // add member to namespace
             nd->insertMember(md); 
             md->setNamespace(nd);
             md->setRefItems(root->todoId,root->testId);
           }
-          else
+          else if (fd)
           {
-            // find file definition
-            //FileDef *fd=0;
-            //bool ambig;
-            //if (!root->fileName.isEmpty() && 
-            //    (fd=findFileDef(inputNameDict,root->fileName,ambig))
-            //   )
-            if (fd)
-            {
-              // add member to the file
-              fd->insertMember(md);
-              md->setFileDef(fd); 
-              md->setRefItems(root->todoId,root->testId);
-            }
+            // add member to the file
+            fd->insertMember(md);
+            md->setFileDef(fd); 
+            md->setRefItems(root->todoId,root->testId);
           }
 
           // add member to the list of file members
@@ -2046,8 +2080,15 @@ static void transferFunctionDocumentation()
     /* find a matching function declaration and definition for this function */
     for (;(md=mni.current());++mni)
     {
-      if (md->isPrototype()) mdec=md;
-      if (md->isFunction() && !md->isStatic() && !md->isPrototype()) mdef=md;
+      if (md->isPrototype()) 
+        mdec=md;
+      else if (md->isVariable() && md->isExternal()) 
+        mdec=md;
+      
+      if (md->isFunction() && !md->isStatic() && !md->isPrototype()) 
+        mdef=md;
+      else if (md->isVariable() && !md->isExternal() && !md->isStatic())
+        mdef=md;
     }
     //printf("mdef=(%p,%s) mdec=(%p,%s)\n",
     //    mdef, mdef ? mdef->name().data() : "",
@@ -2335,10 +2376,14 @@ static bool findBaseClassRelation(Entry *root,ClassDef *cd,
           baseClass->insertSuperClass(cd,bi->prot,bi->virt,templSpec);
           return TRUE;
         }
-        else if (insertUndocumented)
+        else if (scopeOffset==0 && insertUndocumented)
         {
-          Debug::print(Debug::Classes,0,"    Undocumented base class `%s' baseClassName=%s\n",bi->name.data(),baseClassName.data());
-          baseClass=new ClassDef(root->fileName,root->startLine,baseClassName,ClassDef::Class);
+          Debug::print(Debug::Classes,0,
+                       "    Undocumented base class `%s' baseClassName=%s\n",
+                       bi->name.data(),baseClassName.data()
+                      );
+          baseClass=new ClassDef(root->fileName,root->startLine,
+                                 baseClassName,ClassDef::Class);
           // add base class to this class
           cd->insertBaseClass(baseClass,bi->prot,bi->virt,templSpec);
           // add this class as super class to the base class
@@ -3511,6 +3556,11 @@ static void findMember(Entry *root,QCString funcDecl,QCString related,bool overl
               funcType,funcName,funcArgs,exceptions,
               root->protection,root->virt,root->stat,TRUE,
               mtype,root->tArgList,root->argList);
+          if (root->tagInfo) 
+          {
+            md->setAnchor(root->tagInfo->anchor);
+            md->setReference(root->tagInfo->tagName);
+          }
           md->setMemberClass(cd);
           md->setDefinition(funcDecl);
           QCString doc=getOverloadDocs();
@@ -3589,6 +3639,11 @@ static void findMember(Entry *root,QCString funcDecl,QCString related,bool overl
               funcType,funcName,funcArgs,exceptions,
               root->protection,root->virt,root->stat,TRUE,
               mtype,root->tArgList,root->argList);
+          if (root->tagInfo) 
+          {
+            md->setAnchor(root->tagInfo->anchor);
+            md->setReference(root->tagInfo->tagName);
+          }
           //printf("Related member name=`%s' decl=`%s' bodyLine=`%d'\n",
           //       funcName.data(),funcDecl.data(),root->bodyLine);
 
@@ -3738,7 +3793,7 @@ static void findMemberDocumentation(Entry *root)
     ((root->section==Entry::FUNCTION_SEC // function
       ||   
       (root->section==Entry::VARIABLE_SEC && // variable
-      !root->type.isEmpty() && root->type.left(8)!="typedef " &&
+      !root->type.isEmpty() && /*root->type.left(8)!="typedef " &&*/
        compoundKeywordDict.find(root->type)==0
       )
      ) && 
@@ -3857,6 +3912,11 @@ static void findEnums(Entry *root)
           root->fileName,root->startLine,
           0,name,0,0,root->protection,Normal,FALSE,FALSE,
           MemberDef::Enumeration,0,0);
+      if (root->tagInfo) 
+      {
+        md->setAnchor(root->tagInfo->anchor);
+        md->setReference(root->tagInfo->tagName);
+      }
       if (!isGlobal) md->setMemberClass(cd); else md->setFileDef(fd);
       //md->setDefFile(root->fileName);
       //md->setDefLine(root->startLine);
@@ -4238,10 +4298,7 @@ static void generateFileSources()
       FileDef *fd;
       for (;(fd=fni.current());++fni)
       {
-        bool src = !fd->isReference() &&
-                   fd->name().right(4)!=".doc" && fd->name().right(4)!=".txt" &&
-                   (Config::verbatimHeaderFlag || Config::sourceBrowseFlag);
-        if (src)
+        if (fd->generateSourceFile())
         {
           msg("Generating code for file %s...\n",fd->name().data());
           fd->writeSource(*outputList);
@@ -4520,6 +4577,32 @@ static void findDefineDocumentation(Entry *root)
   {
     //printf("found define `%s' `%s' brief=`%s' doc=`%s'\n",
     //       root->name.data(),root->args.data(),root->brief.data(),root->doc.data());
+
+    if (root->tagInfo && !root->name.isEmpty()) // define read from a tag file
+    {
+      MemberDef *md=new MemberDef("<tagfile>",1,
+                    "#define",root->name,root->args,0,
+                    Public,Normal,FALSE,FALSE,MemberDef::Define,0,0);
+      md->setAnchor(root->tagInfo->anchor);
+      md->setReference(root->tagInfo->tagName);
+      bool ambig;
+      QCString filePathName = root->parent->fileName;
+      FileDef *fd=findFileDef(inputNameDict,filePathName,ambig);
+      //printf("Searching for `%s' fd=%p\n",filePathName.data(),fd);
+      md->setFileDef(fd);
+      MemberName *mn;
+      if ((mn=functionNameDict[root->name]))
+      {
+        mn->append(md);
+      }
+      else 
+      {
+        mn = new MemberName(root->name);
+        mn->append(md);
+        functionNameDict.insert(root->name,mn);
+        functionNameList.inSort(mn);
+      }
+    }
     MemberName *mn=functionNameDict[root->name];
     if (mn)
     {
@@ -4723,7 +4806,7 @@ static void generatePageDocs()
   PageInfo *pi=0;
   for (pdi.toFirst();(pi=pdi.current());++pdi)
   {
-    if (!pi->inGroup)
+    if (!pi->inGroup && !pi->isReference())
     {
       msg("Generating docs for page %s...\n",pi->name.data());
       outputList->disable(OutputGenerator::Man);
@@ -4747,6 +4830,15 @@ static void generatePageDocs()
       outputList->endTextBlock();
       endFile(*outputList);
       outputList->enable(OutputGenerator::Man);
+
+      if (!Config::genTagFile.isEmpty())
+      {
+        tagFile << "  <compound kind=\"page\">" << endl;
+        tagFile << "    <name>" << pi->name << "</name>" << endl;
+        tagFile << "    <title>" << pi->title << "</title>" << endl;
+        tagFile << "    <filename>" << pi->name << "</filename>" << endl;
+        tagFile << "  </compound>" << endl;
+      }
     }
   }
 }
@@ -4837,7 +4929,10 @@ static void generateGroupDocs()
     //       "Warning: group %s does not have any (documented) members.",
     //        gd->name().data());
     //}
-    gd->writeDocumentation(*outputList);
+    if (!gd->isReference())
+    {
+      gd->writeDocumentation(*outputList);
+    }
   }
 }
 
@@ -5065,7 +5160,7 @@ static void generateConfigFile(const char *configFile,bool shortList)
 
 //----------------------------------------------------------------------------
 
-static void readTagFile(const char *tl)
+static void readTagFile(Entry *root,const char *tl)
 {
   QCString tagLine = tl;
   QCString fileName;
@@ -5077,7 +5172,7 @@ static void readTagFile(const char *tl)
     destName = tagLine.right(tagLine.length()-eqPos-1).stripWhiteSpace();
     QFileInfo fi(fileName);
     tagDestinationDict.insert(fi.fileName(),new QCString(destName));
-    //printf("insert tagDestination %s->%s\n",fileName.data(),destName.data());
+    //printf("insert tagDestination %s->%s\n",fi.fileName().data(),destName.data());
   }
   else
   {
@@ -5097,7 +5192,7 @@ static void readTagFile(const char *tl)
   else
     msg("Reading tag file `%s'...\n",fileName.data());
 
-  parseTagFile(fileName);
+  parseTagFile(root,fi.absFilePath(),fi.fileName());
 }
 
 //----------------------------------------------------------------------------
@@ -5921,6 +6016,17 @@ int main(int argc,char **argv)
     msg("Read %d bytes\n",input.curPos());
   }
 
+  // Notice: the order of the function calls below is very important!
+  
+  if (Config::generateHtml)
+  {
+    msg("Reading formula repository...\n");
+    readFormulaRepository();
+  }
+  
+  Entry *root=new Entry;
+  root->program=input;
+
 
   /**************************************************************************
    *             Handle Tag Files                                           *
@@ -5931,13 +6037,14 @@ int main(int argc,char **argv)
   s=Config::tagFileList.first();
   while (s)
   {
-    readTagFile(s);
+    readTagFile(root,s);
     s=Config::tagFileList.next();
   }
   
-  QFile *tag =new QFile(Config::genTagFile);
+  QFile *tag=0;
   if (!Config::genTagFile.isEmpty())
   {
+    tag=new QFile(Config::genTagFile);
     if (!tag->open(IO_WriteOnly))
     {
       err("Error: cannot open tag file %s for writing\n",
@@ -5946,23 +6053,13 @@ int main(int argc,char **argv)
       exit(1);
     }
     tagFile.setDevice(tag);
+    tagFile << "<tagfile>" << endl;
   }
   
   /**************************************************************************
    *             Gather information                                         * 
    **************************************************************************/
   
-  // Notice: the order of the function calls below is very important!
-  
-  if (Config::generateHtml)
-  {
-    msg("Reading formula repository...\n");
-    readFormulaRepository();
-  }
-  
-  Entry *root=new Entry;
-  root->program=input;
-
   msg("Parsing input...\n");
   parseMain(root);            // build a tree of entries
 
@@ -6217,12 +6314,16 @@ int main(int argc,char **argv)
   {
     FTVHelp::getInstance()->finalize();
   }
+  if (!Config::genTagFile.isEmpty())
+  {
+    tagFile << "</tagfile>" << endl;
+    delete tag;
+  }
 
 
   if (Config::generateHtml) removeDoxFont(Config::htmlOutputDir);
   if (Config::generateRTF)  removeDoxFont(Config::rtfOutputDir);
 
-  delete tag;
 
   return 0;
 }
diff --git a/src/doxygen.pro.in b/src/doxygen.pro.in
index f963466..92c60f8 100644
--- a/src/doxygen.pro.in
+++ b/src/doxygen.pro.in
@@ -20,7 +20,7 @@ HEADERS      =	doxygen.h scanner.h doc.h classdef.h classlist.h memberdef.h \
                 membername.h index.h memberlist.h definition.h \
                 entry.h logos.h instdox.h message.h code.h \
                 filedef.h util.h cppvalue.h constexp.h \
-		outputgen.h outputlist.h htmlgen.h latexgen.h tag.h \
+		outputgen.h outputlist.h htmlgen.h latexgen.h \
 	        filename.h defargs.h groupdef.h gifenc.h diagram.h image.h \
 		namespacedef.h version.h language.h translator.h \
 		translator_nl.h translator_se.h translator_cz.h translator_fr.h \
@@ -28,23 +28,26 @@ HEADERS      =	doxygen.h scanner.h doc.h classdef.h classlist.h memberdef.h \
                 translator_ru.h translator_pl.h dot.h rtfgen.h xml.h xml_dtd.h \
                 reflist.h page.h sortdict.h translator_hu.h translator_kr.h \
                 translator_ro.h translator_si.h translator_cn.h ftvhelp.h \
-                treeview.h
+                treeview.h tagreader.h
 SOURCES      =	doxygen.cpp scanner.cpp doc.cpp classdef.cpp classlist.cpp \
                 memberdef.cpp membername.cpp index.cpp memberlist.cpp \
 		entry.cpp logos.cpp instdox.cpp message.cpp code.cpp \
                 config.cpp filedef.cpp util.cpp groupdef.cpp \
                 outputgen.cpp outputlist.cpp htmlgen.cpp latexgen.cpp mangen.cpp \
 	        cppvalue.cpp ce_lex.cpp ce_parse.cpp pre.cpp \
-		tag.cpp filename.cpp declinfo.cpp defargs.cpp define.cpp \
+		filename.cpp declinfo.cpp defargs.cpp define.cpp \
 		diagram.cpp gifenc.cpp image.cpp namespacedef.cpp \
 		version.cpp language.cpp definition.cpp formula.cpp debug.cpp \
 		membergroup.cpp htmlhelp.cpp dot.cpp rtfgen.cpp xml.cpp \
-                reflist.cpp ftvhelp.cpp
-unix:LIBS    += -L../qtools -lqtools
-win32:INCLUDEPATH += .
-win32:LIBS   += qtools.lib shell32.lib 
-win32:TMAKE_LFLAGS += /LIBPATH:..\qtools
-win32:TMAKE_CXXFLAGS += -DQT_NODLL
-INCLUDEPATH += ../qtools
-TARGET       =	../bin/doxygen
-OBJECTS_DIR  =  ../objects
+                reflist.cpp ftvhelp.cpp tagreader.cpp
+unix:LIBS                  += -L../qtools -lqtools
+win32:INCLUDEPATH          += .
+win32-mingw:LIBS           += -L../qtools -lqtools
+win32-msvc:LIBS            += qtools.lib shell32.lib 
+win32-msvc:TMAKE_LFLAGS    += /LIBPATH:..\qtools
+win32-borland:LIBS         += qtools.lib shell32.lib
+win32-borland:TMAKE_LFLAGS += -L..\qtools
+win32:TMAKE_CXXFLAGS       += -DQT_NODLL
+INCLUDEPATH                += ../qtools
+TARGET                     =  ../bin/doxygen
+OBJECTS_DIR                =  ../objects
diff --git a/src/doxygen.t b/src/doxygen.t
index be0dcc4..d1f6a64 100644
--- a/src/doxygen.t
+++ b/src/doxygen.t
@@ -53,9 +53,6 @@ sub GenerateDep {
 #$ GenerateDep("pre.cpp","pre.l");
 	$(LEX) -PpreYY -t pre.l >pre.cpp 
 
-#$ GenerateDep("tag.cpp","tag.l");
-	$(LEX) -PtagYY -t tag.l >tag.cpp 
-
 #$ GenerateDep("config.cpp","config.l");
 	$(LEX) -PconfigYY -t config.l >config.cpp 
 
diff --git a/src/doxytag.l b/src/doxytag.l
index 001b756..2d9e7b4 100644
--- a/src/doxytag.l
+++ b/src/doxytag.l
@@ -36,6 +36,27 @@
 #include "suffixtree.h"
 #include "searchindex.h"
 #include "logos.h"
+
+static QCString convertToXML(const char *s)
+{ 
+  QCString result;
+  if (s==0) return result;
+  const char *p=s;
+  char c;
+  while ((c=*p++))
+  {     
+    switch (c)
+    {   
+      case '<':  result+="&lt;";   break;
+      case '>':  result+="&gt;";   break;
+      case '&':  result+="&amp;";  break;
+      case '\'': result+="&apos;"; break; 
+      case '"':  result+="&quot;"; break;
+      default:   result+=c;        break;         
+    }
+  }
+  return result;
+}
   
 struct MemberDef
 {
@@ -61,21 +82,20 @@ QDict<ClassDef> fileDict(1009);
 static bool genTag;
 static bool genIndex;
 
-static QStrList bases;
+static QStrList  bases;
 static QCString  inputString;
-static int      inputPosition;
+static int       inputPosition;
 static QCString  yyFileName;
-static int      yyLineNr;
+static int       yyLineNr;
 static QCString  classFile;
 static QCString  memberRef;
 static QCString  memberName;
 static QCString  memberArgs;
 static QCString  className;
-//static bool     newClass;
 static QCString  docBaseLink;
 static QCString  docAnchor;
 static QCString  docRefName;
-static bool     nameBug;
+static bool      nameBug;
 static SearchIndex searchIndex;
 
 #define YY_NEVER_INTERACTIVE 1
@@ -423,7 +443,8 @@ void parse(QCString &s)
 void parseFile(QFileInfo &fi)
 {
   fprintf(stderr,"Parsing file %s...\n",fi.fileName().data());
-  QFile f(fi.absFilePath().data());
+  QFile f;
+  f.setName(fi.absFilePath());
   if (f.open(IO_ReadOnly))
   {
     yyFileName = fi.fileName();
@@ -575,7 +596,8 @@ int main(int argc,char **argv)
       fi.setFile(dir+"/search.cgi");
       if (!fi.exists())
       {
-        QFile f(dir+"/search.cgi");
+        QFile f;
+	f.setName(dir+"/search.cgi");
 	if (f.open(IO_WriteOnly))
 	{
 	  QTextStream t(&f);
@@ -601,31 +623,40 @@ int main(int argc,char **argv)
   }
   if (genTag)
   {
-    QFile f(tagName);
+    QFile f;
+    f.setName(tagName);
     if (f.open(IO_WriteOnly))
     {
       QTextStream t(&f);
+      t << "<tagfile>" << endl;
       ClassDef *cd=classList.first();
       while (cd)
       {
-	if (cd->isFile) t << "&"; else t << ">";
-	t << cd->name << ":";
+	t << "  <compound kind=\"";
+	if (cd->isFile) t << "file"; else t << "class";  
+	t << "\">" << endl;
+	t << "    <name>" << convertToXML(cd->name) << "</name>" << endl; 
         char *base=cd->bases.first();
         while (base)
 	{
-	  t << base << "?";
+	  t << "    <base>" << convertToXML(base) << "</base>" << endl;
 	  base=cd->bases.next();
 	}
-	if (!cd->isFile) t << " \"" << cd->fileName << "\"";
-	t << endl; 
+	t << "    <filename>" << convertToXML(cd->fileName) << "</filename>" << endl;
 	MemberDef *md=cd->memberList.first();
 	while (md)
 	{
-	  t << md->name << " " << md->anchor << " \"" << md->args << "\"" << endl;
+	  t << "    <member kind=\"function\">" << endl;
+	  t << "      <name>" << convertToXML(md->name) << "</name>" << endl;
+	  t << "      <anchor>" << convertToXML(md->anchor) << "</anchor>" << endl;
+	  t << "      <arglist>" << convertToXML(md->args) << "</arglist>" << endl;
+	  t << "    </member>" << endl;
 	  md=cd->memberList.next();
 	}
+	t << "  </compound>" << endl;
 	cd=classList.next();
       }
+      t << "</tagfile>" << endl;
     }
     else
     {
diff --git a/src/doxytag.pro.in b/src/doxytag.pro.in
index d91378d..58b2e95 100644
--- a/src/doxytag.pro.in
+++ b/src/doxytag.pro.in
@@ -19,11 +19,14 @@ CONFIG       =	console warn_on $extraopts
 HEADERS      =  suffixtree.h searchindex.h logos.h version.h
 SOURCES      =	doxytag.cpp suffixtree.cpp searchindex.cpp \
 		logos.cpp version.cpp 
-unix:LIBS    += -L../qtools -lqtools
-win32:INCLUDEPATH += . 
-win32:LIBS   += qtools.lib 
-win32:TMAKE_LFLAGS += /LIBPATH:..\qtools
-win32:TMAKE_CXXFLAGS += -DQT_NODLL
-INCLUDEPATH += ../qtools
-OBJECTS_DIR  =  ../objects
-TARGET       =	../bin/doxytag
+unix:LIBS                  += -L../qtools -lqtools
+win32:INCLUDEPATH          += .
+win32-mingw:LIBS           += -L../qtools -lqtools
+win32-msvc:LIBS            += qtools.lib shell32.lib 
+win32-msvc:TMAKE_LFLAGS    += /LIBPATH:..\qtools
+win32-borland:LIBS         += qtools.lib shell32.lib
+win32-borland:TMAKE_LFLAGS += -L..\qtools
+win32:TMAKE_CXXFLAGS       += -DQT_NODLL
+INCLUDEPATH                += ../qtools
+OBJECTS_DIR                =  ../objects
+TARGET                     =  ../bin/doxytag
diff --git a/src/entry.cpp b/src/entry.cpp
index a8dfb9b..829bc3b 100644
--- a/src/entry.cpp
+++ b/src/entry.cpp
@@ -39,6 +39,7 @@ Entry::Entry()
   tArgList = 0;
   mtArgList = 0;
   mGrpId = -1;
+  tagInfo = 0;
   reset();
 }
 
@@ -75,6 +76,7 @@ Entry::Entry(const Entry &e)
   initLines   = e.initLines;
   todoId      = e.todoId;
   testId      = e.testId;
+  tagInfo     = e.tagInfo;
   sublist     = new QList<Entry>;
   sublist->setAutoDelete(TRUE);
   extends     = new QList<BaseInfo>;
@@ -157,6 +159,7 @@ Entry::Entry(const Entry &e)
       //printf("appending argument %s %s\n",a->type.data(),a->name.data());
     }
   }
+
 }
 
 Entry::~Entry()
@@ -170,6 +173,7 @@ Entry::~Entry()
   delete argList;
   delete tArgList;
   delete mtArgList;
+  delete tagInfo;
   num--;
 }
 
@@ -233,6 +237,7 @@ void Entry::reset()
   groups->clear();
   anchors->clear();
   argList->clear();
+  if (tagInfo) { delete tagInfo; tagInfo=0; }
   if (tArgList) { delete tArgList; tArgList=0; }
   if (mtArgList) { delete mtArgList; mtArgList=0; }
 }
diff --git a/src/entry.h b/src/entry.h
index c836d87..2968b1e 100644
--- a/src/entry.h
+++ b/src/entry.h
@@ -93,6 +93,13 @@ class ArgumentList : public QList<Argument>
 
 typedef QListIterator<Argument> ArgumentListIterator;
 
+struct TagInfo 
+{
+  QCString tagName;
+  QCString fileName;
+  QCString anchor;
+};
+
 /*! Raw entry. parseMain() in scanner.l will generate a tree of these
  *  entries.
  */
@@ -200,6 +207,7 @@ class Entry
     int		startLine;    // start line of entry in the source
     int         todoId;       // id of the todo item of this entry
     int         testId;       // id of the test item of this entry
+    TagInfo    *tagInfo;      // tag file info
     static int  num;          // counts the total number of entries
   private:
     Entry &operator=(const Entry &); 
diff --git a/src/filedef.cpp b/src/filedef.cpp
index bb75335..b27f8ac 100644
--- a/src/filedef.cpp
+++ b/src/filedef.cpp
@@ -119,10 +119,16 @@ void FileDef::writeDocumentation(OutputList &ol)
   startFile(ol,diskname,pageTitle);
   startTitle(ol,getOutputFileBase());
   parseText(ol,theTranslator->trFileReference(docname));
-  endTitle(ol,getOutputFileBase(),getOutputFileBase());
+  endTitle(ol,getOutputFileBase(),docName());
   //ol.newParagraph();
   
-  if (!Config::genTagFile.isEmpty()) tagFile << "&" << name() << ":\n";
+  if (!Config::genTagFile.isEmpty()) 
+  {
+    tagFile << "  <compound kind=\"file\">" << endl;
+    tagFile << "    <name>" << convertToXML(name()) << "</name>" << endl;
+    tagFile << "    <path>" << convertToXML(getPath()) << "</path>" << endl;
+    tagFile << "    <filename>" << convertToXML(diskname) << ".html</filename>" << endl;
+  }
   
   ol.startTextBlock();
   //brief=brief.stripWhiteSpace();
@@ -272,7 +278,11 @@ void FileDef::writeDocumentation(OutputList &ol)
               nd->getOutputFileBase(),
               0,
               nd->name()
-                            );
+          );
+          if (!Config::genTagFile.isEmpty()) 
+          {
+             tagFile << "    <namespace>" << convertToXML(nd->name()) << "</namespace>" << endl;
+          }
         }
         else
         {
@@ -422,6 +432,12 @@ void FileDef::writeDocumentation(OutputList &ol)
   ol.endGroupHeader();
   parseText(ol,theTranslator->trGeneratedAutomatically(Config::projectName));
   ol.enableAll();
+
+  if (!Config::genTagFile.isEmpty()) 
+  {
+    tagFile << "  </compound>" << endl;
+  }
+
   endFile(ol);
 }
 
@@ -497,6 +513,7 @@ void FileDef::addMembersToMemberGroup()
 /*! Adds member definition \a md to the list of all members of this file */
 void FileDef::insertMember(MemberDef *md)
 {
+  //printf("%s:FileDef::insertMember(%s)\n",name().data(),md->name().data());
   allMemberList.append(md); 
   switch(md->memberType())
   {
@@ -524,11 +541,7 @@ void FileDef::insertMember(MemberDef *md)
       else
         enumMembers.append(md);
       break;
-    case MemberDef::EnumValue:    
-      //if (Config::sortMembersFlag)
-      //  enumValMembers.inSort(md); 
-      //else
-      //  enumValMembers.append(md);
+    case MemberDef::EnumValue:    // enum values are shown inside their enums
       break;
     case MemberDef::Prototype:    
       if (Config::sortMembersFlag)
@@ -692,3 +705,12 @@ void FileDef::generateXML(QTextStream &t)
   t << "    </compounddef>" << endl;
 }
 
+bool FileDef::generateSourceFile() const 
+{ 
+  return !isReference() && 
+         (Config::sourceBrowseFlag || 
+           (Config::verbatimHeaderFlag && guessSection(name())==Entry::HEADER_SEC) 
+         ) &&
+         name().right(4)!=".doc" && name().right(4)!=".txt"; 
+}
+
diff --git a/src/filedef.h b/src/filedef.h
index fe3a761..510b49a 100644
--- a/src/filedef.h
+++ b/src/filedef.h
@@ -121,12 +121,7 @@ class FileDef : public Definition
     void addUsingDeclaration(ClassDef *cd);
     ClassList *getUsedClasses() const { return usingDeclList; }
 
-    //void setGenerateSource(bool b) { isSource=b; }
-    bool generateSourceFile() const 
-    { return !isReference() && 
-              (Config::sourceBrowseFlag || Config::verbatimHeaderFlag) &&
-              name().right(4)!=".doc" && name().right(4)!=".txt"; 
-    }
+    bool generateSourceFile() const;
 
     void addIncludeDependency(FileDef *fd,const char *incName,bool local);
     void addIncludedByDependency(FileDef *fd,const char *incName,bool local);
diff --git a/src/formula.cpp b/src/formula.cpp
index 16626fd..abe529a 100644
--- a/src/formula.cpp
+++ b/src/formula.cpp
@@ -103,7 +103,7 @@ void FormulaList::generateBitmaps(const char *path)
   {
     //printf("Running latex...\n");
     //system("latex _formulas.tex </dev/null >/dev/null");
-    if (iSystem("latex _formulas.tex")!=0)
+    if (iSystem("latex","_formulas.tex")!=0)
     {
       err("Problems running latex. Check your installation or look for typos in _formulas.tex!\n");
       formulaError=TRUE;
@@ -117,14 +117,14 @@ void FormulaList::generateBitmaps(const char *path)
     {
       int pageNum=*pagePtr;
       msg("Generating image form-%d.gif for formula\n",pageNum);
-      char dviCmd[256];
+      char dviArgs[4096];
       QCString formBase;
       formBase.sprintf("_form%d",pageNum);
       // run dvips to convert the page with number pageIndex to an
       // encapsulated postscript.
-      sprintf(dviCmd,"dvips -q -D 600 -E -n 1 -p %d -o %s.eps _formulas.dvi",
+      sprintf(dviArgs,"-q -D 600 -E -n 1 -p %d -o %s.eps _formulas.dvi",
           pageIndex,formBase.data());
-      if (iSystem(dviCmd)!=0)
+      if (iSystem("dvips",dviArgs)!=0)
       {
         err("Problems running dvips. Check your installation!\n");
         return;
@@ -208,13 +208,13 @@ void FormulaList::generateBitmaps(const char *path)
         WaitForSingleObject(sInfo.hProcess,INFINITE); 
       }
 #else
-      char gsCmd[256];
-      sprintf(gsCmd,"gs -q -g%dx%d -r%dx%dx -sDEVICE=ppmraw "
+      char gsArgs[4096];
+      sprintf(gsArgs,"-q -g%dx%d -r%dx%dx -sDEVICE=ppmraw "
                     "-sOutputFile=%s.pnm -DNOPAUSE -- %s.ps",
                     gx,gy,(int)(scaleFactor*72),(int)(scaleFactor*72),
                     formBase.data(),formBase.data()
              );
-      if (iSystem(gsCmd)!=0)
+      if (iSystem("gs",gsArgs)!=0)
       {
         err("Problem running ghostscript. Check your installation!\n");
         return;
diff --git a/src/ftvhelp.cpp b/src/ftvhelp.cpp
index cac212b..c9e315d 100644
--- a/src/ftvhelp.cpp
+++ b/src/ftvhelp.cpp
@@ -37,7 +37,7 @@ unsigned char ftv2blank_gif[] = {
   0xcd, 0xbb, 0xff, 0x60, 0x28, 0x8e, 0x64, 0x69, 0x9e, 0x68, 0xaa, 0x3e,
   0x11, 0x00, 0x3b
 };
-unsigned int ftv2blank_gif_len = 135;
+const unsigned int ftv2blank_gif_len = 135;
 
 unsigned char ftv2doc_gif[] = {
   0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x18, 0x00, 0x16, 0x00, 0xa2, 0x00,
@@ -53,7 +53,7 @@ unsigned char ftv2doc_gif[] = {
   0x85, 0xfc, 0x42, 0x5c, 0xdb, 0x32, 0x86, 0xf5, 0x0d, 0xce, 0xe8, 0x74,
   0xf7, 0x41, 0x6b, 0xbb, 0x39, 0xf0, 0xb8, 0xdc, 0x92, 0x00, 0x00, 0x3b
 };
-unsigned int ftv2doc_gif_len = 144;
+const unsigned int ftv2doc_gif_len = 144;
 
 unsigned char ftv2folderclosed_gif[] = {
   0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x18, 0x00, 0x16, 0x00, 0xa2, 0x00,
@@ -69,7 +69,7 @@ unsigned char ftv2folderclosed_gif[] = {
   0xd5, 0x5a, 0x4e, 0x43, 0x2f, 0x08, 0x43, 0x05, 0x99, 0xcf, 0xe8, 0x49,
   0x02, 0x00, 0x3b
 };
-unsigned int ftv2folderclosed_gif_len = 135;
+const unsigned int ftv2folderclosed_gif_len = 135;
 
 unsigned char ftv2folderopen_gif[] = {
   0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x18, 0x00, 0x16, 0x00, 0xa2, 0x00,
@@ -86,7 +86,7 @@ unsigned char ftv2folderopen_gif[] = {
   0x95, 0x88, 0x36, 0x42, 0x27, 0x5f, 0x80, 0x7c, 0x2e, 0xef, 0x46, 0x6b,
   0xf8, 0xbc, 0xbd, 0xc3, 0xef, 0xfb, 0x1b, 0x09, 0x00, 0x3b
 };
-unsigned int ftv2folderopen_gif_len = 154;
+const unsigned int ftv2folderopen_gif_len = 154;
 
 unsigned char ftv2lastnode_gif[] = {
   0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x10, 0x00, 0x16, 0x00, 0xb3, 0x00,
@@ -102,7 +102,7 @@ unsigned char ftv2lastnode_gif[] = {
   0xcd, 0xbb, 0xff, 0x60, 0x28, 0x72, 0xc0, 0x57, 0x7a, 0x67, 0x97, 0x92,
   0x4f, 0xe9, 0xb6, 0x63, 0x2c, 0xcf, 0x5e, 0x04, 0x00, 0x3b
 };
-unsigned int ftv2lastnode_gif_len = 142;
+const unsigned int ftv2lastnode_gif_len = 142;
 
 unsigned char ftv2link_gif[] = {
   0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x18, 0x00, 0x16, 0x00, 0xb3, 0x00,
@@ -126,7 +126,7 @@ unsigned char ftv2link_gif[] = {
   0x07, 0x8e, 0x8e, 0x89, 0x70, 0x38, 0x93, 0x94, 0x91, 0x22, 0x97, 0x98,
   0x99, 0x9a, 0x0f, 0x11, 0x00, 0x3b
 };
-unsigned int ftv2link_gif_len = 234;
+const unsigned int ftv2link_gif_len = 234;
 
 unsigned char ftv2mlastnode_gif[] = {
   0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x10, 0x00, 0x16, 0x00, 0xb3, 0x00,
@@ -141,7 +141,7 @@ unsigned char ftv2mlastnode_gif[] = {
   0xd9, 0xf5, 0x7a, 0xeb, 0x35, 0x49, 0x82, 0xc0, 0xa0, 0x70, 0x48, 0x2c,
   0x1a, 0x35, 0x11, 0x00, 0x3b
 };
-unsigned int ftv2mlastnode_gif_len = 125;
+const unsigned int ftv2mlastnode_gif_len = 125;
 
 unsigned char ftv2mnode_gif[] = {
   0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x10, 0x00, 0x16, 0x00, 0xb3, 0x00,
@@ -156,7 +156,7 @@ unsigned char ftv2mnode_gif[] = {
   0xd9, 0xf5, 0x7a, 0xeb, 0x35, 0x49, 0x82, 0x40, 0x4c, 0x70, 0x28, 0x24,
   0x06, 0x71, 0xc6, 0x0d, 0x52, 0x12, 0x01, 0x00, 0x3b
 };
-unsigned int ftv2mnode_gif_len = 129;
+const unsigned int ftv2mnode_gif_len = 129;
 
 unsigned char ftv2node_gif[] = {
   0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x10, 0x00, 0x16, 0x00, 0xb3, 0x00,
@@ -173,7 +173,7 @@ unsigned char ftv2node_gif[] = {
   0x4f, 0xe9, 0xb6, 0xd7, 0xba, 0xc9, 0x1a, 0x9d, 0xd9, 0x18, 0x1e, 0x63,
   0x11, 0x00, 0x3b
 };
-unsigned int ftv2node_gif_len = 147;
+const unsigned int ftv2node_gif_len = 147;
 
 unsigned char ftv2plastnode_gif[] = {
   0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x10, 0x00, 0x16, 0x00, 0xb3, 0x00,
@@ -188,7 +188,7 @@ unsigned char ftv2plastnode_gif[] = {
   0xdd, 0xec, 0x04, 0xdb, 0xa7, 0x9a, 0xa3, 0x3d, 0x17, 0x89, 0x04, 0x2a,
   0x1a, 0x8f, 0xc8, 0xa4, 0x72, 0xa9, 0x89, 0x00, 0x00, 0x3b
 };
-unsigned int ftv2plastnode_gif_len = 130;
+const unsigned int ftv2plastnode_gif_len = 130;
 
 unsigned char ftv2pnode_gif[] = {
   0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x10, 0x00, 0x16, 0x00, 0xb3, 0x00,
@@ -204,7 +204,7 @@ unsigned char ftv2pnode_gif[] = {
   0xc6, 0x8c, 0x48, 0x5e, 0xd2, 0xd8, 0x5a, 0x72, 0x9a, 0x93, 0x08, 0x00,
   0x3b
 };
-unsigned int ftv2pnode_gif_len = 133;
+const unsigned int ftv2pnode_gif_len = 133;
 
 unsigned char ftv2vertline_gif[] = {
   0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x10, 0x00, 0x16, 0x00, 0xb3, 0x00,
@@ -220,7 +220,7 @@ unsigned char ftv2vertline_gif[] = {
   0xcd, 0xbb, 0xff, 0x60, 0x28, 0x72, 0xc0, 0x57, 0x7a, 0x67, 0x97, 0x92,
   0x66, 0x8b, 0xba, 0x2a, 0x5c, 0x45, 0x00, 0x3b
 };
-unsigned int ftv2vertline_gif_len = 140;
+const unsigned int ftv2vertline_gif_len = 140;
 
 struct ImageInfo
 {
@@ -272,7 +272,16 @@ static void generateFolderTreeViewData()
   else
   {
     QTextStream t(&f);
-    t << "<html><head><title>" << Config::projectName << "</title></head>" << endl;
+    t << "<html><head><title>"; 
+    if (Config::projectName.isEmpty())
+    {
+      t << "Doxygen Documentation";
+    }
+    else
+    {
+      t << Config::projectName;
+    }
+    t << "</title></head>" << endl;
     t << "<frameset cols=\"" << Config::treeViewWidth << ",*\">" << endl;
     t << "  <frame src=\"tree.html\" name=\"treefrm\">" << endl;
     t << "  <frame src=\"main.html\" name=\"basefrm\">" << endl;
@@ -361,7 +370,7 @@ void FTVHelp::initialize()
   }
   /* Write the header of the contents file */
   m_cts.setDevice(m_cf);
-  m_cts << "foldersTree = gFld(\"\", \"<b>";
+  m_cts << "foldersTree = gFld(\"<b>";
   if (Config::projectName.isEmpty())
   {
     m_cts << "Root";
@@ -370,7 +379,7 @@ void FTVHelp::initialize()
   {
     m_cts << Config::projectName;
   }
-  m_cts << "</b>\", \"\")\n";
+  m_cts << "</b>\", \"\", \"\")\n";
 }
 
 /*! Finalizes the FTV help. This will finish and close the
diff --git a/src/groupdef.cpp b/src/groupdef.cpp
index 054222a..501ceb0 100644
--- a/src/groupdef.cpp
+++ b/src/groupdef.cpp
@@ -249,7 +249,7 @@ void GroupDef::writeDocumentation(OutputList &ol)
   startFile(ol,fileName,title);
   startTitle(ol,getOutputFileBase());
   ol.docify(title);
-  endTitle(ol,getOutputFileBase(),name());
+  endTitle(ol,getOutputFileBase(),title);
 
   //brief=brief.stripWhiteSpace();
   //int bl=brief.length();
@@ -269,6 +269,13 @@ void GroupDef::writeDocumentation(OutputList &ol)
     ol.popGeneratorState();
   }
 
+  if (!Config::genTagFile.isEmpty()) 
+  {
+    tagFile << "  <compound kind=\"group\">" << endl;
+    tagFile << "    <name>" << convertToXML(name()) << "</name>" << endl;
+    tagFile << "    <title>" << convertToXML(title) << "</title>" << endl;
+    tagFile << "    <filename>" << convertToXML(fileName) << ".html</filename>" << endl;
+  }
   
   ol.startMemberSections();
   if (fileList->count()>0)
@@ -284,6 +291,10 @@ void GroupDef::writeDocumentation(OutputList &ol)
       ol.docify("file ");
       ol.insertMemberAlign();
       ol.writeObjectLink(fd->getReference(),fd->getOutputFileBase(),0,fd->name());
+      if (!Config::genTagFile.isEmpty()) 
+      {
+        tagFile << "    <file>" << convertToXML(fd->name()) << "</file>" << endl;
+      }
       ol.endMemberItem(FALSE);
       if (!fd->briefDescription().isEmpty() && Config::briefMemDescFlag)
       {
@@ -309,6 +320,10 @@ void GroupDef::writeDocumentation(OutputList &ol)
       ol.docify("namespace ");
       ol.insertMemberAlign();
       ol.writeObjectLink(nd->getReference(),nd->getOutputFileBase(),0,nd->name());
+      if (!Config::genTagFile.isEmpty()) 
+      {
+        tagFile << "    <namespace>" << convertToXML(nd->name()) << "</namespace>" << endl;
+      }
       ol.endMemberItem(FALSE);
       if (!nd->briefDescription().isEmpty() && Config::briefMemDescFlag)
       {
@@ -333,6 +348,10 @@ void GroupDef::writeDocumentation(OutputList &ol)
       ol.startMemberItem(0);
       //ol.insertMemberAlign();
       ol.writeObjectLink(gd->getReference(),gd->getOutputFileBase(),0,gd->groupTitle());
+      if (!Config::genTagFile.isEmpty()) 
+      {
+        tagFile << "    <subgroup>" << convertToXML(gd->name()) << "</subgroup>" << endl;
+      }
       ol.endMemberItem(FALSE);
       if (!gd->briefDescription().isEmpty() && Config::briefMemDescFlag)
       {
@@ -396,23 +415,27 @@ void GroupDef::writeDocumentation(OutputList &ol)
   PageSDictIterator pdi(*pageDict);
   for (pdi.toFirst();(pi=pdi.current());++pdi)
   {
-    QCString pageName;
-    if (Config::caseSensitiveNames)
-      pageName=pi->name.copy();
-    else
-      pageName=pi->name.lower();
-    
-    SectionInfo *si=0;
-    if (!pi->title.isEmpty() && !pi->name.isEmpty() &&
-        (si=sectionDict[pi->name])!=0)
+    if (!pi->isReference())
     {
-      ol.startSection(si->label,si->title,TRUE);
-      ol.docify(si->title);
-      ol.endSection(si->label,TRUE);
+      QCString pageName = pi->getOutputFileBase();
+
+      if (!Config::genTagFile.isEmpty()) 
+      {
+        tagFile << "    <page>" << convertToXML(pageName) << "</page>" << endl;
+      }
+
+      SectionInfo *si=0;
+      if (!pi->title.isEmpty() && !pi->name.isEmpty() &&
+          (si=sectionDict[pi->name])!=0)
+      {
+        ol.startSection(si->label,si->title,TRUE);
+        ol.docify(si->title);
+        ol.endSection(si->label,TRUE);
+      }
+      ol.startTextBlock();
+      parseDoc(ol,pi->defFileName,pi->defLine,0,0,pi->doc);
+      ol.endTextBlock();
     }
-    ol.startTextBlock();
-    parseDoc(ol,pi->defFileName,pi->defLine,0,0,pi->doc);
-    ol.endTextBlock();
   }
 
   defineMembers.countDocMembers(TRUE);
@@ -475,6 +498,11 @@ void GroupDef::writeDocumentation(OutputList &ol)
     varMembers.writeDocumentation(ol,name(),this);
   }
 
+  if (!Config::genTagFile.isEmpty()) 
+  {
+    tagFile << "  </compound>" << endl;
+  }
+
   endFile(ol); 
   ol.popGeneratorState();
 }
diff --git a/src/htmlgen.cpp b/src/htmlgen.cpp
index a077ab2..86c90e9 100644
--- a/src/htmlgen.cpp
+++ b/src/htmlgen.cpp
@@ -304,6 +304,7 @@ void HtmlGenerator::writeString(const char *text)
 void HtmlGenerator::writeIndexItem(const char *ref,const char *f,
                                    const char *name)
 {
+  //printf("HtmlGenerator::writeIndexItem(%s,%s,%s)\n",ref,f,name);
   QCString *dest;
   t << "<li>";
   if (ref || f)
diff --git a/src/htmlgen.h b/src/htmlgen.h
index 0f3b588..0a0ebf1 100644
--- a/src/htmlgen.h
+++ b/src/htmlgen.h
@@ -188,7 +188,7 @@ class HtmlGenerator : public OutputGenerator
     void writeSectionRef(const char *,const char *,const char *);
     void writeSectionRefItem(const char *,const char *,const char *);
     void writeSectionRefAnchor(const char *,const char *,const char *);
-    void addToIndex(const char *,const char *) {}
+    void addIndexItem(const char *,const char *) {}
     void startIndent();
     void endIndent();
     void writeSynopsis() {}
diff --git a/src/index.cpp b/src/index.cpp
index 09b2e71..9ef8bc1 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()) count++;
+    if (nd->isLinkableInProject() && nd->countMembers()>0) count++;
   }
   return count;
 }
@@ -726,7 +726,7 @@ void writeNamespaceIndex(OutputList &ol)
   endTitle(ol,0,0);
   ol.startTextBlock();
   HtmlHelp *htmlHelp = 0;
-  FTVHelp  *ftvHelp = 0;
+  FTVHelp  *ftvHelp  = 0;
   bool hasHtmlHelp = Config::generateHtml && Config::htmlHelpFlag /*&& !Config::htmlHelpGroupsOnly*/;
   bool hasFtvHelp =  Config::generateHtml && Config::ftvHelpFlag  /*&& !Config::htmlHelpGroupsOnly*/;
   if (hasHtmlHelp)
@@ -1677,8 +1677,11 @@ int countGroups()
   GroupDef *gd;
   for (;(gd=gli.current());++gli)
   {
-    gd->visited=FALSE;
-    count++;
+    if (!gd->isReference())
+    {
+      gd->visited=FALSE;
+      count++;
+    }
   }
   return count;
 }
@@ -1751,7 +1754,13 @@ void writeGroupTreeNode(OutputList &ol, GroupDef *gd)
     //parseText(ol,gd->groupTitle());
     //ol.endTextLink();
     
-    ol.writeIndexItem(0,gd->getOutputFileBase(),gd->groupTitle());
+    ol.writeIndexItem(gd->getReference(),gd->getOutputFileBase(),gd->groupTitle());
+    if (gd->isReference()) 
+    { 
+      ol.startTypewriter(); 
+      ol.docify(" [external]");
+      ol.endTypewriter();
+    }
     
     //ol.writeStartAnnoItem(0,gd->getOutputFileBase(),0,gd-);
     //parseText(ol,gd->groupTitle());
@@ -1962,20 +1971,14 @@ void writeGroupIndex(OutputList &ol)
   if (hasHtmlHelp)
   {
     htmlHelp = HtmlHelp::getInstance();
-    //if(!Config::htmlHelpGroupsOnly)
-    //{
-        htmlHelp->addContentsItem(TRUE,htmlHelpTitle,"modules"); 
-        htmlHelp->incContentsDepth();
-    //}
+    htmlHelp->addContentsItem(TRUE,htmlHelpTitle,"modules"); 
+    htmlHelp->incContentsDepth();
   }
   if (hasFtvHelp)
   {
     ftvHelp = FTVHelp::getInstance();
-    //if(!Config::htmlHelpGroupsOnly)
-    //{
-        ftvHelp->addContentsItem(TRUE,0,"modules",0,htmlHelpTitle); 
-        ftvHelp->incContentsDepth();
-    //}
+    ftvHelp->addContentsItem(TRUE,0,"modules",0,ftvHelpTitle); 
+    ftvHelp->incContentsDepth();
   }
   parseText(ol,theTranslator->trModulesDescription());
   ol.endTextBlock();
diff --git a/src/latexgen.cpp b/src/latexgen.cpp
index e0e72fc..7baafa1 100644
--- a/src/latexgen.cpp
+++ b/src/latexgen.cpp
@@ -494,9 +494,12 @@ void LatexGenerator::startIndexSection(IndexSections is)
         bool found=FALSE;
         while (gd && !found)
         {
-          if (Config::compactLatexFlag) t << "\\section"; else t << "\\chapter";
-          t << "{"; //Module Documentation}\n";
-          found=TRUE;
+          if (!gd->isReference())
+          {
+            if (Config::compactLatexFlag) t << "\\section"; else t << "\\chapter";
+            t << "{"; //Module Documentation}\n";
+            found=TRUE;
+          }
           gd=groupList.next();
         }
       }
@@ -507,7 +510,7 @@ void LatexGenerator::startIndexSection(IndexSections is)
         bool found=FALSE;
         while (nd && !found)
         {
-          if (nd->isLinkableInProject())
+          if (nd->isLinkableInProject() && nd->countMembers()>0)
           {
             if (Config::compactLatexFlag) t << "\\section"; else t << "\\chapter";
             t << "{"; // Namespace Documentation}\n":
@@ -616,14 +619,20 @@ void LatexGenerator::endIndexSection(IndexSections is)
         bool found=FALSE;
         while (gd && !found)
         {
-          t << "}\n\\input{" << gd->getOutputFileBase() << "}\n";
-          found=TRUE;
+          if (!gd->isReference())
+          {
+            t << "}\n\\input{" << gd->getOutputFileBase() << "}\n";
+            found=TRUE;
+          }
           gd=groupList.next();
         }
         while (gd)
         {
-          if (Config::compactLatexFlag) t << "\\input"; else t << "\\include";
-          t << "{" << gd->getOutputFileBase() << "}\n";
+          if (!gd->isReference())
+          {
+            if (Config::compactLatexFlag) t << "\\input"; else t << "\\include";
+            t << "{" << gd->getOutputFileBase() << "}\n";
+          }
           gd=groupList.next();
         }
       }
@@ -1050,7 +1059,7 @@ void LatexGenerator::writeAnchor(const char *fName,const char *name)
 //  writeDoxyAnchor(0,clName,anchor,0);
 //}
 
-void LatexGenerator::addToIndex(const char *s1,const char *s2)
+void LatexGenerator::addIndexItem(const char *s1,const char *s2)
 {
   if (s1)
   {
@@ -1067,6 +1076,7 @@ void LatexGenerator::addToIndex(const char *s1,const char *s2)
   }
 }
 
+
 void LatexGenerator::startSection(const char *lab,const char *,bool sub)
 {
   if (Config::pdfHyperFlag)
@@ -1092,13 +1102,16 @@ void LatexGenerator::writeSectionRef(const char *,const char *lab,
     t << "}{";
     docify(text);
     t << "}";
+    //t << " {\\rm (p.\\,\\pageref{" << lab << "})}";
   }
   else
   {
     if (strcmp(lab,text)!=0) // lab!=text
     {
       // todo: don't hardcode p. here!
-      t << "{\\bf " << text << "} {\\rm (p.\\,\\pageref{" << lab << "})}";
+      t << "{\\bf ";
+      docify(text);
+      t << "} {\\rm (p.\\,\\pageref{" << lab << "})}";
     }
     else
     {
diff --git a/src/latexgen.h b/src/latexgen.h
index b08e7b3..4095eb5 100644
--- a/src/latexgen.h
+++ b/src/latexgen.h
@@ -185,7 +185,7 @@ class LatexGenerator : public OutputGenerator
     void writeSectionRef(const char *,const char *,const char *);
     void writeSectionRefItem(const char *,const char *,const char *);
     void writeSectionRefAnchor(const char *,const char *,const char *);
-    void addToIndex(const char *,const char *);
+    void addIndexItem(const char *,const char *);
     void startIndent()       {}
     void endIndent()         {}
     void writeSynopsis()     {}
diff --git a/src/mangen.h b/src/mangen.h
index 731f35e..39d9f2d 100644
--- a/src/mangen.h
+++ b/src/mangen.h
@@ -175,7 +175,7 @@ class ManGenerator : public OutputGenerator
     void writeSectionRef(const char *,const char *,const char *) {}
     void writeSectionRefItem(const char *,const char *,const char *) {}
     void writeSectionRefAnchor(const char *,const char *,const char *) {}
-    void addToIndex(const char *,const char *) {}
+    void addIndexItem(const char *,const char *) {}
     void startIndent()        {}
     void endIndent()          {}
     void writeSynopsis();
diff --git a/src/memberdef.cpp b/src/memberdef.cpp
index 5bf7e46..cf6d9c2 100644
--- a/src/memberdef.cpp
+++ b/src/memberdef.cpp
@@ -258,6 +258,7 @@ MemberDef::MemberDef(const char *df,int dl,
   initLines=0;
   type=t;
   args=a;
+  args=args.stripWhiteSpace();
   if (type.isEmpty()) decl=name()+args; else decl=type+" "+name()+args;
   declLine=0;
   memberGroup=0;
@@ -277,6 +278,7 @@ MemberDef::MemberDef(const char *df,int dl,
   annEnumType=0;
   indDepth=0;
   section=0;
+  explExt=FALSE;
   maxInitLines=defMaxInitLines;
   docEnumValues=FALSE;
   // copy function template arguments (if any)
@@ -507,8 +509,43 @@ void MemberDef::writeDeclaration(OutputList &ol,
     
     if (!Config::genTagFile.isEmpty())
     {
-      tagFile << name() << " " << anchor() << " \""
-              << argsString() << "\"\n";
+      tagFile << "    <member kind=\"";
+      switch (mtype)
+      {
+        case Define:      tagFile << "define";      break;
+        case EnumValue:   tagFile << "enumvalue";   break;
+        case Property:    tagFile << "property";    break;
+        case Variable:    tagFile << "variable";    break;
+        case Typedef:     tagFile << "typedef";     break;
+        case Enumeration: tagFile << "enumeration"; break;
+        case Function:    tagFile << "function";    break;
+        case Signal:      tagFile << "signal";      break;
+        case Prototype:   tagFile << "prototype";   break;
+        case Friend:      tagFile << "friend";      break;
+        case DCOP:        tagFile << "dcop";        break;
+        case Slot:        tagFile << "slot";        break;
+      }
+      if (prot!=Public)
+      {
+        tagFile << "\" protection=\"";
+        if (prot==Protected) tagFile << "public";
+        else /* Private */   tagFile << "protected"; 
+      }
+      if (virt!=Normal)
+      {
+        tagFile << "\" virtualness=\"";
+        if (virt==Virtual) tagFile << "virtual";
+        else /* Pure */    tagFile << "pure"; 
+      }
+      if (isStatic())
+      {
+        tagFile << "\" static=\"yes";
+      }
+      tagFile << "\">" << endl;
+      tagFile << "      <name>" << convertToXML(name()) << "</name>" << endl;
+      tagFile << "      <anchor>" << convertToXML(anchor()) << "</anchor>" << endl;
+      tagFile << "      <arglist>" << convertToXML(argsString()) << "</arglist>" << endl;
+      tagFile << "    </member>" << endl;
     }
       
     Definition *d=0;
@@ -593,8 +630,10 @@ void MemberDef::writeDeclaration(OutputList &ol,
       QCString doxyName=name().copy();
       if (!cname.isEmpty()) doxyName.prepend(cname+"::");
       ol.startDoxyAnchor(cfname,anchor(),doxyName);
-      ol.addToIndex(name(),cname);
-      ol.addToIndex(cname,name());
+
+      ol.addIndexItem(name(),cname);
+      ol.addIndexItem(cname,name());
+
       if (hasHtmlHelp)
       {
         htmlHelp->addIndexItem(cname,name(),cfname,anchor());
@@ -1115,8 +1154,10 @@ void MemberDef::writeDocumentation(MemberList *ml,OutputList &ol,
               //ol.startItemList();
               ol.startDescTable();
             }
-            ol.addToIndex(fmd->name(),cname);
-            ol.addToIndex(cname,fmd->name());
+
+            ol.addIndexItem(fmd->name(),cname);
+            ol.addIndexItem(cname,fmd->name());
+
             if (Config::generateHtml && Config::htmlHelpFlag)
             {
               HtmlHelp::getInstance()->addIndexItem(cname,fmd->name(),cfname,fmd->anchor());
diff --git a/src/memberdef.h b/src/memberdef.h
index bee7ca4..7f211f1 100644
--- a/src/memberdef.h
+++ b/src/memberdef.h
@@ -118,6 +118,7 @@ class MemberDef : public Definition
     bool isInline() const                 { return (memSpec&Entry::Inline)!=0; }
     bool isExplicit() const               { return (memSpec&Entry::Explicit)!=0; }
     bool isMutable() const                { return (memSpec&Entry::Mutable)!=0; }
+    bool isExternal() const               { return explExt; }
 
     // output info
     bool isLinkableInProject();
@@ -142,6 +143,7 @@ class MemberDef : public Definition
     void setMemberClass(ClassDef *cd)     { classDef=cd; }
     void setSectionList(MemberList *sl)   { section=sl; }
     void setGroupDef(GroupDef *gd)        { group=gd; }
+    void setExplicitExternal(bool b)      { explExt=b; }
     
     void makeRelated()                    { related=TRUE; } 
 
@@ -269,6 +271,7 @@ class MemberDef : public Definition
     MemberGroup *memberGroup; // group's member definition
 
     GroupDef *group;          // group in which this member is in
+    bool explExt;             // member was explicitly declared external
 
 
     // disable copying of member defs
diff --git a/src/membergroup.h b/src/membergroup.h
index 238d688..01312b2 100644
--- a/src/membergroup.h
+++ b/src/membergroup.h
@@ -22,8 +22,6 @@
 #include <qlist.h>
 #include <qintdict.h>
 
-//#include "definition.h"
-
 #define NOGROUP -1
 
 class MemberDef;
diff --git a/src/memberlist.cpp b/src/memberlist.cpp
index 17b9226..7a1a538 100644
--- a/src/memberlist.cpp
+++ b/src/memberlist.cpp
@@ -291,8 +291,13 @@ void MemberList::writePlainDeclarations(OutputList &ol,
             if (md->isLinkableInProject() || md->hasDocumentedEnumValues())
             {
               if (!Config::genTagFile.isEmpty())
-                tagFile << md->name() << " " << md->anchor() 
-                  << " \"\"" << endl;
+              {
+                tagFile << "    <member>" << endl;
+                tagFile << "      <name>" << convertToXML(md->name()) << "</name>" << endl; 
+                tagFile << "      <anchor>" << convertToXML(md->anchor()) << "</anchor>" << endl; 
+                tagFile << "      <arglist>" << convertToXML(md->argsString()) << "</arglist>" << endl; 
+                tagFile << "    </member>" << endl;
+              }
               md->writeLink(typeDecl,cd,nd,fd,gd);
             }
             else
@@ -325,9 +330,14 @@ void MemberList::writePlainDeclarations(OutputList &ol,
 
               if (fmd->hasDocumentation()) // enum value has docs
               {
-                if (!Config::genTagFile.isEmpty())
-                  tagFile << fmd->name() << " " << fmd->anchor() 
-                    << " \"" << fmd->argsString() << "\"";
+              if (!Config::genTagFile.isEmpty())
+              {
+                tagFile << "    <member>" << endl;
+                tagFile << "      <name>" << convertToXML(fmd->name()) << "</name>" << endl; 
+                tagFile << "      <anchor>" << convertToXML(fmd->anchor()) << "</anchor>" << endl; 
+                tagFile << "      <arglist>" << convertToXML(fmd->argsString()) << "</arglist>" << endl; 
+                tagFile << "    </member>" << endl;
+              }
                 fmd->writeLink(typeDecl,cd,nd,fd,gd);
               }
               else // no docs for this enum value
diff --git a/src/namespacedef.cpp b/src/namespacedef.cpp
index 6377295..b92d2e5 100644
--- a/src/namespacedef.cpp
+++ b/src/namespacedef.cpp
@@ -198,7 +198,12 @@ void NamespaceDef::writeDocumentation(OutputList &ol)
   parseText(ol,theTranslator->trNamespaceReference(name()));
   endTitle(ol,getOutputFileBase(),name());
   
-  if (!Config::genTagFile.isEmpty()) tagFile << "%" << name() << ":\n";
+  if (!Config::genTagFile.isEmpty())
+  {
+    tagFile << "  <compound kind=\"namespace\">" << endl;
+    tagFile << "    <name>" << convertToXML(name()) << "</name>" << endl;
+    tagFile << "    <filename>" << convertToXML(fileName) << ".html</filename>" << endl;
+  }
   
   ol.startTextBlock();
     
@@ -346,7 +351,12 @@ void NamespaceDef::writeDocumentation(OutputList &ol)
   parseText(ol,theTranslator->trAuthor());
   ol.endGroupHeader();
   parseText(ol,theTranslator->trGeneratedAutomatically(Config::projectName));
-  //ol.enableAll();
+
+  if (!Config::genTagFile.isEmpty()) 
+  {
+    tagFile << "  </compound>" << endl;
+  }
+
   ol.popGeneratorState();
   endFile(ol);
 }
diff --git a/src/outputgen.h b/src/outputgen.h
index 7cc8e18..f890a30 100644
--- a/src/outputgen.h
+++ b/src/outputgen.h
@@ -176,7 +176,7 @@ class OutputGenerator
     virtual void writeSectionRefItem(const char *,const char *,const char *) = 0;
     virtual void writeSectionRefAnchor(const char *,const char *,const char *) = 0;
     virtual void lineBreak() = 0;
-    virtual void addToIndex(const char *s1,const char *s2) = 0;
+    virtual void addIndexItem(const char *s1,const char *s2) = 0;
     virtual void startIndent() = 0;
     virtual void endIndent() = 0;
     virtual void writeSynopsis() = 0;
diff --git a/src/outputlist.h b/src/outputlist.h
index eb7b03c..b964483 100644
--- a/src/outputlist.h
+++ b/src/outputlist.h
@@ -71,14 +71,10 @@ class OutputList
     { forall(&OutputGenerator::writeStyleInfo,part); }
     void startFile(const char *name,const char *title,bool external)
     { forall(&OutputGenerator::startFile,name,title,external); }
-    void startPlainFile(const char *name)
-    { forall(&OutputGenerator::startPlainFile,name); }
     void writeFooter(int fase,bool external)
     { forall(&OutputGenerator::writeFooter,fase,external); }
     void endFile() 
     { forall(&OutputGenerator::endFile); }
-    void endPlainFile() 
-    { forall(&OutputGenerator::endPlainFile); }
     void startTitleHead(const char *fileName) 
     { forall(&OutputGenerator::startTitleHead,fileName); }
     void endTitleHead(const char *fileName,const char *name)
@@ -313,8 +309,8 @@ class OutputList
     { forall(&OutputGenerator::writeSectionRefItem,page,lab,title); }
     void writeSectionRefAnchor(const char *page,const char *lab, const char *title)
     { forall(&OutputGenerator::writeSectionRefAnchor,page,lab,title); }
-    void addToIndex(const char *s1,const char *s2)
-    { forall(&OutputGenerator::addToIndex,s1,s2); }
+    void addIndexItem(const char *s1,const char *s2)
+    { forall(&OutputGenerator::addIndexItem,s1,s2); }
     void writeSynopsis() 
     { forall(&OutputGenerator::writeSynopsis); }
     void startClassDiagram()
@@ -389,6 +385,32 @@ class OutputList
     void endFontClass()
     { forall(&OutputGenerator::endFontClass); }
 
+#if 0
+    void startPlainFile(const char *name)
+    { forall(&OutputGenerator::startPlainFile,name); }
+    void endPlainFile() 
+    { forall(&OutputGenerator::endPlainFile); }
+#else // this is to work around a bug in the SGI MipsPro compiler
+    void startPlainFile(const char *name)
+    { 
+      OutputGenerator *og=outputs->first();
+      while (og)
+      {
+        if (og->isEnabled()) (og->startPlainFile)(name);
+        og=outputs->next();
+      }
+    }
+    void endPlainFile() 
+    { 
+      OutputGenerator *og=outputs->first();
+      while (og)
+      {
+        if (og->isEnabled()) (og->endPlainFile)();
+        og=outputs->next();
+      }
+    }
+#endif
+
   private:
     void debug();
     void clear();
diff --git a/src/page.h b/src/page.h
index bb841f3..cbcf33c 100644
--- a/src/page.h
+++ b/src/page.h
@@ -16,6 +16,7 @@
  */
 
 #include "sortdict.h"
+#include "config.h"
 
 class PageInfo
 {
@@ -33,6 +34,15 @@ class PageInfo
     QCString doc;
     QCString title;
 
+    // external reference? if so then this is the tag file name
+    QCString reference;
+
+    // functions to get a uniform interface with Definitions
+    QCString getOutputFileBase() const 
+    { if (Config::caseSensitiveNames) return name; else return name.lower(); }
+    bool isReference() const { return !reference.isEmpty(); }
+    QCString getReference() const { return reference; }
+    
     // ids
     int todoId;
     int testId;
diff --git a/src/rtfgen.cpp b/src/rtfgen.cpp
index 22cd3e8..8a1dae2 100644
--- a/src/rtfgen.cpp
+++ b/src/rtfgen.cpp
@@ -671,7 +671,7 @@ void RTFGenerator::beginRTFDocument()
     }    
     if (array.at(index) != 0)
     {
-      QCString key(iter.currentKey());
+      QCString key(convertToQCString(iter.currentKey()));
       msg("Style '%s' redefines \\s%d.\n", key.data(), index);
     }
     array.at(index) = style;      
@@ -810,8 +810,11 @@ void RTFGenerator::startIndexSection(IndexSections is)
         bool found=FALSE;
         while (gd && !found)
         {
-          beginRTFChapter();
-          found=TRUE;
+          if (!gd->isReference())
+          {
+            beginRTFChapter();
+            found=TRUE;
+          }
           gd=groupList.next();
         }
       }
@@ -965,10 +968,13 @@ void RTFGenerator::endIndexSection(IndexSections is)
         t << "{\\tc \\v " << theTranslator->trModuleDocumentation() << "}"<< endl;
         while (gd)
         {
-          t << "\\par " << Rtf_Style_Reset << endl;
-          t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"";
-          t << gd->getOutputFileBase();
-          t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n";
+          if (!gd->isReference())
+          {
+            t << "\\par " << Rtf_Style_Reset << endl;
+            t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"";
+            t << gd->getOutputFileBase();
+            t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n";
+          }
           gd=groupList.next();
         }
       }
@@ -1519,7 +1525,7 @@ void RTFGenerator::endTitleHead(const char *fileName,const char *name)
     t << "}" << endl;
 
     // make an index entry
-    addToIndex(name,0);
+    addIndexItem(name,0);
 
     //if (name)
     //{
@@ -1566,8 +1572,8 @@ void RTFGenerator::startMemberDoc(const char *clname,
   DBG_RTF(t << "{\\comment startMemberDoc}" << endl)
   if (memname && memname[0]!='@')
   {
-    addToIndex(memname,clname);
-    addToIndex(clname,memname);
+    addIndexItem(memname,clname);
+    addIndexItem(clname,memname);
   }
   t << Rtf_Style_Reset << Rtf_Style["Heading4"]->reference;
   //styleStack.push(Rtf_Style_Heading4);
@@ -1619,7 +1625,7 @@ void RTFGenerator::endDoxyAnchor(const char *fName,const char *anchor)
 //  writeDoxyAnchor(0,clName,anchor,0);
 //}
 
-void RTFGenerator::addToIndex(const char *s1,const char *s2)
+void RTFGenerator::addIndexItem(const char *s1,const char *s2)
 {
   if (s1)
   {
diff --git a/src/rtfgen.h b/src/rtfgen.h
index 8fc53ad..2631dc0 100644
--- a/src/rtfgen.h
+++ b/src/rtfgen.h
@@ -171,7 +171,7 @@ class RTFGenerator : public OutputGenerator
     void writeSectionRef(const char *,const char *,const char *);
     void writeSectionRefItem(const char *,const char *,const char *);
     void writeSectionRefAnchor(const char *,const char *,const char *);
-    void addToIndex(const char *,const char *);
+    void addIndexItem(const char *,const char *);
     void startIndent();
     void endIndent();
     void writeSynopsis()     {}
diff --git a/src/scanner.l b/src/scanner.l
index eb5c5f6..cfcc689 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -141,6 +141,7 @@ static QCString         *pCopyRoundString;
 static QCString         *pCopyCurlyString;
 static QCString         *pCopyQuotedString;
 static QCString         *pSkipDoc;
+static QCString         autoGroupName;
 
 static bool             insideFormula;
 
@@ -166,6 +167,18 @@ static void initParser()
   isTypedef = FALSE;
 }
 
+static void initEntry()
+{
+  current->protection = protection ;
+  current->mtype      = mtype;
+  current->virt       = virt;
+  current->stat       = gstat;
+  current->mGrpId     = memberGroupId;
+  if (!autoGroupName.isEmpty())
+  {
+    current->groups->append(new QCString(autoGroupName));
+  }
+}
 //-----------------------------------------------------------------------------
 
 static void lineCount()
@@ -311,7 +324,7 @@ static int yyread(char *buf,int max_size)
 %}
 
 CMD	  ("\\"|"@")
-SECTIONCMD {CMD}("image"|"author"|"internal"|"version"|"date"|"deprecated"|"param"|"exception"|"return"[s]?|"retval"|"bug"|"warning"|"par"|"sa"|"see"|"pre"|"post"|"invariant"|"note"|"remark"[s]?|"todo"|"test"|"ingroup"|"latexonly"|"htmlonly") 
+SECTIONCMD {CMD}("image"|"author"|"internal"|"version"|"date"|"deprecated"|"param"|"exception"|"return"[s]?|"retval"|"bug"|"warning"|"par"|"sa"|"see"|"pre"|"post"|"invariant"|"note"|"remark"[s]?|"todo"|"test"|"ingroup"|"latexonly"|"htmlonly"|"{") 
 BN        [ \t\n\r]
 BL        [ \t\r]*"\n"
 B         [ \t]
@@ -469,7 +482,6 @@ TITLE     [tT][iI][tT][lL][eE]
 					  if (sec)
 					  {
 					    current->name    = yyFileName;
-					    current->name    = current->name;
 					    current->section = sec;
 					    current_root->addSubEntry(current);
 					    current          = new Entry;
@@ -824,11 +836,7 @@ TITLE     [tT][iI][tT][lL][eE]
 					  //printf("Found using declaration %s\n",yytext);
 					  current_root->addSubEntry(current);
 					  current             = new Entry ;
-					  current->protection = protection ;
-				          current->mtype      = mtype;
-					  current->virt       = virt;
-					  current->stat       = gstat;
-					  current->mGrpId     = memberGroupId;
+					  initEntry();
 					  BEGIN(Using);
   					}
 <UsingDirective>{SCOPENAME}		{ current->name=yytext;
@@ -837,11 +845,7 @@ TITLE     [tT][iI][tT][lL][eE]
 					  //printf("Found using directive %s\n",yytext);
 					  current_root->addSubEntry(current);
 					  current             = new Entry ;
-					  current->protection = protection ;
-				          current->mtype      = mtype;
-					  current->virt       = virt;
-					  current->stat       = gstat;
-					  current->mGrpId     = memberGroupId;
+					  initEntry();
 					  BEGIN(Using);
   					}
 <Using>";"				{ BEGIN(FindMembers); }
@@ -874,11 +878,19 @@ TITLE     [tT][iI][tT][lL][eE]
 					  else
 					    BEGIN( EndTemplate );
   					}
+<EndTemplate>"<<"			{
+  					  current->name+=yytext;
+  					  *currentTemplateSpec+=yytext; 
+  					}
 <EndTemplate>"<"			{ 
   					  current->name+='<';
   					  *currentTemplateSpec+='<'; 
 					  sharpCount++; 
 					}
+<EndTemplate>">>"			{
+  					  current->name+=yytext;
+  					  *currentTemplateSpec+=yytext; 
+  					}
 <EndTemplate>">"			{
   					  current->name+='>';
 					  *currentTemplateSpec+='>';
@@ -1000,11 +1012,7 @@ TITLE     [tT][iI][tT][lL][eE]
 					  current->section    = Entry::DEFINE_SEC;
 					  current_root->addSubEntry(current);
 					  current             = new Entry ;
-					  current->protection = protection ;
-				          current->mtype      = mtype;
-					  current->virt       = virt;
-					  current->stat       = gstat;
-					  current->mGrpId     = memberGroupId;
+					  initEntry();
 					  BEGIN(FindMembers);
   					}
 <DefineEnd>\\[\r]?\n			{
@@ -1092,7 +1100,7 @@ TITLE     [tT][iI][tT][lL][eE]
 					    BEGIN(AfterDoc);
 					  }
   					}
-<FindMembers,FindFields>"//@{"|"/*@{"	{
+<FindMembers,FindFields>"//"([!*]?){B}*"@{"|"/*"([!*]?){B}*"@{"	{
 					  if (memberGroupId!=NOGROUP)
 					  {
   					    warn(yyFileName,yyLineNr,"Warning: ignoring nested member group. "
@@ -1130,13 +1138,13 @@ TITLE     [tT][iI][tT][lL][eE]
 					    BEGIN( Doc );
 					  }
   					}
-<FindMembers,FindFields,ReadInitializer>"//@}"|"/*@}*/"	{
-					  if (memberGroupId==NOGROUP)
+<FindMembers,FindFields,ReadInitializer>"//"([!*]?){B}*"@}"|"/*"([!*]?){B}*"@}"{B}*"*/"	{
+					  if (memberGroupId==NOGROUP && autoGroupName.isEmpty())
 					  {
 					    warn(yyFileName,yyLineNr,
-                                                 "Warning: end of member group without matching begin.");
+                                                 "Warning: end of group without matching begin.");
 					  }
-					  else
+					  else if (memberGroupId!=NOGROUP) // end of member group
 					  {
   					    memberHeaderDict.insert(memberGroupId,
 					                            new QCString(memberGroupHeader.stripWhiteSpace())
@@ -1145,10 +1153,29 @@ TITLE     [tT][iI][tT][lL][eE]
 					      	               new QCString(memberGroupDocs)
 							      );
 					    memberGroupId=NOGROUP;
-					    if (YY_START!=ReadInitializer) current->mGrpId=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);
+					  }
   					}
 <FindMembers>"="			{
   					  current->bodyLine = yyLineNr;
@@ -1285,7 +1312,6 @@ TITLE     [tT][iI][tT][lL][eE]
   					}
 <FindMembers>[;,]			{ 
   					  QCString oldType = current->type.copy();
-					  QCString oldDocs = current->doc.copy();
 					  if (current->bodyLine==-1)
 					  {
 					    current->bodyLine = yyLineNr;
@@ -1308,20 +1334,18 @@ TITLE     [tT][iI][tT][lL][eE]
 					  current->startLine = yyLineNr;
 					  //printf("New variable type=`%s' name=`%s' groupId=%d\n",current->type.data(),current->name.data(),current->mGrpId);
 					  current_root->addSubEntry( current ) ;
-					  current = new Entry ;
-					  // variable found 
-					  current->section = Entry::EMPTY_SEC ;
-					  current->protection = protection;
-				          current->mtype = Method;
-					  current->virt = Normal; 
-					  current->stat = gstat;
-					  current->mGrpId = memberGroupId;
-					  if ( *yytext == ',' )
+					  if ( *yytext == ',')
 					  {
+					    current = new Entry(*current);
+					    current->name.resize(0);
 					    int i=oldType.length(); 
 					    while (i>0 && (oldType[i-1]=='*' || oldType[i-1]=='&' || oldType[i-1]==' ')) i--;
 					    current->type = oldType.left(i);
-					    current->doc  = oldDocs;
+					  }
+					  else
+					  {
+					    current = new Entry ;
+					    initEntry();
 					  }
 					  BEGIN( FindMembers ) ;
 					}
@@ -1398,11 +1422,7 @@ TITLE     [tT][iI][tT][lL][eE]
 					    // add to the scope surrounding the enum (copy!)
 					    current_root->parent->addSubEntry(current);
 					    current             = new Entry ;
-					    current->protection = protection ;
-                                            current->mtype      = mtype;
-					    current->virt       = virt;
-					    current->stat       = gstat;
-					    current->mGrpId     = memberGroupId;
+					    initEntry();
 					  }
 					  else // probably a redundant , 
 					  {
@@ -1471,11 +1491,7 @@ TITLE     [tT][iI][tT][lL][eE]
 						 )
 					      { // namespaces and interfaces ends with a closing bracket without semicolon
 						current->reset();
-						current->protection = protection ;
-                                                current->mtype = mtype;
-						current->virt = virt;
-						current->stat = gstat;
-						current->mGrpId = memberGroupId;
+						initEntry();
 						BEGIN( FindMembers ) ;
 					      }
 					      else
@@ -1498,11 +1514,7 @@ TITLE     [tT][iI][tT][lL][eE]
 					  //printf("Adding compound %s %s %s\n",current->type.data(),current->name.data(),current->args.data());
 					  current_root->addSubEntry( current ) ;
 					  current = new Entry;
-					  current->protection = protection ;
-                                          current->mtype = mtype;
-					  current->virt = virt;
-					  current->stat = gstat;
-					  current->mGrpId = memberGroupId;
+					  initEntry();
   					  BEGIN(MemberSpecSkip); 
   					}
 <MemberSpec>([*&]*{BN}*)*{ID}("["[a-z_A-Z0-9]*"]")* { // the [] part could be improved.
@@ -1587,11 +1599,7 @@ TITLE     [tT][iI][tT][lL][eE]
 					    msArgs.resize(0);
 					    isTypedef=FALSE;
 					    current->reset();
-					    current->protection = protection ;
-					    current->mtype = mtype;
-					    current->virt = virt;
-					    current->stat = gstat;
-					    current->mGrpId = memberGroupId;
+					    initEntry();
 					    BEGIN( FindMembers );
 					  }
   					}					
@@ -2021,11 +2029,7 @@ TITLE     [tT][iI][tT][lL][eE]
 					  previous = current;
 					  current_root->addSubEntry(current);
 					  current = new Entry ;
-					  current->protection = protection;
-					  current->mtype = mtype;
-					  current->virt = virt;
-					  current->stat = gstat;
-					  current->mGrpId = memberGroupId;
+					  initEntry();
 					  lastCurlyContext = FindMembers;
 					  if( *yytext == '{' )
 					  {
@@ -2652,7 +2656,7 @@ TITLE     [tT][iI][tT][lL][eE]
   					  if (current->todoId!=0)
 					  {
 					    RefItem *item = todoList.getRefItem(current->todoId);
-					    item->text += "<p>";
+					    item->text += " <p>";
 					    item->text += current->brief;
 					  }
 					  else
@@ -2682,7 +2686,7 @@ TITLE     [tT][iI][tT][lL][eE]
   					  if (current->testId!=0)
 					  {
 					    RefItem *item = testList.getRefItem(current->testId);
-					    item->text += "<p>";
+					    item->text += " <p>";
 					    item->text += current->brief;
 					  }
 					  else
@@ -3024,6 +3028,22 @@ TITLE     [tT][iI][tT][lL][eE]
 							  lineCount();
 							  BEGIN( GroupName );
   							}
+<ClassDoc,Doc,JavaDoc>{CMD}"{"				{
+  							  if (current->section == Entry::GROUPDOC_SEC)
+							  {
+							    autoGroupName=current->name;
+							  }
+							  else if (current->section == Entry::MEMBERGRP_SEC)
+							  {
+					                    memberGroupId = newMemberGroupId();
+					                    current->mGrpId = memberGroupId;
+					                    lastMemberGroupLine = yyLineNr;
+							  }
+							  else
+							  {
+							    warn(yyFileName,yyLineNr,"Warning: @{ may only be used in a group block!\n");
+							  }
+  							}
 <ExampleDoc,PageDoc,ClassDoc>.    	 	        { current->doc += yytext; }
 <Doc,JavaDoc,LineDoc,ExampleDoc,PageDoc,ClassDoc>^{B}*"//" 
 <Doc,ExampleDoc,PageDoc,ClassDoc>"//"  			{ current->doc += yytext; }
@@ -3122,11 +3142,7 @@ TITLE     [tT][iI][tT][lL][eE]
 					    //printf("Add docs for class %s\n",current->name.data());
 					    current_root->addSubEntry(current);
 					    current = new Entry ;
-					    current->protection = protection ;
-					    current->mtype = mtype;
-					    current->virt = virt;
-					    current->stat = gstat;
-					    current->mGrpId = memberGroupId;
+					    initEntry();
 					    BEGIN( FindMembers );
 					  }
 					}
@@ -3175,7 +3191,7 @@ TITLE     [tT][iI][tT][lL][eE]
 <DocBaseClass>\n			{ yyLineNr++; BEGIN( ClassDoc ); }
 <ClassDocBrief>{BS}({BL}|"\\n\\n")	{ 
   					  current->brief=current->brief.stripWhiteSpace();
-					  if (!current->doc.isEmpty()) current->doc+="<p>";
+					  if (!current->doc.isEmpty()) current->doc+=" <p>";
 					  if (lastBriefContext==TodoParam || lastBriefContext==TestParam)
 					  {
 					    unput('\n');
@@ -3389,23 +3405,19 @@ TITLE     [tT][iI][tT][lL][eE]
 					  BEGIN(lastAfterDocContext);
   					}
 <ClassDocRelates,ClassDocFunc,ClassDocDefine,GroupDocArg1,ClassDocArg1,SectionTitle,EnumDocArg1,PageDocArg1,ExampleDocArg1,ClassDefineArgs,GroupName>"*/" {
-					  current->doc += "\n\n";
-					  warn(yyFileName,yyLineNr,
-                                              "Warning: unexpected end of "
-				              "documentation block."
-					      );
-					  BEGIN( lastDocContext );
+                                          // defer "*/" to a later time
+  					  unput('/');
+  					  unput('*');
+					  // insert \n and decrement the line number to compensate for the artifical newline
+					  unput('\n');
+					  yyLineNr--;
 					}
 <FileDocArg1>"*/"			{
   					  current->name = yyFileName;
   					  current->doc += "\n\n";
 					  current_root->addSubEntry(current);
 					  current = new Entry ;
-					  current->protection = protection ;
-					  current->mtype = mtype;
-					  current->virt = virt;
-					  current->stat = gstat;
-					  current->mGrpId = memberGroupId;
+					  initEntry();
 					  BEGIN( FindMembers );
   					}
 <Doc>"*/"				{ 
diff --git a/src/sortdict.h b/src/sortdict.h
index 471a447..9c46e9b 100644
--- a/src/sortdict.h
+++ b/src/sortdict.h
@@ -23,6 +23,25 @@
 #include <qlist.h>
 #include <qdict.h>
 
+template<class T> class SDict;
+
+/*! internal wrapper class that redirects compareItems() to the 
+ *  dictionary 
+ */
+template<class T>
+class SList : public QList<T>
+{
+  public:
+    SList(SDict<T> *owner) : m_owner(owner) {}
+    ~SList() {}
+    int compareItems(GCI item1,GCI item2)
+    {
+      return m_owner->compareItems(item1,item2);
+    }
+  private:
+    SDict<T> *m_owner;  
+};
+
 /*! Ordered dictionary of elements of type T. 
  *  Internally uses a QList<T> and a QDict<T>.
  */
@@ -30,23 +49,7 @@ template<class T>
 class SDict 
 {
   private:
-
-    /*! internal wrapper class that redirects compareItems() to the 
-     *  dictionary 
-     */
-    class SList : public QList<T>
-    {
-      public:
-        SList(SDict<T> *owner) : m_owner(owner) {}
-       ~SList() {}
-        int compareItems(GCI item1,GCI item2)
-        {
-          return m_owner->compareItems(item1,item2);
-        }
-      private:
-        SDict<T> *m_owner;  
-    };
-    SList *m_list;
+    SList<T> *m_list;
     QDict<T> *m_dict;
     
   public:
@@ -56,7 +59,7 @@ class SDict
      */
     SDict(int size) 
     {
-      m_list = new SList(this);
+      m_list = new SList<T>(this);
       m_dict = new QDict<T>(size);
     }
     /*! Destroys the dictionary */
@@ -169,5 +172,4 @@ class SDict
 
 };
 
-
 #endif
diff --git a/src/tag.h b/src/tag.h
deleted file mode 100644
index 33b066d..0000000
--- a/src/tag.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/******************************************************************************
- *
- * 
- *
- * Copyright (C) 1997-2000 by Dimitri van Heesch.
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation under the terms of the GNU General Public License is hereby 
- * granted. No representations are made about the suitability of this software 
- * for any purpose. It is provided "as is" without express or implied warranty.
- * See the GNU General Public License for more details.
- *
- * Documents produced by Doxygen are derivative works derived from the
- * input used in their production; they are not affected by this license.
- *
- */
-
-#ifndef TAG_H
-#define TAG_H
-
-extern void parseTagFile(const char *fileName);
-
-#endif
diff --git a/src/tag.l b/src/tag.l
deleted file mode 100644
index 2030b41..0000000
--- a/src/tag.l
+++ /dev/null
@@ -1,291 +0,0 @@
-/******************************************************************************
- *
- * 
- *
- * Copyright (C) 1997-2000 by Dimitri van Heesch.
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation under the terms of the GNU General Public License is hereby 
- * granted. No representations are made about the suitability of this software 
- * for any purpose. It is provided "as is" without express or implied warranty.
- * See the GNU General Public License for more details.
- *
- * Documents produced by Doxygen are derivative works derived from the
- * input used in their production; they are not affected by this license.
- *
- */
-
-%{
-
-/*
- *	includes
- */
-#include <stdio.h>
-  
-#include "qtbc.h"
-#include <qfileinfo.h>
-  
-#include "classdef.h"
-#include "filedef.h"
-#include "namespacedef.h"
-#include "memberdef.h"
-#include "doxygen.h"
-#include "util.h"
-#include "message.h"
-#include "defargs.h"
-  
-#define YY_NO_UNPUT
-#define YY_NEVER_INTERACTIVE 1
-
-static int yyLineNr;
-static QCString className;
-static QCString fileName;
-static QCString namespaceName;
-static QCString tagName;
-static QCString memberName;
-static QCString anchorName;
-static QCString argString;
-static ClassDef *cd;
-static FileDef *fd;
-static NamespaceDef *nd;
-
-static void addClass(const char *name,const char *fileName)
-{
-  //printf("adding class %s\n",name);
-  if (name!=0 && strlen(name)>0 && classDict[name]==0)
-  {
-    cd = new ClassDef(fileName,1,name,ClassDef::Class,tagName,fileName);
-    fd = 0;
-    nd = 0;
-    classList.inSort(cd);
-    classDict.insert(className,cd);
-  }
-}
-
-static void addFile(const char *name)
-{
-  //printf("adding file %s tagName=`%s'\n",name,tagName.data());
-  fd = new FileDef(0,name,tagName);
-  FileName *mn;
-  if ((mn=inputNameDict->find(name)))
-  {
-    mn->append(fd); 
-  }
-  else
-  {
-    mn = new FileName(name,name);
-    mn->append(fd);
-    inputNameList.inSort(mn);
-    inputNameDict->insert(name,mn);
-  }
-  cd = 0;
-  nd = 0;
-  //fileList.inSort(fd);
-  //fileDict.insert(fileName,fd);
-}
-
-static void addNamespace(const char *name)
-{
-  if ((nd=namespaceDict[name])==0)
-  {
-    // TODO: we assume that each namespace is limited to a single tagfile.
-    // since namespace are open, this need not to be the case. As a result
-    // namespace may contain members that are located in 
-    // different namespaces!
-    nd = new NamespaceDef("<tagfile>",1,name,tagName);
-    namespaceList.inSort(nd);
-    namespaceDict.insert(name,nd);
-  }
-  cd = 0;
-  fd = 0;
-}
-
-static void addMember(const char *name,const char *anchor,const char *args)
-{
-  //printf("adding member `%s' `%s'\n",name,anchor);
-  if (cd || fd)
-  {
-    MemberNameDict *mnd=0;
-    MemberNameList *mnl=0;
-    MemberDef *md;
-    ArgumentList *argList = new ArgumentList;
-    stringToArgumentList(args,argList);
-    md=new MemberDef("<tagfile>",1,
-                       0,name,args,0,Public,Normal,FALSE,FALSE,
-                       MemberDef::Function,0,argList); 
-    delete argList;
-    md->setAnchor(anchor);
-    md->setReference(tagName);
-    if (cd) // member of a class
-    {
-      md->setMemberClass(cd);
-      cd->insertMember(md); 
-      mnd=&memberNameDict;
-      mnl=&memberNameList;
-    }
-    else if (nd) // member of a namespace
-    {
-      md->setNamespace(nd);
-      nd->insertMember(md); 
-      mnd=&functionNameDict;
-      mnl=&functionNameList;
-    }
-    else // member of a file
-    {
-      md->setFileDef(fd);
-      fd->insertMember(md);
-      mnd=&functionNameDict;
-      mnl=&functionNameList;
-    }
-    MemberName *mn = 0;
-    if ((mn=(*mnd)[memberName]))
-    {
-      //printf("mn->inSort()\n");
-      mn->append(md);
-    }
-    else
-    {
-      //printf("mn->append()\n");
-      mn=new MemberName(memberName);
-      mn->append(md);
-      //printf("Adding memberName=%s\n",mn->memberName());
-      mnl->inSort(mn);
-      mnd->insert(memberName,mn);
-    }
-  }
-}
-
-/* -----------------------------------------------------------------
- */
-
-%}
-
-ID [a-z_A-Z0-9]+
-FILE [a-z_A-Z0-9\.\-\+\:\\\/]+
-SCOPE ({ID}"::")*{ID}
-
-%option noyywrap
-
-%x Pass1
-%x Pass2
-%x AnchorName
-%x ArgString1
-%x ArgString2
-%x ClassName1
-%x ClassName2
-%x FileName
-%x NamespaceName
-%x BaseClasses
-%x ClassFile1
-%x ClassFile2
-
-%%
-
-<Pass1>^">"				{ // start of a class
-  					  BEGIN(ClassName1);
-  					}
-<Pass1>^"&"				{ // start of a file
-  					  BEGIN(FileName);
-  					}
-<Pass1>^"%"				{ // start of a namespace
-  					  BEGIN(NamespaceName);
-  					}
-<Pass1>^[~a-z_A-Z][^ \n]*/" "		{
-  					  memberName=yytext;
-					  BEGIN(AnchorName);
-  					}
-<Pass2>^">"				{
-  					  BEGIN(ClassName2);
-  					}
-<AnchorName>{ID}			{
-  					  anchorName=yytext;
-					  BEGIN(ArgString1);
-  					}
-<ArgString1>"\""			{
-  					  BEGIN(ArgString2);
-  					}
-<ArgString2>[^\"\n]*/"\""		{
-  					  argString=yytext;
-					  addMember(memberName,anchorName,argString);
-					  BEGIN(Pass1);
-  					}
-<FileName>{FILE}/":"			{
-  					  fileName=yytext;
-					  addFile(yytext);
-					  BEGIN(Pass1);
-  					}
-<NamespaceName>{SCOPE}/":"		{
-  					  namespaceName=yytext;
-					  addNamespace(yytext);
-					  BEGIN(Pass1);
-  					}
-<ClassName1>{SCOPE}/":"			{
-  					  className=yytext;		  
-					  BEGIN(ClassFile1);
-  					}
-<ClassFile1>\"				{
-  					  BEGIN(ClassFile2);
-  					}
-<ClassFile2>[^\"]*/\"			{
-  					  addClass(className,yytext); 
-					  BEGIN(Pass1);
-  					}
-<ClassFile2>\n				{
-  					  yyLineNr++;
-					  BEGIN(Pass1);
-  					}
-<ClassName2>{ID}/":"			{
-  					  cd=getClass(yytext);
-					  BEGIN(BaseClasses);
-  					}
-<BaseClasses>{ID}/"?"			{
-  					  ClassDef *bcd=getClass(yytext);
-					  if (cd && bcd)
-					  {
-					    cd->insertBaseClass(bcd,Public,Normal);
-					    bcd->insertSuperClass(cd,Public,Normal);
-					  }
-  					}
-<BaseClasses>\n				{
-  					  yyLineNr++;
-  					  BEGIN(Pass2);
-  					}
-<*>.					
-<*>\n					{ yyLineNr++ ; }
-
-%%
-
-/*@ ----------------------------------------------------------------------------
- */
-
-void parseTagFile(const char *fileName)
-{
-  FILE *f=fopen(fileName,"r");
-  QFileInfo fi(fileName);
-  if (!f || !fi.exists()) 
-  {
-    if (f) fclose(f);
-    return;
-  }
-  tagName = fi.fileName();
-  tagYYin = f;
-
-  cd=0;
-  yyLineNr      = 1;
-  tagYYrestart( tagYYin );
-  BEGIN(Pass1);
-  tagYYlex();
-
-  rewind(f);
-  cd=0;
-  yyLineNr      = 1;
-  tagYYrestart( tagYYin );
-  BEGIN(Pass2);
-  tagYYlex();
-
-  fclose(f);
-}
-
-//extern "C" { // some bogus code to keep the compiler happy
-//  int  tagYYwrap() { return 1 ; }
-//}
diff --git a/src/tagreader.cpp b/src/tagreader.cpp
new file mode 100644
index 0000000..d01e4bd
--- /dev/null
+++ b/src/tagreader.cpp
@@ -0,0 +1,902 @@
+#include "tagreader.h"
+
+#include <stdio.h>
+#include <qxml.h>
+#include <qstack.h>
+#include <qdict.h>
+#include <qfileinfo.h>
+#include <qlist.h>
+#include <qstring.h>
+#include <qstringlist.h>
+
+#include "entry.h"
+#include "classdef.h"
+#include "doxygen.h"
+#include "util.h"
+#include "message.h"
+
+/*! Container for member specific info that can be read from a tagfile */
+class TagMemberInfo
+{
+  public:
+    TagMemberInfo() : prot(Public), virt(Normal), isStatic(FALSE) {}
+    QString name;
+    QString anchor;
+    QString arglist;
+    QString kind;
+    Protection prot;
+    Specifier virt;
+    bool isStatic; 
+};
+
+/*! Container for class specific info that can be read from a tagfile */
+class TagClassInfo
+{
+  public:
+    enum Kind { Class, Struct, Union, Interface, Exception };
+    TagClassInfo() { bases=0, members.setAutoDelete(TRUE); }
+   ~TagClassInfo() { delete bases; }
+    QString name;
+    QString filename;
+    QList<BaseInfo> *bases;
+    QList<TagMemberInfo> members;
+    Kind kind;
+};
+
+/*! Container for namespace specific info that can be read from a tagfile */
+class TagNamespaceInfo
+{
+  public:
+    TagNamespaceInfo() { members.setAutoDelete(TRUE); }
+    QString name;
+    QString filename;
+    QList<TagMemberInfo> members;
+    QStringList classList;
+};
+
+/*! Container for file specific info that can be read from a tagfile */
+class TagFileInfo
+{
+  public:
+    TagFileInfo() { members.setAutoDelete(TRUE); }
+    QString name;
+    QString path;
+    QString filename;
+    QList<TagMemberInfo> members;
+    QStringList classList;
+    QStringList namespaceList;
+};
+
+/*! Container for group specific info that can be read from a tagfile */
+class TagGroupInfo
+{
+  public:
+    TagGroupInfo() { members.setAutoDelete(TRUE); }
+    QString name;
+    QString title;
+    QString filename;
+    QList<TagMemberInfo> members;
+    QStringList subgroupList;
+    QStringList classList;
+    QStringList namespaceList;
+    QStringList fileList;
+    QStringList pageList;
+};
+
+/*! Container for page specific info that can be read from a tagfile */
+class TagPageInfo
+{
+  public:
+    QString name;
+    QString title;
+    QString filename;
+};
+
+
+/*! Tag file parser. 
+ *  Reads an XML-structured tagfile and builds up the structure in
+ *  memory. The method buildLists() is used to transfer/translate 
+ *  the structures to the doxygen engine.
+ */
+class TagFileParser : public QXmlDefaultHandler
+{
+    enum State { Invalid,
+                 InClass,
+                 InFile,
+                 InNamespace,
+                 InGroup,
+                 InPage,
+                 InMember
+               };
+    class StartElementHandler
+    {
+        typedef void (TagFileParser::*Handler)(const QXmlAttributes &attrib); 
+      public:
+        StartElementHandler(TagFileParser *parent, Handler h) : m_parent(parent), m_handler(h) {}
+        void operator()(const QXmlAttributes &attrib) { (m_parent->*m_handler)(attrib); }
+      private:
+        TagFileParser *m_parent;
+        Handler m_handler;
+    };
+    class EndElementHandler
+    {
+        typedef void (TagFileParser::*Handler)(); 
+      public:
+        EndElementHandler(TagFileParser *parent, Handler h) : m_parent(parent), m_handler(h) {}
+        void operator()() { (m_parent->*m_handler)(); }
+      private:
+        TagFileParser *m_parent;
+        Handler m_handler;
+    };
+
+  public:
+    TagFileParser(const char *tagName) : m_tagName(tagName) {}
+
+    void startCompound( const QXmlAttributes& attrib )
+    {
+      m_curString = "";
+      QString kind = attrib.value("kind");
+      if (kind=="class")
+      {
+        m_curClass = new TagClassInfo;
+        m_curClass->kind = TagClassInfo::Class;
+        m_state = InClass;
+      }
+      else if (kind=="struct")
+      {
+        m_curClass = new TagClassInfo;
+        m_curClass->kind = TagClassInfo::Struct;
+        m_state = InClass;
+      }
+      else if (kind=="union")
+      {
+        m_curClass = new TagClassInfo;
+        m_curClass->kind = TagClassInfo::Union;
+        m_state = InClass;
+      }
+      else if (kind=="interface")
+      {
+        m_curClass = new TagClassInfo;
+        m_curClass->kind = TagClassInfo::Interface;
+        m_state = InClass;
+      }
+      else if (kind=="exception")
+      {
+        m_curClass = new TagClassInfo;
+        m_curClass->kind = TagClassInfo::Exception;
+        m_state = InClass;
+      }
+      else if (kind=="file")
+      {
+        m_curFile = new TagFileInfo;
+        m_state = InFile;
+      }
+      else if (kind=="namespace")
+      {
+        m_curNamespace = new TagNamespaceInfo;
+        m_state = InNamespace;
+      }
+      else if (kind=="group")
+      {
+        m_curGroup = new TagGroupInfo;
+        m_state = InGroup;
+      }
+      else if (kind=="page")
+      {
+        m_curPage = new TagPageInfo;
+        m_state = InPage;
+      }
+      else
+      {
+        err("Error: Unknown compound attribute `%s' found!\n",kind.data());
+      }
+    }
+    void endCompound()
+    {
+      switch (m_state)
+      {
+        case InClass:     m_tagFileClasses.append(m_curClass); 
+                          m_curClass=0; break; 
+        case InFile:      m_tagFileFiles.append(m_curFile); 
+                          m_curFile=0; break; 
+        case InNamespace: m_tagFileNamespaces.append(m_curNamespace); 
+                          m_curNamespace=0; break; 
+        case InGroup:     m_tagFileGroups.append(m_curGroup); 
+                          m_curGroup=0; break; 
+        case InPage:      m_tagFilePages.append(m_curPage); 
+                          m_curPage=0; break; 
+        default:
+                          err("Error: tag `compound' was not expected!\n");
+      }
+    }
+    void startMember( const QXmlAttributes& attrib)
+    {
+      m_curMember = new TagMemberInfo;
+      m_curMember->kind = attrib.value("kind");
+      QString protStr = attrib.value("protection");
+      QString virtStr = attrib.value("virtualness");
+      QString staticStr = attrib.value("static");
+      if (protStr=="protected")
+      {
+        m_curMember->prot = Protected;
+      }
+      else if (protStr=="private")
+      {
+        m_curMember->prot = Private;
+      }
+      if (virtStr=="virtual")
+      {
+        m_curMember->virt = Virtual;
+      }
+      else if (virtStr=="pure")
+      {
+        m_curMember->virt = Pure;
+      }
+      if (staticStr=="yes")
+      {
+        m_curMember->isStatic = TRUE;
+      }
+      m_stateStack.push(new State(m_state));
+      m_state = InMember;
+    }
+    void endMember()
+    {
+      m_state = *m_stateStack.pop();
+      switch(m_state)
+      {
+        case InClass:     m_curClass->members.append(m_curMember); break;
+        case InFile:      m_curFile->members.append(m_curMember); break;
+        case InNamespace: m_curNamespace->members.append(m_curMember); break;
+        case InGroup:     m_curGroup->members.append(m_curMember); break;
+        default:   err("Error: Unexpected tag `member' found\n"); break; 
+      }
+    }
+    void endClass()
+    {
+      switch(m_state)
+      {
+        case InFile:      m_curFile->classList.append(m_curString); break;
+        case InNamespace: m_curNamespace->classList.append(m_curString); break;
+        case InGroup:     m_curGroup->classList.append(m_curString); break;
+        default:   err("Error: Unexpected tag `class' found\n"); break; 
+      }
+    }
+    void endNamespace()
+    {
+      switch(m_state)
+      {
+        case InFile:      m_curFile->namespaceList.append(m_curString); break;
+        case InGroup:     m_curGroup->namespaceList.append(m_curString); break;
+        default:   err("Error: Unexpected tag `namespace' found\n"); break; 
+      }
+    }
+    void endFile()
+    {
+      switch(m_state)
+      {
+        case InGroup:      m_curGroup->fileList.append(m_curString); break;
+        default:   err("Error: Unexpected tag `file' found\n"); break; 
+      }
+    }
+    void endPage()
+    {
+      switch(m_state)
+      {
+        case InGroup:      m_curGroup->fileList.append(m_curString); break;
+        default:   err("Error: Unexpected tag `page' found\n"); break; 
+      }
+    }
+    void startStringValue(const QXmlAttributes& )
+    {
+      m_curString = "";
+    }
+    void endName()
+    {
+      switch (m_state)
+      {
+        case InClass:     m_curClass->name     = m_curString; break;
+        case InFile:      m_curFile->name      = m_curString; break;
+        case InNamespace: m_curNamespace->name = m_curString; break;
+        case InGroup:     m_curGroup->name     = m_curString; break;
+        case InPage:      m_curPage->name      = m_curString; break;
+        case InMember:    m_curMember->name    = m_curString; break;
+        default: err("Error: Unexpected tag `name' found\n"); break; 
+      }
+    }
+    void startBase(const QXmlAttributes& attrib )
+    {
+      m_curString="";
+      if (m_state==InClass && m_curClass)
+      {
+        QString protStr = attrib.value("protection");
+        QString virtStr = attrib.value("virtualness");
+        Protection prot = Public;
+        Specifier  virt = Normal;
+        if (protStr=="protected")
+        {
+          prot = Protected;
+        }
+        else if (protStr=="private")
+        {
+          prot = Private;
+        }
+        if (virtStr=="virtual")
+        {
+          virt = Virtual;
+        }
+        if (m_curClass->bases==0) m_curClass->bases = new QList<BaseInfo>;
+        m_curClass->bases->append(new BaseInfo(m_curString,prot,virt));
+      }
+      else
+      {
+        err("Error: Unexpected tag `base' found\n");
+      }
+    }
+    void endBase()
+    {
+      if (m_state==InClass && m_curClass)
+      {
+        m_curClass->bases->getLast()->name = m_curString;
+      }
+      else
+      {
+        err("Error: Unexpected tag `base' found\n");
+      }
+    }
+    void endFilename()
+    {
+      switch (m_state)
+      {
+        case InClass:     m_curClass->filename     = m_curString;    break;
+        case InNamespace: m_curNamespace->filename = m_curString;    break;
+        case InFile:      m_curFile->filename      = m_curString;    break;
+        case InGroup:     m_curGroup->filename     = m_curString;    break;
+        case InPage:      m_curPage->filename      = m_curString;    break;
+        default: err("Error: Unexpected tag `filename' found\n"); break; 
+      }
+    }
+    void endPath()
+    {
+      switch (m_state)
+      {
+        case InFile:      m_curFile->path          = m_curString;    break;
+        default: err("Error: Unexpected tag `path' found\n");     break; 
+      }
+    }
+    void endAnchor()
+    {
+      if (m_state==InMember)
+      {
+        m_curMember->anchor = m_curString; 
+      }
+      else
+      {
+        err("Error: Unexpected tag `anchor' found\n");
+      }
+    }
+    void endArglist()
+    {
+      if (m_state==InMember)
+      {
+        m_curMember->arglist = m_curString; 
+      }
+      else
+      {
+        err("Error: Unexpected tag `arglist' found\n");
+      }
+    }
+    void endTitle()
+    {
+      switch (m_state)
+      {
+        case InGroup:     m_curGroup->title     = m_curString;    break;
+        case InPage:      m_curPage->title      = m_curString;    break;
+        default: err("Error: Unexpected tag `title' found\n"); break; 
+      }
+    }
+    void endSubgroup()
+    {
+      if (m_state==InGroup)
+      {
+        m_curGroup->subgroupList.append(m_curString);
+      }
+      else
+      {
+        err("Error: Unexpected tag `subgroup' found\n");
+      }
+    }
+    void startIgnoreElement(const QXmlAttributes& )
+    {
+    }
+    void endIgnoreElement()
+    {
+    }
+
+    bool startDocument()
+    {
+      m_curClass=0;
+      m_curNamespace=0;
+      m_curFile=0;
+      m_curGroup=0;
+      m_curPage=0;
+      m_state = Invalid;
+      m_stateStack.setAutoDelete(TRUE);
+      m_tagFileClasses.setAutoDelete(TRUE);
+      m_tagFileFiles.setAutoDelete(TRUE);
+      m_tagFileNamespaces.setAutoDelete(TRUE);
+      m_tagFileGroups.setAutoDelete(TRUE);
+      m_tagFilePages.setAutoDelete(TRUE);
+      m_startElementHandlers.insert("compound",  new StartElementHandler(this,&TagFileParser::startCompound));
+      m_startElementHandlers.insert("member",    new StartElementHandler(this,&TagFileParser::startMember));
+      m_startElementHandlers.insert("name",      new StartElementHandler(this,&TagFileParser::startStringValue));
+      m_startElementHandlers.insert("base",      new StartElementHandler(this,&TagFileParser::startBase));
+      m_startElementHandlers.insert("filename",  new StartElementHandler(this,&TagFileParser::startStringValue));
+      m_startElementHandlers.insert("path",      new StartElementHandler(this,&TagFileParser::startStringValue));
+      m_startElementHandlers.insert("anchor",    new StartElementHandler(this,&TagFileParser::startStringValue));
+      m_startElementHandlers.insert("arglist",   new StartElementHandler(this,&TagFileParser::startStringValue));
+      m_startElementHandlers.insert("title",     new StartElementHandler(this,&TagFileParser::startStringValue));
+      m_startElementHandlers.insert("subgroup",  new StartElementHandler(this,&TagFileParser::startStringValue));
+      m_startElementHandlers.insert("class",     new StartElementHandler(this,&TagFileParser::startStringValue));
+      m_startElementHandlers.insert("namespace", new StartElementHandler(this,&TagFileParser::startStringValue));
+      m_startElementHandlers.insert("file",      new StartElementHandler(this,&TagFileParser::startStringValue));
+      m_startElementHandlers.insert("page",      new StartElementHandler(this,&TagFileParser::startStringValue));
+      m_startElementHandlers.insert("tagfile",   new StartElementHandler(this,&TagFileParser::startIgnoreElement));
+      m_endElementHandlers.insert("compound",    new EndElementHandler(this,&TagFileParser::endCompound));
+      m_endElementHandlers.insert("member",      new EndElementHandler(this,&TagFileParser::endMember));
+      m_endElementHandlers.insert("name",        new EndElementHandler(this,&TagFileParser::endName));
+      m_endElementHandlers.insert("base",        new EndElementHandler(this,&TagFileParser::endBase));
+      m_endElementHandlers.insert("filename",    new EndElementHandler(this,&TagFileParser::endFilename));
+      m_endElementHandlers.insert("path",        new EndElementHandler(this,&TagFileParser::endPath));
+      m_endElementHandlers.insert("anchor",      new EndElementHandler(this,&TagFileParser::endAnchor));
+      m_endElementHandlers.insert("arglist",     new EndElementHandler(this,&TagFileParser::endArglist));
+      m_endElementHandlers.insert("title",       new EndElementHandler(this,&TagFileParser::endTitle));
+      m_endElementHandlers.insert("subgroup",    new EndElementHandler(this,&TagFileParser::endSubgroup));
+      m_endElementHandlers.insert("class"   ,    new EndElementHandler(this,&TagFileParser::endClass));
+      m_endElementHandlers.insert("namespace",   new EndElementHandler(this,&TagFileParser::endNamespace));
+      m_endElementHandlers.insert("file",        new EndElementHandler(this,&TagFileParser::endFile));
+      m_endElementHandlers.insert("page",        new EndElementHandler(this,&TagFileParser::endPage));
+      m_endElementHandlers.insert("tagfile",     new EndElementHandler(this,&TagFileParser::endIgnoreElement));
+      return TRUE;
+    }
+    bool startElement( const QString&, const QString&, 
+                       const QString&name, const QXmlAttributes& attrib )
+    {
+      //printf("startElement `%s'\n",name.data());
+      StartElementHandler *handler = m_startElementHandlers[name];
+      if (handler)
+      {
+        (*handler)(attrib);
+      }
+      else 
+      {
+        err("Error: Unknown tag `%s' found!\n",name.data());
+      }
+      return TRUE;
+    }
+    bool endElement( const QString&, const QString&, const QString& name )
+    {
+      //printf("endElement `%s'\n",name.data());
+      EndElementHandler *handler = m_endElementHandlers[name];
+      if (handler)
+      {
+        (*handler)();
+      }
+      else 
+      {
+        err("Error: Unknown tag `%s' found!\n",name.data());
+      }
+      return TRUE;
+    }
+    bool characters ( const QString & ch ) 
+    {
+      m_curString+=ch;
+      return TRUE;
+    }
+    void dump();
+    void buildLists(Entry *root);
+    
+  private:
+    void buildMemberList(Entry *ce,QList<TagMemberInfo> &members);
+    QList<TagClassInfo>        m_tagFileClasses;
+    QList<TagFileInfo>         m_tagFileFiles;
+    QList<TagNamespaceInfo>    m_tagFileNamespaces;
+    QList<TagGroupInfo>        m_tagFileGroups;
+    QList<TagPageInfo>         m_tagFilePages;
+    QDict<StartElementHandler> m_startElementHandlers;
+    QDict<EndElementHandler>   m_endElementHandlers;
+    TagClassInfo              *m_curClass;
+    TagFileInfo               *m_curFile;
+    TagNamespaceInfo          *m_curNamespace;
+    TagGroupInfo              *m_curGroup;
+    TagPageInfo               *m_curPage;
+    TagMemberInfo             *m_curMember;
+    QCString                   m_curString;
+    QString                    m_tagName;
+    State                      m_state;
+    QStack<State>              m_stateStack;
+};
+
+/*! Error handler for the XML tag file parser. 
+ *  Basically dumps all fatal error to stderr using err().
+ */
+class TagFileErrorHandler : public QXmlErrorHandler
+{
+  public:
+    virtual ~TagFileErrorHandler() {}
+    bool warning( const QXmlParseException & )
+    {
+      return FALSE;
+    }
+    bool error( const QXmlParseException & )
+    {
+      return FALSE;
+    }
+    bool fatalError( const QXmlParseException &exception )
+    {
+      err("Fatal error at line %d column %d: %s\n",
+          exception.lineNumber(),exception.columnNumber(),
+          exception.message().data());
+      return FALSE;
+    }
+    QString errorString() { return ""; }
+
+  private:
+    QString errorMsg;
+};
+
+/*! Dumps the internal structures. For debugging only! */
+void TagFileParser::dump()
+{
+  printf("Result:\n");
+  QListIterator<TagClassInfo> lci(m_tagFileClasses);
+
+  //============== CLASSES
+  TagClassInfo *cd;
+  for (;(cd=lci.current());++lci)
+  {
+    printf("class `%s'\n",cd->name.data());
+    printf("  filename `%s'\n",cd->filename.data());
+    if (cd->bases)
+    {
+      QListIterator<BaseInfo> bii(*cd->bases);
+      BaseInfo *bi;
+      for ( bii.toFirst() ; (bi=bii.current()) ; ++bii) 
+      {
+        printf( "  base: %s \n", bi->name.data() );
+      }
+    }
+
+    QListIterator<TagMemberInfo> mci(cd->members);
+    TagMemberInfo *md;
+    for (;(md=mci.current());++mci)
+    {
+      printf("  member:\n");
+      printf("    kind: `%s'\n",md->kind.data());
+      printf("    name: `%s'\n",md->name.data());
+      printf("    anchor: `%s'\n",md->anchor.data());
+      printf("    arglist: `%s'\n",md->arglist.data());
+    }
+  }
+  //============== NAMESPACES
+  QListIterator<TagNamespaceInfo> lni(m_tagFileNamespaces);
+  TagNamespaceInfo *nd;
+  for (;(nd=lni.current());++lni)
+  {
+    printf("namespace `%s'\n",nd->name.data());
+    printf("  filename `%s'\n",nd->filename.data());
+    QStringList::Iterator it;
+    for ( it = nd->classList.begin(); 
+        it != nd->classList.end(); ++it ) 
+    {
+      printf( "  class: %s \n", (*it).latin1() );
+    }
+
+    QListIterator<TagMemberInfo> mci(nd->members);
+    TagMemberInfo *md;
+    for (;(md=mci.current());++mci)
+    {
+      printf("  member:\n");
+      printf("    kind: `%s'\n",md->kind.data());
+      printf("    name: `%s'\n",md->name.data());
+      printf("    anchor: `%s'\n",md->anchor.data());
+      printf("    arglist: `%s'\n",md->arglist.data());
+    }
+  }
+  //============== FILES
+  QListIterator<TagFileInfo> lfi(m_tagFileFiles);
+  TagFileInfo *fd;
+  for (;(fd=lfi.current());++lfi)
+  {
+    printf("file `%s'\n",fd->name.data());
+    printf("  filename `%s'\n",fd->filename.data());
+    QStringList::Iterator it;
+    for ( it = fd->namespaceList.begin(); 
+        it != fd->namespaceList.end(); ++it ) 
+    {
+      printf( "  namespace: %s \n", (*it).latin1() );
+    }
+    for ( it = fd->classList.begin(); 
+        it != fd->classList.end(); ++it ) 
+    {
+      printf( "  class: %s \n", (*it).latin1() );
+    }
+
+    QListIterator<TagMemberInfo> mci(fd->members);
+    TagMemberInfo *md;
+    for (;(md=mci.current());++mci)
+    {
+      printf("  member:\n");
+      printf("    kind: `%s'\n",md->kind.data());
+      printf("    name: `%s'\n",md->name.data());
+      printf("    anchor: `%s'\n",md->anchor.data());
+      printf("    arglist: `%s'\n",md->arglist.data());
+    }
+  }
+
+  //============== GROUPS
+  QListIterator<TagGroupInfo> lgi(m_tagFileGroups);
+  TagGroupInfo *gd;
+  for (;(gd=lgi.current());++lgi)
+  {
+    printf("group `%s'\n",gd->name.data());
+    printf("  filename `%s'\n",gd->filename.data());
+    QStringList::Iterator it;
+    for ( it = gd->namespaceList.begin(); 
+        it != gd->namespaceList.end(); ++it ) 
+    {
+      printf( "  namespace: %s \n", (*it).latin1() );
+    }
+    for ( it = gd->classList.begin(); 
+        it != gd->classList.end(); ++it ) 
+    {
+      printf( "  class: %s \n", (*it).latin1() );
+    }
+    for ( it = gd->fileList.begin(); 
+        it != gd->fileList.end(); ++it ) 
+    {
+      printf( "  file: %s \n", (*it).latin1() );
+    }
+    for ( it = gd->subgroupList.begin(); 
+        it != gd->subgroupList.end(); ++it ) 
+    {
+      printf( "  subgroup: %s \n", (*it).latin1() );
+    }
+    for ( it = gd->pageList.begin(); 
+        it != gd->pageList.end(); ++it ) 
+    {
+      printf( "  page: %s \n", (*it).latin1() );
+    }
+
+    QListIterator<TagMemberInfo> mci(gd->members);
+    TagMemberInfo *md;
+    for (;(md=mci.current());++mci)
+    {
+      printf("  member:\n");
+      printf("    kind: `%s'\n",md->kind.data());
+      printf("    name: `%s'\n",md->name.data());
+      printf("    anchor: `%s'\n",md->anchor.data());
+      printf("    arglist: `%s'\n",md->arglist.data());
+    }
+  }
+  //============== PAGES
+  QListIterator<TagPageInfo> lpi(m_tagFilePages);
+  TagPageInfo *pd;
+  for (;(pd=lpi.current());++lpi)
+  {
+    printf("page `%s'\n",pd->name.data());
+    printf("  title `%s'\n",pd->title.data());
+    printf("  filename `%s'\n",pd->filename.data());
+  }
+}
+
+void TagFileParser::buildMemberList(Entry *ce,QList<TagMemberInfo> &members)
+{
+  QListIterator<TagMemberInfo> mii(members);
+  TagMemberInfo *tmi;
+  for (;(tmi=mii.current());++mii)
+  {
+    Entry *me      = new Entry;
+    me->name       = tmi->name;
+    me->args       = tmi->arglist;
+    me->protection = tmi->prot;
+    me->virt       = tmi->virt;
+    me->stat       = tmi->isStatic;
+    TagInfo *ti    = new TagInfo;
+    ti->tagName    = m_tagName;
+    ti->anchor     = tmi->anchor;
+    me->tagInfo    = ti;
+    if (tmi->kind=="define")
+    {
+      me->type="#define";
+      me->section = Entry::DEFINE_SEC;
+    }
+    else if (tmi->kind=="enumvalue")
+    {
+      me->section = Entry::VARIABLE_SEC;
+      me->mtype = Method;
+    }
+    else if (tmi->kind=="property")
+    {
+      me->section = Entry::FUNCTION_SEC;
+      me->mtype = Property;
+    }
+    else if (tmi->kind=="variable")
+    {
+      me->section = Entry::VARIABLE_SEC;
+      me->mtype = Method;
+    }
+    else if (tmi->kind=="typedef")
+    {
+      me->section = Entry::TYPEDEF_SEC;
+      me->mtype = Method;
+    }
+    else if (tmi->kind=="enumeration")
+    {
+      me->section = Entry::ENUM_SEC;
+      me->mtype = Method;
+    }
+    else if (tmi->kind=="function")
+    {
+      me->section = Entry::FUNCTION_SEC;
+      me->mtype = Method;
+    }
+    else if (tmi->kind=="signal")
+    {
+      me->section = Entry::FUNCTION_SEC;
+      me->mtype = Signal;
+    }
+    else if (tmi->kind=="prototype")
+    {
+      me->section = Entry::FUNCTION_SEC;
+      me->mtype = Method;
+    }
+    else if (tmi->kind=="friend")
+    {
+      me->section = Entry::FUNCTION_SEC;
+      me->mtype = Method;
+    }
+    else if (tmi->kind=="dcop")
+    {
+      me->section = Entry::FUNCTION_SEC;
+      me->mtype = DCOP;
+    }
+    else if (tmi->kind=="slot")
+    {
+      me->section = Entry::FUNCTION_SEC;
+      me->mtype = Slot;
+    }
+    ce->addSubEntry(me);
+  }
+}
+
+void TagFileParser::buildLists(Entry *root)
+{
+  // build class list
+  TagClassInfo *tci = m_tagFileClasses.first();
+  while (tci)
+  {
+    Entry *ce = new Entry;
+    switch (tci->kind)
+    {
+      case TagClassInfo::Class:     ce->section = Entry::CLASS_SEC;     break;
+      case TagClassInfo::Struct:    ce->section = Entry::STRUCT_SEC;    break;
+      case TagClassInfo::Union:     ce->section = Entry::UNION_SEC;     break;
+      case TagClassInfo::Interface: ce->section = Entry::INTERFACE_SEC; break;
+      case TagClassInfo::Exception: ce->section = Entry::EXCEPTION_SEC; break;
+    }
+    ce->name     = tci->name;
+    TagInfo *ti  = new TagInfo;
+    ti->tagName  = m_tagName;
+    ti->fileName = tci->filename;
+    ce->tagInfo = ti;
+    // transfer base class list
+    if (tci->bases)
+    {
+      ce->extends = tci->bases; tci->bases = 0;
+    }
+
+    buildMemberList(ce,tci->members);
+    root->addSubEntry(ce);
+    tci = m_tagFileClasses.next();
+  }
+
+  // build file list
+  TagFileInfo *tfi = m_tagFileFiles.first();
+  while (tfi)
+  {
+    Entry *fe = new Entry;
+    fe->section = guessSection(tfi->name);
+    fe->name     = tfi->name;
+    TagInfo *ti  = new TagInfo;
+    ti->tagName  = m_tagName;
+    ti->fileName = tfi->filename;
+    fe->tagInfo  = ti;
+    
+    QString fullName = m_tagName+":"+tfi->path+tfi->name;
+    fe->fileName = fullName;
+    FileDef *fd = new FileDef(m_tagName+":"+tfi->path,tfi->name,m_tagName);
+    FileName *mn;
+    if ((mn=inputNameDict->find(tfi->name)))
+    {
+      mn->append(fd);
+    }
+    else
+    {
+      mn = new FileName(fullName,tfi->name);
+      mn->append(fd);
+      inputNameList.inSort(mn);
+      inputNameDict->insert(tfi->name,mn);
+    }
+    buildMemberList(fe,tfi->members);
+    root->addSubEntry(fe);
+    tfi = m_tagFileFiles.next();
+  }
+
+  // build namespace list
+  TagNamespaceInfo *tni = m_tagFileNamespaces.first();
+  while (tni)
+  {
+    Entry *ne    = new Entry;
+    ne->section  = Entry::NAMESPACE_SEC;
+    ne->name     = tni->name;
+    TagInfo *ti  = new TagInfo;
+    ti->tagName  = m_tagName;
+    ti->fileName = tni->filename;
+    ne->tagInfo  = ti;
+
+    buildMemberList(ne,tni->members);
+    root->addSubEntry(ne);
+    tni = m_tagFileNamespaces.next();
+  }
+
+  // build group list
+  TagGroupInfo *tgi = m_tagFileGroups.first();
+  while (tgi)
+  {
+    Entry *ge    = new Entry;
+    ge->section  = Entry::GROUPDOC_SEC;
+    ge->name     = tgi->name;
+    ge->type     = tgi->title;
+    TagInfo *ti  = new TagInfo;
+    ti->tagName  = m_tagName;
+    ti->fileName = tgi->filename;
+    ge->tagInfo  = ti;
+
+    buildMemberList(ge,tgi->members);
+    root->addSubEntry(ge);
+    tgi = m_tagFileGroups.next();
+  }
+
+  // build page list
+  TagPageInfo *tpi = m_tagFilePages.first();
+  while (tpi)
+  {
+    Entry *pe    = new Entry;
+    pe->section  = Entry::PAGEDOC_SEC;
+    pe->name     = tpi->name;
+    pe->args     = tpi->title;
+    TagInfo *ti  = new TagInfo;
+    ti->tagName  = m_tagName;
+    ti->fileName = tpi->filename;
+    pe->tagInfo  = ti;
+
+    root->addSubEntry(pe);
+    tpi = m_tagFilePages.next();
+  }
+}
+
+void parseTagFile(Entry *root,const char *fullName,const char *tagName)
+{
+  QFileInfo fi(fullName);
+  if (!fi.exists()) return;
+  TagFileParser handler( tagName );
+  TagFileErrorHandler errorHandler;
+  QFile xmlFile( fullName );
+  QXmlInputSource source( xmlFile );
+  QXmlSimpleReader reader;
+  reader.setContentHandler( &handler );
+  reader.setErrorHandler( &errorHandler );
+  reader.parse( source );
+  handler.buildLists(root);
+}
+
diff --git a/src/tagreader.h b/src/tagreader.h
new file mode 100644
index 0000000..1501274
--- /dev/null
+++ b/src/tagreader.h
@@ -0,0 +1,10 @@
+#ifndef TAGREADER_H
+#define TAGREADER_H
+
+#include "qtbc.h"
+
+class Entry;
+
+void parseTagFile(Entry *root,const char *fullPathName,const char *fileName);
+
+#endif
diff --git a/src/translator_de.h b/src/translator_de.h
index 44d2ec5..dd32ec8 100644
--- a/src/translator_de.h
+++ b/src/translator_de.h
@@ -383,7 +383,7 @@ class TranslatorGerman : public Translator
 
     QCString trNamespaceList()
       // used as the title of page containing all the index of all namespaces.
-    { return ""; }
+    { return "Lister aller Namensberiche"; }
     QCString trNamespaceListDescription(bool extractAll)
       // used as an introduction to the namespace list
     {
diff --git a/src/util.cpp b/src/util.cpp
index 8282ccd..dd04fde 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -17,6 +17,9 @@
 
 #include <stdlib.h>
 #include <ctype.h>
+#ifdef _WIN32
+#include <windows.h>
+#endif
 
 #include "qtbc.h"
 #include <qregexp.h>
@@ -110,8 +113,8 @@ void TextGeneratorXMLImpl::writeLink(const char *extRef,const char *file,
 //------------------------------------------------------------------------
 
     
-/*! Implements an interruptable system call on Unix */
-int iSystem(const char *command)
+/*! Implements an interruptable system call on Unix/Windows */
+int iSystem(const char *command,const char *args)
 {
 #ifndef _WIN32
   /*! taken from the system() manpage on my Linux box */
@@ -122,10 +125,14 @@ int iSystem(const char *command)
   if (pid==-1) return -1;
   if (pid==0)
   {
+    char buf[4096];
+    strcpy(buf,command);
+    strcat(buf," ");
+    strcat(buf,args);
     const char * argv[4];
     argv[0] = "sh";
     argv[1] = "-c";
-    argv[2] = command;
+    argv[2] = buf;
     argv[3] = 0;
     execve("/bin/sh",(char * const *)argv,environ);
     exit(127);
@@ -142,7 +149,33 @@ int iSystem(const char *command)
     }
   }
 #else
-  return system(command);
+  SHELLEXECUTEINFO sInfo = {
+    sizeof(SHELLEXECUTEINFO),   /* structure size */
+    SEE_MASK_NOCLOSEPROCESS,    /* leave the process running */
+    NULL,                       /* window handle */
+    NULL,                       /* action to perform: open */
+    command,                    /* file to execute */
+    args,                       /* argument list */ 
+    NULL,                       /* use current working dir */
+    SW_HIDE,                    /* minimize on start-up */
+    0,                          /* application instance handle */
+    NULL,                       /* ignored: id list */
+    NULL,                       /* ignored: class name */
+    NULL,                       /* ignored: key class */
+    0,                          /* ignored: hot key */
+    NULL,                       /* ignored: icon */
+    NULL                        /* resulting application handle */
+  };
+  if (!ShellExecuteEx(&sInfo))
+  {
+    return -1;
+  }
+  else if (sInfo.hProcess)      /* executable was launched, wait for it to finish */
+  {
+    WaitForSingleObject(sInfo.hProcess,INFINITE); 
+  }
+  return 0;
+  //return system(command);
 #endif
 }
 
@@ -305,13 +338,17 @@ QCString stripFromPath(const QCString &path)
 int guessSection(const char *name)
 {
   QCString n=((QCString)name).lower();
-  if (n.right(2)==".c"   ||
+  if (n.right(2)==".c"   || // source
       n.right(3)==".cc"  ||
       n.right(4)==".cxx" ||
       n.right(4)==".cpp" ||
-      n.right(4)==".c++"
+      n.right(4)==".c++" ||
+      n.right(3)==".ii"  || // inline
+      n.right(4)==".ixx" ||
+      n.right(4)==".ipp" ||
+      n.right(4)==".i++"
      ) return Entry::SOURCE_SEC;
-  if (n.right(2)==".h"   ||
+  if (n.right(2)==".h"   || // header
       n.right(3)==".hh"  ||
       n.right(4)==".hxx" ||
       n.right(4)==".hpp" ||
@@ -1257,14 +1294,14 @@ static void trimNamespaceScope(QCString &t1,QCString &t2)
  */
 void stripIrrelevantConstVolatile(QCString &s)
 {
-  int i,j;
+  int i;
   if (s=="const")    { s.resize(0); return; }
   if (s=="volatile") { s.resize(0); return; }
   i = s.find("const ");
   if (i!=-1) 
   {
     // no & or * after the const
-    if ((j=s.find('*',i+6))==-1 && (j=s.find('&',i+6))==-1)
+    if (s.find('*',i+6)==-1 && s.find('&',i+6)==-1)
     {
       s=s.left(i)+s.right(s.length()-i-6); 
     }
@@ -1273,7 +1310,7 @@ void stripIrrelevantConstVolatile(QCString &s)
   if (i!=-1) 
   {
     // no & or * after the volatile
-    if ((j=s.find('*',i+9))==-1 && (j=s.find('&',i+9))==-1)
+    if (s.find('*',i+9)==-1 && s.find('&',i+9)==-1)
     {
       s=s.left(i)+s.right(s.length()-i-9); 
     }
@@ -1993,9 +2030,9 @@ bool getDefs(const QCString &scName,const QCString &memberName,
   // maybe an namespace, file or group member ?
   //printf("Testing for global function scopeName=`%s' mScope=`%s' :: mName=`%s'\n",
   //              scopeName.data(),mScope.data(),mName.data());
-  //printf("  >member name found\n");
   if ((mn=functionNameDict[mName])) // name is known
   {
+    //printf("  >member name found\n");
     NamespaceDef *fnd=0;
     int scopeOffset=scopeName.length();
     do
@@ -2298,13 +2335,11 @@ bool generateRef(OutputList &ol,const char *scName,
   if (bracePos!=-1) argsStr=tmpName.right(tmpName.length()-bracePos);
   
   // create a default link text if none was explicitly given
-  bool explicitLink=TRUE;
   if (linkText.isEmpty())
   {
     //if (!scopeUser.isEmpty()) linkText=scopeUser+"::";
     linkText=nameStr;
     if (linkText.left(2)=="::") linkText=linkText.right(linkText.length()-2);
-    explicitLink=FALSE;
   } 
   //printf("scope=`%s' name=`%s' arg=`%s' linkText=`%s'\n",
   //       scopeStr.data(),nameStr.data(),argsStr.data(),linkText.data());
@@ -2445,12 +2480,12 @@ bool generateLink(OutputList &ol,const char *clName,
     {
       SectionInfo *si=0;
       if (!pi->name.isEmpty()) si=sectionDict[pi->name];
-      ol.writeObjectLink(0,gd->getOutputFileBase(),si ? si->label.data() : 0,lt);  
+      ol.writeObjectLink(gd->getReference(),gd->getOutputFileBase(),si ? si->label.data() : 0,lt);  
       writePageRef(ol,gd->getOutputFileBase(),si ? si->label.data() : 0);
     }
     else
     {
-      ol.writeObjectLink(0,pi->name,0,lt);  
+      ol.writeObjectLink(pi->getReference(),pi->getOutputFileBase(),0,lt);  
       writePageRef(ol,pi->name,0);
     }
     return TRUE;
@@ -2877,3 +2912,23 @@ QCString stripScope(const char *name)
   return result;
 }
 
+QCString convertToXML(const char *s)
+{
+  QCString result;
+  if (s==0) return result;
+  const char *p=s;
+  char c;
+  while ((c=*p++))
+  {
+    switch (c)
+    {
+      case '<':  result+="&lt;";   break;
+      case '>':  result+="&gt;";   break;
+      case '&':  result+="&amp;";  break;
+      case '\'': result+="&apos;"; break; 
+      case '"':  result+="&quot;"; break;
+      default:   result+=c;        break;         
+    }
+  }
+  return result;
+}
diff --git a/src/util.h b/src/util.h
index e0b3d69..26941b7 100644
--- a/src/util.h
+++ b/src/util.h
@@ -133,6 +133,7 @@ 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);
@@ -149,7 +150,7 @@ 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);
+int iSystem(const char *command,const char *args);
 
 #endif
 
diff --git a/src/xml.cpp b/src/xml.cpp
index fd2cf45..1171a2e 100644
--- a/src/xml.cpp
+++ b/src/xml.cpp
@@ -22,6 +22,7 @@
 #include "message.h"
 #include "config.h"
 #include "classlist.h"
+#include "util.h"
 
 #include <qdir.h>
 #include <qfile.h>
@@ -46,21 +47,7 @@ void generateDTD()
 
 void writeXMLString(QTextStream &t,const char *s)
 {
-  if (s==0) return;
-  const char *p=s;
-  char c;
-  while ((c=*p++))
-  {
-    switch (c)
-    {
-      case '<':  t << "&lt;";   break;
-      case '>':  t << "&gt;";   break;
-      case '&':  t << "&amp;";  break;
-      case '\'': t << "&apos;"; break; 
-      case '"':  t << "&quot;"; break;
-      default:   t << c;        break;         
-    }
-  }
+  t << convertToXML(s);
 }
 
 void writeXMLLink(QTextStream &t,const char *compoundId,const char *memId,
diff --git a/src/xml.h b/src/xml.h
index ee0f85f..313e935 100644
--- a/src/xml.h
+++ b/src/xml.h
@@ -19,6 +19,7 @@ class QTextStream;
 
 void generateXML();
 void writeXMLString(QTextStream &t,const char *s);
+void writeXMLString(QTextStream &t,const char *s);
 void writeXMLLink(QTextStream &t,const char *compoundRef,const char *memAnchor,
                                  const char *text);
 
diff --git a/tmake/lib/win32-mingw/app.t b/tmake/lib/win32-mingw/app.t
new file mode 100755
index 0000000..fc4dc2c
--- /dev/null
+++ b/tmake/lib/win32-mingw/app.t
@@ -0,0 +1,6 @@
+#############################################################################
+#!
+#! This is a tmake template for building Win32 applications.
+#!
+#$ Project('TMAKE_APP_FLAG = 1');
+#$ IncludeTemplate("generic.t");
diff --git a/tmake/lib/win32-mingw/generic.t b/tmake/lib/win32-mingw/generic.t
new file mode 100755
index 0000000..4d333c1
--- /dev/null
+++ b/tmake/lib/win32-mingw/generic.t
@@ -0,0 +1,241 @@
+#!
+#! This is a tmake template for building Win32 applications or libraries.
+#!
+#${
+    if ( Config("qt") ) {
+	if ( !(Project("DEFINES") =~ /QT_NODLL/) &&
+	     ((Project("DEFINES") =~ /QT_(?:MAKE)?DLL/) ||
+	      ($ENV{"QT_DLL"} && !$ENV{"QT_NODLL"})) ) {
+	    Project('TMAKE_QT_DLL = 1');
+	    if ( (Project("TARGET") eq "qt") && Project("TMAKE_LIB_FLAG") ) {
+		Project('CONFIG += dll');
+	    }
+	}
+    }
+    if ( Config("dll") || Project("TMAKE_APP_FLAG") ) {
+	Project('CONFIG -= staticlib');
+	Project('TMAKE_APP_OR_DLL = 1');
+    } else {
+	Project('CONFIG += staticlib');
+    }
+    if ( Config("warn_off") ) {
+	Project('TMAKE_CFLAGS += $$TMAKE_CFLAGS_WARN_OFF');
+	Project('TMAKE_CXXFLAGS += $$TMAKE_CXXFLAGS_WARN_OFF');
+    } elsif ( Config("warn_on") ) {
+	Project('TMAKE_CFLAGS += $$TMAKE_CFLAGS_WARN_ON');
+	Project('TMAKE_CXXFLAGS += $$TMAKE_CXXFLAGS_WARN_ON');
+    }
+    if ( Config("debug") ) {
+	Project('TMAKE_CFLAGS += $$TMAKE_CFLAGS_DEBUG');
+	Project('TMAKE_CXXFLAGS += $$TMAKE_CXXFLAGS_DEBUG');
+	Project('TMAKE_LFLAGS += $$TMAKE_LFLAGS_DEBUG');
+    } elsif ( Config("release") ) {
+	Project('TMAKE_CFLAGS += $$TMAKE_CFLAGS_RELEASE');
+	Project('TMAKE_CXXFLAGS += $$TMAKE_CXXFLAGS_RELEASE');
+	Project('TMAKE_LFLAGS += $$TMAKE_LFLAGS_RELEASE');
+    }
+    if ( Config("qt") || Config("opengl") ) {
+	Project('CONFIG += windows' );
+    }
+    if ( Config("qt") ) {
+	Project('CONFIG *= moc');
+	AddIncludePath(Project("TMAKE_INCDIR_QT"));
+	if ( Config("release") ) {
+	    Project('DEFINES += NO_DEBUG');
+	}
+	if ( Config("opengl") ) {
+	    Project('TMAKE_LIBS *= $$TMAKE_LIBS_QT_OPENGL');
+	}
+	if ( (Project("TARGET") eq "qt") && Project("TMAKE_LIB_FLAG") ) {
+	    if ( Project("TMAKE_QT_DLL") ) {
+		Project('DEFINES -= QT_DLL');
+		Project('DEFINES *= QT_MAKEDLL');
+		Project('TMAKE_LFLAGS += $$TMAKE_LFLAGS_QT_DLL');
+	    }
+	} else {
+	    if ( Project("TMAKE_QT_DLL") ) {
+		Project('DEFINES *= QT_DLL');
+	    }
+	    Project('TMAKE_LIBS *= $$TMAKE_LIBS_QT');
+	    if ( Project("TMAKE_QT_DLL") ) {
+		my $qtver =FindHighestLibVersion($ENV{"QTDIR"} . "/lib", "qt");
+		Project("TMAKE_LIBS /= s/qt.lib/qt${qtver}.lib/");
+		if ( !Config("dll") ) {
+		    Project('TMAKE_LIBS *= $$TMAKE_LIBS_QT_DLL');
+		}
+	    }
+	}
+    }
+    if ( Config("opengl") ) {
+	Project('TMAKE_LIBS *= $$TMAKE_LIBS_OPENGL');
+    }
+    if ( Config("dll") ) {
+	Project('TMAKE_LFLAGS_CONSOLE_ANY = $$TMAKE_LFLAGS_CONSOLE_DLL');
+	Project('TMAKE_LFLAGS_WINDOWS_ANY = $$TMAKE_LFLAGS_WINDOWS_DLL');
+	if ( Project("TMAKE_LIB_FLAG") ) {
+	    my $ver = Project("VERSION");
+	    $ver =~ s/\.//g;
+	    $project{"TARGET_EXT"} = "${ver}.dll";
+	} else {
+	    $project{"TARGET_EXT"} = ".dll";
+	}
+    } else {
+	Project('TMAKE_LFLAGS_CONSOLE_ANY = $$TMAKE_LFLAGS_CONSOLE');
+	Project('TMAKE_LFLAGS_WINDOWS_ANY = $$TMAKE_LFLAGS_WINDOWS');
+	if ( Project("TMAKE_APP_FLAG") ) {
+	    $project{"TARGET_EXT"} = ".exe";
+	} else {
+	    $project{"TARGET_EXT"} = ".a";
+	}
+    }
+    if ( Config("windows") ) {
+	if ( Config("console") ) {
+	    Project('TMAKE_LFLAGS *= $$TMAKE_LFLAGS_CONSOLE_ANY');
+	    Project('TMAKE_LIBS   *= $$TMAKE_LIBS_CONSOLE');
+	} else {
+	    Project('TMAKE_LFLAGS *= $$TMAKE_LFLAGS_WINDOWS_ANY');
+	}
+	Project('TMAKE_LIBS   *= $$TMAKE_LIBS_WINDOWS');
+    } else {
+	Project('TMAKE_LFLAGS *= $$TMAKE_LFLAGS_CONSOLE_ANY');
+	Project('TMAKE_LIBS   *= $$TMAKE_LIBS_CONSOLE');
+    }
+    if ( Config("moc") ) {
+	$moc_aware = 1;
+    }
+    Project('TMAKE_LIBS += $$LIBS');
+    Project('TMAKE_FILETAGS = HEADERS SOURCES DEF_FILE RC_FILE TARGET TMAKE_LIBS DESTDIR DLLDESTDIR $$FILETAGS');
+    foreach ( split(/\s/,Project("TMAKE_FILETAGS")) ) {
+	$project{$_} =~ s-[/\\]+-/-g;
+    }
+    if ( Project("DEF_FILE") ) {
+	Project('TMAKE_LFLAGS *= $$DEF_FILE');
+    }
+    if ( Project("RC_FILE") ) {
+	if ( Project("RES_FILE") ) {
+	    tmake_error("Both .rc and .res file specified.\n" .
+			"Please specify one of them, not both.");
+	}
+	$project{"RES_FILE"} = $project{"RC_FILE"};
+	$project{"RES_FILE"} =~ s/\.rc$/.res/i;
+	Project('TARGETDEPS += $$RES_FILE');
+    }
+    if ( Project("RES_FILE") ) {
+	Project('TMAKE_LIBS *= $$RES_FILE');
+    }
+    $obj_ext  = "o";
+    $dir_sep  = "/";
+    $gnuwin32 = 1;
+    if ( Config("qt") ) {
+	$qtdir = $ENV{"QTDIR"};
+	$project{"INCPATH"} =~ s/\$\(QTDIR\)/$qtdir/;
+	$project{"INCPATH"} =~ s/\\/\//g;
+	$project{"TMAKE_LIBS"} =~ s/\$\(QTDIR\)/$qtdir/;
+	$project{"TMAKE_LIBS"} =~ s/\\/\//g;
+    }
+    StdInit();
+    if ( Project("VERSION") ) {
+	$project{"VER_MAJ"} = $project{"VERSION"};
+	$project{"VER_MAJ"} =~ s/\.\d+$//;
+	$project{"VER_MIN"} = $project{"VERSION"};
+	$project{"VER_MIN"} =~ s/^\d+\.//;
+    }    
+    if ( Config("staticlib") ) {
+	$project{"TARGET"} = $project{"DESTDIR"} . "lib" . $project{"TARGET"};
+    } else {
+	$project{"TARGET"} = $project{"DESTDIR"} . $project{"TARGET"};
+    }
+#$}
+#!
+# Makefile for building #$ Expand("TARGET")
+# Generated by tmake at #$ Now();
+#     Project: #$ Expand("PROJECT");
+#    Template: #$ Expand("TEMPLATE");
+#############################################################################
+
+####### Compiler, tools and options
+
+CC	=	#$ Expand("TMAKE_CC");
+CXX	=	#$ Expand("TMAKE_CXX");
+CFLAGS	=	#$ Expand("TMAKE_CFLAGS"); ExpandGlue("DEFINES","-D"," -D","");
+CXXFLAGS=	#$ Expand("TMAKE_CXXFLAGS"); ExpandGlue("DEFINES","-D"," -D","");
+INCPATH	=	#$ ExpandPath("INCPATH",'-I',' -I','');
+#$ !Project("TMAKE_APP_OR_DLL") && DisableOutput();
+LINK	=	#$ Expand("TMAKE_LINK");
+LFLAGS	=	#$ Expand("TMAKE_LFLAGS");
+LIBS	=	#$ Expand("TMAKE_LIBS");
+#$ !Project("TMAKE_APP_OR_DLL") && EnableOutput();
+#$ Project("TMAKE_APP_OR_DLL") && DisableOutput();
+AR	=	#$ Expand("TMAKE_AR");
+RANLIB	=	#$ Expand("TMAKE_RANLIB");
+#$ Project("TMAKE_APP_OR_DLL") && EnableOutput();
+MOC	=	#$ Expand("TMAKE_MOC");
+
+ZIP	=	#$ Expand("TMAKE_ZIP");
+
+####### Files
+
+HEADERS =	#$ ExpandList("HEADERS");
+SOURCES =	#$ ExpandList("SOURCES");
+OBJECTS =	#$ ExpandList("OBJECTS");
+SRCMOC	=	#$ ExpandList("SRCMOC");
+OBJMOC	=	#$ ExpandList("OBJMOC");
+DIST	=	#$ ExpandList("DISTFILES");
+TARGET	=	#$ ExpandGlue("TARGET",$project{"DESTDIR"},"",$project{"TARGET_EXT"});
+
+####### Implicit rules
+
+.SUFFIXES: .cpp .cxx .cc .c
+
+.cpp.o:
+	#$ Expand("TMAKE_RUN_CXX_IMP");
+
+.cxx.o:
+	#$ Expand("TMAKE_RUN_CXX_IMP");
+
+.cc.o:
+	#$ Expand("TMAKE_RUN_CXX_IMP");
+
+.c.o:
+	#$ Expand("TMAKE_RUN_CC_IMP");
+
+####### Build rules
+
+all: #$ ExpandGlue("ALL_DEPS",""," "," "); $text .= '$(TARGET)';
+
+$(TARGET): $(OBJECTS) $(OBJMOC) #$ Expand("TARGETDEPS");
+#$ Project("TMAKE_APP_OR_DLL") || DisableOutput();
+	$(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJMOC) $(LIBS)
+#$ Project("TMAKE_APP_OR_DLL") || EnableOutput();
+#$ Project("TMAKE_APP_OR_DLL") && DisableOutput();
+	-rm -f $(TARGET)
+	$(AR) $(TARGET) $(OBJECTS) $(OBJMOC)
+	#$ ExpandGlue("TMAKE_RANLIB","",""," \$(TARGET)");
+#$ Project("TMAKE_APP_OR_DLL") && EnableOutput();
+#$ (Config("dll") && Project("DLLDESTDIR")) || DisableOutput();
+	-cp $(TARGET) #$ Expand("DLLDESTDIR");
+#$ (Config("dll") && Project("DLLDESTDIR")) || EnableOutput();
+#$ Project('RC_FILE') || DisableOutput();
+
+#$ Substitute("\$\$RES_FILE: \$\$RC_FILE\n\t\$\$TMAKE_RC \$\$RC_FILE");
+#$ Project('RC_FILE') || EnableOutput();
+
+moc: $(SRCMOC)
+
+#$ TmakeSelf();
+
+dist:
+	#$ Substitute('$(ZIP) $$PROJECT.zip $$PROJECT.pro $(SOURCES) $(HEADERS) $(DIST)');
+
+clean:
+	-rm -f $(OBJECTS) $(OBJMOC) $(SRCMOC) $(TARGET)
+	#$ ExpandGlue("TMAKE_CLEAN","-rm -f "," ","");
+	-rm -f *~ core
+	#$ ExpandGlue("CLEAN_FILES","-rm -f "," ","");
+
+####### Compile
+
+#$ BuildObj(Project("OBJECTS"),Project("SOURCES"));
+#$ BuildMocObj(Project("OBJMOC"),Project("SRCMOC"));
+#$ BuildMocSrc(Project("HEADERS"));
+#$ BuildMocSrc(Project("SOURCES"));
diff --git a/tmake/lib/win32-mingw/lib.t b/tmake/lib/win32-mingw/lib.t
new file mode 100755
index 0000000..d8ac6c7
--- /dev/null
+++ b/tmake/lib/win32-mingw/lib.t
@@ -0,0 +1,6 @@
+#############################################################################
+#!
+#! This is a tmake template for building Win32 libraries.
+#!
+#$ Project('TMAKE_LIB_FLAG = 1');
+#$ IncludeTemplate("generic.t");
diff --git a/tmake/lib/win32-mingw/subdirs.t b/tmake/lib/win32-mingw/subdirs.t
new file mode 100755
index 0000000..8b881ab
--- /dev/null
+++ b/tmake/lib/win32-mingw/subdirs.t
@@ -0,0 +1,2 @@
+#! Use the common Win32 template
+#$ IncludeTemplate("../win32/subdirs.t");
diff --git a/tmake/lib/win32-mingw/tmake.conf b/tmake/lib/win32-mingw/tmake.conf
new file mode 100755
index 0000000..c6d1918
--- /dev/null
+++ b/tmake/lib/win32-mingw/tmake.conf
@@ -0,0 +1,56 @@
+#
+# 
+#
+# tmake configuration for Win32/mingw (MINGW gnu-win32)
+#
+
+TEMPLATE		= app
+CONFIG			= qt warn_on release
+
+TMAKE_CC		= gcc
+TMAKE_CFLAGS		=
+TMAKE_CFLAGS_WARN_ON	=
+TMAKE_CFLAGS_WARN_OFF	=
+TMAKE_CFLAGS_RELEASE	= -O2 -s
+TMAKE_CFLAGS_DEBUG	= -g
+TMAKE_CFLAGS_YACC	= -Wno-unused -Wno-parentheses
+
+TMAKE_CXX		= g++
+TMAKE_CXXFLAGS		= $$TMAKE_CFLAGS
+TMAKE_CXXFLAGS_WARN_ON	= $$TMAKE_CFLAGS_WARN_ON
+TMAKE_CXXFLAGS_WARN_OFF	= $$TMAKE_CFLAGS_WARN_OFF
+TMAKE_CXXFLAGS_RELEASE	= $$TMAKE_CFLAGS_RELEASE
+TMAKE_CXXFLAGS_DEBUG	= $$TMAKE_CFLAGS_DEBUG
+TMAKE_CXXFLAGS_YACC	= $$TMAKE_CFLAGS_YACC
+
+TMAKE_INCDIR		=
+TMAKE_INCDIR_QT		= $(QTDIR)/include
+
+TMAKE_RUN_CC		= $(CC) -c $(CFLAGS) $(INCPATH) -o $obj $src
+TMAKE_RUN_CC_IMP	= $(CC) -c $(CFLAGS) $(INCPATH) -o $@ $<
+TMAKE_RUN_CXX		= $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $obj $src
+TMAKE_RUN_CXX_IMP	= $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
+
+TMAKE_LINK		= g++
+TMAKE_LFLAGS		=
+TMAKE_LFLAGS_RELEASE	= -s
+TMAKE_LFLAGS_DEBUG	=
+TMAKE_LFLAGS_CONSOLE	= -Wl,-subsystem,console
+TMAKE_LFLAGS_WINDOWS	= -Wl,-subsystem,windows
+TMAKE_LFLAGS_CONSOLE_DLL= -Wl,-subsystem,console
+TMAKE_LFLAGS_WINDOWS_DLL= -Wl,-subsystem,windows
+
+TMAKE_LIBS		=
+TMAKE_LIBS_CONSOLE	=
+TMAKE_LIBS_WINDOWS	= -luser32 -lgdi32 -lcomdlg32 -limm32 -lole32 -luuid -lwsock32
+TMAKE_LIBS_QT		= -L$(QTDIR)/lib -lqt
+TMAKE_LIBS_QT_DLL	= -lqtmain
+TMAKE_LIBS_QT_OPENGL	= -lqgl
+TMAKE_LIBS_OPENGL	= -lopengl32
+
+TMAKE_MOC		= moc
+
+TMAKE_AR		= ar cqs
+TMAKE_RANLIB		=
+
+TMAKE_ZIP		= zip -r -9
diff --git a/wintools/make.pl b/wintools/make.pl
index ae1eff3..e34fc2a 100755
--- a/wintools/make.pl
+++ b/wintools/make.pl
@@ -1,5 +1,12 @@
 # make script used to create a config file for windows
 
+$target = shift @ARGV;
+$make   = "make";
+if ($target eq "msvc") 
+{
+  $make = "nmake";
+}
+
 use Cwd;
 
 # get current working directory
@@ -9,9 +16,9 @@ $pwd=cwd();
 open(FILE,">makeconfig") || die "Cannot create file makeconfig!";
 
 print FILE "DOXYGEN   = $pwd\n";
-print FILE "TMAKEPATH = $pwd\\tmake\\lib\\win32-msvc\n";
+print FILE "TMAKEPATH = $pwd\\tmake\\lib\\win32-$target\n";
 print FILE "TMAKE     = $pwd\\tmake\\bin\\tmake\n";
-print FILE "MAKE      = nmake\n";
+print FILE "MAKE      = $make\n";
 print FILE "PERL      = perl\n";
 print FILE "RM        = del /s /q\n";
 print FILE "VERSION   = ";
-- 
cgit v0.12

