(****************************************************************)
(*                     DATABASE TOOLBOX 4.0                     *)
(*     Copyright (c) 1984, 87 by Borland International, Inc.    *)
(*                                                              *)
(*                     Reflex Unit                              *)
(*  Routines to create Reflex files from Turbo Pascal Access    *)
(*  files and vice versa.                                       *)
(****************************************************************)
unit Reflex;

interface

uses DOS,
     CRT,
     FileUtil,
     MiscTool,
{    If a compiler error occurs here, you need to unpack the source
     to the MiscTool unit from the archived file Tools.arc.  See the
     README file on disk 1 for detailed instructions. }

     FieldDef,
     RealConv,
     RefDate;

const
  MaxSections = 44;     { Maximum number of sections in a Reflex file }
  MaxField = 249;       { Maximum number of fields in Reflex record }

type
  FileName = String[66];
  ErrorStr = string[80];
  { Information needed to access a particular logical section  in
    a Reflex file }
  SectionDesc = record
                  SectionType : integer;
                  SectionAddr,
                  SectionLen : LongInt;
                end; { SectionDesc }

  { Fixed length Reflex file header.  We are mostly concerned with
    Dfsection, which holds the information on the other, variable
    length sections in the file where the actual data will be stored }
  RefHeader = record
                HdrSz : integer;
                Stamp : array[1..12] of char;
                Dirty,
                VerViews,
                VerModels,
                VerData,
                fRecalc  : integer;
                  { If error set fRecalc so that Reflex will recalculate }
                ScreenType,
                CheckSum : byte;
                Reserved : array[1..38] of byte;
                SectionCt : integer;
                DfSection : array[1..MaxSections] of SectionDesc;
                buffer : real;
              end; { RefHeader }

{ Besides the File Header, a reflex file is built out of variable length
  structures.  Data records for example are variable size.  To represent
  a variable sized record we will use the following structure }
  VarLenBuf = record              { represents a variable length buffer }
                MaxAllocate,    { length initially allocated for buffer }
                Len : word;                   { length of the buffer }
                Buf : ^byte;        { pointer to the buffer, use GetMem }
              end;


  {  This is how the field names are actually stored in the Reflex file.
     There are three variable length records.  FieldNamePool actually
     contains the names of the record fields.  The FieldNameIndex is
     a pointer into the FieldNamePointers.  FieldDescriptions contains
     the information about each field name (pool ptr), type, offset in
     record etc.  At this time a RepeatingTextPool will not be created.
  }
  ReflexFieldDirectory = record
                           FieldNameIndex,
                           FieldNamePool,
                           FieldDescriptions,
                           RepeatingTextPool : VarLenBuf;
                         end;

  ETRec = record
            Index,
            Pool : LongInt;
          end;
  DescPtr = ^FieldDesc;
  FieldDesc = record
                NameOffset : integer;
                DataType   : byte;
                PrecForm   : byte;
                FieldOffset : integer;
                Etr : ETRec;
                SortPos,
                Reserved : byte;
              end;

    FieldDescTbl = array[0..MaxField] of DescPtr;

   RepTPool  =  ^TextPool;
   TextPool = record
                FIDNum : byte;
                PoolIndex,
                Pool : VarLenBuf;
                Next : RepTPool;
              end;

  ReflexRef = record
{ This record represents a Reflex Database file variables
  of this type are used in almost every routine to indicate
  which Reflex file is being manipulated and the record
  structure of that file. }
    RefFile : File;                      { Reflex file variable }
    CurrentRecord,
    NumberOfRecs : integer;
    Modified : boolean;
    LocalTextPool,                { used for the current record }
    RepeatingTextPool   : VarLenBuf;
    DataSectionAddr,                { start of the data section }
    DataSectionLen : LongInt;         { length of the data section }
    ReflexHeader : RefHeader;              { Reflex file header }
    FieldsIncluded : integer;
    FieldDir : ReflexFieldDirectory;
    FieldDescriptors : FieldDescTbl;
    RepTextPool : RepTPool;
    FixedRecordLen : word;
    TextFields : byte;
    ReflexRec : VarLenBuf;
    FDTable : FieldDirectory;
  end;

procedure AddReflexRec(var ReflexF : ReflexRef;
                       var TurboRec);
{ Converts the Pascal record TurboRec into a Reflex record
  and adds it to the file specified by ReflexF.
}

procedure CloseReflexFile(var ReflexF : ReflexRef);
{  Saves important reflex file header information and closes the
   file specified by ReflexF. Note: This routine is required! when
   modifying reflex files. }

procedure GetReflexRec(var ReflexTable : ReflexRef;
                       var TurboRec;
                       RecordNum : integer);
{  Gets a reflex variable length data record specified by
   record num and translates it to a Turbo Pascal fixed length
   record of the type specificed in the .DEF file. }

procedure MakeReflexFile(var ReflexF : ReflexRef;
                         RefFileNm : FileName;
                         var FD : FieldDirectory);
{ Creates a reflex file name RefFileNm, with a record
  definition specified in FD.  ReflexF will be used to refer
  to this file in all subsequent operation.
}

function OpenReflexFile(var ReflexF : ReflexRef;
                            RefFileNm : FileName): boolean;
{  Opens the reflex file named RefFileNm, and generates
   a defintion file which describes the structure
   of the reflex record. ReflexF will be used to refer to
   this file in all subsequent operations. }

function ReflexFileLen(var ReflexF : ReflexRef) : integer;
{  Returns the number of Records in the Reflex file referenced
   by ReflexF. }

function SetUpReflexFD(var ReflexF : ReflexRef;
                       var FDFileNm : FileSpec;
                       TAccessF,
                       LoadFDFile : boolean) : boolean;

implementation

{$V-}

const
  DataSectionNum = 1;
  MasterSectionNum = 2;
  FieldDirSectionNum = 3;
  FieldDirSection  = 2;   { relevant sections in the reflex file }
  MasterRecSection = 9;
  DataRecSection   = 1;

