Browse Source

+ Merged from fixbranch

michael 24 years ago
parent
commit
9a9ee075e5
4 changed files with 4222 additions and 0 deletions
  1. 1264 0
      fcl/db/dbase/Makefile
  2. 17 0
      fcl/db/dbase/Makefile.fpc
  3. 2896 0
      fcl/db/dbase/dbf.pas
  4. 45 0
      fcl/db/dbase/testdbf.pp

+ 1264 - 0
fcl/db/dbase/Makefile

@@ -0,0 +1,1264 @@
+#
+# Makefile generated by fpcmake v1.00 [2000/12/08]
+#
+
+defaultrule: all
+
+#####################################################################
+# Autodetect OS (Linux or Dos or Windows NT)
+# define inUnix when running under Unix (Linux,FreeBSD)
+# define inWinNT when running under WinNT
+#####################################################################
+
+# We need only / in the path
+override PATH:=$(subst \,/,$(PATH))
+
+# Search for PWD and determine also if we are under linux
+PWD:=$(strip $(wildcard $(addsuffix /pwd.exe,$(subst ;, ,$(PATH)))))
+ifeq ($(PWD),)
+PWD:=$(strip $(wildcard $(addsuffix /pwd,$(subst :, ,$(PATH)))))
+ifeq ($(PWD),)
+nopwd:
+	@echo You need the GNU utils package to use this Makefile!
+	@echo Get ftp://ftp.freepascal.org/pub/fpc/dist/go32v2/utilgo32.zip
+	@exit
+else
+inUnix=1
+endif
+else
+PWD:=$(firstword $(PWD))
+endif
+
+# Detect NT - NT sets OS to Windows_NT
+# Detect OS/2 - OS/2 has OS2_SHELL defined
+ifndef inUnix
+ifeq ($(OS),Windows_NT)
+inWinNT=1
+else
+ifdef OS2_SHELL
+inOS2=1
+endif
+endif
+endif
+
+# The extension of executables
+ifdef inUnix
+SRCEXEEXT=
+else
+SRCEXEEXT=.exe
+endif
+
+# The path which is searched separated by spaces
+ifdef inUnix
+SEARCHPATH=$(subst :, ,$(PATH))
+else
+SEARCHPATH=$(subst ;, ,$(PATH))
+endif
+
+# Base dir
+ifdef PWD
+BASEDIR:=$(shell $(PWD))
+else
+BASEDIR=.
+endif
+
+#####################################################################
+# FPC version/target Detection
+#####################################################################
+
+# What compiler to use ?
+ifndef FPC
+# Compatibility with old makefiles
+ifdef PP
+FPC=$(PP)
+else
+FPC=ppc386
+endif
+endif
+override FPC:=$(subst $(SRCEXEEXT),,$(FPC))
+override FPC:=$(subst \,/,$(FPC))$(SRCEXEEXT)
+
+# Target OS
+ifndef OS_TARGET
+OS_TARGET:=$(shell $(FPC) -iTO)
+endif
+
+# Source OS
+ifndef OS_SOURCE
+OS_SOURCE:=$(shell $(FPC) -iSO)
+endif
+
+# Target CPU
+ifndef CPU_TARGET
+CPU_TARGET:=$(shell $(FPC) -iTP)
+endif
+
+# Source CPU
+ifndef CPU_SOURCE
+CPU_SOURCE:=$(shell $(FPC) -iSP)
+endif
+
+# FPC version
+ifndef FPC_VERSION
+FPC_VERSION:=$(shell $(FPC) -iV)
+endif
+
+export FPC OS_TARGET OS_SOURCE CPU_TARGET CPU_SOURCE FPC_VERSION
+
+#####################################################################
+# FPCDIR Setting
+#####################################################################
+
+# Test FPCDIR to look if the RTL dir exists
+ifdef FPCDIR
+override FPCDIR:=$(subst \,/,$(FPCDIR))
+ifeq ($(wildcard $(FPCDIR)/rtl),)
+ifeq ($(wildcard $(FPCDIR)/units),)
+override FPCDIR=wrong
+endif
+endif
+else
+override FPCDIR=wrong
+endif
+
+# Default FPCDIR
+ifeq ($(FPCDIR),wrong)
+override FPCDIR=../../..
+ifeq ($(wildcard $(FPCDIR)/rtl),)
+ifeq ($(wildcard $(FPCDIR)/units),)
+override FPCDIR=wrong
+endif
+endif
+endif
+
+# Detect FPCDIR
+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 $(FPCDIR)/rtl),)
+ifeq ($(wildcard $(FPCDIR)/units),)
+override FPCDIR:=$(FPCDIR)/..
+ifeq ($(wildcard $(FPCDIR)/rtl),)
+ifeq ($(wildcard $(FPCDIR)/units),)
+override FPCDIR=c:/pp
+endif
+endif
+endif
+endif
+endif
+endif
+
+ifndef PACKAGESDIR
+PACKAGESDIR=$(FPCDIR)/packages
+endif
+ifndef TOOLKITSDIR
+TOOLKITSDIR=
+endif
+ifndef COMPONENTSDIR
+COMPONENTSDIR=
+endif
+
+# Create units dir
+ifneq ($(FPCDIR),.)
+UNITSDIR=$(FPCDIR)/units/$(OS_TARGET)
+endif
+
+#####################################################################
+# User Settings
+#####################################################################
+
+
+# Targets
+
+override UNITOBJECTS+=dbf
+override EXAMPLEOBJECTS+=testdbf
+
+# Clean
+
+
+# Install
+
+UNITSUBDIR=fcl
+PACKAGENAME=fcl
+ZIPTARGET=install
+
+# Defaults
+
+override NEEDOPT=-S2 -Sh
+
+# Directories
+
+ifndef TARGETDIR
+TARGETDIR=../../$(OS_TARGET)
+endif
+
+# Packages
+
+override PACKAGES+=rtl
+
+# Libraries
+
+
+# Info
+
+INFOTARGET=fpc_infocfg fpc_infoobjects fpc_infoinstall 
+
+#####################################################################
+# Shell tools
+#####################################################################
+
+# echo
+ifndef ECHO
+ECHO:=$(strip $(wildcard $(addsuffix /gecho$(EXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO:=$(strip $(wildcard $(addsuffix /echo$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO:=echo
+ECHOE:=echo
+else
+ECHO:=$(firstword $(ECHO))
+ECHOE=$(ECHO) -E
+endif
+else
+ECHO:=$(firstword $(ECHO))
+ECHOE=$(ECHO) -E
+endif
+endif
+
+# To copy pograms
+ifndef COPY
+COPY:=cp -fp
+endif
+
+# Copy a whole tree
+ifndef COPYTREE
+COPYTREE:=cp -rfp
+endif
+
+# To move pograms
+ifndef MOVE
+MOVE:=mv -f
+endif
+
+# Check delete program
+ifndef DEL
+DEL:=rm -f
+endif
+
+# Check deltree program
+ifndef DELTREE
+DELTREE:=rm -rf
+endif
+
+# To install files
+ifndef INSTALL
+ifdef inUnix
+INSTALL:=install -c -m 644
+else
+INSTALL:=$(COPY)
+endif
+endif
+
+# To install programs
+ifndef INSTALLEXE
+ifdef inUnix
+INSTALLEXE:=install -c -m 755
+else
+INSTALLEXE:=$(COPY)
+endif
+endif
+
+# To make a directory.
+ifndef MKDIR
+ifdef inUnix
+MKDIR:=install -m 755 -d
+else
+MKDIR:=ginstall -m 755 -d
+endif
+endif
+
+export ECHO ECHOE COPY COPYTREE MOVE DEL DELTREE INSTALL INSTALLEXE MKDIR
+
+#####################################################################
+# Default Tools
+#####################################################################
+
+# assembler, redefine it if cross compiling
+ifndef AS
+AS=as
+endif
+
+# linker, but probably not used
+ifndef LD
+LD=ld
+endif
+
+# ppas.bat / ppas.sh
+ifdef inUnix
+PPAS=ppas.sh
+else
+ifdef inOS2
+PPAS=ppas.cmd
+else
+PPAS=ppas.bat
+endif
+endif
+
+# ldconfig to rebuild .so cache
+ifdef inUnix
+LDCONFIG=ldconfig
+else
+LDCONFIG=
+endif
+
+# ppumove
+ifndef PPUMOVE
+PPUMOVE:=$(strip $(wildcard $(addsuffix /ppumove$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(PPUMOVE),)
+PPUMOVE=
+else
+PPUMOVE:=$(firstword $(PPUMOVE))
+endif
+endif
+export PPUMOVE
+
+# ppufiles
+ifndef PPUFILES
+PPUFILES:=$(strip $(wildcard $(addsuffix /ppufiles$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(PPUFILES),)
+PPUFILES=
+else
+PPUFILES:=$(firstword $(PPUFILES))
+endif
+endif
+export PPUFILES
+
+# Look if UPX is found for go32v2 and win32. We can't use $UPX becuase
+# upx uses that one itself (PFV)
+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
+
+# ZipProg, you can't use Zip as the var name (PFV)
+ifndef ZIPPROG
+ZIPPROG:=$(strip $(wildcard $(addsuffix /zip$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ZIPPROG),)
+ZIPPROG=
+else
+ZIPPROG:=$(firstword $(ZIPPROG))
+endif
+endif
+export ZIPPROG
+
+ZIPOPT=-9
+ZIPEXT=.zip
+
+# Tar
+ifndef TARPROG
+TARPROG:=$(strip $(wildcard $(addsuffix /tar$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(TARPROG),)
+TARPROG=
+else
+TARPROG:=$(firstword $(TARPROG))
+endif
+endif
+export TARPROG
+
+ifeq ($(USETAR),bz2)
+TAROPT=vI
+TAREXT=.tar.bz2
+else
+TAROPT=vz
+TAREXT=.tar.gz
+endif
+
+#####################################################################
+# Default extensions
+#####################################################################
+
+# Default needed extensions (Go32v2,Linux)
+LOADEREXT=.as
+EXEEXT=.exe
+PPLEXT=.ppl
+PPUEXT=.ppu
+OEXT=.o
+ASMEXT=.s
+SMARTEXT=.sl
+STATICLIBEXT=.a
+SHAREDLIBEXT=.so
+RSTEXT=.rst
+FPCMADE=fpcmade
+
+# Go32v1
+ifeq ($(OS_TARGET),go32v1)
+PPUEXT=.pp1
+OEXT=.o1
+ASMEXT=.s1
+SMARTEXT=.sl1
+STATICLIBEXT=.a1
+SHAREDLIBEXT=.so1
+FPCMADE=fpcmade.v1
+endif
+
+# Go32v2
+ifeq ($(OS_TARGET),go32v2)
+FPCMADE=fpcmade.dos
+endif
+
+# Linux
+ifeq ($(OS_TARGET),linux)
+EXEEXT=
+HASSHAREDLIB=1
+FPCMADE=fpcmade.lnx
+endif
+
+# Linux
+ifeq ($(OS_TARGET),freebsd)
+EXEEXT=
+HASSHAREDLIB=1
+FPCMADE=fpcmade.freebsd
+endif
+
+# Win32
+ifeq ($(OS_TARGET),win32)
+PPUEXT=.ppw
+OEXT=.ow
+ASMEXT=.sw
+SMARTEXT=.slw
+STATICLIBEXT=.aw
+SHAREDLIBEXT=.dll
+FPCMADE=fpcmade.w32
+endif
+
+# OS/2
+ifeq ($(OS_TARGET),os2)
+PPUEXT=.ppo
+ASMEXT=.so2
+OEXT=.oo2
+SMARTEXT=.so
+STATICLIBEXT=.ao2
+SHAREDLIBEXT=.dll
+FPCMADE=fpcmade.os2
+endif
+
+# library prefix
+LIBPREFIX=lib
+ifeq ($(OS_TARGET),go32v2)
+LIBPREFIX=
+endif
+ifeq ($(OS_TARGET),go32v1)
+LIBPREFIX=
+endif
+
+# determine which .pas extension is used
+ifndef PASEXT
+ifdef EXEOBJECTS
+override TESTPAS:=$(strip $(wildcard $(addsuffix .pas,$(firstword $(EXEOBJECTS)))))
+else
+override TESTPAS:=$(strip $(wildcard $(addsuffix .pas,$(firstword $(UNITOBJECTS)))))
+endif
+ifeq ($(TESTPAS),)
+PASEXT=.pp
+else
+PASEXT=.pas
+endif
+endif
+
+
+# Check if the dirs really exists, else turn it off
+ifeq ($(wildcard $(UNITSDIR)),)
+UNITSDIR=
+endif
+ifeq ($(wildcard $(TOOLKITSDIR)),)
+TOOLKITSDIR=
+endif
+ifeq ($(wildcard $(PACKAGESDIR)),)
+PACKAGESDIR=
+endif
+ifeq ($(wildcard $(COMPONENTSDIR)),)
+COMPONENTSDIR=
+endif
+
+
+# PACKAGESDIR packages
+
+PACKAGERTL=1
+
+ifdef PACKAGERTL
+ifneq ($(wildcard $(FPCDIR)/rtl),)
+ifneq ($(wildcard $(FPCDIR)/rtl/$(OS_TARGET)),)
+PACKAGEDIR_RTL=$(FPCDIR)/rtl/$(OS_TARGET)
+else
+PACKAGEDIR_RTL=$(FPCDIR)/rtl
+endif
+ifeq ($(wildcard $(PACKAGEDIR_RTL)/$(FPCMADE)),)
+override COMPILEPACKAGES+=package_rtl
+package_rtl:
+	$(MAKE) -C $(PACKAGEDIR_RTL) all
+endif
+UNITDIR_RTL=$(PACKAGEDIR_RTL)
+else
+PACKAGEDIR_RTL=
+ifneq ($(wildcard $(UNITSDIR)/rtl),)
+ifneq ($(wildcard $(UNITSDIR)/rtl/$(OS_TARGET)),)
+UNITDIR_RTL=$(UNITSDIR)/rtl/$(OS_TARGET)
+else
+UNITDIR_RTL=$(UNITSDIR)/rtl
+endif
+else
+UNITDIR_RTL=
+endif
+endif
+ifdef UNITDIR_RTL
+override NEEDUNITDIR+=$(UNITDIR_RTL)
+endif
+endif
+
+
+#####################################################################
+# Default Directories
+#####################################################################
+
+# Linux and freebsd use unix dirs with /usr/bin, /usr/lib
+# When zipping use the target as default, when normal install then
+# use the source os as default
+ifdef ZIPNAME
+# Zipinstall
+ifeq ($(OS_TARGET),linux)
+UNIXINSTALLDIR=1
+endif
+ifeq ($(OS_TARGET),freebsd)
+UNIXINSTALLDIR=1
+endif
+else
+# Normal install
+ifeq ($(OS_SOURCE),linux)
+UNIXINSTALLDIR=1
+endif
+ifeq ($(OS_SOURCE),freebsd)
+UNIXINSTALLDIR=1
+endif
+endif
+
+# set the prefix directory where to install everything
+ifndef PREFIXINSTALLDIR
+ifdef UNIXINSTALLDIR
+PREFIXINSTALLDIR=/usr
+else
+PREFIXINSTALLDIR=/pp
+endif
+endif
+export PREFIXINSTALLDIR
+
+# Where to place the resulting zip files
+ifndef DESTZIPDIR
+DESTZIPDIR:=$(BASEDIR)
+endif
+export DESTZIPDIR
+
+#####################################################################
+# Install Directories
+#####################################################################
+
+# set the base directory where to install everything
+ifndef BASEINSTALLDIR
+ifdef UNIXINSTALLDIR
+BASEINSTALLDIR=$(PREFIXINSTALLDIR)/lib/fpc/$(FPC_VERSION)
+else
+BASEINSTALLDIR=$(PREFIXINSTALLDIR)
+endif
+endif
+
+# set the directory where to install the binaries
+ifndef BININSTALLDIR
+ifdef UNIXINSTALLDIR
+BININSTALLDIR=$(PREFIXINSTALLDIR)/bin
+else
+BININSTALLDIR=$(BASEINSTALLDIR)/bin/$(OS_TARGET)
+endif
+endif
+
+# set the directory where to install the units.
+ifndef UNITINSTALLDIR
+UNITINSTALLDIR=$(BASEINSTALLDIR)/units/$(OS_TARGET)
+ifdef UNITSUBDIR
+UNITINSTALLDIR:=$(UNITINSTALLDIR)/$(UNITSUBDIR)
+endif
+endif
+
+# Where to install shared libraries
+ifndef LIBINSTALLDIR
+ifdef UNIXINSTALLDIR
+LIBINSTALLDIR=$(PREFIXINSTALLDIR)/lib
+else
+LIBINSTALLDIR=$(UNITINSTALLDIR)
+endif
+endif
+
+# Where the source files will be stored
+ifndef SOURCEINSTALLDIR
+ifdef UNIXINSTALLDIR
+SOURCEINSTALLDIR=$(PREFIXINSTALLDIR)/src/fpc-$(FPC_VERSION)
+else
+SOURCEINSTALLDIR=$(BASEINSTALLDIR)/source
+endif
+ifdef SOURCESUBDIR
+SOURCEINSTALLDIR:=$(SOURCEINSTALLDIR)/$(SOURCESUBDIR)
+endif
+endif
+
+# Where the doc files will be stored
+ifndef DOCINSTALLDIR
+ifdef UNIXINSTALLDIR
+DOCINSTALLDIR=$(PREFIXINSTALLDIR)/doc/fpc-$(FPC_VERSION)
+else
+DOCINSTALLDIR=$(BASEINSTALLDIR)/doc
+endif
+endif
+
+# Where to install the examples, under linux we use the doc dir
+# because the copytree command will create a subdir itself
+ifndef EXAMPLEINSTALLDIR
+ifdef UNIXINSTALLDIR
+EXAMPLEINSTALLDIR=$(DOCINSTALLDIR)/examples
+else
+EXAMPLEINSTALLDIR=$(BASEINSTALLDIR)/examples
+endif
+ifdef EXAMPLESUBDIR
+EXAMPLEINSTALLDIR:=$(EXAMPLEINSTALLDIR)/$(EXAMPLESUBDIR)
+endif
+endif
+
+# Where the some extra (data)files will be stored
+ifndef DATAINSTALLDIR
+DATAINSTALLDIR=$(BASEINSTALLDIR)
+endif
+
+#####################################################################
+# Redirection
+#####################################################################
+
+ifndef REDIRFILE
+REDIRFILE=log
+endif
+
+ifdef REDIR
+ifndef inUnix
+override FPC=redir -eo $(FPC)
+endif
+# set the verbosity to max
+override FPCOPT+=-va
+override REDIR:= >> $(REDIRFILE)
+endif
+
+
+#####################################################################
+# Compiler Command Line
+#####################################################################
+
+# Load commandline OPTDEF and add FPC_CPU define
+override FPCOPTDEF:=-d$(CPU_TARGET)
+
+# Load commandline OPT and add target and unit dir to be sure
+ifneq ($(OS_TARGET),$(OS_SOURCE))
+override FPCOPT+=-T$(OS_TARGET)
+endif
+
+# User dirs should be first, so they are looked at first
+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
+
+# Smartlinking
+ifdef LINKSMART
+override FPCOPT+=-XX
+endif
+
+# Smartlinking creation
+ifdef CREATESMART
+override FPCOPT+=-CX
+endif
+
+# Debug
+ifdef DEBUG
+override FPCOPT+=-gl -dDEBUG
+endif
+
+# Release mode (strip, optimize and don't load ppc386.cfg)
+# 0.99.12b has a bug in the optimizer so don't use it by default
+ifdef RELEASE
+ifeq ($(FPC_VERSION),0.99.12)
+override FPCOPT+=-Xs -OGp3 -n
+else
+override FPCOPT+=-Xs -OG2p3 -n
+endif
+endif
+
+# Strip
+ifdef STRIP
+override FPCOPT+=-Xs
+endif
+
+# Optimizer
+ifdef OPTIMIZE
+override FPCOPT+=-OG2p3
+endif
+
+# Verbose settings (warning,note,info)
+ifdef VERBOSE
+override FPCOPT+=-vwni
+endif
+
+ifdef NEEDOPT
+override FPCOPT+=$(NEEDOPT)
+endif
+
+ifdef NEEDUNITDIR
+override FPCOPT+=$(addprefix -Fu,$(NEEDUNITDIR))
+endif
+
+ifdef UNITSDIR
+override FPCOPT+=-Fu$(UNITSDIR)
+endif
+
+# Target dirs and the prefix to use for clean/install
+ifdef TARGETDIR
+override FPCOPT+=-FE$(TARGETDIR)
+ifeq ($(TARGETDIR),.)
+override TARGETDIRPREFIX=
+else
+override TARGETDIRPREFIX=$(TARGETDIR)/
+endif
+endif
+ifdef UNITTARGETDIR
+override FPCOPT+=-FU$(UNITTARGETDIR)
+ifeq ($(UNITTARGETDIR),.)
+override UNITTARGETDIRPREFIX=
+else
+override UNITTARGETDIRPREFIX=$(TARGETDIR)/
+endif
+else
+ifdef TARGETDIR
+override UNITTARGETDIR=$(TARGETDIR)
+override UNITTARGETDIRPREFIX=$(TARGETDIRPREFIX)
+endif
+endif
+
+# Add commandline options last so they can override
+ifdef OPT
+override FPCOPT+=$(OPT)
+endif
+
+# Add defines from FPCOPTDEF to FPCOPT
+ifdef FPCOPTDEF
+override FPCOPT+=$(FPCOPTDEF)
+endif
+
+# Error file ?
+ifdef ERRORFILE
+override FPCOPT+=-Fr$(ERRORFILE)
+endif
+
+# Was a config file specified ?
+ifdef CFGFILE
+override FPCOPT+=@$(CFGFILE)
+endif
+
+# For win32 the options are passed using the environment FPCEXTCMD
+ifeq ($(OS_SOURCE),win32)
+override FPCEXTCMD:=$(FPCOPT)
+override FPCOPT:=!FPCEXTCMD
+export FPCEXTCMD
+endif
+
+# Compiler commandline
+override COMPILER:=$(FPC) $(FPCOPT)
+
+# also call ppas if with command option -s
+# but only if the OS_SOURCE and OS_TARGE are equal
+ifeq (,$(findstring -s ,$(COMPILER)))
+EXECPPAS=
+else
+ifeq ($(OS_SOURCE),$(OS_TARGET))
+EXECPPAS:=@$(PPAS)
+endif
+endif
+
+#####################################################################
+# Standard rules
+#####################################################################
+
+all: fpc_all
+
+debug: fpc_debug
+
+examples: fpc_examples
+
+test: fpc_test
+
+smart: fpc_smart
+
+shared: fpc_shared
+
+showinstall: fpc_showinstall
+
+install: fpc_install
+
+sourceinstall: fpc_sourceinstall
+
+exampleinstall: fpc_exampleinstall
+
+zipinstall: fpc_zipinstall
+
+zipsourceinstall: fpc_zipsourceinstall
+
+zipexampleinstall: fpc_zipexampleinstall
+
+clean: fpc_clean
+
+distclean: fpc_distclean
+
+cleanall: fpc_cleanall
+
+info: fpc_info
+
+.PHONY:  all debug examples test smart shared showinstall install sourceinstall exampleinstall zipinstall zipsourceinstall zipexampleinstall clean distclean cleanall info
+
+#####################################################################
+# Units
+#####################################################################
+
+.PHONY: fpc_units
+
+override ALLTARGET+=fpc_units
+
+override UNITPPUFILES=$(addsuffix $(PPUEXT),$(UNITOBJECTS))
+override INSTALLPPUFILES+=$(UNITPPUFILES)
+override CLEANPPUFILES+=$(UNITPPUFILES)
+
+fpc_units: $(UNITPPUFILES)
+
+#####################################################################
+# Examples
+#####################################################################
+
+.PHONY: fpc_examples fpc_test
+
+ifdef EXAMPLEOBJECTS
+override EXAMPLESOURCEFILES:=$(addsuffix $(PASEXT),$(EXAMPLEOBJECTS))
+override EXAMPLEFILES:=$(addsuffix $(EXEEXT),$(EXAMPLEOBJECTS))
+override EXAMPLEOFILES:=$(addsuffix $(OEXT),$(EXAMPLEOBJECTS)) $(addprefix $(LIBPREFIX),$(addsuffix $(STATICLIBEXT),$(EXAMPLEOBJECTS)))
+
+override CLEANEXEFILES+=$(EXAMPLEFILES) $(EXAMPLEOFILES)
+endif
+
+fpc_examples: all $(EXAMPLEFILES) $(addsuffix _all,$(EXAMPLEDIROBJECTS))
+
+fpc_test: examples
+
+#####################################################################
+# General compile rules
+#####################################################################
+
+.PHONY: fpc_packages fpc_all fpc_debug
+
+$(FPCMADE): $(ALLTARGET)
+	@$(ECHO) Compiled > $(FPCMADE)
+
+fpc_packages: $(COMPILEPACKAGES)
+
+fpc_all: fpc_packages $(FPCMADE)
+
+fpc_debug:
+	$(MAKE) all DEBUG=1
+
+# Search paths for .ppu if targetdir is set
+ifdef UNITTARGETDIR
+vpath %$(PPUEXT) $(UNITTARGETDIR)
+endif
+
+# General compile rules, available for both possible PASEXT
+
+.SUFFIXES: $(EXEEXT) $(PPUEXT) $(OEXT) .pas .pp
+
+%$(PPUEXT): %.pp
+	$(COMPILER) $< $(REDIR)
+	$(EXECPPAS)
+
+%$(PPUEXT): %.pas
+	$(COMPILER) $< $(REDIR)
+	$(EXECPPAS)
+
+%$(EXEEXT): %.pp
+	$(COMPILER) $< $(REDIR)
+	$(EXECPPAS)
+
+%$(EXEEXT): %.pas
+	$(COMPILER) $< $(REDIR)
+	$(EXECPPAS)
+
+#####################################################################
+# Library
+#####################################################################
+
+.PHONY: fpc_smart fpc_shared
+
+ifdef LIBVERSION
+LIBFULLNAME=$(LIBNAME).$(LIBVERSION)
+else
+LIBFULLNAME=$(LIBNAME)
+endif
+
+# Default sharedlib units are all unit objects
+ifndef SHAREDLIBUNITOBJECTS
+SHAREDLIBUNITOBJECTS:=$(UNITOBJECTS)
+endif
+
+fpc_smart:
+	$(MAKE) all LINKSMART=1 CREATESMART=1
+
+fpc_shared: all
+ifdef HASSHAREDLIB
+ifndef LIBNAME
+	@$(ECHO) "LIBNAME not set"
+else
+	$(PPUMOVE) $(SHAREDLIBUNITOBJECTS) -o$(LIBFULLNAME)
+endif
+else
+	@$(ECHO) "Shared Libraries not supported"
+endif
+
+#####################################################################
+# Install rules
+#####################################################################
+
+.PHONY: fpc_showinstall fpc_install
+
+ifdef EXTRAINSTALLUNITS
+override INSTALLPPUFILES+=$(addsuffix $(PPUEXT),$(EXTRAINSTALLUNITS))
+endif
+
+ifdef INSTALLPPUFILES
+override INSTALLPPUFILES:=$(addprefix $(UNITTARGETDIRPREFIX),$(INSTALLPPUFILES))
+ifdef PPUFILES
+INSTALLPPULINKFILES:=$(shell $(PPUFILES) -S -O $(INSTALLPPUFILES))
+else
+INSTALLPPULINKFILES:=$(wildcard $(subst $(PPUEXT),$(OEXT),$(INSTALLPPUFILES)) $(addprefix $(LIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(INSTALLPPUFILES))))
+endif
+override INSTALLPPULINKFILES:=$(addprefix $(UNITTARGETDIRPREFIX),$(INSTALLPPULINKFILES))
+endif
+
+ifdef INSTALLEXEFILES
+override INSTALLEXEFILES:=$(addprefix $(TARGETDIRPREFIX),$(INSTALLEXEFILES))
+endif
+
+fpc_showinstall: $(SHOWINSTALLTARGET)
+ifdef INSTALLEXEFILES
+	@$(ECHO) -e $(addprefix "\n"$(BININSTALLDIR)/,$(INSTALLEXEFILES))
+endif
+ifdef INSTALLPPUFILES
+	@$(ECHO) -e $(addprefix "\n"$(UNITINSTALLDIR)/,$(INSTALLPPUFILES))
+ifneq ($(INSTALLPPULINKFILES),)
+	@$(ECHO) -e $(addprefix "\n"$(UNITINSTALLDIR)/,$(INSTALLPPULINKFILES))
+endif
+ifneq ($(wildcard $(LIBFULLNAME)),)
+	@$(ECHO) $(LIBINSTALLDIR)/$(LIBFULLNAME)
+ifdef HASSHAREDLIB
+	@$(ECHO) $(LIBINSTALLDIR)/$(LIBNAME)
+endif
+endif
+endif
+ifdef EXTRAINSTALLFILES
+	@$(ECHO) -e $(addprefix "\n"$(DATAINSTALLDIR)/,$(EXTRAINSTALLFILES))
+endif
+
+fpc_install: $(INSTALLTARGET)
+# Create UnitInstallFiles
+ifdef INSTALLEXEFILES
+	$(MKDIR) $(BININSTALLDIR)
+# Compress the exes if upx is defined
+ifdef UPXPROG
+	-$(UPXPROG) $(INSTALLEXEFILES)
+endif
+	$(INSTALLEXE) $(INSTALLEXEFILES) $(BININSTALLDIR)
+endif
+ifdef INSTALLPPUFILES
+	$(MKDIR) $(UNITINSTALLDIR)
+	$(INSTALL) $(INSTALLPPUFILES) $(UNITINSTALLDIR)
+ifneq ($(INSTALLPPULINKFILES),)
+	$(INSTALL) $(INSTALLPPULINKFILES) $(UNITINSTALLDIR)
+endif
+ifneq ($(wildcard $(LIBFULLNAME)),)
+	$(MKDIR) $(LIBINSTALLDIR)
+	$(INSTALL) $(LIBFULLNAME) $(LIBINSTALLDIR)
+ifdef inUnix
+	ln -sf $(LIBFULLNAME) $(LIBINSTALLDIR)/$(LIBNAME)
+endif
+endif
+endif
+ifdef EXTRAINSTALLFILES
+	$(MKDIR) $(DATAINSTALLDIR)
+	$(INSTALL) $(EXTRAINSTALLFILES) $(DATAINSTALLDIR)
+endif
+
+#####################################################################
+# SourceInstall rules
+#####################################################################
+
+.PHONY: fpc_sourceinstall
+
+ifndef SOURCETOPDIR
+SOURCETOPDIR=$(BASEDIR)
+endif
+
+fpc_sourceinstall: clean
+	$(MKDIR) $(SOURCEINSTALLDIR)
+	$(COPYTREE) $(SOURCETOPDIR) $(SOURCEINSTALLDIR)
+
+#####################################################################
+# exampleinstall rules
+#####################################################################
+
+.PHONY: fpc_exampleinstall
+
+fpc_exampleinstall: $(addsuffix _clean,$(EXAMPLEDIROBJECTS))
+ifdef EXAMPLESOURCEFILES
+	$(MKDIR) $(EXAMPLEINSTALLDIR)
+	$(COPY) $(EXAMPLESOURCEFILES) $(EXAMPLEINSTALLDIR)
+endif
+ifdef EXAMPLEDIROBJECTS
+ifndef EXAMPLESOURCEFILES
+	$(MKDIR) $(EXAMPLEINSTALLDIR)
+endif
+	$(COPYTREE) $(addsuffix /*,$(EXAMPLEDIROBJECTS)) $(EXAMPLEINSTALLDIR)
+endif
+
+#####################################################################
+# Zip
+#####################################################################
+
+.PHONY: fpc_zipinstall
+
+# Create suffix to add
+ifndef PACKAGESUFFIX
+PACKAGESUFFIX=$(OS_TARGET)
+ifeq ($(OS_TARGET),go32v2)
+PACKAGESUFFIX=go32
+endif
+ifeq ($(OS_TARGET),win32)
+PACKAGESUFFIX=w32
+endif
+endif
+
+# Temporary path to pack a file
+ifndef PACKDIR
+ifndef inUnix
+PACKDIR=$(BASEDIR)/pack_tmp
+else
+PACKDIR=/tmp/fpc-pack
+endif
+endif
+
+# Maybe create default zipname from packagename
+ifndef ZIPNAME
+ifdef PACKAGENAME
+ZIPNAME=$(PACKAGEPREFIX)$(PACKAGENAME)$(PACKAGESUFFIX)
+endif
+endif
+
+# Use tar by default under linux
+ifndef USEZIP
+ifdef inUnix
+USETAR=1
+endif
+endif
+
+fpc_zipinstall:
+ifndef ZIPNAME
+	@$(ECHO) "Please specify ZIPNAME!"
+	@exit 1
+else
+	$(MAKE) $(ZIPTARGET) PREFIXINSTALLDIR=$(PACKDIR)
+ifdef USETAR
+	$(DEL) $(DESTZIPDIR)/$(ZIPNAME)$(TAREXT)
+	cd $(PACKDIR) ; $(TARPROG) cf$(TAROPT) $(DESTZIPDIR)/$(ZIPNAME)$(TAREXT) * ; cd $(BASEDIR)
+else
+	$(DEL) $(DESTZIPDIR)/$(ZIPNAME)$(ZIPEXT)
+	cd $(PACKDIR) ; $(ZIPPROG) -Dr $(ZIPOPT) $(DESTZIPDIR)/$(ZIPNAME)$(ZIPEXT) * ; cd $(BASEDIR)
+endif
+	$(DELTREE) $(PACKDIR)
+endif
+
+.PHONY:  fpc_zipsourceinstall
+
+fpc_zipsourceinstall:
+	$(MAKE) fpc_zipinstall ZIPTARGET=sourceinstall PACKAGESUFFIX=src
+
+.PHONY:  fpc_zipexampleinstall
+
+fpc_zipexampleinstall:
+	$(MAKE) fpc_zipinstall ZIPTARGET=exampleinstall PACKAGESUFFIX=exm
+
+#####################################################################
+# Clean rules
+#####################################################################
+
+.PHONY: fpc_clean fpc_cleanall fpc_distclean
+
+ifdef EXEFILES
+override CLEANEXEFILES:=$(addprefix $(TARGETDIRPREFIX),$(CLEANEXEFILES))
+endif
+
+ifdef EXTRACLEANUNITS
+override CLEANPPUFILES+=$(addsuffix $(PPUEXT),$(EXTRACLEANUNITS))
+endif
+
+ifdef CLEANPPUFILES
+override CLEANPPUFILES:=$(addprefix $(UNITTARGETDIRPREFIX),$(CLEANPPUFILES))
+# Get the .o and .a files created for the units
+ifdef PPUFILES
+CLEANPPULINKFILES:=$(shell $(PPUFILES) $(CLEANPPUFILES))
+else
+CLEANPPULINKFILES:=$(wildcard $(subst $(PPUEXT),$(OEXT),$(CLEANPPUFILES)) $(addprefix $(LIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(CLEANPPUFILES))))
+endif
+override CLEANPPULINKFILES:=$(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 EXTRACLEANFILES
+	-$(DEL) $(EXTRACLEANFILES)
+endif
+ifdef LIBNAME
+	-$(DEL) $(LIBNAME) $(LIBFULLNAME)
+endif
+	-$(DEL) $(FPCMADE) $(PPAS) link.res $(FPCEXTFILE) $(REDIRFILE)
+
+fpc_distclean: fpc_clean
+
+# Also run clean first if targetdir is set. Unittargetdir is always
+# set if targetdir or unittargetdir is specified
+ifdef UNITTARGETDIR
+TARGETDIRCLEAN=fpc_clean
+endif
+
+fpc_cleanall: $(CLEANTARGET) $(TARGETDIRCLEAN)
+ifdef CLEANEXEFILES
+	-$(DEL) $(CLEANEXEFILES)
+endif
+	-$(DEL) *$(OEXT) *$(PPUEXT) *$(RSTEXT) *$(ASMEXT) *$(STATICLIBEXT) *$(SHAREDLIBEXT) *$(PPLEXT)
+	-$(DELTREE) *$(SMARTEXT)
+	-$(DEL) $(FPCMADE) $(PPAS) link.res $(FPCEXTFILE) $(REDIRFILE)
+
+#####################################################################
+# Info rules
+#####################################################################
+
+.PHONY: fpc_info fpc_cfginfo fpc_objectinfo fpc_toolsinfo fpc_installinfo \
+	fpc_dirinfo
+
+fpc_info: $(INFOTARGET)
+
+fpc_infocfg:
+	@$(ECHO)
+	@$(ECHO)  == Configuration info ==
+	@$(ECHO)
+	@$(ECHO)  FPC....... $(FPC)
+	@$(ECHO)  Version... $(FPC_VERSION)
+	@$(ECHO)  CPU....... $(CPU_TARGET)
+	@$(ECHO)  Source.... $(OS_SOURCE)
+	@$(ECHO)  Target.... $(OS_TARGET)
+	@$(ECHO)
+
+fpc_infoobjects:
+	@$(ECHO)
+	@$(ECHO)  == Object info ==
+	@$(ECHO)
+	@$(ECHO)  LoaderObjects..... $(LOADEROBJECTS)
+	@$(ECHO)  UnitObjects....... $(UNITOBJECTS)
+	@$(ECHO)  ExeObjects........ $(EXEOBJECTS)
+	@$(ECHO)
+	@$(ECHO)  ExtraCleanUnits... $(EXTRACLEANUNITS)
+	@$(ECHO)  ExtraCleanFiles... $(EXTRACLEANFILES)
+	@$(ECHO)
+	@$(ECHO)  ExtraInstallUnits. $(EXTRAINSTALLUNITS)
+	@$(ECHO)  ExtraInstallFiles. $(EXTRAINSTALLFILES)
+	@$(ECHO)
+
+fpc_infoinstall:
+	@$(ECHO)
+	@$(ECHO)  == Install info ==
+	@$(ECHO)
+ifdef DATE
+	@$(ECHO)  DateStr.............. $(DATESTR)
+endif
+ifdef PACKAGEPREFIX
+	@$(ECHO)  PackagePrefix........ $(PACKAGEPREFIX)
+endif
+ifdef PACKAGENAME
+	@$(ECHO)  PackageName.......... $(PACKAGENAME)
+endif
+	@$(ECHO)  PackageSuffix........ $(PACKAGESUFFIX)
+	@$(ECHO)
+	@$(ECHO)  BaseInstallDir....... $(BASEINSTALLDIR)
+	@$(ECHO)  BinInstallDir........ $(BININSTALLDIR)
+	@$(ECHO)  LibInstallDir........ $(LIBINSTALLDIR)
+	@$(ECHO)  UnitInstallDir....... $(UNITINSTALLDIR)
+	@$(ECHO)  SourceInstallDir..... $(SOURCEINSTALLDIR)
+	@$(ECHO)  DocInstallDir........ $(DOCINSTALLDIR)
+	@$(ECHO)  DataInstallDir....... $(DATAINSTALLDIR)
+	@$(ECHO)
+	@$(ECHO)  DestZipDir........... $(DESTZIPDIR)
+	@$(ECHO)  ZipName.............. $(ZIPNAME)
+	@$(ECHO)
+
+#####################################################################
+# Local Makefile
+#####################################################################
+
+ifneq ($(wildcard fpcmake.loc),)
+include fpcmake.loc
+endif
+

+ 17 - 0
fcl/db/dbase/Makefile.fpc

@@ -0,0 +1,17 @@
+#
+# Makefile.fpc for interbase.pp units
+
+[targets]
+units=dbf
+examples=testdbf
+
+[require]
+options=-S2 -Sh
+
+[install]
+unitsubdir=fcl
+packagename=fcl
+
+[dirs]
+fpcdir=../../..
+targetdir=../../$(OS_TARGET)

+ 2896 - 0
fcl/db/dbase/dbf.pas

@@ -0,0 +1,2896 @@
+unit dbf;
+{===============================================================================
+||         TDbf Component         ||         http://tdbf.netfirms.com         ||
+===============================================================================}
+interface
+
+uses
+{$ifdef fpc}
+  SysUtils, Classes, db;
+{$else}
+  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+  Db,  DsgnIntf, ExptIntf;
+{$endif}  
+// If you got a compilation error here or asking for dsgntf.pas, then just add
+// this file in your project:
+// dsgnintf.pas in 'C:\Program Files\Borland\Delphi5\Source\Toolsapi\dsgnintf.pas'
+
+const
+  _MAJOR_VERSION = 3;
+  _MINOR_VERSION = 007;
+
+
+{$ifdef VER100}      // Delphi 3
+   {$define DELPHI_3}
+{$endif}
+
+{$ifdef VER110}      // CBuilder 3
+   {$define DELPHI_3}
+{$endif}
+
+{$ifdef linux}
+  DirSeparator = '/';
+{$else}
+  DirSeparator = '\';
+{$endif}  
+
+//====================================================================
+// Delphi is a bit to permissive for me,  I mean protected doesn't work within
+// one unit. So i decided that convention:
+//    private member begins by '_'
+// It's forbidden to access any '_something' except from the class where it
+// is defined. To check that, I just have to look for '._' anywhere in the code.
+//====================================================================
+type
+
+//====================================================================
+//=== Common exceptions and constants
+//====================================================================
+  EBinaryDataSetError = class (Exception);
+  EFieldToLongError = class (Exception);
+
+  xBaseVersion = (xBaseIII,xBaseIV,xBaseV);
+
+//====================================================================
+//=== Utility classes
+//====================================================================
+  TPagedFile = class(TObject)
+  protected
+    Stream : TStream;
+    HeaderSize : Integer;
+    RecordSize : Integer;
+    _cntuse:integer;
+    _Filename:string;
+  public
+    constructor Create(const FileName: string; Mode: Word);
+    destructor Destroy; override;
+
+    procedure Release;
+    function CalcRecordCount:Integer;
+    procedure _Seek(page:Integer);
+    procedure ReadRecord(IntRecNum:Integer;Buffer:Pointer);
+    procedure WriteRecord(IntRecNum:Integer;Buffer:Pointer);
+  end;
+//====================================================================
+//=== Dbf support (first part)
+//====================================================================
+  rDbfHdr = record
+    VerDBF      : byte;   // 0
+    Year        : byte;   // 1
+    Month       : byte;   // 2
+    Day         : byte;   // 3
+    RecordCount : Integer;  // 4-7
+    FullHdrSize : word;   // 8-9
+    RecordSize  : word;   // 10-11
+    Dummy1      : Word;   // 12-13
+    IncTrans    : byte;   // 14
+    Encrypt     : byte;   // 15
+    Dummy2      : Integer; // 16-19
+    Dummy3      : array[20..27] of byte; // 20-27
+    MDXFlag     : char; // 28
+    Language    : char; // 29
+    dummy4      : word; // 30-31
+  end;
+//====================================================================
+  TMyFieldInfo = class
+  public
+    FieldName:string;
+    Size:Integer;
+    Prec:Integer;
+    Offset:Integer;
+  end;
+//====================================================================
+  TDbfFile = class(TPagedFile)
+  protected
+    _RecordBufferSize:integer;
+    _DataHdr : rDbfHdr;
+    _DbfVersion : xBaseVersion;
+    _MyFieldInfos: TList;
+  public
+    constructor Create(const FileName: string; Mode: Word);
+    destructor Destroy; override;
+    function RecordCount:integer;
+    procedure CreateFieldDefs(FieldDefs:TFieldDefs);
+    procedure ClearMyFieldInfos;
+    procedure DbfFile_CreateTable(FieldDefs:TFieldDefs);
+    procedure DbfFile_PackTable;
+    function GetFieldInfo(FieldName:string):TMyFieldInfo;
+    function GetFieldData(Column:Integer;DataType:TFieldType; Src,Dst: Pointer): Boolean;
+    procedure SetFieldData(Column:integer;DataType:TFieldType; Src,Dst: Pointer);
+    procedure WriteHeader;
+
+  end;
+//====================================================================
+//=== Index support
+//====================================================================
+  TIndex = class;
+//====================================================================
+  rNdxHdr = record
+    startpage : Integer; // 0..3
+    nbPage : Integer; // 4..7
+    keyformat: Char; //8
+    keytype : char; //9
+    dummy : Word; // 10..11
+    keylen : Word; // 12..13
+    nbkey : Word; // 14..15
+    skeytype : Word; // 16..17
+    keyreclen : Word; // 18..19
+    dummy2 : Word; // 20..21
+    dummy3 : Byte; // 22
+    Unique : Byte; // 23
+    KeyDesc : array[0..255] of char; // 24...
+  end;
+
+  rMdxTag = record
+    pageno      : Integer; // 0..3
+    tagname      : array [0..11] of char; // 4..14
+    keyformat    : byte; // 15
+    forwardTag1  : char; // 16
+    forwardTag2 : byte; // 17
+    backwardTag : byte; // 18
+    dummy       : byte; // 19
+    keytype     : byte; // 20
+  end;
+
+  NdxKeyType = (N,C);
+  PNdxPage  = ^rNdxPage;
+  rNdxPage  = record
+    NbEntries : longint;  //  0..3 lower page
+    Entries   : ARRAY [0..507] OF char;
+  end;
+
+  PNdxentry  = ^rNdxentry;
+  rNdxentry  = record
+    _LowerPage : longint;  //  0..3 lower page
+    RecNo     : Longint;  //  4..7 recno
+    case NdxKeyType of
+      N: ( NKey: double);
+      C: ( CKey: array [0..503] of char);
+  end;
+//====================================================================
+  rMdxHdr = record
+    MdxHdr   : byte;       // 0
+    Year        : byte;       // 1
+    Month       : byte;       // 2
+    Day         : byte;      // 3
+    FileName    : array[0..15] of char; // 4..19 of byte
+    BlockSize    : word; // 20 21
+    BlockAdder  : word; // 22 23
+    IndexFlag   : byte; // 24
+    NoTag       : byte; // 25
+    TagSize     : byte; // 26
+    Dummy1      : byte; // 27
+    TagUsed     : word; // 28..29
+    Dummy2      : word; // 30..31
+    NbPage      : Integer; // 32..35
+    FreePage    : Integer; // 36..39
+    BlockFree   : Integer; // 40..43
+    UpdYear     : byte; // 44
+    UpdMonth    : byte; // 45
+    UpdDay      : byte; // 46
+  end;
+//====================================================================
+  TIndexFile = class(TPagedFile)
+  protected
+    _IndexVersion : xBaseVersion;
+    _MdxHdr : rMdxHdr;
+  public
+    constructor Create(const FileName: string; Mode: Word);
+    destructor Destroy; override;
+  end;
+//====================================================================
+  PIndexPosInfo = ^TIndexPage;
+  TIndexPage = class
+  protected
+    _Index : TIndex;
+    _PageNo : Integer;
+    _EntryNo : Integer;
+    Entry : PNdxentry;
+    _LowerLevel : TIndexPage;
+    _UpperLevel : TIndexPage;
+    _PageBuff:rNdxPage;
+
+    procedure LocalFirst;
+    procedure LocalLast;
+    function  LocalPrev:boolean;
+    function  LocalNext:boolean;
+    function  LastEntryNo:integer;
+    function  LocalInsert(Recno:Integer; Buffer:PChar; LowerPage:integer):boolean;
+    function  LocalDelete:boolean;
+
+    function  GetPEntry(EntryNo:integer):PNdxEntry;
+    procedure First;
+    procedure Last;
+    function Prev:boolean;
+    function Next:boolean;
+    procedure Write;
+    procedure AddNewLevel;
+  public
+    constructor Create(Parent:TIndex);
+    destructor Destroy; override;
+
+    procedure SetPageNo(page:Integer);
+    procedure SetEntryNo(entryno:Integer);
+    procedure WritePage(Page:integer);
+    function FindNearest(Recno:integer; Key:PChar):integer;
+    function Insert(Recno:integer; Buffer:pchar; LowerPage:integer):boolean;
+    procedure SetEntry(Recno:integer; key:pchar; LowerPage:integer);
+    function Delete:boolean;
+    function LowerLevel : TIndexPage;
+  end;
+//====================================================================
+  TIndex = class(TObject)
+  protected
+    _IndexFile:TIndexFile;
+    _NdxHdr:rNdxHdr;
+    _Root:TIndexPage;
+    _TagPosition:Integer;
+    _FieldPos : integer;
+    _FieldLen : integer;
+    _NbLevel : integer;
+    _RootPage: integer;
+
+    function Pos:TIndexPage;
+  public
+    IndexRecNo:integer;
+    function Prev:boolean;
+    function Next:boolean;
+    procedure First;
+    procedure Last;
+    function Find(Recno:integer; Buffer:PChar; var pPos:TIndexPage):integer;
+    procedure Insert(Recno:integer; Buffer:PChar);
+    function Delete:boolean;
+    procedure GotoKey(Recno:integer; Buffer:PChar);
+    procedure Update(Recno: integer; PrevBuffer,NewBuffer: PChar);
+//    procedure ResyncInd;
+    function GetRealRecNo: Integer;
+    constructor Create(Parent:TIndexFile; RootPage:integer;CreateIt:boolean);
+    procedure InitFieldDef(dbfFile:TDbfFile;FieldDesc:string);
+    destructor Destroy; override;
+// optionnal
+    function GuessRecordCount: Integer;
+    function GuessRecNo: Integer;
+  end;
+//====================================================================
+//=== Memo and binary fields support
+//====================================================================
+  rDbtHdr = record
+    NextBlock:Longint;
+    Dummy : array [4..7] of byte;
+    _dbfFile : array [0..7] of Byte; //8..15
+    bVer : Byte; //16
+    Dummy2 : array [17..19] of byte;
+    BlockLen:  Word;
+  end;
+//====================================================================
+  TDbtFile = class(TPagedFile)
+  protected
+    _DbtVersion:xBaseVersion;
+    _MemoHdr:rDbtHdr;
+  public
+    constructor Create(const FileName: string; Mode: Word; Ver:xBaseVersion);
+    procedure ReadMemo(recno:Integer;Dst:TStream);
+    procedure WriteMemo(var MemoRecno:Integer;ReadSize:Integer;Src:TStream);
+  end;
+//====================================================================
+  TMyBlobFile = class(TMemoryStream)
+  public
+    Mode: TBlobStreamMode;
+    Field:TField;
+    MemoRecno:Integer;
+    ReadSize:Integer;
+    constructor Create(ModeVal:TBlobStreamMode; FieldVal:TField);
+    destructor destroy;  override;
+  end;
+//====================================================================
+//=== Dbf support 2
+//====================================================================
+  rFieldHdrIII = record
+    FieldName   : array[0..10] of char;
+    FieldType   : char; // 11
+    Dummy        : array[12..15] of byte;
+    FieldSize   : byte; // 16
+    FieldPrecision  : byte; //17
+    dummy2      : array[18..31] of byte;
+  end;
+//====================================================================
+  rFieldHdrV = record
+    FieldName   : array[0..10] of char;
+    Dummy0        : array[11..31] of byte;
+    FieldType   : char; // 32
+    FieldSize   : byte; // 33
+    FieldPrecision  : byte; //34
+    dummy2      : array[35..47] of byte;
+  end;
+//====================================================================
+  PBookMarkData = ^rBookMarkData;
+  rBookmarkData = record
+    RecNo:longint;
+  end;
+//====================================================================
+  rBeforeRecord = record
+    BookmarkData: rBookmarkData;
+    BookmarkFlag: TBookmarkFlag;
+    //... record come here
+  end;
+//====================================================================
+  pDbfRecord = ^rDbfRecord;
+  rDbfRecord = record
+    BookmarkData: rBookmarkData;
+    BookmarkFlag: TBookmarkFlag;
+    DeletedFlag : char;
+    Fields : array[0..4000] of char;
+  end;
+//====================================================================
+  PRecInfo = ^TRecInfo;
+  TRecInfo = record
+    Bookmark: Longint;
+    IdxBookmark: Longint;
+    BookmarkFlag: TBookmarkFlag;
+  end;
+//====================================================================
+  pRecordHdr = ^tRecordHdr;
+  tRecordHdr = record
+    DeletedFlag : char;
+  end;
+
+// and at LEAST the most useful class : TDbf
+//====================================================================
+  TDbf = class(TDataSet)
+  private
+    _ShowDeleted:boolean;
+    _TableName: string;    // table path and file name
+    _RunTimePath: string;    // table path and file name
+    _DesignTimePath: string;    // table path and file name
+    _ReadOnly : Boolean;
+    _FilterBuffer:pchar;
+    _PrevBuffer:pchar;
+    _IndexFiles:TStrings;
+  protected
+    function _FullRecordSize:integer;
+    function _FilterRecord(Buffer: PChar): Boolean;
+    procedure _OpenFiles(CreateIt:boolean);
+    procedure _CloseFiles;
+    procedure _ResyncIndexes(Buffer: PChar);
+    function _GetIndexName: string;
+    procedure _SetIndexName(const Value: string);
+    function _GetIndex(filename:string):TIndex;
+    function _GetPath:string;
+    function _ComponentInfo:string;
+  public
+    { my own methods and properties}
+    { most looks like ttable functions but they are not tdataset related
+     I use the same syntax to facilitate the conversion between bde and tdbf  }
+    easyfilter:string;
+    procedure CreateTable; //(FieldDefs:TFieldDefs);
+    procedure DeleteIndex(const AName: string);
+    property IndexName: string read _GetIndexName write _SetIndexName;
+
+{$ifdef DELPHI_3}
+    procedure AddIndex(const IndexName, Fields: String; Options: TIndexOptions);
+{$else}
+{$ifndef FPC}
+    procedure AddIndex(const IndexName, Fields: String; Options: TIndexOptions; const DescFields: String='');
+{$else}
+    procedure AddIndex(const AnIndexName, IndexFields: String; Options: TIndexOptions);
+    procedure AddIndex(const AnIndexName, IndexFields: String; Options: TIndexOptions; const DescFields: String);
+ 
+{$endif}    
+{$endif}
+    procedure CloseIndexFile(const IndexFileName: string);
+    procedure OpenIndexFile(AnIndexName:string);
+    procedure PackTable;
+  public
+    { abstract methods }
+    function GetFieldData(Field: TField; Buffer: Pointer): Boolean; override; {virtual abstract}
+    {virtual methods (mostly optionnal) }
+    function CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream; override; {virtual}
+{$ifdef DELPHI_3}
+    procedure Translate(Src, Dest: PChar; ToOem: Boolean); override; {virtual}
+{$else}
+{$ifdef fpc}
+    procedure Translate(Src, Dest: PChar; ToOem: Boolean); override; {virtual}
+{$else}
+    function Translate(Src, Dest: PChar; ToOem: Boolean): Integer; override; {virtual}
+{$endif}  
+{$endif}
+    procedure ClearCalcFields(Buffer : PChar); override;
+  protected
+    { abstract methods }
+    function AllocRecordBuffer: PChar; override; {virtual abstract}
+    procedure FreeRecordBuffer(var Buffer: PChar); override; {virtual abstract}
+    procedure GetBookmarkData(Buffer: PChar; Data: Pointer); override; {virtual abstract}
+    function GetBookmarkFlag(Buffer: PChar): TBookmarkFlag; override; {virtual abstract}
+    function GetRecord(Buffer: PChar; GetMode: TGetMode; DoCheck: Boolean): TGetResult; override; {virtual abstract}
+    function GetRecordSize: Word; override; {virtual abstract}
+    procedure InternalAddRecord(Buffer: Pointer; DoAppend: Boolean); override; {virtual abstract}
+    procedure InternalClose; override; {virtual abstract}
+    procedure InternalDelete; override; {virtual abstract}
+    procedure InternalFirst; override; {virtual abstract}
+    procedure InternalGotoBookmark(ABookmark: Pointer); override; {virtual abstract}
+    procedure InternalHandleException; override; {virtual abstract}
+    procedure InternalInitFieldDefs; override; {virtual abstract}
+    procedure InternalInitRecord(Buffer: PChar); override; {virtual abstract}
+    procedure InternalLast; override; {virtual abstract}
+    procedure InternalOpen; override; {virtual abstract}
+    procedure InternalPost; override; {virtual abstract}
+    procedure InternalSetToRecord(Buffer: PChar); override; {virtual abstract}
+    function IsCursorOpen: Boolean; override; {virtual abstract}
+    procedure SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag); override; {virtual abstract}
+    procedure SetBookmarkData(Buffer: PChar; Data: Pointer); override; {virtual abstract}
+    procedure SetFieldData(Field: TField; Buffer: Pointer); override; {virtual abstract}
+    {virtual methods (mostly optionnal) }
+
+    function GetRecordCount: Integer; override; {virtual}
+    function GetRecNo: Integer; override; {virtual}
+    procedure SetRecNo(Value: Integer); override; {virual}
+
+  public
+    constructor Create(AOwner: TComponent); override;
+    destructor Destroy; override;
+
+  published
+    property ComponentInfo: string  read _ComponentInfo;
+    property TableName: string  read _TableName write _TableName;
+    property RunTimePath: string  read _RunTimePath write _RunTimePath;
+    property DesignTimePath: string  read _DesignTimePath write _DesignTimePath;
+    property ReadOnly : Boolean read _ReadOnly write _Readonly default False;
+    property ShowDeleted:boolean read _ShowDeleted write _ShowDeleted;
+    // redeclared data set properties
+    property Active;
+    property Filtered;
+    property BeforeOpen;
+    property AfterOpen;
+    property BeforeClose;
+    property AfterClose;
+    property BeforeInsert;
+    property AfterInsert;
+    property BeforeEdit;
+    property AfterEdit;
+    property BeforePost;
+    property AfterPost;
+    property BeforeCancel;
+    property AfterCancel;
+    property BeforeDelete;
+    property AfterDelete;
+    property BeforeScroll;
+    property AfterScroll;
+    property OnCalcFields;
+    property OnDeleteError;
+    property OnEditError;
+    property OnFilterRecord;
+    property OnNewRecord;
+    property OnPostError;
+
+//my datas....
+  protected
+    _IsCursorOpen:boolean;
+    _PhysicalRecno:integer;
+    _CurIndex: TIndex;
+    _Indexes:TList;      // index
+    _indexFile : TIndexFile;
+    _dbtFile : TDbtFile;
+  public
+    _dbfFile:TDbfFile;
+    property PhysicalRecno:integer read _PhysicalRecno;
+    function _RecordDataSize:integer;
+  end;
+
+{$ifndef fpc}
+procedure Register;
+{$endif}
+
+var
+  tDbf_TrimFields : boolean;
+
+implementation
+
+var
+    _PagedFiles : TList;
+
+//====================================================================
+// Some types and consts which are not useful in the interface.
+//====================================================================
+(*
+ * tSmallint  16 bits = -32768 to 32767
+ *                      123456 = 6 digit max
+ * ftInteger  32 bits = -2147483648 to 2147483647
+ *                      12345678901 = 11 digits max
+ * ftLargeInt 64 bits = -9223372036854775808 to 9223372036854775807
+ *                      12345678901234567890 = 20 digits max
+ *)
+const
+  DIGITS_SMALLINT = 6;
+  DIGITS_INTEGER = 11;
+  DIGITS_LARGEINT = 20;
+  sDBF_DEC_SEP= '.';
+
+type
+  rAfterHdrIII = record // Empty
+  end;
+
+  rAfterHdrV = record
+    Dummy   : array[32..67] of byte;
+  end;
+
+  PMdxTag = ^rMdxTag;
+
+  rMdxTagHdr = record
+    RootPage        : longint;// 0..3
+    FilePages        : longint;// 4..7
+    KeyFormat        : byte;   // 8
+    KeyType          : char;   // 9
+    dummy            : word;   // 10..11
+    IndexKeyLength   : word;   // 12..13
+    MaxNbKeys       : word;   // 14..15
+    SecondKeyType   : word;   // 16..17
+    IndexKeyItemLen  : word;   // 18..19
+    dummy2           : array [20..22] of byte;
+    UniqueFlag      : byte;   // 23
+  end;
+
+
+  rAfterHdrV3 = record
+    Dummy   : array[12..31] of byte;
+  end;
+
+  rAfterHdrV4 = record
+    Dummy   : array[12..67] of byte;
+  end;
+
+  rFieldHdrV3 = record
+    FieldName   : array[0..10] of char;
+    FieldType   : char; // 11
+    Dummy        : array[12..15] of byte;
+    FieldSize   : byte; // 16
+    FieldPrecision  : byte; //17
+    dummy2      : array[18..31] of byte;
+  end;
+
+  rFieldHdrV4 = record
+    FieldName   : array[0..10] of char;
+    Dummy0        : array[11..31] of byte;
+    FieldType   : char; // 32
+    FieldSize   : byte; // 33
+    FieldPrecision  : byte; //34
+    dummy2      : array[35..47] of byte;
+  end;
+  PDouble = ^double;
+//====================================================================
+// Now some common functions and procedure
+//====================================================================
+// ****************************************************************************
+// International separator
+// thanks to Bruno Depero from Italy
+// and Andreas Wöllenstein from Denmark
+
+function DbfStrToFloat(s: string): Extended;
+var iPos: integer;
+     eValue: extended;
+begin
+    iPos:= Pos(sDBF_DEC_SEP, s);
+    if iPos> 0 then
+      s[iPos]:= DecimalSeparator;
+{$ifndef fpc}
+    if TextToFloat(pchar(s), eValue, fvExtended) then
+{$else}
+                Val(s,eValue,Ipos);
+                If Ipos=0 then
+{$endif}
+      Result:= eValue
+    else Result:= 0;
+end;
+
+function FloatToDbfStr(f: Extended; size, prec: integer): string;
+var iPos: integer;
+begin
+    Result:= FloatToStrF(f, ffFixed, Size, prec);
+    iPos:= Pos(DecimalSeparator, Result);
+    if iPos> 0 then
+      Result[iPos]:= sDBF_DEC_SEP;
+end;
+
+procedure MyMove(Source, Dest:PChar; Count: Integer);
+var
+  c:char;
+  i:integer;
+begin
+  i:=0;
+  while i<Count do begin
+    c:=PChar(Source)[i];
+    if c=#0 then break;
+    PChar(Dest)[i]:=c;
+    Inc(i);
+  end;
+  while i<Count do begin
+    PChar(Dest)[i]:=' ';
+    Inc(i);
+  end;
+end;
+//====================================================================
+// TPagedFile
+//====================================================================
+function GetPagedFile(FileName: string):TPagedFile;
+var
+  idx:integer;
+  idf:TPagedFile;
+begin
+  FileName:=LowerCase(FileName);
+  for idx:=0 to _PagedFiles.Count-1 do begin
+    idf:= TPagedFile(_PagedFiles[idx]);
+    if idf._FileName=FileName then begin
+      result:=idf;
+      exit;
+    end;
+  end;
+  result:=nil;
+end;
+
+procedure TPagedFile.Release;
+begin
+  dec(_cntuse);
+  if _cntuse<=0 then begin
+    _PagedFiles.Delete(_PagedFiles.IndexOf(self));
+    Free;
+  end;
+end;
+
+function TPagedFile.CalcRecordCount:Integer;
+begin
+  if RecordSize = 0 then Result:=0
+  else Result:=(Stream.Size - HeaderSize) div RecordSize;
+end;
+
+constructor TPagedFile.Create(const FileName: string; Mode: Word);
+begin
+  if filename='' then Stream:=TMemoryStream.Create()
+  else begin
+    Stream:=TFileStream.Create(FileName,Mode);
+  end;
+  HeaderSize:=0;
+  RecordSize:=0;
+  _cntuse:=0;
+  _filename:=lowercase(filename);
+  _PagedFiles.Add(Self);
+end;
+
+destructor TPagedFile.Destroy;
+begin
+  Stream.Free;
+  Stream:=nil;
+  inherited;
+end;
+
+procedure TPagedFile._Seek(page:Integer);
+var
+  p:Integer;
+begin
+  p:=HeaderSize + (RecordSize * page );
+  Stream.Position := p;
+end;
+
+Procedure TPagedFile.ReadRecord(IntRecNum:Integer; Buffer:Pointer);
+begin
+  _Seek(IntRecNum);
+  Stream.Read(Buffer^,RecordSize);
+end;
+
+procedure TPagedFile.WriteRecord(IntRecNum:Integer; Buffer:Pointer);
+begin
+  _Seek(IntRecNum);
+  Stream.Write(Buffer^, RecordSize);
+end;
+
+//====================================================================
+// TDbfFile
+//====================================================================
+constructor TDbfFile.Create(const FileName: string; Mode: Word);
+var
+  lRecordCount:Integer;
+begin
+  _MyFieldInfos:=TList.Create;
+  // check if the file exists
+  inherited Create(Filename, Mode);
+
+
+  if Mode = fmCreate then begin
+    FillChar(_DataHdr,sizeof(_DataHdr),0);
+    HeaderSize:=0;
+    RecordSize:=0;
+    _DataHdr.VerDBF:=$03; // Default version xBaseIV without memo
+    _DataHdr.Language:='X';
+  end else begin
+    Stream.Seek(0,soFromBeginning);
+    Stream.ReadBuffer (_DataHdr, SizeOf(_DataHdr));
+    case _DataHdr.VerDBF of
+    $03,$83:          _DbfVersion:=xBaseIII;
+    $04,$8B,$8E,$7B:  _DbfVersion:=xBaseIV;
+    $05 :             _DbfVersion:=xbaseV;
+    else
+      _DbfVersion:=xBaseIV; // My favorite...
+    end;
+    HeaderSize:=_DataHdr.FullHdrSize;
+    RecordSize:=_DataHdr.RecordSize;
+    lRecordCount:=CalcRecordCount;
+    if _DataHdr.RecordCount <> lRecordCount then begin
+{$ifndef fpc}    
+      ShowMessage('Invalid Record Count,'+^M+
+      'RecordCount in Hdr : '+IntToStr(_DataHdr.RecordCount)+^M+
+      'expected : '+IntToStr(lRecordCount));
+{$endif}      
+      _DataHdr.RecordCount := lRecordCount;
+    end;
+  end;
+
+end;
+
+
+destructor TDbfFile.Destroy;
+begin
+  inherited;
+  ClearMyFieldInfos;
+  _MyFieldInfos.Free;
+  _MyFieldInfos:=nil;
+
+end;
+
+function TDbfFile.RecordCount:integer;
+begin
+  if RecordSize=0 then result:=0
+  else result:=(Stream.Size - HeaderSize) div RecordSize;
+  if result<0 then result:=0;
+end;
+
+procedure TDbfFile.ClearMyFieldInfos;
+var
+  i:Integer;
+begin
+  for i:=0 to _MyFieldInfos.Count-1 do begin
+    TMyFieldInfo(_MyFieldInfos.Items[i]).Free;
+  end;
+  _MyFieldInfos.Clear;
+end;
+
+procedure TDbfFile.CreateFieldDefs(FieldDefs:TFieldDefs);
+var
+  lColumnCount,lHeaderSize,lFieldSize:Integer;
+  Il : Integer;
+  lFieldOffset : Integer;
+  fn:string;
+  ft:TFieldType;
+  fs,nfs,fd:Integer;
+  MyFieldInfo:TMyFieldInfo;
+  lFieldHdrIII:rFieldHdrIII;
+  lFieldHdrV:rFieldHdrV;
+
+  function ToFieldType(dbasetype:char;fs,fd:Integer):TFieldType;
+  begin
+    case dbasetype of
+    'C' :
+      begin
+        Result:=ftString;
+      end;
+    'L' :
+      begin
+        Result:=ftBoolean;
+      end;
+    'F' :
+      begin
+        Result:=ftFloat;
+      end;
+    'N' :
+      begin
+        if fd=0 then begin
+          if fs <= DIGITS_SMALLINT then begin
+            Result:=ftSmallInt;
+          end else begin
+{$ifdef DELPHI_3}
+            Result:=ftInteger;
+{$else}
+            if fs <= DIGITS_INTEGER then Result:=ftInteger
+            else Result:=ftLargeInt;
+{$endif}
+          end;
+        end else begin
+          Result:=ftFloat;
+        end;
+      end;
+    'D' :
+      begin
+        Result:=ftDate;
+      end;
+    'M' :
+      begin
+        Result:=ftMemo;
+      end;
+    else
+      begin
+        Result:=ftString;
+      end;
+    end; //case
+  end;
+begin
+  ClearMyFieldInfos;
+
+  if _DbfVersion>=xBaseV then begin
+    lHeaderSize:=SizeOf(rAfterHdrV) + SizeOf(rDbfHdr);
+    lFieldSize:=SizeOf(rFieldHdrV);
+  end else begin
+    lHeaderSize:=SizeOf(rAfterHdrIII) + SizeOf(rDbfHdr);
+    lFieldSize:=SizeOf(rFieldHdrIII);
+  end;
+  lColumnCount:= (_DataHdr.FullHdrSize - lHeaderSize) div lFieldSize;
+
+  if (lColumnCount <= 0) or (lColumnCount > 255) then
+      Raise eBinaryDataSetError.Create('Invalid field count : ' + IntToStr(lColumnCount) + ' (must be between 1 and 255)');
+
+  lFieldOffset := 1;
+
+  Stream.Position := lHeaderSize;
+  for Il:=0 to lColumnCount-1 do begin
+    if _DbfVersion>=xBaseV then begin
+      Stream.ReadBuffer(lFieldHdrV,SizeOf(lFieldHdrV));
+      fn:=PCHAR(@lFieldHdrV.FieldName[0]);
+      fs:=lFieldHdrV.FieldSize;
+      fd:=lFieldHdrV.FieldPrecision;
+      nfs:=fs;
+      ft:=ToFieldType(lFieldHdrV.FieldType,nfs,fd);
+    end else begin
+      Stream.ReadBuffer(lFieldHdrIII,SizeOf(lFieldHdrIII));
+      fn:=PCHAR(@lFieldHdrIII.FieldName[0]);
+      fs:=lFieldHdrIII.FieldSize;
+      fd:=lFieldHdrIII.FieldPrecision;
+      nfs:=fs;
+      ft:=ToFieldType(lFieldHdrIII.FieldType,nfs,fd);
+
+    end;
+    // first create the bde field
+    if ft in [ftString,ftBCD] then fieldDefs.Add(fn,ft,fs,false)
+    else fieldDefs.Add(fn,ft,0,false);
+    // then create the for our own fieldinfo
+    MyFieldInfo:=TMyFieldInfo.Create;
+    MyFieldInfo.Offset:=lFieldOffset;
+    MyFieldInfo.Size:=fs;
+    MyFieldInfo.Prec:=fd;
+    MyFieldInfo.FieldName:=lowercase(fn);
+
+    _MyFieldInfos.Add(MyFieldInfo);
+    Inc(lFieldOffset,fs);
+  end;
+  if (lFieldOffset <> _DataHdr.RecordSize) then begin
+{$ifndef fpc}
+    ShowMessage('Invalid Record Size,'+^M+
+                                     'Record Size in Hdr : '+IntToStr(_DataHdr.RecordSize)+^M+
+                                     'Expected : '+IntToStr(lFieldOffset));
+{$endif}
+    _DataHdr.RecordSize := lFieldOffset;
+  end;
+end;
+
+procedure TDbfFile.DbfFile_CreateTable(FieldDefs:TFieldDefs);
+var
+  ix:Integer;
+  lFieldHdrIII:rFieldHdrIII;
+  lType:Char;
+  lSize,lPrec:Integer;
+  Offs:Integer;
+  lterminator:Byte;
+begin
+  // first reset file.
+  Stream.Size:= 0;
+  Stream.Position:=SizeOf(rDbfHdr) + SizeOf(rAfterHdrIII);
+  Offs:=1; // deleted mark count 1.
+  for Ix:=0 to FieldDefs.Count-1 do
+  begin
+    with FieldDefs.Items[Ix] do
+    begin
+      FillChar(lFieldHdrIII,SizeOf(lFieldHdrIII),#0);
+      lPrec:=0;
+      case DataType of
+        ftString:
+          begin
+            ltype:='C';
+            lSize := Size;
+          end;
+        ftBoolean:
+          begin
+            ltype:='L';
+            lSize := 1;
+          end;
+        ftSmallInt:
+          begin
+            ltype:='N';
+            lSize := 6;
+          end;
+        ftInteger:
+          begin
+            ltype:='N';
+            lSize := 11;
+          end;
+        ftCurrency:
+          begin
+            ltype:='N';
+            lSize := 20;
+            lPrec := 2;
+          end;
+{$ifndef DELPHI_3}
+        ftLargeInt:
+          begin
+            ltype:='N';
+            lSize := 20;
+            lPrec := 0;
+          end;
+{$endif}
+        ftFloat:
+          begin
+            ltype:='N';
+            lSize := 20;
+            lPrec := 4;
+          end;
+        ftDate:
+          begin
+            ltype:='D';
+            lSize := 8;
+          end;
+        ftMemo:
+          begin
+            ltype:='M';
+            lSize := 10;
+          end;
+        else
+          begin
+            raise EBinaryDataSetError.Create(
+             'InitFieldDefs: Unsupported field type');
+          end;
+      end; // case
+
+      lFieldHdrIII.FieldType:=ltype; //DataType;
+      StrPCopy(lFieldHdrIII.FieldName,FieldDefs.Items[Ix].Name);
+      lFieldHdrIII.FieldSize:=lSize;
+      lFieldHdrIII.FieldPrecision:=lPrec;
+
+      Stream.Write(lFieldHdrIII,SizeOf(lFieldHdrIII));
+      Inc(Offs,lSize);
+    end;
+  end;
+  // end of header
+  lterminator := $0d;
+  Stream.Write(lterminator,SizeOf(lterminator));
+
+  // update header
+  _DataHdr.RecordSize := Offs;
+  _DataHdr.FullHdrSize := Stream.Position;
+  RecordSize := _DataHdr.RecordSize;
+  HeaderSize := _DataHdr.FullHdrSize;
+  // write the updated header
+  WriteHeader;
+end;
+
+procedure TDbfFile.DbfFile_PackTable;
+var
+  first,last:integer;
+  p: Pointer;
+begin
+  // Non tested.
+  if (RecordSize <> 0) then
+  begin
+    first:=0;
+    last:=CalcRecordCount-1;
+    GetMem(p, RecordSize);
+    try
+      while first<last do begin
+        // first find the first hole
+        while first<last do begin
+          ReadRecord(first, p);
+          if (pRecordHdr(p)^.DeletedFlag <> ' ') then break;
+          inc(first);
+        end;
+        // now find last one non deleted.
+        while first<last do begin
+          ReadRecord(last, p);
+          if (pRecordHdr(p)^.DeletedFlag = ' ') then break;
+          dec(last);
+        end;
+        if first<last then begin
+          // found a non deleted record to put in the hole.
+          WriteRecord(first, p);
+          inc(first);
+          dec(last);
+        end;
+      end;
+    last:=CalcRecordCount;
+      Stream.Size:=(last+1) * RecordSize + HeaderSize;
+    finally
+      FreeMem(p);
+    end;
+  end;
+end;
+
+function TDbfFile.GetFieldInfo(FieldName:string):TMyFieldInfo;
+var
+  i:Integer;
+  lfi:TMyFieldInfo;
+begin
+  FieldName:=LowerCase(FieldName);
+  for i:=0 to _MyFieldInfos.Count-1 do begin
+    lfi:=TMyFieldInfo(_MyFieldInfos.Items[i]);
+    if lfi.FieldName = FieldName then begin
+      result:=lfi;
+      exit;
+    end;
+  end;
+  result:=nil;
+end;
+
+function TDbfFile.GetFieldData(Column:Integer;DataType:TFieldType; Src,Dst:Pointer): Boolean;
+var
+  FieldOffset: Integer;
+  FieldSize: Integer;
+  s:string;
+  d:TDateTime;
+  ld,lm,ly: word;
+  MyFieldInfo:TMyFieldInfo;
+  function TrimStr(const s: string): string;
+  var
+    iPos: integer;
+  begin
+    if DataType=ftString then
+    begin
+      if tDbf_TrimFields then Result:=Trim(s)
+      else Result:=TrimRight(s);
+    end
+    else Result:= Trim(s);
+  end;
+  procedure CorrectYear(var wYear: word);
+  var wD, wM, wY, CenturyBase: word;
+{$ifdef DELPHI_3}
+  // Delphi 3 standard-behavior no change possible
+  const TwoDigitYearCenturyWindow= 0;
+{$endif}
+  begin
+     if wYear>= 100 then
+       Exit;
+     DecodeDate(Date, wY, wm, wD);
+     // use Delphi-Date-Window
+     CenturyBase := wY{must be CurrentYear} - TwoDigitYearCenturyWindow;
+     Inc(wYear, CenturyBase div 100 * 100);
+     if (TwoDigitYearCenturyWindow > 0) and (wYear < CenturyBase) then
+        Inc(wYear, 100);
+  end;
+begin
+  MyFieldInfo:=TMyFieldInfo(_MyFieldInfos.Items[Column]);
+  FieldOffset := MyFieldInfo.Offset;
+  FieldSize := MyFieldInfo.Size;
+  SetString(s, PChar(Src) + FieldOffset, FieldSize );
+  s:=TrimStr(s);
+  result:=length(s)>0; // return if field is empty
+  if Result and (Dst<>nil) then// data not needed if Result= FALSE or Dst=nil
+    case DataType of
+    ftBoolean:
+      begin
+        // in DBase- FileDescription lowercase t is allowed too
+        // with asking for Result= TRUE s must be longer then 0
+        // else it happens an AV, maybe field is NULL
+        if (UpCase(s[1])='T') then Word(Dst^) := 1
+        else Word(Dst^) := 0;
+      end;
+    ftInteger, ftSmallInt{$ifndef DELPHI_3},ftLargeInt{$endif}:
+      begin
+        case DataType of
+        ftSmallInt : SmallInt(Dst^):= StrToIntDef(s, 0);
+        {$ifndef DELPHI_3}
+        ftLargeint : LargeInt(Dst^):= StrToInt64Def(s, 0);
+        {$endif}
+        else // ftInteger :
+          Integer(Dst^):= StrToIntDef(s, 0);
+        end; // case
+      end;
+    ftFloat:
+      begin
+        Double(Dst^) := DBFStrToFloat(s);
+      end;
+    ftCurrency:
+      begin
+        Double(Dst^) := DBFStrToFloat(s);
+      end;
+    ftDate:
+      begin
+        ld:=StrToIntDef(Copy(s,7,2),1);
+        lm:=StrToIntDef(Copy(s,5,2),1);
+        ly:=StrToIntDef(Copy(s,1,4),0);
+        if ld=0 then ld:=1;
+        if lm=0 then lm:=1;
+//           if (ly<1900) or (ly>2100) then ly:=1900;
+//           Year from 0001 to 9999 is possible
+//           everyting else is an error, an empty string too
+//           Do DateCorrection with Delphis possibillities for one or two digits
+        if (ly< 100) and (Length(Trim(Copy(s,1,4)))in [1, 2]) then CorrectYear(ly);
+        try
+          d:=EncodeDate(ly,lm,ld);
+          if Assigned(Dst) then  Integer(Dst^) := DateTimeToTimeStamp(d).Date;
+        except
+          Integer(Dst^) := 0;
+        end;
+      end;
+        ftString: begin
+        StrPCopy(Dst,s);
+      end;
+   end;
+end;
+
+procedure TDbfFile.SetFieldData(Column:integer;DataType:TFieldType; Src,Dst:Pointer);
+var
+  FieldSize,FieldPrec: Integer;
+  s:string;
+  fl:Double;
+  ts:TTimeStamp;
+  MyFieldInfo:TMyFieldInfo;
+begin
+  MyFieldInfo:=TMyFieldInfo(_MyFieldInfos.Items[Column]);
+  FieldSize := MyFieldInfo.Size;
+  FieldPrec := MyFieldInfo.Prec;
+
+  Dst:=PChar(Dst)+MyFieldInfo.Offset;
+  if src<>nil then begin
+    case DataType of
+    ftBoolean:
+      begin
+        if Word(Src^) = 1 then s:='T'
+        else s:='F';
+      end;
+    ftInteger, ftSmallInt {$ifndef DELPHI_3},ftLargeInt{$endif}:
+      begin
+        case DataType of
+        ftSmallInt : s:= IntToStr(SmallInt(Src^));
+        {$ifndef DELPHI_3}
+        ftLargeInt: s:= IntToStr(LargeInt(Src^));
+        {$endif}
+        else //ftInteger
+          s:= IntToStr(Integer(Src^));
+        end;
+        // left filling
+        if Length(s)<FieldSize then s:=StringOfChar(' ',FieldSize-Length(s)) + s;
+      end;
+    ftFloat,ftCurrency:
+      begin
+        fl := Double(Src^);
+        s:=FloatToDbfStr(fl,FieldSize,FieldPrec);
+        if Length(s)<FieldSize then s:=StringOfChar(' ',FieldSize-Length(s)) + s;
+      end;
+    ftDate:
+      begin
+        ts.Time:=0;
+        ts.Date:=Integer(Src^);
+        s:= FormatDateTime('yyyymmdd', TimeStampToDateTime(ts));
+      end;
+    ftString:
+      begin
+        s:=PChar(Src); // finish with first 0
+      end;
+    end; // case
+  end; // if src<>nil (thanks andreas)
+  if Length(s)<FieldSize then begin
+    s:=s+StringOfChar(' ',FieldSize-Length(s));
+  end else if (Length(s)>FieldSize) then begin
+    if DataType= ftString then begin
+      // never raise for strings to long, its not customary
+      // TTable never raises
+      SetLength(s, FieldSize)
+    end else begin
+      raise eFieldToLongError.Create('Fielddata too long :' + IntToStr(Length(s))
+        + ' (must be between 1 and ' + IntToStr(FieldSize) + ').');
+    end;
+  end;
+  Move(PChar(s)^, Dst^, FieldSize);
+end;
+
+
+procedure TDbfFile.WriteHeader;
+var
+  SystemTime: TSystemTime;
+  lAfterHdrIII:rAfterHdrIII;
+  lAfterHdrV:rAfterHdrV;
+  lterminator:Byte;
+begin
+  Assert(Stream<>nil,'_dbfFile=Nil');
+
+  Stream.Position:=0;
+  GetLocalTime(SystemTime);
+{$ifndef fpc}
+  _DataHdr.Year := SystemTime.wYear - 1900;
+  _DataHdr.Month := SystemTime.wMonth;
+  _DataHdr.Day := SystemTime.wDay;
+{$else}
+  _DataHdr.Year := SystemTime.Year - 1900;
+  _DataHdr.Month := SystemTime.Month;
+  _DataHdr.Day := SystemTime.Day;
+{$endif}  
+  Stream.Seek(0,soFromBeginning);
+  Stream.WriteBuffer (_DataHdr, SizeOf(_DataHdr));
+  _DataHdr.RecordCount := CalcRecordCount;
+
+  if _DbfVersion >= xBaseV then begin
+    FillChar(lAfterHdrV,SizeOf(lAfterHdrV),0);
+    Stream.WriteBuffer (lAfterHdrV, SizeOf(lAfterHdrV));
+  end else begin
+    FillChar(lAfterHdrIII,SizeOf(lAfterHdrIII),0);
+    Stream.WriteBuffer (lAfterHdrIII, SizeOf(lAfterHdrIII));
+  end;
+  _Seek(_DataHdr.RecordCount); // last byte usually...
+  lterminator := $1A;
+  Stream.Write(lterminator,SizeOf(lterminator));
+end;
+
+function TDbf._ComponentInfo:string;
+begin
+  Result:='TDbf V' + IntToStr(_MAJOR_VERSION) + '.' + IntToStr(_MINOR_VERSION);
+end;
+
+procedure TDbf._OpenFiles(CreateIt:boolean);
+var
+  fileopenmode : integer;
+  lPath,lFilename,lIndexName,lMemoName : string;
+  isAbsolute:boolean;
+  design,doreadonly:boolean;
+
+begin
+  design:=(csDesigning in ComponentState);
+  doreadonly:=design or _ReadOnly;
+
+  lPath:=_GetPath;
+  isAbsolute:=((length(_TableName)>=1) and (_TableName[1]='\'))
+    or ((length(_TableName)>=2) and (_TableName[2]=':'));
+  if isAbsolute then lfilename:=_TableName
+  else lFilename:=lPath+_TableName;
+  lFilename:=ChangeFileExt(lFilename,'.dbf');
+  lIndexName:=ChangeFileExt(lFilename,'.mdx');
+  lMemoName:=ChangeFileExt(lFilename,'.dbt');
+
+  // check if the file exists
+  _dbfFile:=TDbfFile(GetPagedFile(lFileName));
+  _indexFile:=TIndexFile(GetPagedFile(lIndexName));
+  _dbtFile:=TDbtFile(GetPagedFile(lMemoName));
+
+  if CreateIt then begin
+    if _dbfFile=nil then _dbfFile:=TDbfFile.Create(lFileName,fmCreate);
+    //if _indexfile=nil then _indexFile := TIndexFile.Create(lIndexName, fmCreate);
+    if _dbtfile=nil then _dbtFile := TDbtFile.Create(lMemoName, fmCreate,_dbfFile._DbfVersion);
+  end else if not FileExists(lFileName) then begin
+    raise eBinaryDataSetError.Create ('Open: Table file not found : ' + lFileName);
+  end else begin
+    if DoReadOnly  then
+      fileopenmode := fmOpenRead + fmShareDenyNone
+    else
+      fileopenmode := fmOpenReadWrite + fmShareDenyWrite;
+
+    if _dbfFile=nil then _dbfFile := TDBFFile.Create(lFileName, fileopenmode);
+    if (_indexFile=nil) and FileExists (lIndexName) then begin
+      _indexFile := TIndexFile.Create(lIndexName, fileopenmode);
+    end;
+    if (_dbtFile=nil) and FileExists (lMemoName) then begin
+      _dbtFile := TDbtFile.Create(lMemoName, fileopenmode,_dbfFile._DbfVersion);
+    end;
+  end;
+  _PrevBuffer:=AllocRecordBuffer;
+  _IsCursorOpen:=true;
+
+end;
+
+function TDbf._GetPath:string;
+var
+  lPath:string;
+begin
+  if (csDesigning in ComponentState) then begin
+    lPath:=_DesignTimePath;
+  end else begin
+    if ((length(_RunTimePath)>=1) and (_RunTimePath[1]=DirSeparator))
+      or ((length(_RunTimePath)>=2) and (_RunTimePath[2]=':'))
+      then begin
+      // if the _RunTimePath is absolute...
+      // it is either \ or \blahblah or c:\
+      lPath:=_RunTimePath;
+    end else begin
+{$ifndef fpc}
+      lPath:=extractfilepath(Application.Exename)+_RunTimePath;
+{$else}      
+      lPath:=extractfilepath(paramstr(0))+_RunTimePath;
+{$endif}
+    end;
+  end;
+  lPath:=ExpandFileName(trim(lPath));
+  if (length(lPath)>0) and (lPath[length(lPath)]<>DirSeparator) then lPath:=lPath+DirSeparator;
+  result:=lPath;
+end;
+
+procedure TDbf._CloseFiles;
+var
+  i:integer;
+begin
+  if _dbfFile<>nil then begin
+    if not _ReadOnly then _dbfFile.WriteHeader;
+    _dbfFile.Release;
+    _dbfFile:=nil;
+  end;
+  if _indexFile<>nil then begin
+    _indexFile.Release;
+    _indexFile:=nil;
+  end;
+
+  if _dbtFile<>nil then begin
+    _dbtFile.Release;
+    _dbtFile:=nil;
+  end;
+
+  if _indexes<>nil then begin
+    for i:=0 to _Indexes.Count-1 do begin
+      TIndex(_Indexes[i]).Free;
+    end;
+    _Indexes.Clear;
+    _CurIndex:=nil;
+  end;
+  if (_PrevBuffer<>nil) then begin
+    FreeRecordBuffer(_PrevBuffer);
+    _PrevBuffer:=nil;
+  end;
+  _IsCursorOpen:=false;
+end;
+
+procedure TDbf._SetIndexName(const Value: string);
+begin
+  _CurIndex:=_GetIndex(Value);
+  Resync([]);
+end;
+
+function TDbf._GetIndexName: string;
+begin
+  if _CurIndex=nil then Result:=''
+  else Result:=_CurIndex._IndexFile._Filename;
+end;
+
+function TDbf._GetIndex(filename:string):TIndex;
+var
+  i:integer;
+  lindex:TIndex;
+begin
+  result:=nil;
+  filename:=lowercase(_GetPath + filename);
+  for i:=0 to _indexes.Count-1 do begin
+    lindex:=TIndex(_indexes.Items[i]);
+    if lindex._IndexFile._Filename=filename then begin
+      result:=lindex;
+      exit;
+    end;
+  end;
+end;
+
+
+//==========================================================
+//============ TMyBlobFile
+//==========================================================
+constructor TMyBlobFile.Create(ModeVal:TBlobStreamMode;FieldVal:TField);
+begin
+  Mode:=ModeVal;
+  Field:=FieldVal;
+end;
+
+destructor TMyBlobFile.destroy;
+var
+  Dbf:TDbf;
+begin
+  if (Mode=bmWrite) then begin
+    Size:=Position; // Strange but it leave tailing trash bytes if I do not write that.
+    Dbf:=TDbf(Field.DataSet);
+    Dbf._dbtFile.WriteMemo(MemoRecno,ReadSize,Self);
+
+    Dbf._dbfFile.SetFieldData(Field.FieldNo-1,
+      ftInteger,@MemoRecno,@pDbfRecord(TDbf(Field.DataSet).ActiveBuffer)^.deletedflag);
+    // seems not bad
+{$ifndef fpc}    
+    // FPC doesn't allow to call protected methods ?!!
+    Dbf.SetModified(true);
+{$endif}    
+    // but would that be better
+    //if not (State in [dsCalcFields, dsFilter, dsNewValue]) then begin
+    //  DataEvent(deFieldChange, Longint(Field));
+    //end;
+  end;
+  inherited;
+end;
+
+//====================================================================
+// TDbf = TDataset Descendant.
+//====================================================================
+constructor TDbf.Create(AOwner: TComponent); {override;}
+begin
+  inherited create(aOwner);
+  BookmarkSize:=sizeof(rBookmarkData);
+
+  _RunTimePath:='.';
+  _IsCursorOpen:=false;
+  _Indexes:=TList.Create;
+  _CurIndex:=nil;
+  _IndexFiles:=TStringList.Create;
+end;
+
+destructor TDbf.Destroy; {override;}
+var
+  i:integer;
+begin
+  inherited;
+  _CurIndex:=nil;
+  for i:=0 to _Indexes.Count-1 do begin
+    TIndex(_Indexes[i]).Free;
+  end;
+  _Indexes.Free;
+  _IndexFiles.Free;
+//  _MemIndex.Free;
+end;
+
+
+function TDbf._FilterRecord(Buffer: PChar): Boolean;
+var
+  SaveState: TDatasetState;
+  s:string;
+begin
+  Result:=True;
+  if Length(easyfilter)<>0 then begin
+    SetString(s,buffer,RecordSize);
+    s:=LowerCase(s);
+    if Pos(easyfilter,s)=0 then begin
+      Result:=False;
+      Exit;
+    end;
+  end;
+  if not Assigned(OnFilterRecord) then Exit;
+  if not Filtered then Exit;
+  _FilterBuffer:=buffer;
+  SaveState:=SetTempState(dsFilter);
+  OnFilterRecord(self,Result);
+  RestoreState(SaveState);
+end;
+
+function TDbf._RecordDataSize:integer;
+begin
+  if _dbfFile=nil then result:=0
+  else result:=_dbfFile.RecordSize;
+end;
+
+function TDbf._FullRecordSize:integer;
+begin
+  result:=sizeof(rBeforeRecord) + _RecordDataSize + CalcFieldsSize;
+end;
+
+function TDbf.AllocRecordBuffer: PChar; {override virtual abstract from TDataset}
+begin
+  result:=StrAlloc(_FullRecordSize);
+  InternalInitRecord(result);
+end;
+
+procedure TDbf.FreeRecordBuffer(var Buffer: PChar); {override virtual abstract from TDataset}
+begin
+  StrDispose(Buffer);
+end;
+
+procedure TDbf.GetBookmarkData(Buffer: PChar; Data: Pointer); {override virtual abstract from TDataset}
+var
+  prec:pDbfRecord;
+begin
+  prec:=pDbfRecord(Buffer);
+  pBookMarkData(Data)^:=prec^.BookMarkData;
+end;
+
+function TDbf.GetBookmarkFlag(Buffer: PChar): TBookmarkFlag; {override virtual abstract from TDataset}
+var
+  prec:pDbfRecord;
+begin
+  prec:=pDbfRecord(Buffer);
+  result:=prec^.BookMarkFlag;
+end;
+
+function TDbf.GetFieldData(Field: TField; Buffer: Pointer): Boolean; {override virtual abstract from TDataset}
+var
+  ptr:pointer;
+begin
+  Result := False;
+  if State=dsFilter then begin
+    Ptr:=_FilterBuffer;
+  end else   if State = dsCalcFields then  begin
+    // ***** calc fields *****  set correct buffer
+    ptr := @(pDbfRecord(CalcBuffer)^.deletedflag);
+  end else begin
+    if IsEmpty then exit;
+    ptr:=@(pDbfRecord(ActiveBuffer)^.deletedflag);
+  end;
+
+  if Field.FieldNo>0 then begin
+    Result:=_dbfFile.GetFieldData(Field.FieldNo - 1,Field.DataType,ptr,Buffer);
+  end else begin { calculated fields.... }
+    Inc(PChar(Ptr), Field.Offset + GetRecordSize);
+{$ifndef fpc}
+    Result := Boolean(PChar(Ptr)[0]);
+{$else}
+    Result := (Pchar(ptr)[0]<>#0);
+{$endif}    
+    if Result and (Buffer <> nil) then
+      Move(PChar(Ptr)[1], Buffer^, Field.DataSize);
+  end;
+end;
+
+
+function TDbf.GetRecord(Buffer: PChar; GetMode: TGetMode; DoCheck: Boolean): TGetResult; {override virtual abstract from TDataset}
+var
+  Acceptable : Boolean;
+  prec:pDBFRecord;
+begin
+  prec:=pDBFRecord(Buffer);
+  if _dbfFile.RecordCount < 1 then
+    Result := grEOF
+  else repeat
+    result := grOk;
+    case GetMode of
+      gmCurrent :
+        begin
+          if prec^.BookmarkData.Recno=_PhysicalRecno then begin
+            exit;    // try to fasten a bit...
+          end;
+        end;
+      gmNext :
+        begin
+          if _curIndex<>nil then begin
+            Acceptable:=_curIndex.Next;
+          end else begin
+            inc(_PhysicalRecno);
+            Acceptable:=(_PhysicalRecno<_dbfFile.RecordCount);
+          end;
+          if Acceptable then begin
+            result:= grOk;
+          end else begin
+            InternalLast;
+            result:= grEOF
+          end;
+        end;
+      gmPrior :
+        begin
+          if _curIndex<>nil then begin
+            Acceptable:=_curIndex.Prev;
+          end else begin
+            dec(_PhysicalRecno);
+            Acceptable:=(_PhysicalRecno>=0);
+          end;
+          if Acceptable then begin
+            result:= grOk;
+          end else begin
+            InternalFirst;
+            result:= grBOF
+          end;
+        end;
+    end;
+    if result=grOk then begin
+      if _curIndex<>nil then _PhysicalRecno:=_CurIndex.GetRealRecNo;
+      if (_PhysicalRecno>=_dbfFile.RecordCount)
+        or (_PhysicalRecno<0) then begin
+        result:=grError;
+      end else begin
+        _dbfFile.ReadRecord(_PhysicalRecno,@prec^.DeletedFlag);
+        result:=grOk;
+      end;
+      if Result = grOK then begin
+        ClearCalcFields(Buffer);
+        GetCalcFields(Buffer);
+        prec^.BookmarkFlag := bfCurrent;
+        prec^.BookmarkData.Recno:=PhysicalRecno;
+      end else if (Result = grError) and DoCheck then
+          raise eBinaryDataSetError.Create ('GetRecord: Invalid record');
+    end;
+    Acceptable := (_ShowDeleted or (prec^.DeletedFlag = ' '))
+      and _FilterRecord(Buffer);
+    if (GetMode=gmCurrent) and Not Acceptable then Result := grError;
+  until (Result <> grOK) or Acceptable;
+end;
+
+function TDbf.GetRecordSize: Word; {override virtual abstract from TDataset}
+begin
+  Result := _RecordDataSize; // data only
+end;
+
+procedure TDbf.InternalAddRecord(Buffer: Pointer; DoAppend: Boolean); {override virtual abstract from TDataset}
+begin
+end;
+
+procedure TDbf.InternalClose; {override virtual abstract from TDataset}
+begin
+  _CloseFiles;
+
+  // disconnect field objects
+  BindFields(False);
+  // destroy field object (if not persistent)
+  if DefaultFields then
+    DestroyFields;
+end;
+
+procedure TDbf.InternalDelete; {override virtual abstract from TDataset}
+begin
+//  CheckActive;
+  pRecordHdr(ActiveBuffer)^.DeletedFlag := '*'; //_DataHdr.LastDeleted;
+  _dbfFile.WriteRecord(_PhysicalRecNo,ActiveBuffer);
+  Resync([]);
+end;
+
+procedure TDbf.InternalFirst; {override virtual abstract from TDataset}
+begin
+  if _dbfFile.RecordCount=0 then InternalLast
+  else if _curindex=nil then _PhysicalRecno:=-1
+  else _curIndex.First;
+end;
+
+procedure TDbf.InternalGotoBookmark(ABookmark: Pointer); {override virtual abstract from TDataset}
+var
+  RecInfo: TRecInfo;
+begin
+  RecInfo := TRecInfo(ABookmark^);
+  if (RecInfo.Bookmark >= 0) and (RecInfo.Bookmark < _dbfFile.RecordCount) then begin
+    _PhysicalRecno:=RecInfo.Bookmark;
+  end else
+    raise eBinaryDataSetError.Create ('Bookmark ' +
+      IntToStr (RecInfo.Bookmark) + ' not found');
+end;
+
+procedure TDbf.InternalHandleException; {override virtual abstract from TDataset}
+begin
+{$ifndef fpc}
+  Application.HandleException(Self);
+{$endif}  
+end;
+
+procedure TDbf.InternalInitFieldDefs; {override virtual abstract from TDataset}
+begin
+  FieldDefs.Clear;
+  with FieldDefs do
+  begin
+    if IsCursorOpen  then begin
+      _dbfFile.CreateFieldDefs(FieldDefs);
+    end else begin
+      _OpenFiles(false);
+      _dbfFile.CreateFieldDefs(FieldDefs);
+      Close();
+    end;
+  end;
+end;
+
+procedure TDbf.InternalInitRecord(Buffer: PChar); {override virtual abstract from TDataset}
+var
+  prec:pDbfRecord;
+begin
+  prec:=pDbfRecord(Buffer);
+  prec^.BookmarkData.RecNo:=-1;
+  prec^.BookmarkFlag:=TBookmarkFlag(0);
+  fillchar(prec^.DeletedFlag,_RecordDataSize,' ');
+end;
+
+procedure TDbf.InternalLast; {override virtual abstract from TDataset}
+begin
+  if _curindex=nil then _PhysicalRecno:=_dbfFile.RecordCount
+  else _curIndex.Last;
+end;
+
+procedure TDbf.InternalOpen; {override virtual abstract from TDataset}
+begin
+  _OpenFiles(false);
+  // if there are no persistent field objects,
+  InternalInitFieldDefs;
+  // create the fields dynamically
+  if DefaultFields then begin
+    CreateFields;
+  end;
+  BindFields (True);
+  // connect the TField objects with the actual fields
+
+  InternalFirst;
+end;
+
+procedure TDbf.InternalPost; {override virtual abstract from TDataset}
+var
+  prec:pDbfRecord;
+  lIndex:TIndex;
+  i:integer;
+begin
+  CheckActive;
+  prec:=pDbfRecord(ActiveBuffer);
+  prec^.DeletedFlag:=' ';
+
+  if State = dsEdit then
+  begin
+    // replace data with new data
+    if _indexes.Count>0 then begin
+      _dbfFile.ReadRecord(_PhysicalRecno,_PrevBuffer);
+      for i:=0 to _indexes.Count-1 do begin
+        lindex:=TIndex(_indexes.Items[i]);
+        lindex.Update(_PhysicalRecno,_PrevBuffer,@prec^.DeletedFlag);
+      end;
+    end;
+  end else begin
+    // append
+    _PhysicalRecno:=_dbfFile._DataHdr.RecordCount;
+    inc(_dbfFile._DataHdr.RecordCount);
+    if _indexes.Count>0 then begin
+      _dbfFile.ReadRecord(_PhysicalRecno,_PrevBuffer);
+      for i:=0 to _indexes.Count-1 do begin
+        lindex:=TIndex(_indexes.Items[i]);
+        lindex.Insert(_PhysicalRecno,@prec^.DeletedFlag);
+      end;
+    end;
+  end;
+  _dbfFile.WriteRecord(_PhysicalRecno,@prec^.DeletedFlag);
+end;
+
+
+procedure TDbf.CreateTable; //(FieldDefs:TFieldDefs);
+var
+  ix:integer;
+begin
+  CheckInactive;
+  //  InternalInitFieldDefs;
+  if FieldDefs.Count = 0 then
+  begin
+    for Ix := 0 to FieldCount - 1 do
+    begin
+      with Fields[Ix] do
+      begin
+        if FieldKind = fkData then
+          FieldDefs.Add(FieldName,DataType,Size,Required);
+      end;
+    end;
+  end;
+  _OpenFiles(true);
+  try
+    _dbfFile.DbfFile_CreateTable(FieldDefs);
+  finally
+    // close the file
+    _CloseFiles;
+  end;
+end;
+
+procedure TDbf.PackTable;
+begin
+  _dbfFile.dbfFile_PackTable;
+  Resync([]);
+end;
+
+
+function TDbf.CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream; {override virtual}
+var
+  Memoi:array[1..32] of char;
+  lBlob:TMyBlobFile;
+begin
+  lBlob:=TMyBlobFile.Create(Mode,Field);
+  if _dbfFile.GetFieldData(Field.FieldNo-1, ftString,@pDbfRecord(ActiveBuffer)^.deletedflag,@Memoi[1]) then begin
+    lBlob.MemoRecno:=StrToIntDef(Memoi,0);
+    _dbtFile.ReadMemo(lBlob.MemoRecno,lBlob);
+    lBlob.ReadSize:=lBlob.Size;
+  end else lBlob.MemoRecno:=0;
+  Result:=lBlob;
+end;
+
+{$ifdef DELPHI_3}
+procedure TDbf.Translate(Src, Dest: PChar; ToOem: Boolean); {override virtual}
+begin
+  if (Src <> nil) and (Dest<>nil) then begin
+    if ToOem then CharToOem(Src,Dest)
+    else OemToChar(Src,Dest);
+  end;
+end;
+{$else}
+{$ifndef fpc}
+function TDbf.Translate(Src, Dest: PChar; ToOem: Boolean): Integer; {override virtual}
+begin
+  if (Src <> nil) and (Dest<>nil) then begin
+    if ToOem then CharToOem(Src,Dest)
+    else OemToChar(Src,Dest);
+    result:= StrLen(Dest);
+  end else result:=0;
+end;
+{$else}
+procedure TDbf.Translate(Src, Dest: PChar; ToOem: Boolean); {override virtual}
+begin
+end;
+{$endif}
+{$endif}
+
+procedure TDbf.ClearCalcFields(Buffer: PChar);
+begin
+  FillChar(Buffer[_dbfFile.RecordSize], CalcFieldsSize, 0);
+end;
+
+procedure TDbf.InternalSetToRecord(Buffer: PChar); {override virtual abstract from TDataset}
+var
+  prec:pDbfRecord;
+begin
+  if Buffer=nil then exit;
+  prec:=pDbfRecord(Buffer);
+  _PhysicalRecno:=prec^.BookmarkData.RecNo;
+  _ResyncIndexes(Buffer);
+end;
+
+procedure TDbf._ResyncIndexes(Buffer: PChar);
+var
+  i:integer;
+  lindex:TIndex;
+begin
+  if _indexes.Count>0 then begin
+    _dbfFile.ReadRecord(_PhysicalRecno,_PrevBuffer);
+    for i:=0 to _indexes.Count-1 do begin
+      lindex:=TIndex(_indexes.Items[i]);
+      lindex.GotoKey(_physicalRecno,nil);
+    end;
+  end;
+end;
+
+function TDbf.IsCursorOpen: Boolean; {override virtual abstract from TDataset}
+begin
+  result:=_IsCursorOpen;
+end;
+
+procedure TDbf.SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag); {override virtual abstract from TDataset}
+var
+  prec:pDbfRecord;
+begin
+  prec:=pDbfRecord(Buffer);
+  prec^.BookMarkFlag:=Value;
+end;
+
+procedure TDbf.SetBookmarkData(Buffer: PChar; Data: Pointer); {override virtual abstract from TDataset}
+var
+  prec:pDbfRecord;
+begin
+  prec:=pDbfRecord(Buffer);
+  prec^.BookMarkData:=pBookMarkData(Data)^;
+end;
+
+procedure TDbf.SetFieldData(Field: TField; Buffer: Pointer); {override virtual abstract from TDataset}
+var
+  prec:pDbfRecord;
+  dst:pointer;
+begin
+  if (Field.FieldNo >= 0) then begin
+    prec:=pDbfRecord(ActiveBuffer);
+    dst:=@prec^.DeletedFlag;
+    _dbfFile.SetFieldData(Field.FieldNo - 1,Field.DataType,Buffer,Dst);
+  end else begin    { ***** fkCalculated, fkLookup ***** }
+    prec:=pDbfRecord(CalcBuffer);
+    dst:=@prec^.DeletedFlag;
+    Inc(integer(dst), GetRecordSize + Field.Offset);
+    Boolean(dst^) := LongBool(Buffer);
+    if Boolean(dst^) then begin
+      Inc(integer(dst), 1);
+      Move(Buffer^, dst^, Field.DataSize);
+    end;
+  end;     { end of ***** fkCalculated, fkLookup ***** }
+  if not (State in [dsCalcFields, dsFilter, dsNewValue]) then begin
+    DataEvent(deFieldChange, Longint(Field));
+  end;
+end;
+
+
+// this function is just for the grid scrollbars
+// it doesn't have to be perfectly accurate, but fast.
+function TDbf.GetRecordCount: Integer; {override virtual}
+begin
+  if _curIndex=nil then begin
+    result:=_dbfFile.RecordCount;
+  end else begin
+    result:=_curIndex.GuessRecordCount;
+  end;
+end;
+
+// this function is just for the grid scrollbars
+// it doesn't have to be perfectly accurate, but fast.
+function TDbf.GetRecNo: Integer; {override virtual}
+begin
+  UpdateCursorPos;
+  if _curIndex=nil then begin
+    result:=_PhysicalRecno+1;
+  end else begin
+    result:=_curIndex.GuessRecNo;
+  end;
+end;
+
+procedure TDbf.SetRecNo(Value: Integer); {override virual}
+begin
+  if _curIndex=nil then begin
+    _PhysicalRecno:=Value-1;
+  end else begin
+    //result:=_curIndex.GuessRecNo;
+  end;
+  Resync([rmExact]);
+end;
+
+procedure TDBf.DeleteIndex(const AName: string);
+
+begin
+  // I must admit that is seems a bit expeditive.
+  // but I does implement this method because TTable does
+  DeleteFile(_GetPath + Name);
+end;
+
+procedure TDbf.CloseIndexFile(const IndexFileName: string);
+var
+  lindex:tindex;
+begin
+  lindex:=_GetIndex(IndexFileName);
+  if lindex<>nil then begin
+    lindex.Free;
+    _indexes.Delete(_indexes.IndexOf(lindex));
+    if _curindex = lindex then begin
+      _curindex:=nil;
+      resync([]);
+    end;
+  end;
+end;
+
+procedure TDbf.OpenIndexFile(AnIndexName:string);
+var
+  lIndexFile:TIndexFile;
+  lIndex:TIndex;
+begin
+  lindex:=_GetIndex(IndexName);
+  if lindex=nil then begin
+    IndexName:=lowercase(_GetPath + IndexName);
+    lIndexFile:=TIndexFile(GetPagedFile(IndexName));
+    if lIndexFile=nil then begin
+      lIndexFile:=TIndexFile.Create(IndexName,fmOpenReadWrite + fmShareDenyWrite);
+    end;
+    lIndex:=TIndex.Create(lIndexFile,0,false);
+    _Indexes.Add(lIndex);
+    lIndex.InitFieldDef(_DbfFile,lIndex._NdxHdr.KeyDesc);
+  end;
+end;
+
+(*
+procedure TDbfFile.DbfFile_PackTable;
+var
+begin
+end;
+*)
+{$ifdef fpc}
+procedure TDbf.AddIndex(const AnIndexName, IndexFields: String; Options: TIndexOptions);
+
+begin
+  AddIndex(indexName,IndexFields,options,'');  
+end;
+{$endif}
+
+{$ifdef DELPHI_3}
+procedure TDbf.AddIndex(const IndexName, Fields: String; Options: TIndexOptions);
+var
+  DescFields:string;
+{$else}
+{$ifndef fpc}
+procedure TDbf.AddIndex(const IndexName, Fields: String; Options: TIndexOptions; const DescFields: String='');
+var
+{$else}
+procedure TDbf.AddIndex(const AnIndexName, IndexFields: String; Options: TIndexOptions; const DescFields: String);
+var
+{$endif}
+{$endif}
+  lfilename:string;
+  lIndexFile:TIndexFile;
+  lIndex:TIndex;
+  cur,thelast:integer;
+begin
+  lfilename:=lowercase(_GetPath+IndexName);
+  lIndexFile:=TIndexFile(GetPagedFile(lfilename));
+  if lIndexFile<>nil then exit;
+  lIndexFile:=TIndexFile.Create(lfilename,fmCreate);
+  lIndex:=TIndex.Create(lIndexFile,0,true);
+{$ifndef fpc}
+  lIndex.InitFieldDef(_DbfFile,Fields);
+{$else}  
+  lIndex.InitFieldDef(_DbfFile,IndexFields);
+{$endif}  
+  with lIndex._NdxHdr do begin
+    startpage:=1;
+    nbPage:=1;
+    keyformat:=#0;
+    keytype:='C';
+    dummy:=$5800;
+    keylen:=lindex._FieldLen;
+    nbkey:=(512-8) div (lindex._FieldLen+8);
+    keyreclen:=lindex._FieldLen+8;
+    Unique:=0;
+    KeyDesc[0]:=' ';
+{$ifndef fpc}    
+    StrLCopy(KeyDesc,PChar(UpperCase(Fields)),255);
+{$else}    
+    StrLCopy(KeyDesc,PChar(UpperCase(IndexFields)),255);
+{$endif}    
+  end;
+  lindex._IndexFile._Seek(lindex._RootPage);
+  lindex._IndexFile.Stream.Write(lindex._NdxHdr,SizeOf(lindex._NdxHdr));
+
+  cur:=0;
+  thelast:=_DbfFile.CalcRecordCount;
+
+  while cur<thelast do begin
+    _DbfFile.ReadRecord(cur, _PrevBuffer);
+    lIndex.Insert(cur,_PrevBuffer);
+    inc(cur);
+  end;
+  _Indexes.Add(lIndex);
+end;
+//==========================================================
+//============ dbtfile
+//==========================================================
+constructor TDbtFile.Create(const FileName: string; Mode: Word; Ver:xBaseVersion);
+begin
+  inherited Create(FileName,Mode);
+  _DbtVersion:=Ver;
+  if mode = fmCreate then begin
+    FillChar(_MemoHdr,sizeof(_MemoHdr),0);
+  end else begin
+    Stream.Position:=0;
+    Stream.read(_MemoHdr,SizeOf(_MemoHdr));
+  end;
+  HeaderSize:=0;
+  RecordSize:=_MemoHdr.BlockLen;
+
+  if (RecordSize=0) or ((RecordSize mod 128)<>0) then begin
+    _MemoHdr.BlockLen := $200;
+    RecordSize := $200;
+  end;
+  // Can you tell me why the header of dbase3 memo contains 1024 and it 512 ?
+  if _DbtVersion=xBaseIII then RecordSize:=512;
+end;
+
+procedure TDbtFile.ReadMemo(recno:Integer;Dst:TStream);
+var
+  Buff:array[0..511] of char;
+  i,lsize:integer;
+  finish:boolean;
+  lastc:char;
+begin
+  if recno=0 then Exit;
+  Stream.Position:= RecordSize * recno;
+  if _DbtVersion >= xBaseIV then begin // dBase4 memofiles
+    Stream.read(Buff[0],8);
+    if (Buff[0]=#$ff) and  (Buff[1]=#$ff) and
+      (Buff[2]=#$08) and (Buff[3]=#$00) then begin
+          // dbase IV memo
+      lsize:=(PInteger(@Buff[4])^)-8;
+    end else begin
+      lsize:=0;
+    end;
+    repeat
+      if lsize>SizeOf(Buff) then begin
+        Stream.read(Buff,SizeOf(Buff));
+        Dst.Write(buff,SizeOf(Buff));
+        Dec(lsize,SizeOf(Buff));
+      end else if lsize>0 then begin
+        Stream.read(Buff,lsize);
+        Dst.Write(buff,lsize);
+        lsize:=0;
+      end;
+    until lsize=0;
+  end else begin
+    finish:=False;
+    Stream.read(Buff,SizeOf(Buff));
+    lastc:=#0;
+    repeat
+      for i:=0 to SizeOf(Buff)-2 do begin
+        if ((Buff[i]=#$1A) and
+          ((Buff[i+1]=#$1A) or ((i=0) and (lastc=#$1A))))
+          or (Buff[i]=#$0)
+          then begin
+          if i>0 then Dst.Write(buff,i);
+          finish:=True;
+          break;
+        end;
+      end;
+      if finish then Break;
+      Dst.Write(buff,512);
+      lastc:=Buff[511];
+      Stream.read(Buff,SizeOf(Buff));
+    until finish;
+  end;
+  Dst.Seek(0,0);
+end;
+
+procedure TDbtFile.WriteMemo(var MemoRecno:Integer;ReadSize:Integer;Src:TStream);
+var
+  ByteBefore:Integer;
+  ByteAfter:Integer;
+  Buff:array[0..511] of char;
+  i:Integer;
+  c:Byte;
+  Append:Boolean;
+begin
+  if _DbtVersion >= xBaseIV then begin // dBase4 memofiles
+    ByteBefore:=8;
+    ByteAfter:=0;
+  end else begin // stupid files
+    ByteBefore:=0;
+    ByteAfter:=2;
+  end;
+  if Src.Size = 0 then begin
+    MemoRecno:=0;
+  end else begin
+    if ((ByteBefore+Src.Size+ByteAfter+_MemoHdr.BlockLen-1) div _MemoHdr.BlockLen)
+      <= ((ReadSize+_MemoHdr.BlockLen-1) div _MemoHdr.BlockLen)
+      then begin
+      Append:=false;
+      //MemoRecno:=MemoRecno;
+    end else begin
+      Append:=True;
+      MemoRecno:=_MemoHdr.NextBlock;
+      if MemoRecno=0 then begin
+        _MemoHdr.NextBlock:=1;
+        MemoRecno:=1;
+      end;
+    end;
+    Stream.Seek(_MemoHdr.BlockLen * MemoRecno,0);
+    i:=Src.Position;
+    Src.Seek(0,0);
+    if ByteBefore=8 then begin
+      i:=$0008ffff;
+      Stream.Write(i,4);
+      i:=Src.Size+ByteBefore+ByteAfter;
+      Stream.Write(i,4);
+    end;
+    repeat
+      i:=Src.Read(buff,512);
+      if i=0 then break;
+      Inc(_MemoHdr.NextBlock);
+      Stream.Write(Buff,i);
+    until i<512;
+    if ByteAfter=2 then begin
+      c:=$1A;
+      Stream.Write(c,1);
+      Stream.Write(c,1);
+    end;
+    if Append then begin
+      Stream.Seek(0,0);
+      Stream.Write(_MemoHdr,SizeOf(_MemoHdr))
+    end;
+  end;
+end;
+
+//==========================================================
+//============ TIndexFile
+//==========================================================
+constructor TIndexFile.Create(const FileName: string; Mode: Word);
+var
+  ext:string;
+  i:Integer;
+begin
+  inherited Create(FileName,Mode);
+  HeaderSize:=0;
+  RecordSize:=512;
+
+  ext:=ExtractFileExt(FileName);
+  if (ext='.mdx') then begin
+    _IndexVersion:=xBaseIV;
+    if Mode = fmCreate then begin
+      FillChar(_MdxHdr,sizeof(_MdxHdr),0);
+    end else begin
+      Stream.read(_MdxHdr,SizeOf(_MdxHdr));
+    end;
+    for i:= 0 to _MdxHdr.TagUsed-1 do begin
+//      Stream.Position :=544 + i * _MdxHdr.TagSize;
+//      Stream.read(lMdxTag,SizeOf(rMdxTag));
+//      lIndex:=TIndex.Create(Self,lMdxTag.pageno);
+//      _Indexes.Add(lIndex);
+//      if i=0 then lIndex.ReadPage(lIndex._NdxHdr.startpage);
+    end;
+  end else begin
+    _IndexVersion:=xBaseIII;
+(*
+      _IndexFile._Seek(Pos);
+      _IndexFile.Stream.Read(_NdxHdr,SizeOf(_NdxHdr));
+      _Root:=TIndexPage.Create(Self);
+      _Root.SetPageNo(_NdxHdr.startpage);
+      lPos:=_Root;
+      _nblevel:=1;
+      repeat
+        lPos.LocalFirst;
+        if lPos.Entry._LowerPage=0 then break;
+        inc(_nblevel);
+    lChild:=TIndexPage.Create(Self);
+    lChild._UpperLevel:=lPos;
+    lPos._LowerLevel:=lChild;
+    lChild.SetPageNo(lPos.Entry._LowerPage);
+    lPos:=lChild;
+  until false;
+
+  _Spare:=TIndexPage.Create(Self);
+//  _Field:=_IndexFile._Dbf.FindField(_NdxHdr.KeyDesc);
+  First;
+*)
+  end;
+end;
+
+destructor TIndexFile.Destroy;
+begin
+  inherited;
+end;
+
+//==========================================================
+//============ TIndexPage
+//==========================================================
+constructor TIndexPage.Create(Parent:TIndex);
+begin
+  _LowerLevel:=nil;
+  _UpperLevel:=nil;
+  _Index:=Parent;
+  _PageNo:=-1;
+  _EntryNo:=-1;
+end;
+
+destructor TIndexPage.Destroy;
+begin
+  if _LowerLevel<>nil then _LowerLevel.Free;
+end;
+
+function  TIndexPage.GetPEntry(EntryNo:integer):PNdxEntry;
+begin
+  Result:=PNdxentry(@_PageBuff.Entries[_Index._NdxHdr.keyreclen*entryno]);
+end;
+
+function  TIndexPage.LocalInsert(Recno:integer; Buffer:Pchar;LowerPage:integer):boolean;
+var
+  src,dst:pointer;
+  siz:integer;
+begin
+  if _PageBuff.NbEntries < _Index._NdxHdr.nbkey then begin
+    src:=Entry;
+    dst:=GetPEntry(_EntryNo+1);
+    siz:=(_PageBuff.NbEntries - _EntryNo)
+      * _Index._NdxHdr.keyreclen + 8;
+    Move(Src^, Dst^, Siz);
+    inc(_PageBuff.NbEntries);
+    SetEntry(Recno,Buffer,LowerPage);
+    Write;
+    Result:=true;
+  end else begin
+    Result:=false;
+  end;
+end;
+
+
+function  TIndexPage.LocalDelete:boolean;
+var
+  src,dst:pointer;
+  siz:integer;
+begin
+  if _PageBuff.NbEntries >=0 then begin
+    if _EntryNo<_PageBuff.NbEntries then begin
+      src:=GetPEntry(_EntryNo+1);
+      dst:=Entry;
+      siz:=(_PageBuff.NbEntries - _EntryNo - 1)
+        * _Index._NdxHdr.keyreclen + 8;
+      Move(Src^, Dst^, Siz);
+    end;
+    dec(_PageBuff.NbEntries);
+    Write;
+    if ((_PageBuff.NbEntries=0) and (_lowerlevel=nil))
+      or (_PageBuff.NbEntries<0) then begin
+      if _UpperLevel<>nil then begin
+        _UpperLevel.LocalDelete;
+      end;
+    end else if (_EntryNo>LastEntryNo) then begin
+      SetEntryNo(LastEntryNo); // We just removed the last on this page.
+      if (_UpperLevel<>nil)  then begin
+        _UpperLevel.SetEntry(0,Entry^.CKey,_PageNo);
+      end;
+    end;
+    Result:=true;
+  end else begin
+    Result:=false;
+  end;
+end;
+
+function  TIndexPage.LastEntryNo:integer;
+begin
+  if (_LowerLevel=nil) then begin
+    result := _PageBuff.NbEntries - 1;
+  end else begin
+    result := _PageBuff.NbEntries;
+  end;
+end;
+
+procedure TIndexPage.LocalFirst;
+begin
+  SetEntryNo(0);
+end;
+
+procedure TIndexPage.LocalLast;
+begin
+  SetEntryNo(LastEntryNo);
+end;
+
+function TIndexPage.LocalPrev:boolean;
+begin
+  if _EntryNo>0 then begin
+    SetEntryNo(_EntryNo-1);
+    Result:=true;
+  end else begin
+    Result:=false;
+  end;
+end;
+
+function TIndexPage.LocalNext:boolean;
+begin
+  if (_EntryNo<LastEntryNo) then begin
+    SetEntryNo(_EntryNo+1);
+    Result:=true;
+  end else begin
+    Result:=false;
+  end;
+end;
+
+procedure TIndexPage.First;
+begin
+  LocalFirst;
+  if (_LowerLevel<>nil) then LowerLevel.First;
+end;
+
+procedure TIndexPage.Last;
+begin
+  LocalLast;
+  if (_LowerLevel<>nil) then LowerLevel.Last;
+end;
+
+function TIndexPage.Prev:boolean;
+begin
+  if (_LowerLevel<>nil) and LowerLevel.Prev then begin
+    result:=true;
+    exit;
+  end;
+  Result:=LocalPrev;
+  if Result and (Entry^._LowerPage>0) then LowerLevel.Last;
+end;
+
+function TIndexPage.Next:boolean;
+begin
+  if (_LowerLevel<>nil) and LowerLevel.next then begin
+    result:=true;
+    exit;
+  end;
+  Result:=LocalNext;
+  if Result and (Entry^._LowerPage>0) then LowerLevel.First;
+end;
+
+
+function TIndexPage.FindNearest(Recno:integer; Key:pchar):integer;
+var
+  cmpres:integer;
+  v1,v2:double;
+  p:TIndexPage;
+begin
+  Result:=-1;
+  if @Key=nil then begin
+    Exit;
+  end;
+  SetEntryNo(0);
+  while _EntryNo<=_PageBuff.NbEntries do begin
+    if _EntryNo=_PageBuff.NbEntries then break;
+    if _Index._NdxHdr.keytype='C' then begin
+      cmpres:=StrLIComp(PChar(Key),Entry^.CKey,_Index._FieldLen);
+    end else begin
+      // Numeric field... to do
+      v1:=PDouble(Key)^;
+      v2:=Entry^.NKey;
+      if v1>v2 then cmpres:=1
+      else if v1<v2 then cmpres:=-1
+      else cmpres:=0;
+    end;
+    if cmpres=0 then begin
+      if _LowerLevel=nil then begin
+        if (Entry^.RecNo=Recno) then begin
+          result:=0;
+          Exit;
+        end else if (Entry^.Recno>Recno) then begin
+          result:=-1;
+          Exit;
+        end;
+      end else begin
+        p:=self;
+        while p._LowerLevel<>nil do begin
+          p:=p.LowerLevel;
+          p.LocalLast;
+        end;
+        if (p.Entry^.Recno>=Recno) then begin
+          result:=-1;
+          Exit;
+        end;
+      end;
+    end else if cmpres<0 then begin
+      result:=-1;
+      exit;
+    end;
+    SetEntryNo(_EntryNo+1);
+  end;
+  result:=1;
+  Exit;
+end;
+
+procedure TIndexPage.SetEntry(Recno:Integer; key:PChar; LowerPage:integer);
+begin
+  assert((_EntryNo>=0) and (_EntryNo<=_PageBuff.NbEntries));
+  if (_EntryNo=self._PageBuff.NbEntries) then begin
+    if (_UpperLevel<>nil)  then begin
+      _UpperLevel.SetEntry(0,key,Self._PageNo);
+    end;
+  end else begin
+    if _Index._NdxHdr.keytype='C' then begin
+      mymove(key,Entry^.CKey,_Index._NdxHdr.keylen);
+    end else begin
+      Entry^.NKey:=PDouble(key)^;
+    end;
+  end;
+  Entry^.RecNo:=RecNo;
+  Entry^._LowerPage:=LowerPage;
+  Write;
+end;
+function TIndexPage.LowerLevel : TIndexPage;
+begin
+  if (_LowerLevel<>nil) and (_LowerLevel._PageNo<>Entry^._LowerPage) then begin
+    _LowerLevel.SetPageNo(Entry^._LowerPage);
+  end;
+  result:=_LowerLevel;
+end;
+
+function TIndexPage.Insert(Recno:Integer; Buffer:PChar; LowerPage:integer):boolean;
+var
+  src,dst:PNdxEntry;
+  siz:integer;
+  split,old_entry:integer;
+  lSpare:TIndexPage;
+begin
+  if not LocalInsert(recno,buffer,lowerpage) then begin
+    // The entry is FULL so we will split this page
+    // 1 - Check parent exist
+    if _UpperLevel=nil then begin
+      AddNewLevel;
+    end;
+
+    old_entry:=_EntryNo;
+    split:=_EntryNo;
+    if split < _Index._NdxHdr.nbkey div 2 then begin
+      split:=_Index._NdxHdr.nbkey div 2;
+    end;
+    lSpare:=TIndexPage.Create(_Index);
+    try
+      // 2 - Create new page with first part
+      inc(_Index._NdxHdr.nbPage);
+      lSpare._PageNo:=_Index._NdxHdr.nbPage;
+      _Index._IndexFile._Seek(_Index._RootPage);
+      _Index._IndexFile.Stream.WriteBuffer (_Index._NdxHdr, SizeOf(_Index._NdxHdr));
+
+      if _lowerlevel=nil then begin
+        lSpare._PageBuff.NbEntries:=split;
+      end else begin
+        lSpare._PageBuff.NbEntries:=split-1;
+      end;
+      siz:=split*_Index._NdxHdr.keyreclen+8;
+      src:=@_PageBuff.Entries;
+      dst:=@lSpare._PageBuff.Entries;
+      Move(src^,dst^,siz);
+      lSpare.Write;
+
+      // 3 - Keep only end-part in this page
+      siz:=(_PageBuff.NbEntries-Split);
+      _PageBuff.NbEntries:=siz;
+
+      siz:=siz*_Index._NdxHdr.keyreclen+8;
+      SetEntryNo(split);
+      src:=Entry;
+      SetEntryNo(0);
+      dst:=Entry;
+      Move(src^,dst^,siz);
+
+      // 3 - Update upper level
+      lSpare.SetEntryNo(split-1);
+      _UpperLevel.Insert(0,lSpare.Entry^.CKey,lSpare._PageNo);
+
+      // We just need to go on inserted record now
+
+      if old_entry>=split then begin
+        _UpperLevel.LocalNext;
+        SetEntryNo(old_entry - split);
+        LocalInsert(Recno,Buffer,LowerPage);
+        lSpare.Write;
+      end else begin
+        lSpare.SetEntryNo(old_entry);
+        lSpare.LocalInsert(Recno,Buffer,LowerPage);
+        Write;
+      end;
+    finally
+      lspare.free;
+    end;
+  end;
+    Result:=true;
+end;
+
+function TIndexPage.Delete:boolean;
+begin
+  Result:=LocalDelete;
+end;
+
+procedure TIndexPage.SetPageNo(page:Integer);
+begin
+  if (_PageNo<>page) and (page>0) then begin
+    _Index._IndexFile.ReadRecord(Page,@_PageBuff);
+    _PageNo:=page;
+    _EntryNo:=-1;
+  end;
+end;
+
+procedure TIndexPage.AddNewLevel;
+var
+  lNewPage:TIndexPage;
+begin
+  lNewPage:=TIndexPage.Create(_Index);
+  inc(_Index._NdxHdr.nbPage);
+  lNewPage._PageNo:= _Index._NdxHdr.nbPage;
+  _Index._NdxHdr.startpage:= _Index._NdxHdr.nbPage;
+  _Index._IndexFile._Seek(_Index._RootPage);
+  _Index._IndexFile.Stream.WriteBuffer (_Index._NdxHdr, SizeOf(_Index._NdxHdr));
+
+  lNewPage._PageBuff.NbEntries:=0;
+  lNewPage._UpperLevel:=nil;
+  lNewPage._LowerLevel:=_Index._Root;
+  lNewPage.SetEntryNo(0);
+  lNewPage.SetEntry(0,nil,_PageNo);
+  _Index._Root._UpperLevel:=lNewPage;
+  _Index._Root:=lNewPage;
+  lNewPage:=nil;
+end;
+
+procedure TIndexPage.Write;
+begin
+  _Index._IndexFile.WriteRecord(_PageNo,@_PageBuff);
+end;
+
+procedure TIndexPage.SetEntryNo(entryno:Integer);
+begin
+  if (_EntryNo<>entryno) then begin
+    _EntryNo:=entryno;
+    if _EntryNo>=0 then Entry:=PNdxentry(@_PageBuff.Entries[_Index._NdxHdr.keyreclen*entryno]);
+  end;
+end;
+
+procedure TIndexPage.WritePage(Page:integer);
+begin
+  _Index._IndexFile.WriteRecord(Page,@_PageBuff);
+end;
+
+//==========================================================
+//============ TIndex
+//==========================================================
+constructor TIndex.Create(Parent:TIndexFile; RootPage:integer;CreateIt:boolean);
+var
+  lPos:TIndexPage;
+  lChild:TIndexPage;
+begin
+  _RootPage:=RootPage;
+  _IndexFile:=Parent;
+  //_IndexOrder:=TList.Create;
+  if CreateIt then begin
+    FillChar(_NdxHdr,sizeof(_NdxHdr),0);
+    _NdxHdr.startpage:=1;
+    _NdxHdr.nbPage:=2;
+    _NdxHdr.keyformat:=#0;
+    _NdxHdr.keytype:='C';
+
+    _IndexFile._Seek(RootPage);
+    _IndexFile.Stream.Write(_NdxHdr,SizeOf(_NdxHdr));
+    _FieldPos := 0;
+    _FieldLen := 0;
+  end else begin
+    _IndexFile._Seek(RootPage);
+    _IndexFile.Stream.Read(_NdxHdr,SizeOf(_NdxHdr));
+  end;
+
+  _Root:=TIndexPage.Create(Self);
+  _Root.SetPageNo(_NdxHdr.startpage);
+  lPos:=_Root;
+  _nblevel:=1;
+  repeat
+    lPos.LocalFirst;
+    if lPos.Entry^._LowerPage=0 then break;
+    inc(_nblevel);
+    lChild:=TIndexPage.Create(Self);
+    lChild._UpperLevel:=lPos;
+    lPos._LowerLevel:=lChild;
+    lChild.SetPageNo(lPos.Entry^._LowerPage);
+    lPos:=lChild;
+  until false;
+
+  inc(_IndexFile._cntuse);
+  First;
+end;
+
+destructor TIndex.Destroy;
+begin
+  _IndexFile.Release;
+   _Root.Free;
+end;
+
+
+function TIndex.Find(Recno:integer; Buffer:PChar; var pPos:TIndexPage):integer;
+var
+  res:integer;
+begin
+  pPos:=_Root;
+  repeat
+    res:=pPos.FindNearest(Recno,Buffer);
+    if res<>0 then begin
+      if pPos.Entry^._LowerPage<>0 then begin
+        pPos:=pPos.LowerLevel;
+        res:=2;
+      end;
+    end;
+  until res<>2;
+  Result:=res;
+end;
+
+procedure TIndex.Update(Recno: integer; PrevBuffer,NewBuffer: PChar);
+var
+  lPos:TIndexPage;
+begin
+  if _FieldLen=0 then exit;
+
+  inc(PrevBuffer,_FieldPos);
+  inc(NewBuffer,_FieldPos);
+
+  if StrLIComp(PrevBuffer,NewBuffer,_FieldLen)<>0 then begin
+    Delete;
+    Find(Recno+1,NewBuffer,lPos);
+    lPos.Insert(Recno+1,NewBuffer,0);
+  end;
+end;
+
+procedure TIndex.Insert(Recno:integer; Buffer:PChar);
+var
+  lPos:TIndexPage;
+begin
+  if _FieldLen=0 then exit;
+
+  inc(Buffer,_FieldPos);
+
+  Find(Recno+1,Buffer,lPos);
+  lPos.Insert(Recno+1,Buffer,0);
+end;
+
+function TIndex.Delete:boolean;
+var
+  lPos:TIndexPage;
+begin
+  lpos:=_root;
+  while lpos._LowerLevel<>nil do begin
+    lPos:=lPos.LowerLevel;
+  end;
+  lPos.Delete;
+  Result:=true;
+end;
+
+
+function TIndex.Pos:TIndexPage;
+var
+  p:TIndexPage;
+begin
+  p:=_Root;
+  while p.Entry^._LowerPage>0 do begin
+    p:=p.LowerLevel;
+  end;
+  result:=p;
+end;
+
+procedure TIndex.First;
+begin
+  _Root.First;
+  dec(Pos._EntryNo);
+end;
+
+procedure TIndex.Last;
+begin
+  _Root.Last;
+  inc(Pos._EntryNo);
+end;
+
+function TIndex.Prev:boolean;
+begin
+  result:=_Root.Prev;
+end;
+
+function TIndex.Next:boolean;
+begin
+  result:=_Root.Next;
+end;
+
+(*
+procedure TIndex.SetRecNo(Value: Integer);
+var
+  pos:integer;
+  p:TIndexPage;
+  i:integer;
+  ldiv:integer;
+begin
+  p:=_Root;
+  ldiv:=1;
+  while p.Entry^._LowerPage>0 do begin
+    ldiv:=ldiv*(_NdxHdr.nbkey+1);
+    p:=p._LowerLevel;
+  end;
+  pos:=value div ldiv;
+  p:=_Root;
+  while p.Entry^._LowerPage>0 do begin
+    p._EntryNo:=pos;
+    value:=value - pos * (_NdxHdr.nbkey+1);
+    ldiv:=ldiv div (_NdxHdr.nbkey+1);
+    pos:=value div ldiv;
+    p:=p._LowerLevel;
+  end;
+{
+  pos:=1;
+  First;
+  While pos<value do begin
+    if Next = false then break;
+    inc(pos);
+  end;
+}
+end;
+*)
+function TIndex.GuessRecordCount: Integer;
+var
+  lPos:TIndexPage;
+  nbrecord:integer;
+begin
+  // I just read first level and Guess an approximate record count...
+  nbrecord:=_Root._PageBuff.NbEntries;
+  lPos:=_Root.LowerLevel;
+  while lpos<>nil do begin
+    nbrecord:=nbrecord*(_NdxHdr.nbkey+1);
+    lPos:=lPos.LowerLevel;
+  end;
+  result:=nbrecord;
+end;
+
+
+function TIndex.GuessRecNo:Integer;
+var
+  p:TIndexPage;
+begin
+  p:=_Root;
+  result:=p._EntryNo;
+  while p.Entry^._LowerPage>0 do begin
+    p:=p.LowerLevel;
+    Result:=Result*(_NdxHdr.nbkey+1) + p._EntryNo;
+  end;
+end;
+
+function TIndex.GetRealRecNo:integer;
+var
+  ippos : TIndexPage;
+begin
+  ippos:=_Root;
+  while ippos._LowerLevel<>nil do begin
+    ippos:=pos.LowerLevel;
+  end;
+  if (ippos._EntryNo<0) or (ippos._EntryNo>=ippos._PageBuff.NbEntries) then Result:=-1
+  else Result:=ippos.Entry^.RecNo-1;
+end;
+
+procedure TIndex.GotoKey(recno:integer; buffer:pchar);
+begin
+  // very temporary implementation
+  // could definitely be a bit faster.
+  _Root.First;
+  repeat
+    if self.Pos.Entry^.RecNo=(recno+1) then begin
+      exit;
+    end;
+  until Next=false;
+end;
+
+procedure TIndex.InitFieldDef(dbfFile:TDbfFile;FieldDesc:string);
+var
+  FieldInfo:TMyFieldInfo;
+begin
+  FieldInfo:=DbfFile.GetFieldInfo(FieldDesc);
+  if FieldInfo<>nil then begin
+    _FieldPos:=FieldInfo.Offset;
+    _FieldLen:=FieldInfo.Size;
+  end;
+end;
+
+//==========================================================
+//============ initialization
+//==========================================================
+
+{$ifndef fpc}
+type
+
+  TTableNameProperty = class(TStringProperty)
+  public
+    procedure Edit; override;
+    function GetAttributes: TPropertyAttributes; override;
+  end;
+
+procedure TTableNameProperty.Edit; {override;}
+var
+  FileOpen: TOpenDialog;
+  Dbf: TDbf;
+begin
+  FileOpen := TOpenDialog.Create(Application);
+  try
+    with fileopen do begin
+      Dbf:=GetComponent(0) as TDbf;
+      Filename := Dbf.DesignTimePath + GetValue;
+      Filter := 'Dbf table|*.dbf';
+      if Execute then begin
+        SetValue(ExtractFilename(Filename));
+        Dbf.DesignTimePath:=ExtractFilePath(Filename);
+      end;
+    end;
+  finally
+    Fileopen.free;
+  end;
+end;
+
+function TTableNameProperty.GetAttributes: TPropertyAttributes; {override;}
+begin
+  Result := [paDialog, paRevertable];
+end;
+
+
+
+type
+  TRunTimePathProperty = class(TStringProperty)
+  end;
+
+  TDesignTimePathProperty = class(TStringProperty)
+  end;
+
+//==========================================================
+//============ initialization
+//==========================================================
+
+procedure Register;
+begin
+  RegisterComponents('Exemples', [TDbf]);
+  RegisterPropertyEditor(TypeInfo(string), TDbf, 'TableName', TTableNameProperty);
+  RegisterPropertyEditor(TypeInfo(string), TDbf, 'RunTimePath', TRunTimePathProperty);
+  RegisterPropertyEditor(TypeInfo(string), TDbf, 'DesignTimePath', TDesignTimePathProperty);
+//  RegisterPropertyEditor(TypeInfo(TStrings), TDbf, 'IndexFiles', TIndexFilesProperty);
+//  ShowMessage(ToolServices.GetProjectName);
+end;
+{$endif fpc}
+
+initialization
+    _PagedFiles := TList.Create;
+    tDbf_TrimFields := true;
+
+finalization
+    _PagedFiles.free;
+
+end.

+ 45 - 0
fcl/db/dbase/testdbf.pp

@@ -0,0 +1,45 @@
+program dumpdb;
+
+{$i+}
+
+uses db,dbf,sysutils;
+
+Procedure DumpTable (Const TN,FN : String);
+
+Var
+  I,Count : longint;
+  F : Text;
+  Buf : Array[1..1024*4] of byte;
+  
+begin
+  Assign(F,FN);
+  Rewrite(F);
+  SetTextBuf(F,Buf);
+  With TDBF.Create(Nil) do
+    begin
+    TableName:=TN;
+    Open;
+    While not EOF do
+      begin
+      Inc(Count);
+      For I:=0 to FieldCount-1 do
+        With Fields[i] do 
+          Writeln(F,FieldName:20,' : ',AsString);
+      Writeln(F,StringOfChar('=',72));
+      Next;
+      end;
+    end;
+  Writeln(F,'Dumped total of ',Count,' records.');
+  Close(F);
+end;
+
+Var i : longint;
+
+begin
+  If ParamCount<2 then
+    begin
+    Writeln('Usage: dumpdb tablename filename');
+    Halt(1);
+    end;
+  DumpTable(Paramstr(1),Paramstr(2));
+end.