home *** CD-ROM | disk | FTP | other *** search
- (* TBTree16 Copyright (c) 1988,1989 Dean H. Farwell II *)
-
- unit FileBuff;
-
- {$I-} (* turn off I/O error checking *)
-
- (*****************************************************************************)
- (* *)
- (* O P E N F I L E B U F F E R H A N D L I N G R O U T I N E S *)
- (* *)
- (*****************************************************************************)
-
- (* This unit handles the opening and closing of files. It allows a user to
- set a parameter on how many files can be open at a given time and then
- keeps a buffer of open files. The number of files which are in the
- buffer, and are therefore open, will not exceed this limit. The limit can
- be changed at any time. Each time a file is accessed, the list is checked
- to see if the desired file is in the list. If the file is in the list the
- file id is returned. If it is not open, it will be opened and the id will
- be returned. If the number of files currently open is equal to the
- maximum the least recently accessed file will be closed prior to opening
- the desired file.
-
- The primary advantage to using this unit is that the user does not have to
- worry about opening too many files and causing a runtime error. If all
- routines which open and close files use this unit instead of explicitly
- opening and closing files then the user can not accidently open too many
- files. Unfortunately, this unit presently only handles Untyped and Text
- files. It will not handle Typed files. This is mainly due to the strong
- type checking of Turbo Pascal. There are ways around it but for now they
- seem a little unwieldy. This unit can be used for all files of
- type File (ie untyped) and Text. These routines have been thoroughly
- tested for untyped files and are used extensively by other TBTREE units.
- I have only done limited testing with text files.
-
- The main advantage of this unit is that many files can now be open at the
- same time, thus the need to arbitrarily close files is alleviated. This
- should reduce overhead caused by the constant opening and closing of
- files.
-
- All file accesses within TBTREE use this unit. Whether you use this unit
- or not, you still need to initially allocate a number of files to this
- unit (in other words the user sets the maximum number of files which can
- be in the file open buffer). Obviously, you must not allocate more files
- to this unit than DOS can handle. This DOS parameter is set in the
- CONFIG.SYS file at bootup time. The absolute maximum allowed by DOS is
- 20. Since Turbo Pascal needs 5 you have 15 to play with. You can
- allocate any number from 1 to 15 to this unit. If you allocate less than
- 15 (actually the number in the CONFIG.SYS file minus 5) the leftover are
- yours to use with Typed files, etc. For example, if you set FILES = 20 in
- the CONFIG.SYS file you can allocate 10 files to this unit and you will
- have (20 - 5) - 10 = 5 left for yourself to use with typed files. One
- added note: you can change this setting at any time during execution. You
- can even set it to a number less than the number of files presently open
- and files will be closed until the number is reached.
-
- You can use the buffer and these routines for within your application,
- thus sharing it with TBTREE. The scenario for use of these routines is as
- follows:
-
- 1. Call SetMaxOpenFiles(n) where n is the maximum number of files
- which can be open at one time. n must be less than or equal to
- the value for 'files' in the CONFIG.SYS file minus 5. See the DOS
- manual for details. If SetMaxOpenFiles is not called, the max
- number of open files will default to one (1). This will not cause
- any errors but it will probably cause a large performance
- degradation.
-
- 2. When you want to create a file use
- RewriteTextFile(xxxxxxxx.xxx,fId) or
- RewriteUntypedFile(xxxxxxxx.xxx,fId) where xxxxxxxx.xxx is the
- file name (including an optional drive and path) for the file to
- create and fId is a file id (file variable) you have declared.
- For untyped files use OpenUntypedFile routine to open your file
- (if it is not open) and return the appropriate file id in fId.
- For text files use OpenTextFile for reading and AppendTextFile for
- writing. You can now use fId as a file variable. For example:
-
- var myFile : Text;
- str : String;
-
- begin
- RewriteTextFile('autoexec.bat',myfile);
- Writeln(myFile,'verify on');
- CloseFile('autoexec.bat');
- .
- . { to access the file see below }
- .
- OpenTextFile('autoexec.bat',myFile);
- Readln(myFile,str);
- .
- .
- .
- CloseAllFiles; { see note 4 below }
- end;
-
- 3. As noted above, to access the file use
- OpenUntypedFile(xxxxxxxx.xxx,fId) or
- OpenTextFile(xxxxxxxx.xxx,fId) or AppendTextFile(xxxxxxxx.xxx,fId)
- depending on file type, etc. This will ensure that the file will
- be open and the routine will open it if it is not. It is only
- necessary to call OpenUntypedFile if there is a possibility that
- the file may not be open or that fId is not current. For example,
- in the above example, AppendTextFile did not have to be called to
- access autoexec.bat immediately after executing the RewriteFile
- routine. To be safe, always call one of the open file routines
- prior to accessing the file. If the file happens to be open there
- in not much overhead associated with the call. For all the
- routines except for RewriteUntypedFile and RewriteTextFile, the
- file must exist.
-
- 4. Do not use CLOSE to close a file. Use CloseFile(xxxxxxxx.xxx) or
- CloseAllFiles instead. This applies to both Text and Untyped
- files. See notes 5 and 6 below.
-
- 5. To ensure that a particular file is closed use
- CloseFile(xxxxxxxx.xxx). When you call this the file will be
- closed if it is not already closed. If it is closed then nothing
- happens.
-
- 6. To ensure all files are closed use CloseAllFiles.
-
- In previous versions, there was a danger of running out of heap
- space and being unable to allocate enough space on the heap to put a file
- on the list. This is now handled properly by initially reserving enough
- space on the heap for one entry. In this way, you will always be able to
- have at least one file open and in the list. It reserves the space as
- part of the initialization sequence when the code in the initialization
- section is called. If there is not enough heap space available, a runtime
- error occurs. If an error does not occur during the initialization, a
- problem will never occur later. However, if there is a very limited
- amount of heap space available, the unit will not allow very many files to
- reside on the list at one time. This will be transparent to you except
- that performance will suffer somewhat.
-
- One warning when using these routines and using a file variable local to a
- procedure or function: BE SURE TO CLOSE THE FILE (CloseFile or
- CloseAllFiles) before leaving the routine. This restriction in not really
- any different than using file variables with the Turbo Pascal supplied
- routines *)
-
- (*\*)
- (* Version Information
-
- Version 1.1 - No Changes
-
- Version 1.2 - No Changes
-
- Version 1.3 - No Changes
-
- Version 1.4 - Internal changes to use the newly redesigned TIME unit
-
- - Changed SetMaxOpenFiles routine. Now this routine handles
- the case where you set the number of open files to a value
- less than the number presently open. It will close files
- automatically until the number open is equal to the number
- being set.
-
- Version 1.5 - I redid parts of the documentation for the unit to better
- explain its use.
-
- - Unit is now compile with {$I-} which means that I/O checking
- off. I now use the IOResult routine supplied with Turbo
- Pascal to get the rusult of an I/O operation. If the I/O
- operation was not successful then I use the ERROR unit to
- handle it. You must become familiar with the error unit!
-
- - Changed code internally to use Inc and Dec where practical
-
- - Changed code internally to use newly added FastMove unit
-
- - Reworked routines for Text Files to alleviate pesky Flush
- problem. Routines now work properly without needing to flush
- after every Write or Writeln. Chris Cardozo was a great help
- in conquering this problem and his efforts are appreciated.
-
- - In previous versions, there was a danger of running out of
- heap space and being unable to allocate enough space on the
- heap to put a file on the list. This is now handled properly
- by initially reserving enough space on the heap for one
- entry. In this way, you will always be able to have at least
- one file open and in the list. It reserves the space as part
- of the initialization sequence when the code in the
- initialization section is called. If there is not enough
- heap space available, a runtime error occurs. If an error
- does not occur during the initialization, a problem will
- never occur later. However, if there is a very limited amount
- of heap space available, the unit will not allow very many
- files to reside on the list at one time. This will be
- transparent to you except that performance will suffer
- somewhat.
-
- Version 1.6 - No Changes *)
-
-
- (*\*)
- (*////////////////////////// I N T E R F A C E //////////////////////////////*)
-
- interface
-
- uses
- Compare,
- Dos,
- Error,
- FastMove,
- FileDecs,
- Numbers,
- Time;
-
- type
- OpenFileRange = Byte;
-
-
- (* This routine will close the given file and delete its entry from the
- open files buffer. *)
-
- procedure CloseFile(fName : FnString);
-
-
- (* This routine will return the file id (fId) for a file after rewriting it.
- It's operation is equivalent to the REWRITE routine of TURBO. It will
- create a new file or rewrie an existing file. It then adds this file
- to the files open buffer in the same manner as OpenFiles would.
-
- note - This routine is for use with Untyped files only. Unlike with the
- Turbo Pascal routine Rewrite, the user must supply recSize. It will
- not default to 128. *)
-
- procedure RewriteUntypedFile(fName : FnString;
- var fId: File;
- recSize : Word);
-
- (*\*)
- (* This routine will return the file id (fId) for the given file. It will
- also open the file if it is not open. If the file is not open the routine
- will open it and place the file name in the file open buffer. If the
- buffer is full showing that the maximum number of files is open, the
- routine will close the least recently used file prior to opening this one.
- The maximum number of files which can be open is set by calling the
- procedure SetMaxOpenFiles which is part of this unit.
-
- Note : This routine uses the TURBO routine RESET. Therefore the
- restrictions that apply to RESET apply to OpenFile. For Example,
- an error will result if OpenFile is used on a file that does not
- exist. Use RewriteUntypedFile first!
-
- note - This routine is for use with Untyped files only. Unlike with the
- Turbo Pascal routine Rewrite, the user must supply recSize. It will
- not default to 128. *)
-
- procedure OpenUntypedFile(fName : FnString;
- var fId : File;
- recSize : Word);
-
-
- (* This routine will return the file id (fId) for a file after rewriting it.
- It's operation is equivalent to the REWRITE routine of TURBO. It will
- create a new file or rewrite an existing file. It then adds this file
- to the files open buffer in the same manner as OpenFiles would.
-
- note - This routine is for use with Text files only. *)
-
- procedure RewriteTextFile(fName : FnString;
- var fId : Text);
-
-
- (* This routine will return the file id (fId) for the given file. It will
- also open the file if it is not open. If the file is not open the routine
- will open it and place the file name in the file open buffer. If the
- buffer is full showing that the maximum number of files is open, the
- routine will close the least recently used file prior to opening this one.
- The maximum number of files which can be open is set by calling the
- procedure SetMaxOpenFiles which is part of this unit.
-
- Note : This routine uses the TURBO routine RESET. Therefore the
- restrictions that apply to RESET apply to OpenFile. For Example,
- an error will result if OpenFile is used on a file that does not
- exist. Use RewriteTextFile first!
-
- note - This routine is for use with Text files only. *)
-
- procedure OpenTextFile(fName : FnString;
- var fId : Text);
-
- (*\*)
- (* This routine will return the file id (fId) for the given file. It will
- also open the file if it is not open. If the file is not open the routine
- will open it and place the file name in the file open buffer. If the
- buffer is full showing that the maximum number of files is open, the
- routine will close the least recently used file prior to opening this one.
- The maximum number of files which can be open is set by calling the
- procedure SetMaxOpenFiles which is part of this unit.
-
- Note : This routine uses the TURBO routine APPEND. Therefore the
- restrictions that apply to APEND apply to OpenFile. For Example,
- an error will result if OpenFile is used on a file that does not
- exist. Use RewriteTextFile first!
-
- note - This routine is for use with Text files only. *)
-
- procedure AppendTextFile(fName : FnString;
- var fId : Text);
-
- (* This routine will Close all files that are open and empty the open file
- buffer. *)
-
- procedure CloseAllFiles;
-
-
- (* This routine will set the maximum files that can be open at a time. It is
- important that this not exceed the number of files DOS will allow to be
- open. The number DOS will allow is set in the CONFIG.SYS file. Also
- remember that Turbo Pascal needs 5 files so you really can only set this to
- the value set in the CONFIG.SYS file minus 5. See the appropriate DOS
- manual for details on the FILES command. The value is initially set to one
- (1). This routine should be called BEFORE using the buffer. You can call
- this routine ANY time with no negative effects. In version 1.4 the routine
- was changed to take care of the situation where the number of files open is
- greater than n. The routine will first check to ensure that n is valid
- (greater than 0). Once this is established, n will be checked against the
- number of open files. If the number of open files exceeds n, the least
- recently used files will be closed until the number of open files equals n.
- Finally, the internal variable will be set and only n number of files will
- ever be open at once, until this routine is called again with a new value
- for n. *)
-
- procedure SetMaxOpenFiles(n : OpenFileRange);
-
-
- (* This routine will return the number of files which are presently open. *)
-
- function GetNumberOpenFiles : OpenFileRange;
-
- (*!*)
- (*\*)
- (*///////////////////// I M P L E M E N T A T I O N /////////////////////////*)
-
- implementation
-
- type
- FilesType = (TEXTFILE,UNTYPEDFILE); (* only file types handled
- by FILEBUFF *)
-
- FileOpenRecPtr = ^FileOpenRec;
- FileOpenRec = record
- fName : FnString;
- timeUsed : TimeArr;
- userPtr : Pointer; (* used to point to users file var *)
- prev : FileOpenRecPtr;
- next : FileOpenRecPtr;
- case fType : FilesType of
- TEXTFILE : (fIdText : Text);
- UNTYPEDFILE : (fIdUntyped : File);
- end;
-
- FileOpenList = record
- head : FileOpenRecPtr;
- count : OpenFileRange;
- end;
-
-
- var
- maxOpenFiles : OpenFileRange;
- fileList : FileOpenList;
- reservedFPtr : FileOpenRecPtr;
-
-
- (*\*)
- (* This routine deletes a file from the list of open files *)
-
- procedure RemoveFileFromList(var fPtr : FileOpenRecPtr);
-
- begin
- Dec(fileList.count);
- fPtr^.prev^.next := fPtr^.next;
- if fPtr^.next <> NIL then
- begin
- fPtr^.next^.prev := fPtr^.prev;
- end;
- if fPtr <> reservedFPtr then
- begin (* dispose of it only is it is not the reserved space *)
- Dispose(fPtr);
- end;
- end; (* end of RemoveFileFromList routine *)
-
-
- (* This routine find the file that was least recently accessed last and returns
- the appropriate pointer. The calling routine must then close this file
- before opening another. *)
-
- function LRUFile : FileOpenRecPtr;
-
- var
- oldPtr, (* points to least recently used file *)
- fPtr : FileOpenRecPtr;
- minTime : TimeArr; (* time least recently used file was last used *)
-
- begin
- fPtr := fileList.head^.next; (* point to first 'real' cell *)
- oldPtr := fPtr;
- SetMaxTime(minTime);
- while fPtr <> NIL do (* go through all open files *)
- begin
- if CompareTime(fPtr^.timeUsed,minTime) = LESSTHAN then
- begin
- minTime := fPtr^.timeUsed;
- oldPtr := fPtr;
- end;
- fPtr := fPtr^.next;
- end;
- LRUFile := oldPtr;
- end; (* end of LRUFile routine *)
-
- (*\*)
- (* This routine will close the given file and delete its entry from the
- open files buffer. *)
-
- procedure CloseFile(fName : FnString);
-
- var
- fPtr : FileOpenRecPtr;
- found : Boolean;
- ioRes : Word;
- ioErrRec : IOErrorRec;
-
- begin
- fPtr := fileList.head^.next;
- found := FALSE;
- while (fPtr <> NIL) and (not found) do
- begin
- if fPtr^.fName = fName then
- begin
- repeat (* I/O loop with error checking *)
- begin
- case fPtr^.fType of (* close it *)
- TEXTFILE :
- begin
- FastMover(fPtr^.userPtr^,
- fPtr^.fIdText,
- 128); (* don't want the buffer .. *)
- Close(fPtr^.fIdText);
- end;
- UNTYPEDFILE :
- begin
- Close(fPtr^.fIdUntyped);
- end;
- end; (* end of case statement *)
-
- ioRes := IOResult;
- if ioRes <> 0 then
- begin
- ioErrRec.routineName := 'CloseFile';
- ioErrRec.tBTreeIOResult := ioRes;
- UserIOError(ioErrRec);
- end;
- end;
- until ioRes = 0;
- RemoveFileFromList(fPtr);
- found := TRUE;
- end
- else
- begin
- fPtr := fPtr^.next;
- end;
- end;
- end; (* end of CloseFile routine *)
-
- (*\*)
- (* This routine will allocate enough heap space for one FileOpenRec record.
- It will first check to see if there is room on the list. If there is not,
- a file will be closed to make room. Then the routine will allocate the
- heap space required. If there is not enough room on the heap for an entry
- a file will be closed to make room. If there are no files open the
- reserved heap space is used. *)
-
- procedure AllocateHeapSpaceForList(var fPtr : FileOpenRecPtr);
-
- begin
- if fileList.count = maxOpenFiles then
- begin (* no more files fit on list ... close one first *)
- fPtr := LRUFile;
- CloseFile(fPtr^.fName);
- end;
- if MaxAvail < SizeOf(FileOpenRec) then
- begin
- if fileList.count > 0 then
- begin (* close a file and use its space *)
- fPtr := LRUFile;
- CloseFile(fPtr^.fName);
- New(fPtr);
- end
- else
- begin (* no files to close so use the reserved heap space *)
- fPtr := reservedFPtr;
- end;
- end
- else
- begin (* room on the heap .. use it *)
- New(fPtr);
- end;
- end; (* end of AllocateHeapSpaceForList routine *)
-
-
- (* This routine will put the record pointed to by fPtr in the list and
- also increments the counter *)
-
- procedure PutFileInList(var fPtr : FileOpenRecPtr);
-
- begin
- fPtr^.prev := fileList.head;
- fPtr^.next := fileList.head^.next; (* put at head of list *)
- fileList.head^.next := fPtr;
- if fPtr^.next <> NIL then
- begin
- fPtr^.next^.prev := fPtr;
- end;
- Inc(fileList.count);
- end; (* end of PutFileInList routine *)
-
- (*\*)
- (* This routine will return the file id (fId) for a file after rewriting it.
- It's operation is equivalent to the REWRITE routine of TURBO. It will
- create a new file or rewrie an existing file. It then adds this file
- to the files open buffer in the same manner as OpenFiles would.
-
- note - This routine is for use with Untyped files only. Unlike with the
- Turbo Pascal routine Rewrite, the user must supply recSize. It will
- not default to 128. *)
-
- procedure RewriteUntypedFile(fName : FnString;
- var fId: File;
- recSize : Word);
-
- var
- fPtr : FileOpenRecPtr;
- ioRes : Word;
- ioErrRec : IOErrorRec;
-
- begin
- CloseFile(fName); (* make sure its closed *)
- AllocateHeapSpaceForList(fPtr);
- repeat (* I/O loop with error checking *)
- Assign(fPtr^.fIdUntyped,fName);
- Rewrite(fPtr^.fIdUntyped,recSize); (* open the file *)
- ioRes := IOResult;
- if ioRes <> 0 then
- begin
- ioErrRec.routineName := 'RewriteUntypedFile';
- ioErrRec.tBTreeIOResult := ioRes;
- UserIOError(ioErrRec);
- end;
- until ioRes = 0;
- fPtr^.fName := fName;
- fPtr^.fType := UNTYPEDFILE;
- PutFileInList(fPtr);
- GetTime(fPtr^.timeUsed); (* set the time used *)
- FastMover(fPtr^.fIdUntyped,fId,SizeOf(fId));
- (* pass back file id to caller *)
- end; (* end of RewriteUntypedFile routine *)
-
- (*\*)
- (* This routine will return the file id (fId) for the given file. It will
- also open the file if it is not open. If the file is not open the routine
- will open it and place the file name in the file open buffer. If the
- buffer is full showing that the maximum number of files is open, the
- routine will close the least recently used file prior to opening this one.
- The maximum number of files which can be open is set by calling the
- procedure SetMaxOpenFiles which is part of this unit.
-
- Note : This routine uses the TURBO routine RESET. Therefore the
- restrictions that apply to RESET apply to OpenFile. For Example,
- an error will result if OpenFile is used on a file that does not
- exist. Use RewriteUntypedFile first!
-
- note - This routine is for use with Untyped files only. Unlike with the
- Turbo Pascal routine Rewrite, the user must supply recSize. It will
- not default to 128. *)
-
- procedure OpenUntypedFile(fName : FnString;
- var fId : File;
- recSize : Word);
-
-
- var
- found : Boolean;
- fPtr : FileOpenRecPtr;
- ioRes : Word;
- ioErrRec : IOErrorRec;
-
- begin
- fPtr := fileList.head^.next; (* points to first 'real' cell *)
- found := FALSE;
- while (not found) and (fPtr <> NIL) do
- begin
- if fPtr^.fName = fName then
- begin
- found := TRUE;
- end
- else
- begin
- fPtr := fptr^.next;
- end;
- end;
- if not found then
- begin
- AllocateHeapSpaceForList(fPtr);
- repeat (* I/O loop with error checking *)
- Assign(fPtr^.fIdUntyped,fName);
- Reset(fPtr^.fIdUntyped,recSize); (* open the file *)
- ioRes := IOResult;
- if ioRes <> 0 then
- begin
- ioErrRec.routineName := 'OpenUntypedFile';
- ioErrRec.tBTreeIOResult := ioRes;
- UserIOError(ioErrRec);
- end;
- until ioRes = 0;
- fPtr^.fName := fName;
- fPtr^.fType := UNTYPEDFILE;
- PutFileInList(fPtr);
- end;
- GetTime(fPtr^.timeUsed); (* set the time used *)
- FastMover(fPtr^.fIdUntyped,fId,SizeOf(fId));
- (* pass back file id to caller *)
- end; (* end of OpenUntypedFile routine *)
-
- (*\*)
- (* This routine will return the file id (fId) for a file after rewriting it.
- It's operation is equivalent to the REWRITE routine of TURBO. It will
- create a new file or rewrite an existing file. It then adds this file
- to the files open buffer in the same manner as OpenFiles would.
-
- note - This routine is for use with Text files only. *)
-
- procedure RewriteTextFile(fName : FnString;
- var fId : Text);
-
-
- var
- fPtr : FileOpenRecPtr;
- ioRes : Word;
- ioErrRec : IOErrorRec;
-
- begin
- CloseFile(fName); (* make sure its closed *)
- AllocateHeapSpaceForList(fPtr);
- repeat (* I/O loop with error checking *)
- Assign(fPtr^.fIdText,fName);
- Rewrite(fPtr^.fIdText); (* rewrite the file *)
- ioRes := IOResult;
- if ioRes <> 0 then
- begin
- ioErrRec.routineName := 'RewriteTextFile';
- ioErrRec.tBTreeIOResult := ioRes;
- UserIOError(ioErrRec);
- end;
- until ioRes = 0;
- fPtr^.fName := fName;
- fPtr^.fType := TEXTFILE;
- fPtr^.userPtr := Addr(fId); (* get address of user file variable *)
- PutFileInList(fPtr);
- GetTime(fPtr^.timeUsed); (* set the time used *)
- FastMover(fPtr^.fIdText,fId,SizeOf(fId)); (* pass back file id to caller *)
- end; (* end of RewriteTextFile routine *)
-
- (*\*)
- (* This routine will return the file id (fId) for the given file. It will
- also open the file if it is not open. If the file is not open the routine
- will open it and place the file name in the file open buffer. If the
- buffer is full showing that the maximum number of files is open, the
- routine will close the least recently used file prior to opening this one.
- The maximum number of files which can be open is set by calling the
- procedure SetMaxOpenFiles which is part of this unit.
-
- Note : This routine uses the TURBO routine RESET. Therefore the
- restrictions that apply to RESET apply to OpenFile. For Example,
- an error will result if OpenFile is used on a file that does not
- exist. Use RewriteTextFile first!
-
- note - This routine is for use with Text files only. *)
-
- procedure OpenTextFile(fName : FnString;
- var fId : Text);
-
-
- var
- found : Boolean;
- fPtr : FileOpenRecPtr;
- ioRes : Word;
- ioErrRec : IOErrorRec;
-
- begin
- fPtr := fileList.head^.next; (* points to first 'real' cell *)
- found := FALSE;
- while (not found) and (fPtr <> NIL) do
- begin
- if fPtr^.fName = fName then
- begin
- found := TRUE;
- end
- else
- begin
- fPtr := fptr^.next;
- end;
- end;
- if not found then
- begin
- AllocateHeapSpaceForList(fPtr);
- repeat (* I/O loop with error checking *)
- Assign(fPtr^.fIdText,fName);
- Reset(fPtr^.fIdText); (* open the file *)
- ioRes := IOResult;
- if ioRes <> 0 then
- begin
- ioErrRec.routineName := 'OpenTextFile';
- ioErrRec.tBTreeIOResult := ioRes;
- UserIOError(ioErrRec);
- end;
- until ioRes = 0;
- fPtr^.fName := fName;
- fPtr^.fType := TEXTFILE;
- fPtr^.userPtr := Addr(fId); (* get address of user file variable *)
- PutFileInList(fPtr);
- FastMover(fPtr^.fIdText,fId,SizeOf(fId)); (* pass back file id to
- caller *)
- (* notice that you do not do
- this if the file is open
- already *)
- end;
- GetTime(fPtr^.timeUsed); (* set the time used *)
- end; (* end of OpenTextFile routine *)
-
- (*\*)
- (* This routine will return the file id (fId) for the given file. It will
- also open the file if it is not open. If the file is not open the routine
- will open it and place the file name in the file open buffer. If the
- buffer is full showing that the maximum number of files is open, the
- routine will close the least recently used file prior to opening this one.
- The maximum number of files which can be open is set by calling the
- procedure SetMaxOpenFiles which is part of this unit.
-
- Note : This routine uses the TURBO routine APPEND. Therefore the
- restrictions that apply to APEND apply to OpenFile. For Example,
- an error will result if OpenFile is used on a file that does not
- exist. Use RewriteTextFile first!
-
- note - This routine is for use with Text files only. *)
-
- procedure AppendTextFile(fName : FnString;
- var fId : Text);
-
-
- var
- found : Boolean;
- fPtr : FileOpenRecPtr;
- ioRes : Word;
- ioErrRec : IOErrorRec;
-
- begin
- fPtr := fileList.head^.next; (* points to first 'real' cell *)
- found := FALSE;
- while (not found) and (fPtr <> NIL) do
- begin
- if fPtr^.fName = fName then
- begin
- found := TRUE;
- end
- else
- begin
- fPtr := fptr^.next;
- end;
- end;
- if not found then
- begin
- AllocateHeapSpaceForList(fPtr);
- repeat (* I/O loop with error checking *)
- Assign(fPtr^.fIdText,fName);
- Append(fPtr^.fIdText); (* open the file *)
- ioRes := IOResult;
- if ioRes <> 0 then
- begin
- ioErrRec.routineName := 'AppendTextFile';
- ioErrRec.tBTreeIOResult := ioRes;
- UserIOError(ioErrRec);
- end;
- until ioRes = 0;
- fPtr^.fName := fName;
- fPtr^.fType := TEXTFILE;
- fPtr^.userPtr := Addr(fId); (* get address of user file variable *)
- PutFileInList(fPtr);
- FastMover(fPtr^.fIdText,fId,SizeOf(fId)); (* pass back file id to
- caller *)
- end;
- GetTime(fPtr^.timeUsed); (* set the time used *)
- end; (* end of AppendTextFile routine *)
-
- (*\*)
- (* This routine will Close all files that are open and empty the open file
- buffer. *)
-
- procedure CloseAllFiles;
-
- begin
- while fileList.count <> 0 do
- begin
- CloseFile(fileList.head^.next^.fName);
- end;
- end; (* end of CloseAllFiles routine *)
-
-
- (* This routine will set the maximum files that can be open at a time. It is
- important that this not exceed the number of files DOS will allow to be
- open. The number DOS will allow is set in the CONFIG.SYS file. Also
- remember that Turbo Pascal needs 5 files so you really can only set this to
- the value set in the CONFIG.SYS file minus 5. See the appropriate DOS
- manual for details on the FILES command. The value is initially set to one
- (1). This routine should be called BEFORE using the buffer. You can call
- this routine ANY time with no negative effects. In version 1.4 the routine
- was changed to take care of the situation where the number of files open is
- greater than n. The routine will first check to ensure that n is valid
- (greater than 0). Once this is established, n will be checked against the
- number of open files. If the number of open files exceeds n, the least
- recently used files will be closed until the number of open files equals n.
- Finally, the internal variable will be set and only n number of files will
- ever be open at once, until this routine is called again with a new value
- for n. *)
-
- procedure SetMaxOpenFiles(n : OpenFileRange);
-
- var
- fPtr : FileOpenRecPtr;
-
- begin
- if n > 0 then
- begin
- if fileList.count <= n then
- begin
- maxOpenFiles := n;
- end
- else
- begin
- while fileList.count > n do
- begin
- fPtr := LRUFile;
- CloseFile(fPtr^.fName);
- end;
- end;
- end;
- end; (* end of SetMaxOpenFiles routine *)
-
- (*\*)
- (* This routine will return the number of files which are presently open. *)
-
- function GetNumberOpenFiles : OpenFileRange;
-
- begin
- GetNumberOpenFiles := fileList.count;
- end; (* end of GetNumberOpenFiles routine *)
-
-
- begin
- New(fileList.head); (* create an empty cell .. easier to use *)
- fileList.count := 0; (* set in-use count *)
- fileList.head^.fName := ''; (* this line not really required *)
- fileList.head^.prev := NIL; (* neither is this one *)
- fileList.head^.next := NIL;
- SetMaxOpenFiles(1); (* initially, only one open file at a time *)
- New(reservedFPtr); (* reserve heap space for at least one entry in list *)
- end. (* end of FileBuff unit *)