type
  {  We move through the records, one field at a time.  This record
     is used to keep track of the offset into the records. }
  TranslateRec = record
                   ReflexOffset,
                   TurboOffset : word;
                 end;

var
  Trans : TranslateRec;

procedure TranslateError(E : ErrorStr);
{ Tells the user the error and then halts }
begin
  Beep;
  Window(1, 1, 80, 25);
  GotoXY(1, 24);
  Write('Translate Error: ');
  GotoXY(1, 25);
  Write(' ', E, ', terminating...');
  Halt;
end; { TranslateError }

procedure AllocateBuf(var V : VarLenBuf; Max : integer);
{ Allocates the space for a variable length buffer of Max
  number of bytes }
begin
  FillChar(V, SizeOf(V), 0);
  with V do
  begin
    MaxAllocate := Max;
    GetMem(Buf, MaxAllocate);
  end;
end; { AllocateBuf }

procedure DeallocateBuf(var V : VarLenBuf);
{ Deallocates the space used by a variable length buffer }
begin
  with V do
  begin
    FreeMem(Buf, MaxAllocate);
    Buf := nil;
  end;
end; { DeallocateBuf }

procedure WriteBuffer(var OutFile : File;
                      var B : VarLenBuf);
var
  BlocksWritten : integer;
begin
  with B do
  begin
    BlockWrite(OutFile, Len, SizeOf(Len), BlocksWritten);
    BlockWrite(OutFile, Buf^, Len, BlocksWritten);
  end;
end; { WriteBuffer }

procedure ReadBuffer(var InFile : File;
                     var B : VarLenBuf);
var
  RecsRead : integer;
begin
  with B do
  begin
    BlockRead(InFile, Len, 2, RecsRead);
    AllocateBuf(B, Len);
    Len := MaxAllocate;
    BlockRead(InFile, Buf^, Len, RecsRead);
    if RecsRead <> Len then
      TranslateError('In ReadBuffer the length is wrong, eof?...');
  end;
end; { ReadBuffer }

procedure GetText(FieldNameText : VarLenBuf;
                  Offset : integer;
                  var T : String);
{ Gets a null terminated string of text from the
  at the specified offset in a variable length buffer }
var
  CurByte : byte;
begin
  T := '';
  with FieldNameText do
  repeat
    CurByte := Mem[Seg(Buf^):Ofs(Buf^) + Offset];
    if (CurByte <> 0) and (Length(T) < pred(SizeOf(t))) then
    { temporary }
      T := T + Chr(CurByte);
     Offset := succ(Offset);
  until (CurByte = 0) or (Offset > Len);
end; { GetText }

procedure AddBlock(var V : VarLenBuf;
                   var B;
                   NumBytes : integer);
{ Copies Numbytes from B onto the end of the variable length
  Buffer B }
begin
  with V do
  begin
    Move(B, Mem[Seg(Buf^):Ofs(Buf^) + Len], NumBytes);
    Len := Len + NumBytes;
  end;
end; { AddBlock }

procedure AddTextToPool(var T : VarLenBuf;
                            S : String;
                        var TextOffset : word);
{ A text pool is a variable length buffer which contains a
  number of AsciiZ strings.  This routine converts the
  String to an Asccii Z string and copies it onto the
  end of the pool. }
var
  MaxLen : byte;
begin
  if T.Buf = nil then
    TranslateError('In AddTextToPool, the text pool is empty');
  with T do
  begin
    TextOffset := Len;
    MaxLen := Length(S);
    if MaxLen = 255 then
      MaxLen := MaxLen - 1;  { Longest string in Reflex }
    Move(S[1], Mem[Seg(Buf^):Ofs(Buf^) + Len], MaxLen);
    Len := Len + MaxLen;
    Mem[Seg(Buf^):Ofs(Buf^) + Len] := 0;
    Len := Succ(Len);
  end;
end; { AddTextToPool }

procedure InitReflexFields(var ReflexF : ReflexRef);
const
  MaxFieldNameLen = 74;
begin
  with ReflexF, FieldDir, FDTable do
  begin
    FillChar(FieldDir, SizeOf(FieldDir), 0);
    FieldsIncluded := FieldTotals[ReflexFile] + FieldTotals[Translate];
    AllocateBuf(FieldNameIndex, FieldsIncluded * 2);
    AllocateBuf(FieldNamePool, FieldsIncluded * MaxFieldNameLen);
    AllocateBuf(FieldDescriptions, FieldsIncluded * SizeOf(FieldDesc));
  end;
end; { InitReflexFields }

procedure MakeFieldEntry(var FieldDir : ReflexFieldDirectory;
                         var CurField : FieldInfoPtr;
                         var RecordOffset : integer);
var
  RefField : FieldDesc;
  TextOffset : word;

begin
  FillChar(RefField, SizeOf(RefField),  0);
  with FieldDir, CurField^ , RefField do
  begin
    AddTextToPool(FieldNamePool, FieldName, TextOffset);
    NameOffset := TextOffset;
    AddBlock(FieldNameIndex, TextOffset, SizeOf(TextOffset));
    TurboToRefType(CurField^);
    DataType := Ord(ReflexType);
    FieldOffset := RecordOffset;
    AddBlock(FieldDescriptions, RefField, SizeOf(RefField));
    Inc(RecordOffset, FieldDefaults[ReflexType].TypeSize);
  end;
end; { MakeFieldEntry }

procedure ConvertFDTable(var ReflexF : ReflexRef);
{  Converts the Field Definition table into the Format that
   Reflex expects for a field directory }
var
  RecordOffset : integer;
  CurField :  byte;
begin
  RecordOffset := 4;
  with ReflexF, FDTable, FieldDir do
  begin
    InitReflexFields(ReflexF);
    for CurField := 0 to (TotalFields - 1) do
      with FieldEntries[CurField]^ do
      if (XLateStatus = Translate)
	 or (XLateStatus = ReflexFile) then
      begin
        MakeFieldEntry(FieldDir, FieldEntries[CurField], RecordOffset);
        if FieldEntries[CurField]^.ReflexType = TextVal then
          Inc(TextFields);
      end;
    FixedRecordLen := RecordOffset;
  end;
