Selaa lähdekoodia

* Added JSON-RPC functionality

git-svn-id: trunk@15360 -
michael 15 vuotta sitten
vanhempi
commit
9797140bad

+ 6 - 0
.gitattributes

@@ -2256,6 +2256,12 @@ packages/fcl-web/src/base/httpdefs.pp svneol=native#text/plain
 packages/fcl-web/src/base/webpage.pp svneol=native#text/plain
 packages/fcl-web/src/base/websession.pp svneol=native#text/plain
 packages/fcl-web/src/base/webutil.pp svneol=native#text/plain
+packages/fcl-web/src/jsonrpc/Makefile svneol=native#text/plain
+packages/fcl-web/src/jsonrpc/Makefile.fpc svneol=native#text/plain
+packages/fcl-web/src/jsonrpc/fpextdirect.pp svneol=native#text/plain
+packages/fcl-web/src/jsonrpc/fpjsonrpc.pp svneol=native#text/plain
+packages/fcl-web/src/jsonrpc/readme.txt svneol=native#text/plain
+packages/fcl-web/src/jsonrpc/webjsonrpc.pp svneol=native#text/plain
 packages/fcl-web/src/webdata/Makefile svneol=native#text/plain
 packages/fcl-web/src/webdata/Makefile.fpc svneol=native#text/plain
 packages/fcl-web/src/webdata/extjsjson.pp svneol=native#text/plain

+ 2455 - 0
packages/fcl-web/src/jsonrpc/Makefile

