瀏覽代碼

+ Initial import in CVS

michael 22 年之前
父節點
當前提交
31fcaf7186

+ 1538 - 0
utils/fpdoc/Makefile

@@ -0,0 +1,1538 @@
+#
+# Don't edit, this file is generated by FPCMake Version 1.1 [2002/10/05]
+#
+default: all
+MAKEFILETARGETS=linux go32v2 win32 os2 freebsd beos netbsd amiga atari sunos qnx netware openbsd wdosx
+override PATH:=$(subst \,/,$(PATH))
+ifeq ($(findstring ;,$(PATH)),)
+inUnix=1
+SEARCHPATH:=$(filter-out .,$(subst :, ,$(PATH)))
+else
+SEARCHPATH:=$(subst ;, ,$(PATH))
+endif
+PWD:=$(strip $(wildcard $(addsuffix /pwd.exe,$(SEARCHPATH))))
+ifeq ($(PWD),)
+PWD:=$(strip $(wildcard $(addsuffix /pwd,$(SEARCHPATH))))
+ifeq ($(PWD),)
+$(error You need the GNU utils package to use this Makefile)
+else
+PWD:=$(firstword $(PWD))
+SRCEXEEXT=
+endif
+else
+PWD:=$(firstword $(PWD))
+SRCEXEEXT=.exe
+endif
+ifndef inUnix
+ifeq ($(OS),Windows_NT)
+inWinNT=1
+else
+ifdef OS2_SHELL
+inOS2=1
+endif
+endif
+else
+ifneq ($(findstring cygwin,$(MACHTYPE)),)
+inCygWin=1
+endif
+endif
+ifeq ($(OS_TARGET),freebsd)
+BSDhier=1
+endif
+ifeq ($(OS_TARGET),netbsd)
+BSDhier=1
+endif
+ifeq ($(OS_TARGET),openbsd)
+BSDhier=1
+endif
+ifdef inUnix
+BATCHEXT=.sh
+else
+ifdef inOS2
+BATCHEXT=.cmd
+else
+BATCHEXT=.bat
+endif
+endif
+ifdef inUnix
+PATHSEP=/
+else
+PATHSEP:=$(subst /,\,/)
+ifneq ($(findstring sh.exe,$(SHELL)),)
+PATHSEP=/
+endif
+endif
+ifdef PWD
+BASEDIR:=$(subst \,/,$(shell $(PWD)))
+ifdef inCygWin
+ifneq ($(findstring /cygdrive/,$(BASEDIR)),)
+BASENODIR:=$(patsubst /cygdrive%,%,$(BASEDIR))
+BASEDRIVE:=$(firstword $(subst /, ,$(BASENODIR)))
+BASEDIR:=$(subst /cygdrive/$(BASEDRIVE)/,$(BASEDRIVE):/,$(BASEDIR))
+endif
+endif
+else
+BASEDIR=.
+endif
+ifdef inOS2
+ifndef ECHO
+ECHO:=$(strip $(wildcard $(addsuffix /gecho$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO:=$(strip $(wildcard $(addsuffix /echo$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO=echo
+else
+ECHO:=$(firstword $(ECHO))
+endif
+else
+ECHO:=$(firstword $(ECHO))
+endif
+endif
+export ECHO
+endif
+override DEFAULT_FPCDIR=../..
+ifndef FPC
+ifdef PP
+FPC=$(PP)
+endif
+endif
+ifndef FPC
+FPCPROG:=$(strip $(wildcard $(addsuffix /fpc$(SRCEXEEXT),$(SEARCHPATH))))
+ifneq ($(FPCPROG),)
+FPCPROG:=$(firstword $(FPCPROG))
+FPC:=$(shell $(FPCPROG) -PB)
+ifneq ($(findstring Error,$(FPC)),)
+override FPC=ppc386
+endif
+else
+override FPC=ppc386
+endif
+endif
+override FPC:=$(subst $(SRCEXEEXT),,$(FPC))
+override FPC:=$(subst \,/,$(FPC))$(SRCEXEEXT)
+ifndef FPC_VERSION
+FPC_VERSION:=$(shell $(FPC) -iV)
+endif
+export FPC FPC_VERSION
+unexport CHECKDEPEND ALLDEPENDENCIES
+ifeq ($(findstring 1.0.,$(FPC_VERSION)),)
+COMPILERINFO:=$(shell $(FPC) -iSP -iTP -iSO -iTO)
+ifndef CPU_SOURCE
+CPU_SOURCE:=$(word 1,$(COMPILERINFO))
+endif
+ifndef CPU_TARGET
+CPU_TARGET:=$(word 2,$(COMPILERINFO))
+endif
+ifndef OS_SOURCE
+OS_SOURCE:=$(word 3,$(COMPILERINFO))
+endif
+ifndef OS_TARGET
+OS_TARGET:=$(word 4,$(COMPILERINFO))
+endif
+else
+ifndef CPU_SOURCE
+CPU_SOURCE:=$(shell $(FPC) -iSP)
+endif
+ifndef CPU_TARGET
+CPU_TARGET:=$(shell $(FPC) -iTP)
+endif
+ifndef OS_SOURCE
+OS_SOURCE:=$(shell $(FPC) -iSO)
+endif
+ifndef OS_TARGET
+OS_TARGET:=$(shell $(FPC) -iTO)
+endif
+endif
+ifndef CPU_TARGET
+ifdef CPU_TARGET_DEFAULT
+CPU_TARGET=$(CPU_TARGET_DEFAULT)
+endif
+endif
+ifndef OS_TARGET
+ifdef OS_TARGET_DEFAULT
+OS_TARGET=$(OS_TARGET_DEFAULT)
+endif
+endif
+FULL_TARGET=$(CPU_TARGET)-$(OS_TARGET)
+FULL_SOURCE=$(CPU_SOURCE)-$(OS_SOURCE)
+ifneq ($(FULL_TARGET),$(FULL_SOURCE))
+CROSSCOMPILE=1
+endif
+ifeq ($(findstring makefile,$(MAKECMDGOALS)),)
+ifeq ($(findstring $(OS_TARGET),$(MAKEFILETARGETS)),)
+$(error The Makefile doesn't support target $(OS_TARGET), please run fpcmake first)
+endif
+endif
+export OS_TARGET OS_SOURCE CPU_TARGET CPU_SOURCE FULL_TARGET FULL_SOURCE CROSSCOMPILE
+ifdef FPCDIR
+override FPCDIR:=$(subst \,/,$(FPCDIR))
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),)
+override FPCDIR=wrong
+endif
+else
+override FPCDIR=wrong
+endif
+ifdef DEFAULT_FPCDIR
+ifeq ($(FPCDIR),wrong)
+override FPCDIR:=$(subst \,/,$(DEFAULT_FPCDIR))
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),)
+override FPCDIR=wrong
+endif
+endif
+endif
+ifeq ($(FPCDIR),wrong)
+ifdef inUnix
+override FPCDIR=/usr/local/lib/fpc/$(FPC_VERSION)
+ifeq ($(wildcard $(FPCDIR)/units),)
+override FPCDIR=/usr/lib/fpc/$(FPC_VERSION)
+endif
+else
+override FPCDIR:=$(subst /$(FPC),,$(firstword $(strip $(wildcard $(addsuffix /$(FPC),$(SEARCHPATH))))))
+override FPCDIR:=$(FPCDIR)/..
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),)
+override FPCDIR:=$(FPCDIR)/..
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),)
+override FPCDIR=c:/pp
+endif
+endif
+endif
+endif
+ifndef CROSSDIR
+CROSSDIR:=$(FPCDIR)/cross/$(FULL_TARGET)
+endif
+ifndef CROSSTARGETDIR
+CROSSTARGETDIR=$(CROSSDIR)/$(FULL_TARGET)
+endif
+ifdef CROSSCOMPILE
+UNITSDIR:=$(wildcard $(CROSSTARGETDIR)/units)
+ifeq ($(UNITSDIR),)
+UNITSDIR:=$(wildcard $(FPCDIR)/units/$(OS_TARGET))
+endif
+else
+UNITSDIR:=$(wildcard $(FPCDIR)/units/$(OS_TARGET))
+endif
+PACKAGESDIR:=$(wildcard $(FPCDIR) $(FPCDIR)/packages/base $(FPCDIR)/packages/extra)
+override PACKAGE_NAME=fpdoc
+override PACKAGE_VERSION=1.0.8
+override TARGET_PROGRAMS+=fpdoc makeskel
+override CLEAN_UNITS+=dglobals dwriter dw_xml sh_pas dw_html dw_latex
+override CLEAN_FILES+=dwriter.rst fpdoc.rst dglobals.rst makeskel.rst
+override INSTALL_FPCPACKAGE=y
+override COMPILER_OPTIONS+=-S2h
+ifdef REQUIRE_UNITSDIR
+override UNITSDIR+=$(REQUIRE_UNITSDIR)
+endif
+ifdef REQUIRE_PACKAGESDIR
+override PACKAGESDIR+=$(REQUIRE_PACKAGESDIR)
+endif
+ifdef ZIPINSTALL
+ifeq ($(OS_TARGET),linux)
+UNIXINSTALLDIR=1
+endif
+ifeq ($(OS_TARGET),freebsd)
+UNIXINSTALLDIR=1
+endif
+ifeq ($(OS_TARGET),netbsd)
+UNIXINSTALLDIR=1
+endif
+ifeq ($(OS_TARGET),openbsd)
+UNIXINSTALLDIR=1
+endif
+ifeq ($(OS_TARGET),sunos)
+UNIXINSTALLDIR=1
+endif
+ifeq ($(OS_TARGET),qnx)
+UNIXINSTALLDIR=1
+endif
+else
+ifeq ($(OS_SOURCE),linux)
+UNIXINSTALLDIR=1
+endif
+ifeq ($(OS_SOURCE),freebsd)
+UNIXINSTALLDIR=1
+endif
+ifeq ($(OS_SOURCE),netbsd)
+UNIXINSTALLDIR=1
+endif
+ifeq ($(OS_SOURCE),openbsd)
+UNIXINSTALLDIR=1
+endif
+ifeq ($(OS_TARGET),sunos)
+UNIXINSTALLDIR=1
+endif
+ifeq ($(OS_TARGET),qnx)
+UNIXINSTALLDIR=1
+endif
+endif
+ifndef INSTALL_PREFIX
+ifdef PREFIX
+INSTALL_PREFIX=$(PREFIX)
+endif
+endif
+ifndef INSTALL_PREFIX
+ifdef UNIXINSTALLDIR
+INSTALL_PREFIX=/usr/local
+else
+ifdef INSTALL_FPCPACKAGE
+INSTALL_BASEDIR:=/pp
+else
+INSTALL_BASEDIR:=/$(PACKAGE_NAME)
+endif
+endif
+endif
+export INSTALL_PREFIX
+ifdef INSTALL_FPCSUBDIR
+export INSTALL_FPCSUBDIR
+endif
+ifndef DIST_DESTDIR
+DIST_DESTDIR:=$(BASEDIR)
+endif
+export DIST_DESTDIR
+ifndef INSTALL_BASEDIR
+ifdef UNIXINSTALLDIR
+ifdef INSTALL_FPCPACKAGE
+INSTALL_BASEDIR:=$(INSTALL_PREFIX)/lib/fpc/$(FPC_VERSION)
+else
+INSTALL_BASEDIR:=$(INSTALL_PREFIX)/lib/$(PACKAGE_NAME)
+endif
+else
+INSTALL_BASEDIR:=$(INSTALL_PREFIX)
+endif
+endif
+ifndef INSTALL_BINDIR
+ifdef UNIXINSTALLDIR
+INSTALL_BINDIR:=$(INSTALL_PREFIX)/bin
+else
+INSTALL_BINDIR:=$(INSTALL_BASEDIR)/bin
+ifdef INSTALL_FPCPACKAGE
+INSTALL_BINDIR:=$(INSTALL_BINDIR)/$(OS_TARGET)
+endif
+endif
+endif
+ifndef INSTALL_UNITDIR
+ifdef CROSSCOMPILE
+INSTALL_UNITDIR:=$(INSTALL_BASEDIR)/cross/$(FULL_TARGET)/units
+else
+INSTALL_UNITDIR:=$(INSTALL_BASEDIR)/units/$(OS_TARGET)
+endif
+ifdef INSTALL_FPCPACKAGE
+ifdef PACKAGE_NAME
+INSTALL_UNITDIR:=$(INSTALL_UNITDIR)/$(PACKAGE_NAME)
+endif
+endif
+endif
+ifndef INSTALL_LIBDIR
+ifdef UNIXINSTALLDIR
+INSTALL_LIBDIR:=$(INSTALL_PREFIX)/lib
+else
+INSTALL_LIBDIR:=$(INSTALL_UNITDIR)
+endif
+endif
+ifndef INSTALL_SOURCEDIR
+ifdef UNIXINSTALLDIR
+ifdef BSDhier
+SRCPREFIXDIR=share/src
+else
+SRCPREFIXDIR=src
+endif
+ifdef INSTALL_FPCPACKAGE
+ifdef INSTALL_FPCSUBDIR
+INSTALL_SOURCEDIR:=$(INSTALL_PREFIX)/$(SRCPREFIXDIR)/fpc-$(FPC_VERSION)/$(INSTALL_FPCSUBDIR)/$(PACKAGE_NAME)
+else
+INSTALL_SOURCEDIR:=$(INSTALL_PREFIX)/$(SRCPREFIXDIR)/fpc-$(FPC_VERSION)/$(PACKAGE_NAME)
+endif
+else
+INSTALL_SOURCEDIR:=$(INSTALL_PREFIX)/$(SRCPREFIXDIR)/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+endif
+else
+ifdef INSTALL_FPCPACKAGE
+ifdef INSTALL_FPCSUBDIR
+INSTALL_SOURCEDIR:=$(INSTALL_BASEDIR)/source/$(INSTALL_FPCSUBDIR)/$(PACKAGE_NAME)
+else
+INSTALL_SOURCEDIR:=$(INSTALL_BASEDIR)/source/$(PACKAGE_NAME)
+endif
+else
+INSTALL_SOURCEDIR:=$(INSTALL_BASEDIR)/source
+endif
+endif
+endif
+ifndef INSTALL_DOCDIR
+ifdef UNIXINSTALLDIR
+ifdef BSDhier
+DOCPREFIXDIR=share/doc
+else
+DOCPREFIXDIR=doc
+endif
+ifdef INSTALL_FPCPACKAGE
+INSTALL_DOCDIR:=$(INSTALL_PREFIX)/$(DOCPREFIXDIR)/fpc-$(FPC_VERSION)/$(PACKAGE_NAME)
+else
+INSTALL_DOCDIR:=$(INSTALL_PREFIX)/$(DOCPREFIXDIR)/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+endif
+else
+ifdef INSTALL_FPCPACKAGE
+INSTALL_DOCDIR:=$(INSTALL_BASEDIR)/doc/$(PACKAGE_NAME)
+else
+INSTALL_DOCDIR:=$(INSTALL_BASEDIR)/doc
+endif
+endif
+endif
+ifndef INSTALL_EXAMPLEDIR
+ifdef UNIXINSTALLDIR
+ifdef INSTALL_FPCPACKAGE
+ifdef BSDhier
+INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/share/examples/fpc-$(FPC_VERSION)/$(PACKAGE_NAME)
+else
+INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/doc/fpc-$(FPC_VERSION)/examples/$(PACKAGE_NAME)
+endif
+else
+ifdef BSDhier
+INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/share/examples/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+else
+INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/doc/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+endif
+endif
+else
+ifdef INSTALL_FPCPACKAGE
+INSTALL_EXAMPLEDIR:=$(INSTALL_BASEDIR)/examples/$(PACKAGE_NAME)
+else
+INSTALL_EXAMPLEDIR:=$(INSTALL_BASEDIR)/examples
+endif
+endif
+endif
+ifndef INSTALL_DATADIR
+INSTALL_DATADIR=$(INSTALL_BASEDIR)
+endif
+ifdef CROSSCOMPILE
+ifndef CROSSBINDIR
+CROSSBINDIR:=$(wildcard $(CROSSTARGETDIR)/bin/$(FULL_SOURCE))
+ifeq ($(CROSSBINDIR),)
+CROSSBINDIR:=$(wildcard $(INSTALL_BASEDIR)/cross/$(FULL_TARGET)/bin/$(FULL_SOURCE))
+endif
+endif
+else
+CROSSBINDIR=
+endif
+ifdef inUnix
+ifndef GCCLIBDIR
+GCCLIBDIR:=$(shell dirname `(gcc -v 2>&1)| head -n 1| awk '{ print $$4 } '`)
+endif
+ifeq ($(OS_TARGET),linux)
+ifndef OTHERLIBDIR
+OTHERLIBDIR:=$(shell grep -v "^\#" /etc/ld.so.conf | awk '{ ORS=" "; print $1 }')
+endif
+endif
+ifeq ($(OS_TARGET),netbsd)
+OTHERLIBDIR+=/usr/pkg/lib
+endif
+export GCCLIBDIR OTHERLIB
+endif
+LOADEREXT=.as
+EXEEXT=.exe
+PPLEXT=.ppl
+PPUEXT=.ppu
+OEXT=.o
+ASMEXT=.s
+SMARTEXT=.sl
+STATICLIBEXT=.a
+SHAREDLIBEXT=.so
+STATICLIBPREFIX=libp
+RSTEXT=.rst
+FPCMADE=fpcmade
+ifeq ($(OS_TARGET),go32v1)
+PPUEXT=.pp1
+OEXT=.o1
+ASMEXT=.s1
+SMARTEXT=.sl1
+STATICLIBEXT=.a1
+SHAREDLIBEXT=.so1
+STATICLIBPREFIX=
+FPCMADE=fpcmade.v1
+PACKAGESUFFIX=v1
+endif
+ifeq ($(OS_TARGET),go32v2)
+STATICLIBPREFIX=
+FPCMADE=fpcmade.dos
+ZIPSUFFIX=go32
+endif
+ifeq ($(OS_TARGET),linux)
+EXEEXT=
+HASSHAREDLIB=1
+FPCMADE=fpcmade.lnx
+ZIPSUFFIX=linux
+endif
+ifeq ($(OS_TARGET),freebsd)
+EXEEXT=
+HASSHAREDLIB=1
+FPCMADE=fpcmade.freebsd
+ZIPSUFFIX=freebsd
+endif
+ifeq ($(OS_TARGET),netbsd)
+EXEEXT=
+HASSHAREDLIB=1
+FPCMADE=fpcmade.netbsd
+ZIPSUFFIX=netbsd
+endif
+ifeq ($(OS_TARGET),openbsd)
+EXEEXT=
+HASSHAREDLIB=1
+FPCMADE=fpcmade.openbsd
+ZIPSUFFIX=openbsd
+endif
+ifeq ($(OS_TARGET),win32)
+PPUEXT=.ppw
+OEXT=.ow
+ASMEXT=.sw
+SMARTEXT=.slw
+STATICLIBEXT=.aw
+SHAREDLIBEXT=.dll
+FPCMADE=fpcmade.w32
+ZIPSUFFIX=w32
+endif
+ifeq ($(OS_TARGET),os2)
+PPUEXT=.ppo
+ASMEXT=.so2
+OEXT=.oo2
+AOUTEXT=.out
+SMARTEXT=.sl2
+STATICLIBPREFIX=
+STATICLIBEXT=.ao2
+SHAREDLIBEXT=.dll
+FPCMADE=fpcmade.os2
+ZIPSUFFIX=emx
+ECHO=echo
+endif
+ifeq ($(OS_TARGET),amiga)
+EXEEXT=
+PPUEXT=.ppu
+ASMEXT=.asm
+OEXT=.o
+SMARTEXT=.sl
+STATICLIBEXT=.a
+SHAREDLIBEXT=.library
+FPCMADE=fpcmade.amg
+endif
+ifeq ($(OS_TARGET),atari)
+PPUEXT=.ppu
+ASMEXT=.s
+OEXT=.o
+SMARTEXT=.sl
+STATICLIBEXT=.a
+EXEEXT=.ttp
+FPCMADE=fpcmade.ata
+endif
+ifeq ($(OS_TARGET),beos)
+PPUEXT=.ppu
+ASMEXT=.s
+OEXT=.o
+SMARTEXT=.sl
+STATICLIBEXT=.a
+EXEEXT=
+FPCMADE=fpcmade.be
+ZIPSUFFIX=be
+endif
+ifeq ($(OS_TARGET),sunos)
+PPUEXT=.ppu
+ASMEXT=.s
+OEXT=.o
+SMARTEXT=.sl
+STATICLIBEXT=.a
+EXEEXT=
+FPCMADE=fpcmade.sun
+ZIPSUFFIX=sun
+endif
+ifeq ($(OS_TARGET),qnx)
+PPUEXT=.ppu
+ASMEXT=.s
+OEXT=.o
+SMARTEXT=.sl
+STATICLIBEXT=.a
+EXEEXT=
+FPCMADE=fpcmade.qnx
+ZIPSUFFIX=qnx
+endif
+ifeq ($(OS_TARGET),netware)
+STATICLIBPREFIX=
+PPUEXT=.ppn
+OEXT=.on
+ASMEXT=.s
+SMARTEXT=.sl
+STATICLIBEXT=.a
+SHAREDLIBEXT=.nlm
+FPCMADE=fpcmade.nw
+ZIPSUFFIX=nw
+EXEEXT=.nlm
+endif
+ifndef ECHO
+ECHO:=$(strip $(wildcard $(addsuffix /gecho$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO:=$(strip $(wildcard $(addsuffix /echo$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO=
+else
+ECHO:=$(firstword $(ECHO))
+endif
+else
+ECHO:=$(firstword $(ECHO))
+endif
+endif
+export ECHO
+ifndef DATE
+DATE:=$(strip $(wildcard $(addsuffix /gdate$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(DATE),)
+DATE:=$(strip $(wildcard $(addsuffix /date$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(DATE),)
+DATE=
+else
+DATE:=$(firstword $(DATE))
+endif
+else
+DATE:=$(firstword $(DATE))
+endif
+endif
+export DATE
+ifndef GINSTALL
+GINSTALL:=$(strip $(wildcard $(addsuffix /ginstall$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(GINSTALL),)
+GINSTALL:=$(strip $(wildcard $(addsuffix /install$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(GINSTALL),)
+GINSTALL=
+else
+GINSTALL:=$(firstword $(GINSTALL))
+endif
+else
+GINSTALL:=$(firstword $(GINSTALL))
+endif
+endif
+export GINSTALL
+ifndef CPPROG
+CPPROG:=$(strip $(wildcard $(addsuffix /cp$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(CPPROG),)
+CPPROG=
+else
+CPPROG:=$(firstword $(CPPROG))
+endif
+endif
+export CPPROG
+ifndef RMPROG
+RMPROG:=$(strip $(wildcard $(addsuffix /rm$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(RMPROG),)
+RMPROG=
+else
+RMPROG:=$(firstword $(RMPROG))
+endif
+endif
+export RMPROG
+ifndef MVPROG
+MVPROG:=$(strip $(wildcard $(addsuffix /mv$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(MVPROG),)
+MVPROG=
+else
+MVPROG:=$(firstword $(MVPROG))
+endif
+endif
+export MVPROG
+ifndef ECHOREDIR
+ECHOREDIR:=$(subst /,$(PATHSEP),$(ECHO))
+endif
+ifndef COPY
+COPY:=$(CPPROG) -fp
+endif
+ifndef COPYTREE
+COPYTREE:=$(CPPROG) -rfp
+endif
+ifndef MOVE
+MOVE:=$(MVPROG) -f
+endif
+ifndef DEL
+DEL:=$(RMPROG) -f
+endif
+ifndef DELTREE
+DELTREE:=$(RMPROG) -rf
+endif
+ifndef INSTALL
+ifdef inUnix
+INSTALL:=$(GINSTALL) -c -m 644
+else
+INSTALL:=$(COPY)
+endif
+endif
+ifndef INSTALLEXE
+ifdef inUnix
+INSTALLEXE:=$(GINSTALL) -c -m 755
+else
+INSTALLEXE:=$(COPY)
+endif
+endif
+ifndef MKDIR
+MKDIR:=$(GINSTALL) -m 755 -d
+endif
+export ECHOREDIR COPY COPYTREE MOVE DEL DELTREE INSTALL INSTALLEXE MKDIR
+ifndef PPUMOVE
+PPUMOVE:=$(strip $(wildcard $(addsuffix /ppumove$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(PPUMOVE),)
+PPUMOVE=
+else
+PPUMOVE:=$(firstword $(PPUMOVE))
+endif
+endif
+export PPUMOVE
+ifndef FPCMAKE
+FPCMAKE:=$(strip $(wildcard $(addsuffix /fpcmake$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(FPCMAKE),)
+FPCMAKE=
+else
+FPCMAKE:=$(firstword $(FPCMAKE))
+endif
+endif
+export FPCMAKE
+ifndef ZIPPROG
+ZIPPROG:=$(strip $(wildcard $(addsuffix /zip$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ZIPPROG),)
+ZIPPROG=
+else
+ZIPPROG:=$(firstword $(ZIPPROG))
+endif
+endif
+export ZIPPROG
+ifndef TARPROG
+TARPROG:=$(strip $(wildcard $(addsuffix /tar$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(TARPROG),)
+TARPROG=
+else
+TARPROG:=$(firstword $(TARPROG))
+endif
+endif
+export TARPROG
+ASNAME=as
+LDNAME=ld
+ARNAME=ar
+RCNAME=rc
+ifeq ($(OS_TARGET),win32)
+ASNAME=asw
+LDNAME=ldw
+ARNAME=arw
+endif
+ifndef ASPROG
+ifdef CROSSBINDIR
+ASPROG=$(CROSSBINDIR)/$(ASNAME)$(SRCEXEEXT)
+else
+ASPROG=$(ASNAME)
+endif
+endif
+ifndef LDPROG
+ifdef CROSSBINDIR
+LDPROG=$(CROSSBINDIR)/$(LDNAME)$(SRCEXEEXT)
+else
+LDPROG=$(LDNAME)
+endif
+endif
+ifndef RCPROG
+ifdef CROSSBINDIR
+RCPROG=$(CROSSBINDIR)/$(RCNAME)$(SRCEXEEXT)
+else
+RCPROG=$(RCNAME)
+endif
+endif
+ifndef ARPROG
+ifdef CROSSBINDIR
+ARPROG=$(CROSSBINDIR)/$(ARNAME)$(SRCEXEEXT)
+else
+ARPROG=$(ARNAME)
+endif
+endif
+AS=$(ASPROG)
+LD=$(LDPROG)
+RC=$(RCPROG)
+AR=$(ARPROG)
+PPAS=ppas$(BATCHEXT)
+ifdef inUnix
+LDCONFIG=ldconfig
+else
+LDCONFIG=
+endif
+ifdef DATE
+DATESTR:=$(shell $(DATE) +%Y%m%d)
+else
+DATESTR=
+endif
+ifndef UPXPROG
+ifeq ($(OS_TARGET),go32v2)
+UPXPROG:=1
+endif
+ifeq ($(OS_TARGET),win32)
+UPXPROG:=1
+endif
+ifdef UPXPROG
+UPXPROG:=$(strip $(wildcard $(addsuffix /upx$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(UPXPROG),)
+UPXPROG=
+else
+UPXPROG:=$(firstword $(UPXPROG))
+endif
+else
+UPXPROG=
+endif
+endif
+export UPXPROG
+ZIPOPT=-9
+ZIPEXT=.zip
+ifeq ($(USETAR),bz2)
+TAROPT=vI
+TAREXT=.tar.bz2
+else
+TAROPT=vz
+TAREXT=.tar.gz
+endif
+override REQUIRE_PACKAGES=rtl fcl
+ifeq ($(OS_TARGET),linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_NETDB=1
+REQUIRE_PACKAGES_LIBASYNC=1
+REQUIRE_PACKAGES_FCL=1
+REQUIRE_PACKAGES_MYSQL=1
+REQUIRE_PACKAGES_IBASE=1
+endif
+ifeq ($(OS_TARGET),go32v2)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL=1
+endif
+ifeq ($(OS_TARGET),win32)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_NETDB=1
+REQUIRE_PACKAGES_FCL=1
+REQUIRE_PACKAGES_MYSQL=1
+REQUIRE_PACKAGES_IBASE=1
+endif
+ifeq ($(OS_TARGET),os2)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL=1
+endif
+ifeq ($(OS_TARGET),freebsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_NETDB=1
+REQUIRE_PACKAGES_LIBASYNC=1
+REQUIRE_PACKAGES_FCL=1
+REQUIRE_PACKAGES_MYSQL=1
+REQUIRE_PACKAGES_IBASE=1
+endif
+ifeq ($(OS_TARGET),beos)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL=1
+endif
+ifeq ($(OS_TARGET),netbsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_NETDB=1
+REQUIRE_PACKAGES_LIBASYNC=1
+REQUIRE_PACKAGES_FCL=1
+REQUIRE_PACKAGES_MYSQL=1
+REQUIRE_PACKAGES_IBASE=1
+endif
+ifeq ($(OS_TARGET),amiga)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL=1
+endif
+ifeq ($(OS_TARGET),atari)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL=1
+endif
+ifeq ($(OS_TARGET),sunos)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL=1
+endif
+ifeq ($(OS_TARGET),qnx)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL=1
+endif
+ifeq ($(OS_TARGET),netware)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL=1
+endif
+ifeq ($(OS_TARGET),openbsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_NETDB=1
+REQUIRE_PACKAGES_LIBASYNC=1
+REQUIRE_PACKAGES_FCL=1
+REQUIRE_PACKAGES_MYSQL=1
+REQUIRE_PACKAGES_IBASE=1
+endif
+ifeq ($(OS_TARGET),wdosx)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL=1
+endif
+ifdef REQUIRE_PACKAGES_RTL
+PACKAGEDIR_RTL:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /rtl/$(OS_TARGET)/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_RTL),)
+ifneq ($(wildcard $(PACKAGEDIR_RTL)/$(OS_TARGET)),)
+UNITDIR_RTL=$(PACKAGEDIR_RTL)/$(OS_TARGET)
+else
+UNITDIR_RTL=$(PACKAGEDIR_RTL)
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_RTL)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_RTL) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_RTL)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_RTL=
+UNITDIR_RTL:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /rtl/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_RTL),)
+UNITDIR_RTL:=$(firstword $(UNITDIR_RTL))
+else
+UNITDIR_RTL=
+endif
+endif
+ifdef UNITDIR_RTL
+override COMPILER_UNITDIR+=$(UNITDIR_RTL)
+endif
+endif
+ifdef REQUIRE_PACKAGES_PASZLIB
+PACKAGEDIR_PASZLIB:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /paszlib/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_PASZLIB),)
+ifneq ($(wildcard $(PACKAGEDIR_PASZLIB)/$(OS_TARGET)),)
+UNITDIR_PASZLIB=$(PACKAGEDIR_PASZLIB)/$(OS_TARGET)
+else
+UNITDIR_PASZLIB=$(PACKAGEDIR_PASZLIB)
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_PASZLIB)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_PASZLIB) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_PASZLIB)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_PASZLIB=
+UNITDIR_PASZLIB:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /paszlib/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_PASZLIB),)
+UNITDIR_PASZLIB:=$(firstword $(UNITDIR_PASZLIB))
+else
+UNITDIR_PASZLIB=
+endif
+endif
+ifdef UNITDIR_PASZLIB
+override COMPILER_UNITDIR+=$(UNITDIR_PASZLIB)
+endif
+endif
+ifdef REQUIRE_PACKAGES_NETDB
+PACKAGEDIR_NETDB:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /netdb/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_NETDB),)
+ifneq ($(wildcard $(PACKAGEDIR_NETDB)/$(OS_TARGET)),)
+UNITDIR_NETDB=$(PACKAGEDIR_NETDB)/$(OS_TARGET)
+else
+UNITDIR_NETDB=$(PACKAGEDIR_NETDB)
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_NETDB)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_NETDB) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_NETDB)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_NETDB=
+UNITDIR_NETDB:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /netdb/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_NETDB),)
+UNITDIR_NETDB:=$(firstword $(UNITDIR_NETDB))
+else
+UNITDIR_NETDB=
+endif
+endif
+ifdef UNITDIR_NETDB
+override COMPILER_UNITDIR+=$(UNITDIR_NETDB)
+endif
+endif
+ifdef REQUIRE_PACKAGES_LIBASYNC
+PACKAGEDIR_LIBASYNC:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /libasync/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_LIBASYNC),)
+ifneq ($(wildcard $(PACKAGEDIR_LIBASYNC)/$(OS_TARGET)),)
+UNITDIR_LIBASYNC=$(PACKAGEDIR_LIBASYNC)/$(OS_TARGET)
+else
+UNITDIR_LIBASYNC=$(PACKAGEDIR_LIBASYNC)
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_LIBASYNC)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_LIBASYNC) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_LIBASYNC)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_LIBASYNC=
+UNITDIR_LIBASYNC:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /libasync/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_LIBASYNC),)
+UNITDIR_LIBASYNC:=$(firstword $(UNITDIR_LIBASYNC))
+else
+UNITDIR_LIBASYNC=
+endif
+endif
+ifdef UNITDIR_LIBASYNC
+override COMPILER_UNITDIR+=$(UNITDIR_LIBASYNC)
+endif
+endif
+ifdef REQUIRE_PACKAGES_FCL
+PACKAGEDIR_FCL:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /fcl/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_FCL),)
+ifneq ($(wildcard $(PACKAGEDIR_FCL)/$(OS_TARGET)),)
+UNITDIR_FCL=$(PACKAGEDIR_FCL)/$(OS_TARGET)
+else
+UNITDIR_FCL=$(PACKAGEDIR_FCL)
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_FCL)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_FCL) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_FCL)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_FCL=
+UNITDIR_FCL:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /fcl/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_FCL),)
+UNITDIR_FCL:=$(firstword $(UNITDIR_FCL))
+else
+UNITDIR_FCL=
+endif
+endif
+ifdef UNITDIR_FCL
+override COMPILER_UNITDIR+=$(UNITDIR_FCL)
+endif
+endif
+ifdef REQUIRE_PACKAGES_MYSQL
+PACKAGEDIR_MYSQL:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /mysql/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_MYSQL),)
+ifneq ($(wildcard $(PACKAGEDIR_MYSQL)/$(OS_TARGET)),)
+UNITDIR_MYSQL=$(PACKAGEDIR_MYSQL)/$(OS_TARGET)
+else
+UNITDIR_MYSQL=$(PACKAGEDIR_MYSQL)
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_MYSQL)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_MYSQL) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_MYSQL)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_MYSQL=
+UNITDIR_MYSQL:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /mysql/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_MYSQL),)
+UNITDIR_MYSQL:=$(firstword $(UNITDIR_MYSQL))
+else
+UNITDIR_MYSQL=
+endif
+endif
+ifdef UNITDIR_MYSQL
+override COMPILER_UNITDIR+=$(UNITDIR_MYSQL)
+endif
+endif
+ifdef REQUIRE_PACKAGES_IBASE
+PACKAGEDIR_IBASE:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /ibase/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_IBASE),)
+ifneq ($(wildcard $(PACKAGEDIR_IBASE)/$(OS_TARGET)),)
+UNITDIR_IBASE=$(PACKAGEDIR_IBASE)/$(OS_TARGET)
+else
+UNITDIR_IBASE=$(PACKAGEDIR_IBASE)
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_IBASE)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_IBASE) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_IBASE)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_IBASE=
+UNITDIR_IBASE:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /ibase/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_IBASE),)
+UNITDIR_IBASE:=$(firstword $(UNITDIR_IBASE))
+else
+UNITDIR_IBASE=
+endif
+endif
+ifdef UNITDIR_IBASE
+override COMPILER_UNITDIR+=$(UNITDIR_IBASE)
+endif
+endif
+ifndef NOCPUDEF
+override FPCOPTDEF=$(CPU_TARGET)
+endif
+ifneq ($(OS_TARGET),$(OS_SOURCE))
+override FPCOPT+=-T$(OS_TARGET)
+endif
+ifeq ($(OS_SOURCE),openbsd)
+override FPCOPT+=-FD$(NEW_BINUTILS_PATH)
+endif
+ifdef UNITDIR
+override FPCOPT+=$(addprefix -Fu,$(UNITDIR))
+endif
+ifdef LIBDIR
+override FPCOPT+=$(addprefix -Fl,$(LIBDIR))
+endif
+ifdef OBJDIR
+override FPCOPT+=$(addprefix -Fo,$(OBJDIR))
+endif
+ifdef INCDIR
+override FPCOPT+=$(addprefix -Fi,$(INCDIR))
+endif
+ifdef LINKSMART
+override FPCOPT+=-XX
+endif
+ifdef CREATESMART
+override FPCOPT+=-CX
+endif
+ifdef DEBUG
+override FPCOPT+=-gl
+override FPCOPTDEF+=DEBUG
+endif
+ifdef RELEASE
+ifeq ($(CPU_TARGET),i386)
+FPCCPUOPT:=-OG2p3
+else
+FPCCPUOPT:=
+endif
+override FPCOPT+=-Xs $(FPCCPUOPT) -n
+override FPCOPTDEF+=RELEASE
+endif
+ifdef STRIP
+override FPCOPT+=-Xs
+endif
+ifdef OPTIMIZE
+ifeq ($(CPU_TARGET),i386)
+override FPCOPT+=-OG2p3
+endif
+endif
+ifdef VERBOSE
+override FPCOPT+=-vwni
+endif
+ifdef COMPILER_OPTIONS
+override FPCOPT+=$(COMPILER_OPTIONS)
+endif
+ifdef COMPILER_UNITDIR
+override FPCOPT+=$(addprefix -Fu,$(COMPILER_UNITDIR))
+endif
+ifdef COMPILER_LIBRARYDIR
+override FPCOPT+=$(addprefix -Fl,$(COMPILER_LIBRARYDIR))
+endif
+ifdef COMPILER_OBJECTDIR
+override FPCOPT+=$(addprefix -Fo,$(COMPILER_OBJECTDIR))
+endif
+ifdef COMPILER_INCLUDEDIR
+override FPCOPT+=$(addprefix -Fi,$(COMPILER_INCLUDEDIR))
+endif
+ifdef CROSSBINDIR
+override FPCOPT+=-FD$(CROSSBINDIR)
+endif
+ifdef COMPILER_TARGETDIR
+override FPCOPT+=-FE$(COMPILER_TARGETDIR)
+ifeq ($(COMPILER_TARGETDIR),.)
+override TARGETDIRPREFIX=
+else
+override TARGETDIRPREFIX=$(COMPILER_TARGETDIR)/
+endif
+endif
+ifdef COMPILER_UNITTARGETDIR
+override FPCOPT+=-FU$(COMPILER_UNITTARGETDIR)
+ifeq ($(COMPILER_UNITTARGETDIR),.)
+override UNITTARGETDIRPREFIX=
+else
+override UNITTARGETDIRPREFIX=$(COMPILER_UNITTARGETDIR)/
+endif
+else
+ifdef COMPILER_TARGETDIR
+override COMPILER_UNITTARGETDIR=$(COMPILER_TARGETDIR)
+override UNITTARGETDIRPREFIX=$(TARGETDIRPREFIX)
+endif
+endif
+ifdef GCCLIBDIR
+override FPCOPT+=-Fl$(GCCLIBDIR)
+endif
+ifdef OTHERLIBDIR
+override FPCOPT+=$(addprefix -Fl,$(OTHERLIBDIR))
+endif
+ifdef OPT
+override FPCOPT+=$(OPT)
+endif
+ifdef FPCOPTDEF
+override FPCOPT+=$(addprefix -d,$(FPCOPTDEF))
+endif
+ifdef CFGFILE
+override FPCOPT+=@$(CFGFILE)
+endif
+ifdef USEENV
+override FPCEXTCMD:=$(FPCOPT)
+override FPCOPT:=!FPCEXTCMD
+export FPCEXTCMD
+endif
+override COMPILER:=$(FPC) $(FPCOPT)
+ifeq (,$(findstring -s ,$(COMPILER)))
+EXECPPAS=
+else
+ifeq ($(OS_SOURCE),$(OS_TARGET))
+EXECPPAS:=@$(PPAS)
+endif
+endif
+.PHONY: fpc_exes
+ifdef TARGET_PROGRAMS
+override EXEFILES=$(addsuffix $(EXEEXT),$(TARGET_PROGRAMS))
+override EXEOFILES:=$(addsuffix $(OEXT),$(TARGET_PROGRAMS)) $(addprefix $(STATICLIBPREFIX),$(addsuffix $(STATICLIBEXT),$(TARGET_PROGRAMS)))
+override ALLTARGET+=fpc_exes
+override INSTALLEXEFILES+=$(EXEFILES)
+override CLEANEXEFILES+=$(EXEFILES) $(EXEOFILES)
+ifeq ($(OS_TARGET),os2)
+override CLEANEXEFILES+=$(addsuffix $(AOUTEXT),$(TARGET_PROGRAMS))
+endif
+endif
+fpc_exes: $(EXEFILES)
+ifdef TARGET_RSTS
+override RSTFILES=$(addsuffix $(RSTEXT),$(TARGET_RSTS))
+override CLEANRSTFILES+=$(RSTFILES)
+endif
+.PHONY: fpc_all fpc_smart fpc_debug fpc_release
+$(FPCMADE): $(ALLDEPENDENCIES) $(ALLTARGET)
+	@$(ECHOREDIR) Compiled > $(FPCMADE)
+fpc_all: $(FPCMADE)
+fpc_smart:
+	$(MAKE) all LINKSMART=1 CREATESMART=1
+fpc_debug:
+	$(MAKE) all DEBUG=1
+fpc_release:
+	$(MAKE) all RELEASE=1
+.SUFFIXES: $(EXEEXT) $(PPUEXT) $(OEXT) .pas .pp .rc .res
+%$(PPUEXT): %.pp
+	$(COMPILER) $<
+	$(EXECPPAS)
+%$(PPUEXT): %.pas
+	$(COMPILER) $<
+	$(EXECPPAS)
+%$(EXEEXT): %.pp
+	$(COMPILER) $<
+	$(EXECPPAS)
+%$(EXEEXT): %.pas
+	$(COMPILER) $<
+	$(EXECPPAS)
+%.res: %.rc
+	windres -i $< -o $@
+vpath %.pp $(COMPILER_SOURCEDIR) $(COMPILER_INCLUDEDIR)
+vpath %.pas $(COMPILER_SOURCEDIR) $(COMPILER_INCLUDEDIR)
+vpath %$(PPUEXT) $(COMPILER_UNITTARGETDIR)
+.PHONY: fpc_install fpc_sourceinstall fpc_exampleinstall
+ifdef INSTALL_UNITS
+override INSTALLPPUFILES+=$(addsuffix $(PPUEXT),$(INSTALL_UNITS))
+endif
+ifdef INSTALL_BUILDUNIT
+override INSTALLPPUFILES:=$(filter-out $(INSTALL_BUILDUNIT)$(PPUEXT),$(INSTALLPPUFILES))
+endif
+ifdef INSTALLPPUFILES
+override INSTALLPPULINKFILES:=$(subst $(PPUEXT),$(OEXT),$(INSTALLPPUFILES)) $(addprefix $(STATICLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(INSTALLPPUFILES)))
+override INSTALLPPUFILES:=$(addprefix $(UNITTARGETDIRPREFIX),$(INSTALLPPUFILES))
+override INSTALLPPULINKFILES:=$(wildcard $(addprefix $(UNITTARGETDIRPREFIX),$(INSTALLPPULINKFILES)))
+override INSTALL_CREATEPACKAGEFPC=1
+endif
+ifdef INSTALLEXEFILES
+override INSTALLEXEFILES:=$(addprefix $(TARGETDIRPREFIX),$(INSTALLEXEFILES))
+endif
+fpc_install: all $(INSTALLTARGET)
+ifdef INSTALLEXEFILES
+	$(MKDIR) $(INSTALL_BINDIR)
+ifdef UPXPROG
+	-$(UPXPROG) $(INSTALLEXEFILES)
+endif
+	$(INSTALLEXE) $(INSTALLEXEFILES) $(INSTALL_BINDIR)
+endif
+ifdef INSTALL_CREATEPACKAGEFPC
+ifdef FPCMAKE
+ifdef PACKAGE_VERSION
+ifneq ($(wildcard Makefile.fpc),)
+	$(FPCMAKE) -p -T$(OS_TARGET) Makefile.fpc
+	$(MKDIR) $(INSTALL_UNITDIR)
+	$(INSTALL) Package.fpc $(INSTALL_UNITDIR)
+endif
+endif
+endif
+endif
+ifdef INSTALLPPUFILES
+	$(MKDIR) $(INSTALL_UNITDIR)
+	$(INSTALL) $(INSTALLPPUFILES) $(INSTALL_UNITDIR)
+ifneq ($(INSTALLPPULINKFILES),)
+	$(INSTALL) $(INSTALLPPULINKFILES) $(INSTALL_UNITDIR)
+endif
+ifneq ($(wildcard $(LIB_FULLNAME)),)
+	$(MKDIR) $(INSTALL_LIBDIR)
+	$(INSTALL) $(LIB_FULLNAME) $(INSTALL_LIBDIR)
+ifdef inUnix
+	ln -sf $(LIB_FULLNAME) $(INSTALL_LIBDIR)/$(LIB_NAME)
+endif
+endif
+endif
+ifdef INSTALL_FILES
+	$(MKDIR) $(INSTALL_DATADIR)
+	$(INSTALL) $(INSTALL_FILES) $(INSTALL_DATADIR)
+endif
+fpc_sourceinstall: distclean
+	$(MKDIR) $(INSTALL_SOURCEDIR)
+	$(COPYTREE) $(BASEDIR)/* $(INSTALL_SOURCEDIR)
+fpc_exampleinstall: $(addsuffix _distclean,$(TARGET_EXAMPLEDIRS))
+ifdef HASEXAMPLES
+	$(MKDIR) $(INSTALL_EXAMPLEDIR)
+endif
+ifdef EXAMPLESOURCEFILES
+	$(COPY) $(EXAMPLESOURCEFILES) $(INSTALL_EXAMPLEDIR)
+endif
+ifdef TARGET_EXAMPLEDIRS
+	$(COPYTREE) $(addsuffix /*,$(TARGET_EXAMPLEDIRS)) $(INSTALL_EXAMPLEDIR)
+endif
+.PHONY: fpc_distinstall
+fpc_distinstall: install exampleinstall
+.PHONY: fpc_zipinstall fpc_zipsourceinstall fpc_zipexampleinstall
+ifndef PACKDIR
+ifndef inUnix
+PACKDIR=$(BASEDIR)/../fpc-pack
+else
+PACKDIR=/tmp/fpc-pack
+endif
+endif
+ifndef ZIPNAME
+ifdef DIST_ZIPNAME
+ZIPNAME=$(DIST_ZIPNAME)
+else
+ZIPNAME=$(ZIPPREFIX)$(PACKAGE_NAME)$(ZIPSUFFIX)
+endif
+endif
+ifndef ZIPTARGET
+ifdef DIST_ZIPTARGET
+ZIPTARGET=DIST_ZIPTARGET
+else
+ZIPTARGET=install
+endif
+endif
+ifndef USEZIP
+ifdef inUnix
+USETAR=1
+endif
+endif
+ifndef inUnix
+USEZIPWRAPPER=1
+endif
+ifdef USEZIPWRAPPER
+ZIPPATHSEP=$(PATHSEP)
+ZIPWRAPPER=$(subst /,$(PATHSEP),$(DIST_DESTDIR)/fpczip$(BATCHEXT))
+else
+ZIPPATHSEP=/
+endif
+ZIPCMD_CDPACK:=cd $(subst /,$(ZIPPATHSEP),$(PACKDIR))
+ZIPCMD_CDBASE:=cd $(subst /,$(ZIPPATHSEP),$(BASEDIR))
+ifdef USETAR
+ZIPDESTFILE:=$(DIST_DESTDIR)/$(ZIPNAME)$(TAREXT)
+ZIPCMD_ZIP:=$(TARPROG) cf$(TAROPT) $(ZIPDESTFILE) *
+else
+ZIPDESTFILE:=$(DIST_DESTDIR)/$(ZIPNAME)$(ZIPEXT)
+ZIPCMD_ZIP:=$(subst /,$(ZIPPATHSEP),$(ZIPPROG)) -Dr $(ZIPOPT) $(ZIPDESTFILE) *
+endif
+fpc_zipinstall:
+	$(MAKE) $(ZIPTARGET) INSTALL_PREFIX=$(PACKDIR) ZIPINSTALL=1
+	$(MKDIR) $(DIST_DESTDIR)
+	$(DEL) $(ZIPDESTFILE)
+ifdef USEZIPWRAPPER
+ifneq ($(ECHOREDIR),echo)
+	$(ECHOREDIR) -e "$(subst \,\\,$(ZIPCMD_CDPACK))" > $(ZIPWRAPPER)
+	$(ECHOREDIR) -e "$(subst \,\\,$(ZIPCMD_ZIP))" >> $(ZIPWRAPPER)
+	$(ECHOREDIR) -e "$(subst \,\\,$(ZIPCMD_CDBASE))" >> $(ZIPWRAPPER)
+else
+	echo $(ZIPCMD_CDPACK) > $(ZIPWRAPPER)
+	echo $(ZIPCMD_ZIP) >> $(ZIPWRAPPER)
+	echo $(ZIPCMD_CDBASE) >> $(ZIPWRAPPER)
+endif
+ifdef inUnix
+	/bin/sh $(ZIPWRAPPER)
+else
+	$(ZIPWRAPPER)
+endif
+	$(DEL) $(ZIPWRAPPER)
+else
+	$(ZIPCMD_CDPACK) ; $(ZIPCMD_ZIP) ; $(ZIPCMD_CDBASE)
+endif
+	$(DELTREE) $(PACKDIR)
+fpc_zipsourceinstall:
+	$(MAKE) fpc_zipinstall ZIPTARGET=sourceinstall ZIPSUFFIX=src
+fpc_zipexampleinstall:
+ifdef HASEXAMPLES
+	$(MAKE) fpc_zipinstall ZIPTARGET=exampleinstall ZIPSUFFIX=exm
+endif
+fpc_zipdistinstall:
+	$(MAKE) fpc_zipinstall ZIPTARGET=distinstall
+.PHONY: fpc_clean fpc_cleanall fpc_distclean
+ifdef EXEFILES
+override CLEANEXEFILES:=$(addprefix $(TARGETDIRPREFIX),$(CLEANEXEFILES))
+endif
+ifdef CLEAN_UNITS
+override CLEANPPUFILES+=$(addsuffix $(PPUEXT),$(CLEAN_UNITS))
+endif
+ifdef CLEANPPUFILES
+override CLEANPPULINKFILES:=$(subst $(PPUEXT),$(OEXT),$(CLEANPPUFILES)) $(addprefix $(STATICLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(CLEANPPUFILES)))
+override CLEANPPUFILES:=$(addprefix $(UNITTARGETDIRPREFIX),$(CLEANPPUFILES))
+override CLEANPPULINKFILES:=$(wildcard $(addprefix $(UNITTARGETDIRPREFIX),$(CLEANPPULINKFILES)))
+endif
+fpc_clean: $(CLEANTARGET)
+ifdef CLEANEXEFILES
+	-$(DEL) $(CLEANEXEFILES)
+endif
+ifdef CLEANPPUFILES
+	-$(DEL) $(CLEANPPUFILES)
+endif
+ifneq ($(CLEANPPULINKFILES),)
+	-$(DEL) $(CLEANPPULINKFILES)
+endif
+ifdef CLEANRSTFILES
+	-$(DEL) $(addprefix $(UNITTARGETDIRPREFIX),$(CLEANRSTFILES))
+endif
+ifdef CLEAN_FILES
+	-$(DEL) $(CLEAN_FILES)
+endif
+ifdef LIB_NAME
+	-$(DEL) $(LIB_NAME) $(LIB_FULLNAME)
+endif
+	-$(DEL) $(FPCMADE) Package.fpc $(PPAS) script.res link.res $(FPCEXTFILE) $(REDIRFILE)
+fpc_distclean: clean
+ifdef COMPILER_UNITTARGETDIR
+TARGETDIRCLEAN=fpc_clean
+endif
+fpc_cleanall: $(CLEANTARGET) $(TARGETDIRCLEAN)
+ifdef CLEANEXEFILES
+	-$(DEL) $(CLEANEXEFILES)
+endif
+	-$(DEL) *$(OEXT) *$(PPUEXT) *$(RSTEXT) *$(ASMEXT) *$(STATICLIBEXT) *$(SHAREDLIBEXT) *$(PPLEXT)
+	-$(DELTREE) *$(SMARTEXT)
+	-$(DEL) $(FPCMADE) Package.fpc $(PPAS) script.res link.res $(FPCEXTFILE) $(REDIRFILE)
+ifdef AOUTEXT
+	-$(DEL) *$(AOUTEXT)
+endif
+.PHONY: fpc_baseinfo
+override INFORULES+=fpc_baseinfo
+fpc_baseinfo:
+	@$(ECHO)
+	@$(ECHO)  == Package info ==
+	@$(ECHO)  Package Name..... $(PACKAGE_NAME)
+	@$(ECHO)  Package Version.. $(PACKAGE_VERSION)
+	@$(ECHO)
+	@$(ECHO)  == Configuration info ==
+	@$(ECHO)
+	@$(ECHO)  FPC.......... $(FPC)
+	@$(ECHO)  FPC Version.. $(FPC_VERSION)
+	@$(ECHO)  Source CPU... $(CPU_SOURCE)
+	@$(ECHO)  Target CPU... $(CPU_TARGET)
+	@$(ECHO)  Source OS.... $(OS_SOURCE)
+	@$(ECHO)  Target OS.... $(OS_TARGET)
+	@$(ECHO)  Full Source.. $(FULL_SOURCE)
+	@$(ECHO)  Full Target.. $(FULL_TARGET)
+	@$(ECHO)
+	@$(ECHO)  == Directory info ==
+	@$(ECHO)
+	@$(ECHO)  Required pkgs... $(REQUIRE_PACKAGES)
+	@$(ECHO)
+	@$(ECHO)  Basedir......... $(BASEDIR)
+	@$(ECHO)  FPCDir.......... $(FPCDIR)
+	@$(ECHO)  CrossBinDir..... $(CROSSBINDIR)
+	@$(ECHO)  UnitsDir........ $(UNITSDIR)
+	@$(ECHO)  PackagesDir..... $(PACKAGESDIR)
+	@$(ECHO)
+	@$(ECHO)  GCC library..... $(GCCLIBDIR)
+	@$(ECHO)  Other library... $(OTHERLIBDIR)
+	@$(ECHO)
+	@$(ECHO)  == Tools info ==
+	@$(ECHO)
+	@$(ECHO)  As........ $(AS)
+	@$(ECHO)  Ld........ $(LD)
+	@$(ECHO)  Ar........ $(AR)
+	@$(ECHO)  Rc........ $(RC)
+	@$(ECHO)
+	@$(ECHO)  Mv........ $(MVPROG)
+	@$(ECHO)  Cp........ $(CPPROG)
+	@$(ECHO)  Rm........ $(RMPROG)
+	@$(ECHO)  GInstall.. $(GINSTALL)
+	@$(ECHO)  Echo...... $(ECHO)
+	@$(ECHO)  Shell..... $(SHELL)
+	@$(ECHO)  Date...... $(DATE)
+	@$(ECHO)  FPCMake... $(FPCMAKE)
+	@$(ECHO)  PPUMove... $(PPUMOVE)
+	@$(ECHO)  Upx....... $(UPXPROG)
+	@$(ECHO)  Zip....... $(ZIPPROG)
+	@$(ECHO)
+	@$(ECHO)  == Object info ==
+	@$(ECHO)
+	@$(ECHO)  Target Loaders........ $(TARGET_LOADERS)
+	@$(ECHO)  Target Units.......... $(TARGET_UNITS)
+	@$(ECHO)  Target Implicit Units. $(TARGET_IMPLICITUNITS)
+	@$(ECHO)  Target Programs....... $(TARGET_PROGRAMS)
+	@$(ECHO)  Target Dirs........... $(TARGET_DIRS)
+	@$(ECHO)  Target Examples....... $(TARGET_EXAMPLES)
+	@$(ECHO)  Target ExampleDirs.... $(TARGET_EXAMPLEDIRS)
+	@$(ECHO)
+	@$(ECHO)  Clean Units......... $(CLEAN_UNITS)
+	@$(ECHO)  Clean Files......... $(CLEAN_FILES)
+	@$(ECHO)
+	@$(ECHO)  Install Units....... $(INSTALL_UNITS)
+	@$(ECHO)  Install Files....... $(INSTALL_FILES)
+	@$(ECHO)
+	@$(ECHO)  == Install info ==
+	@$(ECHO)
+	@$(ECHO)  DateStr.............. $(DATESTR)
+	@$(ECHO)  ZipPrefix............ $(ZIPPREFIX)
+	@$(ECHO)  ZipSuffix............ $(ZIPSUFFIX)
+	@$(ECHO)  Install FPC Package.. $(INSTALL_FPCPACKAGE)
+	@$(ECHO)
+	@$(ECHO)  Install base dir..... $(INSTALL_BASEDIR)
+	@$(ECHO)  Install binary dir... $(INSTALL_BINDIR)
+	@$(ECHO)  Install library dir.. $(INSTALL_LIBDIR)
+	@$(ECHO)  Install units dir.... $(INSTALL_UNITDIR)
+	@$(ECHO)  Install source dir... $(INSTALL_SOURCEDIR)
+	@$(ECHO)  Install doc dir...... $(INSTALL_DOCDIR)
+	@$(ECHO)  Install example dir.. $(INSTALL_EXAMPLEDIR)
+	@$(ECHO)  Install data dir..... $(INSTALL_DATADIR)
+	@$(ECHO)
+	@$(ECHO)  Dist destination dir. $(DIST_DESTDIR)
+	@$(ECHO)  Dist zip name........ $(DIST_ZIPNAME)
+	@$(ECHO)
+.PHONY: fpc_info
+fpc_info: $(INFORULES)
+.PHONY: fpc_makefile fpc_makefiles fpc_makefile_sub1 fpc_makefile_sub2 \
+	fpc_makefile_dirs
+fpc_makefile:
+	$(FPCMAKE) -w -T$(OS_TARGET) Makefile.fpc
+fpc_makefile_sub1:
+ifdef TARGET_DIRS
+	$(FPCMAKE) -w -T$(OS_TARGET) $(addsuffix /Makefile.fpc,$(TARGET_DIRS))
+endif
+ifdef TARGET_EXAMPLEDIRS
+	$(FPCMAKE) -w -T$(OS_TARGET) $(addsuffix /Makefile.fpc,$(TARGET_EXAMPLEDIRS))
+endif
+fpc_makefile_sub2: $(addsuffix _makefile_dirs,$(TARGET_DIRS) $(TARGET_EXAMPLEDIRS))
+fpc_makefile_dirs: fpc_makefile_sub1 fpc_makefile_sub2
+fpc_makefiles: fpc_makefile fpc_makefile_dirs
+all: fpc_all
+debug: fpc_debug
+smart: fpc_smart
+release: fpc_release
+examples:
+shared:
+install: fpc_install
+sourceinstall: fpc_sourceinstall
+exampleinstall: fpc_exampleinstall
+distinstall: fpc_distinstall
+zipinstall: fpc_zipinstall
+zipsourceinstall: fpc_zipsourceinstall
+zipexampleinstall: fpc_zipexampleinstall
+zipdistinstall: fpc_zipdistinstall
+clean: fpc_clean
+distclean: fpc_distclean
+cleanall: fpc_cleanall
+info: fpc_info
+makefiles: fpc_makefiles
+.PHONY: all debug smart release examples shared install sourceinstall exampleinstall distinstall zipinstall zipsourceinstall zipexampleinstall zipdistinstall clean distclean cleanall info makefiles
+ifneq ($(wildcard fpcmake.loc),)
+include fpcmake.loc
+endif
+fpdoc$(EXEEXT): fpdoc.pp dglobals.pp dwriter.pp dw_xml.pp sh_pas.pp dw_html.pp\
+  dw_latex.pp
+makeskel$(EXEEXT): makeskel.pp dglobals.pp

+ 33 - 0
utils/fpdoc/Makefile.fpc

@@ -0,0 +1,33 @@
+#
+#   Makefile.fpc for FPDoc
+#
+
+[package]
+name=fpdoc
+version=1.0.8
+
+[require]
+packages=fcl
+
+[target]
+programs=fpdoc makeskel
+rst=dwriter fpdoc dglobals makeskel
+
+[compiler]
+options=-S2h
+
+[install]
+fpcpackage=y
+
+[default]
+fpcdir=../..
+
+[clean]
+units=dglobals dwriter dw_xml sh_pas dw_html dw_latex
+files=dwriter.rst fpdoc.rst dglobals.rst makeskel.rst
+
+[rules]
+fpdoc$(EXEEXT): fpdoc.pp dglobals.pp dwriter.pp dw_xml.pp sh_pas.pp dw_html.pp\
+  dw_latex.pp
+
+makeskel$(EXEEXT): makeskel.pp dglobals.pp

+ 53 - 0
utils/fpdoc/README

@@ -0,0 +1,53 @@
+For more informations, see readme.html in the 'doc' subdirectory. There you
+can also find the default CSS for the HTML output.
+
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+(the file COPYING contains the whole GNU General Public License)
+
+
+Source file overview
+--------------------
+
+dglobals.pp
+  * Global declarations
+  * Catalogue management (internal link and description lookup tables)
+
+dwriter.pp
+  * Basic writer (output generator) class
+
+dw_html.pp
+  * HTML/XHTML output generator
+
+dw_latex.pp
+  * LaTeX output generator
+
+dw_xml.pp
+  * 'XML struct' output generator
+
+fpdoc.pp
+  * Main program
+
+makeskel.pp
+  * Skeleton XML description file generator
+
+Contributors
+------------
+French output strings by Pierre Muller
+Dutch output strings by Marco van de Voort
+
+Lots of input from Michael van Canneyt

+ 1118 - 0
utils/fpdoc/dglobals.pp

@@ -0,0 +1,1118 @@
+{
+    $Id$
+
+    FPDoc  -  Free Pascal Documentation Tool
+    Copyright (C) 2000 - 2002 by
+      Areca Systems GmbH / Sebastian Guenther, [email protected]
+
+    * Global declarations
+    * Link list management
+    * Document node tree
+    * Main engine
+
+    See the file COPYING, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+}
+
+
+unit dGlobals;
+
+{$MODE objfpc}
+{$H+}
+
+interface
+
+uses Classes, DOM, PasTree, PParser;
+
+resourcestring
+  // Output strings
+  SDocPackageTitle = 'Reference for package ''%s''';
+  SDocPrograms = 'Programs';
+  SDocUnits = 'Units';
+  SDocUnitTitle = 'Reference for unit ''%s''';
+  SDocInterfaceSection = 'Interface section';
+  SDocImplementationSection = 'Implementation section';
+  SDocUsedUnits = 'Used units';
+  SDocUsedUnitsByUnitXY = 'Used units by unit ''%s''';
+  SDocConstsTypesVars = 'Constants, types and variables';
+  SDocResStrings = 'Resource strings';
+  SDocTypes = 'Types';
+  SDocConstants = 'Constants';
+  SDocClasses = 'Classes';
+  SDocProceduresAndFunctions = 'Procedures and functions';
+  SDocVariables = 'Variables';
+
+  SDocUnitOverview = 'Overview of unit ''%s''';
+  SDocOverview = 'Overview';
+  SDocSearch = 'Search';
+  SDocDeclaration = 'Declaration';
+  SDocDescription = 'Description';
+  SDocErrors = 'Errors';
+  SDocSeeAlso = 'See also';
+  SDocExample = 'Example';
+  SDocArguments = 'Arguments';
+  SDocFunctionResult = 'Function result';
+  SDocRemark = 'Remark:   ';
+  SDocMethodOverview = 'Method overview';
+  SDocPropertyOverview = 'Property overview';
+  SDocPage = 'Page';
+  SDocMethod = 'Method';
+  SDocProperty = 'Property';
+  SDocAccess = 'Access';
+  SDocInheritance = 'Inheritance';
+  SDocProperties = 'Properties';
+  SDocMethods = 'Methods';
+  SDocEvents = 'Events';
+  SDocByName = 'by Name';
+  SDocValue = 'Value';
+  SDocExplanation = 'Explanation';
+  SDocValuesForEnum = 'Enumeration values for type %s';
+
+type
+
+  // Assumes a list of TObject instances and frees them on destruction
+
+  TObjectList = class(TList)
+  public
+    destructor Destroy; override;
+  end;
+
+
+  { Link entry tree
+    TFPDocEngine stores the root of the entry tree in its property
+    "RootLinkNode". The root has one child node for each package, for which
+    documentation links are available. The children of a package node
+    are module nodes; and the children of a module node are the top-level
+    declarations of this module; the next level in the tree stores e.g. record
+    members, and so on...
+  }
+
+  TLinkNode = class
+  private
+    FFirstChild, FNextSibling: TLinkNode;
+    FName: String;
+    FLink: String;
+  public
+    constructor Create(const AName, ALink: String);
+    destructor Destroy; override;
+    function FindChild(const APathName: String): TLinkNode;
+    function CreateChildren(const APathName, ALinkTo: String): TLinkNode;
+    // Properties for tree structure
+    property FirstChild: TLinkNode read FFirstChild;
+    property NextSibling: TLinkNode read FNextSibling;
+    // Link properties
+    property Name: String read FName;
+    property Link: String read FLink;
+  end;
+
+
+  { Documentation entry tree
+    TFPDocEngine stores the root of the entry tree in its property
+    "RootDocNode". The root has one child node for each package, for which
+    documentation is being provided by the user. The children of a package node
+    are module nodes; and the children of a module node are the top-level
+    declarations of this module; the next level in the tree stores e.g. record
+    members, and so on...
+  }
+
+  TDocNode = class
+  private
+    FFirstChild, FNextSibling: TDocNode;
+    FName: String;
+    FNode: TDOMElement;
+    FIsSkipped: Boolean;
+    FShortDescr: TDOMElement;
+    FDescr: TDOMElement;
+    FErrorsDoc: TDOMElement;
+    FSeeAlso: TDOMElement;
+    FFirstExample: TDOMElement;
+    FLink: String;
+  public
+    constructor Create(const AName: String; ANode: TDOMElement);
+    destructor Destroy; override;
+    function FindChild(const APathName: String): TDocNode;
+    function CreateChildren(const APathName: String): TDocNode;
+    // Properties for tree structure
+    property FirstChild: TDocNode read FFirstChild;
+    property NextSibling: TDocNode read FNextSibling;
+    // Basic properties
+    property Name: String read FName;
+    property Node: TDOMElement read FNode;
+    // Data fetched from the XML document
+    property IsSkipped: Boolean read FIsSkipped;
+    property ShortDescr: TDOMElement read FShortDescr;
+    property Descr: TDOMElement read FDescr;
+    property ErrorsDoc: TDOMElement read FErrorsDoc;
+    property SeeAlso: TDOMElement read FSeeAlso;
+    property FirstExample: TDOMElement read FFirstExample;
+    property Link: String read FLink;
+  end;
+
+
+  // The main FPDoc engine
+
+  TFPDocEngine = class(TPasTreeContainer)
+  protected
+    DescrDocs: TObjectList;		// List of XML documents
+    DescrDocNames: TStringList;		// Names of the XML documents
+    FRootLinkNode: TLinkNode;
+    FRootDocNode: TDocNode;
+    FPackages: TList;			// List of TFPPackage objects
+    CurModule: TPasModule;
+    CurPackageDocNode: TDocNode;
+  public
+    constructor Create;
+    destructor Destroy; override;
+    procedure SetPackageName(const APackageName: String);
+    procedure ReadContentFile(const AFilename, ALinkPrefix: String);
+    procedure WriteContentFile(const AFilename: String);
+
+    function CreateElement(AClass: TPTreeElement; const AName: String;
+      AParent: TPasElement; AVisibility: TPasMemberVisibility): TPasElement;
+      override;
+    function FindElement(const AName: String): TPasElement; override;
+    function FindModule(const AName: String): TPasModule; override;
+
+    // Link tree support
+    procedure AddLink(const APathName, ALinkTo: String);
+    function FindAbsoluteLink(const AName: String): String;
+    function ResolveLink(AModule: TPasModule; const ALinkDest: String): String;
+
+    // Documentation file support
+    procedure AddDocFile(const AFilename: String);
+
+    // Documentation retrieval
+    function FindDocNode(AElement: TPasElement): TDocNode;
+    function FindDocNode(ARefModule: TPasModule; const AName: String): TDocNode;
+    function FindShortDescr(AElement: TPasElement): TDOMElement;
+    function FindShortDescr(ARefModule: TPasModule;
+      const AName: String): TDOMElement;
+    function GetExampleFilename(const ExElement: TDOMElement): String;
+
+    property RootLinkNode: TLinkNode read FRootLinkNode;
+    property RootDocNode: TDocNode read FRootDocNode;
+    property Package: TPasPackage read FPackage;
+
+    Output: String;
+    HasContentFile: Boolean;
+    HidePrivate: Boolean;	// Hide private class members in output?
+    HideProtected: Boolean;	// Hide protected class members in output?
+  end;
+
+
+procedure TranslateDocStrings(const Lang: String);
+
+
+
+implementation
+
+uses SysUtils, Gettext, XMLRead;
+
+
+{ TObjectList }
+
+destructor TObjectList.Destroy;
+var
+  i: Integer;
+begin
+  for i := 0 to Count - 1 do
+    TObject(Items[i]).Free;
+  inherited Destroy;
+end;
+
+
+{ TLinkNode }
+
+constructor TLinkNode.Create(const AName, ALink: String);
+begin
+  inherited Create;
+  FName := AName;
+  FLink := ALink;
+end;
+
+destructor TLinkNode.Destroy;
+begin
+  if Assigned(FirstChild) then
+    FirstChild.Free;
+  if Assigned(NextSibling) then
+    NextSibling.Free;
+  inherited Destroy;
+end;
+
+function TLinkNode.FindChild(const APathName: String): TLinkNode;
+var
+  DotPos: Integer;
+  ChildName: String;
+  Child: TLinkNode;
+begin
+  if Length(APathName) = 0 then
+    Result := Self
+  else
+  begin
+    DotPos := Pos('.', APathName);
+    if DotPos = 0 then
+      ChildName := APathName
+    else
+      ChildName := Copy(APathName, 1, DotPos - 1);
+    Child := FirstChild;
+    while Assigned(Child) do
+    begin
+      if CompareText(Child.Name, ChildName) = 0 then
+      begin
+        if DotPos = 0 then
+	  Result := Child
+	else
+          Result := Child.FindChild(
+	    Copy(APathName, DotPos + 1, Length(APathName)));
+	exit;
+      end;
+      Child := Child.NextSibling;
+    end;
+    Result := nil;
+  end;
+end;
+
+function TLinkNode.CreateChildren(const APathName, ALinkTo: String): TLinkNode;
+var
+  DotPos: Integer;
+  ChildName: String;
+  Child, LastChild: TLinkNode;
+begin
+  if Length(APathName) = 0 then
+    Result := Self
+  else
+  begin
+    DotPos := Pos('.', APathName);
+    if DotPos = 0 then
+      ChildName := APathName
+    else
+      ChildName := Copy(APathName, 1, DotPos - 1);
+    Child := FirstChild;
+    LastChild := nil;
+    while Assigned(Child) do
+    begin
+      if CompareText(Child.Name, ChildName) = 0 then
+      begin
+        if DotPos = 0 then
+	  Result := Child
+	else
+          Result := Child.CreateChildren(
+	    Copy(APathName, DotPos + 1, Length(APathName)), ALinkTo);
+	exit;
+      end;
+      LastChild := Child;
+      Child := Child.NextSibling;
+    end;
+    { No child found, let's create one if we are at the end of the path }
+    if DotPos > 0 then
+      // !!!: better throw an exception
+      WriteLn('Link path does not exist: ', APathName);
+    Result := TLinkNode.Create(ChildName, ALinkTo);
+    if Assigned(LastChild) then
+      LastChild.FNextSibling := Result
+    else
+      FFirstChild := Result;
+  end;
+end;
+
+
+{ TDocNode }
+
+constructor TDocNode.Create(const AName: String; ANode: TDOMElement);
+begin
+  inherited Create;
+  FName := AName;
+  FNode := ANode;
+end;
+
+destructor TDocNode.Destroy;
+begin
+  if Assigned(FirstChild) then
+    FirstChild.Free;
+  if Assigned(NextSibling) then
+    NextSibling.Free;
+  inherited Destroy;
+end;
+
+function TDocNode.FindChild(const APathName: String): TDocNode;
+var
+  DotPos: Integer;
+  ChildName: String;
+  Child: TDocNode;
+begin
+  if Length(APathName) = 0 then
+    Result := Self
+  else
+  begin
+    DotPos := Pos('.', APathName);
+    if DotPos = 0 then
+      ChildName := APathName
+    else
+      ChildName := Copy(APathName, 1, DotPos - 1);
+    Child := FirstChild;
+    while Assigned(Child) do
+    begin
+      if CompareText(Child.Name, ChildName) = 0 then
+      begin
+        if DotPos = 0 then
+	  Result := Child
+	else
+          Result := Child.FindChild(
+	    Copy(APathName, DotPos + 1, Length(APathName)));
+	exit;
+      end;
+      Child := Child.NextSibling;
+    end;
+    Result := nil;
+  end;
+end;
+
+function TDocNode.CreateChildren(const APathName: String): TDocNode;
+var
+  DotPos: Integer;
+  ChildName: String;
+  Child: TDocNode;
+begin
+  if Length(APathName) = 0 then
+    Result := Self
+  else
+  begin
+    DotPos := Pos('.', APathName);
+    if DotPos = 0 then
+      ChildName := APathName
+    else
+      ChildName := Copy(APathName, 1, DotPos - 1);
+    Child := FirstChild;
+    while Assigned(Child) do
+    begin
+      if CompareText(Child.Name, ChildName) = 0 then
+      begin
+        if DotPos = 0 then
+	  Result := Child
+	else
+          Result := Child.CreateChildren(
+	    Copy(APathName, DotPos + 1, Length(APathName)));
+	exit;
+      end;
+      Child := Child.NextSibling;
+    end;
+    // No child found, let's create one
+    Result := TDocNode.Create(ChildName, nil);
+    if Assigned(FirstChild) then
+    begin
+      Result.FNextSibling := FirstChild;
+      FFirstChild := Result;
+    end else
+      FFirstChild := Result;
+
+    if DotPos > 0 then
+      Result := Result.CreateChildren(
+        Copy(APathName, DotPos + 1, Length(APathName)));
+  end;
+end;
+
+
+{ TFPDocEngine }
+
+constructor TFPDocEngine.Create;
+begin
+  inherited Create;
+  DescrDocs := TObjectList.Create;
+  DescrDocNames := TStringList.Create;
+  FRootLinkNode := TLinkNode.Create('', '');
+  FRootDocNode := TDocNode.Create('', nil);
+  HidePrivate := True;
+  FPackages := TList.Create;
+end;
+
+destructor TFPDocEngine.Destroy;
+var
+  i: Integer;
+begin
+  for i := 0 to FPackages.Count - 1 do
+    TPasPackage(FPackages[i]).Release;
+  FPackages.Free;
+  FRootDocNode.Free;
+  FRootLinkNode.Free;
+  DescrDocNames.Free;
+  DescrDocs.Free;
+  inherited Destroy;
+end;
+
+procedure TFPDocEngine.SetPackageName(const APackageName: String);
+begin
+  ASSERT(not Assigned(Package));
+  FPackage := TPasPackage(inherited CreateElement(TPasPackage, '#' + APackageName, nil));
+  FPackages.Add(FPackage);
+  CurPackageDocNode := RootDocNode.FindChild('#' + APackageName);
+end;
+
+procedure TFPDocEngine.ReadContentFile(const AFilename, ALinkPrefix: String);
+var
+  f: Text;
+
+  procedure ReadLinkTree;
+  var
+    s: String;
+    PrevSpaces, ThisSpaces, i, StackIndex: Integer;
+    CurParent, PrevSibling, NewNode: TLinkNode;
+    ParentStack, SiblingStack: array[0..7] of TLinkNode;
+  begin
+    PrevSpaces := 0;
+    CurParent := RootLinkNode;
+    PrevSibling := nil;
+    StackIndex := 0;
+    while True do
+    begin
+      ReadLn(f, s);
+      if Length(s) = 0 then
+        break;
+      ThisSpaces := 0;
+      while s[ThisSpaces + 1] = ' ' do
+        Inc(ThisSpaces);
+      if ThisSpaces <> PrevSpaces then
+      begin
+        if ThisSpaces > PrevSpaces then
+	begin
+	  { Dive down one level }
+	  ParentStack[StackIndex] := CurParent;
+	  SiblingStack[StackIndex] := PrevSibling;
+	  Inc(StackIndex);
+          CurParent := PrevSibling;
+	  PrevSibling := nil;
+	end else
+	  while PrevSpaces > ThisSpaces do
+	  begin
+	    Dec(StackIndex);
+	    CurParent := ParentStack[StackIndex];
+	    PrevSibling := SiblingStack[StackIndex];
+	    Dec(PrevSpaces);
+	  end;
+	PrevSpaces := ThisSpaces;
+      end;
+
+      i := ThisSpaces + 1;
+      while s[i] <> ' ' do
+        Inc(i);
+      NewNode := TLinkNode.Create(Copy(s, ThisSpaces + 1, i - ThisSpaces - 1),
+        ALinkPrefix + Copy(s, i + 1, Length(s)));
+      if Assigned(PrevSibling) then
+        PrevSibling.FNextSibling := NewNode
+      else
+        CurParent.FFirstChild := NewNode;
+      PrevSibling := NewNode;
+    end;
+  end;
+
+  procedure ReadClasses;
+
+    function CreateClass(const AName: String): TPasClassType;
+    var
+      DotPos, DotPos2, i: Integer;
+      s: String;
+      Package: TPasPackage;
+      Module: TPasModule;
+    begin
+      // Find or create package
+      DotPos := Pos('.', AName);
+      s := Copy(AName, 1, DotPos - 1);
+      Package := nil;
+      for i := 0 to FPackages.Count - 1 do
+        if CompareText(TPasPackage(FPackages[i]).Name, s) = 0 then
+	begin
+	  Package := TPasPackage(FPackages[i]);
+	  break;
+	end;
+      if not Assigned(Package) then
+      begin
+        Package := TPasPackage(inherited CreateElement(TPasPackage, s, nil));
+        FPackages.Add(Package);
+      end;
+
+      // Find or create module
+      DotPos2 := DotPos;
+      repeat
+        Inc(DotPos2);
+      until AName[DotPos2] = '.';
+      s := Copy(AName, DotPos + 1, DotPos2 - DotPos - 1);
+      Module := nil;
+      for i := 0 to Package.Modules.Count - 1 do
+        if CompareText(TPasModule(Package.Modules[i]).Name, s) = 0 then
+	begin
+	  Module := TPasModule(Package.Modules[i]);
+	  break;
+	end;
+      if not Assigned(Module) then
+      begin
+	Module := TPasModule.Create(s, Package);
+	Module.InterfaceSection := TPasSection.Create('', Module);
+	Package.Modules.Add(Module);
+      end;
+
+      // Create node for class
+      Result := TPasClassType.Create(Copy(AName, DotPos2 + 1, Length(AName)),
+        Module.InterfaceSection);
+      Result.ObjKind := okClass;
+      Module.InterfaceSection.Declarations.Add(Result);
+      Module.InterfaceSection.Classes.Add(Result);
+    end;
+
+  var
+    s, Name: String;
+    CurClass: TPasClassType;
+    i: Integer;
+    Member: TPasElement;
+  begin
+    CurClass := nil;
+    while True do
+    begin
+      ReadLn(f, s);
+      if Length(s) = 0 then
+        break;
+      if s[1] = '#' then
+      begin
+        // New class
+	i := Pos(' ', s);
+	CurClass := CreateClass(Copy(s, 1, i - 1));
+      end else
+      begin
+        i := Pos(' ', s);
+	if i = 0 then
+          Name := Copy(s, 3, Length(s))
+	else
+	  Name := Copy(s, 3, i - 3);
+
+        case s[2] of
+	  'M':
+	    Member := TPasProcedure.Create(Name, CurClass);
+	  'P':
+	    begin
+	      Member := TPasProperty.Create(Name, CurClass);
+	      if i > 0 then
+	        while i <= Length(s) do
+		begin
+		  case s[i] of
+		    'r':
+		      TPasProperty(Member).ReadAccessorName := '<dummy>';
+		    'w':
+		      TPasProperty(Member).WriteAccessorName := '<dummy>';
+		    's':
+		      TPasProperty(Member).StoredAccessorName := '<dummy>';
+		  end;
+		  Inc(i);
+		end;
+	    end;
+	  'V':
+	    Member := TPasVariable.Create(Name, CurClass);
+	  else
+	    raise Exception.Create('Invalid member type: ' + s[2]);
+	end;
+	CurClass.Members.Add(Member);
+      end;
+    end;
+  end;
+
+var
+  s: String;
+begin
+  Assign(f, AFilename);
+  Reset(f);
+  while not EOF(f) do
+  begin
+    ReadLn(f, s);
+    if (Length(s) = 0) or (s[1] = '#') then
+      continue;
+    if s = ':link tree' then
+      ReadLinkTree
+    else if s = ':classes' then
+      ReadClasses
+    else
+      repeat
+        ReadLn(f, s);
+      until EOF(f) or (Length(s) = 0);
+  end;
+  Close(f);
+end;
+
+procedure TFPDocEngine.WriteContentFile(const AFilename: String);
+var
+  ContentFile: Text;
+
+  procedure ProcessLinkNode(ALinkNode: TLinkNode; const AIdent: String);
+  var
+    ChildNode: TLinkNode;
+  begin
+    WriteLn(ContentFile, AIdent, ALinkNode.Name, ' ', ALinkNode.Link);
+    ChildNode := ALinkNode.FirstChild;
+    while Assigned(ChildNode) do
+    begin
+      ProcessLinkNode(ChildNode, AIdent + ' ');
+      ChildNode := ChildNode.NextSibling;
+    end;
+  end;
+
+var
+  LinkNode: TLinkNode;
+  i, j, k: Integer;
+  Module: TPasModule;
+  ClassDecl: TPasClassType;
+  Member: TPasElement;
+  s: String;
+begin
+  Assign(ContentFile, AFilename);
+  Rewrite(ContentFile);
+  try
+    WriteLn(ContentFile, '# FPDoc Content File');
+    WriteLn(ContentFile, ':link tree');
+    LinkNode := RootLinkNode.FirstChild;
+    while Assigned(LinkNode) do
+    begin
+      if LinkNode.Name = Package.Name then
+      begin
+        ProcessLinkNode(LinkNode, '');
+      end;
+      LinkNode := LinkNode.NextSibling;
+    end;
+
+  if Assigned(Package) then
+  begin
+    WriteLn(ContentFile);
+    WriteLn(ContentFile, ':classes');
+    for i := 0 to Package.Modules.Count - 1 do
+    begin
+      Module := TPasModule(Package.Modules[i]);
+      for j := 0 to Module.InterfaceSection.Classes.Count - 1 do
+      begin
+        ClassDecl := TPasClassType(Module.InterfaceSection.Classes[j]);
+        Write(ContentFile, ClassDecl.PathName, ' ');
+        if Assigned(ClassDecl.AncestorType) then
+          WriteLn(ContentFile, ClassDecl.AncestorType.PathName)
+        else if ClassDecl.ObjKind = okClass then
+          WriteLn(ContentFile, '.TObject');
+	for k := 0 to ClassDecl.Members.Count - 1 do
+	begin
+	  Member := TPasElement(ClassDecl.Members[k]);
+	  Write(ContentFile, Chr(Ord(Member.Visibility) + Ord('0')));
+	  SetLength(s, 0);
+	  if Member.ClassType = TPasVariable then
+	    Write(ContentFile, 'V')
+	  else if Member.ClassType = TPasProperty then
+	  begin
+	    Write(ContentFile, 'P');
+	    if Length(TPasProperty(Member).ReadAccessorName) > 0 then
+	      s := s + 'r';
+	    if Length(TPasProperty(Member).WriteAccessorName) > 0 then
+	      s := s + 'w';
+	    if Length(TPasProperty(Member).StoredAccessorName) > 0 then
+	      s := s + 's';
+	  end else
+	    Write(ContentFile, 'M');	// Member must be a method
+	  Write(ContentFile, Member.Name);
+	  if Length(s) > 0 then
+	    WriteLn(ContentFile, ' ', s)
+	  else
+	    WriteLn(ContentFile);
+	end;
+      end;
+    end;
+  end;
+
+
+  finally
+    Close(ContentFile);
+  end;
+end;
+
+function TFPDocEngine.CreateElement(AClass: TPTreeElement; const AName: String;
+  AParent: TPasElement; AVisibility: TPasMemberVisibility): TPasElement;
+begin
+  Result := AClass.Create(AName, AParent);
+  Result.Visibility := AVisibility;
+  if AClass.InheritsFrom(TPasModule) then
+    CurModule := TPasModule(Result);
+end;
+
+function TFPDocEngine.FindElement(const AName: String): TPasElement;
+
+  function FindInModule(AModule: TPasModule; const LocalName: String): TPasElement;
+  var
+    l: TList;
+    i: Integer;
+  begin
+    l := AModule.InterfaceSection.Declarations;
+    for i := 0 to l.Count - 1 do
+    begin
+      Result := TPasElement(l[i]);
+      if CompareText(Result.Name, LocalName) = 0 then
+        exit;
+    end;
+    Result := nil;
+ end;
+
+var
+  i: Integer;
+  //ModuleName, LocalName: String;
+  Module: TPasElement;
+begin
+{!!!: Don't know if we ever will have to use the following:
+  i := Pos('.', AName);
+  if i <> 0 then
+  begin
+    WriteLn('Dot found in name: ', AName);
+    Result := nil;
+  end else
+  begin}
+    Result := FindInModule(CurModule, AName);
+    if not Assigned(Result) then
+      for i := CurModule.InterfaceSection.UsesList.Count - 1 downto 0 do
+      begin
+        Module := TPasElement(CurModule.InterfaceSection.UsesList[i]);
+	if Module.ClassType = TPasModule then
+	begin
+          Result := FindInModule(TPasModule(Module), AName);
+	  if Assigned(Result) then
+	    exit;
+	end;
+      end;
+  {end;}
+end;
+
+function TFPDocEngine.FindModule(const AName: String): TPasModule;
+
+  function FindInPackage(APackage: TPasPackage): TPasModule;
+  var
+    i: Integer;
+  begin
+    for i := 0 to APackage.Modules.Count - 1 do
+    begin
+      Result := TPasModule(APackage.Modules[i]);
+      if CompareText(Result.Name, AName) = 0 then
+        exit;
+    end;
+    Result := nil;
+  end;
+
+var
+  i: Integer;
+begin
+  Result := FindInPackage(Package);
+  if not Assigned(Result) then
+    for i := FPackages.Count - 1 downto 0 do
+    begin
+      if TPasPackage(FPackages[i]) = Package then
+        continue;
+      Result := FindInPackage(TPasPackage(FPackages[i]));
+      if Assigned(Result) then
+        exit;
+    end;
+end;
+
+procedure TFPDocEngine.AddLink(const APathName, ALinkTo: String);
+begin
+  RootLinkNode.CreateChildren(APathName, ALinkTo);
+end;
+
+function TFPDocEngine.FindAbsoluteLink(const AName: String): String;
+var
+  LinkNode: TLinkNode;
+begin
+  LinkNode := RootLinkNode.FindChild(AName);
+  if Assigned(LinkNode) then
+    Result := LinkNode.Link
+  else
+    SetLength(Result, 0);
+end;
+
+function TFPDocEngine.ResolveLink(AModule: TPasModule;
+  const ALinkDest: String): String;
+var
+  i: Integer;
+  ThisPackage: TLinkNode;
+  UnitList: TList;
+begin
+//WriteLn('ResolveLink(', ALinkDest, ')... ');
+  if Length(ALinkDest) = 0 then
+  begin
+    SetLength(Result, 0);
+    exit;
+  end;
+
+  if ALinkDest[1] = '#' then
+    Result := FindAbsoluteLink(ALinkDest)
+  else
+  begin
+    Result := ResolveLink(AModule, AModule.PathName + '.' + ALinkDest);
+    if Length(Result) > 0 then
+      exit;
+
+    { Try all packages }
+    SetLength(Result, 0);
+    ThisPackage := RootLinkNode.FirstChild;
+    while Assigned(ThisPackage) do
+    begin
+      Result := ResolveLink(AModule, ThisPackage.Name + '.' + ALinkDest);
+      if Length(Result) > 0 then
+	exit;
+      ThisPackage := ThisPackage.NextSibling;
+    end;
+
+    if Length(Result) = 0 then
+    begin
+      { Okay, then we have to try all imported units of the current module }
+      UnitList := AModule.InterfaceSection.UsesList;
+      for i := UnitList.Count - 1 downto 0 do
+      begin
+	{ Try all packages }
+	ThisPackage := RootLinkNode.FirstChild;
+	while Assigned(ThisPackage) do
+	begin
+	  Result := ResolveLink(AModule, ThisPackage.Name + '.' +
+	    TPasType(UnitList[i]).Name + '.' + ALinkDest);
+	  if Length(Result) > 0 then
+	    exit;
+	  ThisPackage := ThisPackage.NextSibling;
+	end;
+      end;
+    end;
+  end;
+
+  if Length(Result) = 0 then
+    for i := Length(ALinkDest) downto 1 do
+      if ALinkDest[i] = '.' then
+      begin
+	Result := ResolveLink(AModule, Copy(ALinkDest, 1, i - 1));
+        exit;
+      end;
+end;
+
+procedure TFPDocEngine.AddDocFile(const AFilename: String);
+
+  function ReadNode(OwnerDocNode: TDocNode; Element: TDOMElement): TDocNode;
+  var
+    Subnode: TDOMNode;
+  begin
+    if OwnerDocNode = RootDocNode then
+      Result := OwnerDocNode.CreateChildren('#' + Element['name'])
+    else
+      Result := OwnerDocNode.CreateChildren(Element['name']);
+    Result.FNode := Element;
+    Result.FLink := Element['link'];
+    Result.FIsSkipped := Element['skip'] = '1';
+    Subnode := Element.FirstChild;
+    while Assigned(Subnode) do
+    begin
+      if Subnode.NodeType = ELEMENT_NODE then
+      begin
+	if Subnode.NodeName = 'short' then
+	  Result.FShortDescr := TDOMElement(Subnode)
+	else if Subnode.NodeName = 'descr' then
+	  Result.FDescr := TDOMElement(Subnode)
+	else if Subnode.NodeName = 'errors' then
+	  Result.FErrorsDoc := TDOMElement(Subnode)
+	else if Subnode.NodeName = 'seealso' then
+	  Result.FSeeAlso := TDOMElement(Subnode)
+	else if (Subnode.NodeName = 'example') and
+	  not Assigned(Result.FirstExample) then
+	  Result.FFirstExample := TDOMElement(Subnode);
+      end;
+      Subnode := Subnode.NextSibling;
+    end;
+  end;
+
+var
+  i: Integer;
+  Node, Subnode, Subsubnode: TDOMNode;
+  Element: TDOMElement;
+  Doc: TXMLDocument;
+  PackageDocNode, ModuleDocNode: TDocNode;
+begin
+  ReadXMLFile(Doc, AFilename);
+  DescrDocs.Add(Doc);
+  DescrDocNames.Add(AFilename);
+
+  Node := Doc.DocumentElement.FirstChild;
+  while Assigned(Node) do
+  begin
+    if (Node.NodeType = ELEMENT_NODE) and (Node.NodeName = 'package') then
+    begin
+      PackageDocNode := ReadNode(RootDocNode, TDOMElement(Node));
+
+      // Scan all 'module' elements within this package element
+      Subnode := Node.FirstChild;
+      while Assigned(Subnode) do
+      begin
+        if (Subnode.NodeType = ELEMENT_NODE) and
+	  (Subnode.NodeName = 'module') then
+	begin
+	  ModuleDocNode := ReadNode(PackageDocNode, TDOMElement(Subnode));
+
+	  // Scan all 'element' elements within this module element
+	  Subsubnode := Subnode.FirstChild;
+	  while Assigned(Subsubnode) do
+	  begin
+	    if (Subsubnode.NodeType = ELEMENT_NODE) and
+	      (Subsubnode.NodeName = 'element') then
+	      ReadNode(ModuleDocNode, TDOMElement(Subsubnode));
+	    Subsubnode := Subsubnode.NextSibling;
+	  end;
+	end;
+        Subnode := Subnode.NextSibling;
+      end;
+    end;
+    Node := Node.NextSibling;
+  end;
+end;
+
+function TFPDocEngine.FindDocNode(AElement: TPasElement): TDocNode;
+begin
+  if AElement.InheritsFrom(TPasUnresolvedTypeRef) then
+    Result := FindDocNode(AElement.GetModule, AElement.Name)
+  else
+    Result := RootDocNode.FindChild(AElement.PathName);
+end;
+
+function TFPDocEngine.FindDocNode(ARefModule: TPasModule;
+  const AName: String): TDocNode;
+var
+  CurPackage: TDocNode;
+  UnitList: TList;
+  i: Integer;
+begin
+  if Length(AName) = 0 then
+    Result := nil
+  else
+  begin
+    if AName[1] = '#' then
+      Result := RootDocNode.FindChild(AName)
+    else
+      Result := RootDocNode.FindChild(Package.Name + '.' + AName);
+    if (not Assigned(Result)) and Assigned(ARefModule) then
+      Result := RootDocNode.FindChild(ARefModule.PathName + '.' + AName);
+
+    if (not Assigned(Result)) and (AName[1] <> '#') then
+    begin
+      CurPackage := RootDocNode.FirstChild;
+      while Assigned(CurPackage) do
+      begin
+	Result := RootDocNode.FindChild(CurPackage.Name + '.' + AName);
+	if Assigned(Result) then
+	  break;
+	CurPackage := CurPackage.NextSibling;
+      end;
+      if not Assigned(Result) then
+      begin
+        { Okay, then we have to try all imported units of the current module }
+        UnitList := CurModule.InterfaceSection.UsesList;
+        for i := UnitList.Count - 1 downto 0 do
+        begin
+          { Try all packages }
+	  CurPackage := RootDocNode.FirstChild;
+	  while Assigned(CurPackage) do
+	  begin
+	    Result := RootDocNode.FindChild(CurPackage.Name + '.' +
+	      TPasType(UnitList[i]).Name + '.' + AName);
+	    if Assigned(Result) then
+	      break;
+	    CurPackage := CurPackage.NextSibling;
+	  end;
+	end;
+      end;
+    end;
+  end;
+end;
+
+function TFPDocEngine.FindShortDescr(AElement: TPasElement): TDOMElement;
+var
+  DocNode: TDocNode;
+begin
+  DocNode := FindDocNode(AElement);
+  if Assigned(DocNode) then
+    Result := DocNode.ShortDescr
+  else
+    Result := nil;
+end;
+
+function TFPDocEngine.FindShortDescr(ARefModule: TPasModule;
+  const AName: String): TDOMElement;
+var
+  DocNode: TDocNode;
+begin
+  DocNode := FindDocNode(ARefModule, AName);
+  if Assigned(DocNode) then
+    Result := DocNode.ShortDescr
+  else
+    Result := nil;
+end;
+
+function TFPDocEngine.GetExampleFilename(const ExElement: TDOMElement): String;
+var
+  i: Integer;
+begin
+  for i := 0 to DescrDocs.Count - 1 do
+    if TDOMDocument(DescrDocs[i]) = ExElement.OwnerDocument then
+    begin
+      Result := ExtractFilePath(DescrDocNames[i]) + ExElement['file'];
+      exit;
+    end;
+  SetLength(Result, 0);
+end;
+
+
+{ Global helpers }
+
+procedure TranslateDocStrings(const Lang: String);
+var
+  mo: TMOFile;
+begin
+{$IFDEF Unix}
+  mo := TMOFile.Create(Format('/usr/local/share/locale/%s/LC_MESSAGES/dglobals.mo', [Lang]));
+{$ELSE}
+  mo := TMOFile.Create(Format('intl/dglobals.%s.mo', [Lang]));
+{$ENDIF}
+  try
+    TranslateResourceStrings(mo);
+  finally
+    mo.Free;
+  end;
+end;
+
+
+
+end.
+
+
+{
+  $Log$
+  Revision 1.1  2003-03-17 23:03:20  michael
+  + Initial import in CVS
+
+  Revision 1.13  2003/03/13 22:02:13  sg
+  * New version with many bugfixes and our own parser (now independent of the
+    compiler source)
+
+  Revision 1.12  2002/11/15 19:44:18  sg
+  * Cosmetic changes
+
+  Revision 1.11  2002/10/12 17:00:45  michael
+  + Changes to be able to disable private/protected nodes in skeleton
+
+  Revision 1.10  2002/05/24 00:13:22  sg
+  * much improved new version, including many linking and output fixes
+
+  Revision 1.9  2002/03/25 23:16:24  sg
+  * fixed missing storing of documenation data for the DocNode of a module
+    (so e.g. the Unit Overview is working again)
+
+  Revision 1.8  2002/03/12 10:58:35  sg
+  * reworked linking engine and internal structure
+
+  Revision 1.7  2002/01/20 11:19:55  michael
+  + Added link attribute and property to TFPelement
+
+  Revision 1.6  2001/12/17 22:16:02  sg
+  * Added TFPDocEngine.HideProtected
+}

+ 2610 - 0
utils/fpdoc/dw_html.pp

@@ -0,0 +1,2610 @@
+{
+    $Id$
+
+    FPDoc  -  Free Pascal Documentation Tool
+    Copyright (C) 2000 - 2003 by
+      Areca Systems GmbH / Sebastian Guenther, [email protected]
+
+    * HTML/XHTML output generator
+
+    See the file COPYING, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+}
+
+
+unit dw_HTML;
+
+interface
+
+uses Classes, DOM, DOM_HTML, dGlobals, PasTree, dWriter;
+
+const
+  // Subpage indices for modules
+  ResstrSubindex = 1;
+  ConstsSubindex = 2;
+  TypesSubindex = 3;
+  ClassesSubindex = 4;
+  ProcsSubindex = 5;
+  VarsSubindex = 6;
+
+  // Subpage indices for classes
+  PropertiesByInheritanceSubindex = 1;
+  PropertiesByNameSubindex = 2;
+  MethodsByInheritanceSubindex = 3;
+  MethodsByNameSubindex = 4;
+  EventsByInheritanceSubindex = 5;
+  EventsByNameSubindex = 6;
+
+type
+
+  TFileAllocator = class
+  public
+    procedure AllocFilename(AElement: TPasElement; ASubindex: Integer); virtual;
+    function GetFilename(AElement: TPasElement;
+      ASubindex: Integer): String; virtual; abstract;
+    function GetRelativePathToTop(AElement: TPasElement): String; virtual;
+    function GetCSSFilename(ARelativeTo: TPasElement): DOMString; virtual;
+  end;
+
+  TShortNameFileAllocator = class(TFileAllocator)
+  private
+    FExtension: String;
+  public
+    constructor Create(const AExtension: String);
+    procedure AllocFilename(AElement: TPasElement; ASubindex: Integer); override;
+    property Extension: String read FExtension;
+  end;
+
+  TLongNameFileAllocator = class(TFileAllocator)
+  private
+    FExtension: String;
+  public
+    constructor Create(const AExtension: String);
+    function GetFilename(AElement: TPasElement;
+      ASubindex: Integer): String; override;
+    function GetRelativePathToTop(AElement: TPasElement): String; override;
+    property Extension: String read FExtension;
+  end;
+
+
+  TPageInfo = class
+    Element: TPasElement;
+    SubpageIndex: Integer;
+  end;
+
+
+  THTMLWriter = class(TFPDocWriter)
+  private
+    FAllocator: TFileAllocator;
+    FPackage: TPasPackage;
+    function GetPageCount: Integer;
+  protected
+    CurDirectory: String;	// relative to curdir of process
+    BaseDirectory: String;	// relative path to package base directory
+    PageInfos: TObjectList;	// list of TPageInfo objects
+
+    Doc: THTMLDocument;
+    BodyElement, TitleElement: TDOMElement;
+
+    Module: TPasModule;
+
+    OutputNodeStack: TList;
+    CurOutputNode: TDOMNode;
+    InsideHeadRow, DoPasHighlighting: Boolean;
+    HighlighterFlags: Byte;
+
+    function ResolveLinkID(const Name: String): DOMString;
+    function ResolveLinkWithinPackage(AElement: TPasElement;
+      ASubpageIndex: Integer): String;
+
+    // Helper functions for creating DOM elements
+    function CreateEl(Parent: TDOMNode; const AName: DOMString): THTMLElement;
+    function CreatePara(Parent: TDOMNode): THTMLElement;
+    function CreateH1(Parent: TDOMNode): THTMLElement;
+    function CreateH2(Parent: TDOMNode): THTMLElement;
+    function CreateH3(Parent: TDOMNode): THTMLElement;
+    function CreateTable(Parent: TDOMNode): THTMLElement;
+    function CreateContentTable(Parent: TDOMNode): THTMLElement;
+    function CreateTR(Parent: TDOMNode): THTMLElement;
+    function CreateTD(Parent: TDOMNode): THTMLElement;
+    function CreateTD_vtop(Parent: TDOMNode): THTMLElement;
+    function CreateLink(Parent: TDOMNode; const AHRef: DOMString): THTMLElement;
+    function CreateAnchor(Parent: TDOMNode; const AName: DOMString): THTMLElement;
+    function CreateCode(Parent: TDOMNode): THTMLElement;
+    function CreateWarning(Parent: TDOMNode): THTMLElement;
+
+    // Description node conversion
+    procedure PushOutputNode(ANode: TDOMNode);
+    procedure PopOutputNode;
+    procedure DescrWriteText(const AText: DOMString); override;
+    procedure DescrBeginBold; override;
+    procedure DescrEndBold; override;
+    procedure DescrBeginItalic; override;
+    procedure DescrEndItalic; override;
+    procedure DescrBeginEmph; override;
+    procedure DescrEndEmph; override;
+    procedure DescrWriteFileEl(const AText: DOMString); override;
+    procedure DescrWriteKeywordEl(const AText: DOMString); override;
+    procedure DescrWriteVarEl(const AText: DOMString); override;
+    procedure DescrBeginLink(const AId: DOMString); override;
+    procedure DescrEndLink; override;
+    procedure DescrWriteLinebreak; override;
+    procedure DescrBeginParagraph; override;
+    procedure DescrEndParagraph; override;
+    procedure DescrBeginCode(HasBorder: Boolean; const AHighlighterName: String); override;
+    procedure DescrWriteCodeLine(const ALine: String); override;
+    procedure DescrEndCode; override;
+    procedure DescrBeginOrderedList; override;
+    procedure DescrEndOrderedList; override;
+    procedure DescrBeginUnorderedList; override;
+    procedure DescrEndUnorderedList; override;
+    procedure DescrBeginDefinitionList; override;
+    procedure DescrEndDefinitionList; override;
+    procedure DescrBeginListItem; override;
+    procedure DescrEndListItem; override;
+    procedure DescrBeginDefinitionTerm; override;
+    procedure DescrEndDefinitionTerm; override;
+    procedure DescrBeginDefinitionEntry; override;
+    procedure DescrEndDefinitionEntry; override;
+    procedure DescrBeginSectionTitle; override;
+    procedure DescrBeginSectionBody; override;
+    procedure DescrEndSection; override;
+    procedure DescrBeginRemark; override;
+    procedure DescrEndRemark; override;
+    procedure DescrBeginTable(ColCount: Integer; HasBorder: Boolean); override;
+    procedure DescrEndTable; override;
+    procedure DescrBeginTableCaption; override;
+    procedure DescrEndTableCaption; override;
+    procedure DescrBeginTableHeadRow; override;
+    procedure DescrEndTableHeadRow; override;
+    procedure DescrBeginTableRow; override;
+    procedure DescrEndTableRow; override;
+    procedure DescrBeginTableCell; override;
+    procedure DescrEndTableCell; override;
+
+
+    procedure AppendText(Parent: TDOMNode; const AText: DOMString);
+    procedure AppendNbSp(Parent: TDOMNode; ACount: Integer);
+    procedure AppendSym(Parent: TDOMNode; const AText: DOMString);
+    procedure AppendKw(Parent: TDOMNode; const AText: DOMString);
+    function AppendPasSHFragment(Parent: TDOMNode; const AText: String;
+      AShFlags: Byte): Byte;
+    procedure AppendShortDescr(Parent: TDOMNode; Element: TPasElement);
+    procedure AppendDescr(AContext: TPasElement; Parent: TDOMNode;
+      DescrNode: TDOMElement; AutoInsertBlock: Boolean);
+    procedure AppendDescrSection(AContext: TPasElement; Parent: TDOMNode;
+      DescrNode: TDOMElement; const ATitle: DOMString);
+    procedure AppendShortDescrCell(Parent: TDOMNode; Element: TPasElement);
+    function AppendHyperlink(Parent: TDOMNode; Element: TPasElement): TDOMElement;
+    function AppendType(CodeEl, TableEl: TDOMElement;
+      Element: TPasType; Expanded: Boolean): TDOMElement;
+    function AppendProcType(CodeEl, TableEl: TDOMElement;
+      Element: TPasProcedureType; Indent: Integer): TDOMElement;
+    procedure AppendProcExt(CodeEl: TDOMElement; Element: TPasProcedure);
+    procedure AppendProcDecl(CodeEl, TableEl: TDOMElement;
+      Element: TPasProcedureBase);
+    procedure AppendProcArgsSection(Parent: TDOMNode;
+      Element: TPasProcedureType);
+
+    procedure AppendTitle(const AText: DOMString);
+    procedure AppendMenuBar(ASubpageIndex: Integer);
+    procedure FinishElementPage(AElement: TPasElement);
+
+    procedure CreatePageBody(AElement: TPasElement; ASubpageIndex: Integer); virtual;
+    procedure CreatePackagePageBody;
+    procedure CreateModulePageBody(AModule: TPasModule; ASubpageIndex: Integer);
+    procedure CreateConstPageBody(AConst: TPasConst);
+    procedure CreateTypePageBody(AType: TPasType);
+    procedure CreateClassPageBody(AClass: TPasClassType; ASubpageIndex: Integer);
+    procedure CreateClassMemberPageBody(AElement: TPasElement);
+    procedure CreateVarPageBody(AVar: TPasVariable);
+    procedure CreateProcPageBody(AProc: TPasProcedureBase);
+  public
+    constructor Create(AEngine: TFPDocEngine; AAllocator: TFileAllocator;
+      APackage: TPasPackage);
+    destructor Destroy; override;
+
+    // Single-page generation
+    function CreateHTMLPage(AElement: TPasElement;
+      ASubpageIndex: Integer): TXMLDocument;
+    function CreateXHTMLPage(AElement: TPasElement;
+      ASubpageIndex: Integer): TXMLDocument;
+
+    // For producing complete package documentation
+    procedure WriteHTMLPages;
+    procedure WriteXHTMLPages;
+
+    SearchPage: String;
+    property Allocator: TFileAllocator read FAllocator;
+    property Package: TPasPackage read FPackage;
+    property PageCount: Integer read GetPageCount;
+
+    property OnTest: TNotifyEvent;
+  end;
+
+
+
+implementation
+
+uses SysUtils, XHTML, XMLWrite, HTMWrite, sh_pas;
+
+
+
+procedure TFileAllocator.AllocFilename(AElement: TPasElement;
+  ASubindex: Integer);
+begin
+end;
+
+function TFileAllocator.GetRelativePathToTop(AElement: TPasElement): String;
+begin
+  SetLength(Result, 0);
+end;
+
+function TFileAllocator.GetCSSFilename(ARelativeTo: TPasElement): DOMString;
+begin
+  Result := GetRelativePathToTop(ARelativeTo) + 'fpdoc.css';
+end;
+
+
+constructor TShortNameFileAllocator.Create(const AExtension: String);
+begin
+  inherited Create;
+  FExtension := AExtension;
+end;
+
+procedure TShortNameFileAllocator.AllocFilename(AElement: TPasElement;
+  ASubindex: Integer);
+begin
+  // !!!: Add element to file list
+end;
+
+
+constructor TLongNameFileAllocator.Create(const AExtension: String);
+begin
+  inherited Create;
+  FExtension := AExtension;
+end;
+
+function TLongNameFileAllocator.GetFilename(AElement: TPasElement;
+  ASubindex: Integer): String;
+var
+  i: Integer;
+begin
+  if AElement.ClassType = TPasPackage then
+    Result := 'index'
+  else if AElement.ClassType = TPasModule then
+    Result := LowerCase(AElement.Name) + PathDelim + 'index'
+  else
+  begin
+    Result := LowerCase(AElement.PathName);
+    i := 1;
+    if Result[1] = '#' then
+    begin
+      while Result[i] <> '.' do
+        Inc(i);
+      Result := Copy(Result, i + 1, Length(Result));
+    end;
+    i := 1;
+    while Result[i] <> '.' do
+      Inc(i);
+    Result[i] := PathDelim;
+  end;
+
+  if ASubindex > 0 then
+    Result := Result + '-' + IntToStr(ASubindex);
+  Result := Result + Extension;
+end;
+
+function TLongNameFileAllocator.GetRelativePathToTop(AElement: TPasElement): String;
+begin
+  if AElement.ClassType = TPasPackage then
+    Result := ''
+  else
+    Result := '../';
+end;
+
+
+
+constructor THTMLWriter.Create(AEngine: TFPDocEngine; AAllocator: TFileAllocator;
+  APackage: TPasPackage);
+
+  procedure AddPage(AElement: TPasElement; ASubpageIndex: Integer);
+  var
+    PageInfo: TPageInfo;
+  begin
+    PageInfo := TPageInfo.Create;
+    PageInfo.Element := AElement;
+    PageInfo.SubpageIndex := ASubpageIndex;
+    PageInfos.Add(PageInfo);
+    Allocator.AllocFilename(AElement, ASubpageIndex);
+    if ASubpageIndex = 0 then
+      Engine.AddLink(AElement.PathName,
+        Allocator.GetFilename(AElement, ASubpageIndex));
+  end;
+
+  procedure AddPages(AElement: TPasElement; ASubpageIndex: Integer;
+    AList: TList);
+  var
+    i: Integer;
+  begin
+    if AList.Count > 0 then
+    begin
+      AddPage(AElement, ASubpageIndex);
+      for i := 0 to AList.Count - 1 do
+        AddPage(TPasElement(AList[i]), 0);
+    end;
+  end;
+
+  procedure ScanModule(AModule: TPasModule);
+  var
+    i, j, k: Integer;
+    s: String;
+    ClassEl: TPasClassType;
+    FPEl, AncestorMemberEl: TPasElement;
+    DocNode: TDocNode;
+    DidAutolink: Boolean;
+  begin
+    AddPage(AModule, 0);
+    with AModule do
+    begin
+      if InterfaceSection.ResStrings.Count > 0 then
+      begin
+        AddPage(AModule, ResstrSubindex);
+	s := Allocator.GetFilename(AModule, ResstrSubindex);
+	for i := 0 to InterfaceSection.ResStrings.Count - 1 do
+	  with TPasResString(InterfaceSection.ResStrings[i]) do
+            Engine.AddLink(PathName, s + '#' + LowerCase(Name));
+      end;
+      AddPages(AModule, ConstsSubindex, InterfaceSection.Consts);
+      AddPages(AModule, TypesSubindex, InterfaceSection.Types);
+      if InterfaceSection.Classes.Count > 0 then
+      begin
+        AddPage(AModule, ClassesSubindex);
+        for i := 0 to InterfaceSection.Classes.Count - 1 do
+	begin
+	  ClassEl := TPasClassType(InterfaceSection.Classes[i]);
+          AddPage(ClassEl, 0);
+	  // !!!: Only add when there are items
+	  AddPage(ClassEl, PropertiesByInheritanceSubindex);
+	  AddPage(ClassEl, PropertiesByNameSubindex);
+	  AddPage(ClassEl, MethodsByInheritanceSubindex);
+	  AddPage(ClassEl, MethodsByNameSubindex);
+	  AddPage(ClassEl, EventsByInheritanceSubindex);
+	  AddPage(ClassEl, EventsByNameSubindex);
+
+          for j := 0 to ClassEl.Members.Count - 1 do
+          begin
+            FPEl := TPasElement(ClassEl.Members[j]);
+            if ((FPEl.Visibility = visPrivate) and Engine.HidePrivate) or
+	      ((FPEl.Visibility = visProtected) and Engine.HideProtected) then
+	      continue;
+
+            DocNode := Engine.FindDocNode(FPEl);
+            if not Assigned(DocNode) then
+            begin
+              DidAutolink := False;
+	      if Assigned(ClassEl.AncestorType) and
+	        (ClassEl.AncestorType.ClassType = TPasClassType) then
+	      begin
+	        for k := 0 to TPasClassType(ClassEl.AncestorType).Members.Count - 1 do
+	        begin
+	          AncestorMemberEl :=
+	            TPasElement(TPasClassType(ClassEl.AncestorType).Members[k]);
+	          if AncestorMemberEl.Name = FPEl.Name then
+	          begin
+	            DocNode := Engine.FindDocNode(AncestorMemberEl);
+	            if Assigned(DocNode) then
+	            begin
+	              DidAutolink := True;
+		      Engine.AddLink(FPEl.PathName,
+	    		Engine.FindAbsoluteLink(AncestorMemberEl.PathName));
+	              break;
+	            end;
+	          end;
+	        end;
+	      end;
+	      if not DidAutolink then
+	        AddPage(FPEl, 0);
+	    end else
+    	      AddPage(FPEl, 0);
+    	  end;
+	end;
+      end;
+      AddPages(AModule, ProcsSubindex, InterfaceSection.Functions);
+      AddPages(AModule, VarsSubindex, InterfaceSection.Variables);
+    end;
+  end;
+
+var
+  i: Integer;
+begin
+  inherited Create(AEngine);
+  FAllocator := AAllocator;
+  FPackage := APackage;
+  OutputNodeStack := TList.Create;
+
+  PageInfos := TObjectList.Create;
+
+  // Allocate page for the package itself, if a name is given (i.e. <> '#')
+  if Length(Package.Name) > 1 then
+    AddPage(Package, 0);
+
+  for i := 0 to Package.Modules.Count - 1 do
+    ScanModule(TPasModule(Package.Modules[i]));
+end;
+
+destructor THTMLWriter.Destroy;
+begin
+  PageInfos.Free;
+  OutputNodeStack.Free;
+  inherited Destroy;
+end;
+
+function THTMLWriter.CreateHTMLPage(AElement: TPasElement;
+  ASubpageIndex: Integer): TXMLDocument;
+var
+  HTMLEl: THTMLHtmlElement;
+  HeadEl: THTMLHeadElement;
+  El: TDOMElement;
+begin
+  Doc := THTMLDocument.Create;
+  Result := Doc;
+  Doc.AppendChild(Doc.CreateProcessingInstruction(
+    'DOCTYPE', 'HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"'));
+
+  HTMLEl := Doc.CreateHtmlElement;
+  Doc.AppendChild(HTMLEl);
+
+  HeadEl := Doc.CreateHeadElement;
+  HTMLEl.AppendChild(HeadEl);
+  El := Doc.CreateElement('meta');
+  HeadEl.AppendChild(El);
+  El['http-equiv'] := 'Content-Type';
+  El['content'] := 'text/html; charset=iso8859-1';
+  TitleElement := Doc.CreateElement('title');
+  HeadEl.AppendChild(TitleElement);
+  El := Doc.CreateElement('link');
+
+  BodyElement := Doc.CreateElement('body');
+  HTMLEl.AppendChild(BodyElement);
+
+  CreatePageBody(AElement, ASubpageIndex);
+
+  HeadEl.AppendChild(El);
+  El['rel'] := 'stylesheet';
+  El['type'] := 'text/css';
+  El['href'] := Allocator.GetCSSFilename(AElement);
+end;
+
+function THTMLWriter.CreateXHTMLPage(AElement: TPasElement;
+  ASubpageIndex: Integer): TXMLDocument;
+begin
+  Result := nil;
+end;
+
+procedure CreatePath(const AFilename: String);
+var
+  EndIndex: Integer;
+  Path: String;
+begin
+  EndIndex := Length(AFilename);
+  while not (AFilename[EndIndex] in DirSeparators) do
+  begin
+    Dec(EndIndex);
+    if EndIndex = 0 then
+      exit;
+  end;
+
+  Path := Copy(AFilename, 1, EndIndex - 1);
+  if not FileExists(Path) then
+  begin
+    CreatePath(Path);
+    MkDir(Path);
+  end;
+end;
+
+procedure THTMLWriter.WriteHTMLPages;
+var
+  i: Integer;
+  PageDoc: TXMLDocument;
+  Filename: String;
+begin
+  for i := 0 to PageInfos.Count - 1 do
+    with TPageInfo(PageInfos[i]) do
+    begin
+      PageDoc := CreateHTMLPage(Element, SubpageIndex);
+      try
+        Filename := Engine.Output + Allocator.GetFilename(Element, SubpageIndex);
+	CreatePath(Filename);
+        WriteHTMLFile(PageDoc, Filename);
+      finally
+        PageDoc.Free;
+      end;
+    end;
+end;
+
+procedure THTMLWriter.WriteXHTMLPages;
+begin
+end;
+
+{procedure THTMLWriter.CreateDoc(const ATitle: DOMString;
+  AElement: TPasElement; const AFilename: String);
+var
+  El: TDOMElement;
+  DocInfo: TDocInfo;
+  CSSName: String;
+begin
+  Doc := TXHTMLDocument.Create;
+  with TXHTMLDocument(Doc) do
+  begin
+    Encoding := 'ISO8859-1';
+    CSSName := 'fpdoc.css';
+    if Assigned(Module) then
+      CSSName := '../' + CSSName;
+$IFNDEF ver1_0
+    StylesheetType := 'text/css';
+    StylesheetHRef := CSSName;
+$ENDIF
+    CreateRoot(xhtmlStrict);
+    with RequestHeadElement do
+    begin
+      AppendText(RequestTitleElement, ATitle);
+      El := CreateElement('link');
+      AppendChild(El);
+      El['rel'] := 'stylesheet';
+      El['type'] := 'text/css';
+      El['href'] := CSSName;
+    end;
+    Self.BodyElement := RequestBodyElement('en');
+  end;
+
+  if Length(AFilename) > 0 then
+  begin
+    DocInfo := TDocInfo.Create;
+    DocInfos.Add(DocInfo);
+    DocInfo.Element := AElement;
+    DocInfo.Filename := AFilename;
+  end;
+end;
+}
+
+
+{ Used for:
+  - <link> elements in descriptions
+  - "see also" entries
+  - AppendHyperlink (for unresolved parse tree element links)
+}
+
+function THTMLWriter.ResolveLinkID(const Name: String): DOMString;
+var
+  i: Integer;
+  ThisPackage: TLinkNode;
+begin
+  if Length(Name) = 0 then
+  begin
+    SetLength(Result, 0);
+    exit;
+  end;
+
+  if Name[1] = '#' then
+    Result := Engine.FindAbsoluteLink(Name)
+  else
+  begin
+    SetLength(Result, 0);
+    { Try all packages }
+    ThisPackage := Engine.RootLinkNode.FirstChild;
+    while Assigned(ThisPackage) do
+    begin
+      Result := Engine.FindAbsoluteLink(ThisPackage.Name + '.' + Name);
+      if Length(Result) = 0 then
+      begin
+        Result := Engine.FindAbsoluteLink(Module.PathName + '.' + Name);
+//	WriteLn('Suche nach ', Module.PathName + '.' + Name, ' => ', Result);
+        if Length(Result) = 0 then
+          for i := Length(Name) downto 1 do
+            if Name[i] = '.' then
+	    begin
+	      Result := ResolveLinkID(Copy(Name, 1, i - 1));
+              break;
+	    end;
+      end;
+      ThisPackage := ThisPackage.NextSibling;
+    end;
+  end;
+
+  if Length(Result) > 0 then
+    if Copy(Result, 1, Length(CurDirectory) + 1) = CurDirectory + '/' then
+      Result := Copy(Result, Length(CurDirectory) + 2, Length(Result))
+    else
+      Result := BaseDirectory + Result;
+end;
+
+function THTMLWriter.ResolveLinkWithinPackage(AElement: TPasElement;
+  ASubpageIndex: Integer): String;
+var
+  ParentEl: TPasElement;
+begin
+  ParentEl := AElement;
+  while Assigned(ParentEl) and not (ParentEl.ClassType = TPasPackage) do
+    ParentEl := ParentEl.Parent;
+  if Assigned(ParentEl) and (TPasPackage(ParentEl) = Engine.Package) then
+  begin
+    Result := Allocator.GetFilename(AElement, ASubpageIndex);
+    if Copy(Result, 1, Length(CurDirectory) + 1) = CurDirectory + '/' then
+      Result := Copy(Result, Length(CurDirectory) + 2, Length(Result))
+    else
+      Result := BaseDirectory + Result;
+  end else
+    SetLength(Result, 0);
+end;
+
+function THTMLWriter.CreateEl(Parent: TDOMNode;
+  const AName: DOMString): THTMLElement;
+begin
+  Result := Doc.CreateElement(AName);
+  Parent.AppendChild(Result);
+end;
+
+function THTMLWriter.CreatePara(Parent: TDOMNode): THTMLElement;
+begin
+  Result := CreateEl(Parent, 'p');
+end;
+
+function THTMLWriter.CreateH1(Parent: TDOMNode): THTMLElement;
+begin
+  Result := CreateEl(Parent, 'h1');
+end;
+
+function THTMLWriter.CreateH2(Parent: TDOMNode): THTMLElement;
+begin
+  Result := CreateEl(Parent, 'h2');
+end;
+
+function THTMLWriter.CreateH3(Parent: TDOMNode): THTMLElement;
+begin
+  Result := CreateEl(Parent, 'h3');
+end;
+
+function THTMLWriter.CreateTable(Parent: TDOMNode): THTMLElement;
+begin
+  Result := CreateEl(Parent, 'table');
+  Result['cellspacing'] := '0';
+  Result['cellpadding'] := '0';
+end;
+
+function THTMLWriter.CreateContentTable(Parent: TDOMNode): THTMLElement;
+begin
+  Result := CreateEl(Parent, 'table');
+end;
+
+function THTMLWriter.CreateTR(Parent: TDOMNode): THTMLElement;
+begin
+  Result := CreateEl(Parent, 'tr');
+end;
+
+function THTMLWriter.CreateTD(Parent: TDOMNode): THTMLElement;
+begin
+  Result := CreateEl(Parent, 'td');
+end;
+
+function THTMLWriter.CreateTD_vtop(Parent: TDOMNode): THTMLElement;
+begin
+  Result := CreateEl(Parent, 'td');
+  Result['valign'] := 'top';
+end;
+
+function THTMLWriter.CreateLink(Parent: TDOMNode;
+  const AHRef: DOMString): THTMLElement;
+begin
+  Result := CreateEl(Parent, 'a');
+  Result['href'] := AHRef;
+end;
+
+function THTMLWriter.CreateAnchor(Parent: TDOMNode;
+  const AName: DOMString): THTMLElement;
+begin
+  Result := CreateEl(Parent, 'a');
+  Result['name'] := AName;
+end;
+
+function THTMLWriter.CreateCode(Parent: TDOMNode): THTMLElement;
+begin
+  Result := CreateEl(CreateEl(Parent, 'tt'), 'nobr');
+end;
+
+function THTMLWriter.CreateWarning(Parent: TDOMNode): THTMLElement;
+begin
+  Result := CreateEl(Parent, 'span');
+  Result['class'] := 'warning';
+end;
+
+
+procedure THTMLWriter.PushOutputNode(ANode: TDOMNode);
+begin
+  OutputNodeStack.Add(CurOutputNode);
+  CurOutputNode := ANode;
+end;
+
+procedure THTMLWriter.PopOutputNode;
+begin
+  CurOutputNode := TDOMNode(OutputNodeStack[OutputNodeStack.Count - 1]);
+  OutputNodeStack.Delete(OutputNodeStack.Count - 1);
+end;
+
+procedure THTMLWriter.DescrWriteText(const AText: DOMString);
+begin
+  AppendText(CurOutputNode, AText);
+end;
+
+procedure THTMLWriter.DescrBeginBold;
+begin
+  PushOutputNode(CreateEl(CurOutputNode, 'b'));
+end;
+
+procedure THTMLWriter.DescrEndBold;
+begin
+  PopOutputNode;
+end;
+
+procedure THTMLWriter.DescrBeginItalic;
+begin
+  PushOutputNode(CreateEl(CurOutputNode, 'i'));
+end;
+
+procedure THTMLWriter.DescrEndItalic;
+begin
+  PopOutputNode;
+end;
+
+procedure THTMLWriter.DescrBeginEmph;
+begin
+  PushOutputNode(CreateEl(CurOutputNode, 'em'));
+end;
+
+procedure THTMLWriter.DescrEndEmph;
+begin
+  PopOutputNode;
+end;
+
+procedure THTMLWriter.DescrWriteFileEl(const AText: DOMString);
+var
+  NewEl: TDOMElement;
+begin
+  NewEl := CreateEl(CurOutputNode, 'span');
+  NewEl['class'] := 'file';
+  AppendText(NewEl, AText);
+end;
+
+procedure THTMLWriter.DescrWriteKeywordEl(const AText: DOMString);
+var
+  NewEl: TDOMElement;
+begin
+  NewEl := CreateEl(CurOutputNode, 'span');
+  NewEl['class'] := 'kw';
+  AppendText(NewEl, AText);
+end;
+
+procedure THTMLWriter.DescrWriteVarEl(const AText: DOMString);
+begin
+  AppendText(CreateEl(CurOutputNode, 'var'), AText);
+end;
+
+procedure THTMLWriter.DescrBeginLink(const AId: DOMString);
+var
+  s: DOMString;
+begin
+  s := ResolveLinkID(AId);
+  if Length(s) = 0 then
+  begin
+    WriteLn(Format(SErrUnknownLinkID, [AId]));
+    PushOutputNode(CreateEl(CurOutputNode, 'b'));
+  end else
+    PushOutputNode(CreateLink(CurOutputNode, s));
+end;
+
+procedure THTMLWriter.DescrEndLink;
+begin
+  PopOutputNode;
+end;
+
+procedure THTMLWriter.DescrWriteLinebreak;
+begin
+  CreateEl(CurOutputNode, 'br');
+end;
+
+procedure THTMLWriter.DescrBeginParagraph;
+begin
+  PushOutputNode(CreatePara(CurOutputNode));
+end;
+
+procedure THTMLWriter.DescrEndParagraph;
+begin
+  PopOutputNode;
+end;
+
+procedure THTMLWriter.DescrBeginCode(HasBorder: Boolean; const AHighlighterName: String);
+begin
+  DoPasHighlighting := (AHighlighterName = '') or (AHighlighterName = 'Pascal');
+  HighlighterFlags := 0;
+  PushOutputNode(CreateEl(CurOutputNode, 'pre'));
+end;
+
+procedure THTMLWriter.DescrWriteCodeLine(const ALine: String);
+begin
+  if DoPasHighlighting then
+  begin
+    HighlighterFlags := AppendPasSHFragment(CurOutputNode, ALine,
+      HighlighterFlags);
+    AppendText(CurOutputNode, #10);
+  end else
+    AppendText(CurOutputNode, ALine + #10);
+end;
+
+procedure THTMLWriter.DescrEndCode;
+begin
+  PopOutputNode;
+end;
+
+procedure THTMLWriter.DescrBeginOrderedList;
+begin
+  PushOutputNode(CreateEl(CurOutputNode, 'ol'));
+end;
+
+procedure THTMLWriter.DescrEndOrderedList;
+begin
+  PopOutputNode;
+end;
+
+procedure THTMLWriter.DescrBeginUnorderedList;
+begin
+  PushOutputNode(CreateEl(CurOutputNode, 'ul'));
+end;
+
+procedure THTMLWriter.DescrEndUnorderedList;
+begin
+  PopOutputNode;
+end;
+
+procedure THTMLWriter.DescrBeginDefinitionList;
+begin
+  PushOutputNode(CreateEl(CurOutputNode, 'dl'));
+end;
+
+procedure THTMLWriter.DescrEndDefinitionList;
+begin
+  PopOutputNode;
+end;
+
+procedure THTMLWriter.DescrBeginListItem;
+begin
+  PushOutputNode(CreateEl(CurOutputNode, 'li'));
+end;
+
+procedure THTMLWriter.DescrEndListItem;
+begin
+  PopOutputNode;
+end;
+
+procedure THTMLWriter.DescrBeginDefinitionTerm;
+begin
+  PushOutputNode(CreateEl(CurOutputNode, 'dt'));
+end;
+
+procedure THTMLWriter.DescrEndDefinitionTerm;
+begin
+  PopOutputNode;
+end;
+
+procedure THTMLWriter.DescrBeginDefinitionEntry;
+begin
+  PushOutputNode(CreateEl(CurOutputNode, 'dd'));
+end;
+
+procedure THTMLWriter.DescrEndDefinitionEntry;
+begin
+  PopOutputNode;
+end;
+
+procedure THTMLWriter.DescrBeginSectionTitle;
+begin
+  PushOutputNode(CreateEl(CurOutputNode, 'h3'));
+end;
+
+procedure THTMLWriter.DescrBeginSectionBody;
+begin
+  PopOutputNode;
+end;
+
+procedure THTMLWriter.DescrEndSection;
+begin
+end;
+
+procedure THTMLWriter.DescrBeginRemark;
+var
+  NewEl, TDEl: TDOMElement;
+begin
+  NewEl := CreateEl(CurOutputNode, 'table');
+  NewEl['width'] := '100%';
+  NewEl['border'] := '0';
+  NewEl['CellSpacing'] := '0';
+  NewEl['class'] := 'remark';
+  NewEl := CreateTR(NewEl);
+  TDEl := CreateTD(NewEl);
+  TDEl['valign'] := 'top';
+  TDEl['class'] := 'pre';
+  AppendText(CreateEl(TDEl, 'b'), SDocRemark);
+  PushOutputNode(CreateTD(NewEl));
+end;
+
+procedure THTMLWriter.DescrEndRemark;
+begin
+  PopOutputNode;
+end;
+
+procedure THTMLWriter.DescrBeginTable(ColCount: Integer; HasBorder: Boolean);
+var
+  Table: TDOMElement;
+begin
+  Table := CreateEl(CurOutputNode, 'table');
+  Table['border'] := IntToStr(Ord(HasBorder));
+  PushOutputNode(Table);
+end;
+
+procedure THTMLWriter.DescrEndTable;
+begin
+  PopOutputNode;
+end;
+
+procedure THTMLWriter.DescrBeginTableCaption;
+begin
+  PushOutputNode(CreateEl(CurOutputNode, 'caption'));
+end;
+
+procedure THTMLWriter.DescrEndTableCaption;
+begin
+  PopOutputNode;
+end;
+
+procedure THTMLWriter.DescrBeginTableHeadRow;
+begin
+  PushOutputNode(CreateTr(CurOutputNode));
+  InsideHeadRow := True;
+end;
+
+procedure THTMLWriter.DescrEndTableHeadRow;
+begin
+  InsideHeadRow := False;
+  PopOutputNode;
+end;
+
+procedure THTMLWriter.DescrBeginTableRow;
+begin
+  PushOutputNode(CreateTR(CurOutputNode));
+end;
+
+procedure THTMLWriter.DescrEndTableRow;
+begin
+  PopOutputNode;
+end;
+
+procedure THTMLWriter.DescrBeginTableCell;
+begin
+  if InsideHeadRow then
+    PushOutputNode(CreateEl(CurOutputNode, 'th'))
+  else
+    PushOutputNode(CreateTD(CurOutputNode));
+end;
+
+procedure THTMLWriter.DescrEndTableCell;
+begin
+  PopOutputNode;
+end;
+
+
+
+
+procedure THTMLWriter.AppendText(Parent: TDOMNode; const AText: DOMString);
+begin
+  Parent.AppendChild(Doc.CreateTextNode(AText));
+end;
+
+procedure THTMLWriter.AppendNbSp(Parent: TDOMNode; ACount: Integer);
+begin
+  while ACount > 0 do
+  begin
+    Parent.AppendChild(Doc.CreateEntityReference('nbsp'));
+    Dec(ACount);
+  end;
+end;
+
+procedure THTMLWriter.AppendSym(Parent: TDOMNode; const AText: DOMString);
+var
+  El: TDOMElement;
+begin
+  El := CreateEl(Parent, 'span');
+  El['class'] := 'sym';
+  AppendText(El, AText);
+end;
+
+procedure THTMLWriter.AppendKw(Parent: TDOMNode; const AText: DOMString);
+var
+  El: TDOMElement;
+begin
+  El := CreateEl(Parent, 'span');
+  El['class'] := 'kw';
+  AppendText(El, AText);
+end;
+
+function THTMLWriter.AppendPasSHFragment(Parent: TDOMNode;
+  const AText: String; AShFlags: Byte): Byte;
+var
+  CurParent: TDOMNode;
+  Line, Last, p: PChar;
+  IsInSpecial: Boolean;
+  El: TDOMElement;
+begin
+  GetMem(Line, Length(AText) * 3 + 4);
+  DoPascalHighlighting(AShFlags, PChar(AText), Line);
+  Result := AShFlags;
+
+  CurParent := Parent;
+  IsInSpecial := False;
+  Last := Line;
+  p := Line;
+  while p[0] <> #0 do
+  begin
+    if p[0] = LF_ESCAPE then
+    begin
+      p[0] := #0;
+      AppendText(CurParent, Last);
+
+      if IsInSpecial then
+        CurParent := Parent;
+      case Ord(p[1]) of
+	shDefault:
+	  IsInSpecial := False;
+	shInvalid:
+	  begin
+	    El := CreateEl(CurParent, 'font');
+	    El['color'] := 'red';
+	    CurParent := El;
+	    IsInSpecial := True;
+	  end;
+	shSymbol:
+	  begin
+	    El := CreateEl(CurParent, 'span');
+	    El['class'] := 'sym';
+	    CurParent := El;
+	    IsInSpecial := True;
+	  end;
+	shKeyword:
+	  begin
+	    El := CreateEl(CurParent, 'span');
+	    El['class'] := 'kw';
+	    CurParent := El;
+	    IsInSpecial := True;
+	  end;
+	shComment:
+	  begin
+	    El := CreateEl(CurParent, 'span');
+	    El['class'] := 'cmt';
+	    CurParent := El;
+	    IsInSpecial := True;
+	  end;
+	shDirective:
+	  begin
+	    El := CreateEl(CurParent, 'span');
+	    El['class'] := 'dir';
+	    CurParent := El;
+	    IsInSpecial := True;
+	  end;
+	shNumbers:
+	  begin
+	    El := CreateEl(CurParent, 'span');
+	    El['class'] := 'num';
+	    CurParent := El;
+	    IsInSpecial := True;
+	  end;
+	shCharacters:
+	  begin
+	    El := CreateEl(CurParent, 'span');
+	    El['class'] := 'chr';
+	    CurParent := El;
+	    IsInSpecial := True;
+	  end;
+	shStrings:
+	  begin
+	    El := CreateEl(CurParent, 'span');
+	    El['class'] := 'str';
+	    CurParent := El;
+	    IsInSpecial := True;
+	  end;
+	shAssembler:
+	  begin
+	    El := CreateEl(CurParent, 'span');
+	    El['class'] := 'asm';
+	    CurParent := El;
+	    IsInSpecial := True;
+	  end;
+      end;
+      Last := p + 2;
+    end;
+    Inc(p);
+  end;
+  if Last <> p then
+    AppendText(CurParent, Last);
+  FreeMem(Line);
+end;
+
+procedure THTMLWriter.AppendShortDescr(Parent: TDOMNode; Element: TPasElement);
+var
+  DocNode: TDocNode;
+begin
+  DocNode := Engine.FindDocNode(Element);
+  if Assigned(DocNode) and Assigned(DocNode.ShortDescr) then
+  begin
+    PushOutputNode(Parent);
+    try
+      if not ConvertShort(Element, DocNode.ShortDescr) then
+        WriteLn(SErrInvalidShortDescr);
+    finally
+      PopOutputNode;
+    end;
+  end;
+end;
+
+procedure THTMLWriter.AppendDescr(AContext: TPasElement; Parent: TDOMNode;
+  DescrNode: TDOMElement; AutoInsertBlock: Boolean);
+begin
+  if Assigned(DescrNode) then
+  begin
+    PushOutputNode(Parent);
+    try
+      ConvertDescr(AContext, DescrNode, AutoInsertBlock);
+    finally
+      PopOutputNode;
+    end;
+  end;
+end;
+
+procedure THTMLWriter.AppendDescrSection(AContext: TPasElement;
+  Parent: TDOMNode; DescrNode: TDOMElement; const ATitle: DOMString);
+begin
+  if not IsDescrNodeEmpty(DescrNode) then
+  begin
+    AppendText(CreateH2(Parent), ATitle);
+    AppendDescr(AContext, Parent, DescrNode, True);
+  end;
+end;
+
+
+procedure THTMLWriter.AppendShortDescrCell(Parent: TDOMNode;
+  Element: TPasElement);
+var
+  ParaEl: TDOMElement;
+begin
+  if Assigned(Engine.FindShortDescr(Element)) then
+  begin
+    AppendNbSp(CreatePara(CreateTD(Parent)), 2);
+    ParaEl := CreatePara(CreateTD(Parent));
+    ParaEl['class'] := 'cmt';
+    AppendShortDescr(ParaEl, Element);
+  end;
+end;
+
+function THTMLWriter.AppendHyperlink(Parent: TDOMNode;
+  Element: TPasElement): TDOMElement;
+var
+  s: String;
+  UnitList: TList;
+  i: Integer;
+  ThisPackage: TLinkNode;
+begin
+  if Assigned(Element) then
+  begin
+    if Element.InheritsFrom(TPasUnresolvedTypeRef) then
+    begin
+      s := ResolveLinkID(Element.Name);
+      if Length(s) = 0 then
+      begin
+	{ Try all packages }
+	ThisPackage := Engine.RootLinkNode.FirstChild;
+	while Assigned(ThisPackage) do
+	begin
+	  s := ResolveLinkID(ThisPackage.Name + '.' + Element.Name);
+	  if Length(s) > 0 then
+	    break;
+	  ThisPackage := ThisPackage.NextSibling;
+	end;
+        if Length(s) = 0 then
+        begin
+          { Okay, then we have to try all imported units of the current module }
+          UnitList := Module.InterfaceSection.UsesList;
+          for i := UnitList.Count - 1 downto 0 do
+          begin
+	    { Try all packages }
+	    ThisPackage := Engine.RootLinkNode.FirstChild;
+	    while Assigned(ThisPackage) do
+	    begin
+	      s := ResolveLinkID(ThisPackage.Name + '.' +
+	        TPasType(UnitList[i]).Name + '.' + Element.Name);
+	      if Length(s) > 0 then
+	        break;
+	      ThisPackage := ThisPackage.NextSibling;
+	    end;
+	    if Length(s) > 0 then
+	      break;
+	  end;
+	end;
+      end;
+    end else
+      s := ResolveLinkID(Element.PathName);
+
+    if Length(s) > 0 then
+    begin
+      Result := CreateLink(Parent, s);
+      AppendText(Result, Element.Name);
+    end else
+    begin
+      Result := nil;
+      AppendText(Parent, Element.Name);
+    end;
+  end else
+  begin
+    Result := nil;
+    AppendText(CreateWarning(Parent), '<NIL>');
+  end;
+end;
+
+
+{ Returns the new CodeEl, which will be the old CodeEl in most cases }
+function THTMLWriter.AppendType(CodeEl, TableEl: TDOMElement;
+  Element: TPasType; Expanded: Boolean): TDOMElement;
+begin
+  Result := CodeEl;
+
+  if not Assigned(Element) then
+    AppendText(CreateWarning(CodeEl), '<NIL>')
+  else if (not Expanded) and (Length(Element.Name) > 0) then
+    AppendHyperlink(CodeEl, Element)
+  else
+  // Array
+  if Element.ClassType = TPasArrayType then
+  begin
+    AppendKw(CodeEl, 'array ');
+    AppendText(CreateWarning(CodeEl), '...');
+    AppendKw(CodeEl, ' of ');
+      Result := AppendType(CodeEl, TableEl, TPasArrayType(Element).ElType, False);
+  end else
+  // Procedure or funtion type
+  if Element.InheritsFrom(TPasProcedureType) then
+  begin
+    AppendKw(CodeEl, TPasProcedureType(Element).TypeName);
+    Result := AppendProcType(CodeEl, TableEl, TPasProcedureType(Element), 0)
+  end else
+  // Range type
+  if Element.InheritsFrom(TPasRangeType) then
+    AppendPasSHFragment(CodeEl, TPasRangeType(Element).RangeStart + '..' +
+      TPasRangeType(Element).RangeEnd, 0)
+  else
+  // Other types
+    AppendHyperlink(CodeEl, Element);
+end;
+
+function THTMLWriter.AppendProcType(CodeEl, TableEl: TDOMElement;
+  Element: TPasProcedureType; Indent: Integer): TDOMElement;
+
+  function CreateIndentedCodeEl(Indent: Integer): TDOMElement;
+  begin
+    Result := CreateCode(CreatePara(CreateTD(CreateTR(TableEl))));
+    AppendNbSp(Result, Indent);
+  end;
+
+var
+  i: Integer;
+  Arg: TPasArgument;
+begin
+  if Element.Args.Count > 0 then
+  begin
+    AppendSym(CodeEl, '(');
+
+    for i := 0 to Element.Args.Count - 1 do
+    begin
+      Arg := TPasArgument(Element.Args[i]);
+      CodeEl := CreateIndentedCodeEl(Indent + 2);
+
+      case Arg.Access of
+	argConst: AppendKw(CodeEl, 'const ');
+	argVar: AppendKw(CodeEl, 'var ');
+	argOut: AppendKw(CodeEl, 'out ');
+      end;
+      AppendText(CodeEl, Arg.Name);
+      if Assigned(Arg.ArgType) then
+      begin
+	AppendSym(CodeEl, ': ');
+	CodeEl := AppendType(CodeEl, TableEl, Arg.ArgType, False);
+      end;
+      if Length(Arg.Value) > 0 then
+        AppendPasSHFragment(CodeEl, ' = ' + Arg.Value, 0);
+      if i < Element.Args.Count - 1 then
+	AppendSym(CodeEl, ';');
+    end;
+
+    if Element.InheritsFrom(TPasFunctionType) or Element.IsOfObject then
+    begin
+      CodeEl := CreateIndentedCodeEl(Indent);
+      if Element.InheritsFrom(TPasFunctionType) then
+      begin
+	AppendSym(CodeEl, '):');
+	AppendHyperlink(CodeEl, TPasFunctionType(Element).ResultEl.ResultType);
+      end else
+	AppendSym(CodeEl, ')');
+      if Element.IsOfObject then
+      begin
+	AppendText(CodeEl, ' ');	// Don't remove
+	AppendKw(CodeEl, 'of object');
+      end;
+    end else
+      if Indent > 0 then
+	AppendSym(CodeEl, ')')
+      else
+      begin
+        CodeEl := CreateCode(CreatePara(CreateTD(CreateTR(TableEl))));
+        AppendSym(CodeEl, ')');
+      end;
+  end else
+  begin
+    { Procedure or function without arguments }
+    if Element.InheritsFrom(TPasFunctionType) then
+    begin
+      AppendSym(CodeEl, ': ');
+      AppendHyperlink(CodeEl, TPasFunctionType(Element).ResultEl.ResultType);
+    end;
+    if Element.IsOfObject then
+      AppendKw(CodeEl, ' of object');
+  end;
+  Result := CodeEl;
+end;
+
+procedure THTMLWriter.AppendProcExt(CodeEl: TDOMElement;
+  Element: TPasProcedure);
+
+  procedure AppendExt(const Ext: String);
+  begin
+    AppendKw(CodeEl, ' ' + Ext);
+    AppendSym(CodeEl, ';');
+  end;
+
+begin
+  if Element.IsVirtual then
+    AppendExt('virtual');
+  if Element.IsDynamic then
+    AppendExt('dynamic');
+  if Element.IsAbstract then
+    AppendExt('abstract');
+  if Element.IsOverride then
+    AppendExt('override');
+  if Element.IsOverload then
+    AppendExt('overload');
+  if Element.IsMessage then
+    AppendExt('message');
+end;
+
+
+{ Used in two places:
+  - Page for the method of a class
+  - Page for a tandalone procedure or function. }
+
+procedure THTMLWriter.AppendProcDecl(CodeEl, TableEl: TDOMElement;
+  Element: TPasProcedureBase);
+
+  procedure WriteVariant(AProc: TPasProcedure);
+  begin
+    AppendProcArgsSection(TableEl.ParentNode, AProc.ProcType);
+
+    AppendKw(CodeEl, AProc.TypeName);
+    if Element.Parent.ClassType = TPasClassType then
+    begin
+      AppendText(CodeEl, ' ');
+      AppendHyperlink(CodeEl, Element.Parent);
+      AppendSym(CodeEl, '.');
+      AppendText(CodeEl, AProc.Name);
+    end else
+      AppendText(CodeEl, ' ' + AProc.FullName);
+    CodeEl := AppendProcType(CodeEl, TableEl, AProc.ProcType, 0);
+    AppendSym(CodeEl, ';');
+    AppendProcExt(CodeEl, AProc);
+  end;
+
+var
+  i: Integer;
+begin
+  if Element.ClassType = TPasOverloadedProc then
+    for i := 0 to TPasOverloadedProc(Element).Overloads.Count - 1 do
+    begin
+      if i > 0 then
+      begin
+        CreateEl(CodeEl, 'br');
+        CreateEl(CodeEl, 'br');
+      end;
+      WriteVariant(TPasProcedure(TPasOverloadedProc(Element).Overloads[i]));
+    end
+  else
+    WriteVariant(TPasProcedure(Element));
+end;
+
+procedure THTMLWriter.AppendProcArgsSection(Parent: TDOMNode;
+  Element: TPasProcedureType);
+var
+  HasFullDescr, IsFirst: Boolean;
+  ResultEl: TPasResultElement;
+  ArgTableEl, TREl: TDOMElement;
+  DocNode: TDocNode;
+  i: Integer;
+  Arg: TPasArgument;
+begin
+  IsFirst := True;
+  for i := 0 to Element.Args.Count - 1 do
+  begin
+    Arg := TPasArgument(Element.Args[i]);
+    if IsDescrNodeEmpty(Engine.FindShortDescr(Arg)) then
+      continue;
+    if IsFirst then
+    begin
+      IsFirst := False;
+      AppendText(CreateH2(Parent), SDocArguments);
+      ArgTableEl := CreateTable(Parent);
+    end;
+    TREl := CreateTR(ArgTableEl);
+    AppendText(CreateCode(CreatePara(CreateTD_vtop(TREl))), Arg.Name);
+    AppendShortDescrCell(TREl, Arg);
+  end;
+
+  if Element.ClassType = TPasFunctionType then
+  begin
+    ResultEl := TPasFunctionType(Element).ResultEl;
+    DocNode := Engine.FindDocNode(ResultEl);
+    HasFullDescr := Assigned(DocNode) and not IsDescrNodeEmpty(DocNode.Descr);
+    if HasFullDescr or
+      (Assigned(DocNode) and not IsDescrNodeEmpty(DocNode.ShortDescr)) then
+    begin
+      AppendText(CreateH2(Parent), SDocFunctionResult);
+      if HasFullDescr then
+	AppendDescr(ResultEl, Parent, DocNode.Descr, True)
+      else
+	AppendDescr(ResultEl, CreatePara(Parent), DocNode.ShortDescr, False);
+    end;
+  end;
+end;
+
+procedure THTMLWriter.AppendTitle(const AText: DOMString);
+begin
+  AppendText(TitleElement, AText);
+  AppendText(CreateH1(BodyElement), AText);
+end;
+
+procedure THTMLWriter.AppendMenuBar(ASubpageIndex: Integer);
+var
+  TableEl, TREl, ParaEl, TitleEl: TDOMElement;
+
+  procedure AddLink(ALinkSubpageIndex: Integer; const AName: String);
+  begin
+    AppendText(ParaEl, '[');
+    if ALinkSubpageIndex = ASubpageIndex then
+      AppendText(ParaEl, AName)
+    else
+      AppendText(
+        CreateLink(ParaEl, ResolveLinkWithinPackage(Module, ALinkSubpageIndex)),
+	AName);
+    AppendText(ParaEl, ']');
+  end;
+
+begin
+  TableEl := CreateEl(BodyElement, 'table');
+  TableEl['cellpadding'] := '4';
+  TableEl['cellspacing'] := '0';
+  TableEl['border'] := '0';
+  TableEl['width'] := '100%';
+  TableEl['class'] := 'bar';
+  TREl := CreateTR(TableEl);
+  ParaEl := CreateEl(CreateTD(TREl), 'b');
+
+  if Assigned(Module) then
+  begin
+    AddLink(0, SDocOverview);
+    if Module.InterfaceSection.ResStrings.Count > 0 then
+      AddLink(ResstrSubindex, SDocResStrings);
+    if Module.InterfaceSection.Consts.Count > 0 then
+      AddLink(ConstsSubindex, SDocConstants);
+    if Module.InterfaceSection.Types.Count > 0 then
+      AddLink(TypesSubindex, SDocTypes);
+    if Module.InterfaceSection.Classes.Count > 0 then
+      AddLink(ClassesSubindex, SDocClasses);
+    if Module.InterfaceSection.Functions.Count > 0 then
+      AddLink(ProcsSubindex, SDocProceduresAndFunctions);
+    if Module.InterfaceSection.Variables.Count > 0 then
+      AddLink(VarsSubindex, SDocVariables);
+  end;
+
+  if Length(SearchPage) > 0 then
+  begin
+    AppendText(ParaEl, '[');
+    AppendText(CreateLink(ParaEl, SearchPage), SDocSearch);
+    AppendText(ParaEl, ']');
+  end;
+  ParaEl := CreateTD(TREl);
+  ParaEl['align'] := 'right';
+  TitleEl := CreateEl(ParaEl, 'span');
+  TitleEl['class'] := 'bartitle';
+  if Assigned(Module) then
+    AppendText(TitleEl, Format(SDocUnitTitle, [Module.Name]));
+  if Assigned(Package) then
+  begin
+    AppendText(TitleEl, ' (');
+    AppendHyperlink(TitleEl, Package);
+    AppendText(TitleEl, ')');
+  end;
+end;
+
+procedure THTMLWriter.FinishElementPage(AElement: TPasElement);
+var
+  DocNode: TDocNode;
+  IsFirstSeeAlso: Boolean;
+  Node: TDOMNode;
+  TableEl, El, TREl, TDEl, ParaEl, NewEl, DescrEl: TDOMElement;
+  s: String;
+  f: Text;
+begin
+  DocNode := Engine.FindDocNode(AElement);
+  if Assigned(DocNode) and Assigned(DocNode.Descr) then
+    AppendDescrSection(AElement, BodyElement, DocNode.Descr, SDocDescription);
+  // ###
+
+  // Append "Errors" section
+  if Assigned(DocNode) and Assigned(DocNode.ErrorsDoc) then
+    AppendDescrSection(AElement, BodyElement, DocNode.ErrorsDoc, SDocErrors);
+
+      // Append "See also" section
+      if Assigned(DocNode) and Assigned(DocNode.SeeAlso) then
+      begin
+        IsFirstSeeAlso := True;
+	Node := DocNode.SeeAlso.FirstChild;
+	while Assigned(Node) do
+	begin
+	  if (Node.NodeType = ELEMENT_NODE) and (Node.NodeName = 'link') then
+	  begin
+	    if IsFirstSeeAlso then
+	    begin
+	      IsFirstSeeAlso := False;
+	      AppendText(CreateH2(BodyElement), SDocSeeAlso);
+	      TableEl := CreateTable(BodyElement);
+	    end;
+
+	    El := TDOMElement(Node);
+	    TREl := CreateTR(TableEl);
+	    ParaEl := CreatePara(CreateTD_vtop(TREl));
+	    s := ResolveLinkID(El['id']);
+	    if Length(s) = 0 then
+	    begin
+	      WriteLn(Format(SErrUnknownLinkID, [El['id']]));
+	      NewEl := CreateEl(ParaEl, 'b')
+	    end else
+	      NewEl := CreateLink(ParaEl, s);
+	    AppendText(NewEl, El['id']);
+
+	    DescrEl := Engine.FindShortDescr(AElement.GetModule, El['id']);
+	    if Assigned(DescrEl) then
+	    begin
+	      AppendNbSp(CreatePara(CreateTD(TREl)), 2);
+	      ParaEl := CreatePara(CreateTD(TREl));
+	      ParaEl['class'] := 'cmt';
+
+	      PushOutputNode(ParaEl);
+	      try
+		ConvertShort(AElement, DescrEl);
+	      finally
+		PopOutputNode;
+	      end;
+	    end;
+	  end;
+	  Node := Node.NextSibling;
+	end;
+      end;
+
+      // Append examples, if present
+      if Assigned(DocNode) and Assigned(DocNode.FirstExample) then
+      begin
+        Node := DocNode.FirstExample;
+	while Assigned(Node) do
+	begin
+	  if (Node.NodeType = ELEMENT_NODE) and (Node.NodeName = 'example') then
+	  begin
+	    AppendText(CreateH2(BodyElement), SDocExample);
+	    try
+	      Assign(f, Engine.GetExampleFilename(TDOMElement(Node)));
+	      Reset(f);
+	      try
+	        PushOutputNode(BodyElement);
+		DescrBeginCode(False, TDOMElement(Node)['highlighter']);
+	        while not EOF(f) do
+	        begin
+	          ReadLn(f, s);
+		  DescrWriteCodeLine(s);
+	        end;
+		DescrEndCode;
+	        PopOutputNode;
+	      finally
+	        Close(f);
+	      end;
+	    except
+	      on e: Exception do
+	      begin
+	        e.Message := '[example] ' + e.Message;
+	        raise;
+	      end;
+	    end;
+	  end;
+	  Node := Node.NextSibling;
+	end;
+      end;
+end;
+
+procedure THTMLWriter.CreatePageBody(AElement: TPasElement;
+  ASubpageIndex: Integer);
+var
+  i: Integer;
+  Element: TPasElement;
+begin
+  CurDirectory := Allocator.GetFilename(AElement, ASubpageIndex);
+  i := Length(CurDirectory);
+  while (i > 0) and not (CurDirectory[i] in DirSeparators) do
+    Dec(i);
+  CurDirectory := Copy(CurDirectory, 1, i);
+  BaseDirectory := Allocator.GetRelativePathToTop(AElement);
+
+  if AElement.ClassType = TPasPackage then
+    CreatePackagePageBody
+  else
+  begin
+    Element := AElement;
+    while Element.ClassType <> TPasModule do
+      Element := Element.Parent;
+    Module := TPasModule(Element);
+
+    if AElement.ClassType = TPasModule then
+      CreateModulePageBody(TPasModule(AElement), ASubpageIndex)
+    else if AElement.Parent.InheritsFrom(TPasClassType) then
+      CreateClassMemberPageBody(AElement)
+    else if AElement.ClassType = TPasConst then
+      CreateConstPageBody(TPasConst(AElement))
+    else if AElement.InheritsFrom(TPasClassType) then
+      CreateClassPageBody(TPasClassType(AElement), ASubpageIndex)
+    else if AElement.InheritsFrom(TPasType) then
+      CreateTypePageBody(TPasType(AElement))
+    else if AElement.ClassType = TPasVariable then
+      CreateVarPageBody(TPasVariable(AElement))
+    else if AElement.InheritsFrom(TPasProcedureBase) then
+      CreateProcPageBody(TPasProcedure(AElement));
+  end;
+end;
+
+procedure THTMLWriter.CreatePackagePageBody;
+var
+  DocNode: TDocNode;
+  TableEl, TREl: TDOMElement;
+  i: Integer;
+  ThisModule: TPasModule;
+begin
+  AppendMenuBar(0);
+  AppendTitle(Format(SDocPackageTitle, [Copy(Package.Name, 2, 256)]));
+  AppendShortDescr(CreatePara(BodyElement), Package);
+
+  AppendText(CreateH2(BodyElement), SDocUnits);
+  TableEl := CreateTable(BodyElement);
+  for i := 0 to Package.Modules.Count - 1 do
+  begin
+    ThisModule := TPasModule(Package.Modules[i]);
+    TREl := CreateTR(TableEl);
+    AppendHyperlink(CreateCode(CreatePara(CreateTD_vtop(TREl))), ThisModule);
+    AppendShortDescrCell(TREl, ThisModule);
+  end;
+
+  DocNode := Engine.FindDocNode(Package);
+  if Assigned(DocNode) and Assigned(DocNode.Descr) then
+    AppendDescrSection(nil, BodyElement, DocNode.Descr, SDocDescription);
+end;
+
+procedure THTMLWriter.CreateModulePageBody(AModule: TPasModule;
+  ASubpageIndex: Integer);
+
+  procedure CreateMainPage;
+  var
+    TableEl, TREl, TDEl, CodeEl: TDOMElement;
+    i: Integer;
+    UnitRef: TPasType;
+    DocNode: TDocNode;
+  begin
+    AppendMenuBar(0);
+    AppendTitle(Format(SDocUnitTitle, [AModule.Name]));
+    AppendShortDescr(CreatePara(BodyElement), AModule);
+
+    if AModule.InterfaceSection.UsesList.Count > 0 then
+    begin
+      TableEl := CreateTable(BodyElement);
+      AppendKw(CreateCode(CreatePara(CreateTD(CreateTR(TableEl)))), 'uses');
+      for i := 0 to AModule.InterfaceSection.UsesList.Count - 1 do
+      begin
+        UnitRef := TPasType(AModule.InterfaceSection.UsesList[i]);
+        DocNode := Engine.FindDocNode(UnitRef);
+        if Assigned(DocNode) and DocNode.IsSkipped then
+          continue;
+        TREl := CreateTR(TableEl);
+        TDEl := CreateTD_vtop(TREl);
+        CodeEl := CreateCode(CreatePara(TDEl));
+        AppendNbSp(CodeEl, 2);
+        AppendHyperlink(CodeEl, UnitRef);
+        if i < AModule.InterfaceSection.UsesList.Count - 1 then
+          AppendSym(CodeEl, ',')
+        else
+          AppendSym(CodeEl, ';');
+        AppendText(CodeEl, '  ');		// Space for descriptions
+        AppendShortDescrCell(TREl, UnitRef);
+      end;
+    end;
+
+    DocNode := Engine.FindDocNode(AModule);
+    if Assigned(DocNode) and Assigned(DocNode.Descr) then
+      AppendDescrSection(AModule, BodyElement, DocNode.Descr, SDocOverview);
+  end;
+
+  procedure CreateSimpleSubpage(const ATitle: DOMString; AList: TList);
+  var
+    TableEl, TREl, TDEl, CodeEl: TDOMElement;
+    i, j: Integer;
+    Decl: TPasElement;
+    SortedList: TList;
+    DocNode: TDocNode;
+  begin
+    AppendMenuBar(ASubpageIndex);
+    AppendTitle(Format(SDocUnitTitle + ': %s', [AModule.Name, ATitle]));
+    SortedList := TList.Create;
+    try
+      for i := 0 to AList.Count - 1 do
+      begin
+        Decl := TPasElement(AList[i]);
+        DocNode := Engine.FindDocNode(Decl);
+        if (not Assigned(DocNode)) or (not DocNode.IsSkipped) then
+        begin
+          j := 0;
+          while (j < SortedList.Count) and (CompareText(
+	    TPasElement(SortedList[j]).PathName, Decl.PathName) < 0) do
+            Inc(j);
+          SortedList.Insert(j, Decl);
+        end;
+      end;
+
+      TableEl := CreateTable(BodyElement);
+      for i := 0 to SortedList.Count - 1 do
+      begin
+        Decl := TPasElement(SortedList[i]);
+        TREl := CreateTR(TableEl);
+        CodeEl := CreateCode(CreatePara(CreateTD_vtop(TREl)));
+        AppendHyperlink(CodeEl, Decl);
+        AppendShortDescrCell(TREl, Decl);
+      end;
+    finally
+      SortedList.Free;
+    end;
+  end;
+
+  procedure CreateResStringsPage;
+  var
+    ParaEl: TDOMElement;
+    i, j: Integer;
+    Decl: TPasResString;
+    DocNode: TDocNode;
+  begin
+    AppendMenuBar(ResstrSubindex);
+    AppendTitle(Format(SDocUnitTitle + ': %s', [AModule.Name, SDocResStrings]));
+    for i := 0 to AModule.InterfaceSection.ResStrings.Count - 1 do
+    begin
+      Decl := TPasResString(AModule.InterfaceSection.ResStrings[i]);
+      CreateEl(BodyElement, 'a')['name'] := LowerCase(Decl.Name);
+      ParaEl := CreatePara(BodyElement);
+      AppendText(CreateCode(ParaEl), Decl.Name);
+      CreateEl(ParaEl, 'br');
+      AppendText(ParaEl, Decl.Value);
+    end;
+  end;
+
+begin
+  case ASubpageIndex of
+    0:
+      CreateMainPage;
+    ResstrSubindex:
+      CreateResStringsPage;
+    ConstsSubindex:
+      CreateSimpleSubpage(SDocConstants, AModule.InterfaceSection.Consts);
+    TypesSubindex:
+      CreateSimpleSubpage(SDocTypes, AModule.InterfaceSection.Types);
+    ClassesSubindex:
+      CreateSimpleSubpage(SDocClasses, AModule.InterfaceSection.Classes);
+    ProcsSubindex:
+      CreateSimpleSubpage(SDocProceduresAndFunctions, AModule.InterfaceSection.Functions);
+    VarsSubindex:
+      CreateSimpleSubpage(SDocVariables, AModule.InterfaceSection.Variables);
+  end;
+end;
+
+procedure THTMLWriter.CreateConstPageBody(AConst: TPasConst);
+var
+  TableEl, CodeEl: TDOMElement;
+begin
+  AppendMenuBar(-1);
+  AppendTitle(AConst.Name);
+  AppendShortDescr(CreatePara(BodyElement), AConst);
+  AppendText(CreateH2(BodyElement), SDocDeclaration);
+
+  TableEl := CreateTable(BodyElement);
+  CodeEl := CreateCode(CreatePara(CreateTD(CreateTR(TableEl))));
+
+  AppendKw(CodeEl, 'const');
+  AppendText(CodeEl, ' ' + AConst.Name);
+  if Assigned(AConst.VarType) then
+  begin
+    AppendSym(CodeEl, ': ');
+    AppendType(CodeEl, TableEl, AConst.VarType, False);
+  end;
+  AppendPasSHFragment(CodeEl, ' = ' + AConst.Value + ';', 0);
+
+  FinishElementPage(AConst);
+end;
+
+procedure THTMLWriter.CreateTypePageBody(AType: TPasType);
+var
+  TableEl, TREl, TDEl, CodeEl: TDOMElement;
+  DocNode: TDocNode;
+  i: Integer;
+  s: String;
+  EnumType: TPasEnumType;
+  EnumValue: TPasEnumValue;
+  Variable: TPasVariable;
+begin
+  AppendMenuBar(-1);
+  AppendTitle(AType.Name);
+  AppendShortDescr(CreatePara(BodyElement), AType);
+  AppendText(CreateH2(BodyElement), SDocDeclaration);
+
+  TableEl := CreateTable(BodyElement);
+  TREl := CreateTR(TableEl);
+  TDEl := CreateTD(TREl);
+  CodeEl := CreateCode(CreatePara(TDEl));
+  AppendKw(CodeEl, 'type ');
+  AppendText(CodeEl, AType.Name);
+  AppendSym(CodeEl, ' = ');
+
+  // Alias
+  if AType.ClassType = TPasAliasType then
+  begin
+    if Assigned(TPasAliasType(AType).DestType) then
+      AppendHyperlink(CodeEl, TPasAliasType(AType).DestType)
+    else
+      AppendText(CreateWarning(CodeEl), '<Destination type is NIL>');
+    AppendSym(CodeEl, ';');
+  end else
+  // Class of
+  if AType.ClassType = TPasClassOfType then
+  begin
+    AppendKw(CodeEl, 'class of ');
+    AppendHyperlink(CodeEl, TPasClassOfType(AType).DestType);
+    AppendSym(CodeEl, ';');
+  end else
+  // Enumeration
+  if AType.ClassType = TPasEnumType then
+  begin
+    AppendSym(CodeEl, '(');
+    for i := 0 to TPasEnumType(AType).Values.Count - 1 do
+    begin
+      EnumValue := TPasEnumValue(TPasEnumType(AType).Values[i]);
+      TREl := CreateTR(TableEl);
+      CodeEl := CreateCode(CreatePara(CreateTD_vtop(TREl)));
+      AppendShortDescrCell(TREl, EnumValue);
+      AppendNbSp(CodeEl, 2);
+      s := EnumValue.Name;
+      if EnumValue.IsValueUsed then
+        s := s + ' = ' + IntToStr(EnumValue.Value);
+      if i < TPasEnumType(AType).Values.Count - 1 then
+        s := s + ',';
+      AppendPasSHFragment(CodeEl, s, 0);
+    end;
+    AppendSym(CreateCode(CreatePara(CreateTD(CreateTR(TableEl)))), ');');
+  end else
+  // Pointer type
+  if AType.ClassType = TPasPointerType then
+  begin
+    AppendSym(CodeEl, '^');
+    if Assigned(TPasPointerType(AType).DestType) then
+      AppendHyperlink(CodeEl, TPasPointerType(AType).DestType)
+    else
+      AppendText(CreateWarning(CodeEl), '<Destination type is NIL>');
+    AppendSym(CodeEl, ';');
+  end else
+  if AType.InheritsFrom(TPasProcedureType) then
+  begin
+    AppendSym(AppendType(CodeEl, TableEl, TPasType(AType), True), ';');
+    AppendProcArgsSection(BodyElement, TPasProcedureType(AType));
+  end else
+  // Record
+  if AType.ClassType = TPasRecordType then
+  begin
+    if TPasRecordType(AType).IsPacked then
+      AppendKw(CodeEl, 'packed record')
+    else
+      AppendKw(CodeEl, 'record');
+
+    for i := 0 to TPasRecordType(AType).Members.Count - 1 do
+    begin
+      Variable := TPasVariable(TPasRecordType(AType).Members[i]);
+      TREl := CreateTR(TableEl);
+      CodeEl := CreateCode(CreatePara(CreateTD_vtop(TREl)));
+      AppendShortDescrCell(TREl, Variable);
+      AppendNbSp(CodeEl, 2);
+      AppendText(CodeEl, Variable.Name);
+      AppendSym(CodeEl, ': ');
+      AppendType(CodeEl, TableEl, Variable.VarType, False);
+      AppendSym(CodeEl, ';');
+    end;
+
+    CodeEl := CreateCode(CreatePara(CreateTD(CreateTR(TableEl))));
+    AppendText(CodeEl, ' '); // !!!: Dirty trick, necessary for current XML writer
+    AppendKw(CodeEl, 'end');
+    AppendSym(CodeEl, ';');
+  end else
+  // Set
+  if AType.ClassType = TPasSetType then
+  begin
+    AppendKw(CodeEl, 'set of ');
+    if TPasSetType(AType).EnumType.ClassType = TPasEnumType then
+    begin
+      AppendSym(CodeEl, '(');
+      EnumType := TPasEnumType(TPasSetType(AType).EnumType);
+      for i := 0 to EnumType.Values.Count - 1 do
+      begin
+        EnumValue := TPasEnumValue(EnumType.Values[i]);
+        TREl := CreateTR(TableEl);
+        CodeEl := CreateCode(CreatePara(CreateTD_vtop(TREl)));
+        AppendShortDescrCell(TREl, EnumValue);
+	AppendNbSp(CodeEl, 2);
+	s := EnumValue.Name;
+        if EnumValue.IsValueUsed then
+	  s := s + ' = ' + IntToStr(EnumValue.Value);
+        if i < EnumType.Values.Count - 1 then
+	  s := s + ',';
+        AppendPasSHFragment(CodeEl, s, 0);
+      end;
+      AppendSym(CreateCode(CreatePara(CreateTD(CreateTR(TableEl)))), ');');
+    end else
+    begin
+      AppendHyperlink(CodeEl, TPasSetType(AType).EnumType);
+      AppendSym(CodeEl, ';');
+    end;
+  end else
+  // Type alias
+  if AType.ClassType = TPasTypeAliasType then
+  begin
+    AppendKw(CodeEl, 'type ');
+    AppendHyperlink(CodeEl, TPasTypeAliasType(AType).DestType);
+    AppendSym(CodeEl, ';');
+  end else
+  // Probably one of the simple types, which allowed in other places as wel...
+    AppendSym(AppendType(CodeEl, TableEl, TPasType(AType), True), ';');
+
+  FinishElementPage(AType);
+end;
+
+
+function PropertyFilter(AMember: TPasElement): Boolean;
+begin
+  Result := (AMember.ClassType = TPasProperty) and
+    (Copy(AMember.Name, 1, 2) <> 'On');
+end;
+
+function MethodFilter(AMember: TPasElement): Boolean;
+begin
+  Result := AMember.InheritsFrom(TPasProcedureBase);
+end;
+
+function EventFilter(AMember: TPasElement): Boolean;
+begin
+  Result := (AMember.ClassType = TPasProperty) and
+    (Copy(AMember.Name, 1, 2) = 'On');
+end;
+
+procedure THTMLWriter.CreateClassPageBody(AClass: TPasClassType;
+  ASubpageIndex: Integer);
+type
+  TMemberFilter = function(AMember: TPasElement): Boolean;
+var
+  ParaEl: TDOMElement;
+
+  procedure AppendMemberListLink(AListSubpageIndex: Integer;
+    const AText: DOMString);
+  var
+    LinkEl: TDOMElement;
+  begin
+    AppendText(ParaEl, '[');
+    LinkEl := CreateEl(ParaEl, 'a');
+    LinkEl['href'] :=
+      ResolveLinkWithinPackage(AClass, AListSubpageIndex);
+    LinkEl['onClick'] := 'window.open(''' + LinkEl['href'] + ''', ''list'', ' +
+     '''dependent=yes,resizable=yes,scrollbars=yes,height=400,width=300''); return false;';
+    AppendText(LinkEl, AText);
+    AppendText(ParaEl, ' (');
+    LinkEl := CreateEl(ParaEl, 'a');
+    LinkEl['href'] :=
+      ResolveLinkWithinPackage(AClass, AListSubpageIndex + 1);
+    LinkEl['onClick'] := 'window.open(''' + LinkEl['href'] + ''', ''list'', ' +
+     '''dependent=yes,resizable=yes,scrollbars=yes,height=400,width=300''); return false;';
+    AppendText(LinkEl, SDocByName);
+    AppendText(ParaEl, ')');
+    AppendText(ParaEl, '] ');
+  end;
+
+  procedure CreateMainPage;
+  var
+    TableEl, TREl, TDEl, CodeEl: TDOMElement;
+    DocNode: TDocNode;
+    Member: TPasElement;
+    CurVisibility: TPasMemberVisibility;
+    i: Integer;
+    s: String;
+    ThisClass: TPasClassType;
+    HaveSeenTObject: Boolean;
+  begin
+    AppendMenuBar(-1);
+    AppendTitle(AClass.Name);
+
+    ParaEl := CreatePara(BodyElement);
+    AppendMemberListLink(PropertiesByInheritanceSubindex, SDocProperties);
+    AppendMemberListLink(MethodsByInheritanceSubindex, SDocMethods);
+    AppendMemberListLink(EventsByInheritanceSubindex, SDocEvents);
+
+    AppendShortDescr(CreatePara(BodyElement), AClass);
+    AppendText(CreateH2(BodyElement), SDocDeclaration);
+
+    TableEl := CreateTable(BodyElement);
+
+    TREl := CreateTR(TableEl);
+    TDEl := CreateTD(TREl);
+    CodeEl := CreateCode(CreatePara(TDEl));
+    AppendKw(CodeEl, 'type');
+    AppendText(CodeEl, ' ' + AClass.Name + ' ');
+    AppendSym(CodeEl, '=');
+    AppendText(CodeEl, ' ');
+    AppendKw(CodeEl, ObjKindNames[AClass.ObjKind]);
+
+    if Assigned(AClass.AncestorType) then
+    begin
+      AppendSym(CodeEl, '(');
+      AppendHyperlink(CodeEl, AClass.AncestorType);
+      AppendSym(CodeEl, ')');
+    end;
+
+    if AClass.Members.Count > 0 then
+    begin
+      CurVisibility := visDefault;
+      for i := 0 to AClass.Members.Count - 1 do
+      begin
+        Member := TPasElement(AClass.Members[i]);
+        if CurVisibility <> Member.Visibility then
+        begin
+          CurVisibility := Member.Visibility;
+  	  if ((CurVisibility = visPrivate) and Engine.HidePrivate) or
+	    ((CurVisibility = visProtected) and Engine.HideProtected) then
+	    continue;
+	  case CurVisibility of
+	    visPrivate: s := 'private';
+	    visProtected: s := 'protected';
+	    visPublic: s := 'public';
+	    visPublished: s := 'published';
+	    visAutomated: s := 'automated';
+	  end;
+	  AppendKw(CreateCode(CreatePara(CreateTD(CreateTR(TableEl)))), s);
+        end else
+	  if ((CurVisibility = visPrivate) and Engine.HidePrivate) or
+	    ((CurVisibility = visProtected) and Engine.HideProtected) then
+	    continue;
+
+        TREl := CreateTR(TableEl);
+        CodeEl := CreateCode(CreatePara(CreateTD_vtop(TREl)));
+        AppendNbSp(CodeEl, 2);
+        AppendShortDescrCell(TREl, Member);
+
+        if Member.InheritsFrom(TPasProcedureBase) then
+        begin
+	  AppendKw(CodeEl, TPasProcedureBase(Member).TypeName + ' ');
+	  AppendHyperlink(CodeEl, Member);
+	  if (Member.ClassType = TPasOverloadedProc) or
+	    (TPasProcedure(Member).ProcType.Args.Count > 0) then
+	    AppendSym(CodeEl, '();')
+	  else
+	    AppendSym(CodeEl, ';');
+	  if Member.ClassType <> TPasOverloadedProc then
+	    AppendProcExt(CodeEl, TPasProcedure(Member));
+        end else
+        if Member.ClassType = TPasVariable then
+        begin
+	  AppendHyperlink(CodeEl, Member);
+	  AppendSym(CodeEl, ': ');
+	  AppendHyperlink(CodeEl, TPasVariable(Member).VarType);
+	  AppendSym(CodeEl, ';');
+        end else
+        if Member.ClassType = TPasProperty then
+        begin
+          AppendKw(CodeEl, 'property ');
+	  AppendHyperlink(CodeEl, Member);
+	  if Assigned(TPasProperty(Member).VarType) then
+	  begin
+	    AppendSym(CodeEl, ': ');
+	    AppendHyperlink(CodeEl, TPasProperty(Member).VarType);
+	  end;
+	  AppendSym(CodeEl, ';');
+	  if TPasProperty(Member).IsDefault then
+	  begin
+	    AppendKw(CodeEl, ' default');
+	    AppendSym(CodeEl, ';');
+	  end;
+	  SetLength(s, 0);
+	  if Length(TPasProperty(Member).ReadAccessorName) > 0 then
+	    s := s + 'r';
+	  if Length(TPasProperty(Member).WriteAccessorName) > 0 then
+	    s := s + 'w';
+	  if Length(TPasProperty(Member).StoredAccessorName) > 0 then
+	    s := s + 's';
+	  if Length(s) > 0 then
+	    AppendText(CodeEl, '  [' + s + ']');
+        end else
+          AppendText(CreateWarning(CodeEl), '<' + Member.ClassName + '>');
+      end;
+
+      CodeEl := CreateCode(CreatePara(CreateTD(CreateTR(TableEl))));
+    end;
+
+    AppendText(CodeEl, ' '); // !!!: Dirty trick, necessary for current XML writer
+    AppendKw(CodeEl, 'end');
+    AppendSym(CodeEl, ';');
+
+
+    AppendText(CreateH2(BodyElement), SDocInheritance);
+    TableEl := CreateTable(BodyElement);
+    HaveSeenTObject := AClass.ObjKind <> okClass;
+    ThisClass := AClass;
+    while True do
+    begin
+      TREl := CreateTR(TableEl);
+      TDEl := CreateTD_vtop(TREl);
+      TDEl['align'] := 'center';
+      CodeEl := CreateCode(CreatePara(TDEl));
+      AppendHyperlink(CodeEl, ThisClass);
+      AppendShortDescrCell(TREl, ThisClass);
+      if HaveSeenTObject or (CompareText(ThisClass.Name, 'TObject') = 0) then
+        HaveSeenTObject := True
+      else
+      begin
+        TDEl := CreateTD(CreateTR(TableEl));
+        TDEl['align'] := 'center';
+        AppendText(TDEl, '|');
+      end;
+
+      if Assigned(ThisClass.AncestorType) then
+      begin
+        if ThisClass.AncestorType.InheritsFrom(TPasClassType) then
+          ThisClass := TPasClassType(ThisClass.AncestorType)
+        else
+        begin
+          TDEl := CreateTD(CreateTR(TableEl));
+	  TDEl['align'] := 'center';
+          AppendText(CreateCode(CreatePara(TDEl)), ThisClass.AncestorType.Name);
+	  if CompareText(ThisClass.AncestorType.Name, 'TObject') = 0 then
+	    HaveSeenTObject := True
+	  else
+	  begin
+            TDEl := CreateTD(CreateTR(TableEl));
+	    TDEl['align'] := 'center';
+	    AppendText(TDEl, '?');
+	  end;
+          break;
+        end
+      end else
+        break;
+    end;
+
+    if not HaveSeenTObject then
+    begin
+      TDEl := CreateTD(CreateTR(TableEl));
+      TDEl['align'] := 'center';
+      AppendText(CreateCode(CreatePara(TDEl)), 'TObject');
+    end;
+
+    FinishElementPage(AClass);
+  end;
+
+  procedure CreateInheritanceSubpage(AFilter: TMemberFilter);
+  var
+    ThisClass: TPasClassType;
+    i: Integer;
+    Member: TPasElement;
+    TableEl, TREl, TDEl, ParaEl, LinkEl: TDOMElement;
+  begin
+    TableEl := CreateTable(BodyElement);
+    ThisClass := AClass;
+    while True do
+    begin
+      TREl := CreateTR(TableEl);
+      TDEl := CreateTD(TREl);
+      TDEl['colspan'] := '3';
+      CreateTD(TREl);
+      LinkEl := AppendHyperlink(CreateEl(CreateCode(CreatePara(TDEl)), 'b'), ThisClass);
+      if Assigned(LinkEl) then
+	LinkEl['onClick'] := 'opener.location.href = ''' + LinkEl['href'] +
+	  '''; return false;';
+      for i := 0 to ThisClass.Members.Count - 1 do
+      begin
+        Member := TPasElement(ThisClass.Members[i]);
+        if ((Member.Visibility = visPrivate) and Engine.HidePrivate) or
+	  ((Member.Visibility = visProtected) and Engine.HideProtected) or
+	  not AFilter(Member) then
+	  continue;
+	TREl := CreateTR(TableEl);
+	ParaEl := CreatePara(CreateTD(TREl));
+	case Member.Visibility of
+	  visPrivate:
+	    AppendText(ParaEl, 'pv');
+	  visProtected:
+	    AppendText(ParaEl, 'pt');
+	  visPublished:
+	    AppendText(ParaEl, 'pl');
+	end;
+	AppendNbSp(ParaEl, 1);
+
+	ParaEl := CreateTD(TREl);
+	if (Member.ClassType = TPasProperty) and
+	  (Length(TPasProperty(Member).WriteAccessorName) = 0) then
+	begin
+	  AppendText(ParaEl, 'ro');
+	  AppendNbSp(ParaEl, 1);
+	end;
+
+        LinkEl := AppendHyperlink(CreatePara(CreateTD(TREl)), Member);
+	if Assigned(LinkEl) then
+	  LinkEl['onClick'] := 'opener.location.href = ''' + LinkEl['href'] +
+	    '''; return false;';
+      end;
+      if (not Assigned(ThisClass.AncestorType)) or
+        (not (ThisClass.AncestorType.ClassType = TPasClassType)) then
+	break;
+      ThisClass := TPasClassType(ThisClass.AncestorType);
+      AppendNbSp(CreatePara(CreateTD(CreateTR(TableEl))), 1);
+    end;
+  end;
+
+  procedure CreateSortedSubpage(AFilter: TMemberFilter);
+  var
+    List: TList;
+    ThisClass: TPasClassType;
+    i, j: Integer;
+    Member: TPasElement;
+    TableEl, TREl, TDEl, ParaEl, LinkEl: TDOMElement;
+  begin
+    List := TList.Create;
+    try
+      ThisClass := AClass;
+      while True do
+      begin
+        for i := 0 to ThisClass.Members.Count - 1 do
+        begin
+          Member := TPasElement(ThisClass.Members[i]);
+          if (not (((Member.Visibility = visPrivate) and Engine.HidePrivate) or
+	    ((Member.Visibility = visProtected) and Engine.HideProtected))) and
+	    AFilter(Member) then
+	  begin
+    	    j := 0;
+	    while (j < List.Count) and
+              (CompareText(TPasElement(List[j]).Name, Member.Name) < 0) do
+	      Inc(j);
+	    List.Insert(j, Member);
+	  end;
+	end;
+        if (not Assigned(ThisClass.AncestorType)) or
+          (not (ThisClass.AncestorType.ClassType = TPasClassType)) then
+	  break;
+        ThisClass := TPasClassType(ThisClass.AncestorType);
+      end;
+
+      TableEl := CreateTable(BodyElement);
+      for i := 0 to List.Count - 1 do
+      begin
+        Member := TPasElement(List[i]);
+        TREl := CreateTR(TableEl);
+        ParaEl := CreatePara(CreateTD(TREl));
+        case Member.Visibility of
+	  visPrivate:
+	    AppendText(ParaEl, 'pv');
+	  visProtected:
+	    AppendText(ParaEl, 'pt');
+	  visPublished:
+	    AppendText(ParaEl, 'pl');
+        end;
+        AppendNbSp(ParaEl, 1);
+
+        ParaEl := CreatePara(CreateTD(TREl));
+        if (Member.ClassType = TPasProperty) and
+	  (Length(TPasProperty(Member).WriteAccessorName) = 0) then
+	begin
+	  AppendText(ParaEl, 'ro');
+	  AppendNbSp(ParaEl, 1);
+	end;
+
+	TDEl := CreateTD(TREl);
+	TDEl['nowrap'] := 'nowrap';
+	ParaEl := CreatePara(TDEl);
+        LinkEl := AppendHyperlink(ParaEl, Member);
+	if Assigned(LinkEl) then
+	  LinkEl['onClick'] := 'opener.location.href = ''' + LinkEl['href'] +
+	    '''; return false;';
+	AppendText(ParaEl, ' (');
+        LinkEl := AppendHyperlink(ParaEl, Member.Parent);
+	if Assigned(LinkEl) then
+	  LinkEl['onClick'] := 'opener.location.href = ''' + LinkEl['href'] +
+	    '''; return false;';
+	AppendText(ParaEl, ')');
+      end;
+    finally
+      List.Free;
+    end;
+  end;
+
+begin
+  case ASubpageIndex of
+    0:
+      CreateMainPage;
+    PropertiesByInheritanceSubindex:
+      CreateInheritanceSubpage(@PropertyFilter);
+    PropertiesByNameSubindex:
+      CreateSortedSubpage(@PropertyFilter);
+    MethodsByInheritanceSubindex:
+      CreateInheritanceSubpage(@MethodFilter);
+    MethodsByNameSubindex:
+      CreateSortedSubpage(@MethodFilter);
+    EventsByInheritanceSubindex:
+      CreateInheritanceSubpage(@EventFilter);
+    EventsByNameSubindex:
+      CreateSortedSubpage(@EventFilter);
+  end;
+end;
+
+procedure THTMLWriter.CreateClassMemberPageBody(AElement: TPasElement);
+var
+  TableEl, TREl, CodeEl: TDOMElement;
+
+  procedure CreateVarPage(Element: TPasVariable);
+  begin
+    AppendHyperlink(CodeEl, Element.Parent);
+    AppendSym(CodeEl, '.');
+    AppendText(CodeEl, Element.Name);
+    if Assigned(Element.VarType) then
+    begin
+      AppendSym(CodeEl, ': ');
+      AppendSym(AppendType(CodeEl, TableEl, Element.VarType, False), ';');
+    end;
+  end;
+
+  procedure CreatePropertyPage(Element: TPasProperty);
+  var
+    NeedBreak: Boolean;
+  begin
+    AppendKw(CodeEl, 'property ');
+    AppendHyperlink(CodeEl, Element.Parent);
+    AppendSym(CodeEl, '.');
+    AppendText(CodeEl, Element.Name);
+    if Assigned(Element.VarType) then
+    begin
+      AppendSym(CodeEl, ': ');
+      AppendType(CodeEl, TableEl, Element.VarType, False);
+    end;
+
+    NeedBreak := False;
+    if Length(TPasProperty(Element).IndexValue) <> 0 then
+    begin
+      CreateEl(CodeEl, 'br');
+      AppendNbsp(CodeEl, 2);
+      AppendKw(CodeEl, 'index ');
+      AppendPasSHFragment(CodeEl, TPasProperty(Element).IndexValue, 0);
+      NeedBreak := True;
+    end;
+    if Length(TPasProperty(Element).ReadAccessorName) <> 0 then
+    begin
+      CreateEl(CodeEl, 'br');
+      AppendNbsp(CodeEl, 2);
+      AppendKw(CodeEl, 'read ');
+      AppendText(CodeEl, TPasProperty(Element).ReadAccessorName);
+      NeedBreak := True;
+    end;
+    if Length(TPasProperty(Element).WriteAccessorName) <> 0 then
+    begin
+      CreateEl(CodeEl, 'br');
+      AppendNbsp(CodeEl, 2);
+      AppendKw(CodeEl, 'write ');
+      AppendText(CodeEl, TPasProperty(Element).WriteAccessorName);
+      NeedBreak := True;
+    end;
+    if Length(TPasProperty(Element).StoredAccessorName) <> 0 then
+    begin
+      CreateEl(CodeEl, 'br');
+      AppendNbsp(CodeEl, 2);
+      AppendKw(CodeEl, 'stored ');
+      AppendText(CodeEl, TPasProperty(Element).StoredAccessorName);
+      NeedBreak := True;
+    end;
+    if Length(TPasProperty(Element).DefaultValue) <> 0 then
+    begin
+      CreateEl(CodeEl, 'br');
+      AppendNbsp(CodeEl, 2);
+      AppendKw(CodeEl, 'default ');
+      AppendPasSHFragment(CodeEl, TPasProperty(Element).DefaultValue, 0);
+      NeedBreak := True;
+    end;
+
+    AppendSym(CodeEl, ';');
+
+    if TPasProperty(Element).IsDefault or TPasProperty(Element).IsNodefault then
+    begin
+      if NeedBreak then
+      begin
+        CreateEl(CodeEl, 'br');
+        AppendNbsp(CodeEl, 2);
+      end;
+      if TPasProperty(Element).IsDefault then
+        AppendKw(CodeEl, 'default')
+      else
+        AppendKw(CodeEl, 'nodefault');
+      AppendSym(CodeEl, ';');
+    end;
+  end;
+
+var
+  s: String;
+  DocNode: TDocNode;
+begin
+  AppendMenuBar(-1);
+  AppendTitle(AElement.FullName);
+  AppendShortDescr(CreatePara(BodyElement), AElement);
+  AppendText(CreateH2(BodyElement), SDocDeclaration);
+
+  TableEl := CreateTable(BodyElement);
+  TREl := CreateTR(TableEl);
+  CodeEl := CreateCode(CreatePara(CreateTD(TREl)));
+  AppendText(CodeEl, ' ');	// !!!: Workaround for current HTML writer
+
+  case AElement.Visibility of
+    visPrivate: s := 'private';
+    visProtected: s := 'protected';
+    visPublic: s := 'public';
+    visPublished: s := 'published';
+    visAutomated: s := 'automated';
+    else s := '';
+  end;
+  if Length(s) > 0 then
+    AppendKw(CodeEl, s);
+  AppendText(CodeEl, ' ');
+
+  if AElement.ClassType = TPasVariable then
+    CreateVarPage(TPasVariable(AElement))
+  else if AElement.InheritsFrom(TPasProcedureBase) then
+    AppendProcDecl(CodeEl, TableEl, TPasProcedureBase(AElement))
+  else if AElement.ClassType = TPasProperty then
+    CreatePropertyPage(TPasProperty(AElement))
+  else
+    AppendText(CreateWarning(BodyElement), '<' + AElement.ClassName + '>');
+
+  FinishElementPage(AElement);
+end;
+
+procedure THTMLWriter.CreateVarPageBody(AVar: TPasVariable);
+var
+  TableEl, TREl, TDEl, CodeEl, El: TDOMElement;
+  DocNode: TDocNode;
+begin
+  AppendMenuBar(-1);
+  AppendTitle(AVar.FullName);
+  AppendShortDescr(CreatePara(BodyElement), AVar);
+  AppendText(CreateH2(BodyElement), SDocDeclaration);
+
+  TableEl := CreateTable(BodyElement);
+  TREl := CreateTR(TableEl);
+  TDEl := CreateTD(TREl);
+  CodeEl := CreateCode(CreatePara(TDEl));
+
+  AppendKw(CodeEl, 'var');
+  AppendText(CodeEl, ' ' + AVar.Name);
+  if Assigned(AVar.VarType) then
+  begin
+    AppendSym(CodeEl, ': ');
+    El := AppendType(CodeEl, TableEl, AVar.VarType, False);
+  end else
+    El := CodeEl;
+  if Length(AVar.Value) > 0 then
+    AppendPasSHFragment(El, ' = ' + AVar.Value + ';', 0)
+  else
+    AppendSym(El, ';');
+
+  FinishElementPage(AVar);
+end;
+
+procedure THTMLWriter.CreateProcPageBody(AProc: TPasProcedureBase);
+var
+  TableEl, TREl, TDEl, CodeEl: TDOMElement;
+begin
+  AppendMenuBar(-1);
+  AppendTitle(AProc.Name);
+  AppendShortDescr(CreatePara(BodyElement), AProc);
+  AppendText(CreateH2(BodyElement), SDocDeclaration);
+
+  TableEl := CreateTable(BodyElement);
+  TREl := CreateTR(TableEl);
+  TDEl := CreateTD(TREl);
+  CodeEl := CreateCode(CreatePara(TDEl));
+
+  AppendProcDecl(CodeEl, TableEl, AProc);
+
+  FinishElementPage(AProc);
+end;
+
+
+// private methods
+
+function THTMLWriter.GetPageCount: Integer;
+begin
+  Result := PageInfos.Count;
+end;
+
+end.
+
+
+{
+  $Log$
+  Revision 1.1  2003-03-17 23:03:20  michael
+  + Initial import in CVS
+
+  Revision 1.15  2003/03/13 22:02:13  sg
+  * New version with many bugfixes and our own parser (now independent of the
+    compiler source)
+
+  Revision 1.14  2002/11/15 19:46:32  sg
+  * Added support for classes and objects (formerly all objects have been
+    written als classes)
+
+  Revision 1.13  2002/05/24 00:13:22  sg
+  * much improved new version, including many linking and output fixes
+
+  Revision 1.12  2002/03/12 10:58:36  sg
+  * reworked linking engine and internal structure
+
+  Revision 1.11  2002/01/20 11:19:55  michael
+  + Added link attribute and property to TFPElement
+
+  Revision 1.10  2001/12/21 11:25:13  sg
+  * The parser can now unget two tokens from the scanner
+  * Added parsing and HTML output of range types
+  * Procedure/function variable bugfixes
+
+  Revision 1.9  2001/12/17 22:34:04  sg
+  * Fixed typo in output for menu bar
+
+  Revision 1.8  2001/12/17 13:41:17  jonas
+    * OsPathSeparator -> PathDelim
+}

+ 1316 - 0
utils/fpdoc/dw_latex.pp

@@ -0,0 +1,1316 @@
+{
+    $Id$
+
+    FPDoc  -  Free Pascal Documentation Tool
+    Copyright (C) 2000 - 2003 by
+      Areca Systems GmbH / Sebastian Guenther, [email protected]
+
+    * LaTeX output generator
+
+    See the file COPYING, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+}
+
+unit dw_LaTeX;
+
+{$MODE objfpc}
+{$H+}
+
+interface
+
+uses DOM, dGlobals, PasTree;
+
+const
+  LateXHighLight: Boolean = False;
+
+procedure CreateLaTeXDocForPackage(APackage: TPasPackage; AEngine: TFPDocEngine);
+
+
+implementation
+
+uses SysUtils, Classes, dWriter;
+
+type
+  TLabelType = (ltConst,ltVar,ltType,ltFunction,ltProcedure,ltClass,
+                ltChapter,ltSection,ltSubsection,
+                ltTable,ltFigure);
+  
+  TLaTeXWriter = class(TFPDocWriter)
+  protected
+    f: Text;
+    FLink: String;
+    Package: TPasPackage;
+    PackageName: String;
+    Module: TPasModule;
+    ModuleName: String;
+    FTableCount : Integer;
+    TableRowStartFlag, TableCaptionWritten: Boolean;
+
+    function GetLabel(AElement: TPasElement): String;
+
+    procedure Write(const s: String);
+    procedure WriteF(const s: String; const Args: array of const);
+    procedure WriteLn(const s: String);
+    procedure WriteLnF(const s: String; const Args: array of const);
+    // Tex functions
+    procedure WriteLabel(El: TPasElement);
+    procedure WriteLabel(const s: String);
+    procedure WriteIndex(El: TPasElement);
+    procedure WriteIndex(const s: String);
+    procedure StartListing(Frames: Boolean; const name: String);
+    procedure StartListing(Frames: Boolean);
+    procedure EndListing;
+
+    procedure WriteCommentLine;
+    procedure WriteComment(Comment : String);
+    procedure StartSection(SectionName : String; SectionLabel : String);
+    procedure StartSection(SectionName : String);
+    procedure StartSubSection(SubSectionName : String; SubSectionLabel : String);
+    procedure StartSubSection(SubSectionName : String);
+    procedure StartChapter(ChapterName : String; ChapterLabel : String);
+    procedure StartChapter(ChapterName : String);
+    // Description node conversion
+    procedure DescrWriteText(const AText: DOMString); override;
+    procedure DescrBeginBold; override;
+    procedure DescrEndBold; override;
+    procedure DescrBeginItalic; override;
+    procedure DescrEndItalic; override;
+    procedure DescrBeginEmph; override;
+    procedure DescrEndEmph; override;
+    procedure DescrWriteFileEl(const AText: DOMString); override;
+    procedure DescrWriteKeywordEl(const AText: DOMString); override;
+    procedure DescrWriteVarEl(const AText: DOMString); override;
+    procedure DescrBeginLink(const AId: DOMString); override;
+    procedure DescrEndLink; override;
+    procedure DescrWriteLinebreak; override;
+    procedure DescrBeginParagraph; override;
+    procedure DescrBeginCode(HasBorder: Boolean; const AHighlighterName: String); override;
+    procedure DescrWriteCodeLine(const ALine: String); override;
+    procedure DescrEndCode; override;
+    procedure DescrEndParagraph; override;
+    procedure DescrBeginOrderedList; override;
+    procedure DescrEndOrderedList; override;
+    procedure DescrBeginUnorderedList; override;
+    procedure DescrEndUnorderedList; override;
+    procedure DescrBeginDefinitionList; override;
+    procedure DescrEndDefinitionList; override;
+    procedure DescrBeginListItem; override;
+    procedure DescrEndListItem; override;
+    procedure DescrBeginDefinitionTerm; override;
+    procedure DescrEndDefinitionTerm; override;
+    procedure DescrBeginDefinitionEntry; override;
+    procedure DescrEndDefinitionEntry; override;
+    procedure DescrBeginSectionTitle; override;
+    procedure DescrBeginSectionBody; override;
+    procedure DescrEndSection; override;
+    procedure DescrBeginRemark; override;
+    procedure DescrEndRemark; override;
+    procedure DescrBeginTable(ColCount: Integer; HasBorder: Boolean); override;
+    procedure DescrEndTable; override;
+    procedure DescrBeginTableCaption; override;
+    procedure DescrEndTableCaption; override;
+    procedure DescrBeginTableHeadRow; override;
+    procedure DescrEndTableHeadRow; override;
+    procedure DescrBeginTableRow; override;
+    procedure DescrEndTableRow; override;
+    procedure DescrBeginTableCell; override;
+    procedure DescrEndTableCell; override;
+    procedure WriteDescr(Element: TPasElement);
+    procedure WriteDescr(AContext: TPasElement; DescrNode: TDOMElement);
+    function ConstValue(ConstDecl: TPasConst): String;
+    procedure ProcessSection(ASection: TPasSection);
+    // Documentation writing methods.
+    procedure WriteResourceStrings(ASection: TPasSection);
+    procedure WriteUnitOverview(ASection: TPasSection);
+    procedure WriteVarsConstsTypes(ASection: TPasSection);
+    procedure WriteConsts(ASection: TPasSection);
+    procedure WriteTypes(ASection: TPasSection);
+    procedure WriteEnumElements(TypeDecl : TPasEnumType);
+    procedure WriteVars(ASection: TPasSection);
+    procedure WriteFunctionsAndProcedures(ASection: TPasSection);
+    procedure WriteProcedure(ProcDecl: TPasProcedureBase);
+    procedure WriteClasses(ASection: TPasSection);
+    procedure WriteClassDecl(ClassDecl: TPasClassType);
+    procedure WriteClassMethodOverview(ClassDecl: TPasClassType);
+    procedure WriteClassPropertyOverview(ClassDecl: TPasClassType);
+    procedure WriteProperty(PropDecl: TPasProperty);
+    procedure WriteExample(ADocNode: TDocNode);
+    procedure WriteSeeAlso(ADocNode: TDocNode);
+    procedure SortElementList(List : TList);
+    Function  ShowMember(M : TPasElement) : boolean;
+  public
+    constructor Create(APackage: TPasPackage; AEngine: TFPDocEngine);
+    procedure WriteDoc;
+  end;
+
+
+
+constructor TLaTeXWriter.Create(APackage: TPasPackage; AEngine: TFPDocEngine);
+
+  procedure AddLabel(AElement: TPasElement);
+  begin
+    Engine.AddLink(AElement.PathName, GetLabel(AElement));
+  end;
+
+  procedure AddList(AElement: TPasElement; AList: TList);
+  var
+    i: Integer;
+  begin
+    for i := 0 to AList.Count - 1 do
+      AddLabel(TPasElement(AList[i]));
+  end;
+
+  procedure ScanModule(AModule: TPasModule);
+  var
+    i, j, k: Integer;
+    s: String;
+    ClassEl: TPasClassType;
+    FPEl, AncestorMemberEl: TPasElement;
+    DocNode: TDocNode;
+    DidAutolink: Boolean;
+  begin
+    AddLabel(AModule);
+    with AModule do
+    begin
+      AddList(AModule, InterfaceSection.ResStrings);
+      AddList(AModule, InterfaceSection.Consts);
+      AddList(AModule, InterfaceSection.Types);
+      if InterfaceSection.Classes.Count > 0 then
+      begin
+        for i := 0 to InterfaceSection.Classes.Count - 1 do
+	begin
+	  ClassEl := TPasClassType(InterfaceSection.Classes[i]);
+          AddLabel(ClassEl);
+
+          for j := 0 to ClassEl.Members.Count - 1 do
+          begin
+            FPEl := TPasElement(ClassEl.Members[j]);
+            if ((FPEl.Visibility = visPrivate) and Engine.HidePrivate) or
+	      ((FPEl.Visibility = visProtected) and Engine.HideProtected) then
+	      continue;
+
+            DocNode := Engine.FindDocNode(FPEl);
+            if not Assigned(DocNode) then
+            begin
+              DidAutolink := False;
+	      if Assigned(ClassEl.AncestorType) and
+	        (ClassEl.AncestorType.ClassType = TPasClassType) then
+	      begin
+	        for k := 0 to TPasClassType(ClassEl.AncestorType).Members.Count - 1 do
+	        begin
+	          AncestorMemberEl :=
+	            TPasElement(TPasClassType(ClassEl.AncestorType).Members[k]);
+	          if AncestorMemberEl.Name = FPEl.Name then
+	          begin
+	            DocNode := Engine.FindDocNode(AncestorMemberEl);
+	            if Assigned(DocNode) then
+	            begin
+	              DidAutolink := True;
+		      Engine.AddLink(FPEl.PathName,
+	    		Engine.FindAbsoluteLink(AncestorMemberEl.PathName));
+	              break;
+	            end;
+	          end;
+	        end;
+	      end;
+	      if not DidAutolink then
+	        AddLabel(FPEl);
+	    end else
+    	      AddLabel(FPEl);
+    	  end;
+	end;
+      end;
+      AddList(AModule, InterfaceSection.Functions);
+      AddList(AModule, InterfaceSection.Variables);
+    end;
+  end;
+
+var
+  i: Integer;
+begin
+  inherited Create(AEngine);
+  Package := APackage;
+
+  { Allocate labels for all elements for which we are going to create
+    documentation. This is needed for links to work correctly. }
+
+  // Allocate label for the package itself, if a name is given (i.e. <> '#')
+  if Length(Package.Name) > 1 then
+    AddLabel(Package);
+
+  for i := 0 to Package.Modules.Count - 1 do
+    ScanModule(TPasModule(Package.Modules[i]));
+end;
+
+procedure TLaTeXWriter.WriteDoc;
+var
+  i: Integer;
+begin
+  PackageName := LowerCase(Copy(Package.Name, 2, 255));
+  Assign(f,  Engine.Output + PathDelim + PackageName + '.tex');
+  Rewrite(f);
+  try
+    WriteLn('% This file has been created automatically by FPDoc,');
+    WriteLn('% (c) 2000-2003 by Areca Systems GmbH / Sebastian Guenther ([email protected])');
+    for i := 0 to Package.Modules.Count - 1 do
+    begin
+      Module := TPasModule(Package.Modules[i]);
+      ModuleName := LowerCase(Module.Name);
+      WriteLn('');
+      WriteLnF('\chapter{%s}', [Format(SDocUnitTitle, [Module.Name])]);
+      WriteLabel(Module);
+      ProcessSection(Module.InterfaceSection);
+    end;
+  finally
+    Close(f);
+  end;
+end;
+
+function TLaTeXWriter.GetLabel(AElement: TPasElement): String;
+var
+  i: Integer;
+begin
+  if AElement.ClassType = TPasUnresolvedTypeRef then
+    Result := Engine.ResolveLink(Module, AElement.Name)
+  else
+  begin
+    Result := AElement.PathName;
+    Result := LowerCase(Copy(Result, 2, Length(Result) - 1));
+  end;
+  for i := 1 to Length(Result) do
+    if Result[i] = '.' then
+      Result[i] := ':';
+end;
+
+procedure TLaTeXWriter.Write(const s: String);
+begin
+  System.Write(f, s);
+end;
+
+procedure TLaTeXWriter.WriteF(const s: String; const Args: array of const);
+begin
+  System.Write(f, Format(s, Args));
+end;
+
+procedure TLaTeXWriter.WriteLn(const s: String);
+begin
+  System.WriteLn(f, s);
+end;
+
+procedure TLaTeXWriter.WriteLnF(const s: String; const Args: array of const);
+begin
+  System.WriteLn(f, Format(s, Args));
+end;
+
+procedure TLaTeXWriter.DescrWriteText(const AText: DOMString);
+var
+  i: Integer;
+  s: DOMString;
+begin
+  SetLength(s, 0);
+  for i := 1 to Length(AText) do
+    case AText[i] of
+      '&','{','}','#','_','$','%':		// Escape these characters
+        s := s + '\' + AText[i];
+      '~','^':
+        S := S + '\'+AText[i]+' ';
+      '\': 
+        S:=S+'$\backslash$'  
+      else
+        s := s + AText[i];
+    end;
+  Write(s);
+end;
+
+procedure TLaTeXWriter.DescrBeginBold;
+begin
+  Write('\textbf{');
+end;
+
+procedure TLaTeXWriter.DescrEndBold;
+begin
+  Write('}');
+end;
+
+procedure TLaTeXWriter.DescrBeginItalic;
+begin
+  Write('\textit{');
+end;
+
+procedure TLaTeXWriter.DescrEndItalic;
+begin
+  Write('}');
+end;
+
+procedure TLaTeXWriter.DescrBeginEmph;
+begin
+  Write('\emph{');
+end;
+
+procedure TLaTeXWriter.DescrEndEmph;
+begin
+  Write('}');
+end;
+
+procedure TLaTeXWriter.DescrWriteFileEl(const AText: DOMString);
+begin
+  Write('\file{');
+  DescrWriteText(AText);
+  Write('}');
+end;
+
+procedure TLaTeXWriter.DescrWriteKeywordEl(const AText: DOMString);
+begin
+  Write('\textbf{\\ttfamily ');
+  DescrWriteText(AText);
+  Write('}');
+end;
+
+procedure TLaTeXWriter.DescrWriteVarEl(const AText: DOMString);
+begin
+  Write('\var{');
+  DescrWriteText(AText);
+  Write('}');
+end;
+
+procedure TLaTeXWriter.DescrBeginLink(const AId: DOMString);
+var
+  i: Integer;
+begin
+  FLink := Engine.ResolveLink(Module, AId);
+//  System.WriteLn('Link "', AId, '" => ', FLink);
+end;
+
+procedure TLaTeXWriter.DescrEndLink;
+begin
+  WriteF(' (\pageref{%s})',[Flink]);
+end;
+
+procedure TLaTeXWriter.DescrWriteLinebreak;
+begin
+  WriteLn('\\');
+end;
+
+procedure TLaTeXWriter.DescrBeginParagraph;
+begin
+  // Do nothing
+end;
+
+procedure TLaTeXWriter.DescrEndParagraph;
+begin
+  WriteLn('');
+  WriteLn('');
+end;
+
+procedure TLaTeXWriter.DescrBeginCode(HasBorder: Boolean;
+  const AHighlighterName: String);
+begin
+  StartListing(HasBorder);
+end;
+
+procedure TLaTeXWriter.DescrWriteCodeLine(const ALine: String);
+begin
+  WriteLn(ALine);
+end;
+
+procedure TLaTeXWriter.DescrEndCode;
+begin
+  EndListing
+end;
+
+procedure TLaTeXWriter.DescrBeginOrderedList;
+begin
+  WriteLn('\begin{enumerate}');
+end;
+
+procedure TLaTeXWriter.DescrEndOrderedList;
+begin
+  WriteLn('\end{enumerate}');
+end;
+
+procedure TLaTeXWriter.DescrBeginUnorderedList;
+begin
+  WriteLn('\begin{itemize}');
+end;
+
+procedure TLaTeXWriter.DescrEndUnorderedList;
+begin
+  WriteLn('\end{itemize}');
+end;
+
+procedure TLaTeXWriter.DescrBeginDefinitionList;
+begin
+  WriteLn('\begin{description');
+end;
+
+procedure TLaTeXWriter.DescrEndDefinitionList;
+begin
+  WriteLn('\end{description}');
+end;
+
+procedure TLaTeXWriter.DescrBeginListItem;
+begin
+  Write('\item ');
+end;
+
+procedure TLaTeXWriter.DescrEndListItem;
+begin
+  WriteLn('');
+end;
+
+procedure TLaTeXWriter.DescrBeginDefinitionTerm;
+begin
+  Write('\item[');
+end;
+
+procedure TLaTeXWriter.DescrEndDefinitionTerm;
+begin
+  WriteLn(']');
+end;
+
+procedure TLaTeXWriter.DescrBeginDefinitionEntry;
+begin
+  // Do nothing
+end;
+
+procedure TLaTeXWriter.DescrEndDefinitionEntry;
+begin
+  WriteLn('');
+end;
+
+procedure TLaTeXWriter.DescrBeginSectionTitle;
+begin
+  Write('\subsection{');
+end;
+
+procedure TLaTeXWriter.DescrBeginSectionBody;
+begin
+  WriteLn('}');
+end;
+
+procedure TLaTeXWriter.DescrEndSection;
+begin
+  // Do noting
+end;
+
+procedure TLaTeXWriter.DescrBeginRemark;
+begin
+  WriteLn('\begin{remark}');
+end;
+
+procedure TLaTeXWriter.DescrEndRemark;
+begin
+  WriteLn('\end{remark}');
+end;
+
+procedure TLaTeXWriter.DescrBeginTable(ColCount: Integer; HasBorder: Boolean);
+var
+  i: Integer;
+begin
+  // !!!: How do we set the border?
+  Write('\begin{FPCltable}{');
+  for i := 1 to ColCount do
+    Write('l');  
+  write('}{');
+  TableCaptionWritten:=False;
+end;
+
+procedure TLaTeXWriter.DescrEndTable;
+begin
+  WriteLn('\end{FPCltable}');
+end;
+
+procedure TLaTeXWriter.DescrBeginTableCaption;
+begin
+  // Do nothing.
+end;
+
+procedure TLaTeXWriter.DescrEndTableCaption;
+begin
+  Write('}{table');
+  Inc(FTableCount);
+  Write(IntToStr(FTableCount));
+  Writeln('}');
+  TableCaptionWritten := True;
+end;
+
+procedure TLaTeXWriter.DescrBeginTableHeadRow;
+begin
+  if not TableCaptionWritten then
+    DescrEndTableCaption;
+  TableRowStartFlag := True;
+end;
+
+procedure TLaTeXWriter.DescrEndTableHeadRow;
+begin
+  WriteLn('\\ \hline');
+end;
+
+procedure TLaTeXWriter.DescrBeginTableRow;
+begin
+  if not TableCaptionWritten then
+    DescrEndTableCaption;
+  TableRowStartFlag := True;
+end;
+
+procedure TLaTeXWriter.DescrEndTableRow;
+begin
+  WriteLn('\\');
+end;
+
+procedure TLaTeXWriter.DescrBeginTableCell;
+begin
+  if TableRowStartFlag then
+    TableRowStartFlag := False
+  else
+    Write(' & ');
+end;
+
+procedure TLaTeXWriter.DescrEndTableCell;
+begin
+  // Do nothing
+end;
+
+
+procedure TLaTeXWriter.WriteDescr(Element: TPasElement);
+var
+  DocNode: TDocNode;
+begin
+  DocNode := Engine.FindDocNode(Element);
+  if Assigned(DocNode) then
+    begin
+    if not IsDescrNodeEmpty(DocNode.Descr) then
+      WriteDescr(Element, DocNode.Descr)
+    else if not IsDescrNodeEmpty(DocNode.ShortDescr) then
+      WriteDescr(Element, DocNode.ShortDescr);
+    end;
+end;
+
+procedure TLaTeXWriter.WriteDescr(AContext: TPasElement; DescrNode: TDOMElement);
+begin
+  if Assigned(DescrNode) then
+    ConvertDescr(AContext, DescrNode, False);
+end;
+
+function TLaTeXWriter.ConstValue(ConstDecl: TPasConst): String;
+begin
+  if Assigned(ConstDecl) then
+    Result := ConstDecl.ClassName
+  else
+    Result := '<nil>';
+end;
+
+procedure TLaTexWriter.WriteUnitOverview(ASection: TPasSection);
+var
+  i: Integer;
+  UnitRef: TPasType;
+  DocNode: TDocNode;
+begin
+  if ASection.UsesList.Count > 0 then
+  begin
+    WriteLnF('\section{%s}', [SDocUsedUnits]);
+    WriteLnF('\begin{FPCltable}{lr}{%s}{%s:0units}',
+      [Format(SDocUsedUnitsByUnitXY, [Module.Name]), ModuleName]);
+    WriteLn('Name & Page \\ \hline');
+    for i := 0 to ASection.UsesList.Count - 1 do
+    begin
+      UnitRef := TPasType(ASection.UsesList[i]);
+      WriteLnF('%s\index{unit!%s} & \pageref{%s} \\',
+        [UnitRef.Name, UnitRef.Name, GetLabel(UnitRef)]);
+    end;
+    WriteLn('\end{FPCltable}');
+  end;
+  DocNode := Engine.FindDocNode(ASection.Parent);
+  if Assigned(DocNode) and not IsDescrNodeEmpty(DocNode.Descr) then
+  begin
+    WriteLnF('\section{%s}', [SDocOverview]);
+    WriteDescr(ASection.Parent, DocNode.Descr);
+    Writeln('');
+  end;
+end;
+
+procedure TLaTeXWriter.WriteResourceStrings(ASection: TPasSection);
+var
+  ResStrDecl: TPasResString;
+  i: Integer;
+begin
+  if ASection.ResStrings.Count > 0 then
+  begin
+    StartSubSection(SDocResStrings,ModuleName+'ResStrings');
+    for i := 0 to ASection.ResStrings.Count - 1 do
+    begin
+      ResStrDecl := TPasResString(ASection.ResStrings[i]);
+      StartListing(false, '');
+      Writeln(ResStrDecl.GetDeclaration(True));
+      EndListing;
+      WriteLabel(ResStrDecl);
+      WriteIndex(ResStrDecl);
+      WriteDescr(ResStrDecl);
+      Writeln('');
+    end;
+  end;
+end;
+
+procedure TLaTeXWriter.WriteConsts(ASection: TPasSection);
+var
+  i: Integer;
+  ConstDecl: TPasConst;
+begin
+  if ASection.Consts.Count > 0 then
+  begin
+    WriteLnF('\subsection{%s}\label{suse:%sConstants}',
+      [SDocConstants, ModuleName]);
+    for i := 0 to ASection.Consts.Count - 1 do
+    begin
+      ConstDecl := TPasConst(ASection.Consts[i]);
+      StartListing(False);
+      WriteLn(ConstDecl.GetDeclaration(True));
+      EndListing;
+      WriteLabel(ConstDecl);  
+      WriteIndex(ConstDecl);
+      WriteDescr(ConstDecl);
+    end;
+  end;
+end;
+
+procedure TLaTeXWriter.WriteEnumElements(TypeDecl : TPasEnumType);
+
+Var
+  EV : TPasEnumValue;
+  I : Integer;
+  DocNode : TDocNode;
+  
+begin
+  With TypeDecl do
+    begin
+    SortElementList(Values);
+    DescrBeginTable(2,True);
+    DescrBeginTableCaption;
+      Writeln(Format(SDocValuesForEnum,[TypeDecl.Name]));
+    DescrEndTableCaption;
+    DescrBeginTableHeadRow;
+      DescrBeginTableCell;
+        Writeln(SDocValue);
+      DescrEndTableCell;
+      DescrBeginTableCell;
+        Writeln(SDocExplanation);
+      DescrEndTableCell;
+    DescrEndTableHeadRow;
+    For I:=0 to Values.Count-1 do
+      begin
+      EV:=TPasEnumValue(Values[i]);
+      DescrBeginTableRow;
+        DescrBeginTableCell;
+          Writeln(EV.Name);
+        DescrEndTableCell;
+        DescrBeginTableCell;
+          DocNode := Engine.FindDocNode(EV);
+          if Assigned(DocNode) and (not IsDescrNodeEmpty(DocNode.ShortDescr)) then
+            WriteDescr(EV,DocNode.ShortDescr);
+        DescrEndTableCell;
+      DescrEndTableRow;  
+      end;
+    DescrEndTable;
+    end;  
+end;
+
+procedure TLaTeXWriter.WriteTypes(ASection: TPasSection);
+var
+  i: Integer;
+  TypeDecl: TPasType;
+begin
+  if ASection.Types.Count > 0 then
+  begin
+    StartSubSection(SDocTypes,ModuleName+'Types');
+    for i := 0 to ASection.Types.Count - 1 do
+    begin
+      TypeDecl := TPasType(ASection.Types[i]);
+      StartListing(False);
+      Writeln(TypeDecl.GetDeclaration(True));
+      EndListing;
+      WriteLabel(TypeDecl);
+      WriteIndex(TypeDecl);
+      If TypeDecl is TPasEnumType then
+        begin
+        WriteENumElements(TypeDecl as TPasEnumType);
+        end;
+      WriteDescr(TypeDecl);
+    end;
+  end;
+end;
+
+procedure TLaTeXWriter.WriteVars(ASection: TPasSection);
+var                        
+  VarDecl: TPasVariable;
+  i: Integer;
+begin
+  if ASection.Variables.Count > 0 then
+  begin
+    StartSubsection(SDocVariables,ModuleName+'Variables');
+    for i := 0 to ASection.Variables.Count - 1 do
+    begin
+      VarDecl := TPasVariable(ASection.Variables[i]);
+      StartListing(False);
+      WriteLn(VarDecl.GetDeclaration(True));
+      EndListing;
+      WriteLabel(VarDecl);
+      WriteIndex(VarDecl);
+      WriteDescr(VarDecl);
+    end;
+  end;
+end;
+
+procedure TLaTeXWriter.WriteVarsConstsTypes(ASection: TPasSection);
+begin
+  With Asection do
+    if (Consts.Count > 0) or 
+       (Types.Count > 0) or
+       (Variables.Count > 0) or
+       (ResStrings.Count>0) then
+      begin
+      StartSection(SDocConstsTypesVars, ModuleName+'ConstsTypesVars');
+      WriteResourceStrings(ASection);
+      WriteConsts(ASection);
+      WriteTypes(ASection);
+      WriteVars(ASection);
+      end;
+end;
+
+const 
+  SVisibility: array[TPasMemberVisibility] of string = 
+       ('Default', 'Private', 'Protected', 'Public',
+      'Published', 'Automated');
+
+procedure TLatexWriter.WriteProcedure(ProcDecl : TPasProcedureBase);
+var
+  DocNode: TDocNode;
+  OP : TPasOverloadedProc;
+  i : integer; 
+begin
+  With ProcDecl do
+    begin
+    if Not (Assigned(Parent) and Parent.InheritsFrom(TPasClassType)) then
+      begin
+      StartSubSection(Name);
+      WriteLabel(ProcDecl);
+      WriteIndex(ProcDecl);
+      end
+    else
+      begin // Parent assigned and hence method.
+      StartSubSection(Parent.Name+'.'+Name);
+      WriteLabel(ProcDecl);
+      WriteIndex(Parent.Name+'.'+Name);
+      end;  
+    Writeln('\begin{FPCList}');
+    DocNode := Engine.FindDocNode(ProcDecl);
+    if Assigned(DocNode) and Assigned(DocNode.ShortDescr) then
+      begin
+      Writeln('\Synopsis');
+      WriteDescr(ProcDecl, DocNode.ShortDescr);
+      end;
+    Writeln('\Declaration ');  
+    StartListing(False);
+    if ClassType = TPasOverloadedProc then
+      begin
+      OP:=TPasOverloadedProc(ProcDecl);
+      for i := 0 to OP.Overloads.Count - 1 do
+        begin
+        WriteLn(TPasProcedure(OP.Overloads[i]).GetDeclaration(True));
+        end;
+      end
+    else
+      WriteLn(GetDeclaration(True));
+    EndListing;
+    If Assigned(Parent) then
+      begin
+      Writeln('\Visibility');
+      Writeln(VisibilityNames[Visibility])
+      end;
+    if Assigned(DocNode) and Assigned(DocNode.Descr) then
+      begin
+      Writeln('\Description');
+      WriteDescr(ProcDecl);
+      end;
+    if Assigned(DocNode) and Assigned(DocNode.ErrorsDoc) then   
+      begin
+      Writeln('\Errors');
+      WriteDescr(ProcDecl, DocNode.ErrorsDoc);
+      end;
+    WriteSeeAlso(DocNode);
+    Writeln('\end{FPCList}');
+    WriteExample(DocNode);
+    end;
+end;
+
+procedure TLaTeXWriter.WriteFunctionsAndProcedures(ASection: TPasSection);
+var
+  i: Integer;
+begin
+  if ASection.Functions.Count > 0 then
+    begin
+    StartSection(SDocProceduresAndFunctions,ModuleName+'Functions');
+    for i := 0 to ASection.Functions.Count - 1 do
+      WriteProcedure(TPasProcedureBase(ASection.Functions[i]));
+    end;
+end;
+
+procedure TlatexWriter.WriteExample(ADocNode: TDocNode);
+var
+  Example: TDOMElement;
+begin
+  if Assigned(ADocNode) then
+  begin
+    Example := ADocNode.FirstExample;
+    while Assigned(Example) do
+    begin
+      WritelnF('\FPCexample{%s}', [Engine.GetExampleFileName(Example)]);
+      if Assigned(Example.NextSibling) then
+        WriteLn('');
+      Example := TDomElement(Example.NextSibling);   
+    end;
+  end;
+end;
+
+procedure TLateXWriter.WriteSeeAlso(ADocNode: TDocNode);
+var
+  Node: TDOMNode;
+  s: String;
+begin
+  if Assigned(ADocNode) and Assigned(ADocNode.SeeAlso) and
+    Assigned(ADocNode.SeeAlso.FirstChild) then
+  begin
+    Writeln('\SeeAlso');
+    Node := ADocNode.SeeAlso.FirstChild;
+    while Assigned(Node) do
+    begin 
+      if (Node.NodeType = ELEMENT_NODE) and 
+        (Node.NodeName = 'link') then
+      begin
+        S:=TDomElement(Node)['id'];
+        DescrBeginLink(S);
+        Writeln(S);
+        DescrEndLink();
+        if Assigned(Node.NextSibling) Then
+          Writeln(',');
+      end;  
+      Node:=Node.NextSibling;  
+    end;
+  end;   
+end;
+
+procedure TLaTeXWriter.WriteClasses(ASection: TPasSection);
+var
+  i: Integer;
+begin
+  if (ASection.Classes.Count > 0) then
+  begin
+    for i := 0 to ASection.Classes.Count - 1 do
+      WriteClassDecl(TPasClassType(ASection.Classes[i]));
+  end;
+
+end;
+
+procedure TLaTeXWriter.ProcessSection(ASection: TPasSection);
+begin
+  With ASection do
+    begin
+    SortElementList(UsesList);
+    SortElementList(Declarations);
+    SortElementList(ResStrings);
+    SortElementList(Types);
+    SortElementList(Consts);
+    SortElementList(Classes);
+    SortElementList(Functions);
+    SortElementList(Variables);
+    end;
+  WriteUnitOverView(ASection);
+  WriteVarsConstsTypes(ASection);
+  WriteFunctionsAndProcedures(ASection);
+  WriteClasses(ASection);
+end;
+
+Function TLatexWriter.ShowMember(M : TPasElement) : boolean;
+
+begin
+  Result:=not ((M.Visibility=visPrivate) and Engine.HidePrivate);
+  If Result then
+    Result:=Not ((M.Visibility=visProtected) and Engine.HideProtected)
+end;
+
+procedure TLatexWriter.WriteClassMethodOverview(ClassDecl : TPasClassType);
+var
+  Member: TPasElement;
+  i, j: Integer;
+  s: String;
+  Arg: TPasArgument;
+  DocNode: TDocNode;
+  Ref : String;
+  List : TStringList;
+  
+begin
+  List:=TStringList.Create;
+  Try
+    List.Sorted:=True;
+    for i := 0 to ClassDecl.Members.Count - 1 do
+      begin
+      Member := TPasElement(ClassDecl.Members[i]);
+      With Member do 
+        if InheritsFrom(TPasProcedureBase) and ShowMember(Member) then
+      List.AddObject(Member.Name,Member);
+      end;
+    If List.Count>0 then
+      begin
+      StartSubSection(SDocMethodOverview);
+      WriteLabel(GetLabel(ClassDecl) + ':Methods');
+      WriteLn('\begin{tabularx}{\textwidth}{llX}');
+      WriteLnF('%s & %s & %s \\ \hline',  [SDocPage, SDocMethod, SDocDescription]);
+      For I:=0 to List.Count-1 do
+        begin
+        Member:=TPasElement(List.Objects[i]);
+        DocNode := Engine.FindDocNode(Member);
+        if Assigned(DocNode) and (Length(DocNode.Link) > 0) then
+          ref:=Format('%s:%s',[Modulename,DocNode.link])
+        else
+          ref:=Format('%s:%s.%s',[ModuleName, LowerCase(ClassDecl.Name),LowerCase(Member.Name)]);
+        WriteF('\pageref{%s} & %s & ',[GetLabel(Member), Member.Name]);
+        if Assigned(DocNode) and Assigned(DocNode.ShortDescr) then
+          WriteDescr(Member, DocNode.ShortDescr);
+        WriteLn('\\');
+        end;
+      WriteLn('\hline');
+      WriteLn('\end{tabularx}');
+      end;
+  Finally
+    List.Free;
+  end;  
+end;
+
+procedure TLatexWriter.WriteClassPropertyOverview(ClassDecl : TPasClassType);
+var
+  Member: TPasElement;
+  i, j: Integer;
+  s: String;
+  Arg: TPasArgument;
+  DocNode: TDocNode;
+  List : TStringList;
+  
+begin
+  // Write property overview
+  List:=TStringList.Create;
+  Try
+    List.Sorted:=True;
+    for i := 0 to ClassDecl.Members.Count - 1 do
+      begin
+      Member := TPasElement(ClassDecl.Members[i]);
+      With Member do
+        if InheritsFrom(TPasProperty) and SHowMember(Member) then
+          List.AddObject(Member.Name,Member)
+      end;
+    If (List.Count>0) then  
+      begin
+      StartSubSection(SDocPropertyOverview);
+      WriteLabel(GetLabel(ClassDecl) + ':Properties');
+      WriteLn('\begin{tabularx}{\textwidth}{lllX}');
+      WriteLnF('%s & %s & %s & %s \\ \hline',
+        [SDocPage, SDocProperty, SDocAccess, SDocDescription]);
+      For I:=0 to List.Count-1 do
+        begin  
+        Member:=TPasElement(List.objects[i]);
+        WriteF('\pageref{%s} & %s & ', [GetLabel(Member), Member.Name]);
+        setlength(S,0);
+        if Length(TPasProperty(Member).ReadAccessorName) > 0 then
+          s := s + 'r';
+        if Length(TPasProperty(Member).WriteAccessorName) > 0 then
+          s := s + 'w';
+        if Length(TPasProperty(Member).StoredAccessorName) > 0 then
+          s := s + 's';
+        Write(s + ' & ');
+        DocNode := Engine.FindDocNode(Member);
+        if Assigned(DocNode) and Assigned(DocNode.ShortDescr) then
+          WriteDescr(Member, DocNode.ShortDescr);
+        WriteLn('\\');
+        end;
+      WriteLn('\hline');
+      WriteLn('\end{tabularx}');
+      end;
+  Finally
+    List.Free;
+  end;      
+end;
+
+
+procedure TLaTeXWriter.WriteClassDecl(ClassDecl: TPasClassType);
+var
+  DocNode: TDocNode;
+  Vis: TPasMemberVisibilities;
+  Member: TPasElement;
+  i: Integer;
+begin
+  StartSection(ClassDecl.Name);
+  WriteLabel(ClassDecl);
+  WriteIndex(ClassDecl);
+  DocNode := Engine.FindDocNode(ClassDecl);
+  if Assigned(DocNode) and ((not IsDescrNodeEmpty(DocNode.Descr)) or
+    (not IsDescrNodeEmpty(DocNode.ShortDescr))) then
+  begin
+    StartSubSection(SDocDescription);
+    WriteDescr(ClassDecl);
+  end;
+
+  // Write method overview
+  WriteClassMethodOverView(ClassDecl);
+  // Write Property Overview;
+  WriteClassPropertyOverView(ClassDecl);
+
+  // Write method & property descriptions
+  
+  // Determine visibilities 
+
+  Vis := AllVisibilities;
+  if Engine.HidePrivate then
+    Exclude(Vis,visPrivate);
+  if Engine.HideProtected then
+    Exclude(Vis,visProtected);
+
+  for i := 0 to ClassDecl.Members.Count - 1 do
+    begin
+    Member := TPasElement(ClassDecl.Members[i]);
+    if ((Member.InheritsFrom(TPasProcedureBase)) and
+        (Member.Visibility in Vis)) then
+      WriteProcedure(TPasProcedureBase(Member));
+    end;
+
+  // properties.
+
+  for i := 0 to ClassDecl.Members.Count - 1 do
+    begin
+    Member := TPasElement(ClassDecl.Members[i]);
+    if ((Member.InheritsFrom(TPasProperty)) and
+        (Member.Visibility in Vis)) then
+      WriteProperty(TPasProperty(Member));
+    end;
+
+end;
+
+procedure TLaTexWriter.WriteProperty(PropDecl : TPasProperty);
+var
+  DocNode: TDocNode;
+  S: String;
+begin
+  With PropDecl do
+    begin
+    StartSubSection(Parent.Name+'.'+Name);
+    WriteLabel(PropDecl);
+    WriteIndex(Parent.Name+'.'+Name);
+    Writeln('\begin{FPCList}');
+    DocNode := Engine.FindDocNode(PropDecl);
+    if Assigned(DocNode) and Assigned(DocNode.ShortDescr) then
+      begin
+      Writeln('\Synopsis');
+      WriteDescr(PropDecl, DocNode.ShortDescr);
+      end;
+    Writeln('\Declaration ');  
+    StartListing(False);
+    WriteLn('Property '+GetDeclaration(True));
+    EndListing;
+    If Assigned(Parent) then
+      begin
+      Writeln('\Visibility');
+      Writeln(VisibilityNames[Visibility])
+      end;
+    Writeln('\Access');
+    Setlength(S,0);
+    If Length(ReadAccessorName) > 0 then
+      S:='Read';
+    if Length(WriteAccessorName) > 0 then
+      begin
+      If S<>'' then
+        S:=S+',';
+      S:=S+'Write';
+      end;
+    Writeln(S);  
+    if Assigned(DocNode) and Assigned(DocNode.Descr) then
+      begin
+      Writeln('\Description');
+      WriteDescr(PropDecl);
+      end;
+    if Assigned(DocNode) and Assigned(DocNode.ErrorsDoc) then   
+      begin
+      Writeln('\Errors');
+      WriteDescr(PropDecl, DocNode.ErrorsDoc);
+      end;
+    WriteSeeAlso(DocNode);
+    Writeln('\end{FPCList}');
+    WriteExample(DocNode);
+    end;
+end;
+
+Function CompareElements(P1,P2 : Pointer) : Integer;
+
+begin
+  Result:=CompareText(TPasElement(P1).Name,TPasElement(P2).Name);
+end;
+
+procedure TLaTeXWriter.SortElementList(List : TList);
+
+begin
+  List.Sort(@CompareElements)
+end;
+
+
+procedure TLaTeXWriter.WriteLabel(El: TPasElement);
+begin
+  WriteLabel(GetLabel(El));
+end;
+
+procedure TLaTeXWriter.WriteLabel(const s: String);
+begin
+  WriteLnF('\label{%s}', [LowerCase(s)]);
+end;
+
+procedure TLaTeXWriter.WriteIndex(El : TPasElement);
+begin
+  WriteIndex(El.Name);
+end;
+
+procedure TLaTeXWriter.WriteIndex(const s : String);
+begin
+  Write('\index{');
+  Write(s);
+  Writeln('}');
+end;
+
+procedure TLaTeXWriter.StartListing(Frames: Boolean; const name: String);
+begin
+  if Not LaTexHighLight then
+    Writeln('\begin{verbatim}')
+  else  
+    if Frames then
+      Writelnf('\begin{lstlisting}{%s}',[Name])
+    else  
+      Writelnf('\begin{lstlisting}[frame=]{%s}',[Name]);
+end;
+
+procedure TLaTeXWriter.StartListing(Frames : Boolean);
+begin
+  StartListing(Frames,'');
+end;
+
+procedure TLaTeXWriter.EndListing;
+begin
+  If LaTexHighLight then
+    Writeln('\end{lstlisting}')
+  else  
+    Writeln('\end{verbatim}')
+end;
+
+procedure TLatexWriter.WriteCommentLine;
+const
+  CommentLine = 
+    '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%';
+begin
+  Writeln(CommentLine);
+end;
+
+procedure TLatexWriter.WriteComment(Comment : String);
+begin
+  Write('% ');
+  Writeln(Comment);
+end;
+
+
+procedure TLatexWriter.StartSection(SectionName : String; SectionLabel : String);
+begin
+  StartSection(SectionName);
+  WriteLabel(SectionLabel);
+end;
+
+procedure TLatexWriter.StartSection(SectionName : String);
+begin
+  Writeln('');
+  WriteCommentLine;
+  WriteComment(SectionName);
+  Writeln('\section{'+SectionName+'}');
+end;
+
+procedure TLatexWriter.StartSubSection(SubSectionName : String; SubSectionLabel : String);
+begin
+  StartSubSection(SubSectionName);
+  WriteLabel(SubsectionLabel);
+end;
+
+procedure TLatexWriter.StartSubSection(SubSectionName : String);
+begin
+  Writeln('');
+  WriteComment(SubsectionName);
+  Writeln('\subsection{'+SubSectionName+'}');
+end;
+
+procedure TLatexWriter.StartChapter(ChapterName : String; ChapterLabel : String);
+begin
+  StartChapter(ChapterName);
+  WriteLabel(ChapterLabel);
+end;
+
+procedure TLatexWriter.StartChapter(ChapterName : String);
+begin
+  Writeln('');
+  WriteCommentLine;
+  WriteComment(ChapterName);
+  WriteCommentLine;
+  Writeln('\chapter{'+ChapterName+'}');
+end;
+
+procedure CreateLaTeXDocForPackage(APackage: TPasPackage; AEngine: TFPDocEngine);
+var
+  Writer: TLaTeXWriter;
+begin
+  Writer := TLaTeXWriter.Create(APackage, AEngine);
+  try
+    Writer.WriteDoc;
+  finally
+    Writer.Free;
+  end;
+end;
+
+
+end.
+
+
+{
+  $Log$
+  Revision 1.1  2003-03-17 23:03:20  michael
+  + Initial import in CVS
+
+  Revision 1.13  2003/03/13 22:02:13  sg
+  * New version with many bugfixes and our own parser (now independent of the
+    compiler source)
+
+  Revision 1.12  2002/10/20 22:49:31  michael
+  + Sorted all overviews. Added table with enumeration values for enumerated types.
+
+  Revision 1.11  2002/05/24 00:13:22  sg
+  * much improved new version, including many linking and output fixes
+
+  Revision 1.10  2002/03/12 10:58:36  sg
+  * reworked linking engine and internal structure
+
+  Revision 1.9  2002/01/20 11:19:55  michael
+  + Added link attribute and property to TFPElement
+
+  Revision 1.8  2002/01/08 13:00:06  michael
+  + Added correct array handling and syntax highlighting is now optional
+
+  Revision 1.7  2002/01/08 08:22:40  michael
+  + Implemented latex writer
+
+  Revision 1.6  2001/12/17 14:41:42  michael
+  + Split out of latex writer
+
+  Revision 1.5  2001/12/17 13:41:18  jonas
+    * OsPathSeparator -> PathDelim
+}

+ 118 - 0
utils/fpdoc/dw_xml.pp

@@ -0,0 +1,118 @@
+{
+    $Id$
+
+    FPDoc  -  Free Pascal Documentation Tool
+    Copyright (C) 2000 - 2003 by
+      Areca Systems GmbH / Sebastian Guenther, [email protected]
+
+    * 'XML struct' output generator
+
+    See the file COPYING, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+}
+
+
+unit dw_XML;
+
+interface
+
+uses DOM, PasTree;
+
+function ModuleToXMLStruct(AModule: TPasModule): TXMLDocument;
+
+
+implementation
+
+function ModuleToXMLStruct(AModule: TPasModule): TXMLDocument;
+var
+  ModuleElement: TDOMElement;
+
+  procedure ProcessProcedure(Proc: TPasProcedure; Element: TDOMElement);
+  var
+    ProcEl: TDOMElement;
+  begin
+    ProcEl := Result.CreateElement(Proc.TypeName);
+    Element.AppendChild(ProcEl);
+    ProcEl['name'] := Proc.Name;
+  end;
+
+  procedure ProcessVariable(AVar: TPasVariable; Element: TDOMElement);
+  var
+    VarEl: TDOMElement;
+  begin
+    VarEl := Result.CreateElement('var');
+    Element.AppendChild(VarEl);
+    VarEl['name'] := AVar.Name;
+  end;
+
+  procedure ProcessSection(ASection: TPasSection; const Name: DOMString);
+  var
+    Element, UsesElement, UnitElement: TDOMElement;
+    i: Integer;
+    Decl: TPasElement;
+  begin
+    Element := Result.CreateElement(Name);
+    ModuleElement.AppendChild(Element);
+    if ASection.UsesList.Count > 0 then
+    begin
+      UsesElement := Result.CreateElement('uses');
+      Element.AppendChild(UsesElement);
+      for i := 0 to ASection.UsesList.Count - 1 do
+      begin
+        UnitElement := Result.CreateElement('unit-ref');
+	UnitElement['name'] := TPasType(ASection.UsesList[i]).Name;
+	UsesElement.AppendChild(UnitElement);
+      end;
+    end;
+
+    for i := 0 to ASection.Declarations.Count - 1 do
+    begin
+      Decl := TPasElement(ASection.Declarations[i]);
+      if Decl.InheritsFrom(TPasProcedure) then
+        ProcessProcedure(TPasProcedure(Decl), Element)
+      else if Decl.ClassType = TPasVariable then
+        ProcessVariable(TPasVariable(Decl), Element);
+    end;
+  end;
+
+begin
+  Result := TXMLDocument.Create;
+  Result.AppendChild(Result.CreateComment(' Generated using FPDoc - (c) 2000-2003 Sebastian Guenther, [email protected] '));
+  Result.AppendChild(Result.CreateElement('fp-refdoc'));
+  ModuleElement := Result.CreateElement('unit');
+  ModuleElement['name'] := AModule.Name;
+  Result.DocumentElement.AppendChild(ModuleElement);
+
+  ProcessSection(AModule.InterfaceSection, 'interface');
+end;
+
+end.
+
+
+{
+  $Log$
+  Revision 1.1  2003-03-17 23:03:20  michael
+  + Initial import in CVS
+
+  Revision 1.5  2003/03/13 22:02:13  sg
+  * New version with many bugfixes and our own parser (now independent of the
+    compiler source)
+
+  Revision 1.4  2002/05/24 00:13:22  sg
+  * much improved new version, including many linking and output fixes
+
+  Revision 1.3  2002/03/12 10:58:36  sg
+  * reworked linking engine and internal structure
+
+  Revision 1.2  2001/07/27 10:21:42  sg
+  * Just a new, improved version ;)
+    (detailed changelogs will be provided again with the next commits)
+
+  Revision 1.1  2000/10/04 09:17:37  sg
+  * First public version
+
+}

+ 787 - 0
utils/fpdoc/dwriter.pp

@@ -0,0 +1,787 @@
+{
+    $Id$
+
+    FPDoc  -  Free Pascal Documentation Tool
+    Copyright (C) 2000 - 2003 by
+      Areca Systems GmbH / Sebastian Guenther, [email protected]
+
+    * Output string definitions
+    * Basic writer (output generator) class
+
+    See the file COPYING, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+}
+
+
+unit dWriter;
+
+{$MODE objfpc}
+{$H+}
+
+interface
+
+uses Classes, DOM, dGlobals, PasTree;
+
+resourcestring
+  SErrFileWriting = 'An error occured during writing of file "%s": %s';
+
+  SErrInvalidShortDescr = 'Invalid short description';
+  SErrInvalidDescr = 'Invalid description (illegal XML element: "%s")';
+  SErrInvalidParaContent = 'Invalid paragraph content';
+  SErrInvalidElementInList = 'Invalid element in list - only "li" allowed';
+  SErrInvalidListContent = 'Invalid list content';
+  SErrInvalidRemarkContent = 'Invalid <remark> content (illegal XML element: "%s")';
+  SErrListIsEmpty = 'List is empty - need at least one "li" element';
+  SErrInvalidDefinitionTermContent = 'Invalid content in definition term';
+  SErrDefinitionEntryMissing = 'Definition entry after definition term is missing';
+  SErrInvalidBorderValue = 'Invalid "border" value for %s';
+  SErrInvalidTableContent = 'Invalid table content';
+  SErrTableRowEmpty = 'Table row is empty (no "td" elements found)';
+  SErrInvalidContentBeforeSectionTitle = 'Invalid content before section title';
+  SErrSectionTitleExpected = 'Section title ("title" element) expected';
+
+  SErrDescrTagUnknown = 'Warning: Unknown tag "%s" in description';
+  SErrUnknownEntityReference = 'Warning: Unknown entity reference "&%s;" found';
+  SErrUnknownLinkID = 'Warning: Target ID of <link> is unknown: "%s"';
+  SErrUnknownPrintShortID = 'Warning: Target ID of <printshort> is unknown: "%s"';
+  SErrUnknownLink = 'Could not resolve link to "%s"';
+
+
+type
+
+  TFPDocWriter = class
+  private
+    FEngine: TFPDocEngine;
+  protected
+
+    procedure Warning(AContext: TPasElement; const AMsg: String);
+    procedure Warning(AContext: TPasElement; const AMsg: String;
+      const Args: array of const);
+
+    // function FindShortDescr(const Name: String): TDOMElement;
+
+    // Description conversion
+    function IsDescrNodeEmpty(Node: TDOMNode): Boolean;
+    function IsExtShort(Node: TDOMNode): Boolean;
+    function ConvertShort(AContext: TPasElement; El: TDOMElement): Boolean;
+    function ConvertBaseShort(AContext: TPasElement; Node: TDOMNode): Boolean;
+    procedure ConvertBaseShortList(AContext: TPasElement; Node: TDOMNode;
+      MayBeEmpty: Boolean);
+    procedure ConvertLink(AContext: TPasElement; El: TDOMElement);
+    function ConvertExtShort(AContext: TPasElement; Node: TDOMNode): Boolean;
+    procedure ConvertDescr(AContext: TPasElement; El: TDOMElement;
+      AutoInsertBlock: Boolean);
+    function ConvertNonSectionBlock(AContext: TPasElement;
+      Node: TDOMNode): Boolean;
+    procedure ConvertExtShortOrNonSectionBlocks(AContext: TPasElement;
+      Node: TDOMNode);
+    function ConvertSimpleBlock(AContext: TPasElement; Node: TDOMNode): Boolean;
+
+    procedure DescrWriteText(const AText: DOMString); virtual; abstract;
+    procedure DescrBeginBold; virtual; abstract;
+    procedure DescrEndBold; virtual; abstract;
+    procedure DescrBeginItalic; virtual; abstract;
+    procedure DescrEndItalic; virtual; abstract;
+    procedure DescrBeginEmph; virtual; abstract;
+    procedure DescrEndEmph; virtual; abstract;
+    procedure DescrWriteFileEl(const AText: DOMString); virtual; abstract;
+    procedure DescrWriteKeywordEl(const AText: DOMString); virtual; abstract;
+    procedure DescrWriteVarEl(const AText: DOMString); virtual; abstract;
+    procedure DescrBeginLink(const AId: DOMString); virtual; abstract;
+    procedure DescrEndLink; virtual; abstract;
+    procedure DescrWriteLinebreak; virtual; abstract;
+    procedure DescrBeginParagraph; virtual; abstract;
+    procedure DescrEndParagraph; virtual; abstract;
+    procedure DescrBeginCode(HasBorder: Boolean; const AHighlighterName: String); virtual; abstract;
+    procedure DescrWriteCodeLine(const ALine: String); virtual; abstract;
+    procedure DescrEndCode; virtual; abstract;
+    procedure DescrBeginOrderedList; virtual; abstract;
+    procedure DescrEndOrderedList; virtual; abstract;
+    procedure DescrBeginUnorderedList; virtual; abstract;
+    procedure DescrEndUnorderedList; virtual; abstract;
+    procedure DescrBeginDefinitionList; virtual; abstract;
+    procedure DescrEndDefinitionList; virtual; abstract;
+    procedure DescrBeginListItem; virtual; abstract;
+    procedure DescrEndListItem; virtual; abstract;
+    procedure DescrBeginDefinitionTerm; virtual; abstract;
+    procedure DescrEndDefinitionTerm; virtual; abstract;
+    procedure DescrBeginDefinitionEntry; virtual; abstract;
+    procedure DescrEndDefinitionEntry; virtual; abstract;
+    procedure DescrBeginSectionTitle; virtual; abstract;
+    procedure DescrBeginSectionBody; virtual; abstract;
+    procedure DescrEndSection; virtual; abstract;
+    procedure DescrBeginRemark; virtual; abstract;
+    procedure DescrEndRemark; virtual; abstract;
+    procedure DescrBeginTable(ColCount: Integer; HasBorder: Boolean); virtual; abstract;
+    procedure DescrEndTable; virtual; abstract;
+    procedure DescrBeginTableCaption; virtual; abstract;
+    procedure DescrEndTableCaption; virtual; abstract;
+    procedure DescrBeginTableHeadRow; virtual; abstract;
+    procedure DescrEndTableHeadRow; virtual; abstract;
+    procedure DescrBeginTableRow; virtual; abstract;
+    procedure DescrEndTableRow; virtual; abstract;
+    procedure DescrBeginTableCell; virtual; abstract;
+    procedure DescrEndTableCell; virtual; abstract;
+  public
+    constructor Create(AEngine: TFPDocEngine);
+    property Engine: TFPDocEngine read FEngine;
+  end;
+
+
+implementation
+
+uses SysUtils;
+
+
+constructor TFPDocWriter.Create(AEngine: TFPDocEngine);
+begin
+  inherited Create;
+  FEngine := AEngine;
+end;
+
+
+// ===================================================================
+//   Generic documentation node conversion
+// ===================================================================
+
+function IsContentNodeType(Node: TDOMNode): Boolean;
+begin
+  Result := (Node.NodeType = ELEMENT_NODE) or (Node.NodeType = TEXT_NODE) or
+    (Node.NodeType = ENTITY_REFERENCE_NODE);
+end;
+
+
+procedure TFPDocWriter.Warning(AContext: TPasElement; const AMsg: String);
+begin
+  WriteLn('[', AContext.PathName, '] ', AMsg);
+end;
+
+procedure TFPDocWriter.Warning(AContext: TPasElement; const AMsg: String;
+  const Args: array of const);
+begin
+  Warning(AContext, Format(AMsg, Args));
+end;
+
+function TFPDocWriter.IsDescrNodeEmpty(Node: TDOMNode): Boolean;
+var
+  Child: TDOMNode;
+begin
+  if (not Assigned(Node)) or (not Assigned(Node.FirstChild)) then
+    Result := True
+  else
+  begin
+    Child := Node.FirstChild;
+    while Assigned(Child) do
+    begin
+      if (Child.NodeType = ELEMENT_NODE) or (Child.NodeType = TEXT_NODE) or
+        (Child.NodeType = ENTITY_REFERENCE_NODE) then
+      begin
+        Result := False;
+        exit;
+      end;
+      Child := Child.NextSibling;
+    end;
+  end;
+  Result := True;
+end;
+
+{ Check wether the nodes starting with the node given as argument make up an
+  'extshort' production. }
+function TFPDocWriter.IsExtShort(Node: TDOMNode): Boolean;
+begin
+  while Assigned(Node) do
+  begin
+    if Node.NodeType = ELEMENT_NODE then
+      if (Node.NodeName <> 'br') and
+         (Node.NodeName <> 'link') and
+         (Node.NodeName <> 'b') and
+         (Node.NodeName <> 'file') and
+         (Node.NodeName <> 'i') and
+         (Node.NodeName <> 'kw') and
+         (Node.NodeName <> 'printshort') and
+         (Node.NodeName <> 'var') then
+      begin
+        Result := False;
+	exit;
+      end;
+    Node := Node.NextSibling;
+  end;
+  Result := True;
+end;
+
+function TFPDocWriter.ConvertShort(AContext: TPasElement;
+ El: TDOMElement): Boolean;
+var
+  Node: TDOMNode;
+begin
+  Result := False;
+  if not Assigned(El) then
+    exit;
+
+  Node := El.FirstChild;
+  while Assigned(Node) do
+  begin
+    if (Node.NodeType = ELEMENT_NODE) and (Node.NodeName = 'link') then
+      ConvertLink(AContext, TDOMElement(Node))
+    else
+      if not ConvertBaseShort(AContext, Node) then
+        exit;
+    Node := Node.NextSibling;
+  end;
+  Result := True;
+end;
+
+function TFPDocWriter.ConvertBaseShort(AContext: TPasElement;
+  Node: TDOMNode): Boolean;
+
+  function ConvertText: DOMString;
+  var
+    s: String;
+    i: Integer;
+  begin
+    if Node.NodeType = TEXT_NODE then
+    begin
+      s := Node.NodeValue;
+      i := 1;
+      SetLength(Result, 0);
+      while i <= Length(s) do
+        if s[i] = #13 then
+	begin
+	  Result := Result + ' ';
+	  Inc(i);
+	  if s[i] = #10 then
+	    Inc(i);
+	end else if s[i] = #10 then
+	begin
+	  Result := Result + ' ';
+	  Inc(i);
+	end else
+	begin
+	  Result := Result + s[i];
+	  Inc(i);
+	end;
+    end else if Node.NodeType = ENTITY_REFERENCE_NODE then
+      if Node.NodeName = 'fpc' then
+        Result := 'Free Pascal'
+      else if Node.NodeName = 'delphi' then
+        Result := 'Delphi'
+      else
+      begin
+        Warning(AContext, Format(SErrUnknownEntityReference, [Node.NodeName]));
+        Result := Node.NodeName;
+      end
+    else if Node.NodeType = ELEMENT_NODE then
+      SetLength(Result, 0);
+  end;
+
+  function ConvertTextContent: DOMString;
+  begin
+    SetLength(Result, 0);
+    Node := Node.FirstChild;
+    while Assigned(Node) do
+    begin
+      Result := Result + ConvertText;
+      Node := Node.NextSibling;
+    end;
+  end;
+
+var
+  El, DescrEl: TDOMElement;
+  FPEl: TPasElement;
+begin
+  Result := True;
+  if Node.NodeType = ELEMENT_NODE then
+    if Node.NodeName = 'b' then
+    begin
+      DescrBeginBold;
+      ConvertBaseShortList(AContext, Node, False);
+      DescrEndBold;
+    end else
+    if Node.NodeName = 'i' then
+    begin
+      DescrBeginItalic;
+      ConvertBaseShortList(AContext, Node, False);
+      DescrEndItalic;
+    end else
+    if Node.NodeName = 'em' then
+    begin
+      DescrBeginEmph;
+      ConvertBaseShortList(AContext, Node, False);
+      DescrEndEmph;
+    end else
+    if Node.NodeName = 'file' then
+      DescrWriteFileEl(ConvertTextContent)
+    else if Node.NodeName = 'kw' then
+      DescrWriteKeywordEl(ConvertTextContent)
+    else if Node.NodeName = 'printshort' then
+    begin
+      El := TDOMElement(Node);
+      DescrEl := Engine.FindShortDescr(AContext.GetModule, El['id']);
+      if Assigned(DescrEl) then
+	ConvertShort(AContext, DescrEl)
+      else
+      begin
+	Warning(AContext, Format(SErrUnknownPrintShortID, [El['id']]));
+	DescrBeginBold;
+	DescrWriteText('#ShortDescr:' + El['id']);
+	DescrEndBold;
+      end;
+    end else if Node.NodeName = 'var' then
+      DescrWriteVarEl(ConvertTextContent)
+    else
+      Result := False
+  else
+    DescrWriteText(ConvertText);
+end;
+
+procedure TFPDocWriter.ConvertBaseShortList(AContext: TPasElement;
+  Node: TDOMNode; MayBeEmpty: Boolean);
+var
+  Child: TDOMNode;
+begin
+  Child := Node.FirstChild;
+  while Assigned(Child) do
+  begin
+    if not ConvertBaseShort(AContext, Child) then
+      Warning(AContext, SErrInvalidShortDescr)
+    else
+      MayBeEmpty := True;
+    Child := Child.NextSibling;
+  end;
+  if not MayBeEmpty then
+    Warning(AContext, SErrInvalidShortDescr)
+end;
+
+procedure TFPDocWriter.ConvertLink(AContext: TPasElement; El: TDOMElement);
+begin
+  DescrBeginLink(El['id']);
+  if not IsDescrNodeEmpty(El) then
+    ConvertBaseShortList(AContext, El, True)
+  else
+    DescrWriteText(El['id']);
+  DescrEndLink;
+end;
+
+function TFPDocWriter.ConvertExtShort(AContext: TPasElement;
+  Node: TDOMNode): Boolean;
+begin
+  Result := False;
+
+  while Assigned(Node) do
+  begin
+    if (Node.NodeType = ELEMENT_NODE) and (Node.NodeName = 'link') then
+      ConvertLink(AContext, TDOMElement(Node))
+    else if (Node.NodeType = ELEMENT_NODE) and (Node.NodeName = 'br') then
+      DescrWriteLinebreak
+    else
+      if not ConvertBaseShort(AContext, Node) then
+        exit;
+    Node := Node.NextSibling;
+  end;
+  Result := True;
+end;
+
+procedure TFPDocWriter.ConvertDescr(AContext: TPasElement; El: TDOMElement;
+  AutoInsertBlock: Boolean);
+var
+  Node, Child: TDOMNode;
+  ParaCreated: Boolean;
+begin
+  if AutoInsertBlock then
+    if IsExtShort(El.FirstChild) then
+      DescrBeginParagraph
+    else
+      AutoInsertBlock := False;
+
+  Node := El.FirstChild;
+  if not ConvertExtShort(AContext, Node) then
+  begin
+    while Assigned(Node) do
+    begin
+      if (Node.NodeType = ELEMENT_NODE) and (Node.NodeName = 'section') then
+      begin
+        DescrBeginSectionTitle;
+	Child := Node.FirstChild;
+	while Assigned(Child) and (Child.NodeType <> ELEMENT_NODE) do
+	begin
+	  if not IsDescrNodeEmpty(Child) then
+	    Warning(AContext, SErrInvalidContentBeforeSectionTitle);
+	  Child := Child.NextSibling;
+	end;
+	if not Assigned(Child) or (Child.NodeName <> 'title') then
+	  Warning(AContext, SErrSectionTitleExpected)
+	else
+	  ConvertShort(AContext, TDOMElement(Child));
+
+	DescrBeginSectionBody;
+
+	if IsExtShort(Child) then
+	begin
+	  DescrBeginParagraph;
+	  ParaCreated := True;
+	end else
+	  ParaCreated := False;
+
+	ConvertExtShortOrNonSectionBlocks(AContext, Child.NextSibling);
+
+	if ParaCreated then
+	  DescrEndParagraph;
+	DescrEndSection;
+      end else if not ConvertNonSectionBlock(AContext, Node) then
+        Warning(AContext, SErrInvalidDescr, [Node.NodeName]);
+      Node := Node.NextSibling;
+    end;
+  end else
+    if AutoInsertBlock then
+      DescrEndParagraph;
+end;
+
+procedure TFPDocWriter.ConvertExtShortOrNonSectionBlocks(AContext: TPasElement;
+  Node: TDOMNode);
+begin
+  if not ConvertExtShort(AContext, Node) then
+    while Assigned(Node) do
+    begin
+      if not ConvertNonSectionBlock(AContext, Node) then
+        Warning(AContext, SErrInvalidDescr, [Node.NodeName]);
+      Node := Node.NextSibling;
+    end;
+end;
+
+function TFPDocWriter.ConvertNonSectionBlock(AContext: TPasElement;
+  Node: TDOMNode): Boolean;
+
+  procedure ConvertCells(Node: TDOMNode);
+  var
+    Child: TDOMNode;
+    IsEmpty: Boolean;
+  begin
+    Node := Node.FirstChild;
+    IsEmpty := True;
+    while Assigned(Node) do
+    begin
+      if (Node.NodeType = ELEMENT_NODE) and (Node.NodeName = 'td') then
+      begin
+        DescrBeginTableCell;
+	Child := Node.FirstChild;
+	if not ConvertExtShort(AContext, Child) then
+	  while Assigned(Child) do
+	  begin
+	    if not ConvertSimpleBlock(AContext, Child) then
+	      Warning(AContext, SErrInvalidTableContent);
+	    Child := Child.NextSibling;
+	  end;
+	DescrEndTableCell;
+	IsEmpty := False;
+      end else
+        if IsContentNodeType(Node) then
+	  Warning(AContext, SErrInvalidTableContent);
+      Node := Node.NextSibling;
+    end;
+    if IsEmpty then
+      Warning(AContext, SErrTableRowEmpty);
+  end;
+
+  procedure ConvertTable;
+
+    function GetColCount(Node: TDOMNode): Integer;
+    begin
+      Result := 0;
+      Node := Node.FirstChild;
+      while Assigned(Node) do
+      begin
+        if (Node.NodeType = ELEMENT_NODE) and (Node.NodeName = 'td') then
+	  Inc(Result);
+        Node := Node.NextSibling;
+      end;
+    end;
+
+  var
+    s: String;
+    HasBorder, CaptionPossible, HeadRowPossible: Boolean;
+    ColCount, ThisRowColCount: Integer;
+    Subnode: TDOMNode;
+  begin
+    s := TDOMElement(Node)['border'];
+    if s = '1' then
+      HasBorder := True
+    else
+    begin
+      HasBorder := False;
+      if (Length(s) <> 0) and (s <> '0') then
+        Warning(AContext, SErrInvalidBorderValue, ['<table>']);
+    end;
+
+    // Determine the number of columns
+    ColCount := 0;
+    Subnode := Node.FirstChild;
+    while Assigned(Subnode) do
+    begin
+      if Subnode.NodeType = ELEMENT_NODE then
+        if (Subnode.NodeName = 'caption') or (Subnode.NodeName = 'th') or
+	  (Subnode.NodeName = 'tr') then
+	begin
+	  ThisRowColCount := GetColCount(Subnode);
+	  if ThisRowColCount > ColCount then
+	    ColCount := ThisRowColCount;
+	end;
+      Subnode := Subnode.NextSibling;
+    end;
+
+    DescrBeginTable(ColCount, HasBorder);
+
+    Node := Node.FirstChild;
+    CaptionPossible := True;
+    HeadRowPossible := True;
+    while Assigned(Node) do
+    begin
+      if Node.NodeType = ELEMENT_NODE then
+        if CaptionPossible and (Node.NodeName = 'caption') then
+	begin
+	  DescrBeginTableCaption;
+	  if not ConvertExtShort(AContext, Node.FirstChild) then
+	    Warning(AContext, SErrInvalidTableContent);
+	  DescrEndTableCaption;
+	  CaptionPossible := False;
+	end else if HeadRowPossible and (Node.NodeName = 'th') then
+	begin
+	  DescrBeginTableHeadRow;
+	  ConvertCells(Node);
+	  DescrEndTableHeadRow;
+	  CaptionPossible := False;
+	  HeadRowPossible := False;
+	end else if Node.NodeName = 'tr' then
+	begin
+	  DescrBeginTableRow;
+	  ConvertCells(Node);
+	  DescrEndTableRow;
+	end else
+	  Warning(AContext, SErrInvalidTableContent)
+      else if IsContentNodeType(Node) then
+        Warning(AContext, SErrInvalidTableContent);
+      Node := Node.NextSibling;
+    end;
+    DescrEndTable;
+  end;
+
+begin
+  if Node.NodeType <> ELEMENT_NODE then
+  begin
+    Result := Node.NodeType = COMMENT_NODE;
+    exit;
+  end;
+  if Node.NodeName = 'remark' then
+  begin
+    DescrBeginRemark;
+    Node := Node.FirstChild;
+    if not ConvertExtShort(AContext, Node) then
+      while Assigned(Node) do
+      begin
+	if (Node.NodeType = ELEMENT_NODE) and (Node.NodeName = 'table') then
+	  ConvertTable
+	else
+	  if not ConvertSimpleBlock(AContext, Node) then
+	    Warning(AContext, SErrInvalidRemarkContent, [Node.NodeName]);
+	Node := Node.NextSibling;
+      end;
+    DescrEndRemark;
+    Result := True;
+  end else if Node.NodeName = 'table' then
+  begin
+    ConvertTable;
+    Result := True;
+  end else
+    Result := ConvertSimpleBlock(AContext, Node);
+end;
+
+function TFPDocWriter.ConvertSimpleBlock(AContext: TPasElement;
+  Node: TDOMNode): Boolean;
+
+  procedure ConvertListItems;
+  var
+    Empty: Boolean;
+  begin
+    Node := Node.FirstChild;
+    Empty := True;
+    while Assigned(Node) do
+    begin
+      if (Node.NodeType = TEXT_NODE) or (Node.NodeType = ENTITY_REFERENCE_NODE)
+        then
+	Warning(AContext, SErrInvalidListContent)
+      else if Node.NodeType = ELEMENT_NODE then
+        if Node.NodeName = 'li' then
+	begin
+	  DescrBeginListItem;
+	  ConvertExtShortOrNonSectionBlocks(AContext, Node.FirstChild);
+	  DescrEndListItem;
+	  Empty := False;
+	end else
+          Warning(AContext, SErrInvalidElementInList);
+      Node := Node.NextSibling;
+    end;
+    if Empty then
+      Warning(AContext, SErrListIsEmpty);
+  end;
+
+  procedure ConvertDefinitionList;
+  var
+    Empty, ExpectDTNext: Boolean;
+  begin
+    Node := Node.FirstChild;
+    Empty := True;
+    ExpectDTNext := True;
+    while Assigned(Node) do
+    begin
+      if (Node.NodeType = TEXT_NODE) or (Node.NodeType = ENTITY_REFERENCE_NODE)
+        then
+	Warning(AContext, SErrInvalidListContent)
+      else if Node.NodeType = ELEMENT_NODE then
+        if ExpectDTNext and (Node.NodeName = 'dt') then
+	begin
+	  DescrBeginDefinitionTerm;
+	  if not ConvertShort(AContext, TDOMElement(Node)) then
+	    Warning(AContext, SErrInvalidDefinitionTermContent);
+	  DescrEndDefinitionTerm;
+	  Empty := False;
+	  ExpectDTNext := False;
+	end else if not ExpectDTNext and (Node.NodeName = 'dd') then
+	begin
+	  DescrBeginDefinitionEntry;
+	  ConvertExtShortOrNonSectionBlocks(AContext, Node.FirstChild);
+	  DescrEndDefinitionEntry;
+	  ExpectDTNext := True;
+	end else
+          Warning(AContext, SErrInvalidElementInList);
+      Node := Node.NextSibling;
+    end;
+    if Empty then
+      Warning(AContext, SErrListIsEmpty)
+    else if not ExpectDTNext then
+      Warning(AContext, SErrDefinitionEntryMissing);
+  end;
+
+  procedure ProcessCodeBody(Node: TDOMNode);
+  var
+    s: String;
+    i, j: Integer;
+  begin
+    Node := Node.FirstChild;
+    SetLength(s, 0);
+    while Assigned(Node) do
+    begin
+      if Node.NodeType = TEXT_NODE then
+      begin
+        s := s + Node.NodeValue;
+	j := 1;
+	for i := 1 to Length(s) do
+	  // In XML, linefeeds are normalized to #10 by the parser!
+	  if s[i] = #10 then
+	  begin
+	    DescrWriteCodeLine(Copy(s, j, i - j));
+	    j := i + 1;
+	  end;
+	if j > 1 then
+	  s := Copy(s, j, Length(s));
+      end;
+      Node := Node.NextSibling;
+    end;
+    if Length(s) > 0 then
+      DescrWriteCodeLine(s);
+  end;
+
+var
+  s: String;
+  HasBorder: Boolean;
+begin
+  if Node.NodeType <> ELEMENT_NODE then
+  begin
+    Result := False;
+    exit;
+  end;
+  if Node.NodeName = 'p' then
+  begin
+    DescrBeginParagraph;
+    if not ConvertExtShort(AContext, Node.FirstChild) then
+      Warning(AContext, SErrInvalidParaContent);
+    DescrEndParagraph;
+    Result := True;
+  end else if Node.NodeName = 'code' then
+  begin
+    s := TDOMElement(Node)['border'];
+    if s = '1' then
+      HasBorder := True
+    else
+    begin
+      if (Length(s) > 0) and (s <> '0') then
+        Warning(AContext, SErrInvalidBorderValue, ['<code>']);
+    end;
+
+    DescrBeginCode(HasBorder, TDOMElement(Node)['highlighter']);
+    ProcessCodeBody(Node);
+    DescrEndCode;
+    Result := True;
+  end else if Node.NodeName = 'pre' then
+  begin
+    DescrBeginCode(False, 'none');
+    ProcessCodeBody(Node);
+    DescrEndCode;
+    Result := True;
+  end else if Node.NodeName = 'ul' then
+  begin
+    DescrBeginUnorderedList;
+    ConvertListItems;
+    DescrEndUnorderedList;
+    Result := True;
+  end else if Node.NodeName = 'ol' then
+  begin
+    DescrBeginOrderedList;
+    ConvertListItems;
+    DescrEndOrderedList;
+    Result := True;
+  end else if Node.NodeName = 'dl' then
+  begin
+    DescrBeginDefinitionList;
+    ConvertDefinitionList;
+    DescrEndDefinitionList;
+    Result := True;
+  end else
+    Result := False;
+end;
+
+
+end.
+
+
+{
+  $Log$
+  Revision 1.1  2003-03-17 23:03:20  michael
+  + Initial import in CVS
+
+  Revision 1.9  2003/03/13 22:02:13  sg
+  * New version with many bugfixes and our own parser (now independent of the
+    compiler source)
+
+  Revision 1.8  2002/05/24 00:13:22  sg
+  * much improved new version, including many linking and output fixes
+
+  Revision 1.7  2002/03/12 10:58:36  sg
+  * reworked linking engine and internal structure
+
+  Revision 1.6  2001/07/27 10:21:42  sg
+  * Just a new, improved version ;)
+    (detailed changelogs will be provided again with the next commits)
+
+  Revision 1.5  2000/11/13 00:18:42  sg
+  * Comments within descriptions should be ignored now in all cases
+
+  Revision 1.4  2000/11/11 23:53:56  sg
+  * Added <pre> tag (with unified handling of <pre> and <code>)
+
+  Revision 1.3  2000/10/30 21:19:59  sg
+  * Changed syntax highlighting attribute in 'code' element from
+    'highlight' to 'highlighter'
+}

+ 129 - 0
utils/fpdoc/fpdoc.css

@@ -0,0 +1,129 @@
+/*
+  $Id$
+
+  Default style sheet for FPDoc reference documentation
+  by Sebastian Guenther, [email protected]
+
+  Feel free to use this file as a template for your own style sheets.
+*/
+
+body {
+  background: white
+}
+
+body, p, th, td, caption, h1, h2, h3, ul, ol, dl {
+  color: black;
+  font-family: sans-serif
+}
+
+tt, span.kw, pre {
+  font-family: Courier, monospace
+}
+
+body, p, th, td, caption, ul, ol, dl, tt, span.kw, pre {
+  font-size: 14px
+}
+
+A:link {
+  color: blue
+}
+
+A:visited {
+  color: darkblue
+}
+
+A:active {
+  color: red
+}
+
+A {
+  text-decoration: none
+}
+
+A:hover {
+  text-decoration: underline
+}
+
+h1, h2, td.h2 {
+  color: #005A9C
+}
+
+/* Especially for Netscape on Linux: */
+h3, td.h3 {
+  font-size: 12pt
+}
+
+/* symbols in source fragments */
+span.sym {
+  color: darkred
+}
+
+/* keywords in source fragments */
+span.kw {
+  font-weight: bold
+}
+
+/* comments in source fragments */
+span.cmt {
+  color: darkcyan;
+  font-style: italic
+}
+
+/* directives in source fragments */
+span.dir {
+  color: darkyellow;
+  font-style: italic
+}
+
+/* numbers in source fragments */
+span.num {
+  color: darkmagenta
+}
+
+/* characters (#...) in source fragments */
+span.chr {
+  color: darkcyan
+}
+
+/* strings in source fragments */
+span.str {
+  color: blue
+}
+
+/* assembler passages in source fragments */
+span.asm {
+  color: green
+}
+
+
+td.pre {
+  white-space: pre
+}
+
+p.cmt {
+  color: gray
+}
+
+span.warning {
+  color: red;
+  font-weight: bold
+}
+
+/* !!!: How should we define this...? */
+span.file {
+  color: darkgreen
+}
+
+table.remark {
+  background-color: #ffffc0;
+}
+
+table.bar {
+  background-color: #a0c0ff;
+}
+
+span.bartitle {
+  font-weight: bold;
+  font-style: italic;
+  color: darkblue
+}

+ 324 - 0
utils/fpdoc/fpdoc.pp

@@ -0,0 +1,324 @@
+{
+    $Id$
+
+    FPDoc  -  Free Pascal Documentation Tool
+    Copyright (C) 2000 - 2003 by
+      Areca Systems GmbH / Sebastian Guenther, [email protected]
+
+    See the file COPYING, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+}
+
+
+program FPDoc;
+
+uses
+  SysUtils, Classes, Gettext, DOM, XMLWrite,
+  dGlobals, PasTree, PParser, dw_XML, dw_HTML, dw_LaTeX;
+
+resourcestring
+  STitle = 'FPDoc - Free Pascal Documentation Tool';
+  SCopyright = '(c) 2000 - 2003 Areca Systems GmbH / Sebastian Guenther, [email protected]';
+  SCmdLineHelp = 'See documentation for usage.';
+  SCmdLineInvalidOption = 'Ignoring unknown option "%s"';
+  SCmdLineInvalidFormat = 'Invalid format "%s" specified';
+  SCmdLineOutputOptionMissing = 'Need an output filename, please specify one with --output=<filename>';
+  SWritingPages = 'Writing %d pages...';
+  SNeedPackageName = 'No package name specified. Please specify one using the --package option.';
+  SDone = 'Done.';
+
+type
+  TCmdLineAction = (actionHelp, actionConvert);
+  TOutputFormat = (fmtHTM, fmtHTML, fmtXHTML, fmtLaTeX, fmtXMLStruct);
+
+const
+  CmdLineAction: TCmdLineAction = actionConvert;
+  OutputFormat: TOutputFormat = fmtHTML;
+
+var
+  InputFiles, DescrFiles: TStringList;
+  PackageName, DocLang, ContentFile, SearchPage: String;
+  Engine: TFPDocEngine;
+
+
+procedure InitOptions;
+begin
+  InputFiles := TStringList.Create;
+  DescrFiles := TStringList.Create;
+  Engine := TFPDocEngine.Create;
+end;
+
+procedure FreeOptions;
+begin
+  Engine.Free;
+  DescrFiles.Free;
+  InputFiles.Free;
+end;
+
+procedure ReadContentFile(const AParams: String);
+var
+  i: Integer;
+begin
+  i := Pos(',', AParams);
+  Engine.ReadContentFile(Copy(AParams, 1, i - 1),
+    Copy(AParams, i + 1, Length(AParams)));
+end;
+
+procedure ParseOption(const s: String);
+
+  procedure AddToFileList(List: TStringList; const FileName: String);
+  var
+    f: Text;
+    s: String;
+  begin
+    if Copy(FileName, 1, 1) = '@' then
+    begin
+      Assign(f, Copy(FileName, 2, Length(FileName)));
+      Reset(f);
+      while not EOF(f) do
+      begin
+        ReadLn(f, s);
+	List.Add(s);
+      end;
+      Close(f);
+    end else
+      List.Add(FileName);
+  end;
+
+var
+  i: Integer;
+  Cmd, Arg: String;
+begin
+  if (s = '-h') or (s = '--help') then
+    CmdLineAction := actionHelp
+  else if s = '--hide-protected' then
+    Engine.HideProtected := True
+  else if s = '--show-private' then
+    Engine.HidePrivate := False
+  else
+  begin
+    i := Pos('=', s);
+    if i > 0 then
+    begin
+      Cmd := Copy(s, 1, i - 1);
+      Arg := Copy(s, i + 1, Length(s));
+    end else
+    begin
+      Cmd := s;
+      SetLength(Arg, 0);
+    end;
+    if Cmd = '--descr' then
+      AddToFileList(DescrFiles, Arg)
+    else if (Cmd = '-f') or (Cmd = '--format') then
+    begin
+      Arg := UpperCase(Arg);
+      if Arg = 'HTM' then
+        OutputFormat := fmtHTM
+      else if Arg = 'HTML' then
+        OutputFormat := fmtHTML
+      else if Arg = 'XHTML' then
+        OutputFormat := fmtXHTML
+      else if Arg = 'LATEX' then
+        OutputFormat := fmtLaTeX
+      else if Arg = 'XML-STRUCT' then
+        OutputFormat := fmtXMLStruct
+      else
+        WriteLn(StdErr, Format(SCmdLineInvalidFormat, [Arg]));
+    end else if (Cmd = '-l') or (Cmd = '--lang') then
+      DocLang := Arg
+    else if (Cmd = '--latex-highlight') then
+      LatexHighLight:=True
+    else if (Cmd = '-i') or (Cmd = '--input') then
+      AddToFileList(InputFiles, Arg)
+    else if (Cmd = '-o') or (Cmd = '--output') then
+    begin
+      Engine.Output := Arg;
+      if (Length(Engine.Output) > 0) and not
+        (Engine.Output[Length(Engine.Output)] in DirSeparators) then
+        Engine.Output := Engine.Output + PathDelim;
+    end else if Cmd = '--content' then
+      ContentFile := Arg
+    else if Cmd = '--import' then
+      ReadContentFile(Arg)
+    else if Cmd = '--package' then
+      PackageName := Arg
+    else if Cmd = '--html-search' then
+      SearchPage := Arg
+    else
+      WriteLn(StdErr, Format(SCmdLineInvalidOption, [s]));
+  end;
+end;
+
+procedure ParseCommandLine;
+var
+  i: Integer;
+begin
+  for i := 1 to ParamCount do
+    ParseOption(ParamStr(i));
+end;
+
+
+var
+  i: Integer;
+  XMLDoc: TXMLDocument;
+  Allocator: TFileAllocator;
+  HTMLWriter: THTMLWriter;
+begin
+{$IFDEF Unix}
+  gettext.TranslateResourceStrings('/usr/local/share/locale/%s/LC_MESSAGES/fpdoc.mo');
+{$ELSE}
+  gettext.TranslateResourceStrings('intl/fpdoc.%s.mo');
+{$ENDIF}
+
+  WriteLn(STitle);
+  WriteLn(SCopyright);
+  WriteLn;
+
+  InitOptions;
+  ParseCommandLine;
+
+  if CmdLineAction = actionHelp then
+    WriteLn(SCmdLineHelp)
+  else
+  begin
+    if (PackageName='') then
+      begin
+      Writeln(SNeedPackageName);
+      Halt(1);
+      end;
+    // Action is to create documentation
+
+    // Read all description files
+    for i := 0 to DescrFiles.Count - 1 do
+      Engine.AddDocFile(DescrFiles[i]);
+
+    // Set the name of the package to be processed
+    Engine.SetPackageName(PackageName);
+
+    // Read all source files
+    for i := 0 to InputFiles.Count - 1 do
+      try
+        ParseSource(Engine, InputFiles[i]);
+      except
+        on e: EParserError do
+	  WriteLn(StdErr, Format('%s(%d,%d): %s',
+	    [e.Filename, e.Row, e.Column, e.Message]));
+      end;
+
+    // Translate internal documentation strings
+    if Length(DocLang) > 0 then
+      TranslateDocStrings(DocLang);
+
+    case OutputFormat of
+      fmtHTM:
+        begin
+	  Allocator := TShortNameFileAllocator.Create('.htm');
+	  try
+	    HTMLWriter := THTMLWriter.Create(Engine, Allocator, Engine.Package);
+	    try
+	      HTMLWriter.SearchPage := SearchPage;
+	      WriteLn(Format(SWritingPages, [HTMLWriter.PageCount]));
+	      HTMLWriter.WriteHTMLPages;
+	    finally
+	      HTMLWriter.Free;
+	    end;
+	  finally
+	    Allocator.Free;
+	  end;
+	end;
+      fmtHTML:
+        begin
+	  Allocator := TLongNameFileAllocator.Create('.html');
+	  try
+	    HTMLWriter := THTMLWriter.Create(Engine, Allocator, Engine.Package);
+	    try
+	      HTMLWriter.SearchPage := SearchPage;
+	      WriteLn(Format(SWritingPages, [HTMLWriter.PageCount]));
+	      HTMLWriter.WriteHTMLPages;
+	    finally
+	      HTMLWriter.Free;
+	    end;
+	  finally
+	    Allocator.Free;
+	  end;
+	end;
+{      fmtXHTML:
+        begin
+	  Allocator := TLongNameFileAllocator.Create('.xml');
+	  try
+	    BeginXHTMLDocForPackage(Engine, XHTMLOptions, Allocator);
+            for i := 0 to InputFiles.Count - 1 do
+	      CreateXHTMLDocFromModule(Engine, XHTMLOptions, Allocator,
+	        ParseSource(Engine, InputFiles[i]));
+	    EndXHTMLDocForPackage(Engine, XHTMLOptions, Allocator);
+	  finally
+	    Allocator.Free;
+	  end;
+	end;}
+      fmtLaTeX:
+        begin
+	  if Length(Engine.Output) = 0 then
+	    WriteLn(SCmdLineOutputOptionMissing)
+	  else
+	    CreateLaTeXDocForPackage(Engine.Package, Engine);
+	end;
+{      fmtXMLStruct:
+        for i := 0 to InputFiles.Count - 1 do
+	begin
+          XMLDoc := ModuleToXMLStruct(Module);
+    	  try
+           WriteXMLFile(XMLDoc, StdOut);
+	  finally
+	    XMLDoc.Free;
+	  end;
+	end;}
+    end;
+
+    if Length(ContentFile) > 0 then
+      Engine.WriteContentFile(ContentFile);
+
+
+  end;
+
+  FreeOptions;
+
+  WriteLn(SDone);
+end.
+
+
+{
+  $Log$
+  Revision 1.1  2003-03-17 23:03:20  michael
+  + Initial import in CVS
+
+  Revision 1.13  2003/03/13 22:02:13  sg
+  * New version with many bugfixes and our own parser (now independent of the
+    compiler source)
+
+  Revision 1.12  2002/10/12 17:09:45  michael
+  + Added check for package name
+
+  Revision 1.11  2002/05/24 00:13:22  sg
+  * much improved new version, including many linking and output fixes
+
+  Revision 1.10  2002/03/12 10:58:36  sg
+  * reworked linking engine and internal structure
+
+  Revision 1.9  2002/01/08 13:00:06  michael
+  + Added correct array handling and syntax highlighting is now optional
+
+  Revision 1.8  2001/12/17 23:24:11  sg
+  * Added "--package" switch
+  * Now uses translation files written in lower-case
+
+  Revision 1.7  2001/07/27 12:17:20  sg
+  * Added "--html-search" command line argument
+
+  Revision 1.6  2001/07/27 10:21:42  sg
+  * Just a new, improved version ;)
+    (detailed changelogs will be provided again with the next commits)
+}

+ 23 - 0
utils/fpdoc/intl/Makefile

@@ -0,0 +1,23 @@
+all:	de
+
+clean:
+	@rm -f *.mo *.pot
+
+de:
+	msgfmt fpdoc.de.po dwriter.de.po -o fpdoc.de.mo
+	msgfmt dglobals.de.po -o dglobals.de.mo
+	msgfmt makeskel.de.po -o makeskel.de.mo
+	msgfmt fpdocmk.de.po -o fpdocmk.de.mo
+
+pot:
+	rstconv -i ../dglobals.rst -o dglobals.pot
+	rstconv -i ../dwriter.rst -o dwriter.pot
+	rstconv -i ../fpdoc.rst -o fpdoc.pot
+	rstconv -i ../makeskel.rst -o makeskel.pot
+	rstconv -i ../fpdocmk.rst -o fpdocmk.pot
+
+install:
+	install -D -m 0644 fpdoc.de.mo /usr/local/share/locale/de/LC_MESSAGES/fpdoc.mo
+	install -D -m 0644 dglobals.de.mo /usr/local/share/locale/de/LC_MESSAGES/dglobals.mo
+	install -D -m 0644 makeskel.de.mo /usr/local/share/locale/de/LC_MESSAGES/makeskel.mo
+	install -D -m 0644 fpdocmk.de.mo /usr/local/share/locale/de/LC_MESSAGES/fpdocmk.mo

+ 160 - 0
utils/fpdoc/intl/dglobals.de.po

@@ -0,0 +1,160 @@
+#: dglobals:sdocpackagetitle
+msgid "Reference for package '%s'"
+msgstr "Referenz für Paket '%s'"
+
+#: dglobals:sdocprograms
+msgid "Programs"
+msgstr "Programme"
+
+#: dglobals:sdocunits
+msgid "Units"
+msgstr "Units"
+
+#: dglobals:sdocunittitle
+msgid "Reference for unit '%s'"
+msgstr "Referenz für Unit '%s'"
+
+#: dglobals:sdocinterfacesection
+msgid "Interface section"
+msgstr "Interface-Abschnitt"
+
+#: dglobals:sdocimplementationsection
+msgid "Implementation section"
+msgstr "Implementation-Abschnitt"
+
+#: dglobals:sdocusedunits
+msgid "Used units"
+msgstr "Verwendete Units"
+
+#: dglobals:sdocusedunitsbyunitxy
+msgid "Used units by unit '%s'"
+msgstr "Von Unit '%s' verwendete Units"
+
+#: dglobals:sdocconststypesvars
+msgid "Constants, types and variables"
+msgstr "Konstanten, Typen und Variablen"
+
+#: dglobals:sdocresstrings
+msgid "Resource strings"
+msgstr "Resource-Strings"
+
+#: dglobals:sdoctypes
+msgid "Types"
+msgstr "Typen"
+
+#: dglobals:sdocconstants
+msgid "Constants"
+msgstr "Konstanten"
+
+#: dglobals:sdocclasses
+msgid "Classes"
+msgstr "Klassen"
+
+#: dglobals:sdocproceduresandfunctions
+msgid "Procedures and functions"
+msgstr "Prozeduren und Funktionen"
+
+#: dglobals:sdocvariables
+msgid "Variables"
+msgstr "Variablen"
+
+#: dglobals:sdocunitoverview
+msgid "Overview of unit '%s'"
+msgstr "Überblick über Unit '%s'"
+
+#: dglobals:sdocoverview
+msgid "Overview"
+msgstr "Überblick"
+
+#: dglobals:sdocsearch
+msgid "Search"
+msgstr "Suchen"
+
+#: dglobals:sdocdeclaration
+msgid "Declaration"
+msgstr "Deklaration"
+
+#: dglobals:sdocdescription
+msgid "Description"
+msgstr "Beschreibung"
+
+#: dglobals:sdocerrors
+msgid "Errors"
+msgstr "Fehler"
+
+#: dglobals:sdocseealso
+msgid "See also"
+msgstr "Siehe auch"
+
+#: dglobals:sdocexample
+msgid "Example"
+msgstr "Beispiel"
+
+#: dglobals:sdocarguments
+msgid "Arguments"
+msgstr "Argumente"
+
+#: dglobals:sdocfunctionresult
+msgid "Function result"
+msgstr "Funktionsergebnis"
+
+#: dglobals:sdocremark
+msgid "Remark:   "
+msgstr "Bemerkung:   "
+
+#: dglobals:sdocmethodoverview
+msgid "Method overview"
+msgstr "Überblick über die Methoden"
+
+#: dglobals:sdocpropertyoverview
+msgid "Property overview"
+msgstr "Überblick über die Eigenschaften"
+
+#: dglobals:sdocpage
+msgid "Page"
+msgstr "Seite"
+
+#: dglobals:sdocmethod
+msgid "Method"
+msgstr "Methode"
+
+#: dglobals:sdocproperty
+msgid "Property"
+msgstr "Eigenschaft"
+
+#: dglobals:sdocaccess
+msgid "Access"
+msgstr "Zugriff"
+
+#: dglobals:sdocinheritance
+msgid "Inheritance"
+msgstr "Ableitung"
+
+#: dglobals:sdocproperties
+msgid "Properties"
+msgstr "Eigenschaften"
+
+#: dglobals:sdocmethods
+msgid "Methods"
+msgstr "Methoden"
+
+#: dglobals:sdocevents
+msgid "Events"
+msgstr "Ereignisse"
+
+#: dglobals:sdocbyname
+msgid "by Name"
+msgstr "nach Name"
+
+#: dglobals:sdocvalue
+msgid "Value"
+msgstr "Wert"
+
+#: dglobals:sdocexplanation
+msgid "Explanation"
+msgstr "Erklärung"
+
+#: dglobals:sdocvaluesforenum
+msgid "Enumeration values for type %s"
+msgstr "Aufzählungswerte für Typ %s"
+

+ 80 - 0
utils/fpdoc/intl/dwriter.de.po

@@ -0,0 +1,80 @@
+#: dwriter:serrfilewriting
+msgid "An error occured during writing of file \"%s\": %s"
+msgstr "Beim Schreiben der Datei \"%s\" ist ein Fehler aufgetrete: %s"
+
+#: dwriter:serrinvalidshortdescr
+msgid "Invalid short description"
+msgstr "Ungültige Kurzbeschreibung"
+
+#: dwriter:serrinvaliddescr
+msgid "Invalid description (illegal XML element: \"%s\")"
+msgstr "Ungültige Beschreibung (illegales XML-Element: \"%s\")"
+
+#: dwriter:serrinvalidparacontent
+msgid "Invalid paragraph content"
+msgstr "Ungültiger Absatzinhalt (in <p>-Element)"
+
+#: dwriter:serrinvalidelementinlist
+msgid "Invalid element in list - only \"li\" allowed"
+msgstr "Ungültiges Element in Liste - nur \"li\" ist erlaubt"
+
+#: dwriter:serrinvalidlistcontent
+msgid "Invalid list content"
+msgstr "Ungültiger Listeninhalt"
+
+#: dwriter:serrlistisempty
+msgid "List is empty - need at least one \"li\" element"
+msgstr "Liste ist leer - brauche mindestens ein \"li\"-Element"
+
+#: dwriter:serrinvalidremarkcontent
+msgid "Invalid <remark> content (illegal XML element: \"%s\")"
+msgstr "Ungültiger <remark>-Inhalt (illegales XML-Element: \"%s\")"
+
+#: dwriter:serrinvaliddefinitiontermcontent
+msgid "Invalid content in definition term"
+msgstr "Ungültiger Inhalt in Definitionsterm"
+
+#: dwriter:serrdefinitionentrymissing
+msgid "Definition entry after definition term is missing"
+msgstr "Definitionseintrag nach Definitionsterm fehlt"
+
+#: dwriter:serrtableinvalidbordervalue
+msgid "Invalid \"border\" value for <table>"
+msgstr "Ungültiger \"border\"-Wert für <table>"
+
+#: dwriter:serrinvalidtablecontent
+msgid "Invalid table content"
+msgstr "Ungültiger Tabelleninhalt"
+
+#: dwriter:serrtablerowempty
+msgid "Table row is empty (no \"td\" elements found)"
+msgstr "Tabellenzeile ist leer (keine \"td\"-Elemente gefunden)"
+
+#: dwriter:serrinvalidcontentbeforesectiontitle
+msgid "Invalid content before section title"
+msgstr "Ungültiger Inhalt vor Abschnittstitel"
+
+#: dwriter:serrsectiontitleexpected
+msgid "Section title (\"title\" element) expected"
+msgstr "Abschnittstitel (\"title\"-Element) erwartet"
+
+#: dwriter:serrdescrtagunknown
+msgid "Warning: Unknown tag \"%s\" in description"
+msgstr "Warnung: Unbekanntes Tag \"%s\" in Beschreibung"
+
+#: dwriter:serrunknownentityreference
+msgid "Warning: Unknown entity reference \"&%s;\" found"
+msgstr "Warnung: Unbekannte Entity-Referenz \"&%s;\" gefunden"
+
+#: dwriter:serrunknownlinkid
+msgid "Warning: Target ID of <link> is unknown: \"%s\""
+msgstr "Warnung: Ziel-ID von <link> ist unbekannt: \"%s\""
+
+#: dwriter:serrunknownprintshortid
+msgid "Warning: Target ID of <printshort> is unknown: \"%s\""
+msgstr "Warnung: Ziel-ID von <printshort> ist unbekannt: \"%s\""
+
+#: dwriter:serrunknownlink
+msgid "Could not resolve link to \"%s\""
+msgstr "Konnte Link auf \"%s\" nicht auflösen"
+

+ 36 - 0
utils/fpdoc/intl/fpdoc.de.po

@@ -0,0 +1,36 @@
+#: fpdoc:stitle
+msgid "FPDoc - Free Pascal Documentation Tool"
+msgstr "FPDoc - Free-Pascal-Dokumentationstool"
+
+#: fpdoc:scopyright
+msgid "(c) 2000 - 2003 Areca Systems GmbH / Sebastian Guenther, [email protected]"
+msgstr "(c) 2000 - 2003 Areca Systems GmbH / Sebastian Günther, [email protected]"
+
+#: fpdoc:scmdlinehelp
+msgid "See documentation for usage."
+msgstr "Siehe Dokumentation zur Beschreibung der Verwendungsweise."
+
+#: fpdoc:scmdlineinvalidoption
+msgid "Ignoring unknown option \"%s\""
+msgstr "Ignoriere unbekannte Option \"%s\""
+
+#: fpdoc:scmdlineinvalidformat
+msgid "Invalid format \"%s\" specified"
+msgstr "Ungültiges Format \"%s\" angegeben"
+
+#: fpdoc:scmdlineoutputoptionmissing
+msgid "Need an output filename, please specify one with --output=<filename>"
+msgstr "Benötige einen Ausgabedateinamen, bitte geben Sie einen mit --output=<dateiname> an"
+
+#: fpdoc:swritingpages
+msgid "Writing %d pages..."
+msgstr "Schreibe %d Seiten..."
+
+#: fpdoc:sneedpackagename
+msgid "No package name specified. Please specify one using the --package option."
+msgstr "Kein Paketname angegeben. Bitte geben Sie einen mit Hilfe der '--package'-Option an."
+
+#: fpdoc:sdone
+msgid "Done."
+msgstr "Fertig."
+

+ 32 - 0
utils/fpdoc/intl/fpdocmk.de.po

@@ -0,0 +1,32 @@
+#: fpdocmk:stitle
+msgid "FPDocMK - Makefile.fpc processor for Free Pascal Documentation Tool"
+msgstr "FPDocMK - Makefile.fpc-Prozessor für das Free-Pascal-Documentationstool"
+
+#: fpdocmk:scopyright
+msgid "(c) 2003 Areca Systems GmbH / Sebastian Guenther, [email protected]"
+msgstr "(c) 2003 Areca Systems GmbH / Sebastian Günther, [email protected]"
+
+#: fpdocmk:scmdlinehelp
+msgid "See documentation for usage."
+msgstr ""
+
+#: fpdocmk:scmdlineinvalidoption
+msgid "Ignoring unknown option \"%s\""
+msgstr ""
+
+#: fpdocmk:scmdlineinvalidformat
+msgid "Invalid format \"%s\" specified"
+msgstr ""
+
+#: fpdocmk:scmdlineoutputoptionmissing
+msgid "Need an output path or filename, please specify one with --output=<filename>"
+msgstr "Benötige einen Ausgabepfad oder -Dateinamen, bitte geben Sie einen mit --output=<dateiname> an"
+
+#: fpdocmk:sneedpackagename
+msgid "No package name specified. Please specify one using the --package option."
+msgstr ""
+
+#: fpdocmk:sdone
+msgid "Done."
+msgstr "Fertig."
+

+ 265 - 0
utils/fpdoc/intl/fpdocstr.de.po

@@ -0,0 +1,265 @@
+#: fpdocstr:sptreeelement
+msgid "Generic element"
+msgstr "Generisches Element"
+
+#: fpdocstr:sptreesection
+msgid "Unit section"
+msgstr "Unit-Abschnitt"
+
+#: fpdocstr:sptreemodule
+msgid "Module"
+msgstr "Modul"
+
+#: fpdocstr:sptreepackage
+msgid "Package"
+msgstr "Paket"
+
+#: fpdocstr:sptreeresstring
+msgid "Resource string"
+msgstr "Ressourcen-String"
+
+#: fpdocstr:sptreetype
+msgid "Generic type"
+msgstr "Generischer Typ"
+
+#: fpdocstr:sptreepointertype
+msgid "Pointer type"
+msgstr "Zeigertyp"
+
+#: fpdocstr:sptreealiastype
+msgid "Alias type"
+msgstr "Alias-Typ"
+
+#: fpdocstr:sptreetypealiastype
+msgid "\"type\" alias type"
+msgstr "\"type\" Alias-Type"
+
+#: fpdocstr:sptreeclassoftype
+msgid "\"class of\" type"
+msgstr "\"class of\" Typ"
+
+#: fpdocstr:sptreerangetype
+msgid "Range type"
+msgstr "Bereichstyp"
+
+#: fpdocstr:sptreearraytype
+msgid "Array type"
+msgstr "Array-Typ"
+
+#: fpdocstr:sptreeenumvalue
+msgid "Enumeration value"
+msgstr "Aufzählungswert"
+
+#: fpdocstr:sptreeenumtype
+msgid "Enumeration type"
+msgstr "Aufzählungstyp"
+
+#: fpdocstr:sptreesettype
+msgid "Set type"
+msgstr "Mengentyp"
+
+#: fpdocstr:sptreerecordtype
+msgid "Record type"
+msgstr "Record-Typ"
+
+#: fpdocstr:sptreeclasstype
+msgid "Class"
+msgstr "Klasse"
+
+#: fpdocstr:sptreeargument
+msgid "Argument"
+msgstr "Argument"
+
+#: fpdocstr:sptreeproceduretype
+msgid "Procedure type"
+msgstr "Prozedur-Typ"
+
+#: fpdocstr:sptreeresultelement
+msgid "Function result"
+msgstr "Funktionsergebnis"
+
+#: fpdocstr:sptreefunctiontype
+msgid "Function type"
+msgstr "Funktionstyp"
+
+#: fpdocstr:sptreetyperef
+msgid "Type reference"
+msgstr "Typ-Verweis"
+
+#: fpdocstr:sptreevariable
+msgid "Variable"
+msgstr "Variable"
+
+#: fpdocstr:sptreeconst
+msgid "Constant"
+msgstr "Konstante"
+
+#: fpdocstr:sptreeproperty
+msgid "Property"
+msgstr "Eigenschaft"
+
+#: fpdocstr:sptreeoverloadedprocedure
+msgid "Overloaded procedure"
+msgstr "Überladene Prozedur"
+
+#: fpdocstr:sptreeprocedure
+msgid "Procedure"
+msgstr "Prozedur"
+
+#: fpdocstr:sptreefunction
+msgid "Function"
+msgstr "Funktion"
+
+#: fpdocstr:sptreeconstructor
+msgid "Constructor"
+msgstr "Konstruktur"
+
+#: fpdocstr:sptreedestructor
+msgid "Destructor"
+msgstr "Destruktor"
+
+#: fpdocstr:sdocpackagetitle
+msgid "Reference for package '%s'"
+msgstr "Referenz für das Paket '%s'"
+
+#: fpdocstr:sdocprograms
+msgid "Programs"
+msgstr "Programme"
+
+#: fpdocstr:sdocunits
+msgid "Units"
+msgstr "Units"
+
+#: fpdocdef:sdocunittitle
+msgid "Reference for unit '%s'"
+msgstr "Referenz für Unit '%s'"
+
+#: fpdocdef:sdocinterfacesection
+msgid "Interface section"
+msgstr "Interface-Abschnitt"
+
+#: fpdocdef:sdocimplementationsection
+msgid "Implementation section"
+msgstr "Implementation-Abschnitt"
+
+#: fpdocdef:sdocusedunits
+msgid "Used units"
+msgstr "Verwendete Units"
+
+#: fpdocdef:sdocusedunitsbyunitxy
+msgid "Used units by unit '%s'"
+msgstr "Von Unit '%s' verwendete Units"
+
+#: fpdocdef:sdocconststypesvars
+msgid "Constants, types and variables"
+msgstr "Konstanten, Typen und Variablen"
+
+#: fpdocdef:sdocresstrings
+msgid "Resource strings"
+msgstr "Ressourcen-Strings"
+
+#: fpdocdef:sdoctypes
+msgid "Types"
+msgstr "Typen"
+
+#: fpdocdef:sdocconstants
+msgid "Constants"
+msgstr "Konstanten"
+
+#: fpdocdef:sdocclasses
+msgid "Classes"
+msgstr "Klassen"
+
+#: fpdocdef:sdocproceduresandfunctions
+msgid "Procedures and functions"
+msgstr "Prozeduren und Funktionen"
+
+#: fpdocdef:sdocvariables
+msgid "Variables"
+msgstr "Variablen"
+
+#: fpdocdef:sdocoverview
+msgid "Overview"
+msgstr "Überblick"
+
+#: fpdocdef:sdocsearch
+msgid "Search"
+msgstr "Suchen"
+
+#: fpdocdef:sdocdeclaration
+msgid "Declaration"
+msgstr "Deklaration"
+
+#: fpdocdef:sdocdescription
+msgid "Description"
+msgstr "Beschreibung"
+
+#: fpdocstr:sdocerrors
+msgid "Errors"
+msgstr "Fehler"
+
+#: fpdocdef:sdocseealso
+msgid "See also"
+msgstr "Siehe auch"
+
+#: fpdocstr:sdocexample
+msgid "Example"
+msgstr "Beispiel"
+
+#: fpdocdef:sdocarguments
+msgid "Arguments"
+msgstr "Argumente"
+
+#: fpdocdef:sdocfunctionresult
+msgid "Function result"
+msgstr "Funktionsergebnis"
+
+#: fpdocstr:sdocremark
+msgid "Remark:   "
+msgstr "Bemerkung:   "
+
+#: fpdocstr:sdocmethodoverview
+msgid "Method overview"
+msgstr "Überblick über die Methoden"
+
+#: fpdocstr:sdocpropertyoverview
+msgid "Property overview"
+msgstr "Überblick über die Eigenschaften"
+
+#: fpdocstr:sdocpage
+msgid "Page"
+msgstr "Seite"
+
+#: fpdocstr:sdocmethod
+msgid "Method"
+msgstr "Methode"
+
+#: fpdocstr:sdocproperty
+msgid "Property"
+msgstr "Eigenschaft"
+
+#: fpdocstr:sdocaccess
+msgid "Access"
+msgstr "Zugriff"
+
+#: fpdocstr:sdocinheritance
+msgid "Inheritance"
+msgstr "Vererbung"
+
+
+#: fpdocstr:sdocproperties
+msgid "Properties"
+msgstr "Eigenschaften"
+
+#: fpdocstr:sdocmethods
+msgid "Methods"
+msgstr "Methoden"
+
+#: fpdocstr:sdocevents
+msgid "Events"
+msgstr "Ereignisse"
+
+#: fpdocstr:sdocbyname
+msgid "by Name"
+msgstr "nach Name"
+

+ 24 - 0
utils/fpdoc/intl/makeskel.de.po

@@ -0,0 +1,24 @@
+#: makeskel:stitle
+msgid "MakeSkel - FPDoc skeleton XML description file generator"
+msgstr "MakeSkel - Skelett-Generator für FPDoc-XML-Beschreibungsdateien"
+
+#: makeskel:scopyright
+msgid "(c) 2000 - 2003 Areca Systems GmbH / Sebastian Guenther, [email protected]"
+msgstr "(c) 2000 - 2003 Areca Systems GmbH / Sebastian Günther, [email protected]"
+
+#: makeskel:scmdlinehelp
+msgid "See documentation for usage."
+msgstr "Siehe Dokumentation zur Handhabung."
+
+#: makeskel:scmdlineinvalidoption
+msgid "Ignoring unknown option \"%s\""
+msgstr "Ignoriere unbekannte Option \"%s\""
+
+#: makeskel:snopackagenameprovided
+msgid "Please specify a package name with --package=<name>"
+msgstr "Bitte geben Sie einen Paketnamen mit --package=<name> an"
+
+#: makeskel:sdone
+msgid "Done."
+msgstr "Fertig."
+

+ 306 - 0
utils/fpdoc/makeskel.pp

@@ -0,0 +1,306 @@
+{
+    $Id$
+
+    FPDoc  -  Free Pascal Documentation Tool
+    Copyright (C) 2000 - 2003 by
+      Areca Systems GmbH / Sebastian Guenther, [email protected]
+
+    * Skeleton XML description file generator
+
+    See the file COPYING, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+}
+
+
+program MakeSkel;
+
+uses
+  SysUtils, Classes, Gettext,
+  dGlobals, PasTree, PParser;
+
+resourcestring
+  STitle = 'MakeSkel - FPDoc skeleton XML description file generator';
+  SCopyright = '(c) 2000 - 2003 Areca Systems GmbH / Sebastian Guenther, [email protected]';
+  SCmdLineHelp = 'See documentation for usage.';
+  SCmdLineInvalidOption = 'Ignoring unknown option "%s"';
+  SNoPackageNameProvided = 'Please specify a package name with --package=<name>';
+  SDone = 'Done.';
+
+type
+  TCmdLineAction = (actionHelp, actionConvert);
+
+  TSkelEngine = class(TFPDocEngine)
+  public
+    function CreateElement(AClass: TPTreeElement; const AName: String;
+      AParent: TPasElement; AVisibility :TPasMemberVisibility): TPasElement; override;
+  end;
+
+const
+  CmdLineAction: TCmdLineAction = actionConvert;
+
+var
+  InputFiles, DescrFiles: TStringList;
+  DocLang: String;
+  Engine: TSkelEngine;
+  DisableErrors,
+  DisableSeealso,
+  DisableArguments,
+  DisableProtected,
+  DisablePrivate,
+  DisableFunctionResults: Boolean;
+  
+  EmitClassSeparator: Boolean;
+  PackageName, OutputName: String;
+  f: Text;
+
+
+function TSkelEngine.CreateElement(AClass: TPTreeElement; const AName: String;
+  AParent: TPasElement; AVisibility : TPasMemberVisibility): TPasElement;
+begin
+  Result := AClass.Create(AName, AParent);
+
+  if AClass.InheritsFrom(TPasModule) then
+    CurModule := TPasModule(Result);
+
+  if Result.ClassType = TPasModule then
+  begin
+    WriteLn(f);
+    WriteLn(f, '<!--');
+    WriteLn(f, '  ====================================================================');
+    WriteLn(f, '    ', Result.Name);
+    WriteLn(f, '  ====================================================================');
+    WriteLn(f, '-->');
+    WriteLn(f);
+    WriteLn(f, '<module name="', Result.Name, '">');
+    WriteLn(f, '<short></short>');
+    WriteLn(f, '<descr>');
+    WriteLn(f, '</descr>');
+  end else if Assigned(AParent) and (Length(AName) > 0) and
+    (not DisableArguments or (Result.ClassType <> TPasArgument)) and
+    (not DisableFunctionResults or (Result.ClassType <> TPasResultElement)) and
+    (not DisablePrivate or (AVisibility<>visPrivate)) and
+    (not DisableProtected or (AVisibility<>visProtected)) then
+  begin
+    WriteLn(f);
+    if EmitClassSeparator and (Result.ClassType = TPasClassType) then
+    begin
+      WriteLn(f, '<!--');
+      WriteLn(f, '  ********************************************************************');
+      WriteLn(f, '    ', Result.PathName);
+      WriteLn(f, '  ********************************************************************');
+      WriteLn(f, '-->');
+      WriteLn(f);
+    end;
+    Writeln(F,'<!-- ', Result.ElementTypeName,' Visibility: ',VisibilityNames[AVisibility], ' -->');
+    WriteLn(f,'<element name="', Result.FullName, '">');
+    WriteLn(f, '<short></short>');
+    WriteLn(f, '<descr>');
+    WriteLn(f, '</descr>');
+    if not DisableErrors then
+    begin
+      WriteLn(f, '<errors>');
+      WriteLn(f, '</errors>');
+    end;
+    if not DisableSeealso then
+    begin
+      WriteLn(f, '<seealso>');
+      WriteLn(f, '</seealso>');
+    end;
+    WriteLn(f, '</element>');
+  end;
+end;
+
+
+procedure InitOptions;
+begin
+  InputFiles := TStringList.Create;
+  DescrFiles := TStringList.Create;
+  Engine := TSkelEngine.Create;
+end;
+
+procedure FreeOptions;
+begin
+  Engine.Free;
+  DescrFiles.Free;
+  InputFiles.Free;
+end;
+
+procedure ParseOption(const s: String);
+
+  procedure AddToFileList(List: TStringList; const FileName: String);
+  var
+    f: Text;
+    s: String;
+  begin
+    if Copy(FileName, 1, 1) = '@' then
+    begin
+      Assign(f, Copy(FileName, 2, Length(FileName)));
+      Reset(f);
+      while not EOF(f) do
+      begin
+        ReadLn(f, s);
+	List.Add(s);
+      end;
+      Close(f);
+    end else
+      List.Add(FileName);
+  end;
+
+var
+  i: Integer;
+  Cmd, Arg: String;
+begin
+  if (s = '-h') or (s = '--help') then
+    CmdLineAction := actionHelp
+  else if s = '--disable-arguments' then
+    DisableArguments := True
+  else if s = '--disable-errors' then
+    DisableErrors := True
+  else if s = '--disable-function-results' then
+    DisableFunctionResults := True
+  else if s = '--disable-seealso' then
+    DisableSeealso := True
+  else if s = '--disable-private' then
+    DisablePrivate := True
+  else if s = '--disable-protected' then
+    begin
+    DisableProtected := True;
+    DisablePrivate :=True;
+    end
+  else if s = '--emitclassseparator' then
+    EmitClassSeparator := True
+  else
+  begin
+    i := Pos('=', s);
+    if i > 0 then
+    begin
+      Cmd := Copy(s, 1, i - 1);
+      Arg := Copy(s, i + 1, Length(s));
+    end else
+    begin
+      Cmd := s;
+      SetLength(Arg, 0);
+    end;
+    if (Cmd = '-i') or (Cmd = '--input') then
+      AddToFileList(InputFiles, Arg)
+    else if (Cmd = '-l') or (Cmd = '--lang') then
+      DocLang := Arg
+    else if (Cmd = '-o') or (Cmd = '--output') then
+      OutputName := Arg
+    else if Cmd = '--package' then
+      PackageName := Arg
+    else
+      WriteLn(StdErr, Format(SCmdLineInvalidOption, [s]));
+  end;
+end;
+
+procedure ParseCommandLine;
+var
+  i: Integer;
+begin
+  for i := 1 to ParamCount do
+    ParseOption(ParamStr(i));
+end;
+
+
+var
+  i: Integer;
+  Module: TPasModule;
+begin
+{$IFDEF Unix}
+  gettext.TranslateResourceStrings('/usr/local/share/locale/%s/LC_MESSAGES/makeskel.mo');
+{$ELSE}
+  gettext.TranslateResourceStrings('intl/makeskel.%s.mo');
+{$ENDIF}
+
+  WriteLn(STitle);
+  WriteLn(SCopyright);
+  WriteLn;
+
+  InitOptions;
+  ParseCommandLine;
+
+  if CmdLineAction = actionHelp then
+    WriteLn(SCmdLineHelp)
+  else
+  begin
+    // Action is to create the XML skeleton
+
+    if Length(PackageName) = 0 then
+    begin
+      WriteLn(SNoPackageNameProvided);
+      Halt(2);
+    end;
+
+    Engine.SetPackageName(PackageName);
+
+    // Translate internal documentation strings
+    if Length(DocLang) > 0 then
+      TranslateDocStrings(DocLang);
+
+    Assign(f, OutputName);
+    Rewrite(f);
+
+    WriteLn(f, '<?xml version="1.0" encoding="ISO8859-1"?>');
+    WriteLn(f, '<fpdoc-descriptions>');
+    WriteLn(f, '<package name="', PackageName, '">');
+
+    // Process all source files
+    for i := 0 to InputFiles.Count - 1 do
+    begin
+      Module := ParseSource(Engine, InputFiles[i]);
+      try
+	WriteLn(f, '</module> <!-- ', Module.Name, ' -->');
+      finally
+        Module.Free;
+      end;
+    end;
+
+    WriteLn(f, '</package>');
+    WriteLn(f, '</fpdoc-descriptions>');
+
+    Close(f);
+  end;
+
+  FreeOptions;
+
+  WriteLn(SDone);
+end.
+
+
+{
+  $Log$
+  Revision 1.1  2003-03-17 23:03:20  michael
+  + Initial import in CVS
+
+  Revision 1.7  2003/03/13 22:02:13  sg
+  * New version with many bugfixes and our own parser (now independent of the
+    compiler source)
+
+  Revision 1.6  2002/10/12 17:00:46  michael
+  + Changes to be able to disable private/protected nodes in skeleton
+
+  Revision 1.5  2002/10/11 18:41:50  sg
+  * Now requires a package name on the command line via "--package=<name>",
+    to match the recent changes in the engine
+  * translation files are now searched at the usual location on Linux
+
+  Revision 1.4  2002/05/24 00:13:22  sg
+  * much improved new version, including many linking and output fixes
+
+  Revision 1.3  2002/03/12 10:58:36  sg
+  * reworked linking engine and internal structure
+
+  Revision 1.2  2001/07/27 10:21:42  sg
+  * Just a new, improved version ;)
+    (detailed changelogs will be provided again with the next commits)
+
+  Revision 1.1  2000/10/28 20:15:26  sg
+  * Many internal architectural improvements (especially linking)
+  * Improved writers
+
+}

+ 334 - 0
utils/fpdoc/sh_pas.pp

@@ -0,0 +1,334 @@
+{
+    $Id$
+
+    "SHEdit" - Text editor with syntax highlighting
+    Copyright (C) 1999-2000 by Sebastian Guenther ([email protected])
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+}
+
+
+// Syntax highlighting class for Pascal sources
+
+// !!! Slightly modified version for fpDoc !!!
+
+
+{$MODE objfpc}
+{$H+}
+
+{$IFDEF Debug}
+{$ASSERTIONS On}
+{$ENDIF}
+
+unit sh_pas;
+
+interface
+
+const
+  LF_SH_Valid      = $01;
+  LF_SH_Multiline1 = $02;
+  LF_SH_Multiline2 = $04;
+  LF_SH_Multiline3 = $08;
+  LF_SH_Multiline4 = $10;
+  LF_SH_Multiline5 = $20;
+  LF_SH_Multiline6 = $40;
+  LF_SH_Multiline7 = $80;
+
+  LF_Escape = #10;
+
+  shDefault = 1;
+  shInvalid = 2;
+  shSymbol = 3;
+  shKeyword = 4;
+  shComment = 5;
+  shDirective = 6;
+  shNumbers = 7;
+  shCharacters = 8;
+  shStrings = 9;
+  shAssembler = 10;
+
+
+procedure DoPascalHighlighting(var flags: Byte; source, dest: PChar);
+
+
+implementation
+
+uses Strings;
+
+const
+
+  LF_SH_Comment1 = LF_SH_Multiline1;	{ Normal braced Comments}
+  LF_SH_Comment2 = LF_SH_Multiline2;    { (* *) Comments}
+  LF_SH_Asm      = LF_SH_Multiline3;
+
+  MaxKeywordLength = 15;
+  MaxKeyword = 60;
+
+  KeywordTable: array[0..MaxKeyword] of PChar =
+    ('AND', 'ARRAY', 'ASM', 'ASSEMBLER',
+     'BEGIN', 'BREAK',
+     'CASE', 'CONST', 'CONSTRUCTOR', 'CLASS',
+     'DEFAULT', 'DESTRUCTOR', 'DIV', 'DO', 'DOWNTO',
+     'ELSE', 'END', 'EXCEPT', 'EXIT',
+     'FINALIZATION', 'FINALLY', 'FOR', 'FUNCTION',
+     'GOTO',
+     'IF', 'IMPLEMENTATION', 'IN', 'INHERITED', 'INITIALIZATION', 'INTERFACE',
+     'NIL', 'NOT',
+     'OBJECT', 'OF', 'ON', 'OR', 'OVERRIDE',
+     'PACKED', 'PRIVATE', 'PROCEDURE', 'PROGRAM', 'PROPERTY', 'PROTECTED',
+       'PUBLIC', 'PUBLISHED',
+     'RAISE', 'RECORD', 'REPEAT', 'RESOURCESTRING',
+     'SET',
+     'THEN', 'TRY', 'TYPE',
+     'UNIT', 'UNTIL', 'USES',
+     'VAR', 'VIRTUAL',
+     'WHILE', 'WITH',
+     'XOR');
+
+  KeywordAsmIndex = 2;
+
+
+procedure DoPascalHighlighting(var flags: Byte; source, dest: PChar);
+var
+  dp: Integer;		// Destination position - current offset in dest
+  LastSHPos: Integer;	// Position of last highlighting character, or 0
+
+  procedure AddSH(sh: Byte);
+  begin
+    ASSERT(sh > 0);
+    if (LastSHPos > 0) and (dp = LastSHPos + 1) then Dec(dp, 2);
+    dest[dp] := LF_Escape; Inc(dp);
+    LastSHPos := dp;
+    dest[dp] := Chr(sh); Inc(dp);
+  end;
+
+  procedure PutChar;
+  begin
+    dest[dp] := source[0]; Inc(dp); Inc(source);
+  end;
+
+  procedure ProcessComment1;
+  begin
+    while source[0] <> #0 do begin
+      if source[0] = '}' then begin
+        PutChar;
+        flags := flags and not LF_SH_Comment1;
+        AddSH(shDefault);
+        break;
+      end;
+      PutChar;
+    end;
+  end;
+
+  procedure ProcessComment2;
+  begin
+    while source[0] <> #0 do begin
+      if (source[0] = '*') and (source[1] = ')') then begin
+        PutChar; PutChar;
+        flags := flags and not LF_SH_Comment2;
+        AddSH(shDefault);
+        break;
+      end;
+      PutChar;
+    end;
+  end;
+
+
+  { Checks if we are at the beginning of a comment (or directive) and processes
+    all types of comments and directives, or returns False }
+
+  function CheckForComment: Boolean;
+  begin
+    Result := True;
+    if source[0] = '{' then begin
+      if source[1] = '$' then
+        AddSH(shDirective)
+      else
+        AddSH(shComment);
+      PutChar;
+      flags := flags or LF_SH_Comment1;
+      ProcessComment1;
+    end else if (source[0] = '(') and (source[1] = '*') then begin
+      AddSH(shComment);
+      PutChar; PutChar;
+      flags := flags or LF_SH_Comment2;
+      ProcessComment2;
+    end else if (source[0] = '/') and (source[1] = '/') then begin
+      AddSH(shComment);
+      repeat PutChar until source[0] = #0;
+      AddSH(shDefault);
+    end else
+      Result := False;
+  end;
+
+  procedure ProcessAsm;
+  var
+    LastChar: Char;
+  begin
+    LastChar := ' ';
+    while source[0] <> #0 do begin
+      if (LastChar in [' ', #9, #10, #13]) and
+        (UpCase(source[0]) = 'E') and (UpCase(source[1]) = 'N') and
+        (UpCase(source[2]) = 'D') then begin
+        AddSH(shKeyword);
+        PutChar; PutChar; PutChar;
+        flags := flags and not LF_SH_Asm;
+        AddSH(shDefault);
+        break;
+      end else
+        if CheckForComment then LastChar := ' '
+        else begin
+          LastChar := source[0];
+          PutChar;
+        end;
+    end;
+  end;
+
+  procedure ProcessSymbol;
+  begin
+    AddSH(shSymbol);
+    if (source[0] = ':') and (source[1] = '=') then
+      PutChar;
+    PutChar;
+    AddSH(shDefault);
+  end;
+
+  function CheckForKeyword: Boolean;
+  var
+    keyword, ukeyword: array[0..MaxKeywordLength] of Char;
+    i, j: Integer;
+  begin
+    i := 0;
+    while (source[i] <> #0) and (i < MaxKeywordLength) and
+      (source[i] in ['0'..'9', 'A'..'Z', 'a'..'z']) do begin
+      keyword[i] := source[i];
+      ukeyword[i] := UpCase(source[i]);
+      Inc(i);
+    end;
+    keyword[i] := #0; ukeyword[i] := #0;
+    Result := False;
+    if i < MaxKeywordLength then
+      for j := 0 to MaxKeyword do
+        if StrIComp(KeywordTable[j], ukeyword) = 0 then begin
+          Result := True; break;
+        end;
+    if not Result then exit;
+    Inc(source, i);
+    AddSH(shKeyword);
+    StrCopy(dest + dp, keyword);
+    Inc(dp, i);
+    if j <> KeywordAsmIndex then
+      AddSH(shDefault)
+    else begin
+      AddSH(shAssembler);
+      flags := flags or LF_SH_Asm;
+      ProcessAsm;
+    end;
+  end;
+
+var
+  StringLength: Integer;
+begin
+  dp := 0;
+  LastSHPos := 0;
+
+  if (flags and LF_SH_Comment1) <> 0 then begin
+    AddSH(shComment);
+    ProcessComment1;
+  end;
+
+  if (flags and LF_SH_Comment2) <> 0 then begin
+    AddSH(shComment);
+    ProcessComment2;
+  end;
+
+  if (flags and LF_SH_Asm) <> 0 then begin
+    AddSH(shAssembler);
+    ProcessAsm;
+  end;
+
+  while source[0] <> #0 do begin
+
+    if CheckForComment then continue;
+
+    case source[0] of
+      ',', ';', ':', '.', '(', ')', '[', ']', '<', '>', '=',
+      '*', '/', '+', '-', '^', '&', '@': ProcessSymbol;
+      '#': begin
+          AddSH(shCharacters);
+          PutChar;
+          if source[0] = '$' then PutChar;
+          while (source[0] >= '0') and (source[0] <= '9') do PutChar;
+          AddSH(shDefault);
+        end;
+      '$': begin
+          AddSH(shNumbers);
+          PutChar;
+          while source[0] in ['0'..'9', 'A'..'F', 'a'..'f'] do PutChar;
+          AddSH(shDefault);
+        end;
+      '0'..'9': begin
+          AddSH(shNumbers);
+          PutChar;
+          while (source[0] >= '0') and (source[0] <= '9') do PutChar;
+          AddSH(shDefault);
+        end;
+      '''': begin
+          AddSH(shStrings);
+          PutChar;
+          StringLength := 0;
+          while source[0] <> #0  do begin
+            if source[0] = '''' then
+              if source[1] = '''' then PutChar
+              else begin
+                PutChar; break;
+              end;
+            Inc(StringLength);
+            PutChar;
+          end;
+          if StringLength = 1 then
+            dest[LastSHPos] := Chr(shCharacters);
+	  if (source[0] = #0) and (dest[dp - 1] <> '''') then
+	    dest[LastSHPos] := Chr(shInvalid);
+          AddSH(shDefault);
+        end;
+      '_', 'A'..'Z', 'a'..'z': begin
+          if not CheckForKeyword then
+            repeat
+              PutChar
+            until not (source[0] in ['0'..'9', '_', 'A'..'Z', 'a'..'z']);
+        end;
+      ' ': PutChar;
+      else begin
+        AddSH(shInvalid);
+        PutChar;  // = found an invalid char!
+	AddSH(shDefault);
+      end;
+    end;
+  end;
+
+  dest[dp] := #0;
+end;
+
+
+end.
+
+
+{
+  $Log$
+  Revision 1.1  2003-03-17 23:03:20  michael
+  + Initial import in CVS
+
+  Revision 1.2  2000/10/30 21:22:10  sg
+  * Increased all highlighting style constants by 1, as 0 is not valid!
+
+  Revision 1.1  2000/10/28 20:15:26  sg
+  * Many internal architectural improvements (especially linking)
+  * Improved writers
+
+}