end; { ConvertFDTable }


procedure CloseReflexFile(var ReflexF : ReflexRef);
{ Saves important reflex file header information and closes the
  file specified by ReflexF. Note: This routine is required! when
  modifying reflex files.
}

procedure PutMasterRec(var ReflexF : ReflexRef);
var
  Master : record
             Total,
             Filtered : integer;
           end;
   BlocksWritten : integer;
begin
  with ReflexF, Master do
  begin
    with ReflexHeader.DfSection[MasterSectionNum] do
    begin
      SectionType := MasterRecSection;
      SectionAddr := FilePos(RefFile);
      SectionLen := SizeOf(Master);
    end;
    Total := CurrentRecord;
    Filtered := CurrentRecord;
    BlockWrite(RefFile, Master, SizeOf(Master), BlocksWritten);
  end;
end; { PutMasterRec }

procedure PutFieldDir(var ReflexF : ReflexRef);
var
  FieldDir : ReflexFieldDirectory;
  SavedPosition : LongInt;

procedure WriteFieldDir(var RefFile : File;
                        var FieldDir : ReflexFieldDirectory);
const
  FieldSortSpec : array[1..12] of byte =
                    ($FF,0,0,0,0,0,0,0,0,0,0,0);
  DefaultFormat : array[1..6] of byte =
                    ($13,00,01,00,00,00);
var
  BlocksWritten : integer;
begin
  with FieldDir do
  begin
    BlockWrite(RefFile, FieldSortSpec, SizeOf(FieldSortSpec), BlocksWritten);
    WriteBuffer(RefFile, FieldNameIndex);
    DeallocateBuf(FieldNameIndex);
    WriteBuffer(RefFile, FieldNamePool);
    DeallocateBuf(FieldNamePool);
    WriteBuffer(RefFile, FieldDescriptions);
    DeallocateBuf(FieldDescriptions);
    BlockWrite(RefFile, DefaultFormat, SizeOf(DefaultFormat), BlocksWritten);
  end;
end; { WriteFieldDir }

begin { PutFieldDir }
  with ReflexF do
  begin
    with ReflexHeader.DfSection[FieldDirSectionNum] do
    begin
      SectionType := FieldDirSection;
      SectionAddr := FilePos(RefFile);
      SavedPosition := FilePos(RefFile);
      WriteFieldDir(RefFile, FieldDir);
      SectionLen := FilePos(RefFile) - SavedPosition;
    end;
  end;
end; { PutFieldDir }

procedure UpdateReflexHeader(var ReflexF : ReflexRef);
var
  BlocksWritten : integer;
begin
  with ReflexF, ReflexHeader do
  begin
    Seek(RefFile, 0);
    SectionCt := 3;
    Dirty := 0;
    with DfSection[DataSectionNum] do
    begin
      SectionType := DataRecSection;
      SectionAddr := DataSectionAddr;
      SectionLen := DataSectionLen;
    end;
    BlockWrite(RefFile, ReflexHeader, SizeOf(ReflexHeader), BlocksWritten);
  end;
end; { UpdateReflexHeader }

begin  { CloseReflexFile }
  with ReflexF do
  begin
    if Modified then
    begin
      PutMasterRec(ReflexF);
      PutFieldDir(ReflexF);
      UpdateReflexHeader(ReflexF);
    end;
    Close(RefFile);
  end;
end; { CloseReflexFile }

function ReflexFileLen{(var ReflexF : ReflexRef) : integer};
{ Returns the number of Records in the Reflex file referenced
  by ReflexF. }
begin
  ReflexFileLen := ReflexF.NumberOfRecs;
end; { ReflexFileLen }

function GetReflexType(var DataType : byte) : ReflexTypes;
var
  found : boolean;
  FieldType : FieldTypes;

begin
  found := false;
  FieldType := Untyped;
  repeat
    if ord(FieldType) = DataType then
      found := true
    else
    begin
      if (FieldType = IntegerVal) then
        FieldType := Untyped
      else
        FieldType := Succ(FieldType);
    end;
  until found or (FieldType = Untyped);
  GetReflexType := FieldType;
end; { GetReflexType }

procedure GenerateFD(var ReflexF : ReflexRef;
                         TAccessDef : boolean);
var
  CurField,
  ExportField : integer;

begin
  with ReflexF, FDTable, FieldDir do
  begin
    ExportField := 0;
    if TAccessDef then
    begin
      new(FieldEntries[ExportField]);
      FieldEntries[ExportField]^ := StatusField;
      Inc(RecordSize, FieldEntries[ExportField]^.TFieldLength);
      Inc(ExportField);
      DataFileType := TAccessFile;
    end
    else
      DataFileType := PascalFile;
    for CurField := 0 to pred(FieldTotals[Translate]) do
    begin
      new(FieldEntries[ExportField]);
      with FieldEntries[ExportField]^,
           FieldDescriptors[CurField]^ do
      begin
        FillChar(FieldEntries[ExportField]^, SizeOf(FieldEntries[ExportField]^), 0);
        GetText(FieldNamePool, NameOffset, FieldName);
        ReflexType := GetReflexType(DataType);
        XLateStatus := Translate;
        RefToTurboType(FieldEntries[ExportField]^);
        Inc(RecordSize, TFieldLength);
        Inc(ExportField);
      end; { with }
    end; { for }
    TotalFields := ExportField;
   end;
end; { GenerateFD }

function CheckFD(var ReflexFD,
                     LoadedFD : FieldDirectory) : boolean;
var
  FDOk : boolean;
  NewField,
  RefField : integer;


