fxpbuffr.pro
4.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
;+
; 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