INTRODUCTION Btv.pas is a fully object oriented Turbo Pascal 6.0 programming interface for Novell's Btrieve database manager. Through OOP techniques Btv.pas greatly simplifies interface to Btrieve for Turbo Pascal. Included in this package are full working examples that demonstrate the ease and power of the BTV interface. Also included is a complete application for recovering damaged files. Just a few of the features are : * Over 40 functions for Btrieve including : * Create, easy file definition and creation * Clone, create an empty copy of a file * Recover, recover records from a damaged file * Save, save all records to a DOS file compatible with BUTIL * Load, read records from a file created by Save or BUTIL * Create Supplemental Indexes * Supports multiple and segmented keys * Supports alternate collating sequences * Supports variable length records * Automatic padding and justification of string keys * Supports full transaction processing * Supports full network record and file locking * Automatic integrated error handling In writing this documentation I have assumed the reader is knowledgeable about the workings of Btrieve and the basics object oriented programming in Turbo Pascal 6.0. This document is not meant to explain or serve as a tutorial on either of these subjects. I think you will find the source code itself fairly well documented. I strongly recommend that you look it over. If you have any questions, suggestions for improvement, or problems, please do not hesitate to contact me. If you need a version for Turbo 5.5 please let me know. Richard Hansen PO Box 18571 Saint Paul, MN 55118-0571 USA CompuServe ID 70242,3367 Btv.pas Copyright (C) 1992 Richard W. Hansen, all rights reserved. Btrieve Copyright (C) Novell, Inc. BUTIL Copyright (C) Novell, Inc. DEFINITION OF SHAREWARE Shareware distribution gives users a chance to try software before buying it. If you try a Shareware program and continue using it, you are expected to register. Individual programs differ on details -- some request registration while others require it, some specify a maximum trial period. With registration, you get anything from the simple right to continue using the software to an updated program with printed manual. Copyright laws apply to both Shareware and commercial software, and the copyright holder retains all rights, with a few specific exceptions as stated below. Shareware authors are accomplished programmers, just like commercial authors, and the programs are of comparable quality. (In both cases, there are good programs and bad ones!) The main difference is in the method of distribution. The author specifically grants the right to copy and distribute the software, either to all and sundry or to a specific group. For example, some authors require written permission before a commercial disk vendor may copy their Shareware. Shareware is a distribution method, not a type of software. You should find software that suits your needs and pocketbook, whether it's commercial or Shareware. The Shareware system makes fitting your needs easier, because you can try before you buy. And because the overhead is low, prices are low also. Shareware has the ultimate money-back guarantee -- if you don't use the product, you don't pay for it. DISCLAIMER - AGREEMENT Users of Btv.pas must accept this disclaimer of warranty: "Btv.pas is supplied as is. The author disclaims all warranties, expressed or implied, including, without limitation, the warranties of merchantability and of fitness for any purpose. The author assumes no liability for damages, direct or consequential, which may result from the use of Btv.pas." Btv.pas is "shareware" and is provided at no charge to the user for evaluation. Feel free to share it with your friends, but do not give it away altered or as part of any other source code package. If you find this source code useful and continue to use Btv.pas after a reasonable trial period, you must register it. The registration fee will license one copy for use on any one computer at any one time. You must treat this software just like a book. An example is that this software may be used by any number of people and may be freely moved from one computer location to another, so long as there is no possibility of it being used at one location while it's being used at another. Just as a book cannot be read by two different persons at the same time. Commercial users of Btv.pas must register and pay for their copies of Btv.pas within 30 days of first use or their license is withdrawn. You may use Btv.pas in your software projects, but you may only distribute it in executable form. No royalties are required for programs you develop using licensed copies of Btv.pas. Anyone distributing Btv.pas for any kind of remuneration must first contact Richard Hansen for authorization. This authorization will be automatically granted to distributors recognized by the ASP as adhering to its guidelines for shareware distributors, and such distributors may begin offering Btv.pas immediately (However Richard Hansen must still be advised so that the distributor can be kept up-to-date with the latest version of Btv.pas.). REGISTRATION You may register by check, money order, credit card, or online on the CompuServe information service. All registrations are $50.00 plus $5.00 shipping and handling. Checks or money orders are prefered if possible. Please make all checks payable in U.S. dollars, drawn on a U.S. bank. Orders paid by check drawn on a non-U.S. bank will be returned. I apologize for any inconvenience but high bank charges, roughly 50%, make this necessary. You can also register online on CompuServe. Type GO SWREG, and follow the prompts. The Registration Id for CompuServe is 759. All Compuserve registrations are $55.00, including shipping and handling. You may place an order by Master Card, VISA, American Express, or Discover by contacting Public Software Library at (800) 242-4PSL (from overseas (713) 524-6394), by FAX at (713) 524-6398, or on CompuServe at 71355,470. These numbers are for credit card orders only! Please, do not call these numbers for any type of technical assistance. The Registration Id for PSL is 10905. All PSL registrations are $55.00, including shipping and handling. Site licenses and multiple copy discounts are available. Remember a registered copy is required for each programmer using BTV.PAS. Please contact me with any comments, suggestions, problems, bugs, or questions. Richard Hansen PO Box 18571 Saint Paul, MN 55118-0571 USA CompuServe : 70242,3367 InterNet : 70242.3367@compuserve.com FidoNet : 1:282/115 OVERVIEW There are three objects that make up the BTV OOP interface to Btrieve. The most important of these is the BtrieveFile object. BtrieveFile contains all the routines for opening and creating files, reading, writing and deleting records, etc. It contains a pointer to the data buffer that can be automatically allocated and deallocated by the object if you desire. Next, is the ErrorHandler object, this object controls error handling for the file. Any Btrieve error may be turned on or off for trapping by the error handler object. This frees you from the need to check for errors after each operation, but still allows for full error checking. Each file object has a pointer to an error handler, this error handler can be the same or different for each file you open. If an error is turned on the error handler will call an error display routine, and based on a return code from it, will continue, abort, or retry an operation. Last, there is the DisplayObject. This object handles the display of any errors encountered. It is called by the error handler, and returns an action code, possibly based on some user response, to the error handler. This action code will cause the error handler to either abort the program, retry the operation, or continue processing. DECLARATIONS const bOpen = 0; ... bGetKey = 50; These constants define all the available btrieve operations. bOkay = 0; ... bLastError = bOutOfMemory; These define all the status codes returned by Btrieve. In addition there are constants for file open modes, locking, key types, file flags, etc. MaxSegments = 24; Defines the maximum total number of key segments allowed for file. If none of your files will ever have this many segments then redefine it to some smaller size and save a few bytes of memory. MaxBuffSize : Word = 16 * 1024; This initialized variable defines the maximum size that will be automatically allocated for a file data buffer. There is no need to redefine this if you are using fixed length records, since only as much memory as needed will actually be allocated. If you are using variable length records and are sure they will be smaller than 16K bytes, then you can redefine this as needed before opening the file. {.$DEFINE BCHECK} If this compiler directive is defined a check for Btrieve will be made during initialization. If it is not present the program will be halted. {.$DEFINE BTRIEVE50} Define this to make all opcodes new to Btrieve version 5.0 available. type PProgress = ^TProgress; TProgress = Object Constructor Init; Procedure Display(Count : LongInt); Virtual; end; Defines an object with a method to display the progress of Recover, Load and Save operations. Count is the current record count, the display routine will be called every ten records. AllErrors = bInvalidOp..bLastError; ErrorSet = Set of AllErrors; These two define a set of all possible Btrieve errors. ErrorAction = (erAbort, erDone, erRetry); Enumerates the possible responses to a Btrieve error. One of these three actions must be returned by your error display routine. If erAbort is returned the program will be halted, if erDone is returned the program will continue, if erRetry is returned the Btrieve operation that generated the error will be executed again. PErrorDisplay = ^ErrorDisplay; ErrorDisplay = Object Constructor Init; Function Display(Error : Integer; ErrorMsg : String; OpCode : Byte; OpCodeMsg : String; FileName : PathStr ): ErrorAction; Virtual; Destructor Done; Virtual; end; ErrorDisplay is the object that will display errors to the user. This is an ABSTRACT object and can never be used as is, you must define a descendant object that does what you want in each program. The error handler will pass an error number, error description, operation, operation description, and the full file path to your object. Your object should display the error and return an action code. This action code can be based on user input, the type of error, operation or whatever. PErrorHandler = ^ErrorHandler; ErrorHandler = Object RetryCount : Word; MaxRetry : Word; RetryDelay : Word; TrappedErrors : ErrorSet; ErrorDisplay : PErrorDisplay; Constructor Init(DisplayObject : PErrorDisplay); Function ErrorDispacther(ErrorCode : Integer; OpCode : Byte; FileName : PathStr ): ErrorAction; Virtual; Function Error(Status : Integer; OpCode : Byte; FileName : PathStr ): Boolean; Virtual; Procedure SetMaxRetry(Retry : Word); Function GetMaxRetry: Word; Procedure SetDelay(Seconds : Word); Function GetDelay: Word; Procedure AddErrors(ErrorCodes : ErrorSet); Procedure RemoveErrors(ErrorCodes : ErrorSet); Procedure SetErrors(ErrorCodes : ErrorSet); Procedure GetErrors(var ErrorCodes : ErrorSet); Procedure ClearRetry; Function ErrorMsg(ErrorCode : Integer): String; Virtual; Function OpMsg(OpCode : Integer): String; Virtual; Destructor Done; Virtual; end; This is the error handler object used to trap Btrieve errors. It can be used as defined. Each possible error can be set so it is trapped or not by this error handler. By default all errors except end of file are trapped. All trapped errors will be routed through the error display object assigned to the handler when it is initialized. Untrapped errors must be handled directly in your program code. Locking errors (record in use, file in use) are a special case. These errors, which happen only on networked systems, automatically generate retries. No error will be generated until the maximum number of retries, set by you, have been attempted. This feature can save some programming work on your part if you are writing an application that uses the networked version of Btrieve. If this all sounds complicated, don't worry, it really isn't that bad. Please take a look at the example code to see how easy it is to setup the error handling. My feelings on error checking are that the more automatic it is the better. In Btv.pas little work up front leads to considerably less coding later. You only need to do this stuff once, no matter how many files you open. Once you get the error handling setup, you can pretty much forget about it in the rest of your program. In fact, it gets even easier if you create a standard error handling Unit and reuse in all your programs. PBtrieveFile = ^BtrieveFile; BtrieveFile = Object Path : PathStr; AltPath : PathStr; Data : Pointer; DataSize : Integer; Allocate : Boolean; BytesRead : Word; BytesToWrite: Word; Key : Pointer; KeySize : Byte; SegmentCnt : Byte; CurIndex : Word; IndexCnt : Byte; Status : Integer; FileOpen : Boolean; ErrHandler : PErrorHandler; KeyList : KeyDefArray; KeyStart : Array[0..MaxSegments - 1] of Byte; PosBlock : Array[1..PosBlockSize] of Byte; VariableLen : Boolean; SISegments : Byte; ReadKeyDefs : Boolean; CurrentKeySize : Byte; Constructor Init(FilePath : PathStr; ErrorObject : PErrorHandler; DataBuf : Pointer; DataBufSize : Word); Destructor Done; Virtual; Procedure AddAltSequence(AltSeqPath : PathStr); Procedure AddKeySegment(Position : Word; Size : Word; Flags : Word; KeyType : Byte; NullValue : Byte; Justify : Byte); Procedure Open(Mode : Integer; Owner: String); Procedure Close; Procedure Create(Flags : Word; RecordSize : Word; PageSize : Word; Pages : Word; Mode : Integer); Procedure Clone(NewFilePath : PathStr; Mode : Integer); Function Error(ErrStatus : Integer; OpCode : Byte; FileName : PathStr ): Boolean; Function Recover(NewFilePath : PathStr; DisplayObj : PProgress): Integer; Function Save(NewFilePath : PathStr; DisplayObj : PProgress): Integer; Function Load(InputFilePath : PathStr; DisplayObj : PProgress): Integer; Procedure AddSupplKeySegment(Position : Word; Size : Word; Flags : Word; KeyType : Byte; NullValue : Byte; Justify : Byte); Procedure CreateIndex; Procedure DropIndex(Index : Integer); Procedure SetOwner(Owner : String; Mode : Integer); Procedure ClearOwner; Procedure SetKeyPath(Number : Word); Procedure MakeKey(V1 : Pointer; V2 : Pointer; V3 : Pointer; V4 : Pointer; V5 : Pointer; V6 : Pointer); Procedure Get(Op : Word; Lock : Word); Procedure GetDirect(Lock : Word; Position : LongInt); Function GetPosition: LongInt; Procedure UnlockAll(Lock : Word); Procedure Insert; Procedure Update; Procedure SetOutputSize(Size : Word); Procedure AddErrors(ErrorCodes : ErrorSet); Procedure RemoveErrors(ErrorCodes : ErrorSet); Procedure SetErrors(ErrorCodes : ErrorSet); Procedure GetErrors(var ErrorCodes : ErrorSet); Procedure Delete; Procedure ClearBuffer; Procedure ClearKey; Procedure FillKeyBuffer(var KeyBuf; Size : Word); Procedure ChangeBufferSize(Size : Word); Procedure Stat(var FData : FileSpec); Function bResult: Integer; Function IsOpen: Boolean; Function NumberOfRecords: LongInt; Procedure StartTransaction(Lock : Word); Procedure EndTransaction; Procedure AbortTransaction; Procedure Unload; Procedure Reset; Procedure Version(var Ver : Word; var Rev : Word; var OSFlag : Char); Procedure FixKeyStrings; end; The BtrieveFile object is the heart of Btv.pas. It contains all the routines for manipulating Btrieve files. It is a fairly complex object; but, it greatly simplifies your interaction with Btrieve files. You will create one of these objects for each file you want to access in a program. To open a file, you execute two object methods. First, you init the object passing a file path, an error handler (can be nil), and a pointer to a data buffer and the data buffer size. Any number of files can share a single error handler. If you pass a nil pointer for the data buffer, a buffer will be allocated for you. Next, you call Open with an open mode (Read Only, Exclusive, or Accelerated ) and file owner name. Creating a file is almost as easy. Init is called the same as for Open. Next, for each key segment needed, you execute the AddKeySegment method passing the key position, size, key type, etc. This will define each key segment you need for the file. After all keys are defined make a call to Create. This method takes the file flags, record size, page size, etc. as parameters and Creates a new file. Create does not open the file, so finish off with a call to the Open method. Reading and writing records is just as simple. For a read by key you must first make a call to MakeKey, to build the key buffer. Then call Get, supplying the opcode for the type of read you want and the locking state. The data will be passed back in the file buffer setup on initialization. For the step operation you just call Get passing the correct opcode. To write a new record, fill the buffer you setup and execute the Insert method. To change a record, first read it with a call to Get. Make any changes to the buffer and call Update. Procedure CheckForBtrieve; This procedure can be called to check for the presence of Btrieve. It halts the program if Btrieve is not loaded. This is the same routine called during program initialization, if that feature is enabled. OBJECT DECLARATIONS - BtrieveFile FIELDS - Allocate : Allocate : Boolean; This field is set by Init and used by Open and Done. If the data buffer pointer passed to Init is nil, Allocate is set to TRUE and file buffer memory will automatically be allocated and deallocated. AltPath : AltPath : PathStr; Holds the name and path of an alternate collating sequence for the file. BytesRead : BytesRead : Integer; Is the number of bytes input from the file on the last read operation. BytesToWrite : BytesToWrite: Integer; Holds the number of bytes in the buffer that will be output to the file on the next write operation. For fixed length records it defaults to the size of the file record and should not be changed. For variable length records it should be set before each record is written. CurIndex : CurIndex : Word; CurIndex is the current Key number (access path) used for the reads and writes. CurrentKeySize : CurrentKeySize : Byte; Used to find the largest key. Data : Data : Pointer; Points to the file buffer. DataSize : DataSize : Integer; DataSize is the size of the file buffer pointed to by Data. ErrHandler : ErrHandler : PErrorHandler; A pointer to the ErrorHandler object that will control all error checking. If ErrHandler is nil no error checking is done. FileOpen : FileOpen : Boolean; Will be set to TRUE if the file is opened successfully. IndexCount : IndexCnt : Byte; Number of keys in the file. Key : Key : Pointer; Points to the file key buffer. KeyList : KeyList : KeyDefArray; Holds a definition record for each key segment in the file. KeySize : KeySize : Byte; Size of the key buffer pointed to by KeySize. KeyStart : KeyStart : Array[0..MaxSegments - 1] of Byte; Holds a list of the offsets of the first segment of each key. Path : Path : PathStr; Path contains the name and path of the file. PosBlock : PosBlock : Array[1..PosBlockSize] of Byte; The Btrieve position block. ReadKeyDefs : ReadKeyDefs : Boolean; Indicates whether the key definitions have been setup manually or should be read from the file. SegmentCnt : SegmentCnt : Byte; The total number of segments in all keys. Status : Status : Integer; The status of the last Btrieve operation. VariableLen : VariableLen : Boolean; Set to TRUE if the file holds variable length records. SISegments : SISegments : Byte; Used in setting up a supplemental index. METHODS - Init : Constructor Init( FilePath : PathStr; var ErrorObject : PErrorHandler; DataBuf : Pointer; DataBufSize : Word); Initializes the file name and path, sets the pointer to the error handler object. If ErrorObject is nil no error checking is done, it is all up to the programmer in this case. If DataBuf is not nil then Allocate will be set to TRUE and memory for the file buffer will be allocated and deallocated automatically. If DataBuf is not nil then DataBufSize must be the size of the buffer pointed to by DataBuf. If DataBuf is nil then the value of DataBufSize is ignored. See Open, Create, Done, ErrorHandler object. Done : Destructor Done; Virtual; Disposes of key buffer memory. If Allocate is TRUE, also disposes of the file buffer memory. See Init. AbortTransaction : Procedure AbortTransaction; Aborts the current Btrieve transaction. See EndTransaction, StartTransaction. AddAltSequence : Procedure AddAltSequence(AltSeqPath : PathStr); Defines an alternate collating sequence file that will be loaded and passed to Btrieve on a Create. This method only needs to be called before Create and if an alternate collating sequence is desired. See Create. AddErrors : Procedure AddErrors(ErrorCodes : ErrorSet); Call AddErrors to add a set of error codes to those handled by the file's error handler. Use it in conjunction with RemoveErrors to turn an error on and off for automatic trapping. AddErrors just makes a call to the error handler AddErrors method, so it is here mostly for convenience. You could just as well add errors by dereferencing the ErrHandler pointer. But this is one of the most often made calls to the error handler. See RemoveErrors, ErrHandler, GetErrors, SetErrors, TErrorHandler. AddKeySegment : Procedure AddKeySegment(Position : Word; Size : Word; Flags : Word; KeyType : Byte; NullValue : Byte; Justify : Byte); AddKeySegment is used to manually define keys for the file. When creating a file the keys must be setup by calls to AddKeySegment. Keys do not have to be defined before opening a file. On an Open if no calls to AddKeySegment have been made, then the key information will be read from the file itself. Except for Justify, the parameters are the same as defined by Btrieve. Position is the position of the segment in the file. It is the same as Btrieve expects, remember they start at one not zero. Size is the number of bytes in the key segment you are defining. Flags are the usual flags such as modifiable, duplicate, etc. KeyType can be any valid type understood by Btrieve. NullValue will normally be set to zero. Please check your Btrieve manual for more information on defining keys. Justify is a special parameter that makes the use of left and right justified key strings simpler. All pascal type strings (Btrieve's lstrings) can be automatically padded to the left or right with spaces to their defined sizes. If Justify is set to bLJustify a string will be padded to it's full length with spaces. If Justify is bRJustify then a string key will be left padded to its defined size with spaces. Set Justify to bNormal to leave your key strings as passed. While this padding is not absolutely necessary, it does make strings easier to use. Since the same padding is done to the keys used to read from or write to the file, you will never need to worry about trailing or leading spaces on your string keys. To define the keys for a file, just make repeated calls to AddKeySegment. Make one call for each segment needed. You must make these calls in order, just as if you were building the key data buffer directly. Add the segments that make up key one first, then the segments for key two, then the segments for key three, etc. The segments for each key must also be added in order, segment one, segment two, etc. The data will be stored in KeyList and passed to Btrieve on a Create. A typical call would look like : F.AddKeySegment(1,10, bModifiable + bExtended, bLstring, 0, False); This key starts at position 1 in the file, is modifiable, is a lstring and is the last segment in its key path, it has a null value of zero, and is not right justified. See the bXXXXX constants, Create. AddSupplKeySegment: Procedure AddSupplKeySegment(Position : Word; Size : Word; Flags : Word; KeyType : Byte; NullValue : Byte; Justify : Byte); This functions the same as AddKeySegment but is used to define a supplemental index. You can only define one key at a time. See the bXXXXX constants, CreateIndex, AddKeySegment. bResult : Function bResult: Integer; This function returns the last error status from Btrieve. Unlike the Turbo Pascal IoResult function; a call to bResult does not reset the status, so multiple calls can be made to this function. ChangeBufferSize : Procedure ChangeBufferSize(Size : Word); This method should only be used for files with variable length records where the file buffer is allocated by the object. Use it in that rare instance when you need to change the size of the file buffer. See Data, Init. ClearBuffer : Procedure ClearBuffer; Clears the file data buffer, the memory pointed to by the Data field. ClearKey : Procedure ClearKey; Clears the file key buffer, the memory pointed to by the Key field. ClearOwner : Procedure ClearOwner; If an owner has been assigned to a file, this method will clear it. The file must be opened before invoking this method. See SetOwner. Clone : Procedure Clone(NewFilePath : PathStr; Mode : Integer); Clone will create an empty copy of the file on the specified file path. Mode indicates whether the file should be over written if it already exists. See the bXXXXX constants. Close : Procedure Close; Closes an open file. See Done. Create : Procedure Create(Flags : Word; RecordSize : Word; PageSize : Word; Pages : Word; Mode : Integer); Create a new file. Flags are the normal Btrieve file flags such as truncate, variable length, or key only. RecordSize is the file record size, or the fixed length portion size for variable length records. PageSize is the page size you want for the file; as usual, it must be a multiple of 512 bytes, up to 4096 bytes. Pages is the number of pages Btrieve should preallocate to the file. Mode indicates whether the file should be over written if it already exists. A typical call could be : F.Create(bNormal, 100, 512, 0, bNoOverWrite); This file would have no special features like variable length records, is 100 bytes long, has a 512 byte page size, has no preallocated pages, and will not over write an existing file on the same path. PLEASE NOTE: Before calling Create you must define the keys by calls to AddKeySegment. See the bXXXXX constants, AddKeySegment, Init. CreateIndex : Procedure CreateIndex; Adds a new supplemental index to the file. First, you must set up the new index by calling AddSupplKeySegment. If you are adding more than one new index, create each one separately. See AddSupplKeySegment. Delete : Procedure Delete; Deletes the current record from the file. You must have previously read a record. See Get, GetDirect. DropIndex : Procedure DropIndex(Index : Integer); Removes the supplemental index specified by the parameter Index from the file. EndTransaction : Procedure EndTransaction; Ends the current Btrieve transaction. See AbortTransaction, StartTransaction. Error : Function Error(ErrStatus: Integer; OpCode : Byte; FileName : PathStr ): Boolean; This method is intended mainly for internal use. If the error handler is not nil just makes a call to the error handlers Error method. FillKeyBuffer : Procedure FillKeyBuffer(var Buff; Size : Byte); This method is for copying data directly into the key buffer. Size is the number of bytes to copy. FixKeyStrings : Procedure FixKeyStrings; Justifies all key strings when writing a record. Internal use only. Get : Procedure Get(Op : Word; Lock : Word); Read a record from the file, this file will execute gets or steps. If you are reading by key value, before executing this method you must set up the key by calling MakeKey. Op is the type of read to attempt, such as equal to the key, greater than the key, less than the key, step first, step last, next record, or previous record. Lock is a standard Btrieve locking type. Please see your Btrieve manual for more information on record locking. See the bXXXXX constants, MakeKey, SetKeyPath. GetDirect : Procedure GetDirect(Lock : Word; Position : LongInt); Read a record from the file using a record position. Lock is a standard Btrieve locking type. Position is the position of the desired record, you should get this by a call to GetPosition. You may want to call SetKeyPath to establish the index that will be active after the read. Please see your Btrieve manual for more information on record locking. See the bXXXXX constants, GetPosition, SetKeyPath. GetPosition : Function GetPosition: LongInt; Returns the position of the current record in the file. You must have previously read a record. Use the value returned as the position parameter to GetDirect. See Get, GetDirect. GetErrors : Procedure GetErrors(var ErrorCodes : ErrorSet); Returns the full set of trapped error codes currently set in the error handler. See TrappedErrors, SetErrors, AddErrors, RemoveErrors, bXXXXX constants. Insert : Procedure Insert; Add a new record to the file. Just fill the file buffer (pointed to by Data) and call this method. When writing variable length records be sure to set the actual number of bytes of data by a call to SetOutputSize. See SetOutputSize, Update. IsOpen : Function IsOpen: Boolean; Returns TRUE if the file is open. Load : Function Load(InputFilePath : PathStr; DisplayObj : PProgress): Integer; Reads records from a DOS file and inserts them into the file. This operates the same as BUTIL with the -Load option. The file being read must be in the same format as BUTIL generates with the -Recover option. Load will read the files generated by the Save method. InputFilePath is the name of the DOS file to read from. DisplayObj is a pointer to a method that can be called to display the progress of Load. Recover. DisplayObj can be nil, in that case no call will be made. Load will return a non-zero value if any errors occur. If there is an error, you can check the value of bResult to tell which file had a problem. If bResult returns zero, then the DOS file had an error. If the error returned is bLoadInputErr, then the DOS file is not in the correct format. See Save. MakeKey : Procedure MakeKey(V1 : Pointer; V2 : Pointer; V3 : Pointer; V4 : Pointer; V5 : Pointer; V6 : Pointer); Use this method to build a key before reading a record. The V1..V6 parameters are the addresses of the data values that will make up the key. These parameters must be specified in the same order as in the key. A key will be built for the current index, held in the CurIndex field. Any unused parameters should be passed with a value of nil. A typical call might be : F.MakeKey(@State, @City, nil, nil, nil, nil); You may need to call SetKeyPath to establish the index that you want to use. See the bXXXXX constants, SetKeyPath. NumberOfRecords : Function NumberOfRecords: LongInt; Returns the NumberOfRecords, actually the largest number of records ever in the file, reported by Btrieve. Open : Procedure Open(Mode : Integer; Owner: String); Open a file. Mode is the file access mode such as accelerated, exclusive, read only or verify. It would normally be set to zero. Owner is the eight character file owner name. Unless you have set an owner name with a call to SetOwner, this should be a null string. See the bXXXXX constants, SetOwner, Init. Recover : Function Recover(NewFilePath : PathStr; DisplayObj : PProgress): Integer; Recover Clones the file, then copies all possible records to the new file. The file should be opened in Read Only mode. NewFilePath is the name of the new file to create. DisplayObj is a pointer to a method that can be called to display the progress of Recover. DisplayObj can be nil, in that case no call will be made. Recover will return a non-zero value if any errors occur. If there is an error, you can check the value of bResult to tell which file had a problem. If bResult returns zero, then the new file had an error. RemoveErrors : Procedure RemoveErrors(ErrorCodes : ErrorSet); Use RemoveErrors to remove a set of error codes from those handled by the file's error handler. Use it in conjunction with AddErrors to turn an error on and off for automatic trapping. RemoveErrors just makes a call to the error handler RemoveErrors method, so it is here mostly for convenience. You could just as well remove errors by dereferencing the ErrHandler pointer. But this is one of the most often used calls for the error handler. See AddErrors, ErrHandler, TErrorHandler. Reset : Procedure Reset; Resets all resources held by a workstation. Save : Function Save(NewFilePath : PathStr; DisplayObj : PProgress): Integer; Writes all the records that can be read to a DOS file. The file should be opened in Read Only mode. This method operates the same as BUTIL with the -Recover option. The file being written is in the same format as BUTIL needs for its -Load option. Save generates file that can be read by the Load method. NewFilePath is the name of the DOS file to create. DisplayObj is a pointer to a method that can be called to display the progress of Save. DisplayObj can be nil, in that case no call will be made. Save will return a non-zero value if any errors occur. If there is an error, you can check the value of bResult to tell which file had a problem. If bResult returns zero, then the DOS file had an error. See Load. SetErrors : Procedure SetErrors(ErrorCodes : ErrorSet); Setup the full set of trapped errors currently used by the error handler. See SetErrors, GetErrors, AddErrors, RemoveErrors, bXXXXX constants. SetKeyPath : Procedure SetKeyPath(Number : Word); Sets the key number (access path) that will be used for all reads and writes. SetOutputSize : Procedure SetOutputSize(Size : Word); Call SetOutputSize to set the length of the buffer before writing a record to the file. This defaults to the size of the record defined in the file, so this is used only for variable length records. SetOwner : Procedure SetOwner(Owner : String; Mode : Integer); Owner is the eight character file owner name. Mode is the restrictions desired on access to the file. Please consult your Btrieve manual for more information on these restrictions. See the bXXXXX constants, ClearOwner. StartTransaction : Procedure StartTransaction(Lock : Word); Start a Btrieve transaction. See AbortTransaction, StartTransaction. Stat : Procedure Stat(var FData : FileSpec); Returns the file statistics reported by Btrieve. Unload : Procedure Unload; Unloads Btrieve from memory. UnlockAll : Procedure UnlockAll(Lock : Word); Unlocks all locked records in the file. Lock identifies the type of locks that are active. Less than or equal to 200 indicates single locks, greater than 200 indicates multiple record locks. Please see your Btrieve manual for more information on record locking. See the bXXXXX constants. Update : Procedure Update; Updates an existing record in the file. When writing variable length records be sure to set the actual number of bytes of data by a call to SetOutputSize. See SetOutputSize, Insert. Version : Procedure Version(var Ver : Word; var Rev : Word; var OSFlag : Char); Returns the version number of Btrieve that is running. Ver is the full version number, Rev is the revision number, OSFlag indicates the operating system. OBJECT DECLARATIONS - ErrorHandler FIELDS - RetryCount : RetryCount : Word; The number of times an operation has been attempted so far. RetryCount is only used on lock errors. MaxRetry : MaxRetry : Word; The maximum number of retries allowed. RetryDelay : RetryDelay : Word; Delay between retries. TrappedErrors : TrappedErrors : ErrorSet; Set of all trapped errors. Any error in this set will be checked for by ErrorHandler and passed to an error display routine. This set defaults to all errors except End Of File. ErrorDisplay : ErrorDisplay : PErrorDisplay; Pointer to the object that will be called to display errors. If ErrorDisplay is nil, no errors will be displayed. METHODS - Init : Constructor Init(var DisplayObject: PErrorDisplay); Initialize the error handler. DisplayObject is the object that will be called to display errors. If DisplayObject is nil, no errors will be displayed. See Done, ErrorDisplay object. Done : Destructor Done; Virtual; Destroys the object. See Init. AddErrors : Procedure AddErrors(ErrorCodes : ErrorSet); Add the errors in the set ErrorCodes to the set of trapped errors. See ErrorSet, TrappedErrors, SetErrors, GetErrors, RemoveErrors, bXXXXX constants. ClearRetry : Procedure ClearRetry; Clears the current number of retries. See SetDelay, GetDelay, RetryCount, ClearRetry, MaxRetry, GetMaxRetry. ErrorDispatcher : Function ErrorDispacther(ErrorCode : Integer; OpCode : Byte; FileName : PathStr ): ErrorAction; Virtual; ErrorDispatcher is called by the Error method. The error code, error description, operation code, operation description, and file path name will be passed to the error display object to display and classify. The error object will return an action code, erAbort, erDone, or erRetry. On erAbort the program will be immediately halted. erDone will cause the error state to be cleared, so the operation will return to your program code. erRetry will leave the error state to TRUE, so the operation can be retried. See Error, ErrorDisplay object, ErrorAction, bXXXXX constants. Error : Function Error(Status : Integer; OpCode : Byte; FileName : PathStr ): Boolean; Virtual; If Status is in the set of trapped errors (zero cannot be added to the set), Error calls the ErrorDispatcher method. The status will be passed to the ErrorDisplay object through the ErrorDispatcher routine. In the case of file or record lock errors (84, 85), no error will be generated until the operation has been tried the number of times stored in RetryCount. If the action code returned by the error dispatcher is erDone, Error will return FALSE to the calling routine, indicating no more errors. If the action code is erRetry then TRUE is returned, so the calling routine will execute the operation again. If a Status is not in the set of trapped errors, FALSE is always returned. In this case the program must check the file status for errors. See ErrorDispatcher, ErrorDisplay object, ErrorAction, bXXXXX constants. ErrorMsg : Function ErrorMsg(ErrorCode : Integer ): String; Virtual; Returns a string describing the error associated with ErrorCode. See the bXXXXX constants. GetDelay : Function GetDelay: Word; Returns the current seconds delay between retries. See GetDelay, RetryCount. GetErrors : Procedure GetErrors(var ErrorCodes : ErrorSet); Returns the full set of trapped error codes. See TrappedErrors, SetErrors, AddErrors, RemoveErrors, ErrorSet, bXXXXX constants. GetMaxRetry : Function GetMaxRetry: Word; Return the maximum number of retries. See RetryCount, ClearRetry, MaxRetry, SetMaxRetry. OpMsg : Function OpMsg(OpCode : Integer): String; Virtual; Returns a string describing the operation associated with OpCode. See the bXXXXX constants. RemoveErrors : Procedure RemoveErrors(ErrorCodes : ErrorSet); Remove the errors in the set ErrorCodes from the set of trapped errors. See TrappedErrors, SetErrors, GetErrors, AddErrors, ErrorSet, bXXXXX constants. SetDelay : Procedure SetDelay(Seconds : Word); Set the seconds of delay between retries. This delay is only used for lock errors. See GetDelay, RetryCount. SetErrors : Procedure SetErrors(ErrorCodes : ErrorSet); Setup the full set of trapped errors. See SetErrors, GetErrors, AddErrors, RemoveErrors, ErrorSet, bXXXXX constants. SetMaxRetry : Procedure SetMaxRetry(Retry : Word); Set the maximum number of retries. See RetryCount, ClearRetry, MaxRetry, GetMaxRetry. OBJECT DECLARATIONS - ErrorDisplay METHODS - Init : Constructor Init; Initialize the object; See Done; Display : Function Display(Error : Integer; ErrorMsg : String; OpCode : Byte; OpCodeMsg : String; FileName : PathStr ): ErrorAction; Virtual; This routine is called by the error handler, for any errors that are in the set of trapped errors. Error is the Btrieve status code, ErrorMsg a description of the error code. OpCode is the operation that generated the error. OpCodeMsg is a description of the operation. FileName is the full path name for the file. This routine must return an action code that will tell the error handler what to do next. Here is an example of a what typical error display method might look like : Function TheErrorDisplay.Display(Error: Integer; ErrorMsg: String; OpCode: Byte; OpCodeMsg: String; FileName: PathStr): ErrorAction; var Ch : Char; begin GotoXY(1,1); { show what happened } Writeln(''); Writeln(FileName); Writeln(ErrorMsg); Writeln(OpCodeMsg); Case Error of { a couple errors to abort on } bFileNotOpen, bFileNotFound, bNotLoaded : begin Writeln('Press a key ...'); Ch := ReadKey; Display := erAbort; end; else { we will let user decide what to do here } begin Writeln('Do you wish to try again (Y/N)?'); Ch := UpCase(ReadKey); if (Ch = 'Y') then Display := erRetry else Display := erDone; end; end; end; As you can see, you have full control of what happens because of any error. You can use the opcode and error to classify errors and control the error handler actions. Pass back erAbort to halt the program, erRetry to make another attempt, or erDone to continue and return the error to your program. Done : Destructor Done; Virtual; Destroys the object. See Init. OBJECT DECLARATIONS - TProgress METHODS - Init : Constructor Init; Display : Procedure Display(Count : LongInt); This method is called by Recover, Save, and Load to display the progress of the operation. You must define a new descendant object with a working Display method. Before calling Recover, Save, or Load, initialize an object of your new type. Then pass a pointer to your object to Recover, Save, or Load. Your Display method will be called every ten records plus one final time when the operation is complete. APPENDIX A - bXXXXX Constants The following are Btrieve defined operation codes. bOpen = 0 bEndTransaction = 20 bClose = 1 bAbortTransaction = 21 bInsert = 2 bGetPosition = 22 bUpdate = 3 bGetDirect = 23 bDelete = 4 bStepNext = 24 bGetEqual = 5 bStop = 25 bGetNext = 6 bVersion = 26 bGetPrev = 7 bUnlock = 27 bGetGreat = 8 bReset = 28 bGetGreatEqual = 9 bSetOwner = 29 bGetLess = 10 bClearOwner = 30 bGetLessEqual = 11 bCreateIndex = 31 bGetFirst = 12 bDropIndex = 32 bGetLast = 13 bStepFirst = 33 bCreate = 14 bStepLast = 34 bStat = 15 bStepPrev = 35 bBeginTransaction = 19 bGetKey = 50 The following are Btrieve defined status codes. bOkay = 0 bNullKeypath = 44 bInvalidOp = 1 bBadKeyFlags = 45 bIOerror = 2 bFileAccessDenied = 46 bFileNotOpen = 3 bMaxOpenFiles = 47 bKeyNotFound = 4 bInvalidAltSequence = 48 bDuplicateKey = 5 bKeyTypeErr = 49 bInvalidKey = 6 bOwnerIsSet = 50 bDifferentKey = 7 bInvalidOwner = 51 bInvalidPos = 8 bCacheWriteErr = 52 bEOF = 9 bInvalidVersion = 53 bKeyModifyErr = 10 bVariablePageErr = 54 bInvalidName = 11 bAutoIncrementErr = 55 bFileNotFound = 12 bBadIndex = 56 bExtendedFileErr = 13 bExpandedMemoryErr = 57 bPreImageOpenErr = 14 bCompressBuffShort = 58 bPreImageIOErr = 15 bFileExists = 59 bExpansionErr = 16 bRejectMax = 60 bCloseErr = 17 bWorkSpaceShort = 61 bDiskFull = 18 bDescriptorErr = 62 bUnRecoverableErr = 19 bExtInsertBuffErr = 63 bNotLoaded = 20 bFilterLimit = 64 bKeyBufferShort = 21 bFieldOffsetErr = 65 bDataBufferShort = 22 bTTSabort = 74 bPosBlockShort = 23 bDeadlock = 78 bPageSizeErr = 24 bConflict = 80 bCreateIOErr = 25 bLockErr = 81 bNumberKeys = 26 bLostPosition = 82 bInvalidKeyPos = 27 bOutOfTransaction = 83 bRecordLenErr = 28 bRecordInUse = 84 bKeyLenErr = 29 bFileInUse = 85 bNotBtrieveFile = 30 bFileTblFull = 86 bFileExtended = 31 bHandleTblFull = 87 bExtendIOErr = 32 bBadModeErr = 88 bExtendNameErr = 34 bDeviceTableFull = 90 bDirectoryErr = 35 bServerErr = 91 bTransactionErr = 36 bTranTableFull = 92 bTransactionActive = 37 bBadLockType = 93 bTransactionFileErr = 38 bPermissionErr = 94 bTransactionEndErr = 39 bSessionInvalid = 95 bTransactionMaxFiles= 40 bCommunicationErr = 96 bOpNotAllowed = 41 bDataMessageShort = 97 bAcceleratedErr = 42 bInternalTTSerr = 98 bInvalidAddress = 43 The follwing are special Btv.pas defined errors. Use the constant names, since the numeric value could well change if Novell adds more error codes. bOutOfMemory = 120 Indicates that buffers could not be allocated due to low memory. bDuplicateFilename = bOutOfMemory + 1 The filename passed to Clone, Recover, Save, Load is the same as the file's name. bLoadInputErr = bDuplicateFilename + 1 Something is wrong with the data that Load is trying to read. bLastError = bLoadInputErr Use if you need the last valid error number for error trapping. The following are Btv.pas defined constants. bNormal = 0 bRJustify = 1 bLJustify = 2 These are the two types of key string justifications. The following is a Btrieve defined file create mode. bNoOverWrite = -1 The following are Btrieve defined file owner access modes. bReadAccess = 1 bReadAccessEncrypt = 3 bWriteAccessEncrypt = 2 The following are Btrieve defined file attribute flags. bVariableLen = 1 bKeyOnly = 16 bBlankTruncate = 2 b10Free = 64 bPreallocate = 4 b20Free = 128 bDataCompress = 8 b30Free = 192 The following are Btrieve defined file open modes. bAccelerated = -1 bVerify = -3 bReadOnly = -2 bExclusive = -4 The following are Btrieve defined key attribute flags. bDuplicates = 1 bAltSequence = 32 bModifiable = 2 bDescending = 64 bBinary = 4 bSupplemental = 128 bNull = 8 bExtended = 256 bSegmented = 16 bManual = 512 The following are Btrieve defined key types. bString = 0 bLogical = 7 bInteger = 1 bNumeric = 8 bFloat = 2 bBfloat = 9 bDate = 3 bLstring = 10 bTime = 4 bZstring = 11 bDecimal = 5 bUnsigned = 14 bMoney = 6 bAutoIncrement = 15 The following are Btrieve defined lock types. bNoLock = 0 bMultipleWait = 300 bSingleWait = 100 bMultipleNoWait = 400 bSingleNoWait = 200 APPENDIX B - Revision History and Notes Date Ver What ============================================================================= 02/01/92 1.01 Changed DataSize, BytesRead, BytesToWrite from Integer to Word so variable length records can be up to 64K. 02/04/92 Check that memory allocation size > 0 before issuing an out of memory error. Added ErrorHandler calls for out of memory errors. 02/08/92 Added error setting routines to the file object, so calls through the error handler object pointer are not needed. 02/20/92 Fixed bug in Clone. Wrong file name being used caused lockup. 02/28/92 1.10 Added Recover, Save and Load methods. 03/14/92 1.11 Open was not calculating the largest key correctly. 04/25/92 1.15 Added the FillKeyBuffer method. 05/13/92 Fixed problem with KeyStart buffer not being setup when key segments not defined before opening a file. Changed Error Handler and Error Display in fields in all objects, and the corresponding parameters in methods, to pointers. This allows nil error objects. PLEASE NOTE : This change will cause a type mismatch when you recompile. Just stick a "@" before any error object parameters and try it again. 12/30/92 1.16 Fixed Off by one error in Open when loading key info. 07/30/93 1.50 Added protected mode support for BP 7.0. Added Windows 3.1 support. Moved all consts into the file BtvConst.pas Defined a DefErrorHandler. DefErrorHandler has the default error messages that are stored in the data segment. Added ErrorON flag and ErrorsOnOff procedure. All examples compile for DOS, Windows, and protected mode.