Browse Source

* First version (with exception of the HTTP unit: This is an improved version
of the old asyncio HTTP unit, now adapted to fpAsync)

sg 23 years ago
parent
commit
b08afa2937

+ 1370 - 0
fcl/net/Makefile

@@ -0,0 +1,1370 @@
+#
+# Don't edit, this file is generated by FPCMake Version 1.1 [2003/04/22]
+#
+default: all
+MAKEFILETARGETS=linux go32v2 win32 os2 freebsd beos netbsd amiga atari sunos qnx netware openbsd wdosx palmos macos macosx
+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 /,\,/)
+ifdef inCygWin
+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
+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_COMPILERINFO:=$(shell $(FPC) -iVSPTPSOTO)
+FPC_VERSION:=$(word 1,$(FPC_COMPILERINFO))
+endif
+export FPC FPC_VERSION FPC_COMPILERINFO
+unexport CHECKDEPEND ALLDEPENDENCIES
+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
+ifneq ($(words $(FPC_COMPILERINFO)),5)
+FPC_COMPILERINFO+=$(shell $(FPC) -iSP)
+FPC_COMPILERINFO+=$(shell $(FPC) -iTP)
+FPC_COMPILERINFO+=$(shell $(FPC) -iSO)
+FPC_COMPILERINFO+=$(shell $(FPC) -iTO)
+endif
+ifndef CPU_SOURCE
+CPU_SOURCE:=$(word 2,$(FPC_COMPILERINFO))
+endif
+ifndef CPU_TARGET
+CPU_TARGET:=$(word 3,$(FPC_COMPILERINFO))
+endif
+ifndef OS_SOURCE
+OS_SOURCE:=$(word 4,$(FPC_COMPILERINFO))
+endif
+ifndef OS_TARGET
+OS_TARGET:=$(word 5,$(FPC_COMPILERINFO))
+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=fcl
+ifeq ($(OS_TARGET),linux)
+override TARGET_PROGRAMS+=mkxmlrpc
+endif
+ifeq ($(OS_TARGET),freebsd)
+override TARGET_PROGRAMS+=mkxmlrpc
+endif
+ifeq ($(OS_TARGET),netbsd)
+override TARGET_PROGRAMS+=mkxmlrpc
+endif
+ifeq ($(OS_TARGET),openbsd)
+override TARGET_PROGRAMS+=mkxmlrpc
+endif
+override TARGET_UNITS+=servlets
+ifeq ($(OS_TARGET),linux)
+override TARGET_UNITS+=http httpsvlt xmlrpc
+endif
+ifeq ($(OS_TARGET),freebsd)
+override TARGET_UNITS+=http httpsvlt xmlrpc
+endif
+ifeq ($(OS_TARGET),netbsd)
+override TARGET_UNITS+=http httpsvlt xmlrpc
+endif
+ifeq ($(OS_TARGET),openbsd)
+override TARGET_UNITS+=http httpsvlt xmlrpc
+endif
+ifeq ($(OS_TARGET),linux)
+override TARGET_RSTS+=httpsvlt
+endif
+ifeq ($(OS_TARGET),freebsd)
+override TARGET_RSTS+=httpsvlt
+endif
+ifeq ($(OS_TARGET),netbsd)
+override TARGET_RSTS+=httpsvlt
+endif
+ifeq ($(OS_TARGET),openbsd)
+override TARGET_RSTS+=httpsvlt
+endif
+ifeq ($(OS_TARGET),linux)
+override TARGET_EXAMPLEDIRS+=tests
+endif
+ifeq ($(OS_TARGET),freebsd)
+override TARGET_EXAMPLEDIRS+=tests
+endif
+ifeq ($(OS_TARGET),netbsd)
+override TARGET_EXAMPLEDIRS+=tests
+endif
+ifeq ($(OS_TARGET),openbsd)
+override TARGET_EXAMPLEDIRS+=tests
+endif
+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
+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
+ifeq ($(OS_TARGET),macos)
+PPUEXT=.ppu
+ASMEXT=.s
+OEXT=.o
+SMARTEXT=.sl
+STATICLIBEXT=.a
+EXEEXT=
+FPCMADE=fpcmade.mcc
+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 
+ifeq ($(OS_TARGET),linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(OS_TARGET),go32v2)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(OS_TARGET),win32)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(OS_TARGET),os2)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(OS_TARGET),freebsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(OS_TARGET),beos)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(OS_TARGET),netbsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(OS_TARGET),amiga)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(OS_TARGET),atari)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(OS_TARGET),sunos)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(OS_TARGET),qnx)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(OS_TARGET),netware)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(OS_TARGET),openbsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(OS_TARGET),wdosx)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(OS_TARGET),palmos)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(OS_TARGET),macos)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(OS_TARGET),macosx)
+REQUIRE_PACKAGES_RTL=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
+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
+ifeq ($(OS_TARGET),linux)
+ifeq ($(FPC_VERSION),1.0.6)
+override FPCOPTDEF+=HASUNIX
+endif
+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_units
+ifdef TARGET_UNITS
+override ALLTARGET+=fpc_units
+override UNITPPUFILES=$(addsuffix $(PPUEXT),$(TARGET_UNITS))
+override IMPLICITUNITPPUFILES=$(addsuffix $(PPUEXT),$(TARGET_IMPLICITUNITS))
+override INSTALLPPUFILES+=$(UNITPPUFILES) $(IMPLICITUNITPPUFILES)
+override CLEANPPUFILES+=$(UNITPPUFILES) $(IMPLICITUNITPPUFILES)
+endif
+fpc_units: $(UNITPPUFILES)
+.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_examples
+ifdef TARGET_EXAMPLES
+HASEXAMPLES=1
+override EXAMPLESOURCEFILES:=$(wildcard $(addsuffix .pp,$(TARGET_EXAMPLES)) $(addsuffix .pas,$(TARGET_EXAMPLES)))
+override EXAMPLEFILES:=$(addsuffix $(EXEEXT),$(TARGET_EXAMPLES))
+override EXAMPLEOFILES:=$(addsuffix $(OEXT),$(TARGET_EXAMPLES)) $(addprefix $(STATICLIBPREFIX),$(addsuffix $(STATICLIBEXT),$(TARGET_EXAMPLES)))
+override CLEANEXEFILES+=$(EXAMPLEFILES) $(EXAMPLEOFILES)
+ifeq ($(OS_TARGET),os2)
+override CLEANEXEFILES+=$(addsuffix $(AOUTEXT),$(TARGET_EXAMPLES))
+endif
+endif
+ifdef TARGET_EXAMPLEDIRS
+HASEXAMPLES=1
+endif
+fpc_examples: all $(EXAMPLEFILES) $(addsuffix _all,$(TARGET_EXAMPLEDIRS))
+.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_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
+ifeq ($(OS_TARGET),linux)
+TARGET_EXAMPLEDIRS_TESTS=1
+endif
+ifeq ($(OS_TARGET),freebsd)
+TARGET_EXAMPLEDIRS_TESTS=1
+endif
+ifeq ($(OS_TARGET),netbsd)
+TARGET_EXAMPLEDIRS_TESTS=1
+endif
+ifeq ($(OS_TARGET),openbsd)
+TARGET_EXAMPLEDIRS_TESTS=1
+endif
+ifdef TARGET_EXAMPLEDIRS_TESTS
+tests_all:
+	$(MAKE) -C tests all
+tests_debug:
+	$(MAKE) -C tests debug
+tests_smart:
+	$(MAKE) -C tests smart
+tests_release:
+	$(MAKE) -C tests release
+tests_examples:
+	$(MAKE) -C tests examples
+tests_shared:
+	$(MAKE) -C tests shared
+tests_install:
+	$(MAKE) -C tests install
+tests_sourceinstall:
+	$(MAKE) -C tests sourceinstall
+tests_exampleinstall:
+	$(MAKE) -C tests exampleinstall
+tests_distinstall:
+	$(MAKE) -C tests distinstall
+tests_zipinstall:
+	$(MAKE) -C tests zipinstall
+tests_zipsourceinstall:
+	$(MAKE) -C tests zipsourceinstall
+tests_zipexampleinstall:
+	$(MAKE) -C tests zipexampleinstall
+tests_zipdistinstall:
+	$(MAKE) -C tests zipdistinstall
+tests_clean:
+	$(MAKE) -C tests clean
+tests_distclean:
+	$(MAKE) -C tests distclean
+tests_cleanall:
+	$(MAKE) -C tests cleanall
+tests_info:
+	$(MAKE) -C tests info
+tests_makefiles:
+	$(MAKE) -C tests makefiles
+tests:
+	$(MAKE) -C tests all
+.PHONY: tests_all tests_debug tests_smart tests_release tests_examples tests_shared tests_install tests_sourceinstall tests_exampleinstall tests_distinstall tests_zipinstall tests_zipsourceinstall tests_zipexampleinstall tests_zipdistinstall tests_clean tests_distclean tests_cleanall tests_info tests_makefiles tests
+endif
+all: fpc_all
+debug: fpc_debug
+smart: fpc_smart
+release: fpc_release
+examples: fpc_examples
+shared:
+install: fpc_install
+sourceinstall: fpc_sourceinstall
+exampleinstall: fpc_exampleinstall
+distinstall:
+zipinstall:
+zipsourceinstall:
+zipexampleinstall:
+zipdistinstall:
+clean: fpc_clean $(addsuffix _clean,$(TARGET_EXAMPLEDIRS))
+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

+ 31 - 0
fcl/net/Makefile.fpc

@@ -0,0 +1,31 @@
+#
+#   Makefile.fpc for FCL net units
+#
+
+[package]
+main=fcl
+
+[target]
+units=servlets
+units_linux=http httpsvlt xmlrpc
+units_freebsd=http httpsvlt xmlrpc
+units_netbsd=http httpsvlt xmlrpc
+units_openbsd=http httpsvlt xmlrpc
+programs_linux=mkxmlrpc
+programs_freebsd=mkxmlrpc
+programs_netbsd=mkxmlrpc
+programs_openbsd=mkxmlrpc
+rsts_linux=httpsvlt mkxmlrpc
+rsts_freebsd=httpsvlt mkxmlrpc
+rsts_netbsd=httpsvlt mkxmlrpc
+rsts_openbsd=httpsvlt mkxmlrpc
+exampledirs_linux=tests
+exampledirs_freebsd=tests
+exampledirs_netbsd=tests
+exampledirs_openbsd=tests
+
+[compiler]
+options=-S2h
+
+[install]
+fpcpackage=y

+ 682 - 0
fcl/net/http.pp