begin
  with LoadedFD do
  begin
    FDOk := TotalFields >= ReflexFD.TotalFields;
    if FDOK then
      FDOk := (FieldTotals[Translate] + FieldTotals[ReflexFile]) =
               ReflexFD.FieldTotals[Translate];
    RefField := 0;
    NewField := 0;
    while FDOK and (NewField < TotalFields) do
    begin
      TurboToRefType(FieldEntries[NewField]^);
      with FieldEntries[NewField]^ do
      begin
        if (XLateStatus = ReflexFile) or (XLateStatus = Translate) then
        begin
          FDOK := RefField < ReflexFD.TotalFields;
          if FDOK then
          begin
            FDOK := ReflexFD.FieldEntries[RefField]^.ReflexType = ReflexType;
            if not FDOK then
              FDOK := (ReflexFD.FieldEntries[RefField]^.ReflexType = RepText)
                      and (ReflexType = TextVal);
          end;
          Inc(RefField);
         end
         else
           with ReflexFD.FieldEntries[RefField]^ do
             if (XLateStatus = TAccessFile) then
               Inc(RefField);
         Inc(NewField);
       end;
    end;
  end;
  CheckFD := FDOk;
end; { CheckFD }

var
  LoadedFD : FieldDirectory;

function SetUpReflexFD(var ReflexF : ReflexRef;
                       var FDFileNm : FileSpec;
                       TAccessF,
                       LoadFDFile : boolean) : boolean;
var
  Ok : boolean;

begin
  Ok := true;
  with ReflexF, FDTable, FDFileNm do
  begin
    GenerateFD(ReflexF, TAccessF);
    RecordName := Name + 'Record';
    if LoadFDFile and Exist(Path + Name + Ext) then
    begin
      FillChar(LoadedFD, SizeOf(LoadedFD), 0);
      LoadFD(LoadedFD, Path + Name + Ext);
      OK := CheckFD(FDTable, LoadedFD);
      if OK then
      begin
        DisposeFD(FDTable);
        CopyFD(LoadedFD, FDTable);
      end
      else
        Abort(Path + Name + Ext + ' is inconsistent with the Reflex file');
      DisposeFD(LoadedFD);
    end;
  end;
  SetUpReflexFD := OK;
end; { SetUpReflexFD }


function OpenReflexFile(var ReflexF : ReflexRef;
                            RefFileNm : FileName) : boolean;
{   Opens the reflex file named RefFileNm, and generates
    a field defintion file which describes the structure
    of the reflex record. ReflexF will be used to refer to
    this file in all subsequent operations. }

function GetSectionAddr(var Header : RefHeader;
                        CurSection : integer) : LongInt;
{ Returns the start of the specified reflex file section }

var
  SecAddr : LongInt;
  i : integer;
  SectionFound : boolean;
begin
  with Header do
  begin
    i := 1;
    repeat
      SectionFound := (DfSection[i].SectionType = CurSection);
      SecAddr := DfSection[i].SectionAddr;
      i := i + 1;
    until (i > SectionCt) or SectionFound;
    if SectionFound then
      GetSectionAddr := SecAddr
    else
      GetSectionAddr := 0;
  end;
end; { GetSectionAddr }

function GetNumberOfRecs(var ReflexF : ReflexRef) : integer;
var
  SectionAddr : LongInt;
  NumRecs, BlocksRead : integer;
begin
  with ReflexF do
  begin
    SectionAddr := GetSectionAddr(ReflexHeader, MasterRecSection);
    if SectionAddr > FileSize(RefFile) then
    begin
      TranslateError('Seek past EOF in getting master record');
      GetNumberOfRecs := 0;
    end
    else
    begin
      Seek(RefFile, SectionAddr);
      BlockRead(RefFile, NumRecs, SizeOf(NumRecs), BlocksRead);
      GetNumberOfRecs := NumRecs;
    end;
  end;
end; { GetNumberOfRecs }


procedure GetReflexHeader(var ReflexFile : File;
                          var Header : RefHeader);
{ Reads in the fixed length Reflex file header of 512 bytes
  note that the block size is 1 byte, set in OpenReflexFile }
var
  BlocksRead : integer;
begin
  Seek(ReflexFile, 0);
  BlockRead(ReflexFile, Header, SizeOf(Header), BlocksRead);
  if BlocksRead <> SizeOf(Header) then
    TranslateError('The Reflex file is too small for a legal header');
end; { GetReflexHeader }

procedure BuildFieldNameTables(var InFile : File;
                               var FieldDir : ReflexFieldDirectory;
                               var TotalFields : integer);
const
  SkipSize = 12; { Field sort }

begin { BuildFieldNameTables }
  Seek(Infile, FilePos(InFile) + SkipSize);
  with FieldDir do
  begin
    ReadBuffer(InFile, FieldNameIndex);
    TotalFields := Lo(FieldNameIndex.Len div 2);
    ReadBuffer(InFile, FieldNamePool);
    ReadBuffer(InFile, FieldDescriptions);
  end;
end; { BuildFieldNameTables }

procedure GetFieldDesc(FieldDirectory : VarLenBuf;
                           FieldNum : integer;
                       var CurField : FieldDesc);
var
  Start, Offset : integer;
begin
  Start := FieldNum * SizeOf(CurField);
  with FieldDirectory do
    for OffSet := 0 to SizeOf(CurField) - 1 do
    begin
      Mem[Seg(CurField):Ofs(CurField) + Offset] :=
      Mem[Seg(Buf^):Ofs(Buf^) + Start + Offset];
    end; { for }
end; { GetFieldDesc }

procedure AddPool(var RepTextPool : RepTPool;
                  var T : TextPool);
var
  P : RepTPool;
begin
  New(P);
  P^ := T;
  if RepTextPool <> nil then
    P^.next := RepTextPool;
  RepTextPool := P;
end; { AddPool }

procedure BuildRepTextPool(var ReflexF : ReflexRef;
                           var InFile : File;
                           FieldCount : byte);
var
  CurPool : TextPool;
begin
  for FieldCount := FieldCount downto 0 do
    with ReflexF, FieldDescriptors[FieldCount]^, CurPool do
      if FieldDescriptors[FieldCount]^.DataType = ord(RepText) then
      begin
        FIDNum := FieldCount;
        ReadBuffer(InFile, PoolIndex);
        ReadBuffer(InFile, Pool);
        Next := nil;
        AddPool(RepTextPool, CurPool);
      end;
end; { BuildRepTextPool }

