             The Unit For Connection With DBF Tables
                  (ODBFile.Pas OR OWDBFile.Pas)


This unit represents an opportunity of  databases  in  the  dBASE
format manipulation with usage of the object-oriented approach.

There are two variants of the unit now:
- for DOS applications (as usual in Turbo Vision applications, or
  at least in programs with use of "Objects"  unit,  because  the
  mechanism of collections is used);
- for Windows applications (in Object Windows applications of BPW
  7.0); the main difference is that dynamically allocated  memory
  allocates  through  GlobalAlloc function of Windows.

The unit  describes  two  object  types:  TField  (contains  full
information about DB field) and TDBF (offers OO interface with DB
file).


     1. Object TField is  inherited  from  TObject.  It  has  the
following fields:

FiName: Array [0..10] of Char;
Description: database field name.

FiType: Char;
Description: database field type; may accept values 'C'  -  Char,
'N' - Numeric, 'D' - Date, 'L' - Logical (Boolean), 'M' - Memo.

FiOfs: Longint;
Description: field's offset from the start of a record.

FiLength: Byte;
Description: field's length; for  'C'  type  this  parameter  may
accept values between 1..254, for 'N' type - 1..19, for 'D'  type
- 8, for 'L' type - 1, for 'M' type - 10 bytes.

FiDecimals: Byte;
Description: number of symbols after a decimal point;  uses  only
for number fields (type 'N').


     2. TDBF  object  is  inherited  from  TObject.  It  has  the
following fields:

FileHeader:  TFileHeader;
Description: pascal record with a description of DBF-file header.

MemoHeader:  TMemoHeader;
Description: pascal record with a description of DBT-file  header
(if database contains memo-fields).

hDBFMem: THandle;
Description: handle of a dinamically distributed by Windows  area
of memory, which is used by object for DB  fields' headers  array
and for operating DB  record  window  (only  OWDBFile!);  methods
LockMem and UnlockMem (both only for OWDBFile!)  let  to  address
this area through pointers Fields and RecBuffer. In  DOS  version
of the unit (ODBFile) these pointers are, of course, fixed.

DBFName, DBTName: Array  [0..79]  of  Char;
Description: full names of DBF-file of DB and DBT-file (if DB has
memo-fields).

DBFError: Integer;
Description:  status  variable;  its  possible  values  must   be
interpreted the following way:

      0 - OK;
      1 - Cannot Open File;
      2 - Error Reading File;
      3 - Not DBF-File;
      4 - Error Writing File;
      5 - Error in Structure;
      6 - Empty Structure;
      7 - Record Out of Range;
      8 - Unknown Name;
      9 - Error Reading N/D/L Field;
     10 - Error Writing N/D/L Field;
     11 - Memory Error (only for OWDBFile).

It must be noted that any method which deals with database sets a
value into this variable as a result of its work, so if you  want
to make your  system  reliable  you  must  check  it  after  each
operation with data and set it to 0 (if it isn't) after  checking
(see method ClearError).

RecNo: Longint;
Description: number of the  current  database  record,  which  is
reflected in the operating window (see RecBuffer).

Fields: PFieldList;
Description:  pointer  to  database  fields'  headers  array;  in
OWDBFile is private and takes value only between a pair of  calls
LockMem..UnlockMem (see hDBFMem).

RecBuffer: PChar;
Description: pointer to memory area which is used as operating DB
record window (for access to current DB record); in  OWDBFile  is
private  and  takes  value  only  between  a  pair    of    calls
LockMem..UnlockMem (see hDBFMem). After jump  to  any  DB  record
(see methods Go, GoTop, GoBottom, Skip, AppendBlank)  all  fields
of this record are copied into this memory area; after saving  of
made changes (see method  ReplaceRecord)  information  from  this
area updates corresponding part of DBF-file.

     TDBF object has the following methods:

Constructor Init;
Description: initializes an object, fills its fields  by  default
values.

Destructor Done; virtual;
Description:  deinitializes  an  object  and  makes   dinamically
allocated memory free.

Procedure Use (Path, Name: PChar);
Description: opens existing DB with file name Name  in  directory
Path; if error occures,  sets  corresponding  value  in  DBFError
field, as any other data manipulation method.

Procedure Create (Path, Name: PChar; Structure: PCollection);
Description: creates a database with file name Name in  directory
Path; the structure of  this  new  database  is  described  as  a
collection of TField objects Structure; you may remain unassigned
fields FiOfs of TField objects when you form this collection.

Function GetStructure: PCollection;
Description: returns  a  pointer  to  freshly  created  (by  this
function) collection of TField objects, which fully describes the
current DB structure.

Procedure AppendBlank;
Description: adds to the end  of  current  DB  empty  (filled  by
spaces) record  and  makes  it  current;  header  of  current  DB
updates, variable RecNo accepts the number of new record.

Procedure Go (N: Longint);
Description: makes Nth record of DB current; its fields are  read
into operating window, variable RecNo accepts value N.

Procedure GoTop;
Description: makes first record current; equal Go(1).

Procedure GoBottom;
Description:  makes  last  record  of  database  current;   equal
Go(FileHeader.NumOfRecords).

Procedure Skip (N: Longint);
Description: makes current a record which is  offset  to  N  from
actually current record; equal Go(RecNo+N).

Procedure ReplaceRecord;
Description:  updates  current  record  in  DBF-file  with    its
reflection, edited in operating window. ATTENTION: you must  call
this method after any kind of  current  record  change  (such  as
SetField, SetN, SetL, SetD, Delete or  UnDelete),  or  else  your
changes will have no effect.

Procedure Delete;
Description:  marks  current  record  (in  operating  window)  as
deleted (writing '*' as its first symbol).

Procedure Undelete;
Description: marks current record undeleted (even if it was,  but
didn't physically removed by Pack) in operating  window  (writing
space as its first symbol).

Function Deleted: Boolean;
Description: returns TRUE if current record in  operating  window
is marked as deleted (first symbol is '*'), else returns FALSE.

Procedure GetField (FieldName: PChar; P: PChar);
Description: copies value of field with the name  FieldName  from
operating window of  current  record  as  zero-terminated  string
(ZTS); buffer size must be at least 1 byte greater  then  maximum
size of corresponding field (FiLength).

Procedure GetN (FieldName: PChar; P: PChar; var N: Real);
Description:  copies  value  of  numeric  field  with  the   name
FieldName from operating window of current record as  ZTS  P  (as
GetField); buffer size must be  at  least  1  byte  greater  then
maximum  size  of  corresponding  field  (FiLength);    moreover,
translates this string in the value of real-type variable N.

Procedure GetD (FieldName: PChar; P: PChar; var Y, M, D: Word);
Description: copies value of date field with the  name  FieldName
from operating window of current record as ZTS P  (as  GetField);
buffer size must be at least 9 bytes; moreover,  translates  this
string in the values of word-type variables Y (year), M  (month),
D (day).

Procedure GetL (FieldName: PChar; P: PChar; var L: Boolean);
Description:  copies  value  of  logical  field  with  the   name
FieldName from operating window of current record as  ZTS  P  (as
GetField); buffer size  must  be  at  least  9  bytes;  moreover,
translates this string in the value of boolean-type variable L.

Procedure SetField (FieldName: PChar; P: PChar);
Description: copies the contents of buffer P (until #0) into  the
field of operating window named FieldName; the rest of this field
fills by spaces.

Procedure SetN (FieldName: PChar; N: Real);
Description: sets the value of  real-type  variable  N  into  the
numeric field of operating window named FieldName.

Procedure SetD (FieldName: PChar; Y, M, D: Word);
Description: sets the values of word-type variables Y  (year),  M
(month) and D (day) into the date field of operating window named
FieldName.

Procedure SetL (FieldName: PChar; L: Boolean);
Description: sets the value of boolean-type variable L  into  the
logical field of operating window named FieldName.

Procedure ForEach (Iterator: PIterProc);
Description: calls repetition of the same action for all  records
of database; as a parameter receives a pointer  to  a  far  local
procedure without parameters, in which the access to actual  TDBF
object is organized through  global  variable  CurrentDBF:  PDBF;
type PIterProc is defined the following way:

     TIterProc = Procedure;     PIterProc = ^TIterProc;

Function FirstThat (Iterator: PIterFunc): Longint;
Description: seeks in the DB the first  record,  which  satisfies
the condition of user boolean function Iterator; as  a  parameter
receives a pointer  to  a  far  local  boolean  function  without
parameters,  in  which  the  access  to  actual  TDBF  object  is
organized through global variable CurrentDBF: PDBF; if the search
is successful, FirstThat returns the number of  the  find  record
and this record becomes current - otherwise it  returns  0;  type
PIterFunc is defined the following way:

     TIterFunc = Function: Boolean;     PIterFunc = ^TIterFunc;

Function LastThat (Iterator: PIterFunc): Longint;
Description: the same as FirstThat, but seeks the  last  database
record, which satisfies the condition (search goes backward  from
the end of the file).

Function NextThat (Iterator: PIterFunc): Longint;
Description: the same as FirstThat, but search goes forward from
the next record after the current one.

Function PredThat (Iterator: PIterFunc): Longint;
Description: the same as LastThat, but search goes backward  from
the previous record before the current one.

Procedure Pack;
Description: rewrites DB fully, except records which  are  marked
as deleted; old variant of file saves with extention BAK.

Procedure ClearError;
Description: writes 0 into object field DBFError.

Procedure LockMem;     {only for OWDBFile}
Description: fixes memory area of hDBFMem.

Procedure UnlockMem;   {only for OWDBFile}
Description: unfixes memory area of hDBFMem.


     3. There are several additional functions in the unit:

Procedure GetUniqueName (Path, Name: PChar);
Description: produces a possible unique file  name  Name  in  the
pointed by Path directory.

Procedure DateString (P: PChar; Y, M, D: Word; Mode: Byte);
Description: creates symbolic expression in buffer P according to
the date (D.M.Y);
 if Mode=0, Expression is Like in Database - YYYYMMDD (StrLen=8);
 if Mode=1, Expression is Normal - DD.MM.YYYY (StrLen=10);
 if Mode=2, Expression is Alternative - MM/DD/YYYY (StrLen=10);
in case of error returns array of spaces in the buffer P.

Procedure SplitDate (P: PChar; var Y, M, D: Word; Mode: Byte);
Description: deciphers symbolic expression of date into variables
(D.M.Y);
 if Mode=0, Expression is Like in Database - YYYYMMDD (StrLen=8);
 if Mode=1, Expression is Normal - DD.MM.YYYY (StrLen=10);
 if Mode=2, Expression is Alternative - MM/DD/YYYY (StrLen=10);
in case of error returns Y=0, M=0, D=0.

Procedure NextDate (var Y, M, D: Word);
Description: shows the next calendar date.

Function CountDays (Y1, M1, D1, Y2, M2, D2: Word): Longint;
Description:  counts  number  of  days  between  two  dates   (if
(Y1,M1,D1)=(Y2,M2,D2) then Returns 1).

Function RusWinToDos (P: PChar): PChar;   {only for OWDBFile}
Description:  translates  russian  letters  of  Windows  standard
(1251) into DOS (866). I don't know about other languages, but in
Russian different standard encodings of national symbols exist in
DOS and Windows. Personally I prefer to store text  data  in  DOS
encoding, but in order to read/write it from Windows applications
I use this function and the next one. People!  If  you  write  in
such style functions for other languages (e.g. Bulgarian, Serbian
etc.), I'll insert them in this unit with pleasure.

Function RusDosToWin (P: PChar): PChar;   {only for OWDBFile}
Description: translates russian letters  of  DOS  standard  (866)
into Windows (1251).


     4. Weak sides of the current version of this unit:

a) database indexes are not supported yet;

b) iteration procedures and  functions  (parameters  of  ForEach,
   FirstThat, ... methods) "see" only global variables;

c) existance of memo fields don't call  any  error,  but  storing
   data in memo fields aren't supported.


     5. Any suggestions and remarks are welcome.


Written by Leonid Schavelev (December, 1995)
Ivanovo State Power University
Ivanovo
Russia
E-mail: leonid@polytech.ivanovo.su