@@ -0,0 +1,682 @@
+{
+    $Id$
+
+    HTTP: Classes for dealing with HTTP requests
+    Copyright (C) 2000-2003 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.
+}
+
+
+unit HTTP;
+
+interface
+
+uses Classes, SSockets, fpAsync;
+
+const
+
+  fieldAccept = 'Accept';
+  fieldAcceptCharset = 'Accept-Charset';
+  fieldAcceptEncoding = 'Accept-Encoding';
+  fieldAcceptLanguage = 'Accept-Language';
+  fieldAuthorization = 'Authorization';
+  fieldContentEncoding = 'Content-Encoding';
+  fieldContentLanguage = 'Content-Language';
+  fieldContentLength = 'Content-Length';
+  fieldContentType = 'Content-Type';
+  fieldCookie = 'Cookie';
+  fieldDate = 'Date';
+  fieldExpires = 'Expires';
+  fieldFrom = 'From';
+  fieldIfModifiedSince = 'If-Modified-Since';
+  fieldLastModified = 'Last-Modified';
+  fieldLocation = 'Location';
+  fieldPragma = 'Pragma';
+  fieldReferer = 'Referer';
+  fieldRetryAfter = 'Retry-After';
+  fieldServer = 'Server';
+  fieldSetCookie = 'Set-Cookie';
+  fieldUserAgent = 'User-Agent';
+  fieldWWWAuthenticate = 'WWW-Authenticate';
+
+type
+
+  PHttpField = ^THttpField;
+  THttpField = record
+    Name, Value: String;
+  end;
+
+
+  THttpHeader = class
+  protected
+    FReader: TAsyncStreamLineReader;
+    FWriter: TAsyncWriteStream;
+    FOnCompleted: TNotifyEvent;
+    FFields: TList;
+    CmdReceived: Boolean;
+
+    procedure ParseFirstHeaderLine(const line: String); virtual; abstract;
+    procedure LineReceived(const ALine: String);
+    function GetFirstHeaderLine: String; virtual; abstract;
+    procedure WriterCompleted(ASender: TObject);
+
+    function GetFieldCount: Integer;
+    function GetFields(AIndex: Integer): String;
+    function GetFieldNames(AIndex: Integer): String;
+    procedure SetFieldNames(AIndex: Integer; const AName: String);
+    function GetFieldValues(AIndex: Integer): String;
+    procedure SetFieldValues(AIndex: Integer; const AValue: String);
+
+
+    function  GetAccept: String;
+    procedure SetAccept(const AValue: String);
+    function  GetAcceptCharset: String;
+    procedure SetAcceptCharset(const AValue: String);
+    function  GetAcceptEncoding: String;
+    procedure SetAcceptEncoding(const AValue: String);
+    function  GetAcceptLanguage: String;
+    procedure SetAcceptLanguage(const AValue: String);
+    function  GetAuthorization: String;
+    procedure SetAuthorization(const AValue: String);
+    function  GetContentEncoding: String;
+    procedure SetContentEncoding(const AValue: String);
+    function  GetContentLanguage: String;
+    procedure SetContentLanguage(const AValue: String);
+    function  GetContentLength: Integer;
+    procedure SetContentLength(AValue: Integer);
+    function  GetContentType: String;
+    procedure SetContentType(const AValue: String);
+    function  Get_Cookie: String;
+    procedure Set_Cookie(const AValue: String);
+    function  GetDate: String;
+    procedure SetDate(const AValue: String);
+    function  GetExpires: String;
+    procedure SetExpires(const AValue: String);
+    function  GetFrom: String;
+    procedure SetFrom(const AValue: String);
+    function  GetIfModifiedSince: String;
+    procedure SetIfModifiedSince(const AValue: String);
+    function  GetLastModified: String;
+    procedure SetLastModified(const AValue: String);
+    function  GetLocation: String;
+    procedure SetLocation(const AValue: String);
+    function  GetPragma: String;
+    procedure SetPragma(const AValue: String);
+    function  GetReferer: String;
+    procedure SetReferer(const AValue: String);
+    function  GetRetryAfter: String;
+    procedure SetRetryAfter(const AValue: String);
+    function  GetServer: String;
+    procedure SetServer(const AValue: String);
+    function  Get_SetCookie: String;
+    procedure Set_SetCookie(const AValue: String);
+    function  GetUserAgent: String;
+    procedure SetUserAgent(const AValue: String);
+    function  GetWWWAuthenticate: String;
+    procedure SetWWWAuthenticate(const AValue: String);
+
+  public
+    HttpVersion: String;
+
+    constructor Create;
+    destructor Destroy; override;
+    procedure SetFieldByName(const AName, AValue: String);
+    function  GetFieldByName(const AName: String): String;
+
+    procedure AsyncSend(AManager: TEventLoop; AStream: THandleStream);
+    procedure AsyncReceive(AManager: TEventLoop; AStream: THandleStream);
+
+    property Reader: TAsyncStreamLineReader read FReader;
+    property Writer: TAsyncWriteStream read FWriter;
+    property FieldCount: Integer read GetFieldCount;
+    property Fields[AIndex: Integer]: String read GetFields;
+    property FieldNames[AIndex: Integer]: String read GetFieldNames write SetFieldNames;
+    property FieldValues[AIndex: Integer]: String read GetFieldValues write SetFieldValues;
+
+    property OnCompleted: TNotifyEvent read FOnCompleted write FOnCompleted;
+
+    property Accept: String read GetAccept write SetAccept;
+    property AcceptCharset: String read GetAcceptCharset write SetAcceptCharset;
+    property AcceptEncoding: String read GetAcceptEncoding write SetAcceptEncoding;
+    property AcceptLanguage: String read GetAcceptLanguage write SetAcceptLanguage;
+    property Authorization: String read GetAuthorization write SetAuthorization;
+    property ContentEncoding: String read GetContentEncoding write SetContentEncoding;
+    property ContentLanguage: String read GetContentLanguage write SetContentLanguage;
+    property ContentLength: Integer read GetContentLength write SetContentLength;
+    property ContentType: String read GetContentType write SetContentType;
+    property Cookie: String read Get_Cookie write Set_Cookie;
+    property Date: String read GetDate write SetDate;
+    property Expires: String read GetExpires write SetExpires;
+    property From: String read GetFrom write SetFrom;
+    property IfModifiedSince: String read GetIfModifiedSince write SetIfModifiedSince;
+    property LastModified: String read GetLastModified write SetLastModified;
+    property Location: String read GetLocation write SetLocation;
+    property Pragma: String read GetPragma write SetPragma;
+    property Referer: String read GetReferer write SetReferer;
+    property RetryAfter: String read GetRetryAfter write SetRetryAfter;
+    property Server: String read GetServer write SetServer;
+    property SetCookie: String read Get_SetCookie write Set_SetCookie;
+    property UserAgent: String read GetUserAgent write SetUserAgent;
+    property WWWAuthenticate: String read GetWWWAuthenticate write SetWWWAuthenticate;
+  end;
+
+
+  THttpRequestHeader = class(THttpHeader)
+  protected
+    procedure ParseFirstHeaderLine(const line: String); override;
+    function  GetFirstHeaderLine: String; override;
+  public
+    CommandLine: String;
+    Command: String;
+    URI: String;		// Uniform Resource Identifier
+    QueryString: String;
+  end;
+
+
+  THttpAnswerHeader = class(THttpHeader)
+  protected
+    procedure ParseFirstHeaderLine(const line: String); override;
+    function  GetFirstHeaderLine: String; override;
+  public
+    Code: Integer;
+    CodeText: String;
+    constructor Create;
+  end;
+
+
+  TCustomHttpConnection = class
+  protected
+    FManager: TEventLoop;
+    FSocket: TInetSocket;
+    SendBuffer: TAsyncWriteStream;
+    FOnHeaderSent, FOnStreamSent, FOnHeaderReceived, FOnStreamReceived: TNotifyEvent;
+    FOnDestroy: TNotifyEvent;
+    RecvSize: Integer;	// How many bytes are still to be read. -1 if unknown.
+    DataAvailableNotifyHandle: Pointer;
+
+    procedure HeaderToSendCompleted(Sender: TObject);
+    procedure StreamToSendCompleted(Sender: TObject);
+    procedure ReceivedHeaderCompleted(Sender: TObject);
+    procedure DataAvailable(Sender: TObject);
+    procedure ReceivedStreamCompleted(Sender: TObject);
+
+    property OnHeaderSent: TNotifyEvent read FOnHeaderSent write FOnHeaderSent;
+    property OnStreamSent: TNotifyEvent read FOnStreamSent write FOnStreamSent;
+    property OnHeaderReceived: TNotifyEvent read FOnHeaderReceived write FOnHeaderReceived;
+    property OnStreamReceived: TNotifyEvent read FOnStreamReceived write FOnStreamReceived;
+    property OnDestroy: TNotifyEvent read FOnDestroy write FOnDestroy;
+
+  public
+    HeaderToSend: THttpHeader;
+    StreamToSend: TStream;
+    ReceivedHeader: THttpHeader;
+    ReceivedStream: TStream;
+    DoDestroy: Boolean;
+
+    constructor Create(AManager: TEventLoop; ASocket: TInetSocket);
+    destructor Destroy; override;
+    procedure Receive;
+    procedure Send;
+  end;
+
+  THttpConnection = class(TCustomHttpConnection)
+  public
+    property OnHeaderSent;
+    property OnStreamSent;
+    property OnHeaderReceived;
+    property OnStreamReceived;
+    property OnDestroy;
+  end;
+
+
+// ===================================================================
+// ===================================================================
+
+implementation
+
+uses SysUtils;
+
+
+// -------------------------------------------------------------------
+//   THttpHeader
+// -------------------------------------------------------------------
+
+procedure THttpHeader.LineReceived(const ALine: String);
+var
+  i: Integer;
+begin
+  if Length(ALine) = 0 then
+  begin
+    FReader.OnLine := nil;	// Stop receiving
+    FReader.StopAndFree;
+    if Assigned(FOnCompleted) then
+      FOnCompleted(Self);
+    FReader := nil;
+  end else
+    if not CmdReceived then
+    begin
+      CmdReceived := True;
+      ParseFirstHeaderLine(ALine);
+    end else
+    begin
+      i := Pos(':', ALine);
+      SetFieldByName(Trim(Copy(ALine, 1, i - 1)),
+        Trim(Copy(ALine, i + 1, Length(ALine))));
+    end;
+end;
+
+procedure THttpHeader.WriterCompleted(ASender: TObject);
+begin
+  if Assigned(FOnCompleted) then
+    FOnCompleted(Self);
+  FreeAndNil(FWriter);
+end;
+
+function THttpHeader.GetFieldCount: Integer;
+begin
+  Result := FFields.Count;
+end;
+
+function THttpHeader.GetFields(AIndex: Integer): String;
+begin
+  Result := FieldNames[AIndex] + ': ' + FieldValues[AIndex];
+end;
+
+function THttpHeader.GetFieldNames(AIndex: Integer): String;
+begin
+  Result := PHttpField(FFields.Items[AIndex])^.Name;
+end;
+
+procedure THttpHeader.SetFieldNames(AIndex: Integer; const AName: String);
+begin
+  PHttpField(FFields.Items[AIndex])^.Name := AName;
+end;
+
+function THttpHeader.GetFieldValues(AIndex: Integer): String;
+begin
+  Result := PHttpField(FFields.Items[AIndex])^.Value;
+end;
+
+procedure THttpHeader.SetFieldValues(AIndex: Integer; const AValue: String);
+begin
+  PHttpField(FFields.Items[AIndex])^.Name := AValue;
+end;
+
+function  THttpHeader.GetAccept: String; begin Result := GetFieldByName(fieldAccept) end;
+procedure THttpHeader.SetAccept(const AValue: String); begin SetFieldByName(fieldAccept, AValue) end;
+function  THttpHeader.GetAcceptCharset: String; begin Result := GetFieldByName(fieldAcceptCharset) end;
+procedure THttpHeader.SetAcceptCharset(const AValue: String); begin SetFieldByName(fieldAcceptCharset, AValue) end;
+function  THttpHeader.GetAcceptEncoding: String; begin Result := GetFieldByName(fieldAcceptEncoding) end;
+procedure THttpHeader.SetAcceptEncoding(const AValue: String); begin SetFieldByName(fieldAcceptEncoding, AValue) end;
+function  THttpHeader.GetAcceptLanguage: String; begin Result := GetFieldByName(fieldAcceptLanguage) end;
+procedure THttpHeader.SetAcceptLanguage(const AValue: String); begin SetFieldByName(fieldAcceptLanguage, AValue) end;
+function  THttpHeader.GetAuthorization: String; begin Result := GetFieldByName(fieldAuthorization) end;
+procedure THttpHeader.SetAuthorization(const AValue: String); begin SetFieldByName(fieldAuthorization, AValue) end;
+function  THttpHeader.GetContentEncoding: String; begin Result := GetFieldByName(fieldContentEncoding) end;
+procedure THttpHeader.SetContentEncoding(const AValue: String); begin SetFieldByName(fieldContentEncoding, AValue) end;
+function  THttpHeader.GetContentLanguage: String; begin Result := GetFieldByName(fieldContentLanguage) end;
+procedure THttpHeader.SetContentLanguage(const AValue: String); begin SetFieldByName(fieldContentLanguage, AValue) end;
+function  THttpHeader.GetContentLength: Integer; var s: String; begin s := GetFieldByName(fieldContentLength); if Length(s) = 0 then Result := -1 else Result := StrToInt(s) end;
+procedure THttpHeader.SetContentLength(AValue: Integer); begin SetFieldByName(fieldContentLength, IntToStr(AValue)) end;
+function  THttpHeader.GetContentType: String; begin Result := GetFieldByName(fieldContentType) end;
+procedure THttpHeader.SetContentType(const AValue: String); begin SetFieldByName(fieldContentType, AValue) end;
+function  THttpHeader.Get_Cookie: String; begin Result := GetFieldByName(fieldCookie) end;
+procedure THttpHeader.Set_Cookie(const AValue: String); begin SetFieldByName(fieldCookie, AValue) end;
+function  THttpHeader.GetDate: String; begin Result := GetFieldByName(fieldDate) end;
+procedure THttpHeader.SetDate(const AValue: String); begin SetFieldByName(fieldDate, AValue) end;
+function  THttpHeader.GetExpires: String; begin Result := GetFieldByName(fieldExpires) end;
+procedure THttpHeader.SetExpires(const AValue: String); begin SetFieldByName(fieldExpires, AValue) end;
+function  THttpHeader.GetFrom: String; begin Result := GetFieldByName(fieldFrom) end;
+procedure THttpHeader.SetFrom(const AValue: String); begin SetFieldByName(fieldFrom, AValue) end;
+function  THttpHeader.GetIfModifiedSince: String; begin Result := GetFieldByName(fieldIfModifiedSince) end;
+procedure THttpHeader.SetIfModifiedSince(const AValue: String); begin SetFieldByName(fieldIfModifiedSince, AValue) end;
+function  THttpHeader.GetLastModified: String; begin Result := GetFieldByName(fieldLastModified) end;
+procedure THttpHeader.SetLastModified(const AValue: String); begin SetFieldByName(fieldLastModified, AValue) end;
+function  THttpHeader.GetLocation: String; begin Result := GetFieldByName(fieldLocation) end;
+procedure THttpHeader.SetLocation(const AValue: String); begin SetFieldByName(fieldLocation, AValue) end;
+function  THttpHeader.GetPragma: String; begin Result := GetFieldByName(fieldPragma) end;
+procedure THttpHeader.SetPragma(const AValue: String); begin SetFieldByName(fieldPragma, AValue) end;
+function  THttpHeader.GetReferer: String; begin Result := GetFieldByName(fieldReferer) end;
+procedure THttpHeader.SetReferer(const AValue: String); begin SetFieldByName(fieldReferer, AValue) end;
+function  THttpHeader.GetRetryAfter: String; begin Result := GetFieldByName(fieldRetryAfter) end;
+procedure THttpHeader.SetRetryAfter(const AValue: String); begin SetFieldByName(fieldRetryAfter, AValue) end;
+function  THttpHeader.GetServer: String; begin Result := GetFieldByName(fieldServer) end;
+procedure THttpHeader.SetServer(const AValue: String); begin SetFieldByName(fieldServer, AValue) end;
+function  THttpHeader.Get_SetCookie: String; begin Result := GetFieldByName(fieldSetCookie) end;
+procedure THttpHeader.Set_SetCookie(const AValue: String); begin SetFieldByName(fieldSetCookie, AValue) end;
+function  THttpHeader.GetUserAgent: String; begin Result := GetFieldByName(fieldUserAgent) end;
+procedure THttpHeader.SetUserAgent(const AValue: String); begin SetFieldByName(fieldUserAgent, AValue) end;
+function  THttpHeader.GetWWWAuthenticate: String; begin Result := GetFieldByName(fieldWWWAuthenticate) end;
+procedure THttpHeader.SetWWWAuthenticate(const AValue: String); begin SetFieldByName(fieldWWWAuthenticate, AValue) end;
+
+constructor THttpHeader.Create;
+begin
+  inherited Create;
+  FFields := TList.Create;
+  HttpVersion := '1.0';
+end;
+
+destructor THttpHeader.Destroy;
+var
+  i: Integer;
+  Field: PHttpField;
+begin
+  if Assigned(FReader) then
+    FReader.StopAndFree;
+  if Assigned(FWriter) then
+    FWriter.StopAndFree;
+  for i := 0 to FFields.Count - 1 do
+  begin
+    Field := PHttpField(FFields.Items[i]);
+{    SetLength(Field^.Name, 0);
+    SetLength(Field^.Value, 0);}
+    Dispose(Field);
+  end;
+  FFields.Free;
+  inherited Destroy;
+end;
+
+function THttpHeader.GetFieldByName(const AName: String): String;
+var
+  i: Integer;
+  Name: String;
+begin
+  Name := UpperCase(AName);
+  for i := 0 to FFields.Count - 1 do
+    if UpperCase(FieldNames[i]) = Name then
+    begin
+      Result := FieldValues[i];
+      exit;
+    end;
+  SetLength(Result, 0);
+end;
+
+procedure THttpHeader.SetFieldByName(const AName, AValue: String);
+var
+  i: Integer;
+  Name: String;
+  Field: PHttpField;
+begin
+  Name := UpperCase(AName);
+  for i := 0 to FFields.Count - 1 do
+    if UpperCase(FieldNames[i]) = Name then
+    begin
+      FieldNames[i] := AName;	// preserve case
+      FieldValues[i] := AValue;
+      exit;
+    end;
+  New(Field);
+  FillChar(Field^, SizeOf(Field^), 0);
+  Field^.Name := AName;
+  Field^.Value := AValue;
+  FFields.Add(field);
+end;
+
+procedure THttpHeader.AsyncSend(AManager: TEventLoop; AStream: THandleStream);
+var
+  i: Integer;
+begin
+  if Assigned(FWriter) then
+    FWriter.StopAndFree;
+  FWriter := TAsyncWriteStream.Create(AManager, AStream);
+  FWriter.OnBufferEmpty := @WriterCompleted;
+  FWriter.EndOfLineMarker := #13#10;
+  FWriter.WriteLine(GetFirstHeaderLine);
+  for i := 0 to FFields.Count - 1 do
+    FWriter.WriteLine(Fields[i]);
+  FWriter.WriteLine('');
+end;
+
+procedure THttpHeader.AsyncReceive(AManager: TEventLoop; AStream: THandleStream);
+begin
+  CmdReceived := False;
+  FReader.Free;
+  FReader := TAsyncStreamLineReader.Create(AManager, AStream);
+  FReader.OnLine := @LineReceived;
+end;
+
+
+// -------------------------------------------------------------------
+//   THttpRequestHeader
+// -------------------------------------------------------------------
+
+procedure THttpRequestHeader.ParseFirstHeaderLine(const line: String);
+var
+  i: Integer;
+begin
+  CommandLine := line;
+  i := Pos(' ', line);
+  Command := UpperCase(Copy(line, 1, i - 1));
+  URI := Copy(line, i + 1, Length(line));
+
+  // Extract HTTP version
+  i := Pos(' ', URI);
+  if i > 0 then
+  begin
+    HttpVersion := Copy(URI, i + 1, Length(URI));
+    URI := Copy(URI, 1, i - 1);
+    HttpVersion := Copy(HttpVersion, Pos('/', HttpVersion) + 1, Length(HttpVersion));
+  end;
+
+  // Extract query string
+  i := Pos('?', URI);
+  if i > 0 then
+  begin
+    QueryString := Copy(URI, i + 1, Length(URI));
+    URI := Copy(URI, 1, i - 1);
+  end;
+end;
+
+function THttpRequestHeader.GetFirstHeaderLine: String;
+begin
+  Result := Command + ' ' + URI;
+  if Length(HttpVersion) > 0 then
+    Result := Result + ' HTTP/' + HttpVersion;
+end;
+
+
+// -------------------------------------------------------------------
+//   THttpAnswerHeader
+// -------------------------------------------------------------------
+
+procedure THttpAnswerHeader.ParseFirstHeaderLine(const line: String);
+var
+  i: Integer;
+  s: String;
+begin
+  i := Pos('/', line);
+  s := Copy(line, i + 1, Length(line));
+  i := Pos(' ', s);
+  HttpVersion := Copy(s, 1, i - 1);
+  s := Copy(s, i + 1, Length(s));
+  i := Pos(' ', s);
+  if i > 0 then begin
+    CodeText := Copy(s, i + 1, Length(s));
+    s := Copy(s, 1, i - 1);
+  end;
+  Code := StrToInt(s);
+end;
+
+function THttpAnswerHeader.GetFirstHeaderLine: String;
+begin
+  Result := Format('HTTP/%s %d %s', [HttpVersion, Code, CodeText]);
+end;
+
+constructor THttpAnswerHeader.Create;
+begin
+  inherited Create;
+  Code := 200;
+  CodeText := 'OK';
+end;
+
+
+// -------------------------------------------------------------------
+//   TCustomHttpConnection
+// -------------------------------------------------------------------
+
+procedure TCustomHttpConnection.HeaderToSendCompleted(Sender: TObject);
+begin
+  //WriteLn('TCustomHttpConnection.HeaderToSendCompleted');
+  if Assigned(FOnHeaderSent) then
+    FOnHeaderSent(Self);
+  if Assigned(StreamToSend) then
+  begin
+    SendBuffer := TAsyncWriteStream.Create(FManager, FSocket);
+    SendBuffer.CopyFrom(StreamToSend, StreamToSend.Size);
+    SendBuffer.OnBufferEmpty := @StreamToSendCompleted;
+  end else
+  begin
+    StreamToSendCompleted(nil);
+    if DoDestroy then
+      Self.Free;
+  end;
+end;
+
+procedure TCustomHttpConnection.StreamToSendCompleted(Sender: TObject);
+begin
+  if Assigned(FOnStreamSent) then
+    FOnStreamSent(Self);
+  //WriteLn('TCustomHttpConnection.StreamToSendCompleted');
+  FreeAndNil(SendBuffer);
+  if DoDestroy then
+    Self.Free;
+end;
+
+procedure TCustomHttpConnection.ReceivedHeaderCompleted(Sender: TObject);
+var
+  BytesInBuffer: Integer;
+begin
+  //WriteLn('TCustomHttpConnection.ReceivedHeaderCompleted');
+  BytesInBuffer := ReceivedHeader.Reader.BytesInBuffer;
+  //WriteLn('BytesInBuffer: ', BytesInBuffer, ', Content length: ', ReceivedHeader.ContentLength);
+  if Assigned(FOnHeaderReceived) then
+    FOnHeaderReceived(Self);
+
+  RecvSize := ReceivedHeader.ContentLength;
+  if Assigned(ReceivedStream) then
+  begin
+    if BytesInBuffer > 0 then
+    begin
+      ReceivedStream.Write(ReceivedHeader.Reader.Buffer^, BytesInBuffer);
+      if RecvSize > 0 then
+        Dec(RecvSize, BytesInBuffer);
+      if BytesInBuffer = ReceivedHeader.ContentLength then
+      begin
+        ReceivedStreamCompleted(nil);
+	exit;
+      end;
+    end;
+    DataAvailableNotifyHandle :=
+      FManager.SetDataAvailableNotify(FSocket.Handle, @DataAvailable, FSocket);
+  end else
+    ReceivedStreamCompleted(nil);
+  if DoDestroy then
+    Self.Free;
+end;
+
+procedure TCustomHttpConnection.DataAvailable(Sender: TObject);
+var
+  FirstRun: Boolean;
+  ReadNow, BytesRead: Integer;
+  buf: array[0..1023] of Byte;
+begin
+  FirstRun := True;
+  while True do
+  begin
+    if RecvSize >= 0 then
+    begin
+      ReadNow := RecvSize;
+      if ReadNow > 1024 then
+        ReadNow := 1024;
+    end else
+      ReadNow := 1024;
+    BytesRead := FSocket.Read(buf, ReadNow);
+    //WriteLn('TCustomHttpConnection.DataAvailable: Read ', BytesRead, ' bytes; RecvSize=', RecvSize);
+    if BytesRead <= 0 then
+    begin
+      if FirstRun then
+        ReceivedStreamCompleted(nil);
+      break;
+    end;
+    FirstRun := False;
+    ReceivedStream.Write(buf, BytesRead);
+    if RecvSize > 0 then
+      Dec(RecvSize, BytesRead);
+    if RecvSize = 0 then
+    begin
+      ReceivedStreamCompleted(nil);
+      break;
+    end;
+  end;
+  if DoDestroy then
+    Self.Free;
+end;
+
+procedure TCustomHttpConnection.ReceivedStreamCompleted(Sender: TObject);
+begin
+  //WriteLn('TCustomHttpConnection.ReceivedStreamCompleted');
+  if Assigned(DataAvailableNotifyHandle) then
+  begin
+    FManager.ClearDataAvailableNotify(DataAvailableNotifyHandle);
+    DataAvailableNotifyHandle := nil;
+  end;
+  if Assigned(FOnStreamReceived) then
+    FOnStreamReceived(Self);
+  if DoDestroy then
+    Self.Free;
+end;
+
+constructor TCustomHttpConnection.Create(AManager: TEventLoop; ASocket: TInetSocket);
+begin
+  inherited Create;
+  FManager := AManager;
+  FSocket := ASocket;
+end;
+
+destructor TCustomHttpConnection.Destroy;
+begin
+  if Assigned(DataAvailableNotifyHandle) then
+    FManager.ClearDataAvailableNotify(DataAvailableNotifyHandle);
+  if Assigned(OnDestroy) then
+    OnDestroy(Self);
+  FreeAndNil(SendBuffer);
+  inherited Destroy;
+end;
+
+procedure TCustomHttpConnection.Receive;
+begin
+  // Start receiver
+  if Assigned(ReceivedHeader) then
+  begin
+    ReceivedHeader.OnCompleted := @ReceivedHeaderCompleted;
+    ReceivedHeader.AsyncReceive(FManager, FSocket);
+  end;
+end;
+
+procedure TCustomHttpConnection.Send;
+begin
+  // Start sender
+  if Assigned(HeaderToSend) then
+  begin
+    HeaderToSend.OnCompleted := @HeaderToSendCompleted;
+    HeaderToSend.AsyncSend(FManager, FSocket);
+  end;
+end;
+
+
+end.
+
+
+{
+  $Log$
+  Revision 1.1  2002-04-25 19:30:29  sg
+  * First version (with exception of the HTTP unit: This is an improved version
+    of the old asyncio HTTP unit, now adapted to fpAsync)
+
+}