procedure BuildFieldDescTbl(var ReflexF : ReflexRef;
                            var InFile : File;
                            var FieldDirectory : VarLenBuf;
                            FieldCount : integer);
var
  CurDesc : 0..MaxField;
  CurField : FieldDesc;
begin
  with ReflexF do
    begin
    for CurDesc := 0 to MaxField do
      FieldDescriptors[CurDesc] := nil;
    for CurDesc := 0 to (FieldCount - 1) do
    begin
      New(FieldDescriptors[CurDesc]);
      GetFieldDesc(FieldDirectory, CurDesc, CurField);
      FieldDescriptors[CurDesc]^ := CurField;
    end;
  end;
end; { BuildFieldDescTbl }

procedure BuildFieldDir(var ReflexF : ReflexRef;
                        var TotalFields : integer);
const
  SkipSize = 6;
begin
  with ReflexF, FieldDir do
  begin
    Seek(RefFile, GetSectionAddr(ReflexHeader, FieldDirSection));
    BuildFieldNameTables(RefFile, FieldDir, TotalFields);
    BuildFieldDescTbl(ReflexF, RefFile, FieldDescriptions, TotalFields);
    Seek(RefFile, FilePos(RefFile) + SkipSize);
    RepTextPool := nil;
    BuildRepTextPool(ReflexF, RefFile, TotalFields - 1);
  end;
end; { BuildFieldDir }


begin
  OpenReflexFile := true;
  with ReflexF, FDTable do
  begin
    if not Exist(RefFileNm) then
    begin
      OpenReflexFile := false;
      Exit;
    end;
    Assign(RefFile, RefFileNm);
    Reset(RefFile, 1);        { Open file with a block size of 1 }
       { This allows us the flexibility of reading various sized }
       { records and the ability to seek to any byte in the file }
    GetReflexHeader(RefFile, ReflexHeader);
    FillChar(FDTable, SizeOf(FDTable), 0);
    BuildFieldDir(ReflexF, FDTable.FieldTotals[Translate]);
    NumberOfRecs := GetNumberOfRecs(ReflexF);
    CurrentRecord := 0;
    DataSectionAddr := GetSectionAddr(ReflexHeader, DataSectionNum) + 2;
    Seek(RefFile, DataSectionAddr);
    Modified := false;  { Open for reading, Modified used in close proc. }
  end;
end; { OpenReflexFile }


procedure GetReflexRec(var ReflexTable : ReflexRef;
                          var TurboRec;
                             RecordNum : integer);
{ Gets a reflex variable length data record specified by
  record num and translates it to a Turbo Pascal fixed length
  record of the type specificed in the .DEF file. }

procedure GetFieldCount(var RecBuf : VarLenBuf;
                        var FieldCount : byte);
{ Returns the number of fields in the given data
  record }
type
  RecHdr = record
             temp : array[1..3] of byte;
             CtFlds : integer;
           end;
var
 CurRec : RecHdr;
begin
  with RecBuf, CurRec do
  begin
    Move(Buf^, CurRec, SizeOf(CurRec));
    FieldCount := Lo(CtFlds);
  end;
end; { GetFieldCount }

procedure TranslateLocText(var ReflexF : ReflexRef;
                           var ReflexRecord : VarLenBuf;
                           var TurboRecord;
                               FieldNum : integer;
                           var Trans : TranslateRec);
var
  TextPos : word;
  S : String;
begin
{$ifdef FlexDebug}
Write('In TranslateLocText');
Readln;
{$endif}

  with ReflexF, ReflexRecord, Trans do
  begin
    TextPos := MemW[Seg(Buf^):Ofs(Buf^) + ReflexOffset];
    Inc(ReflexOffset,2);    { Move the offset to the next field }
    if (TextPos = 0) then
      S := ''
    else
      if (TextPos = 1) then
        S := 'ERROR'
    else
      if (TextPos >= 2) and (TextPos < Len) then
        GetText(ReflexRecord, TextPos, S)
      else
        S := '';
    {$ifdef FlexDebug}
    Write('TextPos = ', TextPos, ' Text returned = ', S);
    Readln;
    {$endif}
    with FDTable, FieldEntries[FieldNum]^ do
    begin
      Move(S, Mem[Seg(TurboRecord):Ofs(TurboRecord) + TurboOffset], TFieldLength);
      Inc(TurboOffset, TFieldLength);
    end;
  end;
end; { TranslateLocText }

function GetPool(var CurPool : RepTPool;
                      FieldNum : byte) : boolean;
var
  found : boolean;
begin
  found := false;
  while (CurPool <> nil) and not found do
    with CurPool^ do
    begin
      found := (FIDNum = FieldNum);
      if not found then
        CurPool := CurPool^.Next
    end;
    {$ifdef FlexDebug}
    Write('In GetPool, we found it = ', found);
    Readln;
    {$endif}
    GetPool := Found;
end; { GetPool }

procedure GetRepText(ReflexF : ReflexRef;
                     FieldNum : byte;
                     TextPos : word;
                     var RepText : String);
var
  CurPool : RepTPool;
begin
{$ifdef FlexDebug}
Write('In GetRepText');
Readln;
{$endif}
  with ReflexF do
  begin
    CurPool := RepTextPool;
    if GetPool(CurPool, FieldNum) then
    begin
      {$ifdef FlexDebug}
      Write('Successfully got the text pool');
      Readln;
      {$endif}
      if TextPos <= 1 then
        RepText := ''
      else
        GetText(CurPool^.Pool, TextPos, RepText);
      {$ifdef FlexDebug}
      Write('String returned is *', RepText,'*');
      Readln;
      {$endif}
      (*if RepText = '' then
        TranslateError('The text was not returned from the text pool'); *)
    end
    else
      RepText := '';
  end;
end; { GetRepText }

procedure TranslateRepText(var ReflexF : ReflexRef;
                           var ReflexRecord : VarLenBuf;
                           var TurboRecord;
                               FieldNum : byte;
                               ReflexFieldNum : byte;
                           var Trans : TranslateRec);
