home *** CD-ROM | disk | FTP | other *** search
- UNIT BTP; { Version 2.0 - last mod 6/10/93 (C) 1993 John C. Leon }
-
- {$A+} {Btrieve interface call wants this set.}
- {$X+,D+}
-
- INTERFACE
- (* ------------------------------------------------------------------------ *)
- (* ------------------------------------------------------------------------ *)
- USES Objects, Memory;
-
- CONST
-
- { Key Attributes Key Types Open Modes }
- { ------------------ ---------------- --------------- }
- Duplicates = 1; BString = 0; Normal = 0;
- Modifiable = 2; BInteger = 1; Accel = -1;
- Binary = 4; BFloat = 2; ReadOnly = -2;
- Null = 8; BDate = 3; Verify = -3;
- Segmented = 16; BTime = 4; Exclusive = -4;
- AltCol = 32; BDecimal = 5;
- Descending = 64; BMoney = 6; { File Flags }
- Supplemental = 128; BLogical = 7; { ------------------------ }
- ExtType = 256; BNumeric = 8; VarLength = 1;
- Manual = 512; BBFloat = 9; BlankTrunc = 2;
- BLString = 10; PreAllocate = 4;
- BZString = 11; DataComp = 8;
- BUnsBinary = 14; KeyOnly = 16;
- BAutoInc = 15; Free10 = 64;
- Free20 = 128;
- Free30 = 192;
-
- { Btrieve Op Codes Error Codes }
- { ----------------------------------------- ------------------------ }
- BOpen = 0; BAbortTran = 21; FileNotOpen = 3;
- BClose = 1; BGetPos = 22; InvalidKeyNumber = 6;
- BInsert = 2; BGetDir = 23; DiffKeyNumber = 7;
- BUpdate = 3; BStepNext = 24; InvalidPosition = 8;
- BDelete = 4; BStop = 25; EndofFile = 9;
- BGetEqual = 5; BVersion = 26; FileNotFound = 12;
- BGetNext = 6; BUnlock = 27; BtrieveNotLoaded = 20;
- BGetPrev = 7; BReset = 28; DataBufferLength = 22;
- BGetGr = 8; BSetOwner = 29; RejectCount = 60;
- BGetGrEq = 9; BClrOwner = 30; IncorrectDesc = 62;
- BGetLess = 10; BCrSuppIdx = 31; FilterLimit = 64;
- BGetLessEq = 11; BDropSuppIdx = 32; IncorrectFldOff = 65;
- BGetFirst = 12; BStepFirst = 33; LostPosition = 82;
- BGetLast = 13; BStepLast = 34;
- BCreate = 14; BStepPrev = 35;
- BStat = 15; BGetNextExt = 36;
- BExtend = 16; BGetPrevExt = 37;
- BSetDosDir = 17; BStepNextExt = 38;
- BGetDosDir = 18; BStepPrevExt = 39;
- BBegTran = 19; BInsertExt = 40;
- BEndTran = 20; BGetKey = 50;
-
- { Extended Ops Comp Codes/Bias Extended Ops Logic Constants }
- { ----------------------------- ----------------------------------- }
- Equal : byte = 1; NoFilter : integer = 0;
- GreaterThan : byte = 2; LastTerm : byte = 0;
- LessThan : byte = 3; NextTermAnd : byte = 1;
- NotEqual : byte = 4; NextTermOr : byte = 2;
- GrOrEqual : byte = 5;
- LessOrEqual : byte = 6; { Owner Access }
- UseAltColl : byte = 32; { -------------------------------------- }
- UseField : byte = 64; RQ = 0; RO = 1; RQENC = 2; ROENC = 3;
- UseNoCase : byte = 128;
-
- { Other Unit-Specific Constants }
- { --------------------------------- }
- Zero : integer = 0;
- NotRequired : integer = 0;
- MaxFixedRecLength = 4090; {Btrieve limits fixed record length for std}
- MaxKBufferLength = 255; {files to 4090. Max key size is 255. }
- MaxExtDBufferLength = 32767;
- MaxFileSpecLength = 665;
- MaxDBufferLength = 32767;
- MaxNumSegments = 24;
- KeySpecSize = 16;
- None = 0; Drop = 1; Retain = 2; {Used in CloneFileFunction}
-
-
- TYPE
-
- TOwnerName = string[9];
-
-
- (* Data types for TRecMgr object *)
- (* ----------------------------- *)
- TVersion = record
- case integer of
- 1: (Number : word;
- Rev : integer;
- Product : char);
- 2: (Entire : array[1..5] of char);
- end;
- PRecMgr = ^TRecMgr;
- TRecMgr = object(TObject) {Base obj handles abort/begin/end}
- BtrieveIsLoaded: boolean;
- Version : TVersion; {tran, reset, version and stop}
- VersionString: string;
- constructor Init;
- destructor Done; virtual;
- function BT(OpCode, Key: integer): integer; virtual;
- function GetVersion: string;
- end;
-
-
- (* Data types for BFile object *)
- (* --------------------------- *)
- BFileName = array[1..80] of char; {79 + blank pad required by Btrieve}
- TAltColSpec = record {The data types for alternate collating}
- case integer of {sequence are used in CreateFile fcn. }
- 1: (Header : byte; {Header always equals $AC}
- Name : array[1..8] of char;
- Table : array[1..256] of char);
- 2: (Entire : array[1..265] of byte);
- end;
- PAltColSeq = ^TAltColSeq;
- TAltColSeq = object(TObject)
- Spec : TAltColSpec;
- constructor Init(const SpecName: FNameStr);
- destructor Done; virtual;
- end;
- PKeySpec = ^TKeySpec;
- TKeySpec = record {data type for a Btrieve key spec}
- case integer of
- 1: (KeyPos : integer;
- KeyLen : integer;
- KeyFlags : integer; {Tho not used in a }
- NotUsed : array[1..4] of byte; {create call, these}
- ExtKeyType : byte; {4 bytes return # }
- NullValue : byte; {unique recs in key}
- Reserved : array[1..4] of byte);{after a stat call.}
- 2: (Irrelevant : array[1..3] of integer;
- NumUnique : longint); {great after a stat call!}
- 3: (Entire : array[1..KeySpecSize] of byte);
- end;
- PKeyList = ^TKeyList;
- TKeyList = record
- KeySpec: TKeySpec;
- Next: PKeyList;
- end;
- PFileSpec = ^TFileSpec;
- TFileSpec = record {Strictly speaking, the KeyArray}
- case integer of {and AltColSpec elements here }
- 1: (RecLen : integer;{only serve to reserve space for}
- PageSize : integer;{the buffer. }
- NumKeys : integer;
- NumRecs : array[1..2] of word;
- FileFlags : integer;
- Reserved : array[1..2] of char;
- PreAlloc : integer;
- KeyArray : array[0..23] of TKeySpec; {24=max # segs}
- AltColSpec : TAltColSpec); {here just to allow room}
- 2: (Irrelevant : array[1..14] of byte;
- UnusedPgs : word); {great after a stat call!}
- 3: (SpecBuf : integer); {used to refer to addr of spec}
- 4: (Entire : array[1..665] of byte);
- end;
- PFileSpecObj = ^TFileSpecObj;
- TFileSpecObj = object(TObject)
- Specs: PFileSpec;
- Keys : PKeyList;
- constructor Init(RecLen, PageSize, NumKeys,
- FileFlags, PreAlloc: integer;
- AKeyList: PKeyList);
- destructor Done; virtual;
- end;
- PBFile = ^BFile;
- BFile = object(TObject)
- DFileName : FNameStr; {DOS filename}
- Specs : TFileSpec; {Btrieve file specs}
- SpecLength : integer; {length of actual file spec}
- NumRecs : longint; {# records at Init time}
- NumSegs : integer; {total # key segs}
- HasAltCol : boolean; {true if file has alt col seq}
- AltColName : string[8]; {name of alt col seq from file}
- IsVarLength: boolean;
- HasOwner : boolean;
- OwnerName : TOwnerName; {8 plus 1 null}
- PosBlk : array[1..128] of char; {position block}
- DBufferLen : integer;
- constructor Init(const UserFileName: FNameStr; OpenMode: integer;
- const OName: TOwnerName);
- function BT(OpCode, Key: integer): integer; virtual;
- function Open(OpenMode: integer): integer; virtual;
- function Close: integer; virtual;
- function AddSuppIdx(KeyList: PKeyList;
- const AltColFile: FNameStr): boolean; virtual;
- destructor Done; virtual;
- private
- FileName : BFileName; {Btrieve-type filename}
- procedure ConvertName(const UserFileName: FNameStr);
- end;
-
-
- (* Data types for BFixed object - descendant of BFile *)
- (* -------------------------------------------------- *)
- TDBuffer = array[1..MaxFixedRecLength] of byte;
- TKBuffer = array[1..MaxKBufferLength] of byte;
- PBFixed = ^BFixed;
- BFixed = object(BFile)
- DBuffer : TDBuffer;
- KBuffer : TKBuffer;
- constructor Init(const UserFileName: FNameStr; OpenMode: integer;
- const OName: TOwnerName);
- function BT(OpCode, Key: integer): integer; virtual;
- destructor Done; virtual;
- end;
-
-
- (* Data types for BSized object - descendant of BFile *)
- (* -------------------------------------------------- *)
- PBSized = ^BSized;
- BSized = object(BFile)
- DBuffer : pointer;
- KBuffer : pointer;
- DBufferSize: integer;
- constructor Init(const UserFileName: FNameStr; OpenMode: integer;
- const OName: TOwnerName; BuffSize: integer);
- function BT(OpCode, Key: integer): integer; virtual;
- destructor Done; virtual;
- end;
-
-
- (* Data types for BFileExt object - descendant of BFile *)
- (* ---------------------------------------------------- *)
- TByteArray = array[1..255] of byte;
- THeader = record
- case integer of
- 1: (DBufferLen : integer;
- Constant : array[1..2] of char);
- 2: (Entire : array[1..4] of byte);
- end;
- TFilter = record
- case integer of
- 1: (MaxSkip : integer;
- NumLogicTerms : integer);
- 2: (Entire : array[1..2] of integer);
- end;
- TLogicTerm = record
- case integer of
- 1: (FieldType : byte;
- FieldLen : integer;
- Offset : integer; {0 relative to start of record}
- CompCode : byte;
- Expression : byte;{0 last term, 1 AND next, 2 OR next}
- case FieldComp: boolean of
- True : (CompOffset: integer);
- False: (Value: TByteArray));{an arbitrary limit of}
- 2: (Fixed : array[1..7] of byte); {255 on len of values }
- end;
- PFilterSpec = ^TFilterSpec;
- TFilterSpec = object(TObject)
- LogicTerm: TLogicTerm;
- constructor InitF(FieldType: byte; FieldLen, Offset:
- integer; CompCode, Expression: byte;
- CompOffset: integer);
- constructor InitV(FieldType: byte; FieldLen, Offset:
- integer; CompCode, Expression: byte;
- const Value: array of byte);
- destructor Done; virtual;
- end;
- TExtractor = record
- case integer of
- 1: (NumRecords : integer;
- NumFields : integer);
- 2: (Entire : array[1..2] of integer);
- end;
- TExtRepeater= record
- FieldLen : integer;
- Offset : integer;
- end;
- PExtSpec = ^TExtSpec;
- TExtSpec = object(TObject)
- ExtRepeater : TExtRepeater;
- constructor Init(Len, Ofs: integer);
- destructor Done; virtual;
- end;
- PExtDBuffer = ^TExtDBuffer;
- TExtDBuffer = record
- case integer of
- 1: (Header : THeader; {Buffer sent includes these}
- Filter : TFilter); {types at its beginning.}
- 2: (NumRecs : integer; {Buffer rec'd looks}
- Repeater : array[1..32765] of char); {like this.}
- {Repeater structure is: 2 for length of record image, }
- { 4 for currency position of rec, }
- { n for record image itself }
- 3: (Entire : array[1..32767] of byte); {Whole buffer.}
- end;
- PBFileExt = ^BFileExt;
- BFileExt = object(BFile)
- Header : THeader;
- Filter : TFilter;
- FilterSpec : PCollection;
- Extractor : TExtractor;
- ExtractorSpec : PCollection;
- ExtDBuffer : PExtDBuffer;
- constructor Init(const UserFileName: FNameStr; OpenMode: integer;
- const OName: TOwnerName);
- function BTExt(OpCode, Key: integer): integer; virtual;
- procedure SetTerms(MSkip, NumLTerms, NRecs, NumFlds: integer);
- destructor Done; virtual;
- private
- procedure SetExtDBufferLen;
- procedure MakeExtDBuffer;
- end;
-
-
- (* PUBLIC VARS *)
- (* ----------- *)
- VAR
- BStatus : integer;
- VarNotRequired : integer; {Dummy parameter.}
- VarPosBlk : array[1..128] of char; {Dummy used in ops that don't}
- {pass/return position block. }
-
- (* PUBLIC FUNCTIONS *)
- (* ---------------- *)
-
- {The Btrv function declared here is public, but should not be needed much. It
- is included in the public declaration only to be complete and give you
- access to the standard call if you should need it.}
-
- function Btrv(Op:integer; var Pos,Data; var DataLen:integer; var KBuf;
- Key:integer): integer;
- function CreateFile(const UserFileName: FNameStr; UserFileSpec:PFileSpec;
- const AltColFile: FNameStr; const OName: TOwnerName;
- Access: integer): integer;
- function CloneFile(const CurrentFile, NewFile: FNameStr; Option: integer;
- const OName: TOwnerName): integer;
- function NewKeySpec(KPos, KLen, KFlags: integer; EType: byte;
- NextKey: PKeyList): PKeyList;
- function IsBtrieveLoaded: boolean;
- function LTrim(S: String): String; {LTrim and RTrim were taken from one of }
- function RTrim(S: String): String; {the Turbo Vision .PAS source files. }
-
-
- IMPLEMENTATION
- (* ------------------------------------------------------------------------ *)
- (* ------------------------------------------------------------------------ *)
- USES Dos; {Dos unit needed for the Btrieve interface call (interrupts)}
-
- {$R-} {Range checking off...is TP's default}
- {$B+} {Boolean complete evaluation on...NOT a default, but apparently
- required by the interface call. Is turned off at end of
- implementation of Btrieve interface definition}
- {$V-} {Non-strict string var checking...Btrieve wants it so. Strict
- checking is turned back on at the end of the interface definition.}
- {$S+} {Stack checking on}
- {$I+} {I/O checking on}
-
- { Module Name: TUR5BTRV.PAS }
-
- { Description: This is the Btrieve interface for Turbo Pascal (MS-DOS). }
- { This routine sets up the parameter block expected by }
- { Btrieve, and issues interrupt 7B. It should be compiled }
- { with the $V- switch so that runtime checks will not be }
- { performed on the variable parameters. }
- { }
- { Synopsis: STAT := BTRV (OP, POS.START, DATA.START, DATALEN, }
- { KBUF.START, KEY); }
- { where }
- { OP is an integer, }
- { POS is a 128 byte array, }
- { DATA is an untyped parameter for the data buffer, }
- { DATALEN is the integer length of the data buffer, }
- { KBUF is the untyped parameter for the key buffer, }
- { and KEY is an integer. }
- { }
- { Returns: Btrieve status code (see Appendix B of the Btrieve Manual). }
- { }
- { Note: The Btrieve manual states that the 2nd, 3rd, and 5th }
- { parameters be declared as variant records, with an integer }
- { type as one of the variants (used only for Btrieve calls), }
- { as is shown in the example below. This is supported, but }
- { the restriction is no longer necessary. In other words, any }
- { variable can be sent in those spots as long as the variable }
- { uses the correct amount of memory so Btrieve does not }
- { overwrite other variables. }
- { }
- { var DATA = record case boolean of }
- { FALSE: ( START: integer ); }
- { TRUE: ( EMPLOYEE_ID: 0..99999; }
- { EMPLOYEE_NAME: packed array[1..50] of char; }
- { SALARY: real; }
- { DATA_OF_HIRE: DATE_TYPE ); }
- { end; }
- { }
- { There should NEVER be any string variables declared in the }
- { data or key records, because strings store an extra byte for }
- { the length, which affects the total size of the record. }
-
- (* BTRV function *)
- (* ------------- *)
- function Btrv (Op: integer; var Pos, Data; var DataLen: integer; var Kbuf;
- Key: integer): integer;
-
- const
- VAR_ID = $6176; {id for variable length records - 'va'}
- BTR_INT = $7B;
- BTR2_INT = $2F;
- BTR_OFFSET = $0033;
- MULTI_FUNCTION = $AB;
-
- { ProcId is used for communicating with the Multi Tasking Version of }
- { Btrieve. It contains the process id returned from BMulti and should }
- { not be changed once it has been set. }
- { }
- ProcId: integer = 0; { initialize to no process id }
- MULTI : boolean = false; { set to true if BMulti is loaded }
- VSet : boolean = false; { set to true if we have checked for BMulti }
-
- type
- ADDR32 = record {32 bit address}
- OFFSET : word; {&&&old->integer}
- SEGMENT: word; {&&&used->integer}
- end;
-
- BTR_PARMS = record
- USER_BUF_ADDR : ADDR32; {data buffer address}
- USER_BUF_LEN : integer; {data buffer length}
- USER_CUR_ADDR : ADDR32; {currency block address}
- USER_FCB_ADDR : ADDR32; {file control block address}
- USER_FUNCTION : integer; {Btrieve operation}
- USER_KEY_ADDR : ADDR32; {key buffer address}
- USER_KEY_LENGTH: BYTE; {key buffer length}
- USER_KEY_NUMBER: shortint; {key number&&&old->BYTE}
- USER_STAT_ADDR : ADDR32; {return status address}
- XFACE_ID : integer; {language interface id}
- end;
-
- var
- STAT : integer; {Btrieve status code}
- XDATA: BTR_PARMS; {Btrieve parameter block}
- REGS : Dos.Registers; {register structure used on interrrupt call}
- DONE : boolean;
-
- begin
- REGS.AX := $3500 + BTR_INT;
- INTR ($21, REGS);
- if (REGS.BX <> BTR_OFFSET) then {make sure Btrieve is installed}
- STAT := 20
- else
- begin
- if (not VSet) then {if we haven't checked for Multi-User version}
- begin
- REGS.AX := $3000;
- INTR ($21, REGS);
- if ((REGS.AX AND $00FF) >= 3) then
- begin
- VSet := true;
- REGS.AX := MULTI_FUNCTION * 256;
- INTR (BTR2_INT, REGS);
- MULTI := ((REGS.AX AND $00FF) = $004D);
- end
- else
- MULTI := false;
- end;
- {make normal btrieve call}
- with XDATA do
- begin
- USER_BUF_ADDR.SEGMENT := SEG (DATA);
- USER_BUF_ADDR.OFFSET := OFS (DATA); {set data buffer address}
- USER_BUF_LEN := DATALEN;
- USER_FCB_ADDR.SEGMENT := SEG (POS);
- USER_FCB_ADDR.OFFSET := OFS (POS); {set FCB address}
- USER_CUR_ADDR.SEGMENT := USER_FCB_ADDR.SEGMENT; {set cur seg}
- USER_CUR_ADDR.OFFSET := USER_FCB_ADDR.OFFSET+38;{set cur ofs}
- USER_FUNCTION := OP; {set Btrieve operation code}
- USER_KEY_ADDR.SEGMENT := SEG (KBUF);
- USER_KEY_ADDR.OFFSET := OFS (KBUF); {set key buffer address}
- USER_KEY_LENGTH := 255; {assume its large enough}
- USER_KEY_NUMBER := KEY; {set key number}
- USER_STAT_ADDR.SEGMENT := SEG (STAT);
- USER_STAT_ADDR.OFFSET := OFS (STAT); {set status address}
- XFACE_ID := VAR_ID; {set language id}
- end;
-
- REGS.DX := OFS (XDATA);
- REGS.DS := SEG (XDATA);
-
- if (NOT MULTI) then {MultiUser version not installed}
- INTR (BTR_INT, REGS)
- else
- begin
- DONE := FALSE;
- repeat
- REGS.BX := ProcId;
- REGS.AX := 1;
- if (REGS.BX <> 0) then
- REGS.AX := 2;
- REGS.AX := REGS.AX + (MULTI_FUNCTION * 256);
- INTR (BTR2_INT, REGS);
- if ((REGS.AX AND $00FF) = 0) then
- DONE := TRUE
- else begin
- REGS.AX := $0200;
- INTR ($7F, REGS);
- DONE := FALSE;
- end;
- until (DONE);
- if (ProcId = 0) then
- ProcId := REGS.BX;
- end;
- DATALEN := XDATA.USER_BUF_LEN;
- end;
- BTRV := STAT;
- end;
- {$B-}
- {$V+}
-
-
- (* IMPLEMENTATION OF OBJECT METHODS *)
- (* ------------------------------------------------------------------------ *)
-
- (* BRECMGR.INIT Constructor *)
- (* ------------------------ *)
- constructor TRecMgr.Init;
- var
- Counter : integer;
- BNumber,
- BRev : string[2];
- BProduct : string[1];
- begin
- inherited Init; {assures all data fields zeroed}
- BStatus := Btrv(BVersion, VarPosBlk, Version, Counter, VarNotRequired, Zero);
- str(Version.Number:2, BNumber);
- BNumber := LTrim(BNumber);
- str(Version.Rev:2, BRev);
- BProduct := Version.Product;
- VersionString := BNumber + '.' + BRev + BProduct;
- end;
-
-
- (* BRECMGR.BT function *)
- (* ------------------- *)
- {Will not handle reset of other workstations as written, as no true key
- buffer is passed. Will handle begin/end/abort transaction, reset & stop.
- Would also handle version op, but is handled by BRecMgr.Init anyway!}
-
- function TRecMgr.BT(OpCode, Key: integer): integer;
- begin
- BT := Btrv(OpCode, VarPosBlk, VarNotRequired, VarNotRequired,
- VarNotRequired, Key);
- end;
-
-
- (* BRECMGR Destructor *)
- (* ------------------ *)
- destructor TRecMgr.Done;
- begin
- inherited Done;
- end;
-
-
- (* BRECMGR.GetVersion function *)
- (* --------------------------- *)
- function TRecMgr.GetVersion: string;
- begin
- GetVersion := VersionString;
- end;
-
-
- (* TALTCOLSEQ.INIT Constructor *)
- (* ---------------------------- *)
- constructor TAltColSeq.Init(const SpecName: FNameStr);
- var
- AltFile: file of TAltColSpec; {The TAltColSpec object type is used }
- begin {internally by the CreateFile function.}
- inherited Init;
- assign(AltFile, SpecName);
- {$I-} reset(AltFile); {$I+} {It's up to user program to assure that the}
- if ioresult = 0 then {alternate collating sequence file exists }
- begin {in the current directory when the }
- read(AltFile, Spec); {CreateFile fcn is called, and is of the }
- close(AltFile); {standard format expected by Btrieve. }
- end
- else
- Fail;
- end;
-
-
- (* TALTCOLSEQ.DONE Destructor *)
- (* --------------------------- *)
- destructor TAltColSeq.Done;
- begin
- inherited Done;
- end;
-
-
- (* TFILESPECOBJ.INIT Constructor *)
- (* ----------------------------- *)
- constructor TFileSpecObj.Init(RecLen, PageSize, NumKeys,
- FileFlags, PreAlloc: integer;
- AKeyList: PKeyList);
- var
- Counter: integer;
- Key: PKeyList;
- begin
- inherited Init;
- Specs := new(PFileSpec);
- Keys := AKeyList; {save head of list for disposal}
- fillchar(Specs^, sizeof(Specs^), 0);
- Specs^.RecLen := RecLen;
- Specs^.PageSize := PageSize;
- Specs^.NumKeys := NumKeys;
- Specs^.FileFlags := FileFlags;
- Specs^.PreAlloc := PreAlloc;
- Counter := 0;
- Key := AKeyList;
- if Key <> nil then
- repeat
- Specs^.KeyArray[Counter].KeyPos := Key^.KeySpec.KeyPos;
- Specs^.KeyArray[Counter].KeyLen := Key^.KeySpec.KeyLen;
- Specs^.KeyArray[Counter].KeyFlags := Key^.KeySpec.KeyFlags;
- Specs^.KeyArray[Counter].ExtKeyType := Key^.KeySpec.ExtKeyType;
- inc(Counter);
- Key := Key^.Next;
- until Key = nil;
- end;
-
-
- (* TFILESPECOBJ.DONE Destructor *)
- (* ---------------------------- *)
- destructor TFileSpecObj.Done;
-
- procedure KillKeyList(x: PKeyList);
- var
- x1, x2: PKeyList;
- begin
- if x = nil then exit;
- x1 := x;
- while x1^.next <> nil do
- begin
- x2 := x1^.next;
- dispose(x1);
- x1 := x2;
- end;
- dispose(x1);
- end;
-
- begin
- inherited Done;
- dispose(Specs);
- KillKeyList(Keys);
- end;
-
-
- (* BFILE.INIT Constructor *)
- (* ---------------------- *)
- constructor BFile.Init(const UserFileName: FNameStr; OpenMode: integer;
- const OName: TOwnerName);
-
- var
- {665 = 16 for filespec + 384 for max key specs}
- FileBufLen, {+ 265 for an alternate collating sequence. }
- KeyBufLen, {Max of 24 keys * 16 bytes per key spec.}
- AltColNameOffset,
- Counter, Counter1,
- Status : integer;
- NumRecsWord1,
- NumRecsWord2 : word;
-
- procedure CountSegments;
- begin
- repeat
- if (Specs.KeyArray[Counter1].KeyFlags and Segmented) = Segmented then
- begin
- if (Specs.KeyArray[Counter1].KeyFlags and AltCol) = AltCol then
- HasAltCol := true;
- inc(NumSegs);
- inc(Counter1);
- end
- else
- begin
- if (Specs.KeyArray[Counter1].KeyFlags and AltCol) = AltCol then
- HasAltCol := true;
- inc(Counter);
- inc(Counter1);
- end;
- until (Specs.KeyArray[Counter1-1].KeyFlags and Segmented) <> Segmented;
- end;
-
- begin
- inherited Init; {assures all data fields zeroed}
- {665 = 16 for filespec + 384 for max key specs}
- FileBufLen := MaxFileSpecLength;{+ 265 for an alternate collating sequence}
- KeyBufLen := 384; {Max of 24 keys * 16 bytes per key spec.}
- HasAltCol := false; {initialize to false 'until proven guilty!'}
- AltColName := '';
- ConvertName(UserFileName); {Sets fields DFileName and FileName}
- IsVarLength := false;
- HasOwner := false;
- OwnerName := '';
- if OName <> '' then
- begin
- OwnerName := OName;
- HasOwner := true;
- end;
- Status := Open(OpenMode);
- if Status = 0 then {if open op successful, do a stat op}
- begin
- Status := Btrv(BStat, PosBlk, Specs.SpecBuf, FileBufLen, KeyBufLen,
- Zero);
- {Btrieve filespecs and key specs are now in the BFile object!}
- {Variable FileBufLen will have been changed to size of data
- buffer returned by stat call. Save that value now.}
- if Status = 0 then {if stat successfull, fill object data fields}
- begin
- SpecLength := FileBufLen;
- NumRecsWord1 := Specs.NumRecs[1]; {get rid of sign bit!! by }
- NumRecsWord2 := Specs.NumRecs[2]; {converting 2 ints to words}
- NumRecs := NumRecsWord1 + NumRecsWord2 * 65536;
- NumSegs := Specs.NumKeys;
- if (Specs.FileFlags and VarLength) = VarLength then
- IsVarLength := true;
- Counter := 1; Counter1 := 0;
- while Counter <= Specs.NumKeys do {Will be skipped if data}
- CountSegments; {only file. }
- if HasAltCol then
- begin
- AltColNameOffset := (16+KeySpecSize*NumSegs+1);
- for Counter := 1 to 8 do
- AltColName[Counter] := chr(Specs.Entire[AltColNameOffset + Counter]);
- end;
- DBufferLen := Specs.RecLen;
- BStatus := 0; {all went well, return a code 0}
- end
- else
- begin
- BStatus := Status; {Open op succeeded but stat failed; put }
- Status := Close; {error code for bad stat in global var and}
- end; {close the damn file quick!}
- end
- else
- BStatus := Status; {assign err code for bad open to global var}
- end;
-
-
- (* BFILE.BT function *)
- (* ----------------- *)
- function BFile.BT(OpCode, Key: integer): integer;
- begin
- Abstract;
- end;
-
-
- (* BFILE.OPEN function *)
- (* ------------------- *)
- function BFile.Open(OpenMode: integer): integer;
- var
- BufferSize: integer;
- begin
- if HasOwner then
- begin
- BufferSize := 8;
- Open := Btrv(BOpen, PosBlk, OwnerName[1], BufferSize, FileName, OpenMode);
- end
- else
- Open := Btrv(BOpen, PosBlk, VarNotRequired, VarNotRequired, FileName, OpenMode);
- end;
-
-
- (* BFILE.CLOSE Function *)
- (* -------------------- *)
- function BFile.Close: integer;
- begin
- Close := Btrv(BClose, PosBlk, VarNotRequired, VarNotRequired,
- VarNotRequired, NotRequired);
- end;
-
-
- (* BFILE.ADDSUPPIDX Function *)
- (* ------------------------- *)
- function BFile.AddSuppIdx(KeyList: PKeyList; const AltColFile: FNameStr): boolean;
- type
- PBuffer = ^TBuffer;
- TBuffer = array[0..MaxFileSpecLength] of byte;
- var
- NewSegmentCount,
- Offset: integer;
- SuppIdxHasAltCol: boolean;
- AKeyList, X1, X2: PKeyList;
- ACS: PAltColSeq;
- Buffer: PBuffer;
- BufferLength: integer;
- begin
- NewSegmentCount := 1;
- SuppIdxHasAltCol := false;
- Offset := 0;
- AKeyList := KeyList;
- while (AKeyList^.Next <> nil) do {Count # segs in new supp idx.}
- begin
- inc(NewSegmentCount);
- AKeyList := AKeyList^.Next;
- end;
- if (NewSegmentCount + NumSegs) > MaxNumSegments then
- AddSuppIdx := false
- else
- begin
- new(Buffer);
- fillchar(Buffer^, sizeof(Buffer^), 0);
- AKeyList := KeyList;
- repeat
- if (AKeyList^.KeySpec.KeyFlags and AltCol) = AltCol then
- SuppIdxHasAltCol := true;
- move(AKeyList^.KeySpec, Buffer^[Offset], KeySpecSize);
- inc(Offset, KeySpecSize);
- AKeyList := AKeyList^.Next;
- until (AKeyList = nil);
- if (KeyList <> nil) then {Dispose of linked list of key specs.}
- begin
- X1 := KeyList;
- while (X1^.Next <> nil) do
- begin
- X2 := X1^.Next;
- dispose(X1);
- X1 := X2;
- end;
- dispose(X1);
- end;
- BufferLength := KeySpecSize * NewSegmentCount;
- {If the supp index will have an ACS, get it into data buffer, and add
- its size to DBufferLen parameter.}
- if (AltColFile <> '') and SuppIdxHasAltCol then
- begin
- ACS := new(PAltColSeq, Init(AltColFile));
- if (ACS <> nil) then
- begin
- move(ACS^.Spec, Buffer^[BufferLength], sizeof(ACS^.Spec));
- inc(BufferLength, sizeof(ACS^.Spec));
- dispose(ACS, Done);
- end;
- end;
- BStatus := Btrv(BCrSuppIdx, PosBlk, Buffer^, BufferLength, VarNotRequired, NotRequired);
- dispose(Buffer);
- if BStatus = 0 then
- AddSuppIdx := true
- else
- AddSuppIdx := false;
- end;
- end;
-
-
- (* BFILE.DONE Destructor *)
- (* --------------------- *)
- destructor BFile.Done;
- begin
- inherited Done;
- end;
-
-
- (* BFILE.CONVERTNAME Procedure *)
- (* --------------------------- *)
- {this one is private to BFile}
- procedure BFile.ConvertName(const UserFileName: FNameStr);
- begin
- DFileName := UserFileName;
- move(DFileName[1], FileName[1], length(DFileName)); {conv string to array}
- FileName[length(DFileName) + 1] := ' '; {provide required pad char}
- end;
-
-
- (* BFIXED.INIT Constructor *)
- (* ----------------------- *)
- constructor BFixed.Init(const UserFileName: FNameStr; OpenMode: integer;
- const OName: TOwnerName);
- begin
- inherited Init(UserFileName, OpenMode, OName);
- end;
-
-
- (* BFIXED.BT function *)
- (* ----------------- *)
- function BFixed.BT(OpCode, Key: integer): integer;
- begin
- BT := Btrv(OpCode, PosBlk, DBuffer, Specs.RecLen, KBuffer, Key);
- end;
-
-
- (* BFIXED.DONE Destructor *)
- (* ---------------------- *)
- destructor BFixed.Done;
- begin
- inherited Done;
- end;
-
-
- (* BSIZED.INIT Constructor *)
- (* ----------------------- *)
- constructor BSized.Init(const UserFileName: FNameStr; OpenMode: integer;
- const OName: TOwnerName; BuffSize: integer);
- begin
- inherited Init(UserFileName, OpenMode, OName);
- if BuffSize <= 0 then
- BuffSize := MaxFixedRecLength;
- DBufferSize := BuffSize;
- DBuffer := memallocseg(BuffSize);
- KBuffer := memallocseg(MaxKBufferLength);
- fillchar(DBuffer^, BuffSize, 0);
- fillchar(KBuffer^, MaxKBufferLength, 0);
- end;
-
-
- (* BSIZED.DONE Destructor *)
- (* ---------------------- *)
- destructor BSized.Done;
- begin
- if DBuffer <> nil then freemem(DBuffer, DBufferSize);
- if KBuffer <> nil then freemem(KBuffer, MaxKBufferLength);
- DBuffer := nil;
- KBuffer := nil;
- inherited Done;
- end;
-
-
- (* BSIZED.BT Function *)
- (* ------------------ *)
- function BSized.BT(OpCode, Key: integer): integer;
- begin
- BT := Btrv(OpCode, PosBlk, DBuffer^, DBufferLen, KBuffer^, Key);
- end;
-
-
- (* TFILTERSPEC.INITF Constructor *)
- (* ----------------------------- *)
- {Be sure to remember that the offset parameter here is 0 relative to start of
- record!!}
-
- constructor TFilterSpec.InitF(FieldType: byte; FieldLen, Offset: integer;
- CompCode, Expression: byte; CompOffset: integer);
- begin
- inherited Init; {assures all data fields zeroed}
- LogicTerm.FieldType := FieldType;
- LogicTerm.FieldLen := FieldLen;
- LogicTerm.Offset := Offset;
- LogicTerm.CompCode := CompCode;
- LogicTerm.Expression := Expression;
- LogicTerm.FieldComp := true;
- LogicTerm.CompOffset := Offset;
- end;
-
-
- (* TFILTERSPEC.INITV Constructor *)
- (* ----------------------------- *)
- {Be sure to remember that the offset parameter here is 0 relative to start of
- record!!}
-
- constructor TFilterSpec.InitV(FieldType: byte; FieldLen, Offset: integer;
- CompCode, Expression: byte; const Value: array of byte);
- begin
- inherited Init; {assures all data fields zeroed}
- LogicTerm.FieldType := FieldType;
- LogicTerm.FieldLen := FieldLen;
- LogicTerm.Offset := Offset;
- LogicTerm.CompCode := CompCode;
- LogicTerm.Expression:= Expression;
- LogicTerm.FieldComp := false;
- move(Value[0], LogicTerm.Value[1], high(Value)+1);
- end;
-
-
- (* TFILTERSPEC.DONE Destructor *)
- (* --------------------------- *)
- destructor TFilterSpec.Done;
- begin
- inherited Done;
- end;
-
-
- (* TEXTSPEC.INIT Constructor *)
- (* ------------------------- *)
- constructor TExtSpec.Init(Len, Ofs: integer);
- begin
- inherited Init; {assures all data fields zeroed}
- ExtRepeater.FieldLen := Len;
- ExtRepeater.Offset := Ofs;
- end;
-
-
- (* TEXTSPEC.DONE Destructor *)
- (* ----------------------- *)
- destructor TExtSpec.Done;
- begin
- inherited Done;
- end;
-
-
- (* BFILEEXT.INIT Constructor *)
- (* ------------------------- *)
- {always check for a failure!}
-
- constructor BFileExt.Init(const UserFileName: FNameStr; OpenMode: integer;
- const OName: TOwnerName);
- begin
- inherited Init(UserFileName, OpenMode, OName);
- Header.Constant[1] := 'E';
- Header.Constant[2] := 'G';
- ExtDBuffer := memallocseg(MaxExtDBufferLength);
- FilterSpec := new(PCollection, Init(2,2));
- ExtractorSpec := new(PCollection, Init(5,2));
- if (ExtDBuffer = nil) or (FilterSpec = nil) or (ExtractorSpec = nil) then
- Fail;
- end;
-
-
- (* BFILEEXT.DONE Destructor *)
- (* ------------------------ *)
- destructor BFileExt.Done;
- begin
- inherited Done;
- dispose(ExtDBuffer);
- dispose(ExtractorSpec, Done);
- dispose(FilterSpec, Done);
- end;
-
-
- (* BFILEEXT.SETEXTDBUFFERLEN function *)
- (* ---------------------------------- *)
- {Compute sizes of data buffers sent and returned, to determine proper size to
- specify in call. Assumes user program has inserted proper items into the
- collections for filter terms and extractor specs. Is private to BFileExt.}
-
- procedure BFileExt.SetExtDBufferLen;
- var
- LengthSent, LengthReturned,
- RecordLengthReturned, RecordImageReturned : integer;
-
- procedure MakeFilterSpecs;
- procedure CalcFilterLengths(FSpec: PFilterSpec); far;
- begin
- with FSpec^ do
- begin
- inc(LengthSent, 7);
- if (LogicTerm.CompCode and UseField) = UseField then
- inc(LengthSent, 2)
- else
- inc(LengthSent, LogicTerm.FieldLen);
- end;
- end;
- begin
- FilterSpec^.ForEach(@CalcFilterLengths);
- end;
-
- procedure MakeExtSpecs;
- procedure CalcExtLengths(ExtSpec: PExtSpec); far;
- begin
- with ExtSpec^ do
- begin
- inc(LengthSent, 4);
- inc(RecordLengthReturned, ExtRepeater.FieldLen);
- end;
- end;
- begin
- ExtractorSpec^.ForEach(@CalcExtLengths);
- end;
-
- begin
- LengthSent := 8; {4 for header length, 4 for fixed filter length}
-
- {Work on filter logic term portion of spec.}
- if FilterSpec^.Count > 0 then {if any filter terms in the collection}
- MakeFilterSpecs;
-
- {Work on extractor portion of spec.}
- inc(LengthSent, 4); {size of fixed part of extractor}
- RecordLengthReturned := 0;
- MakeExtSpecs; {there must always be at least 1 extractor spec}
-
- {2 for count of recs, 4 for currency pos}
- RecordImageReturned := RecordLengthReturned + 6;
- {2 for count of recs}
- LengthReturned := 2 + (RecordImageReturned * Extractor.NumRecords);
-
- Header.DBufferLen := LengthSent;
-
- if LengthSent >= LengthReturned then
- DBufferLen := LengthSent
- else
- DBufferLen := LengthReturned;
- end;
-
-
- (* BFILEEXT.MAKEEXTDBUFFER Function *)
- (* -------------------------------- *)
- {Private to BFileExt, called in BFileExt.BT, which is called by each
- descendant's override of BFileExt.BT. Assumes program has already set up
- the collections required.}
-
- procedure BFileExt.MakeExtDBuffer;
- var
- Offset : integer;
-
- procedure MoveFilterSpecs;
- procedure MoveSingleFilterSpec(FSpec: PFilterSpec); far;
- begin
- with FSpec^ do
- begin
- {move fixed part of logic term}
- move(LogicTerm, ExtDBuffer^.Entire[Offset], sizeof(LogicTerm.Fixed));
- inc(Offset, sizeof(LogicTerm.Fixed));
- {now need to move variable part of logic term}
- if (LogicTerm.CompCode and UseField) = UseField then
- begin
- move(LogicTerm.CompOffset, ExtDBuffer^.Entire[Offset],
- sizeof(LogicTerm.CompOffset));
- Offset := Offset + sizeof(LogicTerm.CompOffset);
- end
- else
- begin
- move(LogicTerm.Value, ExtDBuffer^.Entire[Offset],
- LogicTerm.FieldLen);
- Offset := Offset + LogicTerm.FieldLen;
- end;
- end;
- end;
- begin
- FilterSpec^.ForEach(@MoveSingleFilterSpec);
- end;
-
- procedure MoveExtractorSpecs;
- procedure MoveSingleExtractorSpec(ExtSpec: PExtSpec); far;
- begin
- with ExtSpec^ do
- begin
- move(ExtSpec^.ExtRepeater, ExtDBuffer^.Entire[Offset],
- sizeof(ExtSpec^.ExtRepeater));
- Offset := Offset + sizeof(ExtSpec^);
- end;
- end;
- begin
- ExtractorSpec^.ForEach(@MoveSingleExtractorSpec);
- end;
-
- begin
- {Move header definition into buffer.}
- move(Header, ExtDBuffer^.Header, sizeof(Header));
-
- {Move fixed part of filter definition into buffer.}
- move(Filter, ExtDBuffer^.Filter, sizeof(Filter));
- Offset := 1 + sizeof(Header) + sizeof(Filter);
-
- {Read filter logic terms into buffer.}
- if FilterSpec^.Count > 0 then
- MoveFilterSpecs;
-
- {Move fixed part of extractor definition into buffer.}
- move(Extractor, ExtDBuffer^.Entire[Offset], sizeof(Extractor.Entire));
- Offset := Offset + sizeof(Extractor.Entire);
-
- {Move extractor terms into buffer.}
- MoveExtractorSpecs;
- end;
-
-
- (* BFILEEXT.BTEXT function *)
- (* ----------------------- *)
- {Overrides of this function in BFileExt descendants MUST call
- BFileExt.BTExt, as it sets the buffer length in the header, and puts
- together the 'send' buffer. User programs MUST have inserted filter logic
- terms and extractor specs into their respective collections before invoking
- this function, or they'll make a fine mess of things, Ollie!}
-
- function BFileExt.BTExt(OpCode, Key: integer): integer;
- begin
- SetExtDBufferLen;
- MakeExtDBuffer;
- end;
-
-
- (* BFILEEXT.SETTERMS procedure *)
- (* --------------------------- *)
- procedure BFileExt.SetTerms(MSkip, NumLTerms, NRecs, NumFlds: integer);
- begin
- Filter.MaxSkip := MSkip;
- Filter.NumLogicTerms := NumLTerms;
- Extractor.NumRecords := NRecs;
- Extractor.NumFields := NumFlds;
- end;
-
-
- (* IMPLEMENTATION OF UTILITY FUNCTIONS/PROCEDURES *)
- (* ------------------------------------------------------------------------ *)
-
- (* CREATEFILE function *)
- (* -------------------- *)
- {Assumes a PFILESPEC variable has been instantiated and assigned its values,
- and that if you use an alternate collating sequence, it exists in the
- current directory. No specific support for null keys, blank compression,
- data-only files.}
-
- function CreateFile(const UserFileName: FNameStr; UserFileSpec:PFileSpec;
- const AltColFile: FNameStr; const OName: TOwnerName;
- Access: integer): integer;
- var
- CFSpecLength,
- Counter,
- Counter1,
- NumSegs,
- Temp : integer;
- BtrieveFileName : BFileName;
- HasAltCol : boolean;
- AltColObj : PAltColSeq;
- NewFile : PBFixed;
-
- procedure CountSegments;
- begin
- with UserFileSpec^ do
- repeat
- if (KeyArray[Counter1].KeyFlags and Segmented) = Segmented then
- begin
- if (KeyArray[Counter1].KeyFlags and AltCol) = AltCol then
- HasAltCol := true;
- inc(NumSegs);
- inc(Counter1);
- end
- else
- begin
- if (KeyArray[Counter1].KeyFlags and AltCol) = AltCol then
- HasAltCol := true;
- inc(Counter);
- inc(Counter1);
- end;
- until (KeyArray[Counter1-1].KeyFlags and Segmented) <> Segmented;
- end;
-
- begin
- move(UserFileName[1], BtrieveFileName[1], length(UserFileName));
- BtrieveFileName[length(UserFileName) + 1] := ' ';
- Counter := 1; Counter1 := 0;
- NumSegs := UserFileSpec^.NumKeys;
- while Counter <= UserFileSpec^.NumKeys do
- CountSegments;
- CFSpecLength := 16 + (NumSegs * KeySpecSize);
- UserFileSpec^.Reserved[1] := chr(0);
- UserFileSpec^.Reserved[2] := chr(0);
- if (AltColFile <> '') and (HasAltCol = true) then {Note the double check!}
- begin
- AltColObj := new(PAltColSeq, Init(AltColFile));
- move(AltColObj^.Spec, UserFileSpec^.Entire[CFSpecLength+1],
- sizeof(AltColObj^.Spec));
- CFSpecLength := CFSpecLength + sizeof(AltColObj^.Spec);
- dispose(AltColObj, Done);
- end;
- BStatus := Btrv(BCreate, VarPosBlk, UserFileSpec^.SpecBuf, CFSpecLength,
- BtrieveFileName, Zero);
- if (BStatus = 0) and (OName <> '') then
- begin
- NewFile := new(PBFixed, Init(UserFileName, Exclusive, ''));
- fillchar(NewFile^.DBuffer[1], 9, 0);
- fillchar(NewFile^.KBuffer[1], 9, 0);
- Temp := length(OName);
- with NewFile^ do
- begin
- move(OName[1], DBuffer[1], Temp);
- move(OName[1], KBuffer[1], Temp);
- inc(Temp);
- Specs.RecLen := Temp;
- BStatus := BT(BSetOwner, Access);
- Close;
- end;
- dispose(NewFile, Done);
- end;
- CreateFile := BStatus;
- end;
-
-
- (* CLONEFILE function *)
- (* ------------------ *)
- {Programmer is responsible for assuring that 'CurrentFile' exists and can be
- opened. Function will overwrite any existing file with 'NewFile' name.
- The integer returned here can be meaningless if the current file does not
- exist or is not opened properly. This function is as streamlined as
- possible, but puts RESPONSIBILITY on the programmer.
-
- It is entirely possible that this clone function will NOT return a byte for
- byte matching file, if cloning an 'empty' Btrieve file. This would be due
- to the inability to determine the number of pages pre-allocated when a file
- was created, if preallocation had been used. The Btrieve Stat call uses
- the 'Preallocate # of pages' bytes to return the number of unused pages!!
- Thus, the CloneFile function clears the Preallocation bit in the FileFlags
- before creating the new file. A non-exact copy would also result if the
- source file used an owner name, as the clone will NOT bear an owner name.
- If you want an owner name in the clone, add it AFTER creating the clone.
-
- NOTE: This function goes beyond the capability of "BUTIL -CLONE" in that
- this function has flexible handling of supplemental indexes in the
- cloned file. It can drop, retain, or make them permanent in the clone. In
- addition, if no permanent indexes use an alternate collating sequence, but
- one or more supplemental indexes DOES use one, the clone can retain the
- supplemental indexes WITH the collating sequence, duplicating the source
- file's structure perfectly. This is something that "BUTIL -CLONE" simply
- CANNOT HANDLE!!
- }
-
- function CloneFile(const CurrentFile, NewFile:FNameStr; Option: integer;
- const OName: TOwnerName): integer;
- type
- PSuppIdxList = ^TSuppIdxList;
- TSuppIdxList = array[0..23] of boolean; {will hold list of indexes}
- PSuppIdx = ^TSuppIdx;
- TSuppIdx = array[0..23] of TKeySpec;
- PSuppIdxHasAltCol = ^TSuppIdxHasAltCol;
- TSuppIdxHasAltCol = array[0..23] of boolean;
- var
- HasSuppIdx,
- PermKeyHasAltCol : boolean;
- NumberSuppSegs,
- NumberSuppIdx,
- NewOffset,
- DBuffOffset,
- Counter, Counter1,
- NewSpecLength,
- NewNumKeys : integer;
- CurrentBFile : PBFile;
- NewBFile : PBFixed;
- NewBFileName : BFileName;
- NewFileSpec : PFileSpec;
- SuppIdxList : PSuppIdxList;
- SuppIdx : PSuppIdx;
- SuppIdxHasAltCol : PSuppIdxHasAltCol;
- begin
- HasSuppIdx := false;
- PermKeyHasAltCol := false;
- NumberSuppSegs := 0;
- NumberSuppIdx := 0;
- NewOffset := 17;
- DBuffOffset := 1;
- SuppIdxList := new(PSuppIdxList);
- SuppIdx := new(PSuppIdx);
- SuppIdxHasAltCol := new(PSuppIdxHasAltCol);
- NewFileSpec := new(PFileSpec);
- fillchar(SuppIdxList^, sizeof(SuppIdxList^), false);
- fillchar(SuppIdx^, sizeof(SuppIdx^), 0);
- fillchar(SuppIdxHasAltCol^, sizeof(SuppIdxHasAltCol^), false);
- fillchar(NewFileSpec^, sizeof(NewFileSpec^), 0); {initialize spec w/zeros}
-
- move(NewFile[1], NewBFileName[1], length(NewFile));{establish new filename}
- NewBFileName[length(NewFile) + 1] := ' ';
-
- CurrentBFile := new(PBFile, Init(CurrentFile, ReadOnly, OName));
- if BStatus <> 0 then {Exit function if problem opening source file.}
- begin
- CloneFile := BStatus;
- exit;
- end;
-
- {Clear the PreAllocate file flag bit if it had been set in CurrentBFile.}
- CurrentBFile^.Specs.FileFlags := CurrentBFile^.Specs.FileFlags and $FD;
- CurrentBFile^.Specs.UnusedPgs := 0; {If preallocate file flag was set, the}
- {cloned file will have no pages pre- }
- {allocated...NO way to get the }
- {original # of pre-allocated pages! }
-
- NewSpecLength := CurrentBFile^.SpecLength; {Initialize...may reduce}
- NewNumKeys := CurrentBFile^.Specs.NumKeys; {both of these later. }
- move(CurrentBFile^.Specs, NewFileSpec^, 16); {Get filespecs, not keys}
-
- {Determine if there are any supplemental indexes in source file. If so,
- set indicator HasSuppIdx to true, set boolean in an array to true, and
- get a count of number of supplemental indexes, and count of total number
- of supplemental index segments.}
- with CurrentBFile^ do
- for Counter := 1 to NumSegs do
- with Specs.KeyArray[Counter-1] do
- begin
- if ((KeyFlags and AltCol) = AltCol) and
- ((KeyFlags and Supplemental) <> Supplemental) then
- PermKeyHasAltCol := true;
- if (KeyFlags and Supplemental) = Supplemental then
- begin
- if (KeyFlags and AltCol) = AltCol then
- SuppIdxHasAltCol^[NumberSuppSegs] := true;
- HasSuppIdx := true;
- SuppIdxList^[Counter-1] := true;
- move(Specs.KeyArray[Counter-1], SuppIdx^[NumberSuppSegs], KeySpecSize);
- SuppIdx^[NumberSuppSegs].KeyFlags := {Zero supplemental bit}
- SuppIdx^[NumberSuppSegs].KeyFlags and $FF7F;
- inc(NumberSuppSegs); {inc count of supplemental segments.}
- if (Specs.KeyArray[Counter-1].KeyFlags and Segmented) <>
- Segmented then
- inc(NumberSuppIdx); {inc count of supplemental indexes.}
- end; {if (KeyFlags and Supplemental) = Supplemental}
- end;
-
- if ((Option = Drop) or (Option = Retain)) and HasSuppIdx then
- begin
- Counter1 := 0;
- for Counter := 1 to CurrentBFile^.Specs.NumKeys do
- begin
- if SuppIdxList^[Counter1] = true then dec(NewNumKeys);
- repeat
- if (SuppIdxList^[Counter1] = false) then
- begin
- move(CurrentBFile^.Specs.KeyArray[Counter1],
- NewFileSpec^.KeyArray[Counter1], KeySpecSize);
- inc(NewOffset, KeySpecSize);
- end
- else
- dec(NewSpecLength, KeySpecSize);
- inc(Counter1);
- until (CurrentBFile^.Specs.KeyArray[Counter1-1].KeyFlags and Segmented)
- <> Segmented;
- end; {for Counter := 1 to CurrentBFile^.Specs.NumKeys do}
-
- NewFileSpec^.NumKeys := NewNumKeys;
-
- if (CurrentBFile^.HasAltCol) = true then
- move(CurrentBFile^.Specs.Entire[17 + (CurrentBFile^.NumSegs * KeySpecSize)],
- NewFileSpec^.Entire[NewOffset], 265);
-
- {Next line executed if source file has supplemental indexes, whether
- they are to be dropped or retained.}
- CloneFile := Btrv(BCreate, VarPosBlk, NewFileSpec^, NewSpecLength,
- NewBFileName, Zero);
- end;{if ((Option = Drop) or (Option = Retain)) and HasSuppIdx}
-
- {If retaining the supplemental indexes, then at this point we're ready to
- add them to the newly created file.}
- if (Option = Retain) and HasSuppIdx then
- begin
- NewBFile := new(PBFixed, Init(NewFile, Accel, ''));
- Counter1 := 0;
- for Counter := 1 to NumberSuppIdx do
- begin
- repeat
- move(SuppIdx^[Counter1], NewBFile^.DBuffer[DBuffOffset], KeySpecSize);
- inc(DBuffOffset, KeySpecSize);
- inc(Counter1);
- until ((SuppIdx^[Counter1-1].KeyFlags) and Segmented) <> Segmented;
- with NewBFile^ do
- begin
- DBufferLen := Counter1 * KeySpecSize;
- if SuppIdxHasAltCol^[Counter1-1] and (PermKeyHasAltCol = false) then
- begin
- move(CurrentBFile^.Specs.Entire[CurrentBFile^.SpecLength - 264],
- DBuffer[DBuffOffset], 265);
- inc(DBufferLen, 265);
- end;
- BStatus := Btrv(BCrSuppIdx, PosBlk, DBuffer, DBufferLen, KBuffer, Zero);
- fillchar(DBuffer, sizeof(DBuffer), 0);
- end;
- inc(DBuffOffset);
- end;
- BStatus := NewBFile^.Close;
- CloneFile := BStatus;
- dispose(NewBFile, Done);
- end;
-
- {WARNING!! If user program specified 'None' and there actually ARE one or
- more supplemental indexes in the source file, they WILL be retained in
- the target file, as permanent indexes!}
- if (Option = None) or ((Option = Retain) and (not HasSuppIdx)) or
- ((Option = Drop) and (not HasSuppIdx)) then
- begin
- BStatus := Btrv(BCreate, VarPosBlk, CurrentBFile^.Specs,
- CurrentBFile^.SpecLength, NewBFileName, Zero);
- CloneFile := BStatus;
- end;
-
- CurrentBFile^.Close;
- dispose(CurrentBFile, Done);
- dispose(NewFileSpec); {Note NewFileSpec is not used if HandleSupps=None}
- dispose(SuppIdxHasAltCol);
- dispose(SuppIdx);
- dispose(SuppIdxList);
- end;
-
-
- (* NEWKEYSPEC Function *)
- (* ------------------- *)
- function NewKeySpec(KPos, KLen, KFlags: integer; EType: byte;
- NextKey: PKeyList): PKeyList;
- var TheKeyList: PKeyList;
- begin
- TheKeyList := new(PKeyList);
- fillchar(TheKeyList^, sizeof(TheKeyList^), 0);
- with TheKeyList^.KeySpec do
- begin
- KeyPos := KPos;
- KeyLen := KLen;
- KeyFlags := KFlags;
- ExtKeyType := EType;
- end;
- TheKeyList^.Next := NextKey;
- NewKeySpec := TheKeyList;
- end;
-
-
- (* IS BTRIEVE LOADED procedure *)
- (* --------------------------- *)
- {this is private to the unit, and is executed only during unit initialization}
- function IsBtrieveLoaded: boolean;
- begin
- BStatus := Btrv(BReset, VarPosBlk, VarNotRequired, VarNotRequired,
- VarNotRequired, Zero);
- if BStatus = BtrieveNotLoaded then
- IsBtrieveLoaded := false
- else
- IsBtrieveLoaded := true;
- end;
-
-
- (* MISCELLANEOUS Functions *)
- (* ----------------------- *)
-
- {LTrim and RTrim were taken from one of the Turbo Vision .PAS source files!}
-
- function LTrim(S: String): String;
- var
- I: integer;
- begin
- I := 1;
- while (I < length(S)) and (S[I] = ' ') do inc(I);
- LTrim := copy(S, I, 255);
- end;
-
- function RTrim(S: String): String;
- var
- I: integer;
- begin
- while S[Length(S)] = ' ' do dec(S[0]);
- RTrim := S;
- end;
-
-
- (* INITIALIZATION Section *)
- (* ----------------------------------------------------------------------- *)
- END.
-
-