+ 628 - 0
fcl/net/httpsvlt.pp

@@ -0,0 +1,628 @@
+{
+    $Id$
+
+    HTTP Servlet Classes
+    Copyright (c) 2003 by
+      Areca Systems GmbH / 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.
+}
+
+unit HTTPSvlt;
+
+interface
+
+uses SysUtils, Classes, SSockets, fpAsync, HTTP, Servlets;
+
+resourcestring
+  SErrUnknownMethod = 'Unknown HTTP method "%s" used';
+  SErrUnsupportedMethod = 'HTTP method "%s" is not supported for this URL';
+
+type
+
+  THttpSession = class
+  public
+    property Attributes[const AName: String]: TObject;	// !!!: Implement this	rw
+    property CreationTime: TDateTime;	// !!!: Implement this
+    property ID: String;		// !!!: Implement this
+    property LastAccessedTime: TDateTime;	// !!!: Implement this
+    property MaxInactiveInterval: TDateTime;	// !!!: Implement this	rw
+    property ServletContext: TServletContext;	// !!!: Implement this
+    property IsNew: Boolean;		// !!!: Implement this
+
+    // procedure Invalidate;		// !!!: Implement this
+    // procedure RemoveAttribute(const AName: String);	// !!!: Implement this
+  end;
+
+  THttpServletRequest = class(TServletRequest)
+  private
+    RequestHeader: THTTPRequestHeader;
+  protected
+    function GetContentLength: Integer; override;
+    function GetContentType: String; override;
+    function GetProtocol: String; override;
+    function GetMethod: String;
+    function GetRequestURI: String;
+    function GetQueryString: String;
+  public
+    constructor Create(ARequestHeader: THTTPRequestHeader; AInputStream: TStream;
+      const AScheme, APathInfo: String);
+    // GetSession
+
+    // function IsRequestedSessionIdFromCookie: Boolean;	// !!!: Implement this
+    // function IsRequestedSessionIdFromURL: Boolean;	// !!!: Implement this
+    // function IsRequestedSessionIdValid: Boolean;	// !!!: Implement this
+
+    property AuthType: String;		// !!!: How to implement?
+    property ContextPath: String;	// !!!: How to implement?
+    property CookieCount: Integer;	// !!!: How to implement?
+    property Cookies[Index: Integer]: Pointer;	// !!!: How to implement?
+    property DateHeaders[const AName: String]: TDateTime;	// !!!: Implement this
+    property Headers[const AName: String]: String;	// !!!: Implement this
+    property IntHeaders[const AName: String]: Integer;	// !!!: Implement this
+    property Method: String read GetMethod;
+    property PathInfo: String read FPathInfo;
+    property PathTranslated: String;	// !!!: How to implement?
+    property QueryString: String read GetQueryString;
+    property RemoteUser: String;	// !!!: How to implement?
+    property RequestedSessionID: String;	// !!!: How to implement?
+    property RequestURI: String read GetRequestURI;
+    property RequestURL: String;	// !!!: How to implement?
+    property ServletPath: String;	// !!!: How to implement?
+  end;
+
+  THttpServletResponse = class(TServletResponse)
+  private
+    ResponseHeader: THTTPAnswerHeader;
+  protected
+    procedure SetContentType(const Value: String); override;
+    procedure SetContentLength(Value: Int64); override;
+  public
+    constructor Create(AResponseHeader: THTTPAnswerHeader;
+      AOutputStream: TStream);
+    // procedure AddCookie(Cookie: TCookie);	// !!!: Implement this
+    // procedure AddDateHeader(const AName: String; ADate: TDateTime);	// !!!: Implement this
+    // procedure AddHeader(const AName, AValue: String);	// !!!: Implement this
+    // procedure AddIntHeader(const AName: String; AValue: Int64);	// !!!: Implement this
+    // function ContainsHeader(const AName: String): Boolean;	// !!!: Implement this
+    // function EncodeRedirectURL(const URL: String): String;	// !!!: Implement this
+    // function EncodeURL(const URL: String): String;	// !!!: Implement this
+    // procedure SendError(StatusCode: Integer);	// !!!: Implement this
+    // procedure SendError(StatusCode: Integer; const Msg: String);	// !!!: Implement this
+    // procedure SendRedirect(const Location: String);	// !!!: Implement this
+    // procedure SetDateHeader(const AName: String; ADate: TDateTime);	// !!!: Implement this
+    // procedure SetHeader(const AName, AValue: String);	// !!!: Implement this
+    // procedure SetIntHeader(const AName: String; AValue: Int64);	// !!!: Implement this
+    // procedure SetStatus(StatusCode: Integer);	// !!!: Implement this
+    // procedure SetStatus(StatusCode: Integer; const Msg: String);	// !!!: Implement this
+  end;
+
+  THttpServlet = class(TGenericServlet)
+  protected
+    // function GetLastModified(Req: THttpServletRequest): TDateTime;
+    // Handlers for HTTP methods
+    procedure DoDelete(Req: THttpServletRequest; Resp: THttpServletResponse);
+      virtual; abstract;
+    procedure DoGet(Req: THttpServletRequest; Resp: THttpServletResponse);
+      virtual; abstract;
+    procedure DoHead(Req: THttpServletRequest; Resp: THttpServletResponse);
+      virtual; abstract;
+    procedure DoOptions(Req: THttpServletRequest; Resp: THttpServletResponse);
+      virtual; abstract;
+    procedure DoPost(Req: THttpServletRequest; Resp: THttpServletResponse);
+      virtual; abstract;
+    procedure DoPut(Req: THttpServletRequest; Resp: THttpServletResponse);
+      virtual; abstract;
+    procedure DoTrace(Req: THttpServletRequest; Resp: THttpServletResponse);
+      virtual; abstract;
+    procedure Service(Req: THttpServletRequest; Resp: THttpServletResponse); virtual;
+  end;
+
+  // A simple file retreiving servlet
+  TCustomFileServlet = class(THttpServlet)
+  private
+    FPath: String;
+  protected
+    procedure DoGet(Req: THttpServletRequest; Resp: THttpServletResponse); override;
+    property Path: String read FPath write FPath;
+  end;
+
+  TFileServlet = class(TCustomFileServlet)
+  published
+    property Path;
+  end;
+
+
+  // HTTP server (servlet container)
+
+  TServletMapping = class(TCollectionItem)
+  private
+    FServlet: TGenericServlet;
+    FURLPattern: String;
+  published
+    property Servlet: TGenericServlet read FServlet write FServlet;
+    property URLPattern: String read FURLPattern write FURLPattern;
+  end;
+
+  TServletMappings = class(TCollection)
+  private
+    function GetItem(Index: Integer): TServletMapping;
+    procedure SetItem(Index: Integer; Value: TServletMapping);
+  public
+    property Items[Index: Integer]: TServletMapping read GetItem write SetItem;
+      default;
+  end;
+
+  THttpServer = class(TComponent)
+  private
+    FEventLoop: TEventLoop;
+    FInetServer: TInetServer;
+    FPort: Word;
+    DataAvailableNotifyHandle: Pointer;
+    Connections: TList;		// List of TXMLRPCServerConnection objects
+    FServletMappings: TServletMappings;
+    procedure InetServerDataAvailable(Sender: TObject);                                                         
+    procedure InetServerConnect(Sender: TObject; Data: TSocketStream);
+    procedure ConnectionClose(Sender: TObject);
+  public
+    constructor Create(AOwner: TComponent); override;
+    destructor Destroy; override;
+    procedure Start(AEventLoop: TEventLoop);
+    procedure AddServlet(AServlet: THttpServlet; const AURLPattern: String);
+    // procedure RemoveServlet(const APathName: String);
+    property EventLoop: TEventLoop read FEventLoop;
+    property InetServer: TInetServer read FInetServer;
+  published
+    property Port: Word read FPort write FPort;
+    property ServletMappings: TServletMappings
+      read FServletMappings write FServletMappings;
+  end;
+
+
+{ No, this one really doesn't belong to here - but as soon as we don't have a
+  nice solution for platform-independent component streaming in the FCL classes
+  unit, it will be left here. }
+function InitInheritedComponent(Instance: TComponent; RootAncestor: TClass): Boolean;
+
+
+
+implementation
+
+
+constructor THttpServletRequest.Create(ARequestHeader: THTTPRequestHeader;
+  AInputStream: TStream; const AScheme, APathInfo: String);
+begin
+  inherited Create(AInputStream, AScheme, APathInfo);
+  RequestHeader := ARequestHeader;
+end;
+
+function THttpServletRequest.GetContentLength: Integer;
+begin
+  Result := RequestHeader.ContentLength;
+end;
+
+function THttpServletRequest.GetContentType: String;
+begin
+  Result := RequestHeader.ContentType;
+end;
+
+function THttpServletRequest.GetProtocol: String;
+begin
+  Result := 'HTTP/' + RequestHeader.HttpVersion;
+end;
+
+function THttpServletRequest.GetMethod: String;
+begin
+  Result := RequestHeader.Command;
+end;
+
+function THttpServletRequest.GetRequestURI: String;
+begin
+  Result := RequestHeader.URI;
+end;
+
+function THttpServletRequest.GetQueryString: String;
+begin
+  Result := RequestHeader.QueryString;
+end;
+
+
+constructor THttpServletResponse.Create(AResponseHeader: THTTPAnswerHeader;
+  AOutputStream: TStream);
+begin
+  inherited Create(AOutputStream);
+  ResponseHeader := AResponseHeader;
+end;
+
+procedure THttpServletResponse.SetContentType(const Value: String);
+begin
+  ResponseHeader.ContentType := Value;
+end;
+
+procedure THttpServletResponse.SetContentLength(Value: Int64);
+begin
+  ResponseHeader.ContentLength := Value;
+end;
+
+
+procedure THttpServlet.Service(Req: THttpServletRequest; Resp: THttpServletResponse);
+var
+  Method: String;
+begin
+  Method := Req.Method;
+  try
+    if Method = 'DELETE' then
+      DoDelete(Req, Resp)
+    else if Method = 'GET' then
+      DoGet(Req, Resp)
+    else if Method = 'HEAD' then
+      DoHead(Req, Resp)
+    else if Method = 'OPTIONS' then
+      DoOptions(Req, Resp)
+    else if Method = 'POST' then
+      DoPost(Req, Resp)
+    else if Method = 'PUT' then
+      DoPut(Req, Resp)
+    else if Method = 'TRACE' then
+      DoTrace(Req, Resp)
+    else
+      raise EServlet.CreateFmt(SErrUnknownMethod, [Method]);
+  except
+    on e: EAbstractError do
+      raise EServlet.CreateFmt(SErrUnsupportedMethod, [Method]);
+  end;
+end;
+
+
+procedure TCustomFileServlet.DoGet(Req: THttpServletRequest;
+  Resp: THttpServletResponse);
+var
+  f: TStream;
+  s: String;
+  i, LastStart: Integer;
+begin
+  s := Req.PathInfo;
+  i := 1;
+  LastStart := 1;
+  while i <= Length(s) do
+  begin
+    if (s[i] = '/') or (s[i] = '\') then
+      LastStart := i + 1
+    else if (i = LastStart) and (s[i] = '.') and (i < Length(s)) and
+      (s[i + 1] = '..') then
+      exit;		// !!!: are ".." allowed in URLs?
+    Inc(i);
+  end;
+
+  if s = '' then
+    s := 'index.html';
+
+  f := TFileStream.Create(Path + '/' + s, fmOpenRead);
+  try
+    Resp.OutputStream.CopyFrom(f, f.Size);
+  finally
+    f.Free;
+  end;
+end;
+
+
+// HTTP Server
+
+function TServletMappings.GetItem(Index: Integer): TServletMapping;
+begin
+  Result := TServletMapping(inherited GetItem(Index));
+end;
+
+procedure TServletMappings.SetItem(Index: Integer; Value: TServletMapping);
+begin
+  inherited SetItem(Index, Value);
+end;
+
+type
+  THttpServerConnection = class
+  private
+    FOnClose: TNotifyEvent;
+    Server: THttpServer;
+    Stream: TInetSocket;
+    HTTPConnection: THTTPConnection;
+    RequestHeader: THTTPRequestHeader;
+    RequestStream: TMemoryStream;
+    ResponseHeader: THTTPAnswerHeader;
+    ResponseStream: TMemoryStream;
+
+    procedure RequestHeaderReceived(Sender: TObject);
+    procedure RequestStreamReceived(Sender: TObject);
+    procedure ResponseStreamSent(Sender: TObject);
+    procedure ConnectionDestroyed(Sender: TObject);
+  public
+    constructor Create(AServer: THttpServer; AStream: TInetSocket);
+    destructor Destroy; override;
+    property OnClose: TNotifyEvent read FOnClose write FOnClose;
+  end;
+
+
+
+constructor THttpServerConnection.Create(AServer: THttpServer;
+  AStream: TInetSocket);
+begin
+  inherited Create;
+  Server := AServer;
+  Stream := AStream;
+  RequestHeader := THTTPRequestHeader.Create;
+  RequestStream := TMemoryStream.Create;
+  HTTPConnection := THTTPConnection.Create(Server.EventLoop, Stream);
+  HTTPConnection.ReceivedHeader := RequestHeader;
+  HTTPConnection.ReceivedStream := RequestStream;
+  HTTPConnection.OnHeaderReceived := @RequestHeaderReceived;
+  HTTPConnection.OnStreamReceived := @RequestStreamReceived;
+  HTTPConnection.OnDestroy := @ConnectionDestroyed;
+  HTTPConnection.Receive;
+end;
+
+destructor THttpServerConnection.Destroy;
+begin
+  RequestHeader.Free;
+  RequestStream.Free;
+  ResponseHeader.Free;
+  ResponseStream.Free;
+  if Assigned(OnClose) then
+    OnClose(Self);
+  Stream.Free;
+  if Assigned(HTTPConnection) then
+  begin
+    HTTPConnection.OnDestroy := nil;
+    HTTPConnection.Free;
+  end;
+  inherited Destroy;
+end;
+
+procedure THttpServerConnection.RequestHeaderReceived(Sender: TObject);
+begin
+  // WriteLn('Header received: Method=', RequestHeader.Command, ', URI=', RequestHeader.URI);
+  if RequestHeader.Command = 'GET' then
+    RequestStreamReceived(nil);
+end;
+
+procedure THttpServerConnection.RequestStreamReceived(Sender: TObject);
+var
+  i: Integer;
+  Servlet: TGenericServlet;
+  s, URI: String;
+  Request: THttpServletRequest;
+  Response: THttpServletResponse;
+begin
+  // WriteLn('Stream received: ', RequestStream.Size, ' bytes');
+
+  URI := UpperCase(RequestHeader.URI);
+  for i := 0 to Server.ServletMappings.Count - 1 do
+  begin
+    s := UpperCase(Server.ServletMappings[i].URLPattern);
+    if ((s[Length(s)] = '*') and (Copy(s, 1, Length(s) - 1) =
+      Copy(URI, 1, Length(s) - 1))) or (s = URI) then
+      break;
+  end;
+
+  if i < Server.ServletMappings.Count then
+    Servlet := Server.ServletMappings[i].Servlet
+  else
+    Servlet := nil;
+
+  if RequestHeader.ContentLength = 0 then
+    RequestHeader.ContentLength := RequestStream.Size;
+  RequestStream.Position := 0;
+
+  if s[Length(s)] = '*' then
+    s := Copy(s, 1, Length(s) - 1);
+  Request := THttpServletRequest.Create(RequestHeader, RequestStream, 'http',
+    Copy(RequestHeader.URI, Length(s) + 1, Length(RequestHeader.URI)));
+
+  ResponseHeader := THTTPAnswerHeader.Create;
+  ResponseStream := TMemoryStream.Create;
+  Response := THttpServletResponse.Create(ResponseHeader, ResponseStream);
+  HTTPConnection.HeaderToSend := ResponseHeader;
+  HTTPConnection.OnStreamSent := @ResponseStreamSent;
+
+  try
+    try
+      if Assigned(Servlet) then
+        if Servlet.InheritsFrom(THttpServlet) then
+	  THttpServlet(Servlet).Service(Request, Response)
+	else
+          Servlet.Service(Request, Response)
+      else
+      begin
+        ResponseHeader.ContentType := 'text/plain';
+	s := 'Invalid URL';
+	ResponseStream.Write(s[1], Length(s));
+      end;
+    except
+      on e: Exception do
+      begin
+        s := 'An error occured: ' + ' ' + e.Message;
+	ResponseHeader.ContentType := 'text/plain';
+	ResponseStream.Write(s[1], Length(s));
+      end;
+    end;
+
+    HTTPConnection.StreamToSend := ResponseStream;
+    ResponseHeader.ContentLength := ResponseStream.Size;
+    ResponseStream.Position := 0;
+
+    HTTPConnection.Send;
+
+  finally
+    Response.Free;
+    Request.Free;
+
+    FreeAndNil(RequestHeader);
+    HTTPConnection.OnHeaderReceived := nil;
+    FreeAndNil(RequestStream);
+    HTTPConnection.OnStreamReceived := nil;
+  end;
+end;
+
+procedure THttpServerConnection.ResponseStreamSent(Sender: TObject);
+begin
+  // WriteLn('Response stream sent');
+  FreeAndNil(Stream);
+  HTTPConnection.DoDestroy := True;
+end;
+
+procedure THttpServerConnection.ConnectionDestroyed(Sender: TObject);
+begin
+  // WriteLn('Connection closed');
+  HTTPConnection := nil;
+  Free;
+end;
+
+
+constructor THttpServer.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner);
+  ServletMappings := TServletMappings.Create(TServletMapping);
+end;
+
+destructor THttpServer.Destroy;
+var
+  i: Integer;
+begin
+  ServletMappings.Free;
+  for i := 0 to Connections.Count - 1 do
+    THttpServerConnection(Connections[i]).Free;
+  Connections.Free;
+  if Assigned(DataAvailableNotifyHandle) and Assigned(EventLoop) then
+    EventLoop.ClearDataAvailableNotify(DataAvailableNotifyHandle);
+  InetServer.Free;
+  inherited Destroy;
+end;
+
+procedure THttpServer.Start(AEventLoop: TEventLoop);
+var
+  i: Integer;
+begin
+  WriteLn(ServletMappings.Count, ' servlet mappings:');
+  for i := 0 to ServletMappings.Count - 1 do
+    WriteLn(ServletMappings[i].URLPattern, ' -> ', ServletMappings[i].Servlet.Name);
+  FEventLoop := AEventLoop;
+  FInetServer := TInetServer.Create(Port);
+  Connections := TList.Create;
+  DataAvailableNotifyHandle := EventLoop.SetDataAvailableNotify(
+    InetServer.Socket, @InetServerDataAvailable, nil);
+  InetServer.OnConnect := @InetServerConnect;
+  InetServer.Listen;
+end;
+
+procedure THttpServer.AddServlet(AServlet: THttpServlet;
+  const AURLPattern: String);
+var
+  Mapping: TServletMapping;
+begin
+  Mapping := TServletMapping(ServletMappings.Add);
+  Mapping.Servlet := AServlet;
+  Mapping.URLPattern := AURLPattern;
+end;
+
+{procedure THttpServer.RemoveServlet(const APathName: String);
+var
+  i: Integer;
+begin
+  for i := 0 to Servlets.Count - 1 do
+    if TServletInfo(Servlets[i]).PathName = APathName then
+    begin
+      TServletInfo(Servlets[i]).Free;
+      Servlets.Delete(i);
+      break;
+    end;
+end;}
+
+procedure THttpServer.InetServerDataAvailable(Sender: TObject);                                                         
+begin
+  InetServer.StartAccepting;
+end;
+
+procedure THttpServer.InetServerConnect(Sender: TObject; Data: TSocketStream);
+var
+  Connection: THttpServerConnection;
+begin
+  // WriteLn('Incoming connection');
+  Connection := THttpServerConnection.Create(Self, Data as TInetSocket);
+  Connection.OnClose := @ConnectionClose;
+  Connections.Add(Connection);
+end;
+
+procedure THttpServer.ConnectionClose(Sender: TObject);
+begin
+  Connections.Remove(Sender);
+end;
+
+
+
+function InitInheritedComponent(Instance: TComponent; RootAncestor: TClass): Boolean;
+
+  function DoInitClass(ClassType: TClass): Boolean;
+  var
+    Filename: String;
+    TextStream, BinStream: TStream;
+  begin
+    Result := False;
+    if (ClassType <> TComponent) and (ClassType <> RootAncestor) then
+    begin
+      { Init the parent class first }
+      Result := DoInitClass(ClassType.ClassParent);
+
+      Filename := LowerCase(Copy(ClassType.ClassName, 2, 255)) + '.frm';
+
+      TextStream := nil;
+      BinStream := nil;
+      try
+        try
+	  TextStream := TFileStream.Create(Filename, fmOpenRead);
+	except
+	  exit;
+	end;
+        BinStream := TMemoryStream.Create;
+        ObjectTextToBinary(TextStream, BinStream);
+        BinStream.Position := 0;
+        BinStream.ReadComponent(Instance);
+        Result := True;
+      finally
+        TextStream.Free;
+	BinStream.Free;
+      end;
+    end;
+  end;
+
+begin
+  {!!!: GlobalNameSpace.BeginWrite;
+  try}
+    if (Instance.ComponentState * [csLoading, csInline]) = [] then
+    begin
+      BeginGlobalLoading;
+      try
+        Result := DoInitClass(Instance.ClassType);
+        NotifyGlobalLoading;
+      finally
+        EndGlobalLoading;
+      end;
+    end else
+      Result := DoInitClass(Instance.ClassType);
+  {finally
+    GlobalNameSpace.EndWrite;
+  end;}
+end;
+
+end.
+
+
+{
+  $Log$
+  Revision 1.1  2002-04-25 19:30:29  sg
+  * First version (with exception of the HTTP unit: This is an improved version
+    of the old asyncio HTTP unit, now adapted to fpAsync)
+
+}