var
  TextPos : integer;
  RepText : String;
begin
{$ifdef FlexDebug}
Write('In Translate RepText for field ', FieldNum);
Readln;
{$endif}

  with ReflexF, ReflexRecord, Trans do
  begin
    TextPos := MemW[Seg(Buf^):Ofs(Buf^) + ReflexOffset];
    {$ifdef FlexDebug}
    Write('TextPos = ', TextPos);
    Readln;
    {$endif}
    Inc(ReflexOffset, 2);    { Move the offset to the next field }
    GetRepText(ReflexF, ReflexFieldNum, TextPos, RepText);
    with FDTable, FieldEntries[FieldNum]^ do
    begin
      Move(RepText, Mem[Seg(TurboRecord) : Ofs(TurboRecord) + TurboOffset], TFieldLength);
      Inc(TurboOffset, TFieldLength);
    end;
  end;
end; { TranslateRepText }


 procedure TransferBytes(var ReflexRecord : VarLenBuf;
                        var TurboRecord;
                            NumBytes : byte;
                        var Trans : TranslateRec);
begin
  with ReflexRecord, Trans do
  begin
    Move(Mem[Seg(Buf^) : Ofs(Buf^) + ReflexOffset],
         Mem[Seg(TurboRecord) : Ofs(TurboRecord) + TurboOffset], NumBytes);
    Inc(ReflexOffset, NumBytes);
    Inc(TurboOffset, NumBytes);
  end;
end; { TransferBytes }

procedure TransRealNum(var ReflexRecord : VarLenBuf;
                       var TurboRecord;
                       FieldLength : byte;
                       var Trans : TranslateRec);

var
  EightByteReal : ieee;
  r : real;

begin
  with ReflexRecord, Trans do
    if (FieldLength = 6) then { Convert number }
    begin
      Move(Mem[Seg(Buf^):Ofs(Buf^) + ReflexOffset], EightByteReal, 8);
      IEEEToTurbo(EightByteReal, r);
      Inc(ReflexOffset, 8);
      Move(r, Mem[Seg(TurboRecord) : Ofs(TurboRecord) + TurboOffset], SizeOf(r));
      Inc(TurboOffset, 6);
    end
    else
      TransferBytes(ReflexRecord, TurboRecord, FieldLength, Trans);
end; { TransRealNum }

procedure TranslateDate(var ReflexRecord : VarLenBuf;
                        var TurboRecord;
                        var Trans : TranslateRec);
var
  D : RDate;
  S : Date;
begin
  with ReflexRecord, Trans do
  begin
    Move(Mem[Seg(Buf^):Ofs(Buf^) + ReflexOffset], D, 2);
    Inc(ReflexOffset, 2);
    DateToStr(D, S);
    Move(S, Mem[Seg(TurboRecord) : Ofs(TurboRecord) + TurboOffset],
         SizeOf(S));
    Inc(TurboOffset, SizeOf(S));
  end;
end; { TranslateDate }

function GetFieldNum(var FDTable : FieldDirectory;
                     CurField : byte) : byte;
var
  F, Total : byte;
begin
  F := 0;
  for CurField := 0 to  pred(CurField) do
  with FDTable, FieldEntries[CurField]^ do
  begin
    if (XLateStatus = Translate) or (XLateStatus = ReflexFile) then
       F := succ(F);
  end;
  GetFieldNum := F;
end; { GetFieldNum }

procedure TranslateField(var ReflexF : ReflexRef;
                         var ReflexRecord : VarLenBuf;
                         var TurboRecord;
                             FieldCount : byte; { needed for repeating text }
                         var Trans : TranslateRec);
begin
  with ReflexF, ReflexRecord, FDTable, FieldEntries[FieldCount]^, Trans do
   case XLateStatus of
    Translate :
      case ReflexType of
        Untyped : ;
        TextVal : TranslateLocText(ReflexF, ReflexRecord, TurboRecord,
                                       FieldCount, Trans);
        RepText : TranslateRepText(ReflexF, ReflexRecord, TurboRecord,
                                   FieldCount,
                                   GetFieldNum(FDTable, FieldCount), Trans);
        DoubleVal : TransRealNum(ReflexRecord, TurboRecord,
                                   TFieldLength, Trans);
        IntegerVal : TransferBytes(ReflexRecord, TurboRecord, 2, Trans);
        RDateVal : TranslateDate(ReflexRecord, TurboRecord, Trans);
      end;
    ReflexFile : Inc(ReflexOffset, FieldDefaults[ReflexType].TypeSize);
    TAccessFile,
    PascalFile : Inc(TurboOffset, TFieldLength);
  end;
end; { TranslateField }

procedure ReflexToTurbo(var ReflexTable : ReflexRef;
                        var ReflexRecord : VarLenBuf;
                        var TurboRecord);
var
  FieldCount : byte;
  Trans : TranslateRec;
begin
  GetFieldCount(ReflexRecord, FieldCount);
  {$ifdef FlexDebug}
  Write('In ReflexToTurbo FieldCount is ', succ(FieldCount));
  Readln;
  {$endif}
  with Trans, ReflexTable, FDTable do
  begin
    ReflexOffset := 4;
    TurboOffset := 0;
    for FieldCount := 0 to (TotalFields - 1) do
    begin
      {$ifdef FlexDebug}
      Writeln;
      Write('Translating field ', FieldCount,  ' ', FieldEntries[FieldCount]^.FieldName);
      Readln;
      {$endif}
      TranslateField(ReflexTable, ReflexRecord, TurboRecord, FieldCount, Trans);
    end;
  end;
end; { ReflexToTurbo }

procedure SkipRecord(var CurFile : File);
var
  RecLen,
  BlocksRead : integer;
begin
  BlockRead(CurFile, RecLen, SizeOf(RecLen), BlocksRead);
  Seek(CurFile, FilePos(CurFile) + RecLen);
end; { SkipRecord }

procedure ReflexRecSeek(var ReflexTable : ReflexRef;
                              RecordNum : word);
