home *** CD-ROM | disk | FTP | other *** search
- (******************************************************************************
-
- FLUSH.PAS
- Version 1.2
- January 9, 1986
- by Randy Forgaard
- CompuServe 70307,521
-
- This file, FLUSH.PAS, is related to the file FLUSH.ACC in DL 1 of the Borland
- SIG on CompuServe. FLUSH.PAS is for use with normal Turbo files, and FLUSH.ACC
- is for use with Turbo (Database) Toolbox files.
-
- This file is for use with MS-DOS or PC-DOS Turbo Pascal 3.0 or higher. These
- are two routines to use in place of Turbo's built-in Flush procedure.
-
- The Flush routine that is built-in to Turbo has no effect on non-Text files,
- and achieves only partial results with Text files. Thus, if a program has
- written to a file, and the program or computer crashes unexpectedly before the
- program gets around to closing the file, the most recently written data does
- not get written to disk (because it is being temporarily saved in memory
- buffers by DOS), and the file length in the directory entry does not get
- updated. This is due to the apparent omission of any DOS function that will
- perform a true "flush" on a file, short of closing and reopening the file.
- Closing the file is fairly fast, but reopening is quite slow, primarily due to
- the directory search involved.
-
- If Turbo's built-in Flush procedure truly flushed a file, one could just do a
- Flush on a file every time the file changed, a fast operation. This would be
- extraordinarily useful in database-intensive applications, where you need to
- ensure that all data actually gets written to disk, and the file length remains
- up-to-date, so that the database will be consistent even if there should be a
- crash while the database files are open. (If lightning strikes during the few
- microseconds between writing to a file and doing a "flush" on it, the file is
- left in an inconsistent state, but that's the sort of thing that you have
- software engineering malpractice insurance for.)
-
- Fortunately, there actually IS a little-known method for flushing a file's
- buffers and updating the file length in the file's directory entry under DOS,
- without reopening the file. The technique for "flushing" a file is: 1) invoke
- DOS function 45H, "Duplicate a File Handle (DUP)," to duplicate the file
- handle, and then 2) invoke DOS function 3EH, "Close a File Handle" to close the
- extra file handle that you just created (this action does not close the
- original file handle). The "Close" function 3EH flushes the file's buffers, as
- documented in the DOS Technical Reference manual. Yet the original file handle
- is still valid and usable, so the file does not need to be reopened. Thanks
- for this clever technique go to Dan Daetwyler in a letter to Ray Duncan's
- 16-Bit Software Toolbox column in the December '85 issue of Dr. Dobb's Journal.
-
- One of the routines below is a new implementation of Turbo's Flush procedure,
- called FlushAny. This procedure will perform an actual flush on any typed or
- untyped Turbo file (but not Text files...see below). It works only with Turbo
- 3.0 and higher (because Turbo 2.0 didn't use file handles), and it works only
- under DOS. It uses the technique described above.
-
- Turbo Text files are handled a little differently from non-Text files, because
- Turbo maintains its own buffer for Text files, in addition to any buffers that
- DOS maintains. Thus, when flushing a Text file, we must call Turbo's Flush
- routine first to flush Turbo's buffer for that file, and then call FlushAny to
- actually flush the data out of DOS' buffers and onto the disk. Furthermore,
- Turbo allows Text files to be logical devices, and DOS does not allow logical
- device handles to be duplicated, so we need to make an explicit check to make
- sure that the Text file is really a disk output file before performing a
- FlushAny on it. FlushText, below, will flush the Turbo buffer associated with
- a Text file, and then (if it is a disk file) flush the DOS buffers and update
- the file length in the directory entry for that file by calling FlushAny.
-
- Now that MicroSoft's secret is out, maybe Borland will change Flush so that it
- does a real "flush" in a future version of Turbo for DOS <grin>.
-
- Many thanks to Andy Miller (CompuServe 70357,3656) for pointing out that the
- routines below do not use any undocumented features of DOS function calls.
-
- Change Log:
-
- Version 1.1: Added caveats, because it was believed that this file used an
- undocumented feature of a DOS function.
-
- Version 1.2: Removed caveats about undocumented use of DOS functions, since
- this file actually only uses documented features of DOS.
-
- ******************************************************************************)
-
-
- {Flushes the buffers associated with "f," and updates the file length in the
- directory entry of "f," without closing "f." The parameter "f" must be any
- non-Text file; e.g., a File, a File of Byte, a File of Foo, etc. (Please
- replace the unfancy error handling in this routine with whatever method you
- are using in your program.)}
-
- procedure FlushAny (var f);
- var
- handle: Integer absolute f; {File handle is the first word of a file's FIB}
- regs: record
- case Integer of
- 1: (AX, BX, CX, DX, BP, SI, DI, DS, ES, Flags: Integer);
- 2: (AL, AH, BL, BH, CL, CH, DL, DH: Byte)
- end;
- begin
- regs.AH := $45; {DOS function to duplicate a file handle}
- regs.BX := handle;
- MsDos(regs);
- if Odd(regs.Flags) then {Check if carry flag is set}
- begin
- writeln('Unable to duplicate file handle');
- Halt
- end;
- regs.BX := regs.AX; {Put new file handle into BX}
- regs.AH := $3E; {Dos function to close a file handle}
- MsDos(regs);
- if Odd(regs.Flags) then {Check if carry flag is set}
- begin
- writeln('Unable to close duplicated handle');
- Halt
- end
- end {FlushAny};
-
-
- {Flushes the buffers associated with "f," and updates the file length in the
- directory entry of "f," without closing "f." The parameter "f" may be any
- Text file, though the buffers will only be flushed (and only need to be
- flushed) if "f" is an output file, and the directory entry will only be
- updated if "f" is a disk file.}
-
- procedure FlushText (var f: Text);
- var
- fib: record
- handle: Integer;
- flags: Byte
- end absolute f;
- begin
- Flush(f);
-
- {Only allow "f" to be flushed if it is an output disk file}
- if fib.flags = $40 then FlushAny(f)
- end; {FlushText};