+ 122 - 0
fcl/net/servlets.pp

@@ -0,0 +1,122 @@
+{
+    $Id$
+
+    Basic Servlet Support
+    Copyright (c) 2003 by
+      Areca Systems GmbH / 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.
+}
+
+unit Servlets;
+
+interface
+
+uses SysUtils, Classes;
+
+type
+
+  EServlet = class(Exception);
+
+  TServletContext = class
+  public
+    property Attributes[const AName: String]: TObject;	// !!!: Implement this	rw
+    // function GetContext(const URIPath: String): TServletContext;	// !!!: How to implement?
+    // function GetRealPath(const APath: String): String;	// !!!: How to implement?
+    property ServletContextName: String;	// !!!: How to implement?
+    // procedure Log(const AMsg: String);	// !!!: Implement this
+    // procedure RemoveAttribute(const AName: String);	// !!!: Implement this
+  end;
+
+  TServletRequest = class
+  private
+    FInputStream: TStream;
+    FScheme, FPathInfo: String;
+  protected
+    function GetContentLength: Integer; virtual; abstract;
+    function GetContentType: String; virtual; abstract;
+    function GetProtocol: String; virtual; abstract;
+  public
+    constructor Create(AInputStream: TStream; const AScheme, APathInfo: String);
+    property Attributes[const AName: String]: TObject;	// !!!: Implement this	rw
+    property CharacterEncoding: String;	// !!!: Implement this  rw
+    property ContentLength: Integer read GetContentLength;
+    property ContentType: String read GetContentType;
+    property InputStream: TStream read FInputStream;
+    property Parameters[const AName: String]: String;	// !!!: Implement this
+    property ParameterValues[const AName: String]: TStrings;	// !!!: Implement this
+    property Protocol: String read GetProtocol;
+    property RemoteAddr: String;	// !!!: Implement this
+    property RemoteHost: String;	// !!!: Implement this
+    property Scheme: String read FScheme;
+    property ServerName: String;	// !!!: How to implement?
+    property ServerPort: Integer;	// !!!: How to implement?
+    property IsSecure: Boolean;		// !!!: Implement this
+
+    // procedure RemoveAttribute(const AName: String);	// !!!: Implement this
+  end;
+
+  TServletResponse = class
+  private
+    FOutputStream: TStream;
+  protected
+    procedure SetContentType(const Value: String); virtual; abstract;
+    procedure SetContentLength(Value: Int64); virtual; abstract;
+  public
+    constructor Create(AOutputStream: TStream);
+    property BufferSize: Integer;	// !!!: How to implement?  rw
+    property CharacterEncoding: String;	// !!!: Implement this
+    property ContentLength: Int64 write SetContentLength;
+    property ContentType: String write SetContentType;
+    property OutputStream: TStream read FOutputStream;
+    property IsCommitted: Boolean;	// !!!: Implement this
+
+    // procedure FlushBuffer;		// !!!: Implement this
+    // procedure Reset;			// !!!: Implement this
+    // procedure ResetBuffer;		// !!!: Implement this
+  end;
+
+  TGenericServlet = class(TComponent)
+  public
+    procedure Service(Req: TServletRequest; Resp: TServletResponse);
+      virtual; abstract;
+    property ServletContext: TServletContext;	// !!!: Implement this
+  end;
+
+
+
+implementation
+
+
+constructor TServletRequest.Create(AInputStream: TStream;
+  const AScheme, APathInfo: String);
+begin
+  inherited Create;
+  FInputStream := AInputStream;
+  FScheme := AScheme;
+  FPathInfo := APathInfo;
+end;
+
+
+constructor TServletResponse.Create(AOutputStream: TStream);
+begin
+  inherited Create;
+  FOutputStream := AOutputStream;
+end;
+
+
+end.
+
+
+{
+  $Log$
+  Revision 1.1  2002-04-25 19:30:29  sg
+  * First version (with exception of the HTTP unit: This is an improved version
+    of the old asyncio HTTP unit, now adapted to fpAsync)
+
+}

