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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
|
# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
include <syserr.h>
include <ctype.h>
include <imhdr.h>
include <imio.h>
include <finfo.h>
include <fset.h>
include "stf.h"
# STF_RFITSHDR -- Read a STF FITS image header, processing all reserved GPB
# definition keywords into the STF descriptor in the image descriptor, and
# saving the remaining cards (excluding cards which GPB keyword names) in
# in a save buffer.
#
# This routine implements a simple cache of FITS headers. If a given header
# is already in the cache and the cached entry is up to date, the cached
# spool file containing the user FITS cards and the saved STF descriptor are
# returned immediately without need to access the header file on disk.
# Otherwise, the new header is read into the oldest cache slot and the cached
# entry returned in the usual fashion. Any modifications to the header file
# which affect the file modify date will invalidate the cached entry. Note
# that multiple processes may cache the same header, so it is not permitted
# to modify the cached entry once the header file has been read.
#
# The following reserved keywords are recognized:
#
# SIMPLE BITPIX DATATYPE NAXIS* GROUPS GCOUNT PCOUNT PSIZE
# PTYPE* PDTYPE* PSIZE*
#
# All unrecognized cards, including HISTORY and COMMENT cards, blank lines,
# and any other garbage in the header, are preserved in the user area of the
# IMIO descriptor (i.e., in the spoolfile). Certain of the standard reserved
# cards (GROUPS, GCOUNT, etc.) are saved in the IMIO user area for the sake
# of the user, although the real values of these parameters are maintained only
# in the STF descriptor.
procedure stf_rfitshdr (im, fits, fitslen)
pointer im #I image descriptor
pointer fits #O pointer to saved FITS cards
int fitslen #O length of FITS save area
long fi[LEN_FINFO]
pointer sp, pp, stf, o_stf, lbuf, op, hdrfile
int in, index, nchars, spool, slot, user, i
bool streq()
long clktime(), fstatl()
int envgeti(), stf_ctype(), finfo(), getline(), open(), stropen()
errchk getline, putline, syserrs, open, seek, calloc, realloc
errchk fpathname, malloc, stf_copyfits
bool initialized # CACHE definitions...
bool reload # reload cache
int rf_refcount # reference count
int rf_cachesize # number of cache slots
pointer rf_stf[MAX_CACHE] # STF descriptor
int rf_lru[MAX_CACHE] # lowest value is oldest slot
long rf_time[MAX_CACHE] # time when entry was cached
long rf_mtime[MAX_CACHE] # modify time of file in cache
int rf_fits[MAX_CACHE] # FITS data
int rf_fitslen[MAX_CACHE] # size of data area
char rf_fname[SZ_PATHNAME,MAX_CACHE] # header file pathname
data initialized /false/
begin
call smark (sp)
call salloc (lbuf, SZ_LINE, TY_CHAR)
call salloc (hdrfile, SZ_PATHNAME, TY_CHAR)
# Initialize the header file cache on the first call.
if (!initialized) {
rf_refcount = 0
do i = 1, MAX_CACHE
rf_stf[i] = 0
iferr (rf_cachesize = envgeti (ENV_STFCACHE))
rf_cachesize = DEF_CACHE
if (rf_cachesize > MAX_CACHE) {
call eprintf ("A maximum of %d STF headers may be cached\n")
call pargi (MAX_CACHE)
rf_cachesize = MAX_CACHE
} else if (rf_cachesize <= 0)
rf_cachesize = 0
initialized = true
}
rf_refcount = rf_refcount + 1
o_stf = IM_KDES(im)
reload = false
slot = 1
# Get file system info on the desired header file.
call fpathname (IM_HDRFILE(im), Memc[hdrfile], SZ_PATHNAME)
if (finfo (Memc[hdrfile], fi) == ERR)
call syserrs (SYS_FOPEN, IM_HDRFILE(im))
repeat {
# Search the header file cache for the named image.
do i = 1, max(1,rf_cachesize) {
if (rf_stf[i] == NULL) {
slot = i
next
}
if (streq (Memc[hdrfile], rf_fname[1,i])) {
# File is in cache; is cached entry still valid?
if (FI_MTIME(fi) != rf_mtime[i]) {
# File modify date has changed, reuse slot.
slot = i
break
} else if (!reload && clktime(rf_time[i]) < 2) {
# The file modify date has not changed, but the cache
# was loaded within the last clock "tick" (second),
# so we cannot be sure that the file was not modified.
# The cache must be reloaded, but set a flag so that
# rf_time is not changed, so that when the cache entry
# ages sufficiently it will be considered valid.
reload = true
slot = i
break
} else {
# Return the cached header.
rf_lru[i] = rf_refcount
call amovi (STF_CACHE(rf_stf[i]), STF_CACHE(o_stf),
STF_CACHELEN(rf_stf[i]))
fits = rf_fits[i]
fitslen = rf_fitslen[i]
# Invalidate entry if cache is disabled.
if (rf_cachesize <= 0)
rf_time[i] = 0
call sfree (sp)
return # IN CACHE
}
} else {
# Keep track of least recently used slot.
if (rf_lru[i] < rf_lru[slot])
slot = i
}
}
# Either the image header is not in the cache, or the cached
# entry is invalid. Prepare the given cache slot and read the
# header into it.
# Free old save buffer and descriptor.
if (rf_stf[slot] != NULL) {
call mfree (rf_stf[slot], TY_STRUCT)
call mfree (rf_fits[slot], TY_CHAR)
}
# Open the header file.
if (IM_HFD(im) == NULL)
in = open (Memc[hdrfile], READ_ONLY, TEXT_FILE)
else {
in = IM_HFD(im)
call seek (in, BOFL)
}
# Allocate a spool file for the FITS data.
call sprintf (rf_fname[1,slot], SZ_PATHNAME, "STFHC#%d")
call pargi (slot)
spool = open (rf_fname[1,slot], READ_WRITE, SPOOL_FILE)
call fseti (spool, F_BUFSIZE, FI_SIZE(fi))
# Allocate cache version of STF descriptor.
call calloc (stf, LEN_STFDES, TY_STRUCT)
# Initialize the cache entry.
call strcpy (Memc[hdrfile], rf_fname[1,slot], SZ_PATHNAME)
rf_stf[slot] = stf
rf_lru[slot] = rf_refcount
rf_mtime[slot] = FI_MTIME(fi)
if (!reload)
rf_time[slot] = clktime (0)
reload = true
# Read successive lines of the FITS header. Process reserved
# keywords into the STF descriptor and spool the remaining cards
# to the fits spool file.
repeat {
# Get the next input line.
nchars = getline (in, Memc[lbuf])
if (nchars == EOF)
break
# Block it out to 80 chars (plus newline) if it is not already.
if (nchars != FITS_RECLEN + 1) {
for (op=nchars; op <= FITS_RECLEN; op=op+1)
Memc[lbuf+op-1] = ' '
Memc[lbuf+FITS_RECLEN] = '\n'
Memc[lbuf+FITS_RECLEN+1] = EOS
}
# Process the header card.
switch (stf_ctype (Memc[lbuf], index)) {
case KW_BITPIX:
call stf_geti (Memc[lbuf], STF_BITPIX(stf))
case KW_DATATYPE:
call stf_gets (Memc[lbuf], STF_DATATYPE(stf), SZ_DATATYPE)
case KW_END:
break
case KW_GCOUNT:
call stf_geti (Memc[lbuf], STF_GCOUNT(stf))
case KW_GROUPS:
call stf_getb (Memc[lbuf], STF_GROUPS(stf))
case KW_NAXIS:
call stf_geti (Memc[lbuf], STF_NAXIS(stf))
case KW_NAXISN:
call stf_geti (Memc[lbuf], STF_LENAXIS(stf,index))
case KW_PCOUNT:
call stf_geti (Memc[lbuf], STF_PCOUNT(stf))
case KW_PDTYPE:
pp = STF_PDES(stf,min(index,MAX_PCOUNT))
call stf_gets (Memc[lbuf], P_PDTYPE(pp), SZ_PDTYPE)
case KW_PSIZE:
call stf_geti (Memc[lbuf], STF_PSIZE(stf))
case KW_PSIZEN:
pp = STF_PDES(stf,min(index,MAX_PCOUNT))
call stf_geti (Memc[lbuf], P_PSIZE(pp))
case KW_PTYPE:
pp = STF_PDES(stf,min(index,MAX_PCOUNT))
call stf_gets (Memc[lbuf], P_PTYPE(pp), SZ_PTYPE)
call stf_getcmt (Memc[lbuf], P_COMMENT(pp), SZ_COMMENT)
case KW_SIMPLE:
;
default:
call putline (spool, Memc[lbuf])
}
}
# Close the header file if opened locally.
if (IM_HFD(im) == NULL)
call close (in)
# Free any unneeded space in the STF descriptor.
if (STF_PCOUNT(stf) > 0) {
call realloc (stf,
LEN_STFBASE + STF_PCOUNT(stf)*LEN_PDES, TY_STRUCT)
rf_stf[slot] = stf
}
# Filter the spooled FITS cards to delete any cards which redefine
# GPB keywords. Store the filtered FITS data in the cache.
call seek (spool, BOFL)
nchars = fstatl (spool, F_FILESIZE)
call malloc (fits, nchars, TY_CHAR)
user = stropen (Memc[fits], nchars, NEW_FILE)
call stf_copyfits (stf, spool, NULL, user)
rf_fits[slot] = fits
rf_fitslen[slot] = fstatl (user, F_FILESIZE)
call close (user)
call close (spool)
}
end
|