@@ -0,0 +1,2455 @@
+#
+# Don't edit, this file is generated by FPCMake Version 2.0.0 [2009/11/05]
+#
+default: all
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-qnx i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian m68k-linux m68k-freebsd m68k-netbsd m68k-amiga m68k-atari m68k-openbsd m68k-palmos m68k-embedded powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macos powerpc-darwin powerpc-morphos powerpc-embedded sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-darwin x86_64-win64 x86_64-embedded arm-linux arm-palmos arm-darwin arm-wince arm-gba arm-nds arm-embedded arm-symbian powerpc64-linux powerpc64-darwin powerpc64-embedded avr-embedded armeb-linux armeb-embedded
+BSDs = freebsd netbsd openbsd darwin
+UNIXs = linux $(BSDs) solaris qnx
+LIMIT83fs = go32v2 os2 emx watcom
+OSNeedsComspecToRunBatch = go32v2 watcom
+FORCE:
+.PHONY: FORCE
+override PATH:=$(patsubst %/,%,$(subst \,/,$(PATH)))
+ifneq ($(findstring darwin,$(OSTYPE)),)
+inUnix=1 #darwin
+SEARCHPATH:=$(filter-out .,$(subst :, ,$(PATH)))
+else
+ifeq ($(findstring ;,$(PATH)),)
+inUnix=1
+SEARCHPATH:=$(filter-out .,$(subst :, ,$(PATH)))
+else
+SEARCHPATH:=$(subst ;, ,$(PATH))
+endif
+endif
+SEARCHPATH+=$(patsubst %/,%,$(subst \,/,$(dir $(MAKE))))
+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 cygdrive,$(PATH)),)
+inCygWin=1
+endif
+endif
+ifdef inUnix
+SRCBATCHEXT=.sh
+else
+ifdef inOS2
+SRCBATCHEXT=.cmd
+else
+SRCBATCHEXT=.bat
+endif
+endif
+ifdef COMSPEC
+ifneq ($(findstring $(OS_SOURCE),$(OSNeedsComspecToRunBatch)),)
+RUNBATCH=$(COMSPEC) /C
+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
+override DEFAULT_FPCDIR=../../../..
+ifndef FPC
+ifdef PP
+FPC=$(PP)
+endif
+endif
+ifndef FPC
+FPCPROG:=$(strip $(wildcard $(addsuffix /fpc$(SRCEXEEXT),$(SEARCHPATH))))
+ifneq ($(FPCPROG),)
+FPCPROG:=$(firstword $(FPCPROG))
+ifneq ($(CPU_TARGET),)
+FPC:=$(shell $(FPCPROG) -P$(CPU_TARGET) -PB)
+else
+FPC:=$(shell $(FPCPROG) -PB)
+endif
+ifneq ($(findstring Error,$(FPC)),)
+override FPC=$(firstword $(strip $(wildcard $(addsuffix /ppc386$(SRCEXEEXT),$(SEARCHPATH)))))
+else
+ifeq ($(strip $(wildcard $(FPC))),)
+FPC:=$(firstword $(FPCPROG))
+endif
+endif
+else
+override FPC=$(firstword $(strip $(wildcard $(addsuffix /ppc386$(SRCEXEEXT),$(SEARCHPATH)))))
+endif
+endif
+override FPC:=$(subst $(SRCEXEEXT),,$(FPC))
+override FPC:=$(subst \,/,$(FPC))$(SRCEXEEXT)
+FOUNDFPC:=$(strip $(wildcard $(FPC)))
+ifeq ($(FOUNDFPC),)
+FOUNDFPC=$(strip $(wildcard $(addsuffix /$(FPC),$(SEARCHPATH))))
+ifeq ($(FOUNDFPC),)
+$(error Compiler $(FPC) not found)
+endif
+endif
+ifndef FPC_COMPILERINFO
+FPC_COMPILERINFO:=$(shell $(FPC) -iVSPTPSOTO)
+endif
+ifndef FPC_VERSION
+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)
+ifeq ($(CPU_TARGET),armeb)
+ARCH=arm
+override FPCOPT+=-Cb
+else
+ifeq ($(CPU_TARGET),armel)
+ARCH=arm
+override FPCOPT+=-CaEABI
+else
+ARCH=$(CPU_TARGET)
+endif
+endif
+ifneq ($(findstring $(OS_SOURCE),$(LIMIT83fs)),)
+TARGETSUFFIX=$(OS_TARGET)
+SOURCESUFFIX=$(OS_SOURCE)
+else
+TARGETSUFFIX=$(FULL_TARGET)
+SOURCESUFFIX=$(FULL_SOURCE)
+endif
+ifneq ($(FULL_TARGET),$(FULL_SOURCE))
+CROSSCOMPILE=1
+endif
+ifeq ($(findstring makefile,$(MAKECMDGOALS)),)
+ifeq ($(findstring $(FULL_TARGET),$(MAKEFILETARGETS)),)
+$(error The Makefile doesn't support target $(FULL_TARGET), please run fpcmake first)
+endif
+endif
+ifneq ($(findstring $(OS_TARGET),$(BSDs)),)
+BSDhier=1
+endif
+ifeq ($(OS_TARGET),linux)
+linuxHier=1
+endif
+export OS_TARGET OS_SOURCE ARCH CPU_TARGET CPU_SOURCE FULL_TARGET FULL_SOURCE TARGETSUFFIX SOURCESUFFIX 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:=$(BASEDIR)
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),)
+override FPCDIR=c:/pp
+endif
+endif
+endif
+endif
+endif
+ifndef CROSSBINDIR
+CROSSBINDIR:=$(wildcard $(FPCDIR)/bin/$(TARGETSUFFIX))
+endif
+ifeq ($(OS_TARGET),darwin)
+ifeq ($(OS_SOURCE),darwin)
+DARWIN2DARWIN=1
+endif
+endif
+ifndef BINUTILSPREFIX
+ifndef CROSSBINDIR
+ifdef CROSSCOMPILE
+ifndef DARWIN2DARWIN
+BINUTILSPREFIX=$(CPU_TARGET)-$(OS_TARGET)-
+endif
+endif
+endif
+endif
+UNITSDIR:=$(wildcard $(FPCDIR)/units/$(TARGETSUFFIX))
+ifeq ($(UNITSDIR),)
+UNITSDIR:=$(wildcard $(FPCDIR)/units/$(OS_TARGET))
+endif
+PACKAGESDIR:=$(wildcard $(FPCDIR) $(FPCDIR)/packages $(FPCDIR)/packages/base $(FPCDIR)/packages/extra)
+override PACKAGE_NAME=fcl-web
+override PACKAGE_VERSION=2.5.1
+PACKAGEDIR_MAIN:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /fcl-web/Makefile.fpc,$(PACKAGESDIR))))))
+ifeq ($(FULL_TARGET),i386-linux)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),i386-go32v2)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),i386-win32)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),i386-os2)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),i386-freebsd)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),i386-beos)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),i386-haiku)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),i386-netbsd)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),i386-solaris)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),i386-qnx)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),i386-netware)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),i386-openbsd)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),i386-wdosx)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),i386-darwin)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),i386-emx)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),i386-watcom)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),i386-netwlibc)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),i386-wince)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),i386-embedded)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),i386-symbian)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),m68k-linux)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),m68k-freebsd)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),m68k-netbsd)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),m68k-amiga)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),m68k-atari)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),m68k-openbsd)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),m68k-palmos)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),m68k-embedded)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),powerpc-linux)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),powerpc-netbsd)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),powerpc-amiga)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),powerpc-macos)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),powerpc-darwin)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),powerpc-morphos)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),powerpc-embedded)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),sparc-linux)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),sparc-netbsd)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),sparc-solaris)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),sparc-embedded)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),x86_64-linux)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),x86_64-freebsd)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),x86_64-darwin)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),x86_64-win64)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),x86_64-embedded)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),arm-linux)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),arm-palmos)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),arm-darwin)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),arm-wince)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),arm-gba)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),arm-nds)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),arm-embedded)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),arm-symbian)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),powerpc64-linux)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),powerpc64-darwin)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),powerpc64-embedded)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),avr-embedded)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),armeb-linux)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+ifeq ($(FULL_TARGET),armeb-embedded)
+override TARGET_UNITS+=fpjsonrpc  webjsonrpc fpextdirect
+endif
+override INSTALL_FPCPACKAGE=y
+ifeq ($(FULL_TARGET),i386-linux)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-go32v2)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-win32)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-os2)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-freebsd)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-beos)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-haiku)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-netbsd)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-solaris)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-qnx)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-netware)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-openbsd)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-wdosx)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-darwin)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-emx)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-watcom)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-netwlibc)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-wince)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-embedded)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-symbian)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),m68k-linux)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),m68k-freebsd)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),m68k-netbsd)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),m68k-amiga)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),m68k-atari)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),m68k-openbsd)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),m68k-palmos)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),m68k-embedded)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),powerpc-linux)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),powerpc-netbsd)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),powerpc-amiga)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),powerpc-macos)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),powerpc-darwin)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),powerpc-morphos)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),powerpc-embedded)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),sparc-linux)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),sparc-netbsd)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),sparc-solaris)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),sparc-embedded)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),x86_64-linux)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),x86_64-freebsd)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),x86_64-darwin)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),x86_64-win64)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),x86_64-embedded)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),arm-linux)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),arm-palmos)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),arm-darwin)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),arm-wince)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),arm-gba)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),arm-nds)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),arm-embedded)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),arm-symbian)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),powerpc64-linux)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),powerpc64-darwin)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),powerpc64-embedded)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),avr-embedded)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),armeb-linux)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),armeb-embedded)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifdef REQUIRE_UNITSDIR
+override UNITSDIR+=$(REQUIRE_UNITSDIR)
+endif
+ifdef REQUIRE_PACKAGESDIR
+override PACKAGESDIR+=$(REQUIRE_PACKAGESDIR)
+endif
+ifdef ZIPINSTALL
+ifneq ($(findstring $(OS_TARGET),$(UNIXs)),)
+UNIXHier=1
+endif
+else
+ifneq ($(findstring $(OS_SOURCE),$(UNIXs)),)
+UNIXHier=1
+endif
+endif
+ifndef INSTALL_PREFIX
+ifdef PREFIX
+INSTALL_PREFIX=$(PREFIX)
+endif
+endif
+ifndef INSTALL_PREFIX
+ifdef UNIXHier
+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 COMPILER_UNITTARGETDIR
+ifdef PACKAGEDIR_MAIN
+COMPILER_UNITTARGETDIR=$(PACKAGEDIR_MAIN)/units/$(TARGETSUFFIX)
+else
+COMPILER_UNITTARGETDIR=units/$(TARGETSUFFIX)
+endif
+endif
+ifndef COMPILER_TARGETDIR
+COMPILER_TARGETDIR=.
+endif
+ifndef INSTALL_BASEDIR
+ifdef UNIXHier
+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 UNIXHier
+INSTALL_BINDIR:=$(INSTALL_PREFIX)/bin
+else
+INSTALL_BINDIR:=$(INSTALL_BASEDIR)/bin
+ifdef INSTALL_FPCPACKAGE
+ifdef CROSSCOMPILE
+ifdef CROSSINSTALL
+INSTALL_BINDIR:=$(INSTALL_BINDIR)/$(SOURCESUFFIX)
+else
+INSTALL_BINDIR:=$(INSTALL_BINDIR)/$(TARGETSUFFIX)
+endif
+else
+INSTALL_BINDIR:=$(INSTALL_BINDIR)/$(TARGETSUFFIX)
+endif
+endif
+endif
+endif
+ifndef INSTALL_UNITDIR
+INSTALL_UNITDIR:=$(INSTALL_BASEDIR)/units/$(TARGETSUFFIX)
+ifdef INSTALL_FPCPACKAGE
+ifdef PACKAGE_NAME
+INSTALL_UNITDIR:=$(INSTALL_UNITDIR)/$(PACKAGE_NAME)
+endif
+endif
+endif
+ifndef INSTALL_LIBDIR
+ifdef UNIXHier
+INSTALL_LIBDIR:=$(INSTALL_PREFIX)/lib
+else
+INSTALL_LIBDIR:=$(INSTALL_UNITDIR)
+endif
+endif
+ifndef INSTALL_SOURCEDIR
+ifdef UNIXHier
+ifdef BSDhier
+SRCPREFIXDIR=share/src
+else
+ifdef linuxHier
+SRCPREFIXDIR=share/src
+else
+SRCPREFIXDIR=src
+endif
+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 UNIXHier
+ifdef BSDhier
+DOCPREFIXDIR=share/doc
+else
+ifdef linuxHier
+DOCPREFIXDIR=share/doc
+else
+DOCPREFIXDIR=doc
+endif
+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 UNIXHier
+ifdef INSTALL_FPCPACKAGE
+ifdef BSDhier
+INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/share/examples/fpc-$(FPC_VERSION)/$(PACKAGE_NAME)
+else
+ifdef linuxHier
+INSTALL_EXAMPLEDIR:=$(INSTALL_DOCDIR)/examples
+else
+INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/doc/fpc-$(FPC_VERSION)/examples/$(PACKAGE_NAME)
+endif
+endif
+else
+ifdef BSDhier
+INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/share/examples/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+else
+ifdef linuxHier
+INSTALL_EXAMPLEDIR:=$(INSTALL_DOCDIR)/examples/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+else
+INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/doc/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+endif
+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
+ifndef INSTALL_SHAREDDIR
+INSTALL_SHAREDDIR=$(INSTALL_PREFIX)/lib
+endif
+ifdef CROSSCOMPILE
+ifndef CROSSBINDIR
+CROSSBINDIR:=$(wildcard $(CROSSTARGETDIR)/bin/$(SOURCESUFFIX))
+ifeq ($(CROSSBINDIR),)
+CROSSBINDIR:=$(wildcard $(INSTALL_BASEDIR)/cross/$(TARGETSUFFIX)/bin/$(FULL_SOURCE))
+endif
+endif
+else
+CROSSBINDIR=
+endif
+ifeq ($(OS_SOURCE),linux)
+ifndef GCCLIBDIR
+ifeq ($(CPU_TARGET),i386)
+ifneq ($(findstring x86_64,$(shell uname -a)),)
+ifeq ($(BINUTILSPREFIX),)
+GCCLIBDIR:=$(shell dirname `gcc -m32 -print-libgcc-file-name`)
+endif
+endif
+endif
+ifeq ($(CPU_TARGET),powerpc64)
+ifeq ($(BINUTILSPREFIX),)
+GCCLIBDIR:=$(shell dirname `gcc -m64 -print-libgcc-file-name`)
+endif
+endif
+endif
+ifndef GCCLIBDIR
+CROSSGCC=$(strip $(wildcard $(addsuffix /$(BINUTILSPREFIX)gcc$(SRCEXEEXT),$(SEARCHPATH))))
+ifneq ($(CROSSGCC),)
+GCCLIBDIR:=$(shell dirname `$(CROSSGCC) -print-libgcc-file-name`)
+endif
+endif
+ifndef OTHERLIBDIR
+OTHERLIBDIR:=$(shell grep -v "^\#" /etc/ld.so.conf | awk '{ ORS=" "; print $1 }')
+endif
+endif
+ifdef inUnix
+ifeq ($(OS_SOURCE),netbsd)
+OTHERLIBDIR+=/usr/pkg/lib
+endif
+export GCCLIBDIR OTHERLIB
+endif
+BATCHEXT=.bat
+LOADEREXT=.as
+EXEEXT=.exe
+PPLEXT=.ppl
+PPUEXT=.ppu
+OEXT=.o
+ASMEXT=.s
+SMARTEXT=.sl
+STATICLIBEXT=.a
+SHAREDLIBEXT=.so
+SHAREDLIBPREFIX=libfp
+STATICLIBPREFIX=libp
+IMPORTLIBPREFIX=libimp
+RSTEXT=.rst
+ifeq ($(findstring 1.0.,$(FPC_VERSION)),)
+ifeq ($(OS_TARGET),go32v1)
+STATICLIBPREFIX=
+SHORTSUFFIX=v1
+endif
+ifeq ($(OS_TARGET),go32v2)
+STATICLIBPREFIX=
+SHORTSUFFIX=dos
+IMPORTLIBPREFIX=
+endif
+ifeq ($(OS_TARGET),watcom)
+STATICLIBPREFIX=
+OEXT=.obj
+ASMEXT=.asm
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=wat
+IMPORTLIBPREFIX=
+endif
+ifeq ($(OS_TARGET),linux)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=lnx
+endif
+ifeq ($(OS_TARGET),freebsd)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=fbs
+endif
+ifeq ($(OS_TARGET),netbsd)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=nbs
+endif
+ifeq ($(OS_TARGET),openbsd)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=obs
+endif
+ifeq ($(OS_TARGET),win32)
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=w32
+endif
+ifeq ($(OS_TARGET),os2)
+BATCHEXT=.cmd
+AOUTEXT=.out
+STATICLIBPREFIX=
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=os2
+ECHO=echo
+IMPORTLIBPREFIX=
+endif
+ifeq ($(OS_TARGET),emx)
+BATCHEXT=.cmd
+AOUTEXT=.out
+STATICLIBPREFIX=
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=emx
+ECHO=echo
+IMPORTLIBPREFIX=
+endif
+ifeq ($(OS_TARGET),amiga)
+EXEEXT=
+SHAREDLIBEXT=.library
+SHORTSUFFIX=amg
+endif
+ifeq ($(OS_TARGET),morphos)
+EXEEXT=
+SHAREDLIBEXT=.library
+SHORTSUFFIX=mos
+endif
+ifeq ($(OS_TARGET),atari)
+EXEEXT=.ttp
+SHORTSUFFIX=ata
+endif
+ifeq ($(OS_TARGET),beos)
+BATCHEXT=.sh
+EXEEXT=
+SHORTSUFFIX=be
+endif
+ifeq ($(OS_TARGET),haiku)
+BATCHEXT=.sh
+EXEEXT=
+SHORTSUFFIX=hai
+endif
+ifeq ($(OS_TARGET),solaris)
+BATCHEXT=.sh
+EXEEXT=
+SHORTSUFFIX=sun
+endif
+ifeq ($(OS_TARGET),qnx)
+BATCHEXT=.sh
+EXEEXT=
+SHORTSUFFIX=qnx
+endif
+ifeq ($(OS_TARGET),netware)
+EXEEXT=.nlm
+STATICLIBPREFIX=
+SHORTSUFFIX=nw
+IMPORTLIBPREFIX=imp
+endif
+ifeq ($(OS_TARGET),netwlibc)
+EXEEXT=.nlm
+STATICLIBPREFIX=
+SHORTSUFFIX=nwl
+IMPORTLIBPREFIX=imp
+endif
+ifeq ($(OS_TARGET),macos)
+BATCHEXT=
+EXEEXT=
+DEBUGSYMEXT=.xcoff
+SHORTSUFFIX=mac
+IMPORTLIBPREFIX=imp
+endif
+ifeq ($(OS_TARGET),darwin)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=dwn
+endif
+ifeq ($(OS_TARGET),gba)
+EXEEXT=.gba
+SHAREDLIBEXT=.so
+SHORTSUFFIX=gba
+endif
+ifeq ($(OS_TARGET),symbian)
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=symbian
+endif
+else
+ifeq ($(OS_TARGET),go32v1)
+PPUEXT=.pp1
+OEXT=.o1
+ASMEXT=.s1
+SMARTEXT=.sl1
+STATICLIBEXT=.a1
+SHAREDLIBEXT=.so1
+STATICLIBPREFIX=
+SHORTSUFFIX=v1
+IMPORTLIBPREFIX=
+endif
+ifeq ($(OS_TARGET),go32v2)
+STATICLIBPREFIX=
+SHORTSUFFIX=dos
+IMPORTLIBPREFIX=
+endif
+ifeq ($(OS_TARGET),watcom)
+STATICLIBPREFIX=
+SHORTSUFFIX=wat
+IMPORTLIBPREFIX=
+endif
+ifeq ($(OS_TARGET),linux)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=lnx
+endif
+ifeq ($(OS_TARGET),freebsd)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=fbs
+endif
+ifeq ($(OS_TARGET),netbsd)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=nbs
+endif
+ifeq ($(OS_TARGET),openbsd)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=obs
+endif
+ifeq ($(OS_TARGET),win32)
+PPUEXT=.ppw
+OEXT=.ow
+ASMEXT=.sw
+SMARTEXT=.slw
+STATICLIBEXT=.aw
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=w32
+endif
+ifeq ($(OS_TARGET),os2)
+BATCHEXT=.cmd
+PPUEXT=.ppo
+ASMEXT=.so2
+OEXT=.oo2
+AOUTEXT=.out
+SMARTEXT=.sl2
+STATICLIBPREFIX=
+STATICLIBEXT=.ao2
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=os2
+ECHO=echo
+IMPORTLIBPREFIX=
+endif
+ifeq ($(OS_TARGET),amiga)
+EXEEXT=
+PPUEXT=.ppu
+ASMEXT=.s
+OEXT=.o
+SMARTEXT=.sl
+STATICLIBEXT=.a
+SHAREDLIBEXT=.library
+SHORTSUFFIX=amg
+endif
+ifeq ($(OS_TARGET),atari)
+PPUEXT=.ppu
+ASMEXT=.s
+OEXT=.o
+SMARTEXT=.sl
+STATICLIBEXT=.a
+EXEEXT=.ttp
+SHORTSUFFIX=ata
+endif
+ifeq ($(OS_TARGET),beos)
+BATCHEXT=.sh
+PPUEXT=.ppu
+ASMEXT=.s
+OEXT=.o
+SMARTEXT=.sl
+STATICLIBEXT=.a
+EXEEXT=
+SHORTSUFFIX=be
+endif
+ifeq ($(OS_TARGET),solaris)
+BATCHEXT=.sh
+PPUEXT=.ppu
+ASMEXT=.s
+OEXT=.o
+SMARTEXT=.sl
+STATICLIBEXT=.a
+EXEEXT=
+SHORTSUFFIX=sun
+endif
+ifeq ($(OS_TARGET),qnx)
+BATCHEXT=.sh
+PPUEXT=.ppu
+ASMEXT=.s
+OEXT=.o
+SMARTEXT=.sl
+STATICLIBEXT=.a
+EXEEXT=
+SHORTSUFFIX=qnx
+endif
+ifeq ($(OS_TARGET),netware)
+STATICLIBPREFIX=
+PPUEXT=.ppu
+OEXT=.o
+ASMEXT=.s
+SMARTEXT=.sl
+STATICLIBEXT=.a
+SHAREDLIBEXT=.nlm
+EXEEXT=.nlm
+SHORTSUFFIX=nw
+IMPORTLIBPREFIX=imp
+endif
+ifeq ($(OS_TARGET),netwlibc)
+STATICLIBPREFIX=
+PPUEXT=.ppu
+OEXT=.o
+ASMEXT=.s
+SMARTEXT=.sl
+STATICLIBEXT=.a
+SHAREDLIBEXT=.nlm
+EXEEXT=.nlm
+SHORTSUFFIX=nwl
+IMPORTLIBPREFIX=imp
+endif
+ifeq ($(OS_TARGET),macos)
+BATCHEXT=
+PPUEXT=.ppu
+ASMEXT=.s
+OEXT=.o
+SMARTEXT=.sl
+STATICLIBEXT=.a
+EXEEXT=
+DEBUGSYMEXT=.xcoff
+SHORTSUFFIX=mac
+IMPORTLIBPREFIX=imp
+endif
+endif
+ifneq ($(findstring $(OS_SOURCE),$(LIMIT83fs)),)
+FPCMADE=fpcmade.$(SHORTSUFFIX)
+ZIPSUFFIX=$(SHORTSUFFIX)
+ZIPCROSSPREFIX=
+ZIPSOURCESUFFIX=src
+ZIPEXAMPLESUFFIX=exm
+else
+FPCMADE=fpcmade.$(TARGETSUFFIX)
+ZIPSOURCESUFFIX=.source
+ZIPEXAMPLESUFFIX=.examples
+ifdef CROSSCOMPILE
+ZIPSUFFIX=.$(SOURCESUFFIX)
+ZIPCROSSPREFIX=$(TARGETSUFFIX)-
+else
+ZIPSUFFIX=.$(TARGETSUFFIX)
+ZIPCROSSPREFIX=
+endif
+endif
+ifndef ECHO
+ECHO:=$(strip $(wildcard $(addsuffix /gecho$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO:=$(strip $(wildcard $(addsuffix /echo$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO= __missing_command_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= __missing_command_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= __missing_command_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= __missing_command_CPPROG
+else
+CPPROG:=$(firstword $(CPPROG))
+endif
+endif
+export CPPROG
+ifndef RMPROG
+RMPROG:=$(strip $(wildcard $(addsuffix /rm$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(RMPROG),)
+RMPROG= __missing_command_RMPROG
+else
+RMPROG:=$(firstword $(RMPROG))
+endif
+endif
+export RMPROG
+ifndef MVPROG
+MVPROG:=$(strip $(wildcard $(addsuffix /mv$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(MVPROG),)
+MVPROG= __missing_command_MVPROG
+else
+MVPROG:=$(firstword $(MVPROG))
+endif
+endif
+export MVPROG
+ifndef MKDIRPROG
+MKDIRPROG:=$(strip $(wildcard $(addsuffix /gmkdir$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(MKDIRPROG),)
+MKDIRPROG:=$(strip $(wildcard $(addsuffix /mkdir$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(MKDIRPROG),)
+MKDIRPROG= __missing_command_MKDIRPROG
+else
+MKDIRPROG:=$(firstword $(MKDIRPROG))
+endif
+else
+MKDIRPROG:=$(firstword $(MKDIRPROG))
+endif
+endif
+export MKDIRPROG
+ifndef ECHOREDIR
+ifndef inUnix
+ECHOREDIR=echo
+else
+ECHOREDIR=$(ECHO)
+endif
+endif
+ifndef COPY
+COPY:=$(CPPROG) -fp
+endif
+ifndef COPYTREE
+COPYTREE:=$(CPPROG) -Rfp
+endif
+ifndef MKDIRTREE
+MKDIRTREE:=$(MKDIRPROG) -p
+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= __missing_command_PPUMOVE
+else
+PPUMOVE:=$(firstword $(PPUMOVE))
+endif
+endif
+export PPUMOVE
+ifndef FPCMAKE
+FPCMAKE:=$(strip $(wildcard $(addsuffix /fpcmake$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(FPCMAKE),)
+FPCMAKE= __missing_command_FPCMAKE
+else
+FPCMAKE:=$(firstword $(FPCMAKE))
+endif
+endif
+export FPCMAKE
+ifndef ZIPPROG
+ZIPPROG:=$(strip $(wildcard $(addsuffix /zip$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ZIPPROG),)
+ZIPPROG= __missing_command_ZIPPROG
+else
+ZIPPROG:=$(firstword $(ZIPPROG))
+endif
+endif
+export ZIPPROG
+ifndef TARPROG
+TARPROG:=$(strip $(wildcard $(addsuffix /gtar$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(TARPROG),)
+TARPROG:=$(strip $(wildcard $(addsuffix /tar$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(TARPROG),)
+TARPROG= __missing_command_TARPROG
+else
+TARPROG:=$(firstword $(TARPROG))
+endif
+else
+TARPROG:=$(firstword $(TARPROG))
+endif
+endif
+export TARPROG
+ASNAME=$(BINUTILSPREFIX)as
+LDNAME=$(BINUTILSPREFIX)ld
+ARNAME=$(BINUTILSPREFIX)ar
+RCNAME=$(BINUTILSPREFIX)rc
+ifneq ($(findstring 1.0.,$(FPC_VERSION)),)
+ifeq ($(OS_TARGET),win32)
+ifeq ($(CROSSBINDIR),)
+ASNAME=asw
+LDNAME=ldw
+ARNAME=arw
+endif
+endif
+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$(SRCBATCHEXT)
+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=vj
+TAREXT=.tar.bz2
+else
+TAROPT=vz
+TAREXT=.tar.gz
+endif
+override REQUIRE_PACKAGES=rtl fcl-base fcl-xml fcl-json
+ifeq ($(FULL_TARGET),i386-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_ICONVENC=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-go32v2)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-win32)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-os2)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-freebsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_ICONVENC=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-beos)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_ICONVENC=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-haiku)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_ICONVENC=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-netbsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-solaris)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-qnx)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-netware)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-openbsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-wdosx)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-darwin)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_UNIVINT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_ICONVENC=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-emx)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-watcom)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-netwlibc)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-wince)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-symbian)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),m68k-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_ICONVENC=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),m68k-freebsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_ICONVENC=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),m68k-netbsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),m68k-amiga)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),m68k-atari)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),m68k-openbsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),m68k-palmos)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),m68k-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),powerpc-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_ICONVENC=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),powerpc-netbsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),powerpc-amiga)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),powerpc-macos)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),powerpc-darwin)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_UNIVINT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_ICONVENC=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),powerpc-morphos)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),powerpc-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),sparc-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_ICONVENC=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),sparc-netbsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),sparc-solaris)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),sparc-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),x86_64-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_ICONVENC=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),x86_64-freebsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_ICONVENC=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),x86_64-darwin)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_UNIVINT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_ICONVENC=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),x86_64-win64)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),x86_64-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),arm-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_ICONVENC=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),arm-palmos)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),arm-darwin)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_UNIVINT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_ICONVENC=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),arm-wince)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),arm-gba)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),arm-nds)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),arm-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),arm-symbian)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),powerpc64-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_ICONVENC=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),powerpc64-darwin)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_UNIVINT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_ICONVENC=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),powerpc64-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),avr-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),armeb-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_ICONVENC=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),armeb-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-XML=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifdef REQUIRE_PACKAGES_RTL
+PACKAGEDIR_RTL:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /rtl/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_RTL),)
+ifneq ($(wildcard $(PACKAGEDIR_RTL)/units/$(TARGETSUFFIX)),)
+UNITDIR_RTL=$(PACKAGEDIR_RTL)/units/$(TARGETSUFFIX)
+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_FCL-BASE
+PACKAGEDIR_FCL-BASE:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /fcl-base/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_FCL-BASE),)
+ifneq ($(wildcard $(PACKAGEDIR_FCL-BASE)/units/$(TARGETSUFFIX)),)
+UNITDIR_FCL-BASE=$(PACKAGEDIR_FCL-BASE)/units/$(TARGETSUFFIX)
+else
+UNITDIR_FCL-BASE=$(PACKAGEDIR_FCL-BASE)
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_FCL-BASE)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_FCL-BASE) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_FCL-BASE)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_FCL-BASE=
+UNITDIR_FCL-BASE:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /fcl-base/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_FCL-BASE),)
+UNITDIR_FCL-BASE:=$(firstword $(UNITDIR_FCL-BASE))
+else
+UNITDIR_FCL-BASE=
+endif
+endif
+ifdef UNITDIR_FCL-BASE
+override COMPILER_UNITDIR+=$(UNITDIR_FCL-BASE)
+endif
+endif
+ifdef REQUIRE_PACKAGES_ICONVENC
+PACKAGEDIR_ICONVENC:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /iconvenc/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_ICONVENC),)
+ifneq ($(wildcard $(PACKAGEDIR_ICONVENC)/units/$(TARGETSUFFIX)),)
+UNITDIR_ICONVENC=$(PACKAGEDIR_ICONVENC)/units/$(TARGETSUFFIX)
+else
+UNITDIR_ICONVENC=$(PACKAGEDIR_ICONVENC)
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_ICONVENC)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_ICONVENC) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_ICONVENC)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_ICONVENC=
+UNITDIR_ICONVENC:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /iconvenc/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_ICONVENC),)
+UNITDIR_ICONVENC:=$(firstword $(UNITDIR_ICONVENC))
+else
+UNITDIR_ICONVENC=
+endif
+endif
+ifdef UNITDIR_ICONVENC
+override COMPILER_UNITDIR+=$(UNITDIR_ICONVENC)
+endif
+endif
+ifdef REQUIRE_PACKAGES_FCL-XML
+PACKAGEDIR_FCL-XML:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /fcl-xml/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_FCL-XML),)
+ifneq ($(wildcard $(PACKAGEDIR_FCL-XML)/units/$(TARGETSUFFIX)),)
+UNITDIR_FCL-XML=$(PACKAGEDIR_FCL-XML)/units/$(TARGETSUFFIX)
+else
+UNITDIR_FCL-XML=$(PACKAGEDIR_FCL-XML)
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_FCL-XML)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_FCL-XML) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_FCL-XML)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_FCL-XML=
+UNITDIR_FCL-XML:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /fcl-xml/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_FCL-XML),)
+UNITDIR_FCL-XML:=$(firstword $(UNITDIR_FCL-XML))
+else
+UNITDIR_FCL-XML=
+endif
+endif
+ifdef UNITDIR_FCL-XML
+override COMPILER_UNITDIR+=$(UNITDIR_FCL-XML)
+endif
+endif
+ifdef REQUIRE_PACKAGES_FCL-JSON
+PACKAGEDIR_FCL-JSON:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /fcl-json/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_FCL-JSON),)
+ifneq ($(wildcard $(PACKAGEDIR_FCL-JSON)/units/$(TARGETSUFFIX)),)
+UNITDIR_FCL-JSON=$(PACKAGEDIR_FCL-JSON)/units/$(TARGETSUFFIX)
+else
+UNITDIR_FCL-JSON=$(PACKAGEDIR_FCL-JSON)
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_FCL-JSON)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_FCL-JSON) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_FCL-JSON)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_FCL-JSON=
+UNITDIR_FCL-JSON:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /fcl-json/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_FCL-JSON),)
+UNITDIR_FCL-JSON:=$(firstword $(UNITDIR_FCL-JSON))
+else
+UNITDIR_FCL-JSON=
+endif
+endif
+ifdef UNITDIR_FCL-JSON
+override COMPILER_UNITDIR+=$(UNITDIR_FCL-JSON)
+endif
+endif
+ifdef REQUIRE_PACKAGES_UNIVINT
+PACKAGEDIR_UNIVINT:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /univint/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_UNIVINT),)
+ifneq ($(wildcard $(PACKAGEDIR_UNIVINT)/units/$(TARGETSUFFIX)),)
+UNITDIR_UNIVINT=$(PACKAGEDIR_UNIVINT)/units/$(TARGETSUFFIX)
+else
+UNITDIR_UNIVINT=$(PACKAGEDIR_UNIVINT)
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_UNIVINT)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_UNIVINT) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_UNIVINT)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_UNIVINT=
+UNITDIR_UNIVINT:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /univint/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_UNIVINT),)
+UNITDIR_UNIVINT:=$(firstword $(UNITDIR_UNIVINT))
+else
+UNITDIR_UNIVINT=
+endif
+endif
+ifdef UNITDIR_UNIVINT
+override COMPILER_UNITDIR+=$(UNITDIR_UNIVINT)
+endif
+endif
+ifndef NOCPUDEF
+override FPCOPTDEF=$(ARCH)
+endif
+ifneq ($(OS_TARGET),$(OS_SOURCE))
+override FPCOPT+=-T$(OS_TARGET)
+endif
+ifneq ($(CPU_TARGET),$(CPU_SOURCE))
+override FPCOPT+=-P$(ARCH)
+endif
+ifeq ($(OS_SOURCE),openbsd)
+override FPCOPT+=-FD$(NEW_BINUTILS_PATH)
+endif
+ifndef CROSSBOOTSTRAP
+ifneq ($(BINUTILSPREFIX),)
+override FPCOPT+=-XP$(BINUTILSPREFIX)
+endif
+ifneq ($(BINUTILSPREFIX),)
+override FPCOPT+=-Xr$(RLINKPATH)
+endif
+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
+ifneq ($(findstring 2.0.,$(FPC_VERSION)),)
+ifeq ($(CPU_TARGET),i386)
+FPCCPUOPT:=-OG2p3
+endif
+ifeq ($(CPU_TARGET),powerpc)
+FPCCPUOPT:=-O1r
+endif
+else
+FPCCPUOPT:=-O2
+endif
+override FPCOPT+=-Ur -Xs $(FPCCPUOPT) -n
+override FPCOPTDEF+=RELEASE
+endif
+ifdef STRIP
+override FPCOPT+=-Xs
+endif
+ifdef OPTIMIZE
+override FPCOPT+=-O2
+endif
+ifdef VERBOSE
+override FPCOPT+=-vwni
+endif
+ifdef COMPILER_OPTIONS
+override FPCOPT+=$(COMPILER_OPTIONS)
+endif
+ifdef COMPILER_UNITDIR
+override FPCOPT+=$(addprefix -Fu,$(COMPILER_UNITDIR))
+endif
+ifdef COMPILER_LIBRARYDIR
+override FPCOPT+=$(addprefix -Fl,$(COMPILER_LIBRARYDIR))
+endif
+ifdef COMPILER_OBJECTDIR
+override FPCOPT+=$(addprefix -Fo,$(COMPILER_OBJECTDIR))
+endif
+ifdef COMPILER_INCLUDEDIR
+override FPCOPT+=$(addprefix -Fi,$(COMPILER_INCLUDEDIR))
+endif
+ifdef CROSSBINDIR
+override FPCOPT+=-FD$(CROSSBINDIR)
+endif
+ifdef COMPILER_TARGETDIR
+override FPCOPT+=-FE$(COMPILER_TARGETDIR)
+ifeq ($(COMPILER_TARGETDIR),.)
+override TARGETDIRPREFIX=
+else
+override TARGETDIRPREFIX=$(COMPILER_TARGETDIR)/
+endif
+endif
+ifdef COMPILER_UNITTARGETDIR
+override FPCOPT+=-FU$(COMPILER_UNITTARGETDIR)
+ifeq ($(COMPILER_UNITTARGETDIR),.)
+override UNITTARGETDIRPREFIX=
+else
+override UNITTARGETDIRPREFIX=$(COMPILER_UNITTARGETDIR)/
+endif
+else
+ifdef COMPILER_TARGETDIR
+override COMPILER_UNITTARGETDIR=$(COMPILER_TARGETDIR)
+override UNITTARGETDIRPREFIX=$(TARGETDIRPREFIX)
+endif
+endif
+ifdef CREATESHARED
+override FPCOPT+=-Cg
+ifeq ($(CPU_TARGET),i386)
+override FPCOPT+=-Aas
+endif
+endif
+ifeq ($(findstring 2.0.,$(FPC_VERSION)),)
+ifeq ($(OS_TARGET),linux)
+ifeq ($(CPU_TARGET),x86_64)
+override FPCOPT+=-Cg
+endif
+endif
+endif
+ifdef LINKSHARED
+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 AFULL_TARGET=$(CPU_TARGET)-$(OS_TARGET)
+override AFULL_SOURCE=$(CPU_SOURCE)-$(OS_SOURCE)
+ifneq ($(AFULL_TARGET),$(AFULL_SOURCE))
+override ACROSSCOMPILE=1
+endif
+ifdef ACROSSCOMPILE
+override FPCOPT+=$(CROSSOPT)
+endif
+override COMPILER:=$(FPC) $(FPCOPT)
+ifeq (,$(findstring -s ,$(COMPILER)))
+EXECPPAS=
+else
+ifeq ($(FULL_SOURCE),$(FULL_TARGET))
+ifdef RUNBATCH
+EXECPPAS:=@$(RUNBATCH) $(PPAS)
+else
+EXECPPAS:=@$(PPAS)
+endif
+endif
+endif
+.PHONY: fpc_units
+ifneq ($(TARGET_UNITS)$(TARGET_IMPLICITUNITS),)
+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: $(COMPILER_UNITTARGETDIR) $(UNITPPUFILES)
+ifdef TARGET_RSTS
+override RSTFILES=$(addsuffix $(RSTEXT),$(TARGET_RSTS))
+override CLEANRSTFILES+=$(RSTFILES)
+endif
+.PHONY: fpc_all fpc_smart fpc_debug fpc_release fpc_shared
+$(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 .lpr .dpr .pp .rc .res
+$(COMPILER_UNITTARGETDIR):
+	$(MKDIRTREE) $(COMPILER_UNITTARGETDIR)
+$(COMPILER_TARGETDIR):
+	$(MKDIRTREE) $(COMPILER_TARGETDIR)
+%$(PPUEXT): %.pp
+	$(COMPILER) $<
+	$(EXECPPAS)
+%$(PPUEXT): %.pas
+	$(COMPILER) $<
+	$(EXECPPAS)
+%$(EXEEXT): %.pp
+	$(COMPILER) $<
+	$(EXECPPAS)
+%$(EXEEXT): %.pas
+	$(COMPILER) $<
+	$(EXECPPAS)
+%$(EXEEXT): %.lpr
+	$(COMPILER) $<
+	$(EXECPPAS)
+%$(EXEEXT): %.dpr
+	$(COMPILER) $<
+	$(EXECPPAS)
+%.res: %.rc
+	windres -i $< -o $@
+vpath %.pp $(COMPILER_SOURCEDIR) $(COMPILER_INCLUDEDIR)
+vpath %.pas $(COMPILER_SOURCEDIR) $(COMPILER_INCLUDEDIR)
+vpath %.lpr $(COMPILER_SOURCEDIR) $(COMPILER_INCLUDEDIR)
+vpath %.dpr $(COMPILER_SOURCEDIR) $(COMPILER_INCLUDEDIR)
+vpath %.inc $(COMPILER_INCLUDEDIR)
+vpath %$(OEXT) $(COMPILER_UNITTARGETDIR)
+vpath %$(PPUEXT) $(COMPILER_UNITTARGETDIR)
+.PHONY: fpc_shared
+override INSTALLTARGET+=fpc_shared_install
+ifndef SHARED_LIBVERSION
+SHARED_LIBVERSION=$(FPC_VERSION)
+endif
+ifndef SHARED_LIBNAME
+SHARED_LIBNAME=$(PACKAGE_NAME)
+endif
+ifndef SHARED_FULLNAME
+SHARED_FULLNAME=$(SHAREDLIBPREFIX)$(SHARED_LIBNAME)-$(SHARED_LIBVERSION)$(SHAREDLIBEXT)
+endif
+ifndef SHARED_LIBUNITS
+SHARED_LIBUNITS:=$(TARGET_UNITS) $(TARGET_IMPLICITUNITS)
+override SHARED_LIBUNITS:=$(filter-out $(INSTALL_BUILDUNIT),$(SHARED_LIBUNITS))
+endif
+fpc_shared:
+ifdef HASSHAREDLIB
+	$(MAKE) all CREATESHARED=1 LINKSHARED=1 CREATESMART=1
+ifneq ($(SHARED_BUILD),n)
+	$(PPUMOVE) -q $(SHARED_LIBUNITS) -i$(COMPILER_UNITTARGETDIR) -o$(SHARED_FULLNAME) -d$(COMPILER_UNITTARGETDIR)
+endif
+else
+	@$(ECHO) Shared Libraries not supported
+endif
+fpc_shared_install:
+ifneq ($(SHARED_BUILD),n)
+ifneq ($(SHARED_LIBUNITS),)
+ifneq ($(wildcard $(COMPILER_UNITTARGETDIR)/$(SHARED_FULLNAME)),)
+	$(INSTALL) $(COMPILER_UNITTARGETDIR)/$(SHARED_FULLNAME) $(INSTALL_SHAREDDIR)
+endif
+endif
+endif
+.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))) $(addprefix $(IMPORTLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(INSTALLPPUFILES)))
+ifneq ($(UNITTARGETDIRPREFIX),)
+override INSTALLPPUFILES:=$(addprefix $(UNITTARGETDIRPREFIX),$(notdir $(INSTALLPPUFILES)))
+override INSTALLPPULINKFILES:=$(wildcard $(addprefix $(UNITTARGETDIRPREFIX),$(notdir $(INSTALLPPULINKFILES))))
+endif
+override INSTALL_CREATEPACKAGEFPC=1
+endif
+ifdef INSTALLEXEFILES
+ifneq ($(TARGETDIRPREFIX),)
+override INSTALLEXEFILES:=$(addprefix $(TARGETDIRPREFIX),$(notdir $(INSTALLEXEFILES)))
+endif
+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$(CPU_TARGET)-$(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))) $(addprefix $(IMPORTLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(CLEANPPUFILES)))
+ifdef DEBUGSYMEXT
+override CLEANPPULINKFILES+=$(subst $(PPUEXT),$(DEBUGSYMEXT),$(CLEANPPUFILES))
+endif
+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)
+	-$(DEL) *$(ASMEXT) *_ppas$(BATCHEXT)
+fpc_cleanall: $(CLEANTARGET)
+ifdef CLEANEXEFILES
+	-$(DEL) $(CLEANEXEFILES)
+endif
+ifdef COMPILER_UNITTARGETDIR
+ifdef CLEANPPUFILES
+	-$(DEL) $(CLEANPPUFILES)
+endif
+ifneq ($(CLEANPPULINKFILES),)
+	-$(DEL) $(CLEANPPULINKFILES)
+endif
+ifdef CLEANRSTFILES
+	-$(DEL) $(addprefix $(UNITTARGETDIRPREFIX),$(CLEANRSTFILES))
+endif
+endif
+	-$(DELTREE) units
+	-$(DEL) *$(OEXT) *$(PPUEXT) *$(RSTEXT) *$(ASMEXT) *$(STATICLIBEXT) *$(SHAREDLIBEXT) *$(PPLEXT)
+ifneq ($(PPUEXT),.ppu)
+	-$(DEL) *.o *.ppu *.a
+endif
+	-$(DELTREE) *$(SMARTEXT)
+	-$(DEL) fpcmade.* Package.fpc $(PPAS) script.res link.res $(FPCEXTFILE) $(REDIRFILE)
+	-$(DEL) *_ppas$(BATCHEXT)
+ifdef AOUTEXT
+	-$(DEL) *$(AOUTEXT)
+endif
+ifdef DEBUGSYMEXT
+	-$(DEL) *$(DEBUGSYMEXT)
+endif
+fpc_distclean: cleanall
+.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)  SourceSuffix. $(SOURCESUFFIX)
+	@$(ECHO)  TargetSuffix. $(TARGETSUFFIX)
+	@$(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)  ZipName.............. $(ZIPNAME)
+	@$(ECHO)  ZipPrefix............ $(ZIPPREFIX)
+	@$(ECHO)  ZipCrossPrefix....... $(ZIPCROSSPREFIX)
+	@$(ECHO)  ZipSuffix............ $(ZIPSUFFIX)
+	@$(ECHO)  FullZipName.......... $(FULLZIPNAME)
+	@$(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
+units: fpc_units
+examples:
+shared: fpc_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 units examples shared install sourceinstall exampleinstall distinstall zipinstall zipsourceinstall zipexampleinstall zipdistinstall clean distclean cleanall info makefiles
+ifneq ($(wildcard fpcmake.loc),)
+include fpcmake.loc
+endif
+.NOTPARALLEL:

+ 26 - 0
packages/fcl-web/src/jsonrpc/Makefile.fpc

@@ -0,0 +1,26 @@
+#
+#   Makefile.fpc for FCL Web components
+#
+
+[package]
+main=fcl-web
+version=2.5.1
+
+[target]
+units=fpjsonrpc  webjsonrpc fpextdirect
+
+[require]
+packages=fcl-base fcl-xml fcl-json
+
+[compiler]
+options=-S2h
+
+[install]
+fpcpackage=y
+
+[default]
+fpcdir=../../../..
+
+
+[rules]
+.NOTPARALLEL:

+ 416 - 0
packages/fcl-web/src/jsonrpc/fpextdirect.pp

@@ -0,0 +1,416 @@
+unit fpextdirect;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, fpjson, fpjsonrpc, webjsonrpc, httpdefs,websession;
+
+Const
+  DefaultExtDirectOptions = DefaultDispatchOptions + [jdoRequireClass];
+
+Type
+  { TCustomExtDirectDispatcher }
+
+  TCustomExtDirectDispatcher = Class(TCustomJSONRPCDispatcher)
+  private
+    FAPIType: String;
+    FNameSpace: String;
+    FURL: String;
+    function GetNameSpace: String;
+    function isNameSpaceStored: boolean;
+  Protected
+    function FormatResult(const AClassName, AMethodName: TJSONStringType;
+      const Params, ID, Return: TJSONData): TJSONData; override;
+    // 'tid'
+    Class Function TransactionProperty : String; override;
+    // 'method'
+    Class Function MethodProperty : String; override;
+    // 'action'
+    Class Function ClassNameProperty : String; override;
+    // 'data'
+    Class Function ParamsProperty : String; override;
+    // Add session support
+    Function FindHandler(Const AClassName,AMethodName : TJSONStringType;AContext : TJSONRPCCallContext; Out FreeObject : TComponent) : TCustomJSONRPCHandler; override;
+    // Create API
+    Function DoAPI : TJSONData; virtual;
+    // Namespace for API description. Must be set. Default 'FPWeb'
+    Property NameSpace : String Read GetNameSpace Write FNameSpace Stored isNameSpaceStored;
+    // URL property for router. Must be set
+    Property URL : String Read FURL Write FURL;
+    // "type". By default: 'remoting'
+    Property APIType : String Read FAPIType Write FAPIType;
+  Public
+    // Override to set additional opions.
+    Constructor Create(AOwner : TComponent); override;
+    // Return API description object
+    Function API: TJSONData;
+    // Return API Description including namespace, as a string
+    Function APIAsString : String;
+  end;
+
+  { TExtDirectDispatcher }
+
+  TExtDirectDispatcher = Class(TCustomExtDirectDispatcher)
+  Published
+    Property NameSpace;
+    Property URL;
+    Property APIType;
+    Property OnStartBatch;
+    Property OnDispatchRequest;
+    Property OnFindHandler;
+    Property OnEndBatch;
+    Property Options;
+  end;
+
+  { TCustomExtDirectContentProducer }
+
+  TCustomExtDirectContentProducer = Class(TCustomJSONRPCContentProducer)
+  Protected
+    Function GetIDProperty : String; override;
+    Procedure DoGetContent(ARequest : TRequest; Content : TStream; Var Handled : Boolean); override;
+  end;
+
+  { TExtDirectContentProducer }
+
+  TExtDirectContentProducer = Class(TCustomExtDirectContentProducer)
+  private
+    FDispatcher: TCustomExtDirectDispatcher;
+    procedure SetDispatcher(const AValue: TCustomExtDirectDispatcher);
+  Protected
+    Function GetDispatcher : TCustomJSONRPCDispatcher; override;
+    procedure Notification(AComponent: TComponent; Operation: TOperation);override;
+  Published
+    Property Dispatcher :  TCustomExtDirectDispatcher Read FDispatcher Write SetDispatcher;
+  end;
+
+  { TCustomExtDirectModule }
+
+  TCustomExtDirectModule = Class(TJSONRPCDispatchModule)
+  private
+    FAPIPath: String;
+    FDispatcher: TCustomExtDirectDispatcher;
+    FOptions: TJSONRPCDispatchOptions;
+    FRequest: TRequest;
+    FResponse: TResponse;
+    FRouterPath: String;
+    procedure SetDispatcher(const AValue: TCustomExtDirectDispatcher);
+  Protected
+    // Create API
+    procedure CreateAPI(ADispatcher: TCustomExtDirectDispatcher; ARequest: TRequest; AResponse: TResponse); virtual;
+    Function CreateDispatcher : TCustomExtDirectDispatcher; virtual;
+    Property Dispatcher :  TCustomExtDirectDispatcher Read FDispatcher Write SetDispatcher;
+    Property DispatchOptions : TJSONRPCDispatchOptions Read FOptions Write FOptions default DefaultDispatchOptions;
+    procedure Notification(AComponent: TComponent; Operation: TOperation);override;
+  Public
+    Constructor CreateNew(AOwner : TComponent; CreateMode : Integer); override;
+    Procedure HandleRequest(ARequest : TRequest; AResponse : TResponse); override;
+    // Access to request
+    Property Request: TRequest Read FRequest;
+    // Access to response
+    Property Response: TResponse Read FResponse;
+    // API path/action. Append to BaseURL to get API. Default 'API'
+    Property APIPath : String Read FAPIPath Write FAPIPath;
+    // Router path/action. Append to baseURL to get router. Default 'router'
+    Property RouterPath : String Read FRouterPath Write FRouterPath;
+  end;
+
+  TExtDirectModule = Class(TCustomExtDirectModule)
+  Published
+    Property APIPath;
+    Property RouterPath;
+  end;
+
+implementation
+
+Resourcestring
+  SErrInvalidPath = 'Invalid path';
+
+{ TCustomExtDirectDispatcher }
+Const
+  DefaultNameSpace = 'FPWeb';
+
+function TCustomExtDirectDispatcher.GetNameSpace: String;
+begin
+  Result:=FNameSpace;
+  If (Result='') then
+    Result:=DefaultNameSpace
+end;
+
+function TCustomExtDirectDispatcher.isNameSpaceStored: boolean;
+begin
+  Result:=NameSpace<>DefaultNameSpace;
+end;
+
+function TCustomExtDirectDispatcher.FormatResult(Const AClassName, AMethodName: TJSONStringType;
+Const Params,ID, Return : TJSONData) : TJSONData;
+
+begin
+  Result:=Inherited FormatResult(AClassName,AMethodName,Params,ID,Return);
+  TJSONObject(Result).Add('type','rpc');
+  TJSONObject(Result).Add('action',AClassName);
+  TJSONObject(Result).Add('method',AMethodName);
+end;
+
+class function TCustomExtDirectDispatcher.TransactionProperty: String;
+begin
+  Result:='tid';
+end;
+
+class function TCustomExtDirectDispatcher.MethodProperty: String;
+begin
+  Result:='method';
+end;
+
+class function TCustomExtDirectDispatcher.ClassNameProperty: String;
+begin
+  Result:='action';
+end;
+
+class function TCustomExtDirectDispatcher.ParamsProperty: String;
+begin
+  Result:='data';
+end;
+
+function TCustomExtDirectDispatcher.FindHandler(const AClassName,
+  AMethodName: TJSONStringType; AContext: TJSONRPCCallContext; out
+  FreeObject: TComponent): TCustomJSONRPCHandler;
+begin
+  Result:=inherited FindHandler(AClassName, AMethodName, AContext, FreeObject);
+  If (AContext is TJSONRPCSessionContext) and (FreeObject is TCustomJSONRPCModule) then
+    TCustomJSONRPCModule(FreeObject).Session:=TJSONRPCSessionContext(AContext).Session;
+end;
+
+function TCustomExtDirectDispatcher.DoAPI: TJSONData;
+
+Var
+  A,D : TJSONObject;
+  R : TJSONArray;
+  N : TJSONStringType;
+  H : TCustomJSONRPCHandler;
+  I,J : Integer;
+  M : TCustomJSONRPCHandlerManager;
+  HD : TJSONRPCHandlerDef;
+
+begin
+  D:=TJSONObject.Create;
+  try
+    D.Add('url',URL);
+    D.Add('type',APIType);
+    A:=TJSONObject.Create;
+    D.Add('actions',A);
+    R:=Nil;
+    N:='';
+    If (jdoSearchOwner in Options) and Assigned(Owner) then
+      begin
+      for I:=Owner.ComponentCount-1 downto 0 do
+        If Owner.Components[i] is TCustomJSONRPCHandler then
+          begin
+          If (R=Nil) then
+            begin
+            N:=Owner.Name;
+            R:=TJSONArray.Create;
+            A.Add(N,R);
+            end;
+          H:=Owner.Components[i] as TCustomJSONRPCHandler;
+          R.Add(TJSONObject.Create(['name',H.Name,'len',H.ParamDefs.Count]));
+          end;
+      end;
+    If (jdoSearchRegistry in Options) then
+      begin
+      M:=JSONRPCHandlerManager;
+      For I:=M.HandlerCount-1 downto 0 do
+        begin
+        HD:=M.HandlerDefs[i];
+        If (R=Nil) or (CompareText(N,HD.HandlerClassName)<>0) then
+          begin
+          N:=HD.HandlerClassName;
+          J:=A.IndexOf(R);
+          If (J=-1) then
+            begin
+            R:=TJSONArray.Create;
+            A.Add(N,R);
+            end
+          else
+            R:=A.Items[i] as TJSONArray;
+          end;
+        R.Add(TJSONObject.Create(['name',HD.HandlerMethodName,'len',HD.ArgumentCount]));
+        end;
+      end;
+    Result:=D;
+  except
+    FreeAndNil(D);
+    Raise;
+  end;
+end;
+
+constructor TCustomExtDirectDispatcher.Create(AOwner: TComponent);
+
+Var
+  O : TJSONRPCDispatchOptions;
+
+begin
+  inherited Create(AOwner);
+  Options:=DefaultExtDirectOptions;
+  APIType:='remoting';
+end;
+
+function TCustomExtDirectDispatcher.API: TJSONData;
+begin
+  Result:=DoAPI;
+end;
+
+function TCustomExtDirectDispatcher.APIAsString: String;
+
+Var
+  A : TJSONData;
+
+begin
+  A:=API;
+  try
+    Result:=NameSpace + ' = ' + A.AsJSON + ';';
+  finally
+    A.Free;
+  end;
+end;
+
+
+{ TCustomExtDirectContentProducer }
+
+function TCustomExtDirectContentProducer.GetIDProperty: String;
+begin
+  Result:='tid';
+end;
+
+procedure TCustomExtDirectContentProducer.DoGetContent(ARequest: TRequest;
+  Content: TStream; var Handled: Boolean);
+
+Var
+  A,R: String;
+
+begin
+  A:=ARequest.GetNextPathInfo;
+  If (A<>'router') then
+    begin
+    R:=TCustomExtDirectDispatcher(GetDispatcher).APIAsString;
+    Content.WriteBuffer(R[1],Length(R));
+    Handled:=True;
+    end
+  else
+    inherited DoGetContent(ARequest, Content, Handled);
+end;
+
+{ TExtDirectContentProducer }
+
+procedure TExtDirectContentProducer.SetDispatcher(
+  const AValue: TCustomExtDirectDispatcher);
+begin
+  if FDispatcher=AValue then exit;
+  If Assigned(FDispatcher) then
+    FDispatcher.RemoveFreeNotification(Self);
+  FDispatcher:=AValue;
+  If Assigned(FDispatcher) then
+    FDispatcher.FreeNotification(Self);
+end;
+
+function TExtDirectContentProducer.GetDispatcher: TCustomJSONRPCDispatcher;
+begin
+  Result:=FDispatcher;
+end;
+
+procedure TExtDirectContentProducer.Notification(AComponent: TComponent;
+  Operation: TOperation);
+begin
+  inherited Notification(AComponent, Operation);
+  If (Operation=opRemove) and (AComponent=FDispatcher) then
+    FDispatcher:=Nil;
+end;
+
+{ TCustomExtDirectModule }
+
+procedure TCustomExtDirectModule.SetDispatcher(
+  const AValue: TCustomExtDirectDispatcher);
+begin
+  if FDispatcher=AValue then exit;
+  If Assigned(FDispatcher) then
+    FDispatcher.RemoveFreeNotification(Self);
+  FDispatcher:=AValue;
+  If Assigned(FDispatcher) then
+    FDispatcher.FreeNotification(Self);
+end;
+
+function TCustomExtDirectModule.CreateDispatcher: TCustomExtDirectDispatcher;
+
+Var
+  E : TExtDirectDispatcher;
+
+begin
+  E:=TExtDirectDispatcher.Create(Self);
+  E.Options:=DispatchOptions;
+  E.URL:=IncludeHTTPPathDelimiter(BaseURL)+RouterPath;
+  Result:=E
+end;
+
+procedure TCustomExtDirectModule.Notification(AComponent: TComponent;
+  Operation: TOperation);
+begin
+  inherited Notification(AComponent, Operation);
+  If (Operation=opRemove) and (AComponent=FDispatcher) then
+    FDispatcher:=Nil;
+end;
+
+constructor TCustomExtDirectModule.CreateNew(AOwner: TComponent;
+  CreateMode: Integer);
+begin
+  inherited CreateNew(AOwner, CreateMode);
+  FOptions:=DefaultDispatchOptions+[jdoSearchRegistry];
+end;
+
+procedure TCustomExtDirectModule.CreateAPI(ADispatcher : TCustomExtDirectDispatcher; ARequest: TRequest;   AResponse: TResponse);
+
+
+begin
+  AResponse.Content:=ADispatcher.APIAsString;
+  AResponse.ContentLength:=Length(AResponse.Content);
+
+end;
+
+procedure TCustomExtDirectModule.HandleRequest(ARequest: TRequest;
+  AResponse: TResponse);
+
+Var
+  Disp : TCustomExtDirectDispatcher;
+  Req,res : TJSONData;
+  R : String;
+
+begin
+  If (Dispatcher=Nil) then
+    Dispatcher:=CreateDispatcher;
+  Disp:=Dispatcher as TCustomExtDirectDispatcher;
+  R:=ARequest.QueryFields.Values['action'];
+  If (R='') then
+    ARequest.GetNextPathInfo;
+  If (CompareText(R,APIPath)=0) then
+    begin
+    CreateAPI(Disp,ARequest,AResponse);
+    AResponse.SendResponse;
+    end
+  else if (CompareText(R,RouterPath)=0) then
+    begin
+    Res:=DispatchRequest(ARequest,Disp);
+    try
+      If Assigned(Res) then
+        AResponse.Content:=Res.AsJSON;
+      AResponse.SendResponse;
+    finally
+      Res.Free;
+    end;
+    AResponse.SendResponse;
+    end
+  else
+    JSONRPCError(SErrInvalidPath);
+end;
+
+end.
+

+ 1230 - 0
packages/fcl-web/src/jsonrpc/fpjsonrpc.pp

@@ -0,0 +1,1230 @@
+unit fpjsonrpc;
+
+{$mode objfpc}{$H+}
+{$inline on}
+
+interface
+
+uses
+  Classes, SysUtils, fpjson;
+
+Type
+
+{ ---------------------------------------------------------------------
+  JSON-RPC Handler support
+  ---------------------------------------------------------------------}
+
+  { TJSONParamDef }
+
+  TJSONParamDef = Class(TCollectionItem)
+  private
+    FName: TJSONStringType;
+    FRequired: Boolean;
+    FType: TJSONtype;
+    procedure SetName(const AValue: TJSONStringType);
+  public
+    Constructor Create(ACollection : TCollection); override;
+  Published
+    Property Name : TJSONStringType Read FName Write SetName;
+    Property DataType : TJSONtype Read FType Write FType default jtString;
+    Property Required : Boolean Read FRequired Write FRequired default True;
+  end;
+
+  { TJSONParamDefs }
+
+  TJSONParamDefs = Class(TCollection)
+  private
+    function GetP(AIndex : Integer): TJSONParamDef;
+    procedure SetP(AIndex : Integer; const AValue: TJSONParamDef);
+  Public
+    Function AddParamDef(Const AName : TJSONStringType; AType : TJSONType = jtString) : TJSONParamDef;
+    Function IndexOfParamDef(Const AName : TJSONStringType) : Integer;
+    Function FindParamDef(Const AName : TJSONStringType) : TJSONParamDef;
+    Function ParamDefByName(Const AName : TJSONStringType) : TJSONParamDef;
+    Property ParamDefs[AIndex : Integer] : TJSONParamDef Read GetP Write SetP; default;
+  end;
+
+  { TCustomJSONRPCHandler }
+  TJSONParamErrorEvent = Procedure (Sender : TObject; Const E : Exception; Var Fatal : boolean) of Object;
+  TJSONRPCOption = (jroCheckParams,jroObjectParams,jroArrayParams);
+  TJSONRPCOptions = set of TJSONRPCOption;
+
+  TJSONRPCCallContext = Class(TObject);
+
+  TCustomJSONRPCHandler = Class(TComponent)
+  private
+    FAfterExecute: TNotifyEvent;
+    FBeforeExecute: TNotifyEvent;
+    FOnParamError: TJSONParamErrorEvent;
+    FOptions: TJSONRPCOptions;
+    FParamDefs: TJSONParamDefs;
+    procedure SetParamDefs(const AValue: TJSONParamDefs);
+  Protected
+    function CreateParamDefs: TJSONParamDefs; virtual;
+    Procedure DoCheckParams(Const Params : TJSONData); virtual;
+    Function DoExecute(Const Params : TJSONData; AContext : TJSONRPCCallContext): TJSONData; virtual;
+    Property BeforeExecute : TNotifyEvent Read FBeforeExecute Write FBeforeExecute;
+    Property AfterExecute : TNotifyEvent Read FAfterExecute Write FAfterExecute;
+    Property OnParamError :TJSONParamErrorEvent Read FOnParamError Write FONParamError;
+    Property Options : TJSONRPCOptions Read FOptions Write FOptions;
+  Public
+    Constructor Create(AOwner : TComponent); override;
+    Destructor Destroy; override;
+    Procedure CheckParams(Const Params : TJSONData);
+    Function Execute(Const Params : TJSONData; AContext : TJSONRPCCallContext = Nil) : TJSONData;
+    Property ParamDefs : TJSONParamDefs Read FParamDefs Write SetParamDefs;
+  end;
+  TCustomJSONRPCHandlerClass = Class of TCustomJSONRPCHandler;
+
+  TJSONRPCEvent = Procedure (Sender : TObject; Const Params : TJSONData; Out Res : TJSONData) of object;
+
+  { TJSONRPCHandler }
+
+  TJSONRPCHandler = Class(TCustomJSONRPCHandler)
+  private
+    FOnExecute: TJSONRPCEvent;
+  protected
+    Function DoExecute(Const Params : TJSONData; AContext : TJSONRPCCallContext): TJSONData; override;
+  Published
+    Property OnExecute : TJSONRPCEvent Read FOnExecute Write FOnExecute;
+    Property BeforeExecute;
+    Property AfterExecute;
+    Property OnParamError;
+    Property Options;
+  end;
+
+  { TJSONRPCEcho }
+
+  TJSONRPCEcho = Class(TCustomJSONRPCHandler)
+  Protected
+    Function DoExecute(Const Params : TJSONData;AContext : TJSONRPCCallContext): TJSONData; override;
+  end;
+
+{ ---------------------------------------------------------------------
+  JSON-RPC dispatcher support
+  ---------------------------------------------------------------------}
+
+  TJSONRPCDispatchOption = (jdoSearchRegistry, // Check JSON Handler registry
+                            jdoSearchOwner, // Check owner (usually webmodule) for request handler
+                            jdoJSONRPC1, // Allow JSON RPC-1
+                            jdoJSONRPC2, // Allow JSON RPC-2
+                            jdoRequireClass, // Require class name (as in Ext.Direct)
+                            jdoNotifications, // Allow JSON Notifications
+                            jdoStrictNotifications // Error if notification returned result. Default is to discard result.
+                            );
+  TJSONRPCDispatchOptions = set of TJSONRPCDispatchOption;
+
+Const
+  DefaultDispatchOptions =  [jdoSearchOwner,jdoJSONRPC1,jdoJSONRPC2,jdoNotifications];
+
+Type
+  TDispatchRequestEvent = Procedure(Sender : TObject; Const AClassName,AMethod : TJSONStringType; Const Params : TJSONData) of object;
+  TFindRPCHandlerEvent =  Procedure(Sender : TObject; Const AClassName,AMethod : TJSONStringType; Out Handler : TCustomJSONRPCHandler) of object;
+
+  { TCustomJSONRPCDispatcher }
+
+  TCustomJSONRPCDispatcher = Class(TComponent)
+  private
+    FFindHandler: TFindRPCHandlerEvent;
+    FOnDispatchRequest: TDispatchRequestEvent;
+    FOnEndBatch: TNotifyEvent;
+    FOnStartBatch: TNotifyEvent;
+    FOptions: TJSONRPCDispatchOptions;
+  Protected
+    // Find handler. If none found, nil is returned. Executes OnFindHandler if needed.
+    // On return 'DoFree' must be set to indicate that the hand
+    Function FindHandler(Const AClassName,AMethodName : TJSONStringType;AContext : TJSONRPCCallContext; Out FreeObject : TComponent) : TCustomJSONRPCHandler; virtual;
+    // Execute method. Finds handler, and returns response.
+    Function ExecuteMethod(Const AClassName, AMethodName : TJSONStringType; Params,ID : TJSONData; AContext : TJSONRPCCallContext) : TJSONData; virtual;
+    // Check and Execute a single request. Exceptions are caught and converted to request error object.
+    function ExecuteRequest(ARequest: TJSONData;AContext : TJSONRPCCallContext): TJSONData;
+    // Execute requests, returns responses in same format as requests (single or array)
+    Function DoExecute(Requests : TJSONData;AContext : TJSONRPCCallContext) : TJSONData; virtual;
+    // Check if single request corresponds to specs.
+    // Returns an error object if an error was found.
+    // if request is OK, then transaction id, classname, method and params *must* be returned.
+    // The returned transaction id, method, classname and params will be ignored if there is an error.
+    function CheckRequest(Request: TJSONData; Out AClassName, AMethodName : TJSONStringType; Out ID, Params : TJSONData): TJSONData; virtual;
+    // Check if requests are OK (check if JSON2 is allowed for array).
+    Function CheckRequests(Requests : TJSONData) : TJSONData; virtual;
+    // Format result of a single request. Result is returned to the client, possibly in an array if multiple requests were received in batch.
+    Function FormatResult(const AClassName, AMethodName: TJSONStringType;  const Params, ID, Return: TJSONData) : TJSONData; virtual;
+    // Hooks for user.
+    Property OnStartBatch : TNotifyEvent Read FOnStartBatch Write FOnStartBatch;
+    Property OnDispatchRequest : TDispatchRequestEvent Read FOnDispatchRequest Write FOnDispatchRequest;
+    Property OnFindHandler : TFindRPCHandlerEvent Read FFindHandler Write FFindHandler;
+    Property OnEndBatch : TNotifyEvent Read FOnEndBatch Write FOnEndBatch;
+    Property Options : TJSONRPCDispatchOptions Read FOptions Write FOptions default DefaultDispatchOptions;
+    Class Function MethodProperty : String; virtual;
+    Class Function ClassNameProperty : String; virtual;
+    Class Function ParamsProperty : String; virtual;
+  Public
+    Constructor Create(AOwner : TComponent); override;
+    Class Function TransactionProperty : String; virtual;
+    Function Execute(Requests : TJSONData;AContext : TJSONRPCCallContext = Nil) : TJSONData;
+  end;
+
+  TJSONRPCDispatcher = Class(TCustomJSONRPCDispatcher)
+  Published
+    Property OnStartBatch;
+    Property OnDispatchRequest;
+    Property OnFindHandler;
+    Property OnEndBatch;
+    Property Options;
+  end;
+
+
+{ ---------------------------------------------------------------------
+  Factory support
+  ---------------------------------------------------------------------}
+
+
+   { TJSONRPCHandlerDef }
+
+  TDataModuleClass = Class of TDataModule; // For the time being. As of rev 15343 it is in classes unit
+
+  TBeforeCreateJSONRPCHandlerEvent = Procedure (Sender : TObject; Var AClass : TCustomJSONRPCHandlerClass) of object;
+  TJSONRPCHandlerEvent = Procedure (Sender : TObject; AHandler : TCustomJSONRPCHandler) of object;
+
+  TJSONRPCHandlerDef = Class(TCollectionItem)
+  private
+    FAfterCreate: TJSONRPCHandlerEvent;
+    FArgumentCount: Integer;
+    FBeforeCreate: TBeforeCreateJSONRPCHandlerEvent;
+    FPClass: TCustomJSONRPCHandlerClass;
+    FDataModuleClass : TDataModuleClass;
+    FHandlerMethodName: TJSONStringType;
+    FHandlerClassName: TJSONStringType;
+    procedure CheckNames(const AClassName, AMethodName: TJSONStringType);
+    procedure SetFPClass(const AValue: TCustomJSONRPCHandlerClass);
+    procedure SetHandlerClassName(const AValue: TJSONStringType);
+    procedure SetHandlerMethodName(const AValue: TJSONStringType);
+  protected
+    Function CreateInstance(AOwner : TComponent; Out AContainer : TComponent) : TCustomJSONRPCHandler; virtual;
+    Property DataModuleClass : TDataModuleClass Read FDataModuleClass;
+  Public
+    Property HandlerClassName : TJSONStringType Read FHandlerClassName Write SetHandlerClassName;
+    Property HandlerMethodName : TJSONStringType Read FHandlerMethodName Write SetHandlerMethodName;
+    Property HandlerClass : TCustomJSONRPCHandlerClass Read FPClass Write SetFPClass;
+    Property BeforeCreate : TBeforeCreateJSONRPCHandlerEvent Read FBeforeCreate Write FBeforeCreate;
+    Property AfterCreate : TJSONRPCHandlerEvent Read FAfterCreate Write FAfterCreate;
+    Property ArgumentCount : Integer Read FArgumentCount Write FArgumentCount;
+  end;
+
+  { TJSONRPCHandlerDefs }
+
+  TJSONRPCHandlerDefs = Class(TCollection)
+  private
+    function GetH(Index : Integer): TJSONRPCHandlerDef;
+    procedure SetH(Index : Integer; const AValue: TJSONRPCHandlerDef);
+  Public
+    Function IndexOfHandler(Const AClassName,AMethodName : TJSONStringType) : Integer;
+    Function AddHandler(Const AClassName,AMethodName : TJSONStringType) : TJSONRPCHandlerDef; overload;
+    Function AddHandler(Const AClassName,AMethodName : TJSONStringType; AClass : TCustomJSONRPCHandlerClass) : TJSONRPCHandlerDef; overload;
+    Property HandlerDefs[Index : Integer] : TJSONRPCHandlerDef Read GetH Write SetH; default;
+  end;
+
+  { TCustomJSONRPCHandlerManager }
+
+  TCustomJSONRPCHandlerManager = Class(TComponent)
+  Private
+    FRegistering: Boolean;
+  Protected
+    procedure Initialize; virtual;
+    // Handler support
+    Procedure RemoveHandlerDef(Const Index : Integer); virtual; abstract;
+    function AddHandlerDef(Const AClassName,AMethodName : TJSONStringType) : TJSONRPCHandlerDef; virtual; abstract;
+    function IndexOfHandlerDef(Const AClassName,AMethodName : TJSONStringType) : Integer; virtual; abstract;
+    function GetHandlerDef(Index : Integer): TJSONRPCHandlerDef; virtual; abstract;
+    function GetHandlerDefCount: Integer; virtual; abstract;
+  Public
+    // Handler support
+    Procedure UnregisterHandler(Const AClassName, AMethodName : TJSONStringType);
+    Procedure RegisterDatamodule(Const AClass : TDatamoduleClass; Const AHandlerClassName : TJSONStringType);
+    Function RegisterHandler(Const AMethodName : TJSONStringType; AClass : TCustomJSONRPCHandlerClass; AArgumentCount : Integer = 0) : TJSONRPCHandlerDef; overload;
+    Function RegisterHandler(Const AClassName,AMethodName : TJSONStringType; AClass : TCustomJSONRPCHandlerClass; AArgumentCount : Integer = 0) : TJSONRPCHandlerDef; overload;
+    Function FindHandlerDefByName(Const AClassName,AMethodName : TJSONStringType) : TJSONRPCHandlerDef;
+    Function GetHandlerDefByName(Const AClassName,AMethodName : TJSONStringType) : TJSONRPCHandlerDef;
+    Function GetHandler(Const ADef : TJSONRPCHandlerDef; AOwner : TComponent; Out AContainer : TComponent): TCustomJSONRPCHandler;
+    Function GetHandler(Const AClassName,AMethodName : TJSONStringType; AOwner : TComponent; Out AContainer : TComponent): TCustomJSONRPCHandler;
+    Procedure GetClassNames (List : TStrings); // Should be a stringlist of TJSONStringType
+    Procedure GetMethodsOfClass(Const AClassName : TJSONStringType; List : TStrings); // Should be a stringlist of TJSONStringType
+    // properties
+    Property Registering : Boolean Read FRegistering;
+    Property HandlerCount : Integer Read GetHandlerDefCount;
+    Property HandlerDefs[Index : Integer] : TJSONRPCHandlerDef Read GetHandlerDef;
+  end;
+  TCustomJSONRPCHandlerManagerClass = Class of TCustomJSONRPCHandlerManager;
+
+  { TJSONRPCHandlerManager }
+
+  TJSONRPCHandlerManager = Class(TCustomJSONRPCHandlerManager)
+  Private
+    FHandlerDefs : TJSONRPCHandlerDefs;
+  Protected
+    Procedure RemoveHandlerDef(Const Index : Integer); override;
+    function AddHandlerDef(Const AClassName,AMethodName : TJSONStringType) : TJSONRPCHandlerDef; override;
+    function IndexOfHandlerDef(Const AClassName,AMethodName : TJSONStringType) : Integer; override;
+    function GetHandlerDef(Index : Integer): TJSONRPCHandlerDef; override;
+    function GetHandlerDefCount: Integer; override;
+  Public
+    Constructor Create(AOwner : TComponent); override;
+    Destructor Destroy; override;
+  end;
+
+
+{ ---------------------------------------------------------------------
+  Auxiliary stuff
+  ---------------------------------------------------------------------}
+
+
+  EJSONRPC = Class(Exception);
+  TJSONErrorObject = Class(TJSONObject);
+
+// Raise EJSONRPC exceptions.
+Procedure JSONRPCError(Msg : String);
+Procedure JSONRPCError(Fmt : String; Args : Array of const);
+
+// Create an 'Error' object for an error response.
+function CreateJSONErrorObject(Const AMessage : String; Const ACode : Integer) : TJSONObject;
+
+// Create a JSON RPC 2 error response object containing an 'Error' object.
+// Result is of type TJSONErrorObject
+function CreateJSON2ErrorResponse(Const AMessage : String; Const ACode : Integer; ID : TJSONData = Nil; idname : TJSONStringType = 'id' ) : TJSONObject;
+function CreateJSON2ErrorResponse(Const AFormat : String; Args : Array of const; Const ACode : Integer; ID : TJSONData = Nil; idname : TJSONStringType = 'id') : TJSONObject;
+// Examines Req (request) and returns Error or an array of clones of Error)
+Function CreateErrorForRequest(Const Req,Error : TJSONData) : TJSONData;
+
+// Return TCustomJSONRPCHandlerManager instance to use for managing JSON-RPC handler.
+
+Function JSONRPCHandlerManager : TCustomJSONRPCHandlerManager;
+
+// Class that will be created. Must be set before first call to JSONRPCHandlerManager.
+Var
+  JSONRPCHandlerManagerClass : TCustomJSONRPCHandlerManagerClass = TJSONRPCHandlerManager;
+
+
+Const
+  // JSON RPC 2.0 error codes
+  EJSONRPCParseError     = -32700;
+  EJSONRPCInvalidRequest = -32600;
+  EJSONRPCMethodNotFound = -32601;
+  EJSONRPCInvalidParams  = -32602;
+  EJSONRPCInternalError  = -32603;
+
+
+resourcestring
+  SErrDuplicateParam  = 'Duplicate JSON-RPC Parameter name';
+  SErrUnknownParamDef = 'Unknown parameter definition: "%s"';
+  SErrParams = 'Error checking JSON-RPC parameters: "%s"';
+  SErrParamsMustBeArrayorObject = 'Parameters must be passed in an object or an array.';
+  SErrParamsMustBeObject = 'Parameters must be passed in an object.';
+  SErrParamsMustBeArray  = 'Parameters must be passed in an array.';
+  SErrRequestMustBeObject = 'JSON-RPC Request must be an object.';
+  SErrNoIDProperty = 'No "id" property found in request.';
+  SErrInvalidIDProperty = 'Type of "id" property is not correct.';
+  SErrNoJSONRPCProperty = 'No "jsonrpc" property in request.';
+  SErrInvalidJSONRPCProperty = 'Type or value of "jsonrpc" property is not correct.';
+  SErrNoMethodName = 'Cannot determine method: No "%s" property found in request.';
+  SErrNoClassName  = 'Cannot determine class: No "%s" property found in request.';
+  SErrNoParams = 'Cannot determine parameters: No "%s" property found in request.';
+  SErrInvalidMethodType = 'Type of "%s" property in request is not correct.';
+  SErrInvalidClassNameType = 'Type of "%s" property in request is not correct.';
+  SErrJSON2NotAllowed = 'JSON RPC 2 calls are not allowed.';
+  SErrJSON1NotAllowed = 'JSON RPC 1 calls are not allowed.';
+  SErrNoResponse = 'No response received from non-notification method "%s".';
+  SErrResponseFromNotification = 'A response was received from a notification method "%s".';
+  SErrInvalidMethodName = 'No method "%s" was found.';
+  SErrInvalidClassMethodName = 'No class "%s" with method "%s" was found.';
+  SErrDuplicateJSONRPCClassHandlerName = 'Duplicate JSON-RPC handler for class "%s" with method "%s".';
+  SErrDuplicateJSONRPCHandlerName = 'Duplicate JSON-RPC handler for method "%s".';
+  SErrUnknownJSONRPCClassMethodHandler = 'Unknown JSON-RPC handler for class "%s", method "%s".';
+  SErrUnknownJSONRPCMethodHandler = 'Unknown JSON-RPC handler for method "%s".';
+  SErrDuplicateRPCCLassMethodHandler = 'Duplicate JSON-RPC handler for class "%s", method "%s".';
+  SErrDuplicateRPCMethodHandler = 'Duplicate JSON-RPC handler for method "%s".';
+  SErrNoDispatcher = 'No method dispatcher available to handle request.';
+
+
+implementation
+
+function CreateJSONErrorObject(Const AMessage : String; Const ACode : Integer) : TJSONObject;
+
+begin
+  Result:=TJSONObject.Create(['code',ACode,'message',AMessage])
+end;
+
+function CreateJSON2ErrorResponse(Const AMessage : String; Const ACode : Integer; ID : TJSONData = Nil; idname : TJSONStringType = 'id' ) : TJSONObject;
+
+begin
+  If (ID=Nil) then
+    ID:=TJSONNull.Create;
+  Result:=TJSONErrorObject.Create(['jsonrpc','2.0','error',CreateJSONErrorObject(AMessage,ACode),idname,ID]);
+end;
+
+function CreateJSON2ErrorResponse(Const AFormat : String; Args : Array of const; Const ACode : Integer; ID : TJSONData = Nil; idname : TJSONStringType = 'id' ) : TJSONObject;
+
+begin
+  If (ID=Nil) then
+    ID:=TJSONNull.Create;
+  Result:=TJSONErrorObject.Create(['jsonrpc','2.0','error',CreateJSONErrorObject(Format(AFormat,Args),ACode),idname,ID]);
+end;
+
+Function CreateErrorForRequest(Const Req,Error : TJSONData) : TJSONData;
+
+Var
+  I : Integer;
+
+begin
+  if Req is TJSONArray then
+    begin
+    Result:=TJSONArray.Create;
+    TJSONArray(Result).Add(Error);
+    For I:=1 to TJSONArray(Req).Count-1 do
+      TJSONArray(Result).Add(Error.Clone);
+    end
+  else
+    Result:=Error;
+end;
+
+
+Var
+  TheHandler : TCustomJSONRPCHandlerManager;
+
+function JSONRPCHandlerManager: TCustomJSONRPCHandlerManager;
+begin
+  If (TheHandler=Nil) then
+    TheHandler:=JSONRPCHandlerManagerClass.Create(Nil);
+  JSONRPCHandlerManager:=TheHandler;
+end;
+
+Procedure JSONRPCError(Msg : String);
+
+begin
+  Raise EJSONRPC.Create(Msg);
+end;
+
+Procedure JSONRPCError(Fmt : String; Args : Array of const);
+
+begin
+  Raise EJSONRPC.CreateFmt(Fmt,Args);
+end;
+
+{ TJSONParamDef }
+
+procedure TJSONParamDef.SetName(const AValue: TJSONStringType);
+begin
+  if FName=AValue then exit;
+  If Assigned(Collection) and (Collection is TJSONParamDefs) then
+    if (Collection as TJSONParamDefs).FindParamDef(AValue)<>Nil then
+      JSONRPCError(SErrDuplicateParam,[AValue]);
+  FName:=AValue;
+end;
+
+constructor TJSONParamDef.Create(ACollection: TCollection);
+begin
+  inherited Create(ACollection);
+  FType:=jtString;
+  FRequired:=True;
+end;
+
+{ TJSONParamDefs }
+
+function TJSONParamDefs.GetP(AIndex : Integer): TJSONParamDef;
+begin
+  Result:=TJSONParamDef(Items[AIndex]);
+end;
+
+procedure TJSONParamDefs.SetP(AIndex : Integer; const AValue: TJSONParamDef);
+begin
+  Items[AIndex]:=AValue;
+end;
+
+function TJSONParamDefs.AddParamDef(const AName: TJSONStringType; AType: TJSONType
+  ): TJSONParamDef;
+begin
+  Result:=Add as TJSONParamDef;
+  try
+    Result.Name:=AName;
+    Result.DataType:=Atype;
+  except
+    FReeAndNil(Result);
+    Raise;
+  end;
+end;
+
+function TJSONParamDefs.IndexOfParamDef(const AName: TJSONStringType): Integer;
+begin
+  Result:=Count-1;
+  While (Result>=0) and (CompareText(AName,GetP(result).Name)<>0) do
+    Dec(Result);
+end;
+
+function TJSONParamDefs.FindParamDef(const AName: TJSONStringType): TJSONParamDef;
+
+Var
+  I : integer;
+
+begin
+  I:=IndexOfParamDef(AName);
+  If (I=-1) then
+    Result:=Nil
+  else
+    Result:=GetP(I);
+end;
+
+function TJSONParamDefs.ParamDefByName(const AName: TJSONStringType): TJSONParamDef;
+begin
+  Result:=FindParamDef(AName);
+  If (Result=Nil) then
+    JSONRPCError(SErrUnknownParamDef,[AName]);
+end;
+
+{ TCustomJSONRPCHandler }
+
+procedure TCustomJSONRPCHandler.CheckParams(const Params: TJSONData);
+
+Var
+  B : Boolean;
+
+begin
+  Try
+    DoCheckParams(Params);
+  Except
+    On E : Exception do
+      begin
+      B:=True;
+      If Assigned(FonParamError) then
+        FonParamError(Self,E,B);
+      If B then
+        Raise;
+      end;
+  end;
+end;
+
+procedure TCustomJSONRPCHandler.SetParamDefs(const AValue: TJSONParamDefs);
+begin
+  if FParamDefs=AValue then exit;
+  FParamDefs.Assign(AValue);
+end;
+
+procedure TCustomJSONRPCHandler.DoCheckParams(const Params: TJSONData);
+begin
+  If (jroObjectParams in Options) and Not (Params is TJSONobject) then
+    JSONRPCError(SErrParams,[SErrParamsMustBeObject]);
+  If (jroArrayParams in Options) and Not (Params is TJSONArray) then
+    JSONRPCError(SErrParams,[SErrParamsMustBeArray]);
+end;
+
+function TCustomJSONRPCHandler.DoExecute(Const Params: TJSONData;AContext : TJSONRPCCallContext): TJSONData;
+begin
+  Result:=Nil;
+end;
+
+constructor TCustomJSONRPCHandler.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner);
+  FParamDefs:=CreateParamDefs;
+end;
+
+destructor TCustomJSONRPCHandler.Destroy;
+begin
+  FreeAndNil(FParamDefs);
+  inherited Destroy;
+end;
+
+function TCustomJSONRPCHandler.CreateParamDefs : TJSONParamDefs;
+
+begin
+  Result:=TJSONParamDefs.Create(TJSONParamDef);
+end;
+
+function TCustomJSONRPCHandler.Execute(Const Params: TJSONData;AContext : TJSONRPCCallContext = Nil): TJSONData;
+begin
+  If Assigned(FBeforeExecute) then
+    FBeforeExecute(Self);
+  if (jroCheckParams in Options) then
+    CheckParams(Params);
+  Result:=DoExecute(Params,AContext);
+  If Assigned(FAfterExecute) then
+    FAfterExecute(Self);
+end;
+
+{ TJSONRPCHandler }
+
+function TJSONRPCHandler.DoExecute(const Params: TJSONData;AContext : TJSONRPCCallContext): TJSONData;
+begin
+  If Assigned(FOnExecute) then
+    FOnExecute(Self,Params,Result);
+end;
+
+{ TJSONRPCEcho }
+
+function TJSONRPCEcho.DoExecute(const Params: TJSONData;AContext : TJSONRPCCallContext): TJSONData;
+
+Var
+  I : Integer;
+  A : TJSONArray;
+  S : TJSONStringType;
+
+begin
+  If Params is TJSONArray then
+    begin
+    A:=Params as TJSONArray;
+    S:='';
+    For I:=0 to A.Count-1 do
+      begin
+      if (S<>'') then
+        S:=S+' ';
+      S:=S+A.Items[i].AsString;
+      end;
+    end
+  else If Params.JSONType in [jtObject,jtNumber] then
+    S:=Params.AsJSON
+  else
+    S:=Params.AsString;
+  Result:=TJSONString.Create(S);
+end;
+
+{ TCustomJSONRPCDispatcher }
+
+function TCustomJSONRPCDispatcher.FindHandler(const AClassName, AMethodName: TJSONStringType;AContext : TJSONRPCCallContext;Out FreeObject : TComponent): TCustomJSONRPCHandler;
+
+Var
+  C : TComponent;
+  D : TJSONRPCHandlerDef;
+
+
+begin
+  Result:=Nil;
+  FreeObject:=Nil;
+  If Assigned(Owner) and ((AClassName='') or (CompareText(AClassName,Owner.name)=0)) then
+    begin
+    C:=Owner.FindComponent(AMethodName);
+    If C is TCustomJSONRPCHandler then
+      Result:=TCustomJSONRPCHandler(C);
+    end;
+  If (Result=Nil) and (jdoSearchRegistry in Options) then
+    begin
+    D:=JSONRPCHandlerManager.FindHandlerDefByName(AClassName,AMethodName);
+    If Assigned(D) then
+      Result:=JSONRPCHandlerManager.GetHandler(D,Self,FreeObject);
+    end;
+ If (Result=Nil) and Assigned(FFindHandler) then
+    begin
+    FFindhandler(Self,AClassName,AMethodName,Result);
+    FreeObject:=Nil
+    end;
+end;
+
+function TCustomJSONRPCDispatcher.ExecuteMethod(Const AClassName,AMethodName: TJSONStringType;
+  Params,ID: TJSONData;AContext : TJSONRPCCallContext): TJSONData;
+
+Var
+  H : TCustomJSONRPCHandler;
+  FreeObject : TComponent;
+
+begin
+  H:=FindHandler(AClassName,AMethodName,AContext,FreeObject);
+  If (H=Nil) then
+    if (AClassName='') then
+      Exit(CreateJSON2ErrorResponse(SErrInvalidMethodName,[AMethodName],EJSONRPCMethodNotFound,ID.Clone,transactionProperty))
+    else
+      Exit(CreateJSON2ErrorResponse(SErrInvalidClassMethodName,[AClassName,AMethodName],EJSONRPCMethodNotFound,ID.Clone,transactionProperty));
+  try
+    If Assigned(FOndispatchRequest) then
+      FOndispatchRequest(Self,AClassName,AMethodName,Params);
+    Result:=H.Execute(Params,AContext);
+  finally
+    If Assigned(FreeObject) then
+      FreeAndNil(FreeObject);
+  end;
+end;
+
+function TCustomJSONRPCDispatcher.FormatResult(Const AClassName, AMethodName: TJSONStringType;
+Const Params,ID, Return : TJSONData) : TJSONData;
+
+begin
+  Result:=TJSONObject.Create(['result',Return,'error',TJSonNull.Create,transactionproperty,ID.Clone]);
+  if jdoJSONRPC2 in options then
+    TJSONObject(Result).Add('jsonrpc','2.0');
+end;
+
+function TCustomJSONRPCDispatcher.ExecuteRequest(ARequest: TJSONData;AContext : TJSONRPCCallContext): TJSONData;
+
+Var
+  C,M : TJSONStringType;
+  Id,P : TJSONData;
+
+
+begin
+  Result:=Nil;
+  try
+    Result:=CheckRequest(ARequest,C,M,ID,P);
+    If (Result=Nil) then
+      begin
+      Result:=ExecuteMethod(C,M,P,ID,AContext);
+      // Do some sanity checks.
+      If (Result=Nil) then
+        begin
+        // No response, and a response was expected.
+        if (ID<>Nil) or not (jdoNotifications in Options) then
+          Result:=CreateJSON2ErrorResponse(SErrNoResponse,[M],EJSONRPCInternalError,ID,transactionProperty);
+        end
+      else
+        begin
+        // A response was received, and no response was expected.
+        if ((ID=Nil) or (ID is TJSONNull))  and (jdoStrictNotifications in Options) then
+          Result:=CreateJSON2ErrorResponse(SErrResponseFromNotification,[M],EJSONRPCInternalError,ID,transactionProperty);
+        If (ID=Nil) or (ID is TJSONNull) then // Notification method, discard result.
+          FreeAndNil(Result);
+        end;
+      end;
+    If Assigned(Result) and not (Result is TJSONErrorObject) then
+      begin
+      Result:=FormatResult(C,M,P,ID,Result);
+      end;
+  except
+    // Something went really wrong if we end up here.
+    On E : Exception do
+      begin
+      If (Result<>Nil) then
+        FreeAndNil(Result);
+      If Assigned(ID) then
+        Result:=CreateJSON2ErrorResponse(E.Message,EJSONRPCInternalError,ID.Clone,transactionproperty)
+      else
+        Result:=CreateJSON2ErrorResponse(E.Message,EJSONRPCInternalError,Nil,transactionproperty)
+      end;
+  end;
+end;
+
+function TCustomJSONRPCDispatcher.DoExecute(Requests: TJSONData;AContext : TJSONRPCCallContext): TJSONData;
+
+Var
+  A : TJSONArray;
+  Res : TJSONData;
+  I : Integer;
+
+begin
+  Result:=Nil;
+  If Requests is TJSONArray then
+    begin
+    A:=Requests as TJSONArray;
+    Result:=TJSONArray.Create();
+    For I:=0 to A.Count-1 do
+      begin
+      Res:=ExecuteRequest(A[i],AContext);
+      If (Res<>Nil) then
+        TJSONArray(Result).Add(Res);
+      end;
+    end
+  else
+    Result:=ExecuteRequest(Requests,ACOntext);
+end;
+
+
+function TCustomJSONRPCDispatcher.CheckRequest(Request: TJSONData; Out AClassName,AMethodName : TJSONStringType; Out ID, Params : TJSONData): TJSONData;
+
+Var
+  O : TJSONObject;
+  I : Integer;
+  D : TJSONData;
+  OJ2 : Boolean;
+
+
+begin
+  AMethodName:='';
+  AClassName:='';
+  ID:=Nil;
+  Params:=Nil;
+  Result:=Nil;
+  If Not (Request is TJSONObject) then
+    Exit(CreateJSON2ErrorResponse(SErrRequestMustBeObject,EJSONRPCInvalidRequest,Nil,transactionproperty));
+  O:=TJSONObject(Request);
+  // Get ID object, if it exists.
+  I:=O.IndexOfName(TransactionProperty);
+  If (I<>-1) then
+    ID:=O.Items[i];
+  // Check ID
+  If (ID=Nil) and not (jdoNotifications in Options) then
+    Exit(CreateJSON2ErrorResponse(SErrNoIDProperty,EJSONRPCInvalidRequest,Nil,transactionproperty));
+  OJ2:=(jdoJSONRPC2 in Options) and not (jdoJSONRPC1 in Options);
+  If OJ2 then
+    begin
+    if Assigned(ID) and not (ID.JSONType in [jtNull,jtString,jtNumber]) then
+      Exit(CreateJSON2ErrorResponse(SErrINvalidIDProperty,EJSONRPCInvalidRequest,Nil,transactionproperty));
+    // Check presence and value of jsonrpc property
+    I:=O.IndexOfName('jsonrpc');
+    If (I=-1) then
+      Exit(CreateJSON2ErrorResponse(SErrNoJSONRPCProperty,EJSONRPCInvalidRequest,ID,transactionproperty));
+    If (O.Items[i].JSONType<>jtString) or (O.Items[i].AsString<>'2.0') then
+      Exit(CreateJSON2ErrorResponse(SErrInvalidJSONRPCProperty,EJSONRPCInvalidRequest,ID,transactionproperty));
+    end;
+  // Get method name, if it exists.
+  I:=O.IndexOfName(MethodProperty);
+  If (I<>-1) then
+    D:=O.Items[i]
+  else
+    Exit(CreateJSON2ErrorResponse(SErrNoMethodName,[MethodProperty],EJSONRPCInvalidRequest,ID,transactionproperty));
+  // Check if it is a string
+  if Not (D is TJSONString) then
+    Exit(CreateJSON2ErrorResponse(SErrInvalidMethodType,[MethodProperty],EJSONRPCInvalidRequest,ID,transactionproperty));
+  AMethodName:=D.AsString;
+  If (AMethodName='') then
+    Exit(CreateJSON2ErrorResponse(SErrNoMethodName,[MethodProperty],EJSONRPCInvalidRequest,ID,transactionproperty));
+  // Get class name, if it exists and is required
+  If (ClassNameProperty<>'') then
+    begin
+    I:=O.IndexOfName(ClassNameProperty);
+    If (I<>-1) then
+      D:=O.Items[i]
+    else if (jdoRequireClass in options) then
+      Exit(CreateJSON2ErrorResponse(SErrNoClassName,[ClassNameProperty],EJSONRPCInvalidRequest,ID,transactionproperty));
+    // Check if it is a string
+    if Not (D is TJSONString) then
+      Exit(CreateJSON2ErrorResponse(SErrInvalidClassNameType,[ClassNameProperty],EJSONRPCInvalidRequest,ID,transactionproperty));
+    AClassName:=D.AsString;
+    If (AMethodName='') and (jdoRequireClass in options)  then
+      Exit(CreateJSON2ErrorResponse(SErrNoClassName,[ClassNameProperty],EJSONRPCInvalidRequest,ID,transactionproperty));
+    end;
+  // Get params, if they exist
+  I:=O.IndexOfName(ParamsProperty);
+  If (I<>-1) then
+    D:=O.Items[i]
+  else
+    Exit(CreateJSON2ErrorResponse(SErrNoParams,[ParamsProperty],EJSONRPCInvalidParams,ID,transactionproperty));
+  if OJ2 then
+    begin
+    // Allow array or object
+    If Not (D.JSONType in [jtArray,jtObject]) then
+      Exit(CreateJSON2ErrorResponse(SErrParamsMustBeArrayorObject,EJSONRPCInvalidParams,ID,transactionproperty));
+    end
+  else if not (jdoJSONRPC2 in Options) then
+    begin
+    // Allow only array
+    If Not (D.JSONType in [jtArray]) then
+      Exit(CreateJSON2ErrorResponse(SErrParamsMustBeArray,EJSONRPCInvalidParams,ID,transactionproperty));
+    end;
+  Params:=D;
+end;
+
+function TCustomJSONRPCDispatcher.CheckRequests(Requests: TJSONData): TJSONData;
+
+Var
+  A : TJSONArray;
+  O : TJSONObject;
+  ID : TJSONData;
+  I,J : Integer;
+
+begin
+  Result:=Nil;
+  If (Requests is TJSONArray) then
+    begin
+    A:=Requests as TJSONArray;
+    If Not (jdoJSONRPC2 in Options) then
+      begin
+      Result:=TJSONArray.Create;
+      For I:=0 to A.Count-1 do
+        begin
+        ID:=Nil;
+        If (A.Items[i] is TJSONObject) then
+          begin
+          O:=A.Objects[i];
+          J:=O.IndexOfName('id');
+          if (J<>-1) then
+            ID:=O.Items[J].Clone;
+          end;
+        TJSONArray(Result).Add(CreateJSON2ErrorResponse(SErrJSON2NotAllowed,EJSONRPCInvalidRequest,ID,transactionproperty));
+        end;
+      end;
+    end
+  else
+    If not (Requests is TJSONObject) then
+      Result:=CreateJSON2ErrorResponse(SErrRequestMustBeObject,EJSONRPCInvalidRequest,Nil,transactionproperty);
+end;
+
+class function TCustomJSONRPCDispatcher.TransactionProperty: String;
+begin
+  Result:='id'; // Do not localize
+end;
+
+class function TCustomJSONRPCDispatcher.MethodProperty: String;
+begin
+  Result:='method'; // Do not localize
+end;
+
+class function TCustomJSONRPCDispatcher.ClassNameProperty: String;
+begin
+  Result:=''; // Do not localize
+end;
+
+class function TCustomJSONRPCDispatcher.ParamsProperty: String;
+begin
+  Result:='params'; // Do not localize
+end;
+
+constructor TCustomJSONRPCDispatcher.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner);
+  FOptions:=DefaultDispatchOptions;
+end;
+
+function TCustomJSONRPCDispatcher.Execute(Requests: TJSONData;AContext : TJSONRPCCallContext = Nil): TJSONData;
+begin
+  If Assigned(FOnStartBatch) then
+    FOnStartBatch(Self);
+  Result:=CheckRequests(Requests);
+  if (Result=Nil) then // Form is OK and allowed.
+    Result:=DoExecute(Requests,AContext);
+  If Assigned(FOnEndBatch) then
+    FOnEndBatch(Self);
+end;
+
+{ TJSONRPCHandlerDef }
+
+procedure TJSONRPCHandlerDef.SetFPClass(const AValue: TCustomJSONRPCHandlerClass
+  );
+begin
+  FPClass:=AValue;
+end;
+
+procedure TJSONRPCHandlerDef.CheckNames(Const AClassName,AMethodName : TJSONStringType);
+
+Var
+  I : Integer;
+
+begin
+  If Assigned(Collection) and (Collection is TJSONRPCHandlerDefs) then
+    begin
+    I:=TJSONRPCHandlerDefs(Collection).IndexOfHandler(AClassName,AMethodName);
+    If (I<>-1) and (Collection.Items[i]<>Self) then
+      if (AClassName<>'') then
+        JSONRPCError(SErrDuplicateJSONRPCClassHandlerName,[AClassName,AMethodName])
+      else
+        JSONRPCError(SErrDuplicateJSONRPCHandlerName,[AClassName,AMethodName]);
+    end;
+end;
+
+procedure TJSONRPCHandlerDef.SetHandlerClassName(const AValue: TJSONStringType);
+begin
+  if FHandlerClassName=AValue then exit;
+  CheckNames(AValue,HandlerMethodName);
+  FHandlerClassName:=AValue;
+end;
+
+procedure TJSONRPCHandlerDef.SetHandlerMethodName(const AValue: TJSONStringType
+  );
+begin
+  if FHandlerMethodName=AValue then exit;
+  CheckNames(HandlerClassName,AValue);
+  FHandlerMethodName:=AValue;
+end;
+
+function TJSONRPCHandlerDef.CreateInstance(AOwner: TComponent; out
+  AContainer: TComponent): TCustomJSONRPCHandler;
+
+Var
+  AClass : TCustomJSONRPCHandlerClass;
+  DM : TDataModule;
+  C : TComponent;
+
+begin
+  Result:=Nil;
+  {$ifdef wmdebug}SendDebug(Format('Creating instance for %s',[Self.ProviderName]));{$endif}
+  If Assigned(FDataModuleClass) then
+    begin
+    {$ifdef wmdebug}SendDebug(Format('Creating datamodule from class %d ',[Ord(Assigned(FDataModuleClass))]));{$endif}
+    DM:=FDataModuleClass.Create(AOwner);
+    {$ifdef wmdebug}SendDebug(Format('Created datamodule from class %s ',[DM.ClassName]));{$endif}
+    C:=DM.FindComponent(FHandlerMethodName);
+    If (C<>Nil) and (C is TCustomJSONRPCHandler) then
+      Result:=TCustomJSONRPCHandler(C)
+    else
+      begin
+      FreeAndNil(DM);
+      JSONRPCError(SErrUnknownJSONRPCMethodHandler,[FHandlerMethodName]);
+      end;
+    end
+  else
+    DM:=TDataModule.CreateNew(AOwner,0);
+  AContainer:=DM;
+  If (Result=Nil) then
+    begin
+    {$ifdef wmdebug}SendDebug(Format('Creating from class pointer %d ',[Ord(Assigned(FPClass))]));{$endif}
+    AClass:=FPCLass;
+    If Assigned(FBeforeCreate) then
+      FBeforeCreate(Self,AClass);
+    Result:=AClass.Create(AContainer);
+    end;
+  If Assigned(FAfterCreate) then
+    FAfterCreate(Self,Result);
+end;
+
+{ TJSONRPCHandlerDefs }
+
+function TJSONRPCHandlerDefs.GetH(Index: Integer): TJSONRPCHandlerDef;
+begin
+  Result:=TJSONRPCHandlerDef(Items[Index]);
+end;
+
+procedure TJSONRPCHandlerDefs.SetH(Index: Integer;
+  const AValue: TJSONRPCHandlerDef);
+begin
+  Items[Index]:=AValue;
+end;
+
+function TJSONRPCHandlerDefs.AddHandler(const AClassName,
+  AMethodName: TJSONStringType): TJSONRPCHandlerDef;
+begin
+  If (IndexOfHandler(AClassName,AMethodName)<>-1) then
+    If (AClassName<>'') then
+      JSONRPCError(SErrDuplicateJSONRPCClassHandlerName,[AClassName,AMethodName])
+    else
+      JSONRPCError(SErrDuplicateJSONRPCHandlerName,[AMethodName]);
+  Result:=TJSONRPCHandlerDef(Add);
+  Result.FHandlerClassName:=AClassName;
+  Result.FHandlerMethodName:=AMethodName;
+end;
+
+function TJSONRPCHandlerDefs.AddHandler(const AClassName,
+  AMethodName: TJSONStringType; AClass: TCustomJSONRPCHandlerClass
+  ): TJSONRPCHandlerDef;
+begin
+  Result:=AddHandler(AClassName,AMethodName);
+  Result.HandlerClass:=AClass;
+end;
+
+function TJSONRPCHandlerDefs.IndexOfHandler(const AClassName,
+  AMethodName: TJSONStringType): Integer;
+
+  Function IsMatch(Index : Integer) : Boolean; inline;
+
+  Var
+    D : TJSONRPCHandlerDef;
+
+  begin
+    D:=GetH(Index);
+    Result:=((AClassName='') or
+             (CompareText(D.HandlerClassName,AClassName)=0)) and
+            (CompareText(AMethodName,D.HandlerMethodName)=0)
+  end;
+
+begin
+  Result:=Count-1;
+  While (Result>=0) and Not IsMatch(Result) do
+    Dec(Result)
+end;
+
+{ TCustomJSONRPCHandlerManager }
+
+procedure TCustomJSONRPCHandlerManager.Initialize;
+begin
+  // Do nothing
+end;
+
+procedure TCustomJSONRPCHandlerManager.UnregisterHandler(const AClassName,
+  AMethodName: TJSONStringType);
+
+Var
+  I : Integer;
+
+begin
+  I:=IndexOfHandlerDef(AClassName,AMethodName);
+  If (I<>-1) then
+    RemoveHandlerDef(I)
+  else
+    If (AClassName<>'') then
+      JSONRPCError(SErrUnknownJSONRPCClassMethodHandler,[AClassName,AMethodName])
+    else
+      JSONRPCError(SErrUnknownJSONRPCMethodHandler,[AMethodName]);
+end;
+
+procedure TCustomJSONRPCHandlerManager.RegisterDatamodule(
+  const AClass: TDatamoduleClass; const AHandlerClassName: TJSONStringType);
+
+Var
+  DM : TDatamodule;
+  I,J : Integer;
+  C : TComponent;
+  D : TJSONRPCHandlerDef;
+  B : Boolean;
+  CN : TJSONStringType;
+
+begin
+  B:=FRegistering;
+  try
+    FRegistering:=True;
+    DM:=AClass.Create(Self);
+    try
+      If (AHandlerClassName='') then
+        CN:=DM.Name
+      else
+        CN:=AHandlerClassName;
+      For I:=0 to DM.ComponentCount-1 do
+        begin
+        C:=DM.Components[i];
+        if C is TCustomJSONRPCHandler then
+          begin
+          J:=IndexOfHandlerDef(CN,C.Name);
+          If (J<>-1) then
+             JSONRPCError(SErrDuplicateRPCCLassMethodHandler,[CN,C.Name]);
+          D:=AddHandlerDef(CN,C.Name);
+          D.ArgumentCount:=TCustomJSONRPCHandler(C).ParamDefs.Count;
+          {$ifdef wmdebug}SendDebug('Registering provider '+C.Name);{$endif}
+          D.FDataModuleClass:=TDataModuleClass(DM.ClassType);
+          end;
+        end;
+    finally
+      DM.Free;
+    end;
+  finally
+    FRegistering:=B;
+  end;
+end;
+
+function TCustomJSONRPCHandlerManager.RegisterHandler(
+  const AMethodName: TJSONStringType;
+  AClass: TCustomJSONRPCHandlerClass;
+  AArgumentCount : Integer = 0): TJSONRPCHandlerDef;
+
+begin
+  Result:=RegisterHandler('',AMethodName,AClass,AArgumentCount);
+end;
+
+function TCustomJSONRPCHandlerManager.RegisterHandler(
+  const AClassName,AMethodName: String;
+  AClass: TCustomJSONRPCHandlerClass;
+  AArgumentCount : Integer = 0): TJSONRPCHandlerDef;
+
+Var
+  I : Integer;
+  B : Boolean;
+
+begin
+  B:=FRegistering;
+  try
+    FRegistering:=True;
+    I:=IndexOfHandlerDef(AClassName,AMethodname);
+    If (I<>-1) then
+      If (AClassName<>'') then
+        JSONRPCError(SErrDuplicateRPCCLassMethodHandler,[AClassName,AMethodName])
+      else
+        JSONRPCError(SErrDuplicateRPCMethodHandler,[AMethodName]);
+    Result:=AddHandlerDef(AClassName,AMEthodName);
+    Result.HandlerClass:=AClass;
+    Result.ArgumentCount:=AArgumentCount;
+  finally
+    FRegistering:=B;
+  end;
+end;
+
+function TCustomJSONRPCHandlerManager.FindHandlerDefByName(const AClassName,
+  AMethodName: TJSONStringType): TJSONRPCHandlerDef;
+
+Var
+  I : integer;
+
+begin
+  I:=IndexOfHandlerDef(AClassName,AMethodName);
+  If (I=-1) then
+    Result:=Nil
+  else
+    Result:=GetHandlerDef(I);
+end;
+
+function TCustomJSONRPCHandlerManager.GetHandlerDefByName(const AClassName,
+  AMethodName: TJSONStringType): TJSONRPCHandlerDef;
+begin
+  Result:=FindHandlerDefByName(AClassName,AMethodName);
+  If (Result=Nil) then
+    If (AClassName<>'') then
+      JSONRPCError(SErrUnknownJSONRPCClassMethodHandler,[AClassName,AMethodName])
+    else
+      JSONRPCError(SErrUnknownJSONRPCMethodHandler,[AMethodName]);
+end;
+
+function TCustomJSONRPCHandlerManager.GetHandler(
+  const ADef: TJSONRPCHandlerDef; AOwner: TComponent; out AContainer: TComponent
+  ): TCustomJSONRPCHandler;
+
+Var
+  O : TComponent;
+
+begin
+  If AOwner=Nil then
+    O:=Self
+  else
+    O:=AOwner;
+  Result:=ADef.CreateInstance(O,AContainer);
+end;
+
+function TCustomJSONRPCHandlerManager.GetHandler(const AClassName,
+  AMethodName: TJSONStringType; AOwner: TComponent; out AContainer: TComponent
+  ): TCustomJSONRPCHandler;
+
+Var
+  D : TJSONRPCHandlerDef;
+
+begin
+  D:=GetHandlerDefByname(AClassName,AMEthodName);
+  Result:=GetHandler(D,AOwner,AContainer);
+end;
+
+procedure TCustomJSONRPCHandlerManager.GetClassNames(List: TStrings);
+begin
+
+end;
+
+procedure TCustomJSONRPCHandlerManager.GetMethodsOfClass(
+  const AClassName: TJSONStringType; List: TStrings);
+begin
+
+end;
+
+{ TJSONRPCHandlerManager }
+
+procedure TJSONRPCHandlerManager.RemoveHandlerDef(const Index: Integer);
+begin
+  FHandlerDefs.Delete(Index);
+end;
+
+function TJSONRPCHandlerManager.AddHandlerDef(const AClassName,
+  AMethodName: TJSONStringType): TJSONRPCHandlerDef;
+begin
+  Result:=FHandlerDefs.AddHandler(AClassName,AMethodName);
+end;
+
+function TJSONRPCHandlerManager.IndexOfHandlerDef(const AClassName,
+  AMethodName: TJSONStringType): Integer;
+begin
+  Result:=FHandlerDefs.IndexOfHandler(AClassName,AMethodName);
+end;
+
+function TJSONRPCHandlerManager.GetHandlerDef(Index: Integer
+  ): TJSONRPCHandlerDef;
+begin
+  Result:=FHandlerDefs[Index];
+end;
+
+function TJSONRPCHandlerManager.GetHandlerDefCount: Integer;
+begin
+  Result:=FHandlerDefs.Count;
+end;
+
+constructor TJSONRPCHandlerManager.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner);
+  FHandlerDefs:=TJSONRPCHandlerDefs.Create(TJSONRPCHandlerDef);
+end;
+
+destructor TJSONRPCHandlerManager.Destroy;
+begin
+  FreeAndNil(FHandlerDefs);
+  inherited Destroy;
+end;
+
+
+Initialization
+Finalization
+  FreeAndNil(TheHandler);
+end.
+