+ 1481 - 0
fcl/net/tests/Makefile

@@ -0,0 +1,1481 @@
+#
+# Don't edit, this file is generated by FPCMake Version 1.1 [2003/04/22]
+#
+default: all
+MAKEFILETARGETS=linux go32v2 win32 os2 freebsd beos netbsd amiga atari sunos qnx netware openbsd wdosx palmos macos macosx
+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 /,\,/)
+ifdef inCygWin
+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
+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_COMPILERINFO:=$(shell $(FPC) -iVSPTPSOTO)
+FPC_VERSION:=$(word 1,$(FPC_COMPILERINFO))
+endif
+export FPC FPC_VERSION FPC_COMPILERINFO
+unexport CHECKDEPEND ALLDEPENDENCIES
+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
+ifneq ($(words $(FPC_COMPILERINFO)),5)
+FPC_COMPILERINFO+=$(shell $(FPC) -iSP)
+FPC_COMPILERINFO+=$(shell $(FPC) -iTP)
+FPC_COMPILERINFO+=$(shell $(FPC) -iSO)
+FPC_COMPILERINFO+=$(shell $(FPC) -iTO)
+endif
+ifndef CPU_SOURCE
+CPU_SOURCE:=$(word 2,$(FPC_COMPILERINFO))
+endif
+ifndef CPU_TARGET
+CPU_TARGET:=$(word 3,$(FPC_COMPILERINFO))
+endif
+ifndef OS_SOURCE
+OS_SOURCE:=$(word 4,$(FPC_COMPILERINFO))
+endif
+ifndef OS_TARGET
+OS_TARGET:=$(word 5,$(FPC_COMPILERINFO))
+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 TARGET_PROGRAMS+=rpcserv rpccli
+override TARGET_UNITS+=svrclass svrclass_xmlrpc
+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
+ifeq ($(OS_TARGET),macos)
+PPUEXT=.ppu
+ASMEXT=.s
+OEXT=.o
+SMARTEXT=.sl
+STATICLIBEXT=.a
+EXEEXT=
+FPCMADE=fpcmade.mcc
+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
+ifeq ($(OS_TARGET),palmos)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL=1
+endif
+ifeq ($(OS_TARGET),macos)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL=1
+endif
+ifeq ($(OS_TARGET),macosx)
+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
+ifeq ($(OS_TARGET),linux)
+ifeq ($(FPC_VERSION),1.0.6)
+override FPCOPTDEF+=HASUNIX
+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_units
+ifdef TARGET_UNITS
+override ALLTARGET+=fpc_units
+override UNITPPUFILES=$(addsuffix $(PPUEXT),$(TARGET_UNITS))
+override IMPLICITUNITPPUFILES=$(addsuffix $(PPUEXT),$(TARGET_IMPLICITUNITS))
+override INSTALLPPUFILES+=$(UNITPPUFILES) $(IMPLICITUNITPPUFILES)
+override CLEANPPUFILES+=$(UNITPPUFILES) $(IMPLICITUNITPPUFILES)
+endif
+fpc_units: $(UNITPPUFILES)
+.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_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:
+zipinstall:
+zipsourceinstall:
+zipexampleinstall:
+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

