home *** CD-ROM | disk | FTP | other *** search
- (* TBTree13 Copyright (c) 1988 Dean H. Farwell II *)
-
- unit FileBuff;
-
- (*****************************************************************************)
- (* *)
- (* 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. Each time a user wants to access a file a
- routine is called to open the file. If the file is already open then the
- file id is returned. If it is not open, it will be opened and the id will
- be returned. Otherwise, the file is opened. It the max number of files is
- already open the least recently accessed file will be closed first.
-
- 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. I may work on adding it later.
- For now, this unit can and should be used for all files of type
- File (untyped) and Text. These routines have been thoroughly tested for
- untyped files and are used extensively. i have only done limited testing
- with text files. The are some peculiarities associated with using these
- routines with text files. This is mainly due to the fact that when a
- call is made to open the a file using OpenTextFile the file id is
- returned to your program. All is well, except that as you write to the
- file, you are changing the values in the record represented by the file
- id. These changes are not being reflected in the file id which is in the
- open files list. Specifically, the id on the open files list does not
- know about any characters in the text buffer. To alleviate this, do a
- Flush after every write operation. This needs to be accomplished prior
- to every call to OpenTextFile or any close file operation. Always
- flushing will alleviate problems.
-
- Given the fact that many files can now be open at the same time, the need
- to arbitrarily close files is alleviated. This should reduce overhead from
- opening and closing files too often.
-
- The user allocates 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, the user 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.
- Normally, the user could just set the number of files allowed open by this
- to the same number allowed by DOS. Unfortuantely, this would preclude the
- user from opening any files outside of this unit. Since this unit doesn't
- allow typed files, this would preclude the use of any typed files. The
- best way to handle this is figure out the DOS limit. I wanted to include
- a routine to do that but haven't figured out how to do it. Anyway, once
- you figure out the DOS limit, figure out the maximum number of Typed files
- which will be open at any given time. Now allocate the difference between
- the DOS limit and the number of Typed files to this unit. In that way, you
- do not have to worry about exceeding the DOS limit. Again, if I could
- figureout the DOS limit at run time, then this could be calculated easily.
-
- 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
- then value for 'files' in the config.sys file. 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 for the file to create and fId is a file id (file
- variable) you have declared. The OpenUntypedFile routine will
- open your file (if it is not open) and return the appropriate
- file id in fId. You can now use fId as a file variable. For text
- files use OpenTextFile for reading and AppendTextFile for writing.
- For example:
-
- var myFile : Text;
- str : String;
-
- begin
- RewriteTextFile('autoexec.bat',myfile);
- Writeln(myFile,'verify on');
- Flush(myFile);
- 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. For all the routines except for RewriteUntypedFile and
- RewriteTextFile, the file must exist.
-
- 4. Do not use CLOSE to close myfile. Use CloseFile(fName) or
- CloseAllFiles instead. 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. *)
-
-
- (* Version Information
-
- Version 1.1 - No Changes
-
- Version 1.2 - No Changes
-
- Version 1.3 - No Changes *)
-
-
-
- (*\*)
- (*////////////////////////// I N T E R F A C E //////////////////////////////*)
-
- interface
-
- uses
- Compare,
- 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 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 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 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 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 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. 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 but do not set the value to a
- number lower than the number of files open. The number open can be checked
- using the GetNumberOpenFiles routine. *)
-
- 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);
-
- FileOpenRecPtr = ^FileOpenRec;
- FileOpenRec = record
- fName : FnString;
- timeUsed : TimeArr;
- 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;
-
- (*\*)
- (* 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;
-
- begin
- fPtr := fileList.head^.next;
- found := FALSE;
- while (fPtr <> NIL) and (not found) do
- begin
- if fPtr^.fName = fName then
- begin
- case fPtr^.fType of (* close it *)
- TEXTFILE : Close(fPtr^.fIdText);
- UNTYPEDFILE : Close(fPtr^.fIdUntyped);
- end; (* end of case statement *)
- fileList.count := fileList.count - 1;
- found := TRUE;
- fPtr^.prev^.next := fPtr^.next;
- if fPtr^.next <> NIL then
- begin
- fPtr^.next^.prev := fPtr^.prev;
- end;
- Dispose(fPtr);
- end
- else
- begin (* not found keep searching *)
- fPtr := fPtr^.next;
- end;
- end;
- end; (* end of CloseFile 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 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;
-
- begin
- CloseFile(fName); (* make sure its closed *)
- if fileList.count = maxOpenFiles then
- begin (* no more files avail - close one first *)
- fPtr := LRUFile;
- CloseFile(fPtr^.fName);
- end;
- New(fPtr); (* create new buffer cell *)
- fPtr^.fName := fName;
- fPtr^.fType := TEXTFILE;
- 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;
- fileList.count := fileList.count + 1;
- Assign(fPtr^.fIdText,fName);
- Rewrite(fPtr^.fIdText); (* create the file *)
- GetTime(fPtr^.timeUsed); (* set the time used *)
- Move(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 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;
-
- begin
- CloseFile(fName); (* make sure its closed *)
- if fileList.count = maxOpenFiles then
- begin (* no more files avail - close one first *)
- fPtr := LRUFile;
- CloseFile(fPtr^.fName);
- end;
- New(fPtr); (* create new buffer cell *)
- fPtr^.fName := fName;
- fPtr^.fType := UNTYPEDFILE;
- 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;
- fileList.count := fileList.count + 1;
- Assign(fPtr^.fIdUntyped,fName);
- Rewrite(fPtr^.fIdUntyped,recSize); (* open the file *)
- GetTime(fPtr^.timeUsed); (* set the time used *)
- Move(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 RewriteTextFile first!
-
- note - This routine is for use with Text files only. *)
-
- procedure OpenTextFile(fName : FnString;
- var fId : Text);
-
-
- var
- found : Boolean;
- fPtr : FileOpenRecPtr;
-
- 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
- if fileList.count = maxOpenFiles then
- begin (* no more files avail - close one first *)
- fPtr := LRUFile;
- CloseFile(fPtr^.fName);
- end;
- New(fPtr); (* create new buffer cell *)
- fPtr^.fName := fName;
- fPtr^.fType := TEXTFILE;
- 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;
- fileList.count := fileList.count + 1;
- Assign(fPtr^.fIdText,fName);
- Reset(fPtr^.fIdText); (* open the file *)
- end;
- GetTime(fPtr^.timeUsed); (* set the time used *)
- Move(fPtr^.fIdText,fId,SizeOf(fId)); (* pass back file id to caller *)
- 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;
-
- 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
- if fileList.count = maxOpenFiles then
- begin (* no more files avail - close one first *)
- fPtr := LRUFile;
- CloseFile(fPtr^.fName);
- end;
- New(fPtr); (* create new buffer cell *)
- fPtr^.fName := fName;
- fPtr^.fType := TEXTFILE;
- 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;
- fileList.count := fileList.count + 1;
- Assign(fPtr^.fIdText,fName);
- Append(fPtr^.fIdText); (* open the file *)
- end;
- GetTime(fPtr^.timeUsed); (* set the time used *)
- Move(fPtr^.fIdText,fId,SizeOf(fId)); (* pass back file id to caller *)
- 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 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;
-
- 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
- if fileList.count = maxOpenFiles then
- begin (* no more files avail - close one first *)
- fPtr := LRUFile;
- CloseFile(fPtr^.fName);
- end;
- New(fPtr); (* create new buffer cell *)
- fPtr^.fName := fName;
- fPtr^.fType := UNTYPEDFILE;
- 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;
- fileList.count := fileList.count + 1;
- Assign(fPtr^.fIdUntyped,fName);
- Reset(fPtr^.fIdUntyped,recSize); (* open the file *)
- end;
- GetTime(fPtr^.timeUsed); (* set the time used *)
- Move(fPtr^.fIdUntyped,fId,SizeOf(fId)); (* pass back file id to caller *)
- end; (* end of OpenUntypedFile 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. 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 but do not set the value to a
- number lower than the number of files open. The number open can be checked
- using the GetNumberOpenFiles routine. *)
-
- procedure SetMaxOpenFiles(n : OpenFileRange);
-
- begin
- maxOpenFiles := n;
- 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
- SetMaxOpenFiles(1); (* initially, only one open file at a time *)
- 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;
- end.