home *** CD-ROM | disk | FTP | other *** search
- { MULKEY } {
-
- +-----------------------------------------------------------------------------+
- | |
- | !! IMPORTANT NOTICE and DISCLAIMER !! |
- | |
- | This software is Copyright 1986, 1987 and 1988 by Mark R. Boler. |
- | All Rights Reserved. Any references to "the developer" in this notice |
- | refers to Mark R. Boler. This source code must not be distributed without |
- | prior written permission from the developer. The use of these routines |
- | require use of the Btrieve file manager system by Novell, Version 4.10 |
- | or later. These routines were tested as well as could be expected but the |
- | developer assumes no responsibility for any errors, omissions, problems or |
- | bugs you may have if you use them. This software is provided "AS IS" |
- | without warranty of any kind. It is your responsibility to test this |
- | software thoroughly! Further, the developer does not warrant, guarantee, |
- | or make any claims of suitability to a particular purpose with regard to |
- | this software. The entire risk as to the results and/or performance of |
- | this software is assumed by you. The developer shall not be liable for |
- | any direct, indirect, consequential, or incidental damages including, but |
- | not limited to, loss of profits or loss of information. By using this |
- | software you agree to the above terms and conditions. |
- | |
- +-----------------------------------------------------------------------------+}
-
- { --------------------------- Compiler Directives --------------------------- }
-
- {$B-} { Boolean complete evaluation off }
- {$D+} { Debug information on }
- {$I-} { I/O checking off }
- {$L+} { Linker uses memory for a buffer }
- {$N-} { No numeric coprocessor }
- {$R-} { Range checking off }
- {$S-} { Stack checking off }
- {$T-} { .TPM file generation off }
- {$V-} { No VAR-String checks }
-
- UNIT Mulkey; { Data file access routines for Btrieve from Turbo Pascal }
-
- INTERFACE { to modify the version - change file MULKEY.INC }
-
- USES Heap, Btrieve, Bits, Strings, Convert, Env;
-
- { --------------------------------------------------------------------------- }
-
- CONST { Exported Constants }
- { --------------------------------- }
- FDescLen = 25; { Length of file description string }
- FSystLen = 25; { Length of file system name string }
- FOwnerLen = 8; { Length of a file owner name }
- MaxPathLen = 68; { Max length of DOS path & name + 2 }
-
- TYPE { Exported Types }
- { ------------------------------- }
- FDescStr = STRING[FDescLen]; { File Description string }
- FSystStr = STRING[FSystLen]; { System name string }
- FOwnerStr = STRING[FOwnerLen]; { Owner name string }
- PathStr = STRING[MaxPathLen]; { DOS file path and name string }
- FSDRec = RECORD { Combined system and fdesc key }
- FDesc: FDescStr;
- FSyst: FSystStr;
- END; {RECORD FSDRec}
-
- { Record Locking Attributes }
- { ------------------------------- }
- FLockAttrib = (NoLocks, { Do not use locks }
- WaitLocks, { Use single wait locks }
- NoWaitLocks, { Use single no wait locks }
- MultiWaitLocks, { Use multiple wait locks }
- MultiNoWaitLocks); { Use multiple no wait locks }
-
- CONST { Exported Variables }
- { DO NOT change these - ONLY READ }
- { ------------------------------- }
- MulkeyActive : BOOLEAN = FALSE; { TRUE if Btreive loaded }
- TransActive : BOOLEAN = FALSE; { TRUE if a transaction is active }
-
- { Changed by your program }
- { ---------------------------- }
- KeyOnly : BOOLEAN = FALSE; { TRUE for Get Key only +50 }
- FileLocks : FLockAttrib = WaitLocks; { Default locks for files }
- TransLocks : FLockAttrib = NoLocks; { Def locks for transactions }
- SystemName : FSystStr = ''; { Empty will find any FileDesc }
-
- { --------------------------------------------------------------------------- }
-
- VAR { ONLY READ these vars - NEVER change }
- { ----------------------------------- }
- IndexError : BOOLEAN; { TRUE if last operation was in error }
- LastErrCode : WORD; { Btrieves last error code }
- BtVersion : STRING[45]; { Returns version of Btrieve loaded }
- MulkeyVersion : STRING[45]; { Returns version of Mulkey in use }
-
- { ------------------- Exported Procedures and Functions --------------------- }
-
- FUNCTION AllowShell: BOOLEAN; { Inline directive }
- INLINE($A0/TransActive/ { mov al, TransActive }
- $F6/$D0); { not al }
-
- { Transaction Procedures }
- { ------------------------------------------ }
- PROCEDURE AbortTransaction; { Aborts a currently running transaction }
-
- PROCEDURE EndTransaction; { Normally ends the current transaction }
-
- PROCEDURE BeginTransaction; { Starts a transaction }
- { ------------------------------------------ }
-
- { Owner Procedures }
- { ------------------------------------ }
- PROCEDURE SetOwner(Handle : WORD; { Handle of the file }
- Owner : FOwnerStr; { The owner name }
- AllowRO: BOOLEAN; { Allow read only without an owner }
- Encrypt: BOOLEAN); { Encrypt the data stored in file }
-
- PROCEDURE ClearOwner(Handle: WORD); { Handle of the file to clear owner on }
- { ------------------------------------ }
-
- { File Locking Procedures }
- { ----------------------------- }
- PROCEDURE SetLocks(Handle : WORD; { Handle of the file }
- LockAttrib: FLockAttrib); { Lock attributes }
-
- { sets the locks attributes Btrieve is to use for the file }
-
- PROCEDURE Unlock(Handle: WORD); { Handle of the file }
-
- { Releases any locks accumulated on a file }
-
- { File Procedures and Functions }
- { ------------------------------- }
- FUNCTION OpenFile(FDesc : FDescStr; { FileDesc string to search for }
- OpenMode: INTEGER; { Mode to open file in }
- Owner : FOwnerStr; { Owner of the file }
- FileName: PathStr): WORD; { Path and Name of the file }
-
- { OpenFile will return a handle in the range of FirstHandle - MaxMulkey. }
- { This handle is how you refer to the open file. A handle of 0 means }
- { an error occured and you should check LastErrCode to see what happened. }
-
- PROCEDURE CloseFile(Handle: WORD); { Closes a file }
-
- PROCEDURE ResetFiles; { Closes all resources }
-
- { Closes any open files and release any locks or resources held by this }
- { station Usually, you would only want to do this when you must terminate }
- { the program abnormally }
-
- PROCEDURE ExtendFile(VAR Handle: WORD; { File handle - could change }
- FileName : PathStr; { File name to use for extension }
- ExtendNow: BOOLEAN); { Extend the file now (or later) }
-
- { This procedure will create an extension for a Btrieve file, usually on }
- { another drive. Use this procedure with caution because it will close }
- { and then re-open a file. If it ends in error, the file could still }
- { possibly have been extended and the re-open failed. The file must be }
- { open before using this procedure. The handle is a VAR parameter since }
- { it could be changed by Mulkey during OpenFile although it is not likely. }
-
- FUNCTION MulkeyFileName(Handle: WORD): PathStr; { The file handle }
-
- { Returns the file name used to open the file }
-
- FUNCTION MulkeyExtension(Handle: WORD): PathStr; { The file handle }
-
- { Returns the name of the extension file if there is one }
-
- PROCEDURE GetKeyBuffer(Handle, KeyNum: WORD; { The File and Key number }
- VAR k); { Your variable }
-
- { Returns the key buffer in Mulkeys key buffer area }
-
- PROCEDURE Stat(Handle: WORD); { The file handle }
-
- { Returns information about the file into Mulkeys buffer area which can be }
- { retrieved later with a call to FileInfo() }
-
- FUNCTION FileInfo(Handle: WORD): POINTER; { The file handle }
-
- { Returns a pointer to the FileSpecType of the file. }
- { If Handle is not valid it returns NIL and sets the appropriate error code. }
-
- FUNCTION NumRecords(Handle: WORD): LONGINT; { The file handle }
-
- { Returns the number of records in a Btrieve file. It returns 0 if the }
- { handle is not active and sets IndexError (set in Stat). }
-
- { Miscellaneous Procedures }
- { ------------------------------ }
- PROCEDURE MulkeySearchKey(FDesc: FDescStr; { Creates proper search key and }
- VAR Key: BYTE; { search string for system name }
- VAR Mult: FSDRec);
-
- PROCEDURE SetErr(Status: WORD); { Set the Mulkey error code }
-
- FUNCTION BtError(Code: WORD): STRING; { Btrieve Error String }
-
- FUNCTION MulkeyError: STRING; { Last Btrieve or Mulkey Error }
- { ------------------------------ }
-
- { Change Record Procedures }
- { ------------------------------ }
- PROCEDURE AddRecord(Handle: WORD; { The file handle }
- VAR d); { The record to add to the file }
-
- PROCEDURE UpdateRecord(Handle: WORD; { The file handle }
- VAR d); { The record to change }
-
- { Update the last retrieved record (you must have just used a get operation) }
- { with data from record d. IndexError usually indicates a duplicate key in a }
- { unique key index. }
-
- PROCEDURE DeleteRecord(Handle: WORD); { The file handle }
-
- { Deletes the last retrieved record (you must have just used a get operation) }
- { from the database and all its keys. IndexError usually indicates no valid }
- { last record retrieved. }
-
- { Retrieve Record Procedures }
- { ------------------------------ }
- FUNCTION GetPosition(Handle: WORD): LONGINT; { Returns file record position }
-
- { This will return the file pointer of the file that Btrieve maintains }
-
- PROCEDURE GetDirect(Handle: WORD; { The file handle }
- p: LONGINT; { The record position }
- VAR d); { The data record to read }
-
- PROCEDURE StepDirect(Handle: WORD; { The file handle }
- VAR d); { The data record to read }
-
-
- PROCEDURE GetLowest(Handle: WORD; { The file handle }
- KeyNum: WORD; { The key number to use }
- VAR d); { The data record to read }
-
- PROCEDURE GetHighest(Handle: WORD; { The file handle }
- KeyNum: WORD; { The key number to use }
- VAR d); { The data record to read }
-
-
- PROCEDURE GetEqual(Handle: WORD; { The file handle }
- KeyNum: WORD; { The key number to use }
- VAR k; { The key value to use }
- VAR d); { The data record to read }
-
- PROCEDURE GetGreater(Handle: WORD; { The file handle }
- KeyNum: WORD; { The key number to use }
- VAR k; { The key value to use }
- VAR d); { The data record to read }
-
- PROCEDURE GetLessThan(Handle: WORD; { The file handle }
- KeyNum: WORD; { The key number to use }
- VAR k; { The key value to use }
- VAR d); { The data record to read }
-
- PROCEDURE GetGreaterOrEqual(Handle: WORD; { The file handle }
- KeyNum: WORD; { The key number to use }
- VAR k; { The key value to use }
- VAR d); { The data record to read }
-
- PROCEDURE GetLessThanOrEqual(Handle: WORD; { The file handle }
- KeyNum: WORD; { The key number to use }
- VAR k; { The key value to use }
- VAR d); { The data record to read }
-
- PROCEDURE NextRecord(Handle: WORD; { The file handle }
- KeyNum: WORD; { The key number to use }
- VAR d); { The data record to read }
-
- PROCEDURE PrevRecord(Handle: WORD; { The file handle }
- KeyNum: WORD; { The key number to use }
- VAR d); { The data record to read }
- { ------------------------------ }
- IMPLEMENTATION
-
- {$I MULKEY.INC}
-
- VAR
- ExitSave: POINTER; { Pointer to save the exit procedure }
- MulPtr : MulkeyTable; { The table of pointers for Mulkey handles }
-
- PROCEDURE SetErr(Status: WORD); EXTERNAL;
-
- FUNCTION AdjOp(Op: WORD; LockAttr: FLockAttrib): WORD; EXTERNAL;
-
- FUNCTION HandleActive(Handle: WORD): BOOLEAN; EXTERNAL;
-
- {$L MULKEY.OBJ}
-
- PROCEDURE BeginTransaction; EXTERNAL;
-
- PROCEDURE AbortTransaction; EXTERNAL;
-
- PROCEDURE EndTransaction; EXTERNAL;
-
- {$L MULTRANS.OBJ}
-
- PROCEDURE SetOwner(Handle : WORD;
- Owner : FOwnerStr;
- AllowRO: BOOLEAN;
- Encrypt: BOOLEAN);
- VAR
- Len,
- Status,
- BitMask: WORD;
-
- BEGIN {SetOwner}
- IF HandleActive(Handle) THEN
- BEGIN
- ForceStr(Owner, FOwnerLen);
- Len:= LENGTH(Owner);
- AsciiZ(Owner);
- BitMask:= 0;
- IF AllowRO THEN SetBit(BitMask, ReadOnlyAccessBit);
- IF Encrypt THEN SetBit(BitMask, EncryptBit);
- Status:= Btrv(SetOwnerOp, MulPtr[Handle]^.PosBlock,
- Owner, Len, Owner, BitMask, SIZEOF(Owner));
- END {if}
- ELSE Status:= BadHandleErr;
- SetErr(Status);
- END; {SetOwner}
-
- PROCEDURE UC_File(Handle: WORD;
- Code: WORD);
-
- VAR
- x,
- Status: WORD;
-
- BEGIN {UC_File}
- IF HandleActive(Handle) THEN
- Status:= Btrv(Code, MulPtr[Handle]^.PosBlock, x, x, x, 0, SIZEOF(x))
- ELSE Status:= BadHandleErr;
- SetErr(Status);
- END; {UC_File}
-
- PROCEDURE ClearOwner; EXTERNAL;
-
- PROCEDURE Unlock; EXTERNAL;
-
- {$L MULUCFIL.OBJ}
-
- PROCEDURE SetLocks(Handle: WORD; LockAttrib: FLockAttrib);
-
- VAR
- Status: WORD;
-
- BEGIN {SetLocks}
- IF HandleActive(Handle) THEN
- BEGIN
- UnLock(Handle); { Unlock any existing locks }
- MulPtr[Handle]^.LockAttr:= LockAttrib; { Set new lock attributes }
- Status:= NoErr; { return no error }
- END
- ELSE Status:= BadHandleErr;
- SetErr(Status);
- END; {SetLocks}
-
- FUNCTION FileInfo(Handle: WORD): POINTER;
-
- VAR
- Status: WORD;
-
- BEGIN {FileInfo}
- IF HandleActive(Handle) THEN Status:= NoErr ELSE Status:= BadHandleErr;
- SetErr(Status);
- IF IndexError THEN FileInfo:= NIL
- ELSE FileInfo:= @MulPtr[Handle]^.FileDesc.FileData;
- END; {FileInfo}
-
- PROCEDURE Stat(Handle: WORD);
-
- { This procedure does a stat operation on the file. All information is }
- { stored into the files data records in the FileDescType. It does nothing }
- { unless the file handle is an active handle. IndexError will be set if not. }
-
- VAR
- x,
- Status : WORD;
- Extent : PathStr;
- HoldData: FileSpecType; { temporary holding area }
-
- BEGIN {Stat}
- IF HandleActive(Handle) THEN
- BEGIN
- x:= SIZEOF(HoldData);
- Status:= Btrv(StatOp, MulPtr[Handle]^.PosBlock, HoldData, x,
- Extent[1], 0, PRED(SIZEOF(PathStr)));
- IF (Status = NoErr) THEN
- BEGIN
- x:= 1;
- WHILE (Extent[x] <> #0) AND (x <= MaxPathLen) DO INC(x);
- Extent[0]:= CHR(PRED(x));
- MulPtr[Handle]^.Changed:= FALSE;
- MulPtr[Handle]^.Extension:= Extent;
- MulPtr[Handle]^.FileDesc.FileData:= HoldData;
- END; {if}
- END
- ELSE Status:= BadHandleErr;
- SetErr(Status);
- END; {Stat}
-
- PROCEDURE MulkeySearchKey(FDesc: FDescStr;
- VAR Key: BYTE;
- VAR Mult: FSDRec);
-
- BEGIN {MulkeySearchKey}
- Mult.FDesc:= StripBlanks(FDesc);
- Mult.FSyst:= StripBlanks(SystemName);
- IF (LENGTH(SystemName) > 0) THEN Key:= FDescAndSystemKey
- ELSE Key:= FDescOnlyKey;
- END; {MulkeySearchKey}
-
- FUNCTION GetFileDesc(FDesc: FDescStr;
- VAR r: FileDescType): BOOLEAN;
-
- VAR
- Found : BOOLEAN;
- Key : BYTE;
- x,
- Len : WORD;
- FileName : PathStr;
- Owner : FOwnerStr;
- SearchKey: FSDRec;
- PosBlock : PosBlockType;
-
- BEGIN {GetFileDesc}
- Found:= FALSE;
- FileName:= GetEnv(EnvVar);
- IF (LENGTH(FileName) > 0) AND (LENGTH(FDesc) > 0) THEN
- BEGIN
- Owner:= FileVersion + Revision;
- Len := LENGTH(Owner);
- AsciiZ(Owner);
- AsciiZ(FileName);
- IF (Btrv(OpenOp, PosBlock, Owner, Len, FileName, NormalOpen,
- SIZEOF(FileName)) = NoErr) THEN
- BEGIN
- MulkeySearchKey(FDesc, Key, SearchKey);
- Len := SIZEOF(r);
- Found:= (Btrv(GetEqualOp, PosBlock, r, Len, SearchKey, PRED(Key),
- SIZEOF(SearchKey)) = NoErr);
- Len := Btrv(CloseOp, PosBlock, x, x, x, 0, SIZEOF(x));
- END; {if}
- END; {if}
- GetFileDesc:= Found;
- END; {GetFileDesc}
-
- FUNCTION OpenFile(FDesc : FDescStr;
- OpenMode: INTEGER;
- Owner : FOwnerStr;
- FileName: PathStr): WORD;
-
- VAR
- h,
- x, y,
- Len,
- Status,
- OwnLen,
- Indexes,
- TotKeyMem: WORD;
- MemError : BOOLEAN;
- FileOwner: FOwnerStr;
- MemNeeded: ARRAY[MKeyRange] OF WORD;
-
- PROCEDURE CleanUp;
-
- BEGIN {CleanUp}
- CloseFile(h);
- SetErr(NoMemoryErr);
- END; {CleanUp}
-
- BEGIN {OpenFile}
- OpenFile:= NoHandle;
- IF MulkeyActive THEN
- BEGIN
- h:= FirstHandle;
- WHILE HandleActive(h) DO INC(h);
- IF (h <= MaxMulkey) THEN
- BEGIN
- IF (MAXAVAIL >= (SIZEOF(MemFileType) + SIZEOF(KBuf) +
- SIZEOF(KeyBufPtr) + SIZEOF(POINTER))) THEN
- BEGIN
- NEW(MulPtr[h]); { Allocate some memory }
- IF (MulPtr[h] <> NIL) THEN
- BEGIN
- ForceStr(FileName, MaxPathLen); { Must be right length }
- ForceStr(Owner, FOwnerLen); { Must be right length }
- FDesc := UpCaseStr(FDesc); { Uppercase for search }
- Owner := UpCaseStr(Owner); { Uppercase for owner }
- OwnLen:= LENGTH(Owner); { Set length of owner }
- FileOwner:= Owner; { Real file owner }
- AsciiZ(FileOwner); { Null terminate owner }
- FileName[SUCC(LENGTH(FileName))]:= #0;{ Null terminate file }
- Status:= Btrv(OpenOp, MulPtr[h]^.PosBlock, FileOwner,
- OwnLen, FileName[1], OpenMode, MaxKeyLen);
- IF (Status = BtNotFoundErr) THEN { Create the file }
- BEGIN
- IF (OwnLen = 0) OR
- (StrICmp(MulPtr[h]^.FileDesc.Owner, Owner) = 0) THEN
- BEGIN
- IF GetFileDesc(FDesc, MulPtr[h]^.FileDesc) THEN
- BEGIN
- Len:= SIZEOF(FileSpecType);
- Status:= Btrv(CreateOp, MulPtr[h]^.PosBlock,
- MulPtr[h]^.FileDesc.FileData, Len, FileName[1], 0,
- MaxKeyLen);
- IF (Status = NoErr) THEN { Open the file }
- Status:= Btrv(OpenOp, MulPtr[h]^.PosBlock,
- FileOwner, OwnLen, FileName[1], OpenMode,
- MaxKeyLen);
- IF ((Status = NoErr) AND (OwnLen > 0)) THEN
- SetOwner(h, Owner, MulPtr[h]^.FileDesc.AllowRO,
- MulPtr[h]^.FileDesc.Encrypt);
- END; {if}
- END
- ELSE Status:= OwnerMatchErr;
- END; {IF Status = BtNotFoundErr}
- SetErr(Status);
- IF IndexError THEN EXIT; { Status has been set }
- Stat(h);
- SetErr(Status);
- IF IndexError THEN EXIT; { Status has been set }
-
- { See if we can allocate the key buffer pointer array }
-
- MulPtr[h]^.KeyPtr:= NIL;
- MulPtr[h]^.KeysAlloc:= 0;
- Indexes:= MulPtr[h]^.FileDesc.FileData.NumIndexes;
- TotKeyMem:= SIZEOF(POINTER) * Indexes;
- IF (MAXAVAIL <= TotKeyMem) THEN
- BEGIN
- CleanUp;
- EXIT;
- END; {if}
-
- { Try to allocate the key buffer pointer array }
-
- GETMEM(MulPtr[h]^.KeyPtr, TotKeyMem);
- IF (MulPtr[h]^.KeyPtr = NIL) THEN
- BEGIN
- CleanUp;
- EXIT;
- END; {if}
-
- { Now calculate the memory needed for the key buffers }
-
- WITH MulPtr[h]^.FileDesc.FileData DO
- BEGIN
- y:= 0;
- TotKeyMem:= 0;
- FOR x:= 1 to Indexes DO
- BEGIN
- MemNeeded[x]:= SIZEOF(KBLType);
- REPEAT
- INC(y);
- INC(MemNeeded[x], KeyBuf[y].Len);
- UNTIL NOT BitIsSet(KeyBuf[y].Flags, SegmentedBit);
- INC(TotKeyMem, MemNeeded[x]);
- END; {for}
- END; {with}
-
- { See if there is memory for them }
-
- IF (MAXAVAIL < TotKeyMem) THEN
- BEGIN
- CleanUp;
- EXIT;
- END; {if}
-
- { now actually allocate them }
-
- x:= 0;
- MemError:= FALSE;
- WITH MulPtr[h]^ DO
- WHILE (x < Indexes) AND (NOT MemError) DO
- BEGIN
- INC(x);
- GETMEM(KeyPtr^[x], MemNeeded[x]);
- MemError:= (KeyPtr^[x] = NIL);
- IF NOT MemError THEN
- BEGIN
- KeyPtr^[x]^.BufferLen:= MemNeeded[x] - SIZEOF(KBLType);
- INC(KeysAlloc);
- FILLCHAR(KeyPtr^[x]^.KeyBuffer,
- MemNeeded[x] - SIZEOF(KBLType), 0);
- END; {if}
- END; {with while}
- IF MemError THEN
- BEGIN
- CleanUp;
- EXIT;
- END; {if}
-
- { All went well so set up variables in master records }
-
- OpenFile:= h;
- MulPtr[h]^.LastKey := 1; { store SUCC of last key }
- MulPtr[h]^.LockAttr:= FileLocks; { default locks }
- MulPtr[h]^.FileName:= FileName; { filename }
- MulPtr[h]^.OpenMode:= LO(OpenMode);
- MulPtr[h]^.FileDesc.Owner:= Owner;
- END
- ELSE SetErr(NoMemoryErr); { Not enough memory }
- END {if}
- ELSE SetErr(NoMemoryErr); { Not enough memory }
- END {if}
- ELSE SetErr(NoHandlesErr); { No more handles }
- END {if}
- ELSE SetErr(NotActiveErr); { Mulkey not initialized yet }
- END; {OpenFile}
-
- PROCEDURE ExtendFile(VAR Handle: WORD;
- FileName : PathStr;
- ExtendNow: BOOLEAN);
-
- VAR
- m : WORD;
- Owner: FOwnerStr;
-
- BEGIN {ExtendFile}
- IF HandleActive(Handle) THEN
- BEGIN
- AsciiZ(FileName);
- IF ExtendNow THEN m:= ExtNowCode ELSE m:= ExtLaterCode;
- SetErr(Btrv(ExtendOp, MulPtr[Handle]^.PosBlock, m, m, FileName, m,
- MaxKeyLen));
- IF NOT IndexError THEN
- BEGIN
- m:= MulPtr[Handle]^.OpenMode;
- Owner:= MulPtr[Handle]^.FileDesc.Owner;
- FileName:= MulPtr[Handle]^.FileName;
- CloseFile(Handle);
- Handle:= OpenFile('', m, Owner, FileName);
- END; {if}
- END
- ELSE SetErr(BadHandleErr);
- END; {ExtendFile}
-
- PROCEDURE AUD_Record(Handle: WORD;
- VAR d;
- Code: BYTE);
- VAR
- Len,
- Status: WORD;
-
- BEGIN {AUD_Record}
- IF HandleActive(Handle) THEN
- WITH MulPtr[Handle]^ DO
- BEGIN
- Len:= FileDesc.FileData.RecordLen;
- Status:= Btrv(Code, PosBlock, d, Len, KeyPtr^[LastKey]^.KeyBuffer,
- PRED(LastKey), KeyPtr^[LastKey]^.BufferLen);
- Changed:= TRUE;
- END
- ELSE Status:= BadHandleErr;
- SetErr(Status);
- END; {AUD_Record}
-
- PROCEDURE AddRecord; EXTERNAL;
-
- PROCEDURE UpdateRecord; EXTERNAL;
-
- PROCEDURE DeleteRecord; EXTERNAL;
-
- {$L MULAUD.OBJ}
-
- FUNCTION GetPosition(Handle: WORD): LONGINT;
-
- VAR
- d,
- Status: WORD;
- p : LONGINT;
-
- BEGIN {GetPosition}
- IF HandleActive(Handle) THEN
- Status:= Btrv(GetPositionOp, MulPtr[Handle]^.PosBlock, p, d, d, 0,
- SIZEOF(d))
- ELSE Status:= BadHandleErr;
- SetErr(Status);
- IF IndexError THEN GetPosition:= 0 ELSE GetPosition:= p;
- END; {GetPosition}
-
- FUNCTION NumRecords(Handle: WORD): LONGINT;
-
- BEGIN {NumRecords}
- IF HandleActive(Handle) THEN
- BEGIN
- IF MulPtr[Handle]^.Changed THEN Stat(Handle) ELSE SetErr(NoErr);
- END
- ELSE SetErr(BadHandleErr);
- IF IndexError THEN NumRecords:= 0
- ELSE NumRecords:= MulPtr[Handle]^.FileDesc.FileData.NumRecs;
- END; {NumRecords}
-
- { The following are the get record procedures, they are filtered by procedure }
- { RPN_Record, which does the work. This is where KeyOnly gets reset, not in }
- { AdjOp(). If KeyOnly was set, it is set to FALSE after function execution. }
-
- PROCEDURE RPN_Record(Handle: WORD;
- KeyNum: WORD;
- VAR k;
- VAR d;
- Code: BYTE);
- VAR
- Len,
- Status: WORD;
-
- BEGIN {RPN_record}
- IF HandleActive(Handle) THEN
- BEGIN
- WITH MulPtr[Handle]^ DO
- BEGIN
-
- { Check the key number and see if it is ok }
-
- IF (KeyNum <= FileDesc.FileData.NumIndexes) AND (KeyNum > 0) THEN
- BEGIN
-
- { if we don't use the last key buffer then put new key in.}
-
- CASE Code OF
- GetEqualOp, GetGreaterOp..GetLessThanOrEqualOp:
- WITH KeyPtr^[KeyNum]^ DO MOVE(k, KeyBuffer, BufferLen);
- END; {case}
- Len:= FileDesc.FileData.RecordLen;
- Status:= Btrv(AdjOp(Code, LockAttr), PosBlock, d, Len,
- KeyPtr^[KeyNum]^.KeyBuffer, PRED(KeyNum),
- KeyPtr^[KeyNum]^.BufferLen);
- END
- ELSE Status:= InvalidKeyErr;
- END; {with}
- END
- ELSE Status:= BadHandleErr;
- KeyOnly:= FALSE; { we reset this every time it is used }
- SetErr(Status);
- END; {RPN_Record}
-
- PROCEDURE GetDirect(Handle: WORD;
- p: LONGINT;
- VAR d);
-
- VAR
- MovP: LONGINT ABSOLUTE d;
-
- BEGIN {GetDirect}
- IF (p <> 0) THEN
- BEGIN
- MovP:= p; { Btrieve expects the position in the data buffer }
- RPN_Record(Handle, MulPtr[Handle]^.LastKey, d, d, GetDirectOp);
- END
- ELSE SetErr(GetDirectErr);
- END; {GetDirect}
-
- PROCEDURE StepDirect(Handle: WORD; VAR d);
-
- BEGIN {StepDirect}
- RPN_Record(Handle, MulPtr[Handle]^.LastKey, d, d, StepDirectOp);
- END; {StepDirect}
-
- PROCEDURE GetLowest; EXTERNAL;
-
- PROCEDURE GetHighest; EXTERNAL;
-
- PROCEDURE NextRecord; EXTERNAL;
-
- PROCEDURE PrevRecord; EXTERNAL;
-
- {$L MULGET1.OBJ}
-
- PROCEDURE GetEqual; EXTERNAL;
-
- PROCEDURE GetGreater; EXTERNAL;
-
- PROCEDURE GetLessThan; EXTERNAL;
-
- PROCEDURE GetGreaterOrEqual; EXTERNAL;
-
- PROCEDURE GetLessThanOrEqual; EXTERNAL;
-
- {$L MULGET2.OBJ}
-
- FUNCTION MulkeyFileName(Handle: WORD): PathStr;
-
- VAR
- Status: WORD;
-
- BEGIN {MulkeyFileName}
- IF HandleActive(Handle) THEN Status:= NoErr ELSE Status:= BadHandleErr;
- SetErr(Status);
- IF IndexError THEN MulkeyFileName:= ''
- ELSE MulkeyFileName:= MulPtr[Handle]^.FileName;
- END; {MulkeyFileName}
-
- FUNCTION MulkeyExtension(Handle: WORD): PathStr;
-
- VAR
- Status: WORD;
-
- BEGIN {MulkeyExtension}
- IF HandleActive(Handle) THEN Status:= NoErr ELSE Status:= BadHandleErr;
- SetErr(Status);
- IF IndexError THEN MulkeyExtension:= ''
- ELSE MulkeyExtension:= MulPtr[Handle]^.Extension;
- END; {MulkeyExtension}
-
- PROCEDURE GetKeyBuffer(Handle, KeyNum: WORD; VAR k);
-
- VAR
- Status: WORD;
-
- BEGIN {GetKeyBuffer}
- IF HandleActive(Handle) THEN
- WITH MulPtr[Handle]^ DO
- BEGIN
- IF (KeyNum <= FileDesc.FileData.NumIndexes) AND (KeyNum > 0) THEN
- BEGIN
- WITH KeyPtr^[KeyNum]^ DO MOVE(k, KeyBuffer, BufferLen);
- Status:= NoErr;
- END
- ELSE Status:= InvalidKeyErr;
- END
- ELSE Status:= BadHandleErr;
- SetErr(Status);
- END; {GetKeyBuffer}
-
- PROCEDURE ResetFiles;
-
- VAR
- x,
- Status: WORD;
-
- BEGIN {ResetFiles}
- IF MulkeyActive THEN
- BEGIN
- FOR x:= FirstHandle TO MaxMulkey DO CloseFile(x);
- Status:= Btrv(ResetOp, x, x, x, x, 0, SIZEOF(x));
- END
- ELSE Status:= NotActiveErr;
- SetErr(Status);
- END; {ResetFiles}
-
- PROCEDURE CloseFile(Handle: WORD);
-
- VAR
- x,
- d,
- Status: WORD;
-
- BEGIN {CloseFile}
- IF HandleActive(Handle) THEN
- BEGIN
- x:= 0;
- REPEAT
- Status:= Btrv(CloseOp, MulPtr[Handle]^.PosBlock, d, d, d, 0,
- SIZEOF(d));
- INC(x);
- UNTIL (Status = NoErr) OR (x > MaxTries);
- WITH MulPtr[Handle]^ DO
- BEGIN
- FOR x:= KeysAlloc DOWNTO 1 DO
- FREEMEM(KeyPtr^[x],
- WORD(KeyPtr^[x]^.BufferLen) + SIZEOF(KBLType));
- IF (KeyPtr <> NIL) THEN
- FREEMEM(KeyPtr, SIZEOF(POINTER) * FileDesc.FileData.NumIndexes);
- END; {with}
- DISPOSE(MulPtr[Handle]);
- MulPtr[Handle]:= NIL;
- END; {if}
- SetErr(NoErr); { We never want closefile to return an error }
- END; {CloseFile}
-
- FUNCTION BtError(Code: WORD): STRING;
-
- BEGIN {BtError}
- CASE Code OF
-
- { BTrieves error codes }
-
- NoErr: BtError:= ''; { None }
- 1: BtError:= 'Invalid operation';
- 2: BtError:= 'I/O error';
- 3: BtError:= 'File not open';
- 4: BtError:= 'Key not found';
- 5: BtError:= 'Duplicate key error';
- 6,
- InvalidKeyErr: BtError:= 'Invalid key number';
- 7: BtError:= 'Different key number';
- 8: BtError:= 'Invalid positioning';
- 9: BtError:= 'End of file';
- 10: BtError:= 'Key not modifiable';
- 11: BtError:= 'Invalid file name';
- 12: BtError:= 'File not found';
- 13: BtError:= 'Extension error';
- 14: BtError:= 'Pre-open error';
- 15: BtError:= 'Pre-image error';
- 16: BtError:= 'Expansion error';
- 17: BtError:= 'Close error';
- 18: BtError:= 'Disk full';
- 19: BtError:= 'Unrecoverable error';
- 20: BtError:= 'Btrieve inactive';
- 21: BtError:= 'Key buffer error';
- 22,97: BtError:= 'Bad data buffer size';
- 23: BtError:= 'Bad position block size';
- 24: BtError:= 'Bad page size';
- 25: BtError:= 'Could not create file';
- 26: BtError:= 'Bad number of keys';
- 27: BtError:= 'Bad key position';
- 28: BtError:= 'Bad record length';
- 29: BtError:= 'Bad key length';
- 30: BtError:= 'Not a Btrieve file';
- 31,
- 32,34: BtError:= 'File extend error';
- 35: BtError:= 'Directory error';
- 36,37,
- 38,39,
- 40,41: BtError:= 'Transaction error';
- 42: BtError:= 'Incomplete accelerated access';
- 43: BtError:= 'Invalid data record address';
- 44: BtError:= 'Null key path';
- 45: BtError:= 'Inconsistent key flags';
- 46: BtError:= 'Access denied';
- 47: BtError:= 'Maximum open files';
- 48: BtError:= 'Invalid alternate sequence';
- 49: BtError:= 'Key type error';
- 50: BtError:= 'Owner already set';
- 51,
- OwnerMatchErr: BtError:= 'Invalid owner';
- 52: BtError:= 'Error writing cache';
- 53: BtError:= 'Invalid interface';
- 54: BtError:= 'Variable page unreadable';
- 56: BtError:= 'Incomplete index';
- 57: BtError:= 'Expanded memory error';
- 80: BtError:= 'Conflict - reread record';
- 81: BtError:= 'Lock full';
- 82: BtError:= 'Lost position';
- 83: BtError:= 'Read outside transaction';
- 84: BtError:= 'Record in use';
- 85: BtError:= 'File in use';
- 86: BtError:= 'File full';
- 87: BtError:= 'Handle full';
- 88: BtError:= 'Mode error';
- 89: BtError:= 'Name error';
- 90: BtError:= 'Device full';
- 91: BtError:= 'Server error';
- 92: BtError:= 'Transaction full';
- 93: BtError:= 'Incompatible lock type';
- 99: BtError:= 'Demo error';
-
- { Mulkey error codes }
-
- GetDirectErr: BtError:= 'No valid position in get direct';
- NotActiveErr: BtError:= 'Mulkey not active';
- BadHandleErr: BtError:= 'Handle not active';
- GetOpErr: BtError:= 'Error in get operation';
- NoHandlesErr: BtError:= 'No more Mulkey handles';
- NoMemoryErr: BtError:= 'Not enough memory';
- MulkeyInitErr: BtError:= 'Could not initialize Mulkey';
- ELSE BtError:= 'Unknown error';
- END; {case}
- END; {BtError}
-
- FUNCTION MulkeyError: STRING; { Last error of Mulkey }
-
- BEGIN {MulkeyError}
- IF (LastErrCode = 0) THEN MulkeyError:= 'NO MULKEY ERROR'
- ELSE MulkeyError:= 'MULKEY ERROR: ' + BtError(LastErrCode);
- END; {MulkeyError}
-
- {$F+}
- PROCEDURE CloseMulkey;
- {$F-}
-
- VAR
- x: WORD;
-
- BEGIN {CloseMulkey}
- FOR x:= FirstHandle TO MaxMulkey DO CloseFile(x);
- EXITPROC:= ExitSave;
- END; {CloseMulkey}
-
- PROCEDURE InitMulkey;
-
- VAR
- x,
- Dummy: WORD;
- BtVer: BtVerType;
- n,
- Min,
- Maj : STRING[8];
-
- BEGIN {InitMulkey}
- x:= SIZEOF(BtVerType);
- SetErr(Btrv(VersionOp, Dummy, BtVer, x, Dummy, 0, SIZEOF(Dummy)));
- MulkeyActive:= (NOT IndexError) AND
- ((BtVer.Version > MinVersion) OR
- ((BtVer.Version = MinVersion) AND
- (BtVer.Revision >= MinRevision))) AND
- ((BtVer.Net = 'N') OR (BtVer.Net = ' '));
-
- { Initialize the array of pointers EVEN if NOT MulkeyActive! }
-
- FILLCHAR(MulPtr, SIZEOF(MulPtr), 0); { sets all to NIL }
-
- { set up MulkeyVersion string for export }
-
- STR(MajorVersion, Maj);
- STR(MinorVersion:2, Min);
- IF (Min[1] = ' ') THEN Min[1]:= '0';
- MulkeyVersion:= 'Mulkey version ' + Maj + '.' + Min + Revision + ' ' +
- MulkeyDate;
-
- IF MulkeyActive THEN
- BEGIN
-
- { set up BtVersion string for export }
-
- IF (BtVer.Net = 'N') THEN n:= 'network ' ELSE n:= '';
- STR(BtVer.Version, Maj);
- STR(BtVer.Revision, Min);
- BtVersion:= 'Btrieve ' + n + 'file manager version ' + Maj +'.'+ Min;
-
- SetErr(NoErr);
-
- { set the exit procedure address }
-
- ExitSave:= EXITPROC;
- EXITPROC:= @CloseMulkey;
- END
- ELSE
- BEGIN
- SetErr(MulkeyInitErr);
- BtVersion:= '';
- END; {elseif}
- END; {InitMulkey}
-
- BEGIN {Init Mulkey}
- InitMulkey;
- END. {Init Mulkey}