+ 16 - 0
fcl/net/tests/Makefile.fpc

@@ -0,0 +1,16 @@
+#
+#   Makefile.fpc for fpWeb tests
+#
+
+[require]
+packages=fcl
+
+[target]
+programs=rpcserv rpccli
+units=svrclass svrclass_xmlrpc
+
+[compiler]
+options=-S2h
+
+[install]
+fpcpackage=y

+ 4 - 0
fcl/net/tests/readme.txt

@@ -0,0 +1,4 @@
+The XML-RPC wrapper has been created using this command:
+
+mkxmlrpc --input="svrclass.pp" --serverclass=TServerClass \
+  --output="svrclass_xmlrpc.pp" --unitname=svrclass_XMLRPC

+ 51 - 0
fcl/net/tests/rpccli.pp

@@ -0,0 +1,51 @@
+program RPCCli;
+
+uses SysUtils, Classes, fpAsync, XMLRPC;
+
+type
+
+  TClientApplication = class
+    procedure WriteStringCompleted(AParser: TXMLRPCParser);
+    procedure AddCompleted(AParser: TXMLRPCParser);
+  public
+    procedure Run;
+  end;
+
+procedure TClientApplication.Run;
+var
+  Client: TXMLRPCClient;
+begin
+  Client := TXMLRPCClient.Create(nil);
+  try
+    Client.Call(@WriteStringCompleted, 'WriteString', ['A test string']);
+    Client.Call(@AddCompleted, 'Add', [123, 456]);
+  finally
+    Client.Free;
+  end;
+end;
+
+procedure TClientApplication.WriteStringCompleted(AParser: TXMLRPCParser);
+begin
+  WriteLn('"WriteString" call completed');
+end;
+
+procedure TClientApplication.AddCompleted(AParser: TXMLRPCParser);
+begin
+  WriteLn('"Add" call completed. Result: ', AParser.GetNextInt);
+end;
+
+var
+  App: TClientApplication;
+begin
+  App := TClientApplication.Create;
+  try
+    try
+      App.Run;
+    except
+      on e: Exception do
+        WriteLn('Error: ', e.Message);
+    end;
+  finally
+    App.Free;
+  end;
+end.

+ 72 - 0
fcl/net/tests/rpcserv.pp

@@ -0,0 +1,72 @@
+program RPCServ;
+
+uses SysUtils, Classes, fpAsync, HTTPSvlt, svrclass, svrclass_XMLRPC;
+
+type
+
+  TServerApplication = class(TComponent)
+  private
+    EventLoop: TEventLoop;
+    HttpServer: THttpServer;
+    ServerClass: TServerClass;
+    XMLRPCServlet: TServerClassXMLRPCServlet;
+    procedure OnKeyboardData(Sender: TObject);
+  public
+    constructor Create;
+    destructor Destroy; override;
+    procedure Run;
+  end;
+
+constructor TServerApplication.Create;
+begin
+  inherited Create(nil);
+
+  EventLoop := TEventLoop.Create;
+
+  ServerClass := TServerClass.Create;
+
+  XMLRPCServlet := TServerClassXMLRPCServlet.Create(Self);
+  XMLRPCServlet.Name := 'XMLRPCServlet';
+  XMLRPCServlet.ServerClass := ServerClass;
+
+  HttpServer := THttpServer.Create(Self);
+  if ParamCount = 2 then
+    HttpServer.Port := StrToInt(ParamStr(1))
+  else
+    HttpServer.Port := 12345;
+  HTTPServer.AddServlet(XMLRPCServlet, '/xmlrpc');
+
+  WriteLn('Listening on port ', HttpServer.Port);
+end;
+
+destructor TServerApplication.Destroy;
+begin
+  HTTPServer.Free;
+  XMLRPCServlet.Free;
+  ServerClass.Free;
+  EventLoop.Free;
+  inherited Destroy;
+end;
+
+procedure TServerApplication.Run;
+begin
+  EventLoop.SetDataAvailableNotify(StdInputHandle, @OnKeyboardData, nil);
+  HttpServer.Start(EventLoop);
+  EventLoop.Run;
+end;
+
+procedure TServerApplication.OnKeyboardData(Sender: TObject);
+begin
+  EventLoop.Break;
+end;
+
+var
+  App: TServerApplication;
+begin
+  App := TServerApplication.Create;
+  try
+    App.Run;
+  finally
+    App.Free;
+  end;
+end.

+ 27 - 0
fcl/net/tests/svrclass.pp

@@ -0,0 +1,27 @@
+unit svrclass;
+
+interface
+
+type
+
+  TServerClass = class
+  public
+    procedure WriteString(const s: String);
+    function Add(Arg1, Arg2: Integer): Integer;
+  end;
+
+
+implementation
+
+procedure TServerClass.WriteString(const s: String);
+begin
+  WriteLn('String: "', s, '"');
+end;
+
+function TServerClass.Add(Arg1, Arg2: Integer): Integer;
+begin
+  WriteLn('Adding ', Arg1, ' and ', Arg2);
+  Result := Arg1 + Arg2;
+end;
+
+end.

+ 40 - 0
fcl/net/tests/svrclass_xmlrpc.pp

@@ -0,0 +1,40 @@
+unit svrclass_XMLRPC;
+
+interface
+
+uses Classes, XMLRPC, svrclass;
+
+type
+  TServerClassXMLRPCServlet = class(TXMLRPCServlet)
+  private
+    FServerClass: TServerClass;
+  protected
+    procedure Dispatch(AParser: TXMLRPCParser; AWriter: TXMLRPCWriter; APath: TStrings); override;
+  published
+    property ServerClass: TServerClass read FServerClass write FServerClass;
+  end;
+
+
+
+implementation
+
+procedure TServerClassXMLRPCServlet.Dispatch(AParser: TXMLRPCParser; AWriter: TXMLRPCWriter; APath: TStrings);
+var
+  s: String;
+begin
+  s := APath[0];
+  if s = 'WRITESTRING' then
+  begin
+    AParser.ResetValueCursor;
+    ServerClass.WriteString(AParser.GetPrevString);
+    AWriter.WriteResponse(nil);
+  end else if s = 'ADD' then
+  begin
+    AParser.ResetValueCursor;
+    AWriter.WriteResponse(AWriter.CreateIntValue(ServerClass.Add(AParser.GetPrevInt, AParser.GetPrevInt)));
+  end else
+    AWriter.WriteFaultResponse(2, 'Invalid method name');
+end;
+
+
+end.

+ 933 - 0
fcl/net/xmlrpc.pp

@@ -0,0 +1,933 @@
+{
+    $Id$
+
+    XML-RPC server and client library
+    Copyright (c) 2003 by
+      Areca Systems GmbH / 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.
+}
+
+unit XMLRPC;
+
+interface
+
+uses SysUtils, Classes, fpAsync, ssockets, DOM, HTTP, HTTPSvlt;
+
+type
+  EXMLRPCParser = class(Exception);
+
+  TXMLRPCParams = class(TDOMElement);
+  TXMLRPCValue = class(TDOMElement);
+  TXMLRPCStruct = class(TXMLRPCValue);
+  TXMLRPCArray = class(TXMLRPCValue);
+
+  TXMLRPCWriter = class
+  private
+    Doc: TXMLDocument;
+  protected
+    function CreateValueEl: TXMLRPCValue;
+  public
+    constructor Create;
+    destructor Destroy; override;
+    function MakeStream: TMemoryStream;
+
+    procedure WriteMethodCall(const AMethodName: DOMString;
+      Params: TXMLRPCParams);
+    procedure WriteResponse(Value: TXMLRPCValue);
+    procedure WriteFaultResponse(FaultCode: LongInt;
+      const FaultString: DOMString);
+    function CreateParams: TXMLRPCParams;
+    procedure AddParam(Params: TXMLRPCParams; Value: TXMLRPCValue);
+    function CreateIntValue(i: LongInt): TXMLRPCValue;
+    function CreateBooleanValue(b: Boolean): TXMLRPCValue;
+    function CreateStringValue(const s: DOMString): TXMLRPCValue;
+    function CreateDoubleValue(d: Double): TXMLRPCValue;
+    function CreateDateTimeValue(dt: TDateTime): TXMLRPCValue;
+    function CreateStruct: TXMLRPCStruct;
+    procedure AddStructMember(Struct: TXMLRPCStruct; const Name: DOMString;
+      Member: TXMLRPCValue);
+    function CreateArray: TXMLRPCArray;
+    procedure AddArrayElement(AArray: TXMLRPCArray; Value: TXMLRPCValue);
+    // !!!: Missing: Binary data
+  end;
+
+  TXMLRPCPostType = (
+    xmlrpcInvalid,		// Invalid post type
+    xmlrpcMethodCall,		// Method call
+    xmlrpcResponse,		// Method call response (successfull)
+    xmlrpcFaultResponse);	// Method call response (failed)
+
+  TXMLRPCParser = class
+  private
+    Doc: TXMLDocument;
+    CurDataNode: TDOMNode;
+    InArray: Boolean;
+    procedure NextNode;
+    procedure PrevNode;
+    function GetValue: String;
+    function FindStructMember(AStruct: TXMLRPCStruct;
+      const AMemberName: String): TDOMElement;
+    function GetStructMemberValue(MemberNode: TDOMElement): String;
+  public
+    constructor Create(AStream: TStream);
+    destructor Destroy; override;
+    function GetPostType: TXMLRPCPostType;
+    function GetMethodName: String;
+    procedure ResetValueCursor;
+    // Simple values
+    function GetNextInt: LongInt;
+    function GetPrevInt: LongInt;
+    function GetNextBoolean: Boolean;
+    function GetPrevBoolean: Boolean;
+    function GetNextString: String;
+    function GetPrevString: String;
+    function GetNextDouble: Double;
+    function GetPrevDouble: Double;
+    // !!!: Missing: DateTime, Binary data
+    // Struct values
+    function GetNextStruct: TXMLRPCStruct;
+    function GetIntMember(AStruct: TXMLRPCStruct; const AName: String;
+      ADefault: Integer): Integer;
+    function GetBooleanMember(AStruct: TXMLRPCStruct; const AName: String;
+      ADefault: Boolean): Boolean;
+    function GetStringMember(AStruct: TXMLRPCStruct; const AName: String;
+      const ADefault: String): String;
+    function GetDoubleMember(AStruct: TXMLRPCStruct; const AName: String;
+      ADefault: Double): Double;
+    // Array values
+    procedure BeginArray;
+    procedure EndArray;
+  end;
+
+
+  TOnXMLRPCCallCompleted = procedure(AParser: TXMLRPCParser) of object;
+
+  TXMLRPCClient = class
+  private
+    FEventLoop: TEventLoop;
+    FServerURL: String;
+    FOnBeginRPC, FOnEndRPC: TNotifyEvent;
+    RequestStream, ResponseStream: TMemoryStream;
+    CurCallback: TOnXMLRPCCallCompleted;
+    LocalEventLoop: TEventLoop;
+    Connection: THttpConnection;
+
+    procedure MakeRequest(const AProcName: String; AArgs: array of const);
+    procedure ProcessAnswer;
+    procedure StreamSent(Sender: TObject);
+    procedure DataAvailable(Sender: TObject);
+  public
+    constructor Create(AEventLoop: TEventLoop);
+    procedure Call(ACallback: TOnXMLRPCCallCompleted;
+      const AProcName: String; AArgs: array of const);
+    procedure CallAsync(ACallback: TOnXMLRPCCallCompleted;
+      const AProcName: String; AArgs: array of const);
+
+    property EventLoop: TEventLoop read FEventLoop;
+    property ServerURL: String read FServerURL write FServerURL;
+
+    property OnBeginRPC: TNotifyEvent read FOnBeginRPC write FOnBeginRPC;
+    property OnEndRPC: TNotifyEvent read FOnEndRPC write FOnEndRPC;
+  end;
+
+
+  TXMLRPCServlet = class(THttpServlet)
+  protected
+    procedure DoPost(Req: THttpServletRequest; Resp: THttpServletResponse);
+      override;
+  public
+    procedure Dispatch(AParser: TXMLRPCParser; AWriter: TXMLRPCWriter;
+      APath: TStrings); virtual; abstract;
+  end;
+
+
+implementation
+
+uses XMLWrite, XMLRead;
+
+
+// Debugging stuff
+
+{$IFDEF Debug}
+const
+  NodeNames: array[ELEMENT_NODE..NOTATION_NODE] of String = (
+    'Element',
+    'Attribute',
+    'Text',
+    'CDATA section',
+    'Entity reference',
+    'Entity',
+    'Processing instruction',
+    'Comment',
+    'Document',
+    'Document type',
+    'Document fragment',
+    'Notation'
+  );
+
+procedure DumpNode(node: TDOMNode; spc: String);
+var
+  i: Integer;
+  attr: TDOMNode;
+begin
+  Write(spc, NodeNames[node.NodeType]);
+  if Copy(node.NodeName, 1, 1) <> '#' then
+    Write(' "', node.NodeName, '"');
+  if node.NodeValue <> '' then
+    Write(' "', node.NodeValue, '"');
+
+  if (node.Attributes <> nil) and (node.Attributes.Length > 0) then begin
+    Write(',');
+    for i := 0 to node.Attributes.Length - 1 do begin
+      attr := node.Attributes.Item[i];
+      Write(' ', attr.NodeName, ' = "', attr.NodeValue, '"');
+    end;
+  end;
+  WriteLn;
+
+  node := node.FirstChild;
+  while Assigned(node) do
+  begin
+    DumpNode(node, spc + '  ');
+    node := node.NextSibling;
+  end;
+end;
+{$ENDIF}
+
+
+// XML-RPC Writer
+
+constructor TXMLRPCWriter.Create;
+begin
+  inherited Create;
+  Doc := TXMLDocument.Create;
+end;
+
+destructor TXMLRPCWriter.Destroy;
+begin
+  Doc.Free;
+  inherited Destroy;
+end;
+
+function TXMLRPCWriter.MakeStream: TMemoryStream;
+begin
+  Result := TMemoryStream.Create;
+  try
+    WriteXMLFile(Doc, Result);
+//    WriteXMLFile(Doc, THandleStream.Create(StdOutputHandle));
+    Result.Position := 0;
+  except
+    on e: Exception do
+      Result.Free;
+  end;
+end;
+
+procedure TXMLRPCWriter.WriteMethodCall(const AMethodName: DOMString;
+  Params: TXMLRPCParams);
+var
+  El, El2: TDOMElement;
+begin
+  El := Doc.CreateElement('methodCall');
+  Doc.AppendChild(El);
+  El2 := Doc.CreateElement('methodName');
+  El.AppendChild(El2);
+  El2.AppendChild(Doc.CreateTextNode(AMethodName));
+  El.AppendChild(Params);
+end;
+
+procedure TXMLRPCWriter.WriteResponse(Value: TXMLRPCValue);
+var
+  El, El2: TDOMElement;
+begin
+  ASSERT(Value is TXMLRPCValue);
+  El := Doc.CreateElement('methodResponse');
+  Doc.AppendChild(El);
+  El2 := Doc.CreateElement('params');
+  El.AppendChild(El2);
+  if not Assigned(Value) then
+    Value := CreateBooleanValue(True);
+  El := Doc.CreateElement('param');
+  El2.AppendChild(El);
+  El.AppendChild(Value);
+end;
+
+procedure TXMLRPCWriter.WriteFaultResponse(FaultCode: LongInt;
+  const FaultString: DOMString);
+var
+  El, El2: TDOMElement;
+  Struct: TXMLRPCStruct;
+begin
+  El := Doc.CreateElement('methodResponse');
+  Doc.AppendChild(El);
+  El2 := Doc.CreateElement('fault');
+  El.AppendChild(El2);
+  Struct := CreateStruct;
+  AddStructMember(Struct, 'faultCode', CreateIntValue(FaultCode));
+  AddStructMember(Struct, 'faultString', CreateStringValue(FaultString));
+  El2.AppendChild(Struct);
+end;
+
+function TXMLRPCWriter.CreateParams: TXMLRPCParams;
+begin
+  Result := TXMLRPCParams(Doc.CreateElement('params'));
+end;
+
+procedure TXMLRPCWriter.AddParam(Params: TXMLRPCParams; Value: TXMLRPCValue);
+var
+  El: TDOMElement;
+begin
+  ASSERT((Params is TXMLRPCParams) and (Value is TXMLRPCValue));
+  El := Doc.CreateElement('param');
+  Params.AppendChild(El);
+  El.AppendChild(Value);
+end;
+
+function TXMLRPCWriter.CreateIntValue(i: LongInt): TXMLRPCValue;
+var
+  El: TDOMElement;
+begin
+  Result := CreateValueEl;
+  El := Doc.CreateElement('int');
+  Result.AppendChild(El);
+  El.AppendChild(Doc.CreateTextNode(IntToStr(i)));
+end;
+
+function TXMLRPCWriter.CreateBooleanValue(b: Boolean): TXMLRPCValue;
+var
+  El: TDOMElement;
+begin
+  Result := CreateValueEl;
+  El := Doc.CreateElement('boolean');
+  Result.AppendChild(El);
+  El.AppendChild(Doc.CreateTextNode(IntToStr(Ord(b))));
+end;
+
+function TXMLRPCWriter.CreateStringValue(const s: DOMString): TXMLRPCValue;
+var
+  El: TDOMElement;
+begin
+  Result := CreateValueEl;
+  El := Doc.CreateElement('string');
+  Result.AppendChild(El);
+  if Length(s) > 0 then
+    El.AppendChild(Doc.CreateTextNode(s));
+end;
+
+function TXMLRPCWriter.CreateDoubleValue(d: Double): TXMLRPCValue;
+var
+  El: TDOMElement;
+begin
+  Result := CreateValueEl;
+  El := Doc.CreateElement('double');
+  Result.AppendChild(El);
+  El.AppendChild(Doc.CreateTextNode(FloatToStr(d)));
+end;
+
+function TXMLRPCWriter.CreateDateTimeValue(dt: TDateTime): TXMLRPCValue;
+var
+  El: TDOMElement;
+begin
+  Result := CreateValueEl;
+  El := Doc.CreateElement('dateTime.iso8601');
+  Result.AppendChild(El);
+  El.AppendChild(Doc.CreateTextNode(FormatDateTime('ddmmyyyyThh:nn:ss', dt)));
+end;
+
+function TXMLRPCWriter.CreateStruct: TXMLRPCStruct;
+begin
+  Result := TXMLRPCStruct(CreateValueEl);
+  Result.AppendChild(Doc.CreateElement('struct'));
+end;
+
+procedure TXMLRPCWriter.AddStructMember(Struct: TXMLRPCStruct;
+  const Name: DOMString; Member: TXMLRPCValue);
+var
+  MemberEl, El: TDOMElement;
+begin
+  ASSERT((Struct is TXMLRPCStruct) and (Name <> '') and
+    (Member is TXMLRPCValue));
+  MemberEl := Doc.CreateElement('member');
+  Struct.FirstChild.AppendChild(MemberEl);
+  El := Doc.CreateElement('name');
+  MemberEl.AppendChild(El);
+  El.AppendChild(Doc.CreateTextNode(Name));
+  MemberEl.AppendChild(Member);
+end;
+
+function TXMLRPCWriter.CreateArray: TXMLRPCArray;
+var
+  ArrayEl: TDOMElement;
+begin
+  Result := TXMLRPCArray(CreateValueEl);
+  ArrayEl := Doc.CreateElement('array');
+  Result.AppendChild(ArrayEl);
+  ArrayEl.AppendChild(Doc.CreateElement('data'));
+end;
+
+procedure TXMLRPCWriter.AddArrayElement(AArray: TXMLRPCArray;
+  Value: TXMLRPCValue);
+begin
+  ASSERT((AArray is TXMLRPCArray) and (Value is TXMLRPCValue));
+  AArray.FirstChild.FirstChild.AppendChild(Value);
+end;
+
+function TXMLRPCWriter.CreateValueEl: TXMLRPCValue;
+begin
+  Result := TXMLRPCValue(Doc.CreateElement('value'));
+end;
+
+
+// XML-RPC Parser
+
+constructor TXMLRPCParser.Create(AStream: TStream);
+var
+  Node: TDOMNode;
+begin
+  inherited Create;
+  ReadXMLFile(Doc, AStream);
+  Node := Doc.DocumentElement;
+  {$IFDEF Debug}DumpNode(Node, 'Parser> ');{$ENDIF}
+  if (Node.NodeName = 'methodCall') or (Node.NodeName = 'methodResponse') then
+  begin
+    Node := Node.FirstChild;
+    while Assigned(Node) and (Node.NodeName <> 'params') do
+      Node := Node.NextSibling;
+    if Assigned(Node) then
+    begin
+      Node := Node.FirstChild;
+      while Assigned(Node) and (Node.NodeName <> 'param') do
+        Node := Node.NextSibling;
+      CurDataNode := Node;
+    end;
+  end;
+end;
+
+destructor TXMLRPCParser.Destroy;
+begin
+  Doc.Free;
+  inherited Destroy;
+end;
+
+function TXMLRPCParser.GetPostType: TXMLRPCPostType;
+var
+  Node: TDOMNode;
+begin
+  Result := xmlrpcInvalid;
+  Node := Doc.DocumentElement;
+  if Node.NodeName = 'methodCall' then
+    Result := xmlrpcMethodCall
+  else if Node.NodeName = 'methodResponse' then
+  begin
+    Node := Node.FirstChild;
+    while Assigned(Node) and (Node.NodeType <> ELEMENT_NODE) do
+      Node := Node.NextSibling;
+    if Assigned(Node) then
+      if Node.NodeName = 'params' then
+        Result := xmlrpcResponse
+      else if Node.NodeName = 'fault' then
+        Result := xmlrpcFaultResponse;
+  end;
+end;
+
+function TXMLRPCParser.GetMethodName: String;
+var
+  Node: TDOMNode;
+begin
+  SetLength(Result, 0);
+  Node := Doc.DocumentElement;
+  if (not Assigned(Node)) or (Node.NodeName <> 'methodCall') then
+    exit;
+  Node := Node.FindNode('methodName');
+  if not Assigned(Node) then
+    exit;
+  Node := Node.FirstChild;
+  while Assigned(Node) do
+  begin
+    if Node.NodeType = TEXT_NODE then
+      Result := Result + Node.NodeValue;
+    Node := Node.NextSibling;
+  end;
+end;
+
+procedure TXMLRPCParser.ResetValueCursor;
+begin
+  CurDataNode := CurDataNode.ParentNode.FirstChild;
+  {$IFDEF Debug}DumpNode(CurDataNode, 'ResetValueCursor> ');{$ENDIF}
+end;
+
+function TXMLRPCParser.GetNextInt: LongInt;
+begin
+  Result := StrToInt(GetValue);
+  NextNode;
+end;
+
+function TXMLRPCParser.GetPrevInt: LongInt;
+begin
+  PrevNode;
+  Result := StrToInt(GetValue);
+end;
+
+function TXMLRPCParser.GetNextBoolean: Boolean;
+begin
+  Result := GetValue = '1';
+  NextNode;
+end;
+
+function TXMLRPCParser.GetPrevBoolean: Boolean;
+begin
+  PrevNode;
+  Result := GetValue = '1';
+end;
+
+function TXMLRPCParser.GetNextString: String;
+begin
+  Result := GetValue;
+  NextNode;
+end;
+
+function TXMLRPCParser.GetPrevString: String;
+begin
+  PrevNode;
+  Result := GetValue;
+end;
+
+function TXMLRPCParser.GetNextDouble: Double;
+begin
+  Result := StrToFloat(GetValue);
+  NextNode;
+end;
+
+function TXMLRPCParser.GetPrevDouble: Double;
+begin
+  PrevNode;
+  Result := StrToFloat(GetValue);
+end;
+
+function TXMLRPCParser.GetNextStruct: TXMLRPCStruct;
+begin
+  if Assigned(CurDataNode) and Assigned(CurDataNode.FirstChild) then
+  begin
+    Result := TXMLRPCStruct(CurDataNode.FirstChild);
+    while Assigned(Result) and (Result.NodeName <> 'struct') do
+      Result := TXMLRPCStruct(Result.NextSibling);
+    NextNode;
+  end else
+    Result := nil;
+end;
+
+function TXMLRPCParser.GetIntMember(AStruct: TXMLRPCStruct;
+  const AName: String; ADefault: Integer): Integer;
+var
+  MemberNode: TDOMElement;
+begin
+  MemberNode := FindStructMember(AStruct, AName);
+  if Assigned(MemberNode) then
+    Result := StrToInt(GetStructMemberValue(MemberNode))
+  else
+    Result := ADefault;
+end;
+
+function TXMLRPCParser.GetBooleanMember(AStruct: TXMLRPCStruct;
+  const AName: String; ADefault: Boolean): Boolean;
+var
+  MemberNode: TDOMElement;
+begin
+  MemberNode := FindStructMember(AStruct, AName);
+  if Assigned(MemberNode) then
+    Result := GetStructMemberValue(MemberNode) = '1'
+  else
+    Result := ADefault;
+end;
+
+function TXMLRPCParser.GetStringMember(AStruct: TXMLRPCStruct;
+  const AName: String; const ADefault: String): String;
+var
+  MemberNode: TDOMElement;
+begin
+  MemberNode := FindStructMember(AStruct, AName);
+  if Assigned(MemberNode) then
+    Result := GetStructMemberValue(MemberNode)
+  else
+    Result := ADefault;
+end;
+
+function TXMLRPCParser.GetDoubleMember(AStruct: TXMLRPCStruct;
+  const AName: String; ADefault: Double): Double;
+var
+  MemberNode: TDOMElement;
+begin
+  MemberNode := FindStructMember(AStruct, AName);
+  if Assigned(MemberNode) then
+    Result := StrToFloat(GetStructMemberValue(MemberNode))
+  else
+    Result := ADefault;
+end;
+
+procedure TXMLRPCParser.BeginArray;
+begin
+  if Assigned(CurDataNode) then
+  begin
+    CurDataNode := CurDataNode.FirstChild;
+    while Assigned(CurDataNode) and (CurDataNode.NodeName <> 'array') do
+      CurDataNode := CurDataNode.NextSibling;
+    if Assigned(CurDataNode) then
+    begin
+      CurDataNode := CurDataNode.FirstChild;
+      while Assigned(CurDataNode) and (CurDataNode.NodeName <> 'data') do
+        CurDataNode := CurDataNode.NextSibling;
+{      if Assigned(CurDataNode) then
+      begin
+        CurDataNodeParent := CurDataNode;
+        CurDataNode := nil;
+        ResetValueCursor;
+      end;}
+    end;
+    //NextNode;
+  end;
+end;
+
+procedure TXMLRPCParser.EndArray;
+begin
+end;
+
+procedure TXMLRPCParser.NextNode;
+begin
+  repeat
+    CurDataNode := CurDataNode.NextSibling;
+  until (not Assigned(CurDataNode)) or (CurDataNode.NodeType = ELEMENT_NODE);
+end;
+
+procedure TXMLRPCParser.PrevNode;
+begin
+  {$IFDEF Debug}DumpNode(CurDataNode, 'PrevNode before> ');{$ENDIF}
+  if Assigned(CurDataNode.PreviousSibling) then
+    CurDataNode := CurDataNode.PreviousSibling
+  else
+    CurDataNode := CurDataNode.ParentNode.LastChild;
+  {$IFDEF Debug}DumpNode(CurDataNode, 'PrevNode result> ');{$ENDIF}
+end;
+
+function TXMLRPCParser.GetValue: String;
+var
+  Node: TDOMNode;
+begin
+  if not Assigned(CurDataNode) then
+    Result := ''
+  else
+  begin
+    Node := CurDataNode;
+    if Node.NodeName <> 'value' then
+      Node := Node.FirstChild;
+    Node := Node.FirstChild;
+    if Node.NodeType = TEXT_NODE then
+      Result := Node.NodeValue
+    else begin
+      while Assigned(Node) and (Node.NodeType <> ELEMENT_NODE) do
+        Node := Node.NextSibling;
+      if Assigned(Node) then
+      begin
+        Node := Node.FirstChild;
+        if Assigned(Node) and (Node.NodeType = TEXT_NODE) then
+          Result := Node.NodeValue
+        else
+          Result := '';
+      end;
+    end;
+  end;
+end;
+
+function TXMLRPCParser.FindStructMember(AStruct: TXMLRPCStruct;
+  const AMemberName: String): TDOMElement;
+var
+  Node: TDOMNode;
+begin
+  Result := TDOMElement(AStruct.FirstChild);
+  while Assigned(Result) and (Result.NodeName = 'member') do
+  begin
+    Node := Result.FirstChild;
+    while Assigned(Node) do
+    begin
+      if Node.NodeName = 'name' then
+      begin
+        if Assigned(Node.FirstChild) and
+          (CompareText(Node.FirstChild.NodeValue, AMemberName) = 0) then
+          exit; 
+      end;
+      Node := Node.NextSibling;
+    end;
+    Result := TDOMElement(Result.NextSibling);
+  end;
+end;
+
+function TXMLRPCParser.GetStructMemberValue(MemberNode: TDOMElement): String;
+var
+  Node, Subnode: TDOMNode;
+begin
+  Node := MemberNode.FirstChild;
+  while Assigned(Node) do
+  begin
+    if Node.NodeName = 'value' then
+    begin
+       Subnode := Node.FirstChild;
+       if Assigned(Subnode) and (Subnode.NodeType = TEXT_NODE) then
+       begin
+         Result := Subnode.NodeValue;
+         exit;
+       end;
+       while Assigned(Subnode) do
+       begin
+         if Subnode.NodeType = ELEMENT_NODE then
+         begin
+           if Assigned(Subnode.FirstChild) then
+             Result := Subnode.FirstChild.NodeValue
+           else
+             Result := '';
+           exit;
+         end;
+         Subnode := Subnode.NextSibling;
+       end;
+    end;
+    Node := Node.NextSibling;
+  end;
+end;
+
+
+// XML-RPC Client
+
+constructor TXMLRPCClient.Create(AEventLoop: TEventLoop);
+begin
+  inherited Create;
+  FEventLoop := AEventLoop;
+end;
+
+procedure TXMLRPCClient.Call(ACallback: TOnXMLRPCCallCompleted;
+  const AProcName: String; AArgs: array of const);
+var
+  Host: String;
+  Port: Word;
+  Socket: TInetSocket;
+begin
+  CurCallback := ACallback;
+  MakeRequest(AProcName, AArgs);
+  try
+    ResponseStream := TMemoryStream.Create;
+    if Assigned(OnBeginRPC) then
+      OnBeginRPC(Self);
+
+    Host := 'localhost';
+    Port := 12345;
+
+    Socket := TInetSocket.Create(Host, Port);
+    try
+      RequestStream.Position := 0;
+//    Socket.Write(RequestStream.Memory^, RequestStream.Size);
+      LocalEventLoop := TEventLoop.Create;
+      try
+        Connection := THttpConnection.Create(LocalEventLoop, Socket);
+        try
+          Connection.HeaderToSend := THttpRequestHeader.Create;
+	  with THttpRequestHeader(Connection.HeaderToSend) do
+	  begin
+	    Command := 'POST';
+	    URI := '/xmlrpc';
+	    UserAgent := 'Free Pascal XML-RPC';
+	    ContentType := 'text/xml';
+	    ContentLength := RequestStream.Size;
+	  end;
+          Connection.StreamToSend := RequestStream;
+	  Connection.ReceivedHeader := THttpAnswerHeader.Create;
+	  Connection.ReceivedStream := ResponseStream;
+	  Connection.OnStreamSent := @StreamSent;
+	  Connection.Send;
+	  LocalEventLoop.Run;
+        finally
+          if Assigned(Connection) then
+	  begin
+            Connection.HeaderToSend.Free;
+            Connection.ReceivedHeader.Free;
+	  end;
+          Connection.Free;
+        end;
+      finally
+        LocalEventLoop.Free;
+      end;
+    finally
+      Socket.Free;
+    end;
+  finally
+    FreeAndNil(RequestStream);
+  end;
+
+//  HTTPConnection.Post(ServerURL, RequestStream, ResponseStream);
+  ProcessAnswer;
+end;
+
+procedure TXMLRPCClient.CallAsync(ACallback: TOnXMLRPCCallCompleted;
+  const AProcName: String; AArgs: array of const);
+begin
+  CurCallback := ACallback;
+  MakeRequest(AProcName, AArgs);
+  ResponseStream := TMemoryStream.Create;
+  if Assigned(OnBeginRPC) then
+    OnBeginRPC(Self);
+
+//  CurRPCThread := TRPCThread.Create(Self);
+end;
+
+procedure TXMLRPCClient.MakeRequest(const AProcName: String;
+  AArgs: array of const);
+var
+  Writer: TXMLRPCWriter;
+  Params: TXMLRPCParams;
+  i: Integer;
+begin
+  Writer := TXMLRPCWriter.Create;
+  try
+    Params := Writer.CreateParams;
+    try
+      for i := Low(AArgs) to High(AArgs) do
+        with AArgs[i] do
+          case VType of
+            vtInteger: Writer.AddParam(Params, Writer.CreateIntValue(VInteger));
+            vtBoolean: Writer.AddParam(Params, Writer.CreateBooleanValue(VBoolean));
+            vtChar: Writer.AddParam(Params, Writer.CreateStringValue(VChar));
+            vtExtended: Writer.AddParam(Params, Writer.CreateDoubleValue(VExtended^));
+            vtString: Writer.AddParam(Params, Writer.CreateStringValue(VString^));
+            vtPChar: Writer.AddParam(Params, Writer.CreateStringValue(VPChar));
+	    {$IFDEF HasWideStrings}
+            vtWideChar: Writer.AddParam(Params, Writer.CreateStringValue(VWideChar));
+            vtPWideChar: Writer.AddParam(Params, Writer.CreateStringValue(VPWideChar));
+	    {$ENDIF}
+            vtAnsiString: Writer.AddParam(Params, Writer.CreateStringValue(String(VAnsiString)));
+            // vtCurrency: ?
+            // vtVariant: ?
+	    {$IFDEF HasWideStrings}
+            vtWideString: Writer.AddParam(Params, Writer.CreateStringValue(WideString(VWideString)));
+	    {$ENDIF}
+            vtInt64: Writer.AddParam(Params, Writer.CreateIntValue(VInt64^));
+          else
+            raise Exception.Create('Unsupported data type in RPC argument list');
+          end;
+      Writer.WriteMethodCall(AProcName, Params);
+      RequestStream := Writer.MakeStream;
+    except
+      Params.Free;
+    end;
+  finally
+    Writer.Free;
+  end;
+end;
+
+procedure TXMLRPCClient.ProcessAnswer;
+var
+  Parser: TXMLRPCParser;
+begin
+  ResponseStream.Position := 0;
+  Parser := TXMLRPCParser.Create(ResponseStream);
+  FreeAndNil(ResponseStream);
+  try
+    case Parser.GetPostType of
+      xmlrpcFaultResponse:
+        {raise Exception.Create(Format('%d - %s', [Parser.GetNextInt,
+          Parser.GetNextString]));}
+        raise Exception.Create('Fehler bei XML-RPC-Befehlsausführung');
+      xmlrpcResponse:
+        if Assigned(CurCallback) then
+          CurCallback(Parser);
+    else
+      raise Exception.Create('Invalid response');
+    end;
+  finally
+    Parser.Free;
+    if Assigned(OnEndRPC) then
+      OnEndRPC(Self);
+  end;
+end;
+
+procedure TXMLRPCClient.StreamSent(Sender: TObject);
+begin
+//  LocalEventLoop.Break;
+  Connection.Receive;
+end;
+
+procedure TXMLRPCClient.DataAvailable(Sender: TObject);
+begin
+  LocalEventLoop.Break;
+end;
+
+
+// XML-RPC Server
+
+procedure TXMLRPCServlet.DoPost(Req: THttpServletRequest;
+  Resp: THttpServletResponse);
+var
+  Parser: TXMLRPCParser;
+  Writer: TXMLRPCWriter;
+  Path: TStringList;
+  LastDot, i: Integer;
+  s, PathStr: String;
+  AnswerStream: TStream;
+begin
+  Parser := TXMLRPCParser.Create(Req.InputStream);
+  try
+    if Parser.GetPostType <> xmlrpcMethodCall then
+      exit;
+
+    Resp.ContentType := 'text/xml';
+
+    Writer := TXMLRPCWriter.Create;
+    try
+      try
+        // ...Header auswerten und zum Dispatcher springen...
+	PathStr := Parser.GetMethodName + '.';
+        Path := TStringList.Create;
+        try
+          LastDot := 1;
+          for i := 1 to Length(PathStr) do
+            if PathStr[i] = '.' then
+	    begin
+    	      Path.Add(UpperCase(Copy(PathStr, LastDot, i - LastDot)));
+	      LastDot := i + 1;
+	    end;
+          Dispatch(Parser, Writer, Path);
+        finally
+          Path.Free;
+        end;
+      except
+        on e: Exception do
+	  Writer.WriteFaultResponse(2,
+	    'Execution error: ' + e.ClassName + ': ' + e.Message);
+      end;
+
+      AnswerStream := Writer.MakeStream;
+      try
+        Resp.ContentLength := AnswerStream.Size;
+        Resp.OutputStream.CopyFrom(AnswerStream, AnswerStream.Size);
+      finally
+        AnswerStream.Free;
+      end;
+    finally
+      Writer.Free;
+    end;
+  finally
+    Parser.Free;
+  end;
+end;
+
+
+end.
+
+
+{
+  $Log$
+  Revision 1.1  2002-04-25 19:30:29  sg
+  * First version (with exception of the HTTP unit: This is an improved version
+    of the old asyncio HTTP unit, now adapted to fpAsync)
+
+}