home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / ADC_TP3.ZIP / FLUSH.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1987-03-01  |  6.6 KB  |  136 lines

  1. (******************************************************************************
  2.  
  3.                                    FLUSH.PAS
  4.                                   Version 1.2
  5.                                 January 9, 1986
  6.                                by Randy Forgaard
  7.                               CompuServe 70307,521
  8.  
  9. This file, FLUSH.PAS, is related to the file FLUSH.ACC in DL 1 of the Borland
  10. SIG on CompuServe.  FLUSH.PAS is for use with normal Turbo files, and FLUSH.ACC
  11. is for use with Turbo (Database) Toolbox files.
  12.  
  13. This file is for use with MS-DOS or PC-DOS Turbo Pascal 3.0 or higher.  These
  14. are two routines to use in place of Turbo's built-in Flush procedure.
  15.  
  16. The Flush routine that is built-in to Turbo has no effect on non-Text files,
  17. and achieves only partial results with Text files.  Thus, if a program has
  18. written to a file, and the program or computer crashes unexpectedly before the
  19. program gets around to closing the file, the most recently written data does
  20. not get written to disk (because it is being temporarily saved in memory
  21. buffers by DOS), and the file length in the directory entry does not get
  22. updated.  This is due to the apparent omission of any DOS function that will
  23. perform a true "flush" on a file, short of closing and reopening the file.
  24. Closing the file is fairly fast, but reopening is quite slow, primarily due to
  25. the directory search involved.
  26.  
  27. If Turbo's built-in Flush procedure truly flushed a file, one could just do a
  28. Flush on a file every time the file changed, a fast operation.  This would be
  29. extraordinarily useful in database-intensive applications, where you need to
  30. ensure that all data actually gets written to disk, and the file length remains
  31. up-to-date, so that the database will be consistent even if there should be a
  32. crash while the database files are open.  (If lightning strikes during the few
  33. microseconds between writing to a file and doing a "flush" on it, the file is
  34. left in an inconsistent state, but that's the sort of thing that you have
  35. software engineering malpractice insurance for.)
  36.  
  37. Fortunately, there actually IS a little-known method for flushing a file's
  38. buffers and updating the file length in the file's directory entry under DOS,
  39. without reopening the file.  The technique for "flushing" a file is: 1) invoke
  40. DOS function 45H, "Duplicate a File Handle (DUP)," to duplicate the file
  41. handle, and then 2) invoke DOS function 3EH, "Close a File Handle" to close the
  42. extra file handle that you just created (this action does not close the
  43. original file handle).  The "Close" function 3EH flushes the file's buffers, as
  44. documented in the DOS Technical Reference manual.  Yet the original file handle
  45. is still valid and usable, so the file does not need to be reopened.  Thanks
  46. for this clever technique go to Dan Daetwyler in a letter to Ray Duncan's
  47. 16-Bit Software Toolbox column in the December '85 issue of Dr. Dobb's Journal.
  48.  
  49. One of the routines below is a new implementation of Turbo's Flush procedure,
  50. called FlushAny.  This procedure will perform an actual flush on any typed or
  51. untyped Turbo file (but not Text files...see below).  It works only with Turbo
  52. 3.0 and higher (because Turbo 2.0 didn't use file handles), and it works only
  53. under DOS.  It uses the technique described above.
  54.  
  55. Turbo Text files are handled a little differently from non-Text files, because
  56. Turbo maintains its own buffer for Text files, in addition to any buffers that
  57. DOS maintains.  Thus, when flushing a Text file, we must call Turbo's Flush
  58. routine first to flush Turbo's buffer for that file, and then call FlushAny to
  59. actually flush the data out of DOS' buffers and onto the disk.  Furthermore,
  60. Turbo allows Text files to be logical devices, and DOS does not allow logical
  61. device handles to be duplicated, so we need to make an explicit check to make
  62. sure that the Text file is really a disk output file before performing a
  63. FlushAny on it.  FlushText, below, will flush the Turbo buffer associated with
  64. a Text file, and then (if it is a disk file) flush the DOS buffers and update
  65. the file length in the directory entry for that file by calling FlushAny.
  66.  
  67. Now that MicroSoft's secret is out, maybe Borland will change Flush so that it
  68. does a real "flush" in a future version of Turbo for DOS <grin>.
  69.  
  70. Many thanks to Andy Miller (CompuServe 70357,3656) for pointing out that the
  71. routines below do not use any undocumented features of DOS function calls.
  72.  
  73. Change Log:
  74.  
  75.   Version 1.1: Added caveats, because it was believed that this file used an
  76.                undocumented feature of a DOS function.
  77.  
  78.   Version 1.2: Removed caveats about undocumented use of DOS functions, since
  79.                this file actually only uses documented features of DOS.
  80.  
  81. ******************************************************************************)
  82.  
  83.  
  84. {Flushes the buffers associated with "f," and updates the file length in the
  85.  directory entry of "f," without closing "f."  The parameter "f" must be any
  86.  non-Text file; e.g., a File, a File of Byte, a File of Foo, etc.  (Please
  87.  replace the unfancy error handling in this routine with whatever method you
  88.  are using in your program.)}
  89.  
  90. procedure FlushAny (var f);
  91. var
  92.   handle: Integer absolute f; {File handle is the first word of a file's FIB}
  93.   regs: record
  94.           case Integer of
  95.             1: (AX, BX, CX, DX, BP, SI, DI, DS, ES, Flags: Integer);
  96.             2: (AL, AH, BL, BH, CL, CH, DL, DH: Byte)
  97.         end;
  98. begin
  99.   regs.AH := $45;             {DOS function to duplicate a file handle}
  100.   regs.BX := handle;
  101.   MsDos(regs);
  102.   if Odd(regs.Flags) then     {Check if carry flag is set}
  103.     begin
  104.       writeln('Unable to duplicate file handle');
  105.       Halt
  106.     end;
  107.   regs.BX := regs.AX;         {Put new file handle into BX}
  108.   regs.AH := $3E;             {Dos function to close a file handle}
  109.   MsDos(regs);
  110.   if Odd(regs.Flags) then     {Check if carry flag is set}
  111.     begin
  112.       writeln('Unable to close duplicated handle');
  113.       Halt
  114.     end
  115. end {FlushAny};
  116.  
  117.  
  118. {Flushes the buffers associated with "f," and updates the file length in the
  119.  directory entry of "f," without closing "f."  The parameter "f" may be any
  120.  Text file, though the buffers will only be flushed (and only need to be
  121.  flushed) if "f" is an output file, and the directory entry will only be
  122.  updated if "f" is a disk file.}
  123.  
  124. procedure FlushText (var f: Text);
  125. var
  126.   fib: record
  127.          handle: Integer;
  128.          flags: Byte
  129.        end absolute f;
  130. begin
  131.   Flush(f);
  132.  
  133.   {Only allow "f" to be flushed if it is an output disk file}
  134.   if fib.flags = $40 then FlushAny(f)
  135. end; {FlushText};
  136.