begin
  with ReflexTable do
  if RecordNum <= NumberOfRecs then
  begin
    if CurrentRecord > RecordNum then
    { If the pointer is past us set it back to the first record }
      CurrentRecord := 0;
    if CurrentRecord = 0 then
      Seek(RefFile, DataSectionAddr);
    while RecordNum > CurrentRecord do
    begin
      SkipRecord(RefFile);
      CurrentRecord := Succ(CurrentRecord);
    end;
  end
  else
    TranslateError('Seek past EOF, record number = ' + NumStr(RecordNum));
end; { ReflexRecSeek }

var
  ReflexRecord : VarLenBuf;
begin
  ReflexRecSeek(ReflexTable, RecordNum);
  with ReflexTable do
  begin
    ReadBuffer(RefFile, ReflexRecord);
    ReflexToTurbo(ReflexTable, ReflexRecord, TurboRec);
    DeallocateBuf(ReflexRecord);
    CurrentRecord := Succ(CurrentRecord);
  end;
end; { GetReflexRec }

{ The following are routines allow you to create Reflex files. You can
  translate  Pascal  fixed  length  records  into Reflex variable
  length records and add these records to the Reflex files.
}

procedure MakeReflexFile(var ReflexF : ReflexRef;
                         RefFileNm : FileName;
                         var FD : FieldDirectory);
{ Creates a reflex file name RefFileNm, with a record
  definition specified in FD.  ReflexF will be used to refer
  to this file in all subsequent operation.
}

type
  HeaderBlock = array[1..512] of byte;

const
  DefaultHdr : HeaderBlock =
    ($00,$02,$33,$51,$2E,$21,$26,$40,$23,$24,$21,$26,$26,$00,$FF,$FF,
     $07,$00,$04,$00,$03,$00,$00,$00,$01,$C2,$00,$00,$00,$00,$00,$00,
     $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
     $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
     $0C,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
     $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
     $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
     $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
     $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
     $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
     $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
     $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
     $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
     $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
     $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
     $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
     $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
     $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
     $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
     $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
     $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
     $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
     $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
     $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
     $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
     $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
     $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
     $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
     $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
     $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
     $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
     $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
   );
var
  BlocksWritten : integer;
begin
  FillChar(ReflexF, SizeOf(ReflexF), 0);
  with ReflexF do
  begin
    Assign(RefFile, RefFileNm);
    Rewrite(RefFile, 1);               { Open and set the block size to 1 }
    ReflexHeader := RefHeader(DefaultHdr);
    BlockWrite(RefFile, ReflexHeader, SizeOf(ReflexHeader), BlocksWritten);
    FDTable := FD;
    ConvertFDTable(ReflexF);
    Modified := true;
  end;
end; { MakeReflexFile }

procedure AddReflexRec(var ReflexF : ReflexRef;
                       var TurboRec);
{ Converts the Pascal record TurboRec into a Reflex record and
  adds it to the file specified by ReflexF. }

procedure SetFieldCount(var ReflexRec : VarLenBuf;
                        var NumFields : integer);
var
  RecHdr : record
             temp : array[1..3] of byte;
             CtFields : byte;
           end;
begin
  with RecHdr do
  begin
    FillChar(temp, SizeOf(Temp), 0);
    CtFields := NumFields;
  end;
  Move(RecHdr, Mem[Seg(ReflexRec.Buf^):Ofs(ReflexRec.Buf^)], SizeOf(RecHdr));
  ReflexRec.Len := SizeOf(RecHdr);
end; { SetFieldCount }

procedure TransTurboBytes(var TurboRec;
                          var ReflexRec : VarLenBuf;
                          NumBytes : byte;
                          var Trans : TranslateRec);
begin
  with ReflexRec, Trans do
  begin
    Move(Mem[Seg(TurboRec) : Ofs(TurboRec) + TurboOffset],
    Mem[Seg(Buf^) : Ofs(Buf^) + Len], NumBytes);
    Inc(Len, NumBytes);
    Inc(TurboOffset, NumBytes);
  end;
end; { TransTurboBytes }

procedure TransTurboByte(var TurboRec;
                         var ReflexRec : VarLenBuf;
                         var Trans : TranslateRec);
var
  b : byte;
  i : integer;
begin
  with ReflexRec, Trans do
  begin
    Move(Mem[Seg(TurboRec) : Ofs(TurboRec) + TurboOffset],
         b, SizeOf(byte));
    Inc(TurboOffset);
    i := b;
    Move(i, Mem[Seg(Buf^) : Ofs(Buf^) + Len], 2);
    Inc(Len, 2);
  end;
end; { TransTurboByte }

procedure TransTurboReal(var TurboRec;
                         var ReflexRec : VarLenBuf;
                         var Trans : TranslateRec);
var
  EightByteReal : ieee;
  r : real;
begin
  with ReflexRec, Trans do
  begin
    Move(Mem[Seg(TurboRec):Ofs(TurboRec) + TurboOffset], r, SizeOf(real));
    Inc(TurboOffset, SizeOf(Real));
    TurboToIEEE(r, EightByteReal);
    Move(EightByteReal, Mem[Seg(Buf^):Ofs(Buf^) + Len], SizeOf(EightByteReal));
    Inc(Len, SizeOf(EightByteReal));
  end;
end; { TransTurboReal }

procedure TransTurboLong(var TurboRec;
                         var ReflexRec : VarLenBuf;
                         var Trans : TranslateRec);
var
  l : LongInt;
  r : real;
  EightByteReal : ieee;
begin
  with ReflexRec, Trans do
  begin
    Move(Mem[Seg(TurboRec):Ofs(TurboRec) + TurboOffset], l, SizeOf(l));
    Inc(TurboOffset, SizeOf(l));
    r := l;
    TurboToIEEE(r, EightByteReal);
    Move(EightByteReal, Mem[Seg(Buf^):Ofs(Buf^) + Len], SizeOf(EightByteReal));
    Inc(Len, SizeOf(EightByteReal));
  end;
end; { TransTurboLong }

procedure MoveLocalText(var TurboRec;
                        Offset,
                        FieldLength : integer;
                        var S);
begin
  Move(Mem[Seg(TurboRec):Ofs(TurboRec) + Offset], S, FieldLength);
end;

procedure TransTurboDate(var TurboRec;
                         var ReflexRec : VarLenBuf;
                         var Trans : TranslateRec);
var
  S : string;
  D : RDate;
begin
  MoveLocalText(TurboRec, Trans.TurboOffset,
                FieldDefaults[DateVal].TypeSize, S);
  Inc(Trans.TurboOffset, FieldDefaults[DateVal].TypeSize);
  if not StrToDate(S, D) then
    D := 0;
  AddBlock(ReflexRec, D, SizeOf(D));
end;

procedure TransTurboText(var ReflexF : ReflexRef;
                         var TurboRec;
                         var ReflexRec : VarLenBuf;
                         var LocalTextPool : VarLenBuf;
                         var Trans : TranslateRec;
                             FieldLength : integer);
var
  S : String;
  Offset : word;

begin
  MoveLocalText(TurboRec, Trans.TurboOffset, FieldLength, S);
  with ReflexF, ReflexRec, Trans do
  begin
    TurboOffset := TurboOffset + FieldLength;
    AddTextToPool(LocalTextPool, S, Offset);
    Inc(Offset, FixedRecordLen);
    AddBlock(ReflexRec, Offset, SizeOf(Offset));
  end;
end; { TransTurboText }

procedure TransTurboChar(var ReflexF : ReflexRef;
                         var TurboRec;
                         var ReflexRec : VarLenBuf;
                         var LocalTextPool : VarLenBuf;
                         var Trans : TranslateRec);
var
  S : String;
  Offset : word;

begin
  MoveLocalText(TurboRec, Trans.TurboOffset, 1, S[1]);
  S[0] := chr(1);
  with ReflexF, ReflexRec, Trans do
  begin
    Inc(TurboOffset);
    AddTextToPool(LocalTextPool, S, Offset);
    Inc(Offset, FixedRecordLen);
    AddBlock(ReflexRec, Offset, SizeOf(Offset));
  end;
end; { TransTurboChar }

procedure ConcatBuffers(var Buffer1, Buffer2 : VarLenBuf);
begin
  with Buffer1 do
  begin
    Move(Buffer2.Buf^,
        Mem[Seg(Buffer1.Buf^):Ofs(Buffer1.Buf^) + Len], Buffer2.Len);
    Len := Len + Buffer2.Len;
  end;
end; { ConcatBuffers }

procedure CreateField(var ReflexF : ReflexRef;
                      var ReflexRec : VarLenBuf;
                      ReflexType : ReflexTypes);
var
  D : RDate;
  i, Offset : word;
begin

  with ReflexF, ReflexRec do
    case
      ReflexType of
        TextVal : begin
                    AddTextToPool(LocalTextPool, '', Offset);
                    Inc(Offset, FixedRecordLen);
                    AddBlock(ReflexRec, Offset, SizeOf(Offset));
                  end;
        RDateVal : AddBlock(ReflexRec, NullIEEE, SizeOf(NullIEEE));
        DoubleVal : begin
                      D := DateNull;
                      AddBlock(ReflexRec, D, SizeOf(D));
                    end;
        IntegerVal : begin
                       i := 0;
                       AddBlock(ReflexRec, i, SizeOf(i));
                     end;
      else ;
    end;
end; { CreateField }

procedure TurboToReflex(var ReflexF : ReflexRef;
                        var TurboRec;
                        var ReflexRec : VarlenBuf);
var
  Trans : TranslateRec;
  CurField : byte;
begin
  FillChar(Trans, SizeOf(Trans), 0);
  with ReflexF, FDTable, Trans, ReflexRec do
  begin
    SetFieldCount(ReflexRec, FieldsIncluded);
    for CurField := 0 to TotalFields - 1 do
    begin
      with FieldEntries[CurField]^ do
      case XLateStatus of
        Translate :
          begin
            case TFieldType of
              IntegerVal,
              DoubleVal,
              RDateVal  : TransTurboBytes(TurboRec, ReflexRec, TFieldLength, Trans);
              RealVal : TransTurboReal(TurboRec, ReflexRec, Trans);
              StringVal : TransTurboText(ReflexF, TurboRec, ReflexRec,
                                       LocalTextPool, Trans, TFieldLength);
              CharVal : TransTurboChar(ReflexF, TurboRec, ReflexRec,
                                     LocalTextPool, Trans);
              ByteVal : TransTurboByte(TurboRec, ReflexRec, Trans);
              LongIntVal : TransTurboLong(TurboRec, ReflexRec, Trans);
              DateVal : TransTurboDate(TurboRec, ReflexRec, Trans);
            end;
          end;
          TAccessFile,
          PascalFile : Inc(TurboOffset, TFieldLength);
          ReflexFile : CreateField(ReflexF, ReflexRec, ReflexType);
        end; { case }
    end; { for }
    if TextFields > 0 then
    begin
      ConcatBuffers(ReflexRec, LocalTextPool);
      LocalTextPool.Len := 0;
    end;
  end;
end; { TurboToReflex }

const
  MaxText = 255;
var
  i, BlocksWritten : integer;

begin { AddReflexRec }
  i := 0;
  with ReflexF do
  begin
    ReflexRec.Len := 0;
    LocalTextPool.Len := 0;
    if (CurrentRecord = 0) then
    begin
      AllocateBuf(ReflexRec, FixedRecordLen + (MaxText * TextFields));
      if (TextFields > 0) then
        AllocateBuf(LocalTextPool, MaxText * TextFields);
      DataSectionAddr := FilePos(RefFile);
      BlockWrite(RefFile, i, SizeOf(i), BlocksWritten);
    end;
    CurrentRecord := Succ(CurrentRecord);
    TurboToReflex(ReflexF, TurboRec, ReflexRec);
    WriteBuffer(RefFile, ReflexRec);
    DataSectionLen := FilePos(RefFile) - DataSectionAddr;
  end;
end; { AddReflexRec }

end.