+ 189 - 0
packages/fcl-web/src/jsonrpc/readme.txt

@@ -0,0 +1,189 @@
+
+The JSON-RPC support for FPC consists out of 2 units:
+
+fpjsonrpc: a set of components suitable for executing requests.
+webjsonrpc: Handles all HTTP transport and content handling for the JSON-RPC requests.
+fpextdirect: implements a Ext.Direct variant of JSON-RPC; 
+             It includes HTTP transport an content handling.
+
+The fpjsonrpc unit implements support for JSON-RPC: it implements versions
+1.0 and 2.0 of the protocol, and has provisions for Ext.Direct-style RPC.
+
+It introduces the following classes:
+
+TCustomJSONRPCHandler = Class(TComponent)
+  The main method of this class is 
+    Function Execute(Const Params : TJSONData; AContext : TJSONRPCCallContext = Nil) : TJSONData;
+       it executes a JSON-RPC call. The parameters to the call are in the Params
+       parameter, the AContext parameter can be used by dispatching mechanisms to
+       provide information about the context of the call (HTTP session etc.)
+    Property ParamDefs : TJSONParamDefs Read FParamDefs Write SetParamDefs;
+       Describes the parameters to the call. If 'Options' contains jroCheckParams, 
+       then the types (and names, if appropriate) of the parameters will be checked.
+
+TJSONRPCHandler = Class(TCustomJSONRPCHandler)
+  A descendent which delegates the execution of the RPC call to an Event Handler.
+  Typically, one will drop an instance of TJSONRPCHandler on a webmodule.
+  Note that it does not provide context information in the event handler.
+
+TCustomJSONRPCDispatcher = Class(TComponent)
+  A request dispatching mechanism. It receives a JSON-encoded RPC request or a batch of
+  requests: 
+    Function Execute(Requests : TJSONData; AContext : TJSONRPCCallContext = Nil) : TJSONData;
+  For each request in the batch, it will examine the 'method' and 'class' 
+  of the request and will search for a TCustomJSONRPCHandler instance that
+  can execute the call, and pass the call on to that instance. It also
+  passes the context to the handler.
+
+  If jsoSearchOwner is in OPtions, then it will look on the Owner (usually a
+  TDatamodule descendent) for a TCustomJSONRPCHandler instance whose name
+  matches 'method' in the request, and will invoke its 'Execute' method.
+
+  if jdoSearchRegistry is in Options, then the JSONRPCHandlerManager factory
+  is queryied for an instance of TCustomJSONRPCHandler that can handle the
+  call. This instance is freed after the call ends.
+
+  The dispatcher can check the validity of the request and responses 
+  based on the Options property:
+    jdoJSONRPC1, // Allow JSON RPC-1
+    jdoJSONRPC2, // Allow JSON RPC-2
+    jdoRequireClass, // Require class name (as in  Ext.Direct)
+    jdoNotifications, // Allow JSON Notifications
+    jdoStrictNotifications // Error if notification returned result. Default is to discard result.
+
+TJSONRPCDispatcher = Class(TCustomJSONRPCDispatcher)
+  A descendent of TCustomJSONRPCDispatcher that publishes some events and  
+  properties:
+
+  OnStartBatch : Called before a batch is started
+  OnFindHandler : Called when no handler is found, can be used to construct custom method handlers.
+  OnDispatchRequest : Called before the request is dispatched to the handler.
+  OnEndBatch : called after the batch has been processed.
+
+  Most methods of this component can be overridden to provide customized
+  behaviour.
+
+
+TCustomJSONRPCHandlerManager = Class(TComponent)
+
+  A class that implements a TCustomJSONRPCHandler factory: definitions of TCustomJSONRPCHandler classes are kept.
+  classes must be registered using one of the calls:
+    Function RegisterHandler(Const AMethodName : TJSONStringType; AClass : TCustomJSONRPCHandlerClass; AArgumentCount : Integer = 0) : TJSONRPCHandlerDef; 
+    Function RegisterHandler(Const AClassName,AMethodName : TJSONStringType; AClass : TCustomJSONRPCHandlerClass; AArgumentCount : Integer = 0) :TJSONRPCHandlerDef; 
+
+  There is also support for registering a datamodule with TCustomJSONRPCHandler instances:
+
+    Procedure RegisterDatamodule(Const AClass : TDatamoduleClass; Const AHandlerClassName : TJSONStringType);
+
+  This will create an instance of the datamodule, register all TCustomJSONRPCHandler instances on the datamodule
+  with the datamodule name as the classname is AHandlerClassName is empty, and the TCustomJSONRPCHandler instance 
+  name as the method name. After registration, the module is freed. 
+
+A global instance of TCustomJSONRPCHandlerManager is available through the
+
+  Function JSONRPCHandlerManager : TCustomJSONRPCHandlerManager;
+
+function. By default, an instance of TJSONRPCHandlerManager is created.
+
+This instance is used by the dispatcher classes to search for a TCustomJSONRPCHandler instance.
+
+The webjsonrpc unit implements HTTP transport and content handling for the json-rpc mechanism. 
+It introduces the following classes:
+
+TCustomJSONRPCContentProducer = Class(THTTPContentProducer)    
+
+  Handles a HTTP request, extracts the JSON-RPC request from it, and returns the result in the HTTP response.
+  It needs a dispatcher instance, which must be provided by a descendent.
+
+TJSONRPCContentProducer = Class(TCustomJSONRPCContentProducer)
+  Publishes a Dispatcher property, which must be set by the programmer. 
+  All requests will be dispatched to this instance
+
+TJSONRPCSessionContext = Class(TJSONRPCCallContext) 
+  JSON-RPC call context which gives access to the HTTP Session object.
+
+TSessionJSONRPCDispatcher = Class(TCustomJSONRPCDispatcher)
+  JSON-RPC dispatcher which initializes the call context if the handler is
+  located on a websession module.
+
+TJSONRPCDispatchModule = Class(TSessionHTTPModule)
+  Webmodule which knows how to dispatch a request and create session information for it.
+
+TCustomJSONRPCModule = Class(TJSONRPCDispatchModule)
+  It completely handles a JSON-RPC request over HTTP. 
+  It creates a dispatcher if needed to handle the request.
+  The dispatcher is by default of type TSessionJSONRPCDispatcher
+
+TJSONRPCModule= Class(TCustomJSONRPCModule)  
+  A webmodule which can be registered in the fcl-web module registry. 
+  Publishes a property Dispatcher to dispatch a request, if set, this
+  dispatcher will be used.
+  Publishes a property DispatchOptions; If the module creates a dispatcher,  
+  it will be passed these properties.
+
+The fpextdirect unit contains the following classes:
+
+TCustomExtDirectDispatcher = Class(TCustomJSONRPCDispatcher)
+  A JSON-RPC dispatcher that conforms to Ext.Direct specifications.
+  It sets the default Options to require a class name.
+  It handles HTTP sessions just as TSessionJSONRPCDispatcher does.
+
+TExtDirectDispatcher = Class(TCustomExtDirectDispatcher)
+  Simply publishes all properties.
+
+TCustomExtDirectContentProducer = Class(TCustomJSONRPCContentProducer)
+  A content producer that knows how to handle the 'API' request. It
+  assumes the path is something like /myapp/extdirect/api. All other
+  paths are treated as actual method calls.
+
+TCustomExtDirectModule =  Class(TJSONRPCDispatchModule)
+  Handles JSON-RPC requests. It has 2 properties APIPath and RouterPath
+  which determine how the request is handled:
+  /modulepath/APIPath will create the API response.
+  /modulepath/RouterPath will route the JSON-RPC request.
+
+TExtDirectModule = Class(TCustomExtDirectModule)
+  Publishes the properties introduced in TCustomExtDirectModule.
+
+There are 4 ways to handle JSON-RPC in fcl-web:
+1. Manual:
+  A. Drop one or more TJSONRPCHandler components on a webmodule.
+  B. Implement the OnExecute handlers of the TJSONRPCHandler components
+  C. Handle the request in a OnRequest handler of an webaction and/or webmodule.
+  This means 
+  1. converting the request to JSONData.
+  2. Extracting the method(s) and (their) parameters from the data.
+  3. locating The TJSONRPCHandler.
+  4. Passing the parameters to the Execute method of the handler.
+  5. Convert the result to JSON and send it back.
+
+2. Using a TJSONRPCDispatcher:
+  A. Drop one or more TJSONRPCHandler components on a webmodule.
+  B. Implement the OnExecute handlers of the TJSONRPCHandler components
+  C. Handle the request in a OnRequest handler of an webaction and/or webmodule.
+  This means 
+  1. converting the request to JSONData.
+  4. Passing the parameters to the Execute method of the handler
+  5. Convert the result to JSON and send it back.
+
+3. Using a TJSONRPCContentProducer:
+   A. Drop one or more TJSONRPCHandler components on a webmodule.
+   B. Implement the OnExecute handlers of the TJSONRPCHandler components.
+   C. Handle the request in a OnRequest handler of an webaction and/or webmodule.
+   1. Return the content of the TJSONRPCContentProducer. 
+
+4. Using a TJSONRPCModule
+   A. Drop one or more TJSONRPCHandler on a TJSONRPCModule.
+   B. Implement the OnExecute handlers of the TJSONRPCHandler components.
+
+For large applicaions, TJSONRPCHandler instances can be dropped on
+datamodules or TJSONRPCModules, and the datamodule and/or TJSONRPCModules
+must be registered using
+  JSONRpcHandlerManager.RegisterModule(TMyModule,'myclassname');
+if TJSONRPCModules are used, only 1 must be registered as a webmodule
+to handle the request. It will dispatch the request to the other instances
+if needed.
+
+Note: if a request contains no class name, then the handler is searched
+using the first matching method name. If 2 modules implement the same
+method name, then the first match is used.

+ 309 - 0
packages/fcl-web/src/jsonrpc/webjsonrpc.pp

@@ -0,0 +1,309 @@
+unit webjsonrpc;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, fpjson, fpjsonrpc, httpdefs, fphttp, jsonparser, websession;
+
+Type
+{ ---------------------------------------------------------------------
+  HTTP handling and content producing methods
+  ---------------------------------------------------------------------}
+
+  { TCustomJSONRPCContentProducer }
+
+  TCustomJSONRPCContentProducer = Class(THTTPContentProducer)
+  Protected
+    Function GetIDProperty : String; virtual;
+    Procedure DoGetContent(ARequest : TRequest; Content : TStream; Var Handled : Boolean); override;
+    Function GetDispatcher : TCustomJSONRPCDispatcher; virtual; abstract;
+  end;
+
+  { TJSONRPCContentProducer }
+
+  TJSONRPCContentProducer = Class(TCustomJSONRPCContentProducer)
+  private
+    FDispatcher: TCustomJSONRPCDispatcher;
+    procedure SetDispatcher(const AValue: TCustomJSONRPCDispatcher);
+  Protected
+    Function GetDispatcher : TCustomJSONRPCDispatcher; override;
+    procedure Notification(AComponent: TComponent; Operation: TOperation);override;
+  Published
+    Property Dispatcher :  TCustomJSONRPCDispatcher Read FDispatcher Write SetDispatcher;
+  end;
+
+
+  { TJSONRPCSessionContext }
+
+  TJSONRPCSessionContext = Class(TJSONRPCCallContext)
+  private
+    FSession: TCustomSession;
+  Public
+    Constructor CreateSession(ASession : TCustomSession);
+    Property Session : TCustomSession Read FSession;
+  end;
+
+  { TSessionJSONRPCDispatcher }
+
+  TSessionJSONRPCDispatcher = Class(TCustomJSONRPCDispatcher)
+  Protected
+    Function FindHandler(Const AClassName,AMethodName : TJSONStringType;AContext : TJSONRPCCallContext; Out FreeObject : TComponent) : TCustomJSONRPCHandler; override;
+  Published
+    Property OnStartBatch;
+    Property OnDispatchRequest;
+    Property OnFindHandler;
+    Property OnEndBatch;
+    Property Options;
+  end;
+
+  { TJSONRPCDispatchModule }
+
+  TJSONRPCDispatchModule = Class(TSessionHTTPModule)
+  protected
+    Function CreateContext : TJSONRPCSessionContext;
+    Function DispatchRequest(Const ARequest : TRequest; ADispatcher : TCustomJSONRPCDispatcher) : TJSONData;
+  end;
+
+  { TCustomJSONRPCModule }
+
+  TCustomJSONRPCModule = Class(TJSONRPCDispatchModule)
+  private
+    FDispatcher: TCustomJSONRPCDispatcher;
+    FOptions: TJSONRPCDispatchOptions;
+    FRequest: TRequest;
+    FResponse: TResponse;
+    procedure SetDispatcher(const AValue: TCustomJSONRPCDispatcher);
+  Protected
+    Function CreateDispatcher : TCustomJSONRPCDispatcher; virtual;
+    procedure Notification(AComponent: TComponent; Operation: TOperation);override;
+    Property Dispatcher :  TCustomJSONRPCDispatcher Read FDispatcher Write SetDispatcher;
+    Property DispatchOptions : TJSONRPCDispatchOptions Read FOptions Write FOptions default DefaultDispatchOptions;
+  Public
+    Constructor CreateNew(AOwner : TComponent; CreateMode : Integer); override;
+    Procedure HandleRequest(ARequest : TRequest; AResponse : TResponse); override;
+    // Access to request
+    Property Request: TRequest Read FRequest;
+    // Access to response
+    Property Response: TResponse Read FResponse;
+  end;
+
+  { TJSONRPCDataModule }
+
+  TJSONRPCModule = Class(TCustomJSONRPCModule)
+  Published
+    Property Dispatcher;
+    Property DispatchOptions;
+  end;
+
+implementation
+{ TCustomJSONRPCContentProducer }
+
+function TCustomJSONRPCContentProducer.GetIDProperty: String;
+begin
+  Result:='id';
+end;
+
+
+procedure TCustomJSONRPCContentProducer.DoGetContent(ARequest: TRequest;
+  Content: TStream; var Handled: Boolean);
+
+Var
+  Disp : TCustomJSONRPCDispatcher;
+  P : TJSONParser;
+  Req,res : TJSONData;
+  R : String;
+
+begin
+  Disp:=Self.GetDispatcher;
+  P:= TJSONParser.Create(ARequest.Content);
+  try
+    Res:=Nil;
+    Req:=Nil;
+    try
+      try
+        Req:=P.Parse;
+        If (Disp<>Nil) then
+          Res:=Disp.Execute(Req,Nil)
+        else // No dispatcher, create error(s)
+          Res:=CreateErrorForRequest(Req,CreateJSON2ErrorResponse(SErrNoDispatcher,EJSONRPCInternalError,Nil,GetIDProperty));
+      except
+        On E : Exception Do
+          begin
+          Res:=CreateJSON2ErrorResponse(E.Message,EJSONRPCParseError,Nil,GetIDProperty);
+          end;
+      end;
+      try
+        If Assigned(Res) then
+          begin
+          R:=Res.AsJSON;
+          Content.WriteBuffer(R[1],Length(R));
+          end;
+        Handled:=True;
+      finally
+        FreeAndNil(Res);
+      end;
+    finally
+      Req.Free;
+    end;
+  finally
+    P.Free;
+  end;
+end;
+
+{ TJSONRPCContentProducer }
+
+procedure TJSONRPCContentProducer.SetDispatcher(
+  const AValue: TCustomJSONRPCDispatcher);
+begin
+  if FDispatcher=AValue then exit;
+  If Assigned(FDispatcher) then
+    FDispatcher.RemoveFreeNotification(Self);
+  FDispatcher:=AValue;
+  If Assigned(FDispatcher) then
+    FDispatcher.FreeNotification(Self);
+end;
+
+function TJSONRPCContentProducer.GetDispatcher: TCustomJSONRPCDispatcher;
+begin
+  Result:=FDispatcher;
+end;
+
+procedure TJSONRPCContentProducer.Notification(AComponent: TComponent;
+  Operation: TOperation);
+begin
+  inherited Notification(AComponent, Operation);
+  If (Operation=opRemove) and (AComponent=FDispatcher) then
+    FDispatcher:=Nil;
+end;
+
+{ TCustomJSONRPCModule }
+
+procedure TCustomJSONRPCModule.SetDispatcher(
+  const AValue: TCustomJSONRPCDispatcher);
+begin
+  if FDispatcher=AValue then exit;
+  If Assigned(FDispatcher) then
+    FDispatcher.RemoveFreeNotification(Self);
+  FDispatcher:=AValue;
+  If Assigned(FDispatcher) then
+    FDispatcher.FreeNotification(Self);
+end;
+
+function TCustomJSONRPCModule.CreateDispatcher: TCustomJSONRPCDispatcher;
+
+Var
+  S : TSessionJSONRPCDispatcher;
+
+begin
+  S:=TSessionJSONRPCDispatcher.Create(Self);
+  S.Options:=DispatchOptions;
+  Result:=S;
+end;
+
+procedure TCustomJSONRPCModule.Notification(AComponent: TComponent;
+  Operation: TOperation);
+begin
+  inherited Notification(AComponent, Operation);
+  If (Operation=opRemove) and (AComponent=FDispatcher) then
+    FDispatcher:=Nil;
+end;
+
+constructor TCustomJSONRPCModule.CreateNew(AOwner: TComponent;
+  CreateMode: Integer);
+begin
+  inherited CreateNew(AOwner, CreateMode);
+  FOptions:=DefaultDispatchOptions+[jdoSearchRegistry];
+end;
+
+
+
+procedure TCustomJSONRPCModule.HandleRequest(ARequest: TRequest;
+  AResponse: TResponse);
+
+Var
+  Disp : TCustomJSONRPCDispatcher;
+  res : TJSONData;
+
+begin
+  If (Dispatcher=Nil) then
+    Dispatcher:=CreateDispatcher;
+  Disp:=Dispatcher;
+  Res:=DispatchRequest(ARequest,Disp);
+  try
+    If Assigned(Res) then
+      begin
+      AResponse.Content:=Res.AsJSON;
+      AResponse.ContentLength:=Length(AResponse.Content);
+      end;
+  AResponse.SendResponse;
+  finally
+    Res.Free;
+  end;
+end;
+
+{ TJSONRPCSessionContext }
+
+constructor TJSONRPCSessionContext.CreateSession(ASession: TCustomSession);
+begin
+  FSession:=ASession;
+end;
+
+{ TJSONRPCDispatchModule }
+
+function TJSONRPCDispatchModule.CreateContext: TJSONRPCSessionContext;
+begin
+  If CreateSession then
+    Result:=TJSONRPCSessionContext.CreateSession(Session)
+  else
+    Result:=TJSONRPCSessionContext.CreateSession(Nil);
+end;
+
+Function TJSONRPCDispatchModule.DispatchRequest(const ARequest: TRequest;
+  ADispatcher: TCustomJSONRPCDispatcher): TJSONData;
+var
+  P : TJSONParser;
+  Req : TJSONData;
+  C : TJSONRPCSessionContext;
+
+
+begin
+  P:= TJSONParser.Create(ARequest.Content);
+  try
+    Result:=Nil;
+    Req:=Nil;
+    try
+      try
+        Req:=P.Parse;
+        C:=CreateContext;
+        try
+          Result:=ADispatcher.Execute(Req,C);
+        finally
+          C.Free;
+        end;
+      except
+        On E : Exception Do
+          Result:=CreateJSON2ErrorResponse(E.Message,EJSONRPCParseError,Nil,ADispatcher.TransactionProperty);
+      end;
+    finally
+      Req.Free;
+    end;
+  finally
+    P.Free;
+  end;
+end;
+
+{ TSessionJSONRPCDispatcher }
+
+function TSessionJSONRPCDispatcher.FindHandler(const AClassName,
+  AMethodName: TJSONStringType; AContext: TJSONRPCCallContext; out
+  FreeObject: TComponent): TCustomJSONRPCHandler;
+begin
+  Result:=Inherited FindHandler(AClassName,AMethodName,AContext,FreeObject);
+  If (AContext is TJSONRPCSessionContext) and (FreeObject is TCustomJSONRPCModule) then
+    TCustomJSONRPCModule(FreeObject).Session:=TJSONRPCSessionContext(AContext).Session;
+end;
+
+end.
+