fxpbuffr.pro 4.24 KB
;+
; NAME:
;   FXPBUFFR
;
; AUTHOR:
;   Craig B. Markwardt, NASA/GSFC Code 662, Greenbelt, MD 20770
;   craigm@lheamail.gsfc.nasa.gov
;   UPDATED VERSIONs can be found on my WEB PAGE: 
;      http://cow.physics.wisc.edu/~craigm/idl/idl.html
;
; PURPOSE:
;   Internal routine to read data from the pipe and store it in a
;            cache file.
;
; DESCRIPTION:
;
;   See the following procedures for appropriate documentation.
;
;     FXGOPEN  - open resource
;     FXGCLOSE - close resource
;     FXGREAD  - read from resource
;     FXGWRITE - write to resource
;     FXGSEEK  - seek on resource (i.e., perform POINT_LUN)
;
;     FXGFILTERED - determine if resource is a normal file.
;
; PARAMETERS
;   unit - LUN of the pipe, *not* the cache file.
;
;   newlen - the new desired length of the file.  After a successful
;            call to FXPBUFFR, the length of the cache file will be at
;            least this long.
;
; Side Effects
;
;  The pipe is read and the cache increases in size.
;
; MODIFICATION HISTORY:
;   Changed copyright notice, 21 Sep 2000, CM
;
;  $Id: fxpbuffr.pro,v 1.3 2007/09/01 23:05:31 craigm Exp $
;
;-
; Copyright (C) 1999-2000, Craig Markwardt
; This software is provided as is without any warranty whatsoever.
; Permission to use, copy, modify, and distribute modified or
; unmodified copies is granted, provided this copyright and disclaimer
; are included unchanged.
;-

PRO FXPBUFFR, UNIT, NEWLEN

@fxfilter
@fxpcommn

  CUNIT = CACHE_UNIT(UNIT)
  CLEN  = CACHE_LEN(UNIT)

  ;; Compute the size of the buffer, rounded to the nearest granularity
  ;; size.
  NTOT = CEIL(DOUBLE(NEWLEN-CLEN)/BUFFER_GRAN) * BUFFER_GRAN

  ;; Advance the cache file pointer to the end of the file
  IF NOT EOF_REACHED(UNIT) THEN $
    POINT_LUN, CUNIT, CLEN

  ;; This strange ON_IOERROR layout is because IDL has problems
  ;; resetting the error handler inside the loop.  Lots of data is
  ;; lost, presumably because it is buffered.  Therefore, I moved the
  ;; ON_IOERROR command outside of the loop.
  READING = 0
  ON_IOERROR, IO_FAILED

  ;; Read from pipe until we are done.  To avoid the "drinking from a
  ;; fire-hose effect, we read in 32K chunks.
      
  WHILE NOT EOF_REACHED(UNIT) AND NTOT GT 0 DO BEGIN

      ;; Don't read more that BUFFER_MAX at a time, in case we fill
      ;; the memory while seeking to the end of the pipe file.
      NREAD = NTOT < BUFFER_MAX
      BUFFER = BYTARR(NREAD)

      ;; You may ask, why this funny treatment of I/O errors here.
      ;; Well, pipes don't have a well defined endpoint.  A read on
      ;; the pipe with a fixed buffer size might read past the end of
      ;; the pipe data stream.  We have to catch that error here since
      ;; an EOF is not fatal.  See above for the initializing
      ;; ON_IOERROR.  When such an error does occur, processing
      ;; proceeds to the end of the loop, and if READING EQ 1, then
      ;; control returns to READ_FAILED.  Ugghh.  But that's the way
      ;; IDL (mis-)handles I/O.
      CC = 0
      READING = 1
      READU, UNIT, BUFFER, TRANSFER_COUNT=CC

      ;; IO Operation could have failed.  If the read operation
      ;; failed, that may actually be a signal that the pipe has
      ;; finished.  There may still be good data to extract from the
      ;; most recent READU command, so we may restart.
      IF 0 THEN BEGIN
          IO_FAILED:
          IF NOT READING THEN GOTO, READ_DONE
      ENDIF

      READ_FAILED:
      READING = 0
      ;; If the transfer count is zero, that is our clue that the pipe
      ;; has ended.
      IF CC EQ 0 THEN BEGIN
          ;; If there really was a failure here, and not enough bytes
          ;; were read, then that will be picked up when we read from
          ;; the cache file.
          CC = FSTAT(UNIT)
          CC = CC.TRANSFER_COUNT
          IF CC EQ 0 THEN EOF_REACHED(UNIT) = 1
      ENDIF

      ;; Write the buffer out to the cache file ...
      IF CC GT 0 THEN WRITEU, CUNIT, BUFFER(0:CC-1)

      ;; ... and note the new cache length.
      CACHE_LEN(UNIT) = CACHE_LEN(UNIT) + CC
      CACHE_MAX(UNIT) = CACHE_MAX(UNIT) + CC
      
      NTOT = NTOT - CC
  ENDWHILE

  READ_DONE:
  ON_IOERROR, NULL
  
  ;; Finally, seek back to the point we started at, since that is what
  ;; the caller is expecting.
  POINT_LUN, CUNIT, POINTER(UNIT)